为什么在稀疏结帐后调用`git read-tree`

Mic*_*ann 6 git sparse-checkout

根据Subdirectory Checkouts with git sparse-checkoutgit 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
Run Code Online (Sandbox Code Playgroud)
  • 你能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.
Run Code Online (Sandbox Code Playgroud)

-u

    After a successful merge, update the files in the work tree with the
    result of the merge.
Run Code Online (Sandbox Code Playgroud)

Von*_*onC 3

在 Git 2.25(2020 年第一季度)中,稀疏签出工作树的管理获得了专用的“稀疏签出”命令。
它引入了一个锥体模式(我在“ Git稀疏结帐与排除”中详细介绍),这将使sparse-checkout必须更快。

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

请参阅Jeff Hostetler ( )提交的 e6152e3(2019 年 11 月 21 日)。 请参阅Ed Maste ( )的提交 761e3d2(2019 年 12 月 20 日)。 请参阅提交 190a65f(2019 年 12 月 13 日),并提交 cff4e91提交 416adc8提交 f75a69f提交 fb10ca5提交 99dfa6f提交 e091228提交 e9de487提交 4dcd4de提交 eb42fec提交 af09ce2提交 96cc8ab提交 879321e提交 72918c1提交7bffca9提交 f6039a9提交 d89f09c提交 bab3c35提交 94c0956(2019 年 11 月 21 日),作者:Derrick Stolee ( )(由Junio C Hamano 合并 -- --提交bd72a08,2019 年 12 月 25 日)Jeff-Hostetler
emaste
derrickstolee
gitster

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

签署人:Derrick Stolee

稀疏签出内置函数使用“ git read-tree -mu HEAD”来更新索引中的跳过工作树位并更新工作目录。
这个额外的过程过于复杂,并且容易失败。它还要求我们在尝试更新索引之前将更改写入稀疏签出文件。

unpack_trees()通过以与 ' ' 相同的方式创建直接调用来删除此额外的进程调用git read-tree -mu HEAD
此外,提供内存中的模式列表,以便我们可以避免从稀疏签出文件中读取。这使我们能够在写入文件之前测试对文件的建议更改。

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


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

请参阅提交 5644ca2提交 681c637提交 ebb568b提交 22ab0b3、提交6271d77、提交1ac83f4提交 cd002c1提交 4ee5d50提交 f56f31a提交 7af7a25提交 30e89c1提交 3cc7c50提交b0a5a12提交 72064ee提交 fa0bde4提交 d61633a提交d7dc1e1提交 031ba55(2020 年 3 月 27 日),作者:Elijah Newren ( newren)
(由Junio C Hamano 合并 -- gitster--提交48eee46,2020 年 4 月 29 日)

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

审阅人:Derrick Stolee
签署人:Elijah Newren

如果诸如 merge 或 rebase 之类的命令将文件作为其工作的一部分,或者之前的稀疏签出命令由于脏更改而无法更新单个文件,则用户可能需要一个命令来简单地“重新应用”稀疏规则。

提供一份。

更新后的git sparse-checkout手册页现在包括:

reapply:

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

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

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


但是,对于 Git 2.27,它不会git read-tree再使用以下方式重新应用/更新自身:

请参阅提交 5644ca2提交 681c637提交 ebb568b提交 22ab0b3、提交6271d77、提交1ac83f4提交 cd002c1提交 4ee5d50提交 f56f31a提交 7af7a25提交 30e89c1提交 3cc7c50提交b0a5a12提交 72064ee提交 fa0bde4提交 d61633a提交d7dc1e1提交 031ba55(2020 年 3 月 27 日),作者:Elijah Newren ( newren)
(由Junio C Hamano 合并 -- gitster--提交48eee46,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)
Run Code Online (Sandbox Code Playgroud)

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

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

  • A) 路上有一条未追踪的路径

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

Flipping !SKIP_WORKTREE -> SKIP_WORKTREE (removing files)
Run Code Online (Sandbox Code Playgroud)

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

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

  • B) 路径未合并
  • C) 路径有未暂存的更改
  • D) 路径有阶段性变化(与HEAD不同)

如果任何路径属于情况 B 或 C,则整个操作将因错误而中止。

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

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

如果用户正在进行变基或对文件进行了修改以引入更多依赖项,那么为了使构建正常工作,他们需要更新稀疏路径。

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

有时,作为响应,用户将暂存文件并重试,但稀疏签出无济于事,或者如果他们使用其前身git read-tree -mu HEAD.

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

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

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

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

B 也可能是这样,尽管我想知道打印警告是否会有所改进。

有些人一开始可能会对 D 感到有点惊讶,但考虑到它用git commitand Even做了正确的事情git commit -agit add忽略被标记的条目SKIP_WORKTREE,因此不会删除它们,并且commit -a是类似的),对我来说这似乎是合乎逻辑的。

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

请参阅Elijah Newren ( )的提交 6c34239(2020 年 5 月 14 日)。(由Junio C Hamano 合并 -- --提交 fde4622中,2020 年 5 月 20 日)newren
gitster

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

注明人:Jeff Hostetler
签署人:Elijah Newren

commit b0a5a12a60(“ unpack-trees:允许check_updates()在不同的索引上工作”,2020-03-27,Git v2.27.0-rc0 -批处理#5中列出的合并)允许在不同的索引上工作,但它调用了硬编码为从事类似的工作check_updates()get_progress()o->resultcheck_updates()

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


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

请参阅Jeff King的提交 55fe225提交 1c89001提交 9a53219(2020 年 8 月 17 日)和提交 f1de981提交 c514c62提交 9101c8e提交 8dc3156(2020 年 8 月 14 日(由Junio C Hamano 合并 -- --提交 0d9a8e3中,2020 年 8 月 27 日)peff
gitster