Tag v0.061
A general guide on how to use the GitFlow branching model and Github integration as the version control model for Oakwood's projects.
###The main goals of this approach are:
- Keep our repositories history very organized, with easy access to specific release versions and hotfixes.
- Implement a limited complexity branching model (GitFlow) solid and scalable enough to handle all our projects.
- Provide an easy and clean way to work with externals contributors.
##Why should I read this document? ###This document will cover the basics of:
- Installing and getting started with git-flow.
- Starting a fresh repository with git-flow.
- Applying GitFlow to existing projects.
- Fetching from and pulling to minieken and GitHub.
- Keeping minieken and GitHub synced.
###This document will not cover:
- How to use git.
- How to use GitHub.
- How to manage minieken's repositories.
- How to manage Oakwood's account on Github.
##Before starting It is strongly recommended that you have some basic notions of how git works before you start digging into anything on this page. There are TONS of references online, and Github also has some nice tutorials. Just google it. Also, feel free to chat with your colleagues that have some experience with git. You can learn a lot from a coffee chitchat.
###Must see links (seriously)
- A successful Git branching model (Original blog post where GitFlow as presented)
- Why aren't you using Git Flow? (Article that opened my eyes to the neat git-flow tools for using the GitFlow model - a lot of the stuff mentioned there is going to be repeated here)
- How to use a scalable Git branching model called git-flow (Nice visual representation of how GitFlow works)
- On the path with git-flow (Very didactic screen cast with real world usage of git-flow)
###How to install in from the source code in a Mac
$ git clone --recursive git://github.com/nvie/gitflow.git
$ cd gitflow
$ sudo make install
This will install git-flow in /usr/local. And we are ready to go.
For more in depth information (different platforms, etc), follow the instructions of the git-flow repository on GitHub. There you will also find a lot of extra information about the project and all the other goodies GitHub provides.
###Clone it!
Considering a fresh example
repository hosted in minieken
, our internal version control server , clone it in your machine using the usual:
$ git clone git@minieken:example.git
The process is exactly the same if the repository was initially available only on GitHub:
$ git clone git://github.com/username/example.git
Nothing forbids you to use git-flow into local-only repositories, although this is not the goal of this document (we are supposed to share the code :)
, the process would be the same.
###Initialize git-flow We have to configure git-flow for the current repository before start using it.
$ cd example
$ git flow init
Now git-flow is going to ask you a couple of question about the default names for the master, develop, feature, release, hotfix and support branches. As the whole point of this guide is to create a solid standard for the version control model, you should just accept the default values. So after you hit return a couple of times, your command line should look like this:
No branches exist yet. Base branches must be created now.
Branch name for production releases: [master]
Branch name for "next release" development: [develop]
How to name your supporting branch prefixes?
Feature branches? [feature/]
Release branches? [release/]
Hotfix branches? [hotfix/]
Support branches? [support/]
Version tag prefix? []
You will be automatically checked out to the develop branch, where you can start working normally. If you did your homework and checked out all the links listed in the beginning of this document, you should be starting to realize that not all of the development should occur on the develop branch itself. The develop branch is place where the more general, shared development should occurs. Any bigger, specialized development, that is likely to be developed by only one person (a.k.a. feature) should be done in a feature branch (:D yes, thats why they exist!). Feature branches are only temporary and should remain local (no need to push them), unless other developers are also going to work with it.
As this repository is totally fresh, the 'master' and 'develop' branches only exist into your local copy. You need to push them to the origin in order to make them avaliable for everyone.
Git might complain though if you try to push a totally empty commit. This a good time to add that nice README (or a basic .gitignore file maybe?). In case you really don't have anything to say now, just create empty files.
$ touch README
$ git add README
$ git commit -m "First commit!"
$ git push origin develop
$ git checkout master
$ git push origin master
You must initialize git-flow on your local copy of the repository before start using it. Luckily there isn't any prerequisite for using it on any existing repository. If the repository already uses the develop/master branches paradigm, perfect, everything will just work out of the box. However if the naming of the branches is different of the standard (develop & master) we might consider doing some adaptions.
If your development branch is called anything else than 'develop' and your release branch is called anything else than 'master' (very unlikely), you have two options:
- Don't rename your branches at all, and just tell git-flow to use the existing names. This might be necessary in case the repository is already being used by lots of people and renaming the branches would cause a lot of confusion between developers. Honestly that will hardly be the case within the scope of our projects.
- Use the default naming conventions and merge your custom named develop/master branches into the standard ones.
There is one very important fact to keep in mind here. As git-flow must be initialized and configured on any repository before being used, you need to inform all the contributors what is the naming conventions being used. Thats a good reason to justify why it's strongly recommended to stick with default names (the whole point it's to make things easier, isn't it?!).
###Clone it! Obviously, you need to get a hold on a copy of the repository you are trying to work with. So first thing to do is to clone it. ####From minieken
$ git clone git@minieken:existingexample.git
####From GitHub
$ git clone git@github.com:username/existingexample.git
###Track all the branches!
By default git clone
will only clone the master branch in your local copy, but you actually want to get a hold on and track all the remote branches (or at least both master & develop, where the action really happens). Unfortunately git won't provide any built-in method for doing that. But fortunately some good soul on stackoverflow* gave us a one-line bash script alternative that will clone and track all the remote branches into local branches with the same name. So after you've cloned your repository, all you gotta do is:
$ for remote in `git branch -r | grep -v master `; do git checkout --track $remote ; done
*Here's the original stackoverflow thread where the script was found.
###Initialize git-flow Now it's time to configure git-flow. Let's kick in!
$ git flow init
It will ask you a couple of questions, being the first ones regarding the master and develop branches. Consider what we said above regarding the naming conventions, and if you going all standard (recommended!), all you will need to do is press return a couple of times and your command line should look similar to this:
Which branch should be used for bringing forth production releases?
- develop
- master
Branch name for production releases: [master]
Which branch should be used for integration of the "next release"?
- develop
Branch name for "next release" development: [develop]
How to name your supporting branch prefixes?
Feature branches? [feature/]
Release branches? [release/]
Hotfix branches? [hotfix/]
Support branches? [support/]
Version tag prefix? []
Sweet, now you will be checked out to develop and ready to go! If you are adopting the default develop/master naming convention from your old custom one (smart move!) now is the time you should merge your code into the new branches and celebrate!
Although git-flow has some interesting built in functionality for keeping your local copy up-to-date with your origin remote (like fetching it before finishing a release or hotfix), it is not really designed to handle multiple remotes scenarios. So, bare in mind that it obviously won't do any magical work. You will still need to configure your remotes and fetch and push them manually...
###Configure your remotes! ####Repositories with only one remote If you are going to work with a repository with only one remote (e.g. if you are an Oakwood developer working a project that won't need any external collaborators and therefore will only be hosted @ minieken, or if you are an external collaborator that will have GitHub as the only version control server you need to keep track of), there's no need to configure anything. When you've cloned the repository, git automatically set the one-and-only remote you will use: 'origin'.
####Repositories with multiple remotes If you are working in a project that will need more than one remote (e.g. hosted on both minieken and GitHub), you need to configure your remotes in order to be able to fetch and push them easily. Git will automatically set your 'origin' remote to be the location you cloned your repository from, so, if you cloned the repository from minieken, your origin is already set for you and all you need to do is to configure the 'github' remote. However if you cloned the repository from GitHub, you will need to reconfigure 'origin' so it point's to the right place. This is very easy to do:
$ git remote set-url origin git@minieken:example.git
Now you can go ahead and add the GitHub remote:
$ git remote add gihub git@github.com:username/example.git
Ok, now all the remotes are set!
###Keeping everything synced To avoid any unnecessary conflicts we should always keep all our branches and remotes up-to-date with each other. Although the internal and external server should always "mirror" each other, there isn't any automated script that will handle that, so it's a very important practice to always fetch from and push to all the remotes regularly. This "distributed synchronization system" is very simple and horizontal; if integrated these practices into your workflow, you won't even need to think about it. So let's boil it down to some good user practices...
####Commit, commit, commit! This is more general git good practice but it worth remembering, don't hold the code for yourself for too long, commit it often so it won't cause any conflict later on. If you are working on a very specific feature that has it own branch, try to brake the development into small milestones and merge your progress back to the develop branch.
####Merge, merge, merge! On the other way around, you always want to have the updates that your team produced merged as soon as possible into your code, so you don't work on top of outdated code. If you are working directly on the develop branch, that is a no-brainer: every time you fetch and merge the remotes, all the updates will be automatically introduced in the code you are working with. But if you are working on a separate, feature branch, the updates in develop won't reach your code until you explicitly merge develop into your branch.
####Fetching and pushing
You might be asking yourself when it's good time to push and when it's good time to fetch... The short answer for that is: always fetch & merge before you push, always commit before you fetch. An simple flow that works well is to commit (it's ok to hold a couple if they are really small) > fetch > merge > push
. In a real world scenario that should be done like that:
#####Commiting After staging your changes:
$ git commit -m "Your commit description"
#####Fetching (all the remotes!)
$ git fetch origin
$ git fetch github
The above lines could also be replaced by the $ git remote update
command. This will automatically fetch all your remotes.
#####Merging If after fetching you see that there are changes coming, you need to merge them into your branches. It's likely that the master branch won't be updated so often as the develop branch, but in anyway, it won't hurt to run the merge command for all of them so you have a clear conscious that everything was updated correctly.
$ git checkout develop
$ git merge origin/develop
$ git merge github/develop
$ git checkout master
$ git merge origin/master
$ git merge github/master
If everyone in the Oakwood team is pushing regularly to both 'origin' and 'github', after you run $ git merge github/{brach-name}
it's almost sure you will get the Already up-to-date.
message, the reason however that you should always check for 'github' is to make sure that you don't miss out any changes introduced by external contributors, in that case 'github' is the only remote your repositories will ever interface.
#####Pushing Time to make your changes public! Don't forget to push to all the remotes.
$ git push origin
$ git push github
Notice that we are running the git push
command without any branch name, that will push all the branches. You could of course push them individually using the git push {branch-name}
.
In case you did a release or hotfix you probably also added a tag to your commit the 'master' branch. In that case you will need to also push the tags explicitly. This is done by adding the --tags
argument at the end of the push command.
$ git push origin --tags
$ git push github --tags