CUBE SUGAR CONTAINER

技術系のこと書きます。

RCS (Revision Control System) を使ってファイルをバージョン管理する

RCS (Revision Control System) は大昔に使われていたバージョン管理システムだ。 21 世紀にもなって何で RCS なんかとも思うんだけど、恐竜が生きていた頃に作られたシステムの中には今でもファイルを RCS で管理しているものももしかすると残っていたりするかもしれない。 今回はその使い方を振り返っておく。

検証環境には CentOS7 を使った。

$ cat /etc/redhat-release
CentOS Linux release 7.1.1503 (Core)
$ uname -r
3.10.0-229.11.1.el7.x86_64

RCS をインストールする

RCS は yum を使ってインストールできる。

$ sudo yum -y install rcs

RCS を使ってみる

RCS を使うには、作業する場所に RCS という名前のディレクトリを作るのがセオリーになっている。

$ mkdir RCS

バージョン管理したいファイルを RCS に登録する

同じ場所に、バージョン管理したいファイルを書き出しておく。

$ cat << EOF > sample.txt
/* \$Id\$ */
Hello, World
EOF

この時点でのファイルの構成は以下のような感じ。

$ find .
.
./RCS
./sample.txt

まずはバージョン管理したいファイルを ci コマンドで RCS に登録する。 説明を求められるので、ファイルの目的や変更内容について記述する。 入力を終えるには、新しい行で '.' (ピリオド) のみを入れて改行する。

$ ci -u sample.txt
RCS/sample.txt,v  <--  sample.txt
enter description, terminated with single '.' or end of file:
NOTE: This is NOT the log message!
>> This is a sample file for training RCS
>> .
initial revision: 1.1
done

これで RCS にファイルが登録された。 すると、次のように RCS ディレクトリ以下に登録したファイルを管理するためのファイルができる。

$ find .
.
./RCS
./RCS/sample.txt,v
./sample.txt

これは単なるテキストファイルになっているようだ。

$ file RCS/sample.txt,v
RCS/sample.txt,v: ASCII text

内容を確認すると $Id$ のところが RCS によってバージョンなどを含む内容に置換されている。

$ cat sample.txt
/* $Id: sample.txt,v 1.1 2015/08/25 13:47:37 vagrant Exp $ */
Hello, World

ちなみに ci コマンドが終わると、下手に編集できないようにファイルから書き込み権限が落ちる。

$ ls -l
合計 4
drwxrwxr-x 2 vagrant vagrant 25  825 13:48 RCS
-r--r--r-- 1 vagrant vagrant 75  825 13:48 sample.txt

バージョン管理しているファイルを編集する

ファイルを編集するには、まず co コマンドでファイルに書き込み権限を付与する。

$ co -l sample.txt
sample.txt,v  -->  sample.txt
revision 1.1 (locked)
done
$ ls -l
合計 4
drwxrwxr-x 2 vagrant vagrant 25  825 13:51 RCS
-rw-r--r-- 1 vagrant vagrant 83  825 13:51 sample.txt

ファイルを好きに編集する。

$ sed -i -e "s:World:RCS:g" sample.txt

変更内容を確認するには rcsdiff コマンドを使おう。

$ rcsdiff sample.txt
===================================================================
RCS file: RCS/sample.txt,v
retrieving revision 1.1
diff -r1.1 sample.txt
2c2
< Hello, World
---
> Hello, RCS

ファイルの新しいバージョンを ci コマンドで登録する。 説明をまた聞かれるので変更内容を入力しておく。

$ ci -u sample.txt
RCS/sample.txt,v  <--  sample.txt
new revision: 1.2; previous revision: 1.1
enter log message, terminated with single '.' or end of file:
>> s:World:RCS:g
>> .
done

ちなみにオプションをたまに間違えるとファイルが消えて焦る

再び首尾よくファイルの編集までが終わったとする。

$ co -l sample.txt
RCS/sample.txt,v  -->  sample.txt
revision 1.2 (locked)
done
$ sed -i -e "s:Hello:Bye:g" sample.txt
$ rcsdiff sample.txt
===================================================================
RCS file: RCS/sample.txt,v
retrieving revision 1.2
diff -r1.2 sample.txt
2c2
< Hello, RCS
---
> Bye, RCS

ここで誤って ci コマンドに -u オプションを付け忘れると、どうなるだろうか。

$ ci sample.txt
RCS/sample.txt,v  <--  sample.txt
new revision: 1.3; previous revision: 1.2
enter log message, terminated with single '.' or end of file:
>> Good-bye RCS eternally
>> .
done

なんと、バージョン管理していたはずのファイルが消えてしまった。

$ ls
RCS

とはいえ焦る必要はない。 実際にはバージョン管理システムに登録されたままなので co コマンドをオプションなしで実行すればすぐにファイルが復活する。

$ co sample.txt
RCS/sample.txt,v  -->  sample.txt
revision 1.3
done
$ ls
RCS  sample.txt

どうせ ci コマンドと co コマンドは上記のオプションを付けて使うことしか無いので、こういったオペミスを防ぐためにオプションを付けた状態で alias を作っておいた方が良い気がする。

$ cat << EOF >> ~/.bashrc
alias ci="ci -u"
alias co="co -l"
EOF

RCS ディレクトリがないとどうなる?

RCS ディレクトリを消した状態でファイルを登録してみよう。 ちなみに前述した通り RCS ディレクトリ以下にファイルの変更履歴が残っているので実際の環境では絶対に消さないように気をつけよう。

$ rm -rf RCS
$ ci -u sample.txt
sample.txt,v  <--  sample.txt
enter description, terminated with single '.' or end of file:
NOTE: This is NOT the log message!
>> .
initial revision: 1.1
done

RCS ディレクトリが無い状況では同じディレクトリにバージョン管理用のファイルができることがわかる。 正直、邪魔だね。

$ ls
sample.txt  sample.txt,v

付録: RCS の代わりに Git を使ってみる

RCS は太古の昔に使われていたバージョン管理システムだし、ファイルのロック周りが煩雑だったりするので今から積極的に使う必要はないと思う。 代わりに Git で似たようなことをする方法について紹介しておく。

Git をインストールする

yum を使って Git をインストールする。

$ sudo yum -y install git

ファイルをコミットする際に必要なので、今のうちに Git の設定にユーザ名とメールアドレスを登録しておこう。

$ git config --global user.name "momijiame"
$ git config --global user.email "momijiame@example.jp"

Git のリポジトリを作る

変更内容を保存するためのディレクトリ (リポジトリ) を作る。

$ mkdir repo
$ cd repo

リポジトリを初期化する。

$ git --bare init --shared
Initialized empty shared Git repository in /home/vagrant/work/repo/

必要なファイルが幾つか作られるので場所をメモっておこう。

$ ls
HEAD  branches  config  description  hooks  info  objects  refs
$ pwd
/home/vagrant/work/repo

ホストが SSH でログインできる状態にあることを確認しておく。

$ ss -ant | grep :22
LISTEN     0      128                       *:22                       *:*
ESTAB      0      0                 10.0.2.15:22                10.0.2.2:59756
LISTEN     0      128                      :::22                      :::*
$ systemctl status sshd
sshd.service - OpenSSH server daemon
   Loaded: loaded (/usr/lib/systemd/system/sshd.service; enabled)
   Active: active (running) since 火 2015-08-25 13:45:14 UTC; 19min ago
 Main PID: 1086 (sshd)
   CGroup: /system.slice/sshd.service
           └─1086 /usr/sbin/sshd -D

Git のリポジトリをチェックアウトする

リモートにある (といってもローカルホストの) リポジトリを手元にチェックアウトしてくる。

$ cd /var/tmp
$ git clone localhost:/home/vagrant/work/repo
Cloning into 'repo'...
The authenticity of host 'localhost (::1)' can't be established.
ECDSA key fingerprint is 0e:ae:85:dc:52:d7:70:4d:fd:6f:9a:f7:0c:2f:a9:99.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'localhost' (ECDSA) to the list of known hosts.
vagrant@localhost's password:
warning: You appear to have cloned an empty repository.
$ ls | grep repo
repo

バージョン管理したいファイルを保存する。

$ cd repo
$ cat << EOF > sample.txt
Hello, World
EOF

変更内容をコミットしたらリモートリポジトリにプッシュする。 これで Git のリモートリポジトリにファイルが登録された。

$ git add sample.txt
$ git commit -m "This is a sample file for training Git"
$ git push origin master
Counting objects: 3, done.
Writing objects: 100% (3/3), 256 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To localhost:/home/vagrant/work/repo
 * [new branch]      master -> master

リモートリポジトリにファイルとその変更履歴は全て残っているので、あとはローカルのリポジトリを削除してしまってもチェックアウトしなおせばすぐに復元できる。

$ cd ..
$ rm -rf repo/
$ git clone localhost:/home/vagrant/work/repo
Cloning into 'repo'...
remote: Counting objects: 3, done.
remote: Total 3 (delta 0), reused 0 (delta 0)
Receiving objects: 100% (3/3), done.
$ cat repo/sample.txt
Hello, World

ばっちり。

まとめ

今回は太古の昔に使われていたバージョン管理システムの RCS の使い方について振り返ってみた。 そして、同じことを現代のバージョン管理システムであるところの Git を使ってやる方法について書いた。