tutorial repositorio proyecto inicializar español descargar crear como clonar git git-subtree git-filter-branch

repositorio - github tutorial español



Separar(mover) el subdirectorio en un repositorio Git separado (22)

La manera más fácil

  1. instalar git splits . Lo creé como una extensión de git, basada en la solución de jkeating .
  2. Dividir los directorios en una rama local #change into your repo''s directory cd /path/to/repo #checkout the branch git checkout XYZ
    #split multiple directories into new branch XYZ git splits -b XYZ XY1 XY2
    #change into your repo''s directory cd /path/to/repo #checkout the branch git checkout XYZ
    #split multiple directories into new branch XYZ git splits -b XYZ XY1 XY2

  3. Crear un repositorio vacío en algún lugar. [email protected]:simpliwp/xyz.git que hemos creado un repositorio vacío llamado xyz en GitHub que tiene la ruta: [email protected]:simpliwp/xyz.git

  4. Empuje al nuevo repositorio. #add a new remote origin for the empty repo so we can push to the empty repo on GitHub git remote add origin_xyz [email protected]:simpliwp/xyz.git #push the branch to the empty repo''s master branch git push origin_xyz XYZ:master

  5. Clone el repositorio remoto recién creado en un nuevo directorio local
    #change current directory out of the old repo cd /path/to/where/you/want/the/new/local/repo #clone the remote repo you just pushed to git clone [email protected]:simpliwp/xyz.git

Tengo un repositorio Git que contiene varios subdirectorios. Ahora he encontrado que uno de los subdirectorios no está relacionado con el otro y debería ser separado a un repositorio separado.

¿Cómo puedo hacer esto mientras mantengo el historial de los archivos dentro del subdirectorio?

Supongo que podría hacer un clon y eliminar las partes no deseadas de cada clon, pero supongo que esto me daría el árbol completo al revisar una revisión anterior, etc. Esto podría ser aceptable, pero preferiría poder fingir que Dos repositorios no tienen un historial compartido.

Solo para dejarlo claro, tengo la siguiente estructura:

XYZ/ .git/ XY1/ ABC/ XY2/

Pero me gustaría esto en su lugar:

XYZ/ .git/ XY1/ XY2/ ABC/ .git/ ABC/


The Easy Way ™

Resulta que esta es una práctica tan común y útil que los amos de git lo hicieron realmente fácil, pero tienes que tener una versión más nueva de git (> = 1.7.11 mayo de 2012). Vea el apéndice para saber cómo instalar el último git. Además, hay un ejemplo del mundo real en el tutorial a continuación.

  1. Preparar el viejo repositorio

    pushd <big-repo> git subtree split -P <name-of-folder> -b <name-of-new-branch> popd

    Nota: <name-of-folder> NO debe contener caracteres iniciales o finales. Por ejemplo, la carpeta llamada subproject DEBE pasarse como subproject , NO ./subproject/

    Nota para los usuarios de Windows: cuando la profundidad de su carpeta es> 1, <name-of-folder> debe tener un separador de carpeta de estilo * nix (/). Por ejemplo, la carpeta llamada path1/path2/subproject DEBE pasarse como path1/path2/subproject

  2. Crea el nuevo repositorio.

    mkdir <new-repo> pushd <new-repo> git init git pull </path/to/big-repo> <name-of-new-branch>

  3. Vincula el nuevo repositorio a Github o donde sea

    git remote add origin <[email protected]:my-user/new-repo.git> git push origin -u master

  4. Limpieza, si se desea

    popd # get out of <new-repo> pushd <big-repo> git rm -rf <name-of-folder>

    Nota : Esto deja todas las referencias históricas en el repositorio. Consulte el Apéndice a continuación si está realmente preocupado por haber ingresado una contraseña o si necesita disminuir el tamaño del archivo de su carpeta .git .

...

Recorrido

Estos son los mismos pasos que arriba , pero siguiendo mis pasos exactos para mi repositorio en lugar de usar <meta-named-things> .

Aquí hay un proyecto que tengo para implementar módulos de navegador de JavaScript en el nodo:

tree ~/Code/node-browser-compat node-browser-compat ├── ArrayBuffer ├── Audio ├── Blob ├── FormData ├── atob ├── btoa ├── location └── navigator

Quiero dividir una sola carpeta, btoa , en un repositorio de git separado

pushd ~/Code/node-browser-compat/ git subtree split -P btoa -b btoa-only popd

Ahora tengo una nueva rama, btoa-only , que solo tiene confirmaciones para btoa y quiero crear un nuevo repositorio.

mkdir ~/Code/btoa/ pushd ~/Code/btoa/ git init git pull ~/Code/node-browser-compat btoa-only

A continuación, creo un nuevo repositorio en Github o bitbucket, o lo que sea y añado que es el origin (por cierto, "origen" es solo una convención, no es parte del comando, puede llamarlo "servidor remoto" o lo que quiera)

git remote add origin [email protected]:node-browser-compat/btoa.git git push origin -u master

¡Día feliz!

Nota: Si creó un repositorio con un README.md , .gitignore y LICENSE , deberá extraer primero:

git pull origin -u master git push origin -u master

Por último, querré eliminar la carpeta del repositorio más grande

git rm -rf btoa

...

Apéndice

Último git en OS X

Para obtener la última versión de git:

brew install git

Para obtener cerveza para OS X:

http://brew.sh

Las últimas git en Ubuntu

sudo apt-get update sudo apt-get install git git --version

Si eso no funciona (tienes una versión muy antigua de ubuntu), prueba

sudo add-apt-repository ppa:git-core/ppa sudo apt-get update sudo apt-get install git

Si eso todavía no funciona, intente

sudo chmod +x /usr/share/doc/git/contrib/subtree/git-subtree.sh sudo ln -s / /usr/share/doc/git/contrib/subtree/git-subtree.sh / /usr/lib/git-core/git-subtree

Gracias a rui.araujo de los comentarios.

limpiando tu historia

De forma predeterminada, eliminar archivos de git no los elimina de git, simplemente confirma que ya no están allí. Si desea eliminar realmente las referencias históricas (es decir, ha confirmado una contraseña), debe hacer esto:

git filter-branch --prune-empty --tree-filter ''rm -rf <name-of-folder>'' HEAD

Después de eso, puedes verificar que tu archivo o carpeta ya no aparezca en el historial de git

git log -- <name-of-folder> # should show nothing

Sin embargo, no puede "empujar" las eliminaciones a github y similares. Si lo intentas, obtendrás un error y tendrás que hacer git pull antes de poder git push - y luego volverás a tener todo en tu historial.

Por lo tanto, si desea eliminar el historial del "origen", es decir, eliminarlo de github, bitbucket, etc., deberá eliminar el repositorio y volver a enviar una copia eliminada del repositorio. Pero espera, ¡ hay más ! - Si está realmente preocupado por deshacerse de una contraseña o algo así, tendrá que eliminar la copia de seguridad (ver más abajo).

haciendo .git más pequeño

El comando para eliminar el historial mencionado anteriormente todavía deja un montón de archivos de copia de seguridad, ya que git es muy amable y te ayuda a no arruinar tu repo por accidente. Eventualmente, eliminará los archivos huérfanos a lo largo de los días y los meses, pero los dejará allí por un tiempo en caso de que se dé cuenta de que accidentalmente eliminó algo que no deseaba.

Entonces, si realmente quieres vaciar la basura para reducir el tamaño de clon de un repositorio, inmediatamente tienes que hacer todo esto realmente extraño:

rm -rf .git/refs/original/ && / git reflog expire --all && / git gc --aggressive --prune=now git reflog expire --all --expire-unreachable=0 git repack -A -d git prune

Dicho esto, recomendaría no realizar estos pasos a menos que sepa que debe hacerlo, en caso de que haya borrado el subdirectorio incorrecto, ¿sabe? Los archivos de copia de seguridad no se deben clonar cuando presiona el repositorio, simplemente estarán en su copia local.

Crédito


Aquí hay una pequeña modificación a la de "The Easy Way ™" para dividir varias subcarpetas (digamos sub1 y sub2 ) en un nuevo repositorio de git.

The Easy Way ™ (subcarpetas múltiples)

  1. Preparar el viejo repositorio

    pushd <big-repo> git filter-branch --tree-filter "mkdir <name-of-folder>; mv <sub1> <sub2> <name-of-folder>/" HEAD git subtree split -P <name-of-folder> -b <name-of-new-branch> popd

    Nota: <name-of-folder> NO debe contener caracteres iniciales o finales. Por ejemplo, la carpeta llamada subproject DEBE pasarse como subproject , NO ./subproject/

    Nota para los usuarios de Windows: cuando la profundidad de su carpeta es> 1, <name-of-folder> debe tener un separador de carpeta de estilo * nix (/). Por ejemplo, la carpeta llamada path1/path2/subproject DEBE pasarse como path1/path2/subproject . Por otra parte, no utilice el comando mv pero move .

    Nota final: la única y gran diferencia con la respuesta básica es la segunda línea del script " git filter-branch... "

  2. Crea el nuevo repositorio.

    mkdir <new-repo> pushd <new-repo> git init git pull </path/to/big-repo> <name-of-new-branch>

  3. Vincula el nuevo repositorio a Github o donde sea

    git remote add origin <[email protected]:my-user/new-repo.git> git push origin -u master

  4. Limpieza, si se desea

    popd # get out of <new-repo> pushd <big-repo> git rm -rf <name-of-folder>

    Nota : Esto deja todas las referencias históricas en el repositorio. Consulte el Apéndice en la respuesta original si realmente está preocupado por haber ingresado una contraseña o si necesita disminuir el tamaño del archivo de su carpeta .git .


Como mencioné anteriormente , tuve que usar la solución inversa (eliminando todas las confirmaciones que no tocan mi dir/subdir/targetdir ) que parecía funcionar bastante bien eliminando aproximadamente el 95% de las confirmaciones (como se desea). Hay, sin embargo, dos pequeños problemas pendientes.

PRIMERO , filter-branch hizo un gran trabajo al eliminar las confirmaciones que introducen o modifican el código, pero aparentemente, las confirmaciones de combinación están debajo de su estación en Gitiverse.

Este es un problema cosmético con el que probablemente pueda vivir (dice ... retrocediendo lentamente con los ojos desviados) .

SEGUNDA las pocas confirmaciones que quedan están prácticamente TODAS duplicadas! Parece que he adquirido una segunda línea de tiempo redundante que abarca casi toda la historia del proyecto. Lo interesante (que se puede ver en la imagen de abajo), es que mis tres sucursales locales no están todas en la misma línea de tiempo (que es, ciertamente, por qué existe y no solo se recolecta la basura).

Lo único que puedo imaginar es que una de las confirmaciones eliminadas fue, tal vez, la única confirmación de fusión que el filter-branch realmente eliminó, y que creó la línea de tiempo paralela ya que cada hebra sin combinar tomó su propia copia de las confirmaciones. ( encogerse de hombros, ¿dónde está mi TARDIS?) Estoy bastante seguro de que puedo solucionar este problema, aunque realmente me encantaría entender cómo sucedió.

En el caso de mergefest-O-RAMA loco, probablemente lo dejaré solo, ya que se ha afianzado tan firmemente en mi historial de compromisos (me amenaza cuando me acerque), no parece estar causando realmente Cualquier problema no cosmético y porque es bastante bonito en Tower.app.


Consulte el proyecto git_split en https://github.com/vangorra/git_split

Convierta los directorios de git en sus propios repositorios en su propia ubicación. No hay negocio de subárbol divertido. Este script tomará un directorio existente en su repositorio git y lo convertirá en un repositorio independiente propio. En el camino, copiará el historial de cambios completo para el directorio que proporcionó.

./git_split.sh <src_repo> <src_branch> <relative_dir_path> <dest_repo> src_repo - The source repo to pull from. src_branch - The branch of the source repo to pull from. (usually master) relative_dir_path - Relative path of the directory in the source repo to split. dest_repo - The repo to push to.


Descubrí que para eliminar correctamente el historial antiguo del nuevo repositorio, tiene que hacer un poco más de trabajo después del paso de filter-branch .

  1. Haz el clon y el filtro:

    git clone --no-hardlinks foo bar; cd bar git filter-branch --subdirectory-filter subdir/you/want

  2. Eliminar todas las referencias a la historia antigua. "Origen" fue rastrear tu clon, y "original" es donde filtro-rama guarda las cosas antiguas:

    git remote rm origin git update-ref -d refs/original/refs/heads/master git reflog expire --expire=now --all

  3. Incluso ahora, su historial puede estar atascado en un paquete de archivos que fsck no tocará. Rasgarlo en tiras, creando un nuevo paquete de archivos y eliminando los objetos no utilizados:

    git repack -ad

Hay una explicación de esto en el manual para la rama de filtro .


Es posible que necesite algo como "git reflog expire --expire = now --all" antes de la recolección de basura para eliminar realmente los archivos. git filter-branch simplemente elimina las referencias en el historial, pero no elimina las entradas de búsqueda que contienen los datos. Por supuesto, prueba esto primero.

Mi uso del disco se redujo drásticamente al hacer esto, aunque mis condiciones iniciales fueron algo diferentes. Quizás --subdirectory-filter niega esta necesidad, pero lo dudo.


Esto ya no es tan complejo que solo puede usar el comando git filter-branch en un clon de su repositorio para seleccionar los subdirectorios que no desea y luego enviar al nuevo control remoto.

git filter-branch --prune-empty --subdirectory-filter <YOUR_SUBDIR_TO_KEEP> master git push <MY_NEW_REMOTE_URL> -f .


La forma correcta ahora es la siguiente:

git filter-branch --prune-empty --subdirectory-filter FOLDER_NAME [first_branch] [another_branch]

GitHub ahora incluso tiene un pequeño artículo sobre tales casos.

Pero asegúrese de clonar su repo original para separar el directorio primero (ya que eliminaría todos los archivos y otros directorios y probablemente necesite trabajar con ellos).

Entonces tu algoritmo debería ser:

  1. Clone su repositorio remoto a otro directorio
  2. utilizando git filter-branch solo deja archivos en algún subdirectorio, presione para nuevo control remoto
  3. Cree un compromiso para eliminar este subdirectorio de su repositorio remoto original

La pregunta original quiere que XYZ / ABC / (archivos *) se convierta en ABC / ABC / (archivos *). Después de implementar la respuesta aceptada para mi propio código, noté que en realidad cambia XYZ / ABC / (* archivos) en ABC / (* archivos). La página de manual de filtro-rama incluso dice:

El resultado contendrá ese directorio (y solo ese) como su raíz del proyecto ".

En otras palabras, promueve que la carpeta de nivel superior "suba" un nivel. Esa es una distinción importante porque, por ejemplo, en mi historial he cambiado el nombre de una carpeta de nivel superior. Al promover las carpetas "hacia arriba" en un nivel, git pierde continuidad en la confirmación donde hice el cambio de nombre.

Mi respuesta a la pregunta es hacer 2 copias del repositorio y eliminar manualmente las carpetas que desea guardar en cada una. La página de manual me respalda con esto:

[...] evite usar [este comando] si una simple confirmación simple sería suficiente para solucionar su problema


Para agregar a la respuesta de Paul , encontré que para recuperar el espacio en última instancia, tengo que empujar HEAD a un repositorio limpio y eso reduce el tamaño del directorio .git / objects / pack.

es decir

$ mkdir ...ABC.git $ cd ...ABC.git $ git init --bare

Después de la poda gc, también haz:

$ git push ...ABC.git HEAD

Entonces puedes hacer

$ git clone ...ABC.git

y se reduce el tamaño de ABC / .git

En realidad, algunos de los pasos que consumen tiempo (por ejemplo, git gc) no son necesarios con el empuje para limpiar el repositorio, es decir:

$ git clone --no-hardlinks /XYZ /ABC $ git filter-branch --subdirectory-filter ABC HEAD $ git reset --hard $ git push ...ABC.git HEAD


Para lo que vale la pena, aquí está cómo usar GitHub en una máquina con Windows. Digamos que tiene un repositorio clonado en residir en C:/dir1 . La estructura del directorio se ve así: C:/dir1/dir2/dir3 . El directorio dir3 es el que quiero que sea un nuevo repositorio separado.

Github:

  1. Crea tu nuevo repositorio: MyTeam/mynewrepo

Mensaje de Bash:

  1. $ cd c:/Dir1
  2. $ git filter-branch --prune-empty --subdirectory-filter dir2/dir3 HEAD
    Devuelto: la Ref ''refs/heads/master'' was rewritten (fyi: dir2 / dir3 distingue entre mayúsculas y minúsculas)

  3. $ git remote add some_name [email protected]:MyTeam/mynewrepo.git
    git remote add origin etc no funcionó, devuelto " remote origin already exists "

  4. $ git push --progress some_name master


Parece que la mayoría (todas?) De las respuestas aquí dependen de alguna forma de git filter-branch --subdirectory-filter y su ilk. Esto puede funcionar "la mayoría de las veces", sin embargo, en algunos casos, por ejemplo, cuando cambió el nombre de la carpeta, por ejemplo:

ABC/ /move_this_dir # did some work here, then renamed it to ABC/ /move_this_dir_renamed

Si realiza un estilo de filtro de git normal para extraer "move_me_renamed", perderá el historial de cambios de archivos que se produjo cuando era inicialmente move_this_dir ( ref ).

Por lo tanto, parece que la única forma de mantener realmente todo el historial de cambios (si el suyo es un caso como este), es, en esencia, copiar el repositorio (crear un nuevo repositorio, establecer que sea el origen), y luego destruir todo lo demás. y renombra el subdirectorio al padre de esta manera:

  1. Clona el proyecto multi-módulo localmente
  2. Sucursales - verifique que hay ahí: git branch -a
  3. Haga un pago a cada sucursal para incluirlo en la división para obtener una copia local en su estación de trabajo: git checkout --track origin/branchABC
  4. Haga una copia en un nuevo directorio: cp -r oldmultimod simple
  5. Entra en la nueva copia del proyecto: cd simple
  6. Deshazte de los otros módulos que no son necesarios en este proyecto:
  7. git rm otherModule1 other2 other3
  8. Ahora solo queda el subdirectorio del módulo de destino.
  9. Deshágase del módulo subdir para que la raíz del módulo se convierta en la nueva raíz del proyecto.
  10. git mv moduleSubdir1/* .
  11. Eliminar el rmdir moduleSubdir1 : rmdir moduleSubdir1
  12. Compruebe los cambios en cualquier punto: git status
  13. Crea el nuevo repositorio de git y copia su URL para apuntar este proyecto en él:
  14. git remote set-url origin http://mygithost:8080/git/our-splitted-module-repo
  15. Verifica que esto sea bueno: git remote -v
  16. Empuje los cambios hasta el repositorio remoto: git push
  17. Ve al repositorio remoto y comprueba que está todo allí.
  18. Repítelo para cualquier otra rama necesaria: git checkout branch2

Esto sigue los pasos 6-11 de github doc "Dividir una subcarpeta en un nuevo repositorio" para llevar el módulo a un nuevo repositorio.

Esto no le ahorrará espacio en su carpeta .git, pero conservará todo su historial de cambios para esos archivos, incluso a través de renombrados. Y puede que esto no valga la pena si no se pierde "mucha" historia, etc. ¡Pero al menos está garantizado que no perderá compromisos más antiguos!


Recomiendo la guía de GitHub para dividir las subcarpetas en un nuevo repositorio . Los pasos son similares a los de la respuesta de Paul , pero sus instrucciones me parecieron más fáciles de entender.

He modificado las instrucciones para que soliciten un repositorio local, en lugar de uno alojado en GitHub.

División de una subcarpeta en un nuevo repositorio

  1. Abrir Git Bash.

  2. Cambie el directorio de trabajo actual a la ubicación donde desea crear su nuevo repositorio.

  3. Clone el repositorio que contiene la subcarpeta.

git clone OLD-REPOSITORY-FOLDER NEW-REPOSITORY-FOLDER

  1. Cambie el directorio de trabajo actual a su repositorio clonado.

cd REPOSITORY-NAME

  1. Para filtrar la subcarpeta del resto de los archivos en el repositorio, ejecute git filter-branch , proporcionando esta información:
    • FOLDER-NAME : la carpeta dentro de su proyecto del que desea crear un repositorio separado.
      • Consejo: los usuarios de Windows deben usar / para delimitar carpetas.
    • BRANCH-NAME : la rama predeterminada para su proyecto actual, por ejemplo, master o gh-pages .

git filter-branch --prune-empty --subdirectory-filter FOLDER-NAME BRANCH-NAME # Filter the specified branch in your directory and remove empty commits Rewrite 48dc599c80e20527ed902928085e7861e6b3cbe6 (89/89) Ref ''refs/heads/BRANCH-NAME'' was rewritten


Tenía exactamente este problema, pero todas las soluciones estándar basadas en git filter-branch eran extremadamente lentas. Si tienes un pequeño repositorio, entonces esto puede no ser un problema, fue para mí. Escribí otro programa de filtrado de git basado en libgit2 que, como primer paso, crea ramas para cada filtrado del repositorio principal y luego los empuja a limpiar repositorios como el siguiente paso. En mi repositorio (500Mb 100000 confirmaciones) los métodos estándar de rama-filtro de git tomaron días. Mi programa toma minutos para hacer el mismo filtrado.

Tiene el fabuloso nombre de git_filter y vive aquí:

https://github.com/slobobaby/git_filter

en GitHub.

Espero que sea de utilidad para alguien.


Utilice este comando de filtro para eliminar un subdirectorio, a la vez que conserva sus etiquetas y ramas:

git filter-branch --index-filter / "git rm -r -f --cached --ignore-unmatch DIR" --prune-empty / --tag-name-filter cat -- --all


Edición: Bash script añadido.

Las respuestas dadas aquí funcionaron solo parcialmente para mí; Muchos archivos grandes permanecieron en el caché. Lo que finalmente funcionó (después de horas en #git en freenode):

git clone --no-hardlinks file:///SOURCE /tmp/blubb cd blubb git filter-branch --subdirectory-filter ./PATH_TO_EXTRACT --prune-empty --tag-name-filter cat -- --all git clone file:///tmp/blubb/ /tmp/blooh cd /tmp/blooh git reflog expire --expire=now --all git repack -ad git gc --prune=now

Con las soluciones anteriores, el tamaño del repositorio era de alrededor de 100 MB. Éste lo bajó a 1.7 MB. Tal vez ayuda a alguien :)

La siguiente secuencia de comandos bash automatiza la tarea:

!/bin/bash if (( $# < 3 )) then echo "Usage: $0 </path/to/repo/> <directory/to/extract/> <newName>" echo echo "Example: $0 /Projects/42.git first/answer/ firstAnswer" exit 1 fi clone=/tmp/${3}Clone newN=/tmp/${3} git clone --no-hardlinks file://$1 ${clone} cd ${clone} git filter-branch --subdirectory-filter $2 --prune-empty --tag-name-filter cat -- --all git clone file://${clone} ${newN} cd ${newN} git reflog expire --expire=now --all git repack -ad git gc --prune=now



Actualización : este proceso es tan común, que el equipo de git lo hizo mucho más simple con una nueva herramienta, git subtree . Vea aquí: Separe (mueva) el subdirectorio en un repositorio Git separado

Desea clonar su repositorio y luego usar git filter-branch para marcar todo, excepto el subdirectorio que desea en su nuevo repositorio para ser recogido en la basura.

  1. Para clonar tu repositorio local:

    git clone /XYZ /ABC

    (Nota: el repositorio se clonará utilizando enlaces físicos, pero eso no es un problema, ya que los archivos enlazados no se modificarán en sí mismos; se crearán nuevos).

  2. Ahora, conservemos las ramas interesantes que también queremos reescribir, y luego eliminemos el origen para evitar empujar allí y asegurarnos de que el origen no haga referencia a las confirmaciones antiguas:

    cd /ABC for i in branch1 br2 br3; do git branch -t $i origin/$i; done git remote rm origin

    o para todas las sucursales remotas:

    cd /ABC for i in $(git branch -r | sed "s/.*origin////"); do git branch -t $i origin/$i; done git remote rm origin

  3. Ahora es posible que también desee eliminar las etiquetas que no tienen relación con el subproyecto; También puedes hacerlo más tarde, pero es posible que tengas que podar tu repositorio nuevamente. No lo hice y obtuve una WARNING: Ref ''refs/tags/v0.1'' is unchanged para todas las etiquetas (ya que no estaban relacionadas con el subproyecto); Además, después de eliminar dichas etiquetas, se reclamará más espacio. Aparentemente, git filter-branch debería poder reescribir otras etiquetas, pero no pude verificar esto. Si desea eliminar todas las etiquetas, use git tag -l | xargs git tag -d git tag -l | xargs git tag -d .

  4. Luego use filter-branch y reinicie para excluir los otros archivos, para que puedan ser podados. También agreguemos --tag-name-filter cat --prune-empty para eliminar las confirmaciones vacías y reescribir las etiquetas (tenga en cuenta que esto tendrá que eliminar su firma):

    git filter-branch --tag-name-filter cat --prune-empty --subdirectory-filter ABC -- --all

    o alternativamente, para volver a escribir la rama HEAD e ignorar las etiquetas y otras ramas:

    git filter-branch --tag-name-filter cat --prune-empty --subdirectory-filter ABC HEAD

  5. Luego borre los respaldos de respaldo para que el espacio pueda ser realmente reclamado (aunque ahora la operación es destructiva)

    git reset --hard git for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git update-ref -d git reflog expire --expire=now --all git gc --aggressive --prune=now

    y ahora tiene un repositorio local de git del subdirectorio ABC con todo su historial conservado.

Nota: Para la mayoría de los usos, git filter-branch debería tener el parámetro agregado -- --all . Sí, eso es realmente - - espacio - - all . Este debe ser el último parámetro para el comando. Como descubrió Matli, esto mantiene las ramas y etiquetas del proyecto incluidas en el nuevo repositorio.

Edición: se incorporaron varias sugerencias de los comentarios a continuación para asegurarse, por ejemplo, de que el repositorio está realmente reducido (lo que no siempre fue así antes).


La respuesta de Paul crea un nuevo repositorio que contiene / ABC, pero no elimina / ABC desde / XYZ. El siguiente comando eliminará / ABC desde / XYZ:

git filter-branch --tree-filter "rm -rf ABC" --prune-empty HEAD

Por supuesto, pruébelo primero en un repositorio de ''clone --no-hardlinks'', y sígalo con los comandos reset, gc y prune de Paul.


Pon esto en tu gitconfig:

reduce-to-subfolder = !sh -c ''git filter-branch --tag-name-filter cat --prune-empty --subdirectory-filter cookbooks/unicorn HEAD && git reset --hard && git for-each-ref refs/original/ | cut -f 2 | xargs -n 1 git update-ref -d && git reflog expire --expire=now --all && git gc --aggressive --prune=now && git remote rm origin''


Estoy seguro de que el subárbol de git está bien y es maravilloso, pero mis subdirectorios del código administrado de git que quería mover estaban en eclipse. Así que si estás usando egit, es muy fácil. Tome el proyecto que desea mover y equipo-> desconéctelo, y luego equipo-> compártelo en la nueva ubicación. Por defecto, intentará utilizar la ubicación de repositorio anterior, pero puede desmarcar la selección de uso existente y elegir el nuevo lugar para moverla. Todos saludan egit.