Git (al menos a partir del 2.11.1) no rastrea copias / renombra / mueve en el repositorio. Sin embargo, se le puede indicar que analice las confirmaciones posteriormente, pero parece que esto solo funciona correctamente con los comandos de registro, no de combinación. Cuando se trabaja con sucursales, puede ser necesario aplicar los cambios que se han realizado en un archivo original a todas las copias, por lo que tendría sentido que una fusión pudiera analizar todas las confirmaciones entre dos revisiones de la misma manera que logre haciéndolo. Desafortunadamente, no puedo encontrar los parámetros / opciones de configuración correctos para hacer que esto funcione.
Vea este ejemplo:
# prepare repository
git init git-copies
cd git-copies
git config --local --add log.follow true
# add initial file
echo first >initial.txt
git add initial.txt
git commit -m 'initial'
# create new branch
git checkout -b copies
# commit first copy
cp initial.txt copy1.txt
git add copy1.txt
git commit -m 'copy 1'
# commit second copy
cp initial.txt copy2.txt
git add copy2.txt
git commit -m 'copy 2'
# rename first copy
mv copy1.txt copy1-renamed.txt
git add copy1-renamed.txt copy1.txt
# at this point git status would show an informational client-local status "renamed" (not recorded in repo AFAIK)
git commit -m 'renamed copy 1'
# create further copies of previously copied files
cp copy1-renamed.txt copy1-renamed-copy1.txt
cp copy1-renamed.txt copy1-renamed-copy2.txt
cp copy2.txt copy2-copy1.txt
cp copy2.txt copy2-copy2.txt
git add copy1-renamed-copy1.txt copy1-renamed-copy2.txt copy2-copy1.txt copy2-copy2.txt
git commit -m 'copies on second level'
# modify each second level second copy
echo 'altered 1' >copy1-renamed-copy2.txt
echo 'altered 2' >copy2-copy2.txt
git add copy1-renamed-copy2.txt copy2-copy2.txt
git commit -m 'altered second level second copies'
# rename the initial file (omit for some extra fun, see below)
mv initial.txt initial-renamed.txt
git add initial.txt initial-renamed.txt
git commit -m 'renamed initial file'
# create a new copy of the renamed initial file (omit for some extra fun, see below)
cp initial-renamed.txt initial-renamed-copy.txt
git add initial-renamed-copy.txt
git commit -m 'copied renamed initial file'
# switch back to master branch and alter initial file
git checkout master
echo changed >initial.txt
git add initial.txt
git commit -m 'changed initial file'
# switch to copies branch again
git checkout copies
Compruebe qué git reconoció como copias:
for file in *.txt; do echo " -- $file"; git --no-pager log --oneline $file; echo; done
-- copy1-renamed-copy1.txt
71ad85b copies on second level
c9266f9 renamed copy 1
d3a0006 copy 1
a7ff313 initial
-- copy1-renamed-copy2.txt
f5e9a0e altered second level second copies
71ad85b copies on second level
c9266f9 renamed copy 1
d3a0006 copy 1
a7ff313 initial
-- copy1-renamed.txt
c9266f9 renamed copy 1
d3a0006 copy 1
a7ff313 initial
-- copy2-copy1.txt
71ad85b copies on second level
c9266f9 renamed copy 1
d3a0006 copy 1
a7ff313 initial
-- copy2-copy2.txt
f5e9a0e altered second level second copies
71ad85b copies on second level
c9266f9 renamed copy 1
d3a0006 copy 1
a7ff313 initial
-- copy2.txt
f66887f copy 2
d3a0006 copy 1
a7ff313 initial
-- initial-renamed-copy.txt
68a2e29 copied renamed initial file
71ad85b copies on second level
c9266f9 renamed copy 1
d3a0006 copy 1
a7ff313 initial
-- initial-renamed.txt
0d89d9b renamed initial file
a7ff313 initial
Si bien Git no distingue las copias textuales entre el primer y el segundo nivel del archivo inicial (como se espera), confunde initial-renamed-copy.txt
Al ser una copia de un archivo de segundo nivel, sí reconoce que todos los archivos tienen el archivo inicialmente confirmado como un antepasado común. Básicamente, espero que una combinación aplique cambios a todos los archivos y emita un conflicto de combinación en las copias de segundo nivel que modificamos más adelante.
Vamos a fusionar
git merge --no-commit master
git status --short
Resultado: M copy1-renamed-copy1.txt
Eh Eso es inesperado de alguna manera ... Reiniciéramos e intentemos nuevamente con algunas opciones que (según entiendo el documentación ) debería poder ayudar:
git reset --hard
git merge --no-commit -s recursive -X patience -X find-renames master
git status --short
Resultado: M copy1-renamed-copy1.txt
Ehm ... Intentemos establecer los parámetros de configuración de renameLimit en algunos valores altos, ¿tal vez ese sea el problema?
git config --local --add diff.renameLimit 999999
git config --local --add merge.renameLimit 999999
git reset --hard
git merge --no-commit -s recursive -X patience -X find-renames master
git status --short
Resultado: M copy1-renamed-copy1.txt
Tristemente no...
Por cierto, renombrando initial.txt
Parece haber confundido mucho a Git. Si omite las dos confirmaciones que he marcado anteriormente, todavía solo obtendremos los cambios aplicados a un archivo, pero al menos el cambio se aplicará a initial.txt
. Parece que solo elegirá un archivo al azar (pero reproducible).
¿Qué estoy haciendo mal?