45 Commits

Author SHA1 Message Date
Tim Pope
62c50ff296 Handle .git in file system root
References https://github.com/tpope/vim-fugitive/issues/908
2017-05-07 15:29:01 -04:00
Tim Pope
c2877d0d5c Show commit message in :Gblame statusline
References #405.
2017-05-02 20:52:19 -04:00
Tim Pope
c640ee78a8 This time I actually tried it 2017-05-02 19:34:47 -04:00
Tim Pope
c9b26e20d3 Fix substitute in jump to file 2017-05-02 19:32:31 -04:00
Tim Pope
79f4a49a94 Fix regexes in jump to file
Closes https://github.com/tpope/vim-fugitive/issues/906
2017-05-02 19:31:17 -04:00
Tim Pope
0cb46585ac Use same character class in all diff matches 2017-05-02 19:31:17 -04:00
Tim Pope
d4df8882c5 Better support for diff.mnemonicPrefix 2017-05-01 14:47:32 -04:00
Tim Pope
d5208d494f Force resolution of symlinked buffers
Closes https://github.com/tpope/vim-fugitive/issues/831
2017-05-01 14:47:32 -04:00
Chris DeLuca
cf248fa66d Fix readme links to Gbrowse plugins
Github changed the way they parse markdown, breaking a bunch of patterns.
2017-05-01 11:41:00 -04:00
Matěj Cepl
779949c255 Add a bit of documentation for d2o and d3o commands
Covering changes in #801.
2017-04-29 12:10:03 -04:00
Jack Nagel
785bb15745 Highlight blame hashes if 'termguicolors' is present 2017-04-27 21:27:20 -04:00
Tim Pope
fbf89773b4 Don't assume support for remote get-url
References https://github.com/tpope/vim-fugitive/issues/844
2017-04-26 13:06:15 -04:00
Geoff Harcourt
02a0be79aa Fix README typo
Recent update b2767d2 misspelled `instaweb`.
2017-04-24 21:09:32 -04:00
Tim Pope
b2767d204b Mention :Gbrowse providers in README
Closes https://github.com/tpope/vim-fugitive/issues/898
2017-04-24 16:07:42 -04:00
Tim Pope
26504eecbd Correctly eliminate trailing space in :Gpush
Note to self: don't test changes to :Gpush by pushing them.
2017-04-23 22:34:41 -04:00
Tim Pope
0d281a2607 Eliminate trailing space in :Gpush 2017-04-23 22:32:01 -04:00
Tim Pope
b2665cc650 Add g:fugitive_git_command
The idea is that g:fugitive_git_command is for user facing commands and
suitable to be changed to something like "hub", while
g:fugitive_git_executable is for low level internals.
2017-04-11 18:54:53 -04:00
Tim Pope
c3052fba84 Heavy handed rhubarb.vim suggestion 2017-04-11 17:59:32 -04:00
dummyunit
4f24757df2 Fix temp_files cache on Windows when TEMP is set to a short path (#893)
If %TEMP% is set to a short path (e.g. "C:\LongDi~1") then tempname()
will return a file name that contains that short path. If that path is
later used as key for entry in s:temp_files dictionary, that entry won't
be found in BufNewFile,BufReadPost events because <afile> is expand()'ed
before it is used as a key for s:temp_files.
In the end, user gets cryptic error message about
"C:\LongDirName\VI12345.tmp.fugitiveblame" not being a git repository
when he tries to open a commit in Gblame window.

To workaround that we expand paths of temp files when adding entries to
s:temp_files. Also, because expand() can't expand short path if it
doesn't exist in the file system, we have to extract the directory part
and expand it separately.
2017-04-05 14:58:03 -04:00
Tim Pope
eb945e9a11 :Gbrowse remote/branch should not resolve upstream
Old behavior: Follow remote/branch to local branch to upstream,
wherever that happens to live.

New behavior: Open branch at remote, without further resolution.
2017-04-03 17:18:20 -04:00
Tim Pope
90cbbf5854 Make unrecognized git type error more informative 2017-04-02 17:04:02 -04:00
Tim Pope
87c1bda4d5 Fix implicit use of v: variable 2017-02-25 17:05:12 -05:00
Tim Pope
c5c1bd66d8 Ensure v:shell_error comes from correct command
Closes https://github.com/tpope/vim-fugitive/issues/648
2017-02-25 16:38:19 -05:00
Jonathan Arnett
f44845e440 Fix for empty buffer :Git command in Neovim (#785)
Detects whether the current buffer is empty; opens a new empty tab if so, a new tab of the same buffer if not.
2017-02-10 12:35:36 -05:00
fREW Schmidt
245ce889e2 Support insteadOf for Gbrowse (#874)
Fixes #873
2017-02-07 18:49:17 -05:00
Nate Bosch
444ba9fda5 Stricter match for fugitive:// buffers (#872)
Fixes #871

It is valid - though odd - to open a file at `some//path`. In that case
the current check for fugitive buffers matches and changes &path
unexpectedly. A stricter match against `://` prevents this.
2017-02-03 11:04:54 -05:00
Tim Pope
b754bc2031 Fix mismatched quotes
References https://github.com/tpope/vim-fugitive/issues/844
2016-11-13 19:04:07 -05:00
Matěj Cepl
b3a8be6975 Add shortcuts for getting hunks from other views of the diff. (#801)
Fixes #798
2016-11-05 12:20:24 -04:00
Tommy Allen
58ed86e434 Use -z for splitting alias config. (#850) 2016-10-21 16:01:34 -04:00
tmsanrinsha
aac85a268e Fix U does not delete Untracked files (#823) 2016-08-08 15:18:18 -04:00
KabbAmine
c00ebd75ac Match printable character in git status
With `LANG=fr_FR.UTF-8`, a non-breakable space character is added to the
text of git status, this commit allows matching it.

Closes #815
2016-07-06 17:50:38 -04:00
Alex Rodionov
50cc268d29 Add --fixup= and --squash= to :Gcommit completion (#811) 2016-06-24 13:45:00 -04:00
canaaerus
4865891565 s:cfile: Match multi-byte characters #806 (#810)
For some locales like de_DE.UTF8 the text of `git status` contains multi-byte characters.
This change allows a subsequent file name to be matched correctly .
2016-06-22 15:46:54 -04:00
Daniel Hahler
3439f999b1 Call s:define_commands directly (#792)
This removes the fugitive_utility augroup, and allows for something like
the following:

> vim --cmd 'au User Fugitive Gbrowse!' path/to/file

Without this patch the user's User autocommand would be run before
fugitive's, and therefore the commands would not be defined already.
2016-05-11 18:01:39 -04:00
Daniel Hahler
6460734b5e Fix typo in s:repo_translate: s/,/./ (#791) 2016-05-11 17:37:45 -04:00
Quinn Strahl
bdd216827a Make :Git open a tab to the left for :terminal
- Users of multiple tabs will find themselves back where they started
  when the terminal closes, instead of in the next tab over
2016-04-14 19:08:11 -04:00
Quinn Strahl
0ac4915cd7 Simplify tabedit invocation for :Gcommit -v
- `-tabedit` does the same thing as `(tabpagenr()-1).'tabedit'`
2016-04-14 19:08:11 -04:00
Ari Pollak
841adb49ad Use "+ instead of "* 2016-04-06 19:51:16 -04:00
Andy Stewart
57afba5bdd Trigger BufWritePost after adding to index with Gwrite
See airblade/vim-gitgutter#278.
2016-03-24 18:54:08 -04:00
Tim Pope
e1ae9effbc Document bang to :Ggrep
Closes https://github.com/tpope/vim-fugitive/issues/767
2016-03-18 11:26:11 -04:00
Tim Pope
19d1c944db Remove unmerged files on :Gstatus U 2016-03-09 21:31:25 -05:00
Tyler Hallada
9315ec694d Document StageUndo key map (U) in :Gstatus 2016-03-09 21:28:26 -05:00
Tim Pope
90250785d1 Call git clean for U on untracked file 2016-03-09 21:26:09 -05:00
Vadim Zeitlin
099d65826e Don't use spaces in Git command to avoid problems under Windows
When using a helper script to make Windows Vim work with Cygwin Git, arguments
containing spaces don't survive being passed through "cmd /c" to this script
and are decomposed into several tokens.

Just use "%x20" instead of spaces in the pretty format to avoid the problem.
2016-03-05 16:14:18 -05:00
Tim Pope
008b957086 Ignore worktree with broken gitdir
References https://github.com/tpope/vim-fugitive/issues/751
2016-02-24 19:29:27 -05:00
3 changed files with 142 additions and 107 deletions

View File

@@ -35,9 +35,15 @@ and you never get any warnings about the file changing outside Vim.
making it like `git add` when called from a work tree file and like making it like `git add` when called from a work tree file and like
`git checkout` when called from the index or a blob in history. `git checkout` when called from the index or a blob in history.
Use `:Gbrowse` to open the current file on GitHub, with optional line Use `:Gbrowse` to open the current file on the web front-end of your favorite
range (try it in visual mode!). If your current repository isn't on hosting provider, with optional line range (try it in visual mode!). Built-in
GitHub, `git instaweb` will be spun up instead. support is provided for `git instaweb`, and plugins are available for popular
providers such as [GitHub][rhubarb.vim], [GitLab][fugitive-gitlab.vim], and
[Bitbucket][fubitive.vim].
[rhubarb.vim]: https://github.com/tpope/vim-rhubarb
[fugitive-gitlab.vim]: https://github.com/shumphrey/fugitive-gitlab.vim
[fubitive.vim]: https://github.com/tommcdo/vim-fubitive
Add `%{fugitive#statusline()}` to `'statusline'` to get an indicator Add `%{fugitive#statusline()}` to `'statusline'` to get an indicator
with the current branch in (surprise!) your statusline. with the current branch in (surprise!) your statusline.

View File

@@ -57,6 +57,10 @@ that are part of Git repositories).
q close status q close status
r reload status r reload status
S |:Gvsplit| S |:Gvsplit|
U |:Git| checkout
U |:Git| checkout HEAD (staged files)
U |:Git| clean (untracked files)
U |:Git| rm (unmerged files)
*fugitive-:Gcommit* *fugitive-:Gcommit*
:Gcommit [args] A wrapper around git-commit. If there is nothing :Gcommit [args] A wrapper around git-commit. If there is nothing
@@ -91,10 +95,10 @@ that are part of Git repositories).
:Gfetch [args] Like |:Gpush|, but for git-fetch. :Gfetch [args] Like |:Gpush|, but for git-fetch.
*fugitive-:Ggrep* *fugitive-:Ggrep*
:Ggrep [args] |:grep| with git-grep as 'grepprg'. :Ggrep[!] [args] |:grep|[!] with git-grep as 'grepprg'.
*fugitive-:Glgrep* *fugitive-:Glgrep*
:Glgrep [args] |:lgrep| with git-grep as 'grepprg'. :Glgrep[!] [args] |:lgrep|[!] with git-grep as 'grepprg'.
*fugitive-:Glog* *fugitive-:Glog*
:Glog [args] Load all previous revisions of the current file into :Glog [args] Load all previous revisions of the current file into
@@ -177,7 +181,9 @@ that are part of Git repositories).
to the right or bottom, depending on 'diffopt' and to the right or bottom, depending on 'diffopt' and
the width of the window relative to 'textwidth'. Use the width of the window relative to 'textwidth'. Use
|do| and |dp| and write to the index file to simulate |do| and |dp| and write to the index file to simulate
"git add --patch". "git add --patch". For the three-way diff, there is
also d2o and d3o pulling the hunk to the middle from
the left or the right window, respectively.
*fugitive-:Gsdiff* *fugitive-:Gsdiff*
:Gsdiff [revision] Like |:Gdiff|, but always split horizontally. :Gsdiff [revision] Like |:Gdiff|, but always split horizontally.
@@ -228,9 +234,7 @@ that are part of Git repositories).
Upstream providers can be added by installing an Upstream providers can be added by installing an
appropriate Vim plugin. For example, GitHub can be appropriate Vim plugin. For example, GitHub can be
supported by installing rhubarb.vim, available at supported by installing rhubarb.vim, available at
<https://github.com/tpope/vim-rhubarb>. (Native <https://github.com/tpope/vim-rhubarb>.
support for GitHub is currently included, but that is
slated to be removed.)
The hosting provider is determined by looking at the The hosting provider is determined by looking at the
remote for the current or specified branch and falls remote for the current or specified branch and falls

View File

@@ -70,6 +70,10 @@ endfunction
let s:git_versions = {} let s:git_versions = {}
function! s:git_command() abort
return get(g:, 'fugitive_git_command', g:fugitive_git_executable)
endfunction
function! fugitive#git_version(...) abort function! fugitive#git_version(...) abort
if !has_key(s:git_versions, g:fugitive_git_executable) if !has_key(s:git_versions, g:fugitive_git_executable)
let s:git_versions[g:fugitive_git_executable] = matchstr(system(g:fugitive_git_executable.' --version'), "\\S\\+\n") let s:git_versions[g:fugitive_git_executable] = matchstr(system(g:fugitive_git_executable.' --version'), "\\S\\+\n")
@@ -112,11 +116,6 @@ function! s:define_commands() abort
endfor endfor
endfunction endfunction
augroup fugitive_utility
autocmd!
autocmd User Fugitive call s:define_commands()
augroup END
let s:abstract_prototype = {} let s:abstract_prototype = {}
" Section: Initialization " Section: Initialization
@@ -132,7 +131,12 @@ function! fugitive#extract_git_dir(path) abort
if s:shellslash(a:path) =~# '^fugitive://.*//' if s:shellslash(a:path) =~# '^fugitive://.*//'
return matchstr(s:shellslash(a:path), '\C^fugitive://\zs.\{-\}\ze//') return matchstr(s:shellslash(a:path), '\C^fugitive://\zs.\{-\}\ze//')
endif endif
let root = s:shellslash(simplify(fnamemodify(a:path, ':p:s?[\/]$??'))) if isdirectory(a:path)
let path = fnamemodify(a:path, ':p:s?[\/]$??')
else
let path = fnamemodify(a:path, ':p:h:s?[\/]$??')
endif
let root = s:shellslash(resolve(path))
let previous = "" let previous = ""
while root !=# previous while root !=# previous
if root =~# '\v^//%([^/]+/?)?$' if root =~# '\v^//%([^/]+/?)?$'
@@ -184,6 +188,9 @@ function! fugitive#detect(path) abort
let dir = fugitive#extract_git_dir(a:path) let dir = fugitive#extract_git_dir(a:path)
if dir !=# '' if dir !=# ''
let b:git_dir = dir let b:git_dir = dir
if empty(fugitive#buffer().path())
silent! exe haslocaldir() ? 'lcd .' : 'cd .'
endif
endif endif
endif endif
if exists('b:git_dir') if exists('b:git_dir')
@@ -200,7 +207,7 @@ function! fugitive#detect(path) abort
nnoremap <buffer> <silent> y<C-G> :call setreg(v:register, <SID>recall())<CR> nnoremap <buffer> <silent> y<C-G> :call setreg(v:register, <SID>recall())<CR>
endif endif
let buffer = fugitive#buffer() let buffer = fugitive#buffer()
if expand('%:p') =~# '//' if expand('%:p') =~# '://'
call buffer.setvar('&path', s:sub(buffer.getvar('&path'), '^\.%(,|$)', '')) call buffer.setvar('&path', s:sub(buffer.getvar('&path'), '^\.%(,|$)', ''))
endif endif
if stridx(buffer.getvar('&tags'), escape(b:git_dir, ', ')) == -1 if stridx(buffer.getvar('&tags'), escape(b:git_dir, ', ')) == -1
@@ -213,6 +220,7 @@ function! fugitive#detect(path) abort
endif endif
try try
let [save_mls, &modelines] = [&mls, 0] let [save_mls, &modelines] = [&mls, 0]
call s:define_commands()
doautocmd User Fugitive doautocmd User Fugitive
finally finally
let &mls = save_mls let &mls = save_mls
@@ -271,6 +279,9 @@ function! s:configured_tree(git_dir) abort
endif endif
elseif filereadable(a:git_dir . '/gitdir') elseif filereadable(a:git_dir . '/gitdir')
let worktree = fnamemodify(readfile(a:git_dir . '/gitdir')[0], ':h') let worktree = fnamemodify(readfile(a:git_dir . '/gitdir')[0], ':h')
if worktree ==# '.'
unlet! worktree
endif
endif endif
if exists('worktree') if exists('worktree')
let s:worktree_for_dir[a:git_dir] = worktree let s:worktree_for_dir[a:git_dir] = worktree
@@ -287,6 +298,9 @@ endfunction
function! s:repo_tree(...) dict abort function! s:repo_tree(...) dict abort
if self.dir() =~# '/\.git$' if self.dir() =~# '/\.git$'
let dir = self.dir()[0:-6] let dir = self.dir()[0:-6]
if dir !~# '/'
let dir .= '/'
endif
else else
let dir = s:configured_tree(self.git_dir) let dir = s:configured_tree(self.git_dir)
endif endif
@@ -344,7 +358,7 @@ function! s:repo_translate(spec) dict abort
elseif filereadable(refs.'remotes/'.a:spec) elseif filereadable(refs.'remotes/'.a:spec)
return refs.'remotes/'.a:spec return refs.'remotes/'.a:spec
elseif filereadable(refs.'remotes/'.a:spec.'/HEAD') elseif filereadable(refs.'remotes/'.a:spec.'/HEAD')
return refs.'remotes/'.a:spec,'/HEAD' return refs.'remotes/'.a:spec.'/HEAD'
else else
try try
let ref = self.rev_parse(matchstr(a:spec,'[^:]*')) let ref = self.rev_parse(matchstr(a:spec,'[^:]*'))
@@ -375,12 +389,14 @@ endfunction
call s:add_methods('repo',['dir','tree','bare','translate','head']) call s:add_methods('repo',['dir','tree','bare','translate','head'])
function! s:repo_git_command(...) dict abort function! s:repo_git_command(...) dict abort
let git = g:fugitive_git_executable . ' --git-dir='.s:shellesc(self.git_dir) let git = s:git_command() . ' --git-dir='.s:shellesc(self.git_dir)
return git.join(map(copy(a:000),'" ".s:shellesc(v:val)'),'') return git.join(map(copy(a:000),'" ".s:shellesc(v:val)'),'')
endfunction endfunction
function! s:repo_git_chomp(...) dict abort function! s:repo_git_chomp(...) dict abort
return s:sub(system(call(self.git_command,a:000,self)),'\n$','') let git = g:fugitive_git_executable . ' --git-dir='.s:shellesc(self.git_dir)
let output = git.join(map(copy(a:000),'" ".s:shellesc(v:val)'),'')
return s:sub(system(output),'\n$','')
endfunction endfunction
function! s:repo_git_chomp_in_tree(...) dict abort function! s:repo_git_chomp_in_tree(...) dict abort
@@ -457,7 +473,7 @@ endfunction
call s:add_methods('repo',['dirglob','superglob']) call s:add_methods('repo',['dirglob','superglob'])
function! s:repo_config(conf) dict abort function! s:repo_config(conf) dict abort
return matchstr(system(s:repo().git_command('config').' '.a:conf),"[^\r\n]*") return matchstr(s:repo().git_chomp('config',a:conf),"[^\r\n]*")
endfun endfun
function! s:repo_user() dict abort function! s:repo_user() dict abort
@@ -469,8 +485,8 @@ endfun
function! s:repo_aliases() dict abort function! s:repo_aliases() dict abort
if !has_key(self,'_aliases') if !has_key(self,'_aliases')
let self._aliases = {} let self._aliases = {}
for line in split(self.git_chomp('config','--get-regexp','^alias[.]'),"\n") for line in split(self.git_chomp('config','-z','--get-regexp','^alias[.]'),"\1")
let self._aliases[matchstr(line,'\.\zs\S\+')] = matchstr(line,' \zs.*') let self._aliases[matchstr(line, '\.\zs.\{-}\ze\n')] = matchstr(line, '\n\zs.*')
endfor endfor
endif endif
return self._aliases return self._aliases
@@ -481,9 +497,9 @@ call s:add_methods('repo',['config', 'user', 'aliases'])
function! s:repo_keywordprg() dict abort function! s:repo_keywordprg() dict abort
let args = ' --git-dir='.escape(self.dir(),"\\\"' ") let args = ' --git-dir='.escape(self.dir(),"\\\"' ")
if has('gui_running') && !has('win32') if has('gui_running') && !has('win32')
return g:fugitive_git_executable . ' --no-pager' . args . ' log -1' return s:git_command() . ' --no-pager' . args . ' log -1'
else else
return g:fugitive_git_executable . args . ' show' return s:git_command() . args . ' show'
endif endif
endfunction endfunction
@@ -694,14 +710,18 @@ function! s:Git(bang, args) abort
if a:bang if a:bang
return s:Edit('edit', 1, a:args) return s:Edit('edit', 1, a:args)
endif endif
let git = g:fugitive_git_executable let git = s:git_command()
if has('gui_running') && !has('win32') if has('gui_running') && !has('win32')
let git .= ' --no-pager' let git .= ' --no-pager'
endif endif
let args = matchstr(a:args,'\v\C.{-}%($|\\@<!%(\\\\)*\|)@=') let args = matchstr(a:args,'\v\C.{-}%($|\\@<!%(\\\\)*\|)@=')
if exists(':terminal') if exists(':terminal')
let dir = s:repo().tree() let dir = s:repo().tree()
tabedit % if expand('%') != ''
-tabedit %
else
-tabnew
endif
execute 'lcd' fnameescape(dir) execute 'lcd' fnameescape(dir)
execute 'terminal' git args execute 'terminal' git args
else else
@@ -860,7 +880,9 @@ function! s:StageUndo() abort
let hash = repo.git_chomp('hash-object', '-w', filename) let hash = repo.git_chomp('hash-object', '-w', filename)
if !empty(hash) if !empty(hash)
if section ==# 'untracked' if section ==# 'untracked'
call delete(s:repo().tree(filename)) call repo.git_chomp_in_tree('clean', '-f', '--', filename)
elseif section ==# 'unmerged'
call repo.git_chomp_in_tree('rm', '--', filename)
elseif section ==# 'unstaged' elseif section ==# 'unstaged'
call repo.git_chomp_in_tree('checkout', '--', filename) call repo.git_chomp_in_tree('checkout', '--', filename)
else else
@@ -1055,13 +1077,14 @@ function! s:Commit(args, ...) abort
else else
noautocmd silent execute '!'.command.' > '.outfile.' 2> '.errorfile noautocmd silent execute '!'.command.' > '.outfile.' 2> '.errorfile
endif endif
let error = v:shell_error
finally finally
execute cd.'`=dir`' execute cd.'`=dir`'
endtry endtry
if !has('gui_running') if !has('gui_running')
redraw! redraw!
endif endif
if !v:shell_error if !error
if filereadable(outfile) if filereadable(outfile)
for line in readfile(outfile) for line in readfile(outfile)
echo line echo line
@@ -1084,7 +1107,7 @@ function! s:Commit(args, ...) abort
if bufname('%') == '' && line('$') == 1 && getline(1) == '' && !&mod if bufname('%') == '' && line('$') == 1 && getline(1) == '' && !&mod
execute 'keepalt edit '.s:fnameescape(msgfile) execute 'keepalt edit '.s:fnameescape(msgfile)
elseif a:args =~# '\%(^\| \)-\%(-verbose\|\w*v\)\>' elseif a:args =~# '\%(^\| \)-\%(-verbose\|\w*v\)\>'
execute 'keepalt '.(tabpagenr()-1).'tabedit '.s:fnameescape(msgfile) execute 'keepalt -tabedit '.s:fnameescape(msgfile)
elseif s:buffer().type() ==# 'index' elseif s:buffer().type() ==# 'index'
execute 'keepalt edit '.s:fnameescape(msgfile) execute 'keepalt edit '.s:fnameescape(msgfile)
execute (search('^#','n')+1).'wincmd+' execute (search('^#','n')+1).'wincmd+'
@@ -1115,7 +1138,7 @@ endfunction
function! s:CommitComplete(A,L,P) abort function! s:CommitComplete(A,L,P) abort
if a:A =~ '^-' || type(a:A) == type(0) " a:A is 0 on :Gcommit -<Tab> if a:A =~ '^-' || type(a:A) == type(0) " a:A is 0 on :Gcommit -<Tab>
let args = ['-C', '-F', '-a', '-c', '-e', '-i', '-m', '-n', '-o', '-q', '-s', '-t', '-u', '-v', '--all', '--allow-empty', '--amend', '--author=', '--cleanup=', '--dry-run', '--edit', '--file=', '--include', '--interactive', '--message=', '--no-verify', '--only', '--quiet', '--reedit-message=', '--reuse-message=', '--signoff', '--template=', '--untracked-files', '--verbose'] let args = ['-C', '-F', '-a', '-c', '-e', '-i', '-m', '-n', '-o', '-q', '-s', '-t', '-u', '-v', '--all', '--allow-empty', '--amend', '--author=', '--cleanup=', '--dry-run', '--edit', '--file=', '--fixup=', '--include', '--interactive', '--message=', '--no-verify', '--only', '--quiet', '--reedit-message=', '--reuse-message=', '--signoff', '--squash=', '--template=', '--untracked-files', '--verbose']
return filter(args,'v:val[0 : strlen(a:A)-1] ==# a:A') return filter(args,'v:val[0 : strlen(a:A)-1] ==# a:A')
else else
return s:repo().superglob(a:A) return s:repo().superglob(a:A)
@@ -1205,7 +1228,7 @@ function! s:Merge(cmd, bang, args) abort
\ !empty(s:repo().git_chomp('diff-files', '--diff-filter=U'))) \ !empty(s:repo().git_chomp('diff-files', '--diff-filter=U')))
let &l:makeprg = g:fugitive_git_executable.' diff-files --name-status --diff-filter=U' let &l:makeprg = g:fugitive_git_executable.' diff-files --name-status --diff-filter=U'
else else
let &l:makeprg = s:sub(g:fugitive_git_executable . ' ' . a:cmd . let &l:makeprg = s:sub(s:git_command() . ' ' . a:cmd .
\ (a:args =~# ' \%(--no-edit\|--abort\|-m\)\>' ? '' : ' --edit') . \ (a:args =~# ' \%(--no-edit\|--abort\|-m\)\>' ? '' : ' --edit') .
\ ' ' . a:args, ' *$', '') \ ' ' . a:args, ' *$', '')
endif endif
@@ -1384,6 +1407,9 @@ function! s:Edit(cmd,bang,...) abort
return 'redraw|echo '.string(':!'.git.' '.args) return 'redraw|echo '.string(':!'.git.' '.args)
else else
let temp = resolve(tempname()) let temp = resolve(tempname())
if has('win32')
let temp = fnamemodify(fnamemodify(temp, ':h'), ':p').fnamemodify(temp, ':t')
endif
let s:temp_files[s:cpath(temp)] = { 'dir': buffer.repo().dir(), 'args': arglist } let s:temp_files[s:cpath(temp)] = { 'dir': buffer.repo().dir(), 'args': arglist }
silent execute a:cmd.' '.temp silent execute a:cmd.' '.temp
if a:cmd =~# 'pedit' if a:cmd =~# 'pedit'
@@ -1563,6 +1589,7 @@ function! s:Write(force,...) abort
unlet! restorewinnr unlet! restorewinnr
let zero = s:repo().translate(':0:'.path) let zero = s:repo().translate(':0:'.path)
silent execute 'doautocmd BufWritePost' s:fnameescape(zero)
for tab in range(1,tabpagenr('$')) for tab in range(1,tabpagenr('$'))
for winnr in range(1,tabpagewinnr(tab,'$')) for winnr in range(1,tabpagewinnr(tab,'$'))
let bufnr = tabpagebuflist(tab)[winnr-1] let bufnr = tabpagebuflist(tab)[winnr-1]
@@ -1625,7 +1652,7 @@ function! s:Dispatch(bang, args)
try try
let b:current_compiler = 'git' let b:current_compiler = 'git'
let &l:errorformat = s:common_efm let &l:errorformat = s:common_efm
let &l:makeprg = g:fugitive_git_executable . ' ' . a:args let &l:makeprg = substitute(s:git_command() . ' ' . a:args, '\s\+$', '', '')
execute cd fnameescape(s:repo().tree()) execute cd fnameescape(s:repo().tree())
if exists(':Make') == 2 if exists(':Make') == 2
noautocmd Make noautocmd Make
@@ -1774,13 +1801,17 @@ function! s:Diff(vert,keepfocus,...) abort
let nr = bufnr('') let nr = bufnr('')
execute 'leftabove '.vert.'split `=fugitive#buffer().repo().translate(s:buffer().expand('':2''))`' execute 'leftabove '.vert.'split `=fugitive#buffer().repo().translate(s:buffer().expand('':2''))`'
execute 'nnoremap <buffer> <silent> dp :diffput '.nr.'<Bar>diffupdate<CR>' execute 'nnoremap <buffer> <silent> dp :diffput '.nr.'<Bar>diffupdate<CR>'
let nr2 = bufnr('')
call s:diffthis() call s:diffthis()
wincmd p wincmd p
execute 'rightbelow '.vert.'split `=fugitive#buffer().repo().translate(s:buffer().expand('':3''))`' execute 'rightbelow '.vert.'split `=fugitive#buffer().repo().translate(s:buffer().expand('':3''))`'
execute 'nnoremap <buffer> <silent> dp :diffput '.nr.'<Bar>diffupdate<CR>' execute 'nnoremap <buffer> <silent> dp :diffput '.nr.'<Bar>diffupdate<CR>'
let nr3 = bufnr('')
call s:diffthis() call s:diffthis()
wincmd p wincmd p
call s:diffthis() call s:diffthis()
execute 'nnoremap <buffer> <silent> d2o :diffget '.nr2.'<Bar>diffupdate<CR>'
execute 'nnoremap <buffer> <silent> d3o :diffget '.nr3.'<Bar>diffupdate<CR>'
return post return post
elseif len(args) elseif len(args)
let arg = join(args, ' ') let arg = join(args, ' ')
@@ -2000,6 +2031,9 @@ function! s:Blame(bang,line1,line2,count,args) abort
endif endif
let top = line('w0') + &scrolloff let top = line('w0') + &scrolloff
let current = line('.') let current = line('.')
if has('win32')
let temp = fnamemodify(fnamemodify(temp, ':h'), ':p').fnamemodify(temp, ':t')
endif
let s:temp_files[s:cpath(temp)] = { 'dir': s:repo().dir(), 'args': cmd } let s:temp_files[s:cpath(temp)] = { 'dir': s:repo().dir(), 'args': cmd }
exe 'keepalt leftabove vsplit '.temp exe 'keepalt leftabove vsplit '.temp
let b:fugitive_blamed_bufnr = bufnr let b:fugitive_blamed_bufnr = bufnr
@@ -2018,6 +2052,7 @@ function! s:Blame(bang,line1,line2,count,args) abort
if exists('+relativenumber') if exists('+relativenumber')
setlocal norelativenumber setlocal norelativenumber
endif endif
let &l:statusline = '%{fugitive#blame_statusline('.bufnr('').')}%<'
execute "vertical resize ".(s:linechars('.\{-\}\ze\s\+\d\+)')+1) execute "vertical resize ".(s:linechars('.\{-\}\ze\s\+\d\+)')+1)
nnoremap <buffer> <silent> <F1> :help fugitive-:Gblame<CR> nnoremap <buffer> <silent> <F1> :help fugitive-:Gblame<CR>
nnoremap <buffer> <silent> g? :help fugitive-:Gblame<CR> nnoremap <buffer> <silent> g? :help fugitive-:Gblame<CR>
@@ -2177,7 +2212,7 @@ endfunction
function! s:RehighlightBlame() abort function! s:RehighlightBlame() abort
for [hash, cterm] in items(s:hash_colors) for [hash, cterm] in items(s:hash_colors)
if !empty(cterm) || has('gui_running') if !empty(cterm) || has('gui_running') || has('termguicolors') && &termguicolors
exe 'hi FugitiveblameHash'.hash.' guifg=#'.hash.get(s:hash_colors, hash, '') exe 'hi FugitiveblameHash'.hash.' guifg=#'.hash.get(s:hash_colors, hash, '')
else else
exe 'hi link FugitiveblameHash'.hash.' Identifier' exe 'hi link FugitiveblameHash'.hash.' Identifier'
@@ -2185,6 +2220,25 @@ function! s:RehighlightBlame() abort
endfor endfor
endfunction endfunction
function! fugitive#blame_statusline(nr) abort
if bufnr('%') != a:nr && !getwinvar(0, '&cursorbind')
return ''
endif
let line = getbufline(a:nr, line('.'))[0]
let hash = matchstr(line, '^\^\=\zs\x\{7}')
if hash =~# '^0*$'
return ''
endif
if type(getbufvar(a:nr, 'fugitive_blame_lookup')) != type({})
call setbufvar(a:nr, 'fugitive_blame_lookup', {})
endif
let lookup = getbufvar(a:nr, 'fugitive_blame_lookup')
if !has_key(lookup, hash)
let lookup[hash] = s:repo().git_chomp('log', '-1', hash, '--pretty=format:'.g:fugitive_summary_format)
endif
return get(lookup, hash, '')
endfunction
" Section: Gbrowse " Section: Gbrowse
call s:command("-bar -bang -range=0 -nargs=* -complete=customlist,s:EditComplete Gbrowse :execute s:Browse(<bang>0,<line1>,<count>,<f-args>)") call s:command("-bar -bang -range=0 -nargs=* -complete=customlist,s:EditComplete Gbrowse :execute s:Browse(<bang>0,<line1>,<count>,<f-args>)")
@@ -2249,10 +2303,11 @@ function! s:Browse(bang,line1,count,...) abort
if path =~# '^\.git/refs/remotes/.' if path =~# '^\.git/refs/remotes/.'
if empty(remote) if empty(remote)
let remote = matchstr(path, '^\.git/refs/remotes/\zs[^/]\+') let remote = matchstr(path, '^\.git/refs/remotes/\zs[^/]\+')
let branch = matchstr(path, '^\.git/refs/remotes/[^/]\+/\zs.\+')
else
let merge = matchstr(path, '^\.git/refs/remotes/[^/]\+/\zs.\+')
let path = '.git/refs/heads/'.merge
endif endif
let merge = matchstr(path, '^\.git/refs/remotes/[^/]\+/\zs.\+')
let branch = ''
let path = '.git/refs/heads/'.merge
elseif path =~# '^\.git/refs/heads/.' elseif path =~# '^\.git/refs/heads/.'
let branch = path[16:-1] let branch = path[16:-1]
elseif !exists('branch') elseif !exists('branch')
@@ -2289,9 +2344,14 @@ function! s:Browse(bang,line1,count,...) abort
if empty(remote) if empty(remote)
let remote = '.' let remote = '.'
let raw = s:repo().git_chomp('config','remote.origin.url') let remote_for_url = 'origin'
else else
let raw = s:repo().git_chomp('config','remote.'.remote.'.url') let remote_for_url = remote
endif
if fugitive#git_version() =~# '^[01]\.|^2\.[0-6]\.'
let raw = s:repo().git_chomp('config','remote.'.remote_for_url.'.url')
else
let raw = s:repo().git_chomp('remote','get-url',remote_for_url)
endif endif
if raw ==# '' if raw ==# ''
let raw = remote let raw = remote
@@ -2315,13 +2375,13 @@ function! s:Browse(bang,line1,count,...) abort
if empty(url) && raw ==# '.' if empty(url) && raw ==# '.'
call s:throw("Instaweb failed to start") call s:throw("Instaweb failed to start")
elseif empty(url) elseif empty(url)
call s:throw('"'.remote."' is not a supported remote") call s:throw("'".remote."' is not a supported remote")
endif endif
let url = s:gsub(url, '[ <>]', '\="%".printf("%02X",char2nr(submatch(0)))') let url = s:gsub(url, '[ <>]', '\="%".printf("%02X",char2nr(submatch(0)))')
if a:bang if a:bang
if has('clipboard') if has('clipboard')
let @* = url let @+ = url
endif endif
return 'echomsg '.string(url) return 'echomsg '.string(url)
elseif exists(':Browse') == 2 elseif exists(':Browse') == 2
@@ -2354,46 +2414,8 @@ function! s:github_url(opts, ...) abort
if repo ==# '' if repo ==# ''
return '' return ''
endif endif
let path = substitute(a:opts.path, '^/', '', '') call s:warn('Install rhubarb.vim for GitHub support')
if index(domains, 'http://' . matchstr(repo, '^[^:/]*')) >= 0 return 'https://github.com/tpope/vim-rhubarb'
let root = 'http://' . s:sub(repo,':','/')
else
let root = 'https://' . s:sub(repo,':','/')
endif
if path =~# '^\.git/refs/heads/'
let branch = a:opts.repo.git_chomp('config','branch.'.path[16:-1].'.merge')[11:-1]
if branch ==# ''
return root . '/commits/' . path[16:-1]
else
return root . '/commits/' . branch
endif
elseif path =~# '^\.git/refs/tags/'
return root . '/releases/tag/' . path[15:-1]
elseif path =~# '^\.git/refs/remotes/[^/]\+/.'
return root . '/commits/' . matchstr(path,'remotes/[^/]\+/\zs.*')
elseif path =~# '.git/\%(config$\|hooks\>\)'
return root . '/admin'
elseif path =~# '^\.git\>'
return root
endif
if a:opts.commit =~# '^\d\=$'
let commit = a:opts.repo.rev_parse('HEAD')
else
let commit = a:opts.commit
endif
if get(a:opts, 'type', '') ==# 'tree' || a:opts.path =~# '/$'
let url = substitute(root . '/tree/' . commit . '/' . path, '/$', '', 'g')
elseif get(a:opts, 'type', '') ==# 'blob' || a:opts.path =~# '[^/]$'
let url = root . '/blob/' . commit . '/' . path
if get(a:opts, 'line2') && a:opts.line1 == a:opts.line2
let url .= '#L' . a:opts.line1
elseif get(a:opts, 'line2')
let url .= '#L' . a:opts.line1 . '-L' . a:opts.line2
endif
else
let url = root . '/commit/' . commit
endif
return url
endfunction endfunction
function! s:instaweb_url(opts) abort function! s:instaweb_url(opts) abort
@@ -2651,7 +2673,7 @@ function! s:BufReadObject() abort
let b:fugitive_type = s:repo().git_chomp('cat-file','-t',hash) let b:fugitive_type = s:repo().git_chomp('cat-file','-t',hash)
endif endif
if b:fugitive_type !~# '^\%(tag\|commit\|tree\|blob\)$' if b:fugitive_type !~# '^\%(tag\|commit\|tree\|blob\)$'
return "echoerr 'fugitive: unrecognized git type'" return "echoerr ".string("fugitive: unrecognized git type '".b:fugitive_type."'")
endif endif
let firstline = getline('.') let firstline = getline('.')
if !exists('b:fugitive_display_format') && b:fugitive_type != 'blob' if !exists('b:fugitive_display_format') && b:fugitive_type != 'blob'
@@ -2686,7 +2708,7 @@ function! s:BufReadObject() abort
if b:fugitive_display_format if b:fugitive_display_format
call s:ReplaceCmd(s:repo().git_command('cat-file',b:fugitive_type,hash)) call s:ReplaceCmd(s:repo().git_command('cat-file',b:fugitive_type,hash))
else else
call s:ReplaceCmd(s:repo().git_command('show','--no-color','--pretty=format:tree %T%nparent %P%nauthor %an <%ae> %ad%ncommitter %cn <%ce> %cd%nencoding %e%n%n%s%n%n%b',hash)) call s:ReplaceCmd(s:repo().git_command('show','--no-color','--pretty=format:tree%x20%T%nparent%x20%P%nauthor%x20%an%x20<%ae>%x20%ad%ncommitter%x20%cn%x20<%ce>%x20%cd%nencoding%x20%e%n%n%s%n%n%b',hash))
keepjumps call search('^parent ') keepjumps call search('^parent ')
if getline('.') ==# 'parent ' if getline('.') ==# 'parent '
silent keepjumps delete_ silent keepjumps delete_
@@ -2838,7 +2860,7 @@ function! s:cfile() abort
elseif getline('.') =~# '^#\trenamed:.* -> ' elseif getline('.') =~# '^#\trenamed:.* -> '
let file = '/'.matchstr(getline('.'),' -> \zs.*') let file = '/'.matchstr(getline('.'),' -> \zs.*')
return [file] return [file]
elseif getline('.') =~# '^#\t[[:alpha:] ]\+: *.' elseif getline('.') =~# '^#\t\(\k\| \)\+\p\?: *.'
let file = '/'.matchstr(getline('.'),': *\zs.\{-\}\ze\%( ([^()[:digit:]]\+)\)\=$') let file = '/'.matchstr(getline('.'),': *\zs.\{-\}\ze\%( ([^()[:digit:]]\+)\)\=$')
return [file] return [file]
elseif getline('.') =~# '^#\t.' elseif getline('.') =~# '^#\t.'
@@ -2895,7 +2917,7 @@ function! s:cfile() abort
let ref = matchstr(getline('.'),'\x\{40\}') let ref = matchstr(getline('.'),'\x\{40\}')
echoerr "warning: unknown context ".matchstr(getline('.'),'^\l*') echoerr "warning: unknown context ".matchstr(getline('.'),'^\l*')
elseif getline('.') =~# '^[+-]\{3\} [ab/]' elseif getline('.') =~# '^[+-]\{3\} [abciow12]\=/'
let ref = getline('.')[4:] let ref = getline('.')[4:]
elseif getline('.') =~# '^[+-]' && search('^@@ -\d\+,\d\+ +\d\+,','bnW') elseif getline('.') =~# '^[+-]' && search('^@@ -\d\+,\d\+ +\d\+,','bnW')
@@ -2909,7 +2931,7 @@ function! s:cfile() abort
let lnum -= 1 let lnum -= 1
endwhile endwhile
let offset += matchstr(getline(lnum), type.'\zs\d\+') let offset += matchstr(getline(lnum), type.'\zs\d\+')
let ref = getline(search('^'.type.'\{3\} [ab]/','bnW'))[4:-1] let ref = getline(search('^'.type.'\{3\} [abciow12]/','bnW'))[4:-1]
let dcmds = [offset, 'normal!zv'] let dcmds = [offset, 'normal!zv']
elseif getline('.') =~# '^rename from ' elseif getline('.') =~# '^rename from '
@@ -2918,22 +2940,22 @@ function! s:cfile() abort
let ref = 'b/'.getline('.')[10:] let ref = 'b/'.getline('.')[10:]
elseif getline('.') =~# '^@@ -\d\+,\d\+ +\d\+,' elseif getline('.') =~# '^@@ -\d\+,\d\+ +\d\+,'
let diff = getline(search('^diff --git \%(a/.*\|/dev/null\) \%(b/.*\|/dev/null\)', 'bcnW')) let diff = getline(search('^diff --git \%([abciow12]/.*\|/dev/null\) \%([abciow12]/.*\|/dev/null\)', 'bcnW'))
let offset = matchstr(getline('.'), '+\zs\d\+') let offset = matchstr(getline('.'), '+\zs\d\+')
let dref = matchstr(diff, '\Cdiff --git \zs\%(a/.*\|/dev/null\)\ze \%(b/.*\|/dev/null\)') let dref = matchstr(diff, '\Cdiff --git \zs\%([abciow12]/.*\|/dev/null\)\ze \%([abciow12]/.*\|/dev/null\)')
let ref = matchstr(diff, '\Cdiff --git \%(a/.*\|/dev/null\) \zs\%(b/.*\|/dev/null\)') let ref = matchstr(diff, '\Cdiff --git \%([abciow12]/.*\|/dev/null\) \zs\%([abciow12]/.*\|/dev/null\)')
let dcmd = 'Gdiff! +'.offset let dcmd = 'Gdiff! +'.offset
elseif getline('.') =~# '^diff --git \%(a/.*\|/dev/null\) \%(b/.*\|/dev/null\)' elseif getline('.') =~# '^diff --git \%([abciow12]/.*\|/dev/null\) \%([abciow12]/.*\|/dev/null\)'
let dref = matchstr(getline('.'),'\Cdiff --git \zs\%(a/.*\|/dev/null\)\ze \%(b/.*\|/dev/null\)') let dref = matchstr(getline('.'),'\Cdiff --git \zs\%([abciow12]/.*\|/dev/null\)\ze \%([abciow12]/.*\|/dev/null\)')
let ref = matchstr(getline('.'),'\Cdiff --git \%(a/.*\|/dev/null\) \zs\%(b/.*\|/dev/null\)') let ref = matchstr(getline('.'),'\Cdiff --git \%([abciow12]/.*\|/dev/null\) \zs\%([abciow12]/.*\|/dev/null\)')
let dcmd = 'Gdiff!' let dcmd = 'Gdiff!'
elseif getline('.') =~# '^index ' && getline(line('.')-1) =~# '^diff --git \%(a/.*\|/dev/null\) \%(b/.*\|/dev/null\)' elseif getline('.') =~# '^index ' && getline(line('.')-1) =~# '^diff --git \%([abciow12]/.*\|/dev/null\) \%([abciow12]/.*\|/dev/null\)'
let line = getline(line('.')-1) let line = getline(line('.')-1)
let dref = matchstr(line,'\Cdiff --git \zs\%(a/.*\|/dev/null\)\ze \%(b/.*\|/dev/null\)') let dref = matchstr(line,'\Cdiff --git \zs\%([abciow12]/.*\|/dev/null\)\ze \%([abciow12]/.*\|/dev/null\)')
let ref = matchstr(line,'\Cdiff --git \%(a/.*\|/dev/null\) \zs\%(b/.*\|/dev/null\)') let ref = matchstr(line,'\Cdiff --git \%([abciow12]/.*\|/dev/null\) \zs\%([abciow12]/.*\|/dev/null\)')
let dcmd = 'Gdiff!' let dcmd = 'Gdiff!'
elseif line('$') == 1 && getline('.') =~ '^\x\{40\}$' elseif line('$') == 1 && getline('.') =~ '^\x\{40\}$'
@@ -2946,18 +2968,21 @@ function! s:cfile() abort
let ref = '' let ref = ''
endif endif
if myhash ==# '' let prefixes = {
let ref = s:sub(ref,'^a/','HEAD:') \ '1': '',
let ref = s:sub(ref,'^b/',':0:') \ '2': '',
if exists('dref') \ 'b': ':0:',
let dref = s:sub(dref,'^a/','HEAD:') \ 'i': ':0:',
endif \ 'o': '',
else \ 'w': ''}
let ref = s:sub(ref,'^a/',myhash.'^:')
let ref = s:sub(ref,'^b/',myhash.':') if len(myhash)
if exists('dref') let prefixes.a = myhash.'^:'
let dref = s:sub(dref,'^a/',myhash.'^:') let prefixes.b = myhash.':'
endif endif
let ref = substitute(ref, '^\(\w\)/', '\=get(prefixes, submatch(1), "HEAD:")', '')
if exists('dref')
let dref = substitute(dref, '^\(\w\)/', '\=get(prefixes, submatch(1), "HEAD:")', '')
endif endif
if ref ==# '/dev/null' if ref ==# '/dev/null'
@@ -3065,7 +3090,7 @@ function! fugitive#foldtext() abort
endif endif
endfor endfor
if filename ==# '' if filename ==# ''
let filename = matchstr(getline(v:foldstart), '^diff .\{-\} a/\zs.*\ze b/') let filename = matchstr(getline(v:foldstart), '^diff .\{-\} [abciow12]/\zs.*\ze [abciow12]/')
endif endif
if filename ==# '' if filename ==# ''
let filename = getline(v:foldstart)[5:-1] let filename = getline(v:foldstart)[5:-1]