So... squashing?
1. first related change
2. first merge commit
3. second related change
4. second merge commit
5. third related change
6. ...
Instead of just having all related changes in several commits with a merge commit at the end that groups those related changes.
If you have a too-huge PR that can be subdivided, it almost always means you have multiple units of work (feature/fixes) into one branch/PR.
The reason I agree with the article and use squash is that it allows us to have a different history between master and the local branches. Developers can freely subdivide each feature into how many commits are useful to their mindset and workflow, while the master branch will remain clean.
In my experience, the individual scope of each commit on the master branch is almost always correlated to the scope of one code review, and thus one PR.
The one thing you lose with just making one PR per commit is the relationship between a set of commits used to implement a feature. One commit involves some retractoring to make it easier to cleanly implement the feature. The other commit would be the feature and tests, and the last commit would be to add calls/references to that feature.
If these commits were kept in the same branch and merged in a single PR, then it would be easy to see the relation between them. If they were merged as 3 separate PRs, then it would be more difficult to see why the refactoring was done, especially if PRs for unrelated changes were merged in the interim.
I'm not saying that I wouldn't broadly discourage the worst of that but most people do not commit every changed line so it is rarely a problem in practice.
What does become a problem are people who insist on "clean history", "re-order these commits", etc etc at PR stage when you both agree the functional problem is done/fixed and now the negotiation has moved on to your git history. I do contract work (read: move around a lot) and this social anti-pattern comes up very often. Usually one guy who's into it throwing his weight around.
Would it surprise you to learn there is a large crossover because people who do this and people who go forensic on other cosmetic stuff: whitespace, syntax, etc?! :)
It was obvious that the later commit was wrong and I could fix it to do X. If it were squashed I would have thought the original intent was to do Y and spent way more time trying to figure out how to fix it.
Obviously it's not guaranteed but throwing away that information is a bad idea if it's just for some arbitrary aesthetics. Same goes for rebasing to clean up the commit history, which would ostensibly do the same.
My solution is:
- small-scoped PRs
- attempt to keep sub-commits readable, but don't waste time on them
Squashed commits also link to the PR where not only do you get the original commit list, but also get the whole discussion around the code.
what about cleaning and filtering out useless commits, by soft reseting the branch and commiting just the actual changes to merge. Sure, it can take a lot of time, but it's done once, by you, after all you're supplying the changes. And if it takes a really long time, you're doing it wrong in the first place by submitting PRs with many LOC.
Have you tried rebasing branches with dozens of short useless commits? That's a real waste of time, and everyone needs to do this if you want to update your main branch. So you've now multiplied the amount of wasted time for everyone.