CVS2Gitを使ってみる

はじめに

これは2017/06/03 に作成した過去記事の移植です。

CVSからGitの移行について

CVSリポジトリをGitリポジトリに変換する機会があったので、使用するコマンドなどをまとめます。 ここでは、まずCVSのリポジトリを作成し、それをGitリポジトリに変換し、履歴がどうなっているのかを確認します。

CVSリポジトリの作成

まずは、CVSのリポジトリ用のディレクトリを作成します。

CVSディレクトリ作成
[root@tk2-256-37863 horiba]mkdir cvsroot  
[root@tk2-256-37863 horiba]ls  
cvsroot  
CVSリポジトリの初期化
[root@tk2-256-37863 horiba] cvs -d /home/horiba/cvsroot/ init

treeコマンドでディレクトリを調べると以下のようになるはずです。

[root@tk2-256-37863 horiba] tree  
.  
 -- cvsroot  
     -- CVSROOT  
        |-- Emptydir  
        |-- checkoutlist  
        |-- checkoutlist,v  
        |-- commitinfo  
        |-- commitinfo,v  
        |-- config  
        |-- config,v  
        |-- cvswrappers  
        |-- cvswrappers,v  
        |-- editinfo  
        |-- editinfo,v  
        |-- history  
        |-- loginfo  
        |-- loginfo,v  
        |-- modules  
        |-- modules,v  
        |-- notify  
        |-- notify,v  
        |-- rcsinfo  
        |-- rcsinfo,v  
        |-- taginfo  
        |-- taginfo,v  
        |-- val-tags  
        |-- verifymsg  
         -- verifymsg,v  

3 directories, 24 files  
CVSROOTの環境パス設定
[root@tk2-256-37863 horiba] CVSROOT=/home/horiba/cvsroot; export CVSROOT
[root@tk2-256-37863 horiba] echo $CVSROOT
/home/horiba/cvsroot
CVSリポジトリの作業場所を作成
[root@tk2-256-37863 horiba] mkdir work
[root@tk2-256-37863 horiba] cd work/
[root@tk2-256-37863 work] mkdir project
[root@tk2-256-37863 work] cd project/
[root@tk2-256-37863 project] echo "CVS initalize commit." > init.txt
[root@tk2-256-37863 project] cat init.txt
CVS initalize commit.
CVSリポジトリにインポートする

CVSに projectをインポートします。
書式は以下の通り

cvs import [モジュール名] [ベンダタグ] [リリースタグ]
[root@tk2-256-37863 project] cvs import -m "Project" project horiba project_0_1
N project/init.txt

No conflicts created by this import

CVSに projectをインポートします。

チェックアウトをする
[root@tk2-256-37863 horiba] mkdir checkout_dir ←チェックアウト用のディレクトリを作成
[root@tk2-256-37863 horiba] cd checkout_dir/
[root@tk2-256-37863 checkout_dir] cvs checkout project ← cvsリポジトリ(projectモジュール)をチェックアウトする。
cvs checkout: Updating project
U project/init.txt
[root@tk2-256-37863 checkout_dir] ll ←チェックアウトできたか確認
合計 0
drwxr-xr-x 3 root root 31  6月  3 16:06 project
[root@tk2-256-37863 checkout_dir] cd project/
[root@tk2-256-37863 project] ll
合計 4
drwxr-xr-x 2 root root 48  6月  3 16:06 CVS
-rw-r--r-- 1 root root 22  6月  3 16:03 init.txt
[root@tk2-256-37863 project] cat init.txt ← 中身を確認
CVS initalize commit.
CVSリポジトリに新たにコミットをする
[root@tk2-256-37863 project] echo "Add new line" >> init.txt
[root@tk2-256-37863 project] cat init.txt ←追加されていることを確認
CVS initalize commit.
Add new line
[root@tk2-256-37863 project] cvs diff ←リポジトリとの差分チェック
cvs diff: Diffing .
Index: init.txt
===================================================================
RCS file: /home/horiba/cvsroot/project/init.txt,v
retrieving revision 1.1.1.1
diff -r1.1.1.1 init.txt
1a2
> Add new line ←ここが追加されている
[root@tk2-256-37863 project] cvs commit -m "Add new Line" ←コミットメッセージを添えてコミット
cvs commit: Examining .
Checking in init.txt;
/home/horiba/cvsroot/project/init.txt,v  <--  init.txt
new revision: 1.2; previous revision: 1.1
done
CVSリポジトリに新しいファイルを追加する
[root@tk2-256-37863 project] echo "New File" > newfile.txt
[root@tk2-256-37863 project] cvs update
cvs update: Updating .
? newfile.txt ← ?マークがついているため、CVSの追跡対象外ファイル
[root@tk2-256-37863 project] cvs add newfile.txt ←CVSの追跡対象にする
cvs add: scheduling file 'newfile.txt' for addition
cvs add: use 'cvs commit' to add this file permanently
[root@tk2-256-37863 project] cvs commit -m "Add newfile.txt"
cvs commit: Examining .
RCS file: /home/horiba/cvsroot/project/newfile.txt,v
done
Checking in newfile.txt;
/home/horiba/cvsroot/project/newfile.txt,v  <--  newfile.txt
initial revision: 1.1
done
[root@tk2-256-37863 project] cvs update
cvs update: Updating .
CVSリポジトリに新しいディレクトリを追加する

ディレクトリはコミットをしなくてもリポジトリに反映される。

[root@tk2-256-37863 project] mkdir src
[root@tk2-256-37863 project] cvs update
cvs update: Updating .
? src
[root@tk2-256-37863 project] cvs add src
Directory /home/horiba/cvsroot/project/src added to the repository
[root@tk2-256-37863 project] cvs update
cvs update: Updating .
cvs update: Updating src

ここまでがCVSの作業です。
テスト用にリポジトリを作成しましたが、実際はもっと巨大なリポジトリになっているはずです。

テスト用にブランチを作成
[root@tk2-256-37863 project] cvs tag -b new_branch ← new_barnchというブランチを作成
cvs tag: Tagging .
T init.txt
T newfile.txt
cvs tag: Tagging src
[root@tk2-256-37863 project] cvs stat init.txt ←現在のブランチを確認
===================================================================
File: init.txt          Status: Up-to-date

   Working revision:    1.2     Sat Jun  3 07:12:34 2017
   Repository revision: 1.2     /home/horiba/cvsroot/project/init.txt,v
   Sticky Tag:          (none) ← Sticky Tagが(none)なので、現ブランチはtrunk
   Sticky Date:         (none)
   Sticky Options:      (none)

[root@tk2-256-37863 project] cvs update -r new_branch ← ブランチを切り替え(new_branch)
cvs update: Updating .
U init.txt
U newfile.txt
cvs update: Updating src
[root@tk2-256-37863 project] cvs stat init.txt
===================================================================
File: init.txt          Status: Up-to-date

   Working revision:    1.2     Sat Jun  3 07:26:46 2017
   Repository revision: 1.2     /home/horiba/cvsroot/project/init.txt,v
   Sticky Tag:          new_branch (branch: 1.2.2) ← new_branchになっている
   Sticky Date:         (none)
   Sticky Options:      (none)

[root@tk2-256-37863 project] echo "new branch" > branch.txt
[root@tk2-256-37863 project] cvs add branch.txt
cvs add: scheduling file 'branch.txt' for addition on branch 'new_branch'
cvs add: use 'cvs commit' to add this file permanently
[root@tk2-256-37863 project] cvs commit -m "Add branch.txt" ←ブランチにコミット
cvs commit: Examining .
cvs commit: Examining src
RCS file: /home/horiba/cvsroot/project/Attic/branch.txt,v
done
Checking in branch.txt;
/home/horiba/cvsroot/project/Attic/branch.txt,v  <--  branch.txt
new revision: 1.1.2.1; previous revision: 1.1
done

Gitリポジトリへの移行

cvs2gitのツール準備

https://github.com/mhagger/cvs2svn/releases ここから cvs2svn をダウンロードする
(リンク切れであったため修正した。上記のURLに読み替えて以下を作業すること)
解凍をし、make installを行う。

[root@tk2-256-37863 horiba] wget http://cvs2svn.tigris.org/files/documents/1462/49237/cvs2svn-2.4.0.tar.gz
[root@tk2-256-37863 horiba] tar zxvf cvs2svn-2.4.0.tar.gz
[root@tk2-256-37863 horiba] mv cvs2svn-2.4.0 cvs2git
[root@tk2-256-37863 horiba] cd cvs2git/
データの準備

CVSROOT 以下と移行したいリポジトリのディレクトリ以下をローカルにコピーしてくる
今回は、/home/horibaにimportというディレクトリを用意し、そこにいれる。

  • CVSROOT
  • インポートしたいプロジェクト
データをインポートさせたい場所に移動
[root@tk2-256-37863 horiba] ll  
合計 4
drwxr-xr-x  3 root root   20  6月  3 16:06 checkout_dir
drwxrwxr-x 10  501  501 4096  6月  3 17:04 cvs2git
drwxr-xr-x  4 root root   34  6月  3 16:03 cvsroot
drwxr-xr-x  2 root root    6  6月  3 17:17 import
drwxr-xr-x  3 root root   20  6月  3 16:00 work
[root@tk2-256-37863 horiba] cp cvsroot/CVSROOT/ import/ -R  
[root@tk2-256-37863 horiba] cp cvsroot/project/ import/ -R  
[root@tk2-256-37863 cvsroot] cd /home/horiba/  

データをインポートする  
[root@tk2-256-37863 horiba]# cvs2git --blobfile=git-blob.dat --dumpfile=git-dump.dat --username=horiba--encoding=utf-8 --fallback-encoding=utf-8 import/
----- pass 1 (CollectRevsPass) -----
Examining all CVS ',v' files...
import/CVSROOT/checkoutlist,v
import/CVSROOT/commitinfo,v
import/CVSROOT/config,v
import/CVSROOT/cvswrappers,v
import/CVSROOT/editinfo,v
import/CVSROOT/loginfo,v
import/CVSROOT/modules,v
import/CVSROOT/notify,v
import/CVSROOT/rcsinfo,v
import/CVSROOT/taginfo,v
import/CVSROOT/verifymsg,v
import/project/init.txt,v
import/project/newfile.txt,v
import/project/Attic/branch.txt,v
Done
Time for pass1 (CollectRevsPass): 0.024 seconds.
----- pass 2 (CleanMetadataPass) -----
Converting metadata to UTF8...
Done
Time for pass2 (CleanMetadataPass): 0.007 seconds.
----- pass 3 (CollateSymbolsPass) -----
Checking for forced tags with commits...
Done
Time for pass3 (CollateSymbolsPass): 0.007 seconds.
----- pass 4 (FilterSymbolsPass) -----
Filtering out excluded symbols and summarizing items...
Done
Time for pass4 (FilterSymbolsPass): 0.093 seconds.
----- pass 5 (SortRevisionsPass) -----
Sorting CVS revision summaries...
Done
Time for pass5 (SortRevisionsPass): 0.005 seconds.
----- pass 6 (SortSymbolsPass) -----
Sorting CVS symbol summaries...
Done
Time for pass6 (SortSymbolsPass): 0.004 seconds.
----- pass 7 (InitializeChangesetsPass) -----
Creating preliminary commit sets...
Done
Time for pass7 (InitializeChangesetsPass): 0.009 seconds.
----- pass 8 (BreakRevisionChangesetCyclesPass) -----
Breaking revision changeset dependency cycles...
Done
Time for pass8 (BreakRevisionChangesetCyclesPass): 0.009 seconds.
----- pass 9 (RevisionTopologicalSortPass) -----
Generating CVSRevisions in commit order...
Done
Time for pass9 (RevisionTopologicalSortPass): 0.009 seconds.
----- pass 10 (BreakSymbolChangesetCyclesPass) -----
Breaking symbol changeset dependency cycles...
Done
Time for pass10 (BreakSymbolChangesetCyclesPass): 0.007 seconds.
----- pass 11 (BreakAllChangesetCyclesPass) -----
Breaking CVSSymbol dependency loops...
Done
Time for pass11 (BreakAllChangesetCyclesPass): 0.008 seconds.
----- pass 12 (TopologicalSortPass) -----
Generating CVSRevisions in commit order...
Done
Time for pass12 (TopologicalSortPass): 0.007 seconds.
----- pass 13 (CreateRevsPass) -----
Mapping CVS revisions to Subversion commits...
Creating Subversion r1 (Project initialization)
Creating Subversion r2 (commit)
Creating Subversion r3 (commit)
Creating Subversion r4 (copying to tag 'project_0_1')
Creating Subversion r5 (commit)
Creating Subversion r6 (commit)
Creating Subversion r7 (copying to branch 'new_branch')
Creating Subversion r8 (commit)
Done
Time for pass13 (CreateRevsPass): 0.010 seconds.
----- pass 14 (SortSymbolOpeningsClosingsPass) -----
Sorting symbolic name source revisions...
Done
Time for pass14 (SortSymbolOpeningsClosingsPass): 0.005 seconds.
----- pass 15 (IndexSymbolsPass) -----
Determining offsets for all symbolic names...
Done.
Time for pass15 (IndexSymbolsPass): 0.003 seconds.
----- pass 16 (OutputPass) -----
Time for pass16 (OutputPass): 0.007 seconds.

cvs2svn Statistics:
------------------
Total CVS Files:                14
Total CVS Revisions:            15
Total CVS Branches:              2
Total CVS Tags:                  1
Total Unique Tags:               1
Total Unique Branches:           1
CVS Repos Size in KB:           12
Total SVN Commits:               8
First Revision Date:    Sat Jun  3 15:51:18 2017
Last Revision Date:     Sat Jun  3 16:27:39 2017
------------------
Timings (seconds):
------------------
0.024   pass1    CollectRevsPass
0.007   pass2    CleanMetadataPass
0.007   pass3    CollateSymbolsPass
0.093   pass4    FilterSymbolsPass
0.005   pass5    SortRevisionsPass
0.004   pass6    SortSymbolsPass
0.009   pass7    InitializeChangesetsPass
0.009   pass8    BreakRevisionChangesetCyclesPass
0.009   pass9    RevisionTopologicalSortPass
0.007   pass10   BreakSymbolChangesetCyclesPass
0.008   pass11   BreakAllChangesetCyclesPass
0.007   pass12   TopologicalSortPass
0.010   pass13   CreateRevsPass
0.005   pass14   SortSymbolOpeningsClosingsPass
0.003   pass15   IndexSymbolsPass
0.007   pass16   OutputPass
0.213   total

[root@tk2-256-37863 horiba]# ll
合計 20
drwxr-xr-x  3 root root    20  6月  3 16:06 checkout_dir
drwxrwxr-x 10  501  501  4096  6月  3 17:04 cvs2git
drwxr-xr-x  4 root root    34  6月  3 16:03 cvsroot
-rw-r--r--  1 root root 10158  6月  3 17:22 git-blob.dat
-rw-r--r--  1 root root  2554  6月  3 17:22 git-dump.dat
drwxr-xr-x  4 root root    34  6月  3 17:20 import
drwxr-xr-x  3 root root    20  6月  3 16:00 work

.datが作成されている
Gitリポジトリへ反映

反映するようのGitリポジトリを作成

[root@tk2-256-37863 horiba] mkdir git_repo
[root@tk2-256-37863 horiba]# cd git_repo/
[root@tk2-256-37863 git_repo]# git init
Initialized empty Git repository in /home/horiba/git_repo/.git/
[root@tk2-256-37863 git_repo]# cat ../git-blob.dat ../git-dump.dat | git fast-import
git-fast-import statistics:
---------------------------------------------------------------------
Alloc d objects:       5000
Total objects:           34 (         0 duplicates                  )
      blobs  :           15 (         0 duplicates          3 deltas of         13 attempts)
      trees  :           12 (         0 duplicates          5 deltas of         12 attempts)
      commits:            7 (         0 duplicates          0 deltas of          0 attempts)
      tags   :            0 (         0 duplicates          0 deltas of          0 attempts)
Total branches:           4 (         3 loads     )
      marks:     1073741824 (        22 unique    )
      atoms:             16
Memory total:          2344 KiB
       pools:          2110 KiB
     objects:           234 KiB
---------------------------------------------------------------------
pack_report: getpagesize()            =       4096
pack_report: core.packedGitWindowSize = 1073741824
pack_report: core.packedGitLimit      = 8589934592
pack_report: pack_used_ctr            =         15
pack_report: pack_mmap_calls          =          4
pack_report: pack_open_windows        =          1 /          1
pack_report: pack_mapped              =       7234 /       7234
---------------------------------------------------------------------
Gitリポジトリの反映確認
リポジトリ確認
[root@tk2-256-37863 git_repo] ll
合計 4
drwxr-xr-x 2 root root 4096  6月  3 17:25 CVSROOT
drwxr-xr-x 2 root root   39  6月  3 17:25 project

ログ確認
[root@tk2-256-37863 git_repo]# git log
commit cda9cc6531facb46b873267e9d313d923f1d5bce
Author: horiba <>
Date:   Sat Jun 3 07:16:13 2017 +0000

    Add newfile.txt

commit 0161fd85c89b575294a48a08e4b9eb96dfe38bf6
Author: horiba <>
Date:   Sat Jun 3 07:13:00 2017 +0000

    Add new Line

commit b67ce725fa1ad57d24cc99d19bf4a91d504c76d3
Author: horiba <>
Date:   Sat Jun 3 07:03:28 2017 +0000

    Project

commit 9069a0b5297af1a034086dd2d6b210f622ab74fd
Author: horiba <>
Date:   Sat Jun 3 06:51:18 2017 +0000

    initial checkin

ブランチ確認
[root@tk2-256-37863 git_repo]# git branch -a
* master
  new_branch
[root@tk2-256-37863 git_repo]#

チェックアウト時のログ確認
[root@tk2-256-37863 git_repo]# git checkout new_branch
Switched to branch 'new_branch'
[root@tk2-256-37863 git_repo]# git log
commit f5fd22bedc9541926bf5e672331c69d4cffff819
Author: horiba <>
Date:   Sat Jun 3 07:27:39 2017 +0000

    Add branch.txt

commit 49710aa5e3f06f97bfe6b70f571471c4faca8b40
Author: horiba--encoding=utf-8 <>
Date:   Sat Jun 3 07:16:14 2017 +0000

    This commit was manufactured by cvs2svn to create branch 'new_branch'.

    Sprout from master 2017-06-03 07:16:13 UTC horiba 'Add newfile.txt'
    Delete:
        CVSROOT/checkoutlist
        CVSROOT/commitinfo
        CVSROOT/config
        CVSROOT/cvswrappers
        CVSROOT/editinfo
        CVSROOT/loginfo
        CVSROOT/modules
        CVSROOT/notify
        CVSROOT/rcsinfo
        CVSROOT/taginfo
        CVSROOT/verifymsg

commit cda9cc6531facb46b873267e9d313d923f1d5bce
Author: horiba <>
Date:   Sat Jun 3 07:16:13 2017 +0000

    Add newfile.txt

commit 0161fd85c89b575294a48a08e4b9eb96dfe38bf6
Author: horiba <>
Date:   Sat Jun 3 07:13:00 2017 +0000

    Add new Line

commit b67ce725fa1ad57d24cc99d19bf4a91d504c76d3
Author: horiba <>
Date:   Sat Jun 3 07:03:28 2017 +0000

    Project

commit 9069a0b5297af1a034086dd2d6b210f622ab74fd
Author: horiba <>
Date:   Sat Jun 3 06:51:18 2017 +0000

    initial checkin

CVSROOTは、masterブランチに存在しているが、不要なので下記コマンドで削除しておく。
[root@tk2-256-37863 git_repo]# rm -fR CVSROOT/

あとは、Gitリポジトリを好きに、リモートに登録して、ブランチを全てプッシュしてあげれば良い。

移行について

CVSはファイル単位での履歴管理なので、どこでバグったかがわかりにくい。
また、修正差分がわかりにくい。
その点Gitはコミット単位での履歴管理なので、修正ファイルが一緒に差分として出せたりするので、とても便利。
Gitは積極的に使うべきであろう。ある程度の操作も覚えるべきだと思う。  

Hugo で構築されています。
テーマ StackJimmy によって設計されています。