64 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
Tim Pope
16c2b7abb9 Support worktrees
Closes https://github.com/tpope/vim-fugitive/issues/655
2016-02-24 16:20:52 -05:00
Tim Pope
1e3f1103d9 DRY up refs/ paths 2016-02-24 15:53:51 -05:00
Tim Pope
9835920a3c Use includeexpr on default <cfile>
Closes https://github.com/tpope/vim-fugitive/issues/744
2016-01-22 20:03:58 -05:00
Tim Pope
fd36aa9c61 Fix issue extracting remote 2016-01-08 17:05:54 -05:00
Tim Pope
4dd41688cf Entertain P as a p alternative in :Gstatus
This could potentially free up `p` as "open in new tab", which would
correspond nicely with `vim -p`.
2016-01-01 16:55:17 -05:00
Tim Pope
18d6d1ab82 Overhaul :Gbrowse remote handling 2015-12-26 19:53:07 -05:00
Tim Pope
9ce67cdc93 Always pass commit SHA to :Gbrowse handlers 2015-12-26 15:09:08 -05:00
Tim Pope
bf04261080 Revert "Remove guard against index stage in :Gbrowse handler"
This reverts commit 14daf094d9.  My
assertion was wrong; commit will no longer be an index stage but it
still might be an empty string.
2015-12-26 14:54:35 -05:00
Tim Pope
52d180af0a Include trailing / in tree paths for :Gbrowse handlers 2015-12-26 14:37:45 -05:00
Tim Pope
14daf094d9 Remove guard against index stage in :Gbrowse handler
This parameter can now always be directly used within a URL, without any
sanity checking
2015-12-26 14:36:39 -05:00
Tim Pope
ac904e806d Don't pass stage number as commit to :Gbrowse handler 2015-12-26 14:18:00 -05:00
Tim Pope
9f768cd3bc Minimum viable URL escaping in :Gbrowse
Closes https://github.com/tpope/vim-fugitive/issues/703.
2015-12-26 14:11:54 -05:00
Tim Pope
09cdce7add Fix jump to file for tree at root of commit
Closes https://github.com/tpope/vim-fugitive/issues/735
2015-12-23 21:27:43 -05:00
Tim Pope
8851b8fe64 Fix jump from diff to file
This code hasn't been touched in 4 years; how did it break?!
2015-12-15 21:19:33 -05:00
Tim Pope
cfa485ede7 Better support for binary file grep results 2015-12-15 19:01:40 -05:00
Tim Pope
207c643ea4 Bring GitHub handler in line with rhubarb.vim
Closes https://github.com/tpope/vim-fugitive/issues/730
2015-12-11 16:38:05 -05:00
Tim Pope
cac2c8ef8e Fix instaweb current buffer assumption 2015-12-01 18:41:29 -05:00
Tim Pope
a9a22e0e4e Never :Gedit with a trailing slash 2015-12-01 18:35:25 -05:00
Tim Pope
c3e918072f Accommodate @ as alias for HEAD 2015-12-01 18:06:38 -05:00
3 changed files with 273 additions and 223 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.
@@ -221,20 +227,20 @@ that are part of Git repositories).
*fugitive-:Gbrowse* *fugitive-:Gbrowse*
:Gbrowse Open the current file, blob, tree, commit, or tag :Gbrowse Open the current file, blob, tree, commit, or tag
in your browser at the upstream hosting provider in your browser at the upstream hosting provider.
indicated by the "origin" remote. If a range is If a range is given, it is appropriately appended to
given, it is appropriately appended to the URL as an the URL as an anchor.
anchor.
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.)
If no upstream support is available, a local instance The hosting provider is determined by looking at the
of git-instaweb will be started and used instead. remote for the current or specified branch and falls
back to "origin". In the special case of a "."
remote, a local instance of git-instaweb will be
started and used.
:Gbrowse {revision} Like :Gbrowse, but for a given |fugitive-revision|. A :Gbrowse {revision} Like :Gbrowse, but for a given |fugitive-revision|. A
useful value here is -, which ties the URL to the useful value here is -, which ties the URL to the

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,25 +116,27 @@ 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
function! fugitive#is_git_dir(path) abort function! fugitive#is_git_dir(path) abort
let path = s:sub(a:path, '[\/]$', '') . '/' let path = s:sub(a:path, '[\/]$', '') . '/'
return isdirectory(path.'objects') && isdirectory(path.'refs') && getfsize(path.'HEAD') > 10 return getfsize(path.'HEAD') > 10 && (
\ isdirectory(path.'objects') && isdirectory(path.'refs') ||
\ getftype(path.'commondir') ==# 'file')
endfunction endfunction
function! fugitive#extract_git_dir(path) abort 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^//%([^/]+/?)?$'
@@ -182,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')
@@ -198,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
@@ -211,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
@@ -265,9 +275,17 @@ function! s:configured_tree(git_dir) abort
let config = readfile(config_file,'',10) let config = readfile(config_file,'',10)
call filter(config,'v:val =~# "^\\s*worktree *="') call filter(config,'v:val =~# "^\\s*worktree *="')
if len(config) == 1 if len(config) == 1
let s:worktree_for_dir[a:git_dir] = matchstr(config[0], '= *\zs.*') let worktree = matchstr(config[0], '= *\zs.*')
let s:dir_for_worktree[s:worktree_for_dir[a:git_dir]] = a:git_dir
endif endif
elseif filereadable(a:git_dir . '/gitdir')
let worktree = fnamemodify(readfile(a:git_dir . '/gitdir')[0], ':h')
if worktree ==# '.'
unlet! worktree
endif
endif
if exists('worktree')
let s:worktree_for_dir[a:git_dir] = worktree
let s:dir_for_worktree[s:worktree_for_dir[a:git_dir]] = a:git_dir
endif endif
endif endif
if s:worktree_for_dir[a:git_dir] =~# '^\.' if s:worktree_for_dir[a:git_dir] =~# '^\.'
@@ -280,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
@@ -298,86 +319,55 @@ function! s:repo_bare() dict abort
endif endif
endfunction endfunction
function! s:repo_disambiguate(spec) dict abort
if a:spec =~# '^:[0-3]:\|^:\=/\|^:\=$\|^\x\{40\}$'
return a:spec
elseif a:spec =~# '^:'
return ':0' . a:spec
elseif a:spec ==# '^\.'
return '/' . a:spec
elseif a:spec =~# '^[^:~^]*\.\.'
let before = self.qualify_ref(matchstr(a:spec, '.\{-\}\ze\.\.'))
let after = self.qualify_ref(matchstr(a:spec, '\.\.\.\=\zs.*'))
if before =~# '^/' || after =~# '^/'
return '/' . a:spec
else
return before . matchstr(a:spec, '\.\.\.\=') . after
endif
endif
let head = s:sub(a:spec, '[:~^].*|\@\{.*', '')
let rest = strpart(a:spec, len(head))
if head ==# '@'
return 'HEAD'.rest
endif
if head =~# "[[?*\001-\037\177]".'\|\%([./]\|\.lock\)\%(/\|$\)'
return '/' . a:spec
endif
let packed = {}
if filereadable(self.dir('packed-refs'))
for [v, k] in map(readfile(self.dir('packed-refs')), 'split(v:val, " ")')
let packed[k] = v
endfor
endif
for pattern in ['%s', 'refs/%s', 'refs/tags/%s', 'refs/heads/%s', 'refs/remotes/%s', 'refs/remotes/%s/HEAD']
let ref = printf(pattern, head)
if filereadable(self.dir(ref)) || has_key(packed, ref)
return ref . rest
endif
endfor
let tag = matchstr(head, '.*\ze-\d\+-g\x\+$')
if !empty(tag) && (filereadable(self.dir('refs/tags/'.tag)) || has_key(packed, ref))
return head . rest
endif
if head =~# '^\x\{4,40\}$'
try
return self.rev_parse(head) . rest
catch /^fugitive:/
endtry
endif
return '/' . a:spec
endfunction
function! s:repo_translate(spec) dict abort function! s:repo_translate(spec) dict abort
let spec = self.disambiguate(a:spec) let refs = self.dir('refs/')
if spec =~# '^/\=\.git$' && self.bare() if filereadable(self.dir('commondir'))
let refs = simplify(self.dir(get(readfile(self.dir('commondir'), 1), 0, ''))) . '/refs/'
endif
if a:spec ==# '.' || a:spec ==# '/.'
return self.bare() ? self.dir() : self.tree()
elseif a:spec =~# '^/\=\.git$' && self.bare()
return self.dir() return self.dir()
elseif spec =~# '^/\=\.git/' elseif a:spec =~# '^/\=\.git/'
return self.dir(s:sub(spec, '^/=\.git/', '')) return self.dir(s:sub(a:spec, '^/=\.git/', ''))
elseif spec =~# '^/' elseif a:spec =~# '^/'
return self.tree().spec return self.tree().a:spec
elseif spec =~# '^:[0-3]:' elseif a:spec =~# '^:[0-3]:'
return 'fugitive://'.self.dir().'//'.spec[1].'/'.spec[3:-1] return 'fugitive://'.self.dir().'//'.a:spec[1].'/'.a:spec[3:-1]
elseif spec ==# ':' elseif a:spec ==# ':'
if $GIT_INDEX_FILE =~# '/[^/]*index[^/]*\.lock$' && fnamemodify($GIT_INDEX_FILE,':p')[0:strlen(self.dir())] ==# self.dir('') && filereadable($GIT_INDEX_FILE) if $GIT_INDEX_FILE =~# '/[^/]*index[^/]*\.lock$' && fnamemodify($GIT_INDEX_FILE,':p')[0:strlen(self.dir())] ==# self.dir('') && filereadable($GIT_INDEX_FILE)
return fnamemodify($GIT_INDEX_FILE,':p') return fnamemodify($GIT_INDEX_FILE,':p')
else else
return self.dir('index') return self.dir('index')
endif endif
elseif spec =~# '^:/' elseif a:spec =~# '^:/'
let ref = self.rev_parse(matchstr(spec,'.[^:]*')) let ref = self.rev_parse(matchstr(a:spec,'.[^:]*'))
return 'fugitive://'.self.dir().'//'.ref return 'fugitive://'.self.dir().'//'.ref
endif elseif a:spec =~# '^:'
return 'fugitive://'.self.dir().'//0/'.a:spec[1:-1]
let ref = matchstr(spec,'[^:]*') elseif a:spec ==# '@'
let path = s:sub(matchstr(spec,':.*'),'^:','/') return self.dir('HEAD')
if empty(path) && ref !~# '[~^]' elseif a:spec =~# 'HEAD\|^refs/' && a:spec !~ ':' && filereadable(refs . '../' . a:spec)
if filereadable(self.dir(ref)) return simplify(refs . '../' . a:spec)
return self.dir(ref) elseif filereadable(refs.a:spec)
return refs.a:spec
elseif filereadable(refs.'tags/'.a:spec)
return refs.'tags/'.a:spec
elseif filereadable(refs.'heads/'.a:spec)
return refs.'heads/'.a:spec
elseif filereadable(refs.'remotes/'.a:spec)
return refs.'remotes/'.a:spec
elseif filereadable(refs.'remotes/'.a:spec.'/HEAD')
return refs.'remotes/'.a:spec.'/HEAD'
else else
return self.dir('packed-refs') try
let ref = self.rev_parse(matchstr(a:spec,'[^:]*'))
let path = s:sub(matchstr(a:spec,':.*'),'^:','/')
return 'fugitive://'.self.dir().'//'.ref.path
catch /^fugitive:/
return self.tree(a:spec)
endtry
endif endif
endif
return 'fugitive://'.self.dir().'//'.self.rev_parse(ref).path
endfunction endfunction
function! s:repo_head(...) dict abort function! s:repo_head(...) dict abort
@@ -396,15 +386,17 @@ function! s:repo_head(...) dict abort
return branch return branch
endfunction endfunction
call s:add_methods('repo',['dir','tree','bare','disambiguate','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
@@ -481,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
@@ -493,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
@@ -505,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
@@ -718,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
@@ -884,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
@@ -1079,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
@@ -1108,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+'
@@ -1139,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)
@@ -1229,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
@@ -1295,7 +1294,7 @@ function! s:Grep(cmd,bang,arg) abort
try try
execute cd.'`=s:repo().tree()`' execute cd.'`=s:repo().tree()`'
let &grepprg = s:repo().git_command('--no-pager', 'grep', '-n', '--no-color') let &grepprg = s:repo().git_command('--no-pager', 'grep', '-n', '--no-color')
let &grepformat = '%f:%l:%m,%f' let &grepformat = '%f:%l:%m,%m %f match%ts,%f'
exe a:cmd.'! '.escape(matchstr(a:arg,'\v\C.{-}%($|[''" ]\@=\|)@='),'|') exe a:cmd.'! '.escape(matchstr(a:arg,'\v\C.{-}%($|[''" ]\@=\|)@='),'|')
let list = a:cmd =~# '^l' ? getloclist(0) : getqflist() let list = a:cmd =~# '^l' ? getloclist(0) : getqflist()
for entry in list for entry in list
@@ -1408,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'
@@ -1443,6 +1445,9 @@ function! s:Edit(cmd,bang,...) abort
catch /^fugitive:/ catch /^fugitive:/
return 'echoerr v:errmsg' return 'echoerr v:errmsg'
endtry endtry
if file !~# '^fugitive:'
let file = s:sub(file, '/$', '')
endif
if a:cmd ==# 'read' if a:cmd ==# 'read'
return 'silent %delete_|read '.s:fnameescape(file).'|silent 1delete_|diffupdate|'.line('.') return 'silent %delete_|read '.s:fnameescape(file).'|silent 1delete_|diffupdate|'.line('.')
else else
@@ -1584,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]
@@ -1646,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
@@ -1795,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, ' ')
@@ -2021,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
@@ -2039,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>
@@ -2198,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'
@@ -2206,13 +2220,39 @@ 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 -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>)")
function! s:Browse(bang,line1,count,...) abort function! s:Browse(bang,line1,count,...) abort
try try
let rev = a:0 ? substitute(join(a:000, ' '),'@[[:alnum:]_-]*\%(://.\{-\}\)\=$','','') : '' let validremote = '\.\|\.\=/.*\|[[:alnum:]_-]\+\%(://.\{-\}\)\='
if a:0
let remote = matchstr(join(a:000, ' '),'@\zs\%('.validremote.'\)$')
let rev = substitute(join(a:000, ' '),'@\%('.validremote.'\)$','','')
else
let remote = ''
let rev = ''
endif
if rev ==# '' if rev ==# ''
let expanded = s:buffer().rev() let expanded = s:buffer().rev()
elseif rev ==# ':' elseif rev ==# ':'
@@ -2223,10 +2263,11 @@ function! s:Browse(bang,line1,count,...) abort
let full = s:repo().translate(expanded) let full = s:repo().translate(expanded)
let commit = '' let commit = ''
if full =~# '^fugitive://' if full =~# '^fugitive://'
let commit = matchstr(full,'://.*//\zs\w\+') let commit = matchstr(full,'://.*//\zs\w\w\+')
let path = matchstr(full,'://.*//\w\+\zs/.*') let path = matchstr(full,'://.*//\w\+\zs/.*')
if commit =~ '..' if commit =~ '..'
let type = s:repo().git_chomp('cat-file','-t',commit.s:sub(path,'^/',':')) let type = s:repo().git_chomp('cat-file','-t',commit.s:sub(path,'^/',':'))
let branch = matchstr(expanded, '^[^:]*')
else else
let type = 'blob' let type = 'blob'
endif endif
@@ -2244,6 +2285,9 @@ function! s:Browse(bang,line1,count,...) abort
let type = 'blob' let type = 'blob'
endif endif
endif endif
if type ==# 'tree' && !empty(path)
let path = s:sub(path, '/\=$', '/')
endif
if path =~# '^\.git/.*HEAD' && filereadable(s:repo().dir(path[5:-1])) if path =~# '^\.git/.*HEAD' && filereadable(s:repo().dir(path[5:-1]))
let body = readfile(s:repo().dir(path[5:-1]))[0] let body = readfile(s:repo().dir(path[5:-1]))[0]
if body =~# '^\x\{40\}$' if body =~# '^\x\{40\}$'
@@ -2255,35 +2299,60 @@ function! s:Browse(bang,line1,count,...) abort
endif endif
endif endif
if a:0 && join(a:000, ' ') =~# '@[[:alnum:]_-]*\%(://.\{-\}\)\=$' let merge = ''
let remote = matchstr(join(a:000, ' '),'@\zs[[:alnum:]_-]\+\%(://.\{-\}\)\=$') if path =~# '^\.git/refs/remotes/.'
elseif path =~# '^\.git/refs/remotes/.' 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 else
let remote = 'origin' let merge = matchstr(path, '^\.git/refs/remotes/[^/]\+/\zs.\+')
let branch = matchstr(rev,'^[[:alnum:]/._-]\+\ze[:^~@]') let path = '.git/refs/heads/'.merge
if branch ==# '' && path =~# '^\.git/refs/\w\+/'
let branch = s:sub(path,'^\.git/refs/\w+/','')
endif endif
if filereadable(s:repo().dir('refs/remotes/'.branch)) elseif path =~# '^\.git/refs/heads/.'
let remote = matchstr(branch,'[^/]\+') let branch = path[16:-1]
let rev = rev[strlen(remote)+1:-1] elseif !exists('branch')
else let branch = s:repo().head()
if branch ==# ''
let branch = matchstr(s:repo().head_ref(),'\<refs/heads/\zs.*')
endif endif
if branch != '' if !empty(branch)
let remote = s:repo().git_chomp('config','branch.'.branch.'.remote') let r = s:repo().git_chomp('config','branch.'.branch.'.remote')
if remote =~# '^\.\=$' let m = s:repo().git_chomp('config','branch.'.branch.'.merge')[11:-1]
let remote = 'origin' if r ==# '.' && !empty(m)
elseif rev[0:strlen(branch)-1] ==# branch && rev[strlen(branch)] =~# '[:^~@]' let r2 = s:repo().git_chomp('config','branch.'.m.'.remote')
let rev = s:repo().git_chomp('config','branch.'.branch.'.merge')[11:-1] . rev[strlen(branch):-1] if r2 !~# '^\.\=$'
let r = r2
let m = s:repo().git_chomp('config','branch.'.m.'.merge')[11:-1]
endif endif
endif endif
if empty(remote)
let remote = r
endif
if r ==# '.' || r ==# remote
let merge = m
if path =~# '^\.git/refs/heads/.'
let path = '.git/refs/heads/'.merge
endif
endif endif
endif endif
let raw = s:repo().git_chomp('config','remote.'.remote.'.url') if empty(commit) && path !~# '^\.git/'
if a:line1 && !a:count && !empty(merge)
let commit = merge
else
let commit = s:repo().rev_parse('HEAD')
endif
endif
if empty(remote)
let remote = '.'
let remote_for_url = 'origin'
else
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
if raw ==# '' if raw ==# ''
let raw = remote let raw = remote
endif endif
@@ -2292,7 +2361,7 @@ function! s:Browse(bang,line1,count,...) abort
let url = call(Handler, [{ let url = call(Handler, [{
\ 'repo': s:repo(), \ 'repo': s:repo(),
\ 'remote': raw, \ 'remote': raw,
\ 'revision': rev, \ 'revision': 'No longer provided',
\ 'commit': commit, \ 'commit': commit,
\ 'path': path, \ 'path': path,
\ 'type': type, \ 'type': type,
@@ -2303,13 +2372,16 @@ function! s:Browse(bang,line1,count,...) abort
endif endif
endfor endfor
if empty(url) if empty(url) && raw ==# '.'
call s:throw("Instaweb failed to start and '".remote."' is not a supported remote") call s:throw("Instaweb failed to start")
elseif empty(url)
call s:throw("'".remote."' is not a supported remote")
endif endif
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
@@ -2342,55 +2414,14 @@ function! s:github_url(opts, ...) abort
if repo ==# '' if repo ==# ''
return '' return ''
endif endif
let path = 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/' . matchstr(path,'[^/]\+$')
elseif path =~# '^\.git/refs/.'
return root . '/commits/' . matchstr(path,'[^/]\+$')
elseif path =~# '.git/\%(config$\|hooks\>\)'
return root . '/admin'
elseif path =~# '^\.git\>'
return root
endif
if a:opts.revision =~# '^[[:alnum:]._-]\+:'
let commit = matchstr(a:opts.revision,'^[^:]*')
elseif a:opts.commit =~# '^\d\=$'
let local = matchstr(a:opts.repo.head_ref(),'\<refs/heads/\zs.*')
let commit = a:opts.repo.git_chomp('config','branch.'.local.'.merge')[11:-1]
if commit ==# ''
let commit = local
endif
else
let commit = a:opts.commit
endif
if a:opts.type == 'tree'
let url = s:sub(root . '/tree/' . commit . '/' . path,'/$','')
elseif a:opts.type == 'blob'
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
if a:opts.remote !=# '.'
return ''
endif
let output = a:opts.repo.git_chomp('instaweb','-b','unknown') let output = a:opts.repo.git_chomp('instaweb','-b','unknown')
if output =~# 'http://' if output =~# 'http://'
let root = matchstr(output,'http://.*').'/?p='.fnamemodify(a:opts.repo.dir(),':t') let root = matchstr(output,'http://.*').'/?p='.fnamemodify(a:opts.repo.dir(),':t')
@@ -2409,10 +2440,8 @@ function! s:instaweb_url(opts) abort
endif endif
let url .= ';h=' . a:opts.repo.rev_parse(a:opts.commit . (a:opts.path == '' ? '' : ':' . a:opts.path)) let url .= ';h=' . a:opts.repo.rev_parse(a:opts.commit . (a:opts.path == '' ? '' : ':' . a:opts.path))
else else
if a:opts.type ==# 'blob' if a:opts.type ==# 'blob' && empty(a:opts.commit)
let tmp = tempname() let url .= ';h='.a:opts.repo.git_chomp('hash-object', '-w', a:opts.path)
silent execute 'write !'.a:opts.repo.git_command('hash-object','-w','--stdin').' > '.tmp
let url .= ';h=' . readfile(tmp)[0]
else else
try try
let url .= ';h=' . a:opts.repo.rev_parse((a:opts.commit == '' ? 'HEAD' : ':' . a:opts.commit) . ':' . a:opts.path) let url .= ';h=' . a:opts.repo.rev_parse((a:opts.commit == '' ? 'HEAD' : ':' . a:opts.commit) . ':' . a:opts.path)
@@ -2551,6 +2580,8 @@ function! s:BufReadIndex() abort
nnoremap <buffer> <silent> dv :<C-U>execute <SID>StageDiff('Gvdiff')<CR> nnoremap <buffer> <silent> dv :<C-U>execute <SID>StageDiff('Gvdiff')<CR>
nnoremap <buffer> <silent> p :<C-U>execute <SID>StagePatch(line('.'),line('.')+v:count1-1)<CR> nnoremap <buffer> <silent> p :<C-U>execute <SID>StagePatch(line('.'),line('.')+v:count1-1)<CR>
xnoremap <buffer> <silent> p :<C-U>execute <SID>StagePatch(line("'<"),line("'>"))<CR> xnoremap <buffer> <silent> p :<C-U>execute <SID>StagePatch(line("'<"),line("'>"))<CR>
nnoremap <buffer> <silent> P :<C-U>execute <SID>StagePatch(line('.'),line('.')+v:count1-1)<CR>
xnoremap <buffer> <silent> P :<C-U>execute <SID>StagePatch(line("'<"),line("'>"))<CR>
nnoremap <buffer> <silent> q :<C-U>if bufnr('$') == 1<Bar>quit<Bar>else<Bar>bdelete<Bar>endif<CR> nnoremap <buffer> <silent> q :<C-U>if bufnr('$') == 1<Bar>quit<Bar>else<Bar>bdelete<Bar>endif<CR>
nnoremap <buffer> <silent> r :<C-U>edit<CR> nnoremap <buffer> <silent> r :<C-U>edit<CR>
nnoremap <buffer> <silent> R :<C-U>edit<CR> nnoremap <buffer> <silent> R :<C-U>edit<CR>
@@ -2642,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'
@@ -2677,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_
@@ -2829,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.'
@@ -2886,13 +2917,13 @@ 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')
let type = getline('.')[0] let type = getline('.')[0]
let lnum = line('.') - 1 let lnum = line('.') - 1
let offset = -1 let offset = 0
while getline(lnum) !~# '^@@ -\d\+,\d\+ +\d\+,' while getline(lnum) !~# '^@@ -\d\+,\d\+ +\d\+,'
if getline(lnum) =~# '^[ '.type.']' if getline(lnum) =~# '^[ '.type.']'
let offset += 1 let offset += 1
@@ -2900,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 '
@@ -2909,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\}$'
@@ -2937,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:',
\ 'o': '',
\ 'w': ''}
if len(myhash)
let prefixes.a = myhash.'^:'
let prefixes.b = myhash.':'
endif endif
else let ref = substitute(ref, '^\(\w\)/', '\=get(prefixes, submatch(1), "HEAD:")', '')
let ref = s:sub(ref,'^a/',myhash.'^:')
let ref = s:sub(ref,'^b/',myhash.':')
if exists('dref') if exists('dref')
let dref = s:sub(dref,'^a/',myhash.'^:') let dref = substitute(dref, '^\(\w\)/', '\=get(prefixes, submatch(1), "HEAD:")', '')
endif
endif endif
if ref ==# '/dev/null' if ref ==# '/dev/null'
@@ -2984,7 +3018,11 @@ function! fugitive#cfile() abort
let pre = '' let pre = ''
let results = s:cfile() let results = s:cfile()
if empty(results) if empty(results)
return expand('<cfile>') let cfile = expand('<cfile>')
if &includeexpr =~# '\<v:fname\>'
sandbox let cfile = eval(substitute(&includeexpr, '\C\<v:fname\>', '\=string(cfile)', 'g'))
endif
return cfile
elseif len(results) > 1 elseif len(results) > 1
let pre = '+' . join(map(results[1:-1], 'escape(v:val, " ")'), '\|') . ' ' let pre = '+' . join(map(results[1:-1], 'escape(v:val, " ")'), '\|') . ' '
endif endif
@@ -3052,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]