2013-06-26 54 views
13

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

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

+0

你是什么意思与异步?会这样做:'git submodule update --init&'? – rodrigo

+1

我的意思是每个子模块在不同的过程中初始化的一种方式。 – Leksat

+1

也就是说,平行而不是顺序? –

回答

2

更新2016年1月:

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


原来的答复2013年中期

你可以尝试:

  • 初始化第一所有子模块:

    git的子模块初始化

然后,foreach syntax

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

如果“&”适用于所有线路(而不是只是“git submodule update --recursive -- $path”部分),那么你可以调用一个脚本这将使更新在后台。

git submodule foreach git_submodule_update 
+1

OP表示“第一次”,这意味着子模块尚未初始化以运行“foreach”命令。对? –

+0

您可能还想添加递归标志 –

+0

@ hus787然后尝试'git submodule init first'(这不是一个昂贵的操作),然后是更新的''foreach''子模块。 – VonC

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 
+0

这适用于我!但由于某种原因,它跳过了一些子模块。我相信这是因为许多后台进程。所以,最后,我必须运行git submodule update --init一次。 – Leksat

+0

使用运算符**等**为例如:http://stackoverflow.com/questions/9258387/bash-ampersand-operator – Karmazzin

+0

以前有错误'错误:无法锁定配置文件.git/config:文件存在'因为并行进程正在写入配置。 现在我在'while'循环中加入了'sleep 0.1',它的工作原理非常完美。 – Leksat

0

这也可以在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,和锁定问题可能会发生:

error: could not lock config file .git/config: File exists

Failed to register url for submodule path '...'

这可以用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 

有了这个,我设法在一个特拉维斯建立,而不需要限制进程池的大小运行的700子模块初始化/更新。我经常会看到几个锁(这是最多〜3个)。

4

正如吉特2.8,你可以这样

git submodule update --init --jobs 4 

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