Work with the CVS repository using Git
This is a short memo on how to work with the CVS repository using Git.
Please note this is still very rough contents in terms of code testing.
Contents
Requirements
Basic understanding of followings are prerequisites:
Work with the CVS repository using git
You may wish to use the convenience of your local git repository when you update an upstream source tree maintained in the CVS system.
Of course, you can set up the full repository history of CVS in the local repository and track the CVS HEAD in your local git repository as the remote branch, e.g., as cvs/master. In short, this is slow and cumbersome. I will explain this later in "Approach 2" which is also the usual case documented elsewhere.
For simplicity, I use following variables.
CVSROOT=${USER}@${HOST}:${PATH_TO_CVSREPO} CWD=`pwd`
Approach 1: only future changes
Let's worry only future changes with following focuses for simplicity:
- do not worrying about the patch-set history
- avoid running cvsps for processing speed
- use the "-W" option to share a single directory between the CVS and git
- use the "-c" option to multiple commits automatically.
Here, you need to track CVS on "master" branch of git and work on "rebase" branch of git.
This can be realized as:
make simple CVS checkout and make it a git repository (1st run only)
$ cvs -d :ext:${CVSROOT} checkout -P -kk $MODULE $ cd $MODULE $ git init; git add .; git commit -m "initial import" $ echo "CVS" > .git/info/exclude $ git checkout -b rebase
NOTE: All CVS directories are excluded from the git repository management.
update the git master branch to the latest CVS (non-1st run only)
$ git reset --hard master && git clean -f $ cvs update -PdA -kk $ git add . ; git commit -m "new cvs HEAD" $ git checkout rebase $ git reset --hard rebase && git clean -f
start hacking the source on master
$ vim foo.txt $ git commit -a -m "commit for foo" $ vim bar.txt $ git commit -a -m "commit for bar" ... (test code etc.) $ vim baz.txt $ git commit -a -m "commit for baz"
update to the latest CVS (to be sure)
$ git checkout master $ git reset --hard master && git clean -f $ cvs update -PdA -kk $ git add . ; git commit -m "new cvs HEAD" $ git checkout rebase $ git reset --hard rebase && git clean -f
rebase to the latest CVS and organize commit candidates
$ git rebase -i master ...
commit as a series of commits
$ git cherry master rebase | sed -n 's/^+ //p' | xargs -l1 \ git cvsexportcommit -ckpvW
This commits each git change set as a single set of CVS commit.
Approach 2: synchronized full history of changes
This approach requires to set up 3 directories to be efficient with the CVS data transaction. Let's arrange them as follows under ${CWD}/:
- ${CWD}/gitdir/
- a local git repository managed by git-cvsimport without CVS/ directories
- ${CWD}/cvsdir/
- a local checkout from the CVS repository with CVS/ directories
- ${CWD}/rsyncdir/
- a full local copy of the CVS repository
Overview of the workflow is the following.
1) 2) 3) Remote CVS -> Local CVS -+-> git-cvsimport (cvsps) -> hack ... + ^ | | | +-> cvs checkout -------------------> + | | +<------------------ git-cvsexportcommit <-------------+ 4)
Create a local copy of the CVS repository
$ rsync -avS --delete --delay-updates --rsh=ssh ${CVSROOT}/. rsyncdir
You should see files under the following directories:
- ${CWD}/rsyncdir/CVSROOT
- ${CWD}/rsyncdir/${MODULE}
Create a local git repository and a local checkout from the CVS repository
$ git cvsimport -akmRv -d ${CWD}/rsyncdir -C gitdir -r cvs $MODULE $ cvs -d ${CWD}/rsyncdir checkout -P -kk -d cvsdir $MODULE
The git-cvsimport command imports the full history of changes to the local git repository and allows to synchronize it continuously with the upstream CVS. The upstream CVS repository data without CVS/ directories is tracked on the remote branch called cvs/master if "-r cvs" option is used.
Hack code while using git
$ cd ${CWD}/gitdir ... hack on master branch starting at remote branch cvs/master $ cd ${CWD} $ rsync -avS --delete --delay-updates --rsh=ssh ${CVSROOT}/. rsyncdir $ cd ${CWD}/cvsdir $ cvs -d ${CWD}/rsyncdir update -PdA -kk $MODULE $ cd ${CWD}/gitdir $ git rebase -i cvs/master ... resolve conflicts and clean up history
Merge pending patches into CVS automatically
$ git cherry cvs/master master | sed -n 's/^+ //p' | xargs -l1 \ git cvsexportcommit -ckpuv -d $CVSROOT -w ${CWD}/cvsdir/ $ rm -rf ${CWD}/cvsdir
The "-d $CVSROOT" is required since CVS is used in an asymmetric fashion.
git-cvs
I am writing a git-cvs script to ease bidirectional operations between a single CVS tree and git.
Download git-cvs script and put it as git-cvs in your $PATH.
See "git cvs help" for what it does. This takes care lots of sanity checks and corner cases.
approach 1
$ git cvs init :ext:${CVSROOT} $MODULE $ cd $MODULE ... hack hack $ git commit -a -m "change set 1" $ git cvs dcommit ... long time $ git cvs update ...
approach 2
$ git cvs sync ${CVSROOT} $MODULE $ cd gitdir ... hack hack $ git commit -a -m "change set 1" $ git cvs dcommit ... long time $ git cvs update ...