How to squash multiple git commits

Kent C. Dodds
InstructorKent C. Dodds

Share this video with your friends

Send Tweet
Published 6 years ago
Updated 3 years ago

Often, project maintainers prefer that a single pull request be represented by a single commit. It makes the git history cleaner and easier to understand. So before your pull request is merged you’ll want to do an interactive git rebase to squash all of your commits and fix your commit message.

[00:00] Now that our changes have been reviewed and the maintainer is good to bring them in, let's clean up our pull request a little bit by squashing both our commits into a single commit and updating the commit message to follow the standards.

[00:11] Let's start at the interactive git rebase. To start a rebase, we need to provide the parent commit of the oldest commit for the start of the rebase. If we enter "git log," we can see that the oldest commit we care about is our first commit here. Let's copy the SHA of the parent commit and use that to do our rebase.

[00:28] Now we'll run the command "git rebase -i." This stands for interactive, which will give us the opportunity to alter individual commits in the process of our rebase. Then we'll paste in the SHA that we just copied.

[00:40] That will open our default editor with the rebase file. I should note that, for me, this is opening in VIN. If you're not comfortable with VIN, look up how you can change the default editor for Git so you can use an editor you're comfortable with.

[00:52] There are a few things you can do for each commit in an interactive rebase. Those are listed in the comments section in this rebase file. I won't discuss all of these in this lesson, but it's helpful to note that an interactive rebase with Git is incredibly powerful.

[01:05] You can think of each line as a command for the rebase to run. If we remove a line, that command is removed and the commit is skipped during the rebase. The commands run, from top to bottom. For us, we simply want to combine these two commits into a single commit and change the commit message for that single commit.

[01:22] To do this, we're going to use the squash command for the bottom commit, which will meld it into the previous commit. If you had more commits you wanted to squash together, you would use this same command for each of them.

[01:33] With this order of commands, it's first going to apply this first commit and then it will squash this second commit into that first commit.

[01:40] Now, we'll save the file and close our editor. Git will begin to execute our commands. Our editor has opened again because the squash command requires a new message. Here, it's giving us the message for both commits being squashed.

[01:53] We'll clear this out and save the file with the message we want for the squashed commit.

[01:57] That's it. If we run git log, we can see that we now have a single commit with a proper commit message. We're good to push our changes to update our pull request.

[02:07] Remember, a rebase is rewriting history so we need to force push to our branch to update our pull request. Otherwise, our push will be rejected. Also remember that this is a destructive operation. You want to double check that you know what you're doing before you do this.

[02:22] Now we'll enter "git push -f" to update the PR. Now we can look at the pull request and it looks terrific. There's a single commit with a conventional commit message. The git dif is exactly right and all the checks have passed. This is ready to be merged.

[02:36] It's important to note that pushing updates to a pull request will not notify the project maintainer or anyone else watching the pull request, so if you want the maintainer to receive a notification you'll need to leave a comment indicating that you've updated the PR and are waiting patiently for feedback. We'll do that now.

James Talmage
James Talmage
~ 6 years ago

Now that GitHub gives maintainers the ability to squash and merge easily from the web interface, I consider asking contributors to squash to be an antipattern. I want to be able to come back after a contributor has addressed my code review and view only the changes since my last comment. If I have asked for just a minor fixup on a large PR, and they squash, I now need to hunt down that minor change in a much larger diff. Squashing also makes it easier for unrelated changes to get slipped into files in the PR that I've already "approved" in my head without me noticing. It is a rare occurrence, and I've never seen it done nefariously, but it's another reason against having the contributor self squash.

Kent C. Dodds
Kent C. Doddsinstructor
~ 6 years ago

I totally agree with you. Thanks for bringing it up. This video was created before the squash and merge functionality was implemented in GitHub's UI.