当我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
苹果电脑:
cat .gitmodules | grep -o '".*"' | cut -d '"' -f 2 | while sleep 0.1 && read line; do git submodule update --init $line & done
从 Git 2.8 开始,您可以这样做:
git submodule update --init --jobs 4
其中 4 是要并行下载的子模块的数量。
2016 年 1 月更新:
使用 Git 2.8(2016 年第一季度),您将能够使用git fetch --recurse-submodules -j2
.
请参阅“如何使用 git clone --recursive 加速/并行下载 git 子模块? ”
2013年年中的原始答案
你可以试试:
首先初始化所有子模块:
git子模块初始化
然后,foreach
语法:
git submodule foreach git submodule update --recursive -- $path &
如果 ' &
' 适用于所有行(而不仅仅是 ' git submodule update --recursive -- $path
' 部分),那么您可以调用一个脚本来在后台进行更新。
git submodule foreach git_submodule_update
这也可以在 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 方法的睡眠更干净。更新的方法可能如下所示:
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
有了这个,我设法在 Travis 构建期间运行了 700 个子模块的初始化/更新,而无需限制进程池的大小。我经常看到一些锁以这种方式被捕获(最多 3 个)。