2012-03-01 16 views
7

Utilizzo di git v1.7.1 Sto tentando di eseguire un rebase con entrambe le funzioni --preserve-merges e --onto allo stesso tempo. I risultati finali sembrano essere senza commit di unione, e quindi appare lineare. Preferirei preservare l'unione commetti, per la stessa ragione per cui le persone userebbero spesso --preserve-merges (più facile vedere il gruppo di commit che era logicamente una funzione separata e sviluppata nel proprio ramo).git rebase "--preserve-merges --onto" non conserva le unioni

mio ramo principale (la destinazione per il rebase) è noioso:

A-B-C

Il ramo di caratteristica voglio prendere da un ramo ha sotto-caratteristica che è stata incorporata in esso. Come:

 X - Y 
/ \ 
V-W ------ Z 

Dove Z è una fusione commit cioè il capo del ramo di caratteristica di prendere da, e X e Y erano su un ramo caratteristica secondaria.

sto usando: git rebase --preserve-merges --onto C V Z

mi piacerebbe finire con:

  X - Y 
     / \ 
A-B-C-W ------ Z 

Ma invece sto diventando:

A-B-C-W-X-Y 

Poiché Z è stato un conflitto- unione libera, lo stato finale del codice è corretto, ma la cronologia non è così espressiva come vorrei.

C'è un modo per ottenere ciò che voglio?

modifica all'indirizzo @Bombe: Ho scritto uno script di bash per costruire il mio esempio. Sul mio sistema (RHEL 6.2 con git 1.7.1) questo dimostra il mio problema.

#! /bin/bash 
# start a new empty repo 
git init 
# make some commits on the master branch 
git checkout master 
touch A.txt; git add A.txt; git commit -m "add A.txt"; git tag Atag 
touch B.txt; git add B.txt; git commit -m "add B.txt"; git tag Btag 
touch C.txt; git add C.txt; git commit -m "add C.txt"; git tag Ctag 
# now build the feature branch 
# start at Btag (more or less arbitrary; point is it's before C) 
git checkout Btag 
git checkout -b feature 
touch V.txt; git add V.txt; git commit -m "add V.txt"; git tag Vtag 
touch W.txt; git add W.txt; git commit -m "add W.txt"; git tag Wtag 
# now a subfeature 
git checkout -b subfeature 
touch X.txt; git add X.txt; git commit -m "add X.txt"; git tag Xtag 
touch Y.txt; git add Y.txt; git commit -m "add Y.txt"; git tag Ytag 
# merge the subfeature into the feature 
# preserves branch history with --no-ff 
git checkout feature 
git merge --no-ff subfeature 
# the merge commit is our Z 
git tag Ztag 
# one more commit so that merge isn't the tip (for better illustration of Z missing later) 
touch postZ.txt; git add postZ.txt; git commit -m "add postZ.txt"; git tag postZtag 
# now do the rebase 
git rebase --preserve-merges --onto Ctag Vtag 
# optionally move the master branch forward to the top of feature branch 
git checkout master 
git merge feature 

Prima della rebase ottengo:

 X-Y 
    / \ 
    V-W-----Z-postZ 
/
A-B-C 

Dopo il rebase ottengo:

 X-Y 
    / \ 
    V-W-----Z-postZ 
/
A-B-C-W'-X'-Y'-postZ' 

nota la mancanza di Z 'fra Y' e postZ'.

risposta

10

Mille grazie a Bombe e un amico offline per aver sottolineato che funziona per alcune persone. Con questa ispirazione, sono ora in grado di rispondere alla mia stessa domanda.

Risposta breve: le versioni git precedenti alla 1.7.5.2 mostrano questo comportamento errato.

Risposta lunga: nel repository di origine di git, commit c192f9c865dbdae48c0400d717581d34cd315fb8 in data 28 aprile 2011 era esplicitamente una soluzione per questo problema.

per citare il messaggio di commit (da Andrew Wong):

git-rebase--interactive.sh: preserve-merges fails on merges created with no-ff 

'git rebase' uses 'git merge' to preserve merges (-p). This preserves 
the original merge commit correctly, except when the original merge 
commit was created by 'git merge --no-ff'. In this case, 'git rebase' 
will fail to preserve the merge, because during 'git rebase', 'git 
merge' will simply fast-forward and skip the commit. For example: 

       B 
      /\ 
      A---M 
      /
    ---o---O---P---Q 

If we try to rebase M onto P, we lose the merge commit and this happens: 

       A---B 
       /
    ---o---O---P---Q 

To correct this, we simply do a "no fast-forward" on all merge commits 
when rebasing. Since by the time we decided to do a 'git merge' inside 
'git rebase', it means there was a merge originally, so 'git merge' 
should always create a merge commit regardless of what the merge 
branches look like. This way, when rebase M onto P from the above 
example, we get: 

        B 
       /\ 
       A---M 
       /
    ---o---O---P---Q 

Soluzione: ottenere una nuova versione del git, compilare i sorgenti, se necessario.

Btw, ho usato git bisect per capirlo. Strumento fantastico

0

Ho appena provato a ricreare la situazione, e posso segnalare che --preserve-merges sembra funzionare come pubblicizzato. Quando sei in commit Z, solo emissione:

git rebase --preserve-merges --onto C V 

Questo è quello che ho fatto e ha preservato il commit di unione.

+0

Ho modificato il post originale per fornire passaggi per riprodurre il mio problema. Sono sicuro che hai ragione, ma non vedo cosa sto sbagliando. – RaveTheTadpole

+2

E in effetti ho una versione più grande di 1.7.5.2. :) – Bombe

1

Mi sono imbattuto in questo problema. Nota la mia versione git, è 1.7.10.2.

Sto facendo un rebase di una gamma commit (identificata dal suo hash SHA1) su un ramo e anche manca l'ultimo merge commesso.

La mia soluzione era di rebase da W a X su C (senza --preserve-merges) e poi rebase (con --preserve-merges) Y, Z e postZ su X '.

Spero che questo aiuti.