Browse Source

[vim] Upgrade vim plug

Emmanuel Bouthenot 2 years ago
parent
commit
89ba7fa138
1 changed files with 184 additions and 48 deletions
  1. 184 48
      .vim/autoload/plug.vim

+ 184 - 48
.vim/autoload/plug.vim

@@ -25,7 +25,7 @@
 "   Plug 'scrooloose/nerdtree', { 'on':  'NERDTreeToggle' }
 "   Plug 'scrooloose/nerdtree', { 'on':  'NERDTreeToggle' }
 "   Plug 'tpope/vim-fireplace', { 'for': 'clojure' }
 "   Plug 'tpope/vim-fireplace', { 'for': 'clojure' }
 "
 "
-"   " Using a non-master branch
+"   " Using a non-default branch
 "   Plug 'rdnetto/YCM-Generator', { 'branch': 'stable' }
 "   Plug 'rdnetto/YCM-Generator', { 'branch': 'stable' }
 "
 "
 "   " Using a tagged release; wildcard allowed (requires git 1.9.2 or above)
 "   " Using a tagged release; wildcard allowed (requires git 1.9.2 or above)
@@ -106,7 +106,7 @@ if s:is_win && &shellslash
 else
 else
   let s:me = resolve(expand('<sfile>:p'))
   let s:me = resolve(expand('<sfile>:p'))
 endif
 endif
-let s:base_spec = { 'branch': 'master', 'frozen': 0 }
+let s:base_spec = { 'branch': '', 'frozen': 0 }
 let s:TYPE = {
 let s:TYPE = {
 \   'string':  type(''),
 \   'string':  type(''),
 \   'list':    type([]),
 \   'list':    type([]),
@@ -116,6 +116,94 @@ let s:TYPE = {
 let s:loaded = get(s:, 'loaded', {})
 let s:loaded = get(s:, 'loaded', {})
 let s:triggers = get(s:, 'triggers', {})
 let s:triggers = get(s:, 'triggers', {})
 
 
+function! s:is_powershell(shell)
+  return a:shell =~# 'powershell\(\.exe\)\?$' || a:shell =~# 'pwsh\(\.exe\)\?$'
+endfunction
+
+function! s:isabsolute(dir) abort
+  return a:dir =~# '^/' || (has('win32') && a:dir =~? '^\%(\\\|[A-Z]:\)')
+endfunction
+
+function! s:git_dir(dir) abort
+  let gitdir = s:trim(a:dir) . '/.git'
+  if isdirectory(gitdir)
+    return gitdir
+  endif
+  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_origin_url(dir) abort
+  let gitdir = s:git_dir(a:dir)
+  let config = gitdir . '/config'
+  if empty(gitdir) || !filereadable(config)
+    return ''
+  endif
+  return matchstr(join(readfile(config)), '\[remote "origin"\].\{-}url\s*=\s*\zs\S*\ze')
+endfunction
+
+function! s:git_revision(dir) abort
+  let gitdir = s:git_dir(a:dir)
+  let head = gitdir . '/HEAD'
+  if empty(gitdir) || !filereadable(head)
+    return ''
+  endif
+
+  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
+    endfor
+  endif
+
+  return ''
+endfunction
+
+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
+  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
 if s:is_win
   function! s:plug_call(fn, ...)
   function! s:plug_call(fn, ...)
     let shellslash = &shellslash
     let shellslash = &shellslash
@@ -179,7 +267,7 @@ function! s:define_commands()
   endif
   endif
   if has('win32')
   if has('win32')
   \ && &shellslash
   \ && &shellslash
-  \ && (&shell =~# 'cmd\.exe' || &shell =~# 'powershell\.exe')
+  \ && (&shell =~# 'cmd\(\.exe\)\?$' || s:is_powershell(&shell))
     return s:err('vim-plug does not support shell, ' . &shell . ', when shellslash is set.')
     return s:err('vim-plug does not support shell, ' . &shell . ', when shellslash is set.')
   endif
   endif
   if !has('nvim')
   if !has('nvim')
@@ -419,7 +507,7 @@ if s:is_win
     let batchfile = s:plug_tempname().'.bat'
     let batchfile = s:plug_tempname().'.bat'
     call writefile(s:wrap_cmds(a:cmd), batchfile)
     call writefile(s:wrap_cmds(a:cmd), batchfile)
     let cmd = plug#shellescape(batchfile, {'shell': &shell, 'script': 0})
     let cmd = plug#shellescape(batchfile, {'shell': &shell, 'script': 0})
-    if &shell =~# 'powershell\.exe'
+    if s:is_powershell(&shell)
       let cmd = '& ' . cmd
       let cmd = '& ' . cmd
     endif
     endif
     return [batchfile, cmd]
     return [batchfile, cmd]
@@ -632,16 +720,38 @@ function! plug#(repo, ...)
     let g:plugs[name] = spec
     let g:plugs[name] = spec
     let s:loaded[name] = get(s:loaded, name, 0)
     let s:loaded[name] = get(s:loaded, name, 0)
   catch
   catch
-    return s:err(v:exception)
+    return s:err(repo . ' ' . v:exception)
   endtry
   endtry
 endfunction
 endfunction
 
 
 function! s:parse_options(arg)
 function! s:parse_options(arg)
   let opts = copy(s:base_spec)
   let opts = copy(s:base_spec)
   let type = type(a:arg)
   let type = type(a:arg)
+  let opt_errfmt = 'Invalid argument for "%s" option of :Plug (expected: %s)'
   if type == s:TYPE.string
   if type == s:TYPE.string
+    if empty(a:arg)
+      throw printf(opt_errfmt, 'tag', 'string')
+    endif
     let opts.tag = a:arg
     let opts.tag = a:arg
   elseif type == s:TYPE.dict
   elseif type == s:TYPE.dict
+    for opt in ['branch', 'tag', 'commit', 'rtp', 'dir', 'as']
+      if has_key(a:arg, opt)
+      \ && (type(a:arg[opt]) != s:TYPE.string || empty(a:arg[opt]))
+        throw printf(opt_errfmt, opt, 'string')
+      endif
+    endfor
+    for opt in ['on', 'for']
+      if has_key(a:arg, opt)
+      \ && type(a:arg[opt]) != s:TYPE.list
+      \ && (type(a:arg[opt]) != s:TYPE.string || empty(a:arg[opt]))
+        throw printf(opt_errfmt, opt, 'string or list')
+      endif
+    endfor
+    if has_key(a:arg, 'do')
+      \ && type(a:arg.do) != s:TYPE.funcref
+      \ && (type(a:arg.do) != s:TYPE.string || empty(a:arg.do))
+        throw printf(opt_errfmt, 'do', 'string or funcref')
+    endif
     call extend(opts, a:arg)
     call extend(opts, a:arg)
     if has_key(opts, 'dir')
     if has_key(opts, 'dir')
       let opts.dir = s:dirpath(s:plug_expand(opts.dir))
       let opts.dir = s:dirpath(s:plug_expand(opts.dir))
@@ -698,7 +808,7 @@ function! s:syntax()
   syn match plugNumber /[0-9]\+[0-9.]*/ contained
   syn match plugNumber /[0-9]\+[0-9.]*/ contained
   syn match plugBracket /[[\]]/ contained
   syn match plugBracket /[[\]]/ contained
   syn match plugX /x/ contained
   syn match plugX /x/ contained
-  syn match plugDash /^-/
+  syn match plugDash /^-\{1}\ /
   syn match plugPlus /^+/
   syn match plugPlus /^+/
   syn match plugStar /^*/
   syn match plugStar /^*/
   syn match plugMessage /\(^- \)\@<=.*/
   syn match plugMessage /\(^- \)\@<=.*/
@@ -716,6 +826,7 @@ function! s:syntax()
   syn match plugError /^x.*/
   syn match plugError /^x.*/
   syn region plugDeleted start=/^\~ .*/ end=/^\ze\S/
   syn region plugDeleted start=/^\~ .*/ end=/^\ze\S/
   syn match plugH2 /^.*:\n-\+$/
   syn match plugH2 /^.*:\n-\+$/
+  syn match plugH2 /^-\{2,}/
   syn keyword Function PlugInstall PlugStatus PlugUpdate PlugClean
   syn keyword Function PlugInstall PlugStatus PlugUpdate PlugClean
   hi def link plug1       Title
   hi def link plug1       Title
   hi def link plug2       Repeat
   hi def link plug2       Repeat
@@ -828,7 +939,7 @@ function! s:prepare(...)
     call s:new_window()
     call s:new_window()
   endif
   endif
 
 
-  nnoremap <silent> <buffer> q  :if b:plug_preview==1<bar>pc<bar>endif<bar>bd<cr>
+  nnoremap <silent> <buffer> q :call <SID>close_pane()<cr>
   if a:0 == 0
   if a:0 == 0
     call s:finish_bindings()
     call s:finish_bindings()
   endif
   endif
@@ -850,6 +961,15 @@ function! s:prepare(...)
   endif
   endif
 endfunction
 endfunction
 
 
+function! s:close_pane()
+  if b:plug_preview == 1
+    pc
+    let b:plug_preview = -1
+  else
+    bd
+  endif
+endfunction
+
 function! s:assign_name()
 function! s:assign_name()
   " Assign buffer name
   " Assign buffer name
   let prefix = '[Plugins]'
   let prefix = '[Plugins]'
@@ -868,9 +988,9 @@ function! s:chsh(swap)
     set shell=sh
     set shell=sh
   endif
   endif
   if a:swap
   if a:swap
-    if &shell =~# 'powershell\.exe' || &shell =~# 'pwsh$'
+    if s:is_powershell(&shell)
       let &shellredir = '2>&1 | Out-File -Encoding UTF8 %s'
       let &shellredir = '2>&1 | Out-File -Encoding UTF8 %s'
-    elseif &shell =~# 'sh' || &shell =~# 'cmd\.exe'
+    elseif &shell =~# 'sh' || &shell =~# 'cmd\(\.exe\)\?$'
       set shellredir=>%s\ 2>&1
       set shellredir=>%s\ 2>&1
     endif
     endif
   endif
   endif
@@ -969,10 +1089,11 @@ endfunction
 
 
 function! s:checkout(spec)
 function! s:checkout(spec)
   let sha = a:spec.commit
   let sha = a:spec.commit
-  let output = s:system(['git', 'rev-parse', 'HEAD'], a:spec.dir)
-  if !v:shell_error && !s:hash_match(sha, s:lines(output)[0])
+  let output = s:git_revision(a:spec.dir)
+  if !empty(output) && !s:hash_match(sha, s:lines(output)[0])
+    let credential_helper = s:git_version_requirement(2) ? '-c credential.helper= ' : ''
     let output = s:system(
     let output = s:system(
-          \ 'git fetch --depth 999999 && git checkout '.plug#shellescape(sha).' --', a:spec.dir)
+          \ 'git '.credential_helper.'fetch --depth 999999 && git checkout '.plug#shellescape(sha).' --', a:spec.dir)
   endif
   endif
   return output
   return output
 endfunction
 endfunction
@@ -1184,7 +1305,7 @@ function! s:update_finish()
         call s:log4(name, 'Checking out '.tag)
         call s:log4(name, 'Checking out '.tag)
         let out = s:system('git checkout -q '.plug#shellescape(tag).' -- 2>&1', spec.dir)
         let out = s:system('git checkout -q '.plug#shellescape(tag).' -- 2>&1', spec.dir)
       else
       else
-        let branch = get(spec, 'branch', 'master')
+        let branch = s:git_origin_branch(spec)
         call s:log4(name, 'Merging origin/'.s:esc(branch))
         call s:log4(name, 'Merging origin/'.s:esc(branch))
         let out = s:system('git checkout -q '.plug#shellescape(branch).' -- 2>&1'
         let out = s:system('git checkout -q '.plug#shellescape(branch).' -- 2>&1'
               \. (has_key(s:update.new, name) ? '' : ('&& git merge --ff-only '.plug#shellescape('origin/'.branch).' 2>&1')), spec.dir)
               \. (has_key(s:update.new, name) ? '' : ('&& git merge --ff-only '.plug#shellescape('origin/'.branch).' 2>&1')), spec.dir)
@@ -1424,7 +1545,7 @@ while 1 " Without TCO, Vim stack is bound to explode
     let [error, _] = s:git_validate(spec, 0)
     let [error, _] = s:git_validate(spec, 0)
     if empty(error)
     if empty(error)
       if pull
       if pull
-        let cmd = ['git', 'fetch']
+        let cmd = s:git_version_requirement(2) ? ['git', '-c', 'credential.helper=', 'fetch'] : ['git', 'fetch']
         if has_tag && !empty(globpath(spec.dir, '.git/shallow'))
         if has_tag && !empty(globpath(spec.dir, '.git/shallow'))
           call extend(cmd, ['--depth', '99999999'])
           call extend(cmd, ['--depth', '99999999'])
         endif
         endif
@@ -2106,9 +2227,9 @@ function! plug#shellescape(arg, ...)
   let opts = a:0 > 0 && type(a:1) == s:TYPE.dict ? a:1 : {}
   let opts = a:0 > 0 && type(a:1) == s:TYPE.dict ? a:1 : {}
   let shell = get(opts, 'shell', s:is_win ? 'cmd.exe' : 'sh')
   let shell = get(opts, 'shell', s:is_win ? 'cmd.exe' : 'sh')
   let script = get(opts, 'script', 1)
   let script = get(opts, 'script', 1)
-  if shell =~# 'cmd\.exe'
+  if shell =~# 'cmd\(\.exe\)\?$'
     return s:shellesc_cmd(a:arg, script)
     return s:shellesc_cmd(a:arg, script)
-  elseif shell =~# 'powershell\.exe' || shell =~# 'pwsh$'
+  elseif s:is_powershell(shell)
     return s:shellesc_ps1(a:arg)
     return s:shellesc_ps1(a:arg)
   endif
   endif
   return s:shellesc_sh(a:arg)
   return s:shellesc_sh(a:arg)
@@ -2160,7 +2281,7 @@ function! s:system(cmd, ...)
         return system(a:cmd)
         return system(a:cmd)
       endif
       endif
       let cmd = join(map(copy(a:cmd), 'plug#shellescape(v:val, {"shell": &shell, "script": 0})'))
       let cmd = join(map(copy(a:cmd), 'plug#shellescape(v:val, {"shell": &shell, "script": 0})'))
-      if &shell =~# 'powershell\.exe'
+      if s:is_powershell(&shell)
         let cmd = '& ' . cmd
         let cmd = '& ' . cmd
       endif
       endif
     else
     else
@@ -2189,18 +2310,17 @@ endfunction
 function! s:git_validate(spec, check_branch)
 function! s:git_validate(spec, check_branch)
   let err = ''
   let err = ''
   if isdirectory(a:spec.dir)
   if isdirectory(a:spec.dir)
-    let result = s:lines(s:system('git rev-parse --abbrev-ref HEAD 2>&1 && git config -f .git/config 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]
     let remote = result[-1]
-    if v:shell_error
+    if empty(remote)
       let err = join([remote, 'PlugClean required.'], "\n")
       let err = join([remote, 'PlugClean required.'], "\n")
     elseif !s:compare_git_uri(remote, a:spec.uri)
     elseif !s:compare_git_uri(remote, a:spec.uri)
       let err = join(['Invalid URI: '.remote,
       let err = join(['Invalid URI: '.remote,
                     \ 'Expected:    '.a:spec.uri,
                     \ 'Expected:    '.a:spec.uri,
                     \ 'PlugClean required.'], "\n")
                     \ 'PlugClean required.'], "\n")
     elseif a:check_branch && has_key(a:spec, 'commit')
     elseif a:check_branch && has_key(a:spec, 'commit')
-      let result = s:lines(s:system('git rev-parse HEAD 2>&1', a:spec.dir))
-      let sha = result[-1]
-      if v:shell_error
+      let sha = s:git_revision(a:spec.dir)
+      if empty(sha)
         let err = join(add(result, 'PlugClean required.'), "\n")
         let err = join(add(result, 'PlugClean required.'), "\n")
       elseif !s:hash_match(sha, a:spec.commit)
       elseif !s:hash_match(sha, a:spec.commit)
         let err = join([printf('Invalid HEAD (expected: %s, actual: %s)',
         let err = join([printf('Invalid HEAD (expected: %s, actual: %s)',
@@ -2208,8 +2328,9 @@ function! s:git_validate(spec, check_branch)
                       \ 'PlugUpdate required.'], "\n")
                       \ 'PlugUpdate required.'], "\n")
       endif
       endif
     elseif a:check_branch
     elseif a:check_branch
-      let branch = result[0]
+      let current_branch = result[0]
       " Check tag
       " Check tag
+      let origin_branch = s:git_origin_branch(a:spec)
       if has_key(a:spec, 'tag')
       if has_key(a:spec, 'tag')
         let tag = s:system_chomp('git describe --exact-match --tags HEAD 2>&1', a:spec.dir)
         let tag = s:system_chomp('git describe --exact-match --tags HEAD 2>&1', a:spec.dir)
         if a:spec.tag !=# tag && a:spec.tag !~ '\*'
         if a:spec.tag !=# tag && a:spec.tag !~ '\*'
@@ -2217,14 +2338,14 @@ function! s:git_validate(spec, check_branch)
                 \ (empty(tag) ? 'N/A' : tag), a:spec.tag)
                 \ (empty(tag) ? 'N/A' : tag), a:spec.tag)
         endif
         endif
       " Check branch
       " Check branch
-      elseif a:spec.branch !=# branch
+      elseif origin_branch !=# current_branch
         let err = printf('Invalid branch: %s (expected: %s). Try PlugUpdate.',
         let err = printf('Invalid branch: %s (expected: %s). Try PlugUpdate.',
-              \ branch, a:spec.branch)
+              \ current_branch, origin_branch)
       endif
       endif
       if empty(err)
       if empty(err)
         let [ahead, behind] = split(s:lastline(s:system([
         let [ahead, behind] = split(s:lastline(s:system([
         \ 'git', 'rev-list', '--count', '--left-right',
         \ 'git', 'rev-list', '--count', '--left-right',
-        \ printf('HEAD...origin/%s', a:spec.branch)
+        \ printf('HEAD...origin/%s', origin_branch)
         \ ], a:spec.dir)), '\t')
         \ ], a:spec.dir)), '\t')
         if !v:shell_error && ahead
         if !v:shell_error && ahead
           if behind
           if behind
@@ -2232,11 +2353,11 @@ function! s:git_validate(spec, check_branch)
             " pushable (and probably not that messed up).
             " pushable (and probably not that messed up).
             let err = printf(
             let err = printf(
                   \ "Diverged from origin/%s (%d commit(s) ahead and %d commit(s) behind!\n"
                   \ "Diverged from origin/%s (%d commit(s) ahead and %d commit(s) behind!\n"
-                  \ .'Backup local changes and run PlugClean and PlugUpdate to reinstall it.', a:spec.branch, ahead, behind)
+                  \ .'Backup local changes and run PlugClean and PlugUpdate to reinstall it.', origin_branch, ahead, behind)
           else
           else
             let err = printf("Ahead of origin/%s by %d commit(s).\n"
             let err = printf("Ahead of origin/%s by %d commit(s).\n"
                   \ .'Cannot update until local changes are pushed.',
                   \ .'Cannot update until local changes are pushed.',
-                  \ a:spec.branch, ahead)
+                  \ origin_branch, ahead)
           endif
           endif
         endif
         endif
       endif
       endif
@@ -2249,7 +2370,7 @@ endfunction
 
 
 function! s:rm_rf(dir)
 function! s:rm_rf(dir)
   if isdirectory(a:dir)
   if isdirectory(a:dir)
-    call s:system(s:is_win
+    return s:system(s:is_win
     \ ? 'rmdir /S /Q '.plug#shellescape(a:dir)
     \ ? 'rmdir /S /Q '.plug#shellescape(a:dir)
     \ : ['rm', '-rf', a:dir])
     \ : ['rm', '-rf', a:dir])
   endif
   endif
@@ -2333,6 +2454,7 @@ endfunction
 function! s:delete(range, force)
 function! s:delete(range, force)
   let [l1, l2] = a:range
   let [l1, l2] = a:range
   let force = a:force
   let force = a:force
+  let err_count = 0
   while l1 <= l2
   while l1 <= l2
     let line = getline(l1)
     let line = getline(l1)
     if line =~ '^- ' && isdirectory(line[2:])
     if line =~ '^- ' && isdirectory(line[2:])
@@ -2341,11 +2463,22 @@ function! s:delete(range, force)
       let answer = force ? 1 : s:ask('Delete '.line[2:].'?', 1)
       let answer = force ? 1 : s:ask('Delete '.line[2:].'?', 1)
       let force = force || answer > 1
       let force = force || answer > 1
       if answer
       if answer
-        call s:rm_rf(line[2:])
+        let err = s:rm_rf(line[2:])
         setlocal modifiable
         setlocal modifiable
-        call setline(l1, '~'.line[1:])
-        let s:clean_count += 1
-        call setline(4, printf('Removed %d directories.', s:clean_count))
+        if empty(err)
+          call setline(l1, '~'.line[1:])
+          let s:clean_count += 1
+        else
+          delete _
+          call append(l1 - 1, s:format_message('x', line[1:], err))
+          let l2 += len(s:lines(err))
+          let err_count += 1
+        endif
+        let msg = printf('Removed %d directories.', s:clean_count)
+        if err_count > 0
+          let msg .= printf(' Failed to remove %d directories.', err_count)
+        endif
+        call setline(4, msg)
         setlocal nomodifiable
         setlocal nomodifiable
       endif
       endif
     endif
     endif
@@ -2554,20 +2687,23 @@ function! s:diff()
     endif
     endif
     call s:append_ul(2, origin ? 'Pending updates:' : 'Last update:')
     call s:append_ul(2, origin ? 'Pending updates:' : 'Last update:')
     for [k, v] in plugs
     for [k, v] in plugs
-      let range = origin ? '..origin/'.v.branch : 'HEAD@{1}..'
-      let cmd = ['git', 'log', '--graph', '--color=never']
-      if s:git_version_requirement(2, 10, 0)
-        call add(cmd, '--no-show-signature')
-      endif
-      call extend(cmd, ['--pretty=format:%x01%h%x01%d%x01%s%x01%cr', range])
-      if has_key(v, 'rtp')
-        call extend(cmd, ['--', v.rtp])
-      endif
-      let diff = s:system_chomp(cmd, v.dir)
-      if !empty(diff)
-        let ref = has_key(v, 'tag') ? (' (tag: '.v.tag.')') : has_key(v, 'commit') ? (' '.v.commit) : ''
-        call append(5, extend(['', '- '.k.':'.ref], map(s:lines(diff), 's:format_git_log(v:val)')))
-        let cnts[origin] += 1
+      let branch = s:git_origin_branch(v)
+      if len(branch)
+        let range = origin ? '..origin/'.branch : 'HEAD@{1}..'
+        let cmd = ['git', 'log', '--graph', '--color=never']
+        if s:git_version_requirement(2, 10, 0)
+          call add(cmd, '--no-show-signature')
+        endif
+        call extend(cmd, ['--pretty=format:%x01%h%x01%d%x01%s%x01%cr', range])
+        if has_key(v, 'rtp')
+          call extend(cmd, ['--', v.rtp])
+        endif
+        let diff = s:system_chomp(cmd, v.dir)
+        if !empty(diff)
+          let ref = has_key(v, 'tag') ? (' (tag: '.v.tag.')') : has_key(v, 'commit') ? (' '.v.commit) : ''
+          call append(5, extend(['', '- '.k.':'.ref], map(s:lines(diff), 's:format_git_log(v:val)')))
+          let cnts[origin] += 1
+        endif
       endif
       endif
       let bar .= '='
       let bar .= '='
       call s:progress_bar(2, bar, len(total))
       call s:progress_bar(2, bar, len(total))
@@ -2629,7 +2765,7 @@ function! s:snapshot(force, ...) abort
   let names = sort(keys(filter(copy(g:plugs),
   let names = sort(keys(filter(copy(g:plugs),
         \'has_key(v:val, "uri") && !has_key(v:val, "commit") && isdirectory(v:val.dir)')))
         \'has_key(v:val, "uri") && !has_key(v:val, "commit") && isdirectory(v:val.dir)')))
   for name in reverse(names)
   for name in reverse(names)
-    let sha = s:system_chomp(['git', 'rev-parse', '--short', 'HEAD'], g:plugs[name].dir)
+    let sha = s:git_revision(g:plugs[name].dir)
     if !empty(sha)
     if !empty(sha)
       call append(anchor, printf("silent! let g:plugs['%s'].commit = '%s'", name, sha))
       call append(anchor, printf("silent! let g:plugs['%s'].commit = '%s'", name, sha))
       redraw
       redraw