ソースファイルをdiffで比較する
ファイルやディレクトリの差分を確認するコマンドは、diff
です。
diff
は一般に文字列で比較するため、プログラミング言語のソースファイルのdiffをとる場合は、何が変わったかわからないことが多くありました。
たとえば次に示すdiffの差分では、Javaのソースファイルに対して以下2つの変更を検出しています。
- パラメータに対する
final
修飾子の追加 System.out.println
の引数の改行
前者はコードの意味を変更するのに対して、後者は単に見た目の変更です。 しかし、diffの結果を見る限りでは、どちらも同じように扱われています。
diff -u Main.orig.java Main.java --- Main.orig.java 2023-12-30 01:27:43 +++ Main.java 2023-12-30 01:29:11 @@ -4,7 +4,7 @@ public class Main { // NFDでの正規化を行い、正規化後の文字列を返す - public static String NFD(String str) { + public static String NFD(final String str) { return Normalizer.normalize(str, Normalizer.Form.NFD); } @@ -37,7 +37,8 @@ System.out.println("|文字列|Unicode|NFD|NFD Unicode|NFC|NFC Unicode|NFKD|NFKD Unicode|NFKC|NFKC Unicode|"); System.out.println("|---|---|---|---|---|---|---|---|---|---|"); for (String str : strs) { - System.out.println("|" + str + "|" + getUnicode(str) + "|" + System.out.println("|" + str + + "|" + getUnicode(str) + "|" + NFD(str) + "|" + getUnicode(NFD(str)) + "|" + NFC(str) + "|" + getUnicode(NFC(str)) + "|" + NFKD(str) + "|" + getUnicode(NFKD(str)) + "|"```
ソースファイルを具象構文木で比較するdifftastic
ソースファイルから具象構文木を生成し、その構文木を比較することで、プログラミング言語のソースファイルのdiffをとることができるツールとしてdifftasticがあります。
まずは使ってみましょう。先のdiff
と同様のファイルを比較してみた結果が以下です。
final
の追加に対しては追加した箇所にハイライトがされている一方、単に改行のみを変更した箇所は差分として検出されていません。これがdiffstasticの特徴です。
difftasticはソースファイルを具象構文木に変換し、その構文木を比較することで、ソースファイルのdiffをとります。抽象構文木(AST)というのはよく聞きますが、difftasticが利用する具象構文木(CST)は空白やコメント、括弧等のASTでは省略される構文的要素を含む構文木です。difftasticはこのCSTを利用して、構文的な差分を検出してくれるわけです。
差分の見せ方
上記の差分のキャプチャは1カラムで出力されていますが、これは単純追加や削除に対し、difftasticがデフォルトで1カラムのみ出力するためです。やや複雑な差分の場合は2カラムで出力されます。
もちろん、強制的に2カラムで出力可能です。このモードの切り替えは--display
オプションで行います。
Gitでの利用法
差分を見るのが頻出するのはgitを利用するタイミングです。
Gitで差分を見る場合はgit diff
を使うことが多いですが、外部ツールを使って差分を見る場合は、一般にgit difftool
を使います。
git difftool is a Git command that allows you to compare and edit files between revisions using common diff tools.
.gitconfig
で次のように定義すれば良いでしょう。
git diff .gitconfig diff --git a/.gitconfig b/.gitconfig index ca27d5e..54727c7 100644 --- a/.gitconfig +++ b/.gitconfig @@ -56,14 +56,25 @@ path = ~/.config/git/tis graph = log --graph --branches --pretty=format:'%C(yellow)%h%C(cyan)%d%Creset %s %C(green)- %an, %cr%Creset' [diff] +tool = difftastic # Choose a diff algorithm. # patience: # Use "patience diff" algorithm when generating patches. algorithm = patience +[difftool] +# difftool を使う時に、プロンプトを出すかどうか +prompt = false + +[difftool "difftastic"] +cmd = difft "$LOCAL" "$REMOTE" + +[pager] +difftool = true +
そうすると、git difftool
でdifftasticが起動します。
対応言語
difftasticが対応している言語はLanguages Supported - Difftastic Manualに一覧があります。 目ぼしい言語には対応していると言えそうです。