From ae379a62dcaa0854086c6763672b806d3175b91c Mon Sep 17 00:00:00 2001 From: Folke Lemaitre Date: Fri, 2 Dec 2022 11:26:07 +0100 Subject: [PATCH] fix(git): fixed branch detection, get target commit from origin and always checkout a tag or commit so we dont need to use git merge --- lua/lazy/manage/git.lua | 45 +++++++++++++++++++++++------------- lua/lazy/manage/lock.lua | 3 +-- lua/lazy/manage/task/git.lua | 20 +++++++++++----- 3 files changed, 44 insertions(+), 24 deletions(-) diff --git a/lua/lazy/manage/git.lua b/lua/lazy/manage/git.lua index df64465..6984afe 100644 --- a/lua/lazy/manage/git.lua +++ b/lua/lazy/manage/git.lua @@ -51,41 +51,54 @@ function M.get_versions(repo, spec) end ---@param plugin LazyPlugin ----@return {branch:string, commit?:string}? +---@return string? function M.get_branch(plugin) if plugin.branch then - return { - branch = plugin.branch, - commit = M.ref(plugin.dir, "heads/" .. plugin.branch), - } + return plugin.branch else + -- we need to return the default branch + -- Try origin first local main = M.ref(plugin.dir, "remotes/origin/HEAD") if main then local branch = main:match("ref: refs/remotes/origin/(.*)") if branch then - return { - branch = branch, - commit = M.ref(plugin.dir, "heads/" .. branch), - } + return branch end end + + -- fallback to local HEAD + main = assert(Util.head(plugin.dir .. "/.git/HEAD")) + return main and main:match("ref: refs/heads/(.*)") + end +end + +-- Return the last commit for the given branch +---@param repo string +---@param branch string +---@param origin? boolean +function M.get_commit(repo, branch, origin) + if origin then + -- origin ref might not exist if it is the same as local + return M.ref(repo, "remotes/origin", branch) or M.ref(repo, "heads", branch) + else + return M.ref(repo, "heads", branch) end end ---@param plugin LazyPlugin ---@return GitInfo? function M.get_target(plugin) - local branch = M.get_branch(plugin) or M.info(plugin.dir) + local branch = assert(M.get_branch(plugin)) if plugin.commit then return { - branch = branch and branch.branch, + branch = branch, commit = plugin.commit, } end if plugin.tag then return { - branch = branch and branch.branch, + branch = branch, tag = plugin.tag, commit = M.ref(plugin.dir, "tags/" .. plugin.tag), } @@ -95,7 +108,7 @@ function M.get_target(plugin) local last = Semver.last(M.get_versions(plugin.dir, version)) if last then return { - branch = branch and branch.branch, + branch = branch, version = last, tag = last.tag, commit = M.ref(plugin.dir, "tags/" .. last.tag), @@ -103,11 +116,11 @@ function M.get_target(plugin) end end ---@diagnostic disable-next-line: return-type-mismatch - return branch + return { branch = branch, commit = M.get_commit(plugin.dir, branch, true) } end -function M.ref(repo, ref) - return Util.head(repo .. "/.git/refs/" .. ref) +function M.ref(repo, ...) + return Util.head(repo .. "/.git/refs/" .. table.concat({ ... }, "/")) end return M diff --git a/lua/lazy/manage/lock.lua b/lua/lazy/manage/lock.lua index 0b03e8c..5141501 100644 --- a/lua/lazy/manage/lock.lua +++ b/lua/lazy/manage/lock.lua @@ -29,8 +29,7 @@ function M.update() if not plugin._.is_local and plugin._.installed then local info = assert(Git.info(plugin.dir)) if not info.branch then - local branch = assert(Git.get_branch(plugin)) - info.branch = branch.branch + info.branch = assert(Git.get_branch(plugin)) end info.commit = info.commit -- f:write(([[ [%q] = { branch = %q, commit = %q },]]):format(name, info.branch, info.commit) .. "\n") diff --git a/lua/lazy/manage/task/git.lua b/lua/lazy/manage/task/git.lua index 5a404ba..c9e3051 100644 --- a/lua/lazy/manage/task/git.lua +++ b/lua/lazy/manage/task/git.lua @@ -30,6 +30,7 @@ M.log = { elseif opts.check then local info = assert(Git.info(self.plugin.dir)) local target = assert(Git.get_target(self.plugin)) + assert(target.commit, self.plugin.name .. " " .. target.branch) table.insert(args, info.commit .. ".." .. target.commit) else vim.list_extend(args, opts.args or Config.options.git.log) @@ -76,22 +77,23 @@ M.clone = { end, } +-- setup origin branches if needed +-- fetch will retrieve the data M.branch = { skip = function(plugin) if not plugin._.installed or plugin._.is_local then return true end local branch = assert(Git.get_branch(plugin)) - return branch and branch.commit + return Git.get_commit(plugin.dir, branch) end, run = function(self) - local branch = assert(Git.get_branch(self.plugin)) local args = { "remote", "set-branches", "--add", "origin", - branch.branch, + assert(Git.get_branch(self.plugin)), } self:spawn("git", { @@ -101,6 +103,7 @@ M.branch = { end, } +-- fetches all needed origin branches M.fetch = { skip = function(plugin) return not plugin._.installed or plugin._.is_local @@ -121,6 +124,8 @@ M.fetch = { end, } +-- checkout to the target commit +-- branches will exists at this point, so so will the commit M.checkout = { skip = function(plugin) return not plugin._.installed or plugin._.is_local @@ -131,7 +136,7 @@ M.checkout = { local info = assert(Git.info(self.plugin.dir)) local target = assert(Git.get_target(self.plugin)) - -- if the plugin is locked and we did not just clone it, + -- if the plugin is pinned and we did not just clone it, -- then don't update if self.plugin.pin and not self.plugin._.cloned then target = info @@ -139,6 +144,7 @@ M.checkout = { local lock if opts.lockfile then + -- restore to the lock if it exists lock = Lock.get(self.plugin) if lock then ---@diagnostic disable-next-line: cast-local-type @@ -146,6 +152,8 @@ M.checkout = { end end + -- dont run checkout if target is already reached. + -- unless we just clones, since then we won't have any data yet if not self.plugin._.cloned and info.commit == target.commit and info.branch == target.branch then self.plugin._.updated = { from = info.commit, @@ -165,8 +173,8 @@ M.checkout = { table.insert(args, "tags/" .. target.tag) elseif self.plugin.commit then table.insert(args, self.plugin.commit) - elseif target.branch then - table.insert(args, target.branch) + else + table.insert(args, target.commit) end self:spawn("git", {