My choice of version control system recently changed from Mercurial to Git. As part of this change I decided that there’s no better time than the present to move to a proper branching strategy (and in doing so replacing my god-branch “strategy” – which is not an actual branching strategy; I was merely using a single branch for all my commits). I’ve since been meaning to start using Git-Flow and decided that an effective way to cement this workflow into my day-to-day commits would be create a Git-Flow Gym.

What is the Git-Flow Gym?

The goal of this post is simple – follow the tasks in an attempt to recreate the commit history example from Vincent Driessen’s blog.

git-flow

There is a task for each number in the image above. After completing these tasks you should be more comfortable and confident moving forward with Git-Flow in your future projects.

In Preparation

Before you attempt the tasks you might want to familiarise yourself with the strategy behind Git-Flow by reading Vincent Driessen’s Blog post. Note that in this post the naming convention has changed from branch-* to branch/*.

Also familiarising yourself with the git flow commands in Daniel Kummer’s Git-Flow cheatsheet (note that feature collaboration and release collaboration is not covered in this post).

Repository Setup

Run the commands below to set up your local repository:

  1. initialise git flow (use the default values) git flow init

  2. create base files touch task00 git add .

  3. perform first commit git commit -m "task00"

  4. rebase to the master branch git checkout master git merge --no-ff develop

  5. tag the master branch (skip this step for other projects) git tag -a 0.1 -m "tagging 0.1"

The Tasks

Complete the following tasks in sequence. Changes to the code base are performed by executing the touch command, e.g. touch task##, where ## is to be replaced with the task number (e.g. touch task01). Furthermore, commit messages follow the pattern git commit -m "task##". A lot of branch switching occurs in theses tasks; the flow has not been optimized so as to get more comfortable with branch checkouts and merges via practice.

  1. Start a new task in the develop branch and commit. git checkout develop
    touch task01
    git add .
    git commit -m "task01"
  2. Create a new commit on the existing task. touch task02
    git add .
    git commit -m "task02"
  3. Create another commit on the existing task. touch task03
    git add .
    git commit -m "task03"
  4. Create a feature branch (call it 'a') and commit a change to it. git flow feature start a
    touch task04
    git add .
    git commit -m "task04"
  5. Create another feature branch (call it 'b') and commit a change to it. git flow feature start b
    touch task05
    git add .
    git commit -m "task05"
  6. Create a commit the development branch. git checkout develop
    touch task06
    git add .
    git commit -m "task06"
  7. Start hotfix 0.2 and commit a change. git flow hotfix start 0.2
    touch task07
    git add .
    git commit -m "task07"
  8. Finish hotfix 0.2 (this merges the branch with both master and develop). git flow hotfix finish 0.2 -m "task08"
  9. Commit a change to feature/a. git checkout feature/a
    touch task09
    git add .
    git commit -m "task09"
  10. Commit a change to feature/b. git checkout feature/b
    touch task10
    git add .
    git commit -m "task10"
  11. Commit a change to feature-b. touch task11
    git add .
    git commit -m "task11"
  12. Finish feature b (this merges the branch with develop). git flow feature finish b
  13. Start a release branch (1.0) and commit a change. git flow release start 1.0
    touch task13
    git add .
    git commit -m "task13"
  14. Commit a change to release 1.0. touch task14
    git add .
    git commit -m "task14"
  15. Merge release 1.0 into develop and commit. git checkout develop
    git merge --no-ff release/1.0
    touch task15
    git add .
    git commit -m "task15"
  16. Commit a change to feature-a. git checkout feature/a
    touch task16
    git add .
    git commit -m "task16"
  17. Create a feature branch (call it 'c') and commit a change to it. git flow feature start c
    touch task17
    git add .
    git commit -m "task17"
  18. Commit a change to release 1.0. git checkout release/1.0
    touch task18
    git add .
    git commit -m "task18"
  19. Commit another change to release 1.0. touch task19
    git add .
    git commit -m "task19"
  20. Finish release 1.0 (this merges the branch with both master and develop). git flow release finish 1.0 -m "task20"
  21. Create a change to feature-c. git checkout feature/c
    touch task21
    git add .
    git commit -m "task21"
  22. Commit a change to feature-c. touch task22
    git add .
    git commit -m "task22"
  23. Create a change to feature-a. git checkout feature/a
    touch task23
    git add .
    git commit -m "task23"
  24. Finish feature c and then feature a. git flow feature finish c
    git flow feature finish a
  25. Start a release branch (1.1) and commit a change. git flow release start 1.1
    touch task25
    git add .
    git commit -m "task25"
  26. Finish release 1.1. git flow release finish 1.1 -m "task26"

If we checkout the master branch and run the command git log --graph --pretty=format:"%s" we should see the following output:

*   Merge branch 'release/1.1'
|\
| * task25
| *   Merge branch 'feature/a' into develop
| |\
| | * task23
| | * task16
| | * task09
| | * task04
| * |   Merge branch 'feature/c' into develop
| |\ \
| | * | task22
| | * | task21
| | * | task17
| * | |   Merge tag '1.0' into develop
| |\ \ \
| |/ / /
|/| / /
| |/ /
* | |   Merge branch 'release/1.0'
|\ \ \
| * | | task19
| * | | task18
| | * | task15
| | * |   Merge branch 'release/1.0' into develop
| | |\ \
| | |/ /
| |/| |
| * | | task14
| * | | task13
| |/ /
| * |   Merge branch 'feature/b' into develop
| |\ \
| | * | task11
| | * | task10
| | * | task05
| | |/
| * |   Merge tag '0.2' into develop
| |\ \
| |/ /
|/| |
* | |   Merge branch 'hotfix/0.2'
|\ \ \
| * | | task07
|/ / /
* | |   Merge branch 'develop'
|\ \ \
| | * | task06
| | |/
| | * task03
| | * task02
| | * task01
| |/
| * task00
|/
* Initial commit

With the aid of the git flow * commands this exercise turned out to be easier than I thought it would be. I hope you found as much value out of this post as I did in creating it.

-f