假设我们有以下工作流程:
D <-HEAD
|
C
|
B
|
A
假设我想在C
和D
之间添加新的提交X
,以便它可以:
D
|
X
|
C
|
B
|
A
所以我用git rebase -i HEAD~2
并为提交C
选择"编辑",以便当变基进入"编辑"提交C
时,我修改 sth,然后使用git add .
和git commit
,之后我应用git rebase --continue
结束变基。 但我得到了以下内容:
D
/
X C
| /
B
|
A
不是我在提交后添加了一个新的提交C
吗? 为什么新的提交X
是在B
之后?
假设我想在 C 和 D 之间添加新的提交 X,以便它可以:
D | X | C | B | A
实际上根本不会这样。
让我水平绘制这些,向右绘制较新的提交,因为我认为这不那么令人困惑(对我来说当然更容易)。 您最初拥有:
...--A--B--C--D <-- branch
当你执行这种变基(或任何一系列产生你想要的结果的 Git 命令)时,你最终会将旧的提交D
复制到一个新的和改进的提交D2
或D'
(我将使用D'
表示法)。 这样做的原因是任何提交都不能更改,这包括其父提交哈希。 现有提交C
的哈希 ID 固定在石头中,现有提交D
本身固定在石头中,并包含现有提交C
的哈希 ID。 因此,必须放弃提交D
,转而使用新的和改进的提交。
你根本不打算做任何事情来提交A
,所以 Git可以不管它,而不用重新复制它。B
和C
也是如此. 根据您运行git rebase
的方式,您可以强制Git 将这些重新复制到新的提交(使用新的和不同的哈希 ID)。 如果这样做,这些新提交将在所有方面与原始提交匹配,但有两个:
它们将具有不同的时间戳。 具体来说,它们将有一个提交者时间戳,该时间戳是使用您强制 Git 进行新提交的当前时间创建的。 每个提交都有两个时间戳,一个用于"作者",一个用于"提交者"。 作者行代表进行原始提交的人,以及他们何时进行;提交者行表示进行此提交的人以及时间。 如果作者和提交者行匹配,这是原始提交;如果它们不同,则这是副本。
同时,除了第一个这样的副本外,每个复制的提交都将具有不同的父提交哈希 ID。 这是因为第一个这样的副本本身具有不同的哈希 ID,并且后续副本必须引用新的和改进的(或至少是新的和微妙的不同)提交。
但是,如果您不强制变基进行复制,它只会在可能的情况下保留原始提交。 所以既然不需要改变A
、B
或C
,Git 就不会了。
但是,要添加X
,Git 需要使其父级是现有提交C
进行新的提交X
:
D <-- branch
/
...--A--B--C--X <-- HEAD [rebuild in progress]
如果您在构造提交X
后检查提交图,您将看到以下内容。
通过git rebase -i
和暂停构造提交X
后,然后运行git rebase --continue
。 这会将现有的提交D
复制到新的提交D'
:
D <-- branch
/
...--A--B--C--X--D' <-- HEAD [rebuild in progress]
如果您设法在这一点上停止 Git(例如,将D
标记为edit
会这样做)并仔细检查提交图,您现在将看到上述内容。 不过,让 Git 继续下去,git rebase
的最后一步是移动分支名称并将HEAD
重新附加到分支名称,给出:
D [abandoned]
/
...--A--B--C--X--D' <-- branch (HEAD)
由于没有可以轻松找到提交D
的名称,因此即使使用git log --all --decorate --oneline --graph
,git log
也不会显示它。 您现在将只看到D'
.
如果您不记得原始提交D
的实际哈希 ID,它看起来像新提交D'
是原始提交D
。不是! Git 知道它不是,因为 Git 使用哈希 ID来识别提交。分支名称无关紧要:重要的是哈希 ID。
Git 使用分支名称来查找起始哈希 ID,这是链中的最后一个提交。 这就是为什么在这些绘图中,较新的提交位于右侧,我们将分支名称放在最右侧,并带有向后箭头。 Git 总是向后工作:一个名称查找链中的最后一个提交,然后从那里,Git 使用存储的哈希 ID 向后工作,一次一个提交。
(当 Git 命中具有两个或多个向后箭头的合并提交时,Git 仍然必须一次处理一个提交,大多数情况下。 为了处理此问题,这些 Git 命令会保留哈希 ID 队列。 队列是优先级队列,其中优先级较高的提交先于优先级较低的提交进行访问。 使提交优先级更高或更低的因素取决于您提供给git log
或git rev-list
的--topo-order
或--graph
或--date-order
或--committer-date-order
或其他排序选项。