You can do this fairly easily without git rebase or git merge --squash. In this example, we'll squash the last 3 commits:
git reset --soft HEAD~3
If you also want to write the new commit message from scratch, this suffices:
git reset --soft HEAD~3
git commit -m "Squashed commit"
If you want to start editing the new commit message with a concatenation of the existing commit messages (i.e. similar to what a pick/squash/squash/…/squash git rebase -i instruction list would start you with), then you need to extract those messages and pass them to git commit:
git reset --soft HEAD~3 &&
git commit --edit -m"$(git log --format=%B --reverse HEAD..HEAD@{1})"
Both of those methods squash the last three commits into a single new commit in the same way. The soft reset just re-points HEAD to the last commit that you do not want to squash. Neither the index nor the working tree are touched by the soft reset, leaving the index in the desired state for your new commit (i.e. it already has all the changes from the commits that you are about to “throw away”).
Edit Based on Comments
Because git reset and git rebase rewrite history, you must use the --force flag to push the modified branch to the remote. This is what the --force flag is meant for. You can also be extra careful and fully define your target:
git push --force-with-lease origin <branch-name>
Answer from Chris Johnsen on Stack OverflowYou can do this fairly easily without git rebase or git merge --squash. In this example, we'll squash the last 3 commits:
git reset --soft HEAD~3
If you also want to write the new commit message from scratch, this suffices:
git reset --soft HEAD~3
git commit -m "Squashed commit"
If you want to start editing the new commit message with a concatenation of the existing commit messages (i.e. similar to what a pick/squash/squash/…/squash git rebase -i instruction list would start you with), then you need to extract those messages and pass them to git commit:
git reset --soft HEAD~3 &&
git commit --edit -m"$(git log --format=%B --reverse HEAD..HEAD@{1})"
Both of those methods squash the last three commits into a single new commit in the same way. The soft reset just re-points HEAD to the last commit that you do not want to squash. Neither the index nor the working tree are touched by the soft reset, leaving the index in the desired state for your new commit (i.e. it already has all the changes from the commits that you are about to “throw away”).
Edit Based on Comments
Because git reset and git rebase rewrite history, you must use the --force flag to push the modified branch to the remote. This is what the --force flag is meant for. You can also be extra careful and fully define your target:
git push --force-with-lease origin <branch-name>
Use git rebase -i <after-this-commit> and replace "pick" on the second and subsequent commits with "squash" or "fixup", as described in the manual:
"fixup" to discard the commit message, and squash it right away.
"squash" to combine the commit message with the previous one, and be able to edit it before squashing.
In this example, <after-this-commit> is either the SHA1 hash or the relative location from the HEAD of the current branch from which commits are analyzed for the rebase command. For example, if the user wishes to view 5 commits from the current HEAD in the past, the command is git rebase -i HEAD~5.
-
Basically "squash" multiple merge commits of different branches into one super branch and one final merge commit with all changes?