52

命令git clone --depth选项说

--depth <depth> 
Create a shallow clone with a history truncated to the specified number of revisions. 
A shallow repository has a number of limitations 
(you cannot clone or fetch from it, nor push from nor into it),
 but is adequate if you are only interested in the recent history of a large project with a long history,
 and would want to send in fixes as patches. 

为什么浅克隆有这个限制?为什么它只是一个补丁工作流程?

对于某些项目工作流程,我只需将来自单个分支的最新提交传递给编码器,然后让他们能够将push其(快进)开发到主服务器。这部分是为了安全、IP 保护和 repo 大小,部分是为了减少大型 repo 给幼稚的编码人员带来的混乱。是否有允许这样做的 git 工作流程?


更新:根据 Karl Bielefeldt 的回答,git checkout --orphan应该是正确的答案。但是仍然需要将该分支单独“克隆”给新用户,并能够有效地推送它。

手册页指出:

git checkout [-q] [-f] [-m] [[-b|-B|--orphan] <new_branch>] [<start_point>] --orphan

创建一个新的孤立分支,命名为<new_branch>,开始于 <start_point> 并切换到它。在这个新分支上进行的第一次提交将没有父母,它将成为与所有其他分支和提交完全断开的新历史的根。

索引和工作树的调整就像您之前运行过一样git checkout <start_point>。这允许您开始一个新的历史记录,该历史记录记录一组类似于<start_point>通过轻松运行git commit -a以进行根提交的路径。

当您想从提交中发布树而不暴露其完整历史时,这可能很有用。您可能希望这样做以发布一个项目的开源分支,该项目的当前树是“干净的”,但其完整历史记录包含专有或其他受阻的代码位。

如果要开始记录一组与 中的路径完全不同的路径的断开连接的历史记录<start_point>,则应在创建孤立分支后立即通过git rm -rf .从工作树的顶层运行来清除索引和工作树。之后,您将准备好准备新文件、重新填充工作树、从其他地方复制它们、提取 tarball 等。

VonC 与 Junio 评论的链接很有趣。我认为手册应该在这种情况下提供指导,并允许正确的命令 [eg clone <branch> --options] 仅提取 repo 的相关部分。显然,push通过在历史底部有一些链接的提交和 SHA1 来增加成功的概率,这将锁定 repo 匹配。


更新 Git 1.9.0:发布说明 2014 年 2 月 14 日。

“过去禁止从浅克隆存储库中获取数据,主要是因为所涉及的代码路径没有经过仔细审查,我们也没有费心支持这种用法。此版本试图以更可控的方式允许对象从浅克隆存储库中传输出去(即接收器变成了一个具有截断历史的浅层存储库)。”

这对浅层克隆者来说是个好消息。下一步 - 可能是狭义克隆。

4

3 回答 3

22

正如 Junio C. Hamano(主要 Git 维护者)所说

规则是不是或多或少像:

如果您的浅层存储库的历史没有延长足够长的时间,并且另一个存储库在您的截断历史之前分叉,那么您将无法计算共同祖先并且您无法推出。

2014 年更新:请参阅“ git clone --depth 1 (shallow clone) 是否比实际使用的更有用? ”:Git 1.9 将取消该限制!

2015 年更新:使用 Git 2.5+,您甚至可以获取单个 commit。请参阅“从远程 git 存储库中拉取特定提交


原始答案(2011 年 8 月):

其实想一想,比“不能计算共同点”强多了。

历史可能是这样的:

          R---R---R
         /
  --R---R---X---X---S---S---S

S您在浅层存储库中的提交在哪里,以及R在接收您的推送的存储库中存在的提交。
因为您的历史很浅,所以两个存储库都没有“ X”,这些提交是为了保持收件人存储库的历史完整而需要存在的;接受者一开始并不肤浅,我们也不想让它变得肤浅。

如果您前段时间进行了浅层克隆,并且在另一方进行时未与另一方通信而工作,并且如果另一方的进度包括历史记录的倒带和重建,您将看到类似的拓扑。
上图中最左边的 ' S' 可能是当您以深度 1 进行浅层克隆时分支的尖端,从那时起,远程端可能已经丢弃了最上面的三个提交并重建了导致最右边的 ' R' 的历史记录。
在这种情况下,推送到遥控器HEAD将失败。


所以它在某些情况下可以工作,但不支持:

如果我不得不在这件事上说些什么……

  • 我认为“不支持”是提供足够好的信息的简洁方式,但它只适用于聪明的人。

  • 不是每个人都是聪明的;有些人自己尝试,发现该操作似乎适用于他们有限的试验次数,并且会得出结论它在大多数情况下都可以工作。
    他们祝贺自己的智慧说“大多数时候”,而不是“总是”。
    当他们看到它不起作用时,他们会感到不安,即使他们已经被警告过。


有关浅克隆更新过程的更多信息,请参阅“如何更新 git 浅克隆? ”。

于 2011-08-01T15:06:38.733 回答
11

是否有允许这样做的 git 工作流程?

是的,它是作为补丁发送修复程序。 git format-patch是专门为实现这一点而设计的。如果您想谷歌了解更多详细信息,它被称为“看门人”工作流程。很难相信像您这样关注“安全和 IP 保护”的组织还没有使用类似的东西,其中一个人或一小群人负责在“不受信任”的更改进入实际构建之前对其进行审查。


根据您的评论,我现在对您的要求有了更好的了解。我建议创建一个孤立分支(请参阅git checkout --orphan),无论您希望开发人员从哪个点开始。仅将该分支克隆到这些开发人员可以访问的不同存储库,并让他们从该存储库正常克隆、推送和拉取。

然后,当您需要将他们的更改重新集成到受保护的官方存储库中时,只需拉出他们的分支,制作它的副本,git branch这样您就不会覆盖原来的孤儿(以防您以后想重复该过程),然后重新建立副本到你原来的分支点,并合并或正常的任何东西。历史看起来就像他们直接从您受保护的仓库中工作一样。

这比正常情况要复杂一些,但这就是额外隔离所付出的代价。

于 2011-08-01T16:47:31.130 回答
1

我找到了使用 git bundles 的解决方法。

这个解决方案会像“git push”那样将完全相同的提交复制到其他存储库,并且不需要变基或导致提交 ID 更改。

不幸的是,它需要对目标主机进行 shell 访问(例如 ssh)。

我将通过示例展示解决方案。

首先,为了演示目的,我们需要获得一个浅克隆。

让我们从https://github.com/skarnet/s6-rc获取单个提交版本 v0.5.0.0作为浅层克隆到一个新的存储库中。

我将在我的示例中使用 shell 变量,而不是直接在命令中包含示例设置,因为这将允许您在将变量设置为适用于您的情况的不同值之后,将来自此帖子的指令直接复制/粘贴到您的 shell 中.

因此,请随意使用不同的 URL 和版本替换以下变量分配。

在我们的示例中,可以使用以下方法创建浅克隆:

$ url=https://github.com/skarnet/s6-rc
$ rel=v0.5.0.0
$ git init ${url##*/} && cd ${url##*/}
$ git pull --depth=1 "$url" $rel:master

这将创建一个包含新克隆的“s6-src”(使用上述变量值时)子目录。

现在我们的浅层克隆只包含一个提交,其所有父历史记录都在本地存储库中丢失,我们将这个单个提交捆绑到一个 git 捆绑文件中:

$ b=$rel.gbnd
$ git bundle create $b HEAD

这将使用之前设置的 shell 变量创建文件 v0.5.0.0.gbnd。

现在您必须将此文件复制到您通常希望推送到的目标机器上。(只有 git push 拒绝从浅层克隆推送,因此无法工作,至少不使用较旧的 git 版本。)

在目标主机上,执行以下操作以创建一个新存储库作为子目录,其中包含与之前捆绑的相同提交:

$ url=https://github.com/skarnet/s6-rc
$ rel=v0.5.0.0
$ git init ${url##*/} && cd ${url##*/}
$ c=`git bundle unbundle $b | cut -d " " -f 1`; echo "$c"
$ git tag $rel $c # optional: create a tag for the imported commit.
$ git reset --hard $c
$ git fetch --depth=1 .

请注意,您应该将变量设置为与在从中复制包的主机上所做的相同的值。

另请注意,您可以省略存储库已经存在的“git init”。

而已!

但是,后面的说明仅适用于定期结帐。

也许您想将浅层克隆包导入“裸”存储库。

在这种情况下,请改为执行以下操作:

$ url=https://github.com/skarnet/s6-rc
$ rel=v0.5.0.0
$ cd ${url##*/}.git
$ c=`git bundle unbundle $b | cut -d " " -f 1`; echo "$c"
$ git tag $rel $c
$ git fetch --depth=1 . $rel
于 2020-04-05T08:02:55.203 回答