I regularly find myself editing some code, encountering an error in a function and then changing the function call and the function itself to debug the problem. Once the problem in the function is solved, I then want to revert the call to what it was. Of course I always forget to save the call to a register beforehand, and I figured the most intuitive solution would be to undo the last change on the current line. I have not been able to find such functionality in Vim however. Is there something I overlooked? In my mind I see a mapping that branches the undo tree and replays all edits, except the last one on the current line.

  • 1
    see if U (uppercase) helps...
    – Sundeep
    Feb 27, 2017 at 10:13
  • 1
    From :h U: "Undo all latest changes on one line, the line where the latest change was made." I'm specifically not looking to undo the latest change in the file, but the latest change on the line.
    – Octaviour
    Feb 27, 2017 at 10:31
  • undotree() doesn't contain line numbers. Probably the easiest way is to 1) undo all changes back to original state, 2) yank link, 3) put changes back, 4) put. That being said, I personally like to use a version control system (git, hg, svn, whatever) for pretty much everything I do to solve this Feb 27, 2017 at 16:38
  • your first option sounds interesting. I do use version control as well, but I find myself not committing for these changes as they seem very small at first.
    – Octaviour
    Feb 27, 2017 at 17:02

1 Answer 1


This will probably do what you want:

function! Undoline()
  let pos = getpos(".")
  let current = getline(pos[1])
  let chg = changenr()
  while changenr() > 0 && current ==# getline(pos[1])
    silent exec 'u'
  let old = getline(pos[1])

  while changenr() < chg
    silent exec 'redo'
  " undo if we jumped over a gap
  if changenr() > chg
    silent exec 'u'
  call setpos('.', pos)
  if old ==# current
    echo 'no change found'
    call setline(pos[1], old)

It will undo until the line you are on changes, take the old value, redo to your current state and then replace the line with the old value.

It will obviously not work if a line above was added or removed, in that case take a look at one of the undo browsing plugins.

  • Thanks, this goes a long way. The only problem I have currently is that I can't undo two edits (it just goes back and forth as the undo is considered a change). I'll wait a bit and see if anyone comes up with another solution. By the way, is there a reason you do not use let current = getline('.')?
    – Octaviour
    Feb 28, 2017 at 11:40
  • @Octaviour if you know a bit of vimscript you can modify the function to accept a count argument and then wait until you find count undo changes on that line. I used getline that way for consistency (see old).
    – laktak
    Feb 28, 2017 at 11:56
  • Count might be an option. I was thinking more in the direction of keeping track of changnumbers that are introduced because of this function. I think this is a better solution because it does not require you to keep track of the number of changes. I've accepted your solution as I think it solves the initial problem and polishing it is trivial.
    – Octaviour
    Feb 28, 2017 at 12:41
  • 1
    @Octaviour do you have a more polished version you could share?
    – alec
    Mar 7, 2019 at 2:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.