一个 git 工作树是否支持多个分支?

5
根据文档,每个git worktree仅服务于一个branch(如dev/feature/prod等)。但是,我认为每个分支都有自己的worktree并不合理,因为这会创建许多文件夹,并且在某些时候可能会令人困惑。
一个git worktree是否可以支持多个branches?例如,所有属于feature的分支,然后根据需要切换到相关的分支。这样做是否正确?

你能指出Git工作树文档中哪里说工作树只服务于一个分支吗? - jthill
git worktree旨在作为临时措施,当您正在处理某些事情并需要快速处理其他事情时使用。它不是您常规工作流程的一部分;每个分支都不应该有自己的worktree。请参见文档中的示例 - Schwern
在一个添加的工作树中,可以从一个分支切换到另一个分支。但正如Schwern所指出的那样,这并不是真正预期的使用模式——只是像jthill所说的那样,它没有被禁止,在Git中,任何未明确禁止的操作都被默认支持。 - torek
4个回答

6

git worktree 创建一个新的检出,它共享您现有的本地仓库。它有自己的 HEAD,跟踪当前检出的提交,以及自己的暂存区用于构建提交。其主要目的是能够在不克隆整个仓库或隐藏更改的情况下同时处理多个分支。

工作树基本上像任何其他检出一样工作。您可以切换到任何分支,除非它已经被另一个工作树检出。您可以运行 git-bisect。您可以变基。

工作树不必为新分支,它可以是现有分支。 git worktree add ../temp master 将创建一个检出了 master 分支的工作树。

只有在打算同时处理多个分支时才需要创建工作树。例如,您正在处理一个功能并且有许多未提交的更改,但突然出现了一个紧急修复。您可以为该修复创建一个工作树,在工作树中进行修复,然后返回到原始功能工作。或者您想针对旧版本测试某些内容,您可以创建一个工作树并检出旧版本。

良好的开发流程不需要您同时处理多个分支。


如果我的主.gitA/,针对分支A,在文件夹B/中有一个B工作树。当我在B/中时,我是否仍然可以从A分支挑选提交?在B工作树中的git log仅显示来自B分支的提交,并且在我尝试挑选明显未知的提交时发出投诉。 编辑:在B/内执行git fetch origin A:A似乎会使B工作树了解A分支。 - Eric Duminil

2

Schwern写道:

你可以切换到任何你喜欢的分支,除非它已被另一个工作树检出。你可以运行git-bisect。你可以rebase。

但是... 如果你当前的工作树正在进行二分查找或变基过程中,就不应该切换分支。

而在Git 2.38之前这并没有强制执行。

在Git 2.38(2022年第三季度)中引入了一个辅助工具,用于判断一个分支是否已经在被处理中(因此不应在工作树中新建检出),该工具的性能比现有的find_shared_symref()要好得多,用来取代后者的许多用法。

查看提交 4b6e18f提交 b489b9d提交 12d47e3提交 d2ba271提交 31ad6b6(2022年6月14日)由Derrick Stolee (derrickstolee)
查看提交 9bef0b1提交 b2463fc(2022年6月18日)由Jeff King (peff)
(由Junio C Hamano -- gitster --合并于提交 c2d0109,2022年7月11日)

branch:检查分支的二分和变基

签名作者:Derrick Stolee

前一个更改中添加了branch_checked_out()助手,但它使用了过于简化的视图来检查分支是否被检出。
它只关注HEAD symref,而忽略了二分或变基是否正在进行。

教会branch_checked_out()检查这些情况,并添加测试以确保我们将来不会丢失此功能。

现在有了这个测试覆盖,我们可以安全地重构validate_new_branchname()以使用branch_checked_out()

请注意,在调用wt_status_check_*()之后,我们需要在'state.branch'之前添加"refs/heads/"。
我们还需要复制wt->path,以防止在调用结束时该值被释放。

在正在进行变基(或二分)的工作树中更改分支将导致以下结果:
 cannot force update the branch <abranch> checked out at <worktree path>

在Git 2.42(2023年第三季度)中,"git branch -f X"(man)用于重新指向分支X时,即使分支X没有被检出,而是正在进行二分或变基操作,也会提示分支X在另一个工作树中被检出。
该消息已经重新表述为分支正在"使用中"。
查看提交 4970bed(2023年7月21日)由Junio C Hamano(gitster完成。
(由Junio C Hamano -- gitster --合并于提交 65e25ae,2023年8月4日)

branch:更新消息以拒绝操作正在使用的分支

协助者:Josh Sref

"git branch -f"(man) 命令可能拒绝强制更新另一个工作树中使用的分支。 最初这种行为的原因是,在不对该工作树中的索引和工作树文件进行匹配更改的情况下,更新在另一个工作树中已检出的分支将导致用户非常困惑。 "git diff"(man) HEAD 将不再提供有用的补丁,因为 HEAD 是与该工作树中的索引和工作树基于的提交无关的,例如。
如今,相同的机制还保护正在进行 rebase 或 bisect 的分支,并且当我们决定保护正在进行其他操作的分支时,相同机制预计也是添加更多检查的正确位置。 然而,我们忘记重新思考消息,最初的消息说我们拒绝触碰该分支,因为它在其他地方“已检出”,当 d2ba271 ("branch: check for bisects and rebases",2022-06-14,Git v2.38.0-rc0 -- merge 列在 batch #1 中) 开始保护正在进行 rebase 或 bisect 的分支时。
检查的精神始终是我们不希望干扰其他工作树中使用的相同分支的使用。 让我们稍微修改一下消息,将分支称为“被”另一个工作树使用,而不是“已检出”。
我们可以教导 branch.c:prepare_checked_out_branches() 函数记住它决定保护特定分支的原因(例如,是因为已检出?正在进行 bisect?还是其他原因?),除了该分支在哪个工作树中使用,然后在错误消息中使用该信息,例如 "you cannot force update this branch because it is being bisected in the worktree X" 等等,但这样的额外复杂性是否值得存疑。 消息已经告诉了用户涉及的工作树所在的目录,并且对于那些感到好奇的用户来说,找出其状态只需执行简单的 "chdir"。 所以我们暂时不做这个修改。

不再:

checked out at ...

但是相反的是:
used by worktree at ...

Git 2.43继续这项工作。 - VonC

2
如果你执行git init或者git clone <args>,你会得到一个带有一个工作树的仓库。[1] git init创建的仓库只有默认分支可用,并且该分支也被检出到主工作树中。
从那里,你可以创建任意数量的分支。但是最多只能有一个分支被检出(你也可以处于“分离头指针”模式,其中没有分支被检出)。
因此,每个分支都没有自己的工作树;仓库包含所有分支,每个工作树在任何给定时间最多只能有一个分支被检出。[3]

在编写代码时,你总是有一个工作树

除非你在“裸”仓库中工作,否则你总是在一个工作树中工作。简单的git init将为你提供一个工作树。
我们还没有使用git worktree add。然而,问题的答案源于基本的仓库管理。

但是,除非您有多个工作树,否则大多数情况下谈论“工作树”要么是多余的,要么是无用的;您可以只说“我的存储库”。

您是否需要多个工作树?

工作树和分支是非常不同的东西。但是它们有一个共同点:您拥有多少个完全取决于您和您的工作流程。

比如我正在为自己的私人笔记创建一个存储库。我可能只使用默认分支。为什么我需要比默认分支更多的分支呢?

同样的原则适用于工作树。您是否需要:

  • 同时处理多个任务而不必每次更改工作树(每个工作树都是唯一的)[4]
  • 在另一个工作树中的分支上工作时,在提交上运行长时间的进程(例如测试套件)
  • 也许还有其他在man git worktrees中提到的用例

如果不需要,则您可能永远不需要使用git-worktree(1)。

多个工作树

最后,我们可以创建一个以上的工作树:

$ git worktree add -b quickfix ../wip
Preparing worktree (new branch 'quickfix')
HEAD is now at 7da80ac i
$ git worktree list
/home/kristoffer/programming/just-init  7da80ac [main]
/home/kristoffer/programming/wip        7da80ac [quickfix]

两个工作树。我们有多少分支?我们至少有两个,但也可能有两千个,因为我们不必为每个分支创建一个工作树。

没有分支的工作树(分离头)

就像您的“主工作树”一样,其他的(“链接”的工作树)也不需要检出分支:

$ git worktree add --detach ../test
Preparing worktree (detached HEAD 7da80ac)
HEAD is now at 7da80ac i

这可能看起来像是一个学术观点,但我认为不是:检查分支顶部的任何提交,在单独的工作树中运行测试套件,然后(在运行测试套件时)继续在原始(可能是main)工作树中对该分支进行修改,这样做非常有用。[5]
事实上,这是使用 Michael Haggerty 的酷程序git-test时推荐的方法:

git testgit worktree非常配合。保留第二个工作树,并将其用于在工作时持续测试当前分支:

git worktree add --detach ../test HEAD cd ../test git test run master..mybranch

注释

  1. $ mkdir just-init && cd just-init
    $ git init
    $ git worktree list
    /home/kristoffer/programming/just-init  0000000 [main]
    
  2. init.defaultBranch 如果设置了,则使用该值;否则使用 master

  3. 一个分支不能同时在两个不同的工作树中检出。

  4. 实际上,您切换到使用 cd 而不是 git checkoutgit switch

  5. 请记住,任何给定分支不能同时在多个工作树中检出。因此,我们必须“分离”。

  6. 来源


1
有趣的工作树观点(我在这里在2015年介绍了Git 2.5+)。已点赞。 - VonC

1

来自 https://git-scm.com/docs/git-worktree

一个 git 仓库可以支持多个工作树,允许您同时检出多个分支。使用 git worktree add 命令,将新的工作树与仓库关联。这个新的工作树被称为“关联工作树”,而不是由 git-init 或 git-clone 准备的“主工作树”。

如果要在工作树中添加新分支,则需要编写:
git worktree add <path> <branch_name>

例如:

git checkout -B new_branch
git checkout main
git worktree add ./new_branch new_branch

要移除它: git worktree remove 这是它的样子: 在树形视图中 在路径参数中,您可以传递任何内容。因此,您可以根据需要管理分支,例如,您可以创建一个文件夹,仅存储具有错误修复或功能的分支。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接