Reputation: 197
I am using this git command for getting logs (from particular commit) in reverse order and commit details :
git log eab3e0ffdsfs.. --reverse -M --numstat --summary --pretty=format:commitId:%H%ndate:%cd%nsubject:%s%nauthor:%an%n
Which gives me all commits after the specified commit including commits from another branches which were later merged into the current branch .
However I am just interested in current branch commits and merged commits log.
I tried following options :
git log --first-parent 8e146445d19b.. --reverse -M --numstat --summary --pretty=format:commitId:%H%ndate:%cd%nsubject:%s%nauthor:%an%n
gives commits of current branch but I don't receive files that have been modified in that merged commit.I just get author name , subject and date of the merged commit.
However , If you go to github and check history for your branch , you get current branch commits and just a merged commit including files modified in that.
Can we achieve this with git command?
Thanks
Upvotes: 2
Views: 3703
Reputation: 489708
Try adding -m
to your mostly-successful git log
command, i.e.:
git log -m --first-parent 8e146445d19b.. --reverse -M --numstat --summary --pretty=format:commitId:%H%ndate:%cd%nsubject:%s%nauthor:%an%n
(The -c
and and --cc
options will also work, but use -m
here.)
It's worth noting something else here though:
However I am just interested in current branch commits and merged commits log.
That first command is showing you the current branch's commits.
When using Git, it's important to realize that the set of commits that is on the current branch changes as you merge other branches:
D--E--F <-- br1
/
...--B--C
\
G--H--I <-- br2
This is a drawing of a series of commits (identified by single uppercase letters rather than their actual hash IDs) on two branches. Earlier commits are to the left, later commits are to the right.
Now, I think it is intuitively obvious, and that everyone will agree, that commits D-E-F
are only on branch br1
, and commits G-H-I
are only on branch br2
. But: which branch or branches are commits B-C
(and any earlier ones) on?
The answer in Git is that these commits are on both branches. Moreover, if you now git checkout br1
and then git merge br2
, you get this as the result:
D--E--F
/ \
...--B--C J <-- br1
\ /
G--H--I <-- br2
and now, suddenly, commits G-H-I
are on both branches as well!
When you add --first-parent
, what you are telling Git is that as it traverses backwards, starting from J
, it should, at merges, follow only the first parent of each merge commit. The first parent of J
is F
(I
is the second parent), so this means: walk from J
to F
, F
to E
, and so on.
... but [with
--first-parent
] I don't receive files that have been modified in that merged commit.
By default, when git log
is showing a merge commit, it does not bother showing any diffs. The three options I mentioned above, -m
, -c
, and --cc
, tell git log
that it should show diffs for merge commits.
The reason there are three options is that the way merge commits get shown is complicated. For a non-merge commit, it's pretty simple: each commit is a complete snapshot of all files, so all Git has to do is compare the files that are in the parent of the commit, to the files that are in the commit itself. For commit F
, for instance, Git can just extract all the files from snapshot E
, then all the files from snapshot F
, and whatever is different, well, that's the change—that's the diff from E
to F
.
With a merge commit like J
, though, there are two parents. Which one should Git compare to J
, E
or I
? The answer git log
uses by default is: don't bother, it's too hard. :-) If you want to convince git log
to show something, you need an extra option. Two of the options—-c
and --cc
—tell Git to use a combined diff.
A combined diff is rather tricky. Git extracts all the files from all the parents, and compares them to all the files in the merge snapshot. If any parent file is exactly the same as the merge commit's file, Git throws that file off the list of files to diff. So now, Git has a very small list of files: those files that, in the merge result, don't match any of the input snapshots.1 Git then diffs each parent's version of each such file against the final merged version, and combines the diffs so that you can see all of the various versions at once. The -c
and --cc
options do this.
The -m
option is conceptually a lot simpler. When encountering a merge commit, Git simply splits the merge for display purposes. Instead of comaparing J
to F
and I
at the same time, Git makes a sort of virtual commit: J-from-F
, and compares that to F
, and shows you that diff. Then, unless you used --first-parent
, Git goes on to make a second virtual commit: J-from-I
, and compares that to I
and shows you that diff.
Since you probably want to view your merge as a change from what was there before the merge, you will want both options, --first-parent
and -m
.
1One reason for doing this is that comparing files for exact-match is really fast in Git, and doesn't actually require extracting the files from the commits. So by tossing out all the "same in at least one parent" files, Git reduces the problem greatly.
Upvotes: 5