51

我最近发现了这个git worktree命令:

新的工作目录链接到当前存储库,共享除工作目录特定文件(如 HEAD、索引等)之外的所有内容。

但文档也表明

…对子模块的支持不完整。不建议对一个超级项目进行多次检查。

没有进一步解释出了什么问题。

有人可以告诉我预期的问题吗?例如,如果我将这种方式生成的单独工作树仅用于不影响子模块的更改,我会好吗?

4

1 回答 1

42

Commit a83a66a对此非常清楚:

git-submodule.sh预计$GIT_DIR/config是每个工作树,至少对于submodule.* part.
在这里,我认为我们有两个选择:

  • 要么更新为除了 (共享)之外config.c还读取 (每个工作树)并将特定于工作树的变量存储在新位置,$GIT_DIR/config.worktree$GIT_DIR/config
  • 或直接从(每个工作树)更新git-submodule.sh为读/写。submodule.*$GIT_DIR/config.submodule

这些需要时间来正确解决。同时,提醒用户不要在子模块上下文中使用多个工作树。

更一般地说,将这些子模块放在哪里?

有几个选项:

  • 您可能希望将$SUB存储库保存在外部的其他地方(可能在中心位置)$SUPER。对于嵌套子模块也是如此,其中一个超级项目可能是另一个超级项目的子模块。
  • 您可能希望将所有$SUBrepos 保存在$SUPER/modules(或其他地方$SUPER
  • 我们甚至可以进一步推动它并将所有$SUBrepos 合并到$SUPER 而不是单独存储它们。但这至少需要启用 ref 命名空间。

此提交是提交 df56607的答案。


从 git 用户的角度来看,这意味着 agit submodule update --init --recursive不知道在哪里签出子模块。
它们是在所有工作树中复制的,还是集中在某个地方?这还没有正式指定。


一年后(使用 git 2.9),clacke在评论中添加

混乱已经解决,但不是以最佳方式。
据我所知,子模块现在工作正常,但是每个工作树都有自己的一组子模块 repos(在 下motherrepo.git/worktree/<worktreename>/modules/<submodule>,所以如果你有一个很大的子模块,你将面临一些严重的磁盘使用。


用于处理子树中的子模块的 Git 别名

别名git wtas需要在git wta全局范围内定义,或者至少为所有涉及的 repos 定义。不包括保修。如果您的路径名中有空格,您最喜欢的宠物可能会感染痛苦。

它期望您的存储库中的结构类似于启动子模块的非裸存储库中的结构,因此如果您有一个裸存储库,则必须模仿该设置。具有名称(不是路径)的子模块foo进入<your-.git-directory>/modules/foo(不是.../foo.git)。如果 repo 中不存在某些模块,它不会崩溃,它只是跳过它。

有改进的余地。它不处理子模块中的子模块,它只向下一层。将子模块调用更改为调用可能会起作用,但我还没有验证这一点。git wtagit wtas

——咔嚓


另请参阅git worktree move(使用 Git 2.17+,2018 年第二季度)。


实际上,在 Git 2.21(2019 年第一季度)之前,当涉及到子模块时,“ git worktree remove”和“ git worktree move”拒绝工作。
这已被放松以忽略未初始化的子模块

请参阅Nguyễn Thái Ngọc Duy ( ) 的提交 00a6d4d(2019 年 1 月 5 日(由Junio C Hamano 合并 -- --726f89c 提交中,2019 年 1 月 18 日)pclouds
gitster

worktree:允许(重新)移动具有未初始化子模块的工作树

未初始化的子模块没有什么值得我们担心的。它们只是 SHA-1。
在这种情况下让“ worktree remove”和“ worktree move”继续,这样人们仍然可以在 repos 上使用多个工作树,其中包含从未填充的可选子模块,就像通过脚本签出时sha1collisiondetection一样。git.gitdoc-diff

请注意,对于“ worktree remove”,用户可能会初始化子模块(*),进行一些提交(但不推送),然后取消初始化它。
此时,子模块未填充,但宝贵的新提交仍在:

$GIT_COMMON_DIR/worktrees/<worktree>/modules/<submodule>

目录,我们不应该允许删除工作树,否则我们将永远丢失这些提交。
添加了新的目录检查以防止这种情况发生。

( *) 是的,无论如何,他们都被搞砸了,因为“ git submodule”会添加submodule.*$GIT_COMMON_DIR/config它在多个工作树之间共享。
但这并不意味着我们让他们被搞得更糟。


在 Git 2.25(2020 年第一季度)之前,如果您submodule.recurse设置了配置选项,则git worktree add在具有已初始化子模块的超级项目中发布将失败。

请参阅Philippe Blain ( ) 的提交 4782cf2ab6(2019 年 10 月 27 日(由Junio C Hamano 合并 -- --726f89c 提交中,2019 年 12 月 1 日)phil-blain
gitster

worktree: 教 " add" 忽略submodule.recurse配置

" worktree add" 内部调用 " reset --hard",但如果 submodule.recurse设置了,reset则尝试递归到初始化的子模块,这使得start_command尝试 cd 进入不存在的子模块路径并死掉。

通过确保对resetin " worktree add" 的调用不会递归来解决此问题。

早期版本的解决方法是暂时停用配置:

git -c submodule.recurse=0 worktree add ...

在 Git 2.26(2020 年第二季度)之前,在带有初始化子模块的存储库的链接工作树中发出git checkout --recurse-submodules(或reset)会错误地移动工作树的 git 存储库中的子模块HEAD ,并破坏链接工作树中子模块的工作目录:read-tree.git

请参阅Philippe Blain ( ) 的提交 a9472afb63(2020 年 1 月 21 日(由Junio C Hamano 合并 -- --ff5134b2 提交中,2020 年 5 月)phil-blain
gitster

submodule.c: 使用get_git_dir()而不是get_git_common_dir()

自从 df56607 (git-common-dir: make " modules/" per-working-directory directory, 2014-11-30) 以来,链接工作树中的子模块被克隆到$GIT_DIR/modules, 即$GIT_COMMON_DIR/worktrees/<name>/modules.

但是,当工作树更新程序命令时并没有遵循这个约定 checkoutreset并且read-tree学会了递归到子模块中。具体来说, submodule.c::submodule_move_head在 6e3c159 中引入(更新子模块:add submodule_move_head,2017-03-14)和submodule.c::submodule_unset_core_worktree,(重新)在 898c2e6 中引入(子模块:unset core.worktree if no working tree is present, 2018-12-14)使用get_git_common_dir()而不是get_git_dir() 获取子模块存储库的路径。

这意味着,例如,git checkout --recurse-submodules <branch>链接工作树中的 ' ' 将正确检出<branch>,在记录的提交处分离子模块的 HEAD<branch>并更新子模块工作树,但将移动的子模块 HEAD 是 in $GIT_COMMON_DIR/modules/<name>/,即子模块存储库的主要超级项目工作树。它还将重写链接工作树的子模块工作树中的 gitfile 以指向$GIT_COMMON_DIR/modules/<name>/. 这会导致主超级项目工作树的子模块工作树中的状态不正确(并且令人困惑!)。

此外,如果切换到子模块不存在的提交, submodule_unset_core_worktree将被调用,并将错误地core.wortree从主超级项目工作树中子模块的配置文件中删除 ' ', $GIT_COMMON_DIR/modules/<name>/config.

get_git_dir() 通过使用和构建子模块存储库submodule_move_head的路径来解决此问题submodule_unset_core_worktree

于 2015-08-07T07:33:52.290 回答