2

Git (по крайней мере, с 2.11.1) не отслеживает копии / переименования / перемещения в хранилище. Тем не менее, впоследствии можно сказать, что он анализирует коммиты, но кажется, что это правильно работает только с командами log, а не командами merge. При работе с ветками может потребоваться применить изменения, которые были внесены в исходный файл, ко всем копиям, поэтому будет иметь смысл, что объединение сможет анализировать все фиксации между двумя ревизиями таким же образом, как журнал способен Делать это. К сожалению, я не могу найти правильные параметры / параметры конфигурации, чтобы сделать эту работу.

Смотрите этот пример:

# 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

Проверьте, какие git распознаются как копии:

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

Хотя Git не может отличить дословные копии между первым и вторым уровнем от исходного файла (как и ожидалось), он путает initial-renamed-copy.txt с копией файла второго уровня, но он действительно распознает, что все файлы имеют изначально зафиксированный файл как общий предок. В общем, я ожидаю, что слияние применяет изменения ко всем файлам и вызовет конфликт слияния для копий второго уровня, которые мы изменили позже.

Давайте объединить:

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

Результат: M copy1-renamed-copy1.txt

А? Это как-то неожиданно ... Давайте сбросим и попробуем еще раз с некоторыми опциями, которые (как я понимаю в документации) должны быть в состоянии помочь:

git reset --hard
git merge --no-commit -s recursive -X patience -X find-renames master
git status --short

Результат: M copy1-renamed-copy1.txt

Эмм ... Давайте попробуем установить для параметров конфигурации renameLimit высокие значения, может быть в этом проблема?

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

Результат: M copy1-renamed-copy1.txt

К сожалению, нет ...

Кстати, переименование initial.txt похоже, сильно запутало Git. Если вы пропустите два коммита, которые я отмечал выше, мы все равно будем применять только изменения к одному файлу, но по крайней мере это изменение будет применено к initial.txt . Похоже, что он просто выберет один файл случайным образом (но воспроизводимый).

Что я делаю неправильно?

0