Follow @learnvim for more Vim tips and tricks!
An efficient vim-git workflow can boost productivity. In this article, I will discuss different ways to integrate vim with git.
Here are topics I will cover:
- Vanilla vim and git
- Vim-fugitive
- Conclusion
- List of git plugins
Vanilla vim and git
Vim and git are two equally great tools for two different things. However, getting them to integrate with each other without plugins can be difficult, but not impossible.
If git is installed in your system, you can use vim's bang (:!
) to execute any shell command.
:!git
:!git stash
:!git diff
:!git log
In vim, %
means current file. With this, you can do:
:!git add %
:!git checkout %
:!git rm %
Vim has a built-in terminal, :term
. You can run your git commands from terminal inside Vim. Personally, I find using a dedicated tmux window/pane for git far more useful than :term
.
Although vim does not have a internal git integration, fortunately for us, Tim Pope created vim-fugitive.
Vim-fugitive
Some of fugitive's feature makes some git activities even easier in Vim than doing it from terminal! You can use any plugin managers or use built-in pack to install it.
I will cover some fugitive features below.
:Git
When you run :Git
without any argument, fugitive displays a summary window similar to :Gstatus
.
Compare running :Gstatus
with :!git status
. The latter will display an ugly "Press ENTER or type command to continue"
outside vim window. Fugitive is a clear winner.
Some things you can do in :Gstatus
window:
<Ctrl-p>/<Ctrl-n> " to go between sections
<return> " to open the file
- " to add/ reset file
s " Stage the file under cursor
u " Unstage file under cursor
- " toggle staging/unstaging
U " Unstage everything
To learn more, check out :h fugitive-staging-maps
.
Fugitive's :Git
wraps the git command. You can pass it any option that works with git
command:
:Git status
:Git add "your-file.txt"
:Git commit -m "your message"
:Git blame
:Git blame
creates a git blame window inside vim. You use this to find the last person responsible for that one buggy the code so you can yell at them (just kidding).
Some shortcuts while you are on blame window:
A " resize to show author
C " resize to show commit column
D " resize to show date/time column
gq " close window
You can use Vim's :q
or <Ctrl-w> + c
to close the blame window.
:Gclog
Fugitive's :Gclog
is another useful feature. It launches vim quickfix (:h quickfix
) window to display all your commit logs.
Fugitive shows tree, parent, and changed files in one convenient window. Pressing enter on the tree or parent SHA will take you to that window. You can't do this easily with original git log
without workaround with git ls-tree
and git show
.
Btw, here's a really cool trick with :Gclog
. In the bottom of top window you see a SHA. That's the current file name. You can yank that with y + <Ctrl-g>
, then paste it with p
or P
.
You can pass options too, like:
:Gclog -5
:Gclog --since=yesterday
Since :Gclog
uses quickfix, normal quickfix navigation works:
:cclose " close quickfix window
:copen " open quickfix window
:cnext " next item on quickfix window list
:cprev " prev item
:cfirst " first item
:clast " last item
:Gread
and :Gwrite
:Gwrite
does :Git add %
and :Gread
does :Git checkout %
.
Imagine that you are editing hello.c
, then decided you want to revert this file back to its state in previous commit. You can run :Gread
and all yourchanges will be replaced with previous commit. Vim considers this as a change, so you can undo (u
) it if you change your mind.
If you're happy with your changes, run :Gwrite
to stage it.
:Gdiffsplit
Fugitive performs a vimdiff
(:h vimdiff
) between a given file and a commit (default last commit) with :Gdiffsplit
.
You can perform a diff against any commits. Fugitive is smart enough to compare it with current file from that commit. Just pass the SHA you want to compare it with:
:Gdiffsplit SHA_FROM_LONG_TIME_AGO
Since it uses Vim's diff window, you can use vimdiff
's ]c
and [c
to jump to next / previous change.
:Gedit
You can view any file from commit SHA or branch with :Gedit
.
:Gedit SHA
:Gedit SHA:path/to/file
:Gedit branch
:Gedit branch:path/tofile
You can get the SHA from git log
or :Gclog
.
Keep in mind you can't edit the file because Vim is in Read-Only mode.
Fugitive Object
Vim-fugitive comes with its own fugitive-object
. For a complete fugitive object list, check out :h fugitive-object
.
Let's do an example with one of the objects to learn how to use it. A fugitive object for the commit referenced by head is @
. If I want to :Gedit
that, I can run :Gedit @
.
Conclusion
I think this is a good place to stop. Vim and git are two wonderful tools for two different things. You can integrate vim and git without plugins with Vim's :term
or bang (:!
).
For better integration, a plugin is required.
Vim-fugitive is a very popular git wrapper and it is easy to see why. To learn more, vim-fugitive doc is very good.
Also, Drew Neil made a fugitive series almost 10 years ago, but most of contents are still relevant today. I highly recommend it.
Vim-fugitive is not the only git plugin that is available for vim. Below is a list of some git plugins.
List of git plugins
Here are some git-related plugins:
- gitgutter to show git diff markers.
- vim-signify, another plugin to show git diff markers.
- vimagit, git-workflow plugin inspired by Emacs' magit.
- gina to asynchronously control git repositories.
- vim-twiggy to manage branches.