Working with vim and git
Tags: vim, neovim, git, fugitive
Published: 2020-05-05 12:53:12

---
title: Working with vim and git
published: true
description: How to work with git inside vim
tags: vim, neovim, git, fugitive
---

*Follow [@learnvim](https://twitter.com/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](https://github.com/tmux/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](https://github.com/tpope/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](https://github.com/tpope/vim-fugitive#installation) 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.

![vim git status with bang](https://dev-to-uploads.s3.amazonaws.com/i/xn02k28js8tjeuttk40s.png)

![fugitive Gstatus](https://dev-to-uploads.s3.amazonaws.com/i/hoqlb8uqqq2t9qedmgy8.png)

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). 

![Fugitive git blame](https://dev-to-uploads.s3.amazonaws.com/i/b01zi7v6ulnsucneciul.png)

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 Gclog](https://dev-to-uploads.s3.amazonaws.com/i/qssslkwvlaqdo3rl6dhi.png)

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`.

![Fugitive Gdiffsplit](https://dev-to-uploads.s3.amazonaws.com/i/p2rwhf0bn2nmtjiiv062.png)

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](https://github.com/tpope/vim-fugitive/blob/master/doc/fugitive.txt) is very good. 

Also, Drew Neil made [a fugitive series](http://vimcasts.org/blog/2011/05/the-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](https://github.com/airblade/vim-gitgutter) to show git diff markers.
- [vim-signify](https://github.com/lambdalisue/gina.vim), another plugin to show git diff markers.
- [vimagit](https://github.com/jreybert/vimagit), git-workflow plugin inspired by Emacs' [magit](https://magit.vc/).
- [gina](https://github.com/lambdalisue/gina.vim) to asynchronously control git repositories.
- [vim-twiggy](https://github.com/sodapopcan/vim-twiggy) to manage branches.