Git 从现有远程分支添加一个工作树

Git add a worktree from existing remote branch

在我的远程仓库中有 3 个分支(master 和 2 个 long 运行 分支):

master  #the common features are here like Core, DAL,...
north   #customized for A company (long-running)
razavi  #customized for B company (long-running)

在我办公室的电脑上,我为那些 northrazavi 分支添加了 2 worktree

$ git worktree list
C:/Source/nis     a6fb6e1 [master]
C:/Source/north   ebc7670 [north]
C:/Source/razavi  eed08a2 [razavi]

到目前为止一切正常,我也决定在家里处理这个项目,但是在我的家用电脑上,当我尝试为这两个分支添加工作树时,出现错误:

$git worktree add -b north ../north north
fatal: A branch named 'north' already exists.

我删除了 -b 开关以不添加新分支,但它也不起作用。

如何从不是本地而是远程的现有分支添加 worktree

TL;DR:您可能想要 git worktree add ../north north

首先,提醒(或其他遇到此问题的信息):git worktree add 想同时创建一个新的工作树 ,确保这个新的工作树使用的是与其他所有工作树不同的 不同的分支名称 。这是因为,虽然每个添加的工作树都有自己的索引和 HEAD,但 HEAD 文件最终 共享 共享存储库中的底层分支指针。拥有两个具有独立索引对象但具有相同底层分支的不同工作树会导致用户处理一些棘手的问题。与其试图找出 如何 来处理这些问题——通过教育程序员或提供工具来处理这些问题——git worktree 只是完全禁止这种情况。

因此,在创建新的工作树时,通常希望创建一个 new 分支名称。根据定义,新分支名称自动不同于每个现有分支名称:

$ git checkout -b newbranch
Switched to a new branch 'newbranch'
$ git checkout -b newbranch
fatal: A branch named 'newbranch' already exists.

这看起来很自然:没有人对此感到惊讶。

您 运行ning git worktree add 的方式与 git checkout -b 类似,只是检出发生在新添加的工作树中。但是您已经有一个名为 north.

的分支

如果现有的 north 分支没有用,您可以将其删除。现在您没有名为 north 的本地分支,您可以创建一个新分支。

如果这个现有的 north 分支 有用,请不要删除它!如果它已经在某个现有的工作树中签出,请移至该工作树并在那里进行处理。如果它没有在一些现有的工作树中检出,你可以创建一个新的工作树确实检出;您只需要避免使用 -b 标志(以及相应的分支名称):

git worktree add ../north north

请注意,当您创建 new 分支时,您不必重复自己:

git worktree add -b newbranch ../path

将在 ../path 中创建一个新的工作树,并使用 git checkout -b newbranch 来填充它。您只需要在以下情况下使用分支名称:

  1. 您没有使用 -b,并且
  2. 路径参数不以分支名称结尾。

例如,如果您想在路径 ../zorg 的新工作树中检出现有分支 zorg,您可以 运行:

git worktree add ../zorg

这里,由于既没有-b zorg也没有final参数,Git通过../zorg的最后一部分计算出分支名称,当然只是zorg,因此这会尝试将现有分支 zorg 检出到新的工作树中。

对于这个问题,worktree add 确实需要一个 --checkout 开关来做到这一点:

$ git worktree add --checkout ../north north
$ git worktree add --checkout ../razavi razavi

除了git worktree add --checkout,Git 2.16 (Q1 2018) 将提出另一个替代方案:

git worktree add”确定从何处创建分支以及在新工作树中检出的方式已更新了一点。

参见 commit e92445a, commit 71d6682 (29 Nov 2017), and commit 4e85333, commit e284e89, commit c4738ae, commit 7c85a87 (26 Nov 2017) by Thomas Gummerer (tgummerer)
(由 Junio C Hamano -- gitster -- in commit 66d3f19 合并,2017 年 12 月 19 日)

add worktree.guessRemote config option

Some users might want to have the --guess-remote option introduced in the previous commit on by default, so they don't have to type it out every time they create a new worktree.

Add a config option worktree.guessRemote that allows users to configure the default behaviour for themselves.

documentation for git config 现在是:

worktree.guessRemote::

With add, if no branch argument, and neither of -b nor -B nor --detach are given, the command defaults to creating a new branch from HEAD.
If worktree.guessRemote is set to true, worktree add tries to find a remote-tracking branch whose name uniquely matches the new branch name.

  • If such a branch exists, it is checked out and set as "upstream" for the new branch.
  • If no such match can be found, it falls back to creating a new branch from the current HEAD.

实际上,Git 2.21(2019 年第 1 季度)阐明了此选项的文档,该选项直接与 "With add" 一起使用,而没有解释 add 是 "git worktree".

参见 commit b4583d5 (23 Dec 2018) by Eric Sunshine (sunshineco)
(由 Eric Sunshine -- sunshineco -- in commit b4583d5 合并,2018 年 12 月 28 日)

The documentation 现在读作:

worktree.guessRemote:

If no branch is specified and neither -b nor -B nor --detach is used, then git worktree add defaults to creating a new branch from HEAD.

除了“猜测远程分支”,正如我,Git 2.18 (Q2 2018) 将提供一个新功能:
git worktree add”学会了检查现有分支。

参见 commit f60a7b7, commit 6427f87, commit 2c27002, commit d861d34 (24 Apr 2018) by Thomas Gummerer (tgummerer)
帮助:Eric Sunshine (sunshineco).
(由 Junio C Hamano -- gitster -- in commit 10174da 合并,2018 年 5 月 23 日)

worktree: teach "add" to check out existing branches

Currently 'git worktree add <path>' creates a new branch named after the basename of the path by default.
If a branch with that name already exists, the command refuses to do anything, unless the '--force' option is given.

However we can do a little better than that, and check the branch out if it is not checked out anywhere else.
This will help users who just want to check an existing branch out into a new worktree
, and save a few keystrokes.

As the current behaviour is to simply 'die()' when a branch with the name of the basename of the path already exists, there are no backwards compatibility worries here.

We will still 'die()' if the branch is checked out in another worktree, unless the --force flag is passed.

documentation now states:

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

If <commit-ish> is omitted and neither -b nor -B nor --detach used, then, as a convenience, the new worktree is associated with a branch (call it <branch>) named after $(basename <path>).

  • If <branch> doesn't exist, a new branch based on HEAD is automatically created as if -b <branch> was given.
  • If <branch> does exist, it will be checked out in the new worktree, if it's not checked out anywhere else, otherwise the command will refuse to create the worktree (unless --force is used).

Git 2.30(2021 年第一季度)修复了“git worktree add"(man) 子命令中带有两个占位符的错误消息的表述。

参见 commit b86339b (20 Nov 2020) by Matheus Tavares (matheustavares)
(由 Junio C Hamano -- gitster -- in commit f73ee0c 合并,2020 年 11 月 30 日)

worktree: fix order of arguments in error message

Signed-off-by: Matheus Tavares
Reviewed-by: Eric Sunshine

git worktree add(man) (without --force) errors out when given a path that is already registered as a worktree and the path is missing on disk.
But the cmd and path strings are switched on the error message.
Let's fix that.

这是关于错误信息的:

<path> is a missing but locked worktree
use '<cmd> -f -f' to override, or 'unlock' and 'prune' or 'remove' to clear

或者:

<path> is a missing but already registered worktree
use '<cmd> -f' to override, or 'unlock' and 'prune' or 'remove' to clear

来自 :

It doesn't work! I try git worktree add ../north north, and as I said it gives me an error fatal:

'north' is already checked out at 'C:/Source/nis'

该错误消息现在应该更清楚了(2022 年第一季度)。

使用 Git 2.35(2022 年第一季度),“git worktree add"(man) 向标准输出流显示“准备工作树”消息,但是当它失败时,消息来自 die() 转到标准错误流。
根据 stdio 流在程序结束时刷新的顺序,这导致了混乱的输出。
已通过将所有冗长的消息发送到标准错误流来更正此问题。

参见 commit b502524commit da8fb6b(2021 年 12 月 2 日)Eric Sunshine (sunshineco)
(由 Junio C Hamano -- gitster -- in commit 986eb34 合并,2021 年 12 月 15 日)

worktree: send "chatty" messages to stderr

Reported-by: Baruch Burstein
Signed-off-by: Eric Sunshine

The order in which the stdout and stderr streams are flushed is not guaranteed to be the same across platforms or libc implementations.
This lack of determinism can lead to anomalous and potentially confusing output if normal (stdout) output is flushed after error (stderr) output.
For instance, the following output which clearly indicates a failure due to a fatal error:

% git worktree add ../foo bar
Preparing worktree (checking out 'bar')
fatal: 'bar' is already checked out at '.../wherever'

has been reported on Microsoft Windows to appear as:

% git worktree add ../foo bar
fatal: 'bar' is already checked out at '.../wherever'
Preparing worktree (checking out 'bar')

which may confuse the reader into thinking that the command somehow recovered and ran to completion despite the error.

This problem crops up because the "chatty" status message "Preparing worktree" is sent to stdout, whereas the "fatal" error message is sent to stderr.

A common practice in Git is for "chatty" messages to be sent to stderr.
Therefore, a more appropriate fix is to adjust git-worktree to conform to that practice by sending its chatty messages to stderr rather than stdout as is currently the case.

There may be concern that relocating messages from stdout to stderr could break existing tooling, however, these messages are already internationalized, thus are unstable.
And, indeed, the "Preparing worktree" message has already been the subject of somewhat significant changes in 2c27002 ("worktree: improve message when creating a new worktree", 2018-04-24, Git v2.18.0-rc0 -- merge listed in batch #6).
Moreover, there is existing precedent, such as 68b939b ("clone: send diagnostic messages to stderr", 2013-09-18, Git v1.8.5-rc0 -- merge) which likewise relocated "chatty" messages from stdout to stderr for git-clone.