gitsigns.nvim is a Neovim plugin that displays Git blame information and hunk status directly in the editor, making it easier to track changes and navigate Git history.

Let’s see it in action. Imagine you’re editing a file that’s under Git version control. As you type, gitsigns.nvim adds annotations to the gutter (the space to the left of your code). These annotations show who last modified a line, when, and in which commit.

Consider this Python file:

def greet(name):
    # This function greets the person passed in as a parameter
    return "Hello, " + name + "!"

if __name__ == "__main__":
    print(greet("World"))

With gitsigns.nvim enabled and configured, the gutter might look something like this:

     def greet(name):
-    # This function greets the person passed in as a parameter  <-- "Alice, 2 days ago"
+    # This function greets the person passed in as a parameter  <-- "Bob, 1 hour ago"
     return "Hello, " + name + "!"
 
 if __name__ == "__main__":
     print(greet("World"))

The - indicates a deleted line, and the + indicates an added line. The text to the right, like "Alice, 2 days ago", is the blame information. This is not just a static display; it’s dynamically updated as you save your file or pull changes.

The core problem gitsigns.nvim solves is context loss. When you’re working on a codebase, especially a large one or one with many collaborators, understanding why a line of code exists, who wrote it, and when, is crucial for debugging, refactoring, or simply understanding the code’s intent. Without this information readily available, you’d have to constantly switch to your terminal, run git blame, and try to match the output to your current line. gitsigns.nvim brings this context directly into your editing workflow.

Internally, gitsigns.nvim works by:

  1. Listening for buffer changes: It hooks into Neovim’s events to know when a file is opened, saved, or modified.
  2. Querying Git: When necessary, it runs Git commands in the background (like git blame and git diff) to fetch the relevant information for the current buffer.
  3. Rendering annotations: It uses Neovim’s built-in features, like virtual text and signs, to display this information in the gutter and potentially in other UI elements.

The primary levers you control are through its configuration in your init.lua or init.vim.

Here’s a typical configuration snippet in Lua:

require('gitsigns').setup{
  signs = {
    add = { text = '+' },
    change = { text = '~' },
    delete = { text = '-' },
    topdelete = { text = '‾' },
    changedelete = { text = '!' }
  },
  signcolumn = true, -- Enable the sign column
  numhl = false, -- Disable line number highlighting for blame
  line_ அலுவலக = true, -- Highlight current line blame
  current_line_blame_width = 20,
  update_in_insert = false, -- Don't update blame while in insert mode
  update_in_diff = false, -- Don't update blame while in diff mode
  watch_git_dir_recursively = true,
  attach_to_untracked = true, -- Show signs for untracked files
  current_hunk_override = 1, -- Highlight the current hunk
  max_file_length = 4096, -- Maximum file length to show blame for
  browse_git_file_history = {
    use_builtin_diff = true,
    diff_tool = 'vimdiff', -- Or your preferred diff tool
  },
  keymaps = {
    -- Hunk navigation
    next_hunk = '}',
    prev_hunk = '{',
    -- Blame navigation
    blame_line = '<leader>gb',
    blame_next_hunk = '<leader>gbn',
    blame_prev_hunk = '<leader>gbp',
    -- Stage/Unstage hunks
    stage_hunk = '<leader>gs',
    undo_stage_hunk = '<leader>gu',
    -- Git actions
    reset_hunk = '<leader>gr',
    view_hunk_diff = '<leader>gd',
  }
}

The signs table controls the characters displayed in the gutter. signcolumn = true ensures the sign column is visible. current_line_blame_width limits how much blame text is shown. The keymaps section is crucial for interactivity, allowing you to jump between hunks ({, }), view blame for a specific line (<leader>gb), and stage or unstage changes.

One of the most powerful, yet often overlooked, features is how gitsigns.nvim integrates with Git’s staging area. When you stage a hunk using a keymap like <leader>gs, gitsigns.nvim doesn’t just stage the entire file. It intelligently stages only the lines within that specific hunk. This allows for granular commits, where you can select precisely which parts of your modified file you want to include in the next commit, a workflow often referred to as "interactive staging" or "patch staging." This is distinct from git add . or git add <filename>, which stage all changes in the file.

The next concept you’ll likely explore is how gitsigns.nvim can be extended or integrated with other plugins for more advanced Git workflows, such as fuzzy finding Git branches or managing Git commits.

Want structured learning?

Take the full Vim course →