From 5d1a276b455dd9a32375a5ac84050adff67062e3 Mon Sep 17 00:00:00 2001 From: Tim Pope Date: Sun, 22 Aug 2021 00:59:39 -0400 Subject: [PATCH] Distinguish between uses of Git dir We use the Git dir for a few purposes: * Direct filesystem access. * Passing to Git as --git-dir=. * Embedding in fugitive:// URLs. * Referring to the repository without otherwise using it. As a start to teasing these apart, introduce s:GitDir() to handle the first 2 cases, s:DirUrlPrefix() for the 3rd case, and keep using s:Dir() as a generic reference. --- autoload/fugitive.vim | 101 +++++++++++++++++++++++------------------- 1 file changed, 55 insertions(+), 46 deletions(-) diff --git a/autoload/fugitive.vim b/autoload/fugitive.vim index 04d12a3..f992a3c 100644 --- a/autoload/fugitive.vim +++ b/autoload/fugitive.vim @@ -396,7 +396,7 @@ function! s:UserCommandList(...) abort let flags = get(a:1, 'flags', flags) let dir = a:1.git_dir elseif a:0 - let dir = a:1 + let dir = s:GitDir(a:1) else let dir = '' endif @@ -465,6 +465,14 @@ function! s:Dir(...) abort return a:0 ? FugitiveGitDir(a:1) : FugitiveGitDir() endfunction +function! s:GitDir(...) abort + return a:0 ? FugitiveGitDir(a:1) : FugitiveGitDir() +endfunction + +function! s:DirUrlPrefix(...) abort + return 'fugitive://' . call('s:GitDir', a:000) . '//' +endfunction + function! s:Tree(...) abort return a:0 ? FugitiveWorkTree(a:1) : FugitiveWorkTree() endfunction @@ -596,7 +604,7 @@ function! fugitive#PrepareDirEnvGitFlagsArgs(...) abort call s:PrepareEnv(autoenv, dir) endif call s:PreparePathArgs(cmd, dir, !exists('explicit_pathspec_option')) - return [dir, env, extend(autoenv, env), git, cmd[0 : -arg_count-1], arg_count ? cmd[-arg_count : -1] : []] + return [s:GitDir(dir), env, extend(autoenv, env), git, cmd[0 : -arg_count-1], arg_count ? cmd[-arg_count : -1] : []] endfunction function! s:BuildEnvPrefix(env) abort @@ -875,10 +883,10 @@ function! fugitive#Head(...) abort let ftime = getftime(file) if ftime == -1 return '' - elseif ftime != get(s:head_cache, dir, [-1])[0] - let s:head_cache[dir] = [ftime, readfile(file)[0]] + elseif ftime != get(s:head_cache, file, [-1])[0] + let s:head_cache[file] = [ftime, readfile(file)[0]] endif - let head = s:head_cache[dir][1] + let head = s:head_cache[file][1] if head =~# '^ref: ' return substitute(head, '\C^ref: \%(refs/\%(heads/\|remotes/\|tags/\)\=\)\=', '', '') elseif head =~# '^\x\{40,\}$' @@ -945,7 +953,7 @@ function! fugitive#Config(...) abort let dict = s:config[dir_key][1] else let dict = copy(s:config_prototype) - let dict.git_dir = dir + let dict.git_dir = s:GitDir(dir) let [lines, message, exec_error] = s:NullError([dir, 'config', '--list', '-z', '--']) if exec_error return {} @@ -1171,7 +1179,7 @@ function! fugitive#RemoteUrl(...) abort let url = remove(args, 0) endif if url ==# '.git' - let url = FugitiveGitDir(config) + let url = s:GitDir(config) elseif url !~# ':\|^/\|^\.\.\=/' let url = FugitiveConfigGet('remote.' . url . '.url', config) endif @@ -1278,7 +1286,7 @@ let s:repo_prototype = {} let s:repos = {} function! fugitive#repo(...) abort - let dir = a:0 ? s:Dir(a:1) : (len(s:Dir()) ? s:Dir() : FugitiveExtractGitDir(expand('%:p'))) + let dir = a:0 ? s:GitDir(a:1) : (len(s:GitDir()) ? s:GitDir() : FugitiveExtractGitDir(expand('%:p'))) if dir !=# '' if has_key(s:repos, dir) let repo = get(s:repos, dir) @@ -1369,7 +1377,7 @@ function! s:DirCommitFile(path) abort if empty(vals) return ['', '', ''] endif - return vals[1:3] + return [s:Dir(vals[1])] + vals[2:3] endfunction function! s:DirRev(url) abort @@ -1378,8 +1386,8 @@ function! s:DirRev(url) abort endfunction let s:merge_heads = ['MERGE_HEAD', 'REBASE_HEAD', 'CHERRY_PICK_HEAD', 'REVERT_HEAD'] -function! s:MergeHead(...) abort - let dir = fugitive#Find('.git/', a:0 ? a:1 : s:Dir()) +function! s:MergeHead(dir) abort + let dir = fugitive#Find('.git/', a:dir) for head in s:merge_heads if filereadable(dir . head) return head @@ -1389,7 +1397,7 @@ function! s:MergeHead(...) abort endfunction function! s:Owner(path, ...) abort - let dir = a:0 ? a:1 : s:Dir() + let dir = a:0 ? s:Dir(a:1) : s:Dir() if empty(dir) return '' endif @@ -1446,7 +1454,7 @@ function! fugitive#Path(url, ...) abort if empty(a:url) return '' endif - let dir = a:0 > 1 ? a:2 : s:Dir() + let dir = a:0 > 1 ? s:Dir(a:2) : s:Dir() let tree = s:Tree(dir) if !a:0 return fugitive#Real(a:url) @@ -1510,7 +1518,7 @@ function! fugitive#Find(object, ...) abort elseif rev =~# '^\.\.\=\%(/\|$\)' return FugitiveVimPath(simplify(getcwd() . '/' . a:object)) endif - let dir = call('FugitiveGitDir', a:000) + let dir = call('s:GitDir', a:000) if empty(dir) let file = matchstr(a:object, '^\%(:\d:\|[^:]*:\)\zs\%(\.\.\=$\|\.\.\=/.*\|/.*\|\w:/.*\)') let dir = FugitiveExtractGitDir(file) @@ -1519,7 +1527,8 @@ function! fugitive#Find(object, ...) abort endif endif let tree = s:Tree(dir) - let base = len(tree) ? tree : 'fugitive://' . dir . '//0' + let urlprefix = s:DirUrlPrefix(dir) + let base = len(tree) ? tree : urlprefix . '0' if rev ==# '.git' let f = len(tree) && len(getftype(tree . '/.git')) ? tree . '/.git' : dir elseif rev =~# '^\.git/' @@ -1551,7 +1560,7 @@ function! fugitive#Find(object, ...) abort elseif rev =~# '^:\%([0-3]:\)\=\.\.\=\%(/\|$\)\|^:[0-3]:\%(/\|\a\+:\)' let f = rev =~# '^:\%([0-3]:\)\=\.' ? simplify(getcwd() . '/' . matchstr(rev, '\..*')) : rev[3:-1] if s:cpath(base . '/', (f . '/')[0 : len(base)]) - let f = 'fugitive://' . dir . '//' . +matchstr(rev, '^:\zs\d\ze:') . '/' . strpart(f, len(base) + 1) + let f = urlprefix . +matchstr(rev, '^:\zs\d\ze:') . '/' . strpart(f, len(base) + 1) else let altdir = FugitiveExtractGitDir(f) if len(altdir) && !s:cpath(dir, altdir) @@ -1559,7 +1568,7 @@ function! fugitive#Find(object, ...) abort endif endif elseif rev =~# '^:[0-3]:' - let f = 'fugitive://' . dir . '//' . rev[1] . '/' . rev[3:-1] + let f = urlprefix . rev[1] . '/' . rev[3:-1] elseif rev ==# ':' let fdir = dir . '/' let f = fdir . 'index' @@ -1579,7 +1588,7 @@ function! fugitive#Find(object, ...) abort let f = base . '/' . f endif elseif rev =~# '^:/\@!' - let f = 'fugitive://' . dir . '//0/' . rev[1:-1] + let f = urlprefix . '0/' . rev[1:-1] else if !exists('f') let commit = matchstr(rev, '^\%([^:.-]\|\.\.[^/:]\)[^:]*\|^:.*') @@ -1608,7 +1617,7 @@ function! fugitive#Find(object, ...) abort endif endif if len(commit) - let f = 'fugitive://' . dir . '//' . commit . file + let f = urlprefix . commit . file else let f = base . '/' . substitute(rev, '^:/:\=\|^[^:]\+:', '', '') endif @@ -1623,7 +1632,7 @@ function! s:Generate(object, ...) abort if !empty(f) return f elseif a:object ==# ':/' - return len(dir) ? FugitiveVimPath('fugitive://' . dir . '//0') : '.' + return len(dir) ? FugitiveVimPath(s:DirUrlPrefix(dir) . '0') : '.' endif let file = matchstr(a:object, '^\%(:\d:\|[^:]*:\)\zs.*') return fnamemodify(FugitiveVimPath(len(file) ? file : a:object), ':p') @@ -1639,7 +1648,7 @@ function! s:DotRelative(path, ...) abort endfunction function! fugitive#Object(...) abort - let dir = a:0 > 1 ? a:2 : s:Dir() + let dir = a:0 > 1 ? s:Dir(a:2) : s:Dir() let [fdir, rev] = s:DirRev(a:0 ? a:1 : @%) if s:cpath(dir) !=# s:cpath(fdir) let rev = '' @@ -2045,7 +2054,7 @@ function! fugitive#glob(url, ...) abort endif call map(files, 'v:val[0]') call filter(files, 'v:val =~# pattern') - let prepend = 'fugitive://' . dir . '//' . substitute(commit, '^:', '', '') . '/' + let prepend = s:DirUrlPrefix(dir) . substitute(commit, '^:', '', '') . '/' call sort(files) call map(files, 'FugitiveVimPath(prepend . v:val . append)') call extend(results, files) @@ -2133,7 +2142,7 @@ function! fugitive#CompletePath(base, ...) abort endif if base =~# '^\.git/' && len(dir) let pattern = s:gsub(base[5:-1], '/', '*&').'*' - let fdir = fugitive#Find(dir . '/') + let fdir = fugitive#Find('.git/', dir) let matches = s:GlobComplete(fdir, pattern) let cdir = fugitive#Find('.git/refs', dir)[0 : -5] if len(cdir) && s:cpath(fdir) !=# s:cpath(cdir) @@ -2586,7 +2595,7 @@ function! fugitive#BufReadStatus() abort if &bufhidden ==# '' setlocal bufhidden=delete endif - let b:dispatch = '-dir=' . s:fnameescape(len(s:Tree()) ? s:Tree() : s:Dir()) . ' ' . s:GitShellCmd() . ' fetch --all' + let b:dispatch = '-dir=' . s:fnameescape(len(s:Tree()) ? s:Tree() : s:GitDir()) . ' ' . s:GitShellCmd() . ' fetch --all' call fugitive#MapJumps() call s:Map('n', '-', ":execute Do('Toggle',0)", '') call s:Map('x', '-', ":execute Do('Toggle',1)", '') @@ -2719,7 +2728,7 @@ function! fugitive#BufReadCmd(...) abort if empty(dir) return 'echo "Invalid Fugitive URL"' endif - let b:git_dir = dir + let b:git_dir = s:GitDir(dir) if rev =~# '^:\d$' let b:fugitive_type = 'stage' else @@ -3327,8 +3336,9 @@ function! fugitive#Command(line1, line2, range, bang, mods, arg) abort if no_pager call add(flags, '--no-pager') endif + let options = {'git': s:UserCommandList(), 'git_dir': s:GitDir(dir), 'flags': flags} if empty(args) && pager is# -1 - let cmd = s:StatusCommand(a:line1, a:line2, a:range, a:line2, a:bang, a:mods, '', '', []) + let cmd = s:StatusCommand(a:line1, a:line2, a:range, a:line2, a:bang, a:mods, '', '', [], options) return (empty(cmd) ? 'exe' : cmd) . after endif let alias = FugitiveConfigGet('alias.' . get(args, 0, ''), config) @@ -3338,8 +3348,6 @@ function! fugitive#Command(line1, line2, range, bang, mods, arg) abort call extend(args, split(alias, '\s\+'), 'keep') endif let name = substitute(get(args, 0, ''), '\%(^\|-\)\(\l\)', '\u\1', 'g') - let git = s:UserCommandList() - let options = {'git': git, 'dir': dir, 'git_dir': dir, 'flags': flags} if pager is# -1 && name =~# '^\a\+$' && exists('*s:' . name . 'Subcommand') && get(args, 1, '') !=# '--help' try let overrides = s:{name}Subcommand(a:line1, a:line2, a:range, a:bang, a:mods, extend({'subcommand': args[0], 'subcommand_args': args[1:-1]}, options)) @@ -3378,7 +3386,7 @@ function! fugitive#Command(line1, line2, range, bang, mods, arg) abort \ (s:HasOpt(args, ['add', 'checkout', 'commit', 'stage', 'stash', 'reset'], '-p', '--patch') || \ s:HasOpt(args, ['add', 'clean', 'stage'], '-i', '--interactive')) && pager is# 0 let mods = substitute(s:Mods(a:mods), '\', '-tab', 'g') - let assign = len(dir) ? '|let b:git_dir = ' . string(dir) : '' + let assign = len(dir) ? '|let b:git_dir = ' . string(options.git_dir) : '' let argv = s:UserCommandList(options) + args let term_opts = len(env) ? {'env': env} : {} if has('nvim') @@ -3393,11 +3401,11 @@ function! fugitive#Command(line1, line2, range, bang, mods, arg) abort endif endif let state = { - \ 'git': git, + \ 'git': options.git, \ 'flags': flags, \ 'args': args, - \ 'dir': dir, - \ 'git_dir': dir, + \ 'dir': options.git_dir, + \ 'git_dir': options.git_dir, \ 'cwd': s:UserCommandCwd(dir), \ 'filetype': 'git', \ 'mods': s:Mods(a:mods), @@ -3458,7 +3466,7 @@ function! fugitive#Command(line1, line2, range, bang, mods, arg) abort let tmp.echo = '' endif let args = s:disable_colors + flags + ['-c', 'advice.waitingForEditor=false'] + args - let argv = s:UserCommandList({'git': git, 'git_dir': dir}) + args + let argv = s:UserCommandList({'git': options.git, 'git_dir': options.git_dir}) + args let [argv, jobopts] = s:JobOpts(argv, env) call fugitive#Autowrite() call writefile([], state.file, 'b') @@ -3626,7 +3634,7 @@ function! s:CompletableSubcommands(dir) abort endfunction function! fugitive#Complete(lead, ...) abort - let dir = a:0 == 1 ? a:1 : a:0 >= 3 ? a:3 : s:Dir() + let dir = a:0 == 1 ? a:1 : a:0 >= 3 ? s:Dir(a:3) : s:Dir() let root = a:0 >= 4 ? a:4 : s:Tree(s:Dir()) let pre = a:0 > 1 ? strpart(a:1, 0, a:2) : '' let subcmd = matchstr(pre, '\u\w*[! ] *\zs[[:alnum:]-]\+\ze ') @@ -3670,7 +3678,7 @@ endfunction " Section: :Gstatus function! s:StatusCommand(line1, line2, range, count, bang, mods, reg, arg, args, ...) abort - let dir = a:0 ? a:1 : s:Dir() + let dir = a:0 ? s:Dir(a:1) : s:Dir() exe s:DirCheck(dir) try let mods = s:Mods(a:mods, &splitbelow ? 'botright' : 'topleft') @@ -4831,7 +4839,7 @@ endfunction " Section: :Git commit, :Git revert function! s:CommitInteractive(line1, line2, range, bang, mods, options, patch) abort - let status = s:StatusCommand(a:line1, a:line2, a:range, a:line2, a:bang, a:mods, '', '', [], a:options.git_dir) + let status = s:StatusCommand(a:line1, a:line2, a:range, a:line2, a:bang, a:mods, '', '', [], a:options) let status = len(status) ? status . '|' : '' if a:patch return status . 'if search("^Unstaged")|exe "normal >"|exe "+"|endif' @@ -5073,7 +5081,7 @@ function! s:MergetoolSubcommand(line1, line2, range, bang, mods, options) abort endfunction function! s:DifftoolSubcommand(line1, line2, range, bang, mods, options) abort - let dir = a:options.git_dir + let dir = s:Dir(a:options) exe s:DirCheck(dir) let i = 0 let argv = copy(a:options.subcommand_args) @@ -5281,7 +5289,7 @@ function! s:GrepSubcommand(line1, line2, range, bang, mods, options) abort exe s:DirCheck(a:options) let listnr = a:line1 == 0 ? a:line1 : a:line2 let cmd = ['grep', '-n', '--no-color', '--full-name'] - let dir = a:options.git_dir + let dir = s:Dir(a:options) let options = s:GrepOptions(args, dir) if listnr > 0 exe listnr 'wincmd w' @@ -5295,8 +5303,8 @@ function! s:GrepSubcommand(line1, line2, range, bang, mods, options) abort \ 'git': a:options.git, \ 'flags': a:options.flags, \ 'args': cmd + args, - \ 'dir': dir, - \ 'git_dir': dir, + \ 'dir': s:GitDir(a:options), + \ 'git_dir': s:GitDir(a:options), \ 'cwd': s:UserCommandCwd(dir), \ 'filetype': 'git', \ 'mods': s:Mods(a:mods), @@ -5363,7 +5371,7 @@ function! s:LogFlushQueue(state, dir) abort return queue endfunction -function! s:LogParse(state, dir, line) abort +function! s:LogParse(state, dir, prefix, line) abort if a:state.mode ==# 'hunk' && a:line =~# '^[-+ ]' return [] endif @@ -5371,7 +5379,7 @@ function! s:LogParse(state, dir, line) abort if len(list) let queue = s:LogFlushQueue(a:state, a:dir) let a:state.mode = 'commit' - let a:state.base = 'fugitive://' . a:dir . '//' . list[2] + let a:state.base = a:prefix . list[2] if len(list[1]) let [a:state.base_module; a:state.parents] = split(list[1], ' ') else @@ -5516,7 +5524,7 @@ function! fugitive#LogCommand(line1, count, range, bang, mods, args, type) abort \ args + extra_args + paths + extra_paths) let state.target = path let title = titlepre . (listnr < 0 ? 'Gclog ' : 'Gllog ') . s:fnameescape(args + paths) - return s:QuickfixStream(listnr, 'log', title, s:UserCommandList(dir) + cmd, !a:bang, a:mods, s:function('s:LogParse'), state, dir) . after + return s:QuickfixStream(listnr, 'log', title, s:UserCommandList(dir) + cmd, !a:bang, a:mods, s:function('s:LogParse'), state, dir, s:DirUrlPrefix(dir)) . after endfunction " Section: :Gedit, :Gpedit, :Gsplit, :Gvsplit, :Gtabedit, :Gread @@ -6312,7 +6320,7 @@ function! fugitive#BlameComplete(A, L, P) abort endfunction function! s:BlameSubcommand(line1, count, range, bang, mods, options) abort - let dir = s:Dir() + let dir = s:Dir(a:options) exe s:DirCheck(dir) let flags = copy(a:options.subcommand_args) let i = 0 @@ -6992,10 +7000,11 @@ function! fugitive#BrowseCommand(line1, count, range, bang, mods, arg, args) abo endif let remote_url = fugitive#RemoteUrl(remote, dir) let raw = empty(remote_url) ? remote : remote_url + let git_dir = s:GitDir(dir) let opts = { - \ 'git_dir': dir, - \ 'repo': {'git_dir': dir}, + \ 'git_dir': git_dir, + \ 'repo': {'git_dir': git_dir}, \ 'remote': raw, \ 'remote_name': remote, \ 'commit': commit,