Come ripristinare più commit git?
-
13-09-2019 - |
Domanda
Ho un repository git che assomiglia a questo:
A -> B -> C -> D -> HEAD
Voglio la testa del ramo al punto A, cioè voglio B, C, D, e HEAD scomparire e voglio testa per essere sinonimo con A.
Sembra che posso neanche provare a rebase (non si applica, dal momento che ho spinto cambiamenti nel mezzo), o tornare. Ma come faccio a Revert multipli impegna? Ho Ripristina uno alla volta? È l'ordine importante?
Soluzione
Espansione quello che ho scritto in un commento
La regola generale è che non si deve riscrivere (cambiamento) storia che hai pubblicato, perché qualcuno potrebbe aver basato il loro lavoro su di esso. Se si riscrive la storia (cambio), si dovrebbe creare problemi con la fusione dei loro modifiche e con l'aggiornamento per loro.
Quindi la soluzione è quella di creare un nuova commettere , che ritorna modifiche che si desidera eliminare. È possibile farlo utilizzando git tornare comando
Si ha la seguente situazione:
A <-- B <-- C <-- D <-- master <-- HEAD
(frecce qui si riferisce alla direzione del puntatore: il riferimento "padre" nel caso di commit, all'inizio commit nel caso di testa ramo (ramo ref), e il nome del ramo in caso di riferimento HEAD ).
Quello che vi serve per creare è la seguente:
A <-- B <-- C <-- D <-- [(BCD)^-1] <-- master <-- HEAD
dove "[(BCD) ^ - 1]" indica il commit che ripristina variazioni impegna B, C, D. matematica ci dice che (BCD) ^ - 1 = D ^ -1 C ^ -1 ^ B - 1, in modo da poter ottenere la situazione desiderata con i seguenti comandi:
$ git revert --no-commit D
$ git revert --no-commit C
$ git revert --no-commit B
$ git commit -m "the commit message"
soluzione alternativa potrebbe essere quella di cassa contenuto di commettere un, e si impegnano questo stato:
$ git checkout -f A -- .
$ git commit -a
Poi si avrebbe la seguente situazione:
A <-- B <-- C <-- D <-- A' <-- master <-- HEAD
Il commettere un' ha lo stesso contenuto commettere, ma è un diverso commit (messaggio di commit, i genitori, la data di commit).
La soluzione href="https://stackoverflow.com/questions/1463340/revert-multiple-git-commits/1463390#comment1312779_1463390"> si basa sul stessa idea, ma usi git resettare :
$ git reset --hard A
$ git reset --soft @{1} # (or ORIG_HEAD), which is D
$ git commit
Altri suggerimenti
Per fare ciò è necessario solo per utilizzare il Ripristina di comando, specificare l'intervallo di commit si desidera ottenere ritornato.
Prendendo in considerazione il vostro esempio, dovreste fare questo (supponendo che si sta sul ramo 'master'):
git revert master~3..master
Questo creerà un nuovo commit nel vostro locale con l'inverso commit di B, C e D (il che significa che sarà annullare le modifiche introdotte da questi commit):
A <- B <- C <- D <- BCD' <- HEAD
modo pulito, che ho trovato utile
git revert --no-commit HEAD~3..
Questo comando ritorna ultimi 3 impegna con un solo commit.
Inoltre non riscrivere la storia.
Simile alla risposta di Jakub, questo permette di selezionare facilmente impegna consecutivi di tornare.
# revert all commits from B to HEAD, inclusively
$ git revert --no-commit B..HEAD
$ git commit -m 'message'
git reset --hard a
git reset --mixed d
git commit
che fungerà da un Revert per tutti in una volta. Dare un buon messaggio di commit.
In primo luogo essere sicuri che la vostra copia di lavoro non viene modificato. Poi:
git diff HEAD commit_sha_you_want_to_revert_to | git apply
e poi basta impegnarsi. Non dimenticare di documentare ciò che è il motivo per il ripristino.
Sono così frustrato che la questione non può essere risolta solo. Ogni altra questione è in relazione a come ripristinare in modo corretto e conservare la storia. Questa domanda dice "Voglio che il capo del ramo per puntare a A, vale a dire che voglio B, C, D, e la testa di sparisco e voglio la testa di essere sinonimo di A."
git checkout <branch_name>
git reset --hard <commit Hash for A>
git push -f
Ho imparato molto leggendo il post di Jakub, ma un ragazzo in azienda (con accesso a spingere per il nostro "test" ramo senza Pull-Request) spinto come 5 cattiva impegna cercando di risolvere e fissare e fissare un errore ha fatto 5 impegna fa. solo, ma uno o due richieste Pull non sono state accettate, che erano ormai male. Così dimenticare, ho trovato l'ultima buona commit (abc1234) e appena eseguito lo script di base:
git checkout testing
git reset --hard abc1234
git push -f
Ho detto agli altri 5 ragazzi che lavorano in questo repo che meglio prendere nota delle loro cambiamenti per le ultime ore e pulire / Re-Branch dall'ultimo test. Fine della storia.
Questo è un ampliamento di una delle soluzioni fornite nella risposta di Jakub
ero di fronte ad una situazione in cui i commit avevo bisogno di ripristinare erano un po 'complessa, con diversi dell'essere commit fusione impegna, e avevo bisogno di evitare di riscrivere la storia. Non ero in grado di utilizzare una serie di comandi git revert
perché alla fine ho incontrato i conflitti tra le modifiche che si aggiunge alla reversione. Ho finito per usare la seguente procedura.
In primo luogo, controllare il contenuto del target commettere lasciando TESTA sulla punta del ramo:
$ git checkout -f <target-commit> -- .
(La - si assicura <target-commit>
viene interpretato come un commit piuttosto che un file, la si riferisce alla directory corrente.).
Poi, determinare quali file sono stati aggiunti nel corso di commit rollback, e quindi devono essere cancellati:
$ git diff --name-status --cached <target-commit>
I file che sono stati aggiunti dovrebbe presentarsi con una "A" all'inizio della linea, e non ci dovrebbero essere altre differenze. Ora, se i file devono essere rimossi, in scena questi file per la rimozione:
$ git rm <filespec>[ <filespec> ...]
Infine, il commit della reversione:
$ git commit -m 'revert to <target-commit>'
Se lo si desidera, fare in modo che siamo di nuovo allo stato desiderato:
$git diff <target-commit> <current-commit>
Non ci dovrebbero essere differenze.
Il modo più semplice per ripristinare un gruppo di commit sul repository condiviso (che la gente usa e si desidera preservare la storia) è quello di utilizzare git revert
in combinazione con git rev-list
. Quest'ultimo vi fornirà un elenco di commit, il primo farà il revert stesso.
Ci sono due modi per farlo. Se si desidera che il multiplo Revert impegna in un singolo uso commit:
for i in `git rev-list <first-commit-sha>^..<last-commit-sha>`; do git revert -n $i; done
questo tornerà un gruppo di commit è necessario, ma lasciare tutte le modifiche sul vostro albero di lavoro, si dovrebbe impegnare tutti, come al solito.
Un'altra opzione è quella di avere un unico commit a cambio ritornato:
for i in `git rev-list <first-commit-sha>^..<last-commit-sha>`; do git revert --no-edit -s $i; done
Per esempio, se si dispone di un albero di impegnarsi come
o---o---o---o---o---o--->
fff eee ddd ccc bbb aaa
per ripristinare le modifiche da eee per bbb , eseguire
for i in `git rev-list eee^..bbb`; do git revert --no-edit -s $i; done
Nessuno di coloro che ha lavorato per me, così ho avuto tre impegna a riportare i (le ultime tre commit), così ho fatto:
git revert HEAD
git revert HEAD~2
git revert HEAD~4
git rebase -i HEAD~3 # pick, squash, squash
Ha lavorato come un fascino:)
A mio parere un modo molto semplice e pulito potrebbe essere:
tornare alla A
git checkout -f A
testa punto di master per lo stato attuale
git symbolic-ref HEAD refs/heads/master
Salva
git commit
Se si desidera ripristinare temporaneamente i commit di una funzione, quindi è possibile utilizzare la serie di comandi seguenti.
git log --pretty = oneline | grep 'feature_name' | cut -d '' -f1 | xargs git -n1 tornare --no-modifica