Wagomu no Akibako

gitツールとしてのNeovim


この​記事はVim駅伝2024年4月26日(金)の​記事です。

前回の​記事は​ ryoppippiさんの​「Neovim + oil.nvim + Weztermで​頑張って​画像を​表示する」と​いう​記事でした。

次回の​記事は​ 4月29日(月) に​投稿される​予定です。


はじめに

Neovimは​習熟するまでの​ハードルが​高いと​言われている​エディタの​ひとつです。​その​ため、​使い​はじめた​ものの​挫折してしまったと​いう​方も​多いのではないでしょうか。
ですから、​今回は​テキストエディタと​してではなく、​gitツールと​して​Neovimを​使う方​法を​紹介しようと​思います。

git操作を​Neovimで​できるようになる​ことで、​あわよくばNeovim​使いに​なって​ほしいなと​願っています。

想定する​読者

  • git commitの​ときに​しか​vimを​起動しない​人
  • VSCodeなどの​guiから​gitを​使っている​人
  • tuiツールで​gitを​使っている​人

注意

windowsユーザーの​皆さんすみません!!!​windowsでは​起動速度が​遅いので​WSLで​使う​ことを​推奨します。
最終的な​コードは​こちらの​レポジトリで​公開しています。

GitHub - staticWagomU/neovim-as-a-git-tool: gitツールとしてのNeovim gitツールとしてのNeovim. Contribute to staticWagomU/neovim-as-a-git-tool development by creating an account...
ogp

実際の​操作

必要な​もの

Neovim

これが​ないと​始まりません。
インストール方​法は​こちらを​参照してください。

neovim/INSTALL.md at master · neovim/neovim Vim-fork focused on extensibility and usability. Contribute to neovim/neovim development by creating...
ogp

deno

deno製の​プラグインを​導入する​ため必要。​インストール方​法は​こちらを​参照してください。

必要な​プラグイン

denops

denoで​プラグインを​動か​すために​必要な​前提プラグイン

gin.vim

denopsを​使って​作られた​git操作を​する​ための​プラグイン

gitsigns

これは​denops製ではない。

Vimの​操作方​法

今回​使うのは​Neovimですが、​基本操作は​vimと​殆ど​変わりません。
操作方​法に​ついては、​Vim駅伝2024年4月17日にyasunori0418さんが​投稿した​記事を​ご覧ください。

はじめの​コード

まずは​この​コードを​貼り付けてください。

操作が​わからない方は​nvimを​開いて"+yの​順に​キーを​押す​ことで​コピーした​ものが​貼り付けられます。​あとは:wq<Cr>(<Cr>は​エンターキー)の​順に​押す​ことで​保存して​終了する​ことができます。

-- windowsユーザーの方は
-- %LOCALAPPDATA%\nvim\init.lua

-- mac/linuxユーザーの方は
-- ~/.config/nvim.init.lua

-- plugin managerの導入
local path_package = vim.fn.stdpath('data') .. '/site/'
local mini_path = path_package .. 'pack/deps/start/mini.deps'
if not vim.loop.fs_stat(mini_path) then
  vim.cmd('echo "Installing `mini.deps`" | redraw')
  local clone_cmd = { 'git', 'clone', '--filter=blob:none', 'https://github.com/echasnovski/mini.deps', mini_path }
  vim.fn.system(clone_cmd)
  vim.cmd('packadd mini.deps | helptags ALL')
  vim.cmd('echo "Installed `mini.deps`" | redraw')
end

vim.opt.number = true

require('mini.deps').setup { path = { package = path_package } }

local add, later = MiniDeps.add, MiniDeps.later
local opts = { noremap = true }

later(function()
  add('lewis6991/gitsigns.nvim')
  require('gitsigns').setup({
    signcolumn = false,
    numhl      = true,
  })
end)

later(function()
  add {
    source = 'lambdalisue/gin.vim',
    depends = { 'vim-denops/denops.vim' },
  }
  -- nvim起動時にGinStatusを実行する
  vim.api.nvim_create_autocmd('User', {
    pattern = "DenopsPluginPost:gin",
    callback = function()
      vim.schedule(function()
        vim.fn.execute('GinStatus')
      end)
    end,
    once = true
  })
end)


vim.cmd.colorscheme('habamax')

再度nvimを​開くと​プラグインの​インストールが​始まり、​このような​画面に​なれば​プラグインの​インストールが​完了です。
Pasted image 20240425172830.png
一度:q<Cr>で​Neovimを​終了して​gitで​管理している​ディレクトリから​nvimコマンドで​Neovimを​起動します。git status -sbの​実行結果のような​画面に​なれば​成功です。
Pasted image 20240425172830.png
git管理していない​ディレクトリで​Neovimを​起動すると​画面下部に​エラーが​表示されます。
Pasted image 20240425172830.png

各プラグインの​役割

必要なプラグインで​導入する​プラグインの​軽い​説明を​しましたが、​もう​少し​具体的に​説明します。

gin.vim

git操作全般を​担当する​プラグイン。
ファイルの​ステージ/アンステージ等の​基本的な​操作はは​もちろんの​こと、:Gin hogeと​実行する​ことでgit hogeを​実行できるので、​ターミナルに​戻る​ことなく​任意の​gitコマンド実行が​できる​優れもの。

gitsigns.nvim

主に​hunk単位での​操作を​行う​ために​使います。
具体的には​hunk単位での​ステージ/アンステージや、​blameの​確認、​hunkの​差分の​確認が​できます。

基本操作編

gin.vim

:Ginと​入力した​状態で<C-d>(Ctrlキーを​押しながら​dキーを​押す)を​押すと​Ginから​始まる​コマンド一覧を​確認できます。
Pasted image 20240425172830.png
私が​よく​使う​機能と​しては

  • gitコマンド相当のGin
  • git log相当のGinLog
  • git branch相当のGinBranch
  • .gitディレクトリが​ある​階層に​自動的にcdしてくれるGinCd
  • git status相当のGinStatus

です。​逆に​それ以外の​コマンドは​ほとんど​使った​ことがありません。​ごめんなさい。

試しに:GinLog<Cr>を​実行します。
このように​ターミナルの​実行結果が​そのまま​Neovim内で​見られます。​いいですね。
commitの​ハッシュが​書いてある​行で<Cr>を​押すと​その​commitの​詳細を​確認する​ことができます。
Pasted image 20240425172830.png
この​画面でaと​入力すると​画面下部にaction:と​表示されます。
Pasted image 20240425172830.png
この​状態で<C-d>を​押すとGinLog内で​実行できる​様々な​アクションを​確認する​ことができます。
Pasted image 20240425172830.png
このようにGinLogでは​様々な​アクションを​実行する​ことができます。
おすすめの​アクションはfixup:instant-fixupです。​詳細に​ついては​こちらの​記事に​委ねます。

gin.vimで捗るgitのログ改竄 (instant fixup) Vim 駅伝の2024/3/15の記事です。 Gitで整然とコミットを詰むのはそうそうたやすいものではありません。 あのコミットでバグを仕込んでしまっ
ogp

aを​押して​アクションを​選択する​ことはGinStatusGinBranchでも​できるので​確認してみてください。

基本操作編にも​かかわらず、​ファイルの​ステージングの​方法を​書いていませんでした。
:GinStatus<Cr>を​実行すると​このような​画面に​なります。
Pasted image 20240425172830.png
ステージングしたい​ファイルの​行で<<を​押す​ことで​ステージングする​ことができます。
アンステージングは>>で​行うことができます。

初期設定されている​キーマッピングに​ついては?を​押す​ことで​確認する​ことができます。

gin.vimの​ヘルプを​見たい方は、:h gin.txt<Cr>で​確認してみてください。

gitsigns.nvim

gitsignsで​定義されている​コマンドを​確認してみましょう
:Gitsigns (最後に​スペース)と​入力して<C-d>を​押すと​定義されている​コマンド一覧を​確認する​ことができます。
Pasted image 20240425172830.png

:GinStatusで​ファイルの​行へ​移動して<Cr>を​すると​その​ファイルを​開く​ことができます。
そして:Gitsigns next_hunk<Cr>と​する​ことで​次の​hunkへ​移動する​ことができます。​これは​言葉では​説明が​難しいので​動画を​撮ってみました。

動画を​見ると​分かるように、​変更が​された​行の​行番号の​色が​変わっています。​これも​gitsignsの​機能です。​どの​行が​変更されたのか​分かりやすくて​気に入っています。

gitsigns.nvimの​ヘルプを​見たい方は、:h gitsigns.txt<Cr>で​確認してみてください。

カスタマイズ編

gin.vim

pushや​pullを​する​ときに:Gin push:Gin pullを​毎回​実行するのは​面倒なので、​キーマッピングを​定義してみましょう。git pullには--autostashを​つけたい​タイプなので--autostash付きです。

later(function()
  add {
    source = 'lambdalisue/gin.vim',
    depends = { 'vim-denops/denops.vim' },
  }
  vim.api.nvim_create_autocmd('User', {
    pattern = "DenopsPluginPost:gin",
    callback = function()
      vim.schedule(function()
        vim.fn.execute('GinStatus')
      end)
    end,
    once = true
  })
+ vim.keymap.set('n', '<C-g>p', '<Cmd>Gin push<Cr>', opts)
+ vim.keymap.set('n', '<C-g>P', '<Cmd>Gin pull --autostash<Cr>', opts)
end)

これに​よって<C-g>pを​押すことに​よってgit pushと​同等の​操作が​でき、<C-g>Pを​押すことに​よってgit pull --autostashと​同等の​操作が​できるようになります。

:GinLog:GinBranch:GinStatusも​毎回​入力するのは​面倒なので​同様に​定義してみましょう。

later(function()
  add {
    source = 'lambdalisue/gin.vim',
...

  vim.keymap.set('n', '<C-g>p', '<Cmd>Gin push<Cr>', opts)
  vim.keymap.set('n', '<C-g>P', '<Cmd>Gin pull --autostash<Cr>', opts)
+ vim.keymap.set('n', '<C-g><C-s>', '<Cmd>GinStatus<Cr>', opts)
+ vim.keymap.set('n', '<C-g><C-b>', '<Cmd>GinBranch<Cr>', opts)
+ vim.keymap.set('n', '<C-g><C-l>', '<Cmd>GinLog<Cr>', opts)
+ vim.keymap.set('n', '<C-g>c', '<Cmd>Gin commit<Cr>', opts)
end)

それ以外に​私が​よく​使う​コマンドと​して、、

  • git fetch
  • git merge
  • git rebase

が​あるので​一緒に​定義していきましょう。

later(function()
  add {
    source = 'lambdalisue/gin.vim',
...

  vim.keymap.set('n', '<C-g>p', '<Cmd>Gin push<Cr>', opts)
  vim.keymap.set('n', '<C-g>P', '<Cmd>Gin pull --autostash<Cr>', opts)
  vim.keymap.set('n', '<C-g><C-s>', '<Cmd>GinStatus<Cr>', opts)
  vim.keymap.set('n', '<C-g><C-b>', '<Cmd>GinBranch<Cr>', opts)
  vim.keymap.set('n', '<C-g><C-l>', '<Cmd>GinLog<Cr>', opts)
+ vim.keymap.set('n', '<C-g>f', ':Gin fetch ', opts)
+ vim.keymap.set('n', '<C-g>m', ':Gin merge ', opts)
+ vim.keymap.set('n', '<C-g>r', ':Gin rebase --autostash ', opts)
end)

これで​コマンドを​打たずとも​好きな​操作が​できるようになりました。

gitsigns.nvim

hunkを​移動する​ために、:Gitsigns next_hunkを​入力するのは​面倒なので​これも​キーマッピングを​定義します。

later(function()
  add('lewis6991/gitsigns.nvim')
  require('gitsigns').setup({
    signcolumn = false,
    numhl      = true,
  })
+ vim.keymap.set('n', ']g', '<Cmd>Gitsigns next_hunk<Cr>', opts)
+ vim.keymap.set('n', '[g', '<Cmd>Gitsigns prev_hunk<Cr>', opts)
end)

ついでに、​自分の​気に入っている​設定も​追加して​おきます。

later(function()
  add('lewis6991/gitsigns.nvim')
  require('gitsigns').setup({
    signcolumn = false,
    numhl      = true,
  })
  vim.keymap.set('n', ']g', '<Cmd>Gitsigns next_hunk<Cr>', opts)
  vim.keymap.set('n', '[g', '<Cmd>Gitsigns prev_hunk<Cr>', opts)
+ vim.keymap.set('n', '<C-g><C-p>', '<Cmd>Gitsigns preview_hunk<Cr>', opts)
+ vim.keymap.set('n', '<C-g><C-v>', '<Cmd>Gitsigns blame_line<Cr>', opts)
+ vim.keymap.set('n', '<C-g>a', '<Cmd>Gitsigns stage_buffer<Cr>', opts)
end)

このように​カスタマイズを​重ねていく​と​様々な​操作が​できるようになります。​ぜひ​自分だけの​Neovimを​作ってみてください。
私が​実際に​使っている​設定も​載せて​おきます。
https://github.com/staticWagomU/dotvim/blob/89e71e06d7fab936f52e4560d6aaae3e90ce3fec/nvim/init.lua#L335-L444

おわりに

今回は​gitツールと​して​Neovimを​使う話です。
キーマッピングは​自由なので​好きに​カスタマイズしてください!​各プラグインの​ヘルプを​読みながら​設定するとより​理解が​深まるはずです。
これを​機に​Neovimに​興味を​持ってもらえると​嬉しいです。

おまけ

Vim駅伝にてgin.vimに​ついて​取り上げた​記事が​あります。​興味が​ある方は​読んで​みてください。

gin.vimでgitの差分を快適に閲覧する 2023/11/29のVim駅伝記事です。 前回はyasunori0418さんによる「vimを切っ掛けにエンジニアになった話」でした。 gin.
ogp
git操作プラグインを探しているならgin.vimはどう? - 輪ごむの空き箱 git操作プラグインを探しているならgin.vimはどう?