Git是否会记录先前的合并冲突?

7

我希望查看存储库的历史记录,看看过去发生了哪些类型的合并冲突。

我尝试使用git log --merges,但那只显示成功的合并。


1
我认为它不会生效,除非你启用git-rerere - melpomene
在 Git 2.36 (Q2 2022) 中,git log --remerge-diff 命令将会展示你在合并冲突解决中所做的工作!请参考我在另一个问题中的回答 - VonC
4个回答

8

Git不记录合并冲突,除非你启用了rerere,但它记录了大部分必要的信息以重新创建它们。你可以编写一个脚本来重新创建合并冲突,但需要注意一些问题... Git不会记录你用于解决合并的策略,因此你需要希望默认策略是明智的选择,或者在你的仓库上进行一些调整才能使其正常工作。

工作原理

你可以使用rev-list枚举合并:

git rev-list --parents --min-parents=2 --all

这种方式比git log更好,因为输出内容适合脚本解析。这将产生一个合并提交的列表,每个提交独占一行。子提交是第一个哈希值,其余哈希值是父提交。例如:

28171e725cc93e8cb85194931e7138c31f980a43 20af81cf6388026ecf0de4eec8783e7a38905ccd 2d77896f5fcc1a9b09f4f099aa6e945e8da86410

这里的合并是在20af和2d77之间进行的。

检查第一个父级,在分离的头部:

git checkout -q --detach 20af81cf6388026ecf0de4eec8783e7a38905ccd

接着合并剩余的父节点:

git merge -q --no-commit --no-ff 2d77896f5fcc1a9b09f4f099aa6e945e8da86410
merge 的状态码如果有冲突会是1,你可以检查一下。如果存在合并冲突,你将会看到在漆器状态中带有 UU 的文件:
git status --porcelain

您可以中止合并以重置到一个状态,使您可以使用存储库:

git merge --abort

脚本

我已经将这个示例转化为脚本。由于它会运行一堆git checkoutgit merge命令,所以必须在一个原始的存储库上运行脚本。

https://gist.github.com/depp/f1838cf4559f9cde74b9d3052b8abbb0

该脚本将使用默认策略重试历史中的每个合并,并报告冲突文件。

如果需要,可以轻松扩展脚本以复制出冲突文件,以便您查看冲突。


@crashmstr:在Git中,工作副本(通常)本身也是一个仓库。这在裸仓库中不起作用,并且您不应该有本地未提交的更改。 - Dietrich Epp
一个非常类似的脚本是 rerere-train,它在 git.git 存储库本身中可用: https://github.com/git/git/blob/master/contrib/rerere-train.sh - A.H.

2

1

虽然不容易,但如果有需要的话您可以编写一个脚本...

您可以使用git log来查找所有合并提交——假设您留下了自动消息,或者使用一个明智而始终相同的信息。例如:

git log --all --oneline --graph --decorate会生成一个很好的仓库树形视图——例如:

*   a1a9bde (HEAD -> TESTER) Merge branch 'test' into TESTER
|\
| * 2ff3965 (test) updated
| * 12af0b0 s
* | eb9ab80 updated
* |   bec65ad (master) Merge branch 'master' of d:\software\sandpit\git-test
|\ \
| * \   595bff6 Merge branch 'master' of d:\software\gitRepos\git-test
| |\ \
| | * | 77d69c7 new file
| | |/
   :

但是对于脚本编写,只需使用git log --oneline --all命令:

a1a9bde Merge branch 'test' into TESTER      <----- LETS LOOK AT THIS MERGE...
eb9ab80 updated
2ff3965 updated
bec65ad Merge branch 'master' of d:\software\sandpit\git-test
8a73cd1 updated test1
58080f2 new file
819226c new file
e122cc6 file for merge back to master
49acb0b file added in branch
a262470 yet another file
12af0b0 s

或者只获取哈希列表:git log --oneline --all | grep "Merge branch" | awk '{print $1}'

a1a9bde
bec65ad

更新 1

或者如 Dietrich Epp (几乎)建议的那样使用 git rev-list --min-parents=2 a1a9bde - 这会给出具有 2 个父级的任何提交的完整哈希值 - 很棒的 Dietrich Epp!

更新 1 - 结束

现在循环遍历这些哈希值,例如从此处使用第一个:a1a9bde

您可以像这样获取父哈希值:git show --format="%P" 595bff6 - 这将产生:

eb9ab8029e6951f68a9c1008bb8611444d31528d 2ff3965b9aa1e6c49c82127e5f08199796a40780

因此,现在您可以通过模拟合并来运行:

  • 检出第一个哈希值:git checkout eb9ab8029e6951f68a9c1008bb8611444d31528d -B merge_test - 这将第一个哈希值检出到名为merge_test的分支上(并替换任何以前同名的分支)

  • 合并第二个哈希值(干运行):git merge --no-commit --no-ff 2ff3965b9aa1e6c49c82127e5f08199796a40780

  • 使用git status | grep "both modified"查看冲突 - 返回:
     both modified:   testfile1.txt     <---- THIS FILE IS A CONFLICT
  • 现在你需要做你需要做的事情,最后用git merge --abort清理一下即可。

总之,虽然有点痛苦,但这可以很容易地编写成脚本,我已经提供了相应的命令,但我没有动力将其写成脚本... :o


1
你应该使用 git rev-parse --min-parents=2 而不是 git log | grep,因为并非所有合并提交都具有相同的格式。 - Dietrich Epp
@DietrichEpp 不错的输入:)虽然让我困惑了一段时间,我想你是指 rev-list - 已经更新啦:) - code_fodder

1

对于首次快速概览,您可以使用:

git log --merges --cc --all

--cc选项是(来自git help log):

-c
   With this option, diff output for a merge commit shows the
   differences from each of the parents to the merge result
   simultaneously instead of showing pairwise diff between a parent
   and the result one at a time. Furthermore, it lists only files
   which were modified from all parents.

--cc
   This flag implies the -c option and further compresses the patch
   output by omitting uninteresting hunks whose contents in the
   parents have only two variants and the merge result picks one of
   them without modification.

这将展示冲突,但 - AFAICT - 更多关于“近似冲突”的信息。

太好了!有了这个,你可以进行冲突猎手并找到需要审查的冲突(通过重新创建冲突并比较合并结果)。 - Edward Anderson
1
@EdwardAnderson现在你可以要求Git重新创建冲突并比较合并结果。请参阅VonC在这里的回答 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接