Esta respuesta proporciona comandos interesantes basados git am
y presentados usando ejemplos, paso a paso.
Objetivo
- Desea mover algunos o todos los archivos de un repositorio a otro.
- Quieres mantener su historia.
- Pero no te importa mantener etiquetas y ramas.
- Acepta un historial limitado para archivos renombrados (y archivos en directorios renombrados).
Procedimiento
- Extraiga el historial en formato de correo electrónico utilizando
git log --pretty=email -p --reverse --full-index --binary
- Reorganice el árbol de archivos y actualice el cambio de nombre de archivo en el historial [opcional]
- Aplicar nuevo historial usando
git am
1. Extraiga el historial en formato de correo electrónico
Ejemplo: historia Extracto de file3
, file4
yfile5
my_repo
├── dirA
│ ├── file1
│ └── file2
├── dirB ^
│ ├── subdir | To be moved
│ │ ├── file3 | with history
│ │ └── file4 |
│ └── file5 v
└── dirC
├── file6
└── file7
Limpie el destino del directorio temporal
export historydir=/tmp/mail/dir # Absolute path
rm -rf "$historydir" # Caution when cleaning
Limpia tu fuente de repositorio
git commit ... # Commit your working files
rm .gitignore # Disable gitignore
git clean -n # Simulate removal
git clean -f # Remove untracked file
git checkout .gitignore # Restore gitignore
Extraiga el historial de cada archivo en formato de correo electrónico
cd my_repo/dirB
find -name .git -prune -o -type d -o -exec bash -c 'mkdir -p "$historydir/${0%/*}" && git log --pretty=email -p --stat --reverse --full-index --binary -- "$0" > "$historydir/$0"' {} ';'
Lamentablemente opción --follow
o --find-copies-harder
no se puede combinar con --reverse
. Es por eso que el historial se corta cuando se cambia el nombre del archivo (o cuando se cambia el nombre de un directorio principal).
Después: historial temporal en formato de correo electrónico
/tmp/mail/dir
├── subdir
│ ├── file3
│ └── file4
└── file5
2. Reorganice el árbol de archivos y actualice el cambio de nombre de archivo en el historial [opcional]
Suponga que desea mover estos tres archivos en este otro repositorio (puede ser el mismo repositorio).
my_other_repo
├── dirF
│ ├── file55
│ └── file56
├── dirB # New tree
│ ├── dirB1 # was subdir
│ │ ├── file33 # was file3
│ │ └── file44 # was file4
│ └── dirB2 # new dir
│ └── file5 # = file5
└── dirH
└── file77
Por lo tanto, reorganice sus archivos:
cd /tmp/mail/dir
mkdir dirB
mv subdir dirB/dirB1
mv dirB/dirB1/file3 dirB/dirB1/file33
mv dirB/dirB1/file4 dirB/dirB1/file44
mkdir dirB/dirB2
mv file5 dirB/dirB2
Tu historial temporal es ahora:
/tmp/mail/dir
└── dirB
├── dirB1
│ ├── file33
│ └── file44
└── dirB2
└── file5
Cambie también los nombres de archivo dentro del historial:
cd "$historydir"
find * -type f -exec bash -c 'sed "/^diff --git a\|^--- a\|^+++ b/s:\( [ab]\)/[^ ]*:\1/$0:g" -i "$0"' {} ';'
Nota: Esto reescribe el historial para reflejar el cambio de ruta y nombre de archivo.
(es decir, el cambio de la nueva ubicación / nombre dentro del nuevo repositorio)
3. Aplicar nuevo historial
Su otro repositorio es:
my_other_repo
├── dirF
│ ├── file55
│ └── file56
└── dirH
└── file77
Aplicar confirmaciones de archivos de historial temporales:
cd my_other_repo
find "$historydir" -type f -exec cat {} + | git am
Su otro repositorio es ahora:
my_other_repo
├── dirF
│ ├── file55
│ └── file56
├── dirB ^
│ ├── dirB1 | New files
│ │ ├── file33 | with
│ │ └── file44 | history
│ └── dirB2 | kept
│ └── file5 v
└── dirH
└── file77
Use git status
para ver la cantidad de confirmaciones listas para ser empujadas :-)
Nota: Como el historial se ha reescrito para reflejar la ruta y el cambio de nombre de archivo:
(es decir, en comparación con la ubicación / nombre dentro del repositorio anterior)
- No es necesario
git mv
cambiar la ubicación / nombre de archivo.
- No es necesario
git log --follow
acceder al historial completo.
Truco adicional: detecte archivos renombrados / movidos dentro de su repositorio
Para enumerar los archivos que han cambiado de nombre:
find -name .git -prune -o -exec git log --pretty=tformat:'' --numstat --follow {} ';' | grep '=>'
Más personalizaciones: puede completar el comando git log
con las opciones --find-copies-harder
o --reverse
. También puede eliminar las dos primeras columnas utilizando cut -f3-
y agrupando el patrón completo '{. * =>. *}'.
find -name .git -prune -o -exec git log --pretty=tformat:'' --numstat --follow --find-copies-harder --reverse {} ';' | cut -f3- | grep '{.* => .*}'