Pragmatic Git Workflow

fleeting

TL;DR: See what flow I would suggest to apply.

I have read a few things about gitflow, github flow, trunk based development and maybe a few others fancy git flow methods.

To me, when people claim that you should do X, Y or Z is a red herring. In my mind, they all are great. Some of them are most suited for big teams, some more suited for small teams.

common principles

I think that they all follow very similar principles. In the end, we should not apply one or the other dogmatically and remain pragmatic.

The intent that I understand of those methods is:

In this note, I use the gitflow names. Not that I like those, but people are used to them.

develop
the branch that contains the shared people’s work,
master
a branch containing only the stable versions of develop,

use a method to keep cognitive load low

One could argue that we should avoid raising barriers and let the developers intuitively decide what is “good” or “bad”. I like this idea, but to me, doing so needs the developers to spend some cognitive load for every decision and it becomes exhausting. I’d rather have a method that guides the developers and let them focus on the actual work. To do so, I feel like the barriers (the method) should follow principles that make sense in the context and should be changed if need be. In other words, the method should help you doing your work without thinking much about the method. Shape your tools, don’t let your tools shape you.

The gitflow is described as a very strict method. In a big team, that might make sense, but I generally work in small teams. I still like several of it’s properties (like the short-lived branches concept). I don’t want to have a flow that would be incompatible with choosing to use the gitflow when the team grows. Indeed, I think that with a team big enough, a strict gitflow framework might be a good idea.

One aspect that I struggle with in gitflow is the “master” branch. I feel like I can use git tags to keep track of the stable versions of develop and it works pretty well in the small teams I have worked with.

On the other hand, I guess that a team big enough would result in a pretty unstable develop branch. Having a process to stabilize the code out of develop and put it into another long-lived branch might make sense then.

But, when there is no need to maintain that stable long-lived branch, because develop became stable enough, I don’t see the point of maintaining the master branch anymore. In my mind, master should be more of a medium-lived branch rather than a long-lived branch.

In other terms, I want a flow that embraces the speed and the complexity of the team. It should not annoy the team members, while supporting rapid paced team work and slower release times.

the method I suggest

What I suggest here is, I think, a dynamic method to

Therefore, my (hopefully) pragmatic workflow is:

  1. we don’t use this “master” branch at first. It might be useful later, but not at first,
  2. we start with a single develop branch, and work on it
  3. tag from time to time when you need to release
  4. when people start coming in the project, use short-lived (feature, bugfix, experimental) branches at will
  5. but don’t force not to use develop (see develop is a magnet). Only use short-lived branches when you feel you need it,
    • use a short-lived branch when your work will take some time, or needs a review before being merged.
    • merge the code back on develop using merge bubble. It makes history much easier to read than simple merges
    • NEVER rebase a short-lived branch on top of another (see below why)
    • use your gut feeling. Prefer using a branch by abstraction if you think it is better suited in this particular case,
  6. but, don’t make the life time of some jira ticket impact the life time of your short lived branches. Short lived branches must be as small as possible, and you should merge then on develop as soon as possible, even though you have (as it is often the case I would say) an unclear jira ticket that may take weeks.
    • be aware and be good with the fact that a jira ticket may take more than one short lived branch to be done.
    • don’t get used to close your jira tickets when a short lived branch is merges on develop.
  7. continue tagging on the developer branch
  8. never git merge outside of the flow. A merge must have a semantic value, it is not just a tool to get content from coworkers,
  9. if at some point the team is big enough that the develop branch struggles being stable, start using a release branch and tag on a separate “master” branch (the master branch is somehow a pseudo-long-lived branch, remaining only until develop becomes stable again)
    • use standard merges to move the code back and forth the long-lived branches
  10. if at some point the team becomes short again and develop becomes stable again, remove the master branch and go back to tagging on develop

You can claim that this is actually gitflow, trunk based development or whatever. I prefer avoid the semantic debate of what is gitflow or what is trunk based development and simply call it pragmatic git workflow.

you don’t want to start with master

Trying to blindly maintain a “master” branch, just because it is written in the gitflow will require a lot of cognitive load maintaining it without much interest. People will likely simply forget about it and tag on develop anyway. Using a more dynamic gitflow branching model, with “master” appearing only when you need it, should allow you to have a system that does not require much cognitive load when it is not necessary.

In the case someone wants to apply the dynamic branching model but start with master instead of develop, I don’t think this would be a good idea. I cannot honestly believe that a small team will work on this branch with the rigidity that a master branch eventually needs. When the develop branch exists, the team will already have learned that the master branch is not strict. Also, when the time comes to create two long-lived branch, the developers would need to migrate to develop to leave “master” alone. Therefore, I think it is better to make people start working on develop.

never rebase a short-lived branch on top of another

I want to insist on the fact that you should never rebase a short-lived branch on top of another one. The main point of a short-lived branch is that you can do whatever you want on it before merging it in a long-lived branch. If someone starts rebasing on your branch, you will end up wanting to “be nice” and keep the branch stable, avoiding changing its history and guessing twice before adding changes that may “break” it. In other terms, it starts behaving like a long-lived branch. If that is so, be intellectually honest and prefer splitting the task at hand, merging its current content in the associated long-lived branch and start a new short-lived branch to finish the work.

I actually have seen teams progressively abandon one long-lived branch like “develop” to migrate to a short-lived branch working on something everyone needs. In that case, prefer merging the code in the long-lived branch and (make clear the fact everyone is working on it) than letting the attention slide to another branch, that does not have the appropriate CI tooling and meaning.

develop is a magnet

Like a magnet, I think you should always be attracted to put the code in the develop branch.

Like a magnet, you can temporarily make the effort of resisting its attraction (using short living branches). But even then, you should still feel the attraction of coming back on it.

The short lived branches should be as short as possible.

Notes linking here