tipos tag submodulos etiquetas crear git git-submodules

tag - ¿Cómo extraer un subdirectorio git y crear un submódulo?



submodulos git (4)

Checkout git filter-branch .

La sección de Examples de la página man muestra cómo extraer un subdirectorio en su propio proyecto, conservando todo su historial y descartando el historial de otros archivos / directorios (justo lo que está buscando).

Para reescribir el repositorio para ver si foodir/ había sido su raíz de proyecto, y descartar el resto de la historia:

git filter-branch --subdirectory-filter foodir -- --all

Por lo tanto, puede, por ejemplo, convertir un subdirectorio de biblioteca en un repositorio propio.
Tenga en cuenta que -- separa filter-branch opciones de la filter-branch opciones de revisión, y --all para reescribir todas las ramas y etiquetas.

Comencé un proyecto hace algunos meses y almacené todo dentro de un directorio principal. En mi directorio principal "Proyecto" hay varios subdirectorios que contienen cosas diferentes: Proyecto / papel contiene un documento escrito en LaTeX Proyecto / código fuente / RailsApp contiene mi aplicación de rieles.

"Proyecto" está GITificado y ha habido muchas confirmaciones en el directorio "papel" y "RailsApp". Ahora, como me gustaría usar cruisecontrol.rb para mi "RailsApp", me pregunto si hay una forma de hacer un submódulo de "RailsApp" sin perder el historial.

¿Alguna sugerencia?


Hoy en día hay una manera mucho más fácil de hacerlo que manualmente usando git filter-branch: git subtree

Instalación

git clone https://github.com/apenwarr/git-subtree.git cd git-subtree sudo rsync -a ./git-subtree.sh /usr/local/bin/git-subtree

O si quieres las páginas man y todo

make doc make install

Uso

Divida un trozo más grande en trozos más pequeños:

# Go into the project root cd ~/my-project # Create a branch which only contains commits for the children of ''foo'' git subtree split --prefix=foo --branch=foo-only # Remove ''foo'' from the project git rm -rf ./foo # Create a git repo for ''foo'' (assuming we already created it on github) mkdir foo pushd foo git init git remote add origin [email protected]:my-user/new-project.git git pull ../ foo-only git push origin -u master popd # Add ''foo'' as a git submodule to `my-project` git submodule add [email protected]:my-user/new-project.git foo

Para obtener documentación detallada (página man), lea git-subtree.txt .


Si desea transferir un subconjunto de archivos a un nuevo repositorio pero conservar el historial, básicamente terminará con un historial completamente nuevo. La forma en que esto funcionaría es básicamente la siguiente:

  1. Crear nuevo repositorio.
  2. Para cada revisión de su antiguo repositorio, combine los cambios de su módulo en el nuevo repositorio. Esto creará una "copia" de su historial de proyectos existente.

Sería algo sencillo automatizar esto si no te importa escribir un script pequeño pero peludo. Directo, sí, pero también doloroso. La gente ha reescrito la historia en Git en el pasado, puedes hacer una búsqueda para eso.

Alternativamente: clone el repositorio, y elimine el papel en el clon, elimine la aplicación en el original. Esto tomaría un minuto, está garantizado que funciona, y puedes volver a cosas más importantes que tratar de purificar tu historial de git. Y no se preocupe por el espacio en el disco duro ocupado por las copias redundantes del historial.


Una forma de hacerlo es la inversa: elimine todo menos el archivo que desea conservar.

Básicamente, haga una copia del repositorio, luego use git filter-branch para eliminar todo menos el archivo / carpetas que desea conservar.

Por ejemplo, tengo un proyecto desde el cual deseo extraer el archivo tvnamer.py a un nuevo repositorio:

git filter-branch --tree-filter ''for f in *; do if [ $f != "tvnamer.py" ]; then rm -rf $f; fi; done'' HEAD

Utiliza git filter-branch --tree-filter para pasar por cada confirmación, ejecutar el comando y volver a enviar el contenido de los directorios resultantes. Esto es extremadamente destructivo (¡así que solo debe hacer esto en una copia de su repositorio!), Y puede tomar un tiempo (aproximadamente 1 minuto en un repositorio con 300 confirmaciones y aproximadamente 20 archivos)

El comando anterior solo ejecuta el siguiente script de shell en cada revisión, que deberá modificar por supuesto (para hacer que excluya su subdirectorio en lugar de tvnamer.py ):

for f in *; do if [ $f != "tvnamer.py" ]; then rm -rf $f; fi; done

El mayor problema obvio es que deja todos los mensajes de confirmación, incluso si no están relacionados con el archivo restante. El script git-remove-empty-commits , corrige esto ..

git filter-branch --commit-filter ''if [ z$1 = z`git rev-parse $3^{tree}` ]; then skip_commit "$@"; else git commit-tree "$@"; fi''

Necesita usar el argumento -f force ejecutar filter-branch nuevamente con cualquier cosa en refs/original/ (que básicamente es una copia de seguridad)

Por supuesto, esto nunca será perfecto, por ejemplo, si sus mensajes de confirmación mencionan otros archivos, pero es lo más aproximado que permite una corriente de git (hasta donde yo sé).

Nuevamente, ¡solo ejecute esto en una copia de su repositorio! - pero en resumen, para eliminar todos los archivos excepto "thisismyfilename.txt":

git filter-branch --tree-filter ''for f in *; do if [ $f != "thisismyfilename.txt" ]; then rm -rf $f; fi; done'' HEAD git filter-branch -f --commit-filter ''if [ z$1 = z`git rev-parse $3^{tree}` ]; then skip_commit "$@"; else git commit-tree "$@"; fi''