Git Rebase: How to Squash Multiple Commits into One

Lakmuthu Dodamwalage
4 min readAug 18, 2024

--

When Should You Use This?

Imagine you are working on a feature or issue that takes a few days to complete. At the end of each day, you commit your work as “WIP” (Work In Progress) and continue the next day. By the time you finish, your branch has multiple commits with vague messages like “WIP-1”, “WIP-2”, and “WIP-3”.

This isn’t ideal for a Pull Request (PR) because these unclear commit messages can make the review process more challenging for your peers. Therefore, it’s good practice to squash these commits into a single, well-explained commit before creating your PR.

How to Squash Commits

Now, let’s go through the process step by step.

Step 1: Check Your Current Commits

First, you need to see the list of commits in your branch. Use the following command:

git log --oneline --decorate --graph

This will display all commits in a condensed format, helping you identify which ones you need to squash.

Step 2: Start Interactive Rebase

To combine your commits, you’ll use the interactive rebase feature. Type the following command:

git rebase -i HEAD~<number_of_commits>

Replace <number_of_commits> with the number of commits you want to squash. For example, if you have three WIP commits, use HEAD~3.

Step 3: Edit the Rebase File

When you run the rebase command, it will open an editor in your terminal. Here’s how to proceed:

  • Pick the first commit: This will be your base commit that remains unchanged.
  • Squash the rest: Change the keyword pick to squash (or s) for the other commits you want to combine with the base commit.

You can see other options in the rebase editor, but for now, focus on changing pick to squash.

To save the changes, press Esc, type :wq!, and hit Enter.

Step 4: Resolve Any Conflicts

During the rebase process, conflicts might occur. If they do, resolve them in the affected files, and then run:

git add .
git rebase --continue

This command will either complete the rebase or continue it if there are more conflicts to resolve.

Step 5: Finalize the Commit Message

After resolving conflicts (if any), Git will ask if you want to edit the commit message. You can either keep the message from the final WIP commit or create a new, descriptive message that clearly explains the feature.

If you need to edit the commit message later, you can re-run the rebase for a single commit using:

git rebase -i HEAD~1

Then, use the r command to revise the commit message.

Step 6: Push Your Changes

Finally, ensure your branch is clean by running:

git log --oneline

If everything looks good, push your changes to the remote repository.

Comparing Push Commands

You have two options when force-pushing your changes:

  1. git push origin +<branch_name> or git push --force: This command forcefully pushes your changes to the remote branch, potentially overwriting any changes made by others that you might not be aware of. It can be risky in collaborative environments because it does not check if the remote branch has diverged from your local branch.
  2. git push --force-with-lease: This command also force-pushes your changes but with an added safety check. It ensures your local branch is up-to-date with the remote branch before force-pushing. If someone else has pushed new commits to the remote branch after your last pull or fetch, the --force-with-lease command will fail, alerting you to those changes. This prevents you from accidentally overwriting someone else’s work.

Why Use --force-with-lease?

  • Collaborative Safety: In a shared repository, other contributors might push changes to the branch while you’re working. The --force-with-lease command prevents your force-push from overwriting their contributions unless you've pulled their changes first.
  • Minimizes Risk: It reduces the risk of losing work, making it a safer option for force-pushing when you need to overwrite your branch’s history after actions like rebasing or squashing commits.

In summary, git push --force-with-lease is recommended over git push --force or git push origin +<branch_name> because it provides an additional layer of protection against overwriting changes made by others.

Final Steps Before Creating a PR

Before creating your PR, ensure your branch is up-to-date with the parent branch:

git checkout <parent_branch>
git pull
git checkout <your_branch_name>
git rebase <parent_branch>

Resolve any conflicts that arise, continue the rebase, and then do a hard push:

git push --force-with-lease

Now, you’re ready to create your PR. Boom, you’re done!

Uses of Squashing Commits

  • Simplifies Code Review: A single, well-explained commit is easier to review than multiple, vague WIP commits.
  • Cleaner Commit History: Your project’s commit history remains clean and meaningful, which is especially important for open-source projects.
  • Better Collaboration: Team members can more easily understand and collaborate on changes when the commit history is clear and concise.

--

--

Lakmuthu Dodamwalage
Lakmuthu Dodamwalage

Written by Lakmuthu Dodamwalage

Software Engineer with 3+ years of experience in Laravel, PHP, AWS, and Docker. Passionate about back-end development, cloud tech.

No responses yet