Come si impegna a squash in una patch con git format-patch?


163

Ho otto commit su una filiale che mi piacerebbe inviare per e-mail ad alcune persone che non sono ancora illuminate. Finora, tutto ciò che faccio o mi dà 8 file di patch, o inizia a darmi file di patch per ogni commit nella storia del ramo, dall'inizio del tempo. Ho usato git rebase - interattivo per eliminare i commit, ma ora tutto ciò che provo mi dà miliardi di patch dall'inizio del tempo. Che cosa sto facendo di sbagliato?

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

Sono curioso di sapere quale metodo finirai per utilizzare tra le proposizioni di seguito. Facci sapere;)
VonC

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

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

1
Prova master..HEAD per specificare un intervallo di giri.
Konrad Kleine,

Risposte:


186

Consiglierei di farlo su un ramo usa e getta come segue. Se i tuoi commit sono nel ramo "newlines" e sei già tornato al tuo ramo "master", questo dovrebbe fare il trucco:

[adam@mbp2600 example (master)]$ git checkout -b tmpsquash
Switched to a new branch "tmpsquash"

[adam@mbp2600 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(-)

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

[adam@mbp2600 example (tmpsquash)]$ git format-patch master
0001-My-squashed-commits.patch

Spero che questo ti aiuti!


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

5
per me, ha funzionato in modo più affidabile git comit -m "My squashed commits"altrimenti avrebbe aggiunto altri file non tracciati
Sebastian,

Inoltre, è possibile passare a un commit specifico anziché al master e fare questo per creare una patch da commit a commit:git checkout 775ec2a && git checkout -b patch && git merge --squash branchname
Berry M.

131

Solo per aggiungere un'altra soluzione al piatto: se invece usi questo:

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

Quindi saranno ancora 8 patch ... ma saranno tutte in un singolo file di patch e verranno applicate come una con:

git am < my_new_patch.diff

13
Mi piace questa soluzione. Vale la pena notare che a volte può creare patch molto più grandi rispetto al 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 il più delle volte questo non è un problema.
Gumik,

1
Questa opzione è ottima se stai cercando di evitare l'unione! (ad esempio, si desidera saltare alcuni commit). Puoi ancora git rebase -i ...e schiacciarli tutti fino a uno.
Jorge Orpinel,

21

Uso sempre git diff così nel tuo esempio, qualcosa del genere

git diff master > patch.txt

15
Tranne che perdi tutti i messaggi e i metadati di commit. Il bello del formato git è che è possibile ricostruire l'intero ramo da un set di patch.
mcepl,

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

in realtà, un messaggio combinato può essere fatto usando git log, vedi la mia risposta per un esempio
woojoo666

2
Bella opzione, ma considera che 'git diff' non può includere differenze binarie (forse c'è un'opzione per farlo).
Santiago Villafuerte,

18

Questo è un adattamento della risposta di Adam Alexander, nel caso in cui le modifiche siano nel ramo principale. In questo modo:

  • Crea un nuovo ramo usa e getta "tmpsquash" dal punto che vogliamo (cerca il tasto SHA che esegue "git --log" o con gitg. Seleziona il commit che vuoi essere tmpsquash head, i commit che saranno dopo in master saranno lo schiacciato si impegna).
  • Unisce le modifiche da master a tmpsquash.
  • Commette le modifiche schiacciate a tmpsquash.
  • Crea la patch con i commit schiacciati.
  • Torna al ramo principale

laura@rune:~/example (master)$ git branch tmpsquash ba3c498878054e25afc5e22e207d62eb40ff1f38
laura@rune:~/example (master)$ git checkout tmpsquash
Switched to branch 'tmpsquash'
laura@rune:~/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(-)
laura@rune:~/example  (tmpsquash)$ git commit -a -m "My squashed commits"
[test2 6127e5c] My squashed commits
11 files changed, 212 insertions(+), 59 deletions(-)
laura@rune:~/example  (tmpsquash)$ git format-patch master
0001-My-squashed-commits.patch
laura@rune:~/example  (tmpsquash)$ git checkout master
Switched to branch 'master'
laura@rune:~/example  (master)$

Apportare modifiche in master è un anti-pattern se non li spingerai a controllarti da remoto. E se lo farai, probabilmente non avrai bisogno di generare file patch per loro.
ivan_pozdeev,

18

Come già sapete, git format-patch -8 HEADvi darà otto patch.

Se vuoi che i tuoi 8 commit vengano visualizzati come uno e non ti dispiaccia riscrivere la cronologia del tuo ramo ( o-o-X-A-B-C-D-E-F-G-H), potresti:

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

o, e sarebbe una soluzione migliore, riprodurre tutti i tuoi 8 commit da X(il commit prima dei tuoi 8 commit) su una nuova filiale

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

In questo modo, hai un solo commit sul ramo "consegna" e rappresenta tutti gli ultimi 8 commit


git merge masterfa semplicemente un avanzamento veloce e non lo schiaccia in uno. Passare a git merge --squash masterper ottenere tutti i commit schiacciati e visibili nell'area in scena. Il tuo flusso funzionerà con questo cambiamento. (Sto usando git versione 2.1.0.)
Stunner

5

Patch di formato 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>

5

Il modo più semplice è utilizzare git diffe aggiungere git logse si desidera il messaggio di commit combinato che il metodo squash produrrebbe. Ad esempio, per creare la patch tra commit abcde 1234:

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

Quindi quando si applica la patch:

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

Non dimenticare l' --binaryargomento di git diffquando si tratta di file non di testo, ad esempio immagini o video.


0

Basato sulla 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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.