从git 1.9 / 2.0 Q1 2014开始,您将不必标记先前的分支原点,就可以将其基于重新编写的上游分支,如Aristotle Pagaltzis的答案所述:
请参阅commit 07d406b和commit d96855f:
在使用topic
创建的分支之后git checkout -b topic origin/master
,远程跟踪分支的历史origin/master
可能已经被重新记录和重建,从而产生了这种形状的历史:
o---B1
/
---o---o---B2--o---o---o---B (origin/master)
\
B3
\
Derived (topic)
其中,origin/master
在提交用于点B3
,B2
,B1
现在它指向B
,和你的topic
分支开始在上面的回来时origin/master
在B3
。
此模式使用reflog的origin/master
findB3
作为派生点,因此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
”命令使用分支工作的“ base
”分支(通常是远程跟踪分支)的引用日志条目来计算要重新建立分支的分支点,以应对“基础”情况分支机构已倒回并重建。
例如,如果历史记录如下所示:
- “
base
”分支的当前尖端位于B
,但是较早的提取观察到它的尖端曾经是B3
,然后B2
再B1
到达当前提交之前,然后
- 根据最新的“基础”重新建立分支的分支基于commit
B3
,
它试图找到B3
通过的“输出去git rev-list --reflog base
”(即B
,B1
,B2
,B3
),直到找到一个提交,它是当前尖端的祖先“ Derived (topic)
”。
在内部,我们get_merge_bases_many()
可以通过一次计算。
我们希望合并之间的合并基础Derived
和虚构的合并提交,这将通过合并所有“ base (origin/master)
”的历史提示而产生。
当存在这样的提交时,我们应该得到一个单一的结果,该结果与“ base
”的引用条目之一完全匹配。
Git的2.1(Q3 2014)将增加使这个功能更强大的这样:看到提交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
和D
是补丁与相同C*
和D*
等都可以被丢弃,从而使最终结果是:
o --- B' --- C* --- D* --- E <- dev
如果未识别出分叉点,则选择B
包含分支的B'
结果将导致冲突;如果未正确识别补丁相同的提交,则选择C
包含D
(或等效D*
结果)的分支将导致冲突。
当在2.20年代用C重写命令时--fork-point
,“ git rebase
”的“ ”模式返回,已在Git 2.27(2020年第二季度)中进行了更正。
参见Junio C Hamano()提交的f08132f(2019年12月9日)。(通过合并JUNIOÇ滨野- -在提交fb4175b 3月27日2020)gitster
gitster
rebase
:--fork-point
回归修复
签名人:Alex Torok
[jc:修改了补丁,并使用了Alex的测试]
签名人:Junio C Hamano
“ git rebase --fork-point master
”过去工作正常,因为它内部称为“ git merge-base --fork-point
”,它知道如何处理短refname并在调用基础get_fork_point()
函数之前将其dwim更改为完整的refname 。
在用C重写命令之后,这种情况不再成立,因为直接对其进行的内部调用get_fork_point()
不会删除短引用。
将“ git merge-base”中使用的“ dwim refname参数移至完整的refname”逻辑移至基础get_fork_point()
函数,以便实现“ git rebase”的函数的另一个调用者以相同的方式进行修复这种回归。