Thursday, June 13, 2013

Git flow in action

Objective:

This is a gentle introduction to "git flow" using a hands-on example.

Introduction:

In an typical Agile/SCRUM shop, there are several teams constituting of developers and QA personnel who collaborate across several sprint lanes. Their primary objective is to deliver functional user stories at the end of each sprint cycle. In such an environment of rapid iterative development, it is essential to have a very well defined strategy to branch, merge, tag, release, patch the source code repository. This can become problematic real fast especially when using DVCS such as GIT. Here is where "Git Flow" comes into play.

Git Flow is both a methodology and software (underneath the covers runs git commands). It takes the best enterprise practices we are familiar with in a centralized version control system and applies them to GIT.

Here are 4 resources that I found really helpful while learning Git Flow.
  1. 2012 UTOSC - Using Git-Flow to Relieve Your Headaches - Tom Doggett
  2. Successful Git Branching Model - Vincent Driessen
  3. Git flow Cheat Sheet - Daniel Kummer
  4. Getting started with Git Flow
  5. Issues with Git Flow; Intro to GitHub Flow - Scott Chacon
Overview:

In this post, I'd like to share how two popular fictitious developers (Bob and Alice) use Git Flow to develop software collaboratively. Both have their own git repository and collaborate via central repository hosted on Github.

We will cover the following scenarios:
  1. Initializing Git Flow's recommended branching mechanism
  2. Developing "features"
  3. Release Management
  4. Hot Fixes

Prerequisites:

If you are reading about git flow, it is fair to assume that you are aware of basics of git and have used GitHub. There are lot of blogs that go over git basics and how to  install git and git flow. I'd suggest that you get a bit of  hands-on experience with git and GitHub before reading further as it will help you follow along much easily.

In this example, both Bob and Alice have read and write access to the same shared GitHub repository.

Deep Dive:

Initializing Git Flow's recommended branching mechanism

Bob begins by creating a repo in Github called "gitflow-example"



Now that Bob has an empty repo on Github, he creates a local Git repo using gitflow and sticks to the recommended branch naming convention suggested by Git Flow.


Ashwinis-MacBook-Pro:git akuntamukkala$ mkdir GitFlowExample
Ashwinis-MacBook-Pro:git akuntamukkala$ cd GitFlowExample/
Ashwinis-MacBook-Pro:GitFlowExample akuntamukkala$ git flow init
Initialized empty Git repository in /Users/akuntamukkala/GIT/GitFlowExample/.git/
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? []
Ashwinis-MacBook-Pro:GitFlowExample akuntamukkala$ git branch
* develop
  master
Ashwinis-MacBook-Pro:GitFlowExample akuntamukkala$ touch README.md
Ashwinis-MacBook-Pro:GitFlowExample akuntamukkala$ echo "this is to help understand use of git flow" > README.md
Ashwinis-MacBook-Pro:GitFlowExample akuntamukkala$ git add .
Ashwinis-MacBook-Pro:GitFlowExample akuntamukkala$ git commit -m "first commit"
[develop 4b88910] first commit
 1 file changed, 1 insertion(+)
 create mode 100644 README.md
Ashwinis-MacBook-Pro:GitFlowExample akuntamukkala$ git remote add origin git@github.com:akuntamukkala/gitflow-example.git
Ashwinis-MacBook-Pro:GitFlowExample akuntamukkala$ git push --all
Counting objects: 5, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (5/5), 430 bytes, done.
Total 5 (delta 0), reused 0 (delta 0)
To git@github.com:akuntamukkala/gitflow-example.git
 * [new branch]      develop -> develop
 * [new branch]      master -> master



Here is the screenshot of repository on Github showing both develop and master branches. Current active branch "develop"



Alice clones the gitflow-example.git repo from Github and initializes git flow on her local repository. She also sticks to the same branch naming convention recommended by Git Flow.



C:\GIT\GitFlowExample>git clone git@github.com:akuntamukkala/gitflow-example.git
Cloning into 'gitflow-example'...
Enter passphrase for key '/c/Users/akuntamu/.ssh/id_rsa':
remote: Counting objects: 5, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 5 (delta 0), reused 5 (delta 0)
Receiving objects: 100% (5/5), done.

C:\GIT\GitFlowExample>cd gitflow-example

C:\GIT\GitFlowExample\gitflow-example>git branch -a
* master
remotes/origin/HEAD -> origin/master
remotes/origin/develop
remotes/origin/master

C:\GIT\GitFlowExample\gitflow-example>git flow init
Which branch should be used for bringing forth production releases?
- master
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? []

C:\GIT\GitFlowExample\gitflow-example>git branch -a
* develop
master
remotes/origin/HEAD -> origin/master
remotes/origin/develop
remotes/origin/master

C:\GIT\GitFlowExample\gitflow-example>git branch -vv
* develop 4b88910 [origin/develop] first commit
master 078f615 [origin/master] Initial commit


C:\GIT\GitFlowExample\gitflow-example>dir
Volume in drive C has no label.
Volume Serial Number is 48D7-B5DC

Directory of C:\GIT\GitFlowExample\gitflow-example
04/24/2013 02:49 PM <DIR> .
04/24/2013 02:49 PM <DIR> ..
04/24/2013 02:49 PM 44 README.md
1 File(s) 44 bytes
2 Dir(s) 39,041,245,184 bytes free

C:\GIT\GitFlowExample\gitflow-example>type README.md
this is to help understand use of git flow


Developing "features" in isolation:

Let's say Alice is implementing a feature "xyz" by herself (not in collaboration)

The following commands creates a branch "feature/feature-xyz" off the "develop" branch.



C:\GIT\GitFlowExample\gitflow-example>git flow feature start feature-xyz
Switched to a new branch 'feature/feature-xyz'
Summary of actions:
- A new branch 'feature/feature-xyz' was created, based on 'develop'
- You are now on branch 'feature/feature-xyz'

Now, start committing on your feature. When done, use:
git flow feature finish feature-xyz

C:\GIT\GitFlowExample\gitflow-example>dir
Volume in drive C has no label.
Volume Serial Number is 48D7-B5DC Directory of C:\GIT\GitFlowExample\gitflow-example
04/24/2013 02:49 PM <DIR> .
04/24/2013 02:49 PM <DIR> ..
04/24/2013 02:49 PM 44 README.md
1 File(s) 44 bytes
2 Dir(s) 39,041,175,552 bytes free

C:\GIT\GitFlowExample\gitflow-example>git branch -vv
develop 4b88910 [origin/develop] first commit
* feature/feature-xyz 4b88910 first commit
master 078f615 [origin/master] Initial commit

Alice starts implementing the feature xyz...



C:\GIT\GitFlowExample\gitflow-example>echo "feature xyz implemented" > feature-xyz-impl.txt

C:\GIT\GitFlowExample\gitflow-example>echo "feature xyz adds cool capability" >> README.md

C:\GIT\GitFlowExample\gitflow-example>git add .

C:\GIT\GitFlowExample\gitflow-example>git commit -m "implemented feature-xyz"
[feature/feature-xyz 02d1a06] implemented feature-xyz
2 files changed, 2 insertions(+)
create mode 100644 feature-xyz-impl.txt


Now that Alice commits the newly implemented feature xyz  to her local repository, it is time for her to merge her changes to the "develop" branch and delete "feature/feature-xyz" branch.


C:\GIT\GitFlowExample\gitflow-example>git flow feature finish feature-xyz
Switched to branch 'develop'
Updating 4b88910..02d1a06
Fast-forward
README.md | 1 +
feature-xyz-impl.txt | 1 +
2 files changed, 2 insertions(+)
create mode 100644 feature-xyz-impl.txt
Deleted branch feature/feature-xyz (was 02d1a06).

Summary of actions:
- The feature branch 'feature/feature-xyz' was merged into 'develop'
- Feature branch 'feature/feature-xyz' has been removed
- You are now on branch 'develop'

C:\GIT\GitFlowExample\gitflow-example>git log --pretty=format:"%h %s" --graph * 02d1a06 implemented feature-xyz
* 4b88910 first commit
* 078f615 Initial commit


Alice pushes her changes from "develop" branch from local repository to the "develop" branch on central repository on GitHub.



C:\GIT\GitFlowExample\gitflow-example>git push
Enter passphrase for key '/c/Users/akuntamu/.ssh/id_rsa':
Counting objects: 6, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (4/4), 414 bytes, done.
Total 4 (delta 0), reused 0 (delta 0)
To git@github.com:akuntamukkala/gitflow-example.git
4b88910..02d1a06 develop -> develop


Now Bob wants to get the newly added feature xyz


Ashwinis-MacBook-Pro:GitFlowExample akuntamukkala$ git branch -vv
* develop 4b88910 first commit
master 078f615 Initial commit

Ashwinis-MacBook-Pro:GitFlowExample akuntamukkala$ git branch --set-upstream develop origin/develop
Branch develop set up to track remote branch develop from origin.

Ashwinis-MacBook-Pro:GitFlowExample akuntamukkala$ git branch --set-upstream master origin/master
Branch master set up to track remote branch master from origin.

Ashwinis-MacBook-Pro:GitFlowExample akuntamukkala$ git branch -vv
* develop 4b88910 [origin/develop: behind 1] first commit
master 078f615 [origin/master] Initial commit

Ashwinis-MacBook-Pro:GitFlowExample akuntamukkala$ git pull
Updating 4b88910..02d1a06
Fast-forward
README.md | 1 +
feature-xyz-impl.txt | 1 +
2 files changed, 2 insertions(+)
create mode 100644 feature-xyz-impl.txt

Ashwinis-MacBook-Pro:GitFlowExample akuntamukkala$ git branch -vv
* develop 02d1a06 [origin/develop] implemented feature-xyz
master 078f615 [origin/master] Initial commit


Developing "features" in collaboration:


Say Bob and Alice now want to start developing a feature collaboratively.

Bob creates a new feature "abc"


Ashwinis-MacBook-Pro:GitFlowExample akuntamukkala$ git flow feature start feature-abc
Switched to a new branch 'feature/feature-abc'
Summary of actions:

- A new branch 'feature/feature-abc' was created, based on 'develop'
- You are now on branch 'feature/feature-abc'
Now, start committing on your feature. When done, use:

git flow feature finish feature-abc

Ashwinis-MacBook-Pro:GitFlowExample akuntamukkala$ git flow feature list
* feature-abc

Bob implements feature "abc", commits changes to local repo's feature/feature-abc branch.


Ashwinis-MacBook-Pro:GitFlowExample akuntamukkala$ touch feature-abc-impl.txt

Ashwinis-MacBook-Pro:GitFlowExample akuntamukkala$ echo "dev 1 implementing feature abc partially" > feature-abc-impl.txt

Ashwinis-MacBook-Pro:GitFlowExample akuntamukkala$ git add .

Ashwinis-MacBook-Pro:GitFlowExample akuntamukkala$ git commit -m "dev 1 - partial impl of feature-abc"
[feature/feature-abc c50551c] dev 1 - partial impl of feature-abc
1 file changed, 1 insertion(+)
create mode 100644 feature-abc-impl.txt

Ashwinis-MacBook-Pro:GitFlowExample akuntamukkala$ git push
Everything up-to-date

Bob now publishes feature-abc to repository on GitHub.


Ashwinis-MacBook-Pro:GitFlowExample akuntamukkala$ git flow feature publish feature-abc
Counting objects: 4, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 381 bytes, done.
Total 3 (delta 0), reused 0 (delta 0)
To git@github.com:akuntamukkala/gitflow-example.git
* [new branch] feature/feature-abc -> feature/feature-abc
Already on 'feature/feature-abc'
Summary of actions:
- A new remote branch 'feature/feature-abc' was created
- The local branch 'feature/feature-abc' was configured to track the remote branch
- You are now on branch 'feature/feature-abc'

Ashwinis-MacBook-Pro:GitFlowExample akuntamukkala$ git branch -vv
develop 02d1a06 [origin/develop] implemented feature-xyz
* feature/feature-abc c50551c [origin/feature/feature-abc] dev 1 - partial impl of feature-abc
master 078f615 [origin/master] Initial commit


Alice now attempts to pull the feature-abc published by Bob

C:\GIT\GitFlowExample\gitflow-example>git flow feature pull origin feature-abc
Enter passphrase for key '/c/Users/akuntamu/.ssh/id_rsa':
Created local branch feature/feature-abc based on origin's feature/feature-abc.

C:\GIT\GitFlowExample\gitflow-example>git branch -a
develop
* feature/feature-abc
master
remotes/origin/HEAD -> origin/master
remotes/origin/develop
remotes/origin/feature/feature-abc
remotes/origin/master

C:\GIT\GitFlowExample\gitflow-example>dir
Volume in drive C has no label.
Volume Serial Number is 48D7-B5DC
Directory of C:\GIT\GitFlowExample\gitflow-example
04/24/2013 04:25 PM <DIR> .
04/24/2013 04:25 PM <DIR> ..
04/24/2013 04:25 PM 42 feature-abc-impl.txt
04/24/2013 03:04 PM 28 feature-xyz-impl.txt
04/24/2013 03:04 PM 81 README.md
3 File(s) 151 bytes
2 Dir(s) 38,988,984,320 bytes free

Alice continues to implement feature abc.


C:\GIT\GitFlowExample\gitflow-example>type feature-abc-impl.txt
dev 1 implementing feature abc partially

Alice finishes the implementation of feature "abc" and commits her changes to her local repository.


C:\GIT\GitFlowExample\gitflow-example>printf "\ndev2 completed implementation of feature abc" >> feature-abc-impl.txt

C:\GIT\GitFlowExample\gitflow-example>type feature-abc-impl.txt
dev 1 implementing feature abc partially
dev2 completed implementation of feature abc

C:\GIT\GitFlowExample\gitflow-example>git add .
warning: LF will be replaced by CRLF in feature-abc-impl.txt.
The file will have its original line endings in your working directory.

C:\GIT\GitFlowExample\gitflow-example>git commit -m "feature abc implementation completed by dev 2"
[feature/feature-abc warning: LF will be replaced by CRLF in feature-abc-impl.txt.
The file will have its original line endings in your working directory.
5671d9f] feature abc implementation completed by dev 2
warning: LF will be replaced by CRLF in feature-abc-impl.txt.
The file will have its original line endings in your working directory.
1 file changed, 3 insertions(+), 1 deletion(-)

C:\GIT\GitFlowExample\gitflow-example>git flow feature list
* feature-abc


Now that this new feature abc is completely implemented, Alice figures it is time to merge changes from "feature/feature-abc" branch to the "develop" branch of her local repository.

C:\GIT\GitFlowExample\gitflow-example>git flow feature finish feature-abc
Branches 'feature/feature-abc' and 'origin/feature/feature-abc' have diverged.
And local branch 'feature/feature-abc' is ahead of 'origin/feature/feature-abc'.
Switched to branch 'develop'
Merge made by the 'recursive' strategy.
feature-abc-impl.txt | 3 +++
1 file changed, 3 insertions(+)
create mode 100644 feature-abc-impl.txt
Deleted branch feature/feature-abc (was 5671d9f).

Summary of actions:
- The feature branch 'feature/feature-abc' was merged into 'develop'
- Feature branch 'feature/feature-abc' has been removed
- You are now on branch 'develop'

C:\GIT\GitFlowExample\gitflow-example>git branch -r
origin/HEAD -> origin/master
origin/develop
origin/feature/feature-abc
origin/master

C:\GIT\GitFlowExample\gitflow-example>git branch -a
* develop
master
remotes/origin/HEAD -> origin/master
remotes/origin/develop
remotes/origin/feature/feature-abc
remotes/origin/master

C:\GIT\GitFlowExample\gitflow-example>git status
# On branch develop
# Your branch is ahead of 'origin/develop' by 3 commits.
#
nothing to commit, working directory clean

Alice pushes changes from her local repository containing completed feature-abc implementation to the central repository on GitHub.


C:\GIT\GitFlowExample\gitflow-example>git push
Enter passphrase for key '/c/Users/akuntamu/.ssh/id_rsa':
Counting objects: 7, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (4/4), 573 bytes, done.
Total 4 (delta 1), reused 0 (delta 0)
To git@github.com:akuntamukkala/gitflow-example.git
02d1a06..fdef09a develop -> develop



It may be noted that "feature/feature-abc" branch has been deleted in Alice's local repository but still exists in Github repository. Alice deletes feature-abc branch from Github repo.

C:\GIT\GitFlowExample\gitflow-example>git branch -a
* develop
master
remotes/origin/HEAD -> origin/master
remotes/origin/develop
remotes/origin/feature/feature-abc
remotes/origin/master

C:\GIT\GitFlowExample\gitflow-example>git fetch origin feature/feature-abc
Enter passphrase for key '/c/Users/akuntamu/.ssh/id_rsa':
From github.com:akuntamukkala/gitflow-example
* branch feature/feature-abc -> FETCH_HEAD

C:\GIT\GitFlowExample\gitflow-example>git branch -vv
* develop fdef09a [origin/develop] Merge branch 'feature/feature-abc' into develop
master 078f615 [origin/master] Initial commit

C:\GIT\GitFlowExample\gitflow-example>git push origin :feature/feature-abc
Enter passphrase for key '/c/Users/akuntamu/.ssh/id_rsa':
To git@github.com:akuntamukkala/gitflow-example.git
- [deleted] feature/feature-abc


Bob updates local repo to get completely implemented feature "abc"


Ashwinis-MacBook-Pro:GitFlowExample akuntamukkala$ git branch -a
develop
* feature/feature-abc
master
remotes/origin/develop
remotes/origin/feature/feature-abc
remotes/origin/master

Ashwinis-MacBook-Pro:GitFlowExample akuntamukkala$ git remote prune origin
Pruning origin
URL: git@github.com:akuntamukkala/gitflow-example.git
* [pruned] origin/feature/feature-abc

Ashwinis-MacBook-Pro:GitFlowExample akuntamukkala$ git branch -vv
develop 02d1a06 [origin/develop: behind 3] implemented feature-xyz
* feature/feature-abc c50551c [origin/feature/feature-abc] dev 1 - partial impl of feature-abc
master 078f615 [origin/master] Initial commit


Ashwinis-MacBook-Pro:GitFlowExample akuntamukkala$ git checkout develop
Switched to branch 'develop'
Your branch is behind 'origin/develop' by 3 commits, and can be fast-forwarded.

Ashwinis-MacBook-Pro:GitFlowExample akuntamukkala$ git pull
Updating 02d1a06..fdef09a
Fast-forward
feature-abc-impl.txt | 3 +++
1 file changed, 3 insertions(+)
create mode 100644 feature-abc-impl.txt

Ashwinis-MacBook-Pro:GitFlowExample akuntamukkala$ git branch
* develop
feature/feature-abc
master

Bob needs to delete feature/feature-abc branch from local repo because his local repository's "develop" branch already contains the merged feature abc implementation.

"git remote prune origin" command helps identify that remote branch (feature/feature-abc) that Bob was tracking has been deleted.


Ashwinis-MacBook-Pro:GitFlowExample akuntamukkala$ git branch -d feature/feature-abc
Deleted branch feature/feature-abc (was c50551c).

Ashwinis-MacBook-Pro:GitFlowExample akuntamukkala$ git branch -vv
* develop fdef09a [origin/develop] Merge branch 'feature/feature-abc' into develop
master 078f615 [origin/master] Initial commit



Moving from Blog.com to Blogspot.com

I had started my blog at http://technologyenthusiast.blog.com a couple of months ago but given blog.com's challenges with uptime where blog.com is more down than up, I decided to abandon blog.com in favor of blogspot.com.
I will continue my open source technology ramblings here on blogspot.com going forward...

Purpose of this blog

This is a blog where I will be sharing some of my hands-on experiences with different open source projects.
I have keen interest in the following:
  • Spring Framework
  • ORM technologies
  • Distributed Version Control Systems
    • GIT/GitHub
  • Middleware Integration
    • WSO2 product suite
    • Apache Camel Integration framework
    • Apache ActiveMQ
  • SOAP/REST Web Services
    • Spring WS
    • Axis
    • CXF
  • OSGI
    • Apache Karaf
    • Virgo
  • Scripting languages
  • Test Driven Development
    • JUnit
    • TestNG
    • DBUnit
    • XmlUnit
    • Mocking Technologies
      • Easymock
      • Powermock
      • Mockito
  • Build Management
    • Maven
  • Continuous Integration
    • Jenkins on Cloudbees
  • Code Quality
    • Sonar
    • FindBugs
  • Artifact Repository
    • Artifactory
    • Archiva
    • Nexus
  • Big Data
    • DataStax/Cassandra
  • AWS/Rackspace/Cloudfoundry
  • Troubleshooting
    • SAP Memory Analyzer for JVM heap dump (surely not fun at all)
    • JVisualVM (remote monitoring through JMX)
I like to revisit GoF Patterns, Enterprise Integration Patterns and SOA Design patterns from time to time. In my opinion those are essential books to have.
Over time my interests will evolve as I handle newer projects that will stretch me to handle greater challenges.
Like most software professionals I use google(90%)/bing(10%) to find answers to errors, stacktraces or to learn up and coming technologies. The more equipped we are with varied skills and technologies, the better we can be at finding a suitable solution to a given problem. We have heard that if the only tool you have is a hammer then everything looks like a nail. Off late I find myself doing that because I tend to apply what I already know. But I find that keeping myself open to newer ideas and technologies helps me find better solutions over time.
Best part of working with open source projects is the breadth of choices and depth of content/expertise already available. It is like “standing on shoulders of giants” as my brilliant colleague Matthew says!
At times I have wondered..hmm..wouldn’t it be nice if a certain open source product or a specific functionality was better documented or explained. It would have saved me considerable amount of time. My goal is to help make time to share some of my practical know-how in certain technologies. I have also realized that through sharing I actually end up learning more! Nice side effect :)
Thanks again for visiting!