Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: improve support for worktrees in bare repos #1167

Merged
merged 1 commit into from
Jan 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 28 additions & 83 deletions lua/gitsigns/attach.lua
Original file line number Diff line number Diff line change
Expand Up @@ -19,82 +19,21 @@ local uv = vim.loop
local M = {}

--- @param name string
--- @return string? buffer
--- @return string? rel_path
--- @return string? commit
local function parse_fugitive_uri(name)
if vim.fn.exists('*FugitiveReal') == 0 then
dprint('Fugitive not installed')
--- @return string? gitdir
local function parse_git_path(name)
if not vim.startswith(name, 'fugitive://') and not vim.startswith(name, 'gitsigns://') then
return
end

---@type string
local path = vim.fn.FugitiveReal(name)
---@type string?
local commit = vim.fn.FugitiveParse(name)[1]:match('([^:]+):.*')
if commit == '0' then
-- '0' means the index so clear commit so we attach normally
commit = nil
end
return path, commit
end

--- @param name string
--- @return string buffer
--- @return string? commit
local function parse_gitsigns_uri(name)
local _proto, head, tail = unpack(vim.split(name, '//'))

--- @type any, any, string?, string?
local _, _, root_path, sub_path = head:find([[(.*)/%.git(.*)]])

--- @type any, any, string?, string?
local _, _, commit, rel_path = tail:find([[(.*):(.*)]])

commit = util.norm_base(commit)

if root_path then
if sub_path then
sub_path = sub_path:gsub('^/modules/', '')
name = string.format('%s/%s/%s', root_path, sub_path, rel_path)
else
name = string.format('%s/%s', root_path, rel_path)
end
end

return name, commit
end

--- @param bufnr integer
--- @return string buffer
--- @return string? commit
--- @return boolean? force_attach
local function get_buf_path(bufnr)
local file = uv.fs_realpath(api.nvim_buf_get_name(bufnr))
or api.nvim_buf_call(bufnr, function()
return vim.fn.expand('%:p')
end)

if vim.startswith(file, 'fugitive://') then
local path, commit = parse_fugitive_uri(file)
dprintf("Fugitive buffer for file '%s' from path '%s'", path, file)
if path then
local realpath = uv.fs_realpath(path)
if realpath and vim.fn.isdirectory(realpath) == 0 then
return realpath, commit, true
end
end
end

if vim.startswith(file, 'gitsigns://') then
local path, commit = parse_gitsigns_uri(file)
dprintf("Gitsigns buffer for file '%s' from path '%s' on commit '%s'", path, file, commit)
local realpath = uv.fs_realpath(path)
if realpath then
return realpath, commit, true
end
end

return file
local proto, gitdir, tail = unpack(vim.split(name, '//'))
assert(proto and gitdir and tail)
local plugin = proto:sub(1, 1):upper() .. proto:sub(2, -2)
local commit, rel_path = unpack(vim.split(tail, ':'))
rel_path = rel_path or tail
dprintf("%s buffer for file '%s' from path '%s' on commit '%s'", plugin, rel_path, file, commit)
return rel_path, commit, gitdir
end

local function on_lines(_, bufnr, _, first, last_orig, last_new, byte_count)
Expand Down Expand Up @@ -202,24 +141,30 @@ local function get_buf_context(bufnr)
return nil, 'Exceeds max_file_length'
end

local file, commit, force_attach = get_buf_path(bufnr)
local file = uv.fs_realpath(api.nvim_buf_get_name(bufnr))
or api.nvim_buf_call(bufnr, function()
return vim.fn.expand('%:p')
end)

if vim.bo[bufnr].buftype ~= '' and not force_attach then
return nil, 'Non-normal buffer'
end
local rel_path, commit, gitdir_from_bufname = parse_git_path(file)

local file_dir = util.dirname(file)
if not gitdir_from_bufname then
if vim.bo[bufnr].buftype ~= '' then
return nil, 'Non-normal buffer'
end

if not file_dir or not util.path_exists(file_dir) then
return nil, 'Not a path'
local file_dir = util.dirname(file)
if not file_dir or not util.path_exists(file_dir) then
return nil, 'Not a path'
end
end

local gitdir, toplevel = on_attach_pre(bufnr)
local gitdir_oap, toplevel_oap = on_attach_pre(bufnr)

return {
file = file,
gitdir = gitdir,
toplevel = toplevel,
file = rel_path or file,
gitdir = gitdir_oap or gitdir_from_bufname,
toplevel = toplevel_oap,
-- Stage buffers always compare against the common ancestor (':1')
-- :0: index
-- :1: common ancestor
Expand Down
7 changes: 6 additions & 1 deletion lua/gitsigns/diffthis.lua
Original file line number Diff line number Diff line change
Expand Up @@ -219,9 +219,14 @@ M.show = async.create(2, function(bufnr, base, _callback)
-- Wait for the buffer to attach in case the user passes a callback that
-- requires the buffer to be attached.
local sbufnr = api.nvim_get_current_buf()
vim.wait(2000, function()

local attached = vim.wait(2000, function()
return cache[sbufnr] ~= nil
end)

if not attached then
log.eprintf("Show buffer '%s' did not attach", bufname)
end
end)

--- @param bufnr integer
Expand Down
Loading