perf(git): run git log sync with bounded count
This commit is contained in:
+41
-28
@@ -6,44 +6,57 @@ local util = require("util")
|
|||||||
local M = {}
|
local M = {}
|
||||||
|
|
||||||
local LOG_FORMAT = "%h %ad {%an}%d %s"
|
local LOG_FORMAT = "%h %ad {%an}%d %s"
|
||||||
|
local DEFAULT_MAX_COUNT = 1000
|
||||||
|
|
||||||
|
---@class ow.Git.LogOpts
|
||||||
|
---@field max_count integer? cap on commits to show. Nil uses the default, <= 0 means "all"
|
||||||
|
|
||||||
|
---@param opts ow.Git.LogOpts?
|
||||||
|
function M.show(opts)
|
||||||
|
opts = opts or {}
|
||||||
|
local max_count = opts.max_count
|
||||||
|
if max_count == nil then
|
||||||
|
max_count = DEFAULT_MAX_COUNT
|
||||||
|
end
|
||||||
|
|
||||||
function M.show()
|
|
||||||
local _, worktree = repo.resolve_cwd()
|
local _, worktree = repo.resolve_cwd()
|
||||||
if not worktree then
|
if not worktree then
|
||||||
log.warning("not in a git repository")
|
log.warning("not in a git repository")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local cmd = {
|
||||||
|
"git",
|
||||||
|
"log",
|
||||||
|
"--graph",
|
||||||
|
"--all",
|
||||||
|
"--decorate",
|
||||||
|
"--date=short",
|
||||||
|
"--format=format:" .. LOG_FORMAT,
|
||||||
|
}
|
||||||
|
if max_count > 0 then
|
||||||
|
table.insert(cmd, "--max-count=" .. max_count)
|
||||||
|
end
|
||||||
|
|
||||||
|
local result = vim.system(cmd, { cwd = worktree, text = true }):wait()
|
||||||
|
if result.code ~= 0 then
|
||||||
|
log.error("git log failed: %s", vim.trim(result.stderr or ""))
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
local buf = git.new_scratch()
|
local buf = git.new_scratch()
|
||||||
vim.b[buf].git_worktree = worktree
|
vim.b[buf].git_worktree = worktree
|
||||||
|
vim.bo[buf].modifiable = true
|
||||||
vim.system(
|
vim.api.nvim_buf_set_lines(
|
||||||
{
|
buf,
|
||||||
"git",
|
0,
|
||||||
"log",
|
-1,
|
||||||
"--graph",
|
false,
|
||||||
"--all",
|
util.split_lines(result.stdout or "")
|
||||||
"--decorate",
|
|
||||||
"--date=short",
|
|
||||||
"--format=format:" .. LOG_FORMAT,
|
|
||||||
},
|
|
||||||
{ cwd = worktree, text = true },
|
|
||||||
vim.schedule_wrap(function(result)
|
|
||||||
if not vim.api.nvim_buf_is_valid(buf) then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
if result.code ~= 0 then
|
|
||||||
log.error("git log failed: %s", vim.trim(result.stderr or ""))
|
|
||||||
return
|
|
||||||
end
|
|
||||||
local lines = util.split_lines(result.stdout or "")
|
|
||||||
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 = "gitlog"
|
|
||||||
end)
|
|
||||||
)
|
)
|
||||||
|
vim.bo[buf].modifiable = false
|
||||||
|
vim.bo[buf].modified = false
|
||||||
|
vim.bo[buf].filetype = "gitlog"
|
||||||
end
|
end
|
||||||
|
|
||||||
return M
|
return M
|
||||||
|
|||||||
+37
-40
@@ -214,14 +214,13 @@ local function parse_porcelain(stdout)
|
|||||||
return branch, groups
|
return branch, groups
|
||||||
end
|
end
|
||||||
|
|
||||||
---Run the ahead/behind `git log` calls for any non-zero counters and call
|
---Fill in the Unpushed/Unpulled groups from `git log` for any non-zero
|
||||||
---`callback(branch, groups)` once they all finish (or immediately when
|
---ahead/behind counter. Capped at 200 commits per range so a wildly
|
||||||
---there's nothing to fetch).
|
---divergent branch can't blow the sidebar's render budget.
|
||||||
---@param worktree string
|
---@param worktree string
|
||||||
---@param branch ow.Git.BranchInfo
|
---@param branch ow.Git.BranchInfo
|
||||||
---@param groups table<string, ow.Git.SidebarEntry[]>
|
---@param groups table<string, ow.Git.SidebarEntry[]>
|
||||||
---@param callback fun(branch: ow.Git.BranchInfo, groups: table<string, ow.Git.SidebarEntry[]>)
|
local function enrich_with_log(worktree, branch, groups)
|
||||||
local function enrich_with_log(worktree, branch, groups, callback)
|
|
||||||
local fetches = {}
|
local fetches = {}
|
||||||
if branch.upstream and branch.ahead > 0 then
|
if branch.upstream and branch.ahead > 0 then
|
||||||
table.insert(
|
table.insert(
|
||||||
@@ -235,45 +234,41 @@ local function enrich_with_log(worktree, branch, groups, callback)
|
|||||||
{ section = "Unpulled", range = "HEAD..@{upstream}" }
|
{ section = "Unpulled", range = "HEAD..@{upstream}" }
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
if #fetches == 0 then
|
-- Submit both subprocesses before waiting so they run concurrently
|
||||||
callback(branch, groups)
|
-- rather than sequentially. Total time = max, not sum.
|
||||||
return
|
local pending = {}
|
||||||
end
|
|
||||||
local pending = #fetches
|
|
||||||
for _, f in ipairs(fetches) do
|
for _, f in ipairs(fetches) do
|
||||||
vim.system(
|
table.insert(pending, {
|
||||||
{
|
f = f,
|
||||||
|
sys = vim.system({
|
||||||
"git",
|
"git",
|
||||||
"log",
|
"log",
|
||||||
|
"--max-count=200",
|
||||||
"--format=%h %s",
|
"--format=%h %s",
|
||||||
f.range,
|
f.range,
|
||||||
},
|
}, { cwd = worktree, text = true }),
|
||||||
{ cwd = worktree, text = true },
|
})
|
||||||
vim.schedule_wrap(function(log_obj)
|
end
|
||||||
if log_obj.code == 0 then
|
for _, p in ipairs(pending) do
|
||||||
for line in (log_obj.stdout or ""):gmatch("[^\r\n]+") do
|
local result = p.sys:wait()
|
||||||
local sha, subject = line:match("^(%S+)%s+(.+)$")
|
if result.code == 0 then
|
||||||
if sha then
|
for line in (result.stdout or ""):gmatch("[^\r\n]+") do
|
||||||
table.insert(groups[f.section], {
|
local sha, subject = line:match("^(%S+)%s+(.+)$")
|
||||||
section = f.section,
|
if sha then
|
||||||
sha = sha,
|
table.insert(groups[p.f.section], {
|
||||||
subject = subject,
|
section = p.f.section,
|
||||||
})
|
sha = sha,
|
||||||
end
|
subject = subject,
|
||||||
end
|
})
|
||||||
else
|
|
||||||
log.error(
|
|
||||||
"git log %s failed: %s",
|
|
||||||
f.range,
|
|
||||||
vim.trim(log_obj.stderr or "")
|
|
||||||
)
|
|
||||||
end
|
end
|
||||||
pending = pending - 1
|
end
|
||||||
if pending == 0 then
|
else
|
||||||
callback(branch, groups)
|
log.error(
|
||||||
end
|
"git log %s failed: %s",
|
||||||
end)
|
p.f.range,
|
||||||
)
|
vim.trim(result.stderr or "")
|
||||||
|
)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -287,7 +282,8 @@ end
|
|||||||
local function fetch_status(worktree, prefetched_stdout, callback)
|
local function fetch_status(worktree, prefetched_stdout, callback)
|
||||||
if prefetched_stdout then
|
if prefetched_stdout then
|
||||||
local branch, groups = parse_porcelain(prefetched_stdout)
|
local branch, groups = parse_porcelain(prefetched_stdout)
|
||||||
enrich_with_log(worktree, branch, groups, callback)
|
enrich_with_log(worktree, branch, groups)
|
||||||
|
callback(branch, groups)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
vim.system(
|
vim.system(
|
||||||
@@ -316,7 +312,8 @@ local function fetch_status(worktree, prefetched_stdout, callback)
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
local branch, groups = parse_porcelain(obj.stdout or "")
|
local branch, groups = parse_porcelain(obj.stdout or "")
|
||||||
enrich_with_log(worktree, branch, groups, callback)
|
enrich_with_log(worktree, branch, groups)
|
||||||
|
callback(branch, groups)
|
||||||
end)
|
end)
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user