虽然技术上不可能,但是通过诡计很容易实现期望的目标。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}
引用来完成此操作,请留待读者自行练习。所有这些都没有经过任何测试。
您可以在.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}
...
git commit --amend
也并不真正修改提交,它只是制作一个新的提交来替换旧的提交。因此,这就是你在git stash
中所要做的事情,就像你所描述的那样。 - torekgit notes
向相关提交添加信息。(尽管可能不明显地存在注释。) - chepner