Se li capisco correttamente (e sono tutt'altro che un esperto in ciascuno) fondamentalmente ognuno di essi ha una filosofia diversa. Ho usato mercurial per 9 mesi. Ora ho usato git per 6.
hg è un software di controllo versione. Il suo obiettivo principale è tenere traccia delle versioni di un software.
git è un file system basato sul tempo. L'obiettivo è aggiungere un'altra dimensione a un file system. La maggior parte ha file e cartelle, git aggiunge tempo. Il fatto che funzioni alla grande come un VCS è un sottoprodotto del suo design.
In hg, c'è una storia dell'intero progetto che cerca sempre di mantenere. Di default credo che hg voglia tutte le modifiche a tutti gli oggetti da parte di tutti gli utenti quando spingono e tirano.
In git c'è solo un pool di oggetti e questi file di tracciamento (rami / teste) che determinano quale set di quegli oggetti rappresenta l'albero dei file in uno stato particolare. Quando spingi o tira git invia solo gli oggetti necessari per i rami particolari che stai spingendo o tirando, che è un piccolo sottoinsieme di tutti gli oggetti.
Per quanto riguarda git, non esiste un "1 progetto". Potresti avere 50 progetti tutti nello stesso repository e git non ti importerebbe. Ognuno potrebbe essere gestito separatamente nello stesso repository e vivere bene.
Il concetto di Hg di rami è rami del progetto principale o rami di rami ecc. Git non ha tale concetto. Un ramo in git è solo uno stato dell'albero, tutto è un ramo in git. Quale filiale è ufficiale, attuale o più recente non ha alcun significato in Git.
Non so se avesse senso. Se potessi disegnare delle immagini, hg potrebbe apparire così dove ogni commit è ao
o---o---o
/
o---o---o---o---o---o---o---o
\ /
o---o---o
Un albero con una sola radice e rami che ne escono. Mentre git può farlo e spesso le persone lo usano in questo modo che non viene applicato. Un'immagine git, se c'è una cosa del genere, potrebbe facilmente apparire così
o---o---o---o---o
o---o---o---o
\
o---o
o---o---o---o
In effetti in qualche modo non ha nemmeno senso mostrare rami in git.
Una cosa che è molto confusa per la discussione, git e mercurial hanno entrambi qualcosa chiamato "ramo" ma non sono le stesse cose da remoto. Una branca in mercurial si verifica quando ci sono conflitti tra diversi repository. Un ramo in git è apparentemente simile a un clone in hg. Ma un clone, sebbene possa dare un comportamento simile, non è sicuramente lo stesso. Considera di provarli in git vs hg usando il repository di cromo che è piuttosto grande.
$ time git checkout -b some-new-branch
Switched to new branch 'some-new-branch'
real 0m1.759s
user 0m1.596s
sys 0m0.144s
E ora in hg usando clone
$ time hg clone project/ some-clone/
updating to branch default
29387 files updated, 0 files merged, 0 files removed, 0 files unresolved.
real 0m58.196s
user 0m19.901s
sys 0m8.957
Entrambi sono tiri caldi. Cioè, li ho eseguiti due volte e questa è la seconda. hg clone è effettivamente lo stesso di git-new-workdir. Entrambi creano una directory di lavoro completamente nuova quasi come se avessi digitato cp -r project project-clone
. Non è lo stesso che creare un nuovo ramo in git. È molto più pesante. Se esiste un vero equivalente della ramificazione di git in hg, non so cosa sia.
Capisco a un certo livello che hg e git potrebbero essere in grado di fare cose simili. In tal caso, c'è ancora un'enorme differenza nel flusso di lavoro a cui ti portano. In git, il flusso di lavoro tipico è quello di creare un ramo per ogni funzione.
git checkout master
git checkout -b add-2nd-joypad-support
git checkout master
git checkout -b fix-game-save-bug
git checkout master
git checkout -b add-a-star-support
Ciò ha appena creato 3 rami, ognuno basato su un ramo chiamato master. (Sono sicuro che c'è un modo in git di creare quelle 1 linea ciascuna invece di 2)
Ora per lavorare su quello che faccio
git checkout fix-game-save-bug
e inizia a lavorare. Impegnati, ecc. Passare da una filiale all'altra anche in un progetto grande come Chrome è quasi istantaneo. In realtà non so come farlo in hg. Non fa parte di alcun tutorial che ho letto.
Un'altra grande differenza. Il palco di Git.
Git ha questa idea di un palcoscenico. Puoi pensarlo come una cartella nascosta. Quando esegui il commit, esegui solo il commit di ciò che è sul palco, non delle modifiche nell'albero di lavoro. Potrebbe sembrare strano. Se si desidera eseguire il commit di tutte le modifiche nella struttura di lavoro, è necessario git commit -a
aggiungere tutti i file modificati allo stage e quindi eseguirne il commit.
Qual è il punto del palcoscenico allora? Puoi facilmente separare i tuoi impegni. Immagina di aver modificato joypad.cpp e gamesave.cpp e di volerli commettere separatamente
git add joypad.cpp // copies to stage
git commit -m "added 2nd joypad support"
git add gamesave.cpp // copies to stage
git commit -m "fixed game save bug"
Git ha anche dei comandi per decidere quali linee particolari nello stesso file si desidera copiare sullo stage in modo da poter dividere anche quelle commit separatamente. Perché vorresti farlo? Perché come commit separati gli altri possono estrarre solo quelli che vogliono o se c'è stato un problema possono ripristinare solo il commit che ha avuto il problema.