gitlineage.nvim: git history for selected lines in Neovim

Cover Image for gitlineage.nvim: git history for selected lines in Neovim
Rahul M. Juliato
Rahul M. Juliato
#neovim#git# plugin# lua

There's a feature in Emacs that I've always loved: vc-git-region-history. You select a range of lines, call the command, and Emacs shows you how those exact lines evolved through git commits.

When I'm working in Neovim, I genuinely miss this. There are great git plugins out there, sure, but none of them gave me exactly this: select lines, see their history, navigate commits. And that's it. No extras. No repeated features I already have provided by other plugins and sometimes even fight between them.


The mini.nvim philosophy

Before I talk about what I built, I want to mention something that deeply influenced the approach: mini.nvim.

If you haven't seen it, mini.nvim is a collection of small, independent Neovim modules. Each one does one thing, and does it well. You don't have to install the whole collection, you can pick exactly the functionality you need.

This resonates with me. I don't want to install a massive git suite just to get one feature. I don't want a plugin that tries to be everything for everyone. I want a small, focused tool that does its job and gets out of the way.

That's the spirit behind what I made.


gitlineage.nvim

gitlineage.nvim: a small Neovim plugin that lets you view git history for selected lines.

logo

What follows is largely based on the project's README.md. Since things may change over time, check the repository for the latest information.


How it Works

  1. Select a range of lines in visual mode.

    demo_1

  2. Press <leader>gl (all bindings are customizable). A new split window opens with the git history of the selected lines.

    demo_2

  3. Advance through commits with ]c.

    demo_3

  4. Quickly yank the commit SHA with yc.

    demo_4

  5. Go back to previous commits with [c.

    demo_5

  6. If diffview.nvim is installed, open the full commit diff by hitting <CR> on a commit line.

    demo_6


Requirements

Before install it, check the requirements:

Required:

  • Neovim >= 0.7.0
  • Git

Optional:


Installation

You can clone the repository and load everything manually, but it is highly recommended to use a plugin manager.

lazy.nvim

{
    "lionyxml/gitlineage.nvim",
    dependencies = {
        "sindrets/diffview.nvim", -- optional, for open_diff feature
    },
    config = function()
        require("gitlineage").setup()
    end
}

mini.deps / vim.pack.add() (Neovim >= 0.12)

Using mini.deps:

local add = require("mini.deps").add

add("lionyxml/gitlineage.nvim")
add("sindrets/diffview.nvim") -- optional, for open_diff feature

require("gitlineage").setup()

Using native vim.pack.add() for Neovim >= 0.12:

vim.pack.add("lionyxml/gitlineage.nvim")
vim.pack.add("sindrets/diffview.nvim") -- optional, for open_diff feature

require("gitlineage").setup()

vim-plug

call plug#begin()

Plug 'lionyxml/gitlineage.nvim'
Plug 'sindrets/diffview.nvim' " optional, for open_diff feature

call plug#end()

lua require("gitlineage").setup()

Configuration

require("gitlineage").setup({
    split = "auto",       -- "vertical", "horizontal", or "auto"
    keymap = "<leader>gl", -- set to nil to disable default keymap
    keys = {
        close = "q",       -- set to nil to disable
        next_commit = "]c", -- set to nil to disable
        prev_commit = "[c", -- set to nil to disable
        yank_commit = "yc", -- set to nil to disable
        open_diff = "<CR>", -- set to nil to disable (requires diffview.nvim)
    },
})
| Option             | Default      | Description                                                                                  |
| ------------------ | ------------ | -------------------------------------------------------------------------------------------- |
| `split`            | `auto`       | How to open the history buffer. `auto` picks vertical for wide windows, horizontal for tall. |
| `keymap`           | `<leader>gl` | Visual mode keymap. Set to `nil` to define your own.                                         |
| `keys.close`       | `q`          | Close the history buffer.                                                                    |
| `keys.next_commit` | `]c`         | Jump to next commit.                                                                         |
| `keys.prev_commit` | `[c`         | Jump to previous commit.                                                                     |
| `keys.yank_commit` | `yc`         | Yank commit SHA when on a commit line.                                                       |
| `keys.open_diff`   | `<CR>`       | Open full commit diff (requires diffview.nvim).                                              |

Custom keymaps

require("gitlineage").setup({
    keymap = "<leader>gh",
    keys = {
        close = "<Esc>",
        next_commit = "<C-n>",
        prev_commit = "<C-p>",
        yank_commit = "y",
        open_diff = "d",
    },
})

Usage

  1. Enter visual mode (v, V, or <C-v>)
  2. Select the lines you want to inspect
  3. Press <leader>gl (or your configured keymap)
  4. A split window opens with the git history
  5. Navigate using buffer keymaps:
| Key    | Action                                         |
| ------ | ---------------------------------------------- |
| `q`    | Close the history buffer                       |
| `]c`   | Jump to next commit                            |
| `[c`   | Jump to previous commit                        |
| `yc`   | Yank commit SHA (on commit line)               |
| `<CR>` | Open full commit diff (requires diffview.nvim) |

Health check

Verify your setup:

:checkhealth gitlineage

This checks:

➖ Neovim version

➖ Git availability

➖ Git repository status

➖ diffview.nvim availability (optional)

➖ Plugin configuration


Conclusion

If you're someone who moves between Emacs and Neovim, or if you've ever wanted a focused, minimal way to inspect line-level git history without installing a full git suite, give https://github.com/LionyxML/gitlineage.nvim a try.

It's small, it does one thing, and it stays out of your way. Just like a good plugin should.