L'affermazione che "la ramificazione è libera in git" è una semplificazione dei fatti perché non è "libera" di per sé. Guardando sotto il cofano, un'affermazione più corretta sarebbe quella di dire che la ramificazione è invece ridicolmente economica , perché le filiali sono fondamentalmente riferimenti a commit . Definisco "economicità" qui come meno sovraccarico più economico.
Scopriamo perché Git è così "economico" esaminando che tipo di spese generali ha:
Come sono implementate le filiali in git?
Il repository git, .git
principalmente costituito da directory con file che contengono metadati che git usa. Ogni volta che crei un ramo in git, ad esempio git branch {name_of_branch}
, accadono alcune cose:
- Viene creato un riferimento alla filiale locale in:
.git/refs/heads/{name_of_branch}
- Viene creato un registro cronologico per la filiale locale in:
.git/logs/refs/heads/{name_of_branch}
È praticamente tutto, vengono creati un paio di file di testo. Se si apre il riferimento come file di testo, il contenuto sarà l'id-sha del commit a cui punta il ramo. Si noti che la ramificazione non richiede di eseguire alcun commit poiché sono un altro tipo di oggetto. Sia le filiali che i commit sono "cittadini di prima classe" e un modo è quello di pensare alla relazione branch-to-commit come aggregazione piuttosto che come composizione. Se rimuovi un ramo, i commit rimarranno comunque "penzolanti". Se hai rimosso accidentalmente un ramo, puoi sempre provare a trovare il commit con git-lost-found
o git-fsck --lost-found
e creare un ramo sullo sha-id che trovi lasciato sospeso (e fintanto che git non ha ancora fatto alcuna garbage collection).
Quindi, come fa Git a tenere traccia di quale ramo stai lavorando? La risposta è con il .git/HEAD
file, che sembra un po 'così se sei sul master
ramo.
ref: refs/heads/master
Il cambio di diramazione modifica semplicemente il riferimento nel .git/HEAD
file, quindi procede a modificare il contenuto dell'area di lavoro con quelli definiti nel commit.
Come si confronta in altri sistemi di controllo versione?
In Subversion , i rami sono directory virtuali nel repository . Quindi il modo più semplice per diramare è farlo da remoto, con un solo strato svn copy {trunk-url} {branch-url} -m "Branched it!"
. Ciò che SVN farà è il seguente:
- Copia la directory di origine, ad esempio
trunk
, in una directory di destinazione,
- Conferma le modifiche per finalizzare l'azione di copia.
È consigliabile eseguire questa azione in remoto sul server, poiché eseguire tale copia localmente è un'operazione lineare, con i file che vengono copiati e collegati in modo simbolico. Questa è un'operazione molto lenta , mentre farlo sul server è un'operazione a tempo costante. Si noti che anche quando si esegue il ramo sul server, la sovversione richiede un commit quando si ramifica mentre git no, il che è una differenza fondamentale. Questo è un tipo di overhead che rende SVN leggermente meno economico di Git.
Il comando per cambiare ramo in SVN , cioè svn switch
, è davvero svn update
sotto mentite spoglie. Grazie al concetto di directory virtuale il comando è un po 'più flessibile in svn che in git. Le sottodirectory nell'area di lavoro possono essere disattivate per rispecchiare un altro URL repository. La cosa più vicina sarebbe usare git-submodule
ma usarlo è semanticamente abbastanza diverso dalla ramificazione. Sfortunatamente questa è anche una decisione di progettazione che rende un passaggio un po 'più lento in SVN che in Git in quanto deve controllare ogni directory dello spazio di lavoro su quale url remoto rispecchia. Nella mia esperienza, Git è più veloce nel cambiare ramo rispetto a SVN.
La ramificazione di SVN ha un costo in quanto copia i file e deve sempre essere resa pubblica. In git, come spiegato sopra, i rami sono "solo riferimenti" e possono essere conservati nel tuo repository locale ed essere pubblicati a tua discrezione. Nella mia esperienza, tuttavia, SVN è ancora notevolmente più economico e più performante rispetto ad esempio a ClearCase.
È solo un peccato che SVN non sia decentralizzato. È possibile disporre di più repository come mirroring di alcuni repository di origine, ma la sincronizzazione di modifiche diverse non è possibile per più repository SVN poiché SVN non ha identificatori univoci per i commit (git ha identificatori con hash basati sul contenuto del commit). Il motivo per cui ho iniziato personalmente a usare git su SVN è perché l' avvio di un repository è notevolmente più semplice ed economico in git . Concettualmente in termini di gestione della configurazione del software, ogni copia divergente di un progetto (clone, fork, area di lavoro o altro) è un "ramo" e, data questa terminologia, creare una nuova copia in SVN non è economico come Git, dove quest'ultimo ha rami "integrati".
Come altro esempio, in Mercurial , il branching è iniziato in modo leggermente diverso rispetto a un DVCS e la creazione / distruzione di rami con nome ha richiesto commit separati. Gli sviluppatori di Mercurial implementati in seguito nei segnalibri di sviluppo per imitare lo stesso modello di ramificazione di Git heads
sono chiamati tips
e branches
sono bookmarks
invece nella terminologia mercuriale.