Git объединяет только коммиты внутри ветки - PullRequest
0 голосов
/ 04 февраля 2020

Рассмотрим это дерево ниже. Извините за дерьмовую диаграмму, но я думаю, вы поняли.

У меня есть MASTER ветвь и MY BRANCH. Я создаю ветку PATCH из MASTER и исправляю эту ветку. Затем я объединяю исправления в и MASTER и MY BRANCH. Когда я делаю это, MY BRANCH также получает коммиты C & D вместе с ним.

MASTER----A----B----C----D-------------MERGE
                \         \             /
                 \       PATCH----E----F
                  \                     \
             MY BRANCH----G----H-------MERGE

Как мне объединить только коммиты в патче в MASTER и MY BRANCH?

Ответы [ 3 ]

2 голосов
/ 04 февраля 2020

Как заметил RomainValeri, график можно нарисовать лучше. Я начну с его варианта, но нарисуйте то, что у нас есть до , и вы попытаетесь выполнить любое слияние:

              E---F <<< patch
             /
A---B---C---D <<< master
     \
      G---H <<< my-branch

Имя patch относится к существующему коммиту F и имена master и my-branch относятся к существующему коммиту H.

Проблема, с которой вы столкнулись, возникает из-за того, что git merge работает на основе графа фиксации , а не названия филиалов . Имена find commit, что нормально, насколько это возможно, но если вы запустите git merge <commit F>, результат будет включать commit F, который будет включать commit E, который будет включать commit D, который будет включать в себя фиксацию C, которая будет включать в себя фиксацию B и т. Д.

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

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

Это приводит к рекомендации, которую люди часто дают, чтобы использовать вишневый выбор здесь. Если вы создаете новую ветку с именем patch2, начиная с коммита H, и копируйте E и F в новые и улучшенные коммиты E' и F', где E' и F' после коммита H, вы получаете:

              E---F   <-- patch
             /
A---B---C---D   <-- master
     \
      G---H   <-- my-branch
           \
            E'-F'  <-- patch2

Теперь вы можете объединить оригинальный патч с master и новым и другим (предположительно улучшенным) patch2 ответвлением в my-branch.

Есть лучший способ! Ну, в любом случае часто . Давайте на мгновение отступим и спросим: Почему вы сначала написали коммиты E и F? ​​

Скорее всего, это исправить ошибку, которая находится в commit A, или commit B, или, может быть, оба. Или, возможно, он добавляет функцию, которой просто не хватает в коммите B. Как бы то ни было, вы считаете, что его можно применить без коммитов C и D.

Теперь вам нужно доказать это . Создайте новую ветку patch2, но не указывайте на существующий коммит H. Запустите его вместо коммита B. Затем скопируйте E и F в свои новые и улучшенные E' и F', получив:

          E--F   <-- patch
         /
     C--D   <-- master
    /
A--B--E'-F'  <-- patch2
    \
     G--H   <-- my-branch

Обратите внимание, что все существующие коммиты все еще там, точно так же. (Вы еще ничего не слили.) Но если patch2 действительно работает, мы можем теперь выбросить ветку с именем patch, отказавшись от коммитов E-F:

          E--F   [abandoned]
         /
     C--D   <-- master
    /
A--B--E'-F'  <-- patch2
    \
     G--H   <-- my-branch

Теперь, когда мы это сделали, давайте прекратим рисовать их и переименуем существующую ветку patch2 в patch:

     C--D   <-- master
    /
A--B--E'-F'  <-- patch
    \
     G--H   <-- my-branch

Скопированный (выбранный вишней или перебазированный ) коммиты E'-F' теперь находятся в положении, в котором мы можем запустить git checkout master; git merge patch и git checkout my-branch; git merge patch. Когда мы это сделаем, мы получим два коммита слияния:

     C--D--M1   <-- master
    /     /
A--B--E'-F'  <-- patch
    \     \
     G--H--M2   <-- my-branch

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

Это приводит к общему правилу создания патчей

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

Причина этого заключается в том, что полученный патч может быть чисто объединен с любым коммитом, который находится "ниже по потоку" от этой точки. В этом случае вы хотели объединить патч с коммитами D, на master ниже B и в H на my-branch ниже B. Поскольку patch в коммите F' находится ниже B, объединение patch в любую ветку приведет к коммиту B. Но commit B - это первое место, в котором ветка patch является полезной . Любая ветвь, кончик которой не является ниже B , вообще не может использовать патч! Таким образом, поместив сам патч сразу после первого места, где он может быть использован , каждая другая ветвь, в которой может использовать патч вообще, может использовать патч легко и чисто.

1 голос
/ 04 февраля 2020

Вы можете использовать диапазон, чтобы указать, какие коммиты вы хотите в ветви назначения:

git checkout my-branch
git cherry-pick master..patch

, где master..patch означает:
все на patch МИНУС все, что уже известно по master


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

              E---F <<< patch
             /     \
A---B---C---D-------I <<< master
     \
      G---H <<< my-branch
1 голос
/ 04 февраля 2020

Либо используйте rebase или cherry-pick, чтобы вручную применить E и F к MYBRANCH, либо правильно создайте ветвь PATCH, указав только E и F для начала.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...