如何修改git中暂存区的消息?

5
假设我太快地将stash放入git中,并且没有提供有信息的stash消息。我想修改stash中的消息,但是在git文档中找不到这样做的方法。我可以使存储库保持干净状态并弹出stash,然后使用“git stash save my save message”重新应用,但我想知道是否有人有解决方案,可以直接修改消息。

3
一个 git stash 条目实际上就是一个提交(至少有两个,有时候三个),就像所有的提交一样,它们都是只读的,技术上不可能改变任何提交。 git commit --amend 也并不真正修改提交,它只是制作一个新的提交来替换旧的提交。因此,这就是你在 git stash 中所要做的事情,就像你所描述的那样。 - torek
@torek 感谢您快速而清晰的解释。如果您将其表述为答案,我将接受/标记为正确。 - Lucas Roberts
2
但是就像其他提交一样,您可以使用git notes向相关提交添加信息。(尽管可能不明显地存在注释。) - chepner
@chepner 很有用,谢谢你的提示。 - Lucas Roberts
一个替代已接受答案的方案在这里 - Mike C
2个回答

5

虽然技术上不可能,但是通过诡计很容易实现期望的目标。Git没有任何内置机制来实现这种诡计,即使git commit--amend选项也是如此。 (也没有干净的方法来劫持git commit --amend来实现这一点。)

最终,您必须按照您建议的方式进行操作。如果您想要,可以将其隐藏在脚本中,但对于单次操作而言,这比手动操作更费力。

技术细节,以便构建脚本

在Git命令行命令、选项等的底层,Git stash条目实际上是一个提交。 更准确地说,它至少有两个提交,有时是三个。 git stash文档在标记为DISCUSSION的部分中轻率地描述了这一点。 使git stash提交特殊的是它们不在任何分支上 - 好吧,还有w(工作树)提交在群集中,这是refs/stash引用定位的提交,具有合并提交的形式,因此它可以列出多个父提交ID。 我更喜欢将它们绘制为:

...--F--G   <-- branch
        |\
        i-w   <-- (the stash)

或者:

...--F--G   <-- branch
        |\
        i-w   <-- (the stash)
         /
        u

这与Git文档中的绘图有些不同,但展示了我所谓的“stash bag”(带有可选的u提交,包含未跟踪的文件)从你制作存储时处于当前状态的提交处悬挂下来。(如果您尚未将HEAD移动到其他地方,则该提交仍然是当前提交。)这里的大写字母代表实际的提交哈希值,它们又长又丑,难以记忆。

与所有提交一样,特殊的存储提交是只读的 - 它们永远无法被更改,只能忘记它们的哈希ID(这就是git stash drop所做的)。

请注意,git commit --amend实际上会创建一个新的提交,将当前(HEAD)提交推到一边。也就是说,如果我们从以下内容开始:

...--F--G   <-- branch (HEAD)

当你执行git commit --amend时,Git会创建一个新的提交(称为G2),其中该提交的父提交是F而不是通常使用G作为G2的父提交,然后将G2的ID写入分支。最终结果如下所示:
       G
      /
...--F--G2  <-- branch (HEAD)

只要旧提交 G 没有名称,我们就无法找到它,Git 不会将其显示给我们,并最终完全删除它,使得看起来我们以某种方式将提交 G 改为了 G2
要使现有的存储条目具有不同的提交注释,我们必须执行相同的操作:将现有的 w 提交复制到一个新的提交中,具有不同的提交消息,但保留 w 的内容和所有父哈希值。如果我们将替换命名为 w2,则会得到:
...--F--G_  <-- branch
        |\`-.
        i-w2 \
         \    \
          -----w   <-- (the stash)

如果我们将refs/stash指向w2而不是w,并假装w不存在了,那么我们就能得到我们想要的结果:
...--F--G   <-- branch
        |\
        i-w2  <-- (the stash)

实际上,我们可以将其编写为一个脚本,从以下代码片段开始:

# get the parents of refs/stash as $1 and $2; $3 exists if there is a u commit
set -- $(git rev-parse refs/stash^@)
# convert these to "-p $1 -p $2 -p $3"
case $# in
2) parents="-p $1 -p $2";;
3) parents="-p $1 -p $2 -p $3";;
*) fatal "refs/stash does not appear to be a valid stash";;
esac
# find the stashed w commit's tree
tree=$(git rev-parse refs/stash^{tree}) || exit
# optional: for editing purposes, gather the current message
existing_message=$(git log --no-walk --pretty=format:%B refs/stash)

# obtain an updated message in some fashion
[snip]

然后:

# create a new w commit, suitable for "git stash store"
new_w_commit=$(git commit-tree $parents "$new_message" $tree)

最终目标是:
git stash drop --quiet
git stash store --quiet -m "$new_message" $new_w_commit

该脚本使用 git stash 本身来替换 stash@{0} ,从而生成新的存储。如果遇到中断,反转这两个操作可能更明智。如何使用 stash@{n} 引用来完成此操作,请留待读者自行练习。所有这些都没有经过任何测试。


0

您可以在.git/logs/refs/stash文件中编辑stash的短消息。

也可以为stash添加普通的长提交消息。例如:

    git rebase -i stash~1 refs/stash --rebase-merges

    # change the `merge -C ...` to `merge -c ...` in the protocol
    # then running the rebase edit the full msg

    git update-ref refs/stash @ stash

    # Then edit `.git/logs/refs/stash file` for the stash short message.

对于旧的存储,使用stash@{N}而不是stash作为rebase中的引用,并省略update-ref。

要查看存储的完整提交消息:

    git show stash
    git show stash@{1}
    git show stash@{2}
    ...

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接