How to convert a CVS repo to GIT using cvs-fast-export?
As another attempt, I'm trying to convert a CVS repository to GIT. cvs-fast-export was recommended. The only problem is, I have no idea how to actually do so. I have it built, but how do I call it? There's tons of flags explained here but that's more confusing than it is helping.
Is there a short explanation somewhere of the actual process of conversion?
The repository is remote, and I normally go in via SSH. I'm not sure if the folder structure of this project is normal. Here's roughly what it looks like:
-
(on the remote server)/somefolder/cvs/anotherfolder/
-
Contains: CVSROOT repo-I-want-to-clone-name
-
repo-I-want-to-clone-name contains an
Attic
, and all the source code files with,v
after them. (No CVSROOT) -
CVSROOT contains an
Attic
, cleanlog.sh, cvsignore, checkoutlist, checkoutlist,v, editinfo, editinfo,v, commmitinfo, loginfo, taginfo, etc. (No source-code like files here)
You need to have a local copy of the CVS repository directory (containing all the RCS ,v
files with history logs). If you have SSH access, use it to download the files via sftp/rsync/tar. If you only have a pserver URL, you need to use something like cvssuck
to generate a local repository. In case the repository is hosted at SourceForge, you can download the whole thing using rsync.
Once you have the RCS files, feed a list of the filenames to cvs-fast-export, and it will output a repository in the intermediate "Git fast-export" format
cd ~/cvsfiles
find . -name '*,v' | cvs-fast-export [some options] > ~/converted.fe
Note: Make sure to include any Attic
directories, as they contain files which existed in old commits but were eventually "deleted".
(Besides that, however, there are no additional metadata files needed – each ,v
file is completely self-contained, as it uses the same single-file history format as RCS does. The job of cvs-fast-export is to mingle those individual file histories into multi-file commits somehow.)
You can then make edits to the dump using reposurgeon
(e.g. assign authors, squash split commits), and finally import it into Git using:
git init ~/result
cd ~/result
git fast-import < ~/converted.fe
The import will generate branches and commits, and will update the working-tree index, but apparently doesn't extract the working-tree files themselves: use git reset --hard
or git checkout -f
to do that.
(In theory, the same "fast-export" dump can also be imported by various other SCMs such as Mercurial, Plastic, or Bzr.)
Here is how I converted and verified my CVS repository named repos
to using cvs-fast-export
on Ubuntu 18.04.
Perform the conversion
First, create a "fast export" file from CVS:
sudo apt install cvs-fast-export
cd repos/ # The CVS repository
find . | cvs-fast-export -kb > ../repos.fe
Import the fast export file to Git:
cd ..
git init repos.git
cd repos.git
git fast-import < ../repos.fe
git fast-import
creates a bare Git repo, so check out the working files:
git checkout -f
Verify the conversion
Create a CVS working copy with keywords not expanded:
cd .. # Directory in which you started
export CVSROOT=$PWD/repos
mkdir checkout-cvs
cd checkout-cvs
cvs co -kb `(cd ../repos; ls | grep -v CVSROOT)`
Recursively prune empty directories, which do not appear in the Git version:
find . -type d | sort -r | xargs rmdir
The above gives an error for every non-empty directory, but that's fine.
Compare the CVS latest version to the Git latest version:
cd ..
diff -r checkout-cvs repos.git