perf(git): run rev-parse and git show <commit> sync

This commit is contained in:
2026-04-28 08:03:05 +02:00
parent 01c0f82e18
commit d2633ae9c2
3 changed files with 68 additions and 107 deletions
+16 -27
View File
@@ -74,13 +74,11 @@ end
---@param user_ref string ---@param user_ref string
---@param path string ---@param path string
local function show_file_in_split(worktree, user_ref, path) local function show_file_in_split(worktree, user_ref, path)
repo.rev_parse(worktree, user_ref, true, function(sha) local label = repo.rev_parse(worktree, user_ref, true) or user_ref
local label = sha or user_ref local uri = "git://" .. label .. "//" .. path
local uri = "git://" .. label .. "//" .. path local buf = vim.fn.bufadd(uri)
local buf = vim.fn.bufadd(uri) vim.b[buf].git_worktree = worktree
vim.b[buf].git_worktree = worktree vim.cmd("split " .. vim.fn.fnameescape(uri))
vim.cmd("split " .. vim.fn.fnameescape(uri))
end)
end end
---@param worktree string ---@param worktree string
@@ -105,27 +103,18 @@ local function run_in_split(worktree, args, conf)
vim.b[buf].git_worktree = worktree vim.b[buf].git_worktree = worktree
if conf.needs_ref then if conf.needs_ref then
local user_ref = first_positional(args, 2) or "HEAD" local user_ref = first_positional(args, 2) or "HEAD"
local function apply_name(label) local sha = repo.rev_parse(worktree, user_ref, true)
if not vim.api.nvim_buf_is_valid(buf) then if sha then
return vim.b[buf].git_ref = sha
end vim.b[buf].git_parent_ref =
pcall(vim.api.nvim_buf_set_name, buf, "git://" .. label .. "//") repo.rev_parse(worktree, user_ref .. "^", true)
vim.bo[buf].filetype = conf.ft
end end
repo.rev_parse(worktree, user_ref, true, function(sha) pcall(
if not sha then vim.api.nvim_buf_set_name,
apply_name(user_ref) buf,
return "git://" .. (sha or user_ref) .. "//"
end )
repo.rev_parse(worktree, user_ref .. "^", true, function(parent) vim.bo[buf].filetype = conf.ft
if not vim.api.nvim_buf_is_valid(buf) then
return
end
vim.b[buf].git_ref = sha
vim.b[buf].git_parent_ref = parent
apply_name(sha)
end)
end)
else else
vim.bo[buf].filetype = conf.ft vim.bo[buf].filetype = conf.ft
end end
+12 -21
View File
@@ -322,35 +322,26 @@ function M.head(path)
return nil return nil
end end
---Resolve a git revision to its object SHA. Calls `callback(sha?)` on the ---Resolve a git revision to its object SHA. Returns nil if the ref can't
---main loop with nil if the ref can't be parsed (root-commit's `^`, blob's ---be parsed (root-commit's `^`, blob's `^`, malformed ref, etc.). When
---`^`, malformed ref, etc.). When `short` is true, the result is abbreviated ---`short` is true, the result is abbreviated via `core.abbrev`
---via `core.abbrev` (auto-extended by git to keep the prefix unique in the ---(auto-extended by git to keep the prefix unique in the current repo).
---current repo).
---@param worktree string ---@param worktree string
---@param ref string ---@param ref string
---@param short boolean ---@param short boolean
---@param callback fun(sha: string?) ---@return string?
function M.rev_parse(worktree, ref, short, callback) function M.rev_parse(worktree, ref, short)
local cmd = { "git", "rev-parse", "--verify", "--quiet" } local cmd = { "git", "rev-parse", "--verify", "--quiet" }
if short then if short then
table.insert(cmd, "--short") table.insert(cmd, "--short")
end end
table.insert(cmd, ref) table.insert(cmd, ref)
vim.system( local result = vim.system(cmd, { cwd = worktree, text = true }):wait()
cmd, if result.code ~= 0 then
{ cwd = worktree, text = true }, return nil
vim.schedule_wrap(function(result) end
local sha local trimmed = vim.trim(result.stdout or "")
if result.code == 0 then return trimmed ~= "" and trimmed or nil
local trimmed = vim.trim(result.stdout or "")
if trimmed ~= "" then
sha = trimmed
end
end
callback(sha)
end)
)
end end
return M return M
+40 -59
View File
@@ -135,68 +135,49 @@ end
---@param opts ow.Git.OpenCommitOpts? ---@param opts ow.Git.OpenCommitOpts?
function M.open_commit(worktree, ref, opts) function M.open_commit(worktree, ref, opts)
local split = opts and opts.split local split = opts and opts.split
repo.rev_parse(worktree, ref, true, function(resolved) local sha = repo.rev_parse(worktree, ref, true) or ref
local sha = resolved or ref local name = "git://" .. sha .. "//"
local name = "git://" .. sha .. "//" -- Commit SHAs are immutable so a previously-opened buffer is still
-- Reuse a previously-opened buffer for the same commit; commit SHAs -- valid. Reuse it instead of refetching.
-- are immutable so the content is stable. local existing = vim.fn.bufnr(name)
local existing = vim.fn.bufnr(name) if existing ~= -1 and vim.api.nvim_buf_is_loaded(existing) then
if existing ~= -1 and vim.api.nvim_buf_is_loaded(existing) then if split == false then
if split == false then vim.cmd.normal({ "m'", bang = true })
vim.cmd.normal({ "m'", bang = true }) vim.api.nvim_set_current_buf(existing)
vim.api.nvim_set_current_buf(existing) else
else vim.api.nvim_open_win(existing, true, {
vim.api.nvim_open_win(existing, true, { split = split or (vim.o.splitbelow and "below" or "above"),
split = split or (vim.o.splitbelow and "below" or "above"), })
})
end
return
end end
return
end
local buf, win = git.new_scratch({ name = name, split = split }) local result = vim.system(
vim.b[buf].git_worktree = worktree { "git", "show", ref },
vim.b[buf].git_ref = sha { cwd = worktree, text = true }
)
:wait()
if result.code ~= 0 then
log.error("git show %s failed: %s", ref, vim.trim(result.stderr or ""))
return
end
vim.system( local parent = repo.rev_parse(worktree, ref .. "^", true)
{ "git", "show", ref }, local buf, _ = git.new_scratch({ name = name, split = split })
{ cwd = worktree, text = true }, vim.b[buf].git_worktree = worktree
vim.schedule_wrap(function(result) vim.b[buf].git_ref = sha
if result.code ~= 0 then vim.b[buf].git_parent_ref = parent
log.error( vim.bo[buf].modifiable = true
"git show %s failed: %s", vim.api.nvim_buf_set_lines(
ref, buf,
vim.trim(result.stderr or "") 0,
) -1,
-- Drop the empty placeholder so a retry runs a fresh false,
-- fetch. With `split = false` the window falls back to util.split_lines(result.stdout or "")
-- its alternate buffer (the gitlog); for a real split )
-- we close the dedicated window to keep the layout tidy. vim.bo[buf].modifiable = false
if split ~= false and vim.api.nvim_win_is_valid(win) then vim.bo[buf].modified = false
pcall(vim.api.nvim_win_close, win, true) vim.bo[buf].filetype = "git"
end
if vim.api.nvim_buf_is_valid(buf) then
vim.api.nvim_buf_delete(buf, { force = true })
end
return
end
if not vim.api.nvim_buf_is_valid(buf) then
return
end
local lines = util.split_lines(result.stdout or "")
repo.rev_parse(worktree, ref .. "^", true, function(parent)
if not vim.api.nvim_buf_is_valid(buf) then
return
end
vim.b[buf].git_parent_ref = parent
vim.bo[buf].modifiable = true
vim.api.nvim_buf_set_lines(buf, 0, -1, false, lines)
vim.bo[buf].modifiable = false
vim.bo[buf].modified = false
vim.bo[buf].filetype = "git"
end)
end)
)
end)
end end
---@return boolean dispatched true if the cursor was on an actionable line ---@return boolean dispatched true if the cursor was on an actionable line