About using git to maintain a drupal module...

Submitted by fago on Wed, 01/06/2010 - 21:50
Some months ago I gave git a first try for developing some stacked core patches. I quickly get used to it and to its nice features (german). Luckily its SVN integration is really nice and simple to use so GIT is even a fine replacement for the usual SVN client. Unfortunately for CVS things are much worse.. :( Poor cvs!

First tries..

I decided to don't go back to CVS for maintaining drupal modules. First I tried using the public GIT mirror of the whole drupal CVS from the French drupal community, however I quickly noted that it was broken for the rules module, so I tried to set up my on mirror. I started using Sam Boyer's scripts, however I had some misc small troubles with them, but more important those scripts copy the whole drupal CVS - but I didn't like to waste ~6 gigs of disk space and the time to sync all the unneeded stuff. So I ended writing my own script based on the instructions in the drupal handbook for maintaining a module with git and Sam's script. After some weeks going back and forth I finally ended up with something useful, so here are my experiences:

What is it about?

Currently I've set the script up to export the drupal CVS of some of my modules to GIT - its automatically pushing to my github account, which is quite convenient. It syncs only the really needed modules using rsync - which is an important step as its greatly speeding up cvsps when exporting from CVS. The nice thing is that it doesn't overwrite any changes not yet in CVS, so I can use the same git repository on github to develop new stuff and export to CVS later on. You can find the script here. To use it, first adapt the config file to your needs, then manually run "sync-cvs" once - so your git repositories have been created. Then go to your $GITDIR and create a new git repository "$module.git" and add the remote you want to push to as "origin" using git remote add origin YOUR_REPOS. Now you can try running "run-sync.sh" which will sync all branches found in CVS with your origin repository.

Exporting back to CVS

Ideally one wouldn't have to care about exporting to CVS, just pushing to the github repository should be enough. Well I think one could automate this too using github's service hooks, however for now I export back to CVS manually. For that you need a fully working local CVS checkout for the branch you want to commit. I've just created one for each branch I'm syncing. Then I've setup my local git repository that way:
# Tell git where to find the local CVS repository
git config cvsexportcommit.cvsdir /full_path/to/repos
Now for exporting you can just use git cvsexportcommit -c -p -v -u <commit-id></commit-id>, however having to export each commit on its own is much too cumbersome. So I've setup some useful aliases:
git config --global alias.lc "log ORIG_HEAD.. --stat"
git config --global alias.export \!"git cherry | sed -n 's/^+ //p' | xargs -l1 git cvsexportcommit -c -p -v -u -k"
git config --global alias.export-cvs \!"git cherry cvs | sed -n 's/^+ //p' | xargs -l1 git cvsexportcommit -c -p -v -u -k"
So you can run git export to export all commits report by git cherry at once. If you have not pushed your work back to github, this should work great and push everything new into CVS. If you want you can double-check what's getting exported beforehand using "git lc" or "git cherry". However if you have already pushed some work to your remote git repository (github), it won't be exported automatically. For that I set a tag "cvs" for the last revision being in cvs: git tag -f cvs COMMIT-ID Then the alias "git export-cvs" can be used - and everything since the tag will be exported to CVS... :)


When doing my script I quickly noted why the French mirror doesn't work for rules: cvsps failed when exporting the rules CVS repository. Luckily I noted that the problem is gone with the cvsps (or git?) version in the latest ubuntu release (9.10). Sorted that problem out I quickly ran into another when exporting to CVS. My patches couldn't be applied to CVS during export so it failed - the cause were the ids $Id$ CVS maintains. When the chagnes are commit to CVS the file changes due to the CVS ids, what might cause the next patch to fail. Really ugly! :( After some investigation I stumbled over the solution: Git supports an option "-k" for the cvsimport command. Those "-k" option makes the CVS Ids being replaced to $Id$ - thus for GIT the ids won't change any more and the patches apply! Yeah! Note: My script already uses that option. However you also need to set to specify -k in your cvsexport command, which is only support for git versions >=1.6.4. For the other way round (cvs -> git) it's supported also in older versions. Ubuntu 9.10 comes with 1.6.3, but luckily there is PPA where you can get the latest version for ubuntu. To update your ubuntu git version just run this commands as root:
add-apt-repository ppa:git-core/ppa
apt-get update &amp;&amp; apt-get upgrade

Update 22.01.10: Fixed cvsexport command to use -k and mention that git 1.6.3 doesn't know -k for exporting to cvs, but cvsimport does.

Scott Reynolds… (not verified)

Fri, 01/08/2010 - 00:57

I use this alias to create patch files for D.o that can be applied against CVS or the standard download drupal-diff = diff --relative --no-prefix . So I just cd into the directory that I want as the base of the patch (i.e Drupal root for a core patch or module root for a module patch) and run git drupal-diff > /tmp/module_name-issue_number.patch

amitaibu@drupal.org (not verified)

Mon, 04/05/2010 - 18:45

I'd like to maintain my modules this way, but there's lot of parts I think I'm missing. Like where to place the CVS/ GIT directories. And from where should I issue the commands. And how to deal with the branches. if/ when you have time -- can you publish a fuller code scenario, e.g.: mkdir foo-cvs mkdir foo-git ...

hm, there shouldn't be much extra work necessary. I've set it up so that the directories "contrib", and "cvs-copy" are in the same place where the scripts are lying - but that shouldn't matter much. Just adjust the directories in "drupal_sync.conf" appropriately and make sure they are writable. Then as written above you just need to initialize 1 git repository per repository. Mine look that way: ls contrib/ entity.cvs entity.git profile2.cvs profile2.git rules.cvs rules.git -> You have to create the $module.git repositories and add the right "origin" once. Then everything should work. @branches: It goes through all the branches it finds via "ls -l .git/refs/remotes/origin/" and makes sure they are synched. However I just noted that doesn't involve "packed refs", not sure which ones git packs. Probably we should fix that to parse "git branch -r" or similar.

Jokes (not verified)

Tue, 05/25/2010 - 08:19

Pretty good post. I just stumbled upon your blog and wanted to say that I have really enjoyed reading your blog posts. Any way I'll be subscribing to your feed and I hope you post again soon.Your blog provided us valuable information to work on.You have done a marvellous job!I've Bookmarked this page for future reference. Thank you Robin Jokes

axel.rutz@drupal.org (not verified)

Mon, 05/31/2010 - 16:37

you write: For that you need a fully working local CVS checkout for the branch you want to commit. I've just created one for each branch I'm syncing. is that what sync-cvs does sufficient or if not, how would i do that? great stuff alas!

hxxvgdgs (not verified)

Mon, 03/17/2014 - 12:01

About using git to maintain a drupal module is a very good and informative share you have here for the readers like me and I am very impressed by the knowledge and quality information updates. Very well and nicely presented article and I will visit again for more. http://www.magneticballtoys.com/buckeye-balls/mood-elevating-stress-buster-balls/