2010-11-11 18 views
8

Ho la seguente situazione: Ho effettuato alcune commit al mio repository locale, e quindi un'enorme fusione di un altro ramo (~ 150 commit) nel master - aveva molti conflitti in esso.Come si usa git rebase -i dopo git merge senza rovinare le cose?

Ora, voglio spostare un commit che ho fatto prima dell'unione per essere dopo di esso prima di premere.

Normalmente, vorrei usare "rebase -i" per questo.

Purtroppo, il comportamento predefinito è quello di rompere l'uno-merge-commit ho fatto che in realtà aggiunge 150 più impegna a padroneggiare in commit separati (capisco è come se avessi usato rebase invece di merge per cominciare) - che è un cattivo comportamento per me per diversi motivi.

Ho scoperto il flag "-p" per rebase, che conserva le unioni e ne sono rimasto molto contento. Sfortunatamente, questo ha applicato di nuovo la stessa unione, e ha dimenticato tutto il mio duro lavoro nella risoluzione dei conflitti. Di nuovo - cattivo comportamento!

C'è una soluzione per quello che voglio? Utilizzare rebase -i dopo l'unione per riordinare o modificare commit specifici senza dover ripetere le operazioni di post-merge?

Grazie!

+2

Hai dato un'occhiata a [git rerere] (http://www.kernel.org/pub/software/scm/git/docs/git-rerere.html)? –

+2

'git rerere' non può aiutarti ora, dal momento che registra la risoluzione del conflitto quando si effettua l'unione ... tranne che c'è uno script chiamato [rerere-train.sh] (http://git.kernel.org/? p = git/git.git; a = blob; f = contrib/rerere-train.sh; hb = HEAD) nella directory contrib di git che "avvia" il database rerere da commit di merge già effettuati. – Cascabel

risposta

13

Ecco lo script di rerere-train.sh che ho menzionato nel mio commento: in sostanza esso ripristina l'unione, utilizza la risoluzione e consente solo di vederlo. Si potrebbe fare questo manualmente solo per il vostro singolo commit se ti piace:

git checkout <parent of merge commit> 
git merge <merged commit>   # if this goes cleanly, we're done 
git rerere      # done automatically if rerere.enabled is true 
git checkout <merge commit> -- . # check out the files from the result of the merge 
git rerere      # done automatically if rerere.enabled is true 
git reset --hard     # wipe away the merge 

# and you'd want to follow with git checkout <branch> to return to where you were 

Ma si potrebbe anche solo impostare rerere.enabled true e fare quei passi meno le chiamate dirette a git rerere - e si sarebbe ambientato nel futuro, con rerere che viene eseguito automaticamente ogni volta che si risolvono i conflitti. Questo è quello che faccio - È fantastico.

Se si desidera eseguire direttamente lo script, è consigliabile eseguirlo con argomenti come rerere-train.sh ^<commit before the merge> <current branch>. (La notazione ^commit significa "non camminare passato questo nella storia", in modo da non preoccuparsi di fare questo per tutta l'unione si impegna nel vostro repo.)

Tuttavia si arriva rerere a fare la sua cosa, dovresti finire con la risoluzione desiderata registrata. Ciò significa che puoi andare avanti e fare il tuo rebase -i, e quando incontri il conflitto, rerere REUSO la REsolution risolta. Solo un colpo d'occhio: lascia ancora i file contrassegnati come in conflitto nell'indice, in modo da poterli controllare, e assicurarsi che ciò che ha avuto senso. Una volta fatto, usa git add per controllarli come se avessi risolto i conflitti tu stesso, e vai avanti come al solito!

Il git-rerere manpage contiene una descrizione molto bella e lunga dell'uso normale di rerere, che non coinvolge mai effettivamente chiamata rerere - è tutto fatto automaticamente. E una nota che non enfatizza: è tutta basata su hunk di conflitto, quindi può riutilizzare una risoluzione anche se il conflitto finisce in un posto completamente diverso, purché sia ​​sempre lo stesso conflitto testuale.

+0

Wow, sembra un vero git-fu! – Benjol

+0

@Benjol: la risoluzione dei conflitti è una cosa seria! (Ma non è davvero spaventoso - basta abilitare rerere nella configurazione e lasciare che la magia accada.) – Cascabel

+0

La manpage git-rerere collegata ora è una 404 non trovata. – Jez

1

Ho creato uno script per farlo here. Vedi lo open issues per le limitazioni note.

È necessario prima installare rerere-train.sh sul PATH.Su Fedora questo può essere fatto con:

install "$(rpm -ql git|grep '/rerere-train.sh$')" ~/bin 
0

ho usato rerere-train.sh da user @ risposta di Jefromi. Tuttavia ho avuto questo errore:

$ ../rerere-train.sh HEAD 
C:\Program Files\Git\mingw64/libexec/git-core/git-sh-setup: line 6: .: git-sh-i18n: file not found 

Da questo http://kernel.opensuse.org/cgit/kernel-source/commit/?h=linux-next&id=d52b9f00588bb18d7f7a0e043eea15e6c27ec40c ho visto questo:

Michal Marek

The git-sh-setup helper has apparently never been meant to be used by scripts outside of git. This became apparent with git 2.10:

Dopo downloading an older version - 2.3.4 Portable - sono riuscito a fare rerere-train.sh lavoro.