mirror of
https://github.com/airblade/vim-gitgutter.git
synced 2025-11-08 11:33:48 -05:00
Fix staging of hunks coming after deleted lines.
Previously vim-gitgutter generated context-free patches and applied those to the index. However when staging a hunk situated after any deleted lines, the line numbers on the patch were out by the number of lines deleted, and without any context git would apply the patch to the wrong part of the file in the index. This commit ensure patches are generated with 1 line of context, allowing git to adjust the line numbers appropriately and apply the patch to the right location. More lines of context would help git more to adjust line numbers; but the more context we have the more we group together hunks we would like to treat separately.
This commit is contained in:
@@ -19,7 +19,7 @@ function! gitgutter#process_buffer(file, realtime)
|
||||
endif
|
||||
try
|
||||
if !a:realtime || gitgutter#utility#has_fresh_changes(a:file)
|
||||
let diff = gitgutter#diff#run_diff(a:realtime || gitgutter#utility#has_unsaved_changes(a:file), 1)
|
||||
let diff = gitgutter#diff#run_diff(a:realtime || gitgutter#utility#has_unsaved_changes(a:file), 1, 0)
|
||||
call gitgutter#hunk#set_hunks(gitgutter#diff#parse_diff(diff))
|
||||
let modified_lines = gitgutter#diff#process_hunks(gitgutter#hunk#hunks())
|
||||
|
||||
@@ -156,17 +156,11 @@ function! gitgutter#stage_hunk()
|
||||
" It doesn't make sense to stage a hunk otherwise.
|
||||
silent write
|
||||
|
||||
" find current hunk
|
||||
let current_hunk = gitgutter#hunk#current_hunk()
|
||||
if empty(current_hunk)
|
||||
return
|
||||
endif
|
||||
|
||||
" construct a diff
|
||||
let diff_for_hunk = gitgutter#diff#generate_diff_for_hunk(current_hunk, 1)
|
||||
let diff_for_hunk = gitgutter#diff#generate_diff_for_hunk(1, 1)
|
||||
|
||||
" apply the diff
|
||||
call gitgutter#utility#system(gitgutter#utility#command_in_directory_of_file('git apply --cached --unidiff-zero - '), diff_for_hunk)
|
||||
call gitgutter#utility#system(gitgutter#utility#command_in_directory_of_file('git apply --cached --recount --allow-overlap - '), diff_for_hunk)
|
||||
|
||||
" refresh gitgutter's view of buffer
|
||||
silent execute "GitGutter"
|
||||
@@ -179,17 +173,11 @@ function! gitgutter#revert_hunk()
|
||||
" It doesn't make sense to stage a hunk otherwise.
|
||||
silent write
|
||||
|
||||
" find current hunk
|
||||
let current_hunk = gitgutter#hunk#current_hunk()
|
||||
if empty(current_hunk)
|
||||
return
|
||||
endif
|
||||
|
||||
" construct a diff
|
||||
let diff_for_hunk = gitgutter#diff#generate_diff_for_hunk(current_hunk, 1)
|
||||
let diff_for_hunk = gitgutter#diff#generate_diff_for_hunk(1, 1)
|
||||
|
||||
" apply the diff
|
||||
call gitgutter#utility#system(gitgutter#utility#command_in_directory_of_file('git apply --reverse --unidiff-zero - '), diff_for_hunk)
|
||||
call gitgutter#utility#system(gitgutter#utility#command_in_directory_of_file('git apply --reverse - '), diff_for_hunk)
|
||||
|
||||
" reload file
|
||||
silent edit
|
||||
@@ -200,14 +188,8 @@ function! gitgutter#preview_hunk()
|
||||
if gitgutter#utility#is_active()
|
||||
silent write
|
||||
|
||||
" find current hunk
|
||||
let current_hunk = gitgutter#hunk#current_hunk()
|
||||
if empty(current_hunk)
|
||||
return
|
||||
endif
|
||||
|
||||
" construct a diff
|
||||
let diff_for_hunk = gitgutter#diff#generate_diff_for_hunk(current_hunk, 0)
|
||||
let diff_for_hunk = gitgutter#diff#generate_diff_for_hunk(0, 0)
|
||||
|
||||
" preview the diff
|
||||
silent! wincmd P
|
||||
|
||||
@@ -3,7 +3,7 @@ let s:grep_command = ' | ' . (g:gitgutter_escape_grep ? '\grep' : 'grep') . ' -e
|
||||
let s:hunk_re = '^@@ -\(\d\+\),\?\(\d*\) +\(\d\+\),\?\(\d*\) @@'
|
||||
|
||||
|
||||
function! gitgutter#diff#run_diff(realtime, use_external_grep)
|
||||
function! gitgutter#diff#run_diff(realtime, use_external_grep, lines_of_context)
|
||||
" Wrap compound command in parentheses to make Windows happy.
|
||||
let cmd = '(git ls-files --error-unmatch ' . gitgutter#utility#shellescape(gitgutter#utility#filename()) . ' && ('
|
||||
|
||||
@@ -11,9 +11,9 @@ function! gitgutter#diff#run_diff(realtime, use_external_grep)
|
||||
let blob_name = ':' . gitgutter#utility#shellescape(gitgutter#utility#file_relative_to_repo_root())
|
||||
let blob_file = tempname()
|
||||
let cmd .= 'git show ' . blob_name . ' > ' . blob_file .
|
||||
\ ' && diff -U0 ' . g:gitgutter_diff_args . ' ' . blob_file . ' - '
|
||||
\ ' && diff -U'.a:lines_of_context.' ' . g:gitgutter_diff_args . ' ' . blob_file . ' - '
|
||||
else
|
||||
let cmd .= 'git diff --no-ext-diff --no-color -U0 ' . g:gitgutter_diff_args . ' ' . gitgutter#utility#shellescape(gitgutter#utility#filename())
|
||||
let cmd .= 'git diff --no-ext-diff --no-color -U'.a:lines_of_context.' ' . g:gitgutter_diff_args . ' ' . gitgutter#utility#shellescape(gitgutter#utility#filename())
|
||||
endif
|
||||
|
||||
if a:use_external_grep && s:grep_available
|
||||
@@ -182,22 +182,24 @@ function! gitgutter#diff#process_modified_and_removed(modifications, from_count,
|
||||
let a:modifications[-1] = [a:to_line + offset - 1, 'modified_removed']
|
||||
endfunction
|
||||
|
||||
function! gitgutter#diff#generate_diff_for_hunk(hunk, keep_header)
|
||||
let diff = gitgutter#diff#discard_hunks(gitgutter#diff#run_diff(0, 0), a:hunk, a:keep_header)
|
||||
function! gitgutter#diff#generate_diff_for_hunk(keep_header, lines_of_context)
|
||||
let diff = gitgutter#diff#run_diff(0, 0, a:lines_of_context)
|
||||
let diff_for_hunk = gitgutter#diff#discard_hunks(diff, a:keep_header)
|
||||
if !a:keep_header
|
||||
" Discard summary line
|
||||
let diff = join(split(diff, '\n')[1:-1], "\n")
|
||||
let diff_for_hunk = join(split(diff_for_hunk, '\n')[1:-1], "\n")
|
||||
endif
|
||||
return diff
|
||||
return diff_for_hunk
|
||||
endfunction
|
||||
|
||||
function! gitgutter#diff#discard_hunks(diff, hunk_to_keep, keep_header)
|
||||
" diff - with non-zero lines of context
|
||||
function! gitgutter#diff#discard_hunks(diff, keep_header)
|
||||
let modified_diff = []
|
||||
let keep_line = a:keep_header
|
||||
for line in split(a:diff, '\n')
|
||||
let hunk_info = gitgutter#diff#parse_hunk(line)
|
||||
if len(hunk_info) == 4 " start of new hunk
|
||||
let keep_line = (hunk_info == a:hunk_to_keep)
|
||||
let keep_line = gitgutter#hunk#cursor_in_hunk(hunk_info)
|
||||
endif
|
||||
if keep_line
|
||||
call add(modified_diff, line)
|
||||
|
||||
@@ -67,15 +67,9 @@ endfunction
|
||||
" hunk.
|
||||
function! gitgutter#hunk#current_hunk()
|
||||
let current_hunk = []
|
||||
let current_line = line('.')
|
||||
|
||||
for hunk in s:hunks
|
||||
if current_line == 1 && hunk[2] == 0
|
||||
let current_hunk = hunk
|
||||
break
|
||||
endif
|
||||
|
||||
if current_line >= hunk[2] && current_line < hunk[2] + (hunk[3] == 0 ? 1 : hunk[3])
|
||||
if gitgutter#hunk#cursor_in_hunk(hunk)
|
||||
let current_hunk = hunk
|
||||
break
|
||||
endif
|
||||
@@ -86,3 +80,17 @@ function! gitgutter#hunk#current_hunk()
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! gitgutter#hunk#cursor_in_hunk(hunk)
|
||||
let current_line = line('.')
|
||||
|
||||
if current_line == 1 && a:hunk[2] == 0
|
||||
return 1
|
||||
endif
|
||||
|
||||
if current_line >= a:hunk[2] && current_line < a:hunk[2] + (a:hunk[3] == 0 ? 1 : a:hunk[3])
|
||||
return 1
|
||||
endif
|
||||
|
||||
return 0
|
||||
endfunction
|
||||
|
||||
|
||||
Reference in New Issue
Block a user