diff --git a/CHANGELOG.md b/CHANGELOG.md index 4192bd6..7961caa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,17 @@ All notable changes to the Vim Plugin Manager will be documented in this file. startup check re-fetches (TTL skipped). It was previously accepted but ignored. +### Fixed +- Update no longer reports "Fetch failed" when an upstream tag moved: the + update fetch is `git fetch --tags --force origin`, so a tag-clobber + rejection (local tag object differing from the remote one) refreshes + the tag mirror instead of failing the whole fetch - branch refs were + already updating successfully in that case. Local tags in a plugin + submodule are mirrors of upstream, never local creations, so the + forced refresh matches the pull trust level. Diagnosed on a real + setup: 12 stale v1.x/v2.1.x tag mirrors were poisoning every update + of the affected module. + ### Removed - Dead code: never-read async job state fields (`id`, `started`, `queued`), the unused `g:plugin_manager_periodic_timer` write, four diff --git a/autoload/plugin_manager/cmd/update.vim b/autoload/plugin_manager/cmd/update.vim index f09c171..f0742ca 100644 --- a/autoload/plugin_manager/cmd/update.vim +++ b/autoload/plugin_manager/cmd/update.vim @@ -88,7 +88,7 @@ function! s:update_specific_plugin_async(ctx) abort " Step 1: Fetch first, stash only if a pull turns out to be needed call plugin_manager#ui#update_operation(l:op_id, 'Fetching updates') - call plugin_manager#async#git('git -C ' . shellescape(a:ctx.module_path) . ' fetch --tags origin', { + call plugin_manager#async#git('git -C ' . shellescape(a:ctx.module_path) . ' fetch --tags --force origin', { \ 'callback': function('s:on_fetch_complete', [a:ctx]) \ }) endfunction @@ -385,7 +385,7 @@ function! s:update_all_plugins_async(ctx) abort for l:module in a:ctx.valid_modules let l:module_path = get(l:module, 'abs_path', l:module.path) call plugin_manager#async#git( - \ 'git -C ' . shellescape(l:module_path) . ' fetch --tags origin', { + \ 'git -C ' . shellescape(l:module_path) . ' fetch --tags --force origin', { \ 'callback': function('s:on_module_fetched', [a:ctx, l:module]) \ }) endfor diff --git a/tests/update.vader b/tests/update.vader index 999c318..5eae805 100644 --- a/tests/update.vader +++ b/tests/update.vader @@ -326,3 +326,28 @@ Execute (custom-branch module is skipped with the exact skip message): call system('git -C ' . shellescape(g:_pm_upd_plug) . ' checkout -q main') call system('git -C ' . shellescape(g:_pm_upd_plug) . ' branch -D dev') unlet g:_pm_upd_sb + +Execute (a moved upstream tag does not fail the fetch): + " Upstream tags can move (re-annotated). The module's local tag copy is + " a mirror, never a local creation: git fetch --tags --force must refresh + " it instead of failing the whole fetch (branch refs update regardless; + " a plain tag rejection must not mark the module as failed). + call system('git -C ' . shellescape(g:_pm_upd_tmp_src) . ' tag -a v9.9.9 -m rel') + call system('git -C ' . shellescape(g:_pm_upd_tmp_src) . ' push -q origin v9.9.9') + " Local tag with a DIFFERENT tag-object SHA than the remote one. + call system('git -C ' . shellescape(g:_pm_upd_plug) . ' tag -a v9.9.9 -m local') + call plugin_manager#cmd#dispatch('update') + let g:_pm_upd_sb = join(getbufline(bufnr('PluginManager'), 1, '$'), "\n") + Assert g:_pm_upd_sb !~# 'Fetch failed', + \ 'a tag clobber rejection must not fail the fetch, got: ' . g:_pm_upd_sb + " The local tag mirror is refreshed to the remote tag object. + let g:_pm_upd_local_tag = substitute( + \ system('git -C ' . shellescape(g:_pm_upd_plug) . ' show-ref --tags v9.9.9'), + \ '\n', '', 'g') + let g:_pm_upd_remote_tag = substitute( + \ system('git -C ' . shellescape(g:_pm_upd_tmp_src) . ' show-ref --tags v9.9.9'), + \ '\n', '', 'g') + Assert g:_pm_upd_local_tag ==# g:_pm_upd_remote_tag, + \ 'tag must be refreshed to the remote object, got: ' + \ . g:_pm_upd_local_tag . ' vs ' . g:_pm_upd_remote_tag + unlet g:_pm_upd_sb g:_pm_upd_local_tag g:_pm_upd_remote_tag