Git doesn't have a good concept of a mainline branch when going back past a merge. It simply records more than one parent for that commit and not which branches they were on before they got merged.
Mercurial does somewhat better in that department by storing the branch name in the commit, so you can pick the parent on the same branch reliably.
I don’t understand what you’re saying. If you have a main branch which is always merged into then `--first-parent` will only list merge commits and regular commits on that branch. I have never seen it fail on our main branch.
In `git merge feature`, `feature` will become the second parent while the commit that you are on will become the first. The linear mainline history falls out of that.
It fails if someone merges main into their feature branch, and then performs a fast-forward merge of their feature branch to main. Now the two parents are in the opposite of the expected order, and --first-parent will follow along the feature branch. This can cause the new state of main to have a lower number of first-parent-commits than prior to the merge!
However, if you have infrastructure that prevents fast-forward merges to main (prevent developers from pushing directly to main, allow only PR merges and disable fast-forward merges for that), then the `--first-parent` approach can work.
> However, if you have infrastructure that prevents fast-forward merges to main
I did say merge, did I not? Yes.
> > If you have a main branch which is always merged into then
If fast-forward is a “merge” too then fuck it, I can’t be bothered to use Git lingo since every idiotic little thing needs to be qualified (see also: Git tag, which is sometimes only an annotated tag but also sometimes also its cousin “lightweight tag”).
You said "git merge feature", which _does_ perform a fast-forward when possible. In my experience, developers on a large enough project will inevitably break Git in a creative way, and this is one of them.
This is the default because "git pull" performs a merge by default. You _want_ that to fast-forward when possible or everyone will create a merge commit every time they pull updates.
For someone to break the mainline parentage they would have to:
1. Do that ugly merge of mainline into their feature branch[1]
2. When they are ready to “incorporate” their commits into mainline: do a fast-forward since that’s apparently possible
But the proposed setup contradicts this chain of events: if their Git config was set up to do a fast-forward when possible, then a proper merge (a merge commit) wouldn’t have happened in stage 1 if mainline and `feature` had not diverged. And since that means that the two have diverged (evidenced by the merge commit), you cannot do a fast-forward in step 2.
And even if the above somehow is not true: step 2 is impossible because now `feature` contains a merge commit from mainline into `feature`, which mainline does not have. So a fast-forward is impossible.
What am I missing here?
[1] Oh right, I have to be specify now: a proper merge, a merge commit. The one with two parents, not an octopus one. Explicit enough already?
> You _want_ that to fast-forward when possible or everyone will create a merge commit every time they pull updates.
Surely this makes only a tiny difference in practice. We’re just a handful of developers and people usually diverge from mainline before they get their PR merged. So there are merge commits going from mainline into feature branches absolutely everywhere, because only two or three of us use rebase.
But I do in fact seem to recall talking to one of the other developers about him breaking the conventional commit parentage at some point in the history. So there is some bump there, a few years back.
But the usual story is that the people on our project do all those nasty merges on their own branches and then use the “merge” button in the Web UI when they get their PR approved. And there is in fact a fast-forward option there, but it’s not like we ever get to use it (unless we rebase) since mainline has diverged already. (I wouldn’t personally use it for “merging” (incorporating my changes) into mainline.)
Mercurial does somewhat better in that department by storing the branch name in the commit, so you can pick the parent on the same branch reliably.