How to squash commits in git after they have been pushed?

GitSquash

Git Problem Overview


This gives a good explanation of squashing multiple commits:

http://git-scm.com/book/en/Git-Branching-Rebasing

but it does not work for commits that have already been pushed. How do I squash the most recent few commits both in my local and remote repos?

When I do git rebase -i origin/master~4 master, keep the first one as pick, set the other three as squash, and then exit (via c-x c-c in emacs), I get:

$ git rebase -i origin/master~4 master
# Not currently on any branch.
nothing to commit (working directory clean)

Could not apply 2f40e2c... Revert "issue 4427: bpf device permission change option added"
$ git rebase -i origin/master~4 master
Interactive rebase already started

where 2f40 is the pick commit. And now none of the 4 commits appear in git log. I expected my editor to be restarted so that I could enter a commit message. What am I doing wrong?

Git Solutions


Solution 1 - Git

Squash commits locally with

git rebase -i origin/master~4 master

and then force push with

git push origin +master

Difference between --force and +

From the documentation of git push:

> Note that --force applies to all the refs that are pushed, hence using > it with push.default set to matching or with multiple push > destinations configured with remote.*.push may overwrite refs other > than the current branch (including local refs that are strictly behind > their remote counterpart). To force a push to only one branch, use a + > in front of the refspec to push (e.g git push origin +master to force > a push to the master branch).

Solution 2 - Git

On a branch I was able to do it like this (for the last 4 commits)

git checkout my_branch
git reset --soft HEAD~4
git commit
git push --force origin my_branch

Solution 3 - Git

Minor difference to accepted answer, but I was having a lot of difficulty squashing and finally got it.

$ git rebase -i HEAD~4
  • At the interactive screen that opens up, replace pick with squash at the top for all the commits that you want to squash.
  • Save and close the editor

Push to the remote using:

$ git push origin branch-name --force

Solution 4 - Git

A lot of problems can be avoided by only creating a branch to work on & not working on master:

git checkout -b mybranch

The following works for remote commits already pushed & a mixture of remote pushed commits / local only commits:

# example merging 4 commits

git checkout mybranch
git rebase -i mybranch~4 mybranch

# at the interactive screen
# choose fixup for commit: 2 / 3 / 4

git push -u origin +mybranch

I also have some pull request notes which may be helpful.

Solution 5 - Git

git rebase -i master

you will get the editor vm open and msgs something like this

Pick 2994283490 commit msg1
f 7994283490 commit msg2
f 4654283490 commit msg3
f 5694283490 commit msg4
#Some message 
#
#some more

Here I have changed pick for all the other commits to "f" (Stands for fixup).

git push -f origin feature/feature-branch-name-xyz

this will fixup all the commits to one commit and will remove all the other commits . I did this and it helped me.

Solution 6 - Git

  1. git rebase -i HEAD~4

To elaborate: It works on the current branch; the HEAD~4 means squashing the latest four commits; interactive mode (-i)

  1. At this point, the editor opened, with the list of commits, to change the second and following commits, replacing pick with squash then save it.

output: Successfully rebased and updated refs/heads/branch-name.

  1. git push origin refs/heads/branch-name --force

output:

remote:
remote: To create a merge request for branch-name, visit:
remote: http://xxx/sc/server/merge_requests/new?merge_request%5Bsource_branch%5D=sss
remote:To ip:sc/server.git
 + 84b4b60...5045693 branch-name -> branch-name (forced update)

Solution 7 - Git

For squashing two commits, one of which was already pushed, on a single branch the following worked:

git rebase -i HEAD~2
    [ pick     older-commit  ]
    [ squash   newest-commit ]
git push --force

By default, this will include the commit message of the newest commit as a comment on the older commit.

Solution 8 - Git

When you are working with a Gitlab or Github you can run in trouble in this way. You squash your commits with one of the above method. My preferite one is:

git rebase -i HEAD~4
or
git rebase -i origin/master

select squash or fixup for yours commit. At this point you would check with git status. And the message could be:

    On branch ABC-1916-remote
    Your branch and 'origin/ABC-1916' have diverged,
    and have 1 and 7 different commits each, respectively.
      (use "git pull" to merge the remote branch into yours)

And you can be tempted to pull it. DO NOT DO THAT or you will be in the same situation as before.

Instead push to your origin with:

git push origin +ABC-1916-remote:ABC-1916

The + allow to force push only to one branch.

Solution 9 - Git

Sqush Changes in remote

  • First ensure your local master is at par with remote
  • Then reset your local feature branch to be at par with master: git reset --soft master
  • then add all ur modifications and changes (that you made on your local feature branch you just reset to master) to staging area: git add .
  • then commit these changes: git commit -m "this is the final commit message"
  • then force push to remote branch: git push RemoteBranch --force

Solution 10 - Git

In my case requirement was to squash all the feature branch commits into one, to have a clean commit history. Utilized the GitHub UI to do so.

Problem:

  • Feature branch (eg:featureBranch) has been created from master (a month ago).
  • Committed all my changes to the featureBranch (~12 commits, a month of work). And has been pushed to remote regularly.

Requirement:

  • To Get the feature branch updated with the master and to have a single commit in a featureBranch

Steps followed:

  • Create a new branch (eg: featureBranchLatest) from master in GitHub UI.
  • Create a PR from featureBranch to featureBranchLatest.
  • Resolve conflicts if any. Merge the PR with the squash commit option in GitHub UI. (Alter the commit message to have a cleaner message).

Now the featureBranchLatest will have a single commit of all the changes needed in a single commit, along with the latest changes from the master. Delete the old branch featureBranch if not required for reference.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionLorenView Question on Stackoverflow
Solution 1 - GitAlan Haggai AlaviView Answer on Stackoverflow
Solution 2 - Gitjakob-rView Answer on Stackoverflow
Solution 3 - GitBLRBoyView Answer on Stackoverflow
Solution 4 - GitStuart CardallView Answer on Stackoverflow
Solution 5 - GitNupurView Answer on Stackoverflow
Solution 6 - GitterwxqianView Answer on Stackoverflow
Solution 7 - GitlobsterhandsView Answer on Stackoverflow
Solution 8 - GitAlexView Answer on Stackoverflow
Solution 9 - GitZulView Answer on Stackoverflow
Solution 10 - GitSasi Kumar MView Answer on Stackoverflow