Come usare git merge --squash?


1209

Ho un server Git remoto, ecco lo scenario che voglio eseguire:

  • Per ogni bug / funzione creo un ramo Git diverso

  • Continuo a impegnare il mio codice in quel ramo Git con messaggi Git non ufficiali

  • Nel repository superiore dobbiamo eseguire un commit per un bug con il messaggio Git ufficiale

Quindi, come posso unire il mio ramo al ramo remoto in modo che ottengano un solo commit per tutti i miei check-in (voglio anche fornire un messaggio di commit per questo)?


1
Non sono sicuro di averti completamente capito, ma potresti desiderare una "fusione di polpo".
MatrixFrog,

27
In genere uso git rebase -i per comprimere tutti i miei commit in un unico commit e riscrivere il messaggio di commit. Quindi lo mando a monte.
Edward Falk,

17
git merge --squashfa tutto dalla riga di comando in un colpo solo e speri solo che funzioni. git rebase -ivisualizza un editor e consente di ottimizzare il rebase. È più lento, ma puoi vedere cosa stai facendo. Inoltre, ci sono differenze tra rebase e merge che sono un po 'troppo coinvolte per essere affrontate in un commento.
Edward Falk,

4
il problema con tutte queste risposte è che devi trovarti sul ramo principale localmente ed eseguire il comando merge --squash ... Voglio eseguire il comando merge --squash dal ramo funzione non dal ramo principale ... quando ho finito, posso spingere il ramo di funzionalità sul telecomando e inviare un PR, è possibile?
Alexander Mills,

2
@AlexanderMills, penso che tu abbia solo bisogno di un secondo ramo di funzionalità (clonato dal ramo principale). Esegui il passaggio merge --squashdal vecchio al nuovo, quindi unisci il nuovo ramo al master. Il vecchio ramo diventa obsoleto.
Gyromite,

Risposte:


2002

Supponiamo che venga chiamato il ramo per la correzione di bug bugfixe si desidera unirlo in master:

git checkout master
git merge --squash bugfix
git commit

Questo prenderà tutti i commit dal bugfixramo, li schiaccerà in 1 commit e li fonderà con il tuo masterramo.


Spiegazione :

git checkout master

Passa al tuo masterramo.

git merge --squash bugfix

Prende tutti i commit dal bugfixramo e li unisce al ramo corrente.

git commit

Crea un unico commit dalle modifiche unite.

Se si omette il -mparametro, è possibile modificare una bozza del messaggio di commit contenente tutti i messaggi dei commit compressi prima di finalizzare il commit.


222
Se vuoi mantenere i riferimenti ai vecchi messaggi di commit puoi scrivere git commit(senza -mparam) e potrai modificare un messaggio di commit redatto contenente tutti i messaggi di commit che hai schiacciato.
Alex

12
Puoi ottenere lo stesso facendo git commit --amend -m '...'più tardi.
Janusz Lenar,

19
Nel caso in cui si verifichino conflitti di unione e questi vengano risolti, git commitnon verrà più mostrato l'utile messaggio di commit contenente tutti i messaggi di commit che hai schiacciato. In tal caso, provare git commit --file .git/SQUASH_MSG(tramite stackoverflow.com/a/11230783/923560 ).
Abdull,

23
Tieni presente che lo schiacciamento di default attribuirà i commit allo squasher . Per mantenere l'autore originale, è necessario specificarlo esplicitamente in questo modo:git commit -a --author="Author" --message="Issue title #id"
gaborous

5
git merge --squashconsente di creare un unico commit sopra il ramo corrente il cui effetto è lo stesso della fusione di un altro ramo. Ma non produrrà il record di unione, il che significa che la tua richiesta pull come risultato non avrebbe modifiche, ma non sarà contrassegnata come unita! Quindi, dovrai solo eliminare quel ramo per essere fatto.
am0wa,

129

Ciò che alla fine mi ha chiarito questo è stato un commento che mostra che:

git checkout main
git merge --squash feature

è l'equivalente di fare:

git checkout feature
git diff main > feature.patch
git checkout main
patch -p1 < feature.patch
git add .

Quando voglio unire un ramo di funzionalità con 105 (!!) commit e averli tutti compressi in uno, non voglio git rebase -i origin/masterperché devo risolvere separatamente i conflitti di unione per ciascuno dei commit intermedi (o almeno quelli che git non riesce a capire se stesso). L'utilizzo git merge --squashmi dà il risultato che desidero, di un unico commit per l'unione di un intero ramo di caratteristiche. E ho solo bisogno di fare al massimo una risoluzione manuale dei conflitti.


75
Consiglio vivamente di eseguire prima l'unione nel ramo delle caratteristiche git merge mastere solo successivamente git merge --squash featurenel ramo principale.
dotancohen,

8
@dotancohen Mi dispiace per il drag-up di un vecchio commento :) Cosa si ottiene dalla fusione nel ramo delle caratteristiche prima di esibirsi git merge --squash featuredal ramo principale?
bitsmack

57
Si desidera unire prima il master nel ramo delle funzionalità e gestire eventuali correzioni manuali nel ramo delle funzioni. Ciò consente anche di eseguire test e assicurarsi che il ramo delle funzionalità funzioni correttamente. Quindi, hai la garanzia di poter eseguire l'unione automatica del ramo della funzionalità in master.
Dan Kohn,

4
@dankohn Ti suggerisco di aggiungere la spiegazione nel tuo commento sopra nella tua risposta.
Guntbert,

3
@bitsmack: per prima cosa uniresti master in funzionalità. Questo ti dà l'opportunità di risolvere i conflitti sulla funzionalità prima di fonderla con il master
Mike

97

Vuoi unirti con l'opzione squash. Questo se vuoi farlo un ramo alla volta.

git merge --squash feature1

Se vuoi unire tutti i rami contemporaneamente ai singoli commit, prima fai un rebase interattivo e schiaccia ogni caratteristica, quindi unisci il polpo:

git checkout feature1
git rebase -i master

Squash in un commit, quindi ripetere per le altre funzionalità.

git checkout master
git merge feature1 feature2 feature3 ...

Quest'ultima fusione è una "fusione di polpo" perché sta unendo molti rami contemporaneamente.

Spero che sia di aiuto


3
Perché ti stai rifacendo?
Umair A.

12
@UmairAshraf è un rebase interattivo che ti dà la possibilità di fare una zucca nel tuo ramo.
andho,

1
Rebasing è una cattiva idea. Non
rifare il

1
@ Sebi2020 git merge --squash riformulerà i tuoi commit già pubblicati in un modo peggiore di un rebase interattivo. Un rebase interattivo (su un ramo di funzionalità) porta poco o nessun effetto negativo.
xiix

1
@xiix Questo vale solo se sei l'unico a lavorare con il ramo delle funzionalità. Questo non è un presupposto che puoi fare. Consiglio di leggere le pagine relative al rebasing su Git-SCM . Afferma " Non reimpostare i commit che esistono al di fuori del tuo repository e le persone potrebbero aver basato il lavoro su di essi " . E se non sai con certezza se le persone già basate lavorano su commit pubblicati (cosa che non puoi sapere a causa del decentramento natura di git) non devi farlo.
Sebi2020

23

Se hai già git merge bugfixattivato main, puoi eliminare il commit di merge in uno con:

git reset --soft HEAD^1
git commit

git reset --soft HEAD^1sembra annullare l'ultimo commit eseguito prima dell'unione, almeno nel caso in cui l'unione sia un avanzamento rapido.
Jesper Matthiesen,

@JesperMatthiesen in caso di avanzamento rapido non ricevi un commit di unione, quindi lo faresti git reset --soft HEAD^<number-of-commits-to-squash>.
qwertzguy,

Questo mi ha aiutato a schiacciare tutto in un unico commit dopo una fusione a valle.
killjoy,

18

Unisci il newFeatureramo in mastercon un commit personalizzato:

git merge --squash newFeature && git commit -m 'Your custom commit message';

Se invece lo fai

git merge --squash newFeature && git commit

riceverai un messaggio di commit che includerà tutti i file newFeature commit ramo, che puoi personalizzare.

Lo spiego a fondo qui: https://youtu.be/FQNAIacelT4


10

So che questa domanda non riguarda specificamente Github, ma poiché Github è così ampiamente usato e questa è la risposta che stavo cercando, la condividerò qui.

Github ha la capacità di eseguire fusioni di squash, a seconda delle opzioni di unione abilitate per il repository.

Se le fusioni di squash sono abilitate, l'opzione "Squash and merge" dovrebbe apparire nel menu a discesa sotto il pulsante "Unisci".

Schermata della funzione Github "Squash and merge"


GitHub utilizza l'e-mail predefinita associata al tuo account. Se disponi di più indirizzi e-mail e devi utilizzarne uno secondario, non puoi utilizzare l'interfaccia utente di GH.
Luca Guidi,

4

Supponiamo di aver lavorato in feature / task1 con più commit.

  1. Vai al ramo del tuo progetto (project / my_project)

    git checkout project/my_project
    
  2. Crea un nuovo ramo (feature / task1_bugfix)

    git checkout -b feature/task1_bugfix
    
  3. Marge con l' --squashopzione

    git merge --squash feature/task1
    
  4. Crea un unico commit

    git commit -am "add single comments"
    
  5. Spingi il tuo ramo

    git push --set-upstream origin feature/task1_bugfix
    

1

Per Git

Crea una nuova funzionalità

tramite terminale / shell:

git checkout origin/feature/<featurename>
git merge --squash origin/feature/<featurename>

Questo non lo commette, ti permette di rivederlo prima.

Quindi esegui il commit e termina la funzione da questo nuovo ramo ed elimina / ignora quello vecchio (quello su cui hai sviluppato).


@Melebius L'unico riferimento a "SourceTree" è nella tua frase, se fosse un tag o una domanda precedente: non esiste più.
Jordan Stefanelli,

1
@JordanStefanelli SourceTree è stato utilizzato nella versione originale di questa risposta . Grazie per aver avvisato che è stato risolto!
Melebio

1

in caso di errore: il commit non è possibile perché sono presenti file non uniti.

git checkout master
git merge --squash bugfix
git add .
git commit -m "Message"

corretti tutti i file di conflitto

git add . 

potresti anche usare

git add [filename]

0

Per schiacciare il tuo ramo locale prima di spingerlo:

  1. controlla la filiale in questione su cui lavorare se non è già stata estratta.

  2. Trova lo sha del commit più vecchio che desideri mantenere.

  3. Crea / checkout un nuovo ramo (tmp1) da quel commit.

    git checkout -b tmp1 <sha1-of-commit>

  4. Unisci il ramo originale nel nuovo schiacciandolo.

    git merge --squash <original branch>

  5. Conferma le modifiche che sono state create dall'unione, con un messaggio di riepilogo di commit.

    git commit -m <msg>

  6. Dai un'occhiata al ramo originale che vuoi schiacciare.

    git checkout <branch>

  7. Ripristina lo sha di commit originale che desideri conservare.

    git reset --soft <sha1>

  8. Rebase questo ramo in base al nuovo ramo tmp1.

    git rebase tmp1

  9. Ecco fatto: ora cancella il ramo temporaneo tmp1 quando sei sicuro che tutto sia a posto.


0

Puoi usare lo strumento che ho creato per semplificare questo processo: git-squash . Ad esempio per schiacciare tutti i commit sul ramo della funzione che è stato ramificato dal ramo principale, scrivere:

git squash master
git push --force
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.