1. 概述

Git 没有直接 clone 子目录的方法,但可以通过 sparse-checkout 实现类似效果,当我们只想检出特定的文件或文件夹时非常有用。

2. 使用 git sparse-checkout

需要说明的是 git sparse-checkout 是实验性的。因此,可能会出现一些非预期行为。

首先我们使用 git clone 克隆仓库:

$ git clone --depth=1 https://github.com/Baeldung/stackify.git

注意我们使用 –depth=1 选项进行浅克隆,仅包含最近的提交。

然后执行 cd 命令,进入仓库所在目录:

$ cd stackify

当前目录包含了全部的文件,我们使用 git sparse-checkout set 检出到所需的子目录如 tomcat-app

$ git sparse-checkout set tomcat-app

运行 git sparse-checkout set 后,我们使用 ls -F 列出目录中的文件:

$ ls -F
pom.xml  README.md  tomcat-app/

可以看到,现在只包含 tomcat-app 文件夹,还有与其平级的文件(这是因为 git sparse-checkout 默认以 cone 模式运行)

cone 模式下,同级文件会被包含在检出中。但我们可以通过执行 no-cone 避免这种情况:

$ git sparse-checkout set --no-cone tomcat-app

然后检查列表

$ ls -F
tomcat-app/

然而,如果 working tree 中其他位置存在名为 tomcat-app 的资源,该命令会将它们包含在sparse-checkout中。但是,我们也可以通过pattern来限制:

$ git sparse-checkout set --no-cone tomcat-app/ '!*/tomcat-app'

‘!\*/tomcat-app’ pattern会指导命令忽略 tomcat-app 子目录的兄弟子目录中任何名为 tomcat-app 的子资源:

$ ls -F
tomcat-app/

2.1. git sparse-checkout add

重复运行 git sparse-checkout set 会覆盖先前的设置,如果我们要添加另一个子目录到working tree中,我们可以使用 git sparse-checkout add 命令:

$ git sparse-checkout add webservices

现在,我们有了 tomcat-appwebservices 两个子目录:

$ ls -F
tomcat-app/  webservices/

如果一开始想要检出多个目录或文件,我们可以在 git sparse-checkout set 命令中一次性设置

我们还可以使用 git sparse-checkout 来处理文件。但是,由于 git sparse-checkout 命令仍处于实验阶段,使用它可能会产生意外的结果。

2.2. 禁用sparse-checkout

如果需要恢复原始状态,则运行 disable 命令:

$ git sparse-checkout disable

这样,全部文件又回来了:

$ ls -F
core-java/    core-kotlin/  junit5-example/  logback-example/  pom.xml    remote-debugging/  spring-boot-app/  spring-security/  tomcat-app/
core-java-9/  deep-jsf/     log4j2-example/  memory-leaks/     README.md  slf4j/             spring-mvc/       thread-pools/     webservices/

3. 使用 git checkout

使用 -no-checkout 克隆时先不检出文件:

$ git clone --no-checkout --depth=1 https://github.com/Baeldung/stackify.git

上面命令只会在本地创建 .git 文件夹,没有其他文件或子目录。我们可以通过 tree 命令验证这一点:

$ tree stackify
stackify

0 directories, 0 files

进入仓库:

$ cd stackify

然后,我们使用 git checkout 检出所需子目录或文件:

$ git checkout master -- tomcat-app

现在,我们只有 tomcat-app 子目录:

$ ls -F
tomcat-app/

使用这种方法从 Git 仓库克隆单个子目录或文件意味着 当我们提交更改时,仓库的其他文件和子目录将会被删除

因此,当我们可以删除仓库的其他资源时,我们会使用这种方法。或者,我们可以使用这种方法获取文件或子目录,然后通过删除 .git 目录将其从仓库中解关联 - 基本上就像下载文件或子目录。

git checkout 方法不同, git sparse-checkout 在我们提交更改时不会删除其他文件和子目录。我们对跟踪资源所做的任何更改都仅影响该资源。因此,即使我们向远程仓库推送,远程仓库中仅跟踪的文件才会更新。

4. 使用 git show

如果已经有一个本地仓库并且我们想下载其中一个文件,我们可以将 git show 的输出重定向到本地文件:

$ git --git-dir ./stackify/.git show master:README.md > /home/baeldung/stackify-README.md

git checkout 方法类似,我们仅在需要文件(而不需要整个仓库)时使用此方法。

5. 总结

在这篇文章中,我们讨论了如何使用 git 克隆存储库的子目录以及 git sparse-checkout 的方法。我们也谈到了如何从仓库中克隆资源,而不将其链接到仓库的情况。