ファイルサーバの整理をしてたら、古(いにしえ)のCVSリポジトリが発掘された。考古学的価値しか無い代物だが、CVSのままでは鑑賞もしづらいので、Gitリポジトリに変換してみた。

git cvsimportを使う場合

Gitの公式ページに書かれている方法。

git cvsimportコマンドでCVSリポジトリとモジュールを指定すると、-Cオプションで指定したパスにGitリポジトリが出力される流れ。

git-cvsをインストールして(下請けのcvsとcvspsは自動で入る)、git cvsimportで変換を実施する。なお、CVSリポジトリのコミットコメントがEUC-JPだったので、文字化けしないよう一時的にi18n.commitencodingをeuc-jpにしておき、変換が終わってから設定を戻した。

sudo apt install git-cvs
git config --global i18n.commitencoding euc-jp
git cvsimport -d ~/cvsrepo1 -C project1_git project1
git config --global --unset i18n.commitencoding

GitリポジトリのルートはCVSモジュールの階層になった。つまり、

  • 「CVSリポ/project1/subdir1/file1」が「Gitリポ/subdir1/file1」になる。

cvs2gitを使う場合

cvs2svnに付属しているcvs2gitを使う方法。cvs2svnはTigris.orgにあったが、すでにサイトが閉鎖されている。果たして今はどこに移ったのか。ドキュメントはRobert Jacobさんのページにある。

cvs2gitコマンドでCVSリポジトリかモジュール(さらにそのサブディレクトリでもいい)を指定すると、Gitにインポートできるファイルが2つ出力されるので、それをgit fast-importでGitリポジトリに取り込む流れ。

cvsとcvs2svnをインストールして、RCSファイル(*,v)が存在するディレクトリを指定して変換する。コミットコメントのエンコーディングは–encodingオプションで指定できる。

sudo apt install cvs cvs2svn
cvs2git --blobfile=git-blob.dat --dumpfile=git-dump.dat --encoding euc-jp ~/cvsrepo1/project1

新規にGitのベアリポジトリを作って、上記で出力された2ファイルを結合してgit fast-importに流し込む。

git init --bare project1.git
cd project1.git
cat ../git-blob.dat ../git-dump.dat | git fast-import

cvs2gitの引数で指定した階層が、Gitリポジトリのルートになった。つまり、

  • 引数で「CVSリポ」を指定した場合は「CVSリポ/project1/subdir1/file1」が「Gitリポ/project1/subdir1/file1」になる。
  • 引数で「CVSリポ/project1」を指定した場合は「CVSリポ/project1/subdir1/file1」が「Gitリポ/subdir1/file1」になる。
  • 引数で「CVSリポ/project1/subdir1」を指定した場合は「CVSリポ/project1/subdir1/file1」が「Gitリポ/file1」になる。

cvs-fast-exportを使う場合

cvs-fast-exportを使う方法。

RCSファイル名のリストをcvs-fast-exportに食わせると、Gitにインポートできるデータが出力されるので、それをgit fast-importでGitリポジトリに取り込む流れ。

cvs-fast-exportをインストールして、変換対象のRCSファイルリストをcvs-fast-exportの標準入力に渡すと、インポートデータが標準出力に吐かれるので、いったんファイルに保存する。

sudo apt install cvs-fast-export
cd ~/cvsrepo1/project1
find . | cvs-fast-export > ~/stream.fi

新規にGitのベアリポジトリを作って、上記で出力されたファイルをgit fast-importに流し込む。

cd  # CVSリポジトリから抜ける
git init --bare project1.git
cd project1.git
git fast-import < ~/stream.fi

エンコーディングの指定ができないので、EUC-JPのコミットコメントは文字化けした。findを実行した階層が、Gitリポジトリのルートになった。つまり、

  • 「CVSリポ」でfindした場合は「CVSリポ/project1/subdir1/file1」が「Gitリポ/project1/subdir1/file1」になる。
  • 「CVSリポ/project1」でfindした場合は「CVSリポ/project1/subdir1/file1」が「Gitリポ/subdir1/file1」になる。
  • 「CVSリポ/project1/subdir1」でfindした場合は「CVSリポ/project1/subdir1/file1」が「Gitリポ/file1」になる。

cvsconvertを使う場合

cvs-fast-exportに付属しているcvsconvertを使う方法。

CVSリポジトリがあるディレクトリでcvsconvertコマンドを打つと、カレントディレクトリにGitリポジトリが出力される流れ。

cvs-fast-exportをインストールして、CVSリポジトリとモジュールを指定して変換するだけ。引数には必ずスラッシュが1つだけ入っていないとエラーになる。

sudo apt install cvs-fast-export
cvsconvert cvsrepo1/project1

エンコーディングの指定ができないので、EUC-JPのコミットコメントは文字化けした。Gitリポジトリのルートは、CVSリポジトリと同じ階層になった。つまり、

  • 「CVSリポ/project1/subdir1/file1」が「Gitリポ/project1/subdir1/file1」になる。

変換対象にproject1まで指定しているにもかかわらず、Gitリポにproject1ディレクトリができるこの動きは、ちょっとおかしい気がする(個人の感想です)。

感想

4つの方法を試したが、変換後のGitリポジトリのブランチ構成は少しずつ違っていて、この中ではcvs2gitの結果がいちばん素直な感じがした。

コマンド Gitリポのルート指定 コミットメッセージのエンコーディング ブランチの解釈
git cvsimport △モジュール固定 ○指定できる ×ちょっと変
cvs2git ○任意 ○指定できる ○スッキリ
cvs-fast-export ○任意 ×指定できない △まあまあ
cvsconvert ×無駄にモジュール固定 ×指定できない △まあまあ

というわけで、個人的にはcvs2gitがいちばん好み。

※バージョンメモ

  • VirtualBox 6.1.6
  • Vagrant 2.2.9
  • Utuntu 18.04 (vagrant box ubuntu/bionic64 (virtualbox, 20200521.0.0))
  • git-cvs 1:2.17.1-1ubuntu0.7
  • cvs2svn 2.5.0-1
  • cvs-fast-export 1.43-1