diff --git a/plug.vim b/plug.vim index 38c4f5d..9262208 100644 --- a/plug.vim +++ b/plug.vim @@ -120,29 +120,23 @@ function! s:isabsolute(dir) abort return a:dir =~# '^/' || (has('win32') && a:dir =~? '^\%(\\\|[A-Z]:\)') endfunction -function! s:get_gitdir(dir) abort - let gitdir = a:dir . '/.git' +function! s:git_dir(dir) abort + let gitdir = s:trim(a:dir) . '/.git' if isdirectory(gitdir) return gitdir endif - try - let line = readfile(gitdir)[0] - if line =~# '^gitdir: ' - let gitdir = line[8:] - if !s:isabsolute(gitdir) - let gitdir = a:dir . '/' . gitdir - endif - if isdirectory(gitdir) - return gitdir - endif - endif - catch - endtry - return '' + if !filereadable(gitdir) + return '' + endif + let gitdir = matchstr(get(readfile(gitdir), 0, ''), '^gitdir: \zs.*') + if len(gitdir) && !s:isabsolute(gitdir) + let gitdir = a:dir . '/' . gitdir + endif + return isdirectory(gitdir) ? gitdir : '' endfunction -function! s:git_get_remote_origin_url(dir) abort - let gitdir = s:get_gitdir(a:dir) +function! s:git_origin_url(dir) abort + let gitdir = s:git_dir(a:dir) let config = gitdir . '/config' if empty(gitdir) || !filereadable(config) return '' @@ -150,44 +144,60 @@ function! s:git_get_remote_origin_url(dir) abort return matchstr(join(readfile(config)), '\[remote "origin"\].\{-}url\s*=\s*\zs\S*\ze') endfunction -function! s:git_get_revision(dir) abort - let gitdir = s:get_gitdir(a:dir) - if gitdir ==# '' +function! s:git_revision(dir) abort + let gitdir = s:git_dir(a:dir) + let head = gitdir . '/HEAD' + if empty(gitdir) || !filereadable(head) return '' endif - try - let line = readfile(gitdir . '/HEAD')[0] - if line =~# '^ref: ' - let ref = line[5:] - if filereadable(gitdir . '/' . ref) - return readfile(gitdir . '/' . ref)[0] + + let line = get(readfile(head), 0, '') + let ref = matchstr(line, '^ref: \zs.*') + if empty(ref) + return line + endif + + if filereadable(gitdir . '/' . ref) + return get(readfile(gitdir . '/' . ref), 0, '') + endif + + if filereadable(gitdir . '/packed-refs') + for line in readfile(gitdir . '/packed-refs') + if line =~# ' ' . ref + return matchstr(line, '^[0-9a-f]*') endif - for line in readfile(gitdir . '/packed-refs') - if line =~# ' ' . ref - return substitute(line, '^\([0-9a-f]*\) ', '\1', '') - endif - endfor - endif - return l:line - catch - endtry + endfor + endif + return '' endfunction -function! s:git_get_branch(dir) abort - let gitdir = s:get_gitdir(a:dir) - if gitdir ==# '' +function! s:git_local_branch(dir) abort + let gitdir = s:git_dir(a:dir) + let head = gitdir . '/HEAD' + if empty(gitdir) || !filereadable(head) return '' endif - try - let line = readfile(gitdir . '/HEAD')[0] - if line =~# '^ref: refs/heads/' - return line[16:] - endif - return 'HEAD' - catch - return '' - endtry + let branch = matchstr(get(readfile(head), 0, ''), '^ref: refs/heads/\zs.*') + return len(branch) ? branch : 'HEAD' +endfunction + +function! s:git_origin_branch(spec) + if len(a:spec.branch) + return a:spec.branch + endif + + " The file may not be present if this is a local repository + let gitdir = s:git_dir(a:spec.dir) + let origin_head = gitdir.'/refs/remotes/origin/HEAD' + if len(gitdir) && filereadable(origin_head) + return matchstr(get(readfile(origin_head), 0, ''), + \ '^ref: refs/remotes/origin/\zs.*') + endif + + " The command may not return the name of a branch in detached HEAD state + let result = s:lines(s:system('git symbolic-ref --short HEAD', a:spec.dir)) + return v:shell_error ? '' : result[-1] endfunction if s:is_win @@ -1065,7 +1075,7 @@ endfunction function! s:checkout(spec) let sha = a:spec.commit - let output = s:git_get_revision(a:spec.dir) + let output = s:git_revision(a:spec.dir) if !empty(output) && !s:hash_match(sha, s:lines(output)[0]) let output = s:system( \ 'git fetch --depth 999999 && git checkout '.plug#shellescape(sha).' --', a:spec.dir) @@ -2282,26 +2292,10 @@ function! s:system_chomp(...) return v:shell_error ? '' : substitute(ret, '\n$', '', '') endfunction -function! s:git_origin_branch(spec) - if len(a:spec.branch) - return a:spec.branch - endif - - " The file may not be present if this is a local repository - let origin_head = a:spec.dir.'/.git/refs/remotes/origin/HEAD' - if filereadable(origin_head) - return split(readfile(origin_head)[0], 'refs/remotes/origin/')[-1] - endif - - " The command may not return the name of a branch in detached HEAD state - let result = s:lines(s:system('git symbolic-ref --short HEAD', a:spec.dir)) - return v:shell_error ? '' : result[-1] -endfunction - function! s:git_validate(spec, check_branch) let err = '' if isdirectory(a:spec.dir) - let result = [s:git_get_branch(a:spec.dir), s:git_get_remote_origin_url(a:spec.dir)] + let result = [s:git_local_branch(a:spec.dir), s:git_origin_url(a:spec.dir)] let remote = result[-1] if empty(remote) let err = join([remote, 'PlugClean required.'], "\n") @@ -2310,7 +2304,7 @@ function! s:git_validate(spec, check_branch) \ 'Expected: '.a:spec.uri, \ 'PlugClean required.'], "\n") elseif a:check_branch && has_key(a:spec, 'commit') - let sha = s:git_get_revision(a:spec.dir) + let sha = s:git_revision(a:spec.dir) if empty(sha) let err = join(add(result, 'PlugClean required.'), "\n") elseif !s:hash_match(sha, a:spec.commit) @@ -2756,7 +2750,7 @@ function! s:snapshot(force, ...) abort let names = sort(keys(filter(copy(g:plugs), \'has_key(v:val, "uri") && !has_key(v:val, "commit") && isdirectory(v:val.dir)'))) for name in reverse(names) - let sha = s:git_get_revision(g:plugs[name].dir) + let sha = s:git_revision(g:plugs[name].dir) if !empty(sha) call append(anchor, printf("silent! let g:plugs['%s'].commit = '%s'", name, sha)) redraw