🎼

fzf.vim で「このブランチ内で変更したファイル」をすぐ開けるようにした

2022/01/13に公開

git 使って開発している場合、「ブランチ切って開発を進めて最後にマージ」というパターンは多いかなと思います。

でまあ、master なり main ブランチからトピックブランチを作って開発するわけですけど、最近 いま作業中のブランチ内で変更したファイルに素速くアクセスしたい という欲求が高まってきました。

今では junegunn/fzf.vim とか yuki-yano/fzf-preview.vim のおかげで、vim の中から目的のファイルを開くのが格段にスムーズです。これらのプラグインを使えば、プロジェクト内のファイルとか最近編集したファイルとかいう単位であいまい検索できてかなり便利だし、とても大好きなプロダクトです。

ですが、プロジェクト内にファイルが多いと結局はまあまあ絞り込みを意識しないといけないこととかあって、ほんの多少ですがわずらわしさも。どうせトピックブランチの中で触るファイルなんて限られてるんだから、それだけ絞り込めたらよくね?という発想で考えたのが「作業中のブランチ内で変更したファイル」からファイル選択できるようにすることです。

まだ使えるようにしただけで、本当に便利なのかよくわからない。FzfPreviewFromResources project_mrw でもいいんではないかという疑惑もある。まあ、せっかく作ったし、もしかしたら誰かの役に立つかもしれないのでやりかたを書いておきます。

現在のブランチ上で変更したファイルの一覧を取得する

まずは目的のファイル一覧を取得するための git コマンドについてです。最終的にやりたいことは ブランチの分岐元のコミットと、ローカルのコミットの diff を取れば実現できるのですが、一発でやるのは難しいので順を追って説明します。

例では master ブランチから feature/vim-love ブランチに派生した場合を想定しています。

git show-branch でブランチのコミット情報が取得できます。一番最後に出力されているコミットが feature/vim-love ブランチの派生元です。結果を見ると、417c9d9b コミットでブランチを切ったことがわかります。

$ git show-branch --sha1-name master feature/vim-love
! [master] Merge pull request #1992 from ktakayama/feature/vim-start
 * [feature/vim-love] さらに次のコミット
--
 * [585c8770] さらに次のコミット
 * [6299c527] 何らかのコミット
-- [417c9d9b] Merge pull request #1992 from ktakayama/feature/vim-start

master とか feature/vim-love とかもコマンドから取得できるようにします。いわゆるメインのブランチを取得する場合はこんな感じでやってます(環境によっては、origin じゃないかもしれません)。

$ git symbolic-ref --short refs/remotes/origin/HEAD
master

現在作業中のブランチの名前を取得するのは以下です。

$ git rev-parse --abbrev-ref HEAD
feature/vim-love

で、最終的に上記のやつを色々組みわせてごちゃごちゃワンライナーにすると、こんな感じになりました。

$ git diff --name-only $(git show-branch --sha1-name \
   $(git symbolic-ref --short refs/remotes/origin/HEAD) \
   $(git rev-parse --abbrev-ref HEAD) | tail -1 | awk -F'[]~^[]' '{print $2}')

長いから改行を入れたんですけど、そのせいで余計見にくくなってたら申し訳ない。

fzf.vim から叩く

vimrc にこんな感じで書きました。:FzfGitBranchFiles で目的のファイルのみに絞って検索できます。夢が実現できる vim って素晴らしい…。

command! -bang FzfGitBranchFiles
  \ call fzf#run({'source':
  \   "git diff --name-only $(git show-branch --sha1-name $(git symbolic-ref --short refs/remotes/origin/HEAD) $(git rev-parse --abbrev-ref HEAD) | tail -1 | awk -F'[]~^[]' '{print $2}')",
  \   'sink': 'e',
  \   'options': '-m --prompt "GitBranchFiles>" --preview "bat --color=always  {}"',
  \   'window': { 'width': 0.92, 'height': 0.7, 'yoffset': 1 }
  \   })

previewbat 使っていたり、window をカスタマイズしていたりするので、そこらへんは適宜カスタマイズしてもらえると。本当はこんなオプションの指定はせずに標準的なレイアウトにしたかったんですけど、fzf.vim で直接コマンドを叩く難易度が高くて意味不明すぎてぜんぜんうまくいかず挫折してこの形になりましたというわけ。

Discussion