ускоренное слияние двух веток извлечение из одной ветки - PullRequest
0 голосов
/ 11 сентября 2018

Я извлек две ветки из ветки "master", скажем, "feature1" и "feature2".Допустим, «C1» - это главный коммит «master», а в ветке «feature1» есть новый коммит «C2», а в ветке «feature2» - новый коммит «C3».

Как объединить «feature2»в ветке "feature1" ускоренной перемоткой вперед, если возможно, в обычное слияние?

Пожалуйста, помогите избежать рекурсивного слияния как можно больше.

Заранее спасибо ...

1 Ответ

0 голосов
/ 11 сентября 2018

Давайте возьмем ваше слово и превратим его в реальную картину.У вас есть имя ветви master, которое указывает на последний коммит в серии коммитов.Я назову этот последний коммит master, который имеет большой уродливый идентификатор хеша, H здесь.Commit H записывает фактический хеш-идентификатор родительского коммита, который я назову G, и так далее.Мы говорим, что мастер указывает на H, а H указывает на G и т. Д.

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

Эти баллы s фактически являются частью коммитов, за исключением самого последнего указателя, который приходит непосредственно от имени master.Коммиты, однажды сделанные, никогда не могут быть изменены, поэтому H навсегда указывает на G.Однако названия веток можно изменить в любое время!Так как те, что внутри коммитов, связаны навсегда, и я хочу нарисовать те, которые указывают назад (влево), но также вверх или вниз, давайте соединим их с линиями и зарезервируем подвижные стрелки для названий веток.(Если бы у меня были разные типы стрелок, я мог бы рисовать в тексте, я использовал бы сильные, похожие на ромб, неизменяемые стрелки для стрелок внутреннего коммита, и большие мягкие, легко изогнутые, для названий ветвей. Но я должен работать сtext-art here.)

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

Вы добавили новое имя ветви feature1 и другое новое имя ветви feature2, чтобы все три имени указывали на фиксацию H:

...--F--G--H   <-- master, feature1, feature2

Затем, находясь на feature1, вы сделали новый коммит, которому звоните C1:

$ git checkout feature1
... do work, git add files ...
$ git commit

, что привело к следующему:

             C1   <-- feature1 (HEAD)
            /
...--F--G--H   <-- master, feature2

Обратите внимание, что feature1 имеет HEAD прикрепленный к нему.Вот как Git знал, когда он создавал новый коммит C1, указывающий на существующий коммит H, что имя для перемещения было feature1.Имя HEAD все еще прикреплено к feature1 прямо сейчас, с именем feature1, указывающим на C1, а master и feature2 все еще указывает на H.

Теперь вызапустите:

$ git checkout feature2

, которая - наряду с подготовкой рабочей области для работы с коммитом H - присоединяет HEAD к имени feature2:

             C1   <-- feature1
            /
...--F--G--H   <-- master, feature2 (HEAD)

Commit H - это то, что вы сейчас извлекли в Git index и ваше рабочее дерево, так что теперь вы снова выполняете некоторую работу, git add для обновления индекса и git commit для создания снимка C2из обновленного индекса.Это перемещает имя feature2, указывающее на фиксацию C2:

             C1   <-- feature1
            /
...--F--G--H   <-- master
            \
             C2   <-- feature2 (HEAD)

Теперь вы говорите так:

Как объединить «feature2» в ветке «feature1» вускоренная перемотка вперед, если это возможно, а также обычное слияние?

A перемотка вперед Операция состоит из взятия одного из этих названий ветвей, такого как master, и «скольжения вперед»(вправо, на нашем рисунке, напротив пути, по которому идут внутренние стрелки), так что он указывает на какой-то другой коммит.Начиная с нового коммита, мы должны иметь возможность вернуться к исходному коммиту.Если мы не можем этого сделать, то сделанное нами движение не является ускоренной перемоткой вперед.

Таким образом, мы можем перемотать вперед master, что в настоящее время указывает на H, так что оно указывает на C1 или C2.Это перемещает его вперед и вверх, или вперед и вниз, и в любом случае мы можем начать с того места, где мы приземлились, и вернуться обратно к H.Но как вы сдвинете стрелку вперед с C1, чтобы она указала на C2?Вы не можете: это в буквальном смысле невозможно.Вы можете сдвинуть его вниз , чтобы оно указывало на C2 и полностью забывало C1, но это не то, что вам нужно.

Следовательно, мы должны прибегнуть кнормальное слияние.Для этого:

$ git checkout feature1
$ git merge feature2

Это будет настоящее слияние, а не ускоренная перемотка вперед.

Пожалуйста, помогите избежать рекурсивного слияния как можно больше.

Реальное слияние является рекурсивным слиянием, 1 , поэтому невозможно объединить коммиты C1 и C2 без слияния.

Подробнее о слиянии читайте в других публикациях StackOverflow или в хорошей книге по Git.

Обратите внимание, что у вас есть еще один вариант: вы можете скопировать коммит C2 в новый и другой коммит C3. Мы можем назвать его C2' вместо C3, чтобы указать, что это копия C2. Предположим, мы изменили две вещи в этой новой копии:

  • Начальным исходным деревом будет дерево C1. Мы применим к этому исходному дереву все изменения, которые мы внесли в терминах H -vs- C2.
  • Родителем новой копии будет C1, а не H.

Если мы рисуем этот новый коммит, он выглядит так:

               C2'  <-- ???
              /
             C1   <-- feature1
            /
...--F--G--H   <-- master
            \
             C2   <-- feature2

Как только мы сделаем эту C2' копию C2 - и получим имя ветки, которое найдет commit C2' - мы получим фиксацию, которую мы можем использовать для ускоренной перемотки вперед. Имя feature1 теперь может скользить вперед-вверх, так что feature1 указывает на C2': с C2' мы можем вернуться к C1 и затем обратно к H и G и F и т. Д.

Самый простой способ сделать C2' - это использовать git cherry-pick, который копирует коммиты. 2 Самый простой способ сделать это с веткой feature2 - это использовать git rebase, который использует git cherry-pick для копирования коммитов, затем перемещает имя ветви , чтобы указать на скопированные коммиты, оставляя оригиналы в пользу новых копий. Но это тема для другого вопроса (а перебазирование уже хорошо освещено в других публикациях StackOverflow).


1 Технически, рекурсивное слияние - это конкретная стратегия слияния в Git. Существуют и другие встроенные стратегии - resolve, octopus и ours, но ни одна из них не поможет в этой ситуации.

2 Это копирование с помощью cherry-pick использует механизм слияния Git, поэтому вы все еще объединяетесь! Вы не можете избежать слияния. Объятия слияния! Учитесь и любите это, потому что вы будете часто его использовать.

...