# mbbill/undotree: browsing Vim's undo branches without disk writes

> undotree exposes Vim's internal undo tree as a navigable panel, so you can jump between diverging edit branches instead of only undoing backwards. It is a pure Vim script plugin, and the README states it never writes to disk.

**mbbill/undotree** — The undo history visualizer for VIM

- Repository: https://github.com/mbbill/undotree
- Website: http://www.vim.org/scripts/script.php?script_id=4177
- Stars: 4,545 · Forks: 120
- Language: Vim Script
- License: BSD-3-Clause
- Published: 2026-09-23 · Updated: 2026-09-23 · Language: en
- Canonical page: https://hysenlabs.com/projects/mbbill-undotree

## The editing problem undotree is built around

Vim does not keep a single linear undo stack. The README describes the internal model plainly: Vim stores the entire edit history for each file as one monolithic tree. Make change A, make change B, go back to A and make change C, and B is not gone. It still exists on a side branch. Plain :undo and :redo walk one path through that tree and give you no way to see the others.

undotree draws the tree in a panel and lets you move around it. The README's own example is exactly the A, B, C case. The audience is narrow and specific: people who already edit in Vim or Neovim and who have felt the loss of a state they thought undo had destroyed. If you have never hit that wall, the plugin solves a problem you have not had yet. If you have, it is the difference between a recoverable edit and a re-typed one.

## How the panel reads the undo tree

The plugin is written in pure Vim script and, per the README, only runs when needed. It does not maintain a parallel history of its own. It reads the tree Vim already holds for the current buffer and renders it, which is why the panel appears instantly and why there is no index to rebuild.

The README is explicit about what switching states does to your file: undotree never saves your data and never writes to disk. It modifies the current buffer temporarily, in the same way auto-completion plugins do, so any change it makes is reversible with a single click. That is the design decision worth noting. A tool that rewrote files to move between states would be dangerous; this one stays inside the buffer.

Markers carry the state. Each change has a sequence number shown before its timestamp. The current state is marked as `> number <`. The state that `:redo` or `<ctrl-r>` would restore is marked `{ number }`. The most recent change is `[ number ]`. Saved changes are marked `s`, and a capital `S` marks the most recent saved change. The history is sorted by timestamps. Pressing `?` inside the undotree window opens quick help, which is the fastest way to learn the markers without leaving the editor.

## Installing undotree and your first branch switch

The README gives Vim's built-in package manager as the first route. The four commands below create the package directory, clone the repository into it, and generate the help tags so `:help undotree` works. After the last command Vim exits immediately; nothing else is printed.

```bash
mkdir -p ~/.vim/pack/mbbill/start
cd ~/.vim/pack/mbbill/start
git clone https://github.com/mbbill/undotree.git
vim -u NONE -c "helptags undotree/doc" -c q
```

If you use a plugin manager instead, the README lists three. For Vundle the line is `Plugin 'mbbill/undotree'`, for Vim-Plug it is `Plug 'mbbill/undotree'`, and for Packer it is `use 'mbbill/undotree'`. Install with `:PluginInstall`, `:PlugInstall` or `:PackerSync` respectively, matching the manager you use.

The command that opens the panel is `:UndotreeToggle`. The README suggests mapping it, using F5 as the example, and gives the Lua equivalent for Neovim.

```vim
nnoremap <F5> :UndotreeToggle<CR>
```

```lua
vim.keymap.set('n', '<leader><F5>', vim.cmd.UndotreeToggle)
```

To see the branch behaviour, open a file, make a change, make a second change, then undo back to the first state and type something different. Toggle the panel and the abandoned second change should still be listed on its own branch. Select it and the buffer returns to that state. Because the README states the plugin does not write to disk, this move is safe to try on a file you have not saved.

## Persistent undo is Vim's feature, not undotree's

This is the point most likely to be misread. undotree does not persist anything. The README says it directly: while tools such as undotree can aid in accessing historical states, it does not offer a permanent solution. Vim's own persistent undo does that, saving the undo history to a separate file on disk that is incremental and keeps every change, similar to Git.

To turn it on, the README shows a block that checks for the feature, points `undodir` at a directory, creates that directory if missing, and enables `undofile`.

```vim
if has("persistent_undo")
   let target_path = expand('~/.undodir')

    if !isdirectory(target_path)
        call mkdir(target_path, "p", 0700)
    endif

    let &undodir=target_path
    set undofile
endif
```

If you only want the history kept for the file you have open right now, the README offers `:UndotreePersistUndo` instead of the global setting. The storage cost is real: the README notes that undo history files grow and that undotree provides an option to clean them up. The size of the history itself is governed by Vim's `undolevels`, which the README points you to with `:help 'undolevels'`.

## Where undotree stops being the right tool

The plugin is Vim-only. The repository ships autoload/, doc/, plugin/ and syntax/ directories for Vim, and the README's install instructions are Vim and Neovim instructions. The related searches for undotree vscode and undotree emacs have nothing in this repository behind them. If you do not edit in Vim or Neovim, there is no version of this plugin for you.

The second boundary is session lifetime. Without `undofile` enabled, the undo tree lives in memory and is gone when the process exits. undotree can only show you the tree that currently exists. The README is candid that this is a limitation of the approach rather than something the plugin works around.

There is also a Vim version note in the README: on Vim 9.0 or higher it points to a separate plugin, undotree.vim by mao-yining, for an experience written in Vim9 script. That is a pointer to another project, not a deprecation of this one, but it is worth knowing before you commit to a configuration.

Finally, the debug path is a file rather than a flag. Creating `~/undotree_debug.log` turns logging on and Vim appends to it; deleting the file turns logging off. If you leave that file in place, expect a growing log.

## How undotree differs from an undo-tree style UI elsewhere

The closest comparison is the undo-tree package in Emacs, which is the reference implementation of this idea in another editor. Both expose a non-linear undo history as a tree you can navigate. The difference is where the tree comes from. Emacs builds and maintains its own undo-tree structure on top of the editor's undo list. undotree does not build a structure at all; Vim already stores the whole edit history per file as a tree, and the plugin renders that existing tree. That is why the README can promise the plugin never writes to disk and only touches the buffer temporarily.

The practical consequence is that undotree inherits Vim's semantics exactly. Whatever `undolevels` allows is what you get, and persistent undo behaves the way Vim's persistent undo behaves. A tool that kept its own parallel history would have to reconcile the two. This one has nothing to reconcile.

Within Vim itself, the alternative is doing it by hand. Vim's `:undo` and `:redo` walk one path, and `:help undo-tree` describes the underlying structure, but there is no built-in command that lists the branches and lets you pick one. That gap is what the plugin fills.

## Maintenance, licence and upgrade cost

The repository is not archived, and the last push was on 2026-03-08. The most recent tagged release listed is rel_6.1 from 2019-10-12, with rel_6.0 in 2018 and rel_5.0 in 2015. The README advises pulling the master branch, which is consistent with that release cadence: the tags are old, and the branch is where changes land. Anyone pinning to a tag should understand that they are pinning to a 2019 snapshot.

The code is pure Vim script, so there is no build step, no compiled artifact and no runtime dependency to upgrade. Updating means pulling the branch or re-running your plugin manager's update command. The main upgrade risk is configuration drift, since the README links the option list to a specific line in plugin/undotree.vim rather than documenting each option inline; check that list after an update if you have set anything beyond the default.

The licence is BSD-3-Clause per the repository, and the README states BSD. That is a permissive licence, which generally means you can use, modify and redistribute the plugin with the copyright notice and disclaimer retained. This is a description of the licence text, not legal advice; read LICENSE in the repository if the terms matter to your distribution.

## Conclusion

Adopt undotree if you edit in Vim or Neovim and regularly undo past the point where you branched, because it is the only way the README describes to see and jump between non-linear undo states. Do not adopt it if you rely on an editor other than Vim or Neovim; the related searches for undotree vscode and undotree emacs have no answer in this repository, which ships only autoload/, doc/, plugin/ and syntax/ for Vim. Before installing, verify your Vim or Neovim build reports has("persistent_undo") if you want history across sessions, and read the option list the README links at plugin/undotree.vim line 27.

## FAQ

### How do I install undotree in Vim or Neovim?

The README gives Vim's built-in package manager as one route: create ~/.vim/pack/mbbill/start, clone the repository into it, then run helptags on undotree/doc. Plugin manager users can instead add Plugin 'mbbill/undotree', Plug 'mbbill/undotree' or use 'mbbill/undotree' depending on the manager.

### Does undotree work with LazyVim or lazy.nvim?

The README does not document LazyVim or lazy.nvim. It lists Vundle, Vim-Plug and Packer as example plugin managers, and the plugin itself is pure Vim script, so any manager that can pull the master branch can install it.

### How is undotree different from Vim's normal undo?

Vim's :undo and :redo walk one path through the edit history. undotree displays the whole tree, including branches left behind when you undo and then make a different change, and lets you switch to any of them.

## Sources

- [License: BSD-3-Clause](https://github.com/mbbill/undotree/blob/master/LICENSE)
- [mbbill/undotree on GitHub](https://github.com/mbbill/undotree)
- [Project website](http://www.vim.org/scripts/script.php?script_id=4177)
- [README](https://github.com/mbbill/undotree/blob/master/README.md)
- [Releases](https://github.com/mbbill/undotree/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/mbbill-undotree
