Vim undo branches

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.

1

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.

2

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.

3

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.

4

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.

5

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.

6

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.