如何使用git拉取特定目录

265

我有一个使用Git的项目,我想要像Subversion那样只克隆或拉取特定目录,比如myproject/javascript。
然后进行一些更改,提交并再次推送回去。
这是可能的吗?


3
稀疏检出可能会吸引您的注意(即使您仍然需要获取所有内容):请参见 https://dev59.com/-XE95IYBdhLWcg3wMa91#2416991。 - VonC
"Clone"和"pull"是Git中的两个不同操作。问题涉及到这两个操作,你已经得到了一些关于每个操作的答案,但有时并不清楚每个答案所针对的是哪一个操作,这很令人困惑。 - LarsH
如果您对GitHub特别感兴趣,请查看此答案:https://dev59.com/Tmw05IYBdhLWcg3wqzis#38879691 - Benjamin
我无法使得这个问题下的答案起作用;这个答案(在另一个SO问题下)对我有用 https://stackoverflow.com/a/63786181/6735035 - undefined
10个回答

244
  1. 进入你的代码库副本的顶层目录
  2. git fetch
  3. git checkout HEAD path/to/your/dir/or/file

    • (3)中的"path/..."从仓库根目录下的包含".../file"的目录开始

    • 注意,可以使用特定提交的哈希码替换"HEAD",那么你将会得到该提交所特有的修订版(文件)或多个修订版(目录)。


2
刚意识到我误解了问题。我的回复实际上是关于如何检出单个文件,然后进行修改和提交的。 - vergueishon
你已经回答了问题的标题,这已经足够好了。对我来说这是正确的答案,特别是因为在Google上这是搜索结果中排名最靠前的。 - Morgon
30
这仍会获取整个代码库。对于一个大小为2GB的项目来说,这样做并不能节省多少时间。 - Pithikos
9
对于那些阅读这些评论但不知道为什么这不能回答问题的人,这个解决方案只是给你一个仅包含那个文件夹的副本,但这不是一个工作副本,也就是说你不能修改并重新提交。所以正如 @Morgon 所说,它回答了问题标题(你可以拉取一个目录),但并没有回答问题正文中的内容("进行一些更改、提交和再次推送")。 - msb
@StanHolodnak 不需要 --。它强制其后的位被解释为路径。因此,如果您要检出一个名为 --help 的文件,那么需要在前面加上这些连字符:git checkout HEAD -- --help - Tim Visée

135
在一个空目录中:
git init
git remote add [REMOTE_NAME] [GIT_URL]
git fetch REMOTE_NAME
git checkout REMOTE_NAME/BRANCH -- path/to/directory

1
如果您只想使用远程文件版本替换本地文件,则可以使用此方法。 - John
这会拉取整个文件夹,如何不下载文件夹,而只下载文件夹中的内容呢? - Al Kasih
不需要使用fetchcheckout命令,我们可以在执行remote add命令后直接发起拉取请求来获取整个主分支。 - Iqra.
11
正如Pithkos在被接受的答案中所指出的那样,这个答案也会将整个远程仓库下载到您的本地机器。shingara的回答最清楚 - 没有办法远程获取仓库的一部分。然而,对于那些不介意带宽,对局部缓存感兴趣的人,被接受的答案向您展示了如何操作。但是我只想澄清一件事情,必须下载整个仓库的历史记录(以压缩格式)到您的机器上。 - Gabe Halsmer
请注意,此解决方案将丢失您的提交历史记录。 - dwjohnston

90

大多数答案/技术会下载整个代码库,即使你仅需要看到/使用其中的一部分。我不喜欢这样做,因为我正在处理的一些项目有很多对我没有兴趣的大文件。在寻找答案、发现没有、放弃、再次尝试等过程中,我最终在另一个SO线程中找到了解决方法:

如何 git-pull 除了一个文件夹之外的所有内容

复制粘贴该链接上的内容:

git init
git remote add -f origin <url>
git config core.sparsecheckout true
echo <dir1>/ >> .git/info/sparse-checkout
echo <dir2>/ >> .git/info/sparse-checkout
echo <dir3>/ >> .git/info/sparse-checkout
git pull origin master

为了实现 OP 想要的(只在一个目录中工作),只需将该目录添加到 .git/info/sparse-checkout,完成上述步骤时。这个解决方案只会下载你想要的,没有多余的东西。

非常感谢 @cforbish!


8
我将在此发布内容,主要是因为每当我尝试搜索如何做到这一点时,这是一个顶级结果,而那个帖子甚至都没有被显示出来。 :( 我觉得复制粘贴很不好,但我认为这是 Stack Overflow 最佳实践? - msb
5
这是唯一一个干净的解决方案。我尝试了上面的答案。在检出其他答案的分支后,我无法拉取,并且有几个新文件需要提交。使用这种解决方案一切看起来都正确。但请注意:无论检出哪个分支,git 都会认为你在 master 分支上。只需确保执行 git branch --set-upstream-to=origin/<branch> 以正确拉取。 - seebiscuit
1
因为分支不同,所以必须执行git read-tree -m -u HEAD(如此处所示:http://vmiklos.hu/blog/sparse-checkout-example-in-git-1-7)。 - TheMaster
1
无法使其工作;传递给git remote-f选项会立即获取整个仓库。请参考此Stack Overflow答案获取更多信息:https://stackoverflow.com/a/4909267/6735035 - undefined

43

如果你想在不进入目录的情况下获取最新的更改,你可以执行以下操作:

$ git -C <Path to directory> pull

17
也许这个命令可以帮助你:
git archive --remote=MyRemoteGitRepo --format=tar BranchName_or_commit  path/to/your/dir/or/file > files.tar

"Et voilà"


3
这将下载特定目录的文件以进行归档,但不会获取您可以修改并推送回去的副本。 - leetNightshade
4
很棒。也许不能作为对问题的解决方案,但它确实是我所需要的,因为我只需要搜索一个巨大的文件夹的内容,而这个文件夹在更大的代码库中,我绝对不想获取它,也不需要修改或提交。 - Oliver
正如@leetNightshade所说,这不是正确的回答方式。 - Arka Mukherjee

15

git clone --filter + git sparse-checkout 可以仅下载所需文件

我不确定 pull/fetch,但至少对于初始克隆,该选项是与远程协议的更新一起添加的,并且确实防止了从服务器下载对象。

例如,要仅克隆此存储库子目录 small/ 所需的对象: https://github.com/cirosantilli/test-git-partial-clone-big-small-no-bigtree,可以执行以下操作:

git clone -n --depth=1 --filter=tree:0 \
  https://github.com/cirosantilli/test-git-partial-clone-big-small-no-bigtree
cd test-git-partial-clone-big-small-no-bigtree
git sparse-checkout set --no-cone small
git checkout

我在这里更详细地介绍了:如何仅克隆Git存储库的子目录?

很可能无论在哪个领域实现git clone,也会有git pull类似物,但我还没有找到它。

在2021年1月测试了git 2.30.0。


12

这是不可能的。你需要拉取整个代码库,否则就什么也得不到。


1
尽管您需要获取所有内容,但在这种情况下,对稀疏检出工作树进行拉取是否有兴趣?请参见https://dev59.com/-XE95IYBdhLWcg3wMa91#2416991。 - VonC
11
补充一下,你不能仅拉取一个目录的原因是因为git使用数据语义跟踪而不是文件语义跟踪,因此你可以在不必告诉源跟踪系统的情况下(直到你更新为止),无缝地移动代码(或其他数据)进入和退出文件中。由于这个原因,代码也可以无缝地从一个目录移动到另一个目录,所以仅获取一个目录没有太多意义。希望能帮到你。 - OmnipotentEntity
14
抱歉,但依我看这是有道理的。实现不应该限制使用。Git 知道什么是目录(至少在创建本地工作副本时知道),因此没有理由它不能在服务器上执行类似的操作并只发送相关输出。当然,目前尚未实现,但这是由于缺少功能,而不是根本上的不可能性。就个人而言,我认为这是一个相当重要的功能,但嘿,这也是我尽可能避免使用 git 的原因之一。 - Basic

6
尝试过并经过测试,这个有效!
mkdir <directory name> ;  //Same directory name as the one you want to pull
cd <directory name>;
git remote add origin <GIT_URL>;
git checkout -b '<branch name>';
git config core.sparsecheckout true;
echo <directory name>/ >> .git/info/sparse-checkout;
git pull origin <pull branch name>

希望这对你有帮助!

2

对于像我一样在理论文件路径和示例方面有困难的人,这里提供一个真实世界的例子:微软在GitHub上提供了他们的文档和示例,不幸的是,他们将大量主题的所有示例文件都放在了同一个代码库中:

https://github.com/microsoftarchive/msdn-code-gallery-community-s-z

我只对路径中的Microsoft Dynamics js文件感兴趣。

msdn-code-gallery-community-s-z/Sdk.Soap.js/

所以我做了以下事情:
创建了一个
msdn-code-gallery-community-s-zSdkSoapjs\.git\info\sparse-checkout

在我的存储库文件夹中的磁盘上

git sparse-checkout init

在Windows系统中使用cmd进入该目录。
该文件的内容为:
msdn-code-gallery-community-s-zSdkSoapjs\.git\info\sparse-checkout

Sdk.Soap.js/*

最后进行一次操作。
git pull origin master

0
有时候,你只是想查看文件的以前版本,而不想通过差异比较的繁琐过程。
在这种情况下,很容易克隆一个存储库并检出你感兴趣的特定提交,然后查看该克隆存储库中的子目录。因为所有内容都是本地的,所以完成后可以直接删除此克隆。

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