Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get `git log --name-status` to work with merge commits?

Tags:

git

I'd like to see the list of files and corresponding diff status for each commit in my log. To do this for normal commits, it's as simple as:

$ git log --oneline --graph --name-status

For merge commits, however, the list of files is blank. What I expect to see is the list of files modified, deleted, or added since the merge before it (for the same 2nd parent).

I tried running the same command above, but with the -m option:

$ git log --oneline --graph --name-status -m

This didn't work either. Merge commits show a huge list of files, some of which I know for a fact did not change during the merge. I actually get more accurate results with git diff --name-status MERGE_SHA1^!, where MERGE_SHA1 is the literal SHA1 value of the merge commit I'm checking.

Why is the --name-status result from log different from what I see in diff? Is the -m option here doing what I think it is?

Is there a way to get the log command to show me the results for merge commits that I expect?

like image 966
void.pointer Avatar asked Mar 03 '16 19:03

void.pointer


People also ask

Which git command is used to display merge history?

The most basic and powerful tool to do this is the git log command. By default, with no arguments, git log lists the commits made in that repository in reverse chronological order — that is, the most recent commits show up first.

What is git log -- Oneline?

Git Log Oneline The oneline option is used to display the output as one commit per line. It also shows the output in brief like the first seven characters of the commit SHA and the commit message.

How can you tell if a commit was merged?

To see the merge commit's message and other details, use git show-merge with the same arguments.

What is git log used for merge local master?

The git log command shows a list of all the commits made to a repository. You can see the hash of each Git commit , the message associated with each commit, and more metadata. This command is useful for displaying the history of a repository.


1 Answers

The answer appears to be "alas, no", but there is a workaround that might suffice.

I have some test repositories I keep around for exploring some of the odd corners of git, with clean and simple cases of branching and merging, or specific changes, etc.; and in this case, they help reveal how -m is implemented, which interacts poorly with how git log --graph is implemented. Here's a snippet from git log --oneline --graph:

*   cc081d4 Merge branch 'branch'
|\  
| * 222c4dd add clobber-reg example
* | dcfaa9d test some python logging package items
|/  
* fb45c22 Revert "edit file foo"

and the same thing with -m --name-status added:

*   cc081d4 (from dcfaa9d) Merge branch 'branch'
|\  
| | A   clob.c
| | cc081d4 (from 222c4dd) Merge branch 'branch'
| | A   logtest.py
| * 222c4dd add clobber-reg example
| | A   clob.c
* | dcfaa9d test some python logging package items
|/  
|   A   logtest.py
* fb45c22 Revert "edit file foo"

The color highlighting is lost here, but it gives an additional clue: cc081d4 (from dcfaa9d) and cc081d4 (from 222c4dd) are colored as a commit ID. It seems that when git log (or git show) is generating a diff, and -m is in force to split merges into as many result-vs-parent pairs as there are parents, git internally splits the commit itself.

That is, in this case, commit cc081d4 is a merge commit, so git constructs, internally, two new commits: cc081d4-vs-2cfaa9d, and cc081d4-vs-222c4dd. It can then show you the diff (and/or draw the graph)—but it puts these new commits into the graph output (replacing the original single commit that is the actual merge).

After these synthetic commits, we get the parent commits, so we see the same single files modified again (since the parents of this merge each have just a single file modified, with no merge conflicts or anything). In my simple-repo case the two parents themselves immediately have a single common parent, which keeps things simple.

In general, as you have already discovered (which is why you are using -m), when git goes to "show" a merge, it uses its special "combined diff" rules. These combined diff modes start by finding files in the merge commit that match neither parent, and then making diffs for those files (all parents' version of each file, vs final-committed version of that file) and presenting them with modified unified-diff form. Using -m splits the diff-ing up, so that you get the merge against each parent, in the way that git diff prefers to compare exactly two trees (easy when you have a normal, non-merge commit: there's the parent, and the commit, and that gives you two trees).

As we just found out, this split affects git log. (I didn't know this until now myself.) So, the workaround is, don't try to get these out of git log. Leave the merges mysterious initially, then go back and fill them in one at a time with git show -m --name-status. (You can suppress the log message too, if you like, with --format=.)

Note that you can find merges with git rev-list --merges (and find non-merges with git rev-list --no-merges).

like image 135
torek Avatar answered Oct 09 '22 04:10

torek