Visualized Git practices for team: branch, merge, rebase

Posted: January 28th, 2012 | Author: | Filed under: Development | Tags: , , , , , | 25 Comments »

The need for a simplified guide on git for teams

For the past few weeks, a few of my friends got started using git and github for their projects, some started afresh, some came from SVN background. Despite knowing all the basic commands (push, pull, checkout, merge) they found themselves confused in actually putting those together to best work for their teams.

I started using git about a year ago, but I only started to really get a sense of the best practices since a few months back while working simultaneously in a team of 3 on master branch of the Rails backend for Denso.

Even long-time git users found it hard to explain all the concepts to a beginner clearly especially on rebasing topic. The problem is that there are so many materials you can easily find on Google, *however*, they are mostly too advanced like this one, or usually in separate articles.
In other words, the resources I found on Google don’t tell you what the hell it is and how to apply it in in layman terms, they tell you how it works, how nodes are moved and stuff, which you honestly don’t care!

So, out of frustration of having to explain it again and again, I hope this post will help you visualizing the 3 very important concepts for your team and something you can copy & paste it to your next hire.

Note: This post is not meant for the absolute beginners, I’m assuming you have been working with git for some time: knowing how to create/clone a repo, commit changes, push, pull, create branch, switch branch, merge, adding/removing remote repos. If you are looking for a beginner git guide, I suggest this excellent summary from StackOverflow.

The github graph

Below is a sample of github’s graph, an excellent tool to visualize the team’s effort. I use it daily and seriously cannot live without it. This shows an example three-day period of commits.

Take your time, there’s nothing really new about this. I only added some annotations make it clear later on this post.

Learn git CLI by heart, stop using GUI

The first and most important practice of git is learn all the git commands by heart and use them, do not rely on GUI for git, because I tried some of the clients, even GitHub for Mac, and sometimes they introduce more junks than just your commits. It will get *extremely messy* when you need to do stuff like merging and branching.

I use CLI for all the git actions (push,pull,rebase,branch,checkout,merge) except git commit. For committing changes, I use GitX because I can selectively select the lines to be part of a single commit. Plus, I can see in realtime, the files affected without having to type git status all the time.

Branch out, merge often, keep in sync

The picture above shows that I’m working on my_branch branch. So one of the common question I’m asked is when should I branch out. There are pretty clear rules about keeping your codes in a separate branch from master branch:

  • You are about to make a major or disruptive change
  • You are about to make some changes that might not be used
  • You want to experiment on something that you are not sure it will work
  • When you are told to branch out, others might have something they need to do in master

After branching out, you should keep in-sync with the master branch, because eventually you need to merge it back to master. In order to avoid a huge complicated mess of conflicts when merging back, you should commit often, merge often. As a simple illustration, the picture below shows the same graph before but with different annotations.

Compare with this with previous diagram, you can see that at the begining of each working day, I pull the changes from master into my branch (merge). I do this often and sometimes solve a few minor conflicts along the way. At the end of 2nd day. I merge my branch back into master without a single conflict! Smooth like butter.

The syntax is simply:

git checkout my_branch // Just to make sure I'm on the right branch
git pull origin master // Read: pull the changes from origin/master into my current local branch my_branch

Another practice is rebasing the changes in master to your branch, however as you can see I’m striking this out because I found it extremely confusing, I do not use this method because it won’t show up as nice arrows on your github’s graph. You should just forget about I’m ever writing this after reading the next section

The mysterious & forever confusing ‘rebase’

This is my own definition, it’s not technically correct, but take it and it will make your life so much easier: (on current branch) git rebasing is taking all your local changes since the last push and put them ahead of other people’s changes regardless of the date you made the commit.

Base on that, git pull --rebase means pulling all the new changes made by others, then taking all my changes that are not yet pushed, and put them ahead of other people’s changes on the current branch.

So why am I striking out again, because I do not want you to remember this: It is not technically correct because rebasing can work across branches, but it is too confusing to be used that way. Just stick to the current branch

The picture above shows the effect of git rebasing when done correctly.
Below are the sequence I use everytime for rebasing:

git commit -am 'My changes'  // While i'm working on my machine
                             // <-- My colleague did a "git push" here
git pull --rebase            // So before I can push, i need to rebase
                             // Another syntax: git pull --rebase origin my_branch
git push                     // Now my changes are on top

The focus of this is the pull command, with additional --rebase parameter.
Before you wonder, yes, that is all you need to know about rebasing. Just one extra parameter. That’s it! Stop your mind from wandering because it is only that simple.

Perhaps you also wonder why people can’t explain it simply that way? Because git rebasing is indeed a lot more complicated, but for small team, I suggest that git rebasing to be used only on the current branch to avoid introducing extra commits as shown in the diagram above.


  1. Stop using GUI for git, seriously, it’s not that many commands
  2. Be safe, branch out, commit often, merge often
  3. Git rebase to be used on the current branch
  4. Replace git pull with git pull --rebase

  • I whole heartedly agree with all of the points in this article. Using git on the command line becomes trivial, as most of the time you have a vocabulary of 3-5 commands, and the rest can be done from Googling.

    Branches are _the_ reason to use git. Branches work so excellently in git that you should be well versed in them, to the point where everything you do is a branch from the main branch, if everyone on the team does this, then pushing individual changes will _just work_.

    I would go a step further with the rebase comments, though. The way our team do this is to create a feature branch, off of the main branch (develop) and every morning and afternoon, pull the develop, and rebase the changes onto your feature branch. When done we do a final pull/rebase, and finally switch back into develop, and use `git merge` to get your changes from your feature branch, into develop. So we rebase-out, merge-in. This strategy means we get commits on the develop branch for every feature branch that has been merged in, which creates a great jumping point to see that change sets.

    Also, you can automate git to do this. By running `git config branch.autosetuprebase always` you can have git automatically rebase any changes in any new branches. For existing branches you’ll need to run `git config branch.[branchname].rebase true` where [branchname] is the name of the branch.

  • Instead of GitX, try using add -p (or –patch). It’ll let you pick blocks of changes rather than having to add the whole file.

    • Sure it is possible to pick blocks but I found it easier to do it graphically and with GitX the changes are almost realtime. It is updated whenever the app is focused.

  • It’s worth pointing out that both you and Keith are describing “rebase” with backwards terminology. When you rebase, you generally rebase a feature branch *onto* master, not the other way round. So if you are on a feature branch and you “git pull –rebase” this is described as rebasing your local commits onto the upstream branch, not “rebasing the changes in master to your branch”. If you want a mnemonic, you move the base of your local commits, “put them ahead of other people’s changes” as you describe so it is the local changes that get rebased (their SHA-1’s change and everything).

    • I am aware of this and many other reasons why my own definition is technically wrong as I mentioned in the post. However as you suggested, I will take another look to see how I can use a better mnemonic that is straightforward and doesn’t involve ‘move’ or ‘shift’ word, I found whenever I use that concept of moving the pointer, people started to be put off easily.

  • On Mac you might try sourcetree from the Mac app store. It’s free and good.

    • I tried SourceTree after seeing your recommendation but I didn’t like it. There are too many UI elements in the app, I prefer the clean slate, single purpose GitX where I can type ‘gitx’ from the terminal when I’m in my repo

  • GitHub’s “Network Graph Visualizer” is useful for showing GitHub-hosted clones of a project. If you just want a graph view, you can use local tools such as gitk (distributed with git), GitX, which you mentioned, or even “git log –graph –oneline” if you want to stay on the command-line. You might want to add –all to the “gitk” or “git log” commands in order to see other branches (such as the main branch, when you’re on a topic branch).

    I’d recommend against doing a “blind” pull –rebase, as rebase requires a clean workspace and you might not want to stash+pop all the time. Rebasing might not be what I want. For example, I may have worked on series of commits that refactored a piece of code in several steps. Having a merge commit keeps them elegantly grouped in the history, which also makes them easier to revert if anything breaks.

    In my workflow, I use “git fetch”, followed by using a graph visualizer that lets me see the current state of things, and then I decide what to do. Sometimes I merge, sometimes I rebase.

  • Rebasing made more sense to me when I started doing these:

    * git fetch origin
    * git log ..origin/master to check what’s new from others
    * git rebase origin/master

    P.S. Step 2 could also be
    git log -u ..origin/master
    git whatschanged ..origin/master

    • NadsH

      For now it is git whatchanged ..origin/qa

  • I find the rebase part interesting, because, the man said (or used to at least) that its something you shouldn’t use if you don’t know what you’re doing, yada yada.

    In reality you _need_ rebase, as you’ve shown.

    In many projects, if I wouldn’t rebase, stuff would eventually go south with a zillion of things to merge that you wanted to have automerged with fast-forward.
    Git only fast-forward untouched files tho so once you merged something, if they don’t perfectly match (spacing, etc) then fast-forward fails.

    I find that to eventually become a short coming, if you can’t educate all humans to make perfect merges.

    Another tool I used in the past is svk for subversion. It takes a different approach.

    Since svn supports properties on commits, branches, etc, it would add a property indicating the last fast forward position.

    During svk 3way merge it would use that information, knowing when the last proper fast forward was done, then use its 3way smart merge to fast forward if changes were only spaces and such crap. Awesome in my book.

    That and per commit signing are things I miss in git. (per commit signing can’t be easily added because of design concerns. “political” issues on how its enough to sign a branch are just stuff people say to excuse the design issue. )

    • Guest

      The warning in the man is about rebase rewriting history.
      The easiest way to say in which case you should heed the warning is: Do not rebase branches that others fetch/pull from. 
      In other cases rebase is fine and like you say even needed.

      Just follow the credo rebase down merge up

  • Pingback: Bookmarks for January 28th | Chris’s Digital Detritus()

  • Junio C Hamano

    I would have to caution that “branch out and *sync often*” is a disease to be avoided. You branched to achieve a specific goal (e.g. “add this feature”, “fix this bug”) and the point of having a dedicated branch for that task is to keep the history of _that_ particular branch readable and understandable, which will lead to less bugs. It will defeat the point of using a separate branch if you randomly merge back from “master” at the point where the work on your branch is not yet ready, and whatever was done on “master” does not affect what the specific goal of adding the feature or fixing the bug.

    • Mr Anonymous

      It is not a disease… when doing properly.

      Once you branch out you lost contact with other code as you said.  That *IS* the devil thing to avoid.  And since there’s a good reason to have feature branches (the ones you said), at least try to minimize as possible.

      So you start with some conventions, like “master” (or development or any “parent” branch) is for completed features.  With this you avoid the “random” part of your merge back: when you get code from master (or the master-like) you are not getting nothing “ramdomly” but you are getting code meant to be there, the way it is there.

      Such code either has nothing in common with yours, in which case there’s no problem briging it onto your branch, or it has, either by chance, bad communications or whatever, in which case you want to know how it does affect to your codebase asap.

      But then, you don’t MERGE from master, because, as you too said, would mean mixing the code that makes your feature with that of others.  What you do is REBASE from master, which has the effect of having neatly separated your code from that you bring from master and giving early notice of any problem it brings with it.

      So, a “clean” feature branch process out of a development “main” branch (add git pull as needed):
      git checkout development
      git checkout -b featureA
      (each morning, within featureA branch)
      git rebase development (clean any conflict that may arise and test your code)
      (once you end with your feature, a last rebase):
      git rebase development
      (finally merge back to the main branch):
      git checkout development
      git merge –no-commit –no-ff featureA
      (this way you have a last chance to review how well the new code integrates with everything else)
      git commit

      • Mythreya J L

        Firstly I wouldn’t argue with Junio of all the people on how Git is meant to be used. Even otherwise, isn’t that EXACTLY what he said. Rebase with master instead of Merge to keep history linear and readable for people who don’t have any business with your experiments on the branch. I would like Merging is really a bad habit unless you’re merging an important feature.

        Like you said. I do it this way.
        1. git checkout -b featureA.
        2. develop some on featureA.
        3. git rebase master -> test suite.
        4. develop some more on featureA.
        5. git rebase master – > test suite.
        6. git checkout master.
        7. git rebase featureA.

        Of course in the meantime I keep master in sync with origin/master at all times.

  • “I use CLI for all the git actions (push,pull,rebase,branch,checkout,merge) except git commit”

    You can use “git add -p” for cheery picking what changes from each file you would like to commit.

  • I also enjoy using an alias I found in this video:

    “git timeline” <– great visual graph in CLI

    Run: git config –global alias.timeline "log –oneline –graph –decorate"

  • Pingback: Essenz 2012/01/30 |

  • Pingback: Visualized Git best practices for team: branch, merge, rebase | Brent Sordyl's blog()

  • It’s 2012, I actually want a GUI to do shit in, and a good one at that. Maybe Git should seriously provide nice api for apps to use

  • pull –rebase is definitely worth remembering – it seems to be the magic source missing from the gitflow strategy. Generally, however, I’d love to avoid having to perform visual network analysis whenever I deal with merges from other developers. Github doesn’t make it any more fun that it isn’t already.

  • Calvin98115

    This is a great visual and communicates many of the concepts that our team is starting to become more comfortable with. I have a question about a detail I am struggling with. When I branch from the master to work on a new feature, I run ‘git checkout -b newfeature’, and start work on the new code. To my surprise, I notice my edits to files are also changed and reflected back on the original master branch.  This seems contradictory to what I was expecting based on the git flows. I’d like the master to remain isolated until I merge the feature branch back to the master. What am I doing wrong?

  • Nikunj Patel

    @kentnguyen:disqus how can i do pull if any other person did something in same file ? Please help me . Thanks in advanced

  • “Learn git CLI by heart, stop using GUI”

    no.. just no.. not in a million years, i despise using command line for anything, doing repetitive typing for the same thing brakes my flow, and loses my focus.

    if we develop software for other people to make their life easier and help them more efficient, is it so wrong to expect us to do use tools for the exact same thing?