commit e4e6605943665c2f7b3bb9f7e2b065188935bd33
parent e6cdb7d481949ce02037d48bdde1d6b37289bd5a
Author: Evgeni Chasnovski <evgeni.chasnovski@gmail.com>
Date: Sun, 16 Nov 2025 20:27:19 +0200
fix(pack): relax minimal Git version to be 2.0 #36573
Problem: Current requirement is Git>=2.36 as `--also-filter-submodules`
flag for `git clone` was introduced there. This is problematic since
default Git version on Ubuntu 22.04 is 2.34.
Solution: Relax minimal Git version to be (at least) 2.0 by selectively
applying necessary flags based on the current Git version.
As 2.0.0 was released in 2014-05-28 (almost the same age as Neovim
project itself), it is reasonable to drop any mention and checks on
minimal version altogether.
Diffstat:
3 files changed, 31 insertions(+), 27 deletions(-)
diff --git a/runtime/doc/pack.txt b/runtime/doc/pack.txt
@@ -217,9 +217,9 @@ or setting |$XDG_DATA_HOME| during startup. Plugin's subdirectory name matches
plugin's name in specification. It is assumed that all plugins in the
directory are managed exclusively by `vim.pack`.
-Uses Git to manage plugins and requires present `git` executable of at least
-version 2.36. Target plugins should be Git repositories with versions as named
-tags following semver convention `v<major>.<minor>.<patch>`.
+Uses Git to manage plugins and requires present `git` executable. Target
+plugins should be Git repositories with versions as named tags following
+semver convention `v<major>.<minor>.<patch>`.
The latest state of all managed plugins is stored inside a *vim.pack-lockfile*
located at `$XDG_CONFIG_HOME/nvim/nvim-pack-lock.json`. It is a JSON file that
diff --git a/runtime/lua/vim/health/health.lua b/runtime/lua/vim/health/health.lua
@@ -417,21 +417,11 @@ local function check_external_tools()
health.warn('ripgrep not available')
end
- -- `vim.pack` requires `git` executable with version at least 2.36
+ -- `vim.pack` prefers git 2.36 but tries to work with 2.x.
if vim.fn.executable('git') == 1 then
local git = vim.fn.exepath('git')
- local out = vim.system({ 'git', 'version' }, {}):wait().stdout or ''
- local version = vim.version.parse(out)
- if version < vim.version.parse('2.36') then
- local msg = string.format(
- 'git is available (%s), but needs at least version 2.36 (not %s) to work with `vim.pack`',
- git,
- tostring(version)
- )
- health.warn(msg)
- else
- health.ok(('%s (%s)'):format(vim.trim(out), git))
- end
+ local version = vim.system({ 'git', 'version' }, {}):wait().stdout or ''
+ health.ok(('%s (%s)'):format(vim.trim(version), git))
else
health.warn('git not available (required by `vim.pack`)')
end
diff --git a/runtime/lua/vim/pack.lua b/runtime/lua/vim/pack.lua
@@ -10,9 +10,9 @@
---Plugin's subdirectory name matches plugin's name in specification.
---It is assumed that all plugins in the directory are managed exclusively by `vim.pack`.
---
----Uses Git to manage plugins and requires present `git` executable of at
----least version 2.36. Target plugins should be Git repositories with versions
----as named tags following semver convention `v<major>.<minor>.<patch>`.
+---Uses Git to manage plugins and requires present `git` executable.
+---Target plugins should be Git repositories with versions as named tags
+---following semver convention `v<major>.<minor>.<patch>`.
---
---The latest state of all managed plugins is stored inside a [vim.pack-lockfile]()
---located at `$XDG_CONFIG_HOME/nvim/nvim-pack-lock.json`. It is a JSON file that
@@ -162,8 +162,12 @@ local function git_cmd(cmd, cwd)
return (stdout:gsub('\n+$', ''))
end
+local git_version = vim.version.parse('1')
+
local function git_ensure_exec()
- if vim.fn.executable('git') == 0 then
+ local sys_res = vim.system({ 'git', 'version' }):wait()
+ git_version = vim.version.parse(sys_res.stdout)
+ if sys_res.stderr ~= '' then
error('No `git` executable')
end
end
@@ -172,14 +176,17 @@ end
--- @param url string
--- @param path string
local function git_clone(url, path)
- local cmd = { 'clone', '--quiet', '--origin', 'origin', '--no-checkout' }
+ local cmd = { 'clone', '--quiet', '--no-checkout', '--recurse-submodules' }
if vim.startswith(url, 'file://') then
cmd[#cmd + 1] = '--no-hardlinks'
else
- -- NOTE: '--also-filter-submodules' requires Git>=2.36
- local filter_args = { '--filter=blob:none', '--recurse-submodules', '--also-filter-submodules' }
- vim.list_extend(cmd, filter_args)
+ 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
end
vim.list_extend(cmd, { '--origin', 'origin', url, path })
@@ -618,8 +625,12 @@ end
local function checkout(p, timestamp)
infer_revisions(p)
- local msg = ('vim.pack: %s Stash before checkout'):format(timestamp)
- git_cmd({ 'stash', '--quiet', '--message', msg }, p.path)
+ 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)
git_cmd({ 'checkout', '--quiet', p.info.sha_target }, p.path)
@@ -693,7 +704,10 @@ local function infer_update_details(p)
return
end
- local older_tags = git_cmd({ 'tag', '--list', '--no-contains', sha_head }, p.path)
+ local older_tags = ''
+ if git_version >= vim.version.parse('2.13') then
+ older_tags = git_cmd({ 'tag', '--list', '--no-contains', sha_head }, p.path)
+ end
local cur_tags = git_cmd({ 'tag', '--list', '--points-at', sha_head }, p.path)
local past_tags = vim.split(older_tags, '\n')
vim.list_extend(past_tags, vim.split(cur_tags, '\n'))