Git Rebase

There are two ways to sync a feature branch with another branch; merge (git merge) or rebase (git rebase). Merging strategy has a few downsides like addition of a merge commit (or not if it can fast-forward), non-linear commit history and others. Where these things are important rebase strategy is viable.

Basic rebase

A rebase to sync changes from another branch can be done in the like this:

git checkout <feature_branch>
git rebase main

Internally, git rebase reapply commits from feature branch on top (ie after) of all changes/commits from main (or specified branch). It basically changes and move base/tip/parent of feature branch.

The following is the visual representation of it:

                 A---B---C feature
                /
           D---E---F---G main

The feature branch after rebase becomes

                         A'--B'--C' feature
                        /
           D---E---F---G main

Interactive rebase

Rebase also has an interactive mode, guiding you through the process and giving additional fine tune controls which can be used for following:

To do an interactive rebase, just add -i or --interactive flag:

git rebase -i main

It will show a visual prompt in a text editor, like the following:

pick f58924e xkcd 1296
pick dd820cc another, xkcd 1597
pick a58124a xkcd 688
 
# Rebase 0bbe6c4..dd820cc onto 0bbe6c4 (2 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# .       create a merge commit using the original merge commit's
# .       message (or the oneline, if no original merge commit was
# .       specified). Use -c <commit> to reword the commit message.
#
# 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.
#

Initial lines show a list of all commits in feature branch, followed by commented commands/actions which can be performed on them.

Change pick to whichever action (reword, edit, squash, drop, etc) required. Action which require additional input will open another set of prompts with instructions for the same. The sequence of commits can also be changed here by moving commit up or down the list.

Squashing commit

Rebase can also be used for squashing commits (in local branch) by following:

git rebase -i HEAD~3

Here 3 is the number of preceding commits to be squashed into one. The command, will open an interactive prompt, as shown in the interactive rebase section. Reorder commits, add pick to a single commit (in which others will be squashed) and move it to the top. Add squash before other commits. After saving, another prompt will open asking for a unified commit message. Edit, save and you’re done.

Caveats of rebase