gpt4 book ai didi

git - 如何撤消 git commit --amend

转载 作者:IT王子 更新时间:2023-10-29 00:50:40 28 4
gpt4 key购买 nike

这个问题在这里已经有了答案:





How to undo “git commit --amend” done instead of “git commit”

(12 个回答)


3年前关闭。




我不小心输入了 git commit --amend。这是一个错误,因为我意识到提交实际上是全新的,应该使用新消息提交。我想做一个新的提交。如何撤消此操作?

最佳答案

PetSerAl's comment 是关键。这是执行您想要的操作的两个命令序列:

git reset --soft @{1}
git commit -C @{1}

并解释这是如何工作的。

描述

当您进行新的提交时,Git 通常1 使用以下事件序列:
  • 读取当前提交的 ID(SHA-1 哈希,如 a123456... )(通过 HEAD ,它为我们提供当前分支)。我们将此 ID 称为 C(代表 Current)。请注意,当前提交有一个父提交;让我们称其为 P(对于 Parent)。
  • 将索引(又名暂存区)变成一棵树。这会产生另一个 ID;我们将此 ID 称为 T(对于 Tree)。
  • 使用 parent = C 和 tree = T 编写新提交。此新提交获得另一个 ID。我们称之为 N(新的)。
  • 使用新的提交 ID N 更新分支。

  • 使用 --amend Git 时会稍微改变这个过程。它仍然像以前一样写一个新的提交,但在第 3 步中,不是用 parent = C 写新提交,而是用 parent = P 写它。

    图片

    从形象上讲,我们可以用这种方式画出发生的事情。我们从一个以 P--C 结尾的提交图开始,由 branch 指向:
    ...--P--C   <-- branch

    当我们进行新的提交 N 时,我们得到:
    ...--P--C--N   <-- branch

    当我们使用 --amend 时,我们会得到这个:
           C
    /
    ...--P--N <-- branch

    请注意,提交 C 仍在存储库中;它只是被推到一边,让开,以便新提交 N 可以指向旧的父级 P

    目标

    git commit --amend 之后,你意识到你想要的是让链看起来像:
    ...--P--C--N   <-- branch

    我们不能完全做到这一点——我们不能改变 N ;一旦任何提交(或任何其他对象)存储在 repo 中,Git 就永远不能更改它——但请注意, ...--P--C 链仍然在那里,完全完好无损。你可以通过 reflogs 找到 commit C,这就是 @{1} 语法所做的。 (具体来说,这是 currentbranch@{1} ,2 的缩写,意思是“ currentbranch 一步前指向的地方”,即“提交 C”。)

    因此,我们现在运行 git reset --soft @{1} ,它执行以下操作:
           C   <-- branch
    /
    ...--P--N

    现在 branch 指向 C ,后者又指向 P
    N 会发生什么?与之前发生在 C 上的事情相同:它通过 reflog 保存了一段时间。

    我们并不真正需要它(尽管它可能会派上用场),因为 --softgit reset 标志使索引/暂存区保持不变(以及工作树)。这意味着我们现在可以再次进行新的提交,只需运行另一个 git commit 。它将经历相同的四个步骤(从 HEAD 读取 ID、创建树、创建新提交和更新分支):
           C--N2   <-- branch
    /
    ...--P--N
    N2 将是我们新的(第二个新的?)提交。

    我们甚至可以让 git commit 重用来自 commit N 的提交消息。 git commit 命令有一个 --reuse-message 参数,也拼写为 -C ;我们所要做的就是给它一些东西,让它找到原始的新提交 N,从中复制消息,制作 N2。我们怎么做?答案是:它在 reflog 中,就像我们需要执行 C 时的 git reset 一样。

    事实上,它是相同的 @{1} !

    请记住, @{1} 的意思是“刚才的位置”,而 git reset 刚刚更新了它,将它从 C 移动到 N 。我们还没有进行新的提交 N2 。 (一旦我们这样做, N 将是 @{2} ,但我们还没有。)

    所以,把它们放在一起,我们得到:
    git reset --soft @{1}
    git commit -C @{1}

    1此描述分解的地方包括何时修改 merge 、何时在分离的 HEAD 上以及何时使用替代索引。尽管如此,如何修改描述还是很明显的。

    2 如果 HEAD 被分离,使得没有当前分支,则含义变为 HEAD@{1} 。请注意, @ 本身是 HEAD 的缩写,因此 @{n} 指的是当前分支而不是 HEAD 本身这一事实有点不一致。

    要查看它们有何不同,请考虑 git checkout develop 后跟 git checkout master(假设两个分支都存在)。第一个 checkoutHEAD 更改为指向 develop ,第二个将 HEAD 更改为指向 master 。这意味着 master@{1} 是在最后一次更新 master 之前提交 master 指向的任何提交;但是 HEAD@{1}develop 现在指向的提交——可能是其他一些提交。

    (回顾:在这两个 git checkout 命令之后, @{1} 现在表示 master@{1}HEAD@{1} 现在表示与 develop 相同的提交,而 @ 表示 HEAD 。如果你感到困惑,那么,我也是,显然我并不孤单:见评论.)

    关于git - 如何撤消 git commit --amend,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38001038/

    28 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com