From d67484fe87d423ace0b0f7b4590a80f8bfc8cee2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20F=2E=20Bortl=C3=ADk?= Date: Sat, 28 Feb 2026 07:44:58 +0100 Subject: [PATCH 1/2] fix: check local branch up-to-date on remote before creating comment --- lua/gitlab/actions/comment.lua | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lua/gitlab/actions/comment.lua b/lua/gitlab/actions/comment.lua index 03202a2b..086cd1e6 100644 --- a/lua/gitlab/actions/comment.lua +++ b/lua/gitlab/actions/comment.lua @@ -349,6 +349,10 @@ M.can_create_comment = function(must_be_visual) return false end + if not git.check_current_branch_up_to_date_on_remote(vim.log.levels.ERROR) then + return false + end + -- Check we're in visual mode for code suggestions and multiline comments if must_be_visual and not u.check_visual_mode() then return false From f7c7a93da4cc9acf97f43e88f55f29940c79ccc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20F=2E=20Bortl=C3=ADk?= Date: Mon, 2 Mar 2026 12:41:28 +0100 Subject: [PATCH 2/2] feat: show ahead and behind commits in winbar --- lua/gitlab/actions/discussions/init.lua | 3 + lua/gitlab/actions/discussions/winbar.lua | 19 +++++- lua/gitlab/annotations.lua | 2 + lua/gitlab/git.lua | 75 +++++++++++------------ lua/gitlab/state.lua | 9 +-- 5 files changed, 64 insertions(+), 44 deletions(-) diff --git a/lua/gitlab/actions/discussions/init.lua b/lua/gitlab/actions/discussions/init.lua index dc0526e3..eb1d6c4c 100644 --- a/lua/gitlab/actions/discussions/init.lua +++ b/lua/gitlab/actions/discussions/init.lua @@ -55,6 +55,9 @@ end ---Makes API call to get the discussion data, stores it in the state, and calls the callback ---@param callback function|nil M.load_discussions = function(callback) + local git = require("gitlab.git") + local ahead, behind = git.get_ahead_behind(git.get_current_branch(), git.get_remote_branch()) + state.ahead_behind = { ahead, behind } state.discussion_tree.last_updated = nil state.load_new_state("discussion_data", function(data) if not state.DISCUSSION_DATA then diff --git a/lua/gitlab/actions/discussions/winbar.lua b/lua/gitlab/actions/discussions/winbar.lua index 719c48f7..6dcd6011 100644 --- a/lua/gitlab/actions/discussions/winbar.lua +++ b/lua/gitlab/actions/discussions/winbar.lua @@ -94,6 +94,8 @@ local function content() resolved_notes = resolved_notes, non_resolvable_notes = non_resolvable_notes, help_keymap = state.settings.keymaps.help, + ahead = state.ahead_behind[1], + behind = state.ahead_behind[2], updated = updated, } @@ -158,7 +160,7 @@ end M.make_winbar = function(t) local discussions_focused = M.current_view_type == "discussions" local discussion_text = add_drafts_and_resolvable( - "Inline Comments:", + "Comments:", t.resolvable_discussions, t.resolved_discussions, t.inline_draft_notes, @@ -190,15 +192,18 @@ M.make_winbar = function(t) local separator = "%#Comment#|" local end_section = "%=" local updated = "%#Text#" .. t.updated + local ahead_behind = M.get_ahead_behind(t.ahead, t.behind) local help = "%#Comment#Help: " .. (t.help_keymap and t.help_keymap:gsub(" ", "") .. " " or "unmapped") return string.format( - " %s %s %s %s %s %s %s %s %s %s %s", + " %s %s %s %s %s %s %s %s %s %s %s %s %s", discussion_text, separator, notes_text, end_section, updated, separator, + ahead_behind, + separator, sort_method, separator, mode, @@ -254,6 +259,16 @@ M.get_mode = function() end end +---@param ahead number|nil +---@param behind number|nil +M.get_ahead_behind = function(ahead, behind) + local a = ahead == nil and "?" or tostring(ahead) + local b = behind == nil and "?" or tostring(behind) + a = ((a == "?" or a == "0") and "%#Comment#" or "%#WarningMsg#") .. a + b = ((b == "?" or b == "0") and "%#Comment#" or "%#WarningMsg#") .. b + return a .. "↑ " .. b .. "↓" +end + ---Toggles the current view type (or sets it to `override`) and then updates the view. ---@param override "discussions"|"notes" Defines the view type to select. M.switch_view_type = function(override) diff --git a/lua/gitlab/annotations.lua b/lua/gitlab/annotations.lua index e1403249..cccd4608 100644 --- a/lua/gitlab/annotations.lua +++ b/lua/gitlab/annotations.lua @@ -92,6 +92,8 @@ ---@field resolved_notes number ---@field non_resolvable_notes number ---@field help_keymap string +---@field ahead number|nil -- Number of commits local is ahead of remote +---@field behind number|nil -- Number of commits local is behind remote ---@field updated string --- ---@class SignTable diff --git a/lua/gitlab/git.lua b/lua/gitlab/git.lua index ba42546e..ae139df5 100644 --- a/lua/gitlab/git.lua +++ b/lua/gitlab/git.lua @@ -74,14 +74,17 @@ M.fetch_remote_branch = function(remote_branch) return true end ----Determines whether the tracking branch is ahead of or behind the current branch, and warns the user if so ----@param current_branch string ----@param remote_branch string ----@param log_level number ----@return boolean -M.get_ahead_behind = function(current_branch, remote_branch, log_level) +---Determines whether the tracking branch is ahead of or behind the current branch and returns the +---number of ahead and behind commits or nil values in case of errors. +---@param current_branch string|nil +---@param remote_branch string|nil +---@return integer|nil ahead, integer|nil behind +M.get_ahead_behind = function(current_branch, remote_branch) + if current_branch == nil or remote_branch == nil then + return nil, nil + end if not M.fetch_remote_branch(remote_branch) then - return false + return nil, nil end local u = require("gitlab.utils") @@ -89,39 +92,16 @@ M.get_ahead_behind = function(current_branch, remote_branch, log_level) run_system({ "git", "rev-list", "--left-right", "--count", current_branch .. "..." .. remote_branch }) if err ~= nil or result == nil then u.notify("Could not determine if branch is up-to-date: " .. err, vim.log.levels.ERROR) - return false + return nil, nil end local ahead, behind = result:match("(%d+)%s+(%d+)") if ahead == nil or behind == nil then - u.notify("Error parsing ahead/behind information.", vim.log.levels.ERROR) - return false - end - - ahead = tonumber(ahead) - behind = tonumber(behind) - - if ahead > 0 and behind == 0 then - u.notify(string.format("There are local changes that haven't been pushed to %s yet", remote_branch), log_level) - return false - end - if behind > 0 and ahead == 0 then - u.notify(string.format("There are remote changes on %s that haven't been pulled yet", remote_branch), log_level) - return false - end - - if ahead > 0 and behind > 0 then - u.notify( - string.format( - "Your branch and the remote %s have diverged. You need to pull, possibly rebase, and then push.", - remote_branch - ), - log_level - ) - return false + u.notify("Error parsing ahead/behind information", vim.log.levels.ERROR) + return nil, nil end - return true -- Checks passed, branch is up-to-date + return tonumber(ahead), tonumber(behind) end ---Return the name of the current branch or nil if it can't be retrieved @@ -184,16 +164,35 @@ end ---@return boolean M.check_current_branch_up_to_date_on_remote = function(log_level) local current_branch = M.get_current_branch() - if current_branch == nil then + local remote_branch = M.get_remote_branch() + local ahead, behind = M.get_ahead_behind(current_branch, remote_branch) + if ahead == nil or behind == nil then return false end - local remote_branch = M.get_remote_branch() - if remote_branch == nil then + local u = require("gitlab.utils") + + if ahead > 0 and behind == 0 then + u.notify(string.format("There are local changes that haven't been pushed to %s yet", remote_branch), log_level) + return false + end + if behind > 0 and ahead == 0 then + u.notify(string.format("There are remote changes on %s that haven't been pulled yet", remote_branch), log_level) return false end - return M.get_ahead_behind(current_branch, remote_branch, log_level) + if ahead > 0 and behind > 0 then + u.notify( + string.format( + "Your branch and the remote %s have diverged. You need to pull, possibly rebase, and then push.", + remote_branch + ), + log_level + ) + return false + end + + return true -- Checks passed, branch is up-to-date end ---Warns user if the current MR is in a bad state (closed, has conflicts, merged) diff --git a/lua/gitlab/state.lua b/lua/gitlab/state.lua index d67e0c06..7a655a72 100644 --- a/lua/gitlab/state.lua +++ b/lua/gitlab/state.lua @@ -3,16 +3,17 @@ -- This module is also responsible for ensuring that the state of the plugin -- is valid via dependencies -local git = require("gitlab.git") local u = require("gitlab.utils") local List = require("gitlab.utils.list") -local M = {} - -M.emoji_map = nil +local M = { + emoji_map = nil, + ahead_behind = { nil, nil }, +} ---Returns a gitlab token, and a gitlab URL. Used to connect to gitlab. ---@return string|nil, string|nil, string|nil M.default_auth_provider = function() + local git = require("gitlab.git") local base_path, err = M.settings.config_path, nil if base_path == nil then base_path, err = git.base_dir()