Git – How to Maintain Different Variations for Deployment Using Git

deploymentgitversion control

Although there are many similar questions here regarding using GIT for maintaining different versions, none seem to answer my specific case.

I'm OK with how to use GIT to do my development, using different branches to do hot fixes, versioning etc.

However, I am making a commercial application that needs to track various modules and configurations for DIFFERENT clients. And I do NOT wish the client to have access to a module or code they haven't paid for. Yet I would like to use GIT to deploy on their server, or to be able to deploy directly on the client server using ssh/rsync, or even on my server in a unique directory, then zip up the source files using a standard process.

Let me give you an example:

Client A:

  • Deploy basic application
  • Deploy Module A (e.g. forum) only
  • Deploy Client A specific theme with Client A specific logo

Client B:

  • Deploy basic application
  • Deploy Module A (e.g. forum)
  • Deploy Module B (e.g. faq system)
  • Deploy Client B specific theme with Client B specific logo

Development Server:

  • Contains basic application
  • Contains Module A (e.g. forum)
  • Contains Module B (e.g. faq system)
  • Contains Client A and Client B themes with all logos
  • Contains Development Notes which must NOT be visible to client
  • Contains build files used with Phing – these must NOT be available to clients

It's very important to understand that GIT on the development server contains proprietary data for Client A and Client B. Therefore Client A must never see my development notes, my Phing build files, Module B (faq system) or code/data/images for Client B.

I do not need to keep variations of a module or the basic application for individual clients. Everything is standard across the system, and it's only the deployment configuration/variation for each client which is unique.

I am happy to use GIT Submodules to keep some parts separate, if that helps.

Note that all my code is in PHP and I am happy to deploy solutions using PHP, Perl, Python or scripting, but I don't want to use Java on the destination server. Ideally I would like to avoid Ruby solutions, if possible. I have access to SSH on the client server and can use rsync over SSH as well, but I need to be able to execute a script on the client server to clean caches etc after an update.

My development machine is Windows – yes, unfortunate, but true. If I cannot achieve what I need on Windows then I will run CentOS/Fedora in VMWare.

This is not a multi-server deployment requiring simultaneous updating across a server farm, although it would be nice to be able push out updates of the application to all the various clients on a schedule or using a single command/procedure rather than having to do it manually for each one. I would also need to be able to push client specific updates to individual clients as and when required (for instance HTML or logo updates).

So, can I use GIT for deployment, or at least track the various configurations using branches? Or is it simply going to be too messy?

Can I hide Client B from Client A, including in commit history, in a particular branch, to make sure someone proficient with GIT at the client's organization cannot retrieve code they mustn't see (and this is a contractual requirement of the project)? If so, how do I do this in GIT?

If not, how can I best manage a build process that allows me to deploy client specific configurations? Note that initially I will be managing around 20 different clients, and this might grow to 100 or more different configurations as each one will include their own HTML and logos, and a variation based on a potentially unique selection of 15-20 modules.

I am happy to maintain a hundred different XML configuration files if that's what it takes. I am aware of Capistrano, but from reading about it, it doesn't seem that suitable for my specific case. If you feel otherwise, please do feel free to state so.

Best Answer

This is not a Git-specific answer, but it should work regardless of the VCS system you use.

I would start with several different repositories

  • One for each client, containing the client-specific files and a configuration file stating which options the client has purchased
  • One or more repositories with the development code

Then I would use a make_release script (written in your favourite scripting language) that does the following:

  1. Given the name of the client, checkout that client's repository to a temporary location
  2. Based on the purchased options, checkout or copy (from an existing checkout) the application and modules to the same location
  3. Remove all files/directories that are not relevant for the client (especially those that contain data meant for the VCS system)
  4. Package the release in a convenient format (e.g. zip or tar.gz)

Then deployment should be as simple as copying the release to the client's server, unpacking it and running whatever scripts that are needed to finish the installation/upgrade.