Lewis Russell d96ef3bbff chore: remove selene 2024-04-12 16:53:20 +01:00
.github test: migrate to nvim-test 2024-04-03 16:56:07 +01:00
doc feat(autocmd) add GitSignsChanged 2024-04-05 14:19:06 +01:00
etc feat(autocmd) add GitSignsChanged 2024-04-05 14:19:06 +01:00
lua fix(stage): staging of files with no nl at eof 2024-04-10 15:53:16 +01:00
test fix(stage): staging of files with no nl at eof 2024-04-10 15:53:16 +01:00
.editorconfig chore: update .editorconfig 2023-06-14 12:07:59 +01:00
.gitattributes chore: update .gitattributes 2023-06-14 12:07:14 +01:00
.gitignore test: migrate to nvim-test 2024-04-03 16:56:07 +01:00
.luarc.json test: migrate to nvim-test 2024-04-03 16:56:07 +01:00
.stylua.toml refactor: remove teal 2023-06-13 15:32:14 +01:00
CONTRIBUTING.md docs: update CONTRIBUTING.md 2023-09-23 10:10:16 +01:00
LICENSE Initial commit 2020-10-18 11:14:44 +01:00
Makefile chore: stylua 2024-04-03 17:21:49 +01:00
README.md feat(nav): add nav_hunk() 2024-04-05 13:35:49 +01:00
gen_help.lua feat(nav): add nav_hunk() 2024-04-05 13:35:49 +01:00
gitsigns.nvim-scm-1.rockspec refactor: remove teal 2023-06-13 15:32:14 +01:00



CI Version License: MIT Gitter

Super fast git decorations implemented purely in Lua.


Hunk Actions Line Blame


  • Signs for added, removed, and changed lines
  • Asynchronous using luv
  • Navigation between hunks
  • Stage hunks (with undo)
  • Preview diffs of hunks (with word diff)
  • Customizable (signs, highlights, mappings, etc)
  • Status bar integration
  • Git blame a specific line using virtual text.
  • Hunk text object
  • Automatically follow files moved in the index.
  • Live intra-line word diff
  • Ability to display deleted/changed lines via virtual lines.
  • Support for detached working trees.


  • Neovim >= 0.8.0

    Note: If your version of Neovim is too old, then you can use a past release.

    Note: If you are running a development version of Neovim (aka master), then breakage may occur if your build is behind latest.

  • Newish version of git. Older versions may not work with some features.

Installation & Usage

Install using your package manager of choice.

For recommended setup with all batteries included:


Configuration can be passed to the setup function. Here is an example with most of the default settings:

require('gitsigns').setup {
  signs = {
    add          = { text = '┃' },
    change       = { text = '┃' },
    delete       = { text = '_' },
    topdelete    = { text = '‾' },
    changedelete = { text = '~' },
    untracked    = { text = '┆' },
  signcolumn = true,  -- Toggle with `:Gitsigns toggle_signs`
  numhl      = false, -- Toggle with `:Gitsigns toggle_numhl`
  linehl     = false, -- Toggle with `:Gitsigns toggle_linehl`
  word_diff  = false, -- Toggle with `:Gitsigns toggle_word_diff`
  watch_gitdir = {
    follow_files = true
  auto_attach = true,
  attach_to_untracked = false,
  current_line_blame = false, -- Toggle with `:Gitsigns toggle_current_line_blame`
  current_line_blame_opts = {
    virt_text = true,
    virt_text_pos = 'eol', -- 'eol' | 'overlay' | 'right_align'
    delay = 1000,
    ignore_whitespace = false,
    virt_text_priority = 100,
  current_line_blame_formatter = '<author>, <author_time:%Y-%m-%d> - <summary>',
  current_line_blame_formatter_opts = {
    relative_time = false,
  sign_priority = 6,
  update_debounce = 100,
  status_formatter = nil, -- Use default
  max_file_length = 40000, -- Disable if file is longer than this (in lines)
  preview_config = {
    -- Options passed to nvim_open_win
    border = 'single',
    style = 'minimal',
    relative = 'cursor',
    row = 0,
    col = 1

For information on configuring Neovim via lua please see nvim-lua-guide.


Gitsigns provides an on_attach callback which can be used to setup buffer mappings.

Here is a suggested example:

  on_attach = function(bufnr)
    local gitsigns = require('gitsigns')

    local function map(mode, l, r, opts)
      opts = opts or {}
      opts.buffer = bufnr
      vim.keymap.set(mode, l, r, opts)

    -- Navigation
    map('n', ']c', function()
      if vim.wo.diff then
        vim.cmd.normal({']c', bang = true})

    map('n', '[c', function()
      if vim.wo.diff then
        vim.cmd.normal({'[c', bang = true})

    -- Actions
    map('n', '<leader>hs', gitsigns.stage_hunk)
    map('n', '<leader>hr', gitsigns.reset_hunk)
    map('v', '<leader>hs', function() gitsigns.stage_hunk {vim.fn.line('.'), vim.fn.line('v')} end)
    map('v', '<leader>hr', function() gitsigns.reset_hunk {vim.fn.line('.'), vim.fn.line('v')} end)
    map('n', '<leader>hS', gitsigns.stage_buffer)
    map('n', '<leader>hu', gitsigns.undo_stage_hunk)
    map('n', '<leader>hR', gitsigns.reset_buffer)
    map('n', '<leader>hp', gitsigns.preview_hunk)
    map('n', '<leader>hb', function() gitsigns.blame_line{full=true} end)
    map('n', '<leader>tb', gitsigns.toggle_current_line_blame)
    map('n', '<leader>hd', gitsigns.diffthis)
    map('n', '<leader>hD', function() gitsigns.diffthis('~') end)
    map('n', '<leader>td', gitsigns.toggle_deleted)

    -- Text object
    map({'o', 'x'}, 'ih', ':<C-U>Gitsigns select_hunk<CR>')

Note this requires Neovim v0.7 which introduces vim.keymap.set. If you are using Neovim with version prior to v0.7 then use the following:

Click to expand
require('gitsigns').setup {
  on_attach = function(bufnr)
    local function map(mode, lhs, rhs, opts)
        opts = vim.tbl_extend('force', {noremap = true, silent = true}, opts or {})
        vim.api.nvim_buf_set_keymap(bufnr, mode, lhs, rhs, opts)

    -- Navigation
    map('n', ']c', "&diff ? ']c' : '<cmd>Gitsigns next_hunk<CR>'", {expr=true})
    map('n', '[c', "&diff ? '[c' : '<cmd>Gitsigns prev_hunk<CR>'", {expr=true})

    -- Actions
    map('n', '<leader>hs', ':Gitsigns stage_hunk<CR>')
    map('v', '<leader>hs', ':Gitsigns stage_hunk<CR>')
    map('n', '<leader>hr', ':Gitsigns reset_hunk<CR>')
    map('v', '<leader>hr', ':Gitsigns reset_hunk<CR>')
    map('n', '<leader>hS', '<cmd>Gitsigns stage_buffer<CR>')
    map('n', '<leader>hu', '<cmd>Gitsigns undo_stage_hunk<CR>')
    map('n', '<leader>hR', '<cmd>Gitsigns reset_buffer<CR>')
    map('n', '<leader>hp', '<cmd>Gitsigns preview_hunk<CR>')
    map('n', '<leader>hb', '<cmd>lua require"gitsigns".blame_line{full=true}<CR>')
    map('n', '<leader>tb', '<cmd>Gitsigns toggle_current_line_blame<CR>')
    map('n', '<leader>hd', '<cmd>Gitsigns diffthis<CR>')
    map('n', '<leader>hD', '<cmd>lua require"gitsigns".diffthis("~")<CR>')
    map('n', '<leader>td', '<cmd>Gitsigns toggle_deleted<CR>')

    -- Text object
    map('o', 'ih', ':<C-U>Gitsigns select_hunk<CR>')
    map('x', 'ih', ':<C-U>Gitsigns select_hunk<CR>')


Implement every feature in vim-fugitive

This plugin is actively developed and by one of the most well regarded vim plugin developers. Gitsigns will only implement features of this plugin if: it is simple, or, the technologies leveraged by Gitsigns (LuaJIT, Libuv, Neovim's API, etc) can provide a better experience.

Support for other VCS

There aren't any active developers of this plugin who use other kinds of VCS, so adding support for them isn't feasible. However a well written PR with a commitment of future support could change this.

Status Line

Use b:gitsigns_status or b:gitsigns_status_dict. b:gitsigns_status is formatted using config.status_formatter. b:gitsigns_status_dict is a dictionary with the keys added, removed, changed and head.


set statusline+=%{get(b:,'gitsigns_status','')}

For the current branch use the variable b:gitsigns_head.

Comparison with vim-gitgutter

Feature gitsigns.nvim vim-gitgutter Note
Shows signs for added, modified, and removed lines
Runs diffs in-process (no IO or pipes) * * Via lua or FFI.
Supports Nvim's diff-linematch * * Via diff-linematch
Only adds signs for drawn lines * * Via Neovims decoration API
Updates immediately * * Triggered on CursorHold
Ensures signs are always up to date * * Watches the git dir to do so
Never saves the buffer * * Writes buffer (and index) to short lived temp files
Quick jumping between hunks
Stage/reset/preview individual hunks
Preview hunks directly in the buffer (inline) * * Via preview_hunk_inline
Stage/reset hunks in range/selection * * Only stage
Stage/reset all hunks in buffer
Undo staged hunks
Word diff in buffer
Word diff in hunk preview
Show deleted/changes lines directly in buffer * * Via virtual lines
Stage partial hunks
Hunk text object
Diff against index or any commit
Folding of unchanged text
Fold text showing whether folded lines have been changed
Load hunk locations into the quickfix or location list
Optional line highlighting
Optional line number highlighting
Optional counts on signs
Customizable signs and mappings
Customizable extra diff arguments
Can be toggled globally or per buffer * * Through the detach/attach functions
Statusline integration
Live blame in buffer (using virtual text)
Blame preview
Automatically follows open files moved with git mv
CLI with completion * * Provides individual commands for some actions
Open diffview with any revision/commit

As of 2022-09-01



When viewing revisions of a file (via :0Gclog for example), Gitsigns will attach to the fugitive buffer with the base set to the commit immediately before the commit of that revision. This means the signs placed in the buffer reflect the changes introduced by that revision of the file.


If installed and enabled (via config.trouble; defaults to true if installed), :Gitsigns setqflist or :Gitsigns setloclist will open Trouble instead of Neovim's built-in quickfix or location list windows.


If you are using lspsaga.nvim you can config code_action.extend_gitsigns (default is false) to show the gitsigns action in lspsaga codeaction.

Similar plugins