My Git Rebase Workflow

In this document, I’ll explain my Git workflow using the rebase feature. I have been using this workflow for a long time, and it works regardless of the situation be it with single master branch, feature branches and even forking projects and submitting pull requests. While it might sound more confusing at the start as compared to just creating commits and merging normally, hopefully I can shed some insight on the advantages of this method.

What is Rebase?

The first thing to understand about Git is that at the core it is a linked list (or a tree to be technically correct).

While each commit stores diffs and Git uses this to construct the entire repo (which might be a complex process), the order of commits can be moved around with little disruption (assuming they work on different pieces of code).

In this case, we have a feature branch which has two commits. However, in the time that the commits have been made, new commits have appeared on the master branch. If we were to merge the feature branch onto master it will require you to create a merge commit to join the two branches together.

Doing a rebase can be thought of as a “replay”, to apply the commits as though they were being made now. Rebasing the feature branch against master results in:

This effectively changes the feature branch to be based off the latest commit in the master branch, and replays the commits on the feature branch on the master branch.

Why Rebase instead of Merge?

The main advantage of the rebase workflow is that it maintains the commit history and the commit authors without creating superfluous merge commits. This helps when tracking bugs/issues in the code and it is required to get the context of who/why were certain lines of code written the way they are, as opposed to getting distracted by merge commits which might result in the git history showing the wrong commit/author as the most recent committer for a line of code.

It also maintains chronological order of the master branch (while sacrificing the local order). This is something that usually confuses people as they might wonder why a commit that they wrote 2 days ago appears after a commit on the master branch which was written just before their rebase against master. However, when we consider that the master branch is the source of truth, we give priority to commits that were made “public” (pushed to origin master) over commits that were made in “private” (locally). This also clears up misunderstanding when two authors may work on the same piece of code, it is the responsibility of the person making the later commit to master to ensure that the their code is compatible (even if they may have written their code before).

Rebase Workflow

I’ll share a workflow that should work for the new proposed branching and PR

  1. Fetch origin changes
  2. Merge origin/master branch into local master branch
  3. Create a branch
  4. Write code💻!! Commit Early and Often
  5. Fetch origin again (in case origin master has had new commits since branch was created)
  6. Rebase against origin/master
  7. Push the branch
  8. Open Pull Request.

1. Fetch Origin Changes

Before doing anything, keep up to date with origin. Fetch the most recent code from the master branch of origin. Git will store these contents locally in origin/master

$ git fetch origin master

Origin

master

Local

master

origin/master

2. Merge origin/master Branch into Local master Branch

$ git chekout master
$ git merge origin/master

Update the local master branch to reflect the changes in origin/master. This will perform a fast-forward merge leaving both master and origin/master at the same commit.

Origin

master

Local

master

origin/master

3. Create a Branch

Now, a branch can be created to track new work.

$ git branch feature
$ git checkout feature

or simply:

$ git checkout -b feature

Origin

master

Local

feature

master

origin/master

4. Write code💻!! Commit Early and Often

Do some actual coding here.

Try to make atomic commits: each commit should do a specific functionality. Write good commit messages.

Commits can be cleaned up here. git rebase interactive HEAD~n opens up the last n commits which allows you to edit the order and how they are applied. It opens up a list of commits that would be applied top to bottom and the commands to apply for each commit. Both the order of the commits and the command itself can be changed. Some useful commands are: edit, fixup.

Origin

master

Local

feature

master

origin/master

5. Fetch Origin Again (in case origin master Has Had New Commits since Branch Was created)

Before the commits can be merged back, need to grab any new commits that have appeared on origin.

$ git fetch origin master

Origin

master

Local

feature

master

origin/master

6. Rebase against origin/master

Rebase will change the original commit on which a branch is based. Rebase will result in new commits (with the same commit messages) with new SHA-1 hashes. Typically rebase will the be done against the branch that is intended to be merged into. In this case, it would be origin/master.

$ git rebase origin/master

Origin

master

Local

feature

master

origin/master

7. Push the Branch

Push the branch to origin.

$ git push --set-upstream origin feature

If there has been a rebase on the branch, it might be required to do a force push

$ git push --force-with-lease origin feature

--force-with-lease will only force push if the remote branch is in the state you expect (i.e., no one else has pushed to it since your last fetch).

Warning! Be careful when rebasing public branches. Rebase should only be done on branches on which you are certain you are the only one working/locally. If you rebase a public branch (eg. master) and push it to origin, it will result in the history being messed up and cause others who have their older version of the branch to have issues merging their branch.

Origin

feature

master

Local

feature

master

origin/master

8. Open Pull Request

At this point, we can open a Pull Request to get a colleague to review. If there is a need to make any changes to the branch, just follow steps 5-7. Pushing to the branch will update the Pull Request with the changes to the branch.

Once the PR is approved, it can be merged into master.

Origin

master

Local

feature

master

origin/master

After this, update your local origin/master and master branches using steps 1 and 2.

Some other Tips

Pull (fetch + merge) but using rebase. Autostash helps when you have changes in your directory, it automatically stashes, pulls and pops the stash.

git pull --rebase --autostash