2009-03-05 14 views
144

Ho otto commit su un ramo che vorrei inviare via email ad alcune persone che non sono ancora illuminate. Finora, tutto ciò che faccio mi dà 8 file di patch, o inizia a darmi i file di patch per ogni commit nella cronologia del ramo, dall'inizio del tempo. Ho usato git rebase - Interactive per schiacciare i commit, ma ora tutto ciò che provo mi dà milioni di patch dall'inizio. Che cosa sto facendo di sbagliato?Come si schiacciano i commit in una patch con git format-patch?

git format-patch master HEAD # yields zillions of patches, even though there's 
          # only one commit since master 
+0

Sono curioso di sapere quale metodo si finirà per utilizzare tra le proposizioni di seguito. Fateci sapere;) – VonC

+3

Userò git diff come suggerito da Rob Di Marco. Ma sono fuori lavoro per due settimane, avendo appena assistito alla nascita della mia seconda bambina la scorsa notte, quindi ci vorrà un po 'prima che la usi! :) – skiphoppy

+2

Mi piacerebbe vedere git format-patch --squash master HEAD – schoetbi

risposta

168

Suggerirei di farlo su un ramo usa e getta come segue. Se i commit sono nel ramo "a capo" e si sono passati di nuovo al vostro ramo "master" già, questo dovrebbe fare il trucco:

[[email protected] example (master)]$ git checkout -b tmpsquash 
Switched to a new branch "tmpsquash" 

[[email protected] example (tmpsquash)]$ git merge --squash newlines 
Updating 4d2de39..b6768b2 
Fast forward 
Squash commit -- not updating HEAD 
test.txt | 2 ++ 
1 files changed, 2 insertions(+), 0 deletions(-) 

[[email protected] example (tmpsquash)]$ git commit -a -m "My squashed commits" 
[tmpsquash]: created 75b0a89: "My squashed commits" 
1 files changed, 2 insertions(+), 0 deletions(-) 

[[email protected] example (tmpsquash)]$ git format-patch master 
0001-My-squashed-commits.patch 

Spero che questo aiuti!

+2

Questo è quello che uso quando voglio mantenere la cronologia locale (nel caso in cui ho bisogno di modificare la patch). Altrimenti uso solo rebase -i e schiaccia i commit. – sebnow

+1

migliore soluzione! grazie :) – kkudi

+5

per me, ha funzionato in modo più affidabile con 'git comit -m" I miei commit schiacciati "' altrimenti aggiungerei altri file non tracciati – Sebastian

18

Come già sapete, un git format-patch -8 HEAD vi darà otto patch.

Se si desidera che le 8 commit appaiono come uno, e non la mente di riscrivere la storia della vostra filiale (o-o-X-A-B-C-D-E-F-G-H), si potrebbe:

git rebase -i 
// squash A, B, C, D, E ,F, G into H 

o, e sarebbe una soluzione migliore, riproduzione tutte le 8 commit da X (il commit prima che i vostri 8 commit) su un nuovo ramo

git branch delivery X 
git checkout delivery 
git merge --squash master 
git format-patch HEAD 

questo modo, si hanno solo un commit sul ramo "fornitura", e rappresentano tutta la tua ultima 8 c ommits

+0

'git merge master' fa semplicemente un avanzamento veloce e non schiaccia i commit in uno solo. Passa a 'git merge --squash master' per ottenere tutti i commit schiacciati e visibili nell'area di staging. Il tuo flusso funzionerà con questo cambiamento. (Sto usando git versione 2.1.0.) – Stunner

+0

@Stunner buon punto. Ho modificato la risposta. – VonC

21

Io uso sempre git diff così nel tuo esempio, qualcosa come

git diff master > patch.txt 
+14

Tranne che perdi tutti i messaggi di commit e i metadati. La bellezza di git format-patch è che è possibile ricostruire l'intero ramo da una serie di patch. – mcepl

+0

il metodo create-branch-and-squash ha il vantaggio di combinare tutti i messaggi di commit in uno solo, ma questo metodo è molto più veloce se si vuole scrivere il proprio messaggio di commit – woojoo666

+0

in realtà, un messaggio combinato può essere fatto usando 'git log ', vedi [la mia risposta] (http://stackoverflow.com/a/32373193/1852456) per un esempio – woojoo666

120

Giusto per aggiungere più una soluzione per il piatto: Se si utilizza questo invece:

git format-patch master --stdout > my_new_patch.diff 

allora sarà saranno ancora 8 patch ... ma saranno tutti in un unico file di patch e si applicheranno come uno con:

git am < my_new_patch.diff 
+13

Mi piace questa soluzione. Vale la pena notare che può creare patch a volte molto più grande del metodo descritto da @Adam Alexander. Questo perché alcuni file possono essere modificati più di una volta tramite commit. Questo metodo tratta ogni commit separatamente, anche se alcuni file sono stati ripristinati. Ma la maggior parte delle volte questo non è un problema. – gumik

+1

Questa opzione è ottima se stai cercando di evitare la fusione! (ad esempio, vuoi saltare alcuni commit). Puoi ancora 'git rebase -i ...' e schiacciali tutti a uno solo. –

17

Questo è un adattamento della risposta di Adam Alexander, nel caso in cui le modifiche siano nel ramo principale. Questo procedere come segue: testa

  • Crea un nuovo ramo usa e getta "tmpsquash" dal punto che vogliamo (cercare la chiave SHA esecuzione "git --log" o con gitg Selezionare il commit si vuole essere tmpsquash. , i commit che sono dopo quello in master saranno i commit schiacciati).
  • Unisce le modifiche da master a tmpsquash.
  • Conferma le modifiche schiacciate a tmpsquash.
  • Crea la patch con i commit schiacciati.
  • risale al ramo principale

[email protected]:~/example (master)$ git branch tmpsquash ba3c498878054e25afc5e22e207d62eb40ff1f38 
[email protected]:~/example (master)$ git checkout tmpsquash 
Switched to branch 'tmpsquash' 
[email protected]:~/example (tmpsquash)$ git merge --squash master 
Updating ba3c498..40386b8 
Fast-forward 
Squash commit -- not updating HEAD 

[snip, changed files] 

11 files changed, 212 insertions(+), 59 deletions(-) 
[email protected]:~/example (tmpsquash)$ git commit -a -m "My squashed commits" 
[test2 6127e5c] My squashed commits 
11 files changed, 212 insertions(+), 59 deletions(-) 
[email protected]:~/example (tmpsquash)$ git format-patch master 
0001-My-squashed-commits.patch 
[email protected]:~/example (tmpsquash)$ git checkout master 
Switched to branch 'master' 
[email protected]:~/example (master)$ 
+0

Effettuare i cambiamenti in master è un anti-pattern se non li spingerai a te stesso da remoto. E se lo farai, probabilmente non avrai bisogno di generare file di patch per loro. –

0

in base alla risposta di Adam Alexander:

git checkout newlines 
## must be rebased to master 
git checkout -b temporary 
# squash the commits 
git rebase -i master 
git format-patch master 
4

Format-patch tra due tag:

git checkout <source-tag> 
git checkout -b <tmpsquash> 
git merge --squash <target-tag> 
git commit -a -m "<message>" 
git format-patch <source-tag> 
4

modo più semplice è per utilizzare git diff, a e aggiungere git log se si desidera che il messaggio di commit combinato venga emesso dal metodo squash. Ad esempio, per creare la patch tra il commit abcd e 1234:

git diff abcd..1234 > patch.diff 
git log abcd..1234 > patchmsg.txt 

Poi, quando l'applicazione della patch:

git apply patch.diff 
git add -A 
git reset patch.diff patchmsg.txt 
git commit -F patchmsg.txt 

Non dimenticare l'argomento --binary a git diff quando si tratta di file non di testo, per esempio immagini o video.