From caf2907fd82f86a02ff3c07faf26fbb1aa3c8479 Mon Sep 17 00:00:00 2001 From: Tim Pope Date: Tue, 16 Mar 2021 16:04:17 -0400 Subject: [PATCH] Retool discard operation during conflict The use of --theirs for Unstaged and --ours for Staged was based entirely on the way conflicts were represented in git status --short, except, that's backwards, the staged column contains our side of the merge so discarding it should use --theirs. I never noticed because I don't use this feature. Fixing this is guaranteed to burn anybody who learned the whole behavior, so let's promote 2X and 3X to official status, and require opting in to the flipped default. Also, since --ours and --theirs only touch the worktree, the correct analogous operations for deletion is *not* git rm, but rather to remove the worktree file directly. So let's do that, and add it to 2X and 3X too. Closes https://github.com/tpope/vim-fugitive/issues/1699 References https://github.com/tpope/vim-fugitive/issues/1648 --- autoload/fugitive.vim | 29 ++++++++++++++++++++++++----- doc/fugitive.txt | 7 +++---- 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/autoload/fugitive.vim b/autoload/fugitive.vim index a17423f..381fca5 100644 --- a/autoload/fugitive.vim +++ b/autoload/fugitive.vim @@ -3614,6 +3614,7 @@ endfunction function! s:StageDelete(lnum1, lnum2, count) abort let restore = [] let err = '' + let did_conflict_err = 0 try for info in s:Selection(a:lnum1, a:lnum2) if empty(info.paths) @@ -3646,14 +3647,30 @@ function! s:StageDelete(lnum1, lnum2, count) abort elseif info.status ==# '?' call s:TreeChomp('clean', '-f', '--', info.paths[0]) elseif a:count == 2 - call s:TreeChomp('checkout', '--ours', '--', info.paths[0]) + if get(b:fugitive_files['Staged'], info.filename, {'status': ''}).status ==# 'D' + call delete(FugitiveVimPath(info.paths[0])) + else + call s:TreeChomp('checkout', '--ours', '--', info.paths[0]) + endif elseif a:count == 3 - call s:TreeChomp('checkout', '--theirs', '--', info.paths[0]) + if get(b:fugitive_files['Unstaged'], info.filename, {'status': ''}).status ==# 'D' + call delete(FugitiveVimPath(info.paths[0])) + else + call s:TreeChomp('checkout', '--theirs', '--', info.paths[0]) + endif elseif info.status =~# '[ADU]' && \ get(b:fugitive_files[info.section ==# 'Staged' ? 'Unstaged' : 'Staged'], info.filename, {'status': ''}).status =~# '[AU]' - call s:TreeChomp('checkout', info.section ==# 'Staged' ? '--ours' : '--theirs', '--', info.paths[0]) + if get(g:, 'fugitive_conflict_x', 0) + call s:TreeChomp('checkout', info.section ==# 'Unstaged' ? '--ours' : '--theirs', '--', info.paths[0]) + else + if !did_conflict_err + let err .= '|echoerr "Use 2X for --ours or 3X for --theirs"' + let did_conflict_err = 1 + endif + continue + endif elseif info.status ==# 'U' - call s:TreeChomp('rm', '--', info.paths[0]) + call delete(FugitiveVimPath(info.paths[0])) elseif info.status ==# 'A' call s:TreeChomp('rm', '-f', '--', info.paths[0]) elseif info.section ==# 'Unstaged' @@ -3661,7 +3678,9 @@ function! s:StageDelete(lnum1, lnum2, count) abort else call s:TreeChomp('checkout', 'HEAD^{}', '--', info.paths[0]) endif - call add(restore, ':Gsplit ' . s:fnameescape(info.relative[0]) . '|' . undo) + if len(undo) + call add(restore, ':Gsplit ' . s:fnameescape(info.relative[0]) . '|' . undo) + endif endfor catch /^fugitive:/ let err .= '|echoerr ' . string(v:exception) diff --git a/doc/fugitive.txt b/doc/fugitive.txt index 556b36f..07f605d 100644 --- a/doc/fugitive.txt +++ b/doc/fugitive.txt @@ -255,10 +255,9 @@ U Unstage everything. X Discard the change under the cursor. This uses `checkout` or `clean` under the hood. A command is echoed that shows how to undo the change. Consult - `:messages` to see it again. You can use this during - a merge conflict to discard "our" changes (--theirs) - in the "Unstaged" section or discard "their" changes - (--ours) in the "Staged" section. + `:messages` to see it again. During a merge conflict, + use 2X to call `checkout --ours` or 3X to call + `checkout --theirs` . *fugitive_=* = Toggle an inline diff of the file under the cursor.