This plugin is primarily a visualizer for Neovim’s internal undo tree.
All undo-related functionality is provided by Neovim itself.
See :h undo.txt and :h undolevels for more details.
| Legacy | Compact |
|---|---|
![]() |
![]() |
- nvim 0.11.0 or above
- Visualizes Neovim’s internal undo tree structure
- Diff preview between the current undo state and the state under the cursor
- Commands for clearing undo history and renaming file
- Two tree styles
- Multiple window layouts
- Self-contained lazy loading
- Live update while editing the file
- Multiple undotree instances
I think it a bit odd to keep undotree open while editing. The plugin is designed for when you want to undo/redo to or copy something from a state outside your current branch, you open the tree, do the operation, and then close it to continue editing the file.
Using Neovim's built-in package manager:
mkdir -p ~/.config/nvim/pack/github/start/
cd ~/.config/nvim/pack/github/start/
git clone https://github.com/jiaoshijie/undotree.gitUsing vim-plug
Plug 'jiaoshijie/undotree'Using lazy.nvim
{
"jiaoshijie/undotree",
opts = {
-- your options
},
keys = { -- load the plugin only when using it's keybinding:
{ "<leader>u", "<cmd>lua require('undotree').toggle()<cr>" },
},
}Note
If you’re fine with the default settings, you don’t need to call the setup function — only the keymaps or user commands need to be configured.
Configuration can be passed to the setup function. Here is an example with the default settings:
require('undotree').setup({
float_diff = true, -- set this `true` will disable layout option
--- @type "left_bottom" | "left_left_bottom"
layout = "left_bottom", -- {left}_{bottom} {left}_{left_bottom}
--- @type "left" | "right"
position = "left",
window = {
width = 0.25, -- the `undotree` window width percentage related to the editor
height = 0.25, -- the `preview`(not floating) window height percentage related to the editor
border = "rounded", -- float window
},
ignore_filetype = {},
--- @type "compact" | "legacy"
parser = "compact",
keymaps = {
["j"] = "move_next",
["k"] = "move_prev",
["gj"] = "move2parent",
["J"] = "move_change_next",
["K"] = "move_change_prev",
["<cr>"] = "action_enter",
["p"] = "enter_diffbuf", -- this can switch between preview and undotree window
["q"] = "quit",
["S"] = "update_undotree_view",
},
})You can directly use :lua require('undotree').toggle() for toggling undotree panel,
or set the following keymaps for convenient using:
vim.keymap.set('n', '<leader>u', require('undotree').toggle, { noremap = true, silent = true })
-- or
vim.keymap.set('n', '<leader>uo', require('undotree').open, { noremap = true, silent = true })
vim.keymap.set('n', '<leader>uc', require('undotree').close, { noremap = true, silent = true })Or if you want to use user command, the following code snippet creates an
Undotree <subcommand> command with three options: toggle, open and close.
vim.api.nvim_create_user_command('Undotree', function(opts)
local args = opts.fargs
local cmd = args[1]
local cb = require("undotree")[cmd]
if cmd == "setup" or cb == nil then
vim.notify("Invalid subcommand: " .. (cmd or ""), vim.log.levels.ERROR)
else
cb()
end
end, {
nargs = 1,
complete = function(arg_lead)
return vim.tbl_filter(function(cmd)
return vim.startswith(cmd, arg_lead)
end, { "toggle", "open", "close" })
end,
desc = "Undotree command with subcommands: toggle, open, close",
})| Mappings | Action |
|---|---|
j |
Move cursor to next undo node |
k |
Move cursor to previous undo node |
gj |
Jump to the parent of the current node |
J |
Move to next node and apply that state |
K |
Move to previous node and apply that state |
Enter |
Undo to this state |
p |
Switch focus between undotree and preview window |
q |
Quit undotree (also works in preview window) |
S |
Force re-parse of Neovim's internal undo history |
Caution
These commands are local to the undotree buffer, not the file buffer, but the operations are performed on the file buffer.
UndotreeClearHistory: Clear the entire in-memory undo history- To persist this change, write the buffer to disk with
:w; Neovim will clear the undo file on disk. - To discard this change, delete the buffer without writing and reopen the file.
- To persist this change, write the buffer to disk with
UndotreeRename: Rename the file while preserving undo history- The target path may be either a filename or a directory (like
mv). - If the target file already exists, you will be asked to confirm the overwrite.
- The target path may be either a filename or a directory (like
Bug reports are welcome.
If you encounter a parser bug:
- Please include a screenshot showing how the undotree ascii graph is rendered.
- If you are able to share the file:
- Use
:wundo {file_name}.undoto generate the undo file. - Attach both the file and its undo file to the issue.
- Use
- If you are not able to share the file:
- Run
:echo undotree()and include the output (Neovim’s internal undo tree table) in the issue.
- Run
MIT

