DEV Community

Heiker
Heiker

Posted on

Packer.nvim: how to recover from a bad plugin update

Neovim's plugin ecosystem moves fast. Sometimes this is great because we get new features. Other times... things break. Having your editor in an unusable state is not fun. But we can recover from that. In going tell you how to use packer.nvim to take your editor back to a good state.

The tools

In packer.nvim there is a thing called a snapshot. This is a JSON file that contains the commit hash of every plugin installed.

To manage the snapshot files packer.nvim offers these commands:

  • PackerSnapshot {name}:

Creates the snapshot file. The first argument of this command the name of the file.

  • PackerSnapshotRollback {name} [{plugin}]:

Reverts the plugins back to the commit specified by a snapshot. {name} must be the name of snapshot file. If you provide the argument {plugin} then only that plugin will be restored.

  • PackerSnapshotDelete {name}

Deletes the snapshot file with {name}.

Our first step

We can't go back to a good state if we don't have snapshot of that.

So the first thing we should do is take a snapshot of our plugins when everything is good. If your editor is working fine right now, you should execute this command.

:PackerSnapshot stable
Enter fullscreen mode Exit fullscreen mode

You could even add a date format to the name. Maybe add month and year.

:PackerSnapshot stable-07-2023
Enter fullscreen mode Exit fullscreen mode

In case of emergency...

What to do when things go wrong? Rollback. Execute the command to revert all your plugins to the state of the stable snapshot.

:PackerSnapshotRollback stable
Enter fullscreen mode Exit fullscreen mode

And remember, you can specify which plugin you want to restore. Something like this would work.

:PackerSnapshotRollback stable nvim-treesitter
Enter fullscreen mode Exit fullscreen mode

Worst case scenario

If your Neovim config breaks before it loads packer.nvim then you'll have to source it yourself.

If your packer config lives in its own lua module, navigate to that file and execute this command

:source %
Enter fullscreen mode Exit fullscreen mode

If you can't execute your packer config without triggering an error, you'll have to go to the place where you have the require('packer').startup block, select the whole thing, then execute this command.

:'<,'>source
Enter fullscreen mode Exit fullscreen mode

Once packer is loaded you can use the rollback command.

Make it convenient

Snapshot are great and all but we can make them better.

We can make a command that creates a snapshot before an update. And make another command that restores the most recent snapshot.

Here is the code.

local last_snapshot = vim.fn.stdpath('data') .. '/last-snapshot-date'

vim.api.nvim_create_user_command(
  'PluginUpdate',
  function()
    local packer = require('packer')
    local name = vim.fn.strftime('%Y-%m-%d@%H:%M:%S')

    packer.snapshot(name)
    vim.fn.writefile({name}, last_snapshot)

    local timer = vim.loop.new_timer()
    local wait_ms = 1000

    timer:start(wait_ms, 0, function()
      timer:stop()
      timer:close()
      packer.sync()
    end)
  end,
  {}
)

vim.api.nvim_create_user_command(
  'PluginRestore',
  function()
    local ok, name = pcall(vim.fn.readfile, last_snapshot, 1)
    if not ok then return end

    require('packer').rollback(name[1])
  end,
  {}
)
Enter fullscreen mode Exit fullscreen mode

With this in your config you will use :PluginUpdate instead of :PackerSync. And if there is a bad update you can use :PluginRestore to go back to the previous state.

How to keep Neovim from breaking

Here is my advice.

  • Use a stable release. Avoid nightly versions if you can.

  • Don't update your plugins daily. Stop it.

  • Update your plugins only on the weekends when you have free time.

Conclusion

Neovim plugins change all the time. They update frecuently and things can break. That's why we need to learn how to deal with this situation. If a plugins breaks our editor, we can go back to a working state using packer.nvim's snapshots.


Thank you for your time. If you find this article useful and want to support my efforts, consider leaving a tip in buy me a coffee ☕.

buy me a coffee

Top comments (0)