For me, this was very interesting, as it mirrors a lot of the work we've done at Constrex with our first product Tender.ly - currently being sold as downloadable software, but one which started life as a SaaS offering, changed from that, and will be returning to that as well in the near future.
However, we explicitly do not keep separate branches for the SaaS and downloadable versions of Tender.ly, as the last thing we want is divergent code branches. This is a bit different of a situation to GitHub, which has separate products, but makes our development a bit easier at the expense of a bit more up-front thought when doing the coding - which probably isn't a bad thing.
We ended up coming up with the same solution as GitHub - coalescing all the divergent code into sets of modules, which are then included based on the rails environment loaded at start-up. As we don't want purchasers of the software establishing themselves as competitors (despite the license conditions), all the SaaS code is simply deleted by the build scripts we use to release.
As an aside, JRuby + Glassfish + Rails is a very nice stack for selling downloadable web software - the same code runs on Windows and Linux with minimal changes, and some simple scripts to do the database setup. I really should write a blog post about it at some stage. Perhaps when the day is extended to 25 or 26 hours.
That's actually pretty similar to how we do it, too: we precompile models, controllers, and most other relevant private libraries, then we deliver it on a JRuby stack.
It's actually quite slick and works pretty well, unless you have a ton of non-Java compiled gems to deal with. We've been able to get through that pretty well or find alternatives, although it looks like JRuby's looking to support those libraries in the near future, too, which is great. Makes JRuby quite an attractive platform for this type of stuff.
The "Conditional Inherited Modules" seems to be one (of many) possible implementations of the venerable Strategy pattern from GoF (http://en.wikipedia.org/wiki/Strategy_pattern). It's a really elegant and one of my favorites. Just define a clean interface and pick between different implementations at runtime.
GoF wrote about the Strategy Pattern (and the rest of them) in 1994, so I'm pretty sure Java (first public release in 1995) was the least of their concerns at the time. And believe it or not, there are times when languages with closures are not an option.
This article was more interesting than I expected from the title. I was expecting something about how GitHub sells FI to enterprise clients, or what features they have to add to FI to make it palatable to enterprises (the latter is touched on a bit).
A more informative title would be "How GitHub manages long-lived development branches". Usually long-lived branches mean you're Doing It Wrong (TM), but as the article indicates, enterprise customisation is one case when a long-lived, occasionally-synced branch makes sense; another is maintaining released versions of installed software.
We are maintaining and developing a huge web application (http://www.popscan.com/ for those interested. Trust me. It's nothing YOU would want to buy :p ) which we also have to heavily customize for various customers and their very special wishes (even though I'd rather not as you'll see).
Some of these installations, we host ourselves, some are hosted by our customers.
We maintain a development head which becomes a release branch every 6 months. This is the core of our application and development done to the core is then part of the new release we give our customers either as part of a maintenance contract or for an upgrade fee.
Early on, we found that it's impossible to give all customers the same solution. Heck, it's not even possible to give them the same version with a completely altered skin. Part of this could be that we have fierce competitors in our customer base, so they want some way to differentiate.
So this is what we have invented the "Customizers" for. Our app is sprinkled with Hooks (currently 305, but steadily increasing) that a customizer can hook into altering just about any behavior that a customer could possible want to have altered. Sometimes it's just for altering data, sometimes, you can outright replace functionality.
That worked quite well, but over time, we needed even more power at which point we added even more stuff like pluggable modules (think very powerful controller if you come from a Rails world), pluggable amendments to existing modules and most recently template overrides:
Our application comes with three base styles (consisting of Smarty (yeah. it's PHP, but quite clean. And 6 years old) templates plus basic CSS and JS) plus a customer specific theme (consisting of CSS plus images).
Of course, sometimes not even that is enough which is why we can now inject smarty code based on the customer at which point our application will load the overridden template instead of the original.
Let me tell you this: This customization is the most painful thing I have ever done in my life. Even though the core application is the same for all our customers, no two apps look (or even work) the same. Hours and hours are spent tweaking every aspect of the application to the customers demand, sometimes even turning cool features off because "it looks to similar to what competitor B has".
None the less: Using the strict separation between core and customization, we can move the product forward without filling the core with customer specific crap and without constantly merging.
It's true: We don't need customer specific branches.
There's just the HEAD and the bi-yearly release branches (auto-deployed weekly to the systems we host). Customer specific changes are done in the customization part of the application and by design they can't affect the core (or, heaven forbid, the customization of another customer).
The only merges we do is the "Friday-merge" in which we forward-port bugfixes made to the release-branches - from oldest to newest to master.
This is where git is really awesome in that it's extremely good at merging making these friday-merges a pleasure to do.
Doing them weekly on a set time removes the need for each developer to manually merge every change (unless they need it in another branch - then they have to cherry-pick) and doing it weekly means that the changes are fresh enough for whoever does the merge to remember what the nature of a change was should a conflict arise.
So while the thing still is a huge, marketing-driven mess, we DO have it under control and are still able to move the product itself forward without the need of having to track a branch per customer (we tried that. it turned out much worse).
In the perfect world though, the customization would not exist and our customers would use the same product maybe with some styling using CSS, but unfortunately, that's plain not possible (for other technical reasons too, but this is already getting long).
However, we explicitly do not keep separate branches for the SaaS and downloadable versions of Tender.ly, as the last thing we want is divergent code branches. This is a bit different of a situation to GitHub, which has separate products, but makes our development a bit easier at the expense of a bit more up-front thought when doing the coding - which probably isn't a bad thing.
We ended up coming up with the same solution as GitHub - coalescing all the divergent code into sets of modules, which are then included based on the rails environment loaded at start-up. As we don't want purchasers of the software establishing themselves as competitors (despite the license conditions), all the SaaS code is simply deleted by the build scripts we use to release.
As an aside, JRuby + Glassfish + Rails is a very nice stack for selling downloadable web software - the same code runs on Windows and Linux with minimal changes, and some simple scripts to do the database setup. I really should write a blog post about it at some stage. Perhaps when the day is extended to 25 or 26 hours.
edit: Apparently I can't conjugate English verbs.