7

I am working on a CMS, in which we have multiple clients that use it, so the code is stored on their servers. Each client has the default code (user manager, pages manager etc), but every client also has it's own set of code (themes, scripts, custom modules).

I am trying to figure out a way to maintain an up-to-date code base for all the clients without having to make every single change to the core to every single client.

We are using GitHub for version control, so I was think of having all the clients as different branches, but how can I keep the core up to date with the master?

Am I think about this all wrong?

What are my options?

1

8 Answers 8

7

Branches are the wrong solution here. Branches are for when the code (temporarily) needs to change from the common base.

The problem with branches is that changes made to one branch stay on that one branch until you explicitly merge them onto another branch. This effectively means that if you have a change in the common code, you need to apply that change to each 'client-branch' individually, which is exactly what you don't want.

I am not fully up to date with git terminology, but the better solution is to have several repositories/sub-modules. You then create one repository for each client and an extra repository for the common code. The client's repository can then include the common repository as an external reference or sub-module and any change made to the common code is then immediately available to all clients repositories without additional work.

4
  • Had a quick look at submodules, they seem like a good idea, but would I have to set them up for every computer that accesses the code locally?
    – Adam
    Nov 28, 2013 at 9:35
  • @Adam: I don't know. I haven't used them enough for that. Nov 28, 2013 at 10:19
  • Right I had a play with them and they have to have their own sub directory, which makes them unsuitable for me
    – Adam
    Nov 28, 2013 at 11:00
  • This answer is misleading. Feature branches (temporary branches) are only one of the many uses for branches. One could easily have one branch for each customer, and merge the product enhancements into each branch as needed. The main challenge is to keep the core funcionality isolated from the customizations. That could be achieved either using inheritance, partial classes or events. Definitely it can be done.
    – drizin
    Sep 17, 2016 at 22:23
3

Branches are the wrong solution here. Branches are for when the code (temporarily) needs to change from the common base.

That is misleading. Feature branches (temporary branches) are only one of the many uses for branches. Client-branches could be long-living branches, that just have a common ancestor and that could periodically benefit from the ancestor updates.

The problem with branches is that changes made to one branch stay on that one branch until you explicitly merge them onto another branch. This effectively means that if you have a change in the common code, you need to apply that change to each 'client-branch' individually, which is exactly what you don't want.

The suggestion of using a submodule (with common code) also requires that you explicitly updates the submodule of each customer. With the disadvantage that when using submodules you cannot cherry pick (choose which changes you want to incorporate), unless you also branch the submodule - which would be the worst of both worlds. Additionally, using submodules will force you to keep all common-code inside a single subfolder, which may be a problem if you need to keep some files (like HTML, ASPX, JSP, etc) inside root folder or into some specific folder. If you are using client-branches, you can have both common-code and client-specific code in the same folders (and as long as you keep them in separated files, merging will always be trivial).

One could easily have one branch for each customer, and merge the product enhancements into each branch as needed (or even rebase the client-branches, which would lead to cleaner history, although that could lead to some inconsistent states in history). This answer explains the client-specific branches. The main challenge here is to keep the core funcionality isolated from the customizations. That could be achieved either using inheritance, partial classes or events.

A simple example: master branch could have base classes, which would host most of the code, and nearly-empty derived classes which would host basically the customizations. Each customer would have it's own branch, and would only change those derived classes. When new features are added to the master branch (product baseline) they can be merged into the customer branches. Customer extensions could break (if using strongly typed language) because of contract changes on the base class - and that's good, that's a sign that the customization should be reviewed.

It's important to isolate the common code from the customer-specific code, so that the merges are straightforward. It's a good idea to keep them into separated files, either being different classes (customization inheriting from the common code) or just being partial classes. The base funcionality and the customizations could even be completely unrelated classes, as long as you plug them in some startup code (like subscribing events or something like that).

By correctly designing the methods (and/or the extension events), you can achieve a quite solid extensible product, and avoid maintenance hell.

1

Branches might be ok. When the code changes, i.e. new features are written, bugs are fixed, etc, then they are added to master and then for the new areas to receive it they should fetch/pull the latest master and/or rebase their branch against it to get the new changes. They can then push the updated branch to github to make sure that the latest version of it is also stored there.

Another option is for other areas to fork the project. This is basically a similar process in terms of getting updates (fetch the latest master and rebase on it).
The difference with forks is that they don't automatically get accepted into then main remote, they have to be approved by the github repository owner (or others who have been given that privilege).

4
  • Just tried to fork it and it says "You are already look at this repository"... I would prefer forking as it seems like a better idea for loads of clients
    – Adam
    Nov 27, 2013 at 13:34
  • Do you know if github moans if you have say 1000 branches, they say keep the repo under 1gb, does that count for the entire repo or each branch?
    – Adam
    Nov 27, 2013 at 13:37
  • Yes, forking implies two user accounts Nov 27, 2013 at 16:15
  • I believe that 1000 branches will not take up that much space, i.e. a branch is NOT a complete copy of the code, it is a version that shared most of the code along with a few changes. So fear not, it will not be current_repo * 1000. It might well be less than current_repo's space x 2 Nov 27, 2013 at 16:17
1

For drupal and wordpress we have a similar problem -- there is a core which gets updated from one direction and then some site-specific files which come from another direction. The solution we came up with was a combination of effectively forked repositories and sub-repositories.

First, for the repositories what we do is create a template project / site incorporating our project layout and configuration scripts and bits with the default application setup in our project. This is setup in a branch -- say wp-default for wordpress -- rather than in master. To spin up a new project, we init a new repo and pull from the default project. We then merge the wp-base branch into the repo making master have a clean copy of our site's setup. We don't actually fork things as the updates aren't going to ever flow back, rather the concrete project will pull updates in from time to time.

For your theme and other customizations, they would just land in the project normally from here on out. When there is an update to the core, you pull changes in from that default project and then merge them into your working copy.

The subrepos kick in for content -- we put the sites content and databases into a subrepo, mainly because we've seen content kill repositories so we want separability and also it makes it easy to automatically update an independent repo. A script copies them into appropriate places or forcibly restores things.

This will work brilliantly so long as your theme and customizations are happening in separate files and things are not horribly intermingled. Having a fully independent end-repo makes it possible to jam in any hacks you need on the pointy end -- we have had to hack the drupal / wordpress core a few times for good and bad reasons.

0

There are lot of issues when you have different code files for each client with each own module, theme etc. All this code is actually a different code base, probably with similar or identical logic to another client code base. Apart from the initial development time, which is something that I personally fall in with a lot of times in the past, maintaining and refactoring such code will definitely be a daunting task. To my mind, you should have a single codebase with all client customizations, if you don't want to changes to every single client code.

0

Here is what I have come up with for my solution.

For a start, I'm the only person who can use git properly (ish) so any command line stuff is out of the question, people just want to use github for windows as "it's pretty".

So I have the core code, with themes and everything in one repository, stable in master. When it comes to creating a new project I just copy and paste it (since you can't fork to your own account) into a new repository.

To update it, I can download the master and literally extract it over the top, so all the core files get replaced.

The master has the database file as "_database.php" so doesn't overwrite anything.

To speed up development on the front end, all CSS and JS is on a local CDN and the core calls it with a random number on the end to always fetch a non-cached copy.

I have written a script which get the latest master, extracts it and dumps it over the top of all code running the CMS which is running perfectly!

So thats it, it keeps all the code up to date, and if a client wants a completely different site it can change and not be updated again. All code is in separate repository so they can have their own master and development branches.

0

Use switch code logic in the source code to start with. Branch out a source code version from trunk and make fixes and urgent changes on both branch and trunk. move clients periodically to next product branch

0

I have that problem to some degree (five versions currently, may become more).

There is one Xcode project with five almost identical targets. Each target has its own configuration file for things that are just different (like application name and some other things). The different versions differ by features and each version enables or disabled whatever features it wants. So the code doesn’t say “if customer = x” but “if feature a is supported” and different customers are configured to support different features.

Everything is in the same git branch. During development, I don’t test all versions but I rotate between different customer version, since they all need to compile at any time. When we release, we release different targets one after the other.

Not the answer you're looking for? Browse other questions tagged or ask your own question.