1

IntelliJ has very convenient Git log functionality for inspecting merge commit details (see screenshot below + https://www.jetbrains.com/help/idea/log-tab.html#changedFiles).

It shows "combined diff", a comparison of merge result to each of parent commits (#1, #2) - basically it is contents of git show merge_commit_sha -m

My questions:

  1. how can i precisely replicate combined diff for merge commit we see at #3 (resulting contents + parents contents for ALL files involved in merge), using just cli + vanilla git? can it be achieved with some fancy options of git diff or git show? i have a suspicion it might be smth like git diff --cc --combined-all-paths?

  2. how can i see historical info which particular files were conflicting during that merge (files which a person had to resolve)?

intellij git log

Max
  • 1,741
  • 3
  • 23
  • 40

1 Answers1

1

Per your previous comment, I proposed, to look at a merge commit (Git 2.36+, Q2 2022):

git log --remerge-diff <rev>^!

With ^! parent shorthand notion being:

The r1^! notation includes commit r1 but excludes all of its parents.
By itself, this notation denotes the single commit r1.

<rev> is a "revision", typically naming a commit object.
You would replace <rev> (including the < and >) with:

  • a commit SHA1
  • or a branch name ("refname")
  • @ (shortcut for HEAD)
  • ...

In every case, in the context of this question, <rev> must represent a merge commit, a commit with (most often) 2 parents.
That <rev> commit represent the result of the merge between the two parents.


How can I see historical info which particular files were conflicting during that merge (files which a person had to resolve)?

For that, you would need Git 2.38, Q3 2022:

# You can list the files with conflicts and why they are in conflicts:
git merge-tree --write-tree --no-messages branch1 branch2

# You can list the files with conflicts (just their names):
git merge-tree --write-tree --no-messages --name-only branch1 branch2

You would replace branch1 and branch2 by your commit <rev> parents:

git merge-tree --write-tree --no-messages --name-only <rev>^1 <rev>^2

After discussion, the OP is after 3 commands for a given merge_commit_sha:

  1. To see what person saw when he tried a merge, merge conflicted - as a big diff with non-conflicted + conflicted files - BEFORE person resolved any conflicts and made his merge commit

    git merge-tree --write-tree --no-messages --name-only merge_sha^1 merge_sha^2
    
  2. To see factual diff that happened during merge conflict resolution and merge commit (person may add some fixes or even new files)

    git show --diff-merges=dense-combined merge_sha
    
  3. to see a bulk change happened to repo with merge commit (merge commit change itself + all combined changes happened in 2 branches since the commit they diverged)

    git diff $(git merge-base merge_sha^1 merge_sha^2) merge_sha"
    

I would add also git diff AUTO_MERGE, with Git 2.42 (Q3 2023) documenting more pseudo-refs, including AUTO_MERGE.

See commit 982ff3a, commit 4fa1edb, commit b7dd54a, commit 1ef3c61, commit 6ec5f46, commit bc11bac (22 May 2023) by Philippe Blain (phil-blain).
(Merged by Junio C Hamano -- gitster -- in commit 0899beb, 20 Jun 2023)

Documentation: document AUTO_MERGE

Signed-off-by: Philippe Blain
Signed-off-by: Junio C Hamano

Since 5291828 ("merge-ort: write $GIT_DIR/AUTO_MERGE whenever we hit a conflict", 2021-03-20, Git v2.32.0-rc0 -- merge), when using the 'ort' merge strategy, the special ref AUTO_MERGE is written when a merge operation results in conflicts.
This ref points to a tree recording the conflicted state of the working tree and is very useful during conflict resolution.
However, this ref is not documented.

Add some documentation for AUTO_MERGE in git-diff(1), git-merge(1), gitrevisions(7) and in the user manual.

Also mention AUTO_MERGE in the "How to resolve conflicts" section, when mentioning 'git diff'(man).

Closes: https://github.com/gitgitgadget/git/issues/1471

git diff now includes in its man page:

A tree of interest is the one pointed to by the special ref AUTO_MERGE, which is written by the 'ort' merge strategy upon hitting merge conflicts (see git merge). Comparing the working tree with AUTO_MERGE shows changes you've made so far to resolve textual conflicts (see the examples below).

$ git diff AUTO_MERGE: Changes in the working tree you've made to resolve textual conflicts so far.

git merge now includes in its man page:

  1. A special ref AUTO_MERGE is written, pointing to a tree corresponding to the current content of the working tree (including conflict markers for textual conflicts).
    Note that this ref is only written when the 'ort' merge strategy is used (the default).

revisions now includes in its man page:

AUTO_MERGE:

records a tree object corresponding to the state the 'ort' merge strategy wrote to the working tree when a merge operation resulted in conflicts.

user-manual now includes in its man page:

When using the 'ort' merge strategy (the default), before updating the working tree with the result of the merge, Git writes a special ref named AUTO_MERGE reflecting the state of the tree it is about to write.

Conflicted paths with textual conflicts that could not be automatically merged are written to this tree with conflict markers, just as in the working tree.

AUTO_MERGE can thus be used with git diff to show the changes you've made so far to resolve conflicts.
Using the same example as above, after resolving the conflict we get:

$ git diff AUTO_MERGE
diff --git a/file.txt b/file.txt
index cd10406..8bf5ae7 100644
--- a/file.txt
b/file.txt
@@ -1,5 +1 @@
-<<<<<<< HEAD:file.txt
-Hello world
-=======
-Goodbye
->>>>>>> 77976da35a11db4580b80ae27e8d65caf5208086:file.txt
Goodbye world

Notice that the diff shows we deleted the conflict markers and both versions of the content line, and wrote "Goodbye world" instead.


The OP Max adds in the comments:

Actually I found out that git merge-base does not work properly when there were periodic merges into branch B from branch A before we finally merge B into A.

So it seems we can't find "changes brought to A in a final merge of B to A" using git merge-base in a general case.

See "Git: how to find commit hash where branch originated from".

VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • VonC, i ran `git merge-tree --write-tree --no-messages --name-only ^1 ^2` and i see, it does indeed give me conflicted file. but also some SHA that i don't see in my Git commits log in IntellJ, what could that SHA be? some internal stuff not getting to final commits log? – Max Jun 17 '23 at 15:02
  • @Max Not sure, which is why I mentioned the same command without `--name-only`: it can add conflict reasons. – VonC Jun 17 '23 at 15:04
  • ah, ok. i've never used `merge-tree`, maybe that is a sort of "dry run" merge, kind of "modelling" a real merge (?) - hense those "virtual" SHAs. i need to read more on it. – Max Jun 17 '23 at 15:10
  • 1
    @Max True, I have edited the answer to make clear that `` here is the merge commit. By using `^1 ^2`, you are forcing Git to "re-simulate" the merge between its two parents. – VonC Jun 17 '23 at 15:12
  • cool. i'll piggyback on your advanced git knowledge :) . imagine i want to explore situation that existed for person when he was resolving merge even more further... say, we have "merge base" commit sha=000, then last commit in branch1 before merge sha=111, and last commit in branch2 sha=222. i want to "simulate" the merge person was facing and see the combined changes (including conflicts) of that "virtual" merge. imagine smth similar to "git merge-tree --write-tree" but spitting kind of a diff to us... – Max Jun 17 '23 at 15:23
  • @Max All you need are the parents of the merge commit. In your case, 111 and 222: `git merge-tree --write-tree --no-messages 111 222`. The "merge base" will be recomputed by Git while running that command. – VonC Jun 17 '23 at 15:28
  • well, yep. it does not show me the "diff" like output. imagine i want to replicate the situation existed for a person when he got a merge conflict (before he resolved the conflicts and made his historical merge commit) – Max Jun 17 '23 at 15:30
  • imagine i want to sit "into time machine" and see the diff of conflicted merge the person was facing before he started to resolve conflict (+including not-conflicted well-merged files) – Max Jun 17 '23 at 15:32
  • 1
    Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/254119/discussion-between-vonc-and-max). – VonC Jun 17 '23 at 16:04
  • actually i found out that `git merge-base` does not work properly when there were periodic merges into branch B from branch A before we finally merge B into A. So seems we can't find "changes brought to A in a final merge of B to A" using `git merge-base` in a general case... see more at https://stackoverflow.com/questions/3998883/git-how-to-find-commit-hash-where-branch-originated-from#comment4283509_3999084 – Max Jul 07 '23 at 18:19
  • @Max Good catch. I will include your comment in the answer... [as soon as I am able to](https://meta.stackoverflow.com/q/425430/6309) – VonC Jul 07 '23 at 18:54
  • i've asked new question for people to reassure me in my findings - https://stackoverflow.com/questions/76641205/what-a-git-merge-of-a-branch-has-brought-to-master – Max Jul 08 '23 at 03:16
  • @Max I have ([finally!](https://meta.stackoverflow.com/questions/425430/how-can-i-avoid-an-error-occurred-submitting-the-edit-error-message)) included your comment in the answer. – VonC Jul 10 '23 at 19:15