2011-06-11 73 views
34

我一直想要使用git命令来保存一个存储而不修改我的工作树,作为一个轻量级的备份,可以安全地从任何git重置或我可能会做的任何事情来搞砸我的索引。基本上相同的功能等同于“git stash save & & git stash apply”,除了工作副本从未被触及,因为这可以使某些文本编辑器/ IDE的胡思乱想。Git命令保存一个藏匿而不修改工作树?

像这样的东西是接近我想要的东西,但并不完全:

git update-ref refs/stash `git stash create "Stash message"` 

此功能工作,但我遇到的问题是,没有藏匿消息显示了在“混帐藏匿名单”,即使实际的隐藏提交确实有我的消息。考虑到存储容量有多大,存储消息非常重要。

回答

26

由于查尔斯的小费,我刮起了bash脚本做我想要的到底是什么(我也陷入了实现这个,因为只有一个别名问题)。它需要一个可选的存储消息,就像git存储保存一样。如果没有提供,它将使用由git存储生成的默认消息。

#!/bin/sh 
# 
# git-stash-push 
# Push working tree onto the stash without modifying working tree. 
# First argument (optional) is the stash message. 
if [ -n "$1" ]; then 
     git update-ref -m "$1" refs/stash "$(git stash create \"$1\")" 
else 
     HASH=`git stash create` 
     MESSAGE=`git log --no-walk --pretty="tformat:%-s" "$HASH"` 
     git update-ref -m "$MESSAGE" refs/stash "$HASH" 
fi 

编辑:正如下面评论指出的那样,在你的路径某处保存该脚本git-stash-push足以能够通过键入git stash-push调用它。

这里的好处是,即使您使用此方法删除存储,您仍然可以使用悬挂提交的git log [commit-hash]来查看存储消息!

编辑:既然git的2.6.0,您可以添加到--create-reflogupdate-ref然后git stash list将显示此即使git stash之前没有使用。

+5

如果你调用'git-stash-push'文件并将它放在PATH的某个地方,就不需要为它创建一个别名。 'git stash-push'会发现(并且调用)'git-stash-push' – 2011-06-12 08:42:20

+0

真的吗?有趣的,我会尝试。 – Eliot 2011-06-13 18:54:31

+0

上述脚本的一个警告,它似乎无法正常工作时,隐藏是空的。 – Eliot 2011-06-24 09:00:12

12

您需要将消息传递给update-ref而不是stash create,因为stash create不会接收消息(它不更新任何ref,因此它没有reflog条目来填充)。

git update-ref -m "Stash message" refs/stash "$(git stash create)" 
+0

谢谢,这就是我一直在寻找!然而,你对git存储的创建并没有留下信息是不正确的。提供给它的消息成为提交消息。因此,要完美模拟由git stash save创建的存储提交,我认为下面的命令将完成这项工作:'git update-ref -m“存储邮件”refs/stash“$(git stash create'Stash message')” 。你能想到一个聪明的方式直接添加这个作为一个GIT别名?如果没有,我可以使它成为一个简单的bash脚本。 – Eliot 2011-06-11 20:13:51

+0

@Eliot:显示在'git stash list'中的消息来自reflog,而不是提交消息。这就是我所指的。你确实发现'create'确实发生了消息,但这不是一个记录的特性,所以我不知道这是故意打算工作,还是它只是实现的人造物。 – 2011-06-11 20:23:24

+0

是的,好点。我意外发现它。我在git wiki上发现了一些关于在别名中使用参数的文档,所以我很好去! – Eliot 2011-06-11 20:27:39

2

由艾略特的解决方案的启发,我伸出他的剧本一点点:

#!/bin/sh 
# 
# git-stash-push 
# Push working tree onto the stash without modifying working tree. 
# First argument (optional) is the stash message. 
# 
# If the working dir is clean, no stash will be generated/saved. 
# 
# Options: 
# -c "changes" mode, do not stash if there are no changes since the 
#  last stash. 
if [ "$1" == "-c" ]; then 
     CHECK_CHANGES=1 
     shift 
fi 


if [ -n "$1" ]; then 
     MESSAGE=$1 
     HASH=$(git stash create "$MESSAGE") 
else 
     MESSAGE=`git log --no-walk --pretty="tformat:%-s" "HEAD"` 
     MESSAGE="Based on: $MESSAGE" 
     HASH=$(git stash create) 
fi 

if [ "$CHECK_CHANGES" ]; then 
     # "check for changes" mode: only stash if there are changes 
     # since the last stash 

     # check if nothing has changed since last stash 
     CHANGES=$(git diff [email protected]{0}) 
     if [ -z "$CHANGES" ] ; then 
       echo "Nothing changed since last stash." 
       exit 0 
     fi 
fi 

if [ -n "$HASH" ]; then 
     git update-ref -m "$MESSAGE" refs/stash "$HASH" 
     echo "Working directory stashed." 
else 
     echo "Working tree clean, nothing to do." 
fi 

我实现了对艾略特的脚本如下更改:

  1. 当工作目录是干净的,该脚本将正常退出
  2. 当使用开关-c时,如果没有与上次存储相比的变化,脚本将退出。如果您将此脚本用作“时间机器”,则每10分钟自动存储一次,这非常有用。如果没有更改,则不会创建新的藏匿处。没有这个开关,你可能会以n个连续的相同的方式结束。

不就是为了使开关-c正常工作,至少有一个藏匿必须存在,否则脚本上git diff [email protected]{0}抛出一个错误,不会做任何事情。

我使用这个脚本作为一个“时间机器”,使用以下的bash循环,每10分钟快照:

while true ; do date ; git stash-push ; sleep 600 ; done