Ho bisogno di far apparire e cancellare un commit "intermedio" nel mio ramo principale. Come posso farlo?


94

Ad esempio, nel seguente ramo principale, devo cestinare solo il commit af5c7bf16e6f04321f966b4231371b21475bc4da, che è il secondo a causa del precedente rebase:

commit 60b413512e616997c8b929012cf9ca56bf5c9113
Author: Luca G. Soave <luca.soave@gmail.com>
Date:   Tue Apr 12 23:50:15 2011 +0200

    add generic config/initializers/omniauth.example.rb

commit af5c7bf16e6f04321f966b4231371b21475bc4da
Author: Luca G. Soave <luca.soave@gmail.com>
Date:   Fri Apr 22 00:15:50 2011 +0200

    show github user info if logged

commit e6523efada4d75084e81971c4dc2aec621d45530
Author: Luca G. Soave <luca.soave@gmail.com>
Date:   Fri Apr 22 17:20:48 2011 +0200

    add multiple .container at blueprint layout

commit 414ceffc40ea4ac36ca68e6dd0a9ee97e73dee22
Author: Luca G. Soave <luca.soave@gmail.com>
Date:   Thu Apr 21 19:55:57 2011 +0200

    add %h1 Fantastic Logo + .right for 'Sign in with Github'

Ho bisogno di mantenere

  • il primo commit 60b413512e616997c8b929012cf9ca56bf5c9113,
  • il terzo commit e6523efada4d75084e81971c4dc2aec621d45530 e
  • l'ultimo commit 414ceffc40ea4ac36ca68e6dd0a9ee97e73dee22

"buttare via" solo il secondo commit af5c7bf16e6f04321f966b4231371b21475bc4da

Come lo posso fare? Grazie in anticipo Luca

Risposte:


98

Rebase o ripristina sono le opzioni. Rebase rimuoverà effettivamente il commit dalla cronologia, quindi sembrerà che il secondo commit non sia mai esistito. Questo sarà un problema se hai trasferito il ramo principale a qualsiasi altro repository. Se in questo caso provi a spingere dopo un rebase, git ti darà un errore di unione non veloce di rifiuto .

Ripristina è la soluzione corretta quando il ramo è stato condiviso con altri repository. git revert af5c7bf16creerà un nuovo commit che inverte semplicemente le modifiche introdotte da af5c7bf16. In questo modo la cronologia non viene riscritta, si mantiene una chiara registrazione dell'errore e altri pronti contro termine accetteranno il push.

Ecco un buon modo per cancellare: git rebase -i <commit>^ ti porta al commit appena prima di quello che vuoi rimuovere. L'editor interattivo ti mostrerà un elenco di tutti i commit fino a quel punto. Puoi scegliere, schiacciare, ecc. In questo caso rimuovi la riga per il commit che desideri cancellare e salva il file. Rebase finirà il suo lavoro.


2
Nel caso in cui scelga Rebase, qual è il commit giusto per rebase? Devo far cadere solo il secondo ...
Luca G. Soave

@ BBJ3 Vedi la risposta di mipadi.
Prajwal Dhatwalia

32

Se rebase è un'opzione, puoi rebase e semplicemente rilasciarlo:

$ git rebase -i 414ceffc^

Se rebase non è un'opzione, puoi semplicemente ripristinarlo:

$ git revert af5c7bf16

se ho ottenuto per "git rebase 414ceffc" che è il quarto commit più vecchio, non perderò anche il terzo e6523 e il primo 60b41?
Luca G. Soave

3
@ Luca G. Soave: "Perdi" un commit solo se dici espressamente git rebasedi lasciarlo cadere (eseguendo rebasein modalità interattiva e rimuovendo la sua voce).
mipadi

Grazie mipadi, do il mio voto a JCotton essenzialmente per l'ampia spiegazione anche se voi due avete detto la stessa cosa ... grazie ancora.
Luca G. Soave

29

Nonostante tutto il merito che le risposte originali hanno ricevuto qui, non le ho trovate per rispondere in modo soddisfacente alla domanda. Se ti trovi in ​​una situazione in cui devi rimuovere un commit o una raccolta di commit dal centro della cronologia, questo è ciò che suggerisco:

  • Crea un nuovo ramo dalla testa di quello contenente tutti i commit e passa ad esso.
  • Ripristina il nuovo ramo al punto da cui desideri iniziare una nuova base.
  • Quindi, (ecco il punto chiave) scegli i commit successivi che desideri effettivamente applicare successivamente dal ramo originale a quello nuovo e salta i commit che non vuoi più (cioè quelli che stai eliminando).
  • Se lo desideri, rinomina il ramo originale con qualcosa che indica il vecchio codice, quindi rinomina il tuo nuovo ramo come è stato chiamato quello originale.
  • Infine, invia le modifiche al tuo repository remoto (se ne usi uno). Probabilmente dovrai usare una "spinta forzata". Se i tuoi collaboratori hanno problemi a tirare le revisioni, potrebbe essere più semplice per loro clonare nuovamente il repository dalla fonte remota. In un modo o nell'altro, probabilmente vorrai parlare con loro se stai comunque strappando dei commit dalla metà della tua storia!

Ecco le informazioni su Cherry Picking: cosa significa selezionare un commit con git?

Eccone alcuni su come farlo con Tortoise Git (come ho appena fatto). È decisamente più facile usare un'utilità gui per questo tipo di operazioni! Cherry pick utilizzando TortoiseGit


6
Questa dovrebbe essere la risposta migliore!
MadOgre

Bel modo di usare Cherry Pick, questa soluzione è anche migliore quando vuoi "saltare" più di un commit.
Johnny Willer

Non affrontando davvero la domanda originale. Sebbene la soluzione suggerita funzioni, richiede molto più tempo / è scomoda e IMO non porta alcun vantaggio. Se il ramo è già stato spinto (e utilizzato in natura), la strategia di ripristino è probabilmente la risposta. In caso contrario, rebase interattivo e rimuovere il commit offensivo è ciò che userei. Se è stato spinto ma sappiamo che non è usato da nessuno, puoi comunque farla franca con un rebase seguito da una spinta forzata.
raduw
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.