English ▾ 主題 ▾ 最新版本 ▾ git-worktree 最後更新於 2.54.0

名稱

git-worktree - 管理多個工作樹

概要

git worktree add [-f] [--detach] [--checkout] [--lock [--reason <string>]]
		 [--orphan] [(-b | -B) <new-branch>] <path> [<commit-ish>]
git worktree list [-v | --porcelain [-z]]
git worktree lock [--reason <string>] <worktree>
git worktree move <worktree> <new-path>
git worktree prune [-n] [-v] [--expire <expire>]
git worktree remove [-f] <worktree>
git worktree repair [<path>…​]
git worktree unlock <worktree>

描述

管理連結到同一個儲存庫的多個工作樹。

一個 Git 儲存庫可以支援多個工作樹,允許您一次檢出多個分支。使用 git worktree add,一個新的工作樹會與該儲存庫關聯,並包含區分該工作樹與同一儲存庫中其他工作樹的額外元數據。該工作樹及其元數據被稱為「工作樹」(worktree)。

這個新的工作樹被稱為「連結工作樹」(linked worktree),相對於由 git-init[1]git-clone[1] 準備的「主工作樹」(main worktree)。一個儲存庫有一個主工作樹(如果不是裸儲存庫)以及零個或多個連結工作樹。當您完成連結工作樹的操作後,請使用 git worktree remove 將其移除。

在最簡單的形式下,git worktree add <路徑> 會自動建立一個新分支,其名稱是 <路徑> 的最後一個組件,如果您打算開發新主題,這會很方便。例如,git worktree add ../hotfix 會建立新分支 hotfix 並將其檢出至路徑 ../hotfix。若要在新的工作樹中開發現有分支,請使用 git worktree add <路徑> <分支>。另一方面,如果您只是打算進行一些實驗性更改或測試,而不干擾現有的開發,通常方便的做法是建立一個不與任何分支關聯的「一次性」工作樹。例如,git worktree add -d <路徑> 會在與當前分支相同的提交上建立一個帶有分離 HEAD 的新工作樹。

如果工作樹是在未使用 git worktree remove 的情況下被刪除的,那麼它存放在儲存庫中的相關管理檔案(見下文「細節」)最終會被自動移除(見 git-config[1] 中的 gc.worktreePruneExpire),或者您可以在主工作樹或任何連結工作樹中執行 git worktree prune 來清理任何過期的管理檔案。

如果連結工作樹的工作樹存放在不常掛載的可攜式裝置或網路共享上,您可以透過執行 git worktree lock 命令來防止其管理檔案被修剪,並可選擇指定 --reason 來解釋工作樹被鎖定的原因。

指令

add <路徑> [<提交號>]

<路徑> 建立一個工作樹並將 <提交號> 檢出到其中。新的工作樹與當前儲存庫連結,共享除每個工作樹專用檔案(如 HEADindex 等)之外的所有內容。為了方便起見,<提交號> 可以是單獨的「-」,這與 @{-1} 同義。

如果 <提交號> 是一個分支名稱(稱之為 <分支>)且未找到,並且未使用 -b-B--detach,但確實存在於正好一個遠端(稱之為 <遠端>)中且名稱相符的追蹤分支,則視為等同於

$ git worktree add --track -b <branch> <path> <remote>/<branch>

如果該分支存在於多個遠端中,且其中一個是由 checkout.defaultRemote 設定變數指定的,我們將使用該遠端來消除歧義,即使 <分支> 在所有遠端中並非唯一。將其設定為例如 checkout.defaultRemote=origin,以便在 <分支> 有歧義但存在於 origin 遠端時,始終從那裡檢出遠端分支。另請參閱 git-config[1] 中的 checkout.defaultRemote

如果省略了 <提交號> 且未使用 -b-B--detach,那麼為了方便起見,新工作樹將與以 $(basename <路徑>) 命名的一個分支(稱之為 <分支>)關聯。如果 <分支> 不存在,則會自動建立一個基於 HEAD 的新分支,就像給出了 -b <分支> 一樣。如果 <分支> 確實存在,且未在其他任何地方檢出,則會在新工作樹中檢出該分支,否則命令將拒絕建立工作樹(除非使用 --force)。

如果省略了 <提交號>,且未使用 --detach--orphan,且沒有有效的本地分支(或如果指定了 --guess-remote 則為遠端分支),那麼為了方便起見,新工作樹將與名為 <分支> 的新未出生分支關聯(如果未使用 -b-B,則依據 $(basename <路徑>)),就像傳遞了 --orphan 給命令一樣。如果儲存庫有遠端且使用了 --guess-remote,但不存在遠端或本地分支,則命令失敗並顯示警告,提醒使用者先從其遠端抓取 (fetch)(或使用 -f/--force 強制執行)。

list

列出每個工作樹的詳細資訊。主工作樹列在最前面,接著是各個連結工作樹。輸出細節包括工作樹是否為裸儲存庫、當前檢出的修訂版本、當前檢出的分支(如果沒有則顯示 "detached HEAD")、如果工作樹已鎖定則顯示 "locked"、如果工作樹可以被 prune 命令修剪則顯示 "prunable"。

lock

如果工作樹位於不常掛載的可攜式裝置或網路共享上,請將其鎖定以防止其管理檔案被自動修剪。這也可以防止它被移動或刪除。可選擇使用 --reason 指定鎖定原因。

move

將工作樹移動到新位置。請注意,主工作樹或包含子模組的連結工作樹無法使用此命令移動。(但是,如果您手動移動主工作樹,git worktree repair 命令可以重新建立與連結工作樹的連接。)

prune

移除 $GIT_DIR/worktrees 中對應工作區已遺失的工作樹資訊。這在手動刪除不再需要的工作樹後很有用(但下次建議使用 "git worktree remove")。此外,如果您將工作樹「移動」到他處導致工作樹資訊懸空,請參閱 "git worktree repair" 以將工作樹重新連接到新的工作樹位置。

remove

移除工作樹。只有乾淨的工作樹(無未追蹤檔案且已追蹤檔案無修改)才能被移除。不乾淨的工作樹或帶有子模組的工作樹可以使用 --force 移除。主工作樹不能被移除。

repair [<路徑>...]

如果工作樹管理檔案因外部因素損壞或過時,請儘可能修復它們。

例如,如果主工作樹(或裸儲存庫)被移動,連結工作樹將無法定位它。在主工作樹中執行 repair 將重新建立連結工作樹回到主工作樹的連接。

同樣地,如果在未使用 git worktree move 的情況下移動了連結工作樹的工作樹,主工作樹(或裸儲存庫)將無法定位它。在最近移動的工作樹中執行 repair 將重新建立連接。如果移動了多個連結工作樹,從任何工作樹執行 repair 並以每個樹的新 <路徑> 作為參數,將重新建立與所有指定路徑的連接。

如果主工作樹和連結工作樹都被手動移動或複製,那麼在主工作樹中執行 repair 並指定每個連結工作樹的新 <路徑>,將重新建立兩個方向的所有連接。

unlock

解鎖工作樹,允許對其進行修剪、移動或刪除。

選項

-f
--force

預設情況下,當 <提交號> 是分支名稱且已被另一個工作樹檢出時,或者如果 <路徑> 已分配給某個工作樹但已遺失(例如,如果 <路徑> 被手動刪除),add 會拒絕建立新的工作樹。此選項會覆蓋這些保護機制。要新增遺失但已鎖定的工作樹路徑,請指定兩次 --force

除非指定兩次 --force,否則 move 會拒絕移動已鎖定的工作樹。如果目標已分配給其他工作樹但已遺失(例如,如果 <新路徑> 被手動刪除),則 --force 允許繼續移動;如果目標已鎖定,請使用兩次 --force

除非使用 --force,否則 remove 會拒絕移除不乾淨的工作樹。要移除鎖定的工作樹,請指定兩次 --force

-b <新分支>
-B <新分支>

配合 add 使用,建立一個名為 <新分支> 且起點為 <提交號> 的新分支,並在新工作樹中檢出 <新分支>。如果省略 <提交號>,則預設為 HEAD。預設情況下,如果 <新分支> 已經存在,-b 會拒絕建立新分支。-B 會覆蓋此保護機制,將 <新分支> 重設為 <提交號>

-d
--detach

配合 add 使用,在新工作樹中分離 HEAD。請參閱 git-checkout[1] 中的「分離 HEAD」(DETACHED HEAD)。

--checkout
--no-checkout

預設情況下,add 會檢出 <提交號>,但是,可以使用 --no-checkout 來抑制檢出,以便進行自定義設定,例如配置稀疏檢出 (sparse-checkout)。請參閱 git-read-tree[1] 中的「稀疏檢出」(Sparse checkout)。

--guess-remote
--no-guess-remote

使用 worktree add <路徑> 且不帶 <提交號> 時,如果正好有一個遠端中存在與 <路徑> 基底名稱 (basename) 相符的追蹤分支,則不從 HEAD 建立新分支,而是以該遠端追蹤分支為基底,並將該遠端追蹤分支標記為新分支的「上游」(upstream)。

這也可以透過使用 worktree.guessRemote 設定選項來設定為預設行為。

--relative-paths
--no-relative-paths

使用相對路徑或絕對路徑(預設)連結工作樹。覆蓋 worktree.useRelativePaths 設定選項,請參閱 git-config[1]

配合 repair 使用時,如果絕對/相對路徑不匹配,即使連結本身正確,連結檔案也會被更新。

--track
--no-track

建立新分支時,如果 <提交號> 是一個分支,則將其標記為新分支的「上游」。如果 <提交號> 是遠端追蹤分支,這也是預設行為。詳情請參閱 git-branch[1] 中的 --track

--lock

在建立後保持工作樹鎖定。這相當於在 git worktree add 之後執行 git worktree lock,但不存在競態條件。

-n
--dry-run

配合 prune 使用時,不移除任何東西;僅報告將會移除的內容。

--orphan

配合 add 使用時,使新的工作樹和索引為空,將工作樹與名為 <新分支> 的新未出生分支關聯。

--porcelain

配合 list 使用時,以易於腳本解析的格式輸出。此格式在 Git 版本之間以及無論使用者如何設定都將保持穩定。建議將此選項與 -z 結合使用。詳情見下文。

-z

--porcelainlist 一起指定時,以 NUL 而非換行符結束每一行。這使得在工作樹路徑包含換行字元時可以解析輸出。

-q
--quiet

配合 add 使用時,抑制回饋訊息。

-v
--verbose

配合 prune 使用時,報告所有移除動作。

配合 list 使用時,輸出有關工作樹的額外資訊(見下文)。

--expire <時間>

配合 prune 使用時,僅修剪早於 <時間> 的遺失工作樹。

配合 list 使用時,如果遺失的工作樹早於 <時間>,則將其標註為可修剪。

--reason <字串>

配合 lockadd --lock 使用,解釋工作樹被鎖定的原因。

<工作樹>

工作樹可以透過相對路徑或絕對路徑來識別。

如果工作樹路徑中的最後一個路徑組件在所有工作樹中是唯一的,則可以用它來識別工作樹。例如,如果您只有兩個工作樹,分別位於 /abc/def/ghi/abc/def/ggg,那麼 ghidef/ghi 就足以指向前者。

引用 (REFS)

當使用多個工作樹時,有些引用在所有工作樹之間共享,但有些則是特定工作樹專有的。一個例子是 HEAD,它在每個工作樹中都不同。本節介紹共享規則以及如何從一個工作樹存取另一個工作樹的引用。

通常,所有偽引用 (pseudo refs) 都是每個工作樹專有的,而所有以 refs/ 開頭的引用都是共享的。偽引用是指像 HEAD 這樣直接位於 $GIT_DIR 下而不是在 $GIT_DIR/refs 內的引用。不過也有例外:refs/bisectrefs/worktreerefs/rewritten 內的引用是不共享的。

特定於工作樹的引用仍然可以透過兩個特殊的內部路徑 main-worktreeworktrees 從另一個工作樹存取。前者允許存取主工作樹的專有引用,而後者則允許存取所有連結工作樹的專有引用。

例如,main-worktree/HEADmain-worktree/refs/bisect/good 分別解析為與主工作樹的 HEADrefs/bisect/good 相同的值。同樣地,worktrees/foo/HEADworktrees/bar/refs/bisect/bad$GIT_COMMON_DIR/worktrees/foo/HEAD$GIT_COMMON_DIR/worktrees/bar/refs/bisect/bad 相同。

要存取引用,最好不要直接查看 $GIT_DIR 內部。應使用像是 git-rev-parse[1]git-update-ref[1] 這樣的命令,它們會正確處理引用。

設定檔

預設情況下,儲存庫的 config 檔案在所有工作樹中共享。如果通用設定檔中存在設定變數 core.barecore.worktreeextensions.worktreeConfig 已停用,則它們將僅套用於主工作樹。

為了擁有特定於工作樹的設定,您可以開啟 worktreeConfig 擴充,例如:

$ git config extensions.worktreeConfig true

在此模式下,特定設定將保留在 git rev-parse --git-path config.worktree 指向的路徑中。您可以使用 git config --worktree 在此檔案中新增或更新設定。舊版 Git 將拒絕存取帶有此擴充的儲存庫。

請注意,在此檔案中,core.barecore.worktree 的例外已消失。如果它們存在於 $GIT_DIR/config 中,您必須將它們移動到主工作樹的 config.worktree。您也可以藉此機會審查並將其他不想共享給所有工作樹的設定移動過去。

  • core.worktree 永遠不應共享。

  • 如果值為 core.bare=true,則 core.bare 不應共享。

  • core.sparseCheckout 不應共享,除非您確定所有工作樹都始終使用稀疏檢出。

有關更多詳細資訊,請參閱 git-config[1]extensions.worktreeConfig 的文件。

細節

每個連結工作樹在儲存庫的 $GIT_DIR/worktrees 目錄中都有一個私有子目錄。私有子目錄的名稱通常是連結工作樹路徑的基底名稱,可能後綴一個數字以使其唯一。例如,當 $GIT_DIR=/path/main/.git 時,命令 git worktree add /path/other/test-next next 會在 /path/other/test-next 中建立連結工作樹,並建立一個 $GIT_DIR/worktrees/test-next 目錄(或如果 test-next 已被佔用則為 $GIT_DIR/worktrees/test-next1)。

在連結工作樹內,$GIT_DIR 被設定為指向此私有目錄(例如範例中的 /path/main/.git/worktrees/test-next),而 $GIT_COMMON_DIR 被設定為指向回主工作樹的 $GIT_DIR(例如 /path/main/.git)。這些設定是在位於連結工作樹頂層目錄的 .git 檔案中進行的。

透過 git rev-parse --git-path 進行的路徑解析會根據路徑使用 $GIT_DIR$GIT_COMMON_DIR。例如,在連結工作樹中,git rev-parse --git-path HEAD 返回 /path/main/.git/worktrees/test-next/HEAD(而不是 /path/other/test-next/.git/HEAD/path/main/.git/HEAD),而 git rev-parse --git-path refs/heads/master 使用 $GIT_COMMON_DIR 並返回 /path/main/.git/refs/heads/master,因為引用是在所有工作樹之間共享的,除了 refs/bisectrefs/worktreerefs/rewritten 之外。

有關更多資訊,請參閱 gitrepository-layout[5]。經驗法則是在需要直接存取 $GIT_DIR 內部的內容時,不要對路徑屬於 $GIT_DIR 還是 $GIT_COMMON_DIR 做任何假設。使用 git rev-parse --git-path 來獲取最終路徑。

如果您手動移動連結工作樹,您需要更新該項錄中的 gitdir 檔案。例如,如果連結工作樹被移動到 /newpath/test-next,且其 .git 檔案指向 /path/main/.git/worktrees/test-next,則更新 /path/main/.git/worktrees/test-next/gitdir 以引用 /newpath/test-next。更好的做法是執行 git worktree repair 以自動重新建立連接。

為了防止 $GIT_DIR/worktrees 項目被修剪(這在某些情況下很有用,例如當該項目的工作樹存放在可攜式裝置上時),請使用 git worktree lock 命令,這會在該項目的目錄中新增一個名為 locked 的檔案。該檔案以純文字包含原因。例如,如果連結工作樹的 .git 檔案指向 /path/main/.git/worktrees/test-next,那麼名為 /path/main/.git/worktrees/test-next/locked 的檔案將防止 test-next 項目被修剪。詳情請參閱 gitrepository-layout[5]

當啟用 extensions.worktreeConfig 時,設定檔 .git/worktrees/<id>/config.worktree 會在 .git/config 之後被讀取。

列表輸出格式

worktree list 命令有兩種輸出格式。預設格式在單行中顯示詳細資訊並分欄位顯示。例如:

$ git worktree list
/path/to/bare-source            (bare)
/path/to/linked-worktree        abcd1234 [master]
/path/to/other-linked-worktree  1234abc  (detached HEAD)

該命令還會根據每個工作樹的狀態顯示標註。這些標註是:

  • locked,如果工作樹已鎖定。

  • prunable,如果工作樹可以透過 git worktree prune 修剪。

$ git worktree list
/path/to/linked-worktree    abcd1234 [master]
/path/to/locked-worktree    acbd5678 (brancha) locked
/path/to/prunable-worktree  5678abc  (detached HEAD) prunable

對於這些標註,可能還會提供原因,這可以在詳細模式 (verbose) 下看到。標註接著會移動到下一行縮排,後跟額外資訊。

$ git worktree list --verbose
/path/to/linked-worktree              abcd1234 [master]
/path/to/locked-worktree-no-reason    abcd5678 (detached HEAD) locked
/path/to/locked-worktree-with-reason  1234abcd (brancha)
	locked: worktree path is mounted on a portable device
/path/to/prunable-worktree            5678abc1 (detached HEAD)
	prunable: gitdir file points to non-existent location

請注意,如果有額外資訊,標註會移至下一行,否則它會與工作樹本身保持在同一行。

機器友善格式 (Porcelain Format)

機器友善格式每個屬性佔一行。如果給出了 -z,則行以 NUL 而非換行符結束。屬性以標籤和值列出,中間用單個空格分隔。布林屬性(如 baredetached)僅列出標籤,且僅在值為 true 時存在。某些屬性(如 locked)可能僅列出標籤,也可能根據是否有原因而帶有值。工作樹的第一個屬性始終是 worktree,空行表示記錄結束。例如:

$ git worktree list --porcelain
worktree /path/to/bare-source
bare

worktree /path/to/linked-worktree
HEAD abcd1234abcd1234abcd1234abcd1234abcd1234
branch refs/heads/master

worktree /path/to/other-linked-worktree
HEAD 1234abc1234abc1234abc1234abc1234abc1234a
detached

worktree /path/to/linked-worktree-locked-no-reason
HEAD 5678abc5678abc5678abc5678abc5678abc5678c
branch refs/heads/locked-no-reason
locked

worktree /path/to/linked-worktree-locked-with-reason
HEAD 3456def3456def3456def3456def3456def3456b
branch refs/heads/locked-with-reason
locked reason why is locked

worktree /path/to/linked-worktree-prunable
HEAD 1233def1234def1234def1234def1234def1234b
detached
prunable gitdir file points to non-existent location

除非使用 -z,否則鎖定原因中任何「不尋常」的字元(如換行符)都會被轉義,並且整個原因會按照設定變數 core.quotePath 的說明加引號(請參閱 git-config[1])。例如:

$ git worktree list --porcelain
...
locked "reason\nwhy is locked"
...

範例

您正處於重構階段,您的老闆進來並要求您立即修復某些問題。您通常可能會使用 git-stash[1] 來暫時儲存您的更改,但是,您的工作樹目前處於非常混亂的狀態(有新增、移動和移除的檔案,以及散落各處的其他零碎檔案),您不想冒險干擾其中的任何內容。相反,您建立一個臨時連結工作樹來進行緊急修復,完成後將其移除,然後恢復之前的重構工作。

$ git worktree add -b emergency-fix ../temp master
$ pushd ../temp
# ... hack hack hack ...
$ git commit -a -m 'emergency fix for boss'
$ popd
$ git worktree remove ../temp

組態設定 (CONFIGURATION)

本節中此行以下的內容是從 git-config[1] 文件中選擇性包含的。內容與該處找到的內容相同

worktree.guessRemote

如果未指定分支且未使用 -b-B--detach,則 git worktree add 預設從 HEAD 建立一個新分支。如果 worktree.guessRemote 設定為 true,worktree add 會嘗試尋找名稱唯一匹配新分支名稱的遠端追蹤分支。如果存在這樣的分支,它將被檢出並設定為新分支的「上游」。如果找不到相符項,它將退而求其次從當前 HEAD 建立一個新分支。

worktree.useRelativePaths

使用相對路徑(當為 "true" 時)或絕對路徑(當為 "false" 時)連結工作樹。這對於儲存庫和工作樹可能在不同位置或環境之間移動的設置特別有用。預設為 "false"。

請注意,將 worktree.useRelativePaths 設定為 "true" 意味著啟用 extensions.relativeWorktrees 設定(參見 git-config[1]),因此與舊版本的 Git 不相容。

錯誤 (BUGS)

一般而言,多重檢出仍處於實驗階段,且對子模組的支持不完整。不建議對超級專案 (superproject) 進行多重檢出。

GIT

git[1] 套件的一部分