我有一个Git仓库,根目录下有两个子目录:
/finisht
/static
当这个项目在SVN上时,/finisht
被检出到一个地方,而/static
则被检出到另一个地方,如下所示:
svn co svn+ssh://admin@domain.example/home/admin/repos/finisht/static static
有没有使用Git的方法可以实现这个?
我有一个Git仓库,根目录下有两个子目录:
/finisht
/static
当这个项目在SVN上时,/finisht
被检出到一个地方,而/static
则被检出到另一个地方,如下所示:
svn co svn+ssh://admin@domain.example/home/admin/repos/finisht/static static
有没有使用Git的方法可以实现这个?
mkdir <repo>
cd <repo>
git init
git remote add -f origin <url>
这将创建一个空白的存储库与您的远程,并获取所有对象但不检出它们。然后执行:
git config core.sparseCheckout true
现在你需要定义要实际检出的文件/文件夹。这可以通过在.git/info/sparse-checkout
中列出它们来完成,例如:
echo "some/dir/" >> .git/info/sparse-checkout
echo "another/sub/tree" >> .git/info/sparse-checkout
最后,使用远程状态更新您的空仓库:
git pull origin master
现在,您的文件系统上将为“some/dir”和“another/sub/tree”检出文件(仍具有这些路径),没有其他路径存在。
您可能想查看扩展教程,并且应该阅读官方稀疏检出文档和read-tree。
作为一个函数:
function git_sparse_clone() (
rurl="$1" localdir="$2" && shift 2
mkdir -p "$localdir"
cd "$localdir"
git init
git remote add -f origin "$rurl"
git config core.sparseCheckout true
# Loops over remaining args
for i; do
echo "$i" >> .git/info/sparse-checkout
done
git pull origin master
)
使用方法:
git_sparse_clone "http://github.com/tj/n" "./local/location" "/bin"
git sparse-checkout init
# same as:
# git config core.sparseCheckout true
git sparse-checkout set "A/B"
# same as:
# echo "A/B" >> .git/info/sparse-checkout
git sparse-checkout list
# same as:
# cat .git/info/sparse-checkout
https://github.com/Umkus/nginx-boilerplate/tree/master/src
的内容直接克隆到 /etc/nginx
。 - macgit remote add
命令并不意味着要进行拉取(fetch), 但是在这里使用的 git remote add -f
命令会执行拉取(fetch)操作!这就是 -f
的含义。 - ntc2--depth=1
,我克隆了 Chromium Devtools,只需要338MB的空间而不是完整的 Blink 源代码和历史记录,其大小为4.9GB。太好了! - Rudiegit clone --filter
+ git sparse-checkout
可以仅下载所需的文件
例如,要在此测试存储库中仅克隆子目录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 sparse-checkout set --no-cone small small2
这种方法不能用于单个文件,但是有另一种方法可以实现:如何从git仓库中稀疏地只检出一个文件?
在这个测试中,克隆基本上是瞬间完成的,并且我们可以确认克隆的仓库非常小,符合我们的要求:
du --apparent-size -hs * .* | sort -hs
提供:
2.0K small
226K .git
该测试仓库包含以下内容:
big/
的子目录,其中包含10个大小为10MB的文件0
、1
、... 9
(这是因为之前的某些尝试会下载顶层文件)small/
和small2/
的子目录,其中包含1000个大小为一个字节的文件所有内容都是伪随机的,因此不可压缩,因此我们可以轻松地注意到是否下载了任何大文件,例如使用ncdu
。
因此,如果您下载了任何不想要的内容,您将获得额外的100 MB,并且这将非常明显。
在上述情况下,git clone
会下载单个对象,可能是提交:
Cloning into 'test-git-partial-clone-big-small'...
remote: Enumerating objects: 1, done.
remote: Counting objects: 100% (1/1), done.
remote: Total 1 (delta 0), reused 1 (delta 0), pack-reused 0
Receiving objects: 100% (1/1), done.
然后最终的结帐会下载我们请求的文件:
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 3 (delta 0), pack-reused 0
Receiving objects: 100% (3/3), 10.19 KiB | 2.04 MiB/s, done.
remote: Enumerating objects: 253, done.
remote: Counting objects: 100% (253/253), done.
Receiving objects: 100% (253/253), 2.50 KiB | 2.50 MiB/s, done.
remote: Total 253 (delta 0), reused 253 (delta 0), pack-reused 0
Your branch is up to date with 'origin/master'.
在2023年1月,已在git 2.37.2和Ubuntu 22.10上进行了测试。
TODO 还要防止下载不必要的树对象
上述方法会下载所有Git树对象(即目录列表,但不包括实际文件内容)。我们可以通过运行以下命令来确认:
git ls-files
而且看到它包含了像这样的大文件目录:
big/0
在大多数项目中,这不应该是一个问题,因为相对于实际文件内容来说,它们应该很小,但完美主义者的我想避免它们。
我还创建了一个非常极端的存储库,其中包含一些非常大的树对象(100 MB),位于目录big_tree
下:https://github.com/cirosantilli/test-git-partial-clone-big-small
如果有人找到了从中克隆small/
目录的方法,请告诉我!
关于命令:
--filter
选项是与远程协议更新一起添加的,它确实防止从服务器下载对象。
不幸的是,sparse-checkout
部分也是必需的。您还可以使用更易理解的方式仅下载某些文件。
git clone --depth 1 --filter=blob:none --no-checkout \
https://github.com/cirosantilli/test-git-partial-clone-big-small
cd test-git-partial-clone-big-small
git checkout master -- d1
但是由于某种原因,该方法逐个下载文件非常缓慢,除非目录中只有很少的文件,否则它是无法使用的。
另一个不那么冗长但失败的尝试是:
git clone --depth 1 --filter=blob:none --sparse \
https://github.com/cirosantilli/test-git-partial-clone-big-small
cd test-git-partial-clone-big-small
git sparse-checkout set small
但是这会下载顶级目录中的所有文件:如何防止 git clone --filter=blob:none --sparse 从根目录下载文件?
梦想:任何目录都可以拥有 Web 接口元数据
这个功能可以彻底改变 Git。
想象一下,将企业的所有代码库 存储在单个 monorepo 中,而不需要 丑陋的第三方工具,如 repo
。
想象一下,直接将大型 blob 存储在 repo 中,而不需要任何丑陋的第三方扩展。
想象一下,如果GitHub允许像星标和权限这样的每个文件/目录元数据,那么您可以将所有个人物品存储在单个仓库中。
想象一下,如果子模块被视为常规目录:只需请求树SHA,以及类似于DNS的机制解决您的请求,首先查找您的本地 ~ / .git
,然后是更接近的服务器(您企业的镜像/缓存),最后到达GitHub。
我有一个梦想。
测试圆锥体单存储库哲学
这是一种无需子模块维护的单存储库维护的可能哲学。
我们希望避免使用子模块,因为每次更改具有子模块和非子模块组件时,都必须在两个不同的存储库中进行提交,这很麻烦。
每个具有Makefile或类似文件的目录都应该构建和测试自己。
这样的目录可能取决于以下两种情况:
在git原生支持此功能之前(即只能跟踪子目录的子模块),我们可以通过git追踪的某些元数据来支持此功能:
monorepo.json
{
"path": "some/useful/lib",
"sha": 12341234123412341234,
}
这里的sha
指的是整个代码库的常规SHA。然后我们需要脚本来检出这些目录,例如在一个被Git忽略的monorepo
文件夹下:
monorepo/som/useful/lib
每当您更改文件时,都必须向上遍历树并测试所有具有Makefile的目录。这是因为目录可以依赖于其最新版本的子目录,因此您可能会破坏上面的某些内容。
相关:
filter=tree:0
也会防止下载blob(除了HEAD顶级目录中的文件)。因此,您不需要将其与blob:none
组合使用。 - Socowi编辑:截至Git 2.19,这是可能的,可参见此答案。
请考虑为该答案点赞。
注意:在Git 2.19中,仅实现了客户端支持,服务器端支持仍然缺失,因此仅在克隆本地存储库时才能使用。另请注意,大型Git主机商,例如GitHub,实际上并未使用Git服务器,他们使用自己的实现,因此即使支持出现在Git服务器上,也不自动意味着它可以在Git主机商上工作。(另一方面,由于他们没有使用Git服务器,他们可以在Git服务器出现之前更快地在自己的实现中实现它。)
不,这在Git中是不可能的。
在Git中实现类似这样的功能需要大量的工作,并且意味着客户端存储库的完整性不能再得到保证。如果您感兴趣,请搜索有关git邮件列表中“稀疏克隆”和“稀疏获取”的讨论。
一般而言,Git社区的共识是,如果您有几个始终独立检出的目录,则这些目录实际上是两个不同的项目,应该存在于两个不同的存储库中。您可以使用Git子模块将它们粘合在一起。
git-read-tree
期间发生的,这是在get-fetch
之后很久才发生的。问题不是关于仅检出子目录,而是关于仅克隆子目录。我不明白如何通过稀疏检出实现这一点,因为git-read-tree
是在克隆完成后运行的。 - Jörg W Mittag你可以结合使用稀疏检出和浅克隆功能。 浅克隆会截断历史记录,而稀疏检出则只拉取与您模式匹配的文件。
git init <repo>
cd <repo>
git remote add origin <url>
git config core.sparsecheckout true
echo "finisht/*" >> .git/info/sparse-checkout
git pull --depth=1 origin master
为了使这个工作正常,您需要至少使用 git 1.9。我自己只测试过 2.2.0 和 2.2.2 版本。
这样,您仍然可以推送,但是使用git archive
是不可能的。
git pull --depth=1 origin master
而是 git pull --depth=1 origin <any-other-branch>
时,对我来说无效。这太奇怪了,请参见我的问题:https://dev59.com/H5Tfa4cB1Zd3GeqPVcfR - Shuman对于其他只想从GitHub下载文件/文件夹的用户,只需使用:
svn export <repo>/trunk/<folder>
需要翻译的内容已经包含在了 "" 和 "
" 标签之间,因此只需将这两个标签保留,并将其余部分翻译为中文即可,即 "例如。"svn export https://github.com/lodash/lodash.com/trunk/docs
是的,这里用的是svn。显然在2016年,你仍然需要使用svn才能简单地下载一些Github文件。
来源:从GitHub repo下载单个文件夹或目录
重要提示 - 确保您更新Github网址并将/tree/master/
替换为“/trunk/”。
作为bash脚本:git-download(){
folder=${@/tree\/master/trunk}
folder=${folder/blob\/master/trunk}
svn export $folder
}
注意:此方法下载的是文件夹,而不是克隆/检出它。您无法将更改推送回存储库。另一方面,与稀疏检出或浅层检出相比,这会导致更小的下载量。
https://github.com/tensorflow/tensorflow/tree/master/tensorflow/examples/trunk/udacity
,但是出现了svn: E170000: URL 'https://github.com/tensorflow/tensorflow/tree/master/tensorflow/examples/trunk/udacity' doesn't exist
的错误 :( 尝试使用此链接,但出现了错误提示,该链接不存在。 - zthomas.nc2022年的答案
我不确定为什么有这么多复杂的答案来回答这个问题。通过对存储库进行稀疏克隆,可以轻松地将其克隆到所需的文件夹中。
cmd
并运行以下命令。git clone --filter=blob:none --sparse %your-git-repo-url%
cd %the repository directory%
git sparse-checkout add %subdirectory-to-be-cloned%
cd %your-subdirectory%
哇!现在您只克隆了您想要的子目录!
解释 - 这些命令实际上是做什么的?
git clone --filter=blob:none --sparse %your-git-repo-url%
在上述命令中,
--filter=blob:none
=> 你告诉 git 你只想克隆元数据文件。这样,git 会收集远程的基本分支详细信息和其他元数据,以确保以后从源代码库检出的时候更加顺利。--sparse
=> 告诉 git 这是一个稀疏克隆。在这种情况下,git 只会检出根目录。现在 git 已经获得了元数据并准备好检出任何你想要处理的子目录/文件。
git sparse-checkout add gui-workspace ==> Checkout folder
git sparse-checkout add gui-workspace/assets/logo.png ==> Checkout a file
通过稀疏克隆,特别是当存在一个包含多个子目录的大型仓库,并且您不总是在所有子目录上工作时,非常有用。在对大型仓库进行稀疏克隆时,可以节省大量时间和带宽。
此外,现在在这个部分克隆的仓库中,您可以继续像往常一样检出和工作。所有这些命令都能正常工作。
git switch -c %new-branch-name% origin/%parent-branch-name% (or) git checkout -b %new-branch-name% origin/%parent-branch-name%
git commit -m "Initial changes in sparse clone branch"
git push origin %new-branch-name%
git switch
命令替换 旧的、混乱的和过时的 git checkout
命令?git switch -c %new-branch-name% origin/%parent-branch-name%
- VonCgit sparse-checkout ...
之前,我必须先cd $CLONEDIR/$REPO_DIRNAME
。你能修改一下吗?谢谢 :-) - Paddy3118如果你从未计划与克隆源互动,你可以使用完整的git clone
命令并使用以下方式重写你的存储库
git filter-branch --subdirectory-filter <subdirectory>
这样做,至少可以保留历史记录。
git filter-branch --subdirectory-filter <subdirectory>
。 - Jaime Hablutzelgit clone https://github.com/your/repo_xx.git && cd repo_xx && git filter-branch --subdirectory-filter repo_xx_subdir
。 - Alex这个看起来简单得多:
git archive --remote=<repo_url> <branch> <path> | tar xvf -
svn export
代替。 - Milo Wielondek您可能希望重写存储库,使其看起来像trunk/public_html/
是其项目根目录,并丢弃所有其他历史记录(使用filter-branch
),在已经检出的分支上尝试:
git filter-branch --subdirectory-filter trunk/public_html -- --all
注意:使用--
将过滤选项与修订选项分开,以及--all
重写所有分支和标签。所有信息,包括原始提交时间或合并信息,都将被保留。此命令遵守.git/info/grafts
文件和refs/replace/
命名空间中的引用,因此如果您定义了任何嫁接或替换refs
,运行此命令将使它们永久化。
警告!重写的历史记录将对所有对象具有不同的对象名称,并且不会与原始分支收敛。您将无法轻松地将重写的分支推送和分发到原始分支上。如果您不知道完整含义,请不要使用此命令,并且如果一个简单的单个提交就足以解决您的问题,请避免使用它。
这里是使用稀疏检出方法的简单步骤,它会在工作目录中稀疏地填充文件,因此您可以告诉Git哪个文件夹或文件值得检出。
Clone repository as usual (--no-checkout
is optional):
git clone --no-checkout git@foo/bar.git
cd bar
You may skip this step, if you've your repository already cloned.
Hint: For large repos, consider shallow clone (--depth 1
) to checkout only latest revision or/and --single-branch
only.
Enable sparseCheckout
option:
git config core.sparseCheckout true
Specify folder(s) for sparse checkout (without space at the end):
echo "trunk/public_html/*"> .git/info/sparse-checkout
or edit .git/info/sparse-checkout
.
Checkout the branch (e.g. master
):
git checkout master
filter-branch
会重写父提交,因此它们将具有不同的SHA1 ID,因此您筛选后的树与远程树没有共同的提交。git pull
不知道从哪里尝试合并。 - Peter Cordes
git clone
最简单的命令是什么?我使用了这个简单的答案。如果有更简单的方法,请评论。 - Peter Krauss