Creare una patch in GIT è un ottimo modo per condividere le modifiche che non sei ancora pronto per inviare al pubblico ramo di un progetto.
Per capire meglio come creeremo una patch, discutiamo prima un po' di come cambiano gli archivi GIT.
Se non conosci GIT, installa git e inizia subito da questo articolo introduttivo a GIT.
La prima volta che viene eseguito il commit di un file in un progetto in GIT, viene archiviata una copia. Per tutti i commit successivi, GIT essenzialmente memorizza le istruzioni che gli dicono come trasformare la versione precedente del progetto nella nuova versione con commit.
In GIT, queste istruzioni sono chiamate "diffs" . Ogni volta che esegui il checkout di un ramo, GIT partirà sostanzialmente dallo stato originale del progetto e applicherà tutte queste differenze in ordine per raggiungere lo stato desiderato.
Sapendo ora come GIT memorizza i commit, è facile vedere che un file di patch sarà semplicemente una concatenazione delle differenze per ciascuno dei commit su cui si estenderà la patch.
Per il nostro esempio, assumiamo la seguente situazione:abbiamo un progetto semplice con 2 rami:master e sperimentale.
$ git log --oneline --all * b36f227 (experimental) third commit -- added file3 * f39ebe8 second commit -- added file2 * 04a26e5 (HEAD, master) first commit -- committed file1
Il master è attualmente al primo commit, mentre lo sperimentale è 2 commit prima di esso. In ogni commit, ho aggiunto un file chiamato rispettivamente file1, file2 e file3. Ecco lo stato attuale di ogni filiale:
Sul master abbiamo solo file1:
$ git status On branch master nothing to commit, working directory clean $ ls file1
Durante la sperimentazione, abbiamo tutti e 3 i file:
$ git status On branch experimental nothing to commit, working directory clean $ ls file1 file2 file3
In questo tutorial spiegheremo come creare una patch delle modifiche sul ramo sperimentale e applicarle al master.
Creazione della patch GIT
Useremo il comando git diff per creare l'output diff, quindi reindirizzarlo in un file. La forma del comando diff che useremo è la seguente:
git diff from-commit to-commit > output-file
dove:
- from-commit – il punto in cui vogliamo che inizi la patch. (Nel nostro caso, il punto in cui sperimentale diverge dal maestro)
- to-commit:la patch estenderà le modifiche fino a questo punto incluso. (Nel nostro caso, il commit più recente di sperimentale)
- file di output:la patch verrà scritta qui
Nota:se vengono omessi from-commit o to-commit, verranno considerati HEAD
Specifichiamo i due commit in base al loro hash univoco. In genere, devi solo specificare una quantità sufficiente di hash di commit per garantirne l'unicità (probabilmente 4 caratteri lo faranno).
$ git diff 04a2 b36f > patch.diff $ ls patch.diff file1 file2 file3
Come puoi vedere dall'output sopra, il file della patch è stato creato.
In questo caso speciale, in cui vogliamo creare una patch dell'intero ramo, possiamo lasciare che GIT faccia parte del lavoro per noi. Possiamo lasciare che GIT determini il punto in cui il nostro ramo sperimentale si è discostato dal ramo principale usando il comando git merge-base:
git diff $(git merge-base <public branch> <experimental branch>) > <output file>
git merge-base determinerà il commit comune più recente tra 2 branch. Notate anche come questa volta abbiamo omesso. Il valore predefinito sarà HEAD e, poiché il ramo sperimentale è stato ritirato, HEAD sarà il commit più recente del ramo sperimentale.
$ git diff $(git merge-base master experimental) > anotherPatch.diff $ ls anotherPatch.diff patch.diff file1 file2 file3
Anche in questo caso, il file della patch è stato creato. Questi file di patch sono identici.
Applicazione della patch GIT
Una volta creato il file di patch, applicarlo è facile. Assicurati che il ramo che hai estratto sia quello a cui vuoi applicare la patch (master nel nostro caso). Quindi puoi applicare la patch usando il comando git apply:git apply
$ git status On branch master ... (rest of output omitted) ... $ ls anotherPatch.diff patch.diff file1 $ git apply patch.diff $ ls anotherPatch.diff patch.diff file1 file2 file3
Le modifiche dal ramo sperimentale ora sono state replicate su master.
Avvertenza:sebbene l'applicazione di una patch in questo modo replichi esattamente il contenuto, non verrà replicata alcuna cronologia dei commit. Ciò significa che anche se la patch che crei si estende su più commit, apparirà come un unico insieme di modifiche quando applicata. Perderai sia la conoscenza di come sono stati interrotti i commit sia i messaggi per ogni commit. Confrontiamo la cronologia dei commit per entrambi i rami:
Su Experimental, abbiamo avuto 3 commit, ognuno con un messaggio di commit significativo.
$ git branch * experimental master $ git log --oneline b36f227 third commit -- added file3 f39ebe8 second commit -- added file2 04a26e5 first commit -- committed file1
Tuttavia, la nostra patch ha semplicemente applicato le modifiche effettive al ramo principale.
$ git branch experimental * master $ git log --oneline 04a26e5 first commit -- committed file1
L'applicazione della patch non ha eseguito il commit delle modifiche, né ha portato con sé la cronologia di commit associata a queste modifiche. Fai attenzione quando usi le patch in GIT.