Skip to content

fix(#1976): improve $GIT_DIR handling #2012

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

Merged
merged 10 commits into from
Apr 22, 2023
20 changes: 7 additions & 13 deletions lua/nvim-tree/explorer/watch.lua
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,19 @@ local Watcher = require("nvim-tree.watcher").Watcher

local M = {}

local function is_git(path)
return vim.fn.fnamemodify(path, ":t") == ".git"
end

local IGNORED_PATHS = {
M.ignore_dirs = {
-- disable watchers on kernel filesystems
-- which have a lot of unwanted events
"/sys",
"/proc",
"/dev",
}

local function is_folder_ignored(path)
for _, folder in ipairs(IGNORED_PATHS) do
if vim.startswith(path, folder) then
return true
end
end
function M.ignore_dir(path)
table.insert(M.ignore_dirs, path)
end

local function is_folder_ignored(path)
for _, ignore_dir in ipairs(M.ignore_dirs) do
if vim.fn.match(path, ignore_dir) ~= -1 then
return true
Expand All @@ -44,7 +38,7 @@ function M.create_watcher(node)
path = node.absolute_path
end

if is_git(path) or is_folder_ignored(path) then
if is_folder_ignored(path) then
return nil
end

Expand Down Expand Up @@ -74,7 +68,7 @@ end
function M.setup(opts)
M.enabled = opts.filesystem_watchers.enable
M.debounce_delay = opts.filesystem_watchers.debounce_delay
M.ignore_dirs = opts.filesystem_watchers.ignore_dirs
M.ignore_dirs = vim.tbl_extend("force", M.ignore_dirs, opts.filesystem_watchers.ignore_dirs)
M.uid = 0
end

Expand Down
37 changes: 25 additions & 12 deletions lua/nvim-tree/git/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ local log = require "nvim-tree.log"
local utils = require "nvim-tree.utils"
local git_utils = require "nvim-tree.git.utils"
local Runner = require "nvim-tree.git.runner"
local Watch = require "nvim-tree.explorer.watch"
local Watcher = require("nvim-tree.watcher").Watcher
local Iterator = require "nvim-tree.iterators.node-iterator"
local explorer_node = require "nvim-tree.explorer.node"
Expand Down Expand Up @@ -164,22 +165,34 @@ function M.load_project_status(cwd)
}

local watcher = nil

if M.config.filesystem_watchers.enable then
log.line("watcher", "git start")

local callback = function(w)
log.line("watcher", "git event scheduled '%s'", w.project_root)
utils.debounce("git:watcher:" .. w.project_root, M.config.filesystem_watchers.debounce_delay, function()
if w.destroyed then
return
end
reload_tree_at(w.project_root)
end)
end
local git_directory = git_utils.get_git_directory(project_root)

if git_directory == nil then
log.line("watcher", "could not found the location of .git folder")
else
local callback = function(w)
log.line("watcher", "git event scheduled '%s'", w.project_root)
utils.debounce("git:watcher:" .. w.project_root, M.config.filesystem_watchers.debounce_delay, function()
if w.destroyed then
return
end
reload_tree_at(w.project_root)
end)
end

-- Add GIT_DIR to the list of directory to ignore
-- local base_gitdir = utils.path_basename(git_directory)
-- Watch.ignore_dir(base_gitdir)
Watch.ignore_dir(git_directory)

watcher = Watcher:new(utils.path_join { project_root, ".git" }, WATCHED_FILES, callback, {
project_root = project_root,
})
watcher = Watcher:new(git_directory, WATCHED_FILES, callback, {
project_root = project_root,
})
end
end

M.projects[project_root] = {
Expand Down
40 changes: 28 additions & 12 deletions lua/nvim-tree/git/utils.lua
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
local M = {}
local log = require "nvim-tree.log"

local has_cygpath = vim.fn.executable "cygpath" == 1
local utils = require "nvim-tree.utils"

function M.get_toplevel(cwd)
local profile = log.profile_start("git toplevel %s", cwd)
Expand All @@ -18,16 +17,9 @@ function M.get_toplevel(cwd)
return nil
end

-- git always returns path with forward slashes
if vim.fn.has "win32" == 1 then
-- msys2 git support
if has_cygpath then
toplevel = vim.fn.system("cygpath -w " .. vim.fn.shellescape(toplevel))
if vim.v.shell_error ~= 0 then
return nil
end
end
toplevel = toplevel:gsub("/", "\\")
toplevel = utils.norm_path(toplevel)
if toplevel == nil then
return nil
end

-- remove newline
Expand Down Expand Up @@ -94,4 +86,28 @@ function M.file_status_to_dir_status(status, cwd)
return r
end

function M.get_git_directory(cwd)
local profile = log.profile_start("git directory %s", cwd)

local cmd = { "git", "-C", cwd, "rev-parse", "--absolute-git-dir" }
log.line("git", vim.inspect(cmd))

local git_dir = vim.fn.system(cmd)

log.raw("git", git_dir)
log.profile_end(profile)

if vim.v.shell_error ~= 0 or not git_dir or #git_dir == 0 or git_dir:match "fatal" then
return nil
end

git_dir = utils.norm_path(git_dir)
if git_dir == nil then
return nil
end

-- remove newline
return git_dir:sub(0, -2)
end

return M
23 changes: 22 additions & 1 deletion lua/nvim-tree/utils.lua
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ local M = {
debouncers = {},
}

local has_cygpath = vim.fn.executable "cygpath" == 1

M.is_unix = vim.fn.has "unix" == 1
M.is_macos = vim.fn.has "mac" == 1 or vim.fn.has "macunix" == 1
M.is_wsl = vim.fn.has "wsl" == 1
-- false for WSL
M.is_windows = vim.fn.has "win32" == 1 or vim.fn.has "win32unix" == 1

function M.str_find(haystack, needle)
Expand Down Expand Up @@ -38,6 +39,26 @@ function M.path_split(path)
return path:gmatch("[^" .. path_separator .. "]+" .. path_separator .. "?")
end

--- Normalise a path:
--- windows: replace slashes with backslashes
--- cygwin: resolve path first via cygpath
--- @param path string
--- @return string|nil nil on cygpath failure
function M.norm_path(path)
if M.is_windows then
-- msys2 git support
if has_cygpath then
path = vim.fn.system("cygpath -w " .. vim.fn.shellescape(path))
if vim.v.shell_error ~= 0 then
return nil
end
end
path = path:gsub("/", "\\")
end

return path
end

---Get the basename of the given path.
---@param path string
---@return string
Expand Down