如何在git stash中修改消息?

时间:2018-05-16 18:53:47

标签: git

假设我过快地将一个藏匿在git中并且没有提供信息性的藏匿消息。我想修改存储中的消息,但无法从git文档中找到一种方法。我可以让repo进入一个干净的状态然后弹出存储并重新应用w / git stash保存“我的保存消息”但是想知道是否有人有解决方案来修改消息。

1 个答案:

答案 0 :(得分:3)

这在技术上是不可能的,但很容易通过欺骗来实现预期的目标。即使git commit具有--amend选项,Git也没有任何内置机制来完成诡计。 (也没有干净的方法可以劫持git commit --amend。)

最后,你必须做你所建议的事情。如果你愿意的话,你可以在脚本中隐藏它,但对于一次性案例来说,除了手工操作之外,还有更多的工作。

技术细节,以防您想要构建脚本

在Git命令行命令和选项等的掩护下,Git存储条目实际上提交。更准确地说,它至少提交了两次,有时是三次。 The git stash documentation在标记为DISCUSSION的部分中描述了这一点(相当轻松和粗心),使git stash提交特殊内容的事情是它们位于 no 分支上,并且,集群中的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实际上会进行 new 提交,将当前(HEAD)提交放在一边。也就是说,如果我们从:

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

并运行git commit --amend,Git将提交 - 让我们调用此G2 - 其父级为F,而不是正常的想法使用G作为G2的父级,然后将G2的ID写入分支,给我们:

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

只要旧的提交G没有我们可以找到它的名称,Git就不会向我们展示它,并最终完全删除它,使它看起来好像我们以某种方式更改了提交{{1}进入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}引用来确定如何执行此操作仍然是一个练习。这些都不会被远程测试。)