Undo recovery from swap file in vim - vim

Right before committing a major change, I accidentally "recovered" the file from an old and outdated swap file in vim. My changes seem to be gone. I've tried exploring the undo tree but large chunks of changes are still missing. Is there anyway I can undo the recover operation or am I doomed?

The following works for me to recover the file, with undo history as well:
Assume you have my_file, that has some persistent undo history + unsaved changes in .my_file.swp
Open file with vim, and press r to get the recovery version
Save recovery version to temporary location e.g. :w /tmp/%
Close without saving (:q!). Open file again, and press d to delete swap file
Optional: compare /tmp/my_file and my_file to make sure you want the recovered version
Manually add changes from /tmp/my_file (e.g. ggdG and :r /tmp/% )
This can probably be simplified, but this works for me.
PS: This does not give you the undo history for the changes between the on-disk and recovered version of the file, that appears as one big edit in the history.

After accidentally recovering the file you can simply type :q! to exit vim without saving the recovered changes - this will leave your original file intact and the swap file where it is.
The next time you open the file, you'll see the same prompt - press D to delete the swap file, or abort and find it manually (and possibly delete any other swap files in the same location)

I just tried this myself (with persistent undo enabled; Vim version 7.3.823). The old changes were still showing (in :undolist, though I usually use a plugin like Gundo or Undotree to visualize it), but when attempting to restore, I get
E438: u_undo: line numbers wrong
Seems like Vim cannot handle this situation. Note that you've been warned; the recovery explictly warns:
Recovery completed. You should check if everything is OK.
E308: Warning: Original file may have been changed

Related

What are some use cases of :e in Vim?

I was reading :help :edit but I really don't understand the following sentence:
This is useful to re-edit the current file, when it has been changed outside of Vim
And what does start all over mean in :help :edit!?
This is useful if you want to start all over again
Could anyone please provide some use cases of them?
"Changed outside of Vim" means that the file that you're editing has been written to by another program. :e will load the latest version, and :e! will do that even if you have unsaved changes.
Loading the current file from the file system is useful if you're following a log, or viewing a generated file that gets updated when you run :make and other situations.
One use for this is to throw away the changes you've made since the last save with :w and go back to the most recent saved version. Which is to say, it's not necessary for the file to have changed behind Vim's back for this to be useful. Although Vim has enough undo depth that you can usually undo your way to back to the unmodified state, it's cumbersome. You can easily "overshoot" and then have to redo. The status line shows you whether the file is [Modified] or not, but as you undo, it gets overwritten with information about each undo, so you have to use Ctrl-G to re-display the file status.
I had no idea :e by itself with no argument did this re-loading, by the way; I have been using :e% for years!

How can I permanently save the last code until next restart in vim

So my question is if I am writing some code in vim & then want to go back 20 minutes earlier, then I type :earlier 20m in vim. But this doesn't work if I exit the vim once or even reboot by system. I understand that it is stored into the temporary registers and once vim restarts, it cleans the whole register buffers. But is there any way I can save the last changes & apply some undo mechanisms. Actually I work on some big project files & if something wrong occurs, I can not go back.
In Vim 7.3 or later, you can use an undo file.
Put this in your .vimrc.
set undofile
By default this will save 100 actions to undo. If you want more, you can set it manually by adding this to your .vimrc, with whatever number you want:
set undolevels=100
Persistent undo will create undo files in the same directories as the files you actually work on. If you want to put these in a separate directory so they don't clutter your filesystem, add this to your .vimrc:
set undodir=~/.vim/undo
Then, you need to actually make the directory. From the command line:
mkdir ~/.vim/undo
I would look into using version control instead of relying on vim's persistent undo to track changes in your projects.

undo reloading new buffer with vim

I had a file open with gvim and it asked me if I wanted to reload the current buffer because it detected a newer version of the file. I accepted, but it turns out the new buffer is not what I want. Is there a way to recover the old buffer? The file on disk (and the swp file, which I viewed with vim -r) contains the new buffer) unfortunately.
If your buffer had fewer lines than the 'undoreload' settings, then its content will be stored in the undotree just before it was reloaded. This means, that a simple u or g- should get your buffer contents back. A plugin like my histwin plugin or the famous Gundo or undotree plugin could be helpful as well.
Note, this needs a Vim of at least version 7.3 or newer to work. Older Vims didn't store the buffer state on reloading.
Try u (undo; if you’ve made changes since reloading, repeat until the old version shows up).
I am in terminal Vim, but I don’t think that should make a difference here. I opened a test file with Vim in one terminal tab, went to a new tab and edited it there, saved that, switched back to the first tab, ran :e to reload the file, and then switched it back to the last version I had opened in the tab with u.
I have something like this is my .vimrc
" Backup stuff
set backupdir=~/.vim/backup
set directory=~/.vim/swap
set undodir=~/.vim/undo
I can help with cases like this were you accidentally overwrite your local changes and you want to find your old version of the file. Make sure to create the directories first to avoid errors on startup.

Recover a vim file from the .un~ file without the undo command

How can I restore a vim file from the undo file without hitting undo?
I had a vim file that I saved while adding text. Then I ran a python command that emptied the file's contents, and I can see some of the words the file contained in the file's .un~ file. When I try to undo in the file, it says Already at latest change. I can't find the swap file in my swap files directory.
As the other answers have noted, you can't recover the whole file from vim's undo files, simply because vim seems to only keep diffs in the undo files, not the whole contents. (That makes a lot of sense, as it's space efficient.)
One thing you can try though, is to extract what's possible from your undo file:
$ strings <undo-file>
The output will not be pretty, but you could end up finding something that's valuable to you.
You can't. The undo information is linked to Vim's last knowledge of the file's contents; when they don't correspond any more, Vim cannot re-apply the changes. This is documented at :help undo-persistence:
Vim will detect if an undo file is no longer synchronized with the file it was
written for (with a hash of the file contents) and ignore it when the file was
changed after the undo file was written, to prevent corruption.
Best you can do is try to manually salvage recognizable bits in the undo file, e.g. with a hex editor, or Vim's binary mode.
It is not exactly possible, as the undo file only contains the text that was changed in a single change. If you at some point reloaded the file, the undofile should contain the complete buffer for that and starting from there one could theorectically recover the file (by going through the undo states).
I have written about this before at the vim_use mailinglist here and here (which even contains a patch, that let's you force reading in the undo-file)
You could try to patch vim and see if you can recover at least some data.
A reminder that if you have set in your .vimrc file
set backupdir=$HOME/tmp
You may have temp copies of the files that are readable and that can be renamed

Vim: Maintain the history of a file after it has been changed and reloaded

If I'm editing a file in Vim, then some external program changes the file, Vim tells me:
W11: Warning: File "test.erl" has changed since editing started
See ":help W11" for more info.
[O]K, (L)oad File:
If I Load the file, though, all the undo history is lost.
Is there any way to avoid that?
Update: it appears that this is one of the new features in Vim 7.3: https://groups.google.com/group/vim_announce/browse_thread/thread/66c02efd1523554b
I don't believe this is possible.
There is a very useful patch available for the vim source code available here that keeps the undo history after exiting vim and restarting. However, I've just tried it and it seems to fail when the file is edited externally. It might be worth contacting the author or reporting a bug on the patch website to see if this can be overcome.
G'day,
I'm not sure but does setting autoread, i.e. entering :set autoread leave the undo history for the file when it changes?
Hmmmm. I'm thinking probably not because the change history is maintained as line numbers and vim doesn't know if those line numbers are still relevant to the changed file.
BTW WTF are you editing a file that is being changed by external forces anyway? Sounds dangerous to me. (-:
This is a workaround I used before Vim 7.3:
" :e usually clears undo history, so we don't really do :e any more.
" Instead we delete the contents of the buffer, then read the file in, which
" is an operation we can undo. We must delete the top (empty) line also.
:map :e<Enter> :%d<Enter>:r<Enter>:0<Enter>dd
When you see the warning prompt, you would have to hit ok instead of load, and then perform the load yourself: :e<Enter>
There are two disadvantages (although I found the tradeoff acceptable):
You lose the line you were on. Your cursor is left sitting at the top of the file.
Vim still thinks the buffer is out of sync with the file, so when you next save, you may need to do :w! instead of the normal :w, and you will need to hit y to confirm the overwrite.
Edit: There might be a workaround for the second problem.
Edit: The first problem could be addressed with a bit more scripting (see :h line.)
I don't see how vim could keep track of something it didn't do.
So, as to the question, I would suggest - source control ... but that's probably not the answer you're looking for.

Resources