2013-01-24 27 views
8

Supponiamo che io ho il seguente scenario:Git rebase sottostruttura

o (master) 
/  o--o (WIP1) 
/ /
o--o--o--o--o--o (WIP2) 
(X)  \ 
      o--o (WIP3) 

Esiste un comando git che crea una nuova filiale in modo che contenga la sottostruttura dopo ramo X? Voglio eseguire un "grande rebase", voglio i tre rami WIP ribattezzati su master.

So che posso farlo con alcuni script Bash ma mi piacerebbe sapere come farlo usando un comando git.

+1

possibile duplicato di [rebasing un ramo con tutti i suoi figli] (http://stackoverflow.com/questions/5600659/rebasing-a-branch -incluso di tutti i suoi figli) –

+1

Possibile duplicato di [Rebasare un albero (un commit/ramo e tutti i suoi figli)] (https://stackoverflow.com/questions/17315285/rebasing-a-tree-a-commit -branch-and-all-its-children) – carnicer

risposta

2
o (master) 
/  o--o (WIP1) 
/ /
o--p--p--o--o--o (WIP2) 
(X)  (Y) 
      \ 
      o--o (WIP3) 

Questo dovrebbe essere un rebase --onto (potete vedere un esempio in "How to move certain commits to another branch in git?"):

git rebase --onto master X WIP1 
git rebase --onto master X WIP2 
git rebase --onto master X WIP3 

Da Chronial s' test, che darebbe:

  p'--p'--o--o (WIP2) 
     /
o-----o-----p--p--o--o--o (WIP1) 
(X) (master) (Y') 
     \ 
     p''--p''--o--o (WIP3) 

Così il il primo rebase è ok, ma è necessario ottenere Y SHA e:

git rebase --onto Y' Y WIP2 
git rebase --onto Y' Y WIP3 
+0

Questo creerà tre rami che divergono dal master, non è vero? Oppure muoverà la struttura dietro X in cima al master (in modo che i rami si spostino in seguito)? – Chronial

+0

@Chronial sì, c'è quel rischio, specialmente considerando che un rebase non riprodurrà un commit se lo stesso contenuto è rilevato sul ramo di destinazione. Dovrò provarlo. – VonC

+0

appena testato, e divergono:/ – Chronial

0

Se si desidera avere questo risultato

o (oldmaster)--o--o--B--o--o(WIP1)--o--o(WIP2)--o--o(WIP3)(master) 
/  
/  
X 

Si dovrebbe fare questo:

git rebase --onto master X WIP1   /* move WIP1 on master */ 
git rebase --onto WIP1 WIP2~3 WIP2  /* move WIP2 on WIP1 */ 
git rebase --onto WIP2 WIP3~3 WIP3  /* move WIP3 on WIP2 */ 
git reset --hard WIP3     /* move master index to WIP3 */ 
11

non esiste un comando unico git per questo. Dovrai fare del lavoro manuale. Per l'utente:

o (master) 
/  o--o (WIP1) 
/ /
X--o--o--B--o--o (WIP2) 
      \ 
      o--o (WIP3) 

Per prima REBASE WIP1 sul maestro:

git rebase --onto master X WIP1 

che porterà a questo:

   o--o (WIP1) 
(master) /
    o--o--o--B’ 
/ 
/  
X--o--o--B--o--o (WIP2) 
      \ 
      o--o (WIP3) 

Se ora si esegue git rebase --onto master X WIP2, si ottiene questo struttura:

   o--o (WIP1) 
(master) /
    o--o--o--B’ 
    /\ 
/ o--o--B’’--o--o (WIP2) 
/  
X--o--o--B--o--o (WIP3) 

Questo probabilmente non è ciò che si vuole, così ora si dovrebbe rebase WIP2 e WIP3 su B’:

git rebase --onto B’ B WIP2 
git rebase --onto B’ B WIP3 

che porterà a questo:

    o--o (WIP1) 
(master)  /
    o--X--o--o--B’--o--o (WIP2) 
       \ 
        o--o (WIP3) 
+0

Sembra simile alla mia modifica.+1 – VonC

+0

Sì, ho visto la tua modifica poco prima di inviarla, ma a quel punto avevo già disegnato tutto ciò che ascii-art ^^ – Chronial

+0

Hai fatto i test, ti meriti i crediti;) – VonC

1

ho contrassegnato questa domanda come duplicato. Scriverò quello che ho spiegato the other answer ma usando il tuo esempio.

L'approccio che uso per questi casi d'uso è quello di unire tutti i rami siano spostati in 1 nodo comune artificiale, e quindi utilizzare il comando rebase con l'opzione --preserve-merges. L'unione di tutti i rami sarà esporre 1 end-point che verrà utilizzato come parametro di input finale per rebase --onto. Il punto iniziale è in genere ovvio, l'origine del sottostruttura da spostare.

In caso di unione per ottenere l'endpoint di sottostruttura , i conflitti dovrebbero essere esplicitamente evitati . Pertanto i comandi di fusione devono essere istruiti per risolverli automaticamente con l'opzione -Xours. Il risultato della fusione non è importante poiché questi nodi di unione artificiali verranno scartati dopo il rebase.

Si consiglia di creare un nuovo ramo pacchetto per non perdere i riferimenti originali . Nell'esempio sopra i seguenti comandi sarebbero eseguiti:

$ git checkout -b pack WIP1 # create new branch at 'WIP1' 
$ git merge -s recursive -Xours WIP2 # merges WIP2 into pack (node p2) 
$ git merge -s recursive -Xours WIP3 # merges WIP3 into pack 

Questi può vedere ciò che l'albero sarebbe diventato. Due nuovinodi p2 e pacchetto sono stati creati con le unioni.

 o (master) 
    /
    /  (WIP1) (p2) 
/  o-----o-----o----o (pack) 
/ /  //
o--o--o--o-----o-----o /(WIP2) 
(X)  \   /
      o------------o (WIP3) 

Ora è il momento di rebase. Da oggi c'è un endpoint comune per tutte le rami (pacchetto), è facile spostare l'intera sottostruttura con:

$ git rebase --preserve-merges --onto master X pack 

che produce questo:

     (WIP1') (p2') 
        o-----o-----o----o (pack') 
    (master)  /  //
o----o----o--o--o-----o-----o /(WIP2') 
(X)    \   /
        o------------o (WIP3') 

Ora è il momento di riorganizzare i riferimenti. Non so perché, in alcuni casi i riferimenti vengono spostati e in altri no. Tipo questo per ogni WIP1 riferimento, WIP2, WIP3 o quello che vi serve:

$ git checkout WIP1 
$ git reset --hard <WIP1' hash> 

E, infine, sbarazzarsi dei artificiali commit che sono stati creati per generare un nodo fine comune sottostruttura.

$ git branch -D pack 
$ git branch -D p2 # if there is any 

Così l'albero finale sarebbe:

     (WIP1') 
        o-----o 
    (master)  /
o----o----o--o--o-----o-----o (WIP2') 
(X)    \ 
        o------------o (WIP3')