2013-06-26 11 views
13

Quando eseguo la prima volta git submodule update --init su un progetto che ha molti sottomoduli, questo di solito richiede molto tempo, perché la maggior parte dei sottomoduli sono memorizzati su server pubblici lenti.Sottomenu Git init async

Esiste la possibilità di inizializzare i sottomoduli in modo asincrono?

+0

Cosa intendi con asincrono? Lo farebbe: 'aggiorna git submodule --init &'? – rodrigo

+1

Intendo un modo quando ciascun sottomodulo viene inizializzato in un processo separato. – Leksat

+1

Cioè, parallelo piuttosto che sequenziale? –

risposta

2

aggiornamento di gennaio 2016:

Con Git 2.8 (Q1 2016), si sarà in grado di recuperare sottomoduli in parallelo con git fetch --recurse-submodules -j2 (!).
Vedere "How to speed up/parallelize downloads of git submodules using git clone --recursive?"


risposta iniziale alla metà del 2013

si potrebbe provare:

  • per inizializzare primi tutti i sottomoduli:

    git modulo init

Poi, il foreach syntax:

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

Se il '&' vale anche per la linea di tutti (e non solo la 'git submodule update --recursive -- $path' parte), allora si potrebbe chiamare uno script che renderebbe l'aggiornamento in background .

git submodule foreach git_submodule_update 
+1

OP dice per la "prima volta" che significa che i sottomoduli non sono ancora stati inizializzati per eseguire il comando 'foreach'. destra? –

+0

Si potrebbe anche aggiungere il flag ricorsivo –

+0

@ hus787 Quindi provare prima un 'git submodule init' (che non è un'operazione costosa), quindi il sottomodulo di aggiornamento' '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

Questo funziona per me! Ma per qualche motivo salta alcuni sottomoduli. Credo che sia a causa di molti processi in background. Quindi, alla fine, devo eseguire l'aggiornamento del sottomodulo git - in un altro momento. – Leksat

+0

Utilizza l'operatore ** wait ** per ex: http://stackoverflow.com/questions/9258387/bash-ampersand-operator – Karmazzin

+0

In precedenza c'erano errori 'error: impossibile bloccare il file di configurazione .git/config: File esiste' perché processi paralleli stavano scrivendo per la configurazione. Ora ho aggiunto 'sleep 0.1' al ciclo' while' e funziona perfettamente. – Leksat

0

Questo può essere fatto anche in Python. In Python 3 (perché siamo nel 2015 ...), possiamo usare qualcosa di simile a questo:

#!/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)) 

Questo può essere più sicuro che l'one-liner data dal @Karmazzin (dato che uno solo mantiene i processi di deposizione delle uova senza alcun controllo sul numero di processi generati), segue sempre la stessa logica: leggere .gitmodules, quindi generare più processi che eseguono il comando git corretto, ma qui utilizzando un pool di processi (è possibile impostare anche il numero massimo di processi). Il percorso del repository clonato deve essere passato come argomento. Questo è stato testato estesamente su un repository con circa 700 sottomoduli.

noti che nel caso di inizializzazione modulo, ogni processo tenterà di scrivere a .git/config, e problemi di blocco può accadere:

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

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

Questo può essere catturato con subprocess.check_output ed un blocco try/except subprocess.CalledProcessError, che è più pulito del sonno aggiunto al metodo di @ Karmazzin. Un metodo aggiornato potrebbe apparire come:

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 

Con questo, sono riuscito a eseguire l'init/aggiornamento di 700 sottomoduli nel corso di un Travis costruire senza la necessità di limitare la dimensione del pool di processi. Vedo spesso alcune serrature catturate in questo modo (~ 3 max).

4

A partire dal Git 2.8 è possibile questo

git submodule update --init --jobs 4 

dove 4 è il numero di moduli per scaricare in parallelo.

Problemi correlati