Cleaner
(整洁)是在观察者(或工作者)的眼中(或手中),但您可以使用
git rebase --onto
将
要复制的提交与
放置副本的位置分离出来。
请记住,git rebase
的意思是:1我有一条线性的提交链,如图1所示,我想将其复制到一个新的线性的提交链,如图2所示。完成副本后,我希望我的分支名称指向最后一个复制的提交。原始的A-B-C
链即使仍然存在也不再有用。
[drawing 1]
...--o--*--o <-- upstream/master
\
A--B--C <-- topic
[drawing 2]
...--o--*--o <-- upstream/master
\
A'-B'-C' <-- topic
最初的提交和副本之间的区别在于,原始提交基于提交
*
,它曾经是
upstream/master
的最新提交。而副本则基于(新的)
upstream/master
的最新提交。这里的“基于”一词实际上有两个含义:提交
A
的父提交是
*
,而提交
A'
的父提交是后来的提交;提交
A
中的快照是
*
+一些更改,而提交
A'
中的快照则将相同的更改添加到了后来的提交中。
由于我们使用了新的提交
A'
(具有不同的哈希值),而不是旧的
A
,因此我们需要将
B
复制为
B'
,将
C
复制为
C'
,并且完成后,我们需要使名称
topic
指向最后一个复制的提交,即
C'
,而不是
C
。
普通的
git rebase
正好可以做到这一点。我们说:
git checkout topic; git rebase upstream/master
这告诉Git:
- 从
C
开始向后枚举所有提交。 这是C
,然后是B
,然后是A
,然后是*
,最后是*
之前的所有内容。
- 从
upstream/master
开始向后枚举所有提交。 这是第二个o
,然后是*
,最后是*
之前的所有内容。
- 从第一个列表中删除第二个列表中的所有内容。 这样就删除了
*
和之前的所有提交。第二个o
不在第一个列表中,但这没关系:如果它在其中,我们会将其删除,但它现在不在,所以我们什么也不做。现在我们的列表变成了C
、B
和A
。
- 反转列表以使其按正确顺序排列,然后逐个将每个提交复制到新位置。新位置从
upstream/master
指向的提交开始。 因此,这将A
复制到A'
,将B
复制到B'
,将C
复制到C'
。
- 从其先前位置上分离当前分支名称
topic
,并像往常一样将其放在新的提交链的末尾。 这将使topic
指向C'
而不是C
。
但在您的新情况下,您有:
...--o--* <-- upstream/master
\
A--B--C <-- feature1
\
D--E--F--G <-- feature2
他们在上游没有采用你的 A-B-C
链。相反,他们制作了自己不同的 ABC
压缩提交。你从上游存储库中获取了它,所以现在你有:
最初的回答已经过时,他们没有采用你的修改,而是创建了一个新的压缩提交。
...--o--*--ABC <-- upstream/master
\
A--B--C <-- feature1
\
D--E--F--G <-- feature2
如果您只运行
git checkout feature2; git rebase upstream/master
,您的Git将枚举提交
G-F-E-D-C-B-A-*-...
,枚举
ABC-*-...
,从第一个中减去第二个,并留下复制
G-F-E-D-C-B-A
链的指令。
更高级的rebase命令是:
git checkout feature2
git rebase --onto upstream/master feature1
这样做的作用是将Git开始复制的目标参数(
target)与限制参数(
limit)分离。现在的
target是
upstream/master
(Git文档称其为
onto参数)。限制参数现在是
feature1
。如果您愿意,可以使用提交
C
的原始哈希ID。Git只需要知道:
我从哪里开始枚举这些提交?(令人困惑的是,Git文档将此称为
upstream参数。)
正如您所看到的,现在它会删掉
C-B-A-*
提交而不仅仅是
*
提交,因此复制后,您将得到:
D'-E'-F'-G' [in progress]
/
...--o--*--ABC <-- upstream/master
\
A--B--C <-- feature1
\
D--E--F--G <-- feature2
现在Git可以将标签feature2
从G
上移除,并粘贴到G2
上。
1技术上讲,git rebase
还有很多更复杂的用法,特别是新加的--rebase-merges
选项。但是,它主要用于进行线性提交链。
额外的好处是,rebase通常可以判断出他们是否已经将你的A-B-C
链复制到他们自己的A'-B'-C'
链中。但这只是通常情况。对于他们将你的A-B-C
压缩成他们自己的ABC
的情况,rebase则无法判断,所以需要使用--onto
选项。