git: объединить две ветви: в каком направлении? - PullRequest
58 голосов
/ 28 февраля 2010

У нас следующая ситуация:

             A --- B --- C --- ... --- iphone
           /
  ... --- last-working --- ... --- master

Между последней работой и iPhone было сделано 32 коммита. Между последней работой и мастером было сделано много коммитов.

Теперь мне нужна новая ветка, в которой iphone и текущий мастер объединены вместе. И через некоторое время это должно быть объединено с мастером.

Сначала я планировал сделать:

git checkout iphone -b iphone31
git merge master

Но тогда я подумал, что будет лучше сделать:

git checkout master -b iphone31
git merge iphone

Теперь мне интересно. Какая разница в результате? Будет ли слияние вести себя иначе?

Я уже попробовал и то и другое, и, как я и ожидал, я получил много конфликтов, потому что iphone действительно старый по сравнению с master. Теперь мне интересно, как проще всего их объединить.

Может быть, даже начинать с мастера и объединять каждый коммит iphone в него будет проще? Как это сделать:

git checkout master -b iphone31
git merge A
git merge B
git merge C
...
git merge iphone

В самом конце, когда это слияние завершено (т.е. все конфликты разрешены и оно работает), я хочу сделать это:

git checkout master
git merge iphone31

Ответы [ 5 ]

42 голосов
/ 28 февраля 2010

Относительно альтернатив

git checkout iphone -b iphone31
git merge master

и

git checkout master -b iphone31
git merge iphone

они будут иметь одинаковую легкость или сложность, это все равно что спорить, наполовину ли стакан или наполовину пуст.

Версия дерева восприятия

То, как мы смотрим на деревья версий, является в некотором роде нашим произвольным восприятием. Допустим, у нас есть дерево версий, подобное следующему:

    A----------+
    |          |
    |          |
   \_/        \_/
    B          X
    |          |
    |          |
   \_/        \_/
    C          Y
    |
    |
   \_/
    D
    |
    |
   \_/
    E

И скажем, мы хотим сделать новую версию Z проверенной из Y основанный на изменениях от C до E, но не включая изменения, сделанные из От А до С.

«О, это будет сложно, потому что нет единой отправной точки». Ну не совсем. Если мы просто разместим объекты немного по-другому в графическом макете, как это

      /
    C+---------+
    | \        |
    |          |
   \_/         |
    D          B
    |         / \
    |          |
   \_/         |
    E          A
               |
               |
              \_/
               X
               |
               |
              \_/
               Y

сейчас все начинает выглядеть многообещающе. Обратите внимание, что я не здесь изменилось любое отношение кораблей, все стрелки указывают так же, как на предыдущей картинке и версии А все еще общая база. Изменен только макет.

Но теперь тривиально представить себе другое дерево

    C'---------+
    |          |
    |          |
   \_/        \_/
    D          B'
    |          |
    |          |
   \_/        \_/
    E          A
               |
               |
              \_/
               X
               |
               |
              \_/
               Y

, где задача состоит в том, чтобы просто объединить версию E.

Так что вы можете объединить все, что хотите, единственное, что влияет легкость или сложность - это совокупность изменений, сделанных между Вы выбираете в качестве отправной точки или общей базы, и где вы сливаетесь с. Вы не ограничены использованием естественной отправной точки инструмент управления версиями.

Это может быть непросто с некоторыми системами / инструментами контроля версий, но если все остальное терпит неудачу там ничто не мешает вам сделать это вручную проверить версию C и сохранить файл как file1, проверить версию E и сохранить файл как file2, проверить версию Y и сохранить файл как file3, и запустить kdiff3 -o merge_result file1 file2 file3.

Ответ

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

Мое предложение было бы поскольку между последним и iphone есть 32 коммита, Например, вы можете начать с ветвления мастера, а затем объединить в первые 16 коммитов. Если это оказывается слишком много проблем, вернитесь и попробуйте объединить 8 первых коммитов. И так далее. В худшем случае вы в конечном итоге сливаете каждый из 32 коммитов по одному, но это, вероятно, будет проще, чем справиться со всеми накопленные конфликты в одной операции слияния (и в этом случае вы работаете с действительно базой расходящегося кода).

Советы:

Нарисуйте на бумаге дерево версий и отметьте стрелками, что вы хотите слияния. Вычеркните вещи, как они сделаны, если вы разделите процесс в несколько шагов. Это даст вам более четкое представление о том, что вы хотите чтобы достичь того, что вы уже сделали и что осталось.

Я действительно могу порекомендовать KDiff3 , это отличный инструмент сравнения / слияния.

9 голосов
/ 31 августа 2017

Есть разница.


Всегда проверять целевую ветвь во время слияния (т. Е. При слиянии A с B, извлекать B).


Люди часто говорят, что направление слияния не имеет значения, но это неправильно. Несмотря на то, что итоговое содержимое будет одинаковым независимо от направления слияния, есть несколько аспектов, которые отличаются:

  1. Различия, перечисленные в результирующем коммите, будут отличаться в зависимости от направления.
  2. Большинство визуализаторов ветвей решают, какая ветвь является "основной", используя направление слияния.

Чтобы уточнить, представьте себе этот преувеличенный пример:

  • Вы отошли от MASTER на 1000 коммитов и назвали его DEVELOP (или в сценарии с отслеживающей ветвью вы не получили его в течение достаточно долгого времени).
  • Вы добавляете один коммит в DEVELOP. Вы знаете, что для этого изменения нет конфликтов.
  • Вы хотите перенести свои изменения в MASTER.
  • Вы неверно объединяете MASTER с DEVELOP (т. Е. DEVELOP извлекается во время объединения). Затем вы нажимаете DEVELOP как новый MASTER.
  • Различия в результирующем коммит-коммите покажут все 1000 коммитов, которые произошли в MASTER, потому что DEVELOP является контрольной точкой.

Эти данные не только бесполезны, но и трудно понять, что происходит. Большинство визуализаторов создадут впечатление, что ваша линия DEVELOP была основной с 1000-ю коммитами.

Мое предложение таково: Всегда проверяйте целевую ветвь во время слияния (т. Е. При слиянии А с В, извлечении Б).

  • Если вы работаете над параллельной ветвью и хотите периодически вносить изменения из основной ветки, тогда извлеките вашу параллельную ветвь. Различия будут иметь смысл - вы увидите изменения, внесенные в основную ветку с вашей веткой.
  • Когда вы закончите работать параллельно и захотите объединить свои изменения с основной веткой, извлеките основную ветку и слит с вашей параллельной веткой. Дифференциал снова будет иметь смысл - он покажет, какие ваши параллельные изменения относятся к основной ветви.

Читаемость журнала, на мой взгляд, имеет значение.

6 голосов
/ 28 февраля 2010

Лучший подход действительно зависит от того, есть ли у других людей удаленные копии вашего кода. Если ветвь master имеется только на вашем локальном компьютере, вы можете использовать команду rebase для интерактивного применения фиксаций из ветви функций в master:

git checkout master -b iphone-merge-branch
git rebase -i iphone

Обратите внимание, что это изменяет историю коммитов вашей новой iphone-merge-branch ветки, что может вызвать проблемы у любого другого, кто попытается позже внести ваши изменения в их извлечение. Команда слияния, напротив, применяет изменения в качестве нового коммита, что безопаснее при совместной работе, поскольку не влияет на историю ветвлений. В этой статье приведены полезные советы по использованию rebase.

Если вам нужно синхронизировать историю коммитов, вам лучше выполнить слияние. Вы можете использовать git mergetool , чтобы интерактивно исправлять конфликты один за другим, используя инструмент визуального различия (учебник по этому вопросу можно найти здесь ):

git checkout master -b iphone-merge-branch
git merge iphone
git mergetool -t kdiff3

Третий вариант, если вам нужен абсолютный контроль над процессом, это использовать git cherry-pick . Вы можете использовать gitk (или ваш любимый просмотрщик истории), чтобы просматривать хэши коммитов в ветке iphone, записывать их и вставлять их по отдельности в ветвь слияния - исправляя конфликты по мере продвижения. Объяснение этого процесса можно найти здесь . Этот процесс будет самым медленным, но может быть лучшим вариантом для отказа, если другие методы не сработают:

gitk iphone
<note down the 35 commit SHA hashes in this branch>
git checkout master -b iphone-merge-branch
git cherry-pick b50788b
git cherry-pick g614590
...
2 голосов
/ 28 февраля 2010

Вы говорите:

ветка iphone очень старая по сравнению с master

Вы действительно хотите объединить их обоих в новую ветвь?

Назначение веток master и iphone теперь было бы совсем другим (потому что iphone очень старый). Новая ветка слияния iphone с предком master будет лучше? Подумай об этом.

Я настоятельно рекомендую вам прочитать Удовольствие от слияния и назначения веток .

После прочтения этой статьи, если вы все еще чувствуете, что хотите объединить iphone и master, тогда @seanhodges объясняет, как действительно хорошо справляться с конфликтами.

1 голос
/ 09 мая 2014

Вы можете сделать локальное резервное копирование своей работы перед экспериментом, чтобы вы могли перезапустить ее, если перестанете понимать, что произошло.

Создайте резервную копию своей работы, чтобы не потерять ее при перезагрузке, если хотите сохранить ее для справки.

git checkout iphone -b iphone_backup

Создать новую ветку от мастера

git checkout master -b iphone31

затем перебазируем сверху.

git rebase -i --onto iphone31 iphone

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

В качестве альтернативы, вы можете сделать только

git rebase -i master iphone

если вас не волнует резервное копирование ветки iphone. Обратитесь к документации по rebase для получения подробной информации и альтернатив http://git -scm.com / docs / git-rebase .

...