Подтвердить что ты не робот

В Git конфликте с слиянием вишни или перебаза, как определяются BASE (aka "ancestor" ), LOCAL и REMOTE?

В обычном конфликте с конфликтом Git три версии файла в игре для трехстороннего слияния примерно следующие:

  • LOCAL: версия из моей ветки
  • REMOTE: версия из другой ветки
  • BASE: версия из общего предка двух ветвей (в частности, общий предок моей ветки HEAD и другой ветки HEAD)

Когда Git вишня-выбор генерирует конфликт слияния, нет общего предка, правильно говоря, так как определяются эти вещи? То же самое можно было бы задать о rebase.

4b9b3361

Ответ 1

вишневого выбор

Если я не ввел себя в заблуждение, тогда, если вы сделаете "git cherry-pick < commit C > ", вы получите:

  • LOCAL: фиксация, которую вы объединяете сверху (т.е. HEAD вашей ветки)
  • REMOTE: фиксация, которую вы выбрали на черри (т.е. < commit C > )
  • BASE: родительский элемент фиксации, который вы выбрали на вишне (т.е. C ^, т.е. родительский элемент C)

Если не сразу понять, почему BASE должно быть C ^, см. раздел "почему" ниже.

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

E <-- master
|
D 
| C <-- foo_feature(*)
|/
B
|
A

и вы находитесь в ветке foo_feature (следовательно, звездочка). Если вы сделаете "git cherry-pick < commit D > ", тогда BASE для этой вишневой подборки будет фиксацией B, которая является общим предком C и D. (C будет LOCAL, а D будет REMOTE. ) Однако, если вы вместо этого выполняете "git cherry-pick < commit E > , тогда BASE будет совершать D. (C будет LOCAL и E будет REMOTE.)

перебазироваться

Для фонового контекста rebase - это приблизительно повторная сортировка вишни. В частности, тема переустановки поверх мастера (т.е. "git тема проверки; git мастер переадресации" ) означает примерно:

git checkout master # switch to master HEAD commit
git checkout -b topic_rebased # create new branch rooted there
for each commit C in master..topic # for each topic commit not already in master...
    git cherry-pick C # bring it over to the new branch
finally, forget what "topic" used to mean and now defined "topic" as the HEAD of topic_rebased.

Надписи, которые применяются во время этого процесса, являются расширениями правил обычной вишни:

  • LOCAL: фиксация, которую вы выбрали на вишне
    • Это HEAD новой ветки topic_rebased
    • Только для первого коммита это будет то же самое, что и HEAD мастера
  • REMOTE: фиксация, которую вы выбрали на черри (т.е. < commit C > )
  • BASE: родительский элемент фиксации, которую вы выбрали на вишне (C ^, т.е. родительский элемент C)

Это подразумевает что-то, чтобы иметь в виду LOCAL vs REMOTE, если вы хотите избежать путаницы:

Несмотря на то, что вы были в ветке, когда вы инициировали rebase, LOCAL никогда не ссылается на фиксацию на ветке темы, пока выполняется переформатирование. Вместо этого LOCAL всегда ссылается на фиксацию новой создаваемой ветки (topic_rebased).

(Если не помнить об этом, то во время неприятного слияния можно начать спрашивать себя: "Подождите, почему это говорит о локальных изменениях? Я клянусь, что это были изменения, сделанные на хозяине, а не на моей ветке." )

Чтобы быть более конкретным, вот пример:

Скажем, у нас есть график графа

D <-- foo_feature(*)
|
| C <-- master
B |
|/
|
A

и в настоящее время мы находимся в ветке foo_feature (обозначается символом "*" ). Если мы запустим "git мастер переадресации", rebase будет выполняться в два этапа:

Во-первых, изменения из B будут воспроизведены поверх C. Во время этого C LOCAL, B - REMOTE, а A - BASE. Заметим, что A является реальным общим предком B и C. После этого первого шага у вас есть график примерно так:

   B' <-- foo_feature
D  |
|  |
|  C <-- master
B /
|/
|
A

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

Во-вторых, изменения от D будут воспроизведены поверх B '. Во время этого B 'является ЛОКАЛЬНЫМ, D - ДИСТАНЦИОННЫМ, а B - BASE. Заметим, что B не является соответствующим общим предком чего-либо. (Например, он не является общим предком текущего LOCAL и REMOTE, B 'и D. И он не является общим предком исходных ветвей ветвей, C и D). После этого шага у вас есть ветвь примерно так:

   D' <-- foo_feature
   |
   B'
D  |
|  |
|  C <-- master
B /
|/
|
A

Для полноты, примечание к концу перестановки B и D удаляется из графика, давая:

D' <-- foo_feature
|
B'
|
C <-- master
|
A

Почему BASE определена как она?

Как отмечалось выше, как для набора вишни, так и для rebase, BASE является родительским (C ^) фиксации C. В общем случае C ^ не является общим предком, поэтому почему назовите его BASE? (В обычном слиянии BASE является общим предком. И часть успеха git в слиянии связана с его способностью находить хорошего общего предка.)

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

  • Если < commit C > не изменяет данный заданный регион файла, тогда будет преобладать версия этого региона из вашей ветки. (Это области, которые "патч" не требует изменения, не получают исправления.)
  • Если < commit C > изменяет заданную область файла, и ваша ветвь покидает этот регион, а затем версию этого региона из < commit x > будет преобладать. (То есть регионы, которые "патч" требует изменения, получают исправление.)
  • Если < commit C > изменяет данный регион файла, но ваша ветвь также изменила этот регион, тогда вы получите конфликт слияния.