使用 git v1.7.1 我正在尝试同时使用 --preserve-merges
和 --onto
功能进行 rebase 。最终结果似乎没有 merge 提交,因此看起来是线性的。我宁愿保留 merge 提交,出于与人们经常使用 --preserve-merges
相同的原因(更容易看到逻辑上是独立功能并在其自己的分支中开发的提交组).
我的 master 分支(rebase 的目的地)很无聊:
A-B-C
我要从中获取的功能分支有一个已 merge 到其中的子功能分支。喜欢:
X - Y
/ \
V-W ------ Z
其中 Z 是 merge 提交,它是要获取的功能分支的头部,而 X 和 Y 位于子功能分支上。
我正在使用:git rebase --preserve-merges --onto C V Z
我想结束:
X - Y
/ \
A-B-C-W ------ Z
但我得到的是:
A-B-C-W-X-Y
由于 Z 是无冲突 merge ,因此代码的最终状态是正确的,但历史记录并不像我希望的那样富有表现力。
有没有办法得到我想要的东西?
编辑地址@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
在 rebase 之前我得到:
X-Y
/ \
V-W-----Z-postZ
/
A-B-C
rebase 后我得到:
X-Y
/ \
V-W-----Z-postZ
/
A-B-C-W'-X'-Y'-postZ'
注意 Y' 和 postZ' 之间缺少 Z'。
最佳答案
非常感谢 Bombe 和一位线下 friend 指出这对某些人确实有效。有了这个灵感,我现在可以回答我自己的问题了。
简短回答:1.7.5.2 之前的 git 版本会出现这种不良行为。
长答案:在 git 自己的源代码库中,提交 c192f9c865dbdae48c0400d717581d34cd315fb8 2011 年 4 月 28 日明确修复了此问题。
引用提交信息(作者:Andrew Wong):
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
来解决这个问题。很棒的工具。
关于git rebase "--preserve-merges --onto"不保留 merge ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9521422/