2015-03-18 14 views
7

Abbiamo un repo git che è abbastanza grande (risorse app ios). Apprezzo che git stia per essere lento quando si lavora con esso, ma se creo un nuovo ramo e modifichi un paio di file (non quelli binari) e spingo, ci vorrà per sempre.git push è molto lento per un ramo

Sembra che l'intero repo venga spinto. Avevo l'impressione che Git avrebbe solo inviato il diff, è sbagliato? (So ​​che git memorizza le versioni compresse dell'intero file, intendo il diff tra il mio ramo e il punto da cui sono derivato).

Se eseguo git diff --stat --cached origin/foo, viene visualizzato un breve elenco di file simile a quello che mi aspetto, ad es. 34 files changed, 1117 insertions(+), 72 deletions(-). Ma quando lo spingo arriva a Writing objects: 21% (2317/10804) e si ferma, come se stesse spingendo tutti i 2,4 GB di dati binari.

Mi manca qualcosa (l'ho cercato su Google)? È questo il comportamento previsto? Sto usando git 2.2.2 su OS X (Mavericks) e ssh ([email protected]).

Ho trovato una domanda simile qui: Git - pushing a remote branch for a large project is really slow ma nessuna risposta reale.

+0

vedere la discussione sulla mailing list git - http://comments.gmane.org/gmane.comp.version-control.git/265716 – grahamrhay

risposta

16

Si sta utilizzando un trasporto "intelligente" (questa è una buona cosa), quindi ottieni delta o, più specificamente, "compressione delta". Ma questo non vuol dire che git spinga diff.

Sia push che fetch funzionano allo stesso modo qui: su un trasporto intelligente, il tuo git richiama il telecomando ed entrambe le estremità hanno una mini conversazione per capire chi ha quali oggetti del repository, identificati da SHA-1 e allegati a specifici etichette (tipicamente nomi di branch e tag anche se sono consentite altre etichette).

Per esempio, in questo caso, il git si richiama la loro e dice: "Propongo di avere si imposta il ramo master SHA-1 1234567... vedo che la tua master è attualmente 333333..., ecco quello che penso che vi serve. per andare da lì a 7777777.... " I loro dovrebbero rispondere con "ok, ho bisogno di alcuni di quelli, ma ho già ...". Una volta che il tuo git ha capito cosa deve essere inviato e cosa è già presente, il tuo git crea un "pacchetto sottile" contenente tutti gli oggetti da inviare. (Questa è la fase "compressione delta utilizzando fino a% d discussioni")

Il pacchetto sottile risultante viene quindi inviato tramite il trasporto intelligente; questo è dove si vedono i messaggi "oggetti di scrittura". (L'intero pacchetto sottile deve essere inviato correttamente, dopo di che il ricevitore "ingrassa" nuovamente usando git index-pack --fix-thin e lo rilascia nel repository.)

Esattamente ciò che viene inviato, dipende dagli oggetti nel pacchetto sottile. Che sia solo l'insieme di commit tra "cosa hanno" e "ciò che stai inviando", oltre a tutti gli oggetti (alberi e blob) necessari per tali commit, oltre a tutti i tag annotati che stai inviando e tutti gli oggetti necessari per quelli che non hanno già.

È possibile trovare i commit in questione utilizzando git fetch per raccogliere le loro ultime informazioni, quindi utilizzare git rev-list per vedere quali commit si invieranno loro.Per esempio, se si sta solo andando a spingere le cose in master:

$ git fetch origin # assuming the remote name is origin 
[wait for it to finish] 
$ git rev-list origin/master..master 

Esaminando questi commit può mostrare un file molto grande binario che è contenuto in uno di quelli di mezzo, poi rimosso di nuovo in un secondo commit:

$ git log --name-status origin/master..master 

Se uno commettere ha A giantfile.bin e poi una successiva (probabilmente elencato per primo nel git log uscita) commit ha D giantfile.bin, probabilmente stai ottenendo appeso l'invio del blob per giantfile.bin.

Se questo è il caso, è possibile utilizzare git rebase -i per eliminare il commit che aggiunge il file binario gigante, in modo che git push non debba inviare quel commit.

(Se la cronologia è lineare, non c'è unione per il push, è possibile, o invece, utilizzare git format-patch per creare una serie di messaggi di posta elettronica contenenti patch.Questi sono adatti per l'invio di e-mail a qualcuno nell'altro sito- non che ci sia qualcuno in github in attesa di riceverli, ma si può facilmente esaminare i file di patch per vedere se qualcuno di loro sono enormi.)


Il pacco è "sottile" in quanto viola un normale regola del file pack che richiede l'eventuale oggetto "downstream" di compressione delta nel pacchetto stesso. Invece, gli oggetti "downstream" possono (di fatto, devono) essere nel repository che riceve il thin pack.

+1

questa è una risposta eccellente, grazie – grahamrhay

+0

sfortunatamente, la patch di formato ammonta a 1.7MB , che non spiega la spinta lenta – grahamrhay

+0

A questo punto la cosa su cui indagare è cosa c'è nel thin-pack, e se il tuo trasporto ssh è semplicemente bloccato (a causa di un problema di rete probabilmente non correlato a git). Un tracciante di rete come tcpdump potrebbe essere utile per quest'ultimo. – torek