Nota: una delle maggiori differenze tra Git e Mercurial è la presenza esplicita dell'indice o dell'area di staging .
Da Mercurial per l'utente Git :
Git è l'unico DistributedSCM che espone il concetto di indice o area di staging. Gli altri possono implementarlo e nasconderlo, ma in nessun altro caso l'utente è a conoscenza né deve occuparsene.
L'equivalente approssimativo di Mercurial è il DirState
, che controlla le informazioni sullo stato della copia di lavoro per determinare i file da includere nel commit successivo. In ogni caso, questo file viene gestito automaticamente.
Inoltre, è possibile essere più selettivi al momento del commit specificando i file che si desidera eseguire il commit sulla riga di comando o utilizzando il RecordExtension
.
Se ti sei sentito a disagio nel trattare con l'indice, stai cambiando in meglio ;-)
Il trucco è che devi davvero capire l'indice per sfruttare appieno Git. Come ci ricorda allora questo articolo del maggio 2006 (ed è ancora vero ora):
"Se neghi l'indice, neghi davvero lo stesso git."
Ora, quell'articolo contiene molti comandi che ora sono più semplici da usare (quindi non fare troppo affidamento sul suo contenuto;)), ma l'idea generale rimane:
Stai lavorando a una nuova funzionalità e inizi ad apportare piccole modifiche a un file.
# working, add a few lines
$ git add myFile
# working, another minor modification
$ git add myFile
A questo punto, il tuo prossimo commit introdurrà 2 piccole modifiche nel ramo corrente
# working, making major modification for the new features
# ... damn! I cannot commit all this in the current branch: nothing would work
$ git commit
Registra solo le modifiche aggiunte all'area di staging (indice) a questo punto, non le modifiche principali attualmente visibili nella directory di lavoro.
$ git branch newFeature_Branch
$ git add myFile
Il prossimo commit registrerà tutte le altre modifiche principali nel nuovo ramo "newFrature_Branch".
Ora, l'aggiunta interattiva o anche la suddivisione di un commit sono funzionalità disponibili con Mercurial, tramite il hg record
comando " " o altre estensioni: dovrai installare RecordExtension
, o il file CrecordExtension
.
Ma questo non fa parte del normale flusso di lavoro per Mercurial.
Git vede un commit come una serie di " modifiche al contenuto del file " e ti consente di aggiungere tali modifiche una alla volta.
Dovresti studiare quella caratteristica e le sue conseguenze: la maggior parte del potere di Git (come la capacità di annullare facilmente un'unione (o dividere in due il problema, o ripristinare un commit) , contrariamente a Mercurial ) deriva da quel paradigma del "contenuto di file".
tonfa (nel profilo: "Hg dev, pythonist": figures ...) è intervenuta, nei commenti:
Non c'è niente di fondamentalmente "git-ish" nell'indice, hg potrebbe usare un indice se fosse ritenuto prezioso, in effetti mq
o shelve
già ne fa parte.
Oh ragazzo. Ci risiamo.
Primo, non sono qui per far sembrare uno strumento migliore di un altro. Trovo Hg fantastico, molto intuitivo, con un buon supporto (soprattutto su Windows, la mia piattaforma principale, anche se lavoro anche su Linux e Solaris8 o 10).
L'indice è in realtà davanti e al centro nel modo in cui Linus Torvalds lavora con un VCS :
Git ha utilizzato gli aggiornamenti espliciti dell'indice dal primo giorno, anche prima della prima unione. È semplicemente come ho sempre lavorato. Tendo ad avere alberi sporchi, con alcune patch casuali nel mio albero che non voglio inserire, perché è solo un aggiornamento del Makefile per la prossima versione
Ora la combinazione di index (che non è una nozione vista solo in Git) e il paradigma "content is king" lo rende piuttosto unico e "git-ish" :
git è un tracker di contenuti e il nome di un file non ha significato se non è associato al suo contenuto. Pertanto, l'unico comportamento corretto per git add filename è aggiungere il contenuto del file e il suo nome all'indice.
Nota: il "contenuto", qui, è definito come segue :
L'indice di Git è fondamentalmente molto definito come
- sufficiente a contenere il " contenuto " totale dell'albero (e questo include tutti i metadati: il nome del file, la modalità e il contenuto del file sono tutte parti del "contenuto" e sono tutti privi di significato da soli! )
- informazioni "stat" aggiuntive per consentire le ovvie e banali (ma estremamente importanti!) ottimizzazioni del confronto del filesystem.
Quindi si dovrebbe vedere l'indice come essendo il contenuto .
Il contenuto non è il "nome file" o il "contenuto file" come parti separate. Non puoi davvero separare i due .
I nomi dei file da soli non hanno senso (devono avere anche il contenuto del file), e il contenuto del file da solo è altrettanto insensato (devi sapere come raggiungerlo).
Quello che sto cercando di dire è che git fondamentalmente non ti consente di vedere un nome di file senza il suo contenuto. L'intera nozione è folle e non valida. Non ha rilevanza per la "realtà".
Dalle FAQ i principali vantaggi sono:
- impegnarsi con una granularità fine
- ti aiuta a mantenere una modifica non modificata nel tuo albero per un tempo ragionevolmente lungo
- esegui diversi piccoli passaggi per un commit, controllando cosa hai fatto
git diff
e convalidando ogni piccolo passaggio con git add
o git add -u
.
- permette un'ottima gestione dei conflitti di unione:
git diff --base
, git diff --ours
, git diff --theirs
.
- permette
git commit --amend
di modificare solo il messaggio di log se nel frattempo l'indice non è stato modificato
Personalmente penso che questo comportamento non dovrebbe essere l'impostazione predefinita, vuoi che le persone inviino qualcosa che viene testato o almeno compilato
Sebbene tu abbia ragione in generale (riguardo alla parte "testata o compilata"), il modo in cui Git ti consente di ramificare e fondere (selezione o ribasatura) ti consente di eseguire il commit tutte le volte che vuoi in un ramo privato temporaneo (solo push al repository di "backup" remoto), mentre si rifanno quei "brutti commit" su un ramo pubblico, con tutti i test giusti in atto.