How to commit changes to a CVS repo but secretly use git to do most of the real work. Or: how to limit your interaction with CVS to the absolute minimum.
We will use the Emacs CVS repository as an example. It is assumed that you have commit access to the CVS repo.
Initial setup
So you've decided that you would much rather be developing Emacs using git. Good choice. Here is one way to set it up.
The directory tree will look like this:
emacs/ git-emacs/ | This is the unofficial git repo for Emacs. cvs-emacs/ | This is the official CVS repo for Emacs. export-from-git | This is a handy script for syncing changes.
First, make your top-level directory, which I have called emacs
here.
cd /path/to/my/projects mkdir emacs cd emacs
Check out either git://git.sv.gnu.org/emacs.git
or
git://repo.or.cz/emacs.git
. I use the former.
git clone $REPO mv emacs git-emacs
Get the CVS repo as well.
cvs -z3 -d:ext:[email protected]:/sources/emacs co emacs mv emacs cvs-emacs
Save the following script to the file export-from-git
(name it
whatever you like).
#!/bin/sh # # Export a commit from git to CVS. if test -z "$1" || test -n "$2"; then echo Incorrect number of arguments exit 1 fi export GIT_DIR=../git-emacs/.git git cvsexportcommit -c -p -v $1
Interacting with the git repo
If you want to update the git repo, and you have not committed any
local changes to the current branch, do git pull origin master
.
If you have committed some changes that you'd like to keep, then do
git fetch
and git rebase origin/master
, assuming you are in the master
branch (or whatever branch in which your changes lie).
If you want to just throw away the local changes (for example, on a
branch where you stage changes before committing them to CVS), do git
reset --hard origin/master
and git pull origin master
. This allows
you to see a pretty diffstat when the pull is done. To replicate that
same diffstat, use git diff --stat master origin/master
, replacing
"master" and "origin/master" as appropriate to indicate the two
markers to compare.
Branches can be set up however you like. Just be sure to use the
--no-track
option to the git branch
command if a branch by the same
name exists on the remote repo, and you do not want to automatically
update it with git pull
. If you are careful like this, you can omit
the arguments to git pull
to save typing.
Syncing to CVS
First, bring up the output from git log
so that you know which commit
IDs you want to sync to CVS.
Then update CVS using cd cvs-emacs; cvs up -dPR
.
Now commit each change from oldest to most recent using the
../export-from-git
script. The current directory should be cvs-emacs
.
The first and only argument should be a single commit ID. This script
will try out the change, and then commit it if things are up-to-date.
Be sure to separate changes to ChangeLog files from other changes,
because they will undoubtedly have to be merged manually. If a commit
doesn't go through, remove the .dotest
directory, fix up the file
manually, and do cvs commit -F .msg -- file1 file2 ...
if you want to
keep the same commit message that is present in the git repo.
Special scenarios
If the remote git repo you are using happens to lag behind for some reason, and there is a commit that you want to check in, there is a way to deal with it.
First, make a new git branch in the git-emacs
repo called something
like fakesync
and check it out. Then switch to the cvs-emacs
directory and run the following:
export GIT_DIR=../git-emacs/.git # If you need to remove files that should not be tracked in git, # do the next command, otherwise skip it. make maintainer-clean git add . git add -u . git commit -m "Fake sync from Emacs" unset GIT_DIR
Now rebase your changes against this new branch, run git log
, and use
../export-to-git
on any commits that you want to sync back to CVS.
Afterward, you can either ignore this branch or remove it.