Как я могу git pu sh все изменения в оригинале master без слияния? - PullRequest
0 голосов
/ 30 марта 2020

git -2.16.2 на linux

git новичок, поэтому, пожалуйста, потерпите ....

Я клонировал репо, изменил несколько файлов и теперь я хочу, чтобы pu sh, что к мастеру происхождения. Я не хочу ничего объединять, я хочу, чтобы git принимал все сделанные мной изменения без объединения.

Я считаю, что мне все еще нужно использовать git pull --rebase. И я знаю, что будут конфликты. Но есть ли способ обойти часть слияния этого и просто вернуть все мои изменения в мастер происхождения без слияния (после git add, git commit of c)?

Ответы [ 3 ]

2 голосов
/ 30 марта 2020

Если состояние происхождения изменилось с тех пор, как вы клонировали (например, лицо B подтолкнуло к нему), вы не можете просто сделать изменения * * * * без уничтожения изменений лица B. Вместо этого вы должны поместить свои локальные изменения в их собственную ветку «new», перетащить изменения Person B в свою основную ветвь, а затем перенести вашу «новую» ветвь в конец master. Тогда пу sh все это обратно.

2 голосов
/ 30 марта 2020

То, что вы описываете, это

git push --force

, и все скажут вам не делать этого. То есть, если вы когда-нибудь работаете вместе с кем-то в репозитории (или даже ветке). Это потому, что вы переписываете историю .

Если это ваш собственный репозиторий (я так думаю), проблем не будет.

Если вы хотите сделать это «правильно», вам придется выполнить слияние, а затем использовать только изменения из локальных, например здесь . Таким образом, вы сохраняете свою историю и достигаете того же результата.

1 голос
/ 31 марта 2020

Git не пу sh меняет , а фиксирует . Это потому, что Git не не сохраняет изменений.

Каждый коммит содержит полный, полный снимок всех своих файлов. Это data часть коммита. Каждый коммит также содержит некоторые метаданные , например, кто его сделал (имя и адрес электронной почты), когда и почему (сообщение журнала). Вы можете просмотреть коммит как изменения, сравнив снимок с моментальным снимком предыдущего коммита, но это все еще полный снимок.

Каждый коммит имеет свой уникальный уникальный идентификатор ha sh. Этот ha sh ID означает , что коммит: никогда никакой другой коммит, и никакой другой репозиторий Git нигде не может использовать этот коммит ha sh ID для любого другого коммита. Каждый Git репозиторий, имеющий этот коммит, использует , который га sh ID для него. (Вот почему идентификаторы коммитов ha sh такие большие и некрасивые: они должны быть уникальными!)

Между тем, внутри метаданных для каждого коммита коммит содержит необработанный идентификатор ха sh некоторых ранее или родительский коммит. Мы говорим, что этот коммит указывает на его родителя. Если мы нарисуем диаграмму нескольких коммитов, мы увидим, что они имеют тенденцию становиться обращенными назад, линейными цепочками:

... <-F <-G <-H

, где H - это последний или последний коммит. У него большой некрасивый идентификатор ha sh, который я только что назвал H, и commit H содержит фактический идентификатор ha sh предыдущего коммита G, который содержит идентификатор ha sh еще более ранний коммит F и так далее. Эти обратные цепочки позволяют с Git по показывать коммит в виде набора изменений, который намного меньше (и полезнее), чем просто каждый раз показывать весь снимок.

Что означает ветвь в Git, так это то, что она позволяет вам - и Git - быстро найти этот последний коммит. Я перестану рисовать внутренние стрелки как стрелки (из-за лени), но продолжайте рисовать имена ветвей в виде стрелок:

...--F--G--H   <-- master

Имя master содержит га sh ID последний коммит H.

Я клонировал репо, изменил несколько файлов, и теперь я хочу добавить sh в исходный мастер.

Технически, вы клонировали репо, что дало вам все их коммитов , и сделали вас своим собственным именем master. Ваш клон также запомнил идентификатор sh последнего коммита в их master под вашим именем origin/master, который мы можем нарисовать так:

...--G--H   <-- master (HEAD), origin/master

(This HEAD дело в том, как Git запоминает, какое имя ветви вы используете.)

Когда вы сделали новый коммит, он получил новый уникальный идентификатор ha sh. Давайте просто назовем это I для краткости:

...--G--H   <-- origin/master
         \
          I   <-- master (HEAD)

Обратите внимание, как ваш master теперь указывает на фиксацию I, а не H. Но вы все равно можете найти H двумя способами: I указывает на H и origin/master указывает на H.

Между тем, в их хранилище Возможно, кто-то добавил новый коммит или два:

...--G--H--J--K   <-- master

Помните, это их хранилище (и их master), а не ваше.

Когда вы запускаете git push origin master, ваши Git вызывают их Git. Ваш Git говорит им, что вы совершили I, и вы хотели бы передать его им. Ваш Git говорит им, что родитель I H, и они говорят хорошо, у меня уже есть этот коммит, просто дайте мне I. Вы отправляете им I:

          I   [your commit]
         /
...--G--H--J--K   <-- master

Неважно, будем ли мы рисовать I выше или ниже или рисовать более ответвленно как:

          I   [your commit]
         /
...--G--H
         \
          J--K   <-- master

пока мы рисуем все соответствующие коммиты и их соединения.

Теперь ваш Git просит их - их Git - установить их master для указания на коммит I, который у вас обоих сейчас есть. Если они выполнят этот вежливый запрос , у них будет:

          I   <-- master
         /
...--G--H--J--K

Они больше не смогут найти коммиты J-K , потому что их Git находит коммиты, используя имя своей ветви. Он находит I, что приводит к H, а затем G и т. Д., Но никогда не идет вперед.

Если вы используете git push --force, вы изменяете свой вежливый запрос на команду: Установите свой master! Если они подчинятся, они потеряют коммиты J-K.

Что вы должны сделать с этим?

Что вам понадобится, если у них есть эти коммиты , это один из способов отправки ваших коммитов, чтобы они не потеряли своих .

У вас есть несколько вариантов. Одним из них является использование git merge origin/master до совмещения вашей работы с их работой. Другой - использовать git rebase, что более сложно.

Объединение

Для объединения используйте git fetch, чтобы убедиться, что ваши собственные Git соответствуют их, а затем использовать git merge origin/master. 1 Это делает новый коммит слияния , который я нарисую как M:

          I-----M   <-- master (HEAD)
         /     /
...--G--H--J--K   <-- origin/master

Что делает коммит слияния объединение состоит в том, что он указывает на более одного родителя . Здесь два родителя - коммиты I и K. Если теперь у вас есть Git, позвоните на их Git и отправьте master, ваш Git предложит им совершить M. Они возьмут M. Поскольку у M есть два родителя, ваш Git предложит I и K. У них есть K, но не I, 2 , поэтому они тоже возьмут I, и ваш Git предложит H. У них есть H, поэтому они просто возьмут M и I в конце.

Затем ваш Git попросит их установить master для указания M. ничего не потеряет , поэтому они, вероятно, примут этот запрос. Ваши собственные Git теперь будут обновлять ваши собственные origin/master - ваши воспоминания об их master - соответственно.


1 Если вам действительно нравится git pull, вы можете используйте git pull до , комбинируйте шаг git fetch с шагом git merge. Все, что git pull делает, это запускает обе команды. Это лишает вас возможности вставлять Git команды между двумя командами, а для Git новичков я нахожу это более запутанным, поэтому я предпочитаю хранить их как отдельные команды.

2 Они могут иметь I с вашей предыдущей попытки или нет, в зависимости от их Git версии ... и от того, предприняли ли вы попытку после всех , Если у них есть I, это нормально: I га sh ID уникален для , который фиксирует.


Rebase

Что git rebase в двух словах означает копировать некоторые коммиты в новые и улучшенные версии, а затем перемещать имя ветки.

Ничего - не вы и не Git сам по себе - может изменить любой существующий коммит. Все коммиты заморожены на все время. Вот что заставляет работать идентификаторы ha sh. Но вы можете взять коммит, и поработать над ним, и сделать новый коммит, который так же хорош, как и оригинал, с точки зрения того, что изменения он делает, и лучше чем новый коммит в том, что он идет в нужное место.

То есть, предположим, у вас есть:

          I   <-- master (HEAD)
         /
...--G--H--J--K   <-- origin/master

Что если есть простой способ получить Git копия существующего коммита I в новый и улучшенный коммит, который приходит после коммита K?

Есть, и это git rebase. Мы запускаем:

git rebase origin/master

и Git перечисляет все коммиты на нашем master (I, H, G, ... на спине), а затем вычеркивает из В этом списке перечислены все коммиты, которые находятся на origin/master (K, J, H, G, ...). Это оставляет коммит I. (Если бы у нас было больше коммитов, таких как I-L, у нас был бы этот список здесь, и следующий шаг скопировал бы два коммита вместо одного.)

Наш Git затем использует detached Режим HEAD (который мы просто замаскируем) для копирования каждого коммита, по одному, после комита K, который мы назвали origin/master:

          I   <-- master
         /
...--G--H--J--K   <-- origin/master
               \
                I'  <-- HEAD

Скопировав все коммиты, наш Git затем восстанавливает наше имя master здесь, до последнего скопированного коммита, и повторно присоединяет HEAD к master:

          I   [abandoned]
         /
...--G--H--J--K   <-- origin/master
               \
                I'  <-- master (HEAD)

Поскольку коммит I не имеет имени , мы не найдем его напрямую, а поскольку I' указывает на K, что указывает на J, что указывает до H, что указывает на G, мы также не найдем его таким образом. Может показаться, что мы каким-то образом изменили существующий коммит I.

У нас - I' не было совершенно другого идентификатора ha sh от I, но поскольку мы единственные Git что у было I, никто больше не должен знать это. Теперь мы можем запустить:

git push origin master

, чтобы отправить коммит I' другому Git и попросить их установить их master, чтобы указать I'. Пока их master все еще указывают на K прямо сейчас, это будет успешным.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...