An incomplete inventory of ways to share code among Drupal initegrators

Whenever a team starts working on a new Drupal-based website, there's an inevitable discussion on how to organize collaboration. Three questions come up regularly:

  1. How and when to use Features, Features Extra and Features Override modules
  2. How to organize production, testing and development environments and where to develop — on a shared server or locally
  3. How to share source code.

Out of the three, the question of the source code is the most contentious. One reason is that while everyone and their friends are already on git, most of the teams that implement Drupal websites do not really need a version control system where developers can cherry-pick and merge changes or analyze bugs by navigating commit histories. Instead, teams are usually interested in incremental backup systems where each team member can be sure that he can roll back his own and other people's changes until everything works again.

Below is the inventory of ways to share source code in Drupal projects.

Incremental backup

Incremental backup with drush

One way of ensuring incremental backups without the overhead of git or other version control system is to use drush. Drush keeps a backup of previous module versions in ~/drush-backups — there is enough info to revert manually to the previously known good state. This setup is ideal for small projects with a handful of custom modules that can be kept in their own git repositories.

When in doubt, don't put your Drupal project in git. Use drush and its build-in backup mechanism.

Incremental backup with svn or brz

A slightly more advanced way of keeping incremental backups is to use the little known --svnsync and --bzrsync drush options. This way, all drush up invocations will trigger an new changeset in the Subversion or Bazaar repository, automatically adding, updating and removing files.

The use of Subversion or Bazaar may trick team members to think that they are using version control, but there's really little difference with backups made by drush. Changesets get polluted with other people's code from numerous Drupal modules rather than team's internal contributions, so virtually the only use of the history of changes is... rollback.

If drush backups are not enough, setup incremental backups with Subversion or Bazaar.

Incremental backup with git

The --gitsync option does not exist in drush. Git is all about human-readable histories that reflect the evolution of a project. Implementing --gitsync would go against the spirit of git. This is probably why this gitsync issue has been around for over 4 years without being resolved.

Strangely enough, setting up a new git repository at $DOCROOT and committing everything there into git is by far the most popular way to organize source code in Drupal projects. Acquia itself promotes it in Acquia Cloud documentation.

The only reason to choose this way of doing incremental backups is that you want to be a git-only shop.

Version control

Version control with profiles

It is possible to implement a true version control with a Drupal profile. For that, build a a repository for the profile that keeps all custom code somewhere in $PROFILEROOT/modules/custom and $PROFILEROOT/themes/custom and downloads the rest from upstream just like a profile normally would. This way, the team commits only its own code into the repository, and upstream code is handled by the profile.

Put your profile and custom code under version control when developing Drupal profiles.

Version control with git submodules

Git allows to reference other git repositories in its tree. So, you can just run git clone git://git.drupal.org/project/drupal.git and add modules with:

git submodule add git://git.drupal.org/project/field_collection.git sites/all/modules/contrib/field_collection
pushd sites/all/modules/contrib/field_collection
git checkout 7.x.1.0-beta3
popd
git commit  sites/all/modules/contrib/field_collection

If you need to update a module, do it along the following lines:

pushd sites/all/modules/contrib/date
git fetch
git checkout 7.x-2.0-rc1
popd
git commit  sites/all/modules/contrib/date

If you need to update ustream, run

git fetch origin
git merge 7.21

This allows to keep upstream history at hand, while having custom code in a separate repository. Module and upstream updates are easy. However, a big disadvantage of this approach is that upstream modules are checked out without release information, which breaks the built-in update module. Git_deploy should fix this, but it has its own quirks and does not work everywhere.

Checkout the core from upstream and use git submodules while to add modules to the project if DevOps is not your concern.

Version control with git subtree

Merging git projects as subtrees is believed to be a superior way to combine multiple repositories in one project. Git subtree command adds the possibility to split a subproject from the main project at any time, which can come in handy if you want to make upstream contributions. If you rarely contribute to upstream, just use git subtree merging. Don't bother with git subtree— in a team where multiple people work together, someone will mess up with your subtree annotations anyway.

This is the only other way to deploy on Acquia. Check out a excellent tutorial here.

Use it if you need to deploy on Acquia.