Using git
how can I load the list of files in the current commit into Quickfix window?
Code Review didn't pass and I want to just fix them one by one.
Vi and Vim Stack Exchange is a question and answer site for people using the vi and Vim families of text editors. It only takes a minute to sign up.
Sign up to join this communityYou could use the following function which has the advantage of not changing the state of your local git repo:
function! CommitQF(...)
" Get the commit hash if it was specified
let commit = a:0 == 0 ? '' : a:1
" Get the result of git show in a list
let flist = system('git show --name-only ' . commit . ' | tail -n +7')
let flist = split(flist, '\n')
" Create the dictionnaries used to populate the quickfix list
let list = []
for f in flist
let dic = {'filename': f, "lnum": 1}
call add(list, dic)
endfor
" Populate the qf list
call setqflist(list)
endfunction
You can call it without argument or with a commit hash as argument (if no argument is specified, the last commit will be used):
call CommitQF("cc5b6a976fde8c9ee66387c91765feb202ba0124")
call CommitQF()
It will use the git show
command with the --name-only
argument to get the name of the files in the commit. The tail -n +7
command removes the lines which are not a file name in the output of git show
.
Then it will create a list of dictionnaries used to populate the quickfix list (see :h setqflist()
for more details about that).
You will need to use :copen
to open the quicklist after calling the function (or you can add it to the function)
Edit Another possible approach (and probably a better one) using only built in features would be to use these settings:
set makeprg=git\ show\ --name-only\ $*\ \\\|\ tail\ -n\ +7
set efm+=%f
This way you can use :make
(for the current commit) or :make fff93a09
(to specify a commit).
The quickfix window will then contain the list of files and you'll be able to navigate to them.
(Of course you might want to create a mapping of something to switch between your usual makeprg
and this one)
You can have a look at these help topics:
Second edit @PeterRincker and @LucHermitte made some really nice suggestions in the comments, many thanks to them.
You could use the following one liner:
command -nargs=? -bar Gshow call setqflist(map(systemlist("git show --pretty='' --name-only <args>"), '{"filename": v:val, "lnum": 1}'))
To create a command :Gshow
which takes a commit hash as an optionnal argument and populate the quickfix list.
git show --pretty='' --name-only <revision>
to remove the commit message information and only show filenames
– Peter Rincker
Aug 31 '17 at 17:03
map(copy(flist), '{"filename": v:val, "lnum": 1}')
instead of the :for
loop -- it's always faster, but also much less annoying to debug.
– Luc Hermitte
Aug 31 '17 at 17:10
command -nargs=? -bar Gshow call setqflist(map(systemlist("git show --pretty='' --name-only <args>"), '{"filename": v:val, "lnum": 1}'))
– Peter Rincker
Aug 31 '17 at 20:46
Here are two related approaches. Both use git-*
scripts; if you put them on your PATH
, you can invoke them as if they were subcommands of git.
git-jump
The git-jump
script provides a handy way to load diff hunks, grep results, or whitespace errors into an editor that supports quickfix formats.
Since git jump diff
forwards its arguments to diff, and since you’re interested in the last commit, you can do
git jump diff @^ @
git-ed
scriptMy git-ed
script was written before I knew about git-jump
. I used it a lot then (less now). It’s only purpose is to open in an editor the changed files (either currently, in a single commit, or in a range of commits). So simply invoke
git ed @
And use the argument list.
/usr/share/doc/git/contrib/git-jump
to your path because git doesn't ship git-jump as executable. You'll have to copy git-jump into your own bin directory.
– idbrii
May 12 '20 at 8:45
/usr/local/share/git-core/contrib/git-jump
, which does ship executable (or at least, for me it did). If you're under doc
, you may not have the right path? The script in the repo has executable permissions, so unless whatever you used to install git removed them, it should retain them
– D. Ben Knoble♦
May 12 '20 at 12:46
The only thing that comes to mind is
git reset --soft head~1
That would "uncommit" the files, and then browse them in Preview window using vim-fugitive
:Gtatus
command. Not exactly Quickfix, but it's readable, stores your position and you can stage/unstage from there.
Add this to your .vimrc
file and you're all set up. This adds files from git diff
to the quick fix
list:
let s:git_status_dictionary = {
\ "A": "Added",
\ "B": "Broken",
\ "C": "Copied",
\ "D": "Deleted",
\ "M": "Modified",
\ "R": "Renamed",
\ "T": "Changed",
\ "U": "Unmerged",
\ "X": "Unknown"
\ }
function! s:get_diff_files()
let list = map(split(system(
\ 'git diff --name-status HEAD'), '\n'),
\ '{"filename":matchstr(v:val, "\\S\\+$"),"text":s:git_status_dictionary[matchstr(v:val, "^\\w")]}'
\ )
call setqflist(list)
copen
endfunction
command! -nargs=0 DiffRev call s:get_diff_files()
Credits: slightly edited
vim-fugitive has added new commands sine the OP raised this question which can do exactly what the OP has asked.
Now you can call
:Git difftool
or the abbreviated version
:G difft[tab complete]
This loads all changesets into the quickfix list. If files have several changes, they occur several times in the quickfix list. I like this. However, if you prefer to have only each file once, run
:G difftool --name-only
Fastest way to add diff hunks to quickfix
Quickfix is very handy feature. It is even has it's own format definition, but it is not easy expand. I found more easy to reformat diff to format of compilation errors: "$file:$line:$message". Reformatting works as standalone filter function. It combination with vim option -q it very easy to use and resuse, no need to additional installations and configutaions:
Here is my the shortest solution.
diff_to_quickfix()
{
perl -ne '/^\+\+\+ (.+)/ && { $f="$1"};/@@.*\+(\d+)/ && print "$f:$1:$_\n"'
}
vim -q <(git show -U0 --no-prefix | diff_to_quickfix)
vim -q <(git diff -U0 --no-prefix | diff_to_quickfix)