[英]When I git stash and then git stash pop my changes are always unstaged
如果我有一些暫存文件和一些未暫存文件並且我需要暫時存儲它們,我會運行:
git stash
然后當我希望他們稍后回來時,我會這樣做:
git stash pop
但是,這些文件現在都已取消暫存,即使它們之前在存儲之前已暫存。 有什么辦法可以彈出一個存儲文件,以便它記住哪些文件是暫存的和未暫存的,並將它們恢復到你存儲它們之前的確切狀態?
您可以使用git stash pop --index
或git stash apply --index
進行分階段提交。
正如Sam 回答的那樣,您想使用--index
選項。 不過,了解內部發生的事情是有幫助的。
當你犯了一個藏匿處,與git stash save
,或較新的動詞, git stash push
1 -git居然寫出兩次提交。 這是因為提交是 Git 的基本存儲單元。 2其中有兩個的原因是其中一個存儲 Git 的index 中的內容,另一個存儲您的work-tree 中的內容。
您使用可以查看和編輯的普通文件來完成您的工作——查看和編輯您的文件。 這些在您的工作樹中(也稱為工作樹或任意數量的類似單詞和短語;舊版本的 Git 也使用短語工作目錄或工作目錄)。 這一切都非常簡單,因為您計算機的所有工具和程序都可以處理這些文件。
但是 Git 不會從工作樹提交。 Git 從index進行新的提交。 索引是如此重要(和/或命名如此糟糕)以至於它在 Git 中有三個名稱:Git 有時像這樣稱其為“索引”,但有時稱其為staging area ,偶爾——最近很少——稱它為 the緩存。 您已經熟悉使用它來暫存更新文件的想法; 這就是名稱暫存區的由來。 但實際上,索引保存了將要進入下一次提交的每個文件的副本3 。 此副本開始時與當前提交中的內容相同,並且當您更新文件和git add
時,索引副本將替換為更新的文件。
換句話說,索引保存了您建議進行下一次提交的內容。 運行git add
更新這個提議的下一次提交。 為了告訴您當前提交和建議的下一次提交之間有什么不同, git status
只是將當前提交中的文件與索引中的文件進行比較。 當它們相同時,它什么也不說,當它們不同時,它說“暫存以進行提交”。
所以:當你運行git stash save
或git stash push
,Git 首先從索引進行提交,就像它可能從索引進行任何提交一樣。 然后存儲代碼創建一個臨時索引——通過復制常規/真實的索引——並將工作樹中的所有文件git add
s 到臨時索引中,即git add -u
。 然后它從這個與您的工作樹匹配的臨時索引進行提交。
這就是兩次提交的來源。 所有 stashes 都至少有這兩個提交。 如果您使用-u
或-a
標志進行存儲,則會增加第三次提交......這會變得混亂,所以讓我們假設您永遠不會這樣做。
當您應用或彈出一個stash- pop
只是手段apply
則drop
-你在這個時候是否使用的第一個藏匿選擇提交,隨着指數的內容,還是不行。 如果您使用--index
標志,Git 將嘗試將索引提交應用於您當前的索引。 這實際上運行了一個git diff
操作,它通過管道傳輸到git apply --cached
(這在舊的git stash
shell 腳本中更容易看到,它實際上運行git diff-tree --binary $s^2^..$s^2 | git apply --cached
)。
如果您不使用--index
選項, git stash apply
只會忽略隱藏的索引! 它只是繼續執行git stash apply
的其余部分,即直接在將隱藏的工作樹與您當前的工作樹合並所需的三個提交上運行git merge-recursive
4 。 如果這一步成功, git stash pop
將刪除stash,這使得恢復索引變得非常困難。
我通常建議完全避免git stash
, 5但如果你確實使用它,我建議避免git stash pop
。 很容易忘記--index
標志。 如果您使用git stash apply
,您仍然可以使用 stash 並且可以重置(參見腳注 4)並使用--index
重試 apply 。
1在 Git 2.13 之前, save
動詞是唯一可用的動詞。 該版本的 Git 添加了push
動詞以允許一系列附加選項。
2內部有一個較小的存儲單元,稱為blob ,但它不適合存儲:您需要大量名稱存儲在 Git 內部樹對象中的 blob,要將它們收集在一起,您需要一個提交對象,所以為什么提交是 Git 中必不可少的存儲單元。
3從技術上講,索引保存了對腳注 2 中提到的內部blob 對象的引用。這些 blob 對象以壓縮的只讀格式存儲文件數據,Git 使用這種格式來保持文件較小並准備好共享。 由於它們是只讀的,例如, README.md
在數十個或數百個提交中的README.md
副本可以在它是同一個副本時共享。 索引也可以共享它。 使用git add
新文件寫入索引,實際上只是將文件的內容壓縮為 blob 格式。 這會自動共享文件的任何現有副本,或者根據需要創建新的 blob。
4你可能永遠不應該自己運行git merge-recursive
,因為它繞過了“一切都安全提交”的檢查。 此檢查可確保如果合並失敗,您可以使用git reset --hard
進行恢復。 git stash
代碼繞過此檢查,因此無法從嘗試應用 stash 中恢復。 因此,如果您完全使用git stash
,那么最好確保git status
表明一切都是干凈的。
5我自己仍然使用它,但很少使用,而且只有在我確定它會起作用的情況下才會使用。 即使那樣,我也會不小心燙傷自己。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.