在没有.git目录的情况下进行Git克隆

217

在进行克隆时,是否有可以传递给git的标志,比如说不要克隆.git目录?如果没有,那么是否有一个标志可以在克隆之后删除.git目录?


46
这个问题与如何执行“git export”(类似于“svn export”) 不是 重复的。这个问题询问如何在没有.git目录的情况下克隆(远程)存储库。所谓的重复问题是询问如何导出已经有.git目录的现有存储库。 - mknaf
3
同意。正如“可能的重复”解决方案所说,你不能使用git archive命令归档远程存储库。 - Vladislav Rastrusny
9个回答

295
使用
git clone --depth=1 --branch=master git://someserver/somerepo dirformynewrepo
rm -rf ./dirformynewrepo/.git
  • depth选项会确保尽可能少地复制历史记录以获取该仓库。
  • branch选项是可选的,如果未指定,则会获取默认分支。
  • 第二行将使您的目录 dirformynewrepo 不再是Git仓库。
  • 如果您正在进行递归子模块克隆,则深度和分支参数不适用于子模块。

15
如果您有兴趣,这是Bash和zsh中“历史扩展”功能的一部分,其中之一是“单词指示符”之一。 - Rufflewind
1
有没有一种方法可以获取存储库中所有分支的深度=1?而不仅仅是主分支或指定分支。 - Gayan Pathirage
3
你可以使用 --no-single-branch 选项来完成此操作,因为 --depth 隐含了 --single-branch,你可以通过 --no-single-branch 取消隐含的效果。(摘自 git clone 手册页) - Robert Stoddard
19
在这种情况下,使用!$虽然在技术上是正确的,但对于不熟悉语法的人来说并没有帮助他们理解实际问题的答案。它还依赖于第二个命令直接跟随第一个命令,并且在同一个shell中执行。如果有人省略了这些隐含的要求,他们可能会意外删除其他内容。因此,我建议您通过显式指定名称dirformynewrepo作为rm命令的参数来改进您的答案,因为这将使两个命令之间的关联更加清晰。 - davidA
1
为什么不使用 git --git-dir=/dev/null 呢? - Rainb
显示剩余4条评论

36

因为您只需要文件,所以不需要将其视为git仓库。

rsync -rlp --exclude '.git' user@host:path/to/git/repo/ .

这仅适用于本地路径和远程ssh/rsync路径,如果远程服务器仅提供git://或https://访问,则可能无法正常工作。


1
不考虑 .gitignore 文件,怎样处理? - JJ Roman
itub 是正确的,这只是复制工作树。git checkout 曾经可以很好地完成这项工作,现在不再能够了。 - Sylvain
2
那么,如果服务器只提供git://访问,你该怎么办? - Rainb

24

或者,如果您已经安装了Node.js,您可以使用以下命令:

npx degit GIT_REPO

npx随同Node一起提供,并且它允许您在不先安装它们的情况下运行基于二进制节点的软件包(或者,您可以使用npm i -g degit全局安装degit)。

Degit是由Rich Harris创建的一个工具,他是Svelte和Rollup的创建者,他使用它通过克隆存储库来快速创建新项目而不保留git文件夹。但它也可以用于仅克隆任何repo...


11
git clone --separate-git-dir=$(mktemp -u) --depth=1 <repo> <dir> && rm <dir>/.git

我更喜欢这个解决方案,因为我不喜欢自动删除东西的 rm -rf。它只会 rm 掉 .git 文件,这意味着它永远不会意外地 rm -rf 错误的 .git 目录。

它依赖于 mktemp 命令,因此只能在 *nix 系统上运行(从我的了解来看,在 MacOS 上需要进一步处理才能让 mktemp 正常工作,如果有人想评论一个可行的解决方案,我会添加它)

在 zsh 中,我将其制作成一个函数,以确保定义了一个 dir 值:

alias np='node-project'
function node-project() {
  dir=${1:-.}
  git clone --separate-git-dir=$(mktemp -u) --depth=1 <my-node-repo> $dir && rm $dir/.git
}

解释

--separate-git-dir标志允许您指定.git目录的路径。结果生成的“项目”将有一个.git文件(而不是目录),其内容将是单行:

gitdir: <the dir you specified in the flag>

因为我们使用了带有mktemp命令的tmp目录,实际的.git目录内容将最终保存在一个tmp目录中。我们还使用了--depth = 1,因此在tmp目录上需要更少的空间。


4
澄清一点 - 这仍然会创建一个 .git 等效文件夹,只是存储在 mktemp 选择的位置,而不是 git clone 目标。当您按照此答案执行 rm <dir>/.git 时,实际上只是删除到在其他地方创建的临时文件夹的符号链接,其中包含正常的 .git 文件。这些文件将保留,直到操作系统自动清理 --separate-git-dir 使用的临时目录。因此,为了正确清理,您可能仍然需要使用 rm -rf,只是针对存储在临时文件夹中而不是克隆目标中的 git 文件夹。 - mbafford

5

对于那些怀疑使用--depth 1解决方案的人,因为它仍然会下载.git目录并且需要手动删除它,也许你需要了解git clone实际工作原理

当你正常地克隆一个repo时,git会将所有文件(跨越提交)下载到.git目录中。当你使用--depth 1克隆时,git只会将最新版本的文件下载到.git中。之后,git会checkout或从.git中检索这些文件到工作目录中(不再进行下载)。

通常情况下,由于.git内部的文件对象是压缩的,因此通过git clone --depth 1下载文件比下载未压缩的文件可以节省更多带宽。对于一些网络较慢的人来说,这是值得的(需要运行rm -rf命令的代价)。

我个人认为git archive解决方案更好,但由于GitHub不支持,--depth 1是可行的选择。

1
如果是GitHub,为什么不直接使用 curl -L https://github.com/${owner}/${repo}/tarball/master | tar xz 呢? - Des Nerger
@DesNerger 因为我们可以使用ssh轻松地从私有仓库进行克隆。 - M Imam Pratama

2
如果存储库在GitHub上,您可以简单地下载任何标签的ZIP文件。
curl -L https://github.com/<user>/<repo-name>/archive/refs/tags/v1.2.3.zip | tar xz

这将下载并解压存储库。内容将位于<repo-name>-1.2.3文件夹中,没有.git文件夹。

1
非常巧妙的技巧,但有很多Git存储库不托管在GitHub上。 - Carl Winbäck
1
好的观点。嗯。他们应该简单地转移到GitHub上。我开玩笑的。我相信也可能在其他主机上做类似的事情。 - sensorario

1

git archive --remote 已经实现了这个功能。


1
我尝试了在线文章中提到的任何 git archive --remote 组合,但都失败了,并显示 Invalid command: 'git-upload-archive '<repo>' - Guido Tarsia
尝试:git archive --remote git@gitlab.com:gitlab-org/gitlab.git -o gitlab_15.9.3ee.tgz v15.9.3-ee - mr.wolle
LFS文件可能不是归档的一部分。 - mr.wolle

1
git clone --depth=1 --branch=master git://someserver/somerepo dirformynewrepo1
rd /s /q  .\dirformynewrepo1\.git

这适用于Windows系统


-2

你总是可以做到的

git clone git://repo.org/fossproject.git && rm -rf fossproject/.git

55
下载所有文件后再删除目录?例如,Emacs的.git文件夹占用了1GB的95%。因此,使用"--depth=1"选项显然是解决方案。 - RParadox
2
当我使用depth=1时,仍然可以看到.git文件夹。 - Aryeh Armon
2
@AryehArmon 当然可以看到。使用--depth并不能阻止.git的创建,它只是创建了一个浅拷贝,.git的大小会变得更小。但是如果你不想要它存在,那么你需要在之后将其删除。 - zeycus

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