Sunday, July 22, 2007

git cvs in 5min

Tired of CVS?  Use git instead.
  1. cvs -d cvs-myproj@cvs.foo.com:/cvs co projectwd
  2. mv projectwd myproj && cd myproj
  3. git-cvsimport -v -C ../git-myproj -a
  4. cd ../git-myproj && git status
This will checkout the CVS repo and convert it in git.  You will need cvsps >= 2.1.
For some reason, when I've done this, I ended up with all my files marked as deleted in my working copy...  If you have the same problem, a simple git reset --hard will undo the deletion.

Now do some work, and commit in your git repo.

It is now time to export these commits in the CVS repo.  You can review your commits with git log origin..master (This assumes that you worked in the master branch which is the case by default.  The origin branch was created by cvsimport and should not be modified unless when you actually sync it with the CVS repo).  Now go back to your CVS working copy:
  1. cd ../myproj
  2. cvs up -d
  3. for i in `GIT_DIR=../git-piscine-j01/.git git-cherry origin work | sed -n 's/^+ //p'`; do echo Exporting $i; GIT_DIR=../git-piscine-j01/.git git-cvsexportcommit -c -p -v $i || break; done
  4. cvs diff -u
  5. git-cvsimport -v -C ../git-myproj -a
  6. cd ../git-myproj
  7. git checkout origin
  8. git merge master
  9. git checkout master
First, make sure your CVS working copy is up to date.  Then we ask git-cherry to give us all the commits that are in master and not in origin, and we pass them to git-cvsexportcommit.  If the patch applies cleanly, the commit will be automatically sent to the CVS server.  It happened to me once that git-cvsexportcommit failed to properly add the new directories I commited in git and I had to checkout another fresh CVS working copy and then it worked.  Weird.  Then (step 4) review your CVS working copy to make sure nothing was left behind.  And then you update your git repository so that it takes into account the new commits you just exported in the CVS repo.  Finally, go back to your git repository and enter the origin branch.  Sync it with your master branch (step 8) and finally switch back to the master branch where you can do some more work and repeat the whole process.

At first I did not expect to have to do steps 7 and 8 but since the sha1 sums generated by the cvsimport for the commits exported by cvsexportcommit are different, these are required so that branches stay in sync.  This extra merge step should however not be of a problem since it should be a simple "fast forward" merge.   The only minor inconvenience is that commits made in git, exported to CVS and imported back to git will appear twice with different sha1 IDs.

This should be enough to work with git instead of CVS.

2 comments:

Naitik Shah said...

Thanks for the useful info - was very helpful.

Anonymous said...

You state that to update the working copy with the latest cvs entries, to do:

git checkout origin
git merge master

Now I'm new to this, so I might be wrong, but it seems to me that it should be:

git checkout master
git merge origin

as "git merge X" takes the changes from X and applies them to the current branch, and in this case we want from cvs branch "origin" to working directory "master".

Here are two shell scripts I created. Thanks for the help!

- - - update-git.sh - - -
git-cvsimport -v -C ../git-project
cd ../git-project
git checkout master
git merge origin

- - - export-commits.sh - - -
for i in `GIT_DIR=../git-project/.git git-cherry origin master | sed -n 's/^+ //p'`; do echo Exporting $i; GIT_DIR=../git-project/.git git-cvsexportcommit -c -p -v $i || break; done