Skip to content

Commit

Permalink
Stage entire file if clean/smudge filter applies
Browse files Browse the repository at this point in the history
If a file is subject to a clean/smudge filter, it is impossible to stage
an individual hunk.  Therefore if the user tries to stage a hunk, ask
whether they want to stage the entire instead.

Determining whether a clean/smudge filter applies is done with:

    git check-attr filter -- path/to/file

– and looking for "unspecified" (not to be) in the output.  The result
is cached so that for a file which is not filtered (the common case),
staging multiple hunks only incurs the cost of the external call once.

See airblade#796.
  • Loading branch information
airblade committed Jun 2, 2023
1 parent 4ec072d commit 885538e
Showing 1 changed file with 36 additions and 5 deletions.
41 changes: 36 additions & 5 deletions autoload/gitgutter/hunk.vim
Original file line number Diff line number Diff line change
Expand Up @@ -294,11 +294,28 @@ endfunction

function! s:stage(hunk_diff)
let bufnr = bufnr('')
let diff = s:adjust_header(bufnr, a:hunk_diff)
" Apply patch to index.
call gitgutter#utility#system(
\ gitgutter#utility#cd_cmd(bufnr, g:gitgutter_git_executable.' '.g:gitgutter_git_args.' apply --cached --unidiff-zero - '),
\ diff)

if s:clean_smudge_filter_applies(bufnr)
let choice = input('File uses clean/smudge filter. Stage entire file (y/n)? ')
normal! :<ESC>
if choice =~ 'y'
let path = gitgutter#utility#repo_path(bufnr, 1)
" Add file to index.
call gitgutter#utility#system(
\ gitgutter#utility#cd_cmd(bufnr, g:gitgutter_git_executable.' '.g:gitgutter_git_args.' add '.path)
\ )
else
return
endif

else
let diff = s:adjust_header(bufnr, a:hunk_diff)
" Apply patch to index.
call gitgutter#utility#system(
\ gitgutter#utility#cd_cmd(bufnr, g:gitgutter_git_executable.' '.g:gitgutter_git_args.' apply --cached --unidiff-zero - '),
\ diff)
endif

if v:shell_error
call gitgutter#utility#warn('Patch does not apply')
else
Expand Down Expand Up @@ -637,3 +654,17 @@ function gitgutter#hunk#is_preview_window_open()
endif
return 0
endfunction


function! s:clean_smudge_filter_applies(bufnr)
let filtered = gitgutter#utility#getbufvar(a:bufnr, 'filter', -1)
if filtered == -1
let path = gitgutter#utility#repo_path(a:bufnr, 1)
let out = gitgutter#utility#system(
\ gitgutter#utility#cd_cmd(a:bufnr, g:gitgutter_git_executable.' '.g:gitgutter_git_args.' check-attr filter -- '.path)
\ )
let filtered = out !~ 'unspecified'
call gitgutter#utility#setbufvar(a:bufnr, 'filter', filtered)
endif
return filtered
endfunction

0 comments on commit 885538e

Please sign in to comment.