阅读git rebase
和git merge-base
人文档:
在使用 git checkout -b 主题 origin/master 创建的主题分支上工作后,远程跟踪分支 origin/master 的历史记录可能已被倒带并重建,从而导致此历史记录 形状:
o---B1 / ---o---o---B2--o---o---o---B (origin/master) B3 Derived (topic)
其中 origin/master 曾经指向提交 B3、B2、B1,现在它指向 B,并且当 origin/master 位于 B3 时,您的主题分支是在它之上启动的。此模式使用 源/主节点,以查找 B3 作为分叉点,以便可以通过以下方式在更新的源/主节点之上重新定位主题:
$ fork_point=$(git merge-base --fork-point origin/master topic) $ git rebase --onto origin/master $fork_point topic
$fork_point
将(如果我理解正确的话)是B3
的提交对象,因此提交B3..topic
将被重新定位到origin/master
分支。
Q1为什么省略B3
提交很有用?topic
分支的提交建立在B3
提交之上,因此省略它意味着它的修改将在origin/master
分支的故事中丢失。重新设置B3
提交和topic
分支的基数将导致更干净的历史记录,不是吗?
Q2有人可以链接/简要描述 git 工作流程中--fork-point
选项的实际用例吗?
你是对的,$fork_point
将被B3
.
我相信这里的意图是省略B3
"不是你的承诺"。
我认为 Git 人员在这里绘制的图表不是很好。 以下是我将如何在不对其进行太多更改的情况下重新绘制和重写它(尽管无论如何我可能只是重新写字母每个提交)。
您首先克隆(或以其他方式更新)一些(origin
)存储库,其图形以提交B3
结尾,然后创建一个主题分支并进行一些提交:
...--o---F---B3 <-- origin/master
G <-- topic
随着时间的推移,加上额外的git fetch
-es 和git commit
s,您的提交图现在如下所示:
...--o---F---B3--B2--B1 <-- origin/master
G---H---I <-- topic
但是,突然之间,在另一个git fetch
之后,你自己的提交图现在看起来像这样:
o---B1' <-- origin/foo
/
...o---F---B2'-o---o---o---B <-- origin/master
B3--G---H---I <-- topic
也就是说,Git 现在会认为提交 B3 属于您的主题分支,而实际上,您的工作始于提交G
。 实际上,拥有名为origin
的存储库的人已经宣布提交B3
是可怕的,应该被丢弃。 (他们在master
上保留了B2
作为B2'
的副本,在他们的foo
上保留了B1
B1'
的副本。
如果您只是git rebase
,则将原始提交B3
复制到新的复制B3'
(同时也复制G-H-I
):
o---B1' <-- origin/foo
/
...o---F---B2'-o---o---o---B <-- origin/master
B3'-G'--H'--I' <-- topic
但你更喜欢:
o---B1' <-- origin/foo
/
...o---F---B2'-o---o---o---B <-- origin/master
G'--H'--I <-- topic
要git rebase
执行此操作,您必须指示 Git 找到提交B3
。 你的 reflogorigin/master
包含所有F
、B3
、B2
和B1
(至少在一个 reflog 条目下,包括在本例中为origin/master@{1}
),而你自己的topic
有F
和B3
,但不是B2
也不是B1
。 因此,--fork-point
选择B3
作为最新(最尖端)共享提交,而不是F
。
这里的关键句子/想法是上游存储库编写者打算完全丢弃提交B3
。
(你应该如何确定这一点有点神秘。 如果变基需要,例如,丢弃一个不应该被提交并且处于B1
中的文件,那么B2'
和B1'
是副本可能并不明显,这就是为什么B1
也被丢弃的原因。 事实上,这个文件现在在B2'
和B3'
中被省略了,这使得它们不是补丁等效的,因此不是明显的副本。
(请注意,您自己的master
也仍然指向B3
!