Que configuração / opção é necessária para o Git aplicar alterações a todas as cópias ao mesclar?

2

O Git (pelo menos a partir de 2.11.1) não rastreia cópias / renomeações / movimentações no repositório. No entanto, ele pode ser avisado para analisar commits depois, mas parece que isso só funciona corretamente com comandos log, e não merge. Ao trabalhar com ramificações, pode ser necessário aplicar as alterações feitas a um arquivo original em todas as cópias, portanto, faria sentido que uma mesclagem pudesse analisar todas as confirmações entre duas revisões da mesma maneira que o log é capaz de fazer. Fazendo. Infelizmente, não consigo encontrar os parâmetros corretos / opções de configuração para fazer isso funcionar.

Veja este exemplo:

# 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

Verifique o que o git reconheceu como cópias:

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

Enquanto o Git não consegue distinguir cópias íntegras entre o primeiro e o segundo nível do arquivo inicial (como é esperado) confunde initial-renamed-copy.txt com ser uma cópia de um arquivo de segundo nível ele realmente reconhece que todos os arquivos têm o arquivo inicialmente confirmado como um ancestral comum. Então, basicamente, eu esperaria uma mesclagem para aplicar alterações a todos os arquivos e emitir um conflito de mesclagem nas cópias de segundo nível que modificamos mais tarde.

Vamos mesclar:

git merge --no-commit master
git status --short

Resultado: M copy1-renamed-copy1.txt

Huh? Isso é inesperado de alguma forma ... Vamos redefinir e tentar novamente com algumas opções que (como eu entendo a documentação ) devem ser capaz de ajudar:

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 ... Vamos tentar configurar os parâmetros de configuração renameLimit para alguns valores altos, talvez esse seja o 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

Infelizmente não ...

A propósito, renomear initial.txt parece ter confundido muito o Git. Se você omitir os dois commits que marquei acima, continuaremos recebendo apenas as alterações aplicadas a um arquivo, mas pelo menos a alteração será aplicada a initial.txt . Parece que ele selecionará apenas um arquivo aleatoriamente (mas reproduzível).

O que estou fazendo de errado?

    
por Energiequant 20.02.2017 / 20:01

0 respostas

Tags