Vim undo branches

Dayne Dayne (57)
0

You probably already know how to use vim's basic undo and redo features. For a quick refresher, read this short tutorial on how to use vim redo and undo. Vim's undo branches are a little more complex but extremely powerful. They allow you to recover lost changes in vim even if you undo them and make new changes.

Here's how they work. Every "change" you make in vim results in another node in your undo history. Before you knew about undo branches, you could think of this history as strictly linear. I make 5 distinct changes, and I can go back in time up to 5 times. I can then go forward in time 5 times. But what if I go back 3 changes and then make a new change? Are those previous 3 changes lost forever?

In order to understand this concept, you need to know how vim stores these changes under the hood—a tree structure. Each node of the tree corresponds to one change. As you make changes and navigate up and down the tree using u undo and ctrl-r redo, vim builds out this tree keeping a numeric index associated with each change. This allows you to use the g- and g+ commands to traverse through the history in chronological order rather than just through the one branch of the tree you're currently in.

This gets confusing quickly, so let's jump into some examples.

Posted in these interests:

vim
PRIMARY
23 guides

Every time you do something in insert mode then leave back to command mode, vim counts that as one change. There are a few notable exceptions that we'll cover later, but for now, we'll keep it simple. So let's go into insert mode and type one sentence.

Here's my document:

Hello World!

And here's a visualization of vim's undo tree:

-- Hello World![1]

My first change has an index of 1, great! We can confirm this by running the following command: :echo changenr() to see a result of 1.

Now let's insert a few more changes, exiting insert mode after each line as you might in the real world while writing code.

Here's my new document:

Happy Howchooing!
Dear reader, I hope this guide is helpful.
It is my goal in life to help you learn more and become more productive.
Enjoy!

Our tree:

-- Happy Howchooing![1] -- Dear reader...[2] -- It is my goal...[3] -- Enjoy! [4]

And our current change number is 4.

Let's say we weren't happy with the last couple of changes so we're going to undo them. Pressing u to undo twice, we end up with the following:

Happy Howchooing!
Dear reader, I hope this guide is helpful.

Our tree:

-- Happy Howchooing![1] -- Dear reader...[2] -- It is my goal...[3] -- Enjoy! [4]
                                    ^
                                    |

Notice that our tree isn't gone, we're just pointing to a lower change number now. The reason our change number isn't 4 or 6 is because pressing u undo or ctrl-r redo navigates through the change history effectively moving us up and down the tree. Running :echo changenr() will reveal that we are indeed at change number 2.

Now we realize we wanted to keep that great line about my goal so let's redo with ctrl-r. You can guess how that affects our status.

Hello World!
Dear reader, I hope this guide is helpful.
It is my goal in life to help you learn more and become more productive.

Our tree:

-- Hello World[1] -- Dear reader...[2] -- It is my goal...[3] -- Enjoy! [4]
                                                           ^
                                                           |

Since all we did was navigate through history, only our change number changes. Everything else remains the same.

Here's the fun part. Now we're going to continue making some changes for a while. Let's say we add 3 new lines.

Happy Howchooing!
Dear reader, I hope this guide is helpful.
It is my goal in life to help you learn more and become more productive.
If it doesn't help you, I have failed
I hope you will let me know how I can improve
Have a good day!

Our tree:

                                             -- If it doesn't... [5] -- I hope you... [6] -- Have a good... [7]
                                           /
-- Happy...[1] -- Dear...[2] -- It is...[3] 
                                           \                     
                                             -- Enjoy! [4]

Let's talk about what happened. We continued editing from change number 3. Vim saw that we had changes with a number higher than 3 so vim branched off of the node with index 3. Everything that happened after 3 now lives in one of two branches.

At this point, u undo and ctrl-r redo will take us up and down our current branch, never navigating the old branch with the "Enjoy" text. In order to access that, we'll have to use some new commands.

You have two options at your disposal for navigating through chronological history instead of simple history navigation. The g- and g+ key or the :earlier <num> and :later <num> commands.

Keeping with our example, let's say we've changed our minds, and we want the old "Enjoy" text back. We know that was a few "changes" ago but we don't know exactly which change number. In this case, it's convenient to just keep mashing g- until you see what you want.

Let's say we hit g- 3 times.

The first 2 times behave just like our u undo command so we're left with this:

Happy Howchooing!
Dear reader, I hope this guide is helpful.
It is my goal in life to help you learn more and become more productive.
If it doesn't help you, I have failed

and a change number of 5.

The 3rd time we use g- though, instead of navigating up the tree, we navigate to change number 4:

Happy Howchooing!
Dear reader, I hope this guide is helpful.
It is my goal in life to help you learn more and become more productive.
Enjoy!

Our last line appears to be swapped with an old line. Here's one last visualization of the tree to drive the point home:

                                             -- If it doesn't... [5] -- I hope you... [6] -- Have a good... [7]
                                           /
-- Happy...[1] -- Dear...[2] -- It is...[3] 
                                           \                     
                                             -- Enjoy! [4]
                                                        ^
                                                        |

u undo and ctrl-r redo will now navigate up and down this branch, and we can get back to the other branch using our chronological history commands, for example :later 3 will get us to change number 7.

Vim's undo branches are one of those features that you really have to understand what's going on behind the scenes before you can take advantage of it. That said, it really is an underrated feature that is worth taking the time to learn.

When you've mastered it, look into some vim plugins like Gundo or Mundo that help you visualize the tree and navigate it more easily.

Dayne's profile pictureDayne
Joined in 2015
Software engineer, co-founder of Howchoo, and renaissance man. Lifelong amateur woodworker, espresso mechanic, freestyle lyricist, drummer, artist, runner, coffee roaster, electrical engineer, gamer, inventor, churner, psychoanalyst, photographer, pizza chef, pit master, audiophile, guitarist, entrepreneur, dad, yogi, cyclist, and barista.
Share this guide!
Related to this guide:
3 ways to use tabs in vim
Vim tabs can be a great way to visualize which files you currently have open. Many vim users get bogged down by them and either end up working too hard to use them or give up altogether.
Dayne's profile picture DayneView
In these interests: vim
Vim redo and undo
Learn how to undo and redo changes using vim. If you are brand new to vim, learn more about the basics in this intro to vim guide.
Dayne's profile picture DayneView
In these interests: vim
Crash course in vim text objects
Once you learn to think in text objects, you'll never be the same
Dayne's profile picture DayneView
In these interests: vim
People also read:
Vim is a powerful tool. I often paste raw data into Vim in order to format it in a specific way, and sometimes I need to clean up the file by removing many blank lines.
One of the strengths of Vim is that it's highly customizable. And while remapping keys is possible, we often want to create shortcuts without changing the default key bindings.
If you find yourself highlighting text in Vim with your mouse to copy and paste it elsewhere, stop. There's a better way, using the yank command, to copy text into your clipboard on macOS or Windows.
Basic vim commands
Because you've accidentally opened Vim and don't know how to exit
Vim is amazing. Well, Python is doing all the work, but I still like Vim. Learn how to format JSON in Vim like a pro with this short guide! tl;dr Paste your json, and run this in vim normal mode. :%!
Tabs are evil. This guide will show you how to convert tabs to spaces in Vim.
Need to change the case of characters to all caps or all lowercase? This is easily done using Vim. This guide will show you how to change the case of characters in Vim.
Posted in these interests:
vim
vim
PRIMARY
Discuss this guide: