Instant context switching using git and vim sessions.
It basically takes a snapshot of the following:
- All of your vim tabs, buffers, splits, and folds along with their sizes and positions
- The location of your cursor for each buffer
- The actively selected tab/buffer
- Your undo history (each branch's undo history is saved separately)
- Your git stage with all tracked/untracked files and staged/unstaged hunks
When you switch to different branches using :Promiscuous your-branch-name
, it takes a snapshot of the current branch and working directory, then checks out the new branch, and loads its corresponding snapshot if one exists.
If no snapshot exists, you are presented with a "fresh" vim instance that only has one tab and an empty buffer.
When :Promiscuous
is called with no arguments, an :FZF
fuzzy finder window is presented with a list of existing branches. From there we can either select an existing branch, or type out a new branch to checkout.
If you're using tmux then your status line will automatically refresh when :Promiscuous
checks out a branch. This is very convenient when you display git information in your status line.
Similar projects:
Load shuber/vim-promiscuous
using your favorite plugin manager e.g. Vundle
It currently depends on :FZF
, but this dependency will be optional in the future.
:Promiscuous [branch]
It's recommended to make a custom key binding for this. I've been using the following mapping:
nmap <leader>gb :Promiscuous<cr>
I also use an additional mapping to checkout the previous branch (usually master
):
nmap <leader>gg :Promiscuous -<cr>
These are the defaults. Feel free to override them.
" The directory to store all sessions and undo history
let g:promiscuous_dir = $HOME . '/.vim/promiscuous'
" The callback used to load a session (receives branch name)
let g:promiscuous_load = 'promiscuous#session#load'
" The prefix prepended to all commit, stash, and log messages
let g:promiscuous_prefix = '[Promiscuous]'
" The callback used to save a session (receives branch name)
let g:promiscuous_save = 'promiscuous#session#save'
" Log all executed commands with echom
let g:promiscuous_verbose = 0
set sessionoptions=blank,buffers,curdir,folds,help,tabpages,winsize
set undolevels=1000
set undoreload=10000
call promiscuous#helpers#clear()
call promiscuous#git#stash()
call promiscuous#git#commit()
let l:branch_was = promiscuous#git#branch()
call call(g:promiscuous_save, [l:branch_was], {})
call promiscuous#session#clean()
call promiscuous#git#checkout(l:branch)
let l:branch = promiscuous#git#branch()
call call(g:promiscuous_load, [l:branch], {})
call promiscuous#git#commit_pop()
call promiscuous#git#stash_pop()
call promiscuous#tmux#refresh()
The output below occurred when switching from master
to something-new
then back to master
.
[Promiscuous] !clear
[Promiscuous] !(git diff --quiet && git diff --cached --quiet) || (git stash save Code_vim_promiscuous_master && git stash apply)
[Promiscuous] !git add . && git commit -am '[Promiscuous]'
[Promiscuous] mksession! /Users/Sean/.vim/promiscuous/Code_vim_promiscuous_master.vim
[Promiscuous] bufdo bd
[Promiscuous] !git checkout - || git checkout -b -
[Promiscuous] source /Users/Sean/.vim/promiscuous/Code_vim_promiscuous_something_new.vim
[Promiscuous] Checkout something-new
[Promiscuous] !clear
[Promiscuous] !(git diff --quiet && git diff --cached --quiet) || (git stash save Code_vim_promiscuous_something_new && git stash apply)
[Promiscuous] !git add . && git commit -am '[Promiscuous]'
[Promiscuous] mksession! /Users/Sean/.vim/promiscuous/Code_vim_promiscuous_something_new.vim
[Promiscuous] bufdo bd
[Promiscuous] !git checkout - || git checkout -b -
[Promiscuous] source /Users/Sean/.vim/promiscuous/Code_vim_promiscuous_master.vim
[Promiscuous] Checkout master
- Fork the project.
- Make your feature addition or bug fix.
- Commit, do not mess with the version or history.
- Send me a pull request. Bonus points for topic branches.
MIT - Copyright © 2015 Sean Huber