If you’re a vim/neovim user and your git interactions are through vim-fugitive1. By some point, you probably needed to stash some work. And you probably use the fugitive :Git stash command. But plain git stash will create a stash with a random hash.

$ git stash
Saved working directory and index state WIP on main: 44bc329

The annoying part is when you have more than one stash, and you need to remember the hash. If you use git stash save you can provide a proper name for your stash.

$ git stash save first-stash
Saved working directory and index state On main: first-stash

Then will be easier to manage stashes, which leads to the next part. How to list all stashes? You can use git log -g stash it’s not a very popular command, but it’s very useful. Especially if your workflow is very involved with stashes.

commit e6d7fbecf32cce82dc2c064aa7aa9559a4e963c2 (refs/stash)
Reflog: stash@{0} (Dimitar Nonov <d.nonov@gmail.com>)
Reflog message: On main: second-stash
Merge: 44bc329 b9bb11b
Author: Dimitar Nonov <d.nonov@gmail.com>
Date:   Sun Sep 10 22:16:58 2023 +0300

    On main: second-stash

commit 26fedbc24545e23001e7f68f5bd32c9c5362fd57
Reflog: stash@{1} (Dimitar Nonov <d.nonov@gmail.com>)
Reflog message: On main: first-stash
Merge: 44bc329 635d5de
Author: Dimitar Nonov <d.nonov@gmail.com>
Date:   Sun Sep 10 22:10:30 2023 +0300

    On main: firs-stash

So this is the output of git log -g stash. And here comes the best part if you execute this in vim vim-fugitive will open a separate buffer. You’ll be able to check out the stash if press enter on top of the commit. Sure you can go back to the buffer with all stashes with <C-o>.

Now we need to discuss the part with popping stashes. If you go for the plain git stash pop. You’re going to pop the last saved stash.

$ git stash pop
On branch main
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
	modified:   main.txt

no changes added to commit (use "git add" and/or "git commit -a")
Dropped refs/stash@{0} (e6d7fbecf32cce82dc2c064aa7aa9559a4e963c2)

In other words git stash and git stash pop follow LIFO(Last In First Out). But what if you want to pop the first stash you have pushed stash@{1} without popping stash@{0}?

You can do git stash pop "stash@{1}". Double quotes around the stash reference are mandatory! If you’re using Git >= 2.11 though, this command is cleaner git stash pop 1.

So we now have all major operations with stashes. How to integrate them in vim?

I’ve put them as key mappings in after/plugin/fugitive.lua.

vim.keymap.set("n", "<leader>gsl", ':Git log -g stash <CR>');
vim.keymap.set("n", "<leader>gs", ':Git stash save');
vim.keymap.set("n", "<leader>gsp", ':Git stash pop "stash@{0}"');

This easily can be translated to vimscript and used in vim.

nmap <leader>gsl :Git log -g stash<CR>
nmap <leader>gs :Git stash save
nmap <leader>gsp :Git stash pop "stash@{0}"

I’ve tried to make good mnemonics, but feel free to change them.

gsl stands for git stash list
gs stands for git stash save
gsp stands for git stash pop

You can see that only one of them will be immediately executed, this is because only <leader>gsl doesn’t need the user’s input. On the other hand <leader>gs will get you to command mode, and you’ll need to add the name of the stash and press enter. For <leader>gsp situation is similar, although if you want to pop stash@{0} you just need to press enter. If you want to pop a different stash you need to change the 0 with whatever stash index you want.

So, I hope this was helpful, and now you have a better workflow with stashes.