是否总是显示消息“成功重新设置基准并更新 refs/heads/master”?

tum*_*vee 3 git rebase

我在 master 分支上工作并尝试过这个git rebase -i HEAD~3。我实际上尝试从提交历史记录中删除提交,但意识到没有必要这样做。

\n\n

纳米编辑器打开后,我没有对文件进行任何更改并关闭它而不保存。然而,命令行中显示一条消息,指出:\n“成功重新设置基址并更新 refs/heads/master ”。这意味着什么?我没有\xc2\xb4t(据我所知)做任何更改。当我查看 git log 和 git status 时,我没有看到任何变化。

\n\n

之后我做了一些提交并将它们推送到远程。

\n\n

我的问题是:为什么显示该消息?实际上有什么改变吗?

\n\n

我问这个问题是因为这实际上是一个共享项目,我正要在重新调整某些东西时犯一个重大错误,现在我担心我可能\xc2\xb4ve这样做了。正如你可能知道的那样,我对 git 非常精通:)

\n\n

感谢您的帮助!

\n

tor*_*rek 6

在你的具体情况下,实际上什么也没发生。变基成功了\xe2\x80\x94,并在过程中做了少量工作\xe2\x80\x94,但它所做的一切都准确地产生了原始提交。因此,最后一部分,当它说时updated refs/heads/master,意味着:我将名称master从识别提交 X 更改为识别提交 X(对于某些哈希 ID X)。本质上,它删除了旧条目并用绝对、完全、100% 相同的条目替换。

\n\n

这里发生了什么(如果你关心的话)

\n\n

这一切的原因有点复杂。本质上来说git rebase,就是复制提交。这里的问题是,提交一旦完成,就会被及时冻结:任何现有提交的任何部分都不能更改。如果我们做出了一个糟糕的提交,或者甚至只是“不太好”,我们可能想用一个新的和改进的提交来替换它:我们可能想将原始提交提取到工作区中,进行一些更改工作区,并进行一个基本相同但略有不同的新提交。

\n\n

如果我们这样做\xe2\x80\x94如果我们制作提交的副本,其中某些部分已更改\xe2\x80\x94,我们将获得一个新的不同的提交,并具有新的不同的哈希ID。这就导致了一个难题,因为 Git 分支名称只记住一个哈希 ID。具体来说,分支名称会记住我们想要调用分支一部分的最后一次提交的哈希 ID。

\n\n

同时,每次提交还会记住一个哈希 ID。更准确地说,每次提交都会记住零个或多个哈希 ID,但通常只有一个。提交记住的通常哈希 ID 是该特定提交之前的提交的哈希 ID 。Git 将其称为提交的提交。

\n\n

请注意,当子提交“诞生”(创建)时,Git 知道子提交的父提交的哈希 ID(或者,对于合并提交,父提交为复数)。因此,Git 可以在创建过程中将该哈希 ID 填充到子项中。但一旦孩子被写出来,它就永远被冻结了。因此,当该子级本身稍后成为父级时,它不能将其子级添加到其中。它只能记住它的父母。

\n\n

但这已经足够好了!如果我们绘制这种情况,我们会发现提交形成了一个很好的简单的向后看链:

\n\n
... <-F <-G <-H\n
Run Code Online (Sandbox Code Playgroud)\n\n

这里H代表最后一次提交的实际哈希 ID。承诺H是最孩子的;它的父级是G; 并H记住了G\的ID。CommitG会记住F\ 的 ID,并F记住另一个父级,依此类推,一直到存储库的开头。

\n\n

因此,像这样的分支名称只需master记住最后一次提交的 ID,在本例中H

\n\n
...--F--G--H   <-- master\n
Run Code Online (Sandbox Code Playgroud)\n\n

为了添加新的提交,我们让 Git 将最新的master提交(即 )提取H到工作区中。然后我们对其进行处理并准备新的提交。一旦一切准备就绪(等等git add),我们就运行git commit. 现在,Git 会冻结我们告诉它为新提交保存的所有内容,添加 的实际哈希 ID H,并写出一个新提交\xe2\x80\x94,它会得到一个新的、唯一的、又大又难看的哈希 ID,我们用它来表示。只需致电I

\n\n
...--F--G--H   <-- master\n            \\\n             I\n
Run Code Online (Sandbox Code Playgroud)\n\n

最后一步是将这个新的哈希 ID 写入名称中以便现在记住 commit而不是 commit 。没关系,因为 commit本身会记住 commit :git commitmastermasterIHIH

\n\n
...--F--G--H\n            \\\n             I   <-- master\n
Run Code Online (Sandbox Code Playgroud)\n\n

如果我们决定我们搞砸了 commit I,我们实际上根本无法更改 I,但我们可以将其复制到一个新的和改进的替代品,也许是一个名为J

\n\n
             J\n            /\n...--F--G--H\n            \\\n             I   <-- master\n
Run Code Online (Sandbox Code Playgroud)\n\n

如果我们现在强制 Git 让名称master记住J哈希 ID,只要我们不关注哈希 ID,看起来我们就以某种方式神奇地改变了。I(相比之下,Git非常严格地关注哈希 ID。哈希 ID 可以说是它的命脉:它们是 Git 内部几乎所有东西的工作原理。)

\n\n

对于某些类型的变基,我们想要复制一系列提交,以便它们位于链中的不同位置:

\n\n
...--F--G--H   <-- master\n      \\\n       I--J   <-- feature\n
Run Code Online (Sandbox Code Playgroud)\n\n

在这里,如果我们希望我们的功能建立在 commitH而不是 commit 的基础上F,我们将不得不重新复制I并使J它们出现在 commit 之后H,并且可能也使用稍微不同的源代码,然后我们将让 Git 删除命名featureJ使其指向新副本:

\n\n
             I\'-J\'  <-- feature\n            /\n...--F--G--H   <-- master\n      \\\n       I--J   [abandoned]\n
Run Code Online (Sandbox Code Playgroud)\n\n

在其他情况下,我们只想做一些小修复。例如,我们从以下开始:

\n\n
...--F--G--H   <-- master\n            \\\n             I--J   <-- feature\n
Run Code Online (Sandbox Code Playgroud)\n\n

但决定我们要更改日志消息(reword在 中git rebase -i)。I\'这将使以前一样焕然一新并得到改进。如果我们所做的一切都是reword,那么,J 很好,但是J\ 的父级是I,所以我们需要一个新的和改进的,J\'其父级是副本I\'

\n\n
             I\'-J\'  <-- feature\n            /\n...--F--G--H   <-- master\n            \\\n             I--J   [abandoned]\n
Run Code Online (Sandbox Code Playgroud)\n\n

聪明的部分git rebase是,除非你告诉它不要\xe2\x80\x94使用--force例如\xe2\x80\x94,否则它会注意到实际上根本没有任何更改需要提交的情况I,并且只需重新使用原始提交I. 如果出现以下情况,就会发生这种情况:

\n\n
    \n
  • 任何来源都没有改变;
  • \n
  • 作者姓名、日志消息等没有变化;和
  • \n
  • 父哈希 ID 没有变化。
  • \n
\n\n

这就是你的 rebase 的情况:你说不要对任何东西进行任何更改,并且父哈希 ID 也是相同的,因此 Git 只是将所有三个提交保留在原处,并仔细确定了这样做是可以的。1

\n\n

然后,就像 Git 在完成 rebase 操作后所做的那样,Git 将最后复制的提交的哈希 ID 填充到分支名称中,以便该名称记录分支中的最后一次提交。这就是那updated部分。

\n\n
\n\n

1由于该--force选项,git rebase确实会检查这一点。如果您告诉 rebase 它绝对必须替换提交,它将进行一个微不足道的更改\xe2\x80\x94更新作者日期,例如\xe2\x80\x94,以便新提交具有新的且不同的哈希ID 。

\n\n

git filter-branch命令在其他方面git rebase与 steroids\xe2\x80\x94 类似,它会复制主要的提交内容,同时根据过滤器参数\xe2\x80\x94 对它们进行任意更改,不会执行任何此类检查。它依赖的事实是,如果您进行绝对、完全、100% 逐位相同的提交,并且与之前的某个现有提交相匹配,您实际上最终会取回原始哈希 ID,并且不会在数据库中存储新对象。如果git rebase没有--force,它可能只会这样做,而不是检查。对于git filter-branch,如果您想强制复制,您应该在其中一个过滤器中进行安排。

\n\n

请注意,100% 匹配要求意味着新提交必须具有:

\n\n
    \n
  • 相同的源树
  • \n
  • 相同的作者和提交者姓名和日期/时间
  • \n
  • 相同的日志消息,包括每个字符的确切拼写(包括空格)和相同的编码(UTF-8 或其他)
  • \n
  • 相同的哈希 ID,即导致该提交的相同历史记录
  • \n
\n\n

如果提交与此非常匹配,那么它就是原始提交,而不是更改后的副本。所以 Git 在这里重新使用原始版本是正确的。

\n