- Notifications
You must be signed in to change notification settings - Fork295
A Vim plugin which shows git diff markers in the sign column and stages/previews/undoes hunks and partial hunks.
License
airblade/vim-gitgutter
Folders and files
| Name | Name | Last commit message | Last commit date | |
|---|---|---|---|---|
Repository files navigation
A Vim plugin which shows a git diff in the sign column. It shows which lines have been added, modified, or removed. You can also preview, stage, and undo individual hunks; and stage partial hunks. The plugin also provides a hunk text object.
The signs are always up to date and the plugin never saves your buffer.
The name "gitgutter" comes from the Sublime Text 3 plugin which inspired this in 2013.
Features:
- Shows signs for added, modified, and removed lines.
- Runs the diffs asynchronously where possible.
- Ensures signs are always up to date.
- Never saves the buffer.
- Quick jumping between blocks of changed lines ("hunks").
- Stage/undo/preview individual hunks.
- Previews highlight intra-line changes.
- Stage partial hunks.
- Provides a hunk text object.
- Diffs against index (default) or any commit.
- Handles file moves / renames.
- Heeds git's "assume unchanged" bit.
- Allows folding all unchanged text.
- Provides fold text showing whether folded lines have been changed.
- Can load all hunk locations into quickfix list or the current window's location list.
- Handles line endings correctly, even with repos that do CRLF conversion.
- Handles clean/smudge filters.
- Optional line highlighting.
- Optional line number highlighting. (Only available in Neovim 0.3.2 or higher)
- Fully customisable (signs, sign column, line (number) highlights, mappings, extra git-diff arguments, etc).
- Can be toggled on/off, globally or per buffer.
- Preserves signs from other plugins.
- Does the right thing when viewing revisions withfugitive's
:0Gclog. - Easy to integrate diff stats into status line; built-in integration withvim-airline.
- Works with fish shell (in addition to the usual shells).
Constraints:
- Supports git only. If you work with other version control systems, I recommendvim-signify.
- Relies on the
FocusGainedevent. If your terminal doesn't report focus events, either use something likeTerminus or setlet g:gitgutter_terminal_reports_focus=0. For tmux,set -g focus-events onin your tmux.conf.
Compatibility:
Compatible back to Vim 7.4, and probably 7.3.
In the screenshot above you can see:
- Lines 183-184 are new.
- Lines 186-187 have been modified.
- The preview for the modified lines highlights changed regions within the line.
First, install using your favourite package manager, or use Vim's built-in package support.
Vim:
mkdir -p ~/.vim/pack/airblade/startcd ~/.vim/pack/airblade/startgit clone https://github.com/airblade/vim-gitgutter.gitvim -u NONE -c "helptags vim-gitgutter/doc" -c qNeovim:
mkdir -p ~/.config/nvim/pack/airblade/startcd ~/.config/nvim/pack/airblade/startgit clone https://github.com/airblade/vim-gitgutter.gitnvim -u NONE -c "helptags vim-gitgutter/doc" -c qSecond, ensure yourupdatetime andsigncolumn options are set appropriately.
When you make a change to a file tracked by git, the diff markers should appear automatically after a short delay. The delay is governed by vim'supdatetime option; the default value is4000, i.e. 4 seconds, but I suggest reducing it to around 100ms (addset updatetime=100 to your vimrc). Noteupdatetime also controls the delay before vim writes its swap file (see:help updatetime).
Thesigncolumn option can have any value except'no'.
There is a potential risk on Windows due tocmd.exe prioritising the current folder over folders inPATH. If you have a file namedgit.* (i.e. with any extension inPATHEXT) in your current folder, it will be executed instead of git whenever the plugin calls git.
You can avoid this risk by configuring the full path to your git executable. For example:
" This path probably won't workletg:gitgutter_git_executable='C:\Program Files\Git\bin\git.exe'
Unfortunately I don't know the correct escaping for the path - if you do, please let me know!
When you make a change to a file tracked by git, the diff markers should appear automatically after a short delay.
You can jump between hunks with[c and]c. You can preview, stage, and undo hunks with<leader>hp,<leader>hs, and<leader>hu respectively.
You cannot unstage a staged hunk.
After updating the signs, the plugin fires theGitGutter User autocommand.
After staging a hunk or part of a hunk, the plugin fires theGitGutterStage User autocommand.
You can explicitly turn vim-gitgutter off and on (defaults to on):
- turn off with
:GitGutterDisable - turn on with
:GitGutterEnable - toggle with
:GitGutterToggle.
To toggle vim-gitgutter per buffer:
- turn off with
:GitGutterBufferDisable - turn on with
:GitGutterBufferEnable - toggle with
:GitGutterBufferToggle
You can turn the signs on and off (defaults to on):
- turn on with
:GitGutterSignsEnable - turn off with
:GitGutterSignsDisable - toggle with
:GitGutterSignsToggle.
And you can turn line highlighting on and off (defaults to off):
- turn on with
:GitGutterLineHighlightsEnable - turn off with
:GitGutterLineHighlightsDisable - toggle with
:GitGutterLineHighlightsToggle.
Note that if you have line highlighting on and signs off, you will have an empty sign column – more accurately, a sign column with invisible signs. This is because line highlighting requires signs and Vim/NeoVim always shows the sign column when there are signs even if the signs are invisible.
With Neovim 0.3.2 or higher, you can turn line number highlighting on and off (defaults to off):
- turn on with
:GitGutterLineNrHighlightsEnable - turn off with
:GitGutterLineNrHighlightsDisable - toggle with
:GitGutterLineNrHighlightsToggle.
The same caveat applies to line number highlighting as to line highlighting just above.
If you switch off both line highlighting and signs, you won't see the sign column.
In older Vims (pre 8.1.0614 / Neovim 0.4.0) vim-gitgutter will suppress the signs when a file has more than 500 changes, to avoid slowing down the UI. As soon as the number of changes falls below the limit vim-gitgutter will show the signs again. You can configure the threshold with:
letg:gitgutter_max_signs=500" default value (Vim < 8.1.0614, Neovim < 0.4.0)letg:gitgutter_max_signs=-1" default value (otherwise)
You can also remove the limit by settingg:gitgutter_max_signs = -1.
You can jump between hunks:
- jump to next hunk (change):
]c - jump to previous hunk (change):
[c.
Both of those take a preceding count.
To set your own mappings for these, for example]h and[h:
nmap]h<Plug>(GitGutterNextHunk)nmap[h<Plug>(GitGutterPrevHunk)
When you jump between hunks, a message likeHunk 4 of 11 is shown on the command line. If you want to turn the message off, you can use:
letg:gitgutter_show_msg_on_hunk_jumping=0
You can load all your hunks into the quickfix list with:GitGutterQuickFix. Note this ignores any unsaved changes in your buffers. If the optiong:gitgutter_use_location_list is set, this command will load hunks into the current window's location list instead. Use:copen (or:lopen) to open the quickfix / location list or add a custom command like this:
command! Gqf GitGutterQuickFix |copen
You can stage or undo an individual hunk when your cursor is in it:
- stage the hunk with
<Leader>hsor - undo it with
<Leader>hu.
To stage part of an additions-only hunk by:
- either visually selecting the part you want and staging with your mapping, e.g.
<Leader>hs; - or using a range with the
GitGutterStageHunkcommand, e.g.:42,45GitGutterStageHunk.
To stage part of any hunk:
- preview the hunk, e.g.
<Leader>hp; - move to the preview window, e.g.
:wincmd P; - delete the lines you do not want to stage;
- stage the remaining lines: either write (
:w) the window or stage via<Leader>hsor:GitGutterStageHunk.
Note the above workflow is not possible if you have opted in to preview hunks with Vim's popup windows.
See the FAQ if you want to unstage staged changes.
The. command will work with both these if you installrepeat.vim.
To set your own mappings for these, for example if you preferg-based maps:
nmapghs<Plug>(GitGutterStageHunk)nmapghu<Plug>(GitGutterUndoHunk)
And you can preview a hunk's changes with<Leader>hp. The location of the preview window is configured withg:gitgutter_preview_win_location (default'bo'). You can of course change this mapping, e.g:
nmapghp<Plug>(GitGutterPreviewHunk)
A hunk text object is provided which works in visual and operator-pending modes.
icoperates on all lines in the current hunk.acoperates on all lines in the current hunk and any trailing empty lines.
To re-map these, for example toih andah:
omapih<Plug>(GitGutterTextObjectInnerPending)omapah<Plug>(GitGutterTextObjectOuterPending)xmapih<Plug>(GitGutterTextObjectInnerVisual)xmapah<Plug>(GitGutterTextObjectOuterVisual)
If you don't want vim-gitgutter to set up any mappings at all, use this:
letg:gitgutter_map_keys=0
Finally, you can force vim-gitgutter to update its signs across all visible buffers with:GitGutterAll.
See the customisation section below for how to change the defaults.
Use theGitGutterDiffOrig command to open a vimdiff view of the current buffer, respectingg:gitgutter_diff_relative_to and:gitgutter_diff_base.
Use theGitGutterFold command to fold all unchanged lines, leaving just the hunks visible. Usezr to unfold 3 lines of context above and below a hunk.
ExecuteGitGutterFold a second time to restore the previous view.
Usegitgutter#fold#foldtext() to augment the defaultfoldtext() with an indicator of whether the folded lines have been changed.
setfoldtext=gitgutter#fold#foldtext()
For a closed fold with changed lines:
Default foldtext(): +-- 45 lines: abcdefgitgutter#fold#foldtext(): +-- 45 lines (*): abcdefYou can usegitgutter#fold#is_changed() in your ownfoldtext expression to find out whether the folded lines have been changed.
Call theGitGutterGetHunkSummary() function from your status line to get a list of counts of added, modified, and removed lines in the current buffer. For example:
" Your vimrcfunction!GitStatus()let [a,m,r]=GitGutterGetHunkSummary()returnprintf('+%d ~%d -%d',a,m,r)endfunctionsetstatusline+=%{GitStatus()}
You can customise:
- The sign column's colours
- Whether or not the sign column is shown when there aren't any signs (defaults to no)
- How to handle non-gitgutter signs
- The signs' colours and symbols
- Line highlights
- Line number highlights (only in Neovim 0.3.2 or higher)
- The diff syntax colours used in the preview window
- The intra-line diff highlights used in the preview window
- Whether the diff is relative to the index (default) or working tree.
- The base of the diff
- Extra arguments for
gitwhen runninggit diff - Extra arguments for
git diff - Key mappings
- Whether vim-gitgutter is on initially (defaults to on)
- Whether signs are shown (defaults to yes)
- Whether line highlighting is on initially (defaults to off)
- Whether line number highlighting is on initially (defaults to off)
- Whether vim-gitgutter runs asynchronously (defaults to yes)
- Whether to clobber or preserve non-gitgutter signs
- The priority of gitgutter's signs.
- Whether to use a floating/popup window for hunk previews
- The appearance of a floating/popup window for hunk previews
- Whether to populate the quickfix list or a location list with all hunks
Please note that vim-gitgutter won't override any colours or highlights you've set in your colorscheme.
Set theSignColumn highlight group to change the sign column's colour. For example:
" vim-gitgutter used to do this by default:highlight!linkSignColumnLineNr" or you could do this:highlightSignColumn guibg=whatever ctermbg=whatever
By default the sign column will appear when there are signs to show and disappear when there aren't. To always have the sign column, add to your vimrc:
" Vim 7.4.2201setsigncolumn=yes
GitGutter can preserve or ignore non-gitgutter signs. For Vim v8.1.0614 and later you can set gitgutter's signs' priorities withg:gitgutter_sign_priority, so gitgutter defaults to clobbering other signs. For Neovim v0.4.0 and later you can set an expanding sign column so gitgutter again defaults to clobbering other signs. Otherwise, gitgutter defaults to preserving other signs. You can configure this with:
letg:gitgutter_sign_allow_clobber=1
If you or your colourscheme has definedGitGutter* highlight groups, the plugin will use them for the signs' colours.
If you want the background colours to match the sign column, but don't want to update theGitGutter* groups yourself, you can get the plugin to do it:
letg:gitgutter_set_sign_backgrounds=1
If noGitGutter* highlight groups exist, the plugin will check theDiff* highlight groups. If their foreground colours differ the plugin will use them; if not, these colours will be used:
highlight GitGutterAdd guifg=#009900 ctermfg=2highlight GitGutterChange guifg=#bbbb00 ctermfg=3highlight GitGutterDelete guifg=#ff2222 ctermfg=1
To customise the symbols, add the following to your~/.vimrc:
letg:gitgutter_sign_added='xx'letg:gitgutter_sign_modified='yy'letg:gitgutter_sign_removed='zz'letg:gitgutter_sign_removed_first_line='^^'letg:gitgutter_sign_removed_above_and_below='{'letg:gitgutter_sign_modified_removed='ww'
Similarly to the signs' colours, set up the following highlight groups in your colorscheme or~/.vimrc:
GitGutterAddLine" default: links to DiffAddGitGutterChangeLine" default: links to DiffChangeGitGutterDeleteLine" default: links to DiffDeleteGitGutterChangeDeleteLine" default: links to GitGutterChangeLine, i.e. DiffChange
For example, in some colorschemes theDiffText highlight group is easier to read thanDiffChange. You could use it like this:
highlightlinkGitGutterChangeLineDiffText
NOTE: This feature requires Neovim 0.3.2 or higher.
Similarly to the signs' colours, set up the following highlight groups in your colorscheme or~/.vimrc:
GitGutterAddLineNr" default: links to CursorLineNrGitGutterChangeLineNr" default: links to CursorLineNrGitGutterDeleteLineNr" default: links to CursorLineNrGitGutterChangeDeleteLineNr" default: links to GitGutterChangeLineNr
Maybe you thinkCursorLineNr is a bit annoying. For example, you could useUnderlined for this:
highlightlinkGitGutterChangeLineNrUnderlined
To change the diff syntax colours used in the preview window, set up thediff* highlight groups in your colorscheme or~/.vimrc:
diffAdded" if not set: use GitGutterAdd's foreground colourdiffChanged" if not set: use GitGutterChange's foreground colourdiffRemoved" if not set: use GitGutterDelete's foreground colour
Note thediff* highlight groups are used in any buffer whose'syntax' isdiff.
To change the intra-line diff highlights used in the preview window, set up the following highlight groups in your colorscheme or~/.vimrc:
GitGutterAddIntraLine" default: gui=reverse cterm=reverseGitGutterDeleteIntraLine" default: gui=reverse cterm=reverse
For example, to useDiffAdd for intra-line added regions:
highlightlinkGitGutterAddIntraLineDiffAdd
By default diffs are relative to the index. How you can make them relative to the working tree:
letg:gitgutter_diff_relative_to='working_tree'
By default buffers are diffed against the index. However you can diff against any commit by setting:
letg:gitgutter_diff_base='<commit SHA>'
If you are looking at a previous version of a file with Fugitive (e.g. via:0Gclog), gitgutter sets the diff base to the parent of the current revision.
This setting is ignored when the diffs are relative to the working tree.
If you want to pass extra arguments togit when runninggit diff, do so like this:
letg:gitgutter_git_args='--git-dir-""'
If you want to pass extra arguments togit diff, for example to ignore whitespace, do so like this:
letg:gitgutter_diff_args='-w'
To disable all key mappings:
letg:gitgutter_map_keys=0
See above for configuring maps for hunk-jumping and staging/undoing.
If you use an alternative to grep, you can tell vim-gitgutter to use it here.
" Default:letg:gitgutter_grep='grep'
Addlet g:gitgutter_enabled = 0 to your~/.vimrc.
Addlet g:gitgutter_signs = 0 to your~/.vimrc.
Addlet g:gitgutter_highlight_lines = 1 to your~/.vimrc.
Addlet g:gitgutter_highlight_linenrs = 1 to your~/.vimrc.
By default diffs are run asynchronously. To run diffs synchronously instead:
letg:gitgutter_async=0
Addlet g:gitgutter_preview_win_floating = 1 to your~/.vimrc. Note that on Vim this prevents you staging (partial) hunks via the preview window.
On Neovim, the preview hunk command will move the cursor into the floating window if it is already open.
Either setg:gitgutter_floating_window_options to a dictionary of the options you want. This dictionary is passed directly topopup_create() (Vim) /nvim_open_win() (Neovim).
Or if you just want to override one or two of the defaults, you can do that with a file in anafter/ directory. For example:
" ~/.vim/after/vim-gitgutter/overrides.vimletg:gitgutter_floating_window_options['border']='single'
Addlet g:gitgutter_use_location_list = 1 to your~/.vimrc.
You can map an operator to do whatever you want to every line in a hunk.
Let's say, for example, you want to remove trailing whitespace.
function!CleanUp(...)ifa:0" opfunclet [first,last]= [line("'["),line("']")]elselet [first,last]= [line("'<"),line("'>")]endiffor lnuminrange(first,last)letline=getline(lnum)" clean up the text, e.g.:letline=substitute(line,'\s\+$','','')callsetline(lnum,line)endforendfunctionnmap<silent><Leader>x:set opfunc=CleanUp<CR>g@
Then place your cursor in a hunk and type\xic (assuming a leader of\).
Alternatively you could place your cursor in a hunk, typevic to select it, then:call CleanUp().
You can write a command to do whatever you want to every changed line in a file.
function!GlobalChangedLines(ex_cmd)for hunkinGitGutterGetHunks()for lnuminrange(hunk[2], hunk[2]+hunk[3]-1)letcursor=getcurpos()silent!execute lnum.a:ex_cmdcallsetpos('.',cursor)endforendforendfunctioncommand -nargs=1 GlinescallGlobalChangedLines(<q-args>)
Let's say, for example, you want to remove trailing whitespace from all changed lines:
:Gliness/\s\+$//
This is like:GitGutterNextHunk but when it gets to the last hunk in the buffer it cycles around to the first.
function!GitGutterNextHunkCycle()letline=line('.')silent! GitGutterNextHunkifline('.')==line1 GitGutterNextHunkendifendfunction
You can use:GitGutterQuickFix to load all hunks into the quickfix list or the current window's location list.
Alternatively, given that]c and[c jump from one hunk to the next in the current buffer, you can use this code to jump to the next hunk no matter which buffer it's in.
function!NextHunkAllBuffers()letline=line('.') GitGutterNextHunkifline('.')!=linereturnendifletbufnr=bufnr('')while1bnextifbufnr('')==bufnrreturnendifif!empty(GitGutterGetHunks())1 GitGutterNextHunkreturnendifendwhileendfunctionfunction!PrevHunkAllBuffers()letline=line('.') GitGutterPrevHunkifline('.')!=linereturnendifletbufnr=bufnr('')while1bpreviousifbufnr('')==bufnrreturnendifif!empty(GitGutterGetHunks())normal! G GitGutterPrevHunkreturnendifendwhileendfunctionnmap<silent>]c:call NextHunkAllBuffers()<CR>nmap<silent>[c:call PrevHunkAllBuffers()<CR>
How can I turn off realtime updates?
Add this to your vim configuration (in an/after/plugin directory):
" .vim/after/plugin/gitgutter.vimautocmd! gitgutterCursorHold,CursorHoldI
I turned off realtime updates, how can I have signs updated when I save a file?
If you really want to update the signs when you save a file, add this to your vimrc:
autocmdBufWritePost* GitGutter
Why can't I unstage staged changes?
This plugin is for showing changes between the buffer and the index (and staging/undoing those changes). Unstaging a staged hunk would require showing changes between the index and HEAD, which is out of scope.
Why are the colours in the sign column weird?
Your colorscheme is configuring theSignColumn highlight group weirdly. Please see the section above on customising the sign column.
What happens if I also use another plugin which uses signs (e.g. Syntastic)?
You can configure whether GitGutter preserves or clobbers other signs usingg:gitgutter_sign_allow_clobber. Set to1 to clobber other signs (default on Vim >= 8.1.0614 and NeoVim >= 0.4.0) or0 to preserve them.
Here are some things you can check:
- Try adding
let g:gitgutter_grep=''to your vimrc. If it works, the problem is grep producing non-plain output; e.g. ANSI escape codes or colours. - Verify
:echo system("git --version")succeeds. - Verify your git config is compatible with the version of git returned by the command above.
- Verify your Vim supports signs (
:echo has('signs')should give1). - Verify your file is being tracked by git and has unstaged changes. Check whether the plugin thinks git knows about your file:
:echo b:gitgutter.pathshould show the path to the file in the repo. - Execute
:sign place group=gitgutter; you should see a list of signs.- If the signs are listed: this is a colorscheme / highlight problem. Compare
:highlight GitGutterAddwith:highlight SignColumn. - If no signs are listed: the call to git-diff is probably failing. Add
let g:gitgutter_log=1to your vimrc, restart, reproduce the problem, and look at thegitgutter.logfile in the plugin's directory.
- If the signs are listed: this is a colorscheme / highlight problem. Compare
- If you use zsh, and you set
CDPATH, make sureCDPATHdoesn't include the current directory.
- Try reducing
updatetime, e.g.set updatetime=100. Note this also controls the delay before vim writes its swap file.
- Your terminal probably isn't reporting focus events. Either try installingTerminus or set
let g:gitgutter_terminal_reports_focus=0. For tmux, tryset -g focus-events onin your tmux.conf.
If this plugin has helped you, or you'd like to learn more about Vim, why not check out this screencast I wrote for PeepCode:
This was one of PeepCode's all-time top three bestsellers and is now available at Pluralsight.
Copyright Andrew Stewart, AirBlade Software Ltd. Released under the MIT licence.
About
A Vim plugin which shows git diff markers in the sign column and stages/previews/undoes hunks and partial hunks.
Topics
Resources
License
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Uh oh!
There was an error while loading.Please reload this page.
