Merging Commits with git rebase

2013-09-07 12:00Edit this page

Recently I’ve been frequently using git for version control and code commits, and gradually discovered the usage and benefits of git rebase. It’s especially flexible when organizing and merging git commit history.

Use Case

After making a commit, you immediately notice that a line or two of code needs to be changed. After making the change, you commit again, then find something else that’s not right…

[root@addcp gitdemo]# vim test.txt
[root@addcp gitdemo]# git commit -am "add test.txt"

Found some code that needs minor changes:

[root@addcp gitdemo]# vim test.txt
[root@addcp gitdemo]# git commit -am "update test.txt"
...
...

Found issues for the Nth time:

[root@addcp gitdemo]# vim test.txt
[root@addcp gitdemo]# git commit -am "update test.txt again and again"
...

The Problem

After doing this multiple times, the git commit history becomes messy - a bunch of small changes taking up many commit entries:

[root@addcp gitdemo]# git log
commit abe26fe0f5b1788e8f7b1949082e1477c5337aa0
Author: xiaocang <xiaocang@addcp.com>
Date:   Sat Sep 7 01:29:48 2013 +0800

    update test.txt again and again

commit c3633d5153bacabeceaeaeb552484e7f9b6a2b9c
Author: xiaocang <xiaocang@addcp.com>
Date:   Sat Sep 7 01:29:21 2013 +0800

    update test.txt again

commit c8bc032daac7d0859a0e73cd83a464cee0f59625
Author: xiaocang <xiaocang@addcp.com>
Date:   Sat Sep 7 01:28:51 2013 +0800

    update test.txt

commit 0e80061e90503189dd7f189297aed809953e5e8b
Author: xiaocang <xiaocang@addcp.com>
Date:   Sat Sep 7 01:28:22 2013 +0800

    add test.txt
......

Rebase Example and Usage

Using git rebase to solve this problem is very easy.

The git rebase syntax is:

git rebase [--interactive | -i] [-v] [--force-rebase | -f] [--no-ff] [--onto <newbase>] [<upstream>|--root] [<branch>] [--quiet | -q]

Here we use the -i option, which is interactive rebase:

[root@addcp gitdemo]# git -i HEAD~3

Where HEAD~3 refers to the last three commits of this branch. You can also add a <branch> parameter to specify the branch to rebase.

pick c8bc032 update test.txt
f c3633d5 update test.txt again
f abe26fe update test.txt again and again

# Rebase 0e80061..abe26fe onto 0e80061
#
# 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
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.

Where pick commits as-is.

reword also commits, but lets you edit the commit message before committing.

edit is similar to reword, but after editing the commit message, it waits for you to git commit --amend, meaning it waits for you to add some files and changes. Then use git rebase --continue to complete the entire rebase.

squash merges this commit into the previous one, but combines the log content of this commit into the previous one.

fixup differs from squash in that it automatically ignores this commit’s log content. This is exactly what I needed for this commit cleanup.

Rebase Result

As shown above, I get a log like this:

[root@addcp gitdemo]# git log
commit 3e5d79d149942f7dc0741a9a42ce43d98beafcd3
Author: xiaocang <xiaocang@addcp.com>
Date:   Sat Sep 7 01:28:51 2013 +0800

    update test.txt

commit 0e80061e90503189dd7f189297aed809953e5e8b
Author: xiaocang <xiaocang@addcp.com>
Date:   Sat Sep 7 01:28:22 2013 +0800

    add test.txt

Now everything is clean and tidy.


Note

Anyone who has read the official git documentation should know:

Do not rebase commits that have been pushed to a public repository

Because changing the commit history on a public repository is not good for a multi-person collaborative project.

Other people on the project will be confused because a commit that previously existed suddenly disappears.

So rebasing is mainly a method for cleaning up commit history before pushing to a public repository.

Unless otherwise stated, articles on this blog are licensed under the Creative Commons Attribution 4.0 International License. Please credit the original author and source when sharing.


Tags: archive

No comments yet

Leave a comment

Creative Commons © 2013 — 2026 xiaocang | Theme based on fzheng.me & NexT | Hosted by Netlify