如何仅对特定提交进行变基?

tem*_*boy 0 git git-rebase

当我git rebase -i <commit>这样做时,它会拉出从该提交开始的提交列表,我必须通过更改为 来选择要编辑的pick提交e。但是当我更改picke关闭编辑器时,git 仍然会迭代所有提交,而不仅仅是我想要编辑的提交。

例如,我确实git rebase -i --root并且只选择编辑最新的提交。Git 仍然尝试迭代整个提交列表。在我关闭编辑器后,它显示Rebasing (1/593)593 是列表中的提交数量。它经历了全部 593 个。它只会停止让我编辑我选择的内容。

有没有办法只针对特定的提交,即使它位于许多其他提交之间,而无需rebase遍历整个列表?

mat*_*att 6

理解这一点的方法就是理解 Git什么。Git 遵循一些极其基本且重要的规则。以下是其中两个:

\n
    \n
  1. 任何提交都不能更改。

    \n
  2. \n
  3. 提交的父指针是该提交的一部分(因此,根据规则 1,不能更改)。

    \n
  4. \n
\n

所以现在考虑这种情况:

\n
A -- B -- C -- D (mybranch)\n
Run Code Online (Sandbox Code Playgroud)\n

其中时间从左到右流动:A 首先被创建,并且是 B 的父级,B 是 C 的父级,C 是 D 的父级。

\n

现在假设我想更改 A 的提交消息。好吧,我不能!您无法更改有关提交的任何内容。但是您可以做的是将A替换为具有不同提交消息(但包含相同文件)的不同提交 \xe2\x80\x94

\n

但如果你这样做,你就会得到这个:

\n
A -- B -- C -- D (mybranch)\n\nA'\n
Run Code Online (Sandbox Code Playgroud)\n

其中 A' 是与 A 类似的新提交,但提交消息不同。这不好,因为这不是我们想要的。我们希望历史保持“相同”,A' 作为历史中 B 的父级。嗯,我们不能那样做!您无法更改 B 的出身。但是您可以做的是将B替换为看起来像 B 但将 A' 作为其父级的提交:

\n
A -- B -- C -- D (mybranch)\n\nA' -- B'\n
Run Code Online (Sandbox Code Playgroud)\n

但是等等,还有更多!对于所有后续提交,我们必须继续这样做。当我们完成后,Git 只需移动mybranch指针移动到新的历史记录:

\n
A -- B -- C -- D\n\nA' -- B' -- C' -- D' (mybranch)\n
Run Code Online (Sandbox Code Playgroud)\n

就是当您使用交互式变基编辑 A 的提交消息时会发生的情况。您将获得A 的所有新提交及其之后的所有提交

\n

这正是您所看到和询问的。

\n
\n

要确认这是真的,请在示例存储库上尝试一下,并观察 SHA 数字。这是一个例子。我通常会git log在一开始就查看我拥有的内容:

\n
* 0c32c25 (HEAD -> main) d\n* 12ec6ca c\n* 28b1e17 b\n* b8cb561 a\n
Run Code Online (Sandbox Code Playgroud)\n

现在我交互式变基到根;以下是我编辑待办事项列表的方法:

\n
r b8cb561 a\npick 28b1e17 b\npick 12ec6ca c\npick 0c32c25 d\n
Run Code Online (Sandbox Code Playgroud)\n

我重写了第一次提交,使其消息为a with a different commit message. 现在变基完成了,这就是我得到的:

\n
* 0931c89 (HEAD -> main) d\n* 45ebf0a c\n* 084b06c b\n* bcc0bed a with a different commit message\n
Run Code Online (Sandbox Code Playgroud)\n

查看 SHA 数字。他们都变了。那是因为这些与我开始时的提交不同!它们都已被替换。

\n
\n

最后一个观察。如果你仔细观察,你应该会说:在图中,被“替换”的原来的A 到 D 发生了什么?

\n
A -- B -- C -- D\n\nA' -- B' -- C' -- D' (mybranch)\n
Run Code Online (Sandbox Code Playgroud)\n

看起来他们还在那里。你是对的!他们还在那里。在你的大变基之后,你的所有提交都会被重复。新版本存在,旧版本也存在。这实际上是 Git 的一个非常酷的功能:提交在被替换时不会被删除。

\n

在这种特殊情况下,您没有简单的方法可以访问原始的 A 到 D。但如果您愿意,也可以。例如,您可以使用引用日志。或者您可以在执行变基之前在 D 上放置另一个分支名称。

\n

最终,回购将被“垃圾收集”。Git 会注意到没有分支名称指向 D,因此也没有指向 C、B 和 A。它们被视为“无法访问”,Git删除它们。但这可能还需要几周的时间。如果您愿意的话,您有很多时间来恢复原始文件。酷吧?

\n