Gitflow

The only gitflow you need

Featured image

There are many Gitflow models out there. Here is the one we’ve been using:

gitflow

We use Gitlab for our projects so there will be references to Gitlab. However you could substitute with whatever Issue tracker you use such as Github or Jira.

The lifecycle of the project is split into 3 stages.

Stage 1: Project starts

Since this is just the beginning we want to emphasize velocity. It is too cumbersome to merge request for every commit because you don’t have anything built yet so instead start an unprotected branch called develop. Since it’s unprotected anyone can push to it on Gitlab. All this freedom may lead you to think there are no guidelines but there are guidelines to follow for the git commit messages. There are 4 types of commits:

  1. Feature: A distinct feature like ‘Implement Sign-in’ or ‘Implement Forget Password’.
  2. Bug: A bug discovered in previously written code.
  3. Refactor: A better implementation of previously written code. Don’t attempt unless you have specs to verify functionality didn’t break after the refactor.
  4. Misc: Anything that doesn’t fit into the above 3 categories.

The format to follow for the commit messages is as follows:

COMMIT TYPE #Issue Number - Brief Description

For example:

FEATURE #284 - Implement Sign-in Feature

Stage 2: MVP

Since the MVP is ready to show to the client it’s time to create a staging server.

At this point in the project we’re ready to introduce the master branch which will be deployed to staging server. This new branch is protected so to push code to it you have to issue a merge request which needs to be assigned to a Senior Developer on the project. If no Senior Developer exists on the project please find a Team Lead to assign it to.

If you are working on a feature and find a problem with it, commit your fix on the feature branch, not directly to the develop branch, this keeps all the code together in a single branch that can be squashed to a single commit which then can be moved around from branch to branch as needed. For example you may find the feature is being tested in develop and it works but ultimately the client doesn’t want it as part of the MVP so it never goes into master branch. Since it’s in a single commit it’s easy to move the commit around. Had it been split amongst multiple commits you’d find yourself cherry-picking multiple commits which makes it easy to miss something.

Master branch always contains working and shippable code. If the code is not working or the client doesn’t want the public to see it keep it in develop branch. Remove it from the master branch.

Any bug fixes done on master branch must be merged back to develop.

Base new features from master branch this way if there are features on develop that you don’t want to see in staging you don’t have to back out the unwanted code, you always start from what is in staging without any unnecessary features.

If develop is a good candidate for the next staging release then merge any features bug fixes from develop branch to master branch.

Stage 3: Production

Site is now ready to go live so we create a production server.

Now that you have a staging and a production server so it’s time to introduce a new branch called staging. Mark staging branch as protected in Gitlab. Since it’s protected you have to issue merge requests to push code to it.

master branch now becomes production ready code and staging branch is what’s deployed to staging server. The role of develop branch stays the same.

Remember that staging branch may get push forced. It may get overwritten with the develop branch if everything on develop needs to go to production. So if you’re not sure whether or not a feature will go into the next deployment candidate keep it on develop branch.

Create Hotfix branches off of master branch if you need to fix something on production and merge them back into staging branch when done. The finally merge back your Hotfix into develop as well. Everything needs to come back to develop since it becomes the new staging at the beginning of every sprint and staging becomes the new master eventually.

At the end of each sprint staging should be:
○ tested
○ merged into master
○ deployed to production server
○ tagged with a Gitlab sprint number

When a new sprint begins push force develop to staging branch.

Merge requests

If you get a merge request assigned to you examine the code, see if it makes sense, if it doesn’t then make a comment on Gitlab and reject it. Always verify the build is passing before approving merge requests, if it’s failing, get it fixed first, do not approve merge requests that fail to bulid

Please ensure:
○ rspec passes
○ frontend spec passes
○ rubocop passes

If it’s failing create an issue for the developer to fix the build. If it makes sense and the build passes, approve the merge request and mark the remote branch for deletion after merge request is complete. This way the remote branches remain clean. You can also squash commits in Gitlab so that you have an atomic commit to move around the branches as necessary.

Now it’s time for a demo

See it in action

Stage 1

  1. create test repository on Gitlab
  2. create develop branch and allow anyone to push to it
git clone gitlab@gitlab.company.com:company/test.git
cd test
git checkout -b develop
echo 'readme' >> README.md
git add .
git commit
# initial commit
git push -u origin develop
  1. create Gitlab project
  2. create sprint 1
  3. create feature
  4. confirm you are in develop branch
echo 'some code' >> feature.rb
git add .
git commit
# FEATURE #23423 - User registration
git push
  1. you discover a bug
  2. create issue on Gitlab
  3. confirm you are in develop branch
echo 'some code' >> fix.rb
git add .
git commit
# BUG #234234 - Fix user registration
git push

Stage 2

Assume staging server is already created and we can just issue cap staging deploy.

  1. create master branch and protect it
  2. set master branch as default
git checkout master
# work on feature
git checkout develop
git checkout -b feature/4324_forgot_password
echo 'some code' >> feature2.rb
git add .
git commit
# FEATURE #4324 - Add 'Forgot password'
git push -u origin feature/4324_forgot_password
# do another commit
echo 'some code' >> feature3.rb
git add .
git commit
# FEATURE #4324 - Add 'Forgot password' feature
#
# - change spelling
git push

Since this feature is complete you’re ready to create a merge request to put it on staging so it can de deployed.

  1. create merge request
  2. go through accepting merge request
  3. examine code
cap staging deploy

What if you find a bug on staging? First create an issue on Gitlab.

git checkout master
git pull #other people may have pushed
git checkout -b bug/4355_fix_forgot_password
echo 'some code' >> bug.rb
git add .
git commit
# BUG #4355 - fix forgot password
git push -u origin bug/4355_fix_forgot_password
  1. create merge request
  2. once it’s merged to master, deploy it
cap staging deploy

and merge it back into develop branch

git checkout develop
git merge master

Stage 3

Assume we have a production server setup and we can issue cap production deploy. Start by creating a staging branch on Gitlab and mark it as protected.

git checkout develop
git checkout -b staging
git push -u origin staging

Now staging branch is deployed to staging and master branch is deployed to production. Everything is same as before but now you also have Hotfix branches for when you discover a problem on production. You then create an issue on Gitlab.

git checkout master
git pull
git checkout -b hotfix/5454_fix_email
echo 'some code' >> fix2.rb
git add .
git commit
# BUG #5454 - Fix email
git push -u origin hotfix/5454_fix_email

Create merge request and once merged:

cap production deploy

marge it back to staging

git checkout staging
git merge master

merge it back to deploy

git checkout deploy
git merge master

when the sprint ends

git checkout staging
git pull

Make sure it’s tested, spec passes, rubocop passes and have a Senior Developer do the merge.

git checkout master
git merge staging
git tag 1.0 #sprint number
cap production deploy

Once new sprint begins restart staging branch from develop.

git checkout develop
git pull
git checkout staging
git reset --hard develop
git push origin staging --force