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

Git: объединить две ветки: в каком направлении?

Мы имеем следующую ситуацию:

             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 действительно старый по сравнению с мастером. Теперь я задаюсь вопросом о самом простом способе их слияния.

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

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

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

git checkout master
git merge iphone31
4b9b3361

Ответ 1

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

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, но не включая изменения, сделанные из От A до C.

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

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

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

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

    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, это отличный инструмент для разметки/слияния.

Ответ 2

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

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
...

Ответ 3

Вы говорите:

Филиал iphone очень старый по сравнению с мастером

Вы действительно хотите объединить их, образуя новую ветку?

Цель основных и iphone-ветвей теперь была бы совсем другой (потому что iphone очень старый). Новая ветка, объединяющая iphone с предком мастера, была бы лучше? Подумайте об этом.

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

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

Ответ 4

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

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

git checkout iphone -b iphone_backup

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

git checkout master -b iphone31

затем переформатируйте поверх него.

git rebase -i --onto iphone31 iphone

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

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

git rebase -i master iphone

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

Ответ 5

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


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


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

  • Дифференциалы, перечисленные в полученном результате слияния, будут отличаться в зависимости от направления.
  • Большинство визуализаторов ветвей решают, какая ветвь "первичная" использует направление слияния.

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

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

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

Мое предложение таково: Всегда проверяйте целевую ветвь во время слияния (т.е. при слиянии A с B, checkout B).

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

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