How to remove all previous commit messages and start clean

You've developed some code and are finally ready to upload it. Just doesn't feel right to have all the small commit messages in the initial live commit of the project. This is a way to use the final code with a clean commit message.

There are a few ways you could achieve this.

1. Remove .git

Perhaps the most basic way of dealing with this is to remove the repository and then just initialize it again.

$ rm -rf .git/
$ git init .

If you already did some customizations, you could copy the .git/config and .git/info/exclude file to some place safe. After the above commands, copy them back to the original location.

2. Orphan branch

Another possibility is to use an orphan branch. The option rev-list can be used to see the number of commits in a small but simple command.

$ git rev-list --count master

If you have more than one, and still need to commit to Github or whatever, then you could do use the orphan branch.

$ git checkout --orphan new-master master
$ git commit -m "Initial commit for new root"

We checkout the code to an orphaned branch called new-master. Then we commit the code.

As a safety check, compare the new-master branch with the master branch. The final commits of both branches should be identical.

$ git diff new-master master

If the git diff command doesn't produce any output, both branches are identical. Now we can safely delete the original master branch and move the new-master branch to the master branch.

$ git branch -D master
$ git branch --move new-master master

3. git rebase

git rebase can be used to combine commits into a large commit.

Warning

Do not do this if you already pushed to a public repository. Other developers might have to remerge their work.

Use git log to see find out the commits you want to squash. Next use the rebase option in interactive mode. git will open an editor and show you the commits

To test this yourself, create directory, put some files in, commit, and repeat this process with a few files. After you've done this, have a look at the commits:

$ git log
commit 54507ca8d75f7c3911910abe6df8e2aac2af94e7
Author: ICT Force <frekkr.linux1@ictforce.be>
Date:   Fri Nov 10 22:30:40 2017 +0100

    Decided to now also add a whisky scorer program

commit 6a3dab982a2ebefcd16076acabb31f7debcaf67e
Author: ICT Force <frekkr.linux1@ictforce.be>
Date:   Fri Nov 10 22:23:57 2017 +0100

    Some install specific instructions added to INSTALL file

commit a106a7302ceb443beb3f05d3470fb965ff9521d3
Author: ICT Force <frekkr.linux1@ictforce.be>
Date:   Fri Nov 10 22:23:06 2017 +0100

    Added a LICENSE file

commit 19ee2fc826f058ac9ab99edf5177b6dac92fc60f
Author: ICT Force <frekkr.linux1@ictforce.be>
Date:   Fri Nov 10 22:22:09 2017 +0100

    Created README and beer-score.py code

Now we tell git to rebase the last 3 commits:

$ git rebase -i HEAD~3

Or use the commit hash or part of it:

$ git rebase -i 19ee2fc

An editor is opened and you see some text with the commit messages:

pick a106a73 Added a LICENSE file
pick 6a3dab9 Some install specific instructions added to INSTALL file
pick 54507ca Decided to now also add a whisky scorer program

# Rebase 19ee2fc..54507ca onto 19ee2fc (3 commands)
#
# 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
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out

Since we want to squash these commits into the first commit, we will change the last 2 pick commands to squash.:

pick a106a73 Added a LICENSE file
squash 6a3dab9 Some install specific instructions added to INSTALL file
squash 54507ca Decided to now also add a whisky scorer program

# Rebase 19ee2fc..54507ca onto 19ee2fc (3 commands)
#
# Commands:

After saving this change and exiting the editor, we see another message:

# This is a combination of 3 commits.
# This is the 1st commit message:
Added a LICENSE file

# This is the commit message #2:

Some install specific instructions added to INSTALL file

# This is the commit message #3:

Decided to now also add a whisky scorer program

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date:      Fri Nov 10 22:23:06 2017 +0100
#
# interactive rebase in progress; onto 19ee2fc
# Last commands done (3 commands done):
#    squash 6a3dab9 Some install specific instructions added to INSTALL file
#    squash 54507ca Decided to now also add a whisky scorer program
# No commands remaining.
# You are currently editing a commit while rebasing branch 'master' on '19ee2fc'.
#
# Changes to be committed:
#       new file:   INSTALL
#       new file:   LICENSE
#       new file:   src/whisky-score.py
#

As the text explains, lines starting with # are ignored. Change the message, save and exit the editor. For this quick example, we use a simple message to see what happens:

# This is a combination of 3 commits.
# This is the 1st commit message:
This is our new commit message for the last 3 commits.

This results in the last 3 commits squashed into 1 commit:

[detached HEAD c246e0b] This is our new commit message for the last 3 commits.
 Date: Fri Nov 10 22:23:06 2017 +0100
 3 files changed, 4 insertions(+)
 create mode 100644 INSTALL
 create mode 100644 LICENSE
 create mode 100644 src/whisky-score.py
Successfully rebased and updated refs/heads/master.

Rechecking with git log:

$ git log
commit c246e0b6100533d98d1cb52a86894ca72475d5c8
Author: ICT Force <frekkr.linux1@ictforce.be>
Date:   Fri Nov 10 22:23:06 2017 +0100

    This is our new commit message for the last 3 commits.

commit 19ee2fc826f058ac9ab99edf5177b6dac92fc60f
Author: ICT Force <frekkr.linux1@ictforce.be>
Date:   Fri Nov 10 22:22:09 2017 +0100

    Created README and beer-score.py code

Again, only use the rebase if you code was not yet pushed to a public repository.

Note

It can be useful to tag the current state of your work before trying a rebase

4. cherry-pick

The git documentation on cherry-pick:

Given one or more existing commits, apply the change each one introduces, recording a new commit for each. This requires your working tree to be clean (no modifications from the HEAD commit).

To do this, we start a new branch starting from the commit we want to use as a base commit:

git checkout -b new-master master~3

Now we will add all commits to this branch one by one:

git cherry-pick -n master~2
git cherry-pick -n master~1
git cherry-pick -n master

Let's see what the commit history is:

$ git log
commit 19ee2fc826f058ac9ab99edf5177b6dac92fc60f
Author: ICT Force <frekkr.linux1@ictforce.be>
Date:   Fri Nov 10 23:22:09 2017 +0100

    Created README and beer-score.py code

Nice, as expected only the first message. Now let's commit the changes:

git commit -am "This is our new commit message for the last 3 commits."

The end result is the same as with the rebase command:

$ git log
commit 0870c8f06966d7510e6201d4634367bb63bcc006
Author: ICT Force <frekkr.linux1@ictforce.be>
Date:   Fri Nov 10 23:03:39 2017 +0100

    This is our new commit message for the last 3 commits.

commit 19ee2fc826f058ac9ab99edf5177b6dac92fc60f
Author: ICT Force <frekkr.linux1@ictforce.be>
Date:   Fri Nov 10 23:22:09 2017 +0100

    Created README and beer-score.py code

Well not quite, as we still have an extra branch. We delete the master (merging master with new-master but be stupid as you will end up with 2 more additional messages: 1 from the new commit message, and 1 from the merge.

$ git branch -D master
$ git branch --move new-master master

5. git reset

It's also possible to use git reset. Basically, you reset to the commit you want to use as a starting point and then use git commit -m:

$ git reset --soft HEAD~3

Checking the commit history:

$ git log
commit 19ee2fc826f058ac9ab99edf5177b6dac92fc60f
Author: ICT Force <frekkr.linux1@ictforce.be>
Date:   Fri Nov 10 23:22:09 2017 +0100

    Created README and beer-score.py code

The files added in the subsequent commits should now be listed as NEW. Let's find out:

git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   INSTALL
    new file:   LICENSE
    new file:   src/whisky.py

Now we commit all the files at once:

$ git commit -am "This is our new commit message for the last 3 commits."

The project now shows 2 commits:

$ git log
commit c3fdc352089887a9ab1ad9c42e9ec1f8ddcbba81
Author: ICT Force <frekkr.linux1@ictforce.be>
Date:   Fri Nov 10 23:17:05 2017 +0100

    This is our new commit message for the last 3 commits.

commit 19ee2fc826f058ac9ab99edf5177b6dac92fc60f
Author: ICT Force <frekkr.linux1@ictforce.be>
Date:   Fri Nov 10 23:22:09 2017 +0100

    Created README and beer-score.py code