> but instead of committing all of your work as you have come to it naturally, you decide to break your work up into several small, "logical" commits. This makes you look good, but it's a lie.
No. Breaking your work up into several small, "logical" commits is exactly the right thing to do.
I find this very useful when doing experimental coding: when I don't really know where I'm going or if my changes will work. I end up with a pile of commits that do break tests and thus bisect etc, before ending up with something that works. Reworking this private branch is exactly the right thing to do.
This is in fact the exact model that open source development has used for years. Try submitting a patch series for inclusion in the kernel which include a bunch of mistakes that you've later corrected (as happens naturally during development) and see what happens. You'll be asked to rework it, since it makes it harder to review.
Take a look at the Linux git tree and find me a single merge commit where the branch being merged contains mistakes and corrections. You won't find one. You will find plenty of regression fixes, but these are there because by this time the commits were public and couldn't be fixed retrospectively using a rebase without rewriting public history (which would obviously cause all sorts of problems).
The author is not arguing against making small, logical commits. He's arguing against making a ton of changes in your working directory, then running `git add file1, file2... ; git commit` a bunch of times in a row to record a series of commits.
The problem with this is exactly the one he mentioned: almost no one ever goes back and makes sure each commit actually builds and passes tests.
After they finish making a series of, say, three commits they just go ahead and push. It's only weeks or months later when someone bisects that they find out the first commit was broken without the contents of the third.
Mercurial users use MQ for this process, and to me it seems like it's a better and safer method with an uglier UI.
With MQ, once you were ready to create your three commits you would say:
`hg qnew file1 file2 ... --message 'Fix the foo bug'`
`hg qnew file2 file3 ... --message 'Add feature bar'`
`hg qnew file4 file5 ... --message 'Add feature baz'`
Now you've got three patches that appear (mostly) as normal changesets in your repo.
You can `hg qpop` back to the beginning of the set, run your tests, fix anything that's broken and add it into the patch. Then you would `hg qpush` the next patch and do the same thing.
Once you know that all three patches represent a working state you can `hg qfinish --all` to turn them into vanilla commits.
Yes, it's more work, but you've got three "logical" commits that actually work, instead of three "logical" commits that might hopefully work.
MQ is also great for the open source workflow you mention, where you send your patches to a mailing list (for example), get feedback, and rework them.
If someone tells you changeset X has problem Y, you can just `hg qpop` back to the patch, fix Y, refresh the patch with that change, and retest/resend.
If you want even more crazy power, you can make the directory containing your patches a Mercurial repository, which lets you track the evolution of your patches over time. It's very weird and meta, but extremely powerful.
MQ lets you do the exact same thing as the interactive rebase. It's not like it forces you to go back and ensure every single patch is correct after you've qfolded some together or reordered them.
> You can `hg qpop` back to the beginning of the set, run your tests, fix anything that's broken and add it into the patch. Then you would `hg qpush` the next patch and do the same thing.
And you can do the exact same thing with your git commits before pushing them, last time i checked MQ had `qpush -a` and did not force you to run your tests between two qpushs.
> Yes, it's more work
Indeed. And if you have no problem with that more work, you can do it just as well with git. MQ doesn't magically make people care.
> If someone tells you changeset X has problem Y, you can just `hg qpop` back to the patch, fix Y, refresh the patch with that change, and retest/resend.
No you can't. Because if it's a changeset (rather than a patch in a series) then you've already qfinished it and pushed it to a public repository, and you're now rewriting public history.
I don't like git for a number of reasons, but this is a terrible strawman: git provides all the tools needed to ensure each and every commit is correct (whereas bazaar, for instance, doesn't. Not without untold amounts of pain anyway), and I've seen a number of blag posts and comments which recommended exactly that approach: tinker on your local branch, rewrite to your heart's content, and before you push anything to remote test each commit individually. There is nothing which prevents you from doing that, just as there is nothing that forces you to do that with mercurial.
Right. For git, IMO the right way to do this is:
$ git add -p # stage the first bunch of changes you want to commit
$ git stash save -k # push all the unstaged changes to the stash
$ # build your code, run tests, whatever
$ # repeat until it builds clean
$ git commit # record the clean (possibly fixed) commit
$ git stash pop # get your other original changes back
Repeat as needed until all your stuff is committed. If you can't make a subset of your changes build clean, then it's not independent and should not be committed standalone.It takes time to write a good change, but it takes way, way more time to figure out what the purpose of some random change was later. I've had people contribute code to a project and try to tell me they didn't understand it well enough to separate it and document it. If you don't understand it, how can I possibly understand it?
The largest, least well-documented commits are the ones that seem to cause the most confusion when I go back to figure them out.
It sounds like you are, so cheers!
Underneath the style there are some interesting points being made about how certain uses of certain features breaks other features. I'd be interested to hear your rebuttal.
What am I supposed to rebut? He gives little reason why the features says get broken are more important than the other things. He just states it.
Of course you shouldn't use merge --squash in that context. That doesn't mean you should never use merge --squash. You just shouldn't use it to rewrite public history. Do you have a local branch in which you fixed some bugs and which branch has not been pushed out to the world and would you like to use merge --squash to merge it into master? Go for it! But if that branch _has_ been pushed out to the world, just use a regular merge.
The fundamental practice the author is arguing against is rewriting public history. But instead of making that point, he makes these sensationalist, dogmatic assertions that rebase, merge --squash and commit --amend are evil and should never be used. Until the end of the article, where he finally admits that really what he (correctly) has a problem with is rewriting public history.
OK, fine. Just title the article "You shouldn't rewrite public history".
If they had used git, they would totally have approved use of rebase for optimizing readability/understandability of commits for the beleaguered maintenance engineer in 2016 trying to figure out what why what we did today (in 37 separate incremental commits) just interacted with new code and blew up $MAJOR_UNIVERSITY's payroll system.
I follow very, very different practices when developing by myself. I largely leave the history as it is, warts and all. If in the course of trying to fix a bug I make five exploratory commits and on the fifth one finally find the magic that works, then history just happens to include five increasingly frustrated commit notes.
I fall on the tool side, which means I rebase & amend and keep history semantically organized, and such. All that makes it easy later to find exactly where I made XYZ change. BUT, I admit that it does ruin the journal aspect of every change. rebase -i does in fact change history, and can make things appear out of order.
I think it's ok, the author doesn't.
It's not lying, it's cleaning up. History rewriting is assembling all the intermediate crap into a comprehensible patch that as an added bonus also comes with a hindsight, or keeping sense in maintaining your work-in-progress on top of some other branch by continuous rebasing.
It's not lying, it's making sense. It's the same thing why you don't save your Emacs editing history to have someone else replay it to produce the source file. You just save the source file because you've spent time doing work to eventually produce something that makes sense. You don't want to bother other people with your errors. It's of no value to them.
However, the time you do not want to do this with public commits. Anything that you have pushed or someone has pulled is public. Anything that flies out of your local nest shall become immutable.
There's some valid bits in there but commandment-from-on-high writing style is pretty offputting.
If all that is a "lie", I'll happily lie to outsiders to present them a nicer image, as long as no harm is done that way.