subir - git divide el repositorio por subcarpeta y conserva todas las ramas antiguas
omitir carpetas git (2)
Respuesta corta
git filter-branch
ofrece exactamente la funcionalidad que desea. Con la opción --subdirectory-filter
puede crear un nuevo conjunto de confirmaciones donde el contenido de subDirectory
encuentra en la raíz del directorio.
git filter-branch --prune-empty --subdirectory-filter subDirectory -- --branches
Recorrido
El siguiente es un ejemplo para realizar esto de una manera segura. dir1
realizar esto para cada subdirectorio que se aislará en su propio repositorio, en este caso dir1
.
Primero clona tu repositorio para mantener los cambios aislados:
git clone yourRemote dir1Clone
cd dir1Clone
Para preparar el repositorio clonado, recrearemos todas las ramas remotas como locales. Nos saltamos el que comienza con *
ya que esa es la rama actual, que en este caso sería de lectura (no branch)
ya que estamos en un estado sin cabeza:
# move to a headless state
# in order to delete all branches without issues
git checkout --detach
# delete all branches
git branch | grep --invert-match "*" | xargs git branch -D
Para recrear todas las sucursales remotas localmente, veremos los resultados de git branch --remotes
. Nos saltamos los que contienen ->
ya que no son ramas:
# get all local branches for remote
git branch --remotes --no-color | grep --invert-match "/->" | while read remote; do
git checkout --track "$remote"
done
# remove remote and remote branches
git remote remove origin
Finalmente ejecute el comando filter-branch
. Esto creará nuevas confirmaciones con todas las confirmaciones que tocan el subdirectorio dir1
. Todas las ramas que también toquen este subdirectorio se actualizarán. La salida mostrará una lista de todas las referencias que no se actualizaron, como es el caso de las sucursales que no tocan dir1
en absoluto.
# Isolate dir1 and recreate branches
# --prune-empty removes all commits that do not modify dir1
# -- --all updates all existing references, which is all existing branches
git filter-branch --prune-empty --subdirectory-filter dir1 -- --all
Después de esto, tendrá un nuevo conjunto de confirmaciones que tienen dir1
en la raíz del repositorio. Solo agregue su control remoto para enviar los nuevos compromisos, o use estos como un nuevo repositorio por completo.
Como último paso adicional si te importa el tamaño del repositorio:
Incluso si todas las sucursales donde se actualizó su repositorio seguirán teniendo todos los objetos del repositorio original, solo se podrá acceder a ellos a través de los registros de ref. Si quieres soltar estos, lee cómo hacer basura recolecta confirmaciones.
Algunos recursos adicionales:
Tengo un repositorio git con 2 directorios y varias sucursales, quiero dividirlas y crear todas las sucursales
`-- Big-repo
|-- dir1
`-- dir2
Branches : branch1, branch2, branch3 ...
Lo que quiero
Quiero dividir dir1 y dir2 como dos repositorios separados y retener las ramas branch1, branch2 ... en ambos repositorios.
dir1
Branches : branch1, branch2, branch3 ...
dir2
Branches : branch1, branch2, branch3 ...
Lo que intenté:
Soy capaz de dividirlos en 2 repos utilizando
git subtree split -P dir1 -b dir1-only
git subtree split -P dir2 -b dir2-only
Pero, no está creando ninguna rama después de la separación.
Para obtener todas las ramas:
git checkout branch1 (in Big-repo)
git subtree split -p dir1 -b dir1-branch1
git checkout branch2 (in Big-repo)
git subtree split -p dir1 -b dir1-branch2
And push these branches to newly created repo.
¿Esto implica un mayor esfuerzo manual y estoy seguro de que podría haber una manera rápida de lograrlo?
¿¿¿Algunas ideas???
Este script hace el trabajo por mí:
#!/bin/bash
set -e
if [ -z "$3" ]; then
echo "usage: $0 /full/path/to/repository path/to/splitfolder/from/repository/root new_origin"
exit
fi
repoDir=$1
folder=$2
newOrigin=$3
cd $repoDir
git checkout --detach
git branch | grep --invert-match "*" | xargs git branch -D
for remote in `git branch --remotes | grep --invert-match "/->"`
do
git checkout --track $remote
git add -vA *
git commit -vam "Changes from $remote" || true
done
git remote remove origin
git filter-branch --prune-empty --subdirectory-filter $folder -- --all
#prune old objects
rm -rf .git/refs/original/*
git reflog expire --all --expire-unreachable=0
git repack -A -d
git prune
#upload to new remote
git remote add origin $newOrigin
git push origin master
for branch in `git branch | grep -v ''/*''`
do
git push origin $branch
done