Git: Come schiacciare tutti i commit sul ramo


315

Faccio nuova filiale da mastercon:

git checkout -b testbranch

Faccio 20 impegni.

Ora voglio eliminare quei 20 commit. Lo faccio con:

git rebase -i HEAD~20

E se non sapessi quanti commit? C'è un modo per fare qualcosa del genere:

git rebase -i all on this branch

6
Puoi fare ciò git rebase -i 58333012713fc168bd70ad00d191b3bdc601fa2dche farà un rebase interattivo in cui il numero di commit è l'ultimo commit che rimane invariato
gennaio

@denns Usando questo metodo con l'ultima impegnano nel ramo che si sta rebasing dalla lavorato fantastico. Grazie mille!
Joshua Pinter,

Risposte:


395

Un altro modo per eliminare tutti i tuoi commit è reimpostare l'indice sul master:

 git checkout yourBranch
 git reset $(git merge-base master yourBranch)
 git add -A
 git commit -m "one commit on yourBranch"

Questo non è perfetto poiché implica che tu sappia da quale ramo proviene il "tuo Branco".
Nota: trovare quel ramo di origine non è facile / possibile con Git (il modo visivo è spesso il più semplice , come visto qui ).


EDIT: dovrai usare git push --force


Karlotcha Hoa aggiunge nei commenti :

Per il ripristino, puoi farlo

git reset $(git merge-base master $(git rev-parse --abbrev-ref HEAD)) 

[That] utilizza automaticamente il ramo in cui ti trovi attualmente.
E se lo usi, puoi anche usare un alias, poiché il comando non si basa sul nome del ramo .


2
Meglio fare il checkout per impegnarsi dove si YourBranchtrova attualmente. Questo rimarrà YourBranchintatto quando lo faireset
Eugen Konkov,

1
@Abdurrahim O apri un git bash e puoi copiare e incollare questi comandi!
VonC,

3
Per il ripristino, è possibile fare git reset $(git merge-base master $(git rev-parse --abbrev-ref HEAD))per utilizzare automaticamente il ramo in cui ci si trova attualmente. E se lo usi, puoi anche usare un alias, poiché il comando non si basa sul nome del ramo.
Karlotcha Hoa,

1
@Druska Per casi di ramificazione simlpe, no, dovrebbe funzionare bene.
VonC,

1
@Shimmy sì, a condizione di forzare la spinta dopo il ripristino: git push --force(e avvisare i colleghi se ci sono diverse persone che lavorano in quel ramo)
VonC

112

Verifica il ramo per il quale desideri eliminare tutti i commit in un commit. Diciamo la sua chiamata, feature_branch.

git checkout feature_branch

Passo 1:

Esegui un soft reset del tuo origin/feature_branchcon la tua masterfiliale locale (a seconda delle tue esigenze, puoi resettare anche con origin / master). Ciò ripristinerà tutti i commit extra nel tuo feature_branch, ma senza cambiare localmente i tuoi file.

git reset --soft master

Passo 2:

Aggiungi tutte le modifiche nella tua directory repository git al nuovo commit che verrà creato. E commetti lo stesso con un messaggio.

git add -A && git commit -m "commit message goes here"


6
Questa è stata la soluzione più affidabile per me, non causando errori di rebase né unendo conflitti.
ANTARA,

1
Attenzione: l'aggiunta git -A aggiunge TUTTO quello che hai nella cartella locale - al ramo.
David H,

amo questa soluzione! questo è esattamente quello che volevo!
jacoballenwood,

1
La migliore soluzione per un noob - non distruttivo e solo un momento di oops potrebbe essere il check-in troppo come segreti delle app, ecc., Che non dovrebbe importare se hai un file gitignore adeguato
kkarakk

@NSduToit Risposta breve: No, non è necessario. Dopo aver eseguito i passaggi sopra indicati nella mia risposta, finirai con un commit con alcune modifiche al codice. Puoi pensarlo come qualsiasi altro commit con alcune modifiche al codice. Puoi spingerlo sul tuo ramo remoto senza la -fbandiera.
Shanky,

110

Quello che stai facendo è piuttosto soggetto a errori. Basta fare:

git rebase -i master

che ridisegnerà automaticamente solo i commit della tua filiale sull'ultimo master attuale.


5
grazie, l'ho
capito

10
Probabilmente perché è facile sbagliare il numero?
Daniel Scott

13
D'accordo, questa è la soluzione migliore. ma segui questo link in quanto spiega meglio cosa devi fare.
Christo,

3
Invece di schiacciare i commit, puoi unire il ramo al master e fare un reset git su origin / master per annullare la messa in scena di tutti i commit. Ciò ti consentirebbe di eseguire il commit del tuo codice non commit -am "the whole thing!"
gestito

2
@nurettin Penso che il reset origin/mastermetodo sia davvero pessimo in quanto è lo stesso che fare commit direttamente sul master - non esiste una cronologia "Unisci ramo", nessuna opzione di richiesta pull. Penso che la risposta di @WaZaA sia molto più in linea con il normale flusso di lavoro git
Drenai,

79

Un altro modo semplice per farlo: andare sul ramo di origine e fare un merge --squash. Questo comando non esegue il commit "schiacciato". quando lo fai, verranno raccolti tutti i messaggi di commit di yourBranch.

$ git checkout master
$ git merge --squash yourBranch
$ git commit # all commit messages of yourBranch in one, really useful
 > [status 5007e77] Squashed commit of the following: ...

1
Vero. Ho accennato la differenza tra fusione --squash e rebase -i in stackoverflow.com/a/2427520/6309
VonC

1
Questo funziona se non vuoi schiacciare il ramo genitore, basta creare e passare a un nuovo ramo basato sul ramo genitore e fare l'unione della zucca in quello.
Charlotte,

Saluti amico, ottimo consiglio!
Nestor Milyaev,

simpatico! creo un ramo "temp" fuori da "master" prima per comprimere "yourBranch", quindi unendo "temp" in "master".
lazieburd,

34

Supponendo che si stia ramificando dal master, non è necessario accedere sempre yourBranchal passaggio di ripristino:

git checkout yourBranch
git reset --soft HEAD~$(git rev-list --count HEAD ^master)
git add -A
git commit -m "one commit on yourBranch"

Spiegazione :

  • git rev-list --count HEAD ^masterconta i commit da quando hai creato il ramo delle caratteristiche dal master, f.ex. 20.
  • git reset --soft HEAD~20eseguirà un reset software degli ultimi 20 commit. Questo lascia le modifiche nei file, ma rimuove i commit.

Utilizzo :

Nel mio .bash_profile ho aggiunto un alias per gisquashfarlo con un solo comando:

# squash all commits into one
alias gisquash='git reset --soft HEAD~$(git rev-list --count HEAD ^master)'

Dopo aver effettuato il ripristino e il commit, è necessario eseguire un git push --force.

Suggerimento :

Se stai usando Gitlab> = 11.0 non devi più farlo poiché ha un'opzione di compressione quando si uniscono i rami. Opzione di compressione di Gitlab


15

Basandomi sulla lettura di diverse domande e risposte su StackOverflow sullo schiacciamento, penso che questo sia un buon esempio per schiacciare tutti i commit su un ramo:

git reset --soft $(git merge-base master YOUR_BRANCH) && git commit -am "YOUR COMMIT MESSAGE" && git rebase -i master

Ciò presuppone che master sia il ramo di base.


1
Grazie mille, la compagnia ha molte restrizioni in atto e non ha potuto rifare il solito modo con un editore, come non è stato ad alta voce salvare. Inoltre, non è stato possibile utilizzare la funzionalità di compressione e unione in git poiché questo ramo va allo sviluppatore principale per la fusione e non gli piace. Questo 1 liner ha funzionato e salvato il mal di testa. Lavoro fantastico.
L1ghtk3ira,

10

Soluzione per le persone che preferiscono fare clic:

  1. Installa sourcetree (è gratuito)

  2. Controlla come appaiono i tuoi commit. Molto probabilmente hai qualcosa di simile a questo inserisci qui la descrizione dell'immagine

  3. Fare clic con il tasto destro del mouse sul commit principale . Nel nostro caso è il ramo principale.

inserisci qui la descrizione dell'immagine

  1. È possibile annullare il commit con quello precedente facendo clic su un pulsante. Nel nostro caso, dobbiamo fare clic 2 volte. Puoi anche cambiare il messaggio di commit inserisci qui la descrizione dell'immagine

  2. I risultati sono fantastici e siamo pronti a spingere! inserisci qui la descrizione dell'immagine

Nota a margine: se spingevi i tuoi commit parziali su remoto devi usare la spinta forzata dopo lo squash


Grazie per questo!
Crystal,

0

Un'altra soluzione sarebbe quella di salvare tutti i log di commit in un file

git log> branch.log

Ora branch.log avrà tutti gli ID di commit dall'inizio .. scorri verso il basso e prendi il primo commit (questo sarà difficile nel terminale) usando il primo commit

git reset --soft

tutti i commit saranno schiacciati


0

Git reset, come menzionato in molte risposte prima, è di gran lunga il modo migliore e più semplice per ottenere ciò che desideri. Lo uso nel seguente flusso di lavoro:

(sul ramo di sviluppo)

git fetch
git merge origin/master  #so development branch has all current changes from master
git reset origin/master  #will show all changes from development branch to master as unstaged
git gui # do a final review, stage all changes you really want
git commit # all changes in a single commit
git branch -f master #update local master branch
git push origin master #push it

0

Tutto questo git reset, duro, morbido e tutto il resto menzionato qui probabilmente funziona (non ha funzionato per me) se fai i passaggi correttamente e una sorta di genio.
Se sei un Joe Smo medio, prova questo:
come usare git merge --squash?


Mi ha salvato la vita e sarà il mio modo di fare squash, lo uso 4 volte da quando l'ho scoperto. Semplice, pulito e sostanzialmente 1 comamnd. In breve:


se sei su un ramo, chiamalo "my_new_feature" off sviluppo e la tua richiesta pull ha 35 commit (o comunque molti) e vuoi che sia 1.

A. Assicurati che il tuo ramo sia aggiornato, Continua sviluppare, ottenere le ultime novità, unire e risolvere eventuali conflitti con "my_new_feature"
(questo passaggio in realtà dovresti comunque fare il prima possibile in ogni momento)

B. Ricevi le ultime novità di sviluppo e ramifica in una nuova filiale chiamalo "my_new_feature_squashed"

C. la magia è qui.
Vuoi portare il tuo lavoro da "my_new_feature" a "my_new_feature_squashed"
Quindi fai (mentre sul tuo nuovo ramo abbiamo creato lo sviluppo):
git merge --squash my_new_feature

Tutte le modifiche saranno ora sul tuo nuovo ramo, sentiti libero di testarlo, quindi esegui solo 1 singolo commit, push, nuovo PR di quel ramo - e attendi la ripetizione il giorno successivo.
Non ti piace la programmazione? :)


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.