Git浅层子模块

是否有可能有浅的子模块? 我有一个超级项目,有几个子模块,每个子模块都有很长的历史,所以它不必要的拖累了所有的历史。

我发现的是这个未答复的线程 。

我应该只是破解git-submodule来实现这个?

新git1.8.4(2013年7月) :

git submodule update ”可以select性地克隆子模块存储库。

(而git 2.10 Q3 2016允许使用git config -f .gitmodules submodule.<name>.shallow true
看到这个答案的结尾)

见提交275cd184d52b5b81cb89e4ec33e540fb2ae61c1f :

--depth选项添加到“git submodule”的add和update命令中,然后将其传递给clone命令。 当子模块非常庞大,而且除了最新的提交之外,对于其他任何东西都没有兴趣,这是非常有用的。

添加testing,并进行一些缩进调整,以符合“子模块更新可以处理pwd中的符号链接”的testing文件的其余部分。

签名:Fredrik Gustafsson <iveqy@iveqy.com>
Acks-by:Jens Lehmann <Jens.Lehmann@web.de>

这意味着这个工作:

 git submodule add --depth 1 -- repository path git submodule update --depth -- [<path>...] 

附:

 --depth:: 

该选项对于addupdate命令有效。
创build一个历史被截断为指定修订版本的“浅”克隆。


atwyman补充说 :

据我所知,这个选项不适用于不能严密跟踪master子模块。 如果将深度设置为1,则只有在您要的子模块提交是最新的主设备时, submodule update才能成功。 否则,你会得到“ fatal: reference is not a tree

那是真实的。
也就是说,直到git 2.8(2016年3月)。 使用2.8, submodule update --depth有一个成功的机会,即使SHA1可以从远程回购HEADs之一直接到达。

请参阅Stefan Beller( stefanbeller ) 提交的fb43e31 (2016年2月24日) 。
帮助: Junio C gitstergitster ) 。
(由Junio C gitster合并- gitster -在承诺9671a76 ,2016年2月26日)

子模块:通过直接读取sha1来尽力获取需要的sha1

在审查Gerrit中更新子模块的更改时,一个常见的审查实践是下载并在本地select该补丁以对其进行testing。
然而,当在本地进行testing时,' git submodule update '可能会无法获取正确的子模块sha1,因为子模块中的相应提交不是项目历史logging的一部分,而只是提议的更改。

如果$sha1不是默认获取的一部分,我们试图直接获取$sha1 。 但是有些服务器不支持sha1直接读取,导致git-fetch快速失败。
我们可以在这里失败,因为仍然失踪的sha1会在结账阶段的晚些时候导致失败,所以失败在这里是我们所能得到的。


MVG 在评论中指出 , 提交fb43e31 (git 2.9,2016年2月)

在我看来, 提交fb43e31通过SHA1 ID请求丢失的提交,所以服务器上的uploadpack.allowReachableSHA1InWantuploadpack.allowTipSHA1InWant设置可能会影响这是否工作。
我今天给git列表写了一篇文章 ,指出如何使用浅层子模块更好地适用于某些场景,即如果提交也是标记。
让我们等着看。

我想这是为什么fb43e31提取特定的SHA1后取回默认分支后的原因。
尽pipe如此,在“ – 深1”的情况下,我认为提前中止是有道理的:如果列出的文件中没有一个与请求中的文件匹配,并且服务器不支持SHA1请求,则没有意义取得任何东西,因为我们无论如何不能满足子模块的要求。


2016年8月更新(3年后)

使用Git 2.10(2016年第三季度),您将能够做到

  git config -f .gitmodules submodule.<name>.shallow true 

请参阅“ Git submodule without extra weight ”了解更多信息。


Git 2.13(2017年第2季度)增加了Sebastian Schuberth( sschuberth ) 提交的8d3047c (2017年4月19日) 。
(合并塞巴斯蒂安·舒伯特 – sschuberth -在承诺8d3047c ,2017年4月20日)

该子模块的克隆将作为浅层克隆(历史深度为1)

在Ryan的回答之后,我能够想出这个简单的脚本,它遍历所有的子模块和浅层克隆:

 #!/bin/bash git submodule init for i in $(git submodule | sed -e 's/.* //'); do spath=$(git config -f .gitmodules --get submodule.$i.path) surl=$(git config -f .gitmodules --get submodule.$i.url) git clone --depth 1 $surl $spath done git submodule update 

Git 2.9.0直接支持submodules浅层克隆,所以现在你可以直接调用:

 git clone url://to/source/repository --recursive --shallow-submodules 

通过git-submodule“source”读取,看起来像git submodule add可以处理已经有其存储库的子模块。 在这种情况下…

 $ git clone $remote1 $repo $ cd $repo $ git clone --depth 5 $remotesub1 $sub1 $ git submodule add $remotesub1 $sub1 #repeat as necessary... 

你将要确保所需的提交是在子模块回购,所以确保你设置一个合适的 – 深度。

编辑:您可能能够摆脱多个手动子模块克隆,然后单个更新:

 $ git clone $remote1 $repo $ cd $repo $ git clone --depth 5 $remotesub1 $sub1 #repeat as necessary... $ git submodule update 

您的子模块的规范位置是否偏远? 如果是这样,你可以克隆一次吗? 换句话说,你是否想要浅层克隆只是因为你正在遭受频繁子模块(再)克隆的浪费带宽?

如果你想浅层克隆来保存本地磁盘空间,那么Ryan Graham的答案似乎是一个好的方法。 手动克隆存储库,使它们很浅。 如果你认为这将是有用的,请修改git submodule来支持它。 发送一封电子邮件到这个问题列表 (实施它的build议,在界面上的build议等)。 在我看来,这些人非常支持潜在的贡献者,他们认真地想要以build设性的方式来增强Git。

如果您可以对每个子模块进行一次完整的克隆(加上后续提取以保持最新),则可以尝试使用git submodule update--reference选项(在Git 1.6.4及更高版本中)来引用到本地对象存储区(例如,make – 典型子模块存储库的--mirror克隆,然后使用子模块中的--reference指向这些本地克隆)。 只要确保在使用--reference之前阅读有关git clone --reference / git clone --shared --reference 。 引用镜像的唯一可能的问题是,如果它们最终会获取非快速更新(尽pipe您可以启用reflog并扩展其到期时间窗口,以帮助保留任何可能导致问题的放弃的提交)。 你不应该有任何问题,只要

  • 你不做任何本地的子模块提交,或者
  • 任何由非快速转义而引起的规范库可能发布的提交不是本地子模块提交的祖先,或者
  • 您将努力保持您的本地子模块提交基于规范子模块存储库中可能发布的任何非快速转发。

如果你这样做,并且有可能在工作树中执行本地子模块提交,那么创build一个自动化系统可能是一个好主意,它可以确保签出的子模块引用的关键对象不是留在镜像存储库中(如果find的话,将它们复制到需要它们的存储库)。

而且,就像git clone manpage所说,如果你不了解这些含义,不要使用--reference

 # Full clone (mirror), done once. git clone --mirror $sub1_url $path_to_mirrors/$sub1_name.git git clone --mirror $sub2_url $path_to_mirrors/$sub2_name.git # Reference the full clones any time you initialize a submodule git clone $super_url super cd super git submodule update --init --reference $path_to_mirrors/$sub1_name.git $sub1_path_in_super git submodule update --init --reference $path_to_mirrors/$sub2_name.git $sub2_path_in_super # To avoid extra packs in each of the superprojects' submodules, # update the mirror clones before any pull/merge in super-projects. for p in $path_to_mirrors/*.git; do GIT_DIR="$p" git fetch; done cd super git pull # merges in new versions of submodules git submodule update # update sub refs, checkout new versions, # but no download since they reference the updated mirrors 

或者,也可以使用本地镜像作为子模块的源代码,而不是使用--reference ,将镜像克隆与git clone的默认硬链接function结合使用。 在新的超级项目克隆中,执行git submodule init ,编辑.git/config的子模块URL指向本地镜像,然后执行git submodule update 。 您需要重新login任何现有的签出子模块来获取硬链接。 您只需下载一次镜像就可以节省带宽,然后从本地获取带宽到检出的子模块。 硬连接将节省磁盘空间(尽pipe提取会倾向于在检出的子模块的对象存储的多个实例中累积和重复;您可以定期从镜像中重新检出检出的子模块,以重新获得由hardlinking)。

我创build了一个稍微不同的版本,因为它不是在stream血的边缘运行,而不是所有的项目。 标准子模块的添加没有工作,上面的脚本也没有。 所以我为标签ref增加了一个哈希查找,如果没有的话,它会回落到完整的克隆。

 #!/bin/bash git submodule init git submodule | while read hash name junk; do spath=$(git config -f .gitmodules --get submodule.$name.path) surl=$(git config -f .gitmodules --get submodule.$name.url) sbr=$(git ls-remote --tags $surl | sed -r "/${hash:1}/ s|^.*tags/([^^]+).*\$|\1|p;d") if [ -z $sbr ]; then git clone $surl $spath else git clone -b $sbr --depth 1 --single-branch $surl $spath fi done git submodule update 

参考如何克隆具有特定版本/变更集的git存储库?

我已经写了一个简单的脚本,当你的子模块引用远离主机时没有问题

 git submodule foreach --recursive 'git rev-parse HEAD | xargs -I {} git fetch origin {} && git reset --hard FETCH_HEAD' 

这个语句将获取子模块的引用版本。

虽然速度很快,但您无法在子模块上进行编辑(您必须在https://stackoverflow.com/a/17937889/3156509之前提取它);

在全:

 #!/bin/bash git submodule init git submodule foreach --recursive 'git rev-parse HEAD | xargs -I {} git fetch origin {} && git reset --hard FETCH_HEAD' git submodule update --recursive