expire - git undo rebase




Annullamento di un rebase git (10)

Qualcuno sa come annullare facilmente un rebase git?

L'unico modo che viene in mente è quello di andare manualmente:

  • git checkout il commit genitore in entrambi i rami
  • quindi creare un ramo temporaneo da lì
  • cherry-pick tutto si commette a mano
  • sostituire il ramo in cui sono stato ribaltato dal ramo creato manualmente

Nella mia situazione attuale funzionerà perché posso facilmente individuare i commit da entrambe le branche (una era la mia roba, l'altra era roba del mio collega).

Tuttavia, il mio approccio mi sembra subottimale e soggetto a errori (diciamo che ho appena ripreso con 2 dei miei rami personali).

Qualche idea?

Chiarimento: sto parlando di un rebase durante il quale un gruppo di commit è stato ripetuto. Non solo uno.


Diciamo che rebase master al mio branch e ottengo 30 nuovi commit che rompono qualcosa. Ho scoperto che spesso è più semplice rimuovere i cattivi commit.

git rebase -i HEAD~31

Rebase interattivo per gli ultimi 31 commit (non fa male se si scelgono troppi).

Basta prendere i commit che vuoi eliminare e contrassegnarli con "d" anziché "pick". Ora i commit vengono cancellati in modo efficace annullando il rebase (se si rimuovono solo i commit che si sono appena ottenuti durante il ribasamento).


Il modo più semplice sarebbe quello di trovare il commit della testa del ramo com'era immediatamente prima che il rebase iniziasse nel reflog ...

git reflog

e per resettare il ramo corrente su di esso (con i soliti avvertimenti circa l'assoluta certezza prima di resettare con l'opzione --hard ).

Supponiamo che il vecchio commit fosse [email protected]{5} nel registro ref:

git reset --hard [email protected]{5}

In Windows, potrebbe essere necessario citare il riferimento:

git reset --hard "[email protected]{5}"

Puoi controllare la cronologia della vecchia testata facendo semplicemente un git log [email protected]{5} ( Windows: git log "[email protected]{5}" ).

Se non hai disabilitato i reflog di branch dovresti essere in grado di fare git reflog [email protected]{1} come rebase che stacca il branch branch prima di ricollegarlo al capo finale. Vorrei ricontrollare questo, anche se non l'ho verificato di recente.

Per impostazione predefinita, tutti i diagrammi vengono attivati ​​per i repository non nudi:

[core]
    logAllRefUpdates = true

Io in realtà metto un tag di backup sul ramo prima di fare qualsiasi operazione non banale (la maggior parte dei rebase è banale, ma lo farei se sembra un po 'complessa).

Quindi ripristinare è facile come git reset --hard BACKUP .


L'uso di reflog non ha funzionato per me.

Ciò che ha funzionato per me è stato simile a quello descritto here . Apri il file in .git / logs / refs chiamato dopo il ramo che è stato ridefinito e trova la riga che contiene "rebase finsihed", qualcosa come:

5fce6b51 88552c8f Kris Leech <[email protected]> 1329744625 +0000  rebase finished: refs/heads/integrate onto 9e460878

Controlla il secondo commit elencato sulla linea.

git checkout 88552c8f

Una volta confermato ciò conteneva i miei cambiamenti persi, mi sono ramificato e ho tirato un sospiro di sollievo.

git log
git checkout -b lost_changes

Nel caso in cui avessi spinto il tuo ramo nel repository remoto (di solito è di origine) e poi hai eseguito un rebase di successo (senza unione) ( git rebase --abort dà "No rebase in progress") puoi facilmente resettare il ramo usando il comando:

git reset --hard source / {branchName}

Esempio:

$ ~/work/projects/{ProjectName} $ git status
On branch {branchName}
Your branch is ahead of 'origin/{branchName}' by 135 commits.
  (use "git push" to publish your local commits)

nothing to commit, working directory clean

$ ~/work/projects/{ProjectName} $ git reset --hard origin/{branchName}
HEAD is now at 6df5719 "Commit message".

$ ~/work/projects/{ProjectName} $ git status
On branch {branchName}
Your branch is up-to-date with 'origin/{branchName}.

nothing to commit, working directory clean

Nel caso in cui non hai completato il rebase e nel mezzo di esso, i seguenti lavori:

git rebase --abort

Per più commit, ricorda che ogni commit fa riferimento a tutta la cronologia che porta a quel commit. Quindi, nella risposta di Charles, leggi "il vecchio commit" come "il più nuovo dei vecchi commit". Se si resetta a quel commit, riapparirà tutta la cronologia che porta a quel commit. Questo dovrebbe fare quello che vuoi.


Reimpostare il ramo sull'oggetto di impegno pendente del suo vecchio suggerimento è ovviamente la soluzione migliore, poiché ripristina lo stato precedente senza impiegare alcuno sforzo. Ma se ti capita di aver perso tali commit (ad esempio perché hai raccolto il tuo repository nel frattempo, o si tratta di un nuovo clone), puoi sempre rebase di nuovo al ramo. La chiave per questo è l' --onto .

Supponiamo che tu abbia un argomento chiamato immaginariamente topic , che hai diramato il master quando la punta del master era il commit 0deadbeef . Ad un certo punto mentre si git rebase master sul ramo topic , hai eseguito git rebase master . Ora vuoi annullare questo. Ecco come:

git rebase --onto 0deadbeef master topic

Questo prenderà tutti i commit su topic che non sono sul master e li 0deadbeef su 0deadbeef .

Con --onto , puoi riorganizzare la tua storia praticamente in qualsiasi forma .

Divertiti. :-)


Se si incasina qualcosa all'interno di un rebase git, ad es. git rebase --abort , mentre si hanno file non salvati, questi andranno persi e git reflog non aiuterà. Questo è successo a me e tu dovrai pensare fuori dagli schemi qui. Se sei fortunato come me e utilizzi IntelliJ Webstorm, puoi fare right-click->local history e ripristinare uno stato precedente dei tuoi file / cartelle, indipendentemente dagli errori che hai commesso con il software di controllo delle versioni. È sempre bene avere un altro funzionamento in sicurezza.


Seguendo la soluzione di @Allan e @Zearin, vorrei poter fare semplicemente un commento, ma non ho abbastanza reputazione, quindi ho usato il seguente comando:

Invece di fare git rebase -i --abort (notare il -i ) dovevo semplicemente fare git rebase --abort ( senza il -i ).

Usando sia -i che --abort allo stesso tempo, Git mi mostra un elenco di utilizzo / opzioni.

Quindi il mio precedente e attuale stato filiale con questa soluzione è:

[email protected] /my/project/environment (branch-123|REBASE-i)
$ git rebase --abort

[email protected] /my/project/environment (branch-123)
$




undo