submodulos - Crea un repositorio de submódulos desde una carpeta y mantén su historial de commit de git
git ver commits (3)
Tengo una aplicación web que explora otras aplicaciones web de una manera particular. Contiene algunas demostraciones web en una carpeta demos
y una de las demos ahora debe tener su propio repositorio. Me gustaría crear un repositorio separado para esta aplicación de demostración y convertirla en una subpaquete submodule del repositorio principal sin perder su historial de compromiso.
¿Es posible mantener el historial de confirmaciones de los archivos en la carpeta de un repositorio y crear un repositorio a partir de él y usarlo como un submodule ?
Solución detallada
Vea la nota al final de esta respuesta (último párrafo) para una alternativa rápida a los submódulos de git usando npm;)
En la siguiente respuesta, sabrá cómo extraer una carpeta de un repositorio y hacer un repositorio git a partir de él y luego incluirlo como un submodule lugar de una carpeta.
Inspirado en el artículo de Gerg Bayer Moviendo archivos de un repositorio de Git a otro, preservando la historia
Al principio, tenemos algo como esto:
<git repository A>
someFolders
someFiles
someLib <-- we want this to be a new repo and a git submodule!
some files
En los pasos a continuación, voy a referir esto someLib
como <directory 1>
.
Al final, tendremos algo como esto:
<git repository A>
someFolders
someFiles
@submodule --> <git repository B>
<git repository B>
someFolders
someFiles
Crea un nuevo repositorio git desde una carpeta en otro repositorio
Paso 1
Obtenga una copia nueva del repositorio para dividir.
git clone <git repository A url>
cd <git repository A directory>
Paso 2
La carpeta actual será el nuevo repositorio, así que elimine el control remoto actual.
git remote rm origin
Paso 3
Extrae el historial de la carpeta deseada y compórtala
git filter-branch --subdirectory-filter <directory 1> -- --all
Ahora debería tener un repositorio de git con los archivos del directory 1
en la raíz de su repositorio con todo el historial de confirmaciones relacionado.
Etapa 4
¡Crea tu repositorio en línea y envía tu nuevo repositorio!
git remote add origin <git repository B url>
git push
Es posible que deba configurar la rama upstream
para su primer impulso
git push --set-upstream origin master
Limpiar <git repository A>
(opcional, ver comentarios)
Queremos eliminar trazas (archivos e historial de confirmaciones) de <git repository B>
desde <git repository A>
para que el historial de esta carpeta solo esté allí una vez.
Esto se basa en Eliminar datos confidenciales de github.
Ir a una nueva carpeta y
git clone <git repository A url>
cd <git repository A directory>
git filter-branch --force --index-filter ''git rm --cached --ignore-unmatch <directory 1> -r'' --prune-empty --tag-name-filter cat -- --all
Reemplace <directory 1>
por la carpeta que desea eliminar. -r
lo hará recursivamente dentro del directorio especificado :). Ahora presione hacia el origin/master
con --force
git push origin master --force
Etapa de jefe (ver la nota a continuación)
Crea un submodule desde <git repository B>
en <git repository A>
git submodule add <git repository B url>
git submodule update
git commit
Verificar si todo funcionó como se esperaba y push
git push origin master
Nota
Después de hacer todo esto, me di cuenta en mi caso de que era más apropiado usar npm para administrar mis propias dependencias. Podemos especificar git urls y versiones, ver el paquete.json git urls como dependencias .
Si lo hace de esta manera, el repositorio que desea utilizar como requisito debe ser un módulo npm, por lo que debe contener un archivo package.json
o obtendrá este error: Error: ENOENT, open ''tmp.tgz-unpack/package.json''
.
tldr (solución alternativa)
Puede que le resulte más fácil usar npm y administrar dependencias con git urls :
- Mover la carpeta a un nuevo repositorio
- ejecutar
npm init
dentro de ambos repositorios -
npm install --save git://github.com/user/project.git#commit-ish
donde quiera quenpm install --save git://github.com/user/project.git#commit-ish
instaladas sus dependencias
La solución de @GabLeRoux aplasta las ramas y las confirmaciones relacionadas.
Una forma simple de clonar y mantener todas esas ramas y confirmaciones adicionales:
1 - Asegúrate de tener este git alias
git config --global alias.clone-branches ''! git branch -a | sed -n "///HEAD /d; ///master$/d; /remotes/p;" | xargs -L1 git checkout -t''
2 - Clona el control remoto, tira de todas las ramas, cambia el control remoto, filtra tu directorio, empuja
git clone [email protected]:user/existing-repo.git new-repo
cd new-repo
git clone-branches
git remote rm origin
git remote add origin [email protected]:user/new-repo.git
git remote -v
git filter-branch --subdirectory-filter my_directory/ -- --all
git push --all
git push --tags
La solución de GabLeRoux funciona bien, excepto si usa git lfs
y tiene archivos grandes en el directorio que desea separar. En ese caso, después del paso 3, todos los archivos grandes seguirán siendo archivos de puntero en lugar de archivos reales. Supongo que probablemente se deba al archivo .gitattributes
que se está eliminando en el proceso de bifurcación del filtro.
Al darme cuenta de esto, creo que la siguiente solución funciona para mí:
cp .gitattributes .git/info/attributes
Copiando .gitattributes
que git lfs usa para rastrear archivos grandes a .git/
directory para evitar ser eliminados.
Cuando filter-branch finaliza, no olvide volver a colocar .gitattributes
si aún desea usar git lfs para el nuevo repositorio:
mv .git/info/attributes .gitattributes
git add .gitattributes
git commit -m ''added back .gitattributes''