Answers:
即将发布的git1.8.4(2013年7月)的新功能:
“
git submodule update
”可以选择浅浅地克隆子模块存储库。
(并且git 2.10 Q3 2016允许使用记录该事件git config -f .gitmodules submodule.<name>.shallow true
。
请参见此答案的结尾)
参见commit 275cd184d52b5b81cb89e4ec33e540fb2ae61c1f:
将
--depth
选项添加到“ git submodule”的添加和更新命令中,然后将其传递给克隆命令。当子模块很大且您对除最新提交以外的任何东西都不真正感兴趣时,这很有用。添加了测试,并对缩进进行了一些调整,以符合“子模块更新可以处理pwd中的符号链接”测试文件的其余部分。
签字人:Fredrik Gustafsson
<iveqy@iveqy.com>
签字人:Jens Lehmann<Jens.Lehmann@web.de>
这意味着这有效:
git submodule add --depth 1 -- repository path
git submodule update --depth -- [<path>...]
带有:
--depth::
此选项对
add
和update
命令有效。
创建一个“浅”克隆,其历史记录被截断为指定的修订版本。
据我所知,此选项不适用于跟踪
master
不太紧密的子模块。如果将深度设置为1,则submodule update
只有在您想要的子模块提交是最新的主模块时,该成功才能成功。 否则,您会得到“fatal: reference is not a tree
”。
那是真实的。
也就是说,直到git 2.8(2016年3月)。使用2.8,submodule update --depth
即使可以从远程回购HEAD之一直接访问SHA1,也有一个成功的机会。
参见Stefan Beller()的commit fb43e31(2016年2月24日)。
帮助:Junio C Hamano()。(由Junio C Hamano合并--在9671a76号提交中,2016年2月26日)stefanbeller
gitster
gitster
子模块:尝试通过直接获取sha1来获取所需的sha1
在检查还可以更新Gerrit中的子模块的更改时,通常的检查做法是在本地下载并挑选补丁来对其进行测试。
但是,在本地对其进行测试时,“git submodule update
”可能无法获取正确的子模块sha1,因为子模块中的相应提交尚未成为项目历史的一部分,而仅仅是提议的更改。如果
$sha1
不是默认获取的一部分,我们尝试$sha1
直接获取。但是,某些服务器不支持通过sha1直接获取,这会导致git-fetch
快速失败。
我们可能会在这里失败,因为仍然缺少的sha1会在结帐阶段的稍后阶段导致失败,因此在这里失败就可以了。
MVG指出,在评论中,以提交fb43e31(GIT 2.9 2月2016)
在我看来,提交fb43e31通过SHA1 id请求丢失的提交,因此服务器上的
uploadpack.allowReachableSHA1InWant
和uploadpack.allowTipSHA1InWant
设置可能会影响此设置是否有效。
我今天在git列表中写了一篇文章,指出了在某些情况下(例如,如果提交也是标签的话)如何使浅子模块的使用更好地工作。
让我们等着看。我想这就是为什么fb43e31将对特定SHA1的获取作为对默认分支的获取之后的回退的原因。
不过,在“深度1”的情况下,我认为尽早中止是有意义的:如果列出的引用均与请求的引用不匹配,并且服务器不支持SHA1的询问,则没有意义。获取任何东西,因为我们将无法以任何一种方式满足子模块的要求。
2016年8月更新(3年后)
使用Git 2.10(2016年第三季度),您将能够
git config -f .gitmodules submodule.<name>.shallow true
有关更多信息,请参见“ 无需额外重量的Git子模块 ”。
Git 2.13(Q2 2017)确实添加了Sebastian Schuberth()的提交8d3047c(2017年4月19日)。(通过合并塞巴斯蒂安Schuberth - -在提交8d3047c 4月20日2017)sschuberth
sschuberth
此子模块的克隆将作为浅克隆(历史深度为1)执行
但是,Ciro Santilli添加了评论(以及他的回答中的详细信息)
shallow = true
on.gitmodules
仅会在使用时影响远程HEAD跟踪的参考--recurse-submodules
,即使目标提交是由分支指向的,即使您也放置branch = mybranch
了.gitmodules
。
Git 2.20(Q4 2018)改进了子模块支持,该子模块支持已更新为在工作树中缺少文件HEAD:.gitmodules
时从Blob读取.gitmodules
。
请参阅提交2b1257e,提交76e9bdc(2018年10月25日)和提交b5c259f,提交23dd8f5,提交b2faad4,提交2502ffc,提交996df4d,提交d1b13df,提交45f5ef3,提交bcbc780(2018年10月5日),由安东尼奥Ospite( )ao2
。
(通过合并JUNIOÇ滨野- gitster
-在提交abb4824 11月13日2018)
submodule
:支持.gitmodules
不在工作树中时的阅读当
.gitmodules
文件在工作树中不可用时,请尝试使用索引和当前分支中的内容。
这涵盖了文件是存储库的一部分但由于某种原因(例如由于稀疏签出)而未签出的情况。这使得它可以至少使用“
git submodule
这”命令读取的gitmodules
配置文件,而无需完全填充的工作树。写入
.gitmodules
仍然需要将文件检出,因此请在调用之前检查该文件config_set_in_gitmodules_file_gently
。还添加类似的检查,
git-submodule.sh::cmd_add()
以预知在无法安全写入git submodule add
时“ ”命令的最终失败.gitmodules
;这样可以防止命令使存储库处于虚假状态(例如,子模块存储库已克隆但.gitmodules
由于config_set_in_gitmodules_file_gently
失败而未更新)。此外,由于
config_from_gitmodules()
现在访问全局对象存储,因此必须保护所有调用该函数的代码路径,防止它们同时访问全局对象存储。
目前,这仅发生在builtin/grep.c::grep_submodules()
,因此grep_read_lock()
在调用涉及的代码之前先进行调用config_from_gitmodules()
。注意:在极少数情况下,此新功能仍无法正常工作:嵌套子模块不在
.gitmodules
其工作树中。
注意:Git 2.24(Q4 2019)修复了克隆浅子模块时可能出现的段错误。
请参阅Ali Utku Selen()的commit ddb3c85(2019年9月30日)。(由Junio C Hamano合并--在auselen
gitster
提交678a9ca,2019年10月9日)
Git 2.25(2020年第一季度)澄清了git submodule update
文档。
请参阅Philippe Blain()的commit f0e58b3(2019年11月24日)。(通过合并JUNIOÇ滨野- -在提交ef61045,2019年12月5日)phil-blain
gitster
doc
:提到'git submodule update'获取丢失的提交帮助人:Junio C Hamano
帮助人:Johannes Schindelin
签名人:Philippe Blain如果找不到在超级项目中记录的SHA-1,则 '
git submodule
update' 将从远程子模块获取新的提交。文档中未提及。
警告:在Git 2.25(2020年第一季度)中,“git clone --recurse-submodules
”和备用对象存储设计不当。
教给文档和代码以在用户看到故障时提出更清晰的建议。
请参阅Jonathan Tan()的commit 4f3e57e和commit 10c64a0(2019年12月2日)。(由合并jhowtan
Junio C gitster
Hamano --在commit 5dd1d59中,2019年12月10日)
submodule--helper
:建议致命替代错误签字人:Jonathan Tan
签名人:杰夫·金当用其中定义的一些浅层模块递归克隆一个超级项目时
.gitmodules
,然后用“--reference=<path>
” 重新克隆,就会发生错误。例如:git clone --recurse-submodules --branch=master -j8 \ https://android.googlesource.com/platform/superproject \ master git clone --recurse-submodules --branch=master -j8 \ https://android.googlesource.com/platform/superproject \ --reference master master2
失败与:
fatal: submodule '<snip>' cannot add alternate: reference repository '<snip>' is shallow
如果无法添加根据超级项目的替代项计算出的替代项,则无论是在这种情况下还是其他情况下,都建议您配置“
submodule.alternateErrorStrategy
”配置选项,并在克隆时使用“--reference-if-able
”代替“--reference
”。
详细说明:
在Git 2.25(2020年第1季度)中,“ git clone --recurse-submodules”与备用对象存储之间的交互设计不良。
Doc
:解释submodule.alternateErrorStrategy签字人:Jonathan Tan
签名人:杰夫·金提交31224cbdc7(“
clone
:递归和引用选项触发子模块替代”,2016-08-17,Git v2.11.0-rc0- 合并在批处理#1中)教导Git支持配置选项“submodule.alternateLocation
”和“submodule.alternateErrorStrategy
在超级项目上 ” 。如果将“
submodule.alternateLocation
”配置为“superproject
在超级项目上将 ”,则每当克隆该超级项目的子模块时,它就会从$GIT_DIR/objects/info/alternates
超级项目中为该子模块计算类似的替代路径,并对其进行引用。“
submodule.alternateErrorStrategy
”选项确定如果无法引用该替代项会发生什么。
但是,尚不清楚克隆是否继续进行,就好像未将该选项未设置为“ die”时未指定其他选项一样(如在31224cbdc7中的测试中可以看到的)。
因此,请相应地记录下来。
在配置子模块文档现在包括:
submodule.alternateErrorStrategy::
指定如何通过来处理子模块的备用选项中的错误
submodule.alternateLocation
。
可能的值是ignore
,info
,die
。
默认值为die
。
请注意,如果设置为ignore
或info
,并且计算的替代项有错误,则克隆将继续进行,就像未指定替代项一样。
--depth
应该吵一架;)
uploadpack.allowReachableSHA1InWant
和uploadpack.allowTipSHA1InWant
设置可能会影响此设置是否有效。我今天在git列表中写了一篇文章,指出了在某些情况下(例如,如果提交也是标签的话)如何使浅子模块的使用更好地工作。让我们等着看。
.gitmodules
,该--depth 1
选项对不紧密跟踪master的分支有效吗?
Git 2.9.0直接支持子模块浅表克隆,因此现在您可以调用:
git clone url://to/source/repository --recursive --shallow-submodules
按照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
fatal: reference is not a tree: 88fb67b07621dfed054d8d75fd50672fb26349df
需要每个子模块
仔细阅读git-submodule的“源”,看起来git submodule add
可以处理已经存在其存储库的子模块。在这种情况下...
$ git clone $remote1 $repo
$ cd $repo
$ git clone --depth 5 $remotesub1 $sub1
$ git submodule add $remotesub1 $sub1
#repeat as necessary...
您需要确保所需的提交在子模块存储库中,因此请确保设置适当的--depth。
编辑:您可能可以摆脱多个手动子模块克隆,然后进行一次更新:
$ git clone $remote1 $repo
$ cd $repo
$ git clone --depth 5 $remotesub1 $sub1
#repeat as necessary...
$ git submodule update
从Git 2.14.1开始的错误/意外/令人讨厌行为的摘要
shallow = true
在.gitmodules
仅影响git clone --recurse-submodules
,如果HEAD
远程子模块指向必需的承诺,即使目标承诺是指向一个分支,即使你把branch = mybranch
上.gitmodules
也是如此。
本地测试脚本。在GitHub 2017-11上的行为相同,HEAD
由默认分支回购设置控制:
git clone --recurse-submodules https://github.com/cirosantilli/test-shallow-submodule-top-branch-shallow
cd test-shallow-submodule-top-branch-shallow/mod
git log
# Multiple commits, not shallow.
git clone --recurse-submodules --shallow-submodules
如果分支或标记均未使用消息引用提交,则失败: error: Server does not allow request for unadvertised object
。
本地测试脚本。在GitHub上的行为相同:
git clone --recurse-submodules --shallow-submodules https://github.com/cirosantilli/test-shallow-submodule-top-sha
# error
我还在邮件列表上问过:https : //marc.info/? l =git&m=151863590026582&w=2,回复是:
从理论上讲,这应该很容易。:)
不幸的是,实际上没有那么多。这是因为克隆只会获取分支的最新提示(通常是主节点)。克隆中没有机制来指定所需的确切sha1。
有线协议支持询问确切的sha1,因此应予以覆盖。(注意:仅当服务器操作员启用github尚未使用AFAICT的uploadpack.allowReachableSHA1InWant时才有效)
git-fetch允许获取任意sha1,因此,一种变通办法是,您可以使用“ git submodule update”在递归克隆之后运行获取,因为它将在初始克隆之后使用获取。
TODO测试:allowReachableSHA1InWant
。
git clone --recursive
仅获取该特定提交。
子模块的规范位置是否远程?如果是这样,您可以将它们克隆一次吗?换句话说,您是否只是因为遭受频繁的子模块(重新)克隆浪费的带宽而想要浅表克隆?
如果您希望浅表克隆保存本地磁盘空间,那么Ryan Graham的答案似乎是个不错的选择。手动克隆存储库,使它们变浅。如果您认为它会有用,请调整git submodule
以支持它。向列表发送一封电子邮件,询问有关该问题的信息(实现建议,界面建议等)。我认为,那里的人们非常支持潜在的贡献者,他们真诚地希望以建设性的方式增强Git。
如果可以对每个子模块进行完整克隆(可以稍后再获取以使它们保持最新状态),则可以尝试使用--reference
选项git submodule update
(在Git 1.6.4和更高版本中)来引用本地对象存储(例如创建--mirror
规范子模块存储库的克隆,然后--reference
在子模块中使用以指向这些本地克隆)。只需确保使用前阅读git clone --reference
/ 。引用镜像的唯一可能问题是它们是否最终获取非快速更新(尽管您可以启用reflog并扩展其过期窗口以帮助保留可能导致问题的所有放弃的提交)。只要你没有任何问题git clone --shared
--reference
如果您使用类似的方法,并且有可能在工作树中携带本地子模块提交,那么创建一个自动系统以确保未检出已检出子模块引用的关键对象可能是一个好主意。留在镜像存储库中悬空(如果找到,将其复制到需要它们的存储库中)。
并且,如git clone
联机帮助页所述,--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
是使用本地镜像作为子模块的源。在新的超级项目克隆中,执行git submodule init
,在其中编辑子模块URL .git/config
以指向本地镜像,然后执行git submodule update
。您将需要重新克隆任何现有的检出子模块以获取硬链接。您只需下载一次到镜像中,然后从本地下载到检出的子模块中,即可节省带宽。硬链接将节省磁盘空间(尽管提取会积累并在已检出子模块的对象存储的多个实例之间重复;您可以定期从镜像中重新克隆已检出的子模块,以重新获得由磁盘提供的磁盘空间节省)硬链接)。
我创建了一个略有不同的版本,用于当它没有在最前沿运行时,并非所有项目都在运行。标准子模块添加无效,以上脚本也不起作用。因此,我为标记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 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
子模块的浅克隆是完美的,因为它们可以在特定的修订/变更集上进行快照。从网站下载zip很容易,所以我尝试了一个脚本。
#!/bin/bash
git submodule deinit --all -f
for value in $(git submodule | perl -pe 's/.*(\w{40})\s([^\s]+).*/\1:\2/'); do
mysha=${value%:*}
mysub=${value#*:}
myurl=$(grep -A2 -Pi "path = $mysub" .gitmodules | grep -Pio '(?<=url =).*/[^.]+')
mydir=$(dirname $mysub)
wget $myurl/archive/$mysha.zip
unzip $mysha.zip -d $mydir
test -d $mysub && rm -rf $mysub
mv $mydir/*-$mysha $mysub
rm $mysha.zip
done
git submodule init
git submodule deinit --all -f
清除允许脚本可重复使用的子模块树。
git submodule
检索40个char sha1,后跟与中相同的路径.gitmodules
。我使用perl连接此信息,并用冒号分隔,然后使用变量转换将值分隔为mysha
和mysub
。
这些是关键键,因为我们需要下载sha1和关联url
.gitmodules中的路径。
给定一个典型的子模块条目:
[submodule "label"]
path = localpath
url = https://github.com/repository.git
myurl
键,path =
然后在获得值后看两行。此方法可能无法始终如一地工作,需要完善。url grep .git
通过匹配最后一个/
以及直到a的所有内容来剥离所有剩余的类型引用.
。
mydir
是mysub
减去最终值/name
的目录,该目录将指向子模块名称。
接下来是 wget
格式为可下载的zip存档网址。将来可能会改变。
将mydir
子模块路径中指定的子目录解压缩到该文件。所得到的文件夹将是最后一个元素url
- sha1
。
检查子模块路径中指定的子目录是否存在,并将其删除以允许重命名提取的文件夹。
mv
将包含我们的sha1的提取文件夹重命名为其正确的子模块路径。
删除下载的zip文件。
子模块初始化
这更是WIP的概念证明,而不是解决方案。当它起作用时,结果是指定变更集处子模块的浅表克隆。
如果存储库将子模块重新放置到其他提交中,请重新运行脚本以进行更新。
这样的脚本唯一有用的时间是用于源项目的非协作本地构建。
git submodule add/update
现在可以“ ”浅克隆子模块存储库了!请在下面