Stage entire file if clean/smudge filter applies

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 #796.
This commit is contained in:
Andy Stewart
2023-06-02 16:01:51 +01:00
parent 4ec072df23
commit 885538efcd

View File

@@ -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
@@ -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