Getting Git Together with Drupal
Any programming project — including Drupal projects — should use a version control system. My favorite such system is git. If you haven’t tried it I recommend that you learn all about it at the tutorial section of github, or from Peepcode’s git screencast.
Assuming that you understand the basics of git, let’s apply it to a Drupal project. The simplest strategy is to create a single git repository that holds everything in your project. You download Drupal core and modules (using FTP, the Update Status module, or drush) and you check them into git as you install them. Your custom changes get checked into the same git repository.
Here’s a couple of hints:
Use branches to separate your code from contrib
You want to make it easy to distinguish changes that you make from those made by others. Creating branches is a good way to accomplish this. When you first set up your project, create:
A branch called
core. You should check the Drupal core code into this branch.A branch called
modules, based oncore. When you install a third party module, you should do so in this branch. (Actually, it would be ideal to create a separate branch for each module, but that’s a bit of work to manage so I’ll hold off on recommending that. I’d hate to scare you away on the first day.)Branches for your site’s code, based on
modules. You’ll probably want a development branch (I tend to name thisdevel) and a production branch (for which I often usemaster).
When you need to update core, you do so in the core branch, then merge core into modules and any other branch that depends on it. When you need to update a module, you do so by switching to the module branch, performing and committing the update, and then merging module into your development branches.
Tell git to ignore certain files
There are certain files in your Drupal installation that you should probably not have under version control at all:
The
filesdirectory, which contains uploaded files.Any
settings.phpfiles.Utility files used by your editor or IDE:
.projectfiles,TAGSfiles, etc.
There are two ways to make git ignore certain files. One is to put the names of those files in a file called .gitignore in the base directory of the respository, right next to the .git directory. The other is inside the .git directory itself: If you add the name of a file to .git/info/exclude it will be excluded from the repository.
No matter which method you use, git won’t delete the ignored files — it will just pretend that they aren’t there. You can ignore whole directories, and you can use wildcards to make git ignore entire sets of files with similar names.
How do you choose which ignoring method to use? The idea is that .gitignore is part of your project: You check it in to git, and it gets copied around wherever your project goes (e.g. to your development server). So if you want to ignore a file across all servers (like the files directory, which will exist everywhere you install the code), you should put that file’s name in .gitignore. Whereas .git/info/exclude is for files that only occur in your local repository and aren’t expected to be anywhere else, like editor settings files, or the directory beneath sites which corresponds to your local machine’s test domain.
Example
Here’s a set of example commands for building a new project. We’ll assume you’ve already downloaded the necessary Drupal tar files to ~/Downloads.
mkdir myproject
cd myproject
git init
# make .gitignore right away.
# This will be handy later; it also
# gives us something to check in immediately.
# You can't start creating branches without
# checking something in first
echo "files" > .gitignore
git add .gitignore
git commit -m "New Drupal project: myproject"
# create the core branch and install drupal core
git branch core
git checkout core
tar xvfz ~/Downloads/drupal-6.9.tar.gz
git add .
git commit -m "Installed Drupal 6.9 core"
git tag DRUPAL-6-9
# create the modules branch and install a
# couple of modules.
# This time let's make the branch and check it out
# in one command.
git checkout -b modules core
mkdir sites/all/modules
cd sites/all/modules
tar xvfz ~/Downloads/views-6.x-2.2.tar.gz
git add .
git commit -m "Installed Views 6.x-2.2"
tar xvfz ~/Downloads/cck-6.x-2.1.tar.gz
# add and commit in one command
git commit -a -m "Installed CCK 6.x-2.1"
# now get to work on your own code
git checkout -b devel modules
When it comes time to upgrade core:
git checkout core
tar xvfz ~/Downloads/drupal-6.10.tar.gz
git commit -a -m "Upgraded to Drupal 6.10"
git tag DRUPAL-6-10
git checkout modules
git merge core
git checkout devel # or any other branch
git merge modules
Now, if you need to know the difference between the current version of core and the previous one:
git diff core^ core
If you need to know the difference between the current official version of the Views module and the one in your code (perhaps because you’ve made a few patches):
git diff modules devel sites/all/modules/views
Or, for all the work you’ve done on the Views module in the devel branch since the last time you merged modules and devel:
git diff modules...devel sites/all/modules/views
Comments
Thanks heaps for this Michael, I have recently started using git for my drupal project's and this was a big help!
lucas
Nice, any chance of a gitk screenshot to make the flow a bit more obvious, particularly all the branches off branches and merging on update...
This is really helpful. Thanks for taking the time to make this guide!
I do have a question about branching though...
When you branch for each production site how do you test the site with MAMP or a similar setup? When I've tried this setup, it seems like I would need to checkout one branch at a time to use with my browser. The checkout changes all the files in my directory to the requested production site. So how can I access the other sites?
Is there a way to checkout more than one production branch at a time so I can develop more than one website at a time?
Would I clone the repository for each production site that I need to access simultaneously?
Yes, if you want to develop more than one site, and to make changes in each site's code independently of the others, you'll probably want to clone the repository once for each of your sites. That's what I do.
Thanks for your answer to my 30 June question. And now another followup...
Once you have the cloned repositories for each site do you merge these back together with the original repository? I got stuck on the "origin" and "remote" branches and merging. Is there any need to merge each site's clone back to the original repository?
Thanks...
Great article. I am wondering though could this process be used with submodule or a subtree of core from http://github.com/drupal ?
I really dont see any point behind making a branch for modules.
The strategy we use is:
After we have a few features ready to release:
This way of using branches with purpose helps support workflow. Git has tools to check the difference of a file between revisions, so keeping branches based on modules seems like a waste of time to me. If i want to see the diffs in a module, soon I can pull that drupal project git repo and git diff it.
You'll find a pretty picture of this at http://nvie.com/git-model
Andrew Burcin
Post new comment