June 10, 2018

Using Git rebase

Updating and rebasing a branch

Back to when I started using Git, I was faced with this challenge. Someone has updated the upstream - how do I include the latest changes into my working branch?

The first approach is to pull master and merge it into the working branch:

Terminal
git pull origin master

Unfortunately, this way we're creating a new commit. What we really want is the following:

  1. Isolate our changes
  2. Get the latest upstream updates
  3. Apply the changes on top
  4. Resolve any conflicts

So we don’t want to merge our branch in the updated upstream but rebase on top of it.


First, let’s fast-forward the local master branch.

Terminal
git checkout master
git pull

Now let’s head back to our working branch and do a rebase. All of our commits will be applied on top of the updated master

Terminal
git checkout working_branch
git rebase origin master

You can completely ignore updating your local master branch and simply run git rebase origin/master. I like having my local master up to date so I opt for the first case.

At this point, we might have a few conflicts. We have a few options to deal with them:

  1. git rebase --abort will completely stop the rebase. The branch's initial state will be restored and we can start over. Nothing changed.
  2. git rebase --skip will ignore the local commit that causes the problem. This is useful if the commit is not relevant anymore or if it’s a mistake.
  3. or fix the conflicts, stage them and keep the rebase going with git rebase --continue

Merging the branch

Having finished the work, it’s always a nice idea to 'squash' commits that that are not relevant in isolation. For example, if you have a few commits that are just fixing typos or minor CSS tweaks, it’s better to merge them into a single commit.

Terminal
For this reason, doing an 'Interactive' rebase is really helpful

```txt title="Terminal"
git rebase -i master

Here’s an example of an interactive rebase prompt:

Terminal
pick 07c6add Include password strength indicator in registration formm
pick d29b1fb Fix the regex
pick 317tt36 Minor typo
pick fa2fff3 CSS tweaks

# Rebase 44a7ee6..fa2fff3 onto 44a7ee6
#
# 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
#
# 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.
#

Now you can do any of the following

  1. Pick - Keep the commit and move on to the next one
  2. Reword - Keep the commit, and get a prompt to update the message
  3. Edit - Keep the commit, but wait for you to update files and include them before moving on
  4. Squash - Merge into the commit above, and get a prompt to update the message
  5. Fixup - Same as Squash but it won’t prompt for a new message
  6. Exec - Allows running shell commands against a commit
You can reorder these commits around if needed.

For this case, we'll:

  1. Reword and keep the first commit
  2. Squash the rest and discard the commit message by doing a Fixup
Terminal
r 07c6add Include password strength indicator in registration formm
f d29b1fb Fix the regex
f 317tt36 Minor typo
f fa2fff3 CSS tweaks

As a result our branch will contain a single meaningful commit on top of all the latest upstream changes.

Finally, we can push the branch to the remote repository and enjoy an up to date branch.

Terminal
git push origin working_branch