【问题标题】:How to do submodule sparse-checkout with Git?如何使用 Git 进行子模块稀疏签出?
【发布时间】:2018-01-23 02:17:05
【问题描述】:

有很多关于稀疏结帐的文章和 SO 问题。不幸的是,我没有找到具体的例子。我想得到以下示例工作:

创建子模块

cd ~
mkdir sub && cd $_
git init 
mkdir foo && touch $_/foo
mkdir bar && touch $_/bar
git add .
git commit -am "Initial commit"

创建项目

cd ~
mkdir project && cd $_
git init
git submodule add ../sub sub
git config -f .gitmodules submodule.sub.shallow true
git config -f .gitmodules submodule.sub.sparsecheckout true
echo foo/* > .git/modules/sub/info/sparse-checkout
git commit -am "Initial commit"
git submodule update
cd sub
git checkout .

此时我希望sub 文件夹仅包含foo/foo 而不是bar。不幸的是它不起作用:

$ ls
bar/ foo/

我怎样才能让它工作?

【问题讨论】:

    标签: git git-submodules git-sparse-checkout


    【解决方案1】:

    git submodule add 自己检出子模块。

    对我来说成功的是:

    git init
    # I did not find a way to add submodule in 1 step without checking out
    git clone --depth=1 --no-checkout ../sub sub
    git submodule add ../sub sub
    git submodule absorbgitdirs
    # note there is no "submodule.sub.sparsecheckout" key
    git -C sub config core.sparseCheckout true
    # note quoted wildcards to avoid their expansion by shell
    echo 'foo/*' >>.git/modules/sub/info/sparse-checkout
    git submodule update --force --checkout sub
    

    【讨论】:

    • 你用你的模式更新了echo bar >>.git/modules/sub/info/sparse-checkout吗?
    • 谢谢,完美!尽管我认为在这种情况下absorbgitdirs 什么都不做,因为submodule add 已经将子模块 git 目录放入了根目录.git。调用它并没有伤害
    【解决方案2】:

    要添加到max630answer

    • since Git 2.25(2020 年第一季度),您将使用新命令 git sparse-checkout

    • 在 Git 2.28(2020 年第三季度)中,sparse checkout 设置对子模块的影响已记录在案。

    意味着如果您使主存储库本身稀疏检出,除了子模块(已经稀疏,如 max630 的回答),在主存储库上使用 git sparse-checkout 不会对子模块产生负面影响(即通过正在进行的工作时出错)。

    参见Elijah Newren (newren)commit e7d7c73(2020 年 6 月 10 日)。
    (由 Junio C Hamano -- gitster -- 合并于 commit 81be89e,2020 年 6 月 22 日)

    git-sparse-checkout:阐明与子模块的交互

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

    暂时忽略 sparse-checkout 功能,如果有一个子模块并在其中创建具有未推送更改的本地分支,并且可能会向其中添加一些未跟踪的文件,那么我们希望避免意外删除这样的子模块。

    所以,例如git.git,如果你运行

    git checkout v2.13.0
    

    然后 sha1collisiondetection/ 子模块不会被删除,即使它在 v2.14.0 之前作为子模块不存在。

    同样,如果您之前只签出 v2.13.0 并运行

    git checkout v2.14.0
    

    尽管是 v2.14.0 的一部分,但 sha1collisiondetection/ 子模块不会自动初始化。

    在这两种情况下,git 都需要单独初始化或取消初始化子模块。

    此外,我们还对其他命令中的子模块进行了特殊处理,例如 clean,这需要两个 --force 标志来删除未跟踪的子模块,并且某些命令具有 --recurse-submodules 标志。

    sparse-checkout 与 checkout 非常相似,其名称相似——它在工作副本中添加和删除文件。

    但是,出于同样的避免数据丢失的原因,我们不希望通过 checkout 从工作副本中删除子模块,我们也不希望通过 sparse-checkout 来执行此操作。

    所以子模块需要单独初始化或者去初始化;更改 sparse-checkout 规则不应自动触发子模块的删除或激活。

    我相信git sparse-checkout 中关于子模块的先前措辞只是针对这个特定问题。

    不幸的是,前面的措辞可能被解释为暗示子模块应该被认为是活跃的,而不管稀疏模式如何。

    更新措辞以避免做出这样的暗示。

    考虑两个措辞差异变得重要的示例情况可能会有所帮助:

    在未来,我们希望用户能够运行类似的命令

    git clone --sparse=moduleA --recurse-submodules $REPO_URL
    

    并自动设置稀疏路径并自动初始化稀疏路径中的子模块

    我们不希望任何路径中的所有子模块都使用该命令自动初始化。

    同样,我们希望能够做类似的事情

    git -c sparse.restrictCmds grep --recurse-submodules $REV $PATTERN
    

    并在记录的稀疏模式中通过$REV 搜索$PATTERN

    我们希望它递归到那些稀疏模式中的子模块,但不希望递归到与稀疏模式不匹配的目录以搜索可能的子模块。

    所以the documentation 现在包括:

    如果您的存储库包含一个或多个子模块,则会根据与 git submodule 命令的交互来填充子模块。
    具体来说,git submodule init -- <path> 将确保<path> 处的子模块存在,而git submodule deinit [-f] -- <path> 将删除<path> 处子模块的文件(包括任何未跟踪的文件、未提交的更改和未推送的历史记录)。
    类似于 sparse-checkout 从工作树中删除文件但仍然在索引中保留条目的方式,取消初始化的子模块从工作目录中删除但仍然在索引中具有条目。

    由于子模块可能有未推送的更改或未跟踪的文件,删除它们可能会导致数据丢失。
    因此,更改稀疏包含/排除规则不会导致已签出 要从工作副本中删除的子模块。
    换句话说,就像checkout 不会导致子模块被自动删除或初始化,即使在删除或添加的分支之间切换时也是如此 子模块,使用sparse-checkout 缩小或扩大“有趣”文件的范围也不会导致子模块被自动取消初始化或初始化。

    此外,上述事实意味着工作副本中可能不存在“跟踪”文件的原因有多种:来自稀疏签出的稀疏模式应用程序和子模块初始化状态。
    因此,像git grep 这样对工作副本中的跟踪文件起作用的命令可能会返回受这些限制中的一个或两个限制的结果。


    在 Git 2.31(2021 年第一季度)中,“git grep(man) 已被调整为仅限于稀疏结帐路径。

    由于您可能在稀疏签出子模块中需要git grep,因此这很重要。

    参见Matheus Tavares (matheustavares)commit 42d906b(2021 年 2 月 9 日)。
    (由 Junio C Hamano -- gitster -- 合并到 commit 628c13c,2021 年 2 月 25 日)

    grep: 在工作树搜索中尊重稀疏结帐

    建议人:Elijah Newren
    签名人:Matheus Tavares
    审核人:Elijah Newren

    在稀疏签出的存储库上,git grep(man)(没有 --cached)在条目与搜索路径规范匹配并具有 SKIP_WORKTREE 位时最终搜索缓存设置。

    这令人困惑,因为稀疏路径不应该出现在工作树搜索中(因为它们没有被检出),而且因为输出混合了工作树和缓存结果而不区分它们。
    (请注意,grep 也会在包含 --assume-unchanged 路径的工作树搜索中使用缓存。
    但在这种情况下,重点是假设索引条目和文件的内容是相同的。
    这不适用于稀疏路径的情况,其中文件甚至不存在。)

    通过教 grep 遵守工作树搜索的稀疏签出规则来解决此问题。
    如果用户想要 grep 当前稀疏检出定义之外的路径,他们可以更新稀疏规则以实现文件,或使用--cached 搜索索引中注册的所有 blob。

    【讨论】:

    • 您好!我不明白 Git 2.28 如何简化/改进@max630 的答案。您介意发布/描述等效命令以实现类似 stackoverflow.com/a/45689692/6108874 的功能吗?谢谢!
    • @GerardBosch 这只是通过描述新的git sparse-checkout 命令如何与子模块交互来补充 max630 的答案。
    • 谢谢,我认为这是一个完整的答案!也许您可以更新它只是为了说明您在此评论中所说的话:) 无论如何谢谢!
    • @GerardBosch 当然可以。我已经编辑了这个答案的介绍,使其目的更清晰。
    猜你喜欢
    • 1970-01-01
    • 2011-09-08
    • 2012-06-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-10
    • 2014-01-31
    • 1970-01-01
    相关资源
    最近更新 更多