git wrapper so awesome, it should be illegal.
That’s at least what states the github page. And it is indeed
awesome and I’m glad it is not illegal. I do most of my work in vim and
fugitive is my go-to wrapper for
git in vim.
Why would you want to use
git inside vim in the first place ? The command line
interface is fine.
Well, most of my work consists in software development. I carefully craft my commits to make them atomic and to keep the code history clean. My workflow consists in reviewing every changes before staging and committing them. During the review I often find myself editing the changes. Once there are changes they need to be at least compiled and sometimes even tested.
git status is available with the command
:Git. It opens a new window with
all the information returned by
git status. Quite a few commands can be
started from this window, I will described the most important in the following
By default the arguments of the
:Git commands if they are not handled by
fugitive itself are sent to the
git program. For example, one can create
and checkout a new branch with
:Git checkout -b bug-fix-1234 or fetch the
latest changes in the remote with
Viewing current editing changes
Let’s say that I currently edit a file tracked by
git. I want to see the
changes I made. I can see them in diff mode in a split view with:
:Gvdiffsplitfor a vertical split diff view
:Ghdiffsplitfor a horizontal split diff view
:Gdiffsplitfor a vertical or horizontal split depending on the current window ratio
Now I can browse and edit the changes. Every shortcuts from diff mode are of course available here. I use mostly:
doto obtain the changes from the other window
dpto put the changes to the other window
Some other interesting commands when editing files tracked by
:Greadto revert the local changes
:Gwriteto stage the file for the next commit
Change review and commit
Now I have done a bunch changes I want to commit. I can get the
git status of
my working directory with
A window appears in an horizontal split showing usually three sections:
- The list of untracked files
- The list of modified files tracked by
gitin the section unstaged
- The list of staged files
I can put the cursor on each of these files and toggle the staged/unstaged
state with the key
X reverts a changed file for the version in
Once I’m done I can hit:
ccto commit staged changes
cato amend the latest commit
Then I’m presented a new buffer where I can write the commit message. Once
saved and closed the commit is added to the
git database. That’s the most
basic workflow, it assumes that I’m happy with the changes I made which is
rarely the case.
Now before committing my changes, I want to review every single hunk to make sure that they are all relevant for the commit I want to add.
I can put my cursor on an unstaged file and hit:
dvfor a vertical split diff view
dhfor a horizontal split diff view
ddfor a vertical or horizontal split depending on the current window ratio
Then I can review my changes and make the appropriate modifications if needed.
Split views are very powerful. It is even possible to stage individual hunks editing the version of the file in the index.
For example, let’s say I have changed a file. I open a vertical diff. On the
left I can see the version in the repository, on the right I have the version I
have edited. The buffer on the left is editable and represents what it is about
to be staged. Practically it means that being in my version on the right if I
go to the first change, I hit
dp it will put my changes in the buffer on the
left. When I save this buffer, that change will be staged.
That’s great, that means that I don’t have to delete all temporary statement in my code before committing them.
Browsing logs can be achieved with the command
:Git log. It opens a buffer
showing the commits in a reverse chronological order such as the latest
commits are located at the top.
Enter key on any ref in the log opens the corresponding commit.
The commit buffer shows the commit message, its author and the changes it
contains as a diff. Well, viewing diff is not very helpful, we usually need to
see the changes in the context of a file. It is fortunately possible to do it
This is how I like to do it:
:set foldmethod=syntaxfolds the diff under each modified filename. Great, now I can see the list of files changed by the commit.
zcopen/close the diff on each filename. But there is better.
Oon a file opens a new tab with a diff view of the changes
:tabcloseI’m back to the commit view and I can choose another file to view
Viewing the commits of a file
A special case of the previous workflow is to look at the log of the current
file. This can be done with
:Git log %.
Browsing through the history of a file
Another variation would be to quickly browse the different versions of the
:0Gllog does just that by filling the location list with those
versions. Browsing through them is possible with the usual
:lprevious. Then call
:lclose when you are done.
In case of a conflict during a merge or a rebase operation, fugitive can present a three panes view with:
- on the left the target branch: where you want to merge i.e. HEAD
- in the middle the version to reconcile. This is the one which contains the
markers you need to get rid of:
- on the right the branch you want to merge
Just resolve the conflicting hunks one after another, save the file, stage it,
then move on with
:Git merge --continue or
:Git rebase --continue depending
on the case.
Other cool features
A feature I use a lot is
git interactive rebase. It’s a great tool to clean
up the commits in a branch before merging them. That can also be done in
git log view, just hit
ri on any commit to start an interactive rebase
from this commit to the current one. Alternatively you can also start it with
:Git rebase -i anyref.
Then you’ll be presented the window listing the commits and a short message describing what you can do with the commit.
git blame is available in two versions in current fugitive.
The first one can be triggered with
:Git blame It opens a window on the left
showing the last editor of the current line. One can blame the previous version
~ on any commit or view the commit with the
One problem with that workflow tho. It is that there is no easy way to get back
to the previous view. Indeed the two windows need to be updated so
not of any help here.
A workaround is to use
:Git blame %. It opens a buffer with the blame message
in front of each line in a single window. An issue is that the syntax highlight
doesn’t work anymore but now it is possible to blame the previous version with
~ and move in the location list as usual with
Viewing the history of a range
In the same vein as here, it is
possible to load all the versions that has affected a specific range of lines
in a file with:
:[range] Gllog. This one is incredibly useful to diagnostic a
bug or a regression.
Getting back to the current editing file
When browsing the
git history, it’s easy to get lost after a while. You can
get back to the current version of the current file any time with
Viewing the commit the current file belongs to
Another handy trick is to reach the last commit that has touched the current
I hope that these use case descriptions have made the demonstration that there
is no point using
git command line or reaching for another tool when editing
git tracked files in vim.
And it only scratches the surface, feel free to start reading the great
:help fugitive and be thankful to Tim Pope for allowing
us not to have to quit vim when in need for