Git: copy el historial del file de un repository a otro

Tengo dos repositorys git, dicen A y B, ambos contienen un file llamado file1.cc. ¿Es posible fusionar / copyr el historial de file1.cc en el repository A a file1.cc en el repository B?

El problema es que ya hemos movido los files del repository A al repository B y se ha perdido el historial de todos los files. pero ahora algunos de los desarrolladores ya comenzaron a trabajar en el repository B y promovieron sus cambios. Así que ahora quiero fusionar / copyr el historial de algunos files desde el repository A hasta el repository B y que son aplicables solo para algunos de los files. ¿Es posible hacerlo? ¿O el historial de los files perdidos se pierde para siempre?

Por favor ayuda. Gracias por adelantado.

Se puede hacer, pero puede no ser fácil. Pero lo primero es lo primero: no hay "movimiento de la historia de un file". Solo hay commits en movimiento, así que si quieres commits que representen el historial de un subset de files, entonces crear esos commits es el primer desafío.

Lo más simple sería transferir toda la historia. (De hecho, si sucede que hiciste Repo B como un clon superficial del Repo A, entonces podrías des-superficializarlo y terminarlo. Pero supongo que no es así como creaste el Repo B …)

A pesar de todo, dado que te estás moviendo de Repo A a Repo B, tal vez haya algún historial que específicamente desees eliminar. Eso es potencialmente un tema completo, pero supongamos que realmente solo quieres el historial de algunos files.

En el caso especial donde todos los files que desea (y no otros) están en un subdirectory, y desea (o, al less, puede aceptar) mover esos files al directory raíz del repository, puede usar filter-branch con el --subdirectory-filter .

En términos más generales, si suponemos que las routes no deberían cambiar y que los files que desea podrían estar en cualquier lugar del tree, entonces podría usar filter-branch con un --index-filter .

 git filter-branch --index-filter 'git rm --cached --ignore-unmatch each file or *glob* you do NOT want' --prune-emtpy -- all 

Eso podría demorar un time si el repository tiene muchas confirmaciones. Si la list de files a rm no es trivial, es posible que desee colocar varios commands de git rm en un script de shell y usar eso como el argumento --index-filter en lugar de subrayarlo como se muestra arriba.

Bueno, de una forma u otra, con suerte, tienes un historial que te gustaría injertar en Repo B.

 cd repo-b git remote add repo-a path/to/repo-a git fetch repo-a 

Ahora lo tienes en Repo B:

 ... A -- B <--(repo-a/master) \ (repo-a/other-branches-maybe) B' -- C -- D (master)(origin/master) 

Así que estoy haciendo una suposition aquí, que el TREE del último master cometido en Repo A – aquel desde el cual nuestra reescritura de historia creó B – o al less alguna parte de ese tree, fue importado como el compromiso raíz en Repo B.

Ahora tiene tres opciones: reaparecer, rebasear o replace

Como supongo que el estado de la historia reciente es más importante que el estado de la historia anterior, y que la historia más antigua se acaba de agregar como reference, lo más seguro sería replace C a B ( A lugar de eso, puede elegir reparar B' a A , pero asumo que eso no hace mucha diferencia …)

Así que tomando de los documentos de la filter-branch en https://git-scm.com/docs/git-filter-branch , podrías

 # be sure you're on master echo "$commit-id $graft-id" >> .git/info/grafts git filter-branch $graft-id..HEAD 

donde $commit-id es el SHA para B y $graft-id es el SHA para C

Una rebase puede ser un poco más simple (suponiendo un cierto nivel de consistencia entre las historias) pero introduce la posibilidad de que termine modificando el tree en D Si decides probar una rebase, sería

 git rebase --onto repo-A/master B' master 

donde B' es la ID SHA del compromiso raíz de Repo B. (Alternativamente

 git rebase --interactive --onto repo-A/master --root master 

y luego soltar la input para B' ).

Cualquiera de estas opciones reescribirá las confirmaciones C y D (Aunque re-parenting asegura que el TREE se modifique, los commits aún se reemplazan.) Tus desarrolladores tendrían que tratar esto como una rebase ascendente (mira la documentation de git rebase bajo "recovering from upstream rebase"). Para mitigar esto, generalmente recomiendo hacer un corte coordinado donde los desarrolladores verifiquen todo lo que tienen, descarten sus clones, luego hagan la reescritura y vuelvan a clonar desde el nuevo repository.

Si desea evitar la reescritura, puede usar la tercera opción: git replace . Se sabe que esto tiene algunos caprichos y requiere que cada clon se configure correctamente para "ver" el historial empalmado.

Entonces, para apoyar esto, simplemente labelría B (y tal vez también B' ):

 git tag old-history repo-a/master git tag new-root B' 

(donde B' es el ID de valor de SHA apropiado, o expresión equivalente).

Cuando alguien clona el repository, solo verá la nueva historia, pero pueden decir

 git replace new-root old-history 

y esto será papel sobre el descanso en la historia.

Una vez que haya hecho su reparent, rebase o replace, puede eliminar el control remoto repo-a .