克隆具有大量子模块的git存储库需要很长时间。以下示例中有大约100个子模块
git clone --recursive https://github.com/Whonix/Whonix
Git一个接一个地克隆它们。所需时间远远超过所需时间。让我们假设(可能的)客户端和服务器都有足够的资源来同时回答多个(并行)请求。
如何使用git clone --recursive
加速/并行下载git子模块?
使用git 2.8(Q12016),您将能够启动子模块的提取。。。并行!
参见Jonathan Nieder提交的fbf7164(2015年12月16日)(artagnon
)
参见Stefan Beller(stefanbeller
)的提交62104ba、提交fe85ee6、提交c553c72、提交bfb6b53、提交b4e04fb、提交1079c4b(2015年12月16日)
(由Junio C Hamano合并——gitster
——提交187c0d3,2016年1月12日)
添加一个框架来并行生成一组进程,并使用它要运行";CCD_ 5";并行。
为此,git fetch
有了新的选择:
-j, --jobs=<n>
用于获取子模块的并行子级数
每个模块将从不同的子模块中提取,这样提取多个子模块会更快
默认情况下,将一次提取一个子模块。
示例:
git fetch --recurse-submodules -j2
这个新功能的大部分内容在Stefan Beller(stefanbeller
)提交的c553c72(2015年12月16日)中。
run-command
:添加异步并行子处理器
这允许在stderr上并行运行外部命令和有序输出。
如果我们并行运行外部命令,我们就无法将输出直接管道传输到stdout/err,因为它会混淆。因此,每个进程的输出都将流经一个管道,我们对其进行缓冲。一个子流程可以直接通过管道输出stdout/err,以便向用户提供低延迟反馈。
注意,在Git 2.24(2019年第四季度)之前;CCD_ 9";在获取子模块时允许<n>
并行作业,但这不适用于";CCD_ 11";从多个远程存储库中获取
现在确实如此。
参见Johannes Schindelin(dscho
)提交的d54dea7(2019年10月5日)
(由Junio C Hamano合并——gitster
——提交d96e31e,2019年10月15日)
fetch
:也让--jobs=<n>
并行化--multiple
签字人:Johannes Schindelin
到目前为止,
--jobs=<n>
只并行化子模块获取/克隆,而不是--multiple
获取,这是不直观的,因为该选项的名称没有特别说明子模块。让我们改变一下
使用此补丁,还可以并行化从多个远程获取。为了向后兼容性(并为子模块和多个远程获取可能需要不同并行限制的用例做准备):
- 配置设置CCD_ 19仍然仅控制CCD_
- 而新引入的设置CCD_ 21控制两者(但对于具有CCD_
另请参阅Git 2.40(2023年第1季度)和git pull
多个远程并行,了解该版本中修复的git fetch --jobs=0
的错误。
当我运行您的命令时,下载68Mb需要338秒的墙壁时间。
通过安装以下依赖GNU并行的Python程序,
#! /usr/bin/env python
# coding: utf-8
from __future__ import print_function
import os
import subprocess
jobs=16
modules_file = '.gitmodules'
packages = []
if not os.path.exists('Whonix/' + modules_file):
subprocess.call(['git', 'clone', 'https://github.com/Whonix/Whonix'])
os.chdir('Whonix')
# get list of packages from .gitmodules file
with open(modules_file) as ifp:
for line in ifp:
if not line.startswith('[submodule '):
continue
package = line.split(' "', 1)[1].split('"', 1)[0]
#print(package)
packages.append(package)
def doit():
p = subprocess.Popen(['parallel', '-N1', '-j{0}'.format(jobs),
'git', 'submodule', 'update', '--init',
':::'],
stdin=subprocess.PIPE, stdout=subprocess.PIPE)
res = p.communicate('n'.join(packages))
print(res[0])
if res[1]:
print("error", res[1])
print('git exit value', p.returncode)
return p.returncode
# sometimes one of the updates interferes with the others and generate lock
# errors, so we retry
for x in range(10):
if doit() == 0:
print('zero exit from git after {0} times'.format(x+1))
break
else:
print('could not get a non-zero exit from git after {0} times'.format(
x+1))
该时间减少到45秒(在同一个系统上,我进行了而不是多次运行以平均波动)。
为了检查是否正常,我将签出的文件与进行了"比较"
find Whonix -name ".git" -prune -o -type f -print0 | xargs -0 md5sum > /tmp/md5.sum
在一个目录和中
md5sum -c /tmp/md5sum
在另一个目录中,反之亦然。