local util = require("git.util") local M = {} M.UNMERGED = { DD = true, AU = true, UD = true, UA = true, DU = true, AA = true, UU = true, } ---@param code string ---@return string? char ---@return string? hl_group function M.indicator(code) if code == "" then return nil end if code == "??" then return "?", "GitUntracked" end if code == "!!" then return "!", "GitIgnored" end if M.UNMERGED[code] then return "U", "GitUnmerged" end local x, y = code:sub(1, 1), code:sub(2, 2) if x == "R" or y == "R" then return "R", "GitRenamed" end if y == " " and x ~= " " then return x, "GitStaged" end if y == "D" then return "D", "GitDeleted" end return "M", "GitUnstaged" end ---@param path string ---@return string? gitdir ---@return string? worktree function M.resolve(path) local found = vim.fs.find(".git", { upward = true, path = path })[1] if not found then return nil end local worktree = vim.fs.dirname(found) local stat = vim.uv.fs_stat(found) if not stat then return nil end if stat.type == "directory" then return found, worktree end local f = io.open(found, "r") if not f then return nil end local content = f:read("*a") f:close() local gitdir = content:match("gitdir:%s*(%S+)") if not gitdir then util.warning(".git file at %s has no `gitdir:` line", found) return nil end if not gitdir:match("^/") then gitdir = vim.fs.joinpath(worktree, gitdir) end return vim.fs.normalize(gitdir), worktree end ---@return string? gitdir ---@return string? worktree function M.resolve_cwd() local path = vim.api.nvim_buf_get_name(0) if path == "" or path:match("^%a+://") then path = vim.fn.getcwd() end return M.resolve(path) end ---@param path string ---@return string? function M.head(path) local gitdir = M.resolve(path) if not gitdir then return nil end local f = io.open(vim.fs.joinpath(gitdir, "HEAD"), "r") if not f then return nil end local first = f:read("*l") f:close() if not first then return nil end local branch = first:match("^ref:%s*refs/heads/(%S+)") if branch then return branch end local sha = first:match("^(%x+)") if sha then return sha:sub(1, 7) end return nil end ---@param worktree string ---@param rev string ---@param short boolean ---@return string? function M.rev_parse(worktree, rev, short) local cmd = { "git", "rev-parse", "--verify", "--quiet" } if short then table.insert(cmd, "--short") end table.insert(cmd, rev) local stdout = util.exec(cmd, { cwd = worktree, silent = true }) local trimmed = stdout and vim.trim(stdout) or "" return trimmed ~= "" and trimmed or nil end return M