Your project's RCS history affects ease of contribution (or: don't squash PRs)
mjg59.dreamwidth.org
mjg59.dreamwidth.org
I agree with the OP that it's a bad blanket policy. We are fortunate that git has powerful abilities to edit commit history (git rebase -i is my favorite). Rather than just requiring everything to be squashed as a matter of policy, maintainers should instead request that commit history be cleaned up if it's not presentable, IMO.
> I agree with the OP that it's a bad blanket policy. We are fortunate that git has powerful abilities to edit commit history (git rebase -i is my favorite). Rather than just requiring everything to be squashed as a matter of policy, maintainers should instead request that commit history be cleaned up if it's not presentable, IMO.
For what it is worth, I think history is sacred. Never rewrite history (except in extraordinary circumstances and that too very rarely). Of course, do whatever you want on your local machine before pushing to remote but once you have pushed, stop worrying about it.
This is what I'm talking about. After you push and share with others, I think you are absolutely right. Before it leaves your computer via git push to a shared location, I advocate that you should tidy things up. Thanks for clarifying...
- WIP: feature foo
- fixed typo
- whoops!
- working
- reformatted
As is often the case with new contributors to open source projects.In theory --no-ff merges give you the best of both worlds, but in practice, I traverse git history with 'git blame' or 'git log -p <filename>' neither of which do a good job of surfacing "this commit was merged as part of feature/foo".
Of course, all the info is there... But I haven't yet found a good UI for it.
Plus it's easier to revert a squashed commit than a merge. (which is the index number of the parent I want?!)
[alias]
log0 = log --first-parent -m
show0 = show --first-parent -m
blame0 = blame --first-parent -m
These aliases treat history as if each merge commit introduced the changes directly, and didn't have the individual history. (Even for one-patch PRs, this means that the log/blame view will point me to a commit with a link to the pull request, which means I can see any discussion of the PR.) For instance, `git show` on a merge commit will typically show no output (unless there was a merge conflict), but `git show0` will show all changes introduced by the branch being merged in, as if they had all been squashed down.My experience is that I've really appreciated projects with a policy of mandatory merge commits (e.g. Rust; every commit is tested and merged by the CI bot, and humans only push to master in emergencies) with these in place.
But solving that issue by adopting a squash-on-merge policy is like doing surgery with a chainsaw. There are better tools for the job.
While it might take more time than squashing everything, git rebase -i really helps a ton in these situations. I can fixup all the "fixed typo" type of commits into a meaningful commit, and even reword commits if necessary.
I don't want to see some massive 3 month worth of feature hacking, 5000 line modification get squashed down into a single commit. I want it broken into the smallest possible working and incremental changes that transform the old code into the new. Each step should make sense for the code maintainers who come along later and try to figure out what you did and why something unexpected broke. ;-)
I don't want to see 200 noisy commits like you say. I've worked with code bases that used both of these styles. The former is vastly superior in my experience.
I care much more about the actual mechanical code change which broke my stuff, than the feature or branch that happened to contain that mechanical code change.
The same problems apply to reviewing the code in the first place. I'll gladly review 10x the code if it's split into nice tiny micro-commits, even messy ones, than try and suss out exactly all the moving parts that changed from a squashed diff to make sure all potential concerns are addressed. Commit #2 might trigger a "email your coworkers to alert them of the breaking change when submitting" review note, whereas I'm liable to miss the fact that you fixed a typo in the first place in a squashed commit.
I am reluctant to merge your PR if it has too many style issues or improper commit history. The last 10% can be important when maintaining a large project.
Because of the way git/github work, modifying someone else's PR (by pulling locally + modifying + resubmitting as a new PR) often means their authorship in the commit headers is erased, and I wouldn't want to do that without permission.
Edit: Not saying PR authors behave perfectly rationally either. Sometimes it's kids in long trousers failing to share their toys, and in the end "my ball my rules" wins.
Of course, I think the same is true with things like comments, obvious coding style fixes, tests (especially if the maintainer has more access to test infrastructure), etc. I can see the advantage of getting people to do it themselves if the maintainer is busy or especially if the contributor is planning on sticking around for a while, but surely the maintainer can ask "Hey, would you <...>? If not, I can do it."
But beyond that, for most projects, tests apply to multiple environments, and I'm only guaranteed to have mine. If a project is supported on Windows, Mac, and Linux, on Python 2.7, 3.3, 3.4, and 3.5, I probably have one, maybe two, of those twelve choices. It makes more sense to reuse the project's test infrastructure than for me to track down the other eleven configurations. And as a random contributor, I might not have access to the test environments.
Of course, if the tests fail, that's a valid reason to push back on me (or for the maintainer to fix the problem and squash, if it requires access to an environment I don't have).
Your argument / opinion as stated could have "commit history" replaced with "unit tests" and in many circles (for some reason), people are still making that argument. For a project to be healthy, a critical eye must be used for every change: from the code, to the tests, to the commit message. If you don't care about any one of these, you are saying you don't care about the quality of the software. I would deny your PR on principle. My project needs more quality than it needs more contributors.
Note that I did not suggest squashing is good or bad. My opinion on that is not related to the fact that you should care about it and treat it as just as important as your contribution, and you should respect the project enough to abide their guidelines for contribution (unless your contribution is revising those guidelines).
So, yes, I certainly do respect the project enough to abide by their guidelines for contribution: but if those guidelines demand too much work of me, that respect will take the form of quietly walking away and spending my time on something else, and the maintainers of the project will likely never know I had any interest in helping to begin with. Guessing that there might be other people like me in the world, then, I suggest that having a complex and specific process for open-source contribution is likely to reduce the pool of devs willing to get involved, and it's worth considering whether the amount of work saved by requiring devs to jump through these hoops outweighs the obstacle that creates for recruitment.
Split your work into bite sized pieces, and amend/squash the relevant fixups into these before merging.
Since these tasks can need knowledge of rebase, I offer to do them for new contributors too, which usually fixes that issue.
High quality code standards (good variable naming, plentiful comments, etc) tell you what's happening at the code level. The commit history tells you what's happening at the feature level.
Don't pollute history with noise.