簡體中文 ▾ 主題 ▾ 最新版本 ▾ git-worktree 最後更新於 2.52.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”。

這個新的 worktree 被稱為“連結工作樹”(linked worktree),與 git-init[1]git-clone[1] 準備的“主工作樹”(main worktree)相對。一個儲存庫有一個主工作樹(如果它不是裸儲存庫),以及零個或多個連結工作樹。當您完成一個連結工作樹後,可以使用 git worktree remove 命令將其刪除。

最簡單的形式是,git worktree add <path> 會自動建立一個新分支,其名稱為 <path> 的最後一個元件,這在您計劃處理新主題時很方便。例如,git worktree add ../hotfix 會建立一個名為 hotfix 的新分支,並將其檢出到路徑 ../hotfix。如果想在新工作樹中處理現有分支,請使用 git worktree add <path> <branch>。另一方面,如果您只是想進行一些實驗性更改或進行測試而不干擾現有開發,通常會建立一個不與任何分支關聯的“臨時”工作樹。例如,git worktree add -d <path> 會建立一個新的工作樹,其 HEAD 指標與當前分支處於同一提交,但處於分離狀態。

如果工作樹未使用 git worktree remove 命令被刪除,那麼與之關聯的管理檔案(位於儲存庫中,請參閱下面的“詳細資訊”)最終會被自動刪除(請參閱 git-config[1] 中的 gc.worktreePruneExpire),或者您可以在主工作樹或任何連結工作樹中執行 git worktree prune 來清理任何過時的管理檔案。

如果連結工作樹的工作樹儲存在行動式裝置或網路共享上,而該裝置或共享並非始終掛載,您可以透過發出 git worktree lock 命令來阻止其管理檔案被刪除,還可以選擇指定 --reason 來解釋鎖定工作樹的原因。

命令

add <path> [<commit-ish>]

<path> 建立一個工作樹,並將 <commit-ish> 檢出到其中。新的工作樹連結到當前儲存庫,共享除每個工作樹特有的檔案(如 HEADindex 等)之外的所有內容。為了方便起見,<commit-ish> 可以是裸字串 “-”,它等同於 @{-1}

如果 <commit-ish> 是一個分支名(稱之為 <branch>)且未找到,同時未使用 -b-B--detach,但恰好在一個遠端儲存庫(稱之為 <remote>)中存在同名的跟蹤分支,則將其視為等同於

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

如果分支存在於多個遠端儲存庫中,並且其中一個遠端儲存庫由 checkout.defaultRemote 配置變數命名,我們將使用該遠端儲存庫進行歧義消除,即使 <branch> 在所有遠端儲存庫中並不唯一。將其設定為例如 checkout.defaultRemote=origin,以便在 <branch> 存在歧義但存在於 origin 遠端儲存庫時,始終從中檢出遠端分支。有關更多資訊,請參閱 git-config[1] 中的 checkout.defaultRemote

如果省略了 <commit-ish> 並且沒有使用 -b-B--detach,那麼為了方便起見,新的工作樹將關聯一個名為 <branch> 的分支(名稱源自 <path> 的基本名稱)。如果 <branch> 不存在,則會建立一個基於 HEAD 的新分支,就像使用了 -b <branch> 命令一樣。如果 <branch> 已經存在,並且沒有在其他地方檢出,則會在新工作樹中檢出該分支;否則,命令將拒絕建立工作樹(除非使用了 --force)。

如果省略了 <commit-ish>,並且沒有使用 --detach--orphan,並且沒有有效的本地分支(如果指定了 --guess-remote,則也沒有遠端分支),那麼為了方便起見,新的工作樹將關聯一個名為 <branch> 的新未出生分支(如果未使用的 -b-B,則名稱源自 <path> 的基本名稱),就像將 --orphan 選項傳遞給命令一樣。如果儲存庫有遠端並且使用了 --guess-remote,但不存在任何遠端或本地分支,則該命令會失敗並顯示警告,提醒使用者先從其遠端儲存庫進行獲取(或透過使用 -f/--force 來覆蓋)。

list

列出每個工作樹的詳細資訊。主工作樹首先列出,然後是每個連結工作樹。輸出的詳細資訊包括工作樹是否為裸體、當前檢出的修訂版本、當前檢出的分支(如果沒有則為“分離的 HEAD”)、如果工作樹被鎖定則為“locked”、如果工作樹可以透過 prune 命令進行修剪則為“prunable”。

lock

如果工作樹位於行動式裝置或網路共享上,而該裝置或共享並非始終掛載,則鎖定它以防止其管理檔案被自動刪除。這還會阻止其被移動或刪除。可以選擇使用 --reason 指定鎖定的原因。

move

將工作樹移動到新位置。請注意,主工作樹或包含子模組的連結工作樹不能使用此命令移動。(然而,git worktree repair 命令可以在手動移動主工作樹後重新建立與連結工作樹的連線。)

prune

修剪 $GIT_DIR/worktrees 中的工作樹資訊。

remove

移除一個工作樹。只能移除乾淨的工作樹(沒有未跟蹤的檔案,也沒有已跟蹤檔案的修改)。不乾淨的工作樹或包含子模組的工作樹可以使用 --force 命令移除。主工作樹不能被移除。

repair [<path>...]

如果工作樹的管理檔案因外部因素而損壞或過時,則在可能的情況下進行修復。

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

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

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

unlock

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

選項

-f
--force

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

move 命令預設拒絕移動鎖定的工作樹,除非指定兩次 --force。如果目標已分配給另一個工作樹但已丟失(例如,<new-path> 被手動刪除),則 --force 允許移動繼續;如果目標被鎖定,請指定兩次 --force

remove 命令預設拒絕移除不乾淨的工作樹,除非使用 --force。要移除鎖定的工作樹,請指定兩次 --force

-b <new-branch>
-B <new-branch>

在使用 add 命令時,建立一個名為 <new-branch> 的新分支,該分支從 <commit-ish> 開始,並將其檢出到新工作樹中。如果省略了 <commit-ish>,則預設為 HEAD。預設情況下,如果 <new-branch> 已存在,-b 會拒絕建立新分支。-B 會覆蓋此保護措施,將 <new-branch> 重置為 <commit-ish>

-d
--detach

在使用 add 命令時,將新工作樹中的 HEAD 置於分離狀態。請參閱 git-checkout[1] 中的“分離的 HEAD”(DETACHED HEAD)。

--checkout
--no-checkout

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

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

在使用 worktree add <path> 命令並且未指定 <commit-ish> 時,該命令不會從 HEAD 建立新分支,而是會嘗試查詢一個遠端跟蹤分支,其名稱唯一匹配 <path> 的基本名稱。如果找到這樣的分支,則會檢出該分支並將其設定為新分支的“上游”。

也可以透過使用 worktree.guessRemote 配置選項將其設定為預設行為。

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

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

在使用 repair 命令時,即使連結是正確的,如果存在絕對/相對路徑不匹配的情況,也會更新連結檔案。

--track
--no-track

建立新分支時,如果 <commit-ish> 是一個分支,則將其標記為新分支的“上游”。如果 <commit-ish> 是一個遠端跟蹤分支,這會是預設行為。有關詳細資訊,請參閱 git-branch[1] 中的 --track

--lock

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

-n
--dry-run

在使用 prune 命令時,不執行任何刪除操作;僅報告將要刪除的內容。

--orphan

在使用 add 命令時,使新的工作樹和索引為空,並將工作樹與一個名為 <new-branch> 的新未出生分支關聯起來。

--porcelain

在使用 list 命令時,以易於指令碼解析的格式輸出。此格式在 Git 版本之間以及忽略使用者配置的情況下都將保持穩定。建議與 -z 選項結合使用。詳細資訊請參閱下文。

-z

當指定 --porcelain 選項與 list 命令一起使用時,使用 NUL 字元而不是換行符來終止每一行。這使得在工作樹路徑包含換行符時也可以解析輸出。

-q
--quiet

在使用 add 命令時,抑制反饋訊息。

-v
--verbose

在使用 prune 命令時,報告所有移除操作。

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

--expire <time>

在使用 prune 命令時,僅過期使用時間超過 <time> 的未使用的工作樹。

在使用 list 命令時,將舊於 <time> 的丟失工作樹標註為可修剪。

--reason <string>

在使用 lock 命令或 add --lock 命令時,提供工作樹被鎖定的原因說明。

<worktree>

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

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

引用

使用多個工作樹時,某些引用(refs)會在所有工作樹之間共享,而另一些則特定於單個工作樹。一個例子是 HEAD,每個工作樹都不同。本節將介紹共享規則以及如何從一個工作樹訪問另一個工作樹的引用。

一般來說,所有偽引用(pseudo refs)都是每個工作樹獨有的,而所有以 refs/ 開頭的引用都是共享的。偽引用是指直接位於 $GIT_DIR 下而不是 $GIT_DIR/refs 中的引用,例如 HEAD。但也有例外:位於 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.worktree 配置變數存在於通用配置檔案中,並且 extensions.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 如果其值為 core.bare=true,則不應被共享。

  • 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

對於這些註解,還可能提供原因,您可以使用詳細模式檢視。然後,該註解將移動到下一行,並縮排,後面跟著額外的資訊。

$ 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 格式

Porcelain 格式每行顯示一個屬性。如果指定了 -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

配置

本節中以下所有內容均從 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 不相容。

BUG

總體而言,多個檢出仍然是實驗性的,並且對子模組的支援不完整。不建議對超級專案進行多個檢出。

GIT

Git[1] 套件的一部分