Getting Started – Git-Flow
In a previous article called “Getting Started – Git” I explained most of the concepts that you should know about Git. I also mentioned in that article that I was busy writing another article on how to use Git-Flow as a branching strategy for your Git Repositories. Even though the name for this specific branching strategy is Git-Flow, you could also choose to use it with some of your other Version Control Systems. For the scope of this article I’ll be explaining the concepts introduced in Git-Flow and then I’m going to explain how to use it with Git and GitHub. I’ll be covering the following:
- Git-Flow – What is it?
- Git-Flow Setup
- Git-Flow Commands
- git flow init
- git flow feature
- git flow feature list
- git flow feature start
- git flow feature publish
- git flow feature pull
- git flow feature finish
- Other “git flow feature” sub-commands
- git flow release
- git flow release list
- git flow release start
- git flow release publish
- git flow release finish
- git flow hotfix
- git flow hotfix start
- git flow hotfix finish
- git flow support
- git flow support start
I’ll be updating this document as I come across more goodies that I think you should know about Git-Flow and how to use it. In this article I’m only going to give you an overview of how to use Git-Flow and how you can then use Git-Flow and GitHub to have teams work together on Feature, Hotfix, and Release branches. I’ll also have a brief explanation of how you can have Continuous Integration using Jenkins. Please note that this is not necessarily the way we use it at the company I work for, but it is the way I do my personal development and probably the way that most people out there using Git-Flow do their development, so it has been tested.
Git-Flow – What is it?
So, before I jump into the way Git-Flow works you may want to know what it is. Well… Git-Flow is a Workflow for Development practice proposed by Vincent Driessen which has since been implemented in a number of variations. There is also an open source project that gives you a “short hand” for implementing this workflow in a consistent manner using the Git Repository. I’ll be explaining the Workflow as well as the open source project and how to use it in this article. I’ll also go into some detail on how to follow the Git-Flow workflow without using this project so you can see how this would compare and what is happening behind the scenes with the automation tool.
For now, all you need to know is that Git-Flow is a workflow for branching that can be used for doing development work.
To setup Git-Flow is very straightforward and easy. I assume that you’ve followed all the instructions in my “Setup – Requirements” article and that you have Git installed. If not, please follow the steps I have in that article before continuing with this installation. To install Git-Flow you should open up a Terminal Window and change your directory to the place where you would like to download the installer script. In my case I changed into my “~/Downloads/Git-Flow” folder. Once you’re in the folder you want to download to, you can run the following command to download Git-Flow:
wget -q – http://github.com/nvie/gitflow/raw/develop/contrib/gitflow-installer.sh –no-check-certificate
This will download a Shell script to install Git-Flow for you. Once downloaded you can run the following command to make the script executable:
sudo chmod a+x gitflow-installer.sh
Once the script is executable you can run it by running the following command:
And you’re done. It’s really simple, right? The install added the following files to your “/usr/local/bin” folder:
I’ll be explaining what these files and the commands they expose do in the section under Git-Flow Commands.
So, while reading all the documentation online with regards to this workflow I went down quite a few rabbit holes trying to understand it and trying to work with it. Once I got the hang of it, I tried to think of a different way of doing branching and development better and for some reason kept coming back to this simple workflow. It seems to work quite well and once you get the hang of the concepts they discuss, you’ll probably try to use your old methods and find they’re lacking a bit in certain scenarios. One thing I can say about Git-Flow is that it’s not easy and it adds some complexities that you’ll find frustrating when you start, but once you start getting us to it, it will work for you, your team as well as your Organization.
To give you an overview you can have a look at the following flow diagram:
If you look at the above image it might come across as being overwhelming at first glance. I’ll break it down in the coming sections so as to make the overall flow of what actually happens in the image above a bit easier to understand.
Branching – Explanation
In Git-Flow everything is broken down into branches. When you do new feature development, you create a new branch off the develop branch. If you’re working on a hotfix, then you branch off master and if you’re busy with release hardening then you branch of the develop branch. So, let me explain the various branches before continuing. In Git-Flow there are two main branches that you should try and keeps as clean as possible and always in a releasable state. The one is master which can be seen as your released code base i.e. what you currently have running in Production. On the other hand you have the develop branch which can be seen as the integration branch of code that consists of completed features and hotfixes that are stable and that should consist of complete unit test suites. Your inter-team as well as support developers will integrate in this branch and you Continuous Integration server will also run against this branch to do your daily builds, run your complete test suites as well as generate test reports such as code coverage and release notes from. To break this down even more I’ll go into how development should be done when following the Git-Flow workflow while doing development.
Feature branches are branches created to do new feature development and should be branched off the develop branch. A feature in this case being a small set of code that completes a sub-section of a business case or in SCRUM terminology it could be a scenario where a group of scenarios complete a story. I always try to make the lifetime of a feature branch as small as possible and if at all possible, something that can be completed by an individual or team of developers in a single day. This makes the merging of various features back into the develop branch much simpler and allows for better Continuous Integration. Once the feature has been completed and merged back into the develop branch it should be deleted so as to ensure that no new code can be added to that specific feature branch.
At some point when you’ve done enough feature development you’ll reach a stage where business is happy with what you have and will want to do a release. At this stage you’ll start a release branch by branching from the develop branch where all the relevant teams and developers will be doing development that ads no new features, but rather stabilizes the features that was developed in the feature branches. This process is called “Release Hardening”. The only thing the developers will be allowed to do on this branch is fix the issues that were picked up by the Quality Assurance team while doing User Acceptance Testing. Release notes and Release packages will be generated from this branch and these will be pushed into your User Acceptance environment for stakeholders, selected users and QA Testers to test to ensure the quality is according to company standard.
The process of generating Release notes and Release packages as well as deployment to the UAT environment should be automated as far as possible, but that’s another article altogether. As the team doing UAT comes across inconsistencies or “unintended features” J they can then raise these things to the team of developers assigned to the hardening process that will be able to do the fixes, run the tests and push their changes to this branch. The team(s) assigned to this hardening process should preferably be the same team(s) that was involved in the feature development or selected members from each of the relevant teams. Once the code has been updated to fix said inconsistencies the UAT team should be notified that they can do a Release on these changes who will then go through the process of ensuring that the changes and fixes does in fact fix the inconsistencies.
After the UAT process has been completed and the Release has been signed off by relevant parties, the same package that was last released to the UAT environment should be pushed to Production and the Release branch should be merged into both the master branch as well as the develop branch to ensure that any fixes that were applied is merged into the develop branch as well as to ensure that the version of the code that is released into production is also the version of the code on which hotfixes are applied. Once merged into the master and develop branches you should delete the Release branch.
Of course there will be the few and odd inconsistency or “unintended feature” that slips through the cracks. In these cases you should create a hotfix branch of the master branch. This is different from the previous sections where the branches were created of the develop branch seeing that you’re now trying to fix something that is currently running in Production and you would like to push it to Production once it’s been fixed and the QA department is happy to do so. On completion of the fix this hotfix branch should be merged into the master as well as the develop branch to ensure that the fix is applied for future releases of bother hotfixes as well as new releases. In the figure above you’ll see that a Tag is assigned to the fix in the form of [version].[hotfix].
This is a concept that I couldn’t really understand seeing that it’s not as clear as the other branches covered above. This support branch is in fact a special kind of branch that can be created of a specific Tag in the master branch. From my understanding this is used if you have customers that do not want to upgrade to the new releases and who needs support on previous versions. So, the idea is that you’ll treat it the same as a hotfix branch where you’ll fix issue and then merge it back into master only. You may think it’s a bit strange to only merge back into the master branch and not the develop branch, but there is a good reason. If your most recent release is on version 10.2 and you’re still doing Support to some big client on version 4.3 then you may not want to merge the changes you’re making with the latest develop branch seeing that the code base and architecture might have changed completely. In these cases you’ll do the fix on this special branch, push it through the UAT process and then do a Release of the software to that specific client after tagging it in the same manner as you would a hotfix.
Once you’ve been through a specific Release process and the hardening is complete you’ll want to change the version of your product. You’ll want to do the same if you have a hotfix of a support item that needs to go out. In these scenarios you’ll also want to use different ways to show in your version which was a Release and which was a Hotfix of Support Release. I know that every company has a different strategy for this, but in my case I like to keep things simple, so I simply version my stuff as [version].[hotfix] where version would be a major release and hotfix would be an item that was fixed under the hotfix branch. By Tagging your source code you ensure that you’ll be able to go back to a specific version as it was at that stage of your product and you should also feel assured that you can release a specific version of your code after applying a hotfix.
In this section I’ll be explaining how the open source project (gitflow) works and I’ll try to explain how the gitflow commands in this project maps to the equivalent Git commands. First let me explain what gitflow is so it makes a bit more sense to those that don’t know yet. As you may have seen above Git-Flow is a workflow for branching and development that can be applied in any Version Control System. In the case of what I’ll be covering next you’ll see that I’ll be talking about Git as the Version Control System and the commands that are made simpler by using the gitflow project. In the next few sections I do assume that you know Git and have worked with it. If you haven’t had the chance to learn about Git, then you can read about it on my article called “Getting Started – Git”. That should help you get an understanding of what Git is and how to work with it.
In the section I’ll be creating a fictitious Git Repository called “Gitflow-Article” that will guide you through the steps
git flow init
This command initializes an empty Git Repository for you and sets up the Git configuration that you’ll need when creating the subsequent branches used in the workflow. To run the command you can run the following command:
git flow init
Once you’ve run this command Gitflow will as you a few questions for the configuration of your Repository. I usually accept the defaults by simply pressing the enter key a whole bunch of times until it stops asking me questionsJ. Gitflow configures the Git Repository by calling the “git config” command. Gitflow takes the values that you enter as the naming conventions for the branches you’ll create in subsequent development tasks. Once you’ve run through these you should have a screen that looks like:
You’ll be able to see the configurations in your Git “.git/config” file and you can see these by opening the config file in your favorite Text Editor. If you do a comparison between a normal .git folder and the one that Gitflow creates you’ll see quite a few differences. I’m not going to go into those, so if you would like to read up about those you’re welcome to do so. For the sake of this article I’ll only discuss the ones that matters most.
Now that you have your Gitflow enabled Repository you’ll also note that Gitflow created a “develop” branch and did a “git checkout” command that switched you into the new branch. As a developer you’ll be spending quite a bit of time in this branch seeing that all your features and releases will be developed by creating feature and release branches based on this branch. You should see this branch as your integration branch and should try and keep it as clean as possible. In the next section I’ll take you through doing your first feature development… Seeing that this will be our remote when we start doing development and other branches you’ll want to switch to the master branch by running the command:
git checkout master
Once you’ve created the Repository you should go to the machine on which you want to do development and clone the Repository that you created. In my case I’ll be connecting to the Repository from the same machine that I have my Gitflow enabled Repository on, but in your case you should be able to clone it by following the steps I have in the “Getting Started – Git” article.
Now that you’ve cloned the Repository you should run the git flow init command on your local Repository as well to get your local Git configuration to match that of your remote as follows:
git flow init
This should automatically switch you into the develop branch and you should now do a Git pull from your remote to ensure that you have the latest develop branch locally by running the following command:
git pull origin develop
Now that you have your local Repository matching that of your remote on both master and develop you should continue to start a feature branch.
git flow feature
In this section I’ll take you through creating your first feature. For simplicity’s sake I’ll take you through how to start a feature branch where we’ll create a README file which we’ll commit and then merge back into the develop branch by ending the feature. In this command you’ll see that there are a few sub-commands that you can run and I’ll be covering those sub-commands and how to use them in this section.
git flow feature list
You can run this command if you want to see what feature branches you have locally.
git flow feature start
This command will start a new feature and will require you to pass it a name for the feature that you would like to add. The format for this command is:
git flow feature start [featureName]
So, in our case we’ll run this command as follows:
git flow feature start ReadmeAdd
This will then create a feature branch called “ReadmeAdd” and automatically switch you into this branch. If you compare this with the normal Git usage then it would be equivalent to running the Git command:
git branch feature/ReadmeAdd
git checkout feature/ReadmeAdd
So if you run the command:
You should see something like:
Now that we have this feature branch and we’re ready to start coding you should be able to create the “README” file by running the following command:
Then you should be able to open this new file in your Text Editor and add some text to it. In my case I simply added the text “The quick brown fox jumped over the lazy dog”. Once we’re done editing our README file we should add it to staging area by using the following Git command:
git add README
Once added we should commit it by running the Git command:
git commit -m “Added readme file with some text”
This should now put us in a position where we would be able to complete this feature, but before we do that there are some other commands that I would like to go through that should make your life a bit easier. These commands are also a part of the “git flow feature” command set and should make some things a bit more clear as to how Gitflow works.
git flow feature publish
If you want to share this feature branch with some of you team mates so you can do some collaborative development then you would use to this sub-command to publish this feature up to your centralized Repository for your team to grab. In this section I’ll take you through the process of publishing the feature that we created in the previous section to the Repository. The format for this command is:
git flow feature publish [featureName]
So, if we build on what we covered in the previous section you should be able to run the following command:
git flow feature publish ReadmeAdd
To compare this to the commands that it would take if you used Git then you would’ve run the following commands:
git push origin featureAdd
git config “branch.featureAdd.remote” “origin”
git config “branch.featureAdd.merge” “refs/heads/featureAdd”
git checkout “featureAdd”
Once you’ve published the feature your team mates will be able to work on the feature branch with you by cloning the Repository from the centralized Repository and then doing a “git flow init”. This will set them up to have a Gitflow enabled local Repository with a master and a develop branch. Once they have a Gitflow enabled Repository they should be in the develop branch on which they should now do a pull to ensure their local Repository is in sync with the one on the remote. Once this is complete they should be able to follow the steps outlined in the next section.
git flow feature pull
This will be done when more than one person works on a feature together. In this section I assume that you followed steps in the previous section where you published your feature to the centralized Git Repository. You should use this command if you want to do a pull on the remote feature branch as follows:
git flow feature pull [alias] [featureName]
In our case this command would look something like:
git flow feature pull origin ReadmeAdd
Something to note here is that if you do a pull from the feature branch with the normal “git pull” command it breaks your HEAD and for some reason it’s very hard to get back to a point where you would be able to push any changes made or even do a feature pull in the future.
My advice when working with Gitflow is to use its commands wherever possible. Now to compare this to what you would have to do when using normal Git commands you can have a look at the following two scenarios:
- First time feature pull:
git fetch -q “origin” “ReadmeAdd”
git branch –no-track “ReadmeAdd” FETCH_HEAD
git checkout -q “ReadmeAdd”
- Subsequent feature pull
git pull -q “origin” “featureAdd”
By using this command you’ll get the source code that has been pushed by your team mates and their changes will be automatically merged into your local branch. If there are conflicts you will be the unlucky or lucky one to do the resolutions of these conflicts.
git flow feature finish
Now that you and your team have been doing some development on a specific feature you’ll probably want to complete the feature. You do this by calling the following command:
git flow feature finish [featureName]
In our example’s case this command would look like:
git flow feature finish ReadmeAdd
To explain what’s happening behind the scenes is not quite so simple seeing that there is a lot going on. To compare this without giving all the commands that you would have to execute from Git would look something like the following:
git checkout develop
git merge –no-ff “ReadmeAdd”
git branch -d ReadmeAdd
As mentioned Gitflow does a few extra things, but from what you can see Gitflow switched into the develop branch, then runs the merge command to merge the feature branch into the develop branch. If there are conflicts, Gitflow will switch into the feature branch again to allow you to do fix the conflicts after which you should commit the changes again and then do a “feature finish” again. If there are no more conflicts Gitflow will delete the local feature branch.
There are some things you’ll to watch out for here. First one is that you should do a pull on the develop branch before doing the “feature finish” so as to ensure that you’re merging into the latest code on the develop branch. The second thing is that you should delete the remote “published” feature, because Gitflow does not do this for you and will allow your team mates to continue making changes on the feature branch and pushing those up to the “published” feature branch even if you delete the remote branch. To delete the feature branch on the remote Repository you should run the following command:
git push origin :feature/ReadmeAdd
This essentially tells Git that it should push nothing into the remote branch and Git will then delete this remote feature branch for you.
Other “git-flow feature” sub-commands
There are other “git flow feature” sub-commands that you can explore, but for this article I’ll stick to these and may decide to bring some of those in at a later stage.
git flow release
Now that we’ve done some feature developments we’re essentially ready to do a deployment of our code to production. Before we can do this we would want to go through some kind of process where we do some usability testing or some kind of QA or UAT. As most of us know there are always some inconsistencies that code out of this process or changes that the users request before you deploy. Usually you don’t want to corrupt this process by introducing new features that should go out in some future release and you also don’t want those developers that are continuing with their feature developments to interrupt this process because they pushed some changes into the branch on which you’re doing this release. For this reason Git-Flow introduces a branch called release, which should be seen as a “Release Candidate” and not a release in the sense that it has been released. Gitflow makes this process a bit easier once again by introducing the “git flow release” command which has some similarities to the “git flow feature” command, but it also has some changes that it introduces which I discussed in the section under “Workflow”. In this section I’ll take you through the steps of doing a “Release Candidate” process. Once thing that you should note here is that there should only ever be one release branch at a time seeing that you won’t want to do two conflicting releases, which most of you may think is quite logical, but some out there may actually try :-).
git flow release list
Same as in the feature sub-command this command lists all the current release branches. For the sake of making things easier you should only have one of these at any time.
git flow release start
You should run this command to start your release development cycle or as I called it earlier, the branch on which you will be doing “Release Hardening”. To run this command you should run:
git flow release start [releaseName]
In our case we’ll make it as informative as we can by calling the following command:
git flow release start Version_1.0
The releaseName that you assign as the name to this release will also be the tag assigned once we finish this release development, so you will always be able to revert back to this specific tag if you want to do a hotfix or support development cycle. At this stage you should bump your version number on your project so as to reflect that of the version that we’re currently developing. In this case we’ll be working on version 1.0 of our software. Once you’ve done this you can generate your release packages for deployment to UAT or QA or whatever your next environment is. Your QA department will then do what they do and give you feedback with regards to the success or changes that are required. When everybody is happy they will release the release packages and you’ll be able to finish this release. Before we get there, there are a few things you should know which I’ll be covering next…
git flow release publish
As is always the case when a major release of software goes out, your company will want more than one developer to help on the hardening phase. For this reason you can publish this release branch to your remote Repository so your team mates can work on it as well. You do this by running the following command:
git flow release publish [releaseName]
In our case our command will look as follows:
git flow release publish Version_1.0
This works the same as when doing a feature development. So, I’m not going to go into it much.
git flow release finish
Once Release Hardening has been done and your operations team has deployed the Release Candidate to Production and you got the go-ahead to finish the release development you should run the following:
git flow release finish [releaseName]
In our case this will look as follows:
git flow release finish -F -p Version_1.0
This will bring up a screen where you’ll be expected to type in some final notes for this release branch. After that the following will happen:
git checkout master
git fetch origin master
git merge –no-ff Version_1.0
git tag -a Version_1.0
git push origin master
git checkout develop
git fetch origin develop
git merge –no-ff Version_1.0
git push origin develop
git branch –d Version_1.0
As you can see there are quite a few things that is done here. To explain this simply you can read the following list:
- Latest objects have been fetched from ‘origin’
- Release branch has been merged into ‘master’
- The release was tagged ‘Version_1.0’
- Release branch has been back-merged into ‘develop’
- Release branch ‘release/Version_1.0’ has been deleted
- ‘develop’, ‘master’ and tags have been pushed to ‘origin’
- Release branch ‘release/Version_1.0’ in ‘origin’ has been deleted.
This concludes the section for release development using Gitflow. In the next section I’ll go into how to do a hotfix development using Gitflow.
git flow hotfix
I hope that you’ve realized that there isn’t much of a difference in the process that is followed when doing the various types of development. This is part of the beauty of using the Workflow. You can do development in a consistent manner and using a Version Control Repository like Git actually makes this Workflow fairly easy to follow. There are a few snags in the process that can break things down for you, but that’s only if you don’t follow it correctly or you try and take some shortcuts. In this section I’ll take you through doing hotfix development where we’ll be getting the version 1.0 that we developed in the previous section and making some minor fix to the README file that was released.
git flow hotfix start
As you have seen in the previous sections, this marks the start of a hotfix and should be seen as a simple small bit of code that can be written to fix something that went wrong. To run this command you can run the following:
git flow hotfix start [hotfixName]
In our example this will be shown as follows:
git flow hotfix start Version_1.1
As you can see, I’m upping the version number of my software to version 1.1 seeing that it’s not a release that has new features in it or that should be seen as a major release. You’re simply going in to patch something that is broken so business can continue getting ready for the subsequent major release of the software.
git flow hotfix finish
The process being followed by this sub-command is the same as in doing a release end. Once this has run it will merge the changes you’ve made back into the master as well as the develop branch so as to ensure that these changes do get released with the next major release and the problem doesn’t come back. To run this command you should run:
git flow hotfix finish [hotfixName]
In our example we’ll run the command:
git flow hotfix finish Version_1.1
That brings us to the end of how the normal branching strategies work. In the next section I’ll go into something most of us developers hate doing, but most of us had the unpleasant experience of having to do which is support development on an older release.
git flow support
This is still a very experimental feature of Gitflow, so you should use it with caution. I’m going to go through it so you understand what this branch is for and how it should be used. As mentioned previously, this is the branch that you should create when and only when you have to support an older version of the software. This is generally for some big lazy client that don’t want to upgrade for some obscure reason, but who has enough money to keep management happy to keep assigning resources to this type of development even though it may in fact cause some trouble in other places. If you’re getting the idea that I don’t think this is ever a good idea, you’re right. Software evolves to quickly for us to be kept back by clients such as these, but alas they are the clients and they do keep us in business :-).
To get back to this… You’ll see that Gitflow only supports one sub-command on this and that is to do a start. This branch will be created, but as far as I know it won’t ever be deleted and will simply become a new sub-version of a current hotfix or major release.
git flow support start
This command takes a slightly different form to the previous ones seeing that you have to tell it which “base” it should be branched off. Base in this instance refers to the version or tag it should be branched off. It looks like:
git flow support start [supportName] [tagName]
In our case we know that we have a version 1.0 and a version 1.1 as we created these in our previous sections. So, for this exercise I’m simply going to create a support branch of off version 1.0 as follows:
git flow support start Version_1.1.1 Version_1.0
That should create a branch for you called Version_1.1.1 which you can then use to do development on for the customer that you’re supporting. How these branches merges back into the master and develop branches I haven’t got an idea. It may even stay outside of those branches as a parallel development, but I would assume that it does come back into the main Workflow at some stage.
Git-Flow is an extremely powerful workflow for doing development and seems to cater for just about every scenario you can come across in business. It is simple to follow once you start using it and makes for a good standard across small and big companies. If you use it in conjunction with Git you’ll quickly realize the strength of it combined with Test Driven Development practices, Continuous Integration as well as Regression Testing scenarios while not even taking into consideration the usual effort that goes into doing a Release or even a Hotfix.
I hope this process makes more sense to those that didn’t know about it as well as for those that are just starting out.