合并时,Git 需要什么配置/选项才能将更改应用于所有副本?

合并时,Git 需要什么配置/选项才能将更改应用于所有副本?

Git(至少从 2.11.1 开始)不跟踪存储库中的复制/重命名/移动。但是,可以指示它在之后分析提交,但这似乎只适用于日志,而不是合并命令。使用分支时,可能需要将对原始文件所做的更改应用于所有副本,因此合并能够以与日志相同的方式分析两个修订之间的所有提交是有意义的。不幸的是,我找不到正确的参数/配置选项来实现这一点。

看看这个例子:

# 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。看起来它只会随机选择一个文件(但可重现)。

我究竟做错了什么?

相关内容