繁体   English   中英

Git:手动合并未检测到的重命名中的更改

[英]Git: Manually merge changes in an undetected rename

这个问题使用Git 2.7.0.windows.1 ,因此某些git命令可能已过时。

如果我的git merge命令没有检测到重命名的文件,我如何告诉git手动合并应该是单个文件的两个文件中的更改,而无需重新开始合并并使用较低的重命名阈值?

复制步骤:

git init
echo "//Hello world!" > hw.h
git add . && git commit -m "Initial commit"
git checkout -b someBranch
mv hw.h hw.hpp
echo "//Foobar" > hw.hpp
git add . && git commit -m "Change hw to HPP & change content"
git checkout master
echo "//Boofar" > hw.h
git add . && git commit -m "Change content of hw"
git merge -X rename-threshold=100% someBranch

您将获得合并冲突,但不会有冲突的块。 也就是说,您应该获得的唯一冲突/错误是:

CONFLICT (modify/delete): hw.h deleted in branchB and modified in HEAD. Version HEAD of hw.h left in tree.
Automatic merge failed; fix conflicts and then commit the result.

git status --porcelain将显示:

UD hw.h
A  hw.hpp

通常,合并时,最好将检测重命名的阈值设置得足够低,以至于无法检测到重命名。 例如, 有人建议5% 就我而言,我正在进行大量合并(> 1000个文件和大约900万个LOC),并且我不得不将重命名阈值提高到足够高的水平,以避免出现任何“误报”。 实际降低了百分之一,而且我得到了大量错误检测到的重命名(我知道,重复的代码很烂)。 以我最终使用的价值,我只得到了很少的错过的重命名,这似乎是一个更好的选择。

TL; DR降低重命名阈值不是我的选择; 如何在不开始合并的情况下告诉git将hw.hhw.hpp视为单个文件(有冲突),而不是如上所述的两个文件?

用于此的工具有些笨拙,但它们那里。

您需要确保合并本身在提交之前停止。 您的情况会自动发生。 对于棘手的合并,Git认为它可以正确执行,但实际上并没有,您可以添加--no-commit ,但这会影响接下来的几个步骤。 我们暂时将忽略该问题。

接下来,您需要获取该文件的所有三个版本。 由于Git因冲突而停止,因此我们处于良好状态:这三个版本均可通过索引访问。 请记住,我们关心的三个版本是merge base ,-- --ours--theirs

如果Git 正确检测到重命名,则所有三个版本将以单个名称在索引中。 既然没有,他们就不是:我们需要两个名字。 (在“ Git认为它正确合并的情况下”,该文件的合并基础版本根本不在索引中,我们必须以其他方式检索它。)在这种情况下,这两个名称是hw.hhw.hpp ,所以现在我们这样做:

$ git show :1:hw.h > hw.h.base    # extract base version
$ git show :2:hw.h > hw.h         # extract ours
$ mv hw.hpp hw.h.theirs           # move theirs into place

(重命名并不是严格必须的,它只是为了使它们保持整洁并得到很好的说明。)

现在我们要用git merge-file

$ git merge-file hw.h hw.h.base hw.h.theirs

这将使用您配置的merge.conflictStyle以便合并文件中的内容与您期望的一样,除了冲突行上的标签略有不同。 我设置了diff3 ,所以我得到:

$ cat hw.h
<<<<<<< hw.h
//Boofar
||||||| hw.h.base
//Hello world!
=======
//Foobar
>>>>>>> hw.h.theirs

现在,您可以解决此像往常一样, rm额外.base.theirs文件, git add最终的结果, git rm --cached hw.hpp ,和git commit (这取决于您何时使用git rm --cached hw.hpp :在提交之前的任何时间都可以安全地执行此操作,但是一旦完成,您将无法再从索引中获取“它们的”;请参见下文。)

注意,“我们的”和“他们的”版本也可以通过git show HEAD:pathgit show MERGE_HEAD:path 为了获得没有索引的基本版本,我们必须运行git merge-base HEAD MERGE_HEAD来查找其哈希ID(然后假设还有一个合并基数1 ),以及git show <hash>:path 如果Git认为它正确完成了合并,这就是我们必须做的。

还要注意,如果您确实想(我想这只有在您想要使用其他一些需要它的工具时才是对的),您可以使用git update-index来随机整理git update-index中的条目,移动hw.hpp入插槽,3 hw.h ,以免被显示为“他们”,并显示了以这种方式git status 对于此特定示例:

 $ printf '100644 bbda177a6ecfe285153467ff8fd332de5ecfb2f8 3\thw.h' |
     git update-index --index-info

这里的哈希值是从哪里来的git ls-files --stage ,是哈希hw.hpp (您需要执行第二步来删除hw.hpp索引条目。)


1使用git merge-base --all查找所有合并库。 如果有多个,则可以任意选择一个(这是-s resolve作用),也可以尝试将所有合并基础合并为虚拟合并基础 要合并两个合并库,您可以找到它们自己的合并库,并使用该合并库合并两个库,就好像它们是分支提示一样。 根据需要进行递归和迭代-这是Git使用默认的-s recursive策略所做的-直到您拥有该文件的单个合并基础版本。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM