2011-06-11 71 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