commit 9afd81512b0ccded5499635d28dd50d065298ff0
parent d2ca90d87e3246b5b827ed08f8c0dfc8ad6ae4c8
Author: Justin M. Keyes <justinkz@gmail.com>
Date: Tue, 13 Jan 2026 00:07:09 -0500
Merge #37377 from echasnovski/pack-fix-checkout
Diffstat:
2 files changed, 102 insertions(+), 16 deletions(-)
diff --git a/runtime/lua/vim/pack.lua b/runtime/lua/vim/pack.lua
@@ -264,17 +264,12 @@ end
--- @param url string
--- @param path string
local function git_clone(url, path)
- local cmd = { 'clone', '--quiet', '--no-checkout', '--recurse-submodules' }
+ local cmd = { 'clone', '--quiet', '--no-checkout' }
if vim.startswith(url, 'file://') then
cmd[#cmd + 1] = '--no-hardlinks'
- else
- if git_version >= vim.version.parse('2.36') then
- cmd[#cmd + 1] = '--filter=blob:none'
- cmd[#cmd + 1] = '--also-filter-submodules'
- elseif git_version >= vim.version.parse('2.27') then
- cmd[#cmd + 1] = '--filter=blob:none'
- end
+ elseif git_version >= vim.version.parse('2.27') then
+ cmd[#cmd + 1] = '--filter=blob:none'
end
vim.list_extend(cmd, { '--origin', 'origin', url, path })
@@ -654,18 +649,27 @@ end
--- @async
--- @param p vim.pack.Plug
--- @param timestamp string
-local function checkout(p, timestamp)
+--- @param skip_stash? boolean
+local function checkout(p, timestamp, skip_stash)
infer_revisions(p)
- local stash_cmd = { 'stash', '--quiet' }
- if git_version > vim.version.parse('2.13') then
- stash_cmd[#stash_cmd + 1] = '--message'
- stash_cmd[#stash_cmd + 1] = ('vim.pack: %s Stash before checkout'):format(timestamp)
+ if not skip_stash then
+ local stash_cmd = { 'stash', '--quiet' }
+ if git_version > vim.version.parse('2.13') then
+ stash_cmd[#stash_cmd + 1] = '--message'
+ stash_cmd[#stash_cmd + 1] = ('vim.pack: %s Stash before checkout'):format(timestamp)
+ end
+ git_cmd(stash_cmd, p.path)
end
- git_cmd(stash_cmd, p.path)
git_cmd({ 'checkout', '--quiet', p.info.sha_target }, p.path)
+ local submodule_cmd = { 'submodule', 'update', '--init', '--recursive' }
+ if git_version >= vim.version.parse('2.36') then
+ submodule_cmd[#submodule_cmd + 1] = '--filter=blob:none'
+ end
+ git_cmd(submodule_cmd, p.path)
+
plugin_lock.plugins[p.spec.name].rev = p.info.sha_target
-- (Re)Generate help tags according to the current help files.
@@ -691,7 +695,7 @@ local function install_list(plug_list, confirm)
-- Prefer revision from the lockfile instead of using `version`
p.info.sha_target = (plugin_lock.plugins[p.spec.name] or {}).rev
- checkout(p, timestamp)
+ checkout(p, timestamp, true)
p.info.installed = true
trigger_event(p, 'PackChanged', 'install')
diff --git a/test/functional/plugin/pack_spec.lua b/test/functional/plugin/pack_spec.lua
@@ -221,6 +221,34 @@ function repos_setup.semver()
add_tag('v1.0.0')
end
+function repos_setup.with_subs()
+ -- To-be-submodule repo
+ init_test_repo('sub')
+
+ repo_write_file('sub', 'sub.lua', 'return "sub init"')
+ git_add_commit('Initial commit for "sub"', 'sub')
+
+ -- With-submodules repo with submodule recorded at its initial commit
+ init_test_repo('with_subs')
+
+ repo_write_file('with_subs', 'lua/with_subs.lua', 'return "with_subs init"')
+ local sub_src = 'file://' .. repo_get_path('sub')
+ git_cmd({ '-c', 'protocol.file.allow=always', 'submodule', 'add', sub_src, 'sub' }, 'with_subs')
+ git_add_commit('Initial commit for "with_subs"', 'with_subs')
+ git_cmd({ 'tag', 'init-commit' }, 'with_subs')
+
+ -- Advance both submodule and with-submodules repos by one commit
+ repo_write_file('sub', 'sub.lua', 'return "sub main"')
+ git_add_commit('Second commit for "sub"', 'sub')
+
+ repo_write_file('with_subs', 'lua/with_subs.lua', 'return "with_subs main"')
+ git_cmd(
+ { '-c', 'protocol.file.allow=always', 'submodule', 'update', '--remote', 'sub' },
+ 'with_subs'
+ )
+ git_add_commit('Second commit for "with_subs"', 'with_subs')
+end
+
-- Utility --------------------------------------------------------------------
local function watch_events(event)
@@ -319,6 +347,25 @@ local function mock_confirm(output_value)
end)
end
+local function mock_git_file_transport()
+ -- HACK: mock `vim.system()` to have `git` commands be executed
+ -- with temporarily set 'protocol.file.allow=always' option.
+ -- Otherwise performing `git` operations with submodules from `vim.pack`
+ -- itself will fail with `fatal: transport 'file' not allowed`.
+ -- Directly adding `-c protocol.file.allow=always` to `git_cmd` in `vim.pack`
+ -- itself is too much and might be bad for security.
+ exec_lua(function()
+ local vim_system_orig = vim.system
+ vim.system = function(cmd, opts, on_exit)
+ if cmd[1] == 'git' then
+ table.insert(cmd, 2, '-c')
+ table.insert(cmd, 3, 'protocol.file.allow=always')
+ end
+ return vim_system_orig(cmd, opts, on_exit)
+ end
+ end)
+end
+
local function is_jit()
return exec_lua('return package.loaded.jit ~= nil')
end
@@ -369,6 +416,11 @@ describe('vim.pack', function()
vim.pack.add({ repos_src.basic })
end)
eq(exec_lua('return #_G.event_log'), 0)
+
+ -- Should not create redundant stash entry
+ local basic_path = pack_get_plug_path('basic')
+ local stash_list = system_sync({ 'git', 'stash', 'list' }, { cwd = basic_path }).stdout or ''
+ eq('', stash_list)
end)
it('passes `data` field through to `opts.load`', function()
@@ -782,6 +834,16 @@ describe('vim.pack', function()
eq(false, vim.tbl_contains(rtp, after_dir))
end)
+ it('installs with submodules', function()
+ mock_git_file_transport()
+ exec_lua(function()
+ vim.pack.add({ repos_src.with_subs })
+ end)
+
+ local sub_lua_file = vim.fs.joinpath(pack_get_plug_path('with_subs'), 'sub', 'sub.lua')
+ eq('return "sub main"', fn.readblob(sub_lua_file))
+ end)
+
it('does not install on bad `version`', function()
local err = pcall_err(exec_lua, function()
vim.pack.add({ { src = repos_src.basic, version = 'not-exist' } })
@@ -823,7 +885,8 @@ describe('vim.pack', function()
local function assert_works()
-- Should auto-install but wait before executing code after it
n.clear({ args_rm = { '-u' } })
- n.exec_lua('vim.wait(500, function() return _G.done end, 50)')
+ vim.uv.sleep(2000)
+ eq(true, exec_lua('return _G.done'))
assert_loaded()
-- Should only `:packadd!`/`:packadd` already installed plugin
@@ -1656,6 +1719,25 @@ describe('vim.pack', function()
eq('return "fetch new 2"', fn.readblob(fetch_lua_file))
end)
+ it('works with submodules', function()
+ mock_git_file_transport()
+ exec_lua(function()
+ vim.pack.add({ { src = repos_src.with_subs, version = 'init-commit' } })
+ end)
+
+ local sub_lua_file = vim.fs.joinpath(pack_get_plug_path('with_subs'), 'sub', 'sub.lua')
+ eq('return "sub init"', fn.readblob(sub_lua_file))
+
+ n.clear()
+ mock_git_file_transport()
+ exec_lua(function()
+ vim.pack.add({ repos_src.with_subs })
+ vim.pack.update({ 'with_subs' })
+ end)
+ n.exec('write')
+ eq('return "sub main"', fn.readblob(sub_lua_file))
+ end)
+
it('can force update', function()
exec_lua(function()
vim.pack.add({ repos_src.fetch })