¿Cómo puedo mover un único directorio de un repositorio de git a un nuevo repositorio mientras mantengo el historial?

110

He heredado un repositorio de git que contiene varios proyectos en directorios separados. Me gustaría dividir el repositorio en nuevos repositorios individuales, uno para cada proyecto y luego hacer que el repositorio principal contenga los proyectos como submódulos. Me gustaría hacer todo esto manteniendo el historial de revisión de los proyectos individuales si es posible.

Podría clonar el repositorio para cada proyecto y eliminar todos los demás proyectos cada vez, pero ¿hay una mejor manera de evitar tener el historial clonado en cada nuevo repositorio de proyectos?

cidrado
fuente
2
Se agregó la etiqueta git-submodules ya que es muy útil para convertir parte de un repositorio en un submódulo.
idbrii
Posible duplicado del subárbol
usuario

Respuestas:

99

Puede utilizar git filter-branchpara reescribir el historial de un proyecto. De la documentación:

Para reescribir el repositorio para que parezca que foodir / hubiera sido la raíz del proyecto y descartar el resto del historial:

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

Haga varias copias de su repositorio, hágalo para cada subdirectorio que desee dividir, y debería terminar con lo que está buscando.

Brian Campbell
fuente
1
¿Y si quisiera excluir foodir y eliminar todo su historial?
saeedgnu
1
Nota: si desea varios directorios, deberá especificar --subdirectory-filtervarias veces. EG git filter-branch --subdirectory-filter foodir --subdirectory-filter bardir, --subdirectoryetc.no tomarán varios directorios, pero se pueden especificar varias veces.
EnabrenTane
3
@Adam Si desea mantener el historial de foodiren el proyecto original, sin reescribir su historial, git rm -r foodirdebería ser suficiente (eso también eliminará la copia en su árbol de trabajo; si no lo desea, use --cached). Si desea eliminarlo por completo del historial (respondiendo también a la pregunta de @ilius), desea algo comogit filter-branch --index-filter 'git rm -r --cached --ignore-unmatched foodir' -- --all
Brian Campbell
2
@ilius Lo siento, me perdí su pregunta anterior, consulte mi respuesta anterior para obtener una respuesta sobre cómo eliminar un directorio y su historial.
Brian Campbell
2
@ilius Sí, eso también funciona. Para un proyecto grande, la --index-filtersolución es más rápida que --tree-filter, ya que no tiene que verificar los archivos, solo puede manipular el índice directamente. El --tree-filterpuede ser un poco más fácil de usar, sin embargo, como se puede utilizar operaciones filsystem ordinarios en lugar de tener que trabajar con las operaciones de manipulación de índice.
Brian Campbell
4

Para exportar una carpeta como un nuevo repositorio, necesita:

  1. Para clonar el repositorio donde se encuentra la carpeta que desea exportar.
  2. Para crear un repositorio vacío en su proveedor de alojamiento como GitHub, para almacenar la carpeta exportada.
  3. Abra la carpeta del repositorio clonado y ejecute este comando:

    git subtree push --prefix=YourFolderNameToExport https://github.com/YourUserName/YourNewCleanRepoName master
    
usuario
fuente
1
git subtreeno está disponible como paquete Cygwin. Si lo necesita: stackoverflow.com/a/27116828/2484903
Jack Miller
2

El punto de git es que el historial se incorpora en cada confirmación mediante el hash del compromiso principal. Podrías "reproducir" las confirmaciones (así es esencialmente como funciona el importador svn) en un nuevo repositorio y solo conservando cada subproyecto. Sin embargo, esto destruiría el significado de los valores hash de confirmación. Si no tiene ningún problema con eso, que así sea.

En el pasado simplemente lo cloné y seguí adelante. Esto hace que las cosas sean más grandes, pero el espacio en disco es barato; mi tiempo es caro.

Tampoco conozco ninguna herramienta para empalmar un directorio. Supongo que podría git-log en el directorio para encontrar todas las confirmaciones en él y luego reproducir las confirmaciones con algo como git-fast-export.

Colin Burnett
fuente
Voté porque esto no merecía ser negativo; ciertamente no seguiría este enfoque, pero puedo ver que lo estaba intentando
Alvin