アルパカログ

📅  2020-11-30

Gitで差分のあるファイルを簡単に入力できるウィジェットの紹介(fzf-git)


Gitを使っていて最も面倒なことのひとつはファイル名の入力だと思います。

git addする前にgit statusをしてファイル名を確認し、ファイル名をコピー&ペーストしてgit addする。場合によっては先にgit diffで差分を確認したりします。

できればもっとスマートにやりたいものです。そこでインクリメンタルサーチの代名詞であるfzfを使ってちょっとしたツールを作ってみました。下記のデモをご覧ください。

An image from Notion
fzf-gitの紹介

デモからおわかりいただけると思いますが、git statusの結果を候補にfzfを実行しています。ついでに右側には選んでいるファイルの差分が出ます。

まだ個人的に使っている段階ですが、とても便利なのでぜひ使っていただければと思います。もしバグを見つけたらPRを投げていただければ幸いです。

以降は少しfzf-gitの仕組み的な話をしてみたいと思います。

fzf-gitの仕組み的な話

fzf-gitは仕組みとしてはとても単純で、git status --shortの結果をfzfにパイプしているだけです。

ソースコードは今のところ50行ほどの1ファイルのみで、その大半を文字列マッチのためのAwkスクリプトが占めています。

このAwkスクリプトの役割は2つあります。ひとつはカラーコード込みのマッチングを頑張ること、もうひとつはGitのワーキングディレクトリとステージングエリアの両方に同時に存在するファイルの扱いです。

前者は調べると(カラーコードだけに)色々情報が出てくるので特に説明はしません。

後者のGitファイルの扱いについて少し説明します。

Gitのワーキングディレクトリとステージングエリアの両方に同じファイルが存在するとき、git status --shortの結果は次のようになります。

$ git status --short
MM foo.txt

Mはmodifiedを表しており、MMの1文字目がステージングエリア、2文字目がワーキングディレクトリを表しています。

ステージングエリアにあるファイルとワーキングディレクトリにあるファイルとではgit diffコマンドのオプションが異なります。つまり、ワーキングディレクトリの差分は単にgit diff <file>となるのに対し、ステージングエリアの差分はgit diff --staged <file>となります。

ですのでMM foo.txtを下記のように2行に分解してあげる必要があります。

M  foo.txt
 M foo.txt

こうしておけば、1文字目がMのファイルに対してはgit diff --staged <file>で、2文字目がMのファイルに対してはgit diff <file>で差分を表示できるようになります。

awk { print $2 }とすればファイル名foo.txtが取得できます。

将来的にはUntrackedなファイルも色付きで差分を表示できたら良いなとは思っています(catだと味気ない)。

以上です。

このエントリではGit管理ファイルをインクリメンタルサーチできるzshウィジェットfzf-gitを紹介しました。

参考にしたエントリ

fzf-gitを作るにあたって下記エントリをたいへん参考にさせていただきました。ありがとうございます。