Skip to content

Windows Neotree cwd and Gitsigns prevents Neovim exit (LazyVim) #1027

@Kayzels

Description

@Kayzels

Description

This happens specifically with a LazyVim setup, but they cannot reproduce it, so checking if there might be more luck here.

Using Neotree, you can change the current working directory by pressing .. Doing this in a git repo, or changing to git repo using it, causes Neovim to freeze on exit. Importantly, it only seems to happen if the Neovim is started in a folder that is a git repo.

Maybe its having an issue with the cwd update? The maintainers of the LazyVim repo couldn't reproduce, so possibly its Windows specific? I noticed that the last working commit that didn't cause this was cdfcd9d - it broke from 720061a.

Any non-git folders aren't affected, and using an older version of gitsigns doesn't cause the issue.

Unfortunately, because it's happening with LazyVim, the repro needs to include that, so it's not particularly small any more.

Neovim version

NVIM v0.10.0 Release

Operating system and version

Windows 10 Pro 22H2 19045.3803

Expected behavior

Neovim should exit without freezing the terminal.

Actual behavior

Neovim hangs on exit.

Nvim_not_closing_gitsigns.mp4

Minimal config

-- DO NOT change the paths and don't remove the colorscheme
local root = vim.fn.fnamemodify("./.repro", ":p")

-- set stdpaths to use .repro
for _, name in ipairs({ "config", "data", "state", "cache" }) do
  vim.env[("XDG_%s_HOME"):format(name:upper())] = root .. "/" .. name
end

-- bootstrap lazy
local lazypath = root .. "/plugins/lazy.nvim"
if not vim.loop.fs_stat(lazypath) then
  vim.fn.system({ "git", "clone", "--filter=blob:none", "https://github.com/folke/lazy.nvim.git", lazypath })
end
vim.opt.runtimepath:prepend(lazypath)

-- install plugins
local plugins = {
  "folke/tokyonight.nvim",
  {
    "LazyVim/LazyVim",
    import = "lazyvim.plugins",
    -- version = "10.x"
  },
  {
    "lewis6991/gitsigns.nvim",
    opts = {
      debug_mode = true,
    },
  },
  {
    "nvim-neo-tree/neo-tree.nvim",
    opts = {
      filesystem = {
        bind_to_cwd = true, -- Lazy sets it to false
        follow_current_file = { enabled = false }, -- Lazy sets it to true
        use_libuv_file_watcher = false,
      },
    },
  },
}
require("lazy").setup(plugins, {
  root = root .. "/plugins",
})

vim.cmd.colorscheme("tokyonight")

Steps to reproduce

  1. Copy the code above and save in a new folder in file called repro.lua (or `minimal.lua, but then you need to update the nvim command.
  2. Make the downloaded code part of a git repo, by typing git init
  3. nvim --clean -u repro.lua
  4. Open the repro.lua file from Neotree, navigating to it by typing :Neotree.
  5. Use Neotree to navigate to some other files, using Backspace to go up a folder.
  6. After the files are opened, navigate back to the created repo, and select the repro.lua file.
  7. Open Neotree again, press Backspace to see a list of the directories including the created one containing the repro.lua file.
  8. Press . on the folder that contains the repro.lua file.
  9. Go back to the repro.lua file.
  10. Try to close Neovim by entering :qa.

Gitsigns debug messages

dprintf: Highlight GitSignsAdd is already defined
dprintf: Highlight GitSignsChange is already defined
dprintf: Highlight GitSignsDelete is already defined
dprintf: Deriving GitSignsChangedelete from GitSignsChange
dprintf: Deriving GitSignsTopdelete from GitSignsDelete
dprintf: Deriving GitSignsUntracked from GitSignsAdd
dprintf: Deriving GitSignsAddNr from GitGutterAddLineNr
dprintf: Deriving GitSignsChangeNr from GitGutterChangeLineNr
dprintf: Deriving GitSignsDeleteNr from GitGutterDeleteLineNr
dprintf: Deriving GitSignsChangedeleteNr from GitSignsChangeNr
dprintf: Deriving GitSignsTopdeleteNr from GitSignsDeleteNr
dprintf: Deriving GitSignsUntrackedNr from GitSignsAddNr
dprintf: Deriving GitSignsAddLn from DiffAdd
dprintf: Deriving GitSignsChangeLn from DiffChange
dprintf: Deriving GitSignsChangedeleteLn from GitSignsChangeLn
dprintf: Deriving GitSignsUntrackedLn from GitSignsAddLn
dprintf: Deriving GitSignsStagedAdd from GitSignsAdd
dprintf: Deriving GitSignsStagedChange from GitSignsChange
dprintf: Deriving GitSignsStagedDelete from GitSignsDelete
dprintf: Deriving GitSignsStagedChangedelete from GitSignsChangedelete
dprintf: Deriving GitSignsStagedTopdelete from GitSignsTopdelete
dprintf: Deriving GitSignsStagedAddNr from GitSignsAddNr
dprintf: Deriving GitSignsStagedChangeNr from GitSignsChangeNr
dprintf: Deriving GitSignsStagedDeleteNr from GitSignsDeleteNr
dprintf: Deriving GitSignsStagedChangedeleteNr from GitSignsChangedeleteNr
dprintf: Deriving GitSignsStagedTopdeleteNr from GitSignsTopdeleteNr
dprintf: Deriving GitSignsStagedAddLn from GitSignsAddLn
dprintf: Deriving GitSignsStagedChangeLn from GitSignsChangeLn
dprintf: Could not derive GitSignsStagedDeleteLn
dprintf: Deriving GitSignsStagedChangedeleteLn from GitSignsChangedeleteLn
dprintf: Could not derive GitSignsStagedTopdeleteLn
dprintf: Deriving GitSignsAddPreview from DiffAdd
dprintf: Deriving GitSignsDeletePreview from DiffDelete
dprintf: Deriving GitSignsCurrentLineBlame from NonText
dprintf: Deriving GitSignsAddInline from TermCursor
dprintf: Deriving GitSignsDeleteInline from TermCursor
dprintf: Deriving GitSignsChangeInline from TermCursor
dprintf: Deriving GitSignsAddLnInline from GitSignsAddInline
dprintf: Deriving GitSignsChangeLnInline from GitSignsChangeInline
dprintf: Deriving GitSignsDeleteLnInline from GitSignsDeleteInline
dprintf: Deriving GitSignsDeleteVirtLn from DiffDelete
dprintf: Deriving GitSignsDeleteVirtLnInLine from GitSignsDeleteLnInline
dprintf: Deriving GitSignsVirtLnum from GitSignsDeleteVirtLn
attach(2): Attaching (trigger=setup)
attach(2): Non-normal buffer
attach(3): Attaching (trigger=setup)
run_job: git --no-pager --no-optional-locks --literal-pathspecs -c gc.auto=0 config user.name
run_job: git --version
run_job: git --version
run_job: git --no-pager --no-optional-locks --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
run_job: git --no-pager --no-optional-locks --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
run_job: git --no-pager --no-optional-locks --literal-pathspecs -c gc.auto=0 rev-parse --short HEAD
run_job: git --no-pager --no-optional-locks --literal-pathspecs -c gc.auto=0 rev-parse --short HEAD
run_job: git --no-pager --no-optional-locks --literal-pathspecs -c gc.auto=0 --git-dir C:/Users/Kyzan/Documents/Test/Gitsigns_Broken/.git -c core.quotepath=off ls-files --stage --others --exclude-standard --eol C:\Users\Kyzan\Documents\Test\Gitsigns_Broken\repro.lua
attach(3): File is untracked
detach(4): Detached
detach(4): Cache was nil
attach(4): Attaching (trigger=BufFilePost)
attach(4): Non-normal buffer
attach(5): Attaching (trigger=BufReadPost)
run_job: git --no-pager --no-optional-locks --literal-pathspecs -c gc.auto=0 config user.name
run_job: git --no-pager --no-optional-locks --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
new: Not in git repo
attach(5): Empty git obj
attach(6): Attaching (trigger=BufReadPost)
run_job: git --no-pager --no-optional-locks --literal-pathspecs -c gc.auto=0 config user.name
run_job: git --no-pager --no-optional-locks --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
new: Not in git repo
attach(6): Empty git obj
cli.run: Running action 'debug_messages' with arguments {}
cli.run: Running action 'debug_messages' with arguments {}
run_job: git --no-pager --no-optional-locks --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
run_job: git --no-pager --no-optional-locks --literal-pathspecs -c gc.auto=0 rev-parse --short HEAD
cwd_watcher_cb: Git cwd dir update
run_job: git --no-pager --no-optional-locks --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
run_job: git --no-pager --no-optional-locks --literal-pathspecs -c gc.auto=0 rev-parse --short HEAD
cli.run: Running action 'debug_messages' with arguments {}
cli.run: Running action 'debug_messages' with arguments {}
cli.run: Running action 'debug_messages' with arguments {}

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingwindowsIssue specific to the windows platform

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions