(→Comments: way to get undo history back?) |
(→Plugins: add some of the distinguishing features of undotree plugin) |
||
(14 intermediate revisions by 5 users not shown) | |||
Line 1: | Line 1: | ||
+ | {{TipNew |
||
− | {{TipProposed |
||
− | |id= |
+ | |id=1643 |
− | |previous= |
+ | |previous=1642 |
− | |next= |
+ | |next=1644 |
|created=May 11, 2010 |
|created=May 11, 2010 |
||
|complexity=basic |
|complexity=basic |
||
Line 11: | Line 11: | ||
|category2= |
|category2= |
||
}} |
}} |
||
− | Vim supports standard [[Undo and Redo|undo and redo]], and also supports ''undo branches'' which allow you to undo some changes, then make a new change, while keeping ''all'' changes available in the undo tree. This tip provides an overview of how undo branches can be used. |
+ | Vim supports standard [[Undo and Redo|undo and redo]], and also supports ''undo branches'' which allow you to undo some changes, then make a new change, while keeping ''all'' changes available in the undo tree. Vim makes this even more useful by allowing you to save the undo information in a file which is restored the next time you edit the same file. This tip provides an overview of how undo branches can be used. |
==What are undo branches?== |
==What are undo branches?== |
||
Vim 7.0 and later support undo branches. This feature prevents the loss of changes, even if you switch back to an earlier state of your text and start editing there. |
Vim 7.0 and later support undo branches. This feature prevents the loss of changes, even if you switch back to an earlier state of your text and start editing there. |
||
− | A '''change''' in this context is considered as all editing you have made while in insert mode, or a single editing command in normal or command-line mode. As soon as you leave insert mode a new '''change''' will start. It is important to leave insert mode so you will really create a new distinct change to which you can later move back, otherwise all changes that are done while you are in insert mode will be considered the same '''change'''. While in insert mode, you can also press Ctrl-G then < |
+ | A '''change''' in this context is considered as all editing you have made while in insert mode, or a single editing command in normal or command-line mode. As soon as you leave insert mode a new '''change''' will start. It is important to leave insert mode so you will really create a new distinct change to which you can later move back, otherwise all changes that are done while you are in insert mode will be considered the same '''change'''. While in insert mode, you can also press Ctrl-G then <code>u</code> to break the undo sequence and start a new change. In fact, it is probably a good idea to automatically do this in some situations, for example so you can [[VimTip86|undo one inserted line at a time]], so you can [[Recover from accidental Ctrl-U|recover if you change your mind after pressing Ctrl-U in normal mode]], or so you can [[Execute accidentally inserted commands|execute a normal-mode command you accidentally entered in insert mode]]. Note, that some commands (CTRL-G u is one of these) will break your insert mode edits into multiple changes. See {{help|ins-special-special}} for details. |
You can imagine the undo branches like a tree with the top node being the first change that you have made to your text. Whenever you undo some changes and make a new change you create a new node. |
You can imagine the undo branches like a tree with the top node being the first change that you have made to your text. Whenever you undo some changes and make a new change you create a new node. |
||
− | Using < |
+ | Using <code>u</code> in normal mode will undo your last change and move you through the tree upwards. In contrast redo (Ctrl-R) will move down through this tree of changes. This is the same, as was done before Version 7 was released and is backwards compatible with other vi clones. |
− | But you can also move through the changes in the order they were made. Thus < |
+ | But you can also move through the changes in the order they were made. Thus <code>g-</code> will move you to the previous change, regardless where it is situated in your undo tree. Further use of <code>g-</code> will move you to the chronological previous change. As <code>g-</code> moves backwards through the undo tree, <code>g+</code> will move forward through all changes until the final state is reached. |
− | Besides the use of < |
+ | Besides the use of <code>g+</code> and <code>g-</code> you can also use the ex-commands <code>:earlier</code> and <code>:later</code>. Both commands optionally accept either a count or a an amount of time that you want to move, thus |
− | ::< |
+ | ::<code>:earlier 10</code> |
will move 10 changes backwards through the undo tree, and |
will move 10 changes backwards through the undo tree, and |
||
− | ::< |
+ | ::<code>:earlier 1h</code> |
− | will move to the state of the buffer as it existed 1 hour ago (use < |
+ | will move to the state of the buffer as it existed 1 hour ago (use <code>s</code> for seconds, <code>m</code> for minutes, and <code>h</code> for hours), and then |
− | ::< |
+ | ::<code>:later 10</code> |
or |
or |
||
− | ::< |
+ | ::<code>:later 1h</code> |
will restore the buffer to the latest state after moving backwards to a previous state. |
will restore the buffer to the latest state after moving backwards to a previous state. |
||
− | With the addition of [[#Persistent undo|persistent undo]] in Vim 7.3, the ex-commands above also provide the ability to easily revisit the state of the buffer exactly as it was the last time it was saved to a file (or 2 saves ago, 3 saves ago, etc.) using, for example, < |
+ | With the addition of [[#Persistent undo|persistent undo]] in Vim 7.3, the ex-commands above also provide the ability to easily revisit the state of the buffer exactly as it was the last time it was saved to a file (or 2 saves ago, 3 saves ago, etc.) using, for example, <code>:earlier 1f</code>. |
==Example== |
==Example== |
||
Line 40: | Line 40: | ||
You start by entering insert mode and entering '1 ' and leaving insert mode. Now enter insert mode again and enter '2 ' and leave insert mode. And finally start insert mode again and enter '3' and leave insert mode again. Your buffer will now contain |
You start by entering insert mode and entering '1 ' and leaving insert mode. Now enter insert mode again and enter '2 ' and leave insert mode. And finally start insert mode again and enter '3' and leave insert mode again. Your buffer will now contain |
||
− | ::< |
+ | ::<code>1 2 3</code> |
You can always check the number of the most recent change with: |
You can always check the number of the most recent change with: |
||
− | ::< |
+ | ::<code>:echo changenr()</code> |
− | This will output < |
+ | This will output <code>3</code> since you have made 3 changes (started insert mode 3 times). |
− | Now press < |
+ | Now press <code>u</code> to undo one change, start insert mode again and change the buffer so it will look like this: |
− | ::< |
+ | ::<code>1 2 4</code> |
You have now branched from the previous version of your buffer and created a new undo branch. Using: |
You have now branched from the previous version of your buffer and created a new undo branch. Using: |
||
− | ::< |
+ | ::<code>:echo changenr()</code> |
will output 4. |
will output 4. |
||
− | If you press < |
+ | If you press <code>u</code> in normal mode you will move back to |
− | ::< |
+ | ::<code>1 2</code> |
− | A further undo using < |
+ | A further undo using <code>u</code> will change the buffer to |
− | ::< |
+ | ::<code>1</code> |
− | and if you press < |
+ | and if you press <code>u</code> a final time, you'll have an empty buffer again, as this is the state at which you started. You are now back before change 1 and |
− | ::< |
+ | ::<code>:echo changenr()</code> |
outputs 0. |
outputs 0. |
||
If you redo your changes using Ctrl-R, you will move to |
If you redo your changes using Ctrl-R, you will move to |
||
− | ::< |
+ | ::<code>1</code> |
then |
then |
||
− | ::< |
+ | ::<code>1 2</code> |
and finally |
and finally |
||
− | ::< |
+ | ::<code>1 2 4</code> |
− | Notice, that you never reached change number 3 in which the buffer contained '1 2 3'. You can however use the < |
+ | Notice, that you never reached change number 3 in which the buffer contained '1 2 3'. You can however use the <code>g-</code> and <code>:earlier</code> commands to move back to that change. So if you now press <code>g-</code> or <code>:earlier</code> your buffer looks like this: |
− | ::< |
+ | ::<code>1 2 3</code> |
− | If you know to which change you want to jump, you can also use < |
+ | If you know to which change you want to jump, you can also use <code>:undo</code> to jump to the specified change. |
Entering |
Entering |
||
− | ::< |
+ | ::<code>:undo 1</code> |
will put your buffer back at: |
will put your buffer back at: |
||
− | ::< |
+ | ::<code>1</code> |
==Undolevels option== |
==Undolevels option== |
||
− | The number of changes that are remembered is controlled by the {{help|prefix=no|'undolevels'}} option. This is a global option that defines how many changes for each buffer will be remembered and that you can travel back. So if you set it to < |
+ | The number of changes that are remembered is controlled by the {{help|prefix=no|'undolevels'}} option. This is a global option that defines how many changes for each buffer will be remembered and that you can travel back. So if you set it to <code>25</code>, you can at most undo 25 changes. If you set it to <code>-1</code> you will not be able to undo any changes! |
==Plugins== |
==Plugins== |
||
Line 95: | Line 95: | ||
The {{script|id=2932|text=histwin}} plugin provides an easy way to jump back to previous branches in your history. |
The {{script|id=2932|text=histwin}} plugin provides an easy way to jump back to previous branches in your history. |
||
− | It provides the command < |
+ | It provides the command <code>:UB</code> to open a new window listing the different branches of the changes made. On each item in the list, if you press Enter, you will move back to that state in the history tree of your buffer. |
− | Additionally, you can tag certain states using < |
+ | Additionally, you can tag certain states using <code>T</code> on the item. If you press <code>D</code>, a diff window is shown allowing you to review all changes that have been made between your current state and the selected state. And as some kind of funny feature, you can even let Vim replay the changes that have been made from the beginning. |
− | After installing the plugin, read its help on configuration and usage by entering < |
+ | After installing the plugin, read its help on configuration and usage by entering <code>:help histwin.txt</code>. |
===Gundo=== |
===Gundo=== |
||
[[File:gundo_screenshot.png|thumb|left|alt=Gundo screenshot|A screenshot of the Gundo plugin]] |
[[File:gundo_screenshot.png|thumb|left|alt=Gundo screenshot|A screenshot of the Gundo plugin]] |
||
− | The [http:// |
+ | The {{script|id=3304|text=Gundo plugin}} requires a [http://www.python.org Python] installation and a [[Build_Python-enabled_Vim_on_Windows_with_MinGW|Vim built with python support]]. Gundo provides a graphical tree view of the entire undo tree, including the stored persistent undo data. Below the tree view is a contextual diff preview of each change made to make it much easier to find the exact state you are looking for. Although it does not provide some of the features of histwin (like diffing to a specific state or tagging specific versions), the tree view and diff preview make it very easy to use. |
− | |||
− | Gundo requires a [[Build_Python-enabled_Vim_on_Windows_with_MinGW|Vim built with python support]]. |
||
{{clear}} |
{{clear}} |
||
+ | |||
+ | ===Others=== |
||
+ | *{{script|id=2141|text=Undo Branches Explorer}} |
||
+ | *{{script|id=4177|text=undotree}} offers a tree view similar to Gundo implemented in pure vimscript. This plugin additionally offers in-text highlighting of changes, automatic updating of the tree view, and extra informational markers on some of the tree nodes. |
||
==Persistent undo== |
==Persistent undo== |
||
The persistent undo feature is now officially available with Vim 7.3. |
The persistent undo feature is now officially available with Vim 7.3. |
||
− | Before Vim 7.3 (or when Vim 7.3 is compiled without support for persistent undo) whenever you end Vim (or force the reloading of a buffer), you lose all undo history and so may accidentally lose data. The persistent undo feature (which should be included with a normal, big |
+ | Before Vim 7.3 (or when Vim 7.3 is compiled without support for persistent undo) whenever you end Vim (or force the reloading of a buffer), you lose all undo history and so may accidentally lose data. The persistent undo feature (which should be included with a normal, big or huge build of Vim) provides the possibility to store the undo history persistently in a file, and reload the undo tree from this file whenever you edit the file associated with the undo information. |
− | To make use of the feature, you need to set < |
+ | To make use of the feature, you need to set <code>'undofile'</code>: |
− | ::< |
+ | ::<code>:set undofile</code> |
− | You can then use the new commands < |
+ | You can then use the new commands <code>:wundo</code> to write the undo history to the file and <code>:rundo</code> to read the undo history back. For each file that is edited, the undo tree will be saved in a separate file in the same directory to the file, that you edited as .filename.un~ similar to the way swap files are saved. If you like to save all undo-files in a separate direcotry, you can set the <code>'undodir'</code> option to specify the directory that will contain all undo files. Whenever persistent undo is enabled the stored undo information will be read back when you start editing that file again. |
− | Additionally Vim 7.3 allows to jump back to previous save states of your file. This can be done by using :earlier <nr>f and :later <nr>f where <nr> is the number of file write. The different number of file-writes can be seen in the saved column of the :undolist command. For |
+ | Additionally Vim 7.3 allows to jump back to previous save states of your file. This can be done by using <code>:earlier <nr>f</code> and <code>:later <nr>f</code> where <code><nr></code> is the number of file write. The different number of file-writes can be seen in the saved column of the <code>:undolist</code> command. For example <code>:earlier 1f</code> would go back to the state where the text was, when it was last saved and <code>:later 1f</code> would move in the undo tree to the next newer state, where the file was saved. |
− | The new option < |
+ | The new option <code>'undoreload'</code> now determines, if the text state will be saved, before the buffer is reloaded using e.g. <code>:e!</code>. This is set by default to the value of 10,000. This means the buffer contents will be stored in the undo tree, if the buffer contains fewer than 10,000 lines. For example if you edit a simple file, <code>:echo changenr()</code> will output, the current position in the undo tree. If you now reload the buffer using <code>:e!</code> and output <code>:echo changenr()</code>, you will notice, that a new change was created (but only, if the buffer contained less lines than the option of <code>'undoreload'</code> specifies or the value of <code>'undoreload'</code> is negative). |
However, note that if a file is modified externally without Vim, Vim will not be able to read the undo history back when you start editing the file again and the undo tree information will be lost. There is no way to get it back. |
However, note that if a file is modified externally without Vim, Vim will not be able to read the undo history back when you start editing the file again and the undo tree information will be lost. There is no way to get it back. |
||
Line 142: | Line 144: | ||
--[[User:Fritzophrenic|Fritzophrenic]] 04:26, October 20, 2010 (UTC) |
--[[User:Fritzophrenic|Fritzophrenic]] 04:26, October 20, 2010 (UTC) |
||
+ | ::This should just[TM] work |
||
+ | ::[[User:Chrisbra|Chrisbra]] 20:54, October 20, 2010 (UTC) |
||
+ | |||
+ | :::I wonder if you could make a FileChangedShell command that would somehow keep the undo data if it detected an outside change. --[[User:Fritzophrenic|Fritzophrenic]] 20:52, January 7, 2011 (UTC) |
Revision as of 16:48, 25 September 2012
created May 11, 2010 · complexity basic · author Chrisbra · version 7.0
Vim supports standard undo and redo, and also supports undo branches which allow you to undo some changes, then make a new change, while keeping all changes available in the undo tree. Vim makes this even more useful by allowing you to save the undo information in a file which is restored the next time you edit the same file. This tip provides an overview of how undo branches can be used.
What are undo branches?
Vim 7.0 and later support undo branches. This feature prevents the loss of changes, even if you switch back to an earlier state of your text and start editing there.
A change in this context is considered as all editing you have made while in insert mode, or a single editing command in normal or command-line mode. As soon as you leave insert mode a new change will start. It is important to leave insert mode so you will really create a new distinct change to which you can later move back, otherwise all changes that are done while you are in insert mode will be considered the same change. While in insert mode, you can also press Ctrl-G then u
to break the undo sequence and start a new change. In fact, it is probably a good idea to automatically do this in some situations, for example so you can undo one inserted line at a time, so you can recover if you change your mind after pressing Ctrl-U in normal mode, or so you can execute a normal-mode command you accidentally entered in insert mode. Note, that some commands (CTRL-G u is one of these) will break your insert mode edits into multiple changes. See :help ins-special-special for details.
You can imagine the undo branches like a tree with the top node being the first change that you have made to your text. Whenever you undo some changes and make a new change you create a new node.
Using u
in normal mode will undo your last change and move you through the tree upwards. In contrast redo (Ctrl-R) will move down through this tree of changes. This is the same, as was done before Version 7 was released and is backwards compatible with other vi clones.
But you can also move through the changes in the order they were made. Thus g-
will move you to the previous change, regardless where it is situated in your undo tree. Further use of g-
will move you to the chronological previous change. As g-
moves backwards through the undo tree, g+
will move forward through all changes until the final state is reached.
Besides the use of g+
and g-
you can also use the ex-commands :earlier
and :later
. Both commands optionally accept either a count or a an amount of time that you want to move, thus
:earlier 10
will move 10 changes backwards through the undo tree, and
:earlier 1h
will move to the state of the buffer as it existed 1 hour ago (use s
for seconds, m
for minutes, and h
for hours), and then
:later 10
or
:later 1h
will restore the buffer to the latest state after moving backwards to a previous state.
With the addition of persistent undo in Vim 7.3, the ex-commands above also provide the ability to easily revisit the state of the buffer exactly as it was the last time it was saved to a file (or 2 saves ago, 3 saves ago, etc.) using, for example, :earlier 1f
.
Example
Suppose you start a new change.
You start by entering insert mode and entering '1 ' and leaving insert mode. Now enter insert mode again and enter '2 ' and leave insert mode. And finally start insert mode again and enter '3' and leave insert mode again. Your buffer will now contain
1 2 3
You can always check the number of the most recent change with:
:echo changenr()
This will output 3
since you have made 3 changes (started insert mode 3 times).
Now press u
to undo one change, start insert mode again and change the buffer so it will look like this:
1 2 4
You have now branched from the previous version of your buffer and created a new undo branch. Using:
:echo changenr()
will output 4.
If you press u
in normal mode you will move back to
1 2
A further undo using u
will change the buffer to
1
and if you press u
a final time, you'll have an empty buffer again, as this is the state at which you started. You are now back before change 1 and
:echo changenr()
outputs 0.
If you redo your changes using Ctrl-R, you will move to
1
then
1 2
and finally
1 2 4
Notice, that you never reached change number 3 in which the buffer contained '1 2 3'. You can however use the g-
and :earlier
commands to move back to that change. So if you now press g-
or :earlier
your buffer looks like this:
1 2 3
If you know to which change you want to jump, you can also use :undo
to jump to the specified change.
Entering
:undo 1
will put your buffer back at:
1
Undolevels option
The number of changes that are remembered is controlled by the 'undolevels' option. This is a global option that defines how many changes for each buffer will be remembered and that you can travel back. So if you set it to 25
, you can at most undo 25 changes. If you set it to -1
you will not be able to undo any changes!
Plugins
Using only the built-in commands, it can be difficult to navigate the undo tree to find your desired state. There are several plugins available to make this easier.
Histwin
The histwin plugin provides an easy way to jump back to previous branches in your history.
It provides the command :UB
to open a new window listing the different branches of the changes made. On each item in the list, if you press Enter, you will move back to that state in the history tree of your buffer.
Additionally, you can tag certain states using T
on the item. If you press D
, a diff window is shown allowing you to review all changes that have been made between your current state and the selected state. And as some kind of funny feature, you can even let Vim replay the changes that have been made from the beginning.
After installing the plugin, read its help on configuration and usage by entering :help histwin.txt
.
Gundo
The Gundo plugin requires a Python installation and a Vim built with python support. Gundo provides a graphical tree view of the entire undo tree, including the stored persistent undo data. Below the tree view is a contextual diff preview of each change made to make it much easier to find the exact state you are looking for. Although it does not provide some of the features of histwin (like diffing to a specific state or tagging specific versions), the tree view and diff preview make it very easy to use.
Others
- Undo Branches Explorer
- undotree offers a tree view similar to Gundo implemented in pure vimscript. This plugin additionally offers in-text highlighting of changes, automatic updating of the tree view, and extra informational markers on some of the tree nodes.
Persistent undo
The persistent undo feature is now officially available with Vim 7.3. Before Vim 7.3 (or when Vim 7.3 is compiled without support for persistent undo) whenever you end Vim (or force the reloading of a buffer), you lose all undo history and so may accidentally lose data. The persistent undo feature (which should be included with a normal, big or huge build of Vim) provides the possibility to store the undo history persistently in a file, and reload the undo tree from this file whenever you edit the file associated with the undo information.
To make use of the feature, you need to set 'undofile'
:
:set undofile
You can then use the new commands :wundo
to write the undo history to the file and :rundo
to read the undo history back. For each file that is edited, the undo tree will be saved in a separate file in the same directory to the file, that you edited as .filename.un~ similar to the way swap files are saved. If you like to save all undo-files in a separate direcotry, you can set the 'undodir'
option to specify the directory that will contain all undo files. Whenever persistent undo is enabled the stored undo information will be read back when you start editing that file again.
Additionally Vim 7.3 allows to jump back to previous save states of your file. This can be done by using :earlier <nr>f
and :later <nr>f
where <nr>
is the number of file write. The different number of file-writes can be seen in the saved column of the :undolist
command. For example :earlier 1f
would go back to the state where the text was, when it was last saved and :later 1f
would move in the undo tree to the next newer state, where the file was saved.
The new option 'undoreload'
now determines, if the text state will be saved, before the buffer is reloaded using e.g. :e!
. This is set by default to the value of 10,000. This means the buffer contents will be stored in the undo tree, if the buffer contains fewer than 10,000 lines. For example if you edit a simple file, :echo changenr()
will output, the current position in the undo tree. If you now reload the buffer using :e!
and output :echo changenr()
, you will notice, that a new change was created (but only, if the buffer contained less lines than the option of 'undoreload'
specifies or the value of 'undoreload'
is negative).
However, note that if a file is modified externally without Vim, Vim will not be able to read the undo history back when you start editing the file again and the undo tree information will be lost. There is no way to get it back.
References
See also
Comments
The persistent undo section says,
- However, note that if a file is modified externally without Vim, Vim will not be able to read the undo history back when you start editing the file again and the undo tree information will be lost. There is no way to get it back.
I do not think this is true in all cases. Can't you get it back by closing the buffer, restoring the file to the old state (for example using your revision control software) and reloading the buffer? Is this too complicated to even bother mentioning?
--Fritzophrenic 04:26, October 20, 2010 (UTC)
- This should just[TM] work
- Chrisbra 20:54, October 20, 2010 (UTC)
- I wonder if you could make a FileChangedShell command that would somehow keep the undo data if it detected an outside change. --Fritzophrenic 20:52, January 7, 2011 (UTC)