Git
英文 ▾ 主題 ▾ 最新版本 ▾ git-stash 最後更新於 2.43.0

名稱

git-stash - 將工作目錄中的變更儲藏起來

概要

git stash list [<log-options>]
git stash show [-u | --include-untracked | --only-untracked] [<diff-options>] [<stash>]
git stash drop [-q | --quiet] [<stash>]
git stash pop [--index] [-q | --quiet] [<stash>]
git stash apply [--index] [-q | --quiet] [<stash>]
git stash branch <branchname> [<stash>]
git stash [push [-p | --patch] [-S | --staged] [-k | --[no-]keep-index] [-q | --quiet]
	     [-u | --include-untracked] [-a | --all] [(-m | --message) <message>]
	     [--pathspec-from-file=<file> [--pathspec-file-nul]]
	     [--] [<pathspec>…​]]
git stash save [-p | --patch] [-S | --staged] [-k | --[no-]keep-index] [-q | --quiet]
	     [-u | --include-untracked] [-a | --all] [<message>]
git stash clear
git stash create [<message>]
git stash store [(-m | --message) <message>] [-q | --quiet] <commit>

描述

當您想要記錄工作目錄和索引的目前狀態,但想要回到乾淨的工作目錄時,請使用 git stash。此命令會儲存您的本機修改,並將工作目錄還原為與 HEAD 提交相符的狀態。

此命令儲藏的修改可以使用 git stash list 列出,使用 git stash show 檢查,並使用 git stash apply 還原(可能會在不同的提交之上)。呼叫不帶任何引數的 git stash 等同於 git stash push。儲藏預設會列為「WIP on branchname …​」,但您可以在建立時在命令列上給予更具描述性的訊息。

您建立的最新儲藏會儲存在 refs/stash 中;較舊的儲藏會在該參考的 reflog 中找到,並且可以使用常用的 reflog 語法命名(例如,stash@{0} 是最近建立的儲藏,stash@{1} 是它之前的儲藏,stash@{2.hours.ago} 也是可能的)。也可以僅指定儲藏索引來參考儲藏(例如,整數 n 等同於 stash@{n})。

命令

push [-p|--patch] [-S|--staged] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q|--quiet] [(-m|--message) <message>] [--pathspec-from-file=<file> [--pathspec-file-nul]] [--] [<pathspec>…​]

將您的本機修改儲存到新的儲藏項目,並將它們回滾到 HEAD(在工作樹和索引中)。<message> 部分是選填的,並提供與儲藏狀態一起的描述。

若要快速建立快照,您可以省略「push」。在此模式中,不允許使用非選項引數,以防止拼寫錯誤的子命令產生不必要的儲藏項目。此規則的兩個例外是 stash -p,它作為 stash push -p 的別名,以及路徑規範元素,這些元素在雙連字號 -- 後允許使用以消除歧義。

save [-p|--patch] [-S|--staged] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q|--quiet] [<message>]

此選項已棄用,建議改用git stash push。它與「stash push」的不同之處在於它不能採用路徑規範。相反,所有非選項引數都會串連起來以形成儲藏訊息。

list [<log-options>]

列出您目前擁有的儲藏項目。每個儲藏項目都會列出其名稱(例如,stash@{0} 是最新項目,stash@{1} 是它之前的項目,依此類推)、建立項目時目前所在分支的名稱,以及項目所根據的提交的簡短描述。

stash@{0}: WIP on submit: 6ebd0e2... Update git-stash documentation
stash@{1}: On master: 9cc0589... Add git-stash

此命令會採用適用於 git log 命令的選項,以控制顯示內容和方式。請參閱 git-log[1]

show [-u|--include-untracked|--only-untracked] [<diff-options>] [<stash>]

顯示儲藏項目中記錄的變更,作為儲藏內容與最初建立儲藏項目時的提交之間的差異。預設情況下,此命令會顯示 diffstat,但它會接受 git diff 已知的任何格式(例如,git stash show -p stash@{1} 以修補程式形式檢視第二個最近的項目)。如果未提供 <diff-option>,則預設行為會由 stash.showStatstash.showPatch 配置變數提供。您也可以使用 stash.showIncludeUntracked 來設定預設是否啟用 --include-untracked

pop [--index] [-q|--quiet] [<stash>]

從儲藏清單中移除單一儲藏狀態,並將其套用在目前的工作樹狀態之上,亦即執行 git stash push 的反向操作。工作目錄必須與索引相符。

套用狀態可能會因衝突而失敗;在這種情況下,它不會從儲藏清單中移除。您需要手動解決衝突,然後再手動呼叫 git stash drop

apply [--index] [-q|--quiet] [<stash>]

pop 類似,但不從儲藏清單中移除狀態。與 pop 不同,<stash> 可能是任何看起來像是透過 stash pushstash create 建立的提交。

branch <branchname> [<stash>]

建立並簽出一個名為 <branchname> 的新分支,從最初建立 <stash> 時的提交開始,將 <stash> 中記錄的變更套用至新的工作樹和索引。如果成功,且 <stash>stash@{<revision>} 形式的參考,則會接著捨棄 <stash>

如果執行 git stash push 的分支已變更到 git stash apply 因衝突而失敗的程度,則此功能很有用。由於儲藏項目會套用在執行 git stash 時的 HEAD 提交之上,因此它會還原最初儲藏的狀態,且沒有任何衝突。

clear

移除所有儲藏項目。請注意,這些項目接著將會進行修剪,且可能無法復原(請參閱下方的「範例」,以了解可能的策略)。

drop [-q|--quiet] [<stash>]

從儲藏項目清單中移除單一儲藏項目。

create

建立儲藏項目(這是一個一般的提交物件),並傳回其物件名稱,而不將其儲存在 ref 命名空間中的任何位置。這旨在對腳本很有用。它可能不是您想要使用的命令;請參閱上方的「push」。

store

將透過 git stash create 建立的指定儲藏(這是一個懸空合併提交)儲存在儲藏參考中,更新儲藏 reflog。這旨在對腳本很有用。它可能不是您想要使用的命令;請參閱上方的「push」。

選項

-a
--all

此選項僅適用於 pushsave 命令。

所有已忽略和未追蹤的檔案也會被儲藏,然後使用 git clean 清理。

-u
--include-untracked
--no-include-untracked

pushsave 命令搭配使用時,所有未追蹤的檔案也會被儲藏,然後使用 git clean 清理。

show 命令搭配使用時,會顯示儲藏項目中未追蹤的檔案,作為差異的一部分。

--only-untracked

此選項僅適用於 show 命令。

僅顯示儲藏項目中未追蹤的檔案,作為差異的一部分。

--index

此選項僅適用於 popapply 命令。

嘗試不僅恢復工作樹的變更,還恢復索引的變更。但是,當您有衝突時,這可能會失敗(這些衝突會儲存在索引中,因此您無法再以它們原本的方式套用變更)。

-k
--keep-index
--no-keep-index

此選項僅適用於 pushsave 命令。

已新增至索引的所有變更都會保持不變。

-p
--patch

此選項僅適用於 pushsave 命令。

以互動方式從 HEAD 和工作樹之間的差異中選取要儲藏的程式碼區塊。建構儲藏項目,使其索引狀態與您儲存庫的索引狀態相同,且其工作樹僅包含您以互動方式選取的變更。然後,從您的工作樹中回滾選取的變更。請參閱 git-add[1] 的「互動模式」章節,以了解如何操作 --patch 模式。

--patch 選項表示 --keep-index。您可以使用 --no-keep-index 來覆寫此選項。

-S
--staged

此選項僅適用於 pushsave 命令。

僅儲藏目前已暫存的變更。這與基本的 git commit 類似,差別在於狀態是提交到儲藏區而不是目前分支。

--patch 選項的優先順序高於此選項。

--pathspec-from-file=<file>

此選項僅對 push 命令有效。

Pathspec 從 <file> 傳入,而不是從命令列引數傳入。如果 <file> 正好是 -,則會使用標準輸入。Pathspec 元素以 LF 或 CR/LF 分隔。Pathspec 元素可以依照組態變數 core.quotePath 的說明加上引號 (請參閱 git-config[1])。另請參閱 --pathspec-file-nul 和全域 --literal-pathspecs

--pathspec-file-nul

此選項僅對 push 命令有效。

僅在與 --pathspec-from-file 一起使用時才有意義。Pathspec 元素以 NUL 字元分隔,所有其他字元都會被視為字面值 (包含換行符號和引號)。

-q
--quiet

此選項僅對 applydroppoppushsavestore 命令有效。

靜默模式,抑制回饋訊息。

--

此選項僅對 push 命令有效。

為了消除歧義,將 pathspec 與選項分開。

<pathspec>…​

此選項僅對 push 命令有效。

新的儲藏項目僅記錄符合 pathspec 的檔案的已修改狀態。索引項目和工作樹檔案也會針對這些檔案回滾到 HEAD 的狀態,而保持不符合 pathspec 的檔案不動。

如需詳細資訊,請參閱 gitglossary[7] 中的 pathspec 條目。

<stash>

此選項僅對 applybranchdroppopshow 命令有效。

形式為 stash@{<revision>} 的參考。若未提供 <stash>,則會假設為最新的儲藏 (即 stash@{0})。

討論

儲藏項目表示為一個 commit,其 tree 記錄了工作目錄的狀態,而其第一個父 commit 是建立該項目時的 HEAD 上的 commit。第二個父 commit 的 tree 記錄了建立該項目時的索引狀態,並使其成為 HEAD commit 的子 commit。其祖先關係圖如下所示

       .----W
      /    /
-----H----I

其中 HHEAD commit,I 是記錄索引狀態的 commit,而 W 是記錄工作樹狀態的 commit。

範例

提取至有未提交變更的樹狀結構

當您正在處理某事時,您得知上游的變更可能與您正在處理的內容有關。當您的本機變更與上游的變更沒有衝突時,簡單的 git pull 將可讓您繼續進行。

但是,在某些情況下,您的本機變更與上游變更發生衝突,而 git pull 會拒絕覆寫您的變更。在這種情況下,您可以將您的變更儲藏起來,執行提取,然後取消儲藏,如下所示

$ git pull
 ...
file foobar not up to date, cannot merge.
$ git stash
$ git pull
$ git stash pop
中斷的工作流程

當您正在處理某事時,您的老闆進來並要求您立即修復某個問題。傳統上,您會將變更提交到臨時分支以儲存起來,然後返回原始分支以進行緊急修復,如下所示

# ... hack hack hack ...
$ git switch -c my_wip
$ git commit -a -m "WIP"
$ git switch master
$ edit emergency fix
$ git commit -a -m "Fix in a hurry"
$ git switch my_wip
$ git reset --soft HEAD^
# ... continue hacking ...

您可以使用 git stash 來簡化上述操作,如下所示

# ... hack hack hack ...
$ git stash
$ edit emergency fix
$ git commit -a -m "Fix in a hurry"
$ git stash pop
# ... continue hacking ...
測試部分提交

當您想要從工作樹的變更中建立兩個或多個提交,並且想要在提交之前測試每個變更時,可以使用 git stash push --keep-index

# ... hack hack hack ...
$ git add --patch foo            # add just first part to the index
$ git stash push --keep-index    # save all other changes to the stash
$ edit/build/test first part
$ git commit -m 'First part'     # commit fully tested change
$ git stash pop                  # prepare to work on all other changes
# ... repeat above five steps until one commit remains ...
$ edit/build/test remaining parts
$ git commit foo -m 'Remaining parts'
儲存無關的變更以供日後使用

當您正在進行大量變更時,並且發現一些與您不想要忘記修復的無關問題時,您可以進行變更,將其暫存,然後使用 git stash push --staged 將其儲藏起來以供日後使用。這與提交暫存的變更類似,只是提交最終會進入儲藏區,而不是在目前分支上。

# ... hack hack hack ...
$ git add --patch foo           # add unrelated changes to the index
$ git stash push --staged       # save these changes to the stash
# ... hack hack hack, finish current changes ...
$ git commit -m 'Massive'       # commit fully tested changes
$ git switch fixup-branch       # switch to another branch
$ git stash pop                 # to finish work on the saved changes
復原錯誤清除/捨棄的儲藏項目

如果您不小心捨棄或清除儲藏項目,則無法透過正常的安全機制來復原它們。但是,您可以嘗試以下指令來取得仍然在您的儲存庫中,但無法再存取的儲藏項目清單

git fsck --unreachable |
grep commit | cut -d\  -f3 |
xargs git log --merges --no-walk --grep=WIP

組態

此區段中此行以下的所有內容均選擇性地從 git-config[1] 文件中包含。內容與那裡找到的內容相同

stash.showIncludeUntracked

如果此設定為 true,則 git stash show 命令將會顯示儲藏項目的未追蹤檔案。預設值為 false。請參閱 git-stash[1]show 命令的描述。

stash.showPatch

如果此設定為 true,則不帶選項的 git stash show 命令將會以 patch 形式顯示儲藏項目。預設值為 false。請參閱 git-stash[1]show 命令的描述。

stash.showStat

如果此設定為 true,則不帶選項的 git stash show 命令將會顯示儲藏項目的 diffstat。預設值為 true。請參閱 git-stash[1]show 命令的描述。

GIT

屬於 git[1] 套件的一部分

scroll-to-top