diff --git a/lua/git/status_win.lua b/lua/git/status_win.lua index 337229d..13cf6fc 100644 --- a/lua/git/status_win.lua +++ b/lua/git/status_win.lua @@ -37,6 +37,7 @@ local SIDEBAR_WIDTH = 50 ---@field diff_right_win integer? ---@field user_aucmd integer? ---@field last_shown_key string? +---@field last_render_key string? fingerprint of the last rendered state ---@type table local state = {} @@ -328,10 +329,41 @@ local function render(bufnr, branch, groups) }) end state[bufnr].lines = meta - -- The diff windows we last opened may now be showing content for an - -- entry whose underlying file has changed. Drop the cache so the next - -- show_diff recomputes pre/post panes instead of short-circuiting. - state[bufnr].last_shown_key = nil +end + +---Build a stable fingerprint of the parsed branch + groups so refresh can +---short-circuit when the porcelain state is byte-identical to the last +---successful render. +---@param branch ow.Git.BranchInfo +---@param groups table +---@return string +local function fingerprint(branch, groups) + local parts = { + branch.head or "", + branch.upstream or "", + tostring(branch.ahead), + tostring(branch.behind), + } + for _, section in ipairs(SECTIONS) do + local entries = groups[section] + if entries then + for _, e in ipairs(entries) do + table.insert( + parts, + e.section + .. ":" + .. (e.path or e.sha or "") + .. ":" + .. (e.orig or "") + .. ":" + .. (e.x or "") + .. ":" + .. (e.y or "") + ) + end + end + end + return table.concat(parts, "\0") end ---@param bufnr integer @@ -356,6 +388,15 @@ local function refresh(bufnr) if not vim.api.nvim_buf_is_valid(bufnr) then return end + -- Any fs-event that triggered this refresh might have changed the + -- worktree under the diff buffers we last opened; invalidate the + -- cache so the next show_diff recomputes panes. + s.last_shown_key = nil + local fp = fingerprint(branch, groups) + if fp == s.last_render_key then + return + end + s.last_render_key = fp render(bufnr, branch, groups) if not saved_path and not saved_sha then return