考虑历史
D origin/master
/
| C master
| |\
| | B
\|/|
A :
|
:
在git pull --rebase --preserve-merges
之后,我希望历史是
C' master
|\
D |
| B
|/|
A :
|
:
但事实证明是
C' master
|\
| B'
|/|
D :
|
A
|
:
换句话说,B提交被重写为B',即使不需要它,因为父母双方都是未经修改的。我知道我在D上重新定位,但这是有问题的,因为B合并中的所有冲突都必须再次解决。
目前的功能是否有好处?
有没有办法获得我想要的功能?
答案 0 :(得分:2)
我无法真正回答“利益”问题,但我可以说明为什么rebase正在按原样行事以及如何获得所需的结果。
Rebase,无论是否具有交互性,都采用“三个类似分支或提交”的参数,它称之为 newbase
, upstream
和 branch
:
git rebase
[-i
|--interactive
] [options
] [--exec cmd
] [--onto newbase
]
[upstream
[branch
]]
如果你遗漏了部分或全部,rebase仍然使用它们,它只是自己找到它们:
branch
默认为当前分支,或HEAD
(包括分离头)。upstream
默认为当前分支的上游,由git branch --set-upstream-to
或类似设置。无论您在此处指定的是什么,还是默认值,都会被赋予git rev-list
以使其停止进行提交,即,将被重新定位的提交是由git rev-list upstream..HEAD
打印的提交。 / LI>
newbase
默认使用与 upstream
相同的提交ID。(如果你在一个新的git中提供--fork-point
以获得--fork-point
,这些都会得到一些修改,但是这里的一般想法仍然适用:根据那些“之后的那些选择重新提交的提交” “默认情况下,上游,直至并包括HEAD。”
当你让git pull
为你运行git rebase
时,它会以upstream
的形式提供当前分支的实际上游(再次通过较新的gits中的fork-point计算进行修改) ,但是如果您提取的实际上游尚未完成自己的变基,则这应该没有效果。 (--onto
通常也会与上游相同。在这种情况下,它相当于git rebase [options] --onto origin/master origin/master master
。)
正如您所看到的(通过运行git rev-list origin/master..master
),这意味着“请将B
和C
重新提交到D
”。添加--preserve-merges
只需使用交互式机制,并根据请求对两个提交进行重新定位后保留合并。
如果您只是运行git fetch
,您将像往常一样获得提交D
,并将您绘制的图表作为第一个:
D origin/master
/
| C master
| |\
| | B
\|/|
A :
|
:
您现在可以尝试手动运行git rebase -p
以重新提交提交C
,将B
指定为其“上游”,以便rebase不会复制提交B
,并将D
指定为--onto
提交,以便将C
重新定位到D
:
$ git rebase -p --onto origin/master master^2 master
不幸的是,这会产生一个新的合并提交,其中两个父项为origin/master
(提交D
)和原始master^
(提交A
)。 (这并不是很明显的原因,尽管它显然与交互式保留模式在内部的工作方式有关。)
因此,在这种情况下的诀窍是进行自己的合并:
$ git branch -m master old-master
$ git checkout master
(这使得新master
指向提交D
),然后:
$ git merge old-master^2
(这是未经修改的B
)的新合并。
你还提到:
...这是有问题的,因为B合并中的所有冲突都必须再次解决。
不幸的是,您无法真正避免这种情况,因为D
可能与A
有足够的不同,实际的合并冲突解决方案 也不同。
如果您确定它们(分辨率)不应该(不同),您也可以通过从旧提交C
获取合并结果来支持此问题。例如,假设冲突发生在dir1/file1
和dir2/file2
,而A
和D
之间的差异全部来自README.txt
或某些此类冲突。然后,当您执行上述合并时,您可以非常简单地“解决”冲突:
$ git checkout old-master -- dir1/file1 dir2/file2
提取这些文件的提交C
版本,更新索引和工作树以恢复以前的合并解析。您的冲突现在已经解决(与以前完全一样),您可以git commit
生成的合并。