2012-05-01 15 views
28

Secondo this:git memorizza informazioni diff negli oggetti commit?

E 'importante notare che questo è molto diverso dalla maggior parte dei sistemi SCM che si può essere a conoscenza. Subversion, CVS, Perforce, Mercurial e simili utilizzano tutti i sistemi di storage Delta: memorizzano le differenze tra un commit e il successivo. Git non lo fa questo - memorizza un'istantanea di ciò che tutti i file nel tuo progetto appaiono in questa struttura ad albero ogni volta che esegui il commit. Questo è un concetto molto importante di da comprendere quando si usa Git.

Eppure, quando ho eseguito git show $SHA1ofCommitObject ...

commit 4405aa474fff8247607d0bf599e054173da84113 
Author: Joe Smoe <[email protected]> 
Date: Tue May 1 08:48:21 2012 -0500 

    First commit 

diff --git a/index.html b/index.html 
new file mode 100644 
index 0000000..de8b69b 
--- /dev/null 
+++ b/index.html 
@@ -0,0 +1 @@ 
+<h1>Hello World!</h1> 
diff --git a/interests/chess.html b/interests/chess.html 
new file mode 100644 
index 0000000..e5be7dd 
--- /dev/null 
+++ b/interests/chess.html 
@@ -0,0 +1 @@ 
+Did you see on Slashdot that King's Gambit accepted is solved! <a href="http://game 

... essa stampa il diff della impegnarsi con i commit precedenti. So che git non memorizza le differenze negli oggetti blob, ma memorizza le differenze negli oggetti commit? O è git show che calcola dinamicamente il diff?

+7

Una nota a margine: Git esegue effettivamente la compressione delta degli oggetti, ma è solo per motivi di compressione. Le persone a volte fraintendono questo come dicendo che Git memorizza le diff. C'è una certa documentazione del formato qui: http://book.git-scm.com/7_the_packfile.html (tieni presente che gli oggetti in cui registra i delta sono solo blob di dati che ha scoperto essere simili, non sono necessariamente versioni consecutive dello stesso file, anche se potrebbero essere. E, naturalmente, i delta non sono diffusi line-by-line. – Cascabel

+1

Aggiornamento del link molto pertinente da Jefromi: http://git-scm.com/book/ it/Git-Internals-Packfiles –

risposta

32

No, gli oggetti commit in git non contengono diffs - invece, ciascun oggetto di commit contiene un hash dell'albero, che definisce in modo ricorsivo e completo il contenuto dell'albero di origine in quel commit. C'è un nice explanation in the git community book di ciò che va in oggetti BLOB, oggetti albero e oggetti commit.

Tutte le differenze mostrate dagli strumenti di Git sono calcolate su richiesta dal contenuto completo dei file.

52

Ciò che la dichiarazione significa è che, la maggior parte degli altri sistemi di controllo delle versioni necessita di un punto di riferimento nel passato per poter ricreare il commit corrente.

Per esempio, ad un certo punto, in passato, un VCS diff-based (sistema di controllo di versione) avrebbe conservato una fotografia completa:

x = snapshot 
+ = diff 
History: 
x-----+-----+-----+-----(+) Where we are now 

Così, in un tale scenario, per ricreare il stato a (ora), dovrebbe effettuare il checkout (x) e quindi applicare diffs per ogni (+) fino a quando non arriva a ora. Si noti che sarebbe estremamente inefficiente archiviare i delta per sempre, quindi ogni VCS basato sul delta memorizza un'istantanea completa. Here's how its done for subversion.

Ora, git è diverso. Git memorizza i riferimenti per completare i BLOB e ciò significa che con git, , è sufficiente un solo commit per ricreare il codebase in quel momento nel tempo. Git non ha bisogno di cercare informazioni dalle revisioni passate per creare un'istantanea.

Quindi se questo è il caso, allora da dove viene la compressione delta che git usa?

Bene, non è nient'altro che un concetto di compressione: non è possibile memorizzare la stessa informazione due volte, se solo una piccola quantità è cambiata. Pertanto, rappresenta ciò che è cambiato, ma memorizza un riferimento ad esso, in modo che il commit a cui appartiene, che è in effetti un albero di riferimenti, possa ancora essere ricreato senza guardare ai commit passati. Il fatto è, però, che Git non lo fa immediatamente dopo ogni commit, ma piuttosto su una raccolta di dati inutili. Quindi, se git non ha eseguito la sua garbage collection, puoi vedere oggetti nel tuo indice con contenuti molto simili.

Tuttavia, quando Git esegue la sua garbage collection (o quando si chiama manualmente git gc), i duplicati vengono puliti e viene creato un file pack di sola lettura.Non devi preoccuparti di eseguire manualmente la garbage collection - git contiene l'euristica che dice quando farlo.

+4

Sorpreso dei pochi voti. –

+0

Grazie, Carl. Quindi commettere piccoli cambiamenti in un grande progetto non gonfia il repository con molte copie ridondanti (almeno nel lungo periodo)? – shuhalo

+0

@shuhalo Proprio così, anche se è ancora meglio di così. Se hai fatto una copia di tutti i tuoi file sorgente e li hai aggiunti al tuo commit corrente, le uniche informazioni aggiuntive dopo una sessione gc sarebbero i metadati: nomi di file, percorsi, autore e simili. Il contenuto effettivo dei file stessi si riferirebbe semplicemente ai blob in passato che provenivano dal codice originale. – Carl