2010-07-10 9 views
12

Ho due repository git che sono correlati tangenzialmente. Vale a dire, il contenuto di uno era un predecessore dell'altro. Vorrei in qualche modo anteporre l'intera cronologia del deposito A al deposito B, in modo che il suggerimento di A sia un genitore del primo changeset del repository B? Le storie in entrambi sono piuttosto lineari.Come concatenare due storie git?

È possibile?

risposta

9

Si potrebbe provare a utilizzare il file di trapianto (.git/info/grafts) dove si poteva sovrascrivere il genitore di un commit (come il primo di projectB avere per il genitore l'ultima delle projectA)

Vedi anche "What are .git/info/grafts for?" e "How to prepend the past to a git repository?" per ulteriori informazioni su questa manipolazione.


skaleecomments circa l'articolo "Git: Grafting repositories" (da SO utente Ben Straub) per un esempio concreto.

Ora quello che vogliamo fare è cambiare il primo commit nel “nuevo” pronti contro termine (“New commit #1”) in modo che il suo genitore è l'ultimo commit nel “vecchio” pronti contro termine (“Old # 3”). Tempo per un po 'voodoo:

git fetch ../old master:ancient_history 

Git permette di essere prelevati dal qualsiasi altro repository git, se questo repo è legato ad esso o no! Brillante! Questo ci lascia con questo:

enter image description here

Nota come abbiamo ribattezzato il vecchio ramo master per ancient_history. Se non lo avessimo fatto, Git avrebbe cercato di unire i due, e probabilmente si sarebbe arreso disgustato.

Ora abbiamo ancora un problema.
I due alberi non sono collegati, e in effetti una tirata di git non otterrà nemmeno il ramo antico_history. Abbiamo bisogno di un modo per creare una connessione tra i due.

Git ha una funzione chiamata innesto, che fondamentalmente simula un collegamento genitore tra due commit.
per fare uno, basta inserire una riga nel file .git/info/grafts in questo formato:

[ref] [parent] 

Entrambi questi hanno bisogno di essere la piena hash dei commit in questione. Quindi cerchiamo di trovarli:

$ git rev-list master | tail -n 1 
d7737bffdad86dc05bbade271a9c16f8f912d3c6 

$ git rev-parse ancient_history 
463d0401a3f34bd381c456c6166e514564289ab2 

$ echo d7737bffdad86dc05bbade271a9c16f8f912d3c6 \ 
     463d0401a3f34bd381c456c6166e514564289ab2 \ 
     > .git/info/grafts 

(in una linea, come suggested da ssokolow)

echo $(git rev-list master | tail -n 1) $(git rev-parse ancient_history) > .git/info/grafts 

Ci.Ora la nostra storia si presenta così:

enter image description here

clonato questa repo risultati in questo:

enter image description here

Woops. Si scopre che gli innesti hanno effetto solo per il repository locale. Siamo in grado di risolvere questo problema con l'applicazione giudiziosa di git fast-import:

$ git fast-export --all > ../export 

$ mkdir ../nuevo-complete 

$ cd ../nuevo-complete 

$ git init 

$ git fast-import < ../export 
git-fast-import statistics: [...] 

(in una linea, come suggested da ssokolow)

git filter-branch $(git rev-parse ancient_history)..HEAD 

Questo trasforma in modo efficace il nostro “falso” collegamento di cronologia in sono soli.
Tutti gli ingegneri dovranno ri-clonare da questo nuovo repository, poiché gli hash saranno tutti diversi, ma questo è un piccolo prezzo da pagare per nessun tempo di inattività e una cronologia completa.

enter image description here

Come Qix commenti below:

fast-import sembra importare solo le informazioni git, ma non controlla nulla.
git init in origine mette il master, quindi è necessario un git reset --hard HEAD per verificare effettivamente i file dopo fast-import.

+0

Ha funzionato bene per me, grazie VonC, non pensavo che sarebbe stato così semplice. – SilentGhost

+1

Quindi puoi riscrivere la cronologia usando 'git filter-branch' per fare ciò che l'innesto ha portato permanente ... ma questo riscrive la storia. –

+0

Articolo breve e accurato che mi ha davvero aiutato a capire quali innesti sono e passo dopo passo come unire quelle storie: http://ben.straubnet.net/post/939181602/git-grafting-repositories – skalee