Ri-fare una fusione ripristinata in Git


231

Ho riscontrato un po 'di un problema qui: avevo un ramo specifico del problema 28sin Git, che ho unito nel developramo generale . Si è scoperto che l'avevo fatto troppo in fretta, quindi ho usato git-revert per annullare l'unione. Ora, però, è giunto il momento di unire 28sin develop, ma il comando git-merge vede l'unione originale, e felicemente annuncia che tutto va bene e rami sono stati già fuse. Cosa faccio ora? Creare un commit "Ripristina" Ripristina "28s -> sviluppa" "? Non sembra essere un buon modo per farlo, ma al momento non riesco a immaginarmene nessun altro.

Come si presenta la struttura ad albero:

Git log output


4
È GitX ( gitx.frim.nl ).
Toms Mikoss,

Risposte:


169

Devi "ripristinare il ripristino". A seconda di come è tornato l'originale, potrebbe non essere così facile come sembra. Guarda il documento ufficiale su questo argomento .

---o---o---o---M---x---x---W---x---Y
              /
      ---A---B-------------------C---D

permettere:

---o---o---o---M---x---x-------x-------*
              /                       /
      ---A---B-------------------C---D

Ma funziona tutto? Certo che lo fa. Puoi ripristinare un'unione e, da un punto di vista puramente tecnico, Git l'ha fatto in modo molto naturale e non ha avuto problemi reali.
Lo considerava solo un passaggio da "stato prima di unire" a "stato dopo unire", e basta.
Niente di complicato, niente di strano, niente di veramente pericoloso. Git lo farà senza nemmeno pensarci.

Quindi da un punto di vista tecnico, non c'è nulla di sbagliato nel ripristinare un'unione, ma da un punto di vista del flusso di lavoro è qualcosa che generalmente dovresti cercare di evitare .

Se possibile, per esempio, se si trova un problema che ha ottenuto fuse in l'albero principale, piuttosto che Ripristina l'unione, cercare davvero difficile :

  • bisecare il problema nel ramo che hai unito e risolverlo,
  • oppure prova a ripristinare il commit individuale che lo ha causato.

Sì, è più complesso, e no, non sta andando sempre al lavoro (a volte la risposta è: "oops, io davvero non avrei dovuto fusa, perché non era ancora pronto, e ho davvero bisogno di annullare tutto il merge "). Quindi, dovresti davvero ripristinare l'unione, ma quando vuoi rifare l'unione, ora devi farlo ripristinando il ripristino.


10
Buon collegamento (+1). Mi sono preso la libertà di copiare parte del documento nella tua risposta per consentire ai lettori di vedere immediatamente le opzioni pertinenti in questo caso. Se non sei d'accordo, sentiti libero di tornare.
VonC,

5
Abbiamo appena incontrato un caso in cui dovevamo farlo e abbiamo scoperto che il divertimento non si ferma proprio qui. Era un ramo di lunga data che è stato unito, quindi abbiamo dovuto continuare ad aggiornarlo. Il mio approccio qui: tech.patientslikeme.com/2010/09/29/…
jdwyah

ho seguito il post sul blog di @ jdwyah ed è stato glorioso (sul serio, è stato fantastico che abbia funzionato).
hellatan,

2
@jdwyah sembra un collegamento interrotto, ma sembra una lettura interessante. Ecco un mirror di archive.org ma mancano le immagini: web.archive.org/web/20111229193713/http://…
Alex KeySmith,

15
Il post sul blog è stato resuscitato, grazie: blog.jdwyah.com/2015/07/dealing-with-git-merge-revisions.html
jdwyah

53

Supponiamo che tu abbia una tale storia

---o---o---o---M---W---x-------x-------*
              /                      
      ---A---B

Dove A, B fallito commette e W - viene ripristinato di M

Quindi, prima di iniziare a risolvere i problemi riscontrati, seleziono W con impegno dal mio ramo

git cherry-pick -x W

Quindi ripristino W commit sul mio ramo

git revert W 

Dopo che posso continuare a riparare.

La storia finale potrebbe apparire come:

---o---o---o---M---W---x-------x-------*
              /                       /     
      ---A---B---W---W`----------C---D

Quando invio un PR mostrerà chiaramente che il PR viene annullato ripristinato e aggiunge alcuni nuovi commit.


3
Sembra che potrebbe essere utile, ma è così scarso sui dettagli (cosa sono C, D nell'ultimo diagramma) che è più frustrante che utile
Isochronous,

4
@Isochronous C e D sembrano essere dei commit che risolvono i problemi introdotti da A e B.
Thomas

@Thomas esattamente
Maksim Kotlyar il

È bene che tu abbia evidenziato l'uso di un PR in questa istanza in quanto può fornire un "controllo di integrità" finale prima di ricollegarlo al master.
Willem van Ketwich,

usa perché riavvii il tuo ramo dalla W originale? Cioè, lascia che il tuo argomento continui da W, con W` seguito da C e D? Ciò rimuove alcune duplicazioni
Erik Carstensen il

12

Per ripristinare il ripristino senza rovinare troppo il flusso di lavoro:

  • Crea una copia cestino locale di sviluppa
  • Ripristina il commit di ripristino sulla copia locale di sviluppo
  • Unisci quella copia nel ramo della tua funzione e invia il ramo della tua caratteristica al tuo server git.

Il ramo delle funzionalità ora dovrebbe essere in grado di essere unito normalmente quando sei pronto. L'unico aspetto negativo qui è che avrai alcuni commit di unione / ripristino extra nella tua storia.


Solo per evitare ulteriori confusioni, ho anche creato una copia 'spazzatura' del mio ramo di funzionalità e ho unito lo sviluppo ripristinato in esso.
jhhwilliams,

Grazie! Questa è l'unica risposta che in realtà spiega come farlo invece di dire che non dovresti farlo. Davvero utile.
Emmy

Grazie, questo mi ha davvero aiutato. :)
Daniel Stracaboško

11

Per ripristinare un ripristino in GIT:

git revert <commit-hash-of-previous-revert>

1
Usando questo nel mio ramo di lavoro per ripristinare il ripristino, quindi nuove PR da sviluppare. Ora git vede tutte le modifiche che erano nel precedente PR che erano state ripristinate. Grazie.
Danstan,

3

Invece di usarlo, git-revertavresti potuto usare questo comando nel develramo per eliminare (annullare) il commit di unione errato (invece di ripristinarlo).

git checkout devel
git reset --hard COMMIT_BEFORE_WRONG_MERGE

Ciò regolerà di conseguenza anche il contenuto della directory di lavoro. Fai attenzione :

  • Salvare le modifiche nel ramo di sviluppo (poiché l'unione errata) perché anche loro verranno cancellate dal git-reset. Tutti si impegnano dopo quello che hai specificato come l' git resetargomento sparirà!
  • Inoltre, non eseguire questa operazione se le modifiche sono già state estratte da altri repository perché il ripristino riscriverà la cronologia.

Consiglio di studiare git-resetattentamente la pagina man prima di provare questo.

Ora, dopo il ripristino, è possibile riapplicare le modifiche devele quindi eseguire

git checkout devel
git merge 28s

Questa sarà una vera e propria unione da 28sin develcome quello iniziale (che è ora cancellato dalla storia di git).


8
Per chiunque non abbia familiarità con Git e potrebbe voler seguire queste istruzioni: attento a combinare reset --harde push origin. Inoltre, tieni presente che una spinta forzata verso l'origine può davvero creare PR aperte su GitHub.
funroll

Molto utile per risolvere alcuni problemi di unione su un server git privato. Grazie!
mix3d

1
+1 per questa tecnica. Potenzialmente distruttivo, ma può farti risparmiare un sacco di mal di testa (e una storia alterata) se applicato con giudizio.
siliconrockstar,

1

Ho appena trovato questo post di fronte allo stesso problema. Trovo sopra wayyy a spaventare per resettare hards ecc. Finirò per eliminare qualcosa che non voglio e non sarò in grado di recuperarlo.

Invece ho verificato il commit e volevo che il ramo tornasse ad es git checkout 123466t7632723. Quindi convertito in un ramo git checkout my-new-branch. Ho quindi eliminato il ramo che non volevo più. Ovviamente questo funzionerà solo se sei in grado di buttare via il ramo che hai incasinato.


1
Il git reflogvi proteggerà su un hard reset per un paio di mesi nel caso in cui più tardi scopre che è necessario il commit persi. Il reflog è limitato al repository locale.
Todd,

1

Ti suggerirei di seguire i passaggi seguenti per ripristinare un ripristino, ad esempio SHA1.

git checkout develop #go to develop branch
git pull             #get the latest from remote/develop branch
git branch users/yourname/revertOfSHA1 #having HEAD referring to develop
git checkout users/yourname/revertOfSHA1 #checkout the newly created branch
git log --oneline --graph --decorate #find the SHA of the revert in the history, say SHA1
git revert SHA1
git push --set-upstream origin users/yourname/revertOfSHA1 #push the changes to remote

Ora crea PR per il ramo users/yourname/revertOfSHA1


1
  1. crea un nuovo ramo al commit prima dell'unione originale - chiamalo "sviluppo-base"
  2. eseguire il rebase interattivo di "sviluppo" sopra "sviluppo-base" (anche se è già in cima). Durante il rebase interattivo, avrai l'opportunità di rimuovere sia il commit di unione, sia il commit che ha invertito l'unione, ovvero rimuovere entrambi gli eventi dalla cronologia di git

A questo punto avrai un ramo 'sviluppo' pulito in cui puoi unire la tua funzionalità come fai regolarmente.


Questo approccio creerà problemi se il ramo di sviluppo è condiviso con altri.
PSR il
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.