Git 是否保留过去合并冲突的记录?

Does Git keep a record of past merge conflicts?

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

我试过使用 git log --merges 但这似乎表明合并成功。

我认为你可以从 git-rerere 中受益,结合之前关于训练它的问题:

我认为实际存放位置在.git/rr-cache,但我没看过也不知道里面有什么。

Git 不记录合并冲突,除非您启用了 rerere,但它确实记录了重新创建冲突所需的大部分信息。您可以编写一个脚本来重新创建合并冲突,但有一些注意事项... Git 没有记录您用于解决合并的合并策略,因此您将不得不希望默认策略是明智的选择,或进行一些调整以使其适用于您的存储库。

工作原理

您可以枚举合并 rev-list:

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

这优于 git log,因为输出适合脚本解析。这将生成一个合并提交列表,每行一个。 child 提交是第一个哈希,其余哈希是 parent。例如,

28171e725cc93e8cb85194931e7138c31f980a43 20af81cf6388026ecf0de4eec8783e7a38905ccd 2d77896f5fcc1a9b09f4f099aa6e945e8da86410

在这里,合并是在20af和2d77之间。

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

git checkout -q --detach 20af81cf6388026ecf0de4eec8783e7a38905ccd

然后合并剩下的parents:

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

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

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

不容易..但是如果你需要的话你可以编写一个脚本...

您可以使用 git 日志查找所有 merge-commits - 假设您保留了自动消息,或者使用(希望)始终相同的明智消息。例如:

git log --all --oneline --graph --decorate 产生了不错的 tree-view 回购 - 例如:

*   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 }':

a1a9bde
bec65ad

更新 1

Dietrich Epp(几乎)建议使用 git rev-list --min-parents=2 a1a9bde - 这给出了具有 2 parents 的任何提交的完整哈希 - 很好 Dietrich Epp!

更新 1 - 结束

现在遍历这些散列,例如从这里开始使用第一个:a1a9bde

您可以获得 parent 散列,例如:git show --format="%P" 595bff6 - 这个产量:

eb9ab8029e6951f68a9c1008bb8611444d31528d 2ff3965b9aa1e6c49c82127e5f08199796a40780

所以现在您可以 运行 mock-merge 通过:

  • 签出第一个散列: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

如需快速概览,您可以使用:

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 - "near conflicts"。