Git子模块init异步

时间:2013-06-26 09:25:53

标签: git git-submodules

当我第一次在具有大量子模块的项目上运行git submodule update --init时,这通常需要花费很多时间,因为大多数子模块存储在慢速公共服务器上。

是否有可能异步初始化子模块?

4 个答案:

答案 0 :(得分:5)

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

答案 1 :(得分:4)

从Git 2.8开始,你可以这样做

var routes = {
    'first': '{{ route('first') }}',
    'second': '{{ route('second') }}',
    // ....
};

// Somewhere later in code
$http.get(routes.second).then(function(result) {
    // do something
});

其中4是要并行下载的子模块数。

答案 2 :(得分:2)

2016年1月更新:

使用Git 2.8(2016年第一季度),您将能够使用git fetch --recurse-submodules -j2并行(!)获取子模块。
请参阅“How to speed up / parallelize downloads of git submodules using git clone --recursive?


2013年中期的原始答案

你可以尝试:

  • 首先初始化所有子模块:

    git submodule init

然后,foreach syntax

git submodule foreach git submodule update --recursive -- $path &

如果“&”适用于所有行(而不仅仅是“git submodule update --recursive -- $path”部分),那么您可以调用一个脚本来进行后台更新。

git submodule foreach git_submodule_update

答案 3 :(得分:1)

这也可以在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给出的单行更安全(因为那个只是保持产生进程而不对生成的进程数进行任何控制),仍然遵循相同的逻辑:read .gitmodules,然后产生运行正确git命令的多个进程,但这里使用进程池(也可以设置最大进程数)。克隆存储库的路径需要作为参数传递。这在包含大约700个子模块的存储库中进行了广泛测试。

请注意,在子模块初始化的情况下,每个进程都会尝试写入.git/config,并且可能会发生锁定问题:

  

错误:无法锁定配置文件.git / config:文件存在

     

无法为子模块路径'...'

注册网址

这可以通过subprocess.check_outputtry/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个)。