How to squash commits which have merge-commit in between?

I am working on a feature branch.

  1. Made several commits. Squashed commits.
  2. Pushed changes to remote branch. Got conflicts.
  3. Merged changes from master, resolved conflicts on feature branch.
    • git fetch origin master
    • git merge FETCH_HEAD
    • Resolved conflicts manually.
    • git commit
    • git push
  4. I made one more commit.

So, current commit history looks like this. From current to old:

  1. commit 3
  2. commit M yyy (Merged)
  3. commit 2

How do I squash above 3 commits into 1 before I merge my feature branch to master?


Solution 1:

You can rebase -i starting with commit 2's parent (that is, the commit on master that you branched from. You'll likely have to re-resolve conflicts when you get to the merge commit.

So if your history looks like

  * D commit 3 (HEAD)
  * M merge
 /|
| * C commit 2
* | B commit on master
|/
* A (master)

Start with git rebase -i A. You'll see a list of commits including both master and your_branch, but not the merge commit. pick the first one (B or C, depending on timing) and squash the rest.

Solution 2:

You can use the tool I've created specifically for this task:

https://github.com/sheerun/git-squash

It's only necessary to merge master branch, and then run squashing command:

git merge master
git squash master

Solution 3:

Assuming the feature branch is called feature and the main branch main:

Create a temporary branch from main:

git checkout -b temp main

Squash the feature branch in:

git merge --squash feature

Commit the changes (the commit message contains all squashed commit messages):

git commit

Go back to the feature branch and point it to the temp branch:

git checkout feature
git reset --hard temp

Delete the temporary branch:

git branch -d temp