We have a web application that gets deployed to multiple regions around our state. An instance of the application for each region. We maintain a staging and production (master) branch in our repository, but we were wondering what is the best way of maintaining each instances codebase. It's similar at the core, but we have to give each region the ability to make specific requests that may not make it into the core of the application.

Right now we have branches for each region, like region_one_staging, and region_one_production. At the rate we're growing we'll have hundreds of branches here in the next few years.

Is there a better way to do this?


You can avoid this by branching by abstraction instead:

Summary: Don't separate differing concerns by using a VCS, use an abstraction instead.

If you start branching in VCS for regional differences, where most common example would be to branch by language or country, you will start to slip into the slippery-slope known as variant management. This is because managing variants through source control itself is a very unmanageable practice, because they can grow into an unmanagable number really quickly.

Let me repeat this:


So what do you do instead? Well, you don't use VCS for branching variations; instead you build the variation support it into your application through abstraction. In your case the application varies in regions, so why not make that what varies into pluggable modules into your application? Or even simpler: have a configuration file for each region that the application would load and use the features needed for the configured region. It could all be checked into one and same branch, instead of bloating it all into several branches.

Here is an anecdotal and hopefully practical example of branching by abstraction:

In one of my previous workplaces website has support for many countries in europe (that has different languages and needs). We had a nifty feature blocker in place where new features would be registered into a feature access list. It initially started out with only logged in developers and testers would have access to the unreleased features. Later we would add checks on countries and languages such as logged in users in the correct region could access the feature.

This way we could quickly push out new features or quickly halt them in production if we ever needed to do that. No need to merge because it is handled by the application itself.

| improve this answer | |
  • 1
    Good idea. Don't have to yell though :-) – Karl Bielefeldt May 15 '11 at 19:20
  • I just wanted to be clear with bold-italic all-caps typeface. So no-one misunderstands the message. I hope it gets through. – Spoike May 15 '11 at 20:41
  • I don't suppose anyone has a link to a blog or tutorial where someone has given an example of how they have implemented this scenario? – Phil Hale Aug 11 '11 at 10:45
  • It all depends on what you're currently using. Regional differences, usually have something to do with languages; and to my knowledge this is usually configured through textfiles (one for each language) with key/value pairs. IDE's such as Netbeans for Java has support for this built in: netbeans.org/kb/docs/java/gui-automatic-i18n.html – Spoike Aug 11 '11 at 11:27
  • And here are other ideas on how to customize per market or customer: programmers.stackexchange.com/questions/97353/… – Spoike Aug 11 '11 at 11:28

If you have multiple slightly different custom versions of your modules, eventually the complexity will overwhelm you and you will no longer be able to effectively share your code. It's a little more work up front, but you want the code to be the same everywhere, with the distinction made in which modules are used, and how those are configured.

That doesn't mean you can't use different revisions of your modules in different sites. The easiest way to use git to help manage this is by putting each module in its own subdirectory and repository, then use submodules to assemble the pieces you want for individual sites.

This way you have one "core" repo with maybe a dev and release branch, one feature repo for each module with their own dev and release branches, and a repo with hundreds of site-specific production and staging branches, that use submodules to pull in the specific versions of core and the modules it needs.

For example, if you wanted to make a change to a feature1 module for a certain site, you would checkout that site's development branch. Then, when you work in the modules/feature1 directory, you are working in the shared submodule repo for feature1. When you push your changes they are made available to all other sites that use that module, but they don't actually receive those changes until they decide to pull and test the latest revision.

| improve this answer | |

If you'll have hundreds of branches because you expect to have hundreds of regions, and if you really want to track changes in each region, that doesn't sound like a bad plan.

Branches are cheap in git.

But are you really sure you want to do that? It would seem like having hundreds of versions of your running code is something to avoid, no matter the VCS/deployment system.

Would it be possible to have a common code base in one repo, and have the custom stuff in a separate code base just for the servers that need it?

| improve this answer | |
  • Is there a git workflow that would fit best with having one repo for the common code base, and having custom stuff in it's own branch? By custom stuff, I mean possible entire modules that don't exist in the core code, or just custom functionality in one of our core modules, or even possibly just one custom view for one of our core modules. – Brandon Cordell May 11 '11 at 20:27
  • 1
    @Brandon, I think you're in for a world of pain if you try to have hundreds of different code bases. Have you worked with any Dependency Injection libraries? I would try to factor out your differences into classes you could configure for each region (using something like Ninject), so that the individual per-region classes would be different but would fit into a framework that doesn't change. Even if not every change can be done this way, it would make sense to do it this way as much as possible. – Kyralessa May 11 '11 at 22:47
  • It will probably also depend on what development environment you're using. Over at scrumdo.com, we have an open source repo and a closed-source repo. We pull them down next to each other. Since it's python/django, we create a localsettings.py that adds a search path and lists a few extra apps from the commercial repo to add into our live site. We do have a tiny amount of cruft in the open source code to determine if these extra apps are installed or not. Also, like Kyralessa mentioned, an IOC container might solve some of it as well. – Marc Hughes May 12 '11 at 13:19

Can't you just use flags instead?

For customisations which involve extensive changes to the code, this isn't necessarily appropriate, but if the changes can be modularised, it might be. You can still look at "only changes to file X" if you need to do that - e.g.

git log filename.c
| improve this answer | |

Have a look at possibly pre- and post- hooks, or more likely smudge and clean filters as one mechanism for keeping everything the same but different...

see the question/ answers in https://stackoverflow.com/questions/5769846/recommended-git-workflow-for-test-and-production-instances as a suggestion that may fit your workflow

| improve this answer | |

There is nothing wrong with having lots of branches. It sounds like your business needs it. Investigate a branch naming strategy instead so you can do operations on subsets of branches easily.

This is called "Branch per Feature". Google for that and you will find plenty of resources on how to execute with lots of branches in a superior way to working off of trunk with feature toggles.

| improve this answer | |
  • Thanks for the quick reply. Could you elaborate on operations on subsets of branches? We've recently moved from SVN to GIT, and haven't really been able to get deep into the features. – Brandon Cordell May 11 '11 at 20:24
  • Branches can be specified with wildcards in them. So you could have something like git log --graph --oneline --decorate deploy-southwest*. This would only give you a view of the history that had to do with deploying to the south-west region. – adymitruk May 13 '11 at 0:39
  • If you used branches for this particular scenario how would you deal with changes in common functionality that needed to be merged into every branch created for a region? It there an easy way to do this using Git? – Phil Hale Aug 11 '11 at 10:53
  • There is indeed something wrong with having lots of branches. As much as possible, you should try to make your variations data-driven instead of hardcoded into the software. If you absolutely have to have custom code, then you should analyze your application and figure out what parts of that are the ones which you need flexibility in, and make those plugins or other swappable modules, running in a universal container. – Michael H. Sep 21 '12 at 17:38
  • as long as they are short-lived there is nothing wrong with them. Managing config issues is a different story. Smudge/clean scripts and deploy scripts should take care of that, not VCS - although you can version those separately from a devops perspective. Updating my answer. – adymitruk Sep 21 '12 at 19:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy