Vadim Samokhin

@wrong.about

Gitflow is a Poor Branching Model Hack

July 30th 2018

and here is why.

Let me repeat: gitflow is just a poor branching flow hack indicating low level of your team’s engineering practices.

Okay, before you eat me alive let me explain.

Brief subjective history of version-control systems

Pre-vcs days
Separate development based on anything but features which resulted in integration hell that could last for years.

SVN
SVN caught me in my twenties and my coding culture apparently was lower than it is now. I didn’t write unit tests, my OOP was poor, I didn’t know about neither SCRUM nor any other agile approaches, but one thing SVN taught me was responsibility. I couldn’t check in the code that didn’t work. There could be no unit tests, the code could be a total mess, but it had to work.

Git
Lots of long-living branches, CI is consigned to oblivion, integration hell comes back.

Git + CI
Lots of branches and continuous merge into develop branch.

So quite a few folks caught at least three main vcs milestones, with all their philosophy. And here is a question: what is right, what is wrong? What branching strategy to use? Should develop branch be stable or not, or to what extent it should be stable?

Well, it’s actually the other way around. It is your branching model that should reflect your team’s workflow.

Writing code

Do you write unit tests? When? Do you write them along with code? What is your code coverage? Can you be sure that everything’s great if all of your tests pass? Or, in other words, can you merge your feature branch with the main one and deploy it right away? If no, apparently, your code needs further testing — be it manual or with functional tests. So if you have a single main branch which corresponds to what is currently in production environment, or, in Fowler’s term, a mainline — you can’t just merge your branch in it: time between this merge and the moment when this feature will be tested and all bugs fixed can be significant. If you think that it’s not problem, think of a situation when a critical bug on production appears and you need to fix it asap. But you can’t: there is either untested or not working (or both) code in your main branch.

So for now you have two options. Either you follow continuous integration practices and have an additional unstable branch where your team continuously merges their code into and pulls from:

or you don’t merge code at all and keep it in its own feature branches:

In the latter case, QA can’t test features in parallel, since after merging them all together in a mainline conflicts can arise. The worst thing is when git silently merges the code, but logical conflicts are still there, and you can’t see them:

Logical conflicts when testing branches in parallel

So the only viable option is to test those features in their branches and merge into the main branch subsequently, so that there is no way they could unpredictably interfere with each other, but more on testing in the following section.

Testing

Does your QA team write functional tests? When? The main question is the same: at what point in time you can be sure that you’ve done the right thing and haven’t broken anything?

Typical approach
You write some code, probably with some unit tests. You have no confidence that everything works fine though. Anyway, by the time when you’re done with your user-story you can’t be sure that everything works as expected and you don’t break anything. The worst thing you can do is to keep this code in its own branch and postpone an inevitable pain of code integration until the end of the sprint. The better option, as mentioned earlier, is to merge it right away into develop branch. After that, your colleagues pull develop into their own branches. Even when none of them writes tests, chances are they encounter wrong behavior, but it’s way easier to fix it, because they know that it was the latest git pull origin develop that broke their branch. So instead of searching for the bug in two-weeks code pile, they just look through the yesterday’s work. And very likely, if they ask about the problem in their dev chat or in the room they all sit in, they will get an answer right away. Once again: it’s easier to find the reason of false behavior if the time between when a bug has appeared and the time it has been discovered is small.

Anyways, somewhere close to the end of the sprint your QA team chimes in and starts to test the sprint user stories. If they really do start to test the sprint in its ending, I bet they do it manually. It just doesn’t make any sense to test user stories during the sprint manually since any following commit can break things. Moreover, in case the testing process lingers, it shouldn’t block developers from implementing the user stories from the next sprint. So QA team has to have their own branch for testing the sprint. Here is how it looks:

Do you recognize what branching strategy corresponds to this workflow? Right, it’s gitflow.

Good approach
Bad engineering practices often result in late and unpredictable deployment discussed above. So common reason says that your test suite should contain not only unit tests but at least functional tests. It automatically means that QA team should start to write their tests as soon as possible. So in this case you’re in a situation that is quite contrary to what I described in a previous chapter. To put is shortly, you can deploy your code as soon as it gets ready, and you only need a single branch, which is always stable. By the way, this is called continuous delivery.

Deployment

Do you deploy manually? Automatically? How long does it take? Are you ready to deploy every commit in the main branch? If no, you probably need to have at least one stable branch that is currently on production and is used for urgent bug fixing, and the second one is, although stable, but due to deploy process difficulties, is deployed, say, once a day. So, here is yet another branching model that plainly suits your workflow.

Summary

There is no such thing as an ideal branching model. Depending on your team’s workflow (which, in turn, depends on the level of its engineering culture), some specific branching workflow suits best for you. And before switching to another branching model, make sure your team is ready for it.

Check out my puristic posts on a following topics:
 * discussion on concrete foundations behind SOLID principles and values they are based upon;
 * how to build resilient and reliable SOA;
 * what to watch out for the most when you create microservices, and the most common reason why they fail;
 * my take on the following ubiquitous concepts: implementation inheritance (evil!), how to decompose domain and avoid anemic domain model, how to decompose a system into modules, static classes (evil again!), DI container (useless evil), ORM (evil as well), domain service classes (right, evil).

More by Vadim Samokhin

More Related Stories