Как получить конфликт между git и веткой master? - PullRequest
1 голос
/ 29 октября 2019

Я разбудил проект, в который добавлены и изменены файлы.

Через некоторое время я понял, что мне следует обновить несколько конфигов из основной ветки. Я попытался сделать git-pull мастер и другие вещи, и я потерял несколько файлов (как-то).

Теперь я удалил весь каталог (возможно, не очень умный), и я пытаюсь загрузить свойразветвляется от последнего коммита следующим образом:

> git clone [URL of the project]
> git checkout [code of the last commit in my fork]
> git pull origin master

и все, что он говорит:

* branch            master     -> FETCH_HEAD
Already up-to-date.

, который ничего не делает и не вносит никаких изменений. Я ожидал некоторых конфликтов в некоторых файлах, поэтому мне было интересно, как мне добраться до того момента, когда две версии (мой форк и мастер) будут показывать конфликт (обычно с чем-то вроде >>>>>>>> HEAD .. .)

1 Ответ

1 голос
/ 29 октября 2019

Здесь есть своего рода основная проблема: это не ветви , которые приводят к конфликтам. Или, может быть, лучше: ветви необходимы, но не достаточны. (Но это также зависит от того, как мы определяем branch .)

Чтобы иметь конфликт в Git, вы должны:

  • выполнить трехстороннее слияние,используя git merge 1
  • с использованием двух входных коммитов (которые будут приходить из ветвей, но здесь не важны ветви)
  • , чьи График коммитов приводит к тому, что Git находит третий базовый коммит коммит, который отличается от двух других входов, и в последнем
  • оба эти коммита имеют изменения водни и те же строки одного и того же файла (ов). 2

При всем этом термин fork совершенно не имеет значения. Вилка - это просто клон с некоторой особой семантикой, предоставленной хостинг-провайдером, который предоставил вам кнопку «вилка» с веб-интерфейсом, доступным через веб-интерфейс, или доступный через Интернет API «вилка». Если вы разветвляли хранилище, вы клонировали его. Если вы клонировали свой клон, вы клонировали его снова. Важно то, какие коммиты у вас есть по их хэш-идентификаторам, которые являются их настоящими именами, даже если вы находите этих коммитов по именам ветвей.

Каждый коммитзапоминает хеш-идентификатор своего непосредственного родителя, 3 , в результате чего получается обратная цепочка:

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

, где H обозначает некоторый хеш-идентификатор фиксации. Commit H запоминает хэш-идентификатор своего предшествующего коммита. Вместо того, чтобы использовать большой некрасивый хэш-идентификатор, мы просто используем другую букву, чтобы заменить его, поэтому мы называем это G. Так что commit H указывает на (содержит хеш-код) commit G. Коммит G в свою очередь указывает на F, который продолжает указывать назад.

Сделав клон или просто набор коммитов в вашем собственном хранилище - все, что имеет значение коммит —У вас теперь есть что-то похожее на это:

          I--J   <-- branch1
         /
...--G--H
         \
          K--L   <-- branch2

ветвь names , branch1 и branch2 здесь, удерживайте идентификатор хеша last коммит в ветке. Git обновил их автоматически, например, когда вы использовали git checkout в ветке и сделали новые коммиты, так что, когда вы делали новые коммиты, ветвь росла, и имя продолжало указывать на последний коммит. Так что теперь они указывают на коммиты J и L соответственно.

Если вы теперь запустите git checkout branch1 и git merge branch2, Git будет обрабатывать коммиты J и L как два входа, которые выобеспечить и самостоятельно - найти лучший общий коммит, который в данном случае, очевидно, является коммитом H, который находится на обеих ветвях. Затем Git:

  • сравнивает все файлы в H со всеми файлами в J - git diff --find-renames H J - чтобы увидеть, что вы изменили, и
  • сравнить все файлы в H со всеми файлами в L - git diff --find-renames H L - чтобы увидеть, что они изменились.

Операция объединения пытаетсяобъединить эти два набора изменений, применяя объединенные изменения к файлам в H, чтобы создать новый набор файлов, которые можно использовать для моментального снимка в новом коммите слияния.

Если это объединениеуспешно, Git сделает новый коммит слияния M самостоятельно:

          I--J
         /    \
...--G--H      M   <-- branch1 (HEAD)
         \    /
          K--L   <-- branch2

HEAD здесь указывает, что это ветвь, в которой мы находимся, и, поскольку мы находимся на branch1, этоимя, которое Git обновляет для хранения хэш-идентификатора нового коммита M. Commit M имеет снимок, сделанный путем применения комбинированных изменений к снимку в H.

Если возникают конфликты слияния, Git останавливается, вообще не делая M. Git оставляет вам беспорядок для очистки. 4 Вы должны сделать свое собственное объединение, а затем сказать Git, что вы успешно исправили все конфликты и получили правильный результат объединения. Затем вы используете git merge --continue или git commit (любой из них), чтобы завершить объединение и сделать коммит M и снимок, который вы построили.


1 Gон также использует трехстороннее слияние для реализации git cherry-pick и git revert, а также несколько других особых случаев, поэтому вы можете получить конфликты слияния без использования git merge. Но git merge - это обычный источник, который вы описываете, поэтому вы можете думать об этом как о «когда вы запускаете git merge» без слишком большой потери точности.

Обратите внимание, что git pull означает запустить git fetch, затем запустить вторую команду Git, обычно git merge. Так что git pull - это просто выборка + слияние.

2 Есть некоторые неприятные детали о том, что означает "то же самое", как для файлов, которые можно переименовывать, так и для строк, которыеможет просто упираться, а не перекрываться. Но опять же, вы можете думать об этом как о «другом изменении в одной и той же строке одного и того же файла» = «конфликт» и быть достаточно близким.

3 Для коммитов слияния коммит запоминается всех его родителей - обычно только двух - и, следовательно, указывает не только на коммит в ветви, на которой вы были, когда вы сделали слияние, но также и на коммит, который был вершиной ветви, которую вы слилив то время, когда вы произвели слияние.

4 Беспорядочное состояние слияния занимает index , который мы здесь вообще не описывали. Git также оставляет вам свою лучшую попытку объединить конфликтующие изменения в файлах в рабочем дереве и оставляет информацию о слиянии, записанном для git merge --continue, которая работает git commit или для git commit,чтобы сделать коммит слияния.

Вы можете отказаться от всего, используя git merge --abort, который возвращает все к тому, что было до того, как вы запустили git merge.

...