Introduzione
git clone sembra una sola operazione ma in realtà ne compone diverse. Capire i passi aiuta quando si risolvono problemi di clone parziali, clone lenti o default sorprendenti.
La sequenza
- Crea la directory di destinazione.
- Esegue
git inital suo interno. - Aggiunge
origincome remote con l'URL di origine. - Configura il refspec predefinito
+refs/heads/*:refs/remotes/origin/*. - Esegue
git fetch originper scaricare oggetti e ref. - Determina il branch predefinito (l'
HEADdel remote). - Crea un branch locale che lo traccia.
- Fa il checkout di quel branch nella working tree.
Vederlo accadere
GIT_TRACE=1 GIT_TRACE_PACKET=1 git clone https://github.com/example/widget.git 2>&1 | head -50
Vedrai negoziazione di capabilities, advertisement dei ref, negoziazione want/have e ricezione del pack.
Wire protocol
Git moderno supporta il protocollo v2 (git config protocol.version 2 o predefinito in 2.26+). Il server pubblicizza solo i ref richiesti invece della lista completa, il che migliora drasticamente i tempi di clone per repo con molti ref.
Varianti
git clone --bare # nessuna working tree
git clone --mirror # bare + tutti i ref, configurato per mirroring
git clone --depth 1 # shallow
git clone --filter=blob:none # partial clone, salta i blob fino al bisogno
git clone --filter=tree:0 # ancora meno dati, tree on-demand
git clone --single-branch # solo storia di un branch
git clone --branch v1.2.3 # checkout di un branch/tag specifico
git clone --recurse-submodules # clona anche i submodule
git clone --no-checkout # salta il popolamento della working tree
Partial clone
I partial clone (--filter) rimandano il download degli oggetti finché non sono necessari. Richiedono supporto del server (la maggior parte degli host moderni ce l'ha):
git clone --filter=blob:none https://github.com/example/big.git
cd big
git log --oneline # economico; solo oggetti commit e tree scaricati
git show HEAD:src/main.c # questo innesca un fetch di blob
Cosa va dove
Dopo un clone riuscito:
.git/objects/pack/: il pack file ricevuto dal server..git/refs/remotes/origin/: ogni branch del server come ref di tracking remoto..git/HEAD: ref simbolico al nuovo branch locale..git/config: sezione[remote "origin"]con URL e refspec.
Advertisement lato server
La prima cosa che il server invia in qualsiasi clone è l'advertisement dei ref. Sotto il protocollo v0/v1 questo elenca ogni ref, anche se ne vuoi solo uno; su repo enormi con milioni di ref il solo advertisement potrebbe richiedere secondi. Il protocollo v2 cambia questo: il client invia una richiesta ls-refs specificando pattern, e il server pubblicizza solo i ref corrispondenti:
git -c protocol.version=2 ls-remote origin 'refs/heads/main'
GIT_TRACE_PACKET=1 git -c protocol.version=2 ls-remote origin 2>&1 | head
Per i clone quotidiani lo speedup è invisibile; per i server di hosting è drammatico.
Errori comuni
Clonare un repo enorme su una rete instabile e ricominciare da capo; git clone in 2.30+ supporta il cloning ripristinabile sopra il protocollo HTTP smart, ma solo se il server lo supporta. Altrimenti prima --depth 1, poi git fetch --unshallow dopo. Clonare in ~/Dropbox o un'altra cartella di sync; il client di sync combatterà con Git per il controllo di .git/index. Clonare un repo con submodule e dimenticare --recurse-submodules, finendo con directory submodule vuote. Infine, clonare via HTTPS senza un credential helper ed essere chiesti delle credenziali a ogni fetch; configurane uno una volta.