代码之家  ›  专栏  ›  技术社区  ›  cityzz

Git工作树:两个工作树指向同一位置,无法修剪

  •  4
  • cityzz  · 技术社区  · 8 年前

    当我这样做的时候 git worktree list ,显示如下。

    /path/to/workspace  c943d35 [master]
    /path/to/workspace  ef4df56 (detached HEAD)
    

    这是我的工作目录(不是工作树目录)。我不知道这是怎么发生的,也不知道该怎么清理。我试过了 git worktree prune ,但它不会改变任何东西。任何帮助都将不胜感激。非常感谢。

    1 回复  |  直到 8 年前
        1
  •  7
  •   VonC    3 年前

    git worktree -- details 提到:

    每个链接的工作树在存储库中都有一个专用子目录 $GIT_DIR/worktrees 目录

    检查您的 main repo/.git/worktrees 并查看是否有可以手动删除的子文件夹。


    Git 2.20(2018年第4季度)修复了一个错误,在该错误中,如果路径丢失(例如,被手动删除),同一路径可以注册在多个工作树条目下。
    此外,为方便起见,扩大以下情况的数量: --force 适用。

    看见 commit 684e742 (2018年8月30日) Jeff King ( peff ) .
    看见 commit 3a54043 , commit f414310 , commit 68a6b3a , commit e19831c , commit cb56f55 , commit 45059e6 , commit 602aaed , commit e5353be , commit 4c5fa9e (2018年8月28日)由 Eric Sunshine ( sunshineco ) .
    (由合并 Junio C Hamano -- gitster -- 在里面 commit 1c515bf ,2018年9月17日)

    worktree :删除 .git/worktrees 如果在'之后为空 remove '

    为了清洁,“ git worktree prune “”删除 .git/工作树 如果修剪完成后该目录为空。

    为了保持一致性,请将“ git worktree remove <path> “同样删除 .git/工作树 如果它在移除之后是空的。


    同样的Git 2.20,当遍历对象以获得可达性并决定什么 物体是不可参考和消耗的,也被教导 考虑将其他工作树的每个工作树引用作为起点 防止数据丢失。

    看见 commit 14f74d5 (2018年11月3日), commit c9ef0d9 , commit b29759d , commit ab3e1f7 , commit 061e420 , commit 3a3b9d8 (2018年10月21日),以及 commit 8aff1a9 , commit 5c79f74 (2018年9月29日) Nguyễn Thái Ngọc Duy ( pclouds ) .
    看见 commit a8c754d (2018年10月21日) Elijah Newren ( newren ) .
    (由合并 滨野朱尼奥C-- 吉斯特尔 -- 在里面 commit e146cc9 ,2018年11月13日)

    特别是( 提交3a3b9d8 ):

    refs :要使每个工作树引用对所有工作树可见的新引用类型

    多个工作树的问题之一是 从另一工作树访问一个工作树的每个工作树引用 .
    这在某种程度上是通过多个ref存储来解决的,其中代码可以打开另一个工作树的ref存储,并可以访问该工作树的引用空间。

    问题在于报告。
    " HEAD “在另一个引用空间中也被称为”HEAD“,就像在当前引用空间中一样。
    为了区分它们,所有代码都必须以某种方式携带ref存储 在周围打印类似“ HEAD from this ref store ".

    我们不输入单独的引用空间,而是在当前引用空间中使用其他工作树中的引用 .
    所以“ 头部 “始终是当前工作树的头部,但我们可以 " worktrees/blah/HEAD “表示名为的工作树中的头 " blah ".
    这个语法恰巧与底层目录结构相匹配,这使得实现更容易。

    必须对主工作树进行特殊处理,因为 从一开始就很特别。
    因此,可以通过名称“”访问主工作树中的HEAD main-worktree/HEAD “而不是” worktrees/main/HEAD “因为” main “可能只是另一个辅助工作树。

    此修补程序还可以在 另一个,例如。

    git log worktrees/foo/HEAD
    

    那个(新的参考) worktrees/<name>/HEAD “)导致了Git 2.23(2019年第2季度),代码现在对工作树的名称进行了消毒,以确保这些引用的格式正确。

    看见 commit 1de16ae (2019年3月8日)由 Nguyán Thi Ngác Duy公司( pclouds公司 ) .
    帮助者: 杰夫·金( 佩夫牌手表 ) .
    (由合并 滨野朱尼奥C-- 吉斯特尔 -- 在里面 commit 0d107b1 ,2019年6月13日)

    worktree add :清理工作树名称

    工作树名称基于 $(basename $GIT_WORK_TREE) .
    它们在之前并不重要 3a3b9d8 ( 参考文献 :要使每个工作树引用对所有工作树可见的新引用类型(2018-10-21,Git v2.20.0-rc0),其中工作树名称可以是引用名称的一部分,并且必须遵循引用名称规则。

    Update ' worktree add ' code remove special characters to follow these rules 。将来,用户将能够指定 如果他们对这个笨蛋不满意的话,他们会自己命名工作树 字符替换。


    同样的Git 2.22.1(2019年第3季度)提到“ git worktree add “用于在连接到同一存储库的另一个工作树损坏时失败,该问题已得到纠正。

    看见 commit 105df73 (2019年5月13日)由 Nguyán Thi Ngác Duy公司( pclouds公司 ) .
    (由合并 滨野朱尼奥C-- 吉斯特尔 -- 在里面 commit 933f294 ,2019年7月25日)

    工作树添加 :容忍腐败的工作树

    find_worktree() 可以意外死亡(),因为它使用 real_path() 而不是更温和的版本。

    当它用于“git worktree add”(添加到 cb56f55 ( 工作树 :不允许多次添加同一路径,2018-08-28,Git v2.20.0-rc0),或从v2.20.0开始。尽管 查找工作树() 更老),并且有一个坏的工作树,这个 die() 可能阻止人们添加新的工作树。

    触发此操作的“坏”条件是当工作树的父级 位置被删除。然后 实际路径() 会抱怨的。

    使用另一个版本,这样坏的工作树不会影响' 工作树添加 '.
    坏的最终会被剪掉,我们只需要容忍一段时间。


    在Git 2.26(2020年第1季度)之前,在极少数情况下“ git worktree add <path> “我可以这么想 <path> 已经是注册的工作树,即使不是,也拒绝添加新的工作树。
    这已得到纠正。

    看见 commit bb69b3b , commit bb4995f , commit a80c4c2 (2020年2月24日) 埃里克·阳光( sunshineco公司 ) .
    (由合并 滨野朱尼奥C-- 吉斯特尔 -- 在里面 commit 49e5043 ,2020年3月5日)

    worktree :不允许“ add “验证被后缀匹配欺骗”

    报告人:Cameron Gunnin
    签字人:Eric Sunshine

    " git工作树 添加<路径> “在批准之前执行各种检查 <路径> 作为新工作树的有效位置。

    除了确保 <路径> 还不存在,它提出的一个问题是 <路径> 已是注册的工作树。
    要执行此检查,它查询 查找工作树() 并禁止“ 添加 “如果 查找工作树() 查找的匹配项 <路径> .
    然而为了方便起见, 查找工作树() 使用户可以通过速记来识别工作树,以便将键入的内容保持在最低限度。
    例如,它执行后缀匹配,在给定子树“ foo/bar “和” foo/baz “,仅在要求时才能正确选择后者” baz ".

    " 添加 “验证知道它正在询问的确切路径,所以这种基于启发式的匹配在最好的情况下对于这个用例是有问题的,在最坏的情况下可能会意外地解释 <路径> 并错误地将其报告为已注册,即使它没有注册。
    (事实上, validate_worktree_add() 已经包含了一个特例,以避免与主工作树意外匹配,正是由于这个问题。)

    通过利用 find_worktree_by_path() 它确定地匹配路径,而不应用由 查找工作树() .

    并且:

    worktree :改进 查找工作树() 文档

    签字人:Eric Sunshine

    更好地解释这一点 查找工作树() 的主要目的是根据用户的输入来定位工作树,这可能是识别工作树而不是实际路径的某种简写。

    例如,用户可以使用唯一的路径后缀(即路径上的给定工作树“ 英尺/巴 “和” 英尺/英尺 “,后者可以简单地标识为” 巴兹 ").
    实际的启发 查找工作树() 用于选择工作树的功能将来可能会扩展(例如,有一天它可能允许通过以下方式选择工作树 <id> .git/worktrees/<id>/ 管理目录),因此文档没有提供如何执行匹配的精确描述,而是将其保留为开放的,以允许将来的增强。

    在执行时,请不要提及非NULL要求 prefix 自从 NULL 早就被允许了。

    例如, prefix_filename() 已明确允许 无效的 自从 116fb64e43 ( prefix_filename :drop length参数,2017-03-20,Git v2.13.0-rc0),以及 查找工作树() 自那以后 e4da43b1f0 (prefix_filename :返回新分配的字符串,2017-03-20,Git v2.13.0-rc0)。


    请注意,同一工作树目录只能注册一次,但“ git worktree move “允许这个不变量被违反,这已经用Git 2.28(2020年第3季度)进行了纠正。

    看见 commit 810382e , commit d179af6 , commit 916133e , commit 4a3ce47 , commit dd9609a , commit 1b14d40 (2020年6月10日),以及 commit c9b77f2 (2020年6月8日) 埃里克·阳光( sunshineco公司 ) .
    (由合并 滨野朱尼奥C-- 吉斯特尔 -- 在里面 commit 9740ef8 ,2020年6月22日)

    使用Git 2.28(2020年第3季度),同一工作树目录只能注册一次,但“ git工作树 move”允许这个不变量被违反,这已经被纠正。

    看见 提交810382e , 提交d179af6 , 提交916133e , 提交4a3ce47 , 提交dd9609a , 提交1b14d40 (2020年6月10日),以及 提交c9b77f2 (2020年6月8日) 埃里克·阳光( sunshineco公司 ) .
    (由合并 滨野朱尼奥C-- 吉斯特尔 -- 在里面 提交9740ef8 ,2020年6月22日)

    worktree :删除引用相同工作树路径的重复条目

    签字人:Eric Sunshine

    链接工作树的一个基本限制是只能有一个与特定路径关联的工作树,因此“ git worktree add “明确禁止在与现有注册工作树相同的位置创建新工作树。

    尽管如此,用户仍然可以通过在 .git/worktree/<id>/ .

    更糟的是,” git工作树移动 “”是粗心的,允许将工作树移动到已注册但丢失的工作树上(例如,如果工作树位于可移动介质上,则可能发生这种情况)。

    例如:

    $ git clone foo.git
    $ cd foo
    $ git worktree add ../bar
    $ git worktree add ../baz
    $ rm -rf ../bar
    $ git worktree move ../baz ../bar
    $ git worktree list
    .../foo beefd00f [master]
    .../bar beefd00f [bar]
    .../bar beefd00f [baz]
    

    通过教学帮助用户从这种形式的腐败中恢复” git worktree prune “以检测多个工作树何时与同一路径关联。

    并且:

    worktree :修剪引用主工作树路径的链接工作树

    报告人:Jonathan Mller
    签字人:Eric Sunshine

    " git工作树修剪 “检测多个条目何时与同一路径关联,并删除重复项。

    但是,它不会检测链接的工作树何时指向主工作树的路径。
    尽管“ git工作树添加 “不允许创建与主工作树路径相同的新工作树,这样的情况可能发生在Git的控制之外,即使用户不参与 .git/工作树/<标识>/ 管理文件。

    例如:

    $ git clone foo.git
    $ git -C foo worktree add ../bar
    $ rm -rf bar
    $ mv foo bar
    $ git -C bar worktree list
    .../bar deadfeeb [master]
    .../bar deadfeeb [bar]
    

    通过扩展“ git worktree prune “还可以检测链接的工作树何时与主工作树的路径关联。


    请注意,Git 2.30确实列出了锁定的工作树:

    看见 commit c57b336 :

    工作树:教学 list 注释锁定的工作树

    git worktree list “显示工作树的绝对路径, 签出的提交和分支的名称。事实并非如此 立即可以明显地看到哪些工作树(如果有的话)被锁定。

    “git工作树移除”拒绝移除锁定的工作树,并显示错误消息。如果“ git工作树列表 “被告知哪些工作树被锁定在其输出中,用户甚至不会尝试删除这样的工作树,或者会意识到 " git worktree remove -f -f <path> “是必需的。

    教学” git工作树列表 “要追加” locked “添加到其输出。
    命令的输出如下:

    $ git worktree list
    /path/to/main             abc123 [master]
    /path/to/worktree         456def (detached HEAD)
    /path/to/locked-worktree  123abc (detached HEAD) locked
    

    Git 2.33(2021第3季度),” git worktree add --lock " ( man ) 学会了用自定义消息记录工作树被锁定的原因。

    看见 commit 0db4961 (2021 7月15日),以及 commit f7c35ea , commit f9365c0 (2021 7月11日) Stephen Manz ( SRManz ) .
    (由合并 滨野朱尼奥C-- 吉斯特尔 -- 在里面 commit 01369fd ,2021 7月28日)

    worktree :教学 添加 接受 --reason <string> 具有 --lock

    签字人:Stephen Manz
    审核:Eric Sunshine

    锁文件中存储的默认原因,“ added with --lock “,不太可能是用户在单独的 git worktree lock ( man ) 命令
    允许 --reason 随附说明 --锁定 当添加工作树时,用户可以在不需要第二个命令的情况下控制锁定的原因。

    git工作树 现在包括在其 man page :

    git worktree add [-f] [--detach] [--checkout] [--lock [--reason <string>]] [-b <new-branch>] <path> [<commit-ish>]
    

    git工作树 现在包括在其 man page :

    具有 lock 或与 add --lock ,一个解释 为什么? 工作树被锁定。