Let's write good code!

A Git Workflow for Humans

Introduction

This blog post serves as a documentation for a Git workflow that I successfully use for my Open Source projects (e.g. coala) as well as my clients. It’s focused on two things:

Code quality, because we need it. Otherwise our stuff will break.

Simplicity, because we’re humans and we don’t want to use something as complicated as Git flow. (I have seen a lot of people claiming to use Git flow, however when we talked about it it almost always turned out they don’t actually use it. :))

It gives general guidelines and I encourage people to change the workflow according to their special needs – however make sure that everything you do goes towards simplificy and quality and happens for a good reason.

The following paragraphs will define the most simple and minimal approach which is a base case of how this workflow works, the extensions paragraph defines some extensions which help you dealing with several common usecases. You will likely end up using the base workflow with one or two extensions.

The last paragraph will recommend some tooling which allows you to run this workflow more efficiently.

Base Workflow

Branch Names

Branch names are important because they influence how we think about the workflow. The main branch for Git repositories is master. Master is supposed to be always stable and the main point for developers to start with. The respect for a branch named master is higher than for e.g. develop and you will yield higher quality results by just naming it like that.

For development you will want to go with user owned branches. If I name my branches feature/newui, the name contains less information than me naming it sils/newui, sils being my user identification. Any developer knows who to contact if there is a stale branch or any problems – the owner of that branch.

As an owner of a branch, I can also reset my branch to a new commit that has nothing to do with the previous history. It’s my branch and it’s my responsibility.

Code Review

Great. I have my owned branch, I developed a crazy new thing and I want it to be in master! How does it work?

Do the natural thing. Submit a Pull Request, Merge Request, patches on BugZilla or whatever review UI you already use.

Start reviewing: my strong recommendation is to make good commits and review every commit on it’s own. Make sure that every commit only changes one thing and is as small as possible. Reviewers will find more bug and you will have saved a lot of time on the long run. “Reduce technical debt.” Of course you will also want to use continuous integration and code analysis on your project to save you lots of review time and enable people to find and fix issues earlier. You can use the git rebase –interactive for fixing up your commits – don’t be afraid, after you lean it once it’ll come in handy in a lot of situations.

Many workflows would now propose to do a merge commit. I recommend to do a fast forward or implement a semi-linear workflow – why? If you worked with merge commits for a longer time you probably saw failing builds on master or other critical branches even if you had CI on all branches – merge commits are changes. If you don’t review them (and that’s a hard thing to do) they may bite you. What does this mean?

Before doing a merge you have to rebase your commits onto the latest version of master. The continuous integration will be retriggered and your builds verify your code again. You should also check manually if the commits you added underneath your existing ones could do any harm! After doing that you can either do a fastforward (git merge –ff-only) or a merge commit (git merge –no-ff) if you want to keep history of your PRs/MRs. I recommend doing the fastforward and thinking in changes, not in features. This purely psychological thing can change the way you develop source code. Your builds will not fail of deterministic reasons anymore.

Releases

I recommend doing continuous releases from your master branch. Either push your website to your server or your package as a prerelease to PyPI.

If you manually want to trigger releases, set up your CI to do it for you on your command right from master. (E.g. using the “when: manual” in GitLab CI or when tagging a commit.)

If that is sufficient for you, you won’t need any other branch than master and user owned branches.

Extensions

The following paragraphs explain how you can extend your workflow.

Hotfix Branches

You may have the need to be able to fix any production issues really quickly. You will want to bypass code review. You might even want to bypass continuous integration. The solution is simple:

Just set up automatic deployment for hotfix/… branches.

The most important thing however is not to use master! Master is always stable and reviewed. You deploy a hotfix *temporarily* and pause all other development until a clean equivalent of the hotfix is merged/fastforwarded to master. This way you don’t get your master broken but you’ll be able to temporarily deploy potentially dirty hacks when needed.

Release Branches

If you want to maintain bugfix releases featuring only selected bugfix commits you will want to branch off a release/… branch when doing a release. Usually you’ll want to name it after the major and minor but not include the micro as your branch will move over your micro releases. (E.g. release/0.8 is good.) Whenever you want to do a bugfix release, just cherry pick your commits onto that branch and trigger a release when needed.

Apply the same code review policies as for master. Doing automatic prereleases may be awesome for the people using your software, being able to get the latest stuff from master in no time.

Tooling

Long story short: keep away from GitHub. GitHub forces you into their workflow using merges, cluttering history, compromising your code quality (at the advantage of being a bit simpler for them to implement and for you to use).

The best tool I found so far for this is the GitLab Enterprise Edition, which is sadly not free software. The recommended setup is:

Protect the master branch. Nobody can push. Everybody can merge.

Allow merges only when builds pass.

Allow merges only when at least one (potentially more) nonauthor approved a merge request.

Set merges to fastforward only. GitLab will offer coders a rebase button even so you don’t have to do it manually every time.

Bit silly to inflate the name master for what it is and abandon the name develop. In the gitflow branching strategy your feature branches get merged to develop. The master branch is only for releases. Releases get merged to both develop and master. That means that on master you only get released code. Not just reviewed, but released code. The difference between released and reviewed code is that released code is also tested.

That suddenly clears up the reason behind why calling it develop: untested code is code in development. Thus the branch name develop. Feature branches are alpha code, far, very far, from having been tested properly. You are merging your feature branches right into master. At what point will your testers test?

Testers’ time is valuable too. You don’t want to waste their time with your feature-branch merges. They need a way to get test and retest releases, and they need a way to test what you are going to release before it is released.

In gitflow you also use the difference between develop and master to release hotfix releases. You can easily take the release from master as a branch, fix it there, get it tested, and then merge both develop and master with it (after having made the tested hotfix release). This way the feature-branch merges happily keep on going on in develop, and the hotfix release (which must be vastly, vastly more stable than the flippidyflop new stuff of the developers) is not influenced by “new stuff”. Yet you have a clean way to bring it to both the stable world (master) and the development world (develop).

The main point for developers to start with is therefor develop. Not master. Master is for the people making releases or picking up the role of making releases if they are developers. Most developers are simply too crazy to be given that responsibility. Especially for software that matters. Not tested = not in master.

Respect for a branch named master has nothing to do with it.

Finally, feature branches are for sharing. If you claim ownership of a feature branch by adding your name to it, you are not going to make your personal branch attractive to co-workers to join you on working together on the feature. What you are proposing are personal branches, not feature branches. Good for solo developers. Not good when in a team.

Gerrit is pretty good for forcing reviews on master and it also has nice plugins on Jenkins for automatic triggering of build for every review request and getting back a Verified +1 when that build succeeds of -1 when it fails. It also has things like rules who can give Reviewed +1 and +2 and bunch of other cool stuff. There are drawbacks, however: it more or less forces you to merge your commits into one before review and it mandates using a commit-msg hook along with a custom push command so that it can create its own Change IDs instead of commit ids which change when you amend a commit.