リビジョン管理

エディタを使って「もの」を書くときには何度も書き足し、書き直せる。 直しているつもりが余計おかしくなったりすることもあるので、 書き直す前のものを保存しておきたいこともよくある。

このような場合には、一つのファイルを新規に作成したときから、現在、未来 に渡って希望する時点の全てのバージョンを記録できるツールを利用する。 これをリビジョン管理システム といい、大切なファイルを 作成する場合には欠かせないものである。

バージョン管理システム

バージョン管理システム(VCS)を使うと、 プログラムのソースやテキストファイル形式の文書の任意の時点の状態を保存でき、 あとから任意のリビジョンを取り出すことができる。VCSを利用してバージョン 管理する場合の流れは以下のようになる。

そののち、以前に登録していたバージョンを参照したいときには、

などの操作ができる。

Gitの導入

ここではバージョン管理ツールとして最も広く用いられている Gitを利用した作業方法を簡単に説明する。

初期設定

利用する端末ごとに編集者登録を行う。 以下の2つのコマンドをターミナル実行する。

git config --global user.email 《自分のemailアドレス》
git config --global user.name "《自分のローマ字名》"

リポジトリ作成

まず、リポジトリを新規作成する。2パターンある。

  1. 作業中のホストのディレクトリをリポジトリ化する
  2. Gitサーバ上でリポジトリを作成し作業ホストにクローンする

順に説明する。

作業ディレクトリにリポジトリを作る方法

新規にディレクトリを作成し、そこで初期化するコマンドを打つ。 この例では myrepo というディレクトリをリポジトリとする。

mkdir myrepo		# ディレクトリを作成
cd myrepo		# そこに移動
git init		# リポジトリ初期化
echo "My repository" > README.md		# ひとまずREADME.mdファイルを作る
ls			# 確認
README.md
git add README.md	# README.mdをリポジトリに登録
git commit -m "Start my repository"		# 更新を登録

Gitサーバでリポジトリを作りクローンする方法(おすすめ)

リモートGitサーバにアカウントを持っている場合は、 リポジトリサーバ上でリポジトリ作成し、それを手元のディレクトリに クローンしてくるのがよい。手順を簡潔にまとめると以下のとおり。

  1. Gitサーバにログイン
  2. New repositoryを作成する
  3. 手元ホストで git clone
  4. そのディレクトリにcdして利用する

GitBucketサーバでのリポジトリ作成例

ファイルをGitで管理する

編集するファイルをGit管理下に置くには、git add する。 通常はコマンドラインで行う。

cd リポジトリのディレクトリ
git add 管理下に置きたいファイル名

Emacsを利用してファイルをGit管理するととても簡単である。

キー操作として、C-x v v だけを覚えておけばよい。 実際にやってみよう。

ここで、foo.html をGit管理するやり方を追ってみよう。 リポジトリとなるディレクトリ内でのファイル作成・操作であると仮定する。

  1. foo.htmlを作成する

    簡単のためファイルの内容は以下のとおりとする。

    <!DOCTYPE html>
    <html lang="ja">
    <head><title>foo!</title></head>
    <body>
    <h1>fooについて</h1>
    </body>
    </html>
    

    ファイルが書けたら保存する(C-x C-s)。

  2. git add する(初回)

    C-x v vをタイプする。一度addすれば以後は そのファイルが履歴管理されるようになる。

  3. ソースを編集する

    新しい文章を書き加えよう。以下のように修正する。

    <!DOCTYPE html>
    <html lang="ja">
    <head><title>foo!</title></head>
    <body>
    <h1>fooについて</h1>
    <p>fooは「ふー」と読みます。</p>
    </body>
    </html>
    

    追加が終わったら保存する。

  4. コミットする

    C-x v vをタイプする。隣にログメッセージを 入力するためのバッファが現れるので、他者にも伝わる更新メモを残す。 何も書かなくてよいが、あとでそのバージョンを取り出す手がかりとなるので、 できるだけ「何故そうしたか」を書く。C-x v v をタイプしたときに出てくるが、ログメッセージを書き終わったら C-c C-c をタイプする。

    <!DOCTYPE html>
    <html lang="ja">
    <head><title>foo!</title></head>
    <body>
    <h1>fooについて</h1>
    <p>fooは「ふー」と読みます。</p>
    </body>
    </html>
    
    
    
    -[あ]-E.E:%%-F1  foo.html  ALL L7  RCS:1.1   (yahtml Fill)  [1]--
    Summary: 読み方を足したよ
    
    
    

    ログメッセージを書いたら C-c C-c で履歴登録(コミット)が完了する。

以後、まとまりのある修正が完了するごとにコミットを繰り返していく。

過去のファイルの取り出し

過去にコミットしたものをいつでも取り出せる。そのときには、 コミット時のログメッセージが手がかりとなる。

  1. ログメッセージの一覧を見る

    C-x v l をタイプする(最後は log のエル)。 下のウィンドウに過去にチェックインしたときのログがあらわれる。

    commit 10c7471c59b86df760478a558bbace28aa6d8e35
    Author: HIROSE Yuuji <ta01002@e.koeki-u.ac.jp>
    Date:   Sun Apr 16 17:08:13 2023 +0859
    
        「こんにちは」を足した。
    
    commit fc0a0e763b2ee2431ff87354689fcc6ff7f8ec5a
    Author: HIROSE Yuuji <ta01002@e.koeki-u.ac.jp>
    Date:   Sun Apr 16 17:07:48 2023 +0859
    
        Dupliate yeah
    
    commit 43bad956b86bab4086f57f51a9956fc2d043c955
    Author: HIROSE Yuuji <ta01002@e.koeki-u.ac.jp>
    Date:   Sat Apr 15 18:16:05 2023 +0859
    
        index.htmlを新規作成した
    
  2. 現在のソースとの違いを見る

    直前のリビジョンとの差分を見るには C-x v = を タイプする。

    もっと古いリビジョンと比べたいときは、C-x v l の ログ一覧から比較したいバージョンが、今のものから何個前かを見ておく。 3つ前のバージョンと比べたければ C-u C-x v = のあと master~3 とタイプする。

    Older revision (default master~1): master~3
    (古いリビジョン番号を入力する)
    Newer version (default: current source): 
    (そのまま[Enter])
    

    現在のソースとの比較結果が下のバッファにあらわれる。

    diff --git a/index.html b/index.html
    index eda1664..e07dbaf 100644
    --- a/index.html
    +++ b/index.html
    @@ -7,6 +7,7 @@
     
     <body>
     <h1>でざいんする!</h1>
    -<p>やあ</p>
    +<p>やあやあ</p>
    +<p>こんにちは。</p>
     </body>
     </html>
    

    行の先頭にマイナスのついているのが、元のソースから消えた行、 プラスのついているのが新しい方に現れた行を意味する。

よく使う割り当てキーの一覧を示す。

C-x v vチェックイン or チェックアウト
C-x v lログ一覧を見る
C-x v gAnnotate
C-x v =直前のリビジョンとの差分を見る
C-u C-x v =指定したリビジョンとの差分を見る

コマンドラインからの利用

Gitの全ての機能を利用するにはコマンドを利用する。

コミット

コミットには、git commit コマンドを使う。

-m "文" をつけずに git commit するとログメッセージの入力を求めてくる。 viエディタが上がる設定の場合は以下のような画面になる。


# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# On branch master
# Your branch is ahead of 'origin/master' by 3 commits.
#   (use "git push" to publish your local commits)
#
# Changes to be committed:
#       modified:   index.html

(※重要※)キーボードで小文字のi(アイ)を打ってから短文を入れ、 ESC Z Z と(ESCキーのあと大文字Zを2回)押す。 viの使い方を知らないと迷子になるので git commit のあとの -m "ログメッセージ" は欠かさずつけたほうがよい。

チェックアウトと過去の履歴参照

古いバージョンのファイルを取り出すことをチェックアウト という。

編集中の1つのファイルの昔のバージョンを見たいだけの場合はEmacsから C-x v g (vc-annotate) を呼び出す。まとめて取り出したいときは コマンドラインから git checkout を使う。

Emacs内で過去の履歴を見る

押した瞬間に以下のような画面が現れる。

43bad956 (HIROSE Yuuji 2023-04-15  1) <!DOCTYPE html>
43bad956 (HIROSE Yuuji 2023-04-15  2) <html lang="ja">
43bad956 (HIROSE Yuuji 2023-04-15  3) <head>
43bad956 (HIROSE Yuuji 2023-04-15  4) <title>でざいんするぜ!</title>
43bad956 (HIROSE Yuuji 2023-04-15  5) <link rel="stylesheet" type="text/css" href="main.css">
43bad956 (HIROSE Yuuji 2023-04-15  6) </head>
43bad956 (HIROSE Yuuji 2023-04-15  7) 
43bad956 (HIROSE Yuuji 2023-04-15  8) <body>
43bad956 (HIROSE Yuuji 2023-04-15  9) <h1>でざいんする!</h1>
fc0a0e76 (HIROSE Yuuji 2023-04-16 10) <p>やあやあ</p>
10c7471c (HIROSE Yuuji 2023-04-16 11) <p>こんにちは。</p>
43bad956 (HIROSE Yuuji 2023-04-15 12) </body>
43bad956 (HIROSE Yuuji 2023-04-15 13) </html>
-U:%*- *Annotate index.html (rev master~1) All L8  (Annotate from index.html) --

モードライン(最下行反転部)にある rev master~1が、 現行バージョンから何個前のバージョンを示す。 チェックアウトで特定のバージョンの複数のファイルをまとめて取り出したいときはコマンドラインで

vc-annotateのキー割当(抜粋)
p1つ前(古い)バージョンに移動
n1つ次(新しい)バージョンに移動
jカーソル行のバージョンに移動
wワーキング中のバージョンに移動
d該当バージョンとの差分表示
l該当バージョンのコミットログ表示
v左にある注釈表示のON/OFF
f該当バージョンのファイルをチェックアウトして開く

最後の f は、作業ディレクトリにそのバージョンのファイルを バージョン番号付きの名前で取り出すのでやりすぎるとディレクトリに 不要なファイルがたくさんできる(以下はEmacs vc-annotate でf を押してファイルを開いたあとにコマンドラインでlsしたもの)。

ls
README.md                 index.html.~43bad956~     main.css
index.html                index.html.~fc0a0e76~

ファイル名の最後が ~ となっているのが 一時的にチェックアウトされたファイルである。大抵の場合不要であるため Emacsから一気に消す方法を示す。

Emacsでindex.htmlを開いたままfind-file (C-x C-f)し、ファイル名を打たずにディレクトリのまま [Enter]するとディレクトリエディタ(dired)が立ち上がる。

  /home/irhome/c101/ta01002/public_html/2023-yuuji:
  total used in directory 1 available 1 TiB
  drwxr-xr-x  3 ta01002  st2001  4096 Apr 16 18:15 .
  drwxr-xr-x  4 ta01002  st2001  4096 Apr 15 18:30 ..
  drwxr-xr-x  8 ta01002  st2001  4096 Apr 16 17:30 .git
  -rw-r--r--  1 ta01002  st2001   121 Apr 15 18:21 README.md
  -rw-r--r--  1 ta01002  st2001   264 Apr 16 17:30 index.html
  -rw-r--r--  1 ta01002  st2001   209 Apr 16 17:48 index.html.~43bad956~
  -rw-r--r--  1 ta01002  st2001   215 Apr 16 18:15 index.html.~fc0a0e76~
  -rw-r--r--  1 ta01002  st2001    54 Apr 15 18:38 main.css

ここでバックアップファイルをマークする ~ をキー入力すると以下のように削除マーク(D)が付く。

  /home/irhome/c101/ta01002/public_html/2023-yuuji:
  total used in directory 1 available 1 TiB
  drwxr-xr-x  3 ta01002  st2001  4096 Apr 16 18:15 .
  drwxr-xr-x  4 ta01002  st2001  4096 Apr 15 18:30 ..
  drwxr-xr-x  8 ta01002  st2001  4096 Apr 16 17:30 .git
  -rw-r--r--  1 ta01002  st2001   121 Apr 15 18:21 README.md
  -rw-r--r--  1 ta01002  st2001   264 Apr 16 17:30 index.html
D -rw-r--r--  1 ta01002  st2001   209 Apr 16 17:48 index.html.~43bad956~
D -rw-r--r--  1 ta01002  st2001   215 Apr 16 18:15 index.html.~fc0a0e76~
  -rw-r--r--  1 ta01002  st2001    54 Apr 15 18:38 main.css

続けてキーボード x をタイプするとファイルが消される。

diredはファイルを選んで消したいときに利用できる。 消したいファイルの行で d を押すと削除マーク(D)が付くので 消したいタイミングで x を押せばよい。

ディレクトリ全体を過去のバージョンに戻す

コマンドラインでリポジトリディレクトリにcdしてから、 git checkout の後ろに戻したいバージョンを指定する。 戻したいバージョンは git log で確認する(これがgitの不便なところ)。

commit 9fd4a5a57ccc03eb75c3f28f4497a54d404b7908 (origin/master, origin/HEAD)
Author: HIROSE Yuuji <ta01002@e.koeki-u.ac.jp>
Date:   Sat Apr 15 18:38:38 2023 +0859

    背景色を変更した

commit 855b51cbc289f8963a6dd4abb02008aedb0da030
Author: HIROSE Yuuji <ta01002@e.koeki-u.ac.jp>
Date:   Sat Apr 15 18:36:26 2023 +0859

    main.cssファイルを足した

commit 80d327c1f3e02c83db1c9568222d27759695c842
Author: HIROSE Yuuji <yuuji@yatex.org>
Date:   Sat Apr 15 18:20:12 2023 +0900

    index.htmlへのリンクを張った

commit 43bad956b86bab4086f57f51a9956fc2d043c955
Author: HIROSE Yuuji <ta01002@e.koeki-u.ac.jp>
Date:   Sat Apr 15 18:16:05 2023 +0859

    index.htmlを新規作成した

commit ebef68bd4903afc2094b3619812864ee1dddb2d0
Author: HIROSE Yuuji <yuuji@yatex.org>
Date:   Sat Apr 15 18:13:34 2023 +0900

    Initial commit

"commit" の後ろにある16進数文字列がリビジョン番号で、 これを指定する(長すぎるのでコピペするしかない)。 もしくは目で何個前か数えて git checkout -f master~3 などとする。

差分生成

指定したリビジョンとの差分を見るには git diff コマンド を使う。

git diff リビジョン ファイル

とするとリビジョン の時点のものと現在のファイル の差分が表示される。リビジョン を省略すると、 最後にコミットしたバージョン、「ファイル」を省略するとすべての ファイルが対象となる。

diffとpatch

C-x v = でソースの変更した箇所を調べたときに出てきた 内容は GNU diff 形式 という。テキストファイルの変更点のみを 記したもので、元のファイルがどんなに大きくても、修正点が少なければ diff形式はその部分だけで済む。大きなソースを配布する場合に 新しいリビジョンの変更点のみをdiff形式で配布することにより、 とても少ない通信量で済ませることができる。

diff -ua 旧ファイル 新ファイル > file.diff

として差分を file.diff に保存する。相手側が 旧ファイル を持っていた場合相手側では

patch < file.diff

とすると、手元にあるファイルが新しいものに書き換えられる。

yuuji@koeki-u.ac.jp