如果文件在Vim之外被编辑,如何保留撤销历史记录

6

如果文件在编辑器外部被编辑,Vim undofile 将被清除。

我如何才能使文件能够回退到旧版本,即使它已经在Vim之外被编辑?这种情况是否可能实现?


如果您查看:h persistent-undo,您会发现撤销文件是加密的。我猜如果文件在外部被更改,vim无法撤消该加密。 - FDinoff
这有点令人惊叹,几乎到了过度杀伐的地步。 - Steven Lu
嗨,看到这个帖子中的评论和答案都是从2013年6月7日开始的,也就是现在已经快10年了,我想问一下您是否在这些年里找到了解决方案?即使存在加密问题,我相信vim仍然可以将文件的新状态视为新更改,就像我手动选择整个文件内容并粘贴新内容一样。 - adamency
在这10年中,我不记得遇到过这个问题,除了最初促使我写这个问题的那个问题。但现在我对它再次感到好奇。我的更新可能不会令您满意...由于我最近从头开始使用Lua重新创建了我的nvim配置,在您的提示下,我将仅将“backup”和“backupdir”设置重新添加到我的vim配置中。虽然这不会恢复由于外部更改而导致的损坏的undofile历史记录,但是在某个地方拥有过去的备份已经足以缓解这个问题,因为这对我来说很少见。 - Steven Lu
@adamency 我在下面发布了自己的答案,我写得可能有点多,但对你的考虑可能会有用。 - Steven Lu
3个回答

2
你可以使用vim备份:
set backup                   " enable backup file
set backupdir=~/.vim/backups " backup directory

如果您想在外部编辑后恢复,请使用vim保存的最后一个备份,但这与undofile不同。如vim维基所述:

然而,请注意,如果文件在没有使用Vim的情况下被外部修改,则在您再次开始编辑该文件时,Vim将无法读取撤消历史记录,并且撤消树信息将丢失。没有办法找回它。


这是因为撤销文件是一种“增量差异”风格的格式/编码吗?我的脚本实际上会备份,所以我没问题,只是有点烦恼不能将其恢复到之前的状态。 - Steven Lu

0

看看我自2015年以来一直在使用的设置:

let vimtmp = $HOME . '/.tmp/' . getpid()
silent! call mkdir(vimtmp, "p", 0700)
let &backupdir=vimtmp
let &directory=vimtmp
set backup

我正在考虑将这个引入到我的新的2023 lua nvim配置中。

这里有几个做我所做的事情的属性:

  • 每个vim进程都将交换和备份存储到以其pid命名的新目录中
  • 实际上,这使我避免了遇到很多令人烦恼的现在已经有了我的新鲜配置对话框swapfile found, do you want to edit anyway or abort。这是因为一个新进程将在其自己的pid特定目录中获得directory,而vim像任何典型的编辑器一样工作,当你保存时文件会被覆盖。这是预期的。现在,在系统崩溃的情况下,我可以选择查找所有过去可能留下的交换和备份文件。实际上,在近10年的实践中,我从未利用过这一点,但拥有它感觉很好。
  • 虽然这没有解决由外部文件修改事件引起的undofile“损坏”问题,但至少在概念上,我甚至不知道这可能是如何发生的,除非内部撤消机制获得智能来检测此类事件并插入非差异基础的日志记录。当然...这应该完成,因为vim CAN识别文件何时被外部修改,例如我在我的配置中有一个au FileChangedShell * echo "Warning: File changed on disk!!"。这在实践中运作良好,并始终立即捕获更改,但是阅读vim自己的关于此aucmd的文档时,我们不应该期望它总是检测到实际文件更改...

所以我还在犹豫是否要将这种行为延续到我的新配置中,但它确实很诱人。我可以说的是,在编辑文件之前,vim/nvim检查是否存在交换文件对我没有帮助,因为在实践中,每当文件被更改时(通常是vim的第二个实例),它总是能够立即重新加载缓冲区与文件状态相同。因此,在vim中,我永远不会真正看到一些旧版本的文件,这会很烦人(默认的交换检查行为旨在防止这种情况发生)。

我认为接下来几天我要做的是考虑实际行为,这意味着找出是否有一个更现代的基于lua的替代撤销树插件,我一直非常满意现在使用的是mbbill/undotree。此外,我还想调查我已经使用了十年的配置如何处理更改的文件,是否以良好的方式管理超过外部文件更改事件的撤消,并且是否存在简单的方法来改进它。

除了上面粘贴的配置之外,我还设置了

set undodir=~/.tmp
set undolevels=10000
set undofile

这意味着,尽管我的交换文件和备份位置被隔离在特定于pid的文件中(因此,对于每个vim实例都是新鲜的),但undofile却不是。我觉得我的经验是这样的,这个功能非常好用(撤销过去的外部更改实际上向我显示了外部更改,只是不像我可能想要的那样漂亮(某种差异),但其行为足够正确,让我感到满意)。但这只是从记忆中得出的结论,因为这种情况并不经常发生。通常只有当我打开两个vim并交替编辑同一个文件时才会发生,因为我很健忘。


-1

如果您指的是通过字母u调用的撤销操作,在我的系统上,即使我看到了由undofile(@%)返回的文件,我也不认为我能够删除它。这不会影响我使用u键的能力。

如果您指的是其他人/程序修改了您当前在vim中打开的文件,则应该收到通知文件已更改。选项有OKLoad File。如果您按下OK,可以按下u键并强制写入:w!。这将清除其他人/程序所做的更改。

如果以上两个答案都不适用于您,请详细说明。


我有一个脚本,使用 sed 对文件进行修改(将其中的所有行注释掉),然后用 vim 将其呈现给我进行编辑。如果我使用错误的参数运行我的脚本,它会执行此修改并清除未保存的历史记录。 - Steven Lu
@cforbish,您误解了,undofile可以在会话之间持久化保存,OP的问题就是在这个背景下提出的。 - adamency

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接