Our Simple Git Workflow

One thing I hear a lot from teams that aren’t using Git yet is that they’ve checked it out but it feels really complicated. I remember diving into Git at first and feeling overwhelmed, so I can definitely sympathize. There are so many concepts presented, and very often each article you read talks about a different way to use Git to control your source. In this article we’ll talk about the workflow that we use here at Carsonified. We like to keep things simple, and hopefully this will help some teams that are thinking about jumping to Git make the switch.

Why Use Git?

We absolutely love using Git, and that’s a big deal when I think back and remember how many version control systems I’ve had a bad relationship with, like Subversion, CVS, and Visual SourceSafe. For me there are two big contributors to why I love Git – it’s distributed and it makes branching extremely inexpensive.

Git is a distributed version control system. That means that there can be any number of repositories, unlike version control systems like Subversion that have one primary repository on a central server. It seems like having any number of repositories would be chaotic, but in practice most teams have a central server that they sync the repositories in their local project working directories to. Having those repositories on your local computer is a big deal, though, because it means that you can do anything you would normally only be able to do while connected to the central repository without actually connecting to it. That means quick commits because they don’t have to sync with the server and also means being able to create experimental branches even when you don’t have internet access. It’s awesome!

The other thing I love about Git is that branching is cheap. With version control systems I’ve used in the past the teams I’ve worked with have been afraid to create branches because it’s too difficult to merge those branches back into the main branch. With Git that fear is basically gone. You can create a new local branch if you’re making a quick change, or push the branch up to the server if you’ll be working on it for a while, and when you’re done it’s a piece of cake to merge your branch back into your main branch. You’ll see below that we use tons of branches at Carsonified. We’re never scared of what might happen because of all that branching.

While Git is amazing because of these features, it’s got a ton more features and a ton of different ways teams can use it. That can get messy, so at Carsonified we have a few simple rules we use with our repos to keep things easy for everyone on the team, even folks who are a little more shy about Git. Our workflow is completely compatible with GUI tools like Github for Mac and GitX. I know a ton of designers who are Terminal heroes, but I’ve also talked to many who really prefer to work with Git with a desktop app, so this workflow is inclusive for them.

Here are those rules:

1. Write new features in feature branches.
2. Integrate on the master branch.
3. Deploy from the release branch.

We’re not covering the basics of pushing, pulling, fetching, adding, and committing with Git here, but there are some great resources available to help you learn the basics. One great site for learning Git is Git Immersion.

Write Features In Feature Branches

When we’re working on a new feature that’s going to be comprised of a decent amount of code, we create a new branch named after the feature. That keeps the new feature out of the way if we need to put together a quick bug fix and also helps out with keeping different team members from stepping on each other’s toes as they work. I’d normally name a feature branch based on the feature, so for example our recent conversion to HTML5 video was in a branch called “video_workflow” because it included a lot of changes concerning how we publish video. For the sake of example, though, I’ll just call it “feature_branch” here. Here’s how we create that new remote branch:

1
2
3
4
5
6
7
8
9
10
11
12
# create a new feature branch in the remote repo named feature_branch
git push origin master:refs/heads/feature_branch
 
# make sure we've got everything updated from the remote repo
git fetch origin
 
# create a local branch named feature_branch that tracks
# the remote feature_branch
git branch --track feature_branch origin/feature_branch
 
# check out the new branch
git checkout feature_branch

If you’re thinking that’s a lot of commands, you’re right. I use a tool called grb, or Git Remote Branch, that makes working with remote branches a ton easier by wrapping up common git operations. It’s easy to install if you have RubyGems on your computer (if you have a Mac you do):

1
gem install grb

and now with grb installed you can ditch that huge list of commands above and just type:

1
grb create feature_branch

Now that you’re on the new branch you can work like you normally would with Git, adding, committing, and pushing code. From time to time it’s helpful to merge any master branch changes that have happened since creating your feature branch into the feature branch. That helps you make sure that you’re taking those changes into consideration as you work. Obviously if nothing has changed on your master branch you won’t need to do this, but there’s no harm in running the command, as it will just tell you that everything’s up to date:

1
git merge master

Once you’re done creating your new feature, you’ll integrate it back into the master branch.

Integrate On The Master Branch

To integrate the feature branch back into the master branch, you’ll first want to merge your master branch into your feature branch one last time to make sure that everything merges correctly. You merge it just like we did above with:

1
git merge master

Now you can check out your master branch and merge the feature branch into it. Since we just merged the master branch into the feature branch, it’s guaranteed to merge cleanly back into the master branch.

1
2
git checkout master
git merge feature_branch

If you’d like you can also delete the feature branch from your local and remote repositories, since you just finished up the feature and won’t need it anymore.

1
2
3
4
5
6
# this has to be in competition for one of the least intuitive
# commands ever, but it removes the remote branch
git push origin :refs/heads/feature_branch
 
# remove the local branch
git branch -d feature_branch

This is another spot where grb can help out if you have it installed, by turning those two commands for deleting the branch into one far more intuitive command:

1
grb rm feature_branch

At this point our master branch includes our new feature and we’re ready to work on another feature or deploy the new code.

Deploy From The Release Branch

I like to have a special branch dedicated to the code that I release. The standard for code getting into that branch is that it’s ready to deploy. That usually means that its tests have been run and are passing, and that the team’s generally happy with the code. You can create your deploy branch just like we did with the feature branch. I usually name my deployment branches “deploy”. Creative, huh?

So let’s say you’ve integrated some code into your master branch and now you’re ready to deploy the code. Here are the commands I use to merge that code into the deployment branch and tag a release:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# checkout the deploy branch
git checkout deploy
 
# pull the deploy branch, just to be sure everything's up to date
git pull origin deploy
 
# merge the master branch into the deploy branch
git merge master
 
# tag the release that we're about to make
git tag -a -m "My comments about this release" [tag_name]
 
# push it all up to the remote repository
git push --tags origin deploy
 
# switch back to the master branch,
# since we never do any work on the deploy branch
git checkout master

I usually bundle up the deploy commands into a script that I share within the repository so that it can be run easily by anyone on the team who needs to merge and tag a release. Those scripts usually include some sort of date and time based mechanism for automatically creating the tag name, since version numbers usually don’t make a lot of sense when you’re deploying your application several times a day like we typically do with our web apps.

Once you’ve merged and tagged the release on the deploy branch, you’re ready to deploy it. How you deploy it depends on what tools you’re using and how your team handles deployments. That’s certainly a far bigger topic than we have time for here, but I can say that we use and like Capistrano for our deployments.

Wrapping Up

It may seem overwhelming if you’re new to git, but once you get the hang of this workflow it’s a piece of cake. It’s not unusual for me to have one major feature branch that I’m working on while a designer is doing some work on another feature branch, and we’ll often have several experimental branches that include work on ideas as well. We almost never run into problems of one person’s commits messing up another’s, and our master branch is always ready for a quick bug fix and deploy, if needed. We’ve really enjoyed this workflow and hope you’ll enjoy it too!

Free Workshops

Watch one of our expert, full-length teaching videos. Choose from HTML, CSS or WordPress.

Start Learning

Treehouse

Our mission is to bring affordable Technology education to people everywhere, in order to help them achieve their dreams and change the world.

Comments

17 comments on “Our Simple Git Workflow

    • I’m a big fan of git-flow, but one issue with it is that it’s not something that’s easily handled in any of the popular GUI apps. I live on the command line, but know a lot of designers who aren’t quite as comfortable there, so I try to keep things easy for everyone.

      • Yep, Nvie’s model is absolutely fantastic. It’s one of the better Git workflow articles with great diagrams of how it all comes together.

  1. For creating new feature branches can’t you just do this?

    master> git checkout -b new_feature
    new_feature> git push origin HEAD

    • In fact, you can do `git checkout -b new-feature` and then `git push -u origin new-feature`. The `-u` flag will track that remote branch. Easier to remember that you just need to push, you know, your branch.

  2. > [...] by turning those two commands for deleting the branch into one far more intuitive command.

    I can’t understand why people think `git push origin :some-branch` is hard to remember while deleting branches. Yes, you just need to push your branch with a colon.

    • It’s not that hard to remember, but I don’t think that pushing to the branch with a colon at the front of its name is intuitive at all. Would that be anywhere near your first guess if you had never used git and were trying to figure out how to delete a remote branch?

      • It’s easier to remember/discover how to do it with Git than rely on a third party library, no? For mac users, ok, Ruby is already set up. What about linux and windows users? Install Ruby, then Rubygems (if you’re running 1.8), then the gem you mentioned, to finally remove your remote branch.

        • I think it’s all just relative to the user. If you have to look up deleting a branch every time but can remember grb, then I’d definitely recommend using grb, even if it takes some extra steps to set up. It sounds like you’ve got the colon set in memory, so I’d recommend sticking with it for sure. That’s why I showed both methods.

          Whatever works for you is great! You won’t find any intense nerd rage here.

          By the way, Nando, I have to say I’m a big fan of what you did with Codeplane. It was brilliant to spot that niche and put that app together.

          • No trolling, no rage. Just want to state what I believe is simpler. There are other tasks which such gem would make more sense. Last comment about this, I swear!

            And thanks for compliment! You just disarmed me. :)

          • Actually `git push origin :some-branch` makes more sense when you look at the normal use for that command, which is pushing a local branch to a server, but onto a branch by a different name. In that case the command is `git push origin local-branch:remote-branch` – This basically takes local-branch and pushes it onto remote-branch. So in essence `git push origin :some-branch` just pushes nothing into some-branch, hence deleting it.

  3. As someone’s who new to Git (I used SVN for years previously), I am absolutely stunned by how great it is. It’s so speedy and easy and a real delight to use. I would highly recommend that anyone using SVN switched over ;)

    And thanks for the heads up on GRB – will definitely need to check it out!

  4. One thing I’ve started doing is stashing between branches and popping a previous stash when I arrive on a different branch. I.e., consider the scenario:

    Implementing two features, “make-stuff-fast” and “amazing-new-feature”. When I am working on “make-stuff-fast”, and I want to switch over to “amazing-new-feature”, I first stash and name my stash with the branch name I’m presently in, i.e., “make-stuff-fast”. Then I switch to “amazing-new-feature” and look in the stash for any stashes named with that branch. I’ll pop all those that match off.

    I also stash & pop with the same mechanism on push/pull.