【问题标题】:Why does one call `git read-tree` after a sparse checkout为什么在稀疏结帐后调用`git read-tree`
【发布时间】:2015-04-29 22:06:42
【问题描述】:

根据Subdirectory Checkouts with git sparse-checkout在已经存在存储库的情况下配置稀疏签出后调用git read-tree -mu HEAD,即:

# Enable sparse-checkout:
git config core.sparsecheckout true

# Configure sparse-checkout 
echo some/dir/ >> .git/info/sparse-checkout
echo another/sub/tree >> .git/info/sparse-checkout

# Update your working tree:
git read-tree -mu HEAD
  • 能否更详细地解释一下read-tree 步骤?
  • 它是如何工作的?
  • 这是怎么回事?
  • 为什么使用read-tree 而不是checkout
  • 为什么要使用-mu(为什么要合并,合并了什么)?

-m

    Perform a merge, not just a read. The command will refuse to run if
    your index file has unmerged entries, indicating that you have not
    finished previous merge you started.

-u

    After a successful merge, update the files in the work tree with the
    result of the merge.

【问题讨论】:

  • 注意:对于 Git 2.27,2020 年第二季度,git read-tree 将不再被 git sparse-checkout 调用。见我的edited answer below

标签: git sparse-checkout


【解决方案1】:

在 Git 2.25(2020 年第一季度)中,稀疏签出工作树的管理获得了专用的“稀疏签出”命令。
它引入了一个锥形模式(我在“Git sparse checkout with exclusion”中有详细说明),这将使sparse-checkout 必须更快。

但它也间接描述了为什么使用git read-tree -mu HEAD(或者,对于新的“锥形”模式,使用了)。

commit e6152e3(2019 年 11 月 21 日)Jeff Hostetler (Jeff-Hostetler)
commit 761e3d2(2019 年 12 月 20 日)Ed Maste (emaste)
commit 190a65f(2019 年 12 月 13 日),commit cff4e91commit 416adc8commit f75a69fcommit fb10ca5commit 99dfa6fcommit e091228commit e9de487,@9876543334@,@9876543334@,@9876534 ,commit 96cc8abcommit 879321ecommit 72918c1commit 7bffca9commit f6039a9commit d89f09ccommit bab3c35commit 94c0956(2019 年 11 月 21 日)by Derrick Stolee (derrickstolee)
Junio C Hamano -- gitster --commit bd72a08,2019 年 12 月 25 日)

sparse-checkout:正在更新工作目录

签字人:Derrick Stolee

sparse-checkout builtin 使用 'git read-tree -mu HEAD' 来更新索引中的 skip-worktree 位并更新工作目录。
这个额外的过程过于复杂,并且容易失败。它还要求我们在尝试更新索引之前将更改写入 sparse-checkout 文件。

通过以与“git read-tree -mu HEAD”相同的方式创建对unpack_trees() 的直接调用来删除这个额外的进程调用。
此外,提供内存中的模式列表,这样我们就可以避免从 sparse-checkout 文件中读取。这允许我们在写入文件之前测试对文件的提议更改。

此补丁的早期版本包含一个错误,即“set”命令由于“稀疏签出在工作目录上没有条目”错误而失败。
它不会回滚 index.lock 文件,因此旧的 sparse-checkout 规范的重放将失败。 t1091 中的测试现在涵盖了该场景。


而且,在 Git 2.27(2020 年第二季度)中,“sparse-checkout”知道如何重新应用自身:

commit 5644ca2commit 681c637commit ebb568bcommit 22ab0b3commit 6271d77commit 1ac83f4commit cd002c1commit 4ee5d50commit f56f31acommit 30e89c1、@989 @,commit b0a5a12commit 72064eecommit fa0bde4commit d61633acommit d7dc1e1commit 031ba55(2020 年 3 月 27 日)由 Elijah Newren (newren).
(由 Junio C Hamano -- gitster -- 合并到 @9876345 @,2020 年 4 月 29 日)

sparse-checkout: 提供一个新的 reapply 子命令

审核人:Derrick Stolee
签字人:Elijah Newren

如果像 merge 或 rebase 这样的命令将文件具体化作为其工作的一部分,或者之前的 sparse-checkout 命令由于脏更改而未能更新单个文件,用户可能需要一个命令来简单地“重新应用”稀疏规则。

提供一个。

updated git sparse-checkout man page 现在包括:

reapply:

将稀疏模式规则重新应用于工作树中的路径。

mergerebase 之类的命令可以具体化路径来完成它们的工作(例如,为了向您显示冲突),而其他稀疏检出命令可能无法稀疏化单个文件(例如,因为它具有未暂存的更改或冲突)。

在这种情况下,在清理受影响的路径(例如解决冲突、撤消或提交更改等)之后运行git sparse-checkout reapply 可能是有意义的。


但是,在 Git 2.27 中,它不会再使用 git read-tree 重新应用/更新自身:

commit 5644ca2commit 681c637commit ebb568bcommit 22ab0b3commit 6271d77commit 1ac83f4commit cd002c1commit 4ee5d50commit f56f31a、@987654382、@、@987654382 @、commit b0a5a12commit 72064eecommit fa0bde4commit d61633acommit d7dc1e1commit 031ba55(2020 年 3 月 27 日)由 Elijah Newren (newren).
(由 Junio C Hamano -- gitster -- 合并到 @98763924 @,2020 年 4 月 29 日)

unpack-trees:添加一个新的update_sparsity()函数

审核人:Derrick Stolee
签字人:Elijah Newren

以前,为各种路径更新 SKIP_WORKTREE 位的唯一方法是调用 git read-tree -mu HEAD 或调用此代码路径调用的相同代码。

但是,如果索引或工作目录不干净,则会出现许多问题。

首先,让我们考虑一下这个案例:

Flipping SKIP_WORKTREE -> !SKIP_WORKTREE (materializing files)

如果工作树是干净的,这很好,但如果有文件或目录或符号链接或给定路径中已经存在的任何内容,则操作将中止并出现错误。

让我们标记这个案例以供以后讨论:

  • A) 途中有一条未跟踪的路径

现在让我们考虑相反的情况:

Flipping !SKIP_WORKTREE -> SKIP_WORKTREE (removing files)

如果索引和工作树是干净的,这很好,但如果有任何不干净的路径,我们就会遇到问题。

需要考虑三种不同的情况:

  • B) 路径未合并
  • C) 路径有未暂存的更改
  • D) 路径已分阶段更改(不同于 HEAD)

如果任何路径落入案例 B 或 C,则整个操作将因错误而中止。

使用sparse-checkout,对于case D,整个操作也将被中止,但对于它的前身直接使用git read-tree -mu HEAD,任何落入case D的路径都将从工作​​副本中删除,并且索引条目该路径将被重置以匹配HEAD——这看起来和感觉就像用户丢失了数据(只有少数人甚至知道询问它是否可以恢复,即使这样它也需要穿过松散的物体来尝试匹配正确的)。

拒绝删除有未保存用户更改的文件是好的,但拒绝在任何其他路径上工作对​​用户来说是很成问题的。

如果用户正在进行 rebase 或对文件进行了修改导致更多依赖项,那么为了使他们的构建工作,他们需要更新稀疏路径。

这种逻辑一直在阻止他们这样做。

有时,作为响应,用户会暂存文件并重试,但使用稀疏签出无济于事,或者如果他们使用其前身git read-tree -mu HEAD,则会担心丢失更改。

添加一个新的update_sparsity() 函数,该函数在任何这些情况下都不会出错,但在特殊情况下的行为如下:

  • A) 将文件单独保留在工作副本中,清除 SKIP_WORKTREE 位,并打印警告(从而使路径处于 status 将文件报告为已修改的状态,这似乎合乎逻辑)。
  • B) 不要将此路径标记为SKIP_WORKTREE,并将其保留为未合并。
  • C) 不要将此路径标记为 SKIP_WORKTREE 并打印有关脏路径的警告。
  • D) 将路径标记为SKIP_WORKTREE,但不要还原存储在索引中的版本以匹配HEAD;保留内容。

我为 A 尝试了不同的行为(保留 SKIP_WORKTREE 位设置),但发现它非常令人惊讶且违反直觉(例如,用户看到它与该目录中的所有其他文件一起存在,尝试暂存它,但git add 忽略它,因为设置了SKIP_WORKTREE 位)。

A 和 C 对我来说似乎是最佳行为。

B 也可以,不过我想知道打印警告是否会有所改进。

起初有些人可能会对 D 感到有些惊讶,但考虑到它对 git commit 甚至 git commit -a 做了正确的事情(git add 会忽略标记为 SKIP_WORKTREE 的条目,因此不会删除它们,和commit -a 是相似的),这对我来说似乎是合乎逻辑的。

而且,仍然使用 Git 2.27(2020 年第二季度):

参见Elijah Newren (newren)commit 6c34239(2020 年 5 月 14 日)。
(由 Junio C Hamano -- gitster -- 合并于 commit fde4622,2020 年 5 月 20 日)

unpack-trees:也允许 get_progress() 处理不同的索引

通知人:Jeff Hostetler
签字人:Elijah Newren

commit b0a5a12a60 ("unpack-trees: 允许check_updates() 在不同的索引上工作", 2020-03-27, Git v2.27.0-rc0 -- merge 列在batch #5) 允许@987654470 @ 处理不同的索引,但它称为 get_progress(),它被硬编码为处理 o->result,就像 check_updates() 一样。

更新它以接受索引参数并让check_updates() 传递该参数,以便两者都在同一个索引上工作。


Git 2.29(2020 年第四季度)的代码更加健壮:

请参阅commit 55fe225commit 1c89001commit 9a53219(2020 年 8 月 17 日)和commit f1de981commit c514c62commit 9101c8ecommit 8dc3156(2020 年 8 月 14 日)Jeff King (peff)
(2020 年 8 月 27 日由 Junio C Hamano -- gitster -- 合并于 commit 0d9a8e3

clear_pattern_list(): 清除嵌入的 hashmaps

签字人:Jeff King
签字人:Derrick Stolee

Commit 96cc8ab531 ("sparse-checkout: use hashmaps for cone patterns", 2019-11-21, Git v2.25.0-rc0 -- merge) 在 pattern_list 结构中添加了一些辅助的 hashmaps,但是当clear_pattern_list() 被调用时,它们就会被泄露。

【讨论】:

    猜你喜欢
    • 2020-11-23
    • 2012-03-23
    • 1970-01-01
    • 2016-06-18
    • 1970-01-01
    • 1970-01-01
    • 2019-11-19
    • 2017-06-07
    • 1970-01-01
    相关资源
    最近更新 更多