如何仅克隆 Git 存储库的子目录?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/600079/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I clone a subdirectory only of a Git repository?
提问by Nick Sergeant
I have my Git repository which, at the root, has two sub directories:
我有我的 Git 存储库,它的根目录有两个子目录:
/finisht
/static
When this was in SVN, /finisht
was checked out in one place, while /static
was checked out elsewhere, like so:
当这是在SVN 中时,/finisht
在一个地方/static
签出,而在其他地方签出,如下所示:
svn co svn+ssh://[email protected]/home/admin/repos/finisht/static static
Is there a way to do this with Git?
有没有办法用 Git 做到这一点?
采纳答案by J?rg W Mittag
EDIT: As of Git 2.19, this is finally possible, as can be seen in this answer.
编辑:从 Git 2.19 开始,这终于成为可能,正如在这个答案中所见。
Consider upvoting that answer.
考虑支持该答案。
Note: in Git 2.19, only client-side support is implemented, server-side support is still missing, so it only works when cloning local repositories. Also note that large Git hosters, e.g. GitHub, don't actually use the Git server, they use their own implementation, so even if support shows up in the Git server, it does not automatically mean that it works on Git hosters. (OTOH, since they don't use the Git server, they could implement it faster in their own implementations before it shows up in Git server.)
注意:在 Git 2.19 中,只实现了客户端支持,仍然缺少服务器端支持,所以它只在克隆本地存储库时有效。另请注意,大型 Git 托管商,例如 GitHub,实际上并不使用 Git 服务器,他们使用自己的实现,因此即使 Git 服务器中显示支持,也并不自动意味着它适用于 Git 托管商。(OTOH,由于他们不使用 Git 服务器,因此他们可以在自己的实现中更快地实现它,然后才会出现在 Git 服务器中。)
No, that's not possible in Git.
不,这在 Git 中是不可能的。
Implementing something like this in Git would be a substantial effort and it would mean that the integrity of the clientside repository could no longer be guaranteed. If you are interested, search for discussions on "sparse clone" and "sparse fetch" on the git mailinglist.
在 Git 中实现这样的东西将是一项巨大的努力,这意味着无法再保证客户端存储库的完整性。如果您有兴趣,请在 git 邮件列表上搜索有关“稀疏克隆”和“稀疏获取”的讨论。
In general, the consensus in the Git community is that if you have several directories that are always checked out independently, then these are really two different projects and should live in two different repositories. You can glue them back together using Git Submodules.
一般而言,Git 社区的共识是,如果您有多个始终独立检出的目录,那么它们实际上是两个不同的项目,应该存在于两个不同的存储库中。您可以使用Git Submodules将它们重新粘合在一起。
回答by Chronial
What you are trying to do is called a sparse checkout, and that feature was added in git 1.7.0 (Feb. 2012). The steps to do a sparse cloneare as follows:
您正在尝试做的称为sparse checkout,该功能已添加到 git 1.7.0(2012 年 2 月)中。进行稀疏克隆的步骤如下:
mkdir <repo>
cd <repo>
git init
git remote add -f origin <url>
This creates an empty repository with your remote, and fetches all objects but doesn't check them out. Then do:
这会使用您的遥控器创建一个空的存储库,并获取所有对象但不检查它们。然后做:
git config core.sparseCheckout true
Now you need to define which files/folders you want to actually check out. This is done by listing them in .git/info/sparse-checkout
, eg:
现在您需要定义要实际检出的文件/文件夹。这是通过在 中列出它们来完成的.git/info/sparse-checkout
,例如:
echo "some/dir/" >> .git/info/sparse-checkout
echo "another/sub/tree" >> .git/info/sparse-checkout
Last but not least, update your empty repo with the state from the remote:
最后但并非最不重要的一点是,使用远程状态更新您的空仓库:
git pull origin master
You will now have files "checked out" for some/dir
and another/sub/tree
on your file system (with those paths still), and no other paths present.
现在,您将拥有的文件“签出”的some/dir
和another/sub/tree
您的文件系统(与路径仍然),并没有其他路径存在。
You might want to have a look at the extended tutorialand you should probably read the official documentation for sparse checkout.
您可能想查看扩展教程,并且您可能应该阅读sparse checkout的官方文档。
As a function:
作为一个函数:
function git_sparse_clone() (
rurl="" localdir="" && 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
)
Usage:
用法:
git_sparse_clone "http://github.com/tj/n" "./local/location" "/bin"
Note that this will still download the whole repository from the server – only the checkout is reduced in size. At the moment it is not possible to clone only a single directory. But if you don't need the history of the repository, you can at least save on bandwidth by creating a shallow clone. See udondan's answerbelow for information on how to combine shallow cloneand sparse checkout.
请注意,这仍会从服务器下载整个存储库 - 仅减小了检出的大小。目前不可能只克隆一个目录。但是如果你不需要存储库的历史,你至少可以通过创建一个浅克隆来节省带宽。有关如何结合浅克隆和稀疏结帐的信息,请参阅下面的udondan 答案。
As of git 2.25.0 (Jan 2020) an experimental sparse-checkoutcommand is added in git:
从 git 2.25.0(2020 年 1 月)开始,在 git 中添加了一个实验性的sparse-checkout命令:
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
回答by udondan
You can combine the sparse checkoutand the shallow clonefeatures. The shallow clonecuts off the history and the sparse checkoutonly pulls the files matching your patterns.
您可以结合稀疏结帐和浅克隆功能。在浅克隆切断历史和稀疏结帐只翻出符合模式的文件。
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
You'll need minimum git 1.9 for this to work. Tested it myself only with 2.2.0 and 2.2.2.
你需要最低 git 1.9 才能工作。我自己只用 2.2.0 和 2.2.2 测试过。
This way you'll be still able to push, which is not possible with git archive
.
这样,您仍然可以推送,而git archive
.
回答by Anona112
For other users who just want to downloada file/folder from github, simply use:
对于只想从 github下载文件/文件夹的其他用户,只需使用:
svn export <repo>/trunk/<folder>
e.g.
例如
svn export https://github.com/lodash/lodash.com/trunk/docs
(yes, that's svn here. apparently in 2016 you still need svn to simply download some github files)
(是的,这里是 svn。显然在 2016 年你仍然需要 svn 来简单地下载一些 github 文件)
Courtesy: Download a single folder or directory from a GitHub repo
Important- Make sure you update the github URL and replace /tree/master/
with '/trunk/'.
重要- 确保更新 github URL 并替换/tree/master/
为“/trunk/”。
As bash script:
作为 bash 脚本:
git-download(){
folder=${@/tree\/master/trunk}
folder=${folder/blob\/master/trunk}
svn export $folder
}
NoteThis method downloads a folder, does not clone/checkout it. You can't push changes back to the repository. On the other hand - this results in smaller download compared to sparse checkout or shallow checkout.
注意此方法下载文件夹,而不是克隆/检出它。您无法将更改推送回存储库。另一方面 - 与稀疏结帐或浅结帐相比,这会导致较小的下载。
回答by hillu
If you never plan to interact with the repository from which you cloned, you can do a full git cloneand rewrite your repository using git filter-branch --subdirectory-filter. This way, at least the history will be preserved.
如果您从不打算与从中克隆的存储库进行交互,您可以执行完整的git clone并使用git filter-branch --subdirectory-filter重写您的存储库。这样,至少可以保留历史。
回答by ErichBSchulz
回答by Chris Johnsen
Git 1.7.0 has “sparse checkouts”. See “core.sparseCheckout” in the git configmanpage, “Sparse checkout” in the git read-treemanpage, and “Skip-worktree bit” in the git update-indexmanpage.
Git 1.7.0 具有“稀疏结帐”功能。请参阅git config 手册页中的“core.sparseCheckout”、git read-tree 手册页中的“Sparse checkout”和git update-index 手册页中的“Skip-worktree bit” 。
The interface is not as convenient as SVN's (e.g. there is no way to make a sparse checkout at the time of an initial clone), but the base functionality upon which simpler interfaces could be built is now available.
该界面不如 SVN 方便(例如,在初始克隆时无法进行稀疏检出),但现在可以使用可构建更简单界面的基本功能。
回答by kenorb
It's not possible to clone subdirectory only with Git, but below are few workarounds.
仅使用 Git 无法克隆子目录,但以下是一些解决方法。
Filter branch
过滤器分支
You may want to rewrite the repository to look as if trunk/public_html/
had been its project root, and discard all other history (using filter-branch
), try on already checkout branch:
您可能希望重写存储库以使其看起来好像trunk/public_html/
是它的项目根目录,并丢弃所有其他历史记录(使用filter-branch
),尝试使用已经结帐的分支:
git filter-branch --subdirectory-filter trunk/public_html -- --all
Notes: The --
that separates filter-branch options from revision options, and the --all
to rewrite all branches and tags. All information including original commit times or merge information will be preserved. This command honors .git/info/grafts
file and refs in the refs/replace/
namespace, so if you have any grafts or replacement refs
defined, running this command will make them permanent.
注意:--
将过滤器分支选项与修订选项分开,并--all
重写所有分支和标签。包括原始提交时间或合并信息在内的所有信息都将被保留。此命令尊重命名空间.git/info/grafts
中的文件和引用refs/replace/
,因此如果您refs
定义了任何移植或替换,运行此命令将使它们永久化。
Warning! The rewritten history will have different object names for all the objects and will not converge with the original branch. You will not be able to easily push and distribute the rewritten branch on top of the original branch. Please do not use this command if you do not know the full implications, and avoid using it anyway, if a simple single commit would suffice to fix your problem.
警告!重写后的历史将对所有对象具有不同的对象名称,并且不会与原始分支收敛。您将无法轻松地将重写的分支推送和分发到原始分支之上。如果您不知道全部含义,请不要使用此命令,并且如果简单的单次提交就足以解决您的问题,请避免使用它。
Sparse checkout
稀疏结帐
Here are simple steps with sparse checkoutapproach which will populate the working directory sparsely, so you can tell Git which folder(s) or file(s) in the working directory are worth checking out.
以下是使用稀疏检出方法的简单步骤,它将稀疏地填充工作目录,因此您可以告诉 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 (withoutspace 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
照常克隆存储库(
--no-checkout
可选):git clone --no-checkout git@foo/bar.git cd bar
如果您已经克隆了存储库,则可以跳过此步骤。
提示:对于大型存储库,请考虑使用浅克隆(
--depth 1
) 仅检出最新修订版或/且--single-branch
仅检出。启用
sparseCheckout
选项:git config core.sparseCheckout true
指定用于稀疏结帐的文件夹(末尾没有空格):
echo "trunk/public_html/*"> .git/info/sparse-checkout
或编辑
.git/info/sparse-checkout
.结帐分支(例如
master
):git checkout master
Now you should have selected folders in your current directory.
现在您应该已经在当前目录中选择了文件夹。
You may consider symbolic links if you've too many levels of directories or filtering branch instead.
如果您有太多级别的目录或过滤分支,您可以考虑使用符号链接。
回答by david_adler
回答by BARJ
This will clone a specific folder and remove all history not related to it.
这将克隆特定文件夹并删除与其无关的所有历史记录。
git clone --single-branch -b {branch} [email protected]:{user}/{repo}.git
git filter-branch --subdirectory-filter {path/to/folder} HEAD
git remote remove origin
git remote add origin [email protected]:{user}/{new-repo}.git
git push -u origin master