Skip to content

Git Rebase Workflow

thewoolleyman edited this page Nov 20, 2014 · 16 revisions

Overview:

  • These are some rough notes on a Git workflow that uses rebasing instead of merging for feature branches.
  • This is an incomplete work in progress It was originally copied from https://gist.github.com/17twenty/6733076 (the best writeup I could find), and then modified. Some things are still not completely accurate, and some I (Chad Woolley) don't fully agree with (e.g. using tags)
  • It also doesn't cover how to handle production release branches (which, like master, are never rebased). Essentially, these can just be branches off of a stable master branch revision.
  • I (Chad Woolley) am working on a tool, 'gitrflow' to support this workflow, as well as some documentation on why rebasing is preferred for feature branches.
  • Finally, an alternative to feature branches (when they are used to hide incomplete features in production is Feature Flags/Toggles.

a simple git branching model

This is a very simple git workflow. It (and variants) is in use by many people. I settled on it after using it very effectively at Athena. GitHub does something similar; Zach Holman mentioned it in this talk.

The gist

  1. master must always be deployable.
  2. all changes made through feature branches (pull-request + merge)
  3. rebase to avoid/resolve conflicts; merge in to master

Or, as Zach Holman succinctly put it:

flow

The workflow

IMPORTANT PREREQUISITES:

  • With this workflow, only ONE PERSON OR PAIR AT A TIME should work on a feature branch concurrently.
  • After a rebase, you will be required to force push - this is OK because only one person at a time is working on it.

Normally, you can work on master, unless you think you will break something.

# everything is happy and up-to-date in master
git status # make sure your working directory is clean

# discarding all changes you don't want
# If you want to discard all changes in your working directory and start over:
git reset --hard
git clean -df

# checkout master branch
git checkout master
git pull origin master

# make changes on master... edit code

# If your changes are safe (and you ran tests), commit on master:
git add -p
git commit -m "message"
git pull --rebase # to get any changes that have happened on master since you started
git push [origin master]

If you think there's a chance you may break something use a feature branch instead of doing the commit on master.

So, use this flow to get on a feature branch, or if you're already on one.

# let's branch to make changes
git checkout -b my-new-feature

# make any more required changes...

# commit your (incremental, atomic) changes
git add -p
git commit -m "my changes"

# push your changes to the feature branch
git push origin my-new-feature

# keep abreast of other changes to master.
# rebasing keeps our code working, merging easy, and history clean.
# Do this often - at the beginning of every day, and after every
# push to the feature branch
git fetch origin
git rebase origin/master
# IMPORTANT NOTE: If you have conflicts, always use '--continue', never '--skip'.
#                 See "DOs" and "DON'Ts" below.  If you are confused, ask for help

# push your branch to github after every commit
git push --force origin my-new-feature

important note: Note the "force" above in the push. This is necessary after a rebase, because the SHAs of the commits change. However, if you are the ONLY person/pair working on the feature branch (and you should be!), then it is fine to force push, because nobody else should have changed it.

# optional: feel free to rebase within your feature branch at will.
#           ok to rebase after pushing if your team can handle it!
git rebase -i origin/master

# merge when done developing.
# --no-ff preserves feature history and easy full-feature reverts
# merge commits should not include changes; rebasing reconciles issues
# github takes care of this in a Pull-Request merge
git checkout master
git pull origin master
git merge --no-ff my-new-feature

# now push the branch to master
git push origin master

# this MIGHT fail if somebody happened to push to master while you were merging.
# If so, you can do `git pull --rebase` to get their changes, then try pushing again
git pull --rebase && git push origin master

# after you are done merging your feature branch back to master and pushing, delete the local
# branch with the '-d' option (not forced, like -D).  if you have successfully merged
# all the feature branch's commits to master, this no-force delete command should complete
# with no warnings or errors, because git knows all the commits on the branch have 
# been successfully merged to master.
git branch -d my-new-feature

# Then, delete the remote branch off of github:
git push --delete origin my-new-feature

# then everyone else can do a fetch with --prune to clean up the branch
# off their local machines
git fetch --prune

# optional: tag important things, such as releases
git tag 1.0.0-RC1

useful config

# autosetup rebase so that pulls rebase by default
git config --global branch.autosetuprebase always

# if you already have branches (made before `autosetuprebase always`)
git config branch.<branchname>.rebase true

DOs and DON'Ts

No DO or DON'T is sacred. You'll obviously run into exceptions, and develop your own way of doing things. However, these are guidelines I've found useful.

DOs

  • DO keep master in working order.
  • DO rebase your feature branches.
    • DO pull in (rebase on top of) changes
  • DO tag releases
  • DO push feature branches for discussion
  • DO learn to rebase
    • When rebasing in changes and resolving conflicts, always use '--continue' - never skip conflicts

DON'Ts

  • DON'T merge in broken code.
  • DON'T rebase master.
  • DON'T merge with conflicts. handle conflicts upon rebasing.
    • When rebasing, you should NEVER commit a merge conflict! If you end up with a merge conflict, you did something wrong, and should abort and start over.

Links

FAQ

Won't git merge --no-ff generate merge bubbles?

Yes. Merge bubbles aren't inherently bad. They allow you to revert entire features at a time. They get confusing and annoying to deal with if they cross (commits interleave), so don't do that.

merge bubbles

What do you mean by "incremental, atomic" changes?

http://en.wikipedia.org/wiki/Atomic_commit#Atomic_Commit_Convention

Thanks wikipedia, I couldn't have put it better myself.

Why not gitflow or another complex workflow?

Be my guest. I've used gitflow and other similar models. After working in various teams, this is just what I've come to use. But next time you have to ask someone whether it is okay to push or pull from this or that branch, remember my face.

But, is it web-scale?

Friends claim more complex models are necessary for scaling large teams, maintaining old releases, controlling information flow, etc. It very well may be that using multiple mainlines (e.g. develop, stable, release, v2, tested, etc) is exactly what fits your organization's constraints. That's for you to decide, not me (unless we work together -- oh hi there!).

But you always have to wonder, "shouldn't I use tags for that"? For example, tracking releases on a branch is a bit silly. A release commit can be tagged. You can checkout a tag, just like any branch, or any commit, and do whatever it is you need to do.

My guess is this relationship holds:

headless

So, perhaps taking five minutes to teach your team how to use checkout and tag might save you more than 15% on car insurance.

GitHub notes

Don't fork. Push feature branches to main repo.

Sometimes I see people forking repositories in order to issue pull-requests. Yes, you may have to do this when contributing to open-source projects you don't regularly contribute to. But, if you are a contributor, or working in the same org, get push rights on the repo and push all your feature branches to it. Issue pull requests from one branch to another within the same repo.

Should I merge Pull Requests on the site or commandline?

Up to you. Github does git merge --no-ff so that the commit message indicates the pull request number. This is useful information to have, don't just throw away history for the sake of it. You never know what will be useful to look at in the future.