2009-11-12 5 views
49

Я хотел иметь простое решение для сквоша двух слияний, совершаемых вместе во время интерактивной перезагрузки.git rebase interactive: squash merge commites together

Мой репозиторий выглядит следующим образом:

X --- Y --------- M1 -------- M2 (my-feature) 
/    /  /
/    /  /
a --- b --- c --- d --- e --- f (stable) 

То есть, у меня есть my-feature ветвь, которая была объединена дважды в последнее время, с никакой реальной не совершает между ними. Я не просто хочу, чтобы перебазироваться в my-feature ветви, так как это изданная филиал своей собственной, я просто хочу, чтобы раздавить вместе последние два слияния совершает в один (не опубликованы эти коммиты еще)

X --- Y ---- M (my-feature) 
/  /
/  /
a --- ... -- f (stable) 

Я пробовал:

git rebase -p -i M1^ 

Но я получил:

Refusing to squash a merge: M2 

То, что я, наконец, сделал это:

git checkout my-feature 
git reset --soft HEAD^ # remove the last commit (M2) but keep the changes in the index 
git commit -m toto  # redo the commit M2, this time it is not a merge commit 
git rebase -p -i M1^ # do the rebase and squash the last commit 
git diff M2 HEAD  # test the commits are the same 

Теперь новое комманда слияния больше не считается фиксацией слияния (в ней хранится только первый родитель). Итак:

git reset --soft HEAD^    # get ready to modify the commit 
git stash       # put away the index 
git merge -s ours --no-commit stable # regenerate merge information (the second parent) 
git stash apply      # get the index back with the real merge in it 
git commit -a      # commit your merge 
git diff M2 HEAD      # test that you have the same commit again 

Но это может усложниться, если у меня много коммитов, есть ли у вас лучшее решение? Спасибо.

Милдред

+0

Ну, когда вы сделайте свое второе слияние, вы всегда можете использовать '--squash', чтобы избежать создания фиксации, а затем использовать' git commit -amend' для изменения предыдущего слияния. – Mildred

+0

Это не сработает, он не сохранит новую версию ветки, с которой вы слились, в commit – Mildred

ответ

8

если вы не опубликовали последние два слияния зафиксируются, можно сделать сброс и простое слияние.

git reset --hard Y 
git merge stable 
+2

Да, но слияние было трудным, я предпочел бы слить как можно меньше изменений. Я не хочу решать конфликты, которые я уже решил. – Mildred

+9

, если вы не хотите повторно разрешать конфликты, вам нужно «использовать» git-rerere (и «используя», я действительно имею в виду «включить его», потому что git-дескрипторы автоматически фиксируют идентичные конфликты, включен). –

47

Это старая тема, но я просто натолкнулся на нее, ища аналогичную информацию.

Трюк похож на описанный в Subtree octopus merge действительно хорошее решение для такого рода проблемы:

git checkout my-feature 
git reset --soft Y 
git rev-parse f > .git/MERGE_HEAD 
git commit 

Это займет индекс, как она существует на кончике-функции, и использовать его для создания новой фиксации Y, а «f» - вторым родителем. Результат такой же, как если бы вы никогда не выполняли M1, но сразу пошли на выполнение M2.

+0

Обратите внимание, что этот вид слияния не имеет ничего общего с поддеревом или слиянием осьминога. В блоге, который вы связываете, просто используется техника для * объединения * слияния поддерева и слияния осьминогов в одно слияние (потому что git не может напрямую выполнять оба слияния за один раз). – sleske

+0

Недостатком этого является то, что git не сможет генерировать правильные сообщения фиксации. Я скопировал сообщения из старого слияния. В противном случае это приятное и легкое решение. –

+0

так много upvote! мы просто сделали очень сложное слияние, и подход моих коллег заключался в том, чтобы объединить каждую фиксацию с его дерева на мое, по одному за раз. затем раздался раздача, и мы нашли это решение. вам жаль, что вам нужно написать собственное сообщение о фиксации. – Sam

0

Ни один из указанных методов не работает для меня с недавней версией git. В моем случае следующий сделал трюк:

git reset --soft Y 
git reset --hard $(git commit-tree $(git write-tree) -p HEAD -p stable < commit_msg) 

Вы должны будете написать сообщение фиксации в файл commit_msg первым, хотя.

5

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

   X 
       \ 
       \ 
a --- b --- c --- M1 (subtree merge) 

То, что я хотел перебазировать слияния M1 и сквош все как один совершать на вершине б.

a --- b --- S (include the changes from c, X and M1) 

Я перепробовал все виды различных комбинаций, но это то, что работает:

git checkout -b rebase b (checkout a working branch at point b) 
git merge --squash M1 

Это применит изменения в индекс, где они могут фиксироваться мерзавец совершающие

+1

Для этого случая вы можете выполнить 'git diff b> diff.patch', затем' git checkout b', 'cat diff.patch | patch -p1', а затем 'git commit'. Это работает, если в * merge * включены разрешения. Оригинальный вопрос отличается; но я думаю, вы пришли сюда, ища то же самое, что и я. Вы можете получить сообщение (ы) регистрации с помощью 'git log' перед раздачей. –

+0

Необходимы дополнительные шаги, если вы хотите, чтобы ситуация была на вашем хозяине: 'git checkout master && git reset --hard b && git rebase rebase'. Это только для того, чтобы исправить себя. Вы могли бы выбрать другое название для ветки, чем «rebase» :) – eis

Смежные вопросы