I work on small team with other remote developers on a Rails application. We are starting to modify our git workflow. We have thought about a branching structure like below:

(dev) -> (qa) -> (stag) -> (master)

But some of the developers thought it might be less confusing for new developers who might automatically push to production on master. They thought instead to have everyone work on master and create a separate branch for production.

(master) -> (qa) -> (stag) -> (prod)

I was taught you want to keep master deployable and not use it as development and from previous places where I've worked master is always meant to be deployable for production.

What would be some of the disadvantages of using a branching structure where master is actively used for development and a separate prod branch is what you use for deployments?

  • In my experience, it pays off to have one place where people can commit to at will (be it for daily check in or whatever) - with no requirements for "always compiles". Without that people delay check-ins and run the risk to lose code in accidents (e.g. disk crash). Then, it is up to them to propagate a meaningful version from there and "release it" towards the integration stream. So my prefered set of stages is like (dev) -> (units) -> (integration) -> (test) -> (production)
    – BitTickler
    Apr 9, 2015 at 14:23
  • 2
    We use successfully the git workflow described at this site with a few of differences. nvie.com/posts/a-successful-git-branching-model The only difference is that we prefer local branch squashing into develop one in order to mantain a clean histori and follow the logic "one commit, one issue"
    – Jepessen
    Apr 9, 2015 at 14:59
  • What normally occurs on your "stag" branch?
    – simgineer
    Dec 19, 2017 at 18:05
  • recommend for clearer CI/CD. master branch is not used since it maybe misintepreted. {develop} - {unit} - {integration} - {staging} - {production}. in blue/green having production continuously building > active slice, and staging > inactive slice. HEAD > develop branch where features are branched off. develop having webhooks to trigger builds towards unit progressing to integration and staging (with appropriate tags at passing integration). hotfixes towards develop+production (rare but it happens). more intricacies but a general idea. Mar 2, 2019 at 3:56

5 Answers 5


There are neither any advantages nor disadvantages to this approach. The reason I say this is simple: to Git, it makes no difference if you develop from master or release from master. You don't even need to release branches; you could tag an arbitrary commit and release that, instead.

The real trouble here is one of process and procedure. The more senior devs that are concerned that doing it in one way will confuse the newer devs need to be prepared to invest the time to explain what the release model is and why it's that way.

So long as everyone understands that master is for development, and some other arbitrary branch is for releases, and the work to maintain this is done, then there shouldn't be any problems with this approach.

  • 1
    I really do think that you hit a good point. Thanks for the feedback.
    – willyw
    Apr 9, 2015 at 17:35
  • +1 for tagging commits. I work by myself most of the time, but I tag releases for two reasons. 1) It works great with visual git history tools to show which commits have actually been in production. 2) It works great with tools like GitHub that can package release versions by checking out the tagged commit and packing into a zip file for consumption.
    – nbering
    Apr 10, 2015 at 13:03
  • 1
    Develop (dev) branch is for development. Master is misleading here and can be removed completely, so: (dev) -> (qa) -> (stag) -> (prod) alone. Oct 13, 2022 at 23:39

I can see your dilemma. I had it too, until I unlearned what I always assumed about master.

I was taught you want to keep master deployable and not use it as development and from previous places where I've worked master is always meant to be deployable for production.

From Git's documentation / book - Git branching

The “master” branch in Git is not a special branch. It is exactly like any other branch. The only reason nearly every repository has one is that the git init command creates it by default and most people don’t bother to change it.

So, if you have a preferred workflow, and it is difficult to work with it because different developers on the team have different ideas about master. You might even consider renaming master to say prod and use a workflow like below -

(dev) -> (qa) -> (stag) -> (prod)

Here is how you change the master branch name.

I am NOT saying that you must change the master branch name. But if you have a preferred workflow and it helps to change the master branch name, do it by all means :-)

  • 1
    That is a very good point. Thanks for brining that up. I don't know if we will go that far as to rename but it's good to know that git doesn't treat master in any special way. Thanks!
    – willyw
    Apr 9, 2015 at 17:33

I prefer checks over conventions in this case. Every team contains member who are better at getting new features started and other people who are better at stabilizing things for a release.

If you lack the latter, then code reviews will help (often, the more disciplined people will want code reviews anyway).

That's why we configure our Git repo (we're using Gitlab) that only certain people can merge pull requests and each developer gets their own private fork of the main repo.

That solves two problems:

  1. New developers can't change the wrong branch (since they can't push their work directly into the main repo). They might push to master on their own repo but that will be fixed when the pull request comes in.

  2. Code conventions quickly spread through the team since each commit is checked by at least another person who brings their view and knowledge.


It all depends on the overall software development process. Configuration management and how a new version comes to be cannot be defined without knowing about the overall process.

There is the "agile" faction who would opt for a "always working first commit area". They would run automated build and test facilities constantly against that area and try to have a working system "at all times".

They would see the (master) -> (release) with maybe 1,2 intermediate steps organization as beneficial.

Then there is the more "classic" faction, which has a process driven by planning and planned integration steps towards milestones, where a "unit of work" release is a planned activity with requirements such as "only release when it is (unit) tested and supposed to fit to the next planned milestone". There, the planning comprises the versioning of "units of work" and typically they go to lengths to define how the next planned product release is supposed to look like in terms of features and fixes. For the sake of planning, they want to know that what a developer releases is "proper" and a conscious act of committing a unit of work.

That classic approach does not mean necessarily that there are longer times where there is no complete product build is available.

So the "classic" workflow would be: (dev) -> (unit) -> (integration) -> (test/qa) -> (production).

The role of the integrator is to "accept/buy" released units or reject them if they do not fit the needs of the next upcoming release.

It is, on a side note also possible to mix those 2 basic approaches in opportune ways.

From my experience (which was mostly in the area of using the "classic" approach), the "classic" approach worked decently well in projects from about 4-50 people in a team.


I think the second option is better:

(master) -> (qa) -> (stag) -> (prod)

(But see the next section for caveats.)

master is the original git init default name.[1] It’s quite natural to assume that the bulk of the work will be done on a branch with that name. For that reason I think that it’s backwards that workflows like “Git Flow” decided that master is the “production ready” branch while the new arbitrary name develop is for active development. Git Flow would be better if instead of this:

(develop) -> (master)

It used this:

(master) -> (production)
  1. It’s quite natural to target your PRs against master
  2. It’s quite natural to avoid something named production for any PR or branch-off

And likewise for your two alternatives:

(dev) -> (qa) -> (stag) -> (master)
  • Here some new contributor might notice master first and just assume that that’s the main branch that you’re supposed to do work against
  • Of course dev has a hint in its name, but it’s somewhat arbitrary what the new contributors will see first

Git Flow’s influence

Of course Git Flow has already been established for a long time and has managed (hmph) to condition some people to think of develop as the main development branch and master as the “production” branch. So it might be the case that dev is more of a “main branch” hint to some people than what master is! So in that case maybe my answer is wrong. But personally when I see people discuss Git (like on StackOverflow), they almost always use master as the stand-in for “our main branch” and almost never develop.

Git Flow seems to be more of a fascination of this particular StackExchange.


  1. Now it’s configurable. main is also common, in part due to GitHub’s default.