My experience has been the opposite. Every organization I worked at used Trunk based development (feature branch->master). Because branches are short lived and usually small, they are the atomic representation of a change, and not the commits in the pull request. Pull requests usually have lots of "linting", "fixing test", "fixing typo" commits that I absolutely do not want in my master branch.
I understand that not all organizations work like this, but that is my point: there is nuance. Blanket statements like these are not productive. The author seems frustrated that people still use squash merge, and just assumes that it's because people just don't understand how git works.
> My experience has been the opposite. Every organization I worked at used Trunk based development (feature branch->master).
Each repository has its own necessities and you need to adapt the workflow to them. Sometimes for small repos what's work the best is commits on main, some people like the so-called "git flow", and Linux have different maintainers for each subsystem.
> Because branches are short lived and usually small, they are the atomic representation of a change, and not the commits in the pull request.
If they are small enough they can be a single commit. No problem in doing that, and the result will be similar to squashing. If they need more than one commit, so they are not exactly "small"
> Pull requests usually have lots of "linting", "fixing test", "fixing typo" commits that I absolutely do not want in my master branch.
I agree that if someone commits something and then commits a "lint", "fix typo", this could be solved in commit correctly once. But this is not always possible, so one can use the rewriting history tools that were mentioned.
But I return the question: what are the downsides of having those commits?
> Blanket statements like these are not productive.
What, exactly, was blank? I tried to justify everything that I could based on the how Git works and debunk statements like "squash makes the history cleaner" (which, in fact, are blank).
> just assumes that it's because people just don't understand how git works.
So, I make the same question of the text: after reading and knowing what squash merges really are, what are the good reasons to still use them?
In my experience, having to rebase on top of a branch with a lot of "lint" "quick fix" "let's try this" "oops, how about this" can be draining and sometimes lead to accidental code deletion.
I like squash merges because I know it was the author's intended change that I'm merging or rebasing onto.
I've worked in orgs that use long lived branches and short lived branches... And short lived branches are by far less stressful to deal with if you can do it, precisely because of merge conflicts.
Reality is never going to match your desire. Things are going to get messy, and so you end up with squashable commits among your commits that shouldn't be squashed. The branch you're merging should match your intent for atomic changes to the code that can be easily reasoned about when rebasing, merging, and bisecting.
You write to history once, but you read from it many times. Therefore, optimize for reads.
> In my experience, having to rebase on top of a branch with a lot of "lint" "quick fix" "let's try this" "oops, how about this" can be draining and sometimes lead to accidental code deletion.
" But this is not always possible, so one can use the rewriting history tools that were mentioned."
> I like squash merges because I know it was the author's intended change that I'm merging or rebasing onto.
The poor commit quality is your issue here, and squashing is merely a way to avoid addressing it. That only makes squashing a good tool to use to make a big mess a slightly smaller mess.
Thank you, but no. I enjoy working on a branch and committing small changes at a time, sometimes trivial, sometimes not even compiling, sometimes formatting or whatever the hell I feel like.
When it comes time to review, I squash all those trivial changes manually (rebase -i) and present a clean branch for review.
We could try harder to enforce stricter policies on devs to ensure they're much more disciplined about their initial commits, but what we do works for us. It allows faster iteration and then we enforce squash and merge once ready to go to master.
I don't understand why this bothers some people so much that they spend time ranting "you're using git wrong". If it was wrong, we'd be noticing and change our workflow. But it doesn't feel wrong, so we'll continue to use it.
Interactive rebasing away fixups in your branch is not squash merging. I agree that fixing a typo in a variable or a small linting issue in a previous (recent or not-pushed) commit in your branch is usually good. A carefully crafted commit history is all anyone can ask for. But then squashing away that history once the PR is merged would be a waste of a good history and the effort you put into it. If you end up squashing your history away anyway, why bother cleaning it up in an interactive rebase?
I can't follow what you're saying. Once people start reviewing the PR, we typically do not manually squash (rebase -i) because it is helpful to see how the flow of the review went. Following this, we sometimes end up with 10 commits on a PR that are just addressing various comments, nitpicky or not.
Then once approved, we click the "squash and merge" button, and github squashes all that useless noise into a single commit on master for us.
> Then once approved, we click the "squash and merge" button, and github squashes all that useless noise into a single commit on master for us.
This is not what squash is. I suggest you to read again the section "What squash merge actually is". tl;dr: "Squash merge is the same as the true merge but with a missing information: the reference to the merged branch."
> We don't have any complaints about this workflow.
> Thank you, but no. I enjoy working on a branch and committing small changes at a time, sometimes trivial, sometimes not even compiling, sometimes formatting or whatever the hell I feel like. When it comes time to review, I squash all those trivial changes
I understand the workflow you've described here. I think the key word is "trivial". Otherwise, when I squash together many "large" patches, the end result will be a huge commit with possibly unrelated changes, and that can be really bad for code archeology. When the future me or someone else wants to revisit the history and try to understand why a change was made, it may be buried down a long list of changes in a single commit, and the commit message won't be able to proper explain the reasoning behind it, IMHO.
Something that I also quite like about having individual patches in a PR/MR, is being able to review them individually too. Makes it easier for me, as a reviewer, to be able to understand the motivations behind each set of changes. But then again, that may only apply for larger patchesets/PRs/MRs...
> Otherwise, when I squash together many "large" patches, the end result will be a huge commit with possibly unrelated changes
Of course not, that would be silly, but who is doing that? I suppose some silly outfits have long lived branches onto which they throw lots of stuff then finally go back to master, but that isn't what this article is arguing about. If I address PR comments, such as typos, simplifying logic etc, this is just noise that doesn't need to be in any history, except maybe for a deep dive by looking at the PR itself.
Yet the article seems to be arguing otherwise and suggesting we use tooling to solve a problem that we don't even have. As someone else said, it is such an engineering nitpick "you're using it wrong" type of article.
We enforce squash commits when we mere PRs to master, and we never have any issues with it.
> If I address PR comments, such as typos, simplifying logic etc, this is just noise that doesn't need to be in any history, except maybe for a deep dive by looking at the PR itself.
Read the rewriting tools references in the text.
> Yet the article seems to be arguing otherwise and suggesting we use tooling to solve a problem that we don't even have.
Read again about the debugging tools mentioned. I never saw a code that needed some kind of debugging. Keeping the history clean makes the debug easier.
You could also say the same about tests. Tests don't solve any problem as long as the code works. But if it doesn't work, test will help to quickly find out where it is broken.
Otherwise, you have no benefit of squashing. If you don't see the benefits of having a commit history, you can use Google Drive instead.
> We enforce squash commits when we mere PRs to master, and we never have any issues with it.
If you use short-lived branches and every PR is one indivisible unit that represents a change, then it will always end up as a single commit anyways. When this is the case, there's no point enforcing a high commig quality - just squashing them will produce the same end-result.
> The poor commit quality is your issue here, and squashing is merely a way to avoid addressing it.
Just like I said: it's like driving reverse because you don't want to learn how to shift gears!
> That only makes squashing a good tool to use to make a big mess a slightly smaller mess.
You're right, in cases that the repository is so cluttered this may be a palliative solution to avoid things to get worse. Squash exists, so it is a tool that can be used if you know what you're doing. But it being useful for rescuing in some situations doesn't mean that can be used in all situations. It's like taking pills instead of vaccines.
There are other tools in this category, such as git push -f: it is a useful tool that you may use when it's necessary if know what you're doing. This doesn't mean that it should be used as first option. Same for squash
My bad experience with squash merging was with Stash at my last job. Some developers there thought the "clean history" was so worth it they made squash-merging the default merge strategy.
The result: the git repository (at least in Stash) slowed to a crawl, because the comments to the commits were several hundred MiB. It was nuts. Never seen a git hosting site go that slow before.
Actually had to replace the whole repo with another, more or less wiping history (kept the old slow repo just in case, of course), and disabling that damn squash-merge button.
Yeah, it was Atlassian's git thing, or one they bought, and combined it with bitbucket or something.
I'll say it was with the configuration and the buggy implementation of squash merging button with Stash.
After replacing the repo, people were amazed with how fast it was. Also apparently I became notorious as the committer of the whole repository, since first commit was mine!
I never keep the comments of the commit when squash merging. Only a sensible title of the PR and the number so it can be found. All the details are then in the PR where the more nuanced discussion is had.
If you're using squash merging, yes. But I find it better to do merge commits anyway.
I mean doctor up your PR so it's one commit and you can hide your mistakes, I mean, development process, before you open the PR, of course, but the button on your git-hosting tool should just be a 'merge'.
As an aside, I find myself doing amend commits all the time these days.
> the comments to the commits were several hundred MiB
I did't even thought about it. In fact, those are hundreds of lines that no one would read, as the commits are lost and you can't do anything with them...
Totally, but that's what was there. For background, I think the comment created would be a combination of all the comments in all the commits in that branch. Horrid.
I hadn't even heard of squash commits before this, and we looked into it because the Stash site kept timing out. All the people that had built it was just shrug, Stash sucks, always been this way, like all seniors-that-are-actually-juniors-because-big-corp-can't-keep-good-folks-to-teach-them do.
I mean maybe the tool sucks, but at least give it a fair chance first.
This is such an engineer's response to a usability problem.
I've worked with quite a few organizations and many of them use squash merges. Commits are often made because of a failed lint check needs a new formatting commit, addressing some comments to tweak some minor details, or even basic documentation changes. The pull request on GitHub ends up being the source of truth for the change, not the git log, and squash merges do a great job at keeping a single pointer to the parent pull request. Ignoring these nuances and how git interacts with other tools amounts to telling the user they're holding it wrong.
Clearly, squash merging does something useful but the author is totally not interested and declares that squash merging is good for one exceptionally specific use case, the only true clean commit history is not using git at all, and the problem exists between the keyboard and the computer.
This post is full of weird non sequiturs and logical fallacies.
So what if git doesn't have a single command to 'squash-merge'? It doesn't natively support a 'pull request' workflow either. Code forges build convenience functionality on top of git. If I didn't have the 'squash merge' feature I'd just use an interactive rebase to fixup/squash the branch's commits before doing a fast-forward-only merge, because I don't want a git history littered with meaningless noise.
And the 'fewer commits are better so that must mean no commits is best' argument is such an obvious slippery slope fallacy, come on man. Do you seriously think this kind of argument will fly in real life? You are just going to annoy the crap out of everyone. We don't squash and rebase because we want fewer commits, we do it because we want fewer meaningless noise commits. Do you want to preserve all your editor keystrokes, like backspaces, moving code around, copy-pasting, etc., before committing? If you don't, then you obviously don't want to track any history, right? Of course not, that's silly. That's what your argument is like.
I don't want my repo history littered with meaningless noise like these merge commit messages:
The only thing that matters here is the log of the actual work, not the incidental artifact that git merged something.
I also don't want a commit history that looks like London's tube system map. Please, keep the history linear so that myself and future team members can quickly focus on the parts that interest them, after just a glance, and don't have to spend time decoding the tangled mess of interlocking branch histories. Much appreciated!
upvoting! "I also don't want a commit history that looks like London's tube system map"
i don't care how you do it. squashing? git reset followed by sensible commits? intense ninja-like git commit hygiene? or my favorite, liberal amounts of git rebase -i?
the only things i care about are these:
1. your PR contains a series of atomic commits
2. each commit makes a single logical change.
3. that each logical change is adequately described by the corresponding commit comment
4. extra credit if the series of changes is consistent to build and work at each step
i don't want to see "ONE" commit per-feature unless it's trivial.
i do want to see the development process, but in a "publish"-able form
i don't want to see "WIP", "almost working", "fixed broken", "redesigned ...", etc. sausage being made. i especially DON'T want to see patches to files be changed and reverted multiple times as mistakes are made and fixed.
the final PR should be you publishing a nice finished series of patches to accomplish a new feature.
then! we simply rebase that nice simple series on top of master and merge it with an optional merge commit. this gets you a nice linear history while avoiding the information loss with simply squashing everything in a PR/feature into a single commit.
Perhaps you live in London, a city with many subway lines and stations that makes many places easy to reach, just like a repository with commits that makes it easy to find where something was introduced.
I live in São Paulo, a city 2 times bigger than London but with a smaller subway map. Few places have a subway station near them. Finding the nearest station is only part of the problem, as we need to find a way to go from the station to where we need to be. Just like a repository that uses squash merges.
> I don't want my repo history littered with meaningless noise like these merge commit messages
> I also don't want a commit history that looks like London's tube system map.
Both sentences starts with "I don't want" followed by aesthetic choices.
31 comments
[ 3.2 ms ] story [ 77.3 ms ] threadI understand that not all organizations work like this, but that is my point: there is nuance. Blanket statements like these are not productive. The author seems frustrated that people still use squash merge, and just assumes that it's because people just don't understand how git works.
> My experience has been the opposite. Every organization I worked at used Trunk based development (feature branch->master).
Each repository has its own necessities and you need to adapt the workflow to them. Sometimes for small repos what's work the best is commits on main, some people like the so-called "git flow", and Linux have different maintainers for each subsystem.
> Because branches are short lived and usually small, they are the atomic representation of a change, and not the commits in the pull request.
If they are small enough they can be a single commit. No problem in doing that, and the result will be similar to squashing. If they need more than one commit, so they are not exactly "small"
> Pull requests usually have lots of "linting", "fixing test", "fixing typo" commits that I absolutely do not want in my master branch.
I agree that if someone commits something and then commits a "lint", "fix typo", this could be solved in commit correctly once. But this is not always possible, so one can use the rewriting history tools that were mentioned.
But I return the question: what are the downsides of having those commits?
> Blanket statements like these are not productive.
What, exactly, was blank? I tried to justify everything that I could based on the how Git works and debunk statements like "squash makes the history cleaner" (which, in fact, are blank).
> just assumes that it's because people just don't understand how git works.
So, I make the same question of the text: after reading and knowing what squash merges really are, what are the good reasons to still use them?
In my experience, having to rebase on top of a branch with a lot of "lint" "quick fix" "let's try this" "oops, how about this" can be draining and sometimes lead to accidental code deletion.
I like squash merges because I know it was the author's intended change that I'm merging or rebasing onto.
I've worked in orgs that use long lived branches and short lived branches... And short lived branches are by far less stressful to deal with if you can do it, precisely because of merge conflicts.
Reality is never going to match your desire. Things are going to get messy, and so you end up with squashable commits among your commits that shouldn't be squashed. The branch you're merging should match your intent for atomic changes to the code that can be easily reasoned about when rebasing, merging, and bisecting.
You write to history once, but you read from it many times. Therefore, optimize for reads.
" But this is not always possible, so one can use the rewriting history tools that were mentioned."
> I like squash merges because I know it was the author's intended change that I'm merging or rebasing onto.
Can you elaborate, please?
When it comes time to review, I squash all those trivial changes manually (rebase -i) and present a clean branch for review.
We could try harder to enforce stricter policies on devs to ensure they're much more disciplined about their initial commits, but what we do works for us. It allows faster iteration and then we enforce squash and merge once ready to go to master.
I don't understand why this bothers some people so much that they spend time ranting "you're using git wrong". If it was wrong, we'd be noticing and change our workflow. But it doesn't feel wrong, so we'll continue to use it.
Then once approved, we click the "squash and merge" button, and github squashes all that useless noise into a single commit on master for us.
We don't have any complaints about this workflow.
This is not what squash is. I suggest you to read again the section "What squash merge actually is". tl;dr: "Squash merge is the same as the true merge but with a missing information: the reference to the merged branch."
> We don't have any complaints about this workflow.
Repeating the same answer: Just because you never had doesn't mean that they don't exist. If you saw it at least once, it means that it exists. I saw it once, and I related here: https://lucasoshiro.github.io/posts-en/2024-06-27-squash-sub...
I understand the workflow you've described here. I think the key word is "trivial". Otherwise, when I squash together many "large" patches, the end result will be a huge commit with possibly unrelated changes, and that can be really bad for code archeology. When the future me or someone else wants to revisit the history and try to understand why a change was made, it may be buried down a long list of changes in a single commit, and the commit message won't be able to proper explain the reasoning behind it, IMHO.
Something that I also quite like about having individual patches in a PR/MR, is being able to review them individually too. Makes it easier for me, as a reviewer, to be able to understand the motivations behind each set of changes. But then again, that may only apply for larger patchesets/PRs/MRs...
Of course not, that would be silly, but who is doing that? I suppose some silly outfits have long lived branches onto which they throw lots of stuff then finally go back to master, but that isn't what this article is arguing about. If I address PR comments, such as typos, simplifying logic etc, this is just noise that doesn't need to be in any history, except maybe for a deep dive by looking at the PR itself.
Yet the article seems to be arguing otherwise and suggesting we use tooling to solve a problem that we don't even have. As someone else said, it is such an engineering nitpick "you're using it wrong" type of article.
We enforce squash commits when we mere PRs to master, and we never have any issues with it.
Read the rewriting tools references in the text.
> Yet the article seems to be arguing otherwise and suggesting we use tooling to solve a problem that we don't even have.
Read again about the debugging tools mentioned. I never saw a code that needed some kind of debugging. Keeping the history clean makes the debug easier.
You could also say the same about tests. Tests don't solve any problem as long as the code works. But if it doesn't work, test will help to quickly find out where it is broken.
Otherwise, you have no benefit of squashing. If you don't see the benefits of having a commit history, you can use Google Drive instead.
> We enforce squash commits when we mere PRs to master, and we never have any issues with it.
Just because you never had doesn't mean that they don't exist. If you saw it at least once, it means that it exists. I saw it once, and I related here: https://lucasoshiro.github.io/posts-en/2024-06-27-squash-sub...
Just like I said: it's like driving reverse because you don't want to learn how to shift gears!
> That only makes squashing a good tool to use to make a big mess a slightly smaller mess.
You're right, in cases that the repository is so cluttered this may be a palliative solution to avoid things to get worse. Squash exists, so it is a tool that can be used if you know what you're doing. But it being useful for rescuing in some situations doesn't mean that can be used in all situations. It's like taking pills instead of vaccines.
There are other tools in this category, such as git push -f: it is a useful tool that you may use when it's necessary if know what you're doing. This doesn't mean that it should be used as first option. Same for squash
The result: the git repository (at least in Stash) slowed to a crawl, because the comments to the commits were several hundred MiB. It was nuts. Never seen a git hosting site go that slow before.
Actually had to replace the whole repo with another, more or less wiping history (kept the old slow repo just in case, of course), and disabling that damn squash-merge button.
I only understood what "Stash" is in this situation after your comment. Looks like it is an Atlassian product that was renamed: https://confluence.atlassian.com/bitbucketserver/bitbucket-r...
Funny that they don't mention the name collision as reason for renaming it...
I'll say it was with the configuration and the buggy implementation of squash merging button with Stash.
After replacing the repo, people were amazed with how fast it was. Also apparently I became notorious as the committer of the whole repository, since first commit was mine!
As an aside, I find myself doing amend commits all the time these days.
I did't even thought about it. In fact, those are hundreds of lines that no one would read, as the commits are lost and you can't do anything with them...
I hadn't even heard of squash commits before this, and we looked into it because the Stash site kept timing out. All the people that had built it was just shrug, Stash sucks, always been this way, like all seniors-that-are-actually-juniors-because-big-corp-can't-keep-good-folks-to-teach-them do. I mean maybe the tool sucks, but at least give it a fair chance first.
I've worked with quite a few organizations and many of them use squash merges. Commits are often made because of a failed lint check needs a new formatting commit, addressing some comments to tweak some minor details, or even basic documentation changes. The pull request on GitHub ends up being the source of truth for the change, not the git log, and squash merges do a great job at keeping a single pointer to the parent pull request. Ignoring these nuances and how git interacts with other tools amounts to telling the user they're holding it wrong.
Clearly, squash merging does something useful but the author is totally not interested and declares that squash merging is good for one exceptionally specific use case, the only true clean commit history is not using git at all, and the problem exists between the keyboard and the computer.
So what if git doesn't have a single command to 'squash-merge'? It doesn't natively support a 'pull request' workflow either. Code forges build convenience functionality on top of git. If I didn't have the 'squash merge' feature I'd just use an interactive rebase to fixup/squash the branch's commits before doing a fast-forward-only merge, because I don't want a git history littered with meaningless noise.
And the 'fewer commits are better so that must mean no commits is best' argument is such an obvious slippery slope fallacy, come on man. Do you seriously think this kind of argument will fly in real life? You are just going to annoy the crap out of everyone. We don't squash and rebase because we want fewer commits, we do it because we want fewer meaningless noise commits. Do you want to preserve all your editor keystrokes, like backspaces, moving code around, copy-pasting, etc., before committing? If you don't, then you obviously don't want to track any history, right? Of course not, that's silly. That's what your argument is like.
I don't want my repo history littered with meaningless noise like these merge commit messages:
The only thing that matters here is the log of the actual work, not the incidental artifact that git merged something.I also don't want a commit history that looks like London's tube system map. Please, keep the history linear so that myself and future team members can quickly focus on the parts that interest them, after just a glance, and don't have to spend time decoding the tangled mess of interlocking branch histories. Much appreciated!
i don't care how you do it. squashing? git reset followed by sensible commits? intense ninja-like git commit hygiene? or my favorite, liberal amounts of git rebase -i?
the only things i care about are these:
1. your PR contains a series of atomic commits
2. each commit makes a single logical change.
3. that each logical change is adequately described by the corresponding commit comment
4. extra credit if the series of changes is consistent to build and work at each step
i don't want to see "ONE" commit per-feature unless it's trivial.
i do want to see the development process, but in a "publish"-able form
i don't want to see "WIP", "almost working", "fixed broken", "redesigned ...", etc. sausage being made. i especially DON'T want to see patches to files be changed and reverted multiple times as mistakes are made and fixed.
the final PR should be you publishing a nice finished series of patches to accomplish a new feature.
then! we simply rebase that nice simple series on top of master and merge it with an optional merge commit. this gets you a nice linear history while avoiding the information loss with simply squashing everything in a PR/feature into a single commit.
Perhaps you live in London, a city with many subway lines and stations that makes many places easy to reach, just like a repository with commits that makes it easy to find where something was introduced.
I live in São Paulo, a city 2 times bigger than London but with a smaller subway map. Few places have a subway station near them. Finding the nearest station is only part of the problem, as we need to find a way to go from the station to where we need to be. Just like a repository that uses squash merges.
Both sentences starts with "I don't want" followed by aesthetic choices.