2015-02-21 6 views
6

Ho la seguente situazione:Git ripristinare il comportamento

Il maestro ramo aveva una versione stabile di applicazione.

Developer Un recentemente fatto una caratteristica-ramo chiamato ramo-a con diversi commit (servano da a-1, a-2, a-3). Le funzionalità implementate qui sono basate sul codice aggiornato dal master e sono ben testate per il momento.

Sviluppatore B aveva una funzione di ramo chiamato ramo-b con diversi commit (per esempio, b-1, b-2, b-3). Per qualche ragione, il signor B aveva una versione obsoleta (basata sullo stato del master di una settimana o due fa) nel suo branch e non aveva affatto testato il codice.

Entrambi gli sviluppatori fusero la loro caratteristica-rami di padroneggiare con:

  1. maestro git checkout
  2. git maestro origine tirare
  3. ramo-X git merge (dove X = a, b)
  4. git push origin master

Non è stato utilizzato alcun comando rebase. In primo luogo questa sequenza è stato fatto da B, il prossimo - di A.

Quando ho (sviluppatore C) tirato da maestro, ho visto in git log qualcosa di simile:

  • un'unione: fondersi con maestro dallo sviluppatore un
  • a-3
  • a-2
  • a-1
  • B-3 (sì, questo commit viene subito dopo quella che si fonde)
  • b-unione-conflitti: fondersi con il maestro dallo sviluppatore B (migliaia di file in conflitto)
  • b-2
  • b-1
  • master-stabile: stabile precedente commette

Come risultato Mr. B in qualche modo aveva forzato la vecchia versione del codice a sovrascrivere la versione stabile durante l'unione (risultato in commit b-merge-conflict).

ora voglio riscrivere la storia e salvare b-1 + B-3 + a-1 + A-2 + A-3 modifiche e annullare B-2 , b-merge-conflict e a-merge.

La mia idea è quella di annullare diversi top impegna fino b-1 e quindi di utilizzare cherry-pick patch per applicare b-3, a-1, a-2, a-3 si impegna nel nuovo master.

ma quando provo: resettare

git HEAD --hard ~ 7 riesco a vedere una storia che contiene solo vecchie commit (prima del master-stabile), senza quelle di ramo-a e ramo-b.

quando provo:

git azzerato HEAD --hard ~ 2

posso vedere nella storia unico master-stabile impegnarsi in alto, ma non a-2 come voglio .

Sembra che git reset non traduca una cifra dopo HEAD come un numero di commit da reimpostare (come avevo sott'occhio dalla documentazione), ma come un numero di HEAD-changes da git pull (nei miei esempi ci sono 2).

Come posso annullare correttamente i primi 7 commit b-2 .. un-merge e riscrivere una cronologia a partire da b-1?

UPDATE chiesto nei commenti

ho usato (senza --all per escludere ulteriori informazioni)

git Log --oneline --decorate --graph

* ef7d93f Merge with master by Developer A 
|\ 
| * 2b9dd31 b-4 
| * 924a452 b-3 
| * 1f9489d b-2 
| * e3cd7a6 Merge by Developer B [2]: Merge branch 'master' from https://github.com .... 
| |\ 
| * | aece506 Merge by Developer B [1]: merge branch 
| * | 487e7ee b-1 
* | | d9404f8 a-1 
| |/ 
|/| 
* | 9b202ce master-stable last commit 
+1

Per quanto riguarda l'ordine, riprovare con --topo-order. L'ordine normale di log è l'ordine delle date, e se sei su Windows gli orologi delle varie macchine sono probabilmente abbastanza fuori sincrono. – jthill

+4

Invece di eseguire semplicemente 'git log', provare a eseguire' git log --oneline --decorate --graph --all'. Questo ti darebbe un'idea migliore dello stato del repository. – Jubobs

+0

@jthill bene .. Vuoi dire che è solo un problema basato sull'ordine? Ma allora come spiegare il comportamento di git resettato --hard HEAD ~ 2? –

risposta

2

git log sta mentendo. Presenta la cronologia Git come se fosse lineare, ti mostra i commit in ordine cronologico. Non è molto utile. git log --graph --decorate ti fornirà una storia più chiara mostrandoti l'albero (grafico davvero) dei commit. Da quello che posso capire, il tuo repository sembra così.

         a1 - a2 - a3 
            /   \ 
origin c1 - c2 - c3 - c4 - b-merge - b3 -------- a-merge [master] 
     \    /
     b1 -------------b2 

Come si può vedere, "tornare indietro di sette commit" può avere diverse interpretazioni. Questo è il motivo per cui dovresti evitare quella notazione per spostare indietro più di un paio di commit, e invece fare riferimento a commit ID.

Quello che vuoi è questo.

    a1 - a2 - a3 [branch-a] 
       /
c1 - c2 - c3 - c4 [master] 
       \ 
        b1 - b3 [branch-b] 

Per arrivarci, creare rami A e B off c4 in modo da avere un luogo da cui costruire.

git branch branch-a c4 
git branch branch-b c4 

      [branch-b]   a1 - a2 - a3 
      [branch-a]  /   \ 
c1 - c2 - c3 - c4 - b-merge - b3 -------- a-merge [master] 
    \    /
    b1 -------------b2 

Ora checkout quei rami e ciliegio scegliere le modifiche appropriate su di loro, risolvendo eventuali conflitti.

    b1b - b3b [branch B] 
       /
       | a1a - a2a - a3a [branch A] 
       |/ 
       |/    a1 - a2 - a3 
       |/    /   \ 
c1 - c2 - c3 - c4 - b-merge - b3 -------- a-merge [master] 
    \    /
    b1 -------------b2 

che potrebbe apparire come un pasticcio, ma padrone ora checkout e git reset --hard c4 e tutto il casino tenuto in vita da maestro di essere in un'unione scenderà di distanza (che è una bugia bianca, origin/master manterrà visibile fino tu spingi, anche Git non metterà in realtà i commit per settimane).

    b1b - b3b [branch B] 
       /
       | a1a - a2a - a3a [branch A] 
       |/ 
c1 - c2 - c3 - c4 [master] 

Ora è possibile unire normalmente A e B. Quando hai finito, devi push --force perché il master non è figlio di origine/master.

Questo è solo un modo per ottenere ciò che desideri. L'importante è essere in grado di visualizzare il grafo del repository, dove vuoi che sia, e quali comandi lo trasformeranno.

+0

mooooolto, tutto sembra chiaro per ora. Ma esiste un modo per annullare i principali commit presentati in modo lineare (data-ordinato)? Forse con ** rebase -i ** rimuovendo i commit repo-braking, riordinando in modo corretto e risolvendo i conflitti? –

+0

@AndreyPesoshin Pensando Git impegna in termini di data di ordinazione è solo un altro modo di fingere la sua storia è lineare, e questo è solo andare a ottenere nei guai. Se vuoi la storia lineare, devi renderla lineare. Crea un ramo fuori da c4 e seleziona il selettore b1, b3, a1, a2 e a3. Ma la storia ramo deve essere conservato, non linearizzato, al fine di mantenere la comprensione che i commit sono correlate (es. Che b1 va con b3, ma A1, A2 e A3 sono un gruppo separato). – Schwern

1

Sono Non sono sicuro di HEAD~ perché di solito uso HEAD^.

Tuttavia non è necessario utilizzare tale notazione. Puoi semplicemente fornire l'hash SHA-1 esadecimale del commit, o le prime 7 cifre o meno di esso.

git reset --hard 72abfd4 
+0

'HEAD ~' e 'HEAD ^' sono equivalenti. – Jubobs

+0

in realtà non funziona, perché quando effettuo il checkout a ** b-1 ** (72abfd4 per esempio), vedo la cronologia basata su branch-b che sembra come rotto –

+1

@Jubobs perché HEAD ~ segue sempre il prima catena principale, e HEAD^è appena impostata su di essa. HEAD ~ 7 e HEAD^7 non sono equivalenti. – jthill