Using git subtree to Make a Distro Your Docroot

  • 7 minute read

A cornerstone of good Drupal development is deploying your site’s code from a version control system like Git or SVN. A further best practice is to put all your code in a directory in the repository, instead of at the top level of the repository. Doing this allows you to put other things into the repository that are not intended to be served publicly. For example, Acquia’s Cloud Hooks are scripts you put into the hooks directory that run when you deploy code, databases, or files, but should never be served as site content. Using Cloud Hooks, your repository looks like:

/docroot/... your site code …

/hooks/... your Cloud Hooks here …

At first glance, though, this approach has a downside. Many people want to use Git to track the Drupal distro their site is built from (Drupal core, Acquia Drupal, Pressflow, etc.) so they can easily pull in changes. However, most distro repositories keep their code directly in the top level of the repository. Simply adding the distro repository as a Git remote and running git pull puts the distro code in the top level of your repository too, which is not where you want it. In addition, you certainly cannot install contributed Drupal modules and themes into the top level of your repository.

Thus, the question for today is: How do you merge a remote repository (the distro) into a directory in your repository (the docroot), such that you preserve the remote repository's history and can easily merge in future updates? The best answer (according to stackoverflow and others) is to use the added set of git subtree commands rather than git's built-in subtree merging facility or the git submodule system.

In brief, here are the steps (assuming you already have git set up):

  1. Install the new git subtree command
  2. Clone your Acquia Cloud git repository
  3. Delete the docroot
  4. Subtree merge the distro as the new docroot so you can later run subtree pull to get updates
  5. Add any other needed modules and themes

Installing the git-subtree command onto your machine is pretty easy. The most generic instructions are:

$ git clone git://github.com/apenwarr/git-subtree.git
$ cd git-subtree
$ sudo bash install.sh

If you are using OSX and have homebrew installed you can take an even simpler path:

$  brew install git-subtree

You can verify that it's installed by typing git subtree with no arguments, which will show the usage options:

$ git subtree
usage: git subtree add   --prefix=<prefix> <commit>
or: git subtree merge --prefix=<prefix> <commit>
or: git subtree pull  --prefix=<prefix> <repository> <refspec...>
or: git subtree push  --prefix=<prefix> <repository> <refspec...>
or: git subtree split --prefix=<prefix> <commit...>

... etc

Look at your Cloud hosting dashboard on the Acquia Network, copy the git URL, clone your repository, and clean out the default docroot:

$ git clone [email protected]:mysite.git
$ cd mysite
$ git rm -r docroot
$ git commit -m"delete initial docroot in preparation for adding distro"

Let’s assume we want to add Pressflow 6.x as the docroot, since Pressflow will let a Drupal 6 site take advantage of HTTP acceleration from Varnish.

$ git subtree add --prefix=docroot git://github.com/pressflow/6.git master

Note that you may want to use the --squash flag so this is a single commit, rather than pulling in the whole history. However, pressflow has relatively few commits, and you may find it interesting to look at some of the specific changes.

Add the settings.php file and add to it the file include command from the “Databases” section of the Acquia Cloud UI.

$ cp docroot/sites/default/default.settings.php docroot/sites/default/settings.php
$ echo "
if (file_exists('/var/www/site-php')) {
  require('/var/www/site-php/mysite/mysite-settings.inc');
}" >> docroot/sites/default/settings.php
$ git add docroot/sites/default/settings.php
$ git commit -m “Adding settings.php”
$ git push

Now, wait a few seconds so the code has time to deploy to your dev environment. Then you can visit install.php and get started, e.g.

http://mysite.devcloud.acquia-sites.com/install.php

If you need to update to e.g. a new release of Pressflow, it’s nearly as easy. Just do this from your local clone of the repo:

$ git subtree pull --prefix=docroot git://github.com/pressflow/6.git master
$ git push

At this point you can download and add additional modules and themes, or use git subtree again if you want to pull them in from git as well.

For example to get the latest Drupal 6 version of Node Clone (using --squash):

$ git subtree add --squash --prefix=docroot/sites/all/modules/node_clone http://git.drupal.org/project/node_clone.git 6.x-1.x
$ git push

You can then later update the module by replacing “add” with “pull”, as shown above for the distro. This approach is likely most useful for modules that are in active development or that you contribute to. For stable releases of other modules, you can use drush or just directly download the module and git add it to your repository.

P.S. - The git subtree install instructions also describe how to make and install a man page. Sadly, this tends to require building a couple helper programs or installing more packages just to end up transforming the initial .txt instructions into a slightly different man page text file. You can use the attached man file and copy it into place.

P.P.S. - If you use svn to managed your code want to do something similar, you can basically use the instructions for svn_load_dirs.pl that I posted before, or make a full-blown vendor branch and track it for merges as written up on drupal.org. This svn-based vendor branch and merge technique is how we manage updates to the www.drupalgardens.com site.