Please stop recommending Git Flow!

Git-flow is a branching and merging methodology popularized by this blog post, entitled “A Successful Git branching model”.

In the last ten years, countless teams have been snookered by the headline and dare I say lied to.

If you read the blog post, the author claims they successfully introduced it in their projects, but purposefully doesn’t talk about the project details that made it successful.

And for the rest of us, this is mistake #1 of trusting the blog post. I’ll claim it as a truism that not all strategies work in all situations, with all people, in all contexts, and I apply that same logic to this branching model.

The end, right? Well, not quite. I can tell a few of you are unconvinced by this line of reasoning, so let’s dig deeper into why the gitflow branching model should die in a fire.

GitFlow Is Complicated On its Face

Even before you think about Microservices, or continuous delivery, gitflow is complicated. Take a look at this image and tell me it’s immediately intuitive:

(source: https://nvie.com/posts/a-successful-git-branching-model/ )

So here you have feature branches, release branches, master, develop, a hotfix branch, and git tags. These are all things that have to be tracked, understood, and accounted for in your build and release process.

More so than that, you also need to keep track of what branch is what, all the time. The mental model you need to retain for this to be useful carries a high cognitive load. I’ve been using git for 10 years now, and I’m not even sure I’m at the point where I could mentally keep up with what’s going on here.

Gitflow violates the “Short-lived” branches rule

In git, the number of merge conflicts with people committing to a branch will increase with the number of people working on that branch. With git-flow, that number increases even more, because there are three other branches (of varying lifetimes) that merge into develop: Feature branches, release branches, and hot-fixes. So now the potential for merge-conflicts is not linear, it’s going to potentially triple the opportunities for merge conflicts.

No thank you.

While I hesitate to say “Worrying about merge conflicts” is a valid reason not to pursue a branching strategy like gitflow; the amount of potential complexity that is introduced when all these branches come together is too much to overlook. This would be fine if you have an organization with a low commit-velocity rate; but for any appreciable fast moving organization or startup, this won’t be the case.

Gitflow abandons rebasing

I recognize rebasing is a complex topic; but it’s important to this conversation. If you pursue gitflow, you’re gonna have to give up rebasing. Remember, rebasing does away with the merge commit — the point where you can see two branches coming together. And with the visual complexity of gitflow, you’re going to need to visually track branches, and that means no rebasing if you want to unwind a problem.

Gitflow makes Continuous Delivery Improbable

Continuous delivery is a practice where the team release directly into production with each “check-in” (in reality, a merge to master), in an automated fashion. Look at the mess that is gitflow and explain to me how you’re going to be able to continuously deliver *that*?

The entire branching model is predicated off a predictable, long term release cycle; not off releasing new code every few minutes or hours. There’s too much overhead for that; not to mention one of the central practices of CD is to roll-forward with fixes; and Gitflow treats hotfixes as a separate entity to be carefully preserved and controlled and separated from other work.

Gitflow is impossible to work with in multiple repositories

With the advent of Microservices; there’s been more of a push towards the idea of micro-repos as well (cue commenter shouting “they’re orthogonal to each other”), where individual teams have control over their repositories and workflows, and where they can control who checks in to their repositories and how their workflows work.

Have you ever *tried* a complex branching model like gitflow with multiple teams, and hoped for everyone to be on the same page? Can’t happen. Soon, the system becomes a manifest of the different revisions of the different repositories, and the only people who know where everything is at are the people pounding out the YAML to update the manifests. “What’s in production” becomes an existential question, if you’re not careful.

Gitflow is impossible to work with in a monorepo as well

So if micro-repos are out due to the difficulty in coordinating releases, why not just one big branching workflow that all the microservices teams have to abide by for releases?

This works for about 3.2 seconds, or the time it takes for a team to say “This has to go out now”, when the other teams aren’t ready for their stuff to be released. If teams are independent and microservices should be independently deployable, you can’t very well tie your workflow to the centralized branching model you created in your mono-repo.

Who should (and shouldn’t) use Gitflow?

If your organization is on a monthly or quarterly release cycle and it’s a team that works on multiple releases in parallel, Gitflow may be a good choice for you. If your team is a startup, or an internet-facing website or web application, where you may have multiple releases in a day; gitflow isn’t good for you. If your team is small (under 10 people), gitflow puts too much ceremony and overhead into your work.

If your teams, on the other hand, are 20+ people working on parallel releases, gitflow introduces just enough ceremony to ensure you don’t mess things up.

Ok, so my team shouldn’t use gitflow. What should we use?

I can’t answer that. Not all branching models work for all teams, in all contexts, and all cultures. If you practice CD, you want something that streamlines your process as much as possible. Some people swear by Trunk-based development and feature flags. However, those scare the hell out of me from a testing perspective.

The crucial point I’m making is to is ask questions of your team: What problems will this branching model help us solve? What problems will it create? What sorts of development will this model encourage? Do we want to encourage that behavior? Any branching model you choose is ultimately meant to make humans work together more easily to produce software, and so the branching model needs to take into account the needs of the particular humans using it, not something someone wrote on the internet and claimed was ‘successful’.

Author’s end note: I thought about using the ‘considered harmful’ moniker that is so common in posts like this; but then did a google search and realized someone else already wrote Gitflow considered harmful. That article is also worth your time.

36 thoughts on “Please stop recommending Git Flow!”

  1. This is an interesting read. I’d be interested to know your own git workflow as at least one viable alternative.

    1. Use Threeflow! (The “No Machete Juggling” blog if you have trouble googling it)

      I mean every use-case is going to be different but if you are at a small startupy place with repos for single apps, Threeflow is going to be a solid improvement.

      The basic idea is that you want in this case everyone in the same room having the same conversation, so you commit to the idea that we should have a place where we merge dev code on the daily as our source of truth about the system. No long-lived feature branches. We subordinate all the rest of our process to this vision. “But I need to control what features get deployed in my releases”—Not A Problem For Your Git!! That needs to be handled in the logic of the repo itself, either with DB states or env vars that push that question to the last possible moment or by a checked in file that defines statically what features are enabled, which devs locally overwrite. “But if we have 7 feature toggles then the QA team has to test 2^7 = 128 different configurations, maybe”—you have to get them talking with everybody better and also restrict the flow of feature requests into your development system so that it is driven by your slowest step, a limit on the number of feature toggles we allow: and you have to clean up branches after they have been deployed for a week. “But my devs check in breaking code”—you need test suites, feature toggles, code review to make sure they don’t, then.

      You subordinate everything else, “I will do whatever I need to, to ensure that everyone is in the same room having the same conversation about the same codebase. That is the one thing I will not budge on, that all my developers checks in their work daily and see merge conflicts early so they can collaborate rather than step on each others’ feet.” And it works extremely well at smaller scales, IF you can get developer buy-in.

      (Developers find feature toggles to just *look ugly* so you have to really lean hard on the fact of “look we need you to do this so that we don’t waste half your time in release planning meetings and other crap. I know it is ugly but here are the ways we are going to bound its ugliness and let the code eventually become beautiful.”)

      1. I have only used feature toggles a handful times, but I suspect it is the way to go.

        Assuming you have a sane release policy that is. If you find yourself doing lots of patches while maintaining several versions, then you will be stuck with a more convoluted work flow.

        My least favorite initialism: “LTS”. Imagine patching a LTS branch and then bring that fix forward into your current release as well as your main dev branch. Or better yet: You start out patching the current release and after a while somebody asks “what about those still running the LTS version?”. (my reply usually is: “Fine, the current release is now considered LTS. Have them upgrade as there are a bunch other useful fixes in there too.”) Oh hang on, should we merge the LTS fix into master as well..?

        I suspect many of us could embrace Continuous Deployment with much more vigor. At least when the user interface is mostly web and no local deployment is involved. At that point I believe the full git workflow becomes overkill.

  2. So, your post is to pull someone’s idea to pieces while offering nothing of value yourself? I am disappointed this article made it onto HN

    1. He literally wrote a thoughtful reason as to why he didn’t recommend something specific and the most important thing of all, to ask questions of your team. Teams should be thinking for themselves more and relying on magical blog posts less. Don’t trash someone if you aren’t going to take the time to understand their point of view.

  3. To be honest, you start with:

    “doesn’t talk about the project details that made it successful”
    Well Gitflow is about 10 years old, so there are many good projects already worked with it.

    “GitFlow Is Complicated On its Face”
    Not really, maybe redundant but not complicated.

    “Gitflow is impossible to work with in a monorepo as well”
    No, it’s maybe not the best solution for a fast agile devEnv. but else its working very well.
    Even if you have a bi-weekly release cycle it’s working fine.
    I would love to share a project of our team, but as you can expect I’m not allowed

    Ok, so my team shouldn’t use gitflow. What should we use?
    You can’t answer that?
    Well there are so many other workflows that you could give some examples

    But yea, you showed some example where you can get problems but to say it’s not good is kinda unfair.
    So i think, you are not completely wrong, but I also have to say that you don’t really grasp the concept behind gitflow as it’s not really complicated if you understand git.
    It’s also discussed very often in different forums and so on.

    https://stackoverflow.com/questions/18188492/what-are-the-pros-and-cons-of-git-flow-vs-github-flow

  4. Quite frankly, Git should die in a fire.

    Not that what Git does is bad. But the idea that it needed no useful tree structured visual interface that looked somewhat like file explorer, SourceSafe or team foundation server is just programmer arrogance at its worst. Those interfaces happened for a solid human-factors *reason* and were not whimsical afterthoughts. They gave the user a mental model, showed both local and remote server information accurately and allowed pinpoint actions on a file, folder or project that you could plainly SEE. Command line options were available and I used them in batch files frequently, but the batch files were useful because I could SEE what I was doing, simultaneously, both locally and on the server.

    Visibility and local action is what made older version control systems *immediately* useful with almost no training. Git, SourceTree GitHub desktop, et. al. Not so much. Git seems *designed* to hide information, possibly with the intent of preventing mistakes. Of course, if you make it difficult to make easy mistakes, you can also make it extremely difficult to do anything.

    It’s not that Git isn’t learnable. I use it daily. It’s just that it was a poorly thought out alternative. It’s *technically* great. It’s the human factors part that’s a disaster.

    And frankly, if you don’t understand the human nervous system and you’re making a human facing product, you’re a lousy engineer because you either don’t understand or ignore half the system you’re building.

    1. I’ve been a developer for only 2 or 3 years and I have no problem visualizing git branches and what not in the terminal. The only user interface I use is the Github website, and that’s strictly for issues and PRs. I rarely look at actual branch graphs or anything.

    2. “It’s not that Git isn’t learnable. I use it daily. It’s just that it was a poorly thought out alternative. It’s *technically* great. It’s the human factors part that’s a disaster.”

      I agree with this and add that in this respect Git is typical for what comes from the Linux world.

    3. “Quite frankly, Git should die in a fire.”

      I would like to take your words out back and shoot them. Git’s commandline interface is quite rightly criticized, but git is the only versioning system I’ve used that gets it right[1]. Period. Its DAG, and especially, the concept that every commit represents the entire working tree at a moment-in-time, is both simple and correct.

      100x over and over, I would rather use a tool that gets it right and has a completely shit user interface, than a tool that has a beautiful user interface but doesn’t get things right.

      [1] I’ve heard great things about Mercurial and couple other tools, but I know git and this thread is about git.

    4. git –all –decorate –oneline –graph
      Alias that to ‘git adog’.

      Git was designed for people who thought a certain way, who subscribed to a certain methodology, and who had a certain level of technical ability. Not all humans are the same. It wasn’t poorly thought out – it just wasn’t what you wanted. The designers of git aren’t the ones suffering from programmer arrogance at it’s worst.

    5. I love Git and I agree with you, I use Git on Visual Studio 2019 and I can’t rebember the last time I needed to use the command line.

  5. Git flow is good enough to get started and will actually take you really far. It’s a recipe for how to use branches effectively, because they’re cheap.
    Now there are a lot of other branching models that are good for a lot of different scenarios.
    Complaining about one branching model without even recommending when the others are suitable makes for poor reading.

  6. I could not agree more and I had the same reaction when I saw that diagram many years ago.

    For anyone asking what to do instead of Gitflow, I’d suggest this: Start simple.

    – Don’t commit to Master (obvs).
    – All work is done in a separate branch that will be merged to master.
    – Keep your PRs small so they are easy to understand and easy to review.
    – Keep Master in a constantly deployable state.

    To handle the complications of adding in large features, find ways to hide them in prod so they can get into Master as early as possible. Feature flags are fantastic for this, but even building a temporary route so you can view the changes but not expose them to your user will work just fine.

    Also, writing tests for work also makes small, frequent merges less of a dangerous game. They aren’t perfect, but if everything has a test around it then you’re less likely to break things even if you’re merging a dozen PRs a day.

    Anyway, love the post. 👍

  7. To pick up where the author left off:

    In short, Trunk-based Development is the solution you are looking for.
    https://trunkbaseddevelopment.com/

    Trunk-based Development has it all, and that website should be considered required reading for anyone implementing or upgrading their personal or professional development workflow.

    If that site doesn’t convince you, then read State of Devops 2019
    https://services.google.com/fh/files/misc/state-of-devOps-2019.pdf

    So long GitFlow, what we had…was not good.

    Cheers, to your better development future! Welcome!

  8. I echo the other commenters: can you give an example of a project you worked on, and what Git branching model was successful and why? Otherwise this post only serves to discourage and confuse people like myself who have used Gitflow in the past.

  9. Huh? There are way less merge conflicts when using git flow correctly. The diagram above is missing a few ghost merges from develop down to feature branches (every time there’s a push by someone else to development, specifically). But that’s one of the main draws – having a highly hierarchical and rigidly adhered-to branching strategy eliminates merge conflicts that aren’t directly related to code the developer who’s doing the pull created themselves.

    I could go point by point on why it seems like you’ve never worked with people who knew how to do this correctly and why that’s coloring your opinion, but I just got a 70 year old on this model from TFS last year and got him loving it, so it’s not too late for you.

    But just FYI: “This has to go out now” is how you know to use a hotfix branch which works against only production/master code. “What’s in production” is always easy – it’s what’s in master. Continuous delivery is a checkbox for development, and you add a combo/dropdown that gets updated once per release for QA to point to the new release branch. And if you can’t coordinate releases and shared code with GitFlow, you’re not going to have any better time rolling your own structure and keeping track of that being different every release…

    Good luck out there.

    1. This is what we’ve been using for years. And it works well. I would say start here, and if you need something more, then look to more involved branching strategies like git flow. I would caution against jumping to something so complicated right out of the gate for new projects.

  10. I’ve been successfully using Git Flow for well over 5 years in a multi-repo, micro-service, continuous delivery environment and I’ve found it to be a really good fit for our team.

    What Git Flow did for us is to standardise a development flow, which removed differences between our Git experts and others, and gave everyone a shared mental model so make teamwork better.

    Despite this blog post’s experiences, in our team it actually reduced merge conflicts, reduced long running branches, and eliminated lost branches because it also eliminated tricky git-fu merges of topic branches along with a bike-shedding.

    It gave our workflow better clarity.
    We have even tied our processes to git flow concepts, and this meant we all had a shared understanding across the team including devs, ops and even managers, who knew, for example what type of work could be a hotfixed vs needing a full release.

    Could all these benefits come another way? Well, certainly. But for us there was a clear before/after transition where all our prior git problems disappeared after we introduced Git Flow. It isn’t perfect, but it solves more problems than it creates for us, and we have made it work in a continuous delivery, micro-service and buzzword compliant environment.

  11. Git flow is a scalable methodology that you. The one in the diagram is the extreme case.

    In my company, we use master, staging (like develop branch in the diagram) and feature branch everything from staging. That’s it. No hotfix or release branch.

    We link all PRs with Jira through a script which updates Jira issue a custom field that specifies whether this issue has been merged or not and if merged, in which branch: staging or master or both. This way we can easily do a JQL and know where is each issue at.

    If I feature branch from staging today and by the time I finish work, the staging bench gets updates, I rebase the feature branch onto staging.

    The fact that you dont suggest an alternative might imply you didn’t try anything else that actually works before writing this post.

  12. This publication level is around this:

    Cars are bad! Because:
    – demands on gas
    – you should have driving licence and study laws to drive a car
    – they move only when you start engine and press pedals
    – requires periodical service
    – there are higher risks of car accident
    – you must decide which color your car should have

    Any approach have its own advantages and disadvantages. And it is about knowing how to use accessible tools properly and not about proclaiming of “stop recommending this tool”. Gitflow is the perfect tool for delivering changes to code and it is definitely better than many custom approaches people usually invent.
    Gitflow real disadvantages mostly affect project management and planning processes and not the software development itself.

  13. So to sum up: there is not only a git-flow approach and you should choose from teams need. Also sounds like a problem to handle more than one branch

  14. This is something that works for us:

    – Single master branch where all the changes go. No commits made here directly (exception can be made for hotfixes)
    – Feature branches are created from the master HEAD and should be short lived.
    – Environment branches (dev, stage, prod), unlike feature branches, are permanent and are always rebased from latest HEAD of master. Changes to these branches trigger the CI/CD pipeline to deploy into those environments automatically. We use separate Kubernetes clusters hosted on GCP/Azure/AWS as the deployment environments. No commits should be made directly to these branches, all commits go to master via feature branches

  15. 1. What is on PRODUCTION? That’s simple – master 🙂
    2. Why are you mixing microservices and GIT? Why microservice team should depend on another? That’s whole point that teams are fully independent one can has Git, another Subversion or X(put name). Different versioning etc.
    3. Propose rather than blame.

  16. I stopped reading at the paragraph about rebaseing. Dude, if you “recognize rebasing is a complex topic”, go back to the classroom and learn GIT from ground up. Rebase is – if you once understood it – not at all complex. I use GitFlow on a daily base and are able to rebase.

  17. I don’t understand how so many ppl like GitFlow. Are those ppl managing releases and hotfixes? I doubt it. If you think you like it and you don’t have release and hotfix branches, you probably don’t do GitFlow.

    In my understand, GitFlow is valuable just if you need to support more than one version of your software. In other cases, a production-like master is enough.

Leave a Reply to Rune Cancel reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.