Fugitive.vim - exploring the history of a git repository
Git provides tools for searching the contents of files, commit messages, and even whether text was added or removed by a commit. In this episode, we’ll see how fugitive’s
Glog commands wrap this functionality up so that we can search the contents and history of a git repo from right inside of Vim.
This is the last of our five part series on fugitive.vim.
I’ll be running my Core Vim Class online on Monday, January 27th. Tickets cost £160, but you can get the earlybird discount of £145 if you buy yours before January 24th. The price includes an exclusive screencast that summarises the material from the class.
Browsing past revisions of a file
Glog command makes it easy to examine all previous revisions of a file. It does this by loading each revision into its own buffer, and queuing them in the quickfix list in chronological order.
You can filter the results
||load all previous revisions of the current file into the quickfix list|
||load the last ten previous revisions of the current file into the quickfix list|
||load the first ten revisions of the current file into the quickfix list (in reverse chronological order)|
||load the last version of the current file that was checked in before midnight last night|
Browsing past commits
You can also use the
:Glog command to review past commit objects, by appending a trailing
-- argument. By default, this will load all ancestral commit objects into the quickfix list. If you supply a filepath after the
-- argument, then the list will be filtered to only include commit objects that touched the specified file.
||load all ancestral commit objects into the quickfix list|
||load all ancestral commit objects that touched the current file into the quickfix list|
Note that when fugitive loads a commit object into a buffer, it is interactive in a number of ways. See episode 34 for more details.
Working with the quickfix list
I recommend installing unimpaired.vim, another plugin by Tim Pope. This provides lots of useful pairs of mappings, including a handful that make working with the quickfix list much easier:
||jump to previous quickfix item|
||jump to next quickfix item|
||jump to first quickfix item|
||jump to last quickfix item|
Searching the working tree with
Ggrep command is a wrapper for
git grep. It uses the results to populate the quickfix list, so you can easily navigate the result list from inside Vim.
If you want to search your working tree for the text ‘find me’, simply run:
:Ggrep 'find me'
git grep command only looks inside files that are tracked by the git repository. The fact that it only looks inside tracked files means that it skips over any files or directories listed in the
Searching branches, tags and commits with
git grep is not just limited to reading files on the filesystem. It can look inside any git object. So using
git grep, you can search all files in any of your git branches without first having to switch to the branch.
||search for 'findme' in working copy files (excluding untracked files)|
||search for 'findme' in the index|
||search for 'findme' in branch 'branchname'|
||search for 'findme' in tag 'tagname'|
||search for 'findme' in the commit/tag identified by SHA|
When you open a file that belongs on another branch, fugitive will automatically create a read only buffer for it.
Searching for text in a commit message
If you want to search the text of commit messages, you can do so by passing the
--grep option to the
git log command. For example, if you wanted to find commit messages containing the text ‘findme’, you could run:
git log --grep=findme
You can also do this from inside of Vim using the
:Glog wrapper. This table summarizes a couple of ways you might use this:
||search for 'findme' in all ancestral commit messages|
||search for 'findme' in all ancestral commit messages that touch the currently active file|
Searching for text added or removed by a commit
Git also makes it possible to search for text that was added or removed by a commit using the pickaxe option. This is activated with the
-S switch as follows:
git log -Sfindme
This tells git to go through every commit, comparing the before and after state of each file that was changed by that commit. If the specified string is present in the file before, but absent from the file after the commit, then it counts as a match. The converse is also true, so if the specified string was either added or removed by the commit, then it will appear the git log results.
Here are a couple of examples demonstrating how the pickaxe option can be used with
||search for 'findme' in the diff for each ancestral commit|
||search for 'findme' in the diff for each ancestral commit that touches the currently active file|