On April 1, 2016, GitHub released a feature that allows you to squash your commits before merging a pull request. Prior to this feature, you had to do this manually by locally squashing and force pushing to the pull request’s branch. The ability to handle the squashing directly on GitHub’s interface saves time, but it does more than just save time: it preserves the individual commits of that pull request.

If you were to locally squash and force push, you’d be disconnecting those squashed commits from their formerly associated branch. They still exist locally, technically, until you run git prune, but unless you happen to know their SHAs then you’ll never be able to find them.1 2

In contrast, when you squash using GitHub’s squash and merge feature, you aren’t changing the pull request’s commits. They remain as they were. Usually this doesn’t have much bearing — you squash and merge, delete the branch, and move on. But what if in that pull request you started to solve a problem one way, committed, and then proceeded to solve the problem another way? Those two commits representing those two different solutions will continue to be accessible in perpetuity if you squash and merge directly on GitHub. This would not be the case if you locally squashed (or performed a fixup) as the final step before force pushing and merging the pull request.

What GitHub has really done, besides make our lives more convenient, is make all of our code changes accessible in a way that it previously was not.

  1. Well, technically you can, but it’s like looking for a needle in a haystack if your working head has any amount of subsequent history on it. I’ve done Nick’s approach but only in a pinch and as a last resort. In anticipation of disconnecting a commit that I might later need, I’ve written down the SHAs in a sticky note before. ↩︎
  2. It’s also worth noting here that GitHub never runs git prune. That means that unless you go far, far out of your way to delete a commit, it’s on GitHub’s servers forever. You might detach it from anything, making it for all practical purposes as secure as a private Gist, but if someone knows the hash, they can still access it (assuming they have repo read access). ↩︎