首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用交互式rebasing添加新提交时的奇怪行为

使用交互式rebasing添加新提交时的奇怪行为
EN

Stack Overflow用户
提问于 2020-03-28 21:03:01
回答 1查看 24关注 0票数 0

假设我们有以下工作流:

代码语言:javascript
复制
D <-HEAD
|
C
|
B
|
A

假设我想在CD之间添加一个新的提交X,这样它就可以:

代码语言:javascript
复制
D 
|
X
|
C
|
B
|
A

所以我使用git rebase -i HEAD~2并为commit C选择'edit‘,这样当rebase到达“编辑”commit C时,我修改了一些东西,然后使用git add .git commit,之后我应用git rebase --continue来结束rebase。但我得到了以下信息:

代码语言:javascript
复制
     D
    /
X  C
| /
B
|
A

这不是我在提交C之后添加了一个新的提交吗?为什么新的提交X紧随B之后

EN

回答 1

Stack Overflow用户

发布于 2020-03-29 03:10:03

假设我想在C和D之间添加一个新的

X,这样它就可以:

D|X|C|B|A

实际上根本不会是这样的。

让我用新的提交向右水平绘制这些,因为我认为这不那么令人困惑(而且对我来说也更容易)。您最初拥有:

代码语言:javascript
复制
...--A--B--C--D   <-- branch

当您执行这种rebase (或任何一系列产生您想要的结果的Git命令)时,您最终会将旧的提交D复制到一个新的、改进的提交D2D' (我将使用D'表示法)。这样做的原因是,关于任何提交的任何内容都不能更改,这包括它的父提交散列。现有提交C的散列ID是固定的,现有提交D本身也是固定的,并且包含现有提交C的散列ID。因此,必须放弃提交D,而支持新的改进的提交。

你根本不打算做任何事情来提交A,所以Git可以不去管它,不需要重新复制它。BC也是如此。根据您运行git rebase的方式,您可以使用强制 Git将这些内容重新复制到新的提交中(使用新的和不同的散列ID)。如果你这样做了,这些新的提交将在除两个之外的所有方面与原始提交相匹配:

  • ,它们会有一个不同的时间戳。具体地说,它们将有一个提交者时间戳,通过使用当前时间强制Git进行新的提交。每次提交都有两个时间戳,一个用于“作者”,另一个用于“提交者”。作者行表示最初提交的人,以及他们何时提交;提交者行表示提交此提交的人和时间。如果作者行和提交者行匹配,则这是原始提交;如果它们不同,这是一个copy.
  • Meanwhile,,除了第一个这样的副本之外,每个复制的提交都将具有不同的父提交散列ID。这是因为第一个这样的副本本身具有不同的散列ID,并且后续副本必须引用新的和改进的(或者至少是新的和微妙不同的)提交。

但是,如果你不强制rebase复制,它就会在可能的情况下让原始提交保持原样。因此,因为不需要更改ABC,所以Git也不需要更改。

不过,要添加X,Git需要创建新的提交X,其父对象是现有的提交C

代码语言:javascript
复制
             D   <-- branch
            /
...--A--B--C--X   <-- HEAD [rebuild in progress]

如果您在构造提交X之后检查您的提交图,您将看到以下内容。

通过git rebase -i和暂停构造提交X之后,您就可以运行git rebase --continue了。这会将现有的提交D复制到新的提交D'

代码语言:javascript
复制
             D   <-- branch
            /
...--A--B--C--X--D'  <-- HEAD [rebuild in progress]

如果您设法在这一点上停止了Git (例如,将D标记为edit就可以做到这一点)并仔细检查提交图,您现在就会看到上面的内容。但是,让Git继续下去,git rebase的最后一步是移动分支名称,并将HEAD重新附加到分支名称,如下所示:

代码语言:javascript
复制
             D   [abandoned]
            /
...--A--B--C--X--D'  <-- branch (HEAD)

由于没有可以轻松找到提交D的名称,因此即使使用git log --all --decorate --oneline --graphgit log也不会显示它。您现在将只看到D'

如果您不记得原始提交D的实际散列ID,那么看起来新的提交D'就是原始提交D。不是的!Git知道它不是,因为Git使用散列it来识别提交。分支名称无关紧要:重要的是散列ID。

Git使用分支名称查找起始散列ID,这是链中的最后一个提交。这就是为什么,在这些较新的提交位于右侧的绘图中,我们将分支名称放在最右侧,并带有一个向后箭头。Git总是向后工作:名称查找链中的最后一个提交,然后从那里,Git使用存储的散列ID向后工作,一次一个提交。

(当Git遇到具有两个或更多向后箭头的合并提交时,Git仍然必须一次执行一个提交,主要是这样。为了处理这个问题,这些Git命令保留了一个散列ID队列。队列是一个优先级队列,其中较高优先级的提交在较低优先级的提交之前被访问。什么使提交优先级更高或更低取决于您为git loggit rev-list提供的--topo-order--graph--date-order--committer-date-order或其他排序选项。)

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/60901503

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档