git rebase "--preserve-merges --onto" не сохраняет слияний - PullRequest
8 голосов
/ 01 марта 2012

Использование git v1.7.1 Я пытаюсь выполнить ребаз с функциями --preserve-merges и --onto одновременно.Конечные результаты, кажется, без коммитов слияния, и поэтому кажутся линейными.Я бы предпочел сохранить коммиты слияния по той же причине, по которой люди часто использовали бы --preserve-merges (проще увидеть группу коммитов, которая была логически отдельной функцией и разработана в отдельной ветке).

MyОсновная ветвь (место назначения для перебазирования) скучна:

A-B-C

В ветви объектов, которую я хочу взять, есть ветвь подфункций, которая была объединена с ней.Например:

     X - Y
   /      \
V-W ------ Z

Где Z - коммит слияния, который является главой ветви объектов, из которой нужно взять, а X и Y - в ветви подфункций.

I'mиспользуя: git rebase --preserve-merges --onto C V Z

Я хотел бы в итоге:

         X - Y
        /     \
A-B-C-W ------ Z

Но вместо этого я получаю:

A-B-C-W-X-Y

Так как Z был конфликтом-свободное слияние, окончательное состояние кода правильное, но история не так выразительна, как хотелось бы.

Есть ли способ получить то, что я хочу?

edit to address @ Bombe : я написал скрипт bash для построения моего примера.В моей системе (RHEL 6.2 с git 1.7.1) это демонстрирует мою проблему.

#! /bin/bash
# start a new empty repo
git init
# make some commits on the master branch
git checkout master
touch A.txt; git add A.txt; git commit -m "add A.txt"; git tag Atag
touch B.txt; git add B.txt; git commit -m "add B.txt"; git tag Btag
touch C.txt; git add C.txt; git commit -m "add C.txt"; git tag Ctag
# now build the feature branch
# start at Btag (more or less arbitrary; point is it's before C)
git checkout Btag
git checkout -b feature
touch V.txt; git add V.txt; git commit -m "add V.txt"; git tag Vtag
touch W.txt; git add W.txt; git commit -m "add W.txt"; git tag Wtag
# now a subfeature
git checkout -b subfeature
touch X.txt; git add X.txt; git commit -m "add X.txt"; git tag Xtag
touch Y.txt; git add Y.txt; git commit -m "add Y.txt"; git tag Ytag
# merge the subfeature into the feature
# preserves branch history with --no-ff
git checkout feature
git merge --no-ff subfeature
# the merge commit is our Z
git tag Ztag
# one more commit so that merge isn't the tip (for better illustration of Z missing later)
touch postZ.txt; git add postZ.txt; git commit -m "add postZ.txt"; git tag postZtag
# now do the rebase
git rebase --preserve-merges --onto Ctag Vtag
# optionally move the master branch forward to the top of feature branch
git checkout master
git merge feature

Перед ребазой я получаю:

        X-Y
       /   \
    V-W-----Z-postZ
   / 
A-B-C

После ребазирования я получаю:

        X-Y
       /   \
    V-W-----Z-postZ
   / 
A-B-C-W'-X'-Y'-postZ'

Обратите внимание на отсутствие Z 'между Y' и postZ '.

Ответы [ 3 ]

12 голосов
/ 02 марта 2012

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

Краткий ответ: версии git до 1.7.5.2 будут демонстрировать это плохое поведение.

Длинный ответ: в собственном репозитории git,Зафиксировать c192f9c865dbdae48c0400d717581d34cd315fb8 28 апреля 2011 г. было явным исправлением этой проблемы.

Цитировать сообщение о фиксации (Эндрю Вонг):

git-rebase--interactive.sh: preserve-merges fails on merges created with no-ff

'git rebase' uses 'git merge' to preserve merges (-p).  This preserves
the original merge commit correctly, except when the original merge
commit was created by 'git merge --no-ff'.  In this case, 'git rebase'
will fail to preserve the merge, because during 'git rebase', 'git
merge' will simply fast-forward and skip the commit.  For example:

               B
              / \
             A---M
            /
    ---o---O---P---Q

If we try to rebase M onto P, we lose the merge commit and this happens:

                 A---B
                /
    ---o---O---P---Q

To correct this, we simply do a "no fast-forward" on all merge commits
when rebasing.  Since by the time we decided to do a 'git merge' inside
'git rebase', it means there was a merge originally, so 'git merge'
should always create a merge commit regardless of what the merge
branches look like. This way, when rebase M onto P from the above
example, we get:

                   B
                  / \
                 A---M
                /
    ---o---O---P---Q

Решение: получите новую версию git, собрав при необходимости исходный код.

Кстати, я использовал git bisect, чтобы понять это.Удивительный инструмент.

1 голос
/ 31 июля 2012

Я сталкивался с этой проблемой. Обратите внимание на мою версию git, это 1.7.10.2.

Я делаю перебазирование диапазона фиксации (определяемого его хэшами SHA1) на ветку и также отсутствует последний коммит слияния.

Мое решение состояло в том, чтобы переместить W в X на C (без --preserve-merges) и затем перебазировать (с --preserve-merges) Y, Z и postZ на X '.

Надеюсь, это поможет.

0 голосов
/ 02 марта 2012

Я только что попытался воссоздать вашу ситуацию, и я могу сообщить, что --preserve-merges, кажется, работает как рекламируется.Когда вы в коммите Z, просто наберите:

git rebase --preserve-merges --onto C V

Это то, что я сделал, и это сохранило коммит слияния.

...