VIM 会记录文本改变之前的状态。因此,你可以使用「撤销」操作 u 来取消更改,也可以通过「重做」操作 Ctrl + r 来恢复更改。
值得注意的是,VIM 采用 tree 数据结构来存储内容变更的历史记录,而不是采用 queue。你的每次改动都会成为存储为树的节点。而且,除了第一次改动(根节点),之后的每次改动都可以找到一个对应的父节点。每一个节点都会记录改动的内容和时间。其中,「分支」代表从任一节点到根节点的路径。当你进行了撤销操作,然后又输入了新的内容,这时候就相当于创建了分支。这个原理和 Git 中的 branch(分支)十分类似。
考虑以下这一系列按键操作:
ifoo<esc>
obar<esc>
obaz<esc>
u
oquux<exc>
那么现在,VIM 中会显示三行文本,分别是 "foo"、"bar" 和 "quux"。这时候,存储的树形结构如下:
foo(1)
/
bar(2)
/ \
baz(3) quux(4)
这个树形结构共包含四次改动,括号中的数字就代表时间顺序。
现在,我们有两种方式遍历这个树结构。一种叫「按分支遍历」,一种叫「按时间遍历」。
撤销 u 与重做 Ctrl + r 操作是按分支遍历。对于上面的例子,现在我们有三行字符。这时候按 u 会回退到 "bar" 节点,如果再按一次 u 则会回退到 "foo" 节点。这时,如果我们按下 Ctrl + r 就会前进至 "bar" 节点,再按一次就回前进至 "quux" 节点。在这种方式下,我们无法访问到兄弟节点(即 "baz" 节点)。
与之对应的是按时间遍历,对应的按键是 g-
和 g+
。对于上面的例子,按下 g-
会首先回退到 "baz" 节点。再次按下 g-
会回退到 "bar" 节点。
命令/按键 | 执行效果 |
---|---|
[count]u 或 :undo [count] |
回退到[count] 次改动之前 |
[count]<c-r> 或 :redo [count] |
重做[count] 次改动 |
U |
回退至最新的改动 |
[count]g- 或 :earlier [count]? |
根据时间回退到[count] 次改动之前。"?" 为 "s"、"m"、"h"、"d" 或 "f"之一。例如,:earlier 2d 会回退到两天之前。:earlier 1f 则会回退到最近一次文件保存时的内容 |
[count]g+ 或 :later [count]? |
类似g- ,但方向相反 |
内容变更记录会储存在内存中,当 VIM 退出时就会清空。如果需要持久化存储内容变更记录,请参阅 备份文件,交换文件,撤销文件以及 viminfo 文件的处理 章节的内容。
如果你觉得这一部分的内容难以理解,请参阅 undotree,这是一个可视化管理内容变更历史记录的插件。类似的还有 vim-mundo。
请参阅以下链接获取更多帮助:
:h undo.txt
:h usr_32