>

There are multiple ways to squash several commits to a single commits before we push to the remote repository.


##### 1. git rebase -i HEAD~x ---

This is the classic way to interactively modify the commits, take an example,

Assume we have 3 commits like this:

$ git log --pretty=format:"%h - %ar : %s"
9963f79 - 4 seconds ago : index.md
4148da5 - 5 minutes ago : java2
921fdb3 - 6 minutes ago : java1

We want to squash all these 3 commits to one

$ git rebase -i HEAD~3

this will open up an editor (e.g. vim), showing below info:

pick 921fdb3 java1
pick 4148da5 java2
pick 9963f79 index.md

# Rebase c59da30..9963f79 onto c59da30 (3 command(s))
# 
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
# d, drop = remove commit

What we need to do is to keep the first line unchanged, it is the oldest commit in these 3, we want to squash the following two commits to it.
change the following two picks to squash, like this:

pick 921fdb3 java1
squash 4148da5 java2
squash 9963f79 index.md

Save and exit, we were be prompt another editor asking us to modify the commit messages:

# This is a combination of 3 commits. 
# The first commit's message is:
java1

# This is the 2nd commit message:
java2

# This is the 3rd commit message:
index.md

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# interactive rebase in progress; onto c59da30
# Last commands done (3 commands done):
#    squash 4148da5 java2
#    squash 9963f79 index.md
# No commands remaining.
# You are currently editing a commit while rebasing branch 'master' on 'c59da30'.
#
# Changes to be committed:
#       new file:   test/hello.java
#       new file:   test/index.md
#       new file:   test/world.java

Edit the commit messages to one like this:

# This is a combination of 3 commits.
# The merged commit's message is:
java1 java2 index.md -> one

Save and exit, then check result:

$ git log --pretty=format:"%h - %ar : %s"
9ca1dde - 25 minutes ago : java1 java2 index.md -> one

Now we can push this merged commit to remote:

$ git push

##### 2. git reset --soft HEAD~X && git commit ---

This is a way of resetting the last several commits, by which means place those commited files back to staged area and then commit them all together.

$ git reset --soft HEAD~3
$ git commit -m 'squash last 3 commits'

Merge with last commit

$ git reset --soft HEAD~1

Note: This method has an advantage of avoiding interactively modify the commit messages in an editor can could be automated in a script.


##### 3. git merge --squash ---

In git, HEAD@{1} is where the branch was just before the previous command, so we can squash all commits from HEAD@{1} to current commit point.

$ git reset --hard HEAD~3
$ git merge --squash HEAD@{1}
$ git commit

###### More
Put the to-be-squashed commits on a working branch (if they aren't already) -- use gitk for this
Check out the target branch (e.g. 'master')
git merge --squash (working branch name)
git commit




###### Reference http://stackoverflow.com/questions/5189560/squash-my-last-x-commits-together-using-git/5201642#5201642