While building Drupal websites, we end up building modules for all sorts of random tasks – anything from simply reorganizing the contents of a node object or adding fields to the Site Information page to views plugins or huge integrations. It’s not unusual to have both in-house and contributed modules for which you or your company are the maintainer, that you use across many project. The problem is this: if you have twenty projects running your in house module and it requires a security update, you’re stuck manually updating each project by patching the files and then following your normal workflow. Your contrib modules can take advantage of Drush for updates, but Drush won’t solve the problem of ongoing project based module maintenance.
First thing’s first – need to be using Git. It’s nearly universally supported on *nix hosts, supported by Drush, and it’s what’s in use at Drupal.org, so it’s a solid choice for a Drupal shop on those grounds alone. At Envision we use the git-flow model (though we do not use the actual git-flow script), which I’ll discuss in detail in a future blog.
Git provides a feature called submodules. Simply put, it is a nested repository. In practice, this allows you to not only easily and reliably manage individual project instances of a custom module, it lets you engage in ongoing development on the module as a part of normal project development. Better still, it provides the ability to switch branches, check out tags, and so forth – all on a project’s module instance. Best of all, it’s extremely simple to set up.
Let’s look at an example. I recently released my first module to the community, Node Auto Queue (link to http://drupal.org/project/auto_nodequeue). It’s a pretty simple module. It allows you to configure a node queue to automatically have new nodes of it’s allowed content types added to the queue on creation. It exposes a new fieldset on node creation forms with a list of checkboxes, one per available queue for that content type, checked or not by default based on the queue’s setting.
- git clone –branch 7.x-1.x firstname.lastname@example.org:project/auto_nodequeue.git
- cd /path/to/myproject
- git submodule add /path/to/auto_nodequeue sites/all/modules/auto_nodequeue
A screenshot of the auto_nodequeue Drupal module as a Git submodule in SmartGit
That’s it! Now I have a fully functional copy of the auto_nodequeue repository inside the myproject Drupal site. As I make updates to auto_nodequeue, I will commit them back to the actual module repository. This allows me to update it with git pull on each project that needs the new code. You might be wondering – what if I’m using an in-house module and I want to customize it for this site only? The answer is to make a new module just for this site. Using a submodule will force you to separate site specific custom code from generally useful custom code relied on by multiple project, a good practice in general but one we’re often not forced to use because we’re copy and pasting common custom in-house module files into our projects and creating a whole new branch with each go-round.
Here are some of the advantages of using Git submodules with Drupal:
- You can git fetch/merge/pull updates for your contributed modules directly from Drupal.org. There is no need to manually download a new version of each, unpack and then commit.
- You can see upstream version history in your own Git log. This makes it easy to see where you're at; you can check if you've got specific upstream commits. Otherwise, all you can see are local changes and "Upgraded Blah from 2.3 to 2.4." log messages.
- You don't need to reapply (cherry-pick) custom changes to your contributed modules after upgrading them. If you use the one-Git-repository method, each contributed-module upgrade will overwrite anything you're previously patched and committed. This is a huge problem because developers often forget to do the reapplying, and then you're left with resolved issues that have been reverted. If you're using submodules, you simply maintain a custom branch, and merge upstream tags (or commit IDs) into it.