git submodule update --init
时,通常会花费很长时间,因为大多数子模块存储在缓慢的公共服务器上。是否有可能异步初始化子模块?git submodule update --init
时,通常会花费很长时间,因为大多数子模块存储在缓慢的公共服务器上。是否有可能异步初始化子模块?Linux:
cat .gitmodules | grep -Po '".*"' | sed 's/.\(.\+\).$/\1/' | while sleep 0.1 && read line; do git submodule update --init $line & done
Mac:
cat .gitmodules | grep -o '".*"' | cut -d '"' -f 2 | while sleep 0.1 && read line; do git submodule update --init $line & done
error: could not lock config file .git/config: File exists
,因为并行进程正在写入配置文件。
现在我已经在 while
循环中添加了 sleep 0.1
,它完美地工作了。 - Leksat`cat .gitmodules | grep -Po '".*"' | sed 's/.\(.\+\).$/\1/' | while sleep 0.1 && read line; do echo $line; done | xargs -L1 -P4 git submodule update --init;`
这样可以防止 shell 在所有克隆完成之前退出,并且将并行进程的数量限制为 4。 - dmi_git submodule update --init --jobs 4
其中4是并行下载的子模块数目。
2016年1月更新:
使用Git 2.8(2016年第一季度),您将能够通过git fetch --recurse-submodules -j2
并行地获取子模块。
请参见"如何使用git clone --recursive加速/并行下载git子模块?"
原始回答于2013年中期
您可以尝试:
首先初始化所有子模块:
git submodule init
然后,使用foreach
语法:
git submodule foreach git submodule update --recursive -- $path &
如果 '&
' 应用于整行 (而不仅仅是 'git submodule update --recursive -- $path
' 部分),那么您可以调用一个脚本,在后台进行更新。
git submodule foreach git_submodule_update
foreach
命令,对吧? - Bleeding Fingersgit submodule init
(这不是一个昂贵的操作),然后更新 'foreach
' 子模块。 - VonC这也可以用Python完成。在Python 3中(因为我们现在是2015年...),我们可以使用类似于以下的东西:
#!/usr/bin/env python3
import os
import re
import subprocess
import sys
from functools import partial
from multiprocessing import Pool
def list_submodules(path):
gitmodules = open(os.path.join(path, ".gitmodules"), 'r')
matches = re.findall("path = ([\w\-_\/]+)", gitmodules.read())
gitmodules.close()
return matches
def update_submodule(name, path):
cmd = ["git", "-C", path, "submodule", "update", "--init", name]
return subprocess.call(cmd, shell=False)
if __name__ == '__main__':
if len(sys.argv) != 2:
sys.exit(2)
root_path = sys.argv[1]
p = Pool()
p.map(partial(update_submodule, path=root_path), list_submodules(root_path))
这种方法可能比 @Karmazzin 给出的一行代码更安全(因为那个方法只是不受控制地生成进程而没有任何关于生成进程数量的控制),但它仍然遵循相同的逻辑:读取 .gitmodules
,然后使用进程池(最大进程数也可以设置)生成运行适当 git 命令的多个进程。克隆存储库的路径需要作为参数传递。在一个包含约 700 个子模块的存储库上进行了广泛测试。
请注意,在子模块初始化的情况下,每个进程都会尝试写入 .git/config
,并且可能会发生锁定问题:
错误:无法锁定配置文件 .git/config: 文件已存在
注册子模块路径 '...' 的 URL 失败
这可以通过 subprocess.check_output
和 try/except subprocess.CalledProcessError
块捕获,这比添加到 @Karmazzin 方法中的 sleep 更清晰。更新后的方法可以像这样:
def update_submodule(name, path):
cmd = ["git", "-C", path, "submodule", "update", "--init", name]
while True:
try:
subprocess.check_output(cmd, stderr=subprocess.PIPE, shell=False)
return
except subprocess.CalledProcessError as e:
if b"could not lock config file .git/config: File exists" in e.stderr:
continue
else:
raise e
git submodule update --init &
? - rodrigo