The command :Gdiff
is equivalent to running git diff
on that file.
What's the equivalent for git diff --staged
or git diff --cached
?
The command :Gdiff
is equivalent to running git diff
on that file.
What's the equivalent for git diff --staged
or git diff --cached
?
I've found a way to do this. Run :Git
, you should get a window with contents like the following:
# Head: master
# Merge: origin/master
# Help: g?
#
# Staged (1)
# M example.txt
#
Scroll down to the staged file, example.txt
, and press dd. This will open a diff view, comparing what's in HEAD and what's in the index. You'll notice on the bar on the bottom that both the filenames are special Fugitive filenames.
Also while in :Git
preview window, you can press g?, which will list all the mappings valid in the current context.
dd
–
Leif dd
in normal mode deletes a line. And :Gstatus
followed by dd
does something different. –
Hamadryad :Gstatus
(now deprecated for :Git
) and type dd
whilst the cursor is on top of the file you want to view the diff for. See :help fugitive-maps
for more keybindings to use in the :Git
buffer. –
Soliloquy While vim-fugitive
does not supply direct analogues for git diff --staged
or git diff --cached
, it does supply a general-purpose Vim command for piping the output of arbitrary git
commands into read-only Vim buffers: :Git!
.
Before we get to that, let's explicitly restate the question. git diff --staged
and git diff --cached
are synonyms for the same underlying operation: diffing the contents of the index (the set of all staged changes) against the contents of the HEAD (the most recent commit for the current branch), typically for reviewing changes prior to commit. The stated question then becomes:
What is the most effective means of reviewing all staged changes in
vim-fugitive
?
It should be clear that the currently accepted self-answer fails to address this question. The next highest rated self-answer is no better.
:Gstatus
bindings only apply to the file on the current line and hence cannot by definition be used to review all staged changes. Moreover, the :Gstatus
D
binding doesn't even review all staged changes for the file on the current line. It only diffs the index and working tree copies of that file, rather than diffing the index and most recently committed copies of that file (which is an altogether different beast).
:Gdiff HEAD
is similarly inapplicable. It only diffs the most recently committed and working tree copies of the file corresponding to the current buffer. :Gdiff
without an argument is equivalent to the :Gstatus
D
binding, again diffing the index and working tree copies of that file. Neither reviews all staged changes.
emaniacs struck the closest to a working solution with this comment to the latter answer:
:Git diff --staged
Now we're approximating the truth!
:Git
pipes the output of the passed git
command to the current external pager, permitting a liesurely review of all staged changes external to Vim. But there's the rub: external to Vim. That means no Vim bindings, buffers, or syntax highlighting. Ideally, we'd prefer a read-only Vim buffer syntax highlighting the output of git diff --staged
. Can we do this?
We can, or Tim Pope isn't the Vim Pope. The !
-suffixed variant of :Git
does just that, permitting a liesurely review of all staged changes within Vim complete with Vim-based syntax highlighting of change differences:
:Git! diff --staged
Yeah. It's pretty awesomeness.
But let's go a step farther. In the time-honoured tradition of slothful slackers everywhere, let's define a new Vim command :Greview
encapsulating this operation and a new binding <leader>gr
running this command. Just stash the following into your .vimrc
:
command Greview :Git! diff --staged
nnoremap <leader>gr :Greview<cr>
Assuming <leader>
to be ,
, reviewing all staged changes reduces to ,gr
. It couldn't get any Vimmier.
:Greview
needs to be part of vim-fugitive
! –
Leptophyllous command Greview :Gtabedit! diff --staged
–
Stgermain dd
on that line. –
Tang :Gdiff HEAD
Gdiff
takes an revision argument. So you can pass it HEAD
. This is not equivalent to git diff --staged
, but it can serve a similar purpose.
:Git diff --staged
, because :Git
is equivalent with git
command. –
Macintosh :Gdiff
does. –
Prisca Update: 3/28/2017,
Current version of fugitive will do this automatically when you press D
on a file.
if the file is staged, only staged changes will be showed in the diff. If the file is not staged, then only change that are not staged will be visible.
As already noted, Gdiff
, Gdiff :
or Gdiff :0
gives you the diff with the index,
Gdiff -
or Gdiff HEAD
gives the diff with the HEAD.
So doing a diff first with :
then with -
show 3 diff-panes in vim:
command! -bar Gvstage :Gvdiff -|Gvdiff : " vertical 3-split
command! -bar Gsstage :Gsdiff -|Gsdiff : " horizontal 3-split
Of course you can also just to Gvdiff -
if you're already in diff mode.
Now pushing and getting changes is sligthly more complicated with 3 open windows, however, you can diffput
from index to working tree and vice-versa easily, as on the HEAD modifiable
is off, so it can never be targeted.
Otherwise, you can add some shortcuts for the diffput
and diffget
commands, knowing that they can take a "buffer specifier", which can be a pattern (see :help merge) or the buffer number. I modified the previous commands to save the initial buffer's number and use patterns for the others:
command! -bar Gvstage :let t:working_copy=bufnr('%')|Gvdiff -|Gvdiff : " vertical 3-split
command! -bar Gsstage :let t:working_copy=bufnr('%')|Gsdiff -|Gsdiff : " horizontal 3-split
nnoremap <Leader>hg :diffget fugitive://*/.git//[0-9a-f][0-9a-f]*/<CR> " HEAD get
nnoremap <Leader>ig :diffget fugitive://*/.git//0/<CR> " index get
nnoremap <Leader>ip :diffput fugitive://*/.git//0/<CR> " index put
nnoremap <Leader>wg :diffget <C-R>=t:working_copy<CR><CR> " work get
nnoremap <Leader>wp :diffput <C-R>=t:working_copy<CR><CR> " work put
Alternately, if you just want a nice vimdiff
view of what is staged instead of a patch, let me sugget:
command! Greview :exec "Git difftool --tool=vimdiff --staged " . fugitive#buffer().path()
This starts a new instance of vim, so when you quit it you go back to your tabs and windows you already had opened, which is perfect. This if faster (at least for me) than transitioning through the git status window, but has the drawback that you can't edit the staged file.
Use :Gtabedit @:% | Gdiff :
.
This is better than the other answers because it opens in split view just like :Gdiff
, rather than dumping diff syntax into a single buffer. When you're done, just :tabc
to get back.
Gtabedit
open a new tab and edit a fugitive object:
@
(HEAD), a specific file :
, the current file %
.Gdiff
diff the current buffer against another fugitive object:
:
(you can specify the file again with :%
but it's not needed).We now have fugitive equivalents for git diff
(:Gdiff
) and git diff --staged
(the command above). To get the behaviour of git show
on the current file, use :Gtabedit @~:% | Gdiff @
.
:help fugitive-object
TLDR:
Gtabedit :0 | Gdiffsplit @:#
Explanation:
There are 3 relevant diffs when you have both staged changes and unstaged changes. The following shows each of those with git
and vim-fugitive
. The vim-fugitive
commands all open an actual vim diff in the current editor session.
NB: Gdiffsplit HEAD
behaves like git diff HEAD -- <current_file>
, not like git diff --staged <current_file>
.
Diff between last commit and staged changes, excluding unstaged changes. i.e. What would actually get committed if you ran git commit
right now (without -a
). This is the answer to the original question as it is written:
git diff --staged <current_file>
or git diff --cached <current_file>
Gtabedit :0 | Gdiffsplit @:#
or Gtabedit @:% | Gdiffsplit :0
(The 2 vim-fugitive
variants here just change the order of the windows)
Diff between working dir (unstaged) and staged changes. i.e. What would get added to index if you ran git add <current_file>
right now:
git diff <current_file>
Gdiffsplit
Diff between all changes (staged and unstaged) and the last commit. i.e. What would get committed if you ran git commit -a
right now:
git diff HEAD -- x
Gdiffsplit HEAD
NB: git commit
commands above would include other tracked files
NOTE: Why is yet another answer needed?
git diff --staged
with git diff HEAD
(this can be seen when you have staged and unstaged changes)Gdiff
i.e. Gdiffsplit
as originally asked)In case you somebody stumbled on this question.
:Gdiff --staged
will do.. :)
© 2022 - 2024 — McMap. All rights reserved.