2010-11-12 6 views
22

Ho usato git-svn per creare un mirror git di un repository SVN. La struttura all'interno di SVN era un po 'fuori standard, quindi git ha creato un ramo che non ha commit in comune con il ramo master.git - impostazione di un genitore di commit senza rebase

 A---B---C topic 

D---E---F---G master 

So che commettere A è basato commettere E e sono abbastanza positivo che ho risolto i problemi che causano git non riconoscere questo fatto (tramite filter-branch). Quello che voglio fare è riattaccare topic al ramo master, impostando E come il genitore di A:

 A---B---C topic 
    /
D---E---F---G master 

git-rebase non sembra funzionare per me, perché il diff per commettere A liste la creazione di un un numero intero di file già esistenti in master, con un numero enorme di conflitti.
Dalla mia comprensione di git è sufficiente impostare E come genitore di A dovrebbe essere sufficiente per risolvere tutti i problemi.
È possibile? Se lo è, come posso farlo?

+0

Qualsiasi possibilità di riavviare il mirror git della svn che punta "rami" alla directory giusta? O aggiustando prima la struttura svn? – stefanw

+0

in realtà il repository ha utilizzato il layout standard tronco/tag/rami. Tuttavia, il ramo che stavo cercando di risolvere è stato creato copiando solo un sottotracciato del trunk - indovina un po 'troppo per git-svn da gestire. –

+0

rebase ha l'opzione 'root'. Usalo con 'on' e' preserve-merges' se ne hai bisogno. –

risposta

28

Dai un'occhiata agli innesti (il file dell'innesto può essere trovato in .git/info/grafts). Il formato è piuttosto semplice:

<commit sha1> <parent1 sha1> <parent2 sha1> … <parentN sha1> 

Ciò rende git credere che un commit ha genitori diversi da quello che effettivamente ha. Utilizzare il filtro-ramo per fare innesti permanente (in modo che il file di innesti può essere rimosso):

git filter-branch --tag-name-filter cat -- --all 

Si noti che questo riscrive la storia del repository, quindi non dovrebbe essere utilizzato su pronti contro termine condivisi!


Se si desidera solo riscrivere la storia dei commit che vengono innestate sul branch master, ad esempio, utilizzare questo comando:

git filter-branch --tag-name-filter cat -- master.. 
+0

non utilizzare innesti o branch branch se non è necessario. –

+3

Gli innesti sono incredibilmente utili se ne hai bisogno, ma come alcune altre funzionalità di git dovrebbero essere utilizzati prima di condividere il repository (o dovrai far ri-clonare tutti gli altri). Come dice la risposta, è sufficiente creare il file di grafts (hash-of-A, spazio, hash-of-E, newline) e utilizzare "git filter-branch --tag-name-filter cat - --all" per riscrivere cronologia senza modificare altri dati di commit – JodaStephen

+0

@JodaStephen dovresti aggiungerlo alla risposta. Sai se è giusto farlo se il repository è pubblicato, ma gli innesti con cui stai scherzando riguardano solo commit nuovi, non pubblicati? – naught101

8

In base ai diagrammi (anche se sono preoccupato per quello che intendi con "Sono abbastanza sicuro di aver risolto i problemi che hanno causato a Git di non riconoscere quel fatto (usando filter-branch)."), dovresti essere in grado di fare qualcosa di simile al seguente.

# checkout A 
git checkout A 

# Reset the branch pointer to E so that E is the parent of the next commit 
# --soft ensures that the index stays the same 
git reset --soft E 

# Remake the commit with the E as the parent, re-using the old commit metadata 
git commit -C [email protected]{1} 

# Rebase the topic branch onto the modified A commit (current HEAD) 
git rebase --onto HEAD A topic 
+0

Funziona quasi bene, ma l'argomento finisce per non tenere traccia dell'origine/argomento remoto dopo quell'operazione! –

5

Tutto ciò che serve è questo:

git rebase --root --onto master^^ topic^^ topic 

l'opzione principale consente di includere A.

UPDATE:

aggiungere l'opzione --preserve-merges se si desidera mantenere la ramificazione e fusione della parte che stai ridefinendo.

+1

Questo comando ha funzionato perfettamente per me! – jarvisschultz

+0

Funziona alla grande se si ha una cronologia lineare, se ha commit di merge, si deve usare '--preserve-merges', e si deve ri-risolvere i conflitti di merge manualmente. – Flimm

+0

Sì. Aggiornerò la risposta Un'altra volta che ho risposto alla stessa domanda, ho incluso questa opzione. –