6

I'm sure this question will be closed as opinion-based but there's nowhere else so ask it so here goes...

I'm trying to view the history of my branch which includes merge commits (specifically what changed) and I found a very useful post here git show of a merge commit that tells me to use git show --first-parent

What's still confusing me is why --first-parent isn't the default for git show, or even why any other behavior is useful at all. If I'm looking in my history on a specific branch at a specific commit, the only thing I ever want to know is the difference between that version of the branch and the previous one.

Of course it could be that git commands are written for the convenience of the authors who don't give a shit what their end users actually want, but I suspect that there is a proper reason. Could someone explain why, with a better knowledge of git, I might not want to use --first-parent all the time.

Andy
  • 10,412
  • 13
  • 70
  • 95
  • First i think this question should be asked on super user stack, second i think you want to run `git log --graph` and use `git diff` with the commit hash(es) and see the diff between the two states – Funonly Apr 10 '18 at 12:19
  • I've been continuing my investigation and I think part of the answer is that I should have enough faith in git's merge capability that I shouldn't want to review the merges that have been done automatically, whereas for SVN I don't trust the merge so I want to review everything the merge has done – Andy Apr 10 '18 at 13:12
  • @Andy, it has nothing to do with what commands you "should" want to run or why. Trusting git's merge algorithm is well and good, but looking at the merge patch (relative to any given parent) *can* be useful. And in the case it's the first parent, that's why the `--first-parent` option is there. So what's the problem with using it? 15 extra characters to type? So create an alias. – Mark Adelsberger Apr 10 '18 at 13:23
  • @Mark what I was trying to achieve was to get into the git mindset (where default current behavior makes sense) as opposed to my current SVN mindset (where it's counter-intuitive), and this is where your answer below really helped. – Andy Apr 10 '18 at 14:39

1 Answers1

13

Well, I guess it's worse than you think, because the behavior of --first-parent is not the behavior you describe as the "only useful" behavior. It often works out to be the same, but that depends on the branch/merge workflow used with the repo.

(None of which has anything to do with the "convenience of the authors", who are quite capable of making an option the default if it actually made sense to do so.)

The "first parent" does not mean "the parent from the branch I'm on". In fact, nothing in git means "the parent from the branch I'm on", because in git the relationship between branches and commits doesn't work that way. If a merge is reachable from a branch, so are all of its parents. It may typically be true that one of those parents was, at one time, pointed to directly by the current branch. That is something git neither knows nor cares about.

"First parent" just means "the commit that was recorded first in the merge's parent list", which has nothing to do with the current state of refs.

Now, if you use the porcelain command git merge to produce a merge commit, then whatever is currently checked out will be recorded as the first parent. And if you're not in detached head state when you do this - meaning you have a branch checked out - then that branch will advance to the merge commit. So it often works out that you're reading a branches history, and you pass through a number of merge commits that were merges "into" the current branch.

But suppose right after merging branch2 into master you then say

git checkout branch2
git merge master

which will fast-forward branch2 onto the merge commit. Now, with branch2 still checked out

git show --first-parent

and you'll see the parent that "came from" master even though that's not the branch you have checked out.

And you can say "but in my workflow, I never do that, so my assumption holds". Well, in that case your assumption holds for you. But git wasn't written just for you, and it doesn't make assumptions that everyone works the way you happen to work.

The purpose of git show is to give information about the specified commit. The purpose of --first-parent - in this and numerous other commands - is to limit that information in cases where looking only at the first parent of a merge makes the picture more clear. That limiting of information needs to be requested so that git doesn't apply it when it would make the picture less clear.

But ok, even though --first-parent doesn't mean quite what you've said you want shows default behavior to be, why not make show behave the way you describe? Well, because the way git stores data, there's no way to identify "the parent from my current branch", and if you changed the way the data is stored to make that possible, it would impose new limitations on git that are bigger problems than what you're trying to solve.

Mark Adelsberger
  • 42,148
  • 4
  • 35
  • 52
  • Thanks for this - the fast-forward example was very useful in understanding why the concept of first parent is arbitrary. I still think i'd want to use first-parent with show most of the time (and I prefer to use no-ff when merging into master) but that is probably because i'm stuck in an SVN mentality. I am starting to see the git POV though :-) – Andy Apr 10 '18 at 13:34
  • @Andy : Sure, it's often a useful option. In many branch workflows that are popular today, it will typically do what you mean for it to do. Even so, someone "cleaning up a mistake" can create conditions you wouldn't expect, so knowing the bigger picture can demystify those situations quite a bit. – Mark Adelsberger Apr 10 '18 at 13:46
  • 2
    re: git having no knowledge of the branch state of a merge's parents: [*the first parent of a merge commit is from the branch you were on when you merged, while the second parent of a merge commit is from the branch that was merged*](https://git-scm.com/book/en/v2/Git-Tools-Revision-Selection). Is that not always true? – pkamb Oct 20 '20 at 17:40
  • 2
    @pkamb - As I wrote in the original answer, if you use the porcelain merge command, and you're on a branch when you use it, and you merge in one other branch, then at the time of the merge the statement you highlighted is true. And as I wrote in the rest of the answer, it doesn't matter, becaue you still can't assume that "first parent" means "from the branch I'm on now". – Mark Adelsberger Oct 21 '20 at 18:34