Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
78 commits
Select commit Hold shift + click to select a range
3990835
fix(git): disable GPG signatures for log/show commands (#540)
Naxdy Nov 1, 2025
75cf106
fix(path): only replace $ with env var if value defined (#557)
bryankenote Nov 8, 2025
b5697de
fix(git): show untracked files when comparing working tree (#587)
KEY60228 Nov 15, 2025
bc08967
fix(git): handle merge-base failure during rebase --root (#577)
ButterSus Nov 22, 2025
2e106b7
feat: add mini.icons support as file icons provider (#571)
folliehiyuki Nov 29, 2025
1b386ce
feat: add close keymaps (q, <esc>) to commit log panel (#482)
kevintraver Dec 6, 2025
e144466
fix: prevent crash due to nil target in sync_scroll (#550)
dlyongemallo Oct 26, 2025
f728b1f
fix(actions): copy hash to unnamed register instead of clipboard (#606)
jecaro Oct 26, 2025
3e27322
feat: add `:DiffviewToggle` command (#517)
cosmicbuffalo Jun 27, 2024
478f726
docs: add `:DiffviewToggle` docs (#517)
cosmicbuffalo Jun 27, 2024
1451a46
feat(git): add `--merge-base` option (#590)
KEY60228 Jul 14, 2025
47b9d9e
fix(help_panel): prevent nil index error on first line
dlyongemallo Jan 17, 2026
7aab651
fix(lib): ensure bootstrap runs before accessing DiffviewGlobal
dlyongemallo Jan 10, 2026
0c48e02
fix(hl): ensure diff.vim highlights are loaded before linking
dlyongemallo Jan 25, 2026
ec3349d
feat(ui): add trailing slash to folder names in file tree
dlyongemallo Jan 11, 2026
0c944fc
feat(config): add file_panel.show option to hide panel by default
dlyongemallo Jan 24, 2026
bc90682
perf(git): set GIT_OPTIONAL_LOCKS=0 to reduce lock contention
dlyongemallo Jan 18, 2026
59237ad
feat(actions): add set_layout for specific layout selection
dlyongemallo Jan 24, 2026
fb4788b
fix(hl): remove redundant FilePanelFileName definition
dlyongemallo Jan 31, 2026
be1a708
fix(hl): use DiffviewFolderSign for FileHistory fold indicators
dlyongemallo Jan 11, 2026
b4994a6
feat(config): add commit_subject_max_length option
dlyongemallo Jan 10, 2026
4ccbaa2
docs: add recommended keymaps and workflow tips
dlyongemallo Jan 24, 2026
1f07a2b
feat(ui): show "Working tree clean" when no changes
dlyongemallo Jan 4, 2026
d46abb7
feat(config): add cycle_layouts option to customise layout cycling
dlyongemallo Jan 17, 2026
0aa2015
docs: add Telescope integration examples
dlyongemallo Jan 10, 2026
3c1c201
feat(config): add always_show_sections option
dlyongemallo Jan 11, 2026
4ea11e6
feat(actions): add open_file_external to open files with system app
dlyongemallo Jan 4, 2026
c78b3c1
feat(actions): add diff_against_head to compare HEAD with history ent…
dlyongemallo Nov 1, 2025
49c3984
fix: preserve tree collapsed state on tab switch (#582)
dlyongemallo Oct 18, 2025
431ee89
fix: prevent scrollbind/cursorbind from persisting after close (#330)
dlyongemallo Dec 10, 2023
5ec3cde
feat(config): add show_branch_name option for file panel (#542)
dlyongemallo Dec 8, 2024
5f1603a
feat: add loading indicator in file panel (#570)
dlyongemallo Aug 10, 2025
bdbe846
feat: show file count on collapsed folders (#597)
dlyongemallo Dec 21, 2025
40ccf1d
docs: add diffopt tip for better diff display (#526)
dlyongemallo May 17, 2025
81a8d41
feat(actions): add open_in_new_tab to duplicate diffview (#432)
dlyongemallo Jun 15, 2024
045881c
docs: clarify revision argument behaviour (#514)
dlyongemallo Oct 6, 2024
ef57357
fix: prevent coroutine failure when view closes during update (#528)
dlyongemallo Nov 30, 2025
2843ba6
feat(config): add "auto" position option for panels (#536)
dlyongemallo Apr 26, 2025
ed13882
fix: disable context plugins in diff buffers for scrollbind alignment
dlyongemallo Jan 4, 2026
cd8e3cc
fix: preserve panel cursor position when switching tabs (#457)
dlyongemallo Dec 28, 2025
61ace22
feat(config): add hide_merge_artifacts option
dlyongemallo Jan 4, 2026
e41367c
feat(config): add auto_close_on_empty option
dlyongemallo Jan 11, 2026
0fb4d16
feat: extend restore_entry to work on directories (#186)
dlyongemallo Oct 27, 2024
0875d9c
feat(config): add date_format option for file history panel (#525)
dlyongemallo Mar 1, 2025
318ce58
feat(file-history): cycle within commit on prev/next (#566)
przepompownia Mar 26, 2025
8f55f8d
feat(actions): add open_commit_in_browser action (#476)
dlyongemallo Jun 22, 2025
4c8a82e
fix: handle global-only options in winopts save
dlyongemallo Jan 11, 2026
e528fd9
fix: disable context plugins on local buffers in diff view
dlyongemallo Jan 18, 2026
4a1fb3f
fix: wrap timer callbacks in `vim.schedule`
dlyongemallo Jan 24, 2026
f27bd55
docs: clarify treesitter-context setup
dlyongemallo Jan 10, 2026
a67a808
fix: limit custom fold creation to prevent UI freeze (#552)
dlyongemallo Jul 13, 2025
77c99d2
fix: prevent buffer flash when opening diffview (#509)
dlyongemallo Jan 12, 2025
3b4d355
fix: nil guards in view update (#395)
dlyongemallo Jan 4, 2025
1d95741
feat: use high foldlevel and jump to first diff
dlyongemallo Jan 3, 2026
0bca5b6
fix: use prepend for `winhl` (#515)
dlyongemallo Nov 10, 2024
a07ce58
fix: always show folder icons (#579)
dlyongemallo Jun 22, 2025
e91acae
fix: disable inlay hints in non-LOCAL buffers
dlyongemallo Jan 18, 2026
a1c2327
feat(config): add `status_icons` option (#607)
anonymousgrasshopper Jan 22, 2026
06bad44
docs: clarify LSP diagnostics behaviour in diff buffers (#580)
dlyongemallo Jul 27, 2025
2c3456f
docs: add FAQ for customising keymaps to avoid conflicts (#518)
dlyongemallo Aug 30, 2025
07be128
chore: normalize keymap description punctuation
dlyongemallo Jan 25, 2026
af12567
fix(git): only show untracked files when comparing index vs working tree
dlyongemallo Jan 10, 2026
9edde82
chore: improvements from PR integrations
dlyongemallo Feb 4, 2026
bac5b73
docs: add fork notice to README
dlyongemallo Feb 4, 2026
f9462f8
fix(keymaps): register commit_log_panel keymaps in init_buffer instea…
dlyongemallo Feb 5, 2026
580f49f
feat(file-history): add stat_style config for stat bars (#2)
dlyongemallo Feb 6, 2026
57ec564
feat(config): add file_panel.sort_file custom comparator (#3)
dlyongemallo Feb 6, 2026
6bf56a3
fix(keymaps): save and restore buffer-local keymaps on attach/detach …
dlyongemallo Feb 6, 2026
e0a6611
refactor: replace deprecated nvim_buf_get/set_option with vim.bo (#5)
dlyongemallo Feb 6, 2026
7009c40
feat(config): add clean_up_buffers option (#6)
dlyongemallo Feb 6, 2026
8ef5221
feat: add --selected-row option for cursor positioning (#7)
dlyongemallo Feb 6, 2026
c5b9200
feat(config): add rename_threshold for git rename detection (#9)
dlyongemallo Feb 6, 2026
773e15b
feat(config): allow diff1_plain layout in standard diff views (#8)
dlyongemallo Feb 6, 2026
ecdb020
feat(file-history): add commit_format config for entry display (#10)
dlyongemallo Feb 6, 2026
5b03610
[breaking change] bump minimum required nvim version to 0.10 (#11)
dlyongemallo Feb 10, 2026
03c74bb
docs(readme): add diffchar.vim recommendation, reorganize plugin sect…
dlyongemallo Feb 11, 2026
a8226b7
docs(readme): note diffchar.vim flag for character-level diff highlig…
dlyongemallo Feb 12, 2026
6422b22
docs: remove fork notice for upstream PR
dlyongemallo Feb 12, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/bug_report.yml
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ body:
})

vim.opt.termguicolors = true
vim.cmd("colorscheme " .. (vim.fn.has("nvim-0.8") == 1 and "habamax" or "slate"))
vim.cmd("colorscheme habamax")

-- ############################################################################
-- ### ADD INIT.LUA SETTINGS THAT ARE _NECESSARY_ FOR REPRODUCING THE ISSUE ###
Expand Down
208 changes: 206 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ for any git rev.

- Git ≥ 2.31.0 (for Git support)
- Mercurial ≥ 5.4.0 (for Mercurial support)
- Neovim ≥ 0.7.0 (with LuaJIT)
- [nvim-web-devicons](https://github.com/nvim-tree/nvim-web-devicons) (optional) For file icons
- Neovim ≥ 0.10.0 (with LuaJIT)
- [nvim-web-devicons](https://github.com/nvim-tree/nvim-web-devicons) or [mini.icons](https://github.com/echasnovski/mini.nvim/blob/main/readmes/mini-icons.md) (optional) for file icons

## Installation

Expand Down Expand Up @@ -503,6 +503,45 @@ restore the file to the state from the left side of the diff (key binding `X`
from the file panel by default). The current state of the file is stored in the
git object database, and a command is echoed that shows how to undo the change.

## Recommended Keymaps

These keymaps are commonly used patterns for working with diffview:

```lua
-- Toggle diffview open/close
vim.keymap.set('n', '<leader>dv', function()
if next(require('diffview.lib').views) == nil then
vim.cmd('DiffviewOpen')
else
vim.cmd('DiffviewClose')
end
end, { desc = 'Toggle Diffview' })

-- Diff working directory
vim.keymap.set('n', '<leader>do', '<cmd>DiffviewOpen<cr>', { desc = 'Diffview open' })
vim.keymap.set('n', '<leader>dc', '<cmd>DiffviewClose<cr>', { desc = 'Diffview close' })

-- File history
vim.keymap.set('n', '<leader>dh', '<cmd>DiffviewFileHistory %<cr>', { desc = 'File history (current file)' })
vim.keymap.set('n', '<leader>dH', '<cmd>DiffviewFileHistory<cr>', { desc = 'File history (repo)' })

-- Visual mode: history for selection
vim.keymap.set('v', '<leader>dh', "<Esc><cmd>'<,'>DiffviewFileHistory --follow<CR>", { desc = 'Range history' })

-- Single line history
vim.keymap.set('n', '<leader>dl', '<cmd>.DiffviewFileHistory --follow<CR>', { desc = 'Line history' })

-- Diff against main/master branch (useful before merging)
vim.keymap.set('n', '<leader>dm', function()
-- Try main first, fall back to master
local handle = io.popen('git rev-parse --verify main 2>/dev/null')
local result = handle:read('*a')
handle:close()
local branch = result ~= '' and 'main' or 'master'
vim.cmd('DiffviewOpen ' .. branch)
end, { desc = 'Diff against main/master' })
```

## Tips and FAQ

- **Hide untracked files:**
Expand All @@ -524,5 +563,170 @@ git object database, and a command is echoed that shows how to undo the change.
- **Q: How do I jump between hunks in the diff?**
- A: Use `[c` and `]c`
- `:h jumpto-diffs`
- **Compare against merge-base (PR-style diff):**
- `DiffviewOpen origin/main...HEAD --merge-base`
- Shows only changes introduced since branching.
- **Use with [Neogit](https://github.com/NeogitOrg/neogit):**
- Configure Neogit with `integrations = { diffview = true }` for seamless
integration.
- **Trace line evolution:**
- Visual select lines, then `:'<,'>DiffviewFileHistory --follow`
- Or for single line: `:.DiffviewFileHistory --follow`
- **Better diff display (changes shown as add+delete instead of modification):**
- Set Neovim's `diffopt` to use a better algorithm:
- `vim.opt.diffopt:append { "algorithm:histogram" }`
- Alternatives: `algorithm:patience` or `algorithm:minimal`
- This affects how Neovim's built-in diff mode displays changes.
- **Understanding revision arguments:**
- `DiffviewOpen HEAD~5` compares HEAD~5 to working tree (all changes since)
- `DiffviewOpen HEAD~5..HEAD` compares HEAD~5 to HEAD (excludes working tree changes)
- `DiffviewOpen HEAD~5^..HEAD~5` shows changes within that single commit
- For viewing a specific commit's changes, use `DiffviewFileHistory` instead
- **LSP diagnostics in diff buffers:**
- Diagnostics only appear for the working tree (LOCAL) side of diffs.
- When comparing commits (e.g., `DiffviewOpen main..HEAD`), neither side is the
working tree, so LSP won't attach to those buffers.
- To see diagnostics, compare against the working tree: `DiffviewOpen main`
(not `main..HEAD`). The right side will show your current files with
diagnostics.
- Inlay hints are automatically disabled for non-working-tree buffers to
prevent position mismatch errors.
- **VSCode-style character-level highlighting:**
- Pair diffview with
[diffchar.vim](https://github.com/rickhowe/diffchar.vim) for precise
character/word-level diff highlights. See
[Companion Plugins > Recommended](#recommended) for setup details.
- **Customizing default keymaps to avoid conflicts:**
- The default keymaps (`<leader>e`, `<leader>b`, `<leader>c*`) may conflict
with your configuration. Override them in your setup:
```lua
require("diffview").setup({
keymaps = {
view = {
-- Use localleader instead to avoid conflicts
{ "n", "<localleader>e", actions.focus_files },
{ "n", "<localleader>b", actions.toggle_files },
-- Or disable specific mappings
{ "n", "<leader>e", false },
},
},
})
```

## Companion Plugins

### Recommended

- **[diffchar.vim](https://github.com/rickhowe/diffchar.vim) (VSCode-style character-level highlighting):**
- diffchar.vim enhances diff mode with precise character and word-level
highlighting. It automatically activates in diff mode, adding a second layer
of highlights on top of Neovim's built-in line-level `DiffChange`
backgrounds. This gives VSCode-style dual-layer highlighting: light
backgrounds for changed lines plus fine-grained highlights for the exact
characters that differ.
- diffchar.vim works with diffview out of the box. Install the plugin and open
a diff — no additional configuration is needed. You may want to enable
visual indicators next to deleted characters to get VSCode-style
character-level diffs, or disable diffchar's default keymaps (`<leader>g`,
`<leader>p`) if they conflict with your mappings:
```lua
{
'rickhowe/diffchar.vim',
config = function()
-- Use bold/underline on adjacent chars instead of virtual blank columns.
vim.g.DiffDelPosVisible = 1

-- Disable diffchar default keymaps.
-- See: https://github.com/rickhowe/diffchar.vim/issues/21
vim.cmd([[
nmap <Leader>g <Nop>
nmap <Leader>p <Nop>
]])
end,
}
```
- diffchar supports multiple diff granularities via `g:DiffUnit`: `'Char'`
(character-level), `'Word1'` (words separated by non-word characters),
`'Word2'` (whitespace-delimited words), and custom delimiter patterns. It
also offers multi-colour matching via `g:DiffColors` to visually correlate
corresponding changed units across windows.

- **[Telescope](https://github.com/nvim-telescope/telescope.nvim) integration:**
- You can use Telescope to select branches or commits for diffview:
```lua
-- Diff against a branch selected via Telescope
vim.keymap.set('n', '<leader>db', function()
require('telescope.builtin').git_branches({
attach_mappings = function(_, map)
map('i', '<CR>', function(prompt_bufnr)
local selection = require('telescope.actions.state').get_selected_entry()
require('telescope.actions').close(prompt_bufnr)
vim.cmd('DiffviewOpen ' .. selection.value)
end)
return true
end,
})
end, { desc = 'Diffview branch' })

-- File history for a commit selected via Telescope
vim.keymap.set('n', '<leader>dC', function()
require('telescope.builtin').git_commits({
attach_mappings = function(_, map)
map('i', '<CR>', function(prompt_bufnr)
local selection = require('telescope.actions.state').get_selected_entry()
require('telescope.actions').close(prompt_bufnr)
vim.cmd('DiffviewOpen ' .. selection.value .. '^!')
end)
return true
end,
})
end, { desc = 'Diffview commit' })
```

### Known Issues

Some plugins may conflict with diffview's window layout or keymaps. Here are
known issues and workarounds:

- **lens.vim (automatic window resizing):**
- [camspiers/lens.vim](https://github.com/camspiers/lens.vim) automatically
resizes windows based on focus, which interferes with diffview's layout.
- **Workaround:** Configure lens.vim to exclude diffview filetypes:
```lua
-- In your lens.vim or lens.nvim config:
vim.g['lens#disabled_filetypes'] = {
'DiffviewFiles', 'DiffviewFileHistory', 'DiffviewFileHistoryPanel'
}
```

- **[nvim-treesitter-context](https://github.com/nvim-treesitter/nvim-treesitter-context):**
- Context plugins that show code context at the top of windows can cause
visual scrollbind misalignment.
- **Workaround:** Configure the plugin to disable itself for diffview buffers
using the `on_attach` callback:
```lua
require('treesitter-context').setup({
on_attach = function(buf)
return not vim.b[buf].ts_context_disable
end,
})
```

- **[vim-markdown](https://github.com/preservim/vim-markdown) (preservim/vim-markdown):**
- vim-markdown creates folds for markdown sections. Older versions of
diffview set `foldlevel=0` which collapsed these sections, hiding diff
content. This has been fixed by setting `foldlevel=99` by default.
- If you still experience issues, you can manually set foldlevel in hooks:
```lua
require('diffview').setup({
hooks = {
diff_buf_win_enter = function(bufnr, winid, ctx)
if ctx.layout_name == 'diff2_horizontal' then
vim.wo[winid].foldlevel = 99
end
end,
},
})
```

<!-- vim: set tw=80 -->
16 changes: 12 additions & 4 deletions doc/diffview.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,13 @@ for any git rev.

USAGE *diffview-usage*

Quick-start: `:DiffviewOpen` to open a Diffview that compares against the
index.
Quick-start: `:DiffviewOpen` or `:DiffviewToggle` to open a Diffview that
compares against the index.

You can have multiple Diffviews open, tracking different git revs. Each Diffview
opens in its own tabpage. To close and dispose of a Diffview, call either
`:DiffviewClose` or `:tabclose` while a Diffview is the current tabpage.
opens in its own tabpage. To close and dispose of a Diffview, call
`:DiffviewClose`, `:DiffviewToggle`, or `:tabclose` while a Diffview is the
current tabpage.
Diffviews are automatically updated:

• Every time you enter a Diffview
Expand Down Expand Up @@ -370,6 +371,13 @@ COMMANDS *diffview-commands*
*:DiffviewClose*
:DiffviewClose Close the active Diffview.

*:DiffviewToggle*
:DiffviewToggle [git-rev] [options] [ -- {paths...}]

Alias for `:DiffviewOpen` when the current tabpage is not a Diffview,
otherwise acts as an alias for `:DiffviewClose`. Accepts the same
arguments as `:DiffviewOpen`.

*:DiffviewToggleFiles*
:DiffviewToggleFiles Toggles the file panel.

Expand Down
19 changes: 18 additions & 1 deletion doc/diffview_defaults.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,28 @@ DEFAULT CONFIG *diffview.defaults*
enhanced_diff_hl = false, -- See |diffview-config-enhanced_diff_hl|
git_cmd = { "git" }, -- The git executable followed by default args.
hg_cmd = { "hg" }, -- The hg executable followed by default args.
use_icons = true, -- Requires nvim-web-devicons
use_icons = true, -- Requires nvim-web-devicons or mini.icons
show_help_hints = true, -- Show hints for how to open the help panel
watch_index = true, -- Update views and index buffers when the git index changes.
hide_merge_artifacts = false, -- Hide merge artifact files (*.orig, *.BACKUP.*, *.BASE.*, *.LOCAL.*, *.REMOTE.*)
auto_close_on_empty = false, -- Close diffview when the last file is staged/resolved
icons = { -- Only applies when use_icons is true.
folder_closed = "",
folder_open = "",
},
status_icons = { -- Configure icons for git status letters.
["A"] = "A", -- Added
["?"] = "?", -- Untracked
["M"] = "M", -- Modified
["R"] = "R", -- Renamed
["C"] = "C", -- Copied
["T"] = "T", -- Type changed
["U"] = "U", -- Unmerged
["X"] = "X", -- Unknown
["D"] = "D", -- Deleted
["B"] = "B", -- Broken
["!"] = "!", -- Ignored
},
signs = {
fold_closed = "",
fold_open = "",
Expand Down Expand Up @@ -60,6 +75,7 @@ DEFAULT CONFIG *diffview.defaults*
width = 35,
win_opts = {},
},
show = true, -- Show the file panel when opening Diffview.
},
file_history_panel = {
log_options = { -- See |diffview-config-log_options|
Expand All @@ -81,6 +97,7 @@ DEFAULT CONFIG *diffview.defaults*
height = 16,
win_opts = {},
},
date_format = "auto", -- Date format: "auto" | "relative" | "iso"
},
commit_log_panel = {
win_config = {}, -- See |diffview-config-win_config|
Expand Down
Loading