Git workflow: master – origin – upstream – and production

Setting up a git workflow might be a tedious task, but can save you a lot of troubles over time. For me, this particular quest started when I wanted to use Chiliproject to manage my client projects.

Not only did I wanted to easily configure and deploy it, I also wanted to contribute to it, when I had the chance.

My main concern was how to keep the hole process a smooth as possible. I should be able to easily update my production setup, as well as my development environment for possible pull requests.

One option was to work with 2 separate versions. One version where fork the projects repository and clone it locally for contributions, and a second one where you clone the projects repository directly so you can set it up and deploy it to your needs.

But I didn’t really like that approach. Having 2 versions of virtually the same software seemed a bit off to me. So I looked for a way to achieving this with only one version.

I’m not saying this is THE way of managing things, but it seems to work out great for me. Haven’t run into any issues yet, but if I do, I’ll try to post them here.

Also feel free to share your thoughts. I’m curious in how other people manage this.

Starting off

First lets start to fork the project from Github into your own public Github repository. This way you can manage pull requests in case you contribute to the project.

So just navigate your browser to the Github repository and press the Fork button.
Now the second step is clone you Github repository locally.

$ git clone git@github.com:<your-github-handle>/<your-github-repository>.git

Congratulations, you just cloned your public repository. You are now ready to contribute. Make those local changes, push them to your public repository and file a pull request.

But now it gets a bit trickier. We want to setup the project as well. This will result in creating some private configuration settings that you don’t want to make public. Not only that, we want to be able to easily upgrade to newer versions and make deployment a breeze.

Preparing for battle

So first, lets start by adding the remote location of the repository that you forked from. This will allow you to fetch any changes made to the main repository.

$ git remote add upstream git://github.com/<main-github-handle>/<main-github-repository>.git

We add the remote under the name upstream as git read-only. Since we’ll only use the upstream to fetch updates.

The next step is to create a local branch. This local branch will be used to store our production settings. In this branch, we will install and configure the software to our needs. Most projects keep tags to version stable releases, so create a branch from the latest tag available.

$ git checkout <latest-tag> -b <production-branch>

This command will checkout the specified tag into a new branch. Make all the necessary changes, but make sure you are working in the newly created production branch and not in the master!

When everything is setup and configured properly, it is time to deploy the installation into production. But we can’t just push the production branch to our public repository or things like database configurations are made public.

For doing this, you’ll need a private repository. Either on Github or a private git server and add this private production repository to your remote:

$ git remote add production <private-git-repository>

Now you’ll have 3 remotes configured:

  1. remote “origin”
    This is your public repository that you’ll use to push updates at so you can create Github pull requests
  2. remote “upstream”
    This is the public project repository. This will be read-only, since we’ll only be using it to pull new updates
  3. remote “production”
    This is our private repository. This private repository will contain our production configuration and will be used for deployment.

You’ll first want to push you production branch to your production repository:

$ git push production production

Now that everything is pushed to your production repository, you can now setup Capistrano. I won’t go into detail on how to use Capistrano here, but the point is that you configure your deployment to point to the private production repository using the production branch.

Updating your production repository

As time passes, a newer version might be available and you want to update your production setup with the latest stable version.
Now, since the tags stand for stable releases, we fetch the new tags in our master branch:

$ git checkout master
$ git fetch –tags upstream

Now switch to your production branch and merge the latest tag

$ git checkout <production-branch>
$ git merge <latest-tag>

Everything should now be up to date without losing your configuration settings. The only thing that is left to do is to push the update to your production repository and deploy

$ git push production production
$ cap deploy

Updating your public repository

Updating the public repository works in a similar way. First, make sure you are working in the master branch

$ git checkout master

Now, pull in the upstream master:

$ git pull upstream master

Now you can work on an up-to-date code base and push the changes back to your public repository and file a pull request.

$ git push origin master

Warning:

Watch out not pushing your production branch to your public repository. If that happens, just delete it again:

$ git push origin :<production-branch>