从 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
可以在更新B3
topic
origin/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
;但是C
and 和 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
选项。