In my opinion, a VCS should maintain a history of all commits, because it's impossible to know which commits will be the key to solving a problem in the future. Even commits that are later reversed can occasionally be of tremendous value.
A truly great VCS would allow you to do a "visual squash", hiding the intermediate commits unless you need to see them.
If Github's UI showed branches diverging, commits being made to that branch, then the merge back to trunk like gitk does then devs could visually see why it's valuable.
Works best if your merge commits have useful messages.
I think you need to recognize that you have some implicit assumptions about what a commit even is, when you make such statements as “all commits [should be preserved]”.
In that frankly ridiculous example, nothing has actually changed but the location and the label for where the meaningful thing happens.
In your example, since you've artificially injected automation to snapshot every 11th keystroke, those keystrokes and those commits are indeed not meaningful. (I would argue that they're not useful either but I allow it's possible to argue they're useful)
But there is still some point where you do decide "here there is a meaningful milestone" and you mark that spot.
Other people do exactly that same thing with commit.
You've just artificially gone out of your way to make your own commits useless for that.
Why? It’s super helpful for me. It makes me a better engineer, and nobody I work with has to care that this is happening, because it’s all gone by the time I make a PR. Why is it “wrong?” Because you have a certain definition in your head about what a commit “is”, and are making a bunch of blanket statement based on this assumption, and everyone who has different assumptions is therefore wrong?
To be fair, I don’t run “git commit” in a loop. I do however, commit extermely early and extremely often. I commit just about every time the code compiles, whether I’m done with what I’m doing or not. Whenever I decide “hmm, approach A isn’t working great, let me try approach B”, I make a commit. If approach B doesn’t work out either, I can compare it with my commit at approach A and decide which elements I want to take from both. I can create branches to do make this easier, so that I can switch between them at will.
The point is, I make commits at what should be considered arbitrary points in time, because for me, a commit doesn’t mean “a thing I want someone to review”. A commit means “I don’t trust my editor not to crash and wipe my undo history, so I’m going to create a checkpoint right now in case of a crash or sudden power loss”. Who are you to judge me for this? Why is it wrong?
> But there is still some point where you do decide "here there is a meaningful milestone" and you mark that spot.
Right, that’s called “a pull request”. It’s the reviewable unit of my productivity. When I decide “here is a thing I believe should be merged”, I put up a PR. I don’t believe this needs to be broken further into the endless commits that it took me to arrive at this point.
> You've just artificially gone out of your way to make your own commits useless for that.
No, I’ve gone out of the way to save my work. Git commit is extremely good at this, because it lets me save my work in a way that supports branches, which my editor’s undo history does not. It lets me compare these units of saved work in a way no editor can (even for editors which support branching undo history.) But with this workflow naturally comes the conclusion that I must squash all of this into one meaningful commit (with a good commit message) once it’s ready to be reviewed. There’s no reason whatsoever that anyone should care that I typed “git commit -am wip” a bunch of times while getting to that point.
WIP commits should be rebased out before the branch is pushed
Commits which fix formatting should definitely be a separate commit so they can be added to `.git-blame-ignore-revs`. This allows anyone looking through the history of a change to see the functional fix, rather than having it mixed in with a refactor/reformat operation.
In this case, each commit should have a useful commit message, both allowing them to be searchable, and to help understanding of the change
(I agree on all points.)
A commit that only changes formatting is a prime example of a useful secondary commit. Separating formatting changes from code changes makes it much easier to see what the actual functional changes were rather than them being hidden in a mess of non-functional changes.
"oh. i should fix this, but it doesn't have anything to do with what i'm currently solving." cd ../worktree-checkout, make a branch, do the fix, push, open a pr. then cd ../original-checkout and continue on. rebasing the fix into my wip when the PR is merged (or cherry-pick if you're confident) as needed.
Instead of finding an offending commit that has only a few lines to analyze, you only get a massive feature-landing commit that doesn't narrow it down.
Interactive rebase or amend can be used to squash "oops forgot a semicolon" junk commits.
Squash is basically a hard requirement for bisect to be useful at all. Especially for compiled languages.
Anyway, accidentally-breaking commits can be skipped, but squashed commits can't be unsquashed.
Github is the problem here. And squash merge is "useful" as in when I would have squashed a commit even before merging, I don't think we should squash merge otherwise