从 git 1.9/2.0 Q1 2014 开始,您不必在将其重新基于重写的上游分支之前标记之前的分支来源,如Aristotle Pagaltzis的回答中所述:
请参阅提交 07d406b和提交 d96855f:
在使用topic创建的分支上工作后git checkout -b topic origin/master,远程跟踪分支的历史origin/master可能已经被倒带和重建,导致这种形状的历史:
o---B1
/
---o---o---B2--o---o---o---B (origin/master)
\
B3
\
Derived (topic)
whereorigin/master曾经指向 commits B3, B2,B1现在它指向B,并且您的topic分支origin/master在B3.
此模式使用 reflog作为分叉点,以便origin/master可以在更新B3topicorigin/master的顶部重新建立:
$ fork_point=$(git merge-base --fork-point origin/master topic)
$ git rebase --onto origin/master $fork_point topic
这就是该git merge-base命令有一个新选项的原因:
--fork-point::
找到一个分支(或任何导致的历史<commit>)从另一个分支(或任何参考)分叉的点<ref>。
这不仅寻找两个提交的共同祖先,而且还考虑了 reflog<ref>以查看导致<commit>分支的历史是否来自分支的早期化身<ref>。
" git pull --rebase" 命令使用分支工作所基于的 " " 分支 (通常是远程跟踪分支) 的 reflog 条目来计算要重新设置的分支的分支点base,以应对 "base"分支已经倒带和重建。
例如,如果历史看起来像这样:
base" " 分支的当前尖端是 at B,但之前的 fetch 观察到它的尖端曾经是B3然后B2然后B1
在到达当前提交之前,并且
它试图B3通过“ git rev-list --reflog base”的输出(即B, B1, )进行查找B2,B3直到找到作为当前提示“ Derived (topic)”的祖先的提交。
在内部,我们get_merge_bases_many()可以一次性计算。
我们想要一个合并基础Derived和一个虚构的合并提交,这将通过合并“ base (origin/master)”的所有历史提示而产生。
当这样的提交存在时,我们应该得到一个结果,它与 " base" 的 reflog 条目之一完全匹配。
Git 2.1(2014 年第三季度)将添加使此功能更加强大:请参阅John Keeping的提交 1e0dacd ( )johnkeeping
正确处理我们具有以下拓扑的场景:
C --- D --- E <- dev
/
B <- master@{1}
/
o --- B' --- C* --- D* <- master
在哪里:
B'是与;B不完全相同的补丁版本。B
C*如果以错误的顺序应用,则与补丁相同且分别与文本D*冲突C;D
E文字上取决于D.
的正确结果git rebase master dev是B被标识为 和 的分叉点dev,master因此C,D是E需要重播到 的提交master;但是Cand 和 andD是一样的C*,D*所以可以去掉,所以最终的结果是:
o --- B' --- C* --- D* --- E <- dev
如果未识别分支点,则选择B包含的分支B'会导致冲突,如果未正确识别补丁相同的提交,则选择C包含D(或等效地D*)的分支会导致冲突。
当命令在 2.20 时代用 C 重写时,“ ”的“ --fork-point”模式倒退了,该问题已在 Git 2.27(2020 年第二季度)中得到纠正。git rebase
请参阅Junio C Hamano ( ) 的提交 f08132f(2019 年 12 月 9 日)。(由Junio C Hamano 合并 -- --在提交 fb4175b中,2020 年 3 月 27 日)gitster
gitster
rebase:--fork-point回归修复
签字人:Alex Torok
[jc:改进了修复并使用了 Alex 的测试]
签字人:Junio C Hamano gitster@pobox.com
" git rebase --fork-point master" 以前可以正常工作,因为它在内部调用了 " git merge-base --fork-point",它知道如何处理短 refname 并将其缩小为完整的 refname,然后再调用底层get_fork_point()函数。
在用 C 重写命令后,这不再是正确的,因为它的内部调用直接调用get_fork_point()不会缩小一个短的 ref。
将“git merge-base”中使用的“dwim refname 参数到完整的refname”逻辑移动到底层get_fork_point()函数,以便在“git rebase”的实现中函数的其他调用者行为相同的方式来修复这种回归。
在 Git 2.31(2021 年第一季度)中,“ git rebase --[no-]fork-point” (man) “获得了一个配置变量rebase.forkPoint,这样用户就不必一直指定非默认设置。
请参阅Alex Henrie ( ) 的提交 2803d80(2021 年 2 月 23 日)。(由Junio C Hamano 合并——在提交 682bbad中,2021 年 2 月 25 日)alexhenrie
gitster
rebase: 添加一个配置选项--no-fork-point
签字人:Alex Henrie
一些用户(包括我自己)宁愿默认关闭此功能,因为它可以静默放弃提交。
git config现在在其手册页中包含:
rebase.forkPoint
如果默认设置为 false 设置--no-fork-point选项。