Table of Contents
This tutorial shows how to use GitHub and git-flow together.
To show in detail the use of git-flow, this tutorial is developed around an
imaginary open-source project called foobar
, developed by a team of software
developers. The same works for a private, closed software project, and for
projects with a different role assignment or software development methodologies.
In the context of this tutorial, the following actors are supposed to exist and to actively participate in some part of the software development cycle:
- a maintainer, responsible to announce, publish and release new versions, make hot fixes and give support to old releases
- an integrator, responsible of the continuous integration of the features the team is producing and to provide a suitable environment for testing
- a team of developers, responsible of the design and implementation of the desired features in the product
In order to have more realistic examples, lets suppose following facts:
-
the maintainer username is
rocher
(it's the GitHub username I'm using to develop and maintain this tutorial; change it forlee
, if you feel more comfortable) -
the integrator username is
ted
-
in the developers team we have
alice
andbob
-
GitHub repository is used as a central, distribution point, so only
master
,develop
andsupport/*
branches should be there -
feature/*
branches might be in GitHub when some team member must publish a feature branch -
software development, integration, testing and release takes place locally, so there is no need that neither
release/*
norhotfix/*
branches to be in GitHub -
the shell examples are written in a
fish
-like look & feel:- the prompt shows only the path, with abbreviated parent directories
- the root path is the same as the username, so
ted>
indicates the home directory ofted
- when in a git repository, the current checked out branch is shown in
parenthesis, so
t/example (master)>
indicates thatted
is currently in the directoryexample
, which is a git repository, beingmaster
the currently checked out branch - there is an number at the beginning of each issued command
- blocks of commands and their respective output are separated by a blank line
- examples end with a single prompt
example:
[1] ted> git init example Initialized empty Git repository in ted/example/.git/ [2] ted> cd example [3] t/example (master)> branch * master [-] t/example (master)>
When starting from scratch, the very first thing to do is to create a new GitHub repository. Please check GitHub documentation on how to do this.
In this tutorial, the project is called foobar
, so the main repository is
named foobar-origin
to emphasize that this is the main public reference of the
project, where versions are released, contributors can send pull requests and
and package integrator can download the source code.
Once created, the maintainer makes a local copy in order to initialize
git-flow
.
[1] rocher> git clone git@github.com:rocher/foobar-origin.git foobar
Cloning into 'foobar'...
warning: You appear to have cloned an empty repository.
[-] rocher>
[1] rocher> cd foobar
[2] r/foobar (master)> git flow init -d
Using default branch names.
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/]
Bugfix branches? [bugfix/]
Release branches? [release/]
Hotfix branches? [hotfix/]
Support branches? [support/]
Version tag prefix? []
Hooks and filters directory? [rocher/foobar/.git/hooks]
[-] r/foobar (develop)>
At this point, local foobar
has two branches but no files, so it is better to
start with simple, common files:
[1] r/foobar (develop)> emacs README.md .gitignore
[ write some initial description in README.md and files to be ignored in .gitignore ]
[2] r/foobar (develop)> git add README.md .gitignore
[3] r/foobar (develop)> git commit -m 'Add basic files'
[develop 3eb00b8] Add basic files
2 files changed, 3 insertions(+)
create mode 100644 .gitignore
create mode 100644 README.md
[4] r/foobar (develop)> git push origin develop
Counting objects: 6, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (6/6), 500 bytes | 0 bytes/s, done.
Total 6 (delta 0), reused 0 (delta 0)
To github.com:rocher/foobar-origin.git
* [new branch] develop -> develop
[-] r/foobar (develop)>
Note that the master
branch has not been created in foobar-origin
, but who
cares? There are no releases to publish, so it is not needed at all.
Ok, at this point your team is ready to implement cool features. The main idea is that each developer works locally on a feature, individually or in collaboration with other members.
Alice and Bob start by creating their local copies of foobar-origin
repository. The example below shows how Alice would proceed, but the same
applies to Bob:
[1] alice> git clone git@github.com:rocher/foobar-origin.git foobar
Cloning into 'foobar'...
remote: Counting objects: 6, done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 6 (delta 0), reused 6 (delta 0), pack-reused 0
Receiving objects: 100% (6/6), done.
warning: remote HEAD refers to nonexistent ref, unable to checkout.
[2] alice> cd foobar
[3] a/foobar (master)> git flow init -d
Using default branch names.
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/]
Bugfix branches? [bugfix/]
Release branches? [release/]
Hotfix branches? [hotfix/]
Support branches? [support/]
Version tag prefix? []
Hooks and filters directory? [alice/foobar/.git/hooks]
[4] a/foobar (develop)> branch
* develop
master
[5] a/foobar (develop)> ls -a1
total 20
./
../
.git/
.gitignore
README.md
[-] a/foobar (develop)>
Once the local repository has been cloned from foobar-origin
and
git-flow-initialized, it's time to create the first feature branch:
[1] a/foobar (develop)> git flow feature start analytic-algorithm
Switched to a new branch 'feature/analytic-algorithm'
Summary of actions:
- A new branch 'feature/analytic-algorithm' was created, based on 'develop'
- You are now on branch 'feature/analytic-algorithm'
Now, start committing on your feature. When done, use:
git flow feature finish analytic-algorithm
[-] a/foobar (feature/analytic-algorithm)>
The same is done by Bob to work on his feature called blog-benchmarking
.
Feature branches can be used (but you're not advised to do) as a kind of backup branches. The question is that
if only one developer is working on a feature branch, then all commits can be safely pushed, even when compilation fails or something else is broken.
That's completely false for other branches, or for feature branches shared between team members. So please make sure how you use feature branches.
Alice has partially finished her work. She wants to share some ideas with other team members, and for that reason she needs to push her files. At this moment, no one is going to work with her code, just read it.
She could push her work as usual, but in git flow it is better to publish a feature branch:
[1] a/foobar (feature/analytic-algorithm)> git add 01-analytic-algorithm.txt
[2] a/foobar (feature/analytic-algorithm)> git commit -m 'Initial algorithm'
[feature/analytic-algorithm a38216f] Initial algorithm
1 file changed, 1 insertion(+)
create mode 100644 01-analytic-algorithm.txt
[3] a/foobar (feature/analytic-algorithm)> git flow feature publish
Counting objects: 3, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 391 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To github.com:rocher/foobar-origin.git
* [new branch] feature/analytic-algorithm -> feature/analytic-algorithm
Branch feature/analytic-algorithm set up to track remote branch feature/analytic-algorithm from origin.
Already on 'feature/analytic-algorithm'
Your branch is up-to-date with 'origin/feature/analytic-algorithm'.
Summary of actions:
- The remote branch 'feature/analytic-algorithm' was created or updated
- The local branch 'feature/analytic-algorithm' was configured to track the remote branch
- You are now on branch 'feature/analytic-algorithm'
[-] a/foobar (feature/analytic-algorithm)>