Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

I would argue that you only loose irrelevant information and you gain the ability to rollback. Without squashing, you are actually way worse off for a "10 times a day release regimen". We release every hour and we squash and rebase with a straight master history.

This enables us to almost mechanically just roll back to the previous commit that was out on Prod, should something happen and it's very easy to skip (revert) just one ticket and let the rest go out. No guessing, no manual figuring out which 7 commits belong to the ticket in question, potentially 6 of them had the ticket number in the commit message like they should, but the 7th, which coincidentally is actually commit number 3 in the sequence but interleaved with other ticket's commits the developer switched some numbers and instead of ticket ABC-123 he wrote ABC-132. Now we have a production incident and a completely garbled attempt to undo it.

We have none of those issues. Each ticket is one commit. If you revert one commit, you are guaranteed to have a working piece of software and you won't have a potentially not even compiling intermediate commit that was subsequently fixed up during a PR, which can happen without squashing.



>No guessing, no manual figuring out which 7 commits belong to the ticket in question, potentially 6 of them had the ticket number in the commit message like they should, but the 7th, [...]

Lots of people it seems don't know this: _you can revert a merge commit_, which includes _all_ the commits that were part of the merge.

So, if you have a feature branch with 7 commits, you merge those 7 commits _with a merge commit_, if you need to rollback, you rollback _the merge commit_, which includes all 7 commits.


The fact that not many people know this unfortunately leads to a side-effect that it is less widely supported by third-party tooling around git.

In terms of simplicity (for example, 'git revert x' is natural-language-like and expresses the intent and meaning), and also in terms of tooling compatibility, that generally leads me to prefer squash commits.

One other thing that squash commits can enable is a sense of developer freedom within their branch(es). There's no need to keep the history super hygienic within each branch; there can be plenty of reverts, experimental commits, etc; the eventual merged product ends up looking clean regardless.


But if only 1 of the 7 commits was actually the cause of the issue, then why would you want to revert all 7 of them instead of just the one?


If you have 7 commits it's very likely that 3 of those commits at least don't build because they were intermediary checkpoints. Then there's the one commit that contains the buggy code and if you revert that it breaks the whole thing and it doesn't work. Now you gotta revert the whole thing anyway, all 7 commits (or the merge).

Why bother with all this time and energy? If each single commit in your straight master history is one self contained thing it's easy to revert that whole thing and done.

We are also talking SaaS here with releases going out multiple times a day. So if something is very broken it's likely to be noticed very quickly and the breaking change is probably the last commit on master and you don't even have to revert it. You just deploy HEAD^ to Prod while you create a PR to fix the problem.


One can ensure that every commit passes the tests suite and linting by running something like:

    git rebase --exec "test_cmd" --exec "lint_cmd" base_branch
and any commit that doesn't pass can be fixed until you get to the point where all commits in the branch pass.

Then you can find the commit that caused the issue, revert it and then make another commit that fixes the issue in the next PR (and ensure that the test suite passes for both commits with the --exec parameter to rebase.

> If each single commit in your straight master history is one self contained thing it's easy to revert that whole thing and done.

Not really. The more lines and files that are affected by applying the commit, the more likely there will be conflicts when trying to revert it. While that won't be the case if the commit (or merge commit) is the current head of the branch, but if other commits and merges have been made since then, then conflicts are fare more likely.

On the other hand, smaller commits are much easier to revert because they tend to not change many files or many lines of code.

> We are also talking SaaS here with releases going out multiple times a day. So if something is very broken it's likely to be noticed very quickly

That's assuming that it's "very" broken and it's noticed quickly. Those assumptions don't always hold.


I personally think that individual commits are mine and nobody should care. They help me. They're not meant to live forever and if you make me make all of them even compile let alone build green then I will squash before ever pushing. A red build should result from the first commit on a bug fix if you ask me.

I think we just fundamentally think differently. Your branches seem much longer lived. And each of your commits is more like the small commits that for us would sit directly on master.

Agreed, they do not always hold. But most of the time if something really bad happens it gets noticed and we roll back to the previously deployed commit. Stuff that is only noticed later is in most cases not such a big thing and is handled as a normal bug fix. Exceptions prove the rule obviously.

We also try to make individual tickets and PRs small, yes. It all plays well together and into each other. It has many advantages like easier PRs from the reviewers point of view. More likely for reviewers to actually find something useful to say as 'review fatigue' (aka 'I already read aaaaall this code and there's moooore? And teeeests? Waaaah! Whatever! ' and then they click approve) is less likely. Smaller tickets mean they get done faster and the pace that sets is more predictable than few large ones where execution time can vary considerably. Product people like predictability. You also deliver smaller chunks of changes so customers can give you more fine grained feedback vs just a large change that changes everything at once and they just go 'I hate change, undo this! Now!'. And should something really be of no use individually, feature flags are an option. Or a feature branch that doesn't live too long.


> I personally think that individual commits are mine and nobody should care. They help me. They're not meant to live forever

But they don't really help when reviewing because they're hard to make sense of. But if you want to make a large change in a single commit, then why not just stage the entire thing as a single commit in the first place. You can address review comments by amending the commit and force pushing it.

By breaking it down into sensible commits, it makes it easier for the reviewer to review your change by filtering it by commit, so that they can see a subset of it.

> You also deliver smaller chunks of changes so customers can give you more fine grained feedback

Some of those changes involve some degree of refactoring. Typically, I'll separate the refactor part from the implementation part as separate commits. If I were to just make a PR that just did refactoring, then how would I justify merging it and deploying it to production?

Also, making a bunch of small changes and merging them separately takes away the association between them, unlike what you get by keeping multiple related commits in a branch.


I make individual commits for addressing review comments. It's sometimes helpful to see this during further review both for existing or new reviewers. They get squashed like any others afterwards. I don't see how it would be valuable after something is merged to master that I renamed a bunch of variables, extracted a method somewhere and added one test after a reviewer commented that I missed a case.

Refactorings are sometimes done with a separate PR and sometimes not. Depends on the size. From our discussion we might have different philosophies on when to do that. And yes at our company merging and deploying a refactoring to master is totally acceptable and done frequently. Even if the ticket takes longer in the end, gets scrapped etc. the refactoring can probably stand on its own and be valuable if we extracted it to its own PR.

Association should be there through tickets. We may have a different idea of what small is and what will be in such a commit. Let's have a made up example:

You are building something that has a table view for some data. That feature is out there. But the table doesn't have sorting capabilities and no filtering and no paging. It just displays everything.

There are individual tickets for adding each of these. Sorting is a small PR because the table component you use actually has that capability. You add the flag to enable sorting and the definition for the default sort and release it.

Filtering is another ticket. Filtering is harder. The API this is based on doesn't support filtering and isn't owned by your team. If this had been part of the same feature branch and released together customers would have nothing yet. Instead they have sorting already. You decide to do filtering via API and not in the UI after fetching everything. So off to create a ticket for the other team and talking to them. Maybe you can help out and do it for them but in any case this will take a while.

While waiting for their answer you move on to Paging! Yet another ticket. You notice that your table component doesn't support infinite scrolling. You want to have that though instead of individual paging. You create two PRs. One to the table component which adds infinite scrolling. This is an individual PR that is regression tested against all the other users of it in your code base. Once that's done you merge it. Why wait? Then you PR the actual change to use infinite scrolling with your specific table. This is at this point still based on that API that doesn't do filtering so you still always retrieve all data. But with lots of data it still helps rendering speed and the API is reasonably fast even with thousands of rows.

You create a new ticket to clean this up and make it work by retrieving paged data once the API also does filtering. Or maybe you never will.


> I make individual commits for addressing review comments.

Those changes are visible when you make a force push in github since it generates a link that shows those changes.

> Association should be there through tickets.

I've seen companies change ticketing systems several times in career. Once it changes, all the old links and associations are as good as gone. But if that association is maintained via git, then that's not an issue.


I like how you first say that doing something in git itself is not needed because a random tool you use but I don't does things so that you can still see it easily and then you turn around and tell me that something is better to be visible in git history itself only because companies change tools.

Weird.

Tell me, in your career, how many times have you seen companies switch source control tools?

I have seen it many many times. In fact I've done some of these migrations for my companies in the past.

I've seen the same with ticketing systems as well. Yes you can loose history in both these transitions. I've worked with systems where either ticket or version history were not available past a certain point. Usually viewing many many years into the past was possible because people realized that historic information can be valuable. But there was a cutoff point that balances out ROI.

Unless required for regulatory purposes maybe, who really needs commit history from 15 years ago? It's cool don't get me wrong. I loved digging through commit history on code that originally was tracked via RCS on a (at the time) ~15 year old code base. And that was about 15 years ago. I'm getting old lol!


> Tell me, in your career, how many times have you seen companies switch source control tools?

Twice. Once from CVS to SVN (where people started using SVN for new projects and left existing projects in CVS). And once from SVN to git where we used tools to get the SVN history into git.

> who really needs commit history from 15 years ago?

It really depends on how old the code is. I've worked on code that was last deployed close to a decade ago and some of the git blame output was showing commit dates from 2008 (not quite 15 years ago). Unfortunately, the commit messages left something to be desired and didn't really help in terms of figuring out what the issue was).

> I loved digging through commit history on code that originally was tracked via RCS on a (at the time) ~15 year old code base. And that was about 15 years ago. I'm getting old lol!

Same here. I never got to use RCS at work, though I learned about it in school :)


> Each ticket is one commit. If you revert one commit, you are guaranteed to have a working piece of software and you won't have a potentially not even compiling intermediate commit that was subsequently fixed up during a PR, which can happen without squashing.

This is the key point and I liked it so much that I bookmarked it. Hope you don’t mind. :)

I frequently have to debate with my teammates on the value of squash merging into our mainline branches. Another value add that squash merge brings is that it enables what I call “accidental documentation”. You get a easy to parse log of work that was done and a link right to the PR with a description and any discussion around it. As a lead I frequently need to coordinate teammates and communicate technical decisions. It’s invaluable to be able to just pull up the commit log and go right to the work in question without having to wade through a bunch of noise.

It also helps a ton with writing release notes.




Consider applying for YC's Winter 2026 batch! Applications are open till Nov 10

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: