不需要先检出整个仓库,是否可以进行稀疏检出?

244

我正在处理一个拥有大量文件的代码库,检出操作需要几个小时时间。我在探索是否可以使用Git来管理这种代码库,因为它可以支持“稀疏检出”,但是我找到的所有示例都执行以下操作:

git clone <path>
git config core.sparsecheckout true
echo <dir> > .git/info/sparse-checkout
git read-tree -m -u HEAD
这个命令序列的问题在于原始克隆(clone)还进行了一次检出(checkout)。如果在原始的克隆命令中添加-n参数,那么read-tree命令将会产生以下错误:

error: Sparse checkout leaves no entry on working directory

如何在不先检出所有文件的情况下进行稀疏检出?

4
可能是重复的问题:有没有办法只克隆 Git 仓库中的子目录? - Chronial
注意:git worktree add --no-checkout也可以在Git 2.9(即2016年)中使用(不仅仅是git clone --no-checkout)。请参见我的答案 - VonC
在尝试了这里的所有解决方案之后,唯一一个只下载目录(不进行推送!)的解决方案是这个 - LondonRob
我已经将所有相关的问题和所有相关的答案(我能找到的)压缩在这里:https://dev59.com/7FIH5IYBdhLWcg3wTL95 - Richard Gomes
现代、简洁的答案是 Fawaz 的回答 - Gringo Suave
16个回答

178
请注意,这个回答确实会从仓库下载完整的数据。git remote add -f 命令会克隆整个仓库。根据 git-remote 的手册页面

使用 -f 选项后,远程信息设置完成后会立即运行 git fetch <name>


尝试这个:

mkdir myrepo
cd myrepo
git init
git config core.sparseCheckout true
git remote add -f origin git://...
echo "path/within_repo/to/desired_subdir/*" > .git/info/sparse-checkout
git checkout [branchname] # ex: master

现在您会发现,您拥有一个“修剪过的”检出版本,其中只有路径/存储库中所需子目录中的文件存在(并且位于该路径中)。

请注意,在Windows命令行中,您不能引用路径,即必须将第六个命令更改为此命令:

echo path/within_repo/to/desired_subdir/* > .git/info/sparse-checkout

如果你不这样做,你将在稀疏检出文件中获得引号,它将无法工作。


4
我无法使用命令"git checkout [分支名称]"(也发现错误:稀疏检出在工作目录中没有条目)。我已经使用了"git pull origin master",它可以正常运行。 - Natty
2
在Linux上使用git版本1.7.2.5,我得到了以下结果:echo 'dir/*'仅检出dir/中的文件,而不是其子目录中的文件;echo 'dir/'(没有星号!)正确地检出了dir/下的整个树形结构。希望对你有所帮助。 - pavek
38
对我来说,这根本不起作用 - "git remote" 命令导致整个 repo 被检出 - 立即!所以接下来的命令中的 "git config..." 和指定感兴趣的子目录无效。 "git remote" 命令中指定的 repo URL 是否只是顶层 .git 文件的路径?或者它应该是一个感兴趣的子目录的路径? - Rob Cranfill
11
这是一个简化版(不需要手动创建目录、执行初始化和添加远程仓库的步骤,只需按照 @onionjake 提到的普通 git clone+checkout 循环,并在其中加入 --no-checkout 选项): git clone --no-checkout <project> cd <project> echo <dir> > .git/info/sparse-checkout git checkout <branch> - Gregor
23
git remote add 命令会下载所有内容,因为 -f 选项告诉它在定义稀疏检出选项之前立即获取。但是省略或重新排序这个选项并不能解决问题。稀疏检出只影响工作树,而不影响存储库。如果你想让你的存储库减肥,那么你需要查看 --depth--single-branch 选项。 - Miral
显示剩余5条评论

99

在2020年,有一种更简单的方法来处理稀疏检出而无需担心.git文件。以下是我的做法:

git clone <URL> --no-checkout <directory>
cd <directory>
git sparse-checkout init --cone # to fetch only root files
git sparse-checkout set apps/my_app libs/my_lib # etc, to list sub-folders to checkout
git checkout # or git switch

请注意,需要安装git版本2.25。在此处阅读更多信息:https://github.blog/2020-01-17-bring-your-monorepo-down-to-size-with-sparse-checkout/ 更新:
上述的git clone命令仍将克隆具有完整历史记录的存储库,但不会检出文件。如果您不需要完整的历史记录,则可以向命令添加--depth参数,如下所示:
# create a shallow clone,
# with only 1 (since depth equals 1) latest commit in history
git clone <URL> --no-checkout <directory> --depth 1

1
@mropp,我更新了答案,添加了--depth参数,这样我们就可以进行浅克隆。这会有帮助吗? @Tao,不确定如何在这种情况下使用--filter,我没有尝试过。你能提供一个例子,或者在这个主题下发布另一个答案吗? - Alexey Grinko
7
请注意,它在2.27版本中的工作方式不同 - 我不知道原因。 - Blazes
1
正如Blazes所说,在2.27中它不再起作用,找不到如何使其再次工作。 - agemO
4
我认为我在2.28版本中成功地完成了以下操作:`git clone <url> --no-checkout <dir>cd <dir>git sparse-checkout set <需要检出的git目录>git checkout master`最后一个checkout命令会将我所需的文件填充到<需要检出的目录>中。 - gxh8Nmate
2
原来这个答案中的行为是一个 bug,在 git 2.27+ 中不起作用。请参阅 https://dev59.com/YlIG5IYBdhLWcg3w3l4l - Curtis Bezault
显示剩余6条评论

74

适用于 git v2.37.1 及以上版本

git clone --filter=blob:none --no-checkout --depth 1 --sparse <project-url>
cd <project>

指定您想要克隆的文件夹

git sparse-checkout add <folder1> <folder2>
git checkout

4
谢谢,我找了一个小时才找到一个简明的、最新的并且可行的答案。 - Gringo Suave
2
这是递归的吗? - tzg
1
@DanM。看起来有两种模式:https://dev59.com/2noPtIcB2Jgan1znwT8W - NateS
1
请考虑使用tree:0替代blob:none - jthill
注意:即使您不添加任何文件夹,也应该运行git checkout,否则git status会显示仓库中的所有文件都被删除,并将这些删除操作添加到索引中(这样您就有可能提交删除操作)。 (在2.39.2.windows.1上进行了测试)。或者不要使用--no-checkout参数。 - undefined
显示剩余8条评论

45
Git clone有一个选项(--no-checkout-n),可以实现你想要的功能。
在你的命令列表中,只需更改:
git clone <path>

变成这样:

git clone --no-checkout <path>

您可以按照问题中所述使用稀疏检出。


8
好的,我会尽力进行翻译。原文意思是说,“是的,它不执行结帐,但仍会执行提取操作以下载整个仓库历史记录。” - Jason S
10
@JasonS 这个问题特别指出了不想要执行checkout操作。如果你不想要整个历史记录,可以在git clone命令中使用“--depth <depth>”选项,它只会下载历史中最近的<depth>个提交。目前还没有办法部分地下载单个提交,但如果你的远程支持,可以使用“git archive --remote”来下载部分文件集合。 - onionjake
现在,您也可以使用https://vfsforgit.org/检出提交,而无需下载任何文件。如果有人仅尝试检出单个提交的一个小子集,这可能很有用。 - onionjake

31

我有一个类似的用例,但我想只检出标签的提交并修剪目录。使用 --depth 1 可以使它非常稀疏,并且可以真正加快速度。

mkdir myrepo
cd myrepo
git init
git config core.sparseCheckout true
git remote add origin <url>  # Note: no -f option
echo "path/within_repo/to/subdir/" > .git/info/sparse-checkout
git fetch --depth 1 origin tag <tagname>
git checkout <tagname>

4
FYI,“--depth 1” 被称为浅克隆。 - Mark Allison
1
谢谢。在尝试了许多其他方法来防止下载整个存储库后,我用这个方法成功了。 - J...S

12

我在之前 pavek 发布的一句话中找到了我想要的答案(感谢!),因此我想在单个回复中提供一份完整的答案,适用于Linux (GIT 1.7.1):

1--> mkdir myrepo
2--> cd myrepo
3--> git init
4--> git config core.sparseCheckout true
5--> echo 'path/to/subdir/' > .git/info/sparse-checkout
6--> git remote add -f origin ssh://...
7--> git pull origin master

我把命令的顺序稍微改了一下,但似乎没有任何影响。关键是在第5步中路径结尾处要有斜杠“/”


3
你确定这就是你想要的吗?"-f" 表示获取所有数据,你仍然会得到其他你不想要的信息,并且速度很慢。(这仍然是“检出整个代码库”)。 - Shuman
1
我在Windows上尝试了以上步骤,但是命令提示符下的稀疏检出无法工作,所以我尝试了Git Bash shell并且它可以工作!!命令提示符能够执行所有的git命令,如push、pull等,但是在稀疏检出时失败。 - user593029
如何只处理子目录中的文件。我只想获取特定子目录内的文件。 - Babish Shrestha
@BabishShrestha 看看 onionjake 在其他答案中的评论,供参考 :| - rogerdpack
这不执行稀疏克隆,不如较新的答案有用。顺便说一下,-f强制完全克隆。 - Gringo Suave

11

2020年更新的答案:

现在有一个命令git sparse-checkout,我会在Git 2.25(2020年第一季度)中详细介绍它。

nicono答案说明了它的用法:

git sparse-checkout init --cone # to fetch only root files
git sparse-checkout add apps/my_app
git sparse-checkout add libs/my_lib

它已经 随着Git 2.27的发展 而进化,并且知道如何 "重新应用" 稀疏检出,就像这里一样
请注意,使用 Git 2.28,git status 将提到您处于稀疏检出的存储库中。


注意/警告:某些在非圆锥模式下有效的稀疏检出模式在圆锥模式下会导致段错误,这个问题已经在Git 2.35(2022年第一季度)得到了修正。

请查看 提交记录a3eca58, 提交记录391c3a1, 提交记录a481d43 (2021年12月16日) 作者为 Derrick Stolee (derrickstolee)
(由 Junio C Hamano -- gitster -- 合并于 提交记录09481fe, 2022年1月10日)

sparse-checkout: 拒绝添加错误的模式

经过审核:Elijah Newren
签署者:Derrick Stolee

在锥形模式的稀疏检出中,如果现有的稀疏检出文件与锥形模式不匹配,不清楚“git sparse-checkout(man)如何添加...应该如何行事。更改行为以失败并显示关于现有模式的错误消息。同时,所有锥形模式模式都以“/”字符开头,因此需要添加该限制。这对于我们的示例测试“cone mode: warn on bad pattern”是必要的,但也需要修改我们用于测试识别锥形模式模式相关警告的示例稀疏检出文件。这种错误检查会导致测试脚本进一步失败,因为测试会添加非锥形模式模式而没有清理它们。现在作为测试的一部分进行清理。
在 Git 2.36 (2022年第二季度) 中, "git sparse-checkout"(man) 希望与每个工作树配置一起使用,但在连接到裸仓库的工作树中无法正常工作。

请参见 提交 3ce1138, 提交 5325591, 提交 7316dc5, 提交 fe18733, 提交 615a84a, 提交 5c11c0d (2022年2月7日) 由Derrick Stolee (derrickstolee)提交。
(由Junio C Hamano -- gitster --合并于提交 6249ce2, 2022年2月25日)

worktree: 在添加时复制sparse-checkout模式和配置

Signed-off-by: Derrick Stolee
Reviewed-by: Elijah Newren

当添加新的工作树时,我们希望使用当前设置的稀疏检出设置来创建新的工作树是合理的。
这对于工作树变得过大而无法使用的存储库尤其重要。
当使用部分克隆时,甚至更加重要,因为我们希望避免下载不应写入新工作树的文件的缺失blob。
在“git worktree add(man)期间复制稀疏检出模式和配置设置是创建此类工作树的唯一方法,而无需扩展完整的工作树。
每个工作树都有自己的稀疏检出模式,当稀疏检出文件丢失时的默认行为是包含HEAD中的所有路径。
因此,我们需要从某个地方获取模式,最好是当前工作树的模式。
然后在将来独立修改它们。
除了稀疏检出文件外,如果启用了工作树配置并且该文件存在,则复制工作树配置文件。
这将复制任何重要的设置以确保新的工作树与当前工作树的行为相同。
我们必须继续做出的唯一例外是在工作树的配置文件中应取消设置core.barecore.worktree

原始回答:2016年

git 2.9(2016年6月)将把--no-checkout选项推广到git worktree add(该命令允许在一个存储库中使用多个工作树

请查看 提交 ef2a0ac(2016年3月29日)由 Ray Zhang(OneRaynyDay 提交。
协助者:Eric Sunshine(sunshinecoJunio C Hamano(gitster
(由 Junio C Hamano -- gitster -- 合并于 2016年4月13日的提交 commit 0d8683c 中)

git worktree man page现在包括:

--[no-]checkout:

默认情况下,add会检出<branch>,但是可以使用--no-checkout来抑制检出以进行自定义,例如配置稀疏检出。

10

可悲的是,以上方法都对我不起作用,所以我花了很长时间尝试不同的 sparse-checkout 文件组合。

在我的情况下,我想跳过带有 IntelliJ IDEA 配置的文件夹。

这是我做的:


运行 git clone https://github.com/myaccount/myrepo.git --no-checkout

运行 git config core.sparsecheckout true

创建 .git\info\sparse-checkout 文件,并填入以下内容

!.idea/*
!.idea_modules/*
/*

运行 'git checkout --' 命令获取所有文件。


使它工作的关键是在文件夹名称后添加 /*

我使用的是 git 1.9 版本。


3
不,它仍然下载所有内容,包括所有提交和所有文件,git 2.3.2。 - Tyguy7
9
稀疏检出只影响工作树,不会影响存储库的大小或获取的内容。如果你想要实现这些效果,需要使用其他选项。 - Miral
下次在 Windows 上工作时,请尝试使用 Git Bash Shell,并按照“pbetkier”的步骤操作,这样可以正常工作。 - user593029

9

根据这个答案(作者:apenwarr)和这条评论(作者:Miral),我想出了以下解决方案,当我本地克隆Linux git存储库时只需要一个文档子目录,它让我节省了近94%的磁盘空间:

$ cd linux
$ du -sh .git .
2.1G    .git
894M    .
$ du -sh 
2.9G    .
$ mkdir ../linux-sparse-test
$ cd ../linux-sparse-test
$ git init
Initialized empty Git repository in /…/linux-sparse-test/.git/
$ git config core.sparseCheckout true
$ git remote add origin ../linux
# Parameter "origin master" saves a tiny bit if there are other branches
$ git fetch --depth=1 origin master
remote: Enumerating objects: 65839, done.
remote: Counting objects: 100% (65839/65839), done.
remote: Compressing objects: 100% (61140/61140), done.
remote: Total 65839 (delta 6202), reused 22590 (delta 3703)
Receiving objects: 100% (65839/65839), 173.09 MiB | 10.05 MiB/s, done.
Resolving deltas: 100% (6202/6202), done.
From ../linux
 * branch              master     -> FETCH_HEAD
 * [new branch]        master     -> origin/master
$ echo "Documentation/hid/*" > .git/info/sparse-checkout
$ git checkout master
Branch 'master' set up to track remote branch 'master' from 'origin'.
Already on 'master'
$ ls -l
total 4
drwxr-xr-x 3 abe abe 4096 May  3 14:12 Documentation/
$  du -sh .git .
181M    .git
100K    .
$  du -sh
182M    .

所以我将文件大小从2.9GB减小到了182MB,这已经相当不错了。

但是我没有通过git clone --depth 1 --no-checkout --filter=blob:none file:///…/linux linux-sparse-test (在此处提醒)使其正常工作,因为缺失的文件都被添加为从索引中删除的文件。因此,如果有人知道git fetch的等效于git clone --filter=blob:none,我们可能可以节省更多的兆字节。(阅读git-rev-list的手册还提示了类似于--filter=sparse:path=…的内容,但我也无法使其正常工作。

(所有尝试均使用来自Debian Buster的git 2.20.1.)


1
现在git-rev-list的手册已经被修改以反映删除了--filter=sparse:path选项:请注意,出于安全原因,想要从文件系统上的任意路径读取的形式--filter=sparse:path=<path>已被删除。 - Arnie97

8

可以下载整个文件夹而不是整个代码库,甚至包括任何/最新提交

以下是实现方法:

D:\Lab>git svn clone https://github.com/Qamar4P/LolAdapter.git/trunk/lol-adapter -r HEAD
  1. -r HEAD 仅下载最后一个版本,忽略所有历史记录。

  2. 请注意主干(trunk)和 /具体文件夹(specific-folder)

复制并更改 /trunk/ 前后的URL。希望这能帮助到某些人。享受吧 :)

更新于2019年9月26日


1
仅适用于使用svn的人或来自svn的人。不会点赞这个。 - C.J.
@CJohnson,正如您所看到的,我正在克隆git存储库文件夹。工作正常。 - Qamar
2
请注意,这不是 Git 提供的基本功能,而是 GitHub 在常规 Git 功能之外提供的附加功能。但是,当您能够利用它时,它可以很好地工作。谢谢! - Qix - MONICA WAS MISTREATED

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接