如何使用git clone --recursive加速/并行化git子模块的下载?

adr*_*nos 16 git performance download git-clone git-submodules

克隆具有大量子模块的git存储库需要很长时间.在以下示例中是~100个子模块

git clone --recursive https://github.com/Whonix/Whonix
Run Code Online (Sandbox Code Playgroud)

Git一个接一个地克隆它们.比需要的时间长得多.让(可能)假设客户端和服务器都有足够的资源同时回答多个(并行)请求.

如何使用git clone --recursive?加速/并行化git子模块的下载?

Von*_*onC 18

使用git 2.8(Q12016),您将能够并行启动子模块的获取!

请参阅Jonathan Nieder()提交fbf7164(2015年12月16日). 请参阅Stefan Beller()提交62104ba,提交fe85ee6,提交c553c72,提交bfb6b53,提交b4e04fb,提交1079c4b(2015年12月16日).(由Junio C Hamano合并- -承诺187c0d3,2016年1月12日)artagnon
stefanbeller
gitster

添加一个框架以并行生成一组进程,并使用它git fetch --recurse-submodules并行运行" ".

为此,git fetch有新选项:

-j, --jobs=<n>
Run Code Online (Sandbox Code Playgroud)

用于获取子模块的并行子节点数.
每个都将从不同的子模块中获取,这样获取许多子模块的速度会更快.
默认情况下,将一次提取一个子模块.

例:

git fetch --recurse-submodules -j2
Run Code Online (Sandbox Code Playgroud)

这个新功能的大部分内容是由Stefan Beller()提交c553c72(2015年12月16日).stefanbeller

run-command:添加异步并行子处理器

这允许在stderr上与有序输出并行运行外部命令.

如果我们并行运行外部命令,我们就无法将输出直接传递给我们的stdout/err,因为它会混淆.因此,每个进程的输出将流经一个管道,我们将其缓冲.一个子进程可以直接通过管道输出到stdout/err,以便向用户提供低延迟反馈.


Ant*_*hon 7

当我运行您的命令时,下载 68 Mb 需要 338 秒的挂墙时间。

安装以下依赖于 GNU parallel 的 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))
Run Code Online (Sandbox Code Playgroud)

那个时间缩短至45秒(在同一系统上,我并没有做多的运行,以平均出波动)。

为了检查一切是否正常,我“比较”了检出的文件:

find Whonix -name ".git" -prune -o -type f -print0 | xargs -0 md5sum > /tmp/md5.sum
Run Code Online (Sandbox Code Playgroud)

在一个目录和

md5sum -c /tmp/md5sum 
Run Code Online (Sandbox Code Playgroud)

在另一个目录中,反之亦然。