English ▾ 主题 ▾ 最新版本 ▾ git-worktree 上次更新于 2.48.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 可以将一个新的工作树与仓库关联,以及额外的元数据,用于区分同一仓库中的不同工作树。工作树以及这些元数据被称为“工作区”。

这个新的工作树被称为“链接工作树”,与 git-init[1]git-clone[1] 准备的“主工作树”相对。一个仓库有一个主工作树(如果它不是裸仓库)和零个或多个链接工作树。当你完成一个链接工作树时,可以使用 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,以便始终从 origin 远程存储库中检出远程分支(如果 <branch> 是模糊的,但在 origin 远程存储库中存在)。 另请参阅 git-config[1] 中的 checkout.defaultRemote

如果省略了 <commit-ish> 并且未使用 -b-B--detach,那么为了方便起见,新的工作树会与一个分支(称之为 <branch>)相关联,该分支以 $(basename <path>) 命名。如果 <branch> 不存在,则会自动创建一个基于 HEAD 的新分支,就好像给出了 -b <branch> 一样。如果 <branch> 确实存在,则它将在新的工作树中检出,如果它未在其他任何地方检出,否则该命令将拒绝创建工作树(除非使用 --force)。

如果省略了 <commit-ish>,既没有使用 --detach,也没有使用 --orphan,并且没有有效的本地分支(或者如果指定了 --guess-remote 则没有远程分支),那么为了方便起见,新的工作树会与一个名为 <branch> 的新未出生的分支相关联(如果既没有使用 -b 也没有使用 -B,则按照 $(basename <path>) 命名),就好像 --orphan 被传递给命令一样。 如果仓库有一个远程仓库并且使用了 --guess-remote,但没有远程或本地分支存在,那么该命令将失败,并显示一个警告,提醒用户首先从其远程仓库获取(或者使用 -f/--force 覆盖)。

list

列出每个工作树的详细信息。 首先列出主工作树,然后列出每个链接的工作树。 输出详细信息包括工作树是否为 bare,当前检出的修订版本,当前检出的分支(如果没有,则为“分离的 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 两次。

除非指定 --force 两次,否则 move 拒绝移动锁定的工作树。 如果目标已分配给其他工作树但已丢失(例如,如果手动删除了 <new-path>),则 --force 允许继续移动; 如果目标被锁定,请使用 --force 两次。

除非使用 --force,否则 remove 拒绝删除不干净的工作树。 要删除锁定的工作树,请指定 --force 两次。

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

使用 add,创建一个名为 <new-branch> 的新分支,从 <commit-ish> 开始,并将 <new-branch> 检出到新的工作目录中。如果省略 <commit-ish>,则默认为 HEAD。默认情况下,如果新分支已存在,-b 会拒绝创建它。 -B 会覆盖此安全措施,将 <new-branch> 重置为 <commit-ish>

-d
--detach

使用 add,在新工作目录中分离 HEAD。请参阅 git-checkout[1] 中的 "DETACHED HEAD"。

--[no-]checkout

默认情况下,add 会检出 <commit-ish>,但是可以使用 --no-checkout 来禁止检出,以便进行自定义,例如配置稀疏检出。请参阅 git-read-tree[1] 中的 "Sparse checkout"。

--[no-]guess-remote

使用 worktree add <path>,如果没有 <commit-ish>,则不会从 HEAD 创建新分支,而是当恰好有一个远程仓库中存在与 <path> 的基本名称匹配的跟踪分支时,将新分支建立在该远程跟踪分支上,并将该远程跟踪分支标记为新分支的“上游”。

也可以使用 worktree.guessRemote 配置选项将此设置为默认行为。

--[no-]relative-paths

使用相对路径或绝对路径(默认)链接工作目录。覆盖 worktree.useRelativePaths 配置选项,请参阅 git-config[1]

使用 repair,如果存在绝对/相对路径不匹配的情况,即使链接正确,也会更新链接文件。

--[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

当使用 list 指定 --porcelain 时,使用 NUL 而不是换行符来终止每一行。这使得在工作目录路径包含换行符时可以解析输出。

-q
--quiet

使用 add,禁止反馈消息。

-v
--verbose

使用 prune,报告所有移除操作。

使用 list,输出有关工作目录的附加信息(请参阅下文)。

--expire <time>

使用 prune,仅过期比 <time> 更旧的未使用的工作目录。

使用 list,如果缺失的工作目录比 <time> 旧,则将其标记为可修剪。

--reason <string>

使用 lockadd --lock,解释工作目录被锁定的原因。

<worktree>

可以通过路径(相对或绝对路径)来标识工作目录。

如果工作目录路径中的最后一个路径组件在工作目录中是唯一的,则可以使用它来标识工作目录。例如,如果您只有两个工作目录,分别位于 /abc/def/ghi/abc/def/ggg,则 ghidef/ghi 足以指向前者工作目录。

REFS

使用多个工作目录时,某些引用在所有工作目录之间共享,但其他引用特定于单个工作目录。一个例子是 HEAD,每个工作目录的 HEAD 都不同。本节介绍共享规则以及如何从一个工作目录访问另一个工作目录的引用。

通常,所有伪引用都是每个工作目录的,所有以 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.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=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/config 之后读取配置文件 .git/worktrees/<id>/config.worktree

列表输出格式

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

请注意,如果附加信息可用,则注释将移动到下一行,否则它将与工作目录本身位于同一行。

瓷器格式

瓷器格式的每一行表示一个属性。如果给出 -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

属于 git[1] 套件的一部分

scroll-to-top