perf(git): fold revspec validation into the cat-file -p the loader needs anyway

This commit is contained in:
2026-04-29 09:53:48 +02:00
parent 5c5da7a854
commit 590651e9d8
3 changed files with 42 additions and 28 deletions
+19 -8
View File
@@ -157,13 +157,17 @@ local function uri_split(opts, cur_buf, cur_revspec)
local cur_writable = cur.stage == 0 local cur_writable = cur.stage == 0
if opts.revspec ~= "" and opts.revspec:find(":", 1, true) then if opts.revspec ~= "" and opts.revspec:find(":", 1, true) then
if not repo.object_exists(worktree, opts.revspec) then local content = util.exec(
{ "git", "cat-file", "-p", opts.revspec },
{ cwd = worktree, silent = true }
)
if not content then
util.warning("invalid revspec: %s", opts.revspec) util.warning("invalid revspec: %s", opts.revspec)
return return
end end
place_pair( place_pair(
cur_buf, cur_buf,
object.buf_for(worktree, opts.revspec), object.buf_for(worktree, opts.revspec, content),
cur_writable, cur_writable,
opts.vertical opts.vertical
) )
@@ -192,13 +196,17 @@ local function uri_split(opts, cur_buf, cur_revspec)
else else
other_revspec = ":0:" .. cur.path other_revspec = ":0:" .. cur.path
end end
if not repo.object_exists(worktree, other_revspec) then local content = util.exec(
{ "git", "cat-file", "-p", other_revspec },
{ cwd = worktree, silent = true }
)
if not content then
util.warning("invalid revspec: %s", other_revspec) util.warning("invalid revspec: %s", other_revspec)
return return
end end
place_pair( place_pair(
cur_buf, cur_buf,
object.buf_for(worktree, other_revspec), object.buf_for(worktree, other_revspec, content),
cur.stage ~= nil, cur.stage ~= nil,
opts.vertical opts.vertical
) )
@@ -248,13 +256,16 @@ function M.split(opts)
else else
revspec = opts.revspec .. ":" .. rel revspec = opts.revspec .. ":" .. rel
end end
if not repo.object_exists(worktree, revspec) then local content = util.exec(
{ "git", "cat-file", "-p", revspec },
{ cwd = worktree, silent = true }
)
if not content then
util.warning("invalid revspec: %s", revspec) util.warning("invalid revspec: %s", revspec)
return return
end end
local buf = vim.fn.bufadd("git://" .. revspec) local object = require("git.object")
vim.b[buf].git_worktree = worktree local buf = object.buf_for(worktree, revspec, content)
local other_writable = util.parse_revspec(revspec).stage == 0 local other_writable = util.parse_revspec(revspec).stage == 0
place_pair(buf, cur_buf, other_writable, opts.vertical) place_pair(buf, cur_buf, other_writable, opts.vertical)
end end
+20 -3
View File
@@ -135,16 +135,29 @@ local function attach_index_writer(buf, worktree, path)
}) })
end end
---Pre-fetched content keyed by bufnr. Set by `buf_for(_, _, content)`
---and consumed by the next `read_uri` dispatch on that buffer. Lets
---callers fold validation + content fetch + buffer load into one
---`cat-file` call instead of preflighting separately.
---@type table<integer, string>
local pending_content = {}
---Return a buffer holding the content addressed by a git revspec. The ---Return a buffer holding the content addressed by a git revspec. The
---URI is `git://<revspec>` and BufReadCmd routes through `M.read_uri`, ---URI is `git://<revspec>` and BufReadCmd routes through `M.read_uri`,
---which loads via `git cat-file -p`. ---which loads via `git cat-file -p`. If `content` is given, primes a
---cache so the BufReadCmd handler reuses it instead of running another
---`cat-file -p`.
---@param worktree string ---@param worktree string
---@param revspec string any revspec git understands (e.g. `HEAD:foo`, `:foo`, `:1:foo`, `<sha>`, `<sha>:foo`) ---@param revspec string any revspec git understands (e.g. `HEAD:foo`, `:foo`, `:1:foo`, `<sha>`, `<sha>:foo`)
---@param content string?
---@return integer ---@return integer
function M.buf_for(worktree, revspec) function M.buf_for(worktree, revspec, content)
local name = "git://" .. revspec local name = "git://" .. revspec
local buf = vim.fn.bufadd(name) local buf = vim.fn.bufadd(name)
vim.b[buf].git_worktree = worktree vim.b[buf].git_worktree = worktree
if content then
pending_content[buf] = content
end
vim.fn.bufload(buf) vim.fn.bufload(buf)
return buf return buf
end end
@@ -172,10 +185,14 @@ function M.read_uri(buf)
vim.bo[buf].swapfile = false vim.bo[buf].swapfile = false
vim.bo[buf].bufhidden = "wipe" vim.bo[buf].bufhidden = "wipe"
local stdout = util.exec( local stdout = pending_content[buf]
pending_content[buf] = nil
if stdout == nil then
stdout = util.exec(
{ "git", "cat-file", "-p", revspec }, { "git", "cat-file", "-p", revspec },
{ cwd = worktree } { cwd = worktree }
) )
end
if stdout then if stdout then
vim.api.nvim_buf_set_lines(buf, 0, -1, false, util.split_lines(stdout)) vim.api.nvim_buf_set_lines(buf, 0, -1, false, util.split_lines(stdout))
end end
-14
View File
@@ -343,18 +343,4 @@ function M.rev_parse(worktree, ref, short)
return trimmed ~= "" and trimmed or nil return trimmed ~= "" and trimmed or nil
end end
---Verify a revspec resolves to an existing git object. `cat-file -e` is
---git's cheapest existence check, and unlike `rev-parse --verify` it
---also accepts the `<commit>:<path>` form that BufReadCmd revspec URIs
---use.
---@param worktree string
---@param revspec string
---@return boolean
function M.object_exists(worktree, revspec)
return util.exec(
{ "git", "cat-file", "-e", revspec },
{ cwd = worktree, silent = true }
) ~= nil
end
return M return M