Sick of developing a Drupal module with CVS? Want to use git but also want your code in CVS on for development snapshots? This is an approach to get rid of using CVS completely by synchronizing a git repository automatically to CVS. Basic git knowledge required. Script is on Github. Needs some testing though.


  • git is fast
  • git commmits are local until you push them somewhere
  • it is painfull to move and delete files/directories in CVS
  • you can't add a file/directory in a patch made from CVS easily (argl!)
  • git is better and faster at merging and branching
  • will move to git sooner or later, so let's start to use it
  • <fill in many more reasons here>


In this approach I used Github for hosting the git repository. All people that you want to collaborate with on that project will push their changes to that git repository. Nobody is allowed to touch the CVS repository on, so that you don't have to do bidirectional synchronization. All changes arrive in the git repository and are then pushed over to the CVS repository.

I think it is best if you have a server or permanently running machine at hand. A cron job will periodically pull from the git repository and export new commits to CVS.

You need to install the package git-cvs on Ubuntu to get the necessary CVS export command for git. Script was tested on Ubuntu 10.04.

Setting up the repositories on your machine

Create a repository on Github or any other git repository provider. Clone that for exporting to CVS on your server. Make sure that "git pull" works, e.g. that your checkout is connected to the remote repository and that the correct branch is checked out that you want to push to CVS. Note: This clone is for synchronization only, don't use it for development (create another clone and do your work there).

Create a CVS checkout of your project on your server. Use your CVS credentials so that you have access to commit the exports later. Make sure that you have checked out the correct branch you want sync with.

If you already have code in your CVS repository use "git cvsimport" to populate your git repository with that. I won't explain that here, there is a blog post about it.

Setting up the export script and cron job

Clone or download the export script from Github and make sure it is executable.

If you just imported the latest CVS code into your git repo, you need to put the latest commit ID hash into ".cvslastexport" file in your git repository directory. You can use "git log" to get the latest commit. Example: "echo f0f09a55532f0be86224f6fe957cec9e31250698 > /path/to/your-git-repo/.cvslastexport". Otherwise you would export the old commits to CVS that are already there - bad idea.

Time for a test run, exectue "/path/to/git-cvs-export/ /path/to/your-git-repo /path/to/your-cvs-repo". If there is nothing in CVS yet, all commits should get synced over. If you just imported from CVS to git before, the script should do nothing (because CVS is up to date).

Now we are ready to automate this command with cron. I suggest to use a time interval of 15 minutes to check for updates in git. Put a new line in your crontab (execute "crontab -e" to edit your crontab):

*/15  *  *  *  *      /path/to/git-cvs-export/ /path/to/your-git-repo /path/to/your-cvs-repo

That's it.

Merging with git

This workflow has one drawback: you can't use the standard "git merge" to merge in form other branches. That's because the commits from the other branch get mixed into the commit history and then each single commit does not apply as patch on top of the previous commit anymore. So you have to use "git merge --squash" to create one single changeset from the other branch. By committing that as single commit you maintain compatibility of your history with the CVS export script. Delete the other branch after the merge as another merge will cause conflicts, because git will try to bring in the whole branch changes again.

Open issues

  • You still need to do branching and tagging in CVS. Create corresponding git and CVS checkouts for each branch and add a cron task for each branch to synchronize. Could be fixed by checking automatically for Drupal CVS compatible branch/tag names and create them on demand in CVS.
  • You still need to create git and CVS checkouts to synchronize. Could be fixed by asking for the git and CVS repository URLs (+credentials for CVS) and setting up everything automatically in a dedicated directory, including the cronjob(s).