28 Commits

Author SHA1 Message Date
Tim Pope
21ed533001 fugitive.vim 3.2
* Provide :Git mergetool to load conflicts into quickfix list.
* Provide :Git difftool to load arbitrary changesets into quickfix list.
* Call FugitiveBlob/FugitiveCommit/etc autocommands on Fugitive buffer load.
* :Git --paginate display results in temp buffer.
* :Git --no-pager no longer displays results in temp buffer.
* Accomodate loading Fugitive buffers in popup window.
* Better PowerShell support.
* Bug fixes.
2020-01-21 04:33:16 -05:00
Tim Pope
29153d5ba1 Provide git config --get-all wrapper 2020-01-20 15:42:54 -05:00
Tim Pope
8d4b85ed09 Replace --format with --pretty=format for older Git 2020-01-20 15:42:54 -05:00
Tim Pope
708595d996 Fix comment typo 2020-01-20 15:42:45 -05:00
Chris DeLuca
dc6719e7b0 Fix :Gdiffsplit! help typo 2020-01-20 10:27:14 -05:00
Tim Pope
c48db08e4e Use appropriate slashes for :Dispatch working directory 2020-01-20 10:27:00 -05:00
Tim Pope
2ebdeef9e0 Change :Git --paginate from :terminal to temp buffer
The --paginate option to Git forces it to use $PAGER rather than its own
configuration, so it makes perfect sense for Fugitive to take on the
role of the pager.

This also removes the same behavior for --no-pager, allowing the command
to run with :! instead.  I really don't like sudden backwards
incompatible changes like this, but the old behavior was based on a bad
understanding of how these options work, and I'd rather rip the band-aid
off sooner rather than later.
2020-01-20 09:03:49 -05:00
Tim Pope
bc0b78ee84 Remove dead code 2020-01-20 08:42:02 -05:00
Tim Pope
5bcb42164e Specify shell command, not wrapper, in b:dispatch
This frees us up to change :Gfetch not to use :Make.
2020-01-20 07:28:55 -05:00
Tim Pope
1a6934fc7e Fix FugitiveParse() return value documentation 2020-01-20 07:03:48 -05:00
Tim Pope
397fb99921 Provide FugitiveBlob style autocommands
This is the real replacement for fugitive#buffer().type(), as the only
real world use of that seemed to be in BufReadPost autocommands.
2020-01-20 05:52:22 -05:00
Tim Pope
5b1213d0db Fix :Gmerge 2020-01-20 05:52:22 -05:00
Tim Pope
ae52b5a96a Better PowerShell support 2020-01-18 01:30:43 -08:00
Tim Pope
9f032ed040 Prevent alternate buffer change loading Fugitive buffer 2020-01-18 00:51:38 -05:00
Tim Pope
d428032600 Fix netrw gx in Fugitive buffers AGAIN 2020-01-18 00:45:17 -05:00
Tim Pope
c83355d5c5 Accomodate loading Fugitive buffers in popup window
Closes https://github.com/tpope/vim-fugitive/issues/1418
2020-01-15 01:26:31 -05:00
Tim Pope
4732bb964a Generalize :Git environment variable overrides 2020-01-14 22:56:11 -05:00
Tim Pope
3e32a55619 Avoid false positives on rebase todo handler 2020-01-14 22:56:11 -05:00
Tim Pope
a65db6fcf8 Move :Gmerge warning to top level function
The old location isn't long for this world.
2020-01-14 22:56:11 -05:00
Tim Pope
305337a9c1 Begin phasing out :Git --paginate special case
This was a mistake.  I took --paginate to be the opposite of --no-pager,
but it forces $PAGER over $GIT_PAGER and pager configuration.  This
defeats the purpose of using it as way to trick :Git into running a
regular command with :terminal.

References https://github.com/tpope/vim-fugitive/issues/1415
2020-01-14 20:43:21 -05:00
Tim Pope
6a638f2392 Match "* Unmerged path" in mergetool
This happens in leiu of a diff when one of the commits adds (or
presumably removes) the file rather than changing it.
2020-01-12 18:53:21 -05:00
Tim Pope
6bc345f6f1 Map cmt to :Git mergetool
References https://github.com/tpope/vim-fugitive/issues/1329
2020-01-10 20:29:58 -05:00
Tim Pope
def982ac4d Softly deprecate :Gmerge for quickfix conflicts 2020-01-10 20:29:15 -05:00
Tim Pope
5fe99dc5df Provide interface for subcommands to set execution options 2020-01-10 19:54:06 -05:00
Tim Pope
394c925381 Fix netrw gx in Fugitive buffers 2020-01-09 21:34:35 -05:00
Tim Pope
4074727343 Really fix packed ref handling in :Gbrowse
References https://github.com/tpope/vim-fugitive/issues/1428
2020-01-06 16:00:21 -05:00
Tim Pope
cfa7bdc82a Handle packed refs in :Gbrowse
Closes https://github.com/tpope/vim-fugitive/issues/1428
2020-01-06 13:33:49 -05:00
Tim Pope
ddd64fc4c5 Provide :Git difftool and :Git mergetool
Closes https://github.com/tpope/vim-fugitive/issues/132
2020-01-05 21:41:18 -05:00
4 changed files with 358 additions and 81 deletions

View File

@@ -33,6 +33,9 @@ Use `:Ggrep` to search the work tree (or any arbitrary commit) with
list. Give them a range (e.g., using visual mode and `:'<,'>Gclog`) to
iterate over every change to that portion of the current file.
`:Git mergetool` loads conflicts into the quickfix list. `:Git difftool` does
the same for any arbitrary set of changes.
`:Gread` is a variant of `git checkout -- filename` that operates on the
buffer rather than the filename. This means you can use `u` to undo it
and you never get any warnings about the file changing outside Vim.
@@ -89,9 +92,8 @@ request the password via a GUI. Fugitive will configure this for you
automatically if you have `ssh-askpass` or `git-gui` installed; otherwise it's
your responsibility to set this up.
As an absolute last resort, you can invoke `:Git --paginate push`. Fugitive
recognizes the pagination request and fires up a `:terminal`, which allows for
interactive password entry.
If you absolutely must type in your password by hand, sidestep Fugitive and
use `:terminal git push`.
[credentials caching]: https://help.github.com/en/articles/caching-your-github-password-in-git

View File

@@ -42,7 +42,7 @@ function! s:Uniq(list) abort
endfunction
function! s:winshell() abort
return has('win32') && &shellcmdflag =~# '^/\|^-Command$'
return has('win32') && &shellcmdflag !~# '^-'
endfunction
function! s:shellesc(arg) abort
@@ -225,6 +225,7 @@ function! s:QuickfixStream(nr, event, title, cmd, first, callback, ...) abort
let contexts = map(copy(buffer), 'get(v:val, "context", {})')
lockvar contexts
call extend(opts.context.items, contexts)
unlet contexts
call s:QuickfixSet(a:nr, remove(buffer, 0, -1), 'a')
redraw
endif
@@ -413,17 +414,24 @@ function! fugitive#PrepareDirEnvArgv(...) abort
return [dir, env, cmd]
endfunction
function! s:BuildEnvPrefix(env) abort
let pre = ''
let env = items(a:env)
if empty(env)
return ''
elseif &shellcmdflag =~# '-Command'
return join(map(env, '"$Env:" . v:val[0] . " = ''" . substitute(v:val[1], "''", "''''", "g") . "''; "'), '')
elseif s:winshell()
return join(map(env, '"set " . substitute(join(v:val, "="), "[&|<>^]", "^^^&", "g") . "& "'), '')
else
return 'env ' . s:shellesc(map(env, 'join(v:val, "=")')) . ' '
endif
endfunction
function! s:BuildShell(dir, env, args) abort
let cmd = copy(a:args)
let tree = s:Tree(a:dir)
let pre = ''
for [var, val] in items(a:env)
if s:winshell()
let pre .= 'set ' . var . '=' . s:shellesc(val) . '& '
else
let pre = (len(pre) ? pre : 'env ') . var . '=' . s:shellesc(val) . ' '
endif
endfor
let pre = s:BuildEnvPrefix(a:env)
if empty(tree) || index(cmd, '--') == len(cmd) - 1
call insert(cmd, '--git-dir=' . FugitiveGitPath(a:dir))
elseif fugitive#GitVersion(1, 8, 5)
@@ -1259,17 +1267,16 @@ function! fugitive#setfperm(url, perm) abort
endfunction
function! s:TempCmd(out, cmd) abort
let prefix = ''
try
let cmd = (type(a:cmd) == type([]) ? fugitive#Prepare(a:cmd) : a:cmd)
let redir = ' > ' . a:out
if s:winshell()
if (s:winshell() || &shellcmdflag ==# '-Command') && !has('nvim')
let cmd_escape_char = &shellxquote == '(' ? '^' : '^^^'
return s:SystemError('cmd /c "' . prefix . s:gsub(cmd, '[<>]', cmd_escape_char . '&') . redir . '"')
return s:SystemError('cmd /c "' . s:gsub(cmd, '[<>%]', cmd_escape_char . '&') . redir . '"')
elseif &shell =~# 'fish'
return s:SystemError(' begin;' . prefix . cmd . redir . ';end ')
return s:SystemError(' begin;' . cmd . redir . ';end ')
else
return s:SystemError(' (' . prefix . cmd . redir . ') ')
return s:SystemError(' (' . cmd . redir . ') ')
endif
endtry
endfunction
@@ -1554,28 +1561,13 @@ function! s:ReplaceCmd(cmd) abort
if exec_error
call s:throw((len(err) ? err : filereadable(temp) ? join(readfile(temp), ' ') : 'unknown error running ' . a:cmd))
endif
let temp = s:Resolve(temp)
let fn = expand('%:p')
silent exe 'keepalt file '.temp
let modelines = &modelines
try
set modelines=0
silent keepjumps noautocmd edit!
finally
let &modelines = modelines
try
silent exe 'keepalt file '.s:fnameescape(fn)
catch /^Vim\%((\a\+)\)\=:E302:/
endtry
call delete(temp)
if s:cpath(fnamemodify(bufname('$'), ':p'), temp)
silent! execute 'bwipeout '.bufnr('$')
endif
endtry
silent exe 'keepalt $read ++edit' s:fnameescape(temp)
silent keepjumps 1delete _
call delete(temp)
endfunction
function! s:QueryLog(refspec) abort
let lines = s:LinesError(['log', '-n', '256', '--format=%h%x09%s', a:refspec, '--'])[0]
let lines = s:LinesError(['log', '-n', '256', '--pretty=format:%h%x09%s', a:refspec, '--'])[0]
call map(lines, 'split(v:val, "\t")')
call map(lines, '{"type": "Log", "commit": v:val[0], "subject": v:val[-1]}')
return lines
@@ -1834,7 +1826,8 @@ function! fugitive#BufReadStatus() abort
if push !=# pull
call s:AddHeader('Push', push)
endif
if empty(s:Tree())
let tree = s:Tree()
if empty(tree)
call s:AddHeader('Bare', 'yes')
endif
call s:AddSection('Rebasing ' . rebasing_head, rebasing)
@@ -1852,7 +1845,8 @@ function! fugitive#BufReadStatus() abort
if &bufhidden ==# ''
setlocal bufhidden=delete
endif
let b:dispatch = ':Gfetch --all'
let b:dispatch = '-compiler=git -dir=' . s:fnameescape(FugitiveVimPath(len(tree) ? tree : s:Dir())) .
\ ' ' . s:UserCommand() . ' ' . s:shellesc(s:AskPassArgs(s:Dir())) . ' fetch --all'
call fugitive#MapJumps()
call s:Map('n', '-', ":<C-U>execute <SID>Do('Toggle',0)<CR>", '<silent>')
call s:Map('x', '-', ":<C-U>execute <SID>Do('Toggle',1)<CR>", '<silent>')
@@ -1915,7 +1909,7 @@ function! fugitive#BufReadStatus() abort
endfor
let b:fugitive_reltime = reltime()
return ''
return 'silent ' . s:DoAutocmd('User FugitiveIndex')
catch /^fugitive:/
return 'echoerr ' . string(v:exception)
endtry
@@ -2018,7 +2012,7 @@ function! fugitive#BufReadCmd(...) abort
setlocal endofline
try
silent doautocmd BufReadPre
silent exe s:DoAutocmd('BufReadPre')
if b:fugitive_type ==# 'tree'
let b:fugitive_display_format = b:fugitive_display_format % 2
if b:fugitive_display_format
@@ -2078,8 +2072,16 @@ function! fugitive#BufReadCmd(...) abort
endtry
setlocal modifiable
let browsex = maparg('<Plug>NetrwBrowseX', 'n')
let remote_check = '\Cnetrw#CheckIfRemote(\%(netrw#GX()\)\=)'
if browsex =~# remote_check
exe 'nnoremap <silent> <buffer> <Plug>NetrwBrowseX' substitute(browsex, remote_check, '0', 'g')
endif
return 'silent ' . s:DoAutocmd('BufReadPost') .
\ (modifiable ? '' : '|setl nomodifiable')
\ (modifiable ? '' : '|setl nomodifiable') . '|silent ' .
\ s:DoAutocmd('User Fugitive' . substitute(b:fugitive_type, '^\l', '\u&', ''))
catch /^fugitive:/
return 'echoerr ' . string(v:exception)
endtry
@@ -2170,19 +2172,26 @@ function! fugitive#Command(line1, line2, range, bang, mods, arg) abort
if exists('*s:' . name . 'Subcommand') && get(args, 1, '') !=# '--help'
try
exe s:DirCheck(dir)
return 'exe ' . string(s:{name}Subcommand(a:line1, a:line2, a:range, a:bang, a:mods, args[1:-1])) . after
let opts = s:{name}Subcommand(a:line1, a:line2, a:range, a:bang, a:mods, args[1:-1])
if type(opts) == type('')
return 'exe ' . string(opts) . after
endif
catch /^fugitive:/
return 'echoerr ' . string(v:exception)
endtry
else
let opts = {}
endif
if a:bang || args[0] =~# '^-P$\|^--no-pager$\|diff\%(tool\)\@!\|log\|^show$' ||
if a:bang || args[0] =~# '^-p$\|^--paginate$\|diff\%(tool\)\@!\|log\|^show$' ||
\ (args[0] ==# 'stash' && get(args, 1, '') ==# 'show') ||
\ (args[0] ==# 'help' || get(args, 1, '') ==# '--help') && !s:HasOpt(args, '--web')
if args[0] =~# '^-p$\|^--paginate$'
call remove(args, 0)
endif
return s:OpenExec((a:line2 > 0 ? a:line2 : '') . (a:line2 ? 'split' : 'edit'), a:mods, args, dir) . after
endif
if s:HasOpt(args, ['add', 'checkout', 'commit', 'stage', 'stash', 'reset'], '-p', '--patch') ||
\ s:HasOpt(args, ['add', 'clean', 'stage'], '-i', '--interactive') ||
\ index(['--paginate', '-p'], args[0]) >= 0
\ s:HasOpt(args, ['add', 'clean', 'stage'], '-i', '--interactive')
let mods = substitute(s:Mods(a:mods), '\<tab\>', '-tab', 'g')
let assign = len(dir) ? '|let b:git_dir = ' . string(dir) : ''
if has('nvim')
@@ -2193,13 +2202,14 @@ function! fugitive#Command(line1, line2, range, bang, mods, arg) abort
return 'exe ' . string(mods . 'terminal ' . (a:line2 ? '' : '++curwin ') . join(map(s:UserCommandList(dir) + args, 's:fnameescape(v:val)'))) . assign . after
endif
endif
let env = get(opts, 'env', {})
if has('gui_running') && !has('win32')
call insert(args, '--no-pager')
endif
let pre = ''
if has('nvim') && executable('env')
let pre .= 'env GIT_TERMINAL_PROMPT=0 '
if has('nvim')
let env.GIT_TERMINAL_PROMPT = '0'
endif
let pre = s:BuildEnvPrefix(env)
return 'exe ' . string('noautocmd !' . escape(pre . s:UserCommand(dir, args), '!#%')) .
\ '|call fugitive#ReloadStatus(' . string(dir) . ', 1)' .
\ after
@@ -3373,7 +3383,7 @@ function! s:CommitSubcommand(line1, line2, range, bang, mods, args, ...) abort
let msgfile = fugitive#Find('.git/COMMIT_EDITMSG', dir)
let outfile = tempname()
try
if s:winshell()
if s:winshell() || &shellcmdflag ==# '-Command'
let command = 'set GIT_EDITOR=false& '
else
let command = 'env GIT_EDITOR=false '
@@ -3528,7 +3538,7 @@ function! s:RebaseSequenceAborter() abort
\ 'echo exec false | cat - "$1" > "$1.fugitive"',
\ 'mv "$1.fugitive" "$1"'],
\ temp)
let s:rebase_sequence_aborter = temp
let s:rebase_sequence_aborter = FugitiveGitPath(temp)
endif
return s:rebase_sequence_aborter
endfunction
@@ -3661,13 +3671,7 @@ function! s:MergeRebase(cmd, bang, mods, args, ...) abort
\ . "%+EXUNG \u0110\u1ed8T %.%#,"
\ . "%+E\u51b2\u7a81 %.%#,"
\ . 'U%\t%f'
if a:cmd =~# '^merge' && empty(args) &&
\ (had_merge_msg || isdirectory(fugitive#Find('.git/rebase-apply', dir)) ||
\ !empty(s:TreeChomp(dir, 'diff-files', '--diff-filter=U')))
let cmd = g:fugitive_git_executable.' diff-files --name-status --diff-filter=U'
else
let cmd = s:UserCommand(dir, argv)
endif
let cmd = s:UserCommand(dir, argv)
if !empty($GIT_SEQUENCE_EDITOR) || has('win32')
let old_sequence_editor = $GIT_SEQUENCE_EDITOR
let $GIT_SEQUENCE_EDITOR = 'true'
@@ -3757,6 +3761,13 @@ function! s:RebaseClean(file) abort
endfunction
function! s:MergeSubcommand(line1, line2, range, bang, mods, args) abort
let dir = s:Dir()
if empty(a:args) && (
\ filereadable(fugitive#Find('.git/MERGE_MSG', dir)) ||
\ isdirectory(fugitive#Find('.git/rebase-apply', dir)) ||
\ !empty(s:TreeChomp(dir, 'diff-files', '--diff-filter=U')))
return 'echohl WarningMsg|echo ":Git merge for loading conflicts is deprecated in favor of :Git mergetool"|echohl NONE|silent Git' . (a:bang ? '!' : '') . ' mergetool'
endif
return s:MergeRebase('merge', a:bang, a:mods, a:args)
endfunction
@@ -3776,7 +3787,7 @@ endfunction
augroup fugitive_merge
autocmd!
autocmd VimLeavePre,BufDelete git-rebase-todo
\ if getbufvar(+expand('<abuf>'), '&bufhidden') ==# 'wipe' |
\ if type(getbufvar(+expand('<abuf>'), 'fugitive_rebase_shas')) == type({}) && getbufvar(+expand('<abuf>'), '&bufhidden') ==# 'wipe' |
\ call s:RebaseClean(expand('<afile>')) |
\ if getfsize(FugitiveFind('.git/rebase-merge/done', +expand('<abuf>'))) == 0 |
\ let s:rebase_continue = [FugitiveGitDir(+expand('<abuf>')), 1] |
@@ -3792,6 +3803,243 @@ augroup fugitive_merge
\ endif
augroup END
" Section: :Git difftool, :Git mergetool
function! s:ToolItems(state, from, to, offsets, text, ...) abort
let items = []
for i in range(len(a:state.diff))
let diff = a:state.diff[i]
let path = (i == len(a:state.diff) - 1) ? a:to : a:from
if empty(path)
return []
endif
let item = {
\ 'valid': a:0 ? a:1 : 1,
\ 'filename': diff.filename . FugitiveVimPath(path),
\ 'lnum': matchstr(get(a:offsets, i), '\d\+'),
\ 'text': a:text}
if len(get(diff, 'module', ''))
let item.module = diff.module . path
endif
call add(items, item)
endfor
let diff = items[0:-2]
let items[-1].context = {'diff': items[0:-2]}
return [items[-1]]
endfunction
function! s:ToolToFrom(str) abort
if a:str =~# ' => '
let str = a:str =~# '{.* => .*}' ? a:str : '{' . a:str . '}'
return [substitute(str, '{.* => \(.*\)}', '\1', ''),
\ substitute(str, '{\(.*\) => .*}', '\1', '')]
else
return [a:str, a:str]
endif
endfunction
function! s:ToolParse(state, line) abort
if type(a:line) !=# type('') || a:state.mode ==# 'hunk' && a:line =~# '^[ +-]'
return []
elseif a:line =~# '^diff '
let a:state.mode = 'diffhead'
let a:state.from = ''
let a:state.to = ''
elseif a:state.mode ==# 'diffhead' && a:line =~# '^--- [^/]'
let a:state.from = a:line[4:-1]
let a:state.to = a:state.from
elseif a:state.mode ==# 'diffhead' && a:line =~# '^+++ [^/]'
let a:state.to = a:line[4:-1]
if empty(get(a:state, 'from', ''))
let a:state.from = a:state.to
endif
elseif a:line[0] ==# '@'
let a:state.mode = 'hunk'
if has_key(a:state, 'from')
let offsets = split(matchstr(a:line, '^@\+ \zs[-+0-9, ]\+\ze @'), ' ')
return s:ToolItems(a:state, a:state.from, a:state.to, offsets, matchstr(a:line, ' @@\+ \zs.*'))
endif
elseif a:line =~# '^\* Unmerged path .'
let file = a:line[16:-1]
return s:ToolItems(a:state, file, file, [], '')
elseif a:line =~# '^[A-Z]\d*\t.\|^:.*\t.'
" --raw, --name-status
let [status; files] = split(a:line, "\t")
return s:ToolItems(a:state, files[0], files[-1], [], a:state.name_only ? '' : status)
elseif a:line =~# '^ \S.* |'
" --stat
let [_, to, changes; __] = matchlist(a:line, '^ \(.\{-\}\) \+|\zs \(.*\)$')
let [to, from] = s:ToolToFrom(to)
return s:ToolItems(a:state, from, to, [], changes)
elseif a:line =~# '^ *\([0-9.]\+%\) .'
" --dirstat
let [_, changes, to; __] = matchlist(a:line, '^ *\([0-9.]\+%\) \(.*\)')
return s:ToolItems(a:state, to, to, [], changes)
elseif a:line =~# '^\(\d\+\|-\)\t\(\d\+\|-\)\t.'
" --numstat
let [_, add, remove, to; __] = matchlist(a:line, '^\(\d\+\|-\)\t\(\d\+\|-\)\t\(.*\)')
let [to, from] = s:ToolToFrom(to)
return s:ToolItems(a:state, from, to, [], add ==# '-' ? 'Binary file' : '+' . add . ' -' . remove, add !=# '-')
elseif a:state.mode !=# 'diffhead' && a:state.mode !=# 'hunk' && len(a:line) || a:line =~# '^git: \|^usage: \|^error: \|^fatal: '
return [{'text': a:line}]
endif
return []
endfunction
function! s:ToolStream(dir, line1, line2, range, bang, mods, args, state, title) abort
let i = 0
let argv = copy(a:args)
let prompt = 1
let state = a:state
while i < len(argv)
let match = matchlist(argv[i], '^\(-[a-zABDFH-KN-RT-Z]\)\ze\(.*\)')
if len(match) && len(match[2])
call insert(argv, match[1])
let argv[i+1] = '-' . match[2]
continue
endif
let arg = argv[i]
if arg =~# '^-t$\|^--tool=\|^--tool-help$\|^--help$'
return {}
elseif arg =~# '^-y$\|^--no-prompt$'
let prompt = 0
call remove(argv, i)
continue
elseif arg ==# '--prompt'
let prompt = 1
call remove(argv, i)
continue
elseif arg =~# '^--\%(no-\)\=\(symlinks\|trust-exit-code\|gui\)$'
call remove(argv, i)
continue
elseif arg ==# '--'
break
endif
let i += 1
endwhile
let a:state.mode = 'init'
let a:state.from = ''
let a:state.to = ''
let exec = s:UserCommandList(a:dir) + ['--no-pager', '-c', 'diff.context=0', 'diff', '--no-ext-diff', '--no-color', '--no-prefix'] + argv
if prompt
return s:QuickfixStream(a:line2, 'difftool', a:title, exec, !a:bang, s:function('s:ToolParse'), a:state)
else
let filename = ''
let cmd = []
let tabnr = tabpagenr() + 1
for line in split(s:SystemError(s:shellesc(exec))[0], "\n")
for item in s:ToolParse(a:state, line)
if len(get(item, 'filename', '')) && item.filename != filename
call add(cmd, 'tabedit ' . s:fnameescape(item.filename))
for i in reverse(range(len(get(item.context, 'diff', []))))
call add(cmd, (i ? 'rightbelow' : 'leftabove') . ' vert Gdiffsplit! ' . s:fnameescape(item.context.diff[i].filename))
endfor
call add(cmd, 'wincmd =')
let filename = item.filename
endif
endfor
endfor
return join(cmd, '|') . (empty(cmd) ? '' : '|' . tabnr . 'tabnext')
endif
endfunction
function! s:MergetoolSubcommand(line1, line2, range, bang, mods, args) abort
let dir = s:Dir()
let i = 0
let argv = copy(a:args)
let prompt = 1
let title = ':Git mergetool' . (len(a:args) ? ' ' . s:fnameescape(a:args) : '')
let cmd = ['diff', '--diff-filter=U']
let state = {'name_only': 0}
let state.diff = [{'prefix': ':2:', 'module': ':2:'}, {'prefix': ':3:', 'module': ':3:'}, {'prefix': ':(top)'}]
call map(state.diff, 'extend(v:val, {"filename": fugitive#Find(v:val.prefix, dir)})')
return s:ToolStream(dir, a:line1, a:line2, a:range, a:bang, a:mods, ['--diff-filter=U'] + a:args, state, title)
endfunction
function! s:DifftoolSubcommand(line1, line2, range, bang, mods, args) abort
let dir = s:Dir()
let i = 0
let argv = copy(a:args)
let commits = []
let cached = 0
let reverse = 1
let prompt = 1
let state = {'name_only': 0}
let merge_base_against = {}
let dash = (index(argv, '--') > i ? ['--'] : [])
while i < len(argv)
let match = matchlist(argv[i], '^\(-[a-zABDFH-KN-RT-Z]\)\ze\(.*\)')
if len(match) && len(match[2])
call insert(argv, match[1])
let argv[i+1] = '-' . match[2]
continue
endif
let arg = argv[i]
if arg ==# '--cached'
let cached = 1
elseif arg ==# '-R'
let reverse = 1
elseif arg ==# '--name-only'
let state.name_only = 1
let argv[0] = '--name-status'
elseif arg ==# '--'
break
elseif arg !~# '^-\|^\.\.\=\%(/\|$\)'
let parsed = s:LinesError(['rev-parse', '--revs-only', substitute(arg, ':.*', '', '')] + dash)[0]
call map(parsed, '{"uninteresting": v:val =~# "^\\^", "prefix": substitute(v:val, "^\\^", "", "") . ":"}')
let merge_base_against = {}
if arg =~# '\.\.\.' && len(parsed) > 2
let display = map(split(arg, '\.\.\.', 1), 'empty(v:val) ? "@" : v:val')
if len(display) == 2
let parsed[0].module = display[1] . ':'
let parsed[1].module = display[0] . ':'
endif
let parsed[2].module = arg . ':'
if empty(commits)
let merge_base_against = parsed[0]
let parsed = [parsed[2]]
endif
elseif arg =~# '\.\.' && len(parsed) == 2
let display = map(split(arg, '\.\.', 1), 'empty(v:val) ? "@" : v:val')
if len(display) == 2
let parsed[0].module = display[0] . ':'
let parsed[1].module = display[1] . ':'
endif
elseif len(parsed) == 1
let parsed[0].module = arg . ':'
endif
call extend(commits, parsed)
endif
let i += 1
endwhile
let title = ':Git difftool' . (len(a:args) ? ' ' . s:fnameescape(a:args) : '')
if len(merge_base_against)
call add(commits, merge_base_against)
endif
let commits = filter(copy(commits), 'v:val.uninteresting') + filter(commits, '!v:val.uninteresting')
if cached
if empty(commits)
call add(commits, {'prefix': '@:', 'module': '@:'})
endif
call add(commits, {'prefix': ':0:', 'module': ':0:'})
elseif len(commits) < 2
call add(commits, {'prefix': ':(top)'})
if len(commits) < 2
call insert(commits, {'prefix': ':0:', 'module': ':0:'})
endif
endif
if reverse
let commits = [commits[-1]] + repeat([commits[0]], len(commits) - 1)
call reverse(commits)
endif
if len(commits) > 2
call add(commits, remove(commits, 0))
endif
call map(commits, 'extend(v:val, {"filename": fugitive#Find(v:val.prefix, dir)})')
let state.diff = commits
return s:ToolStream(dir, a:line1, a:line2, a:range, a:bang, a:mods, argv, state, title)
endfunction
" Section: :Ggrep, :Glog
if !exists('g:fugitive_summary_format')
@@ -3846,11 +4094,7 @@ function! s:GrepSubcommand(line1, line2, range, bang, mods, args) abort
call add(cmd, '--column')
endif
let tree = s:Tree(dir)
if type(a:args) == type([])
let [args, after] = [a:args, '']
else
let [args, after] = s:SplitExpandChain(a:args, tree)
endif
let args = a:args
let prefix = FugitiveVimPath(s:HasOpt(args, '--cached') || empty(tree) ? 'fugitive://' . dir . '//0/' : tree . '/')
let name_only = s:HasOpt(args, '-l', '--files-with-matches', '--name-only', '-L', '--files-without-match')
let title = [listnr < 0 ? ':Ggrep' : ':Glgrep'] + args
@@ -3873,9 +4117,9 @@ function! s:GrepSubcommand(line1, line2, range, bang, mods, args) abort
redraw
endif
if !a:bang && !empty(list)
return (listnr < 0 ? 'c' : 'l').'first' . after
return (listnr < 0 ? 'c' : 'l').'first'
else
return after[1:-1]
return ''
endif
endfunction
@@ -4170,13 +4414,7 @@ function! s:OpenExec(cmd, mods, args, ...) abort
let dir = a:0 ? s:Dir(a:1) : s:Dir()
let temp = tempname()
let columns = get(g:, 'fugitive_columns', 80)
if columns <= 0
let env = ''
elseif s:winshell()
let env = 'set COLUMNS=' . columns . '& '
else
let env = 'env COLUMNS=' . columns . ' '
endif
let env = s:BuildEnvPrefix({'COLUMNS': columns})
silent! execute '!' . escape(env . s:UserCommand(dir, ['--no-pager'] + a:args), '!#%') .
\ (&shell =~# 'csh' ? ' >& ' . temp : ' > ' . temp . ' 2>&1')
redraw!
@@ -5472,7 +5710,12 @@ function! fugitive#BrowseCommand(line1, count, range, bang, mods, arg, args) abo
endif
let i = 0
while commit =~# '^ref: ' && i < 10
let commit = readfile(cdir . '/' . commit[5:-1], '', 1)[0]
let ref_file = cdir . '/' . commit[5:-1]
if getfsize(ref_file) > 0
let commit = readfile(ref_file, '', 1)[0]
else
let commit = fugitive#RevParse(commit[5:-1], dir)
endif
let i -= 1
endwhile
endif
@@ -5694,6 +5937,7 @@ function! fugitive#MapJumps(...) abort
nnoremap <buffer> cm<Space> :Git merge<Space>
nnoremap <buffer> cm<CR> :Git merge<CR>
nnoremap <buffer> cmt :Git mergetool
nnoremap <buffer> <silent> cm? :help fugitive_cm<CR>
nnoremap <buffer> cz<Space> :Git stash<Space>

View File

@@ -20,10 +20,9 @@ that are part of Git repositories).
:G {args} but chdir to the repository tree first. For some
subcommands, a Fugitive command is called instead.
*:Git!*
:Git! {args} Like |:Git|, but capture the output into a temp file,
:Git --no-pager {args} and |:split| that temp file. Use :0Git to
:Git -P {args} |:edit| the temp file instead. A temp file is always
:Git --paginate {args} and |:split| that temp file. Use :0Git to
:Git -p {args} |:edit| the temp file instead. A temp file is always
used for diff and log commands.
*:Gstatus*
@@ -103,9 +102,23 @@ that are part of Git repositories).
:Glgrep[!] [args] |:lgrep|[!] with git-grep as 'grepprg'.
:0Git[!] grep [args]
*:Git-difftool*
:Git[!] difftool [args] Invoke `git diff [args]` and load the changes into the
quickfix list. Each changed hunk gets a separate
quickfix entry unless you pass an option like
--name-only or --name-status. Jumps to the first
change unless [!] is given.
:Git difftool -y [args] Invoke `git diff [args]`, open each changed file in a
new tab, and invoke `:Gdiffsplit!` against the
appropriate commit.
*:Git-mergetool*
:Git mergetool [args] Like |:Git-difftool|, but target merge conflicts.
*:Gclog* *:Glog*
:Gclog[!] [args] Use git-log [args] to load the commit history into the
:Glog[!] [args] |quickfix| list. Jump to the first commit unless [!]
:Glog[!] [args] |quickfix| list. Jumps to the first commit unless [!]
is given.
:{range}Gclog[!] [args] Use git-log -L to load previous revisions of the given
@@ -194,7 +207,7 @@ that are part of Git repositories).
focus on the current window. During a merge conflict,
this is a three-way diff against the "ours" and
"theirs" ancestors. Additional d2o and d3o maps are
provided to to obtain the hunk from the "ours" or
provided to obtain the hunk from the "ours" or
"theirs" ancestor, respectively.
:Gdiffsplit! {object} Like |:Gdiffsplit|, but retain focus on the current

View File

@@ -1,6 +1,6 @@
" fugitive.vim - A Git wrapper so awesome, it should be illegal
" Maintainer: Tim Pope <http://tpo.pe/>
" Version: 3.1
" Version: 3.2
" GetLatestVimScripts: 2975 1 :AutoInstall: fugitive.vim
if exists('g:loaded_fugitive')
@@ -66,8 +66,8 @@ function! FugitivePath(...) abort
endfunction
" FugitiveParse() takes a fugitive:// URL and returns a 2 element list
" containing the Git dir and an object name ("commit:file"). It's effectively
" then inverse of FugitiveFind().
" containing an object name ("commit:file") and the Git dir. It's effectively
" the inverse of FugitiveFind().
function! FugitiveParse(...) abort
let path = s:Slash(a:0 ? a:1 : @%)
if path !~# '^fugitive:'
@@ -103,6 +103,24 @@ function! FugitiveConfig(...) abort
endif
endfunction
" Retrieve a Git configuration value. An optional second argument provides
" the Git dir as with FugitiveFind(). Pass a blank string to limit to the
" global config.
function! FugitiveConfigGet(name, ...) abort
return call('FugitiveConfig', [a:name] + a:000)
endfunction
" Like FugitiveConfigGet(), but return a list of all values.
function! FugitiveConfigGetAll(name, ...) abort
if a:0 && type(a:1) ==# type({})
let config = a:1
else
let config = fugitive#Config(FugitiveGitDir(a:0 ? a:1 : -1))
endif
let name = substitute(a:name, '^[^.]\+\|[^.]\+$', '\L&', 'g')
return copy(get(config, name, []))
endfunction
function! FugitiveRemoteUrl(...) abort
return fugitive#RemoteUrl(a:0 ? a:1 : '', FugitiveGitDir(a:0 > 1 ? a:2 : -1))
endfunction