perf(git): cache index blob sha, drop rev-parse from the edit path
This commit is contained in:
+22
-4
@@ -123,6 +123,16 @@ local function affects_resolve(relpath)
|
|||||||
or relpath == "FETCH_HEAD"
|
or relpath == "FETCH_HEAD"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@private
|
||||||
|
---@param prefix string
|
||||||
|
function Repo:_clear_cache_prefix(prefix)
|
||||||
|
for key in pairs(self._cache) do
|
||||||
|
if vim.startswith(key, prefix) then
|
||||||
|
self._cache[key] = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
---@private
|
---@private
|
||||||
---@param relpath string
|
---@param relpath string
|
||||||
function Repo:_invalidate(relpath)
|
function Repo:_invalidate(relpath)
|
||||||
@@ -132,11 +142,10 @@ function Repo:_invalidate(relpath)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
if affects_resolve(relpath) then
|
if affects_resolve(relpath) then
|
||||||
for key in pairs(self._cache) do
|
self:_clear_cache_prefix("resolve:")
|
||||||
if vim.startswith(key, "resolve:") then
|
|
||||||
self._cache[key] = nil
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
if relpath == "index" then
|
||||||
|
self:_clear_cache_prefix("index:")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -587,6 +596,15 @@ function Repo:rev_parse(rev, short)
|
|||||||
return trimmed ~= "" and trimmed or nil
|
return trimmed ~= "" and trimmed or nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@param rel string worktree-relative path
|
||||||
|
---@return string?
|
||||||
|
function Repo:index_sha(rel)
|
||||||
|
local sha = self:get_cached("index:" .. rel, function(self)
|
||||||
|
return self:rev_parse(":" .. rel, false) or false
|
||||||
|
end)
|
||||||
|
return sha or nil
|
||||||
|
end
|
||||||
|
|
||||||
---@alias ow.Git.Repo.ResolveStatus "ok"|"ambiguous"|"missing"
|
---@alias ow.Git.Repo.ResolveStatus "ok"|"ambiguous"|"missing"
|
||||||
|
|
||||||
---@param abbrev string
|
---@param abbrev string
|
||||||
|
|||||||
+1
-2
@@ -262,8 +262,7 @@ local function recompute(buf)
|
|||||||
if not state then
|
if not state then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
local r = state.repo
|
local new_sha = state.repo:index_sha(state.rel)
|
||||||
local new_sha = r:rev_parse(":" .. state.rel, true)
|
|
||||||
if not new_sha then
|
if not new_sha then
|
||||||
state.index = nil
|
state.index = nil
|
||||||
state.index_sha = nil
|
state.index_sha = nil
|
||||||
|
|||||||
@@ -71,6 +71,32 @@ t.test("get_cached memoizes by key", function()
|
|||||||
t.truthy(v1 == v2, "second call should return cached table")
|
t.truthy(v1 == v2, "second call should return cached table")
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
t.test("index_sha returns the blob sha and caches it", function()
|
||||||
|
local dir = h.make_repo({ a = "x\n" })
|
||||||
|
local r = assert(require("git.core.repo").resolve(dir))
|
||||||
|
local sha = r:index_sha("a")
|
||||||
|
t.truthy(sha and #sha > 0, "index_sha returns the stage-0 blob sha")
|
||||||
|
t.truthy(r._cache["index:a"] ~= nil, "the result is cached")
|
||||||
|
t.eq(r:index_sha("a"), sha, "a cached call returns the same sha")
|
||||||
|
end)
|
||||||
|
|
||||||
|
t.test("index_sha caches a negative result for an untracked path", function()
|
||||||
|
local dir = h.make_repo({ a = "x\n" })
|
||||||
|
local r = assert(require("git.core.repo").resolve(dir))
|
||||||
|
t.eq(r:index_sha("nope"), nil, "an untracked path has no index sha")
|
||||||
|
t.eq(r._cache["index:nope"], false, "the negative result is cached")
|
||||||
|
end)
|
||||||
|
|
||||||
|
t.test("index_sha cache clears when the index is written", function()
|
||||||
|
local dir = h.make_repo({ a = "x\n" })
|
||||||
|
local r = assert(require("git.core.repo").resolve(dir))
|
||||||
|
r:index_sha("a")
|
||||||
|
t.truthy(r._cache["index:a"] ~= nil, "sha is cached before the stage")
|
||||||
|
t.write(dir, "a", "y\n")
|
||||||
|
h.git(dir, "add", "a")
|
||||||
|
wait_cleared(r, "index:a", 2000)
|
||||||
|
end)
|
||||||
|
|
||||||
t.test("cache clears after top-level .git change (commit)", function()
|
t.test("cache clears after top-level .git change (commit)", function()
|
||||||
local dir = h.make_repo({ a = "x" })
|
local dir = h.make_repo({ a = "x" })
|
||||||
local r = assert(require("git.core.repo").resolve(dir))
|
local r = assert(require("git.core.repo").resolve(dir))
|
||||||
|
|||||||
Reference in New Issue
Block a user