はじめに
vimdiff
が使える場合はこの記事は読む必要がありません。
また、はじめには読み飛ばして下さって構いません。
エンジニアにとって、2つのファイルの比較を行うことはよくあることだと思います。
ですが最近仕事で2つのファイルの差分を誰でもすぐに読み解ける方法を考え出す必要が出てきました。なお、補足をするとそのプロジェクトではgitを導入できる段階ではありませんでした。
全員がvimを使えるならvimdiff
で良いと思います。
ここでは主にdiff
コマンドに関することでの視覚的なことについてメモしたいと思います。
パッチ等他の形式については Linuxエンジニアらしいパッチのつくりかた がよくまとまっていると思いますので、そちらをご覧ください。
diffコマンド
一般的に差分を取るときは普通はdiff
コマンドが思いつきます。diff
コマンドの差分の判定についてのオプションについてはここでは省略します。
説明のために以下の2つのファイルを用意します。これ以降このファイルを使用します。
the
quick
brown
fox
jumps
over
the
lazy
dog
the
quick
brown
fox
jumped
over
the
lazy
dogs
この状態でdiff a.txt b.txt
を実行すると以下のようになります。
% diff a.txt b.txt
5,6c5
<
< jumps
---
> jumped
8a8
>
10c10
< dog
---
> dogs
ここからは、以下の情報が読み取れると思います。他にも削除(d
: deleted)があります。
- a.txtの5, 6行目とb.txtの5行目で改行+
jumps
のjumped
への変更(c
: changed)がされた - a.txtの8行目とb.txtの8行目で改行の追加(
a
: added)がされた - a.txtの10行目とb.txtの10行目で
dog
のdogs
への変更(c
: changed)がされた
読み取ることはできますが誰でも読み解けるか、と言われると疑問が残ります。
Unified形式
-u
オプションをつけることで、Unified形式で出力することができます。
-U
オプションで何行(デフォルトは3行)何行ずつ結合するか指定できます。
% diff -u a.txt b.txt
--- a.txt 2016-08-29 06:43:45.000000000 +0900
+++ b.txt 2016-08-29 06:43:59.000000000 +0900
@@ -2,9 +2,9 @@
quick
brown
fox
-
-jumps
+jumped
over
the
+
lazy
-dog
+dogs
ここからは、a.txtとb.txtの2行目から9行目にかけて以下の情報が上から順に読み取れます。
- a.txtからb.txtで改行の削除(-)がされた
- a.txtからb.txtで
jumps
の削除(-)がされた - a.txtからb.txtの
jumped
の追加(+)がされた - a.txtからb.txtで改行の追加(+)がされた
- a.txtからb.txtで
dog
の削除(-)がされた - a.txtからb.txtで
dogs
の追加(+)がされた
Unified形式では同じファイルの文脈の中で上から順に差分を調べることができます。
Context形式
-c
オプションをつけることで、Context形式で出力することができます。
-C
オプションで何行(デフォルトは3行)何行ずつコピーするか指定できます。
% diff -c a.txt b.txt
*** a.txt 2016-08-29 06:43:45.000000000 +0900
--- b.txt 2016-08-29 06:43:59.000000000 +0900
***************
*** 2,10 ****
quick
brown
fox
!
! jumps
over
the
lazy
! dog
--- 2,10 ----
quick
brown
fox
! jumped
over
the
+
lazy
! dogs
ここからはまず、a.txtの2行目から10行目にかけて以下の情報が上から順に読み取れます。
- 改行が削除または変更された
-
jumps
が削除または変更された -
dogs
が削除または変更された
また、b.txtの2行目から10行目にかけて以下の情報が上から順に読み取れます。
-
jumped
が変更された - 改行が追加された
-
dogs
が変更された
Context形式ではそれぞれのファイルの文脈の中で上から順に差分を調べることができます。
2カラム形式
-y
オプションをつけることで2カラムにして表示することができます。このとき-W
オプションで合計の横幅(デフォルトは130)を設定することができます。似たものにsdiff
があります。
% diff -y -W 80 a.txt b.txt
the the
quick quick
brown brown
fox fox
| jumped
jumps <
over over
the the
>
lazy lazy
dog | dogs
読み方の説明はもはや不要に思えますが>
が追加、<
が削除、|
が変更を表しています。
2カラム形式は、とても視覚的で誰にとっても読み易いとはと思いませんか?(あくまで私の感想ですが)
しかし、この表示には欠点があります。それは、行数がつかめないことです。
これを解決する方法をコラムの後に述べます。
コラム: diffに色をつけて表示する
色があると読み易さが格段に向上します。
他にも色をつけられるコマンドはたくさんありますが linux(CentOS)のコマンドに色付け の記事にまとまっています。
diff
に色をつける場合にはcolordiff
があります。
導入方法
Homebrewの場合
% brew install colordiff
Debian系の場合
# apt-get install colordiff
RHEL系の場合
# yum install colordiff
使い方
diff
コマンドではなく、colordiff
を実行すれば良いです。
毎回colordiff
と打つのが面倒であれば以下のように.bashrc
や.zshrc
などに以下を追記します。
alias diff='colordiff'
このときdotfilesをgit管理していて複数の環境で使うという場合などでは以下のように追記すると良いでしょう。
if [[ -x `which colordiff` ]]; then
alias diff='colordiff'
else
alias diff='diff'
fi
icdiffを利用する
行数を表示して2カラムが表示できても行数がなければどこか特定するのは難しくなります。
そこでicdiff
の--line-numbers
オプションを利用してみます。
導入方法
導入方法は jeffkaufman/icdiff: improved colored diff にもまとまっています。gitで利用したい場合は参照すると良いでしょう。
# pip install git+https://github.com/jeffkaufman/icdiff.git
使い方
-U
オプションで表示される行を少なくしています。
また、icdiff
など色付きコマンドをlessに入れる場合は... | less -R
とすると良いでしょう。
diffコマンドでicdiffコマンドが呼び出されるのは強引な気がしますので、今回はオプションのエイリアスで止めておきます。以下のようにすれば良いでしょう。
alias icdiff='icdiff -U 1 --line-numbers'
まとめ
-
diff
の表示形式にはUnified形式、Context形式、2カラム方式がある(RCS formatなどは視覚的でないため除く) - 色をつけるには
colordiff
を使うと良い -
icdiff
を利用すればは2カラム形式で色をつけ、行番号を簡単につけられる - 全員vimを使えるなら
vimdiff
が...いいのです...