lewis6991 / gitsigns.nvim

Git integration for buffers
MIT License
4.91k stars 187 forks source link

Neovim freezes for several seconds while performing some vim-fugitive operations #1015

Closed TheLeoP closed 3 months ago

TheLeoP commented 4 months ago

Description

Performing some vim-fugitive actions (not only the ones described in the repro, but I couldn't found a different minimal repro) freeze Neovim without the option of being interrupted (i.e. <c-c>).

This doesn't happen if gitsigns is disabled.

I encountered this problem while writing commit messages and navigating the :G menu in general.

Neovim version

NVIM v0.10.0-dev-3020+g435dee74b

Operating system and version

Windows 11 23H2

Expected behavior

Neovim shouldn't freeze

Actual behavior

Neovim freezes. This happens not only after performing the vim-fugitive actions, but also at unknown time intervals afterwards.

Minimal config

for name, url in pairs {
  gitsigns = "https://github.com/lewis6991/gitsigns.nvim",
  fugitive = "https://github.com/tpope/vim-fugitive",
  -- ADD OTHER PLUGINS _NECESSARY_ TO REPRODUCE THE ISSUE
} do
  local install_path = vim.fn.fnamemodify("gitsigns_issue/" .. name .. "/", ":p:h")
  if vim.fn.isdirectory(install_path) == 0 then vim.fn.system { "git", "clone", "--depth=1", url, install_path } end
  vim.opt.runtimepath:append(install_path)
end

require("gitsigns").setup {
  debug_mode = true,
}

-- ADD INIT.LUA SETTINGS THAT IS _NECESSARY_ FOR REPRODUCING THE ISSUE

vim.fn.setreg(
  "",
  "noau normal Gksusususususususususususususususususususususususususususususususususususususususususususususususususu"
)

local example_repo = "https://github.com/theprimeagen/refactoring.nvim"
local example_repo_path = vim.fn.fnamemodify("refactoring/", ":p:h")
if vim.fn.isdirectory(example_repo_path) == 0 then
  vim.fn.system { "git", "clone", "--depth=1", example_repo, example_repo_path }
end

local example_file = example_repo_path .. "/lua/refactoring/tests/refactor/106/py/with-decorators/extract.start.py"
vim.cmd.edit(example_file)
vim.cmd.normal "Go\27:w\13"

Steps to reproduce

  1. nvim --clean -u minimal.lua an example git repo is downloaded. A file on that repo opened, modified and saved. The vim-fugitive status is opened (i..e. :G)
  2. q:p the command line window is opened and the command noau normal Gksusususususususususususususususususususususususususususususususususususususususususususususususususu (don't execute automcds during the command. Go to the last line of the buffer and then go up one line. Now we are over the Unstaged (1) text. Stage all the changes and then unstage all the changes 50 times) is pasted into it
  3. <cr> the command is executed and Neovim will freeze in the meantime (expected behaviour).
  4. After the command finishes (the command line window will be closed and the screen redrawn), Neovim will freeze again (unexpected behaviour). Trying to move up or down with j and k will do nothing for a few seconds.
  5. Neovim will unfreeze, but it may freeze again after some unknown amount of time*

Notes:

https://github.com/lewis6991/gitsigns.nvim/blob/805610a9393fa231f2c2b49cb521bfa413fadb3d/lua/gitsigns/watcher.lua#L123

but I don't know how to further debug this.

Gitsigns debug messages

debug_messages.txt

dump_cache.txt

glebglazov commented 3 months ago

Hey, that happens to me on MacOS as well, so it seems that it's not a Windows-specific issue.

Providing as well versions of software I use:

gitsigns.nvim 3.32ms 
branch main
commit 805610a
❯ nvim --version
NVIM v0.10.0-dev-2387+g01c15a30c-Homebrew
Build type: Release
LuaJIT 2.1.1710088188
❯ git --version
git version 2.39.3 (Apple Git-146)

For me it's creating a lot of glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD

Here's output of pstree -s nvim on my machine:

 | |-+= 91624 glebglazov /bin/zsh
 | | \-+= 03279 glebglazov nvim .
 | |   \-+= 03280 glebglazov nvim --embed .
 | |     |--= 12062 glebglazov node /Users/glebglazov/.local/share/nvim/mason/bin/yaml-language-server --stdio
 | |     |-+= 13381 glebglazov node /Users/glebglazov/.local/share/nvim/mason/bin/typescript-language-server --stdio
 | |     | |--- 13418 glebglazov /Users/glebglazov/.local/share/mise/installs/node/20.7.0/bin/node /Users/glebglazov/.local/share/nvim/mason/packages/typescript-language-server/node_modules/t
 | |     | \-+- 13419 glebglazov /Users/glebglazov/.local/share/mise/installs/node/20.7.0/bin/node /Users/glebglazov/.local/share/nvim/mason/packages/typescript-language-server/node_modules/t
 | |     |   \--- 13456 glebglazov /Users/glebglazov/.local/share/mise/installs/node/20.7.0/bin/node /Users/glebglazov/.local/share/nvim/mason/packages/typescript-language-server/node_modules
 | |     |--= 48973 glebglazov node /Users/glebglazov/.local/share/nvim/lazy/copilot.lua/copilot/index.js
 | |     |--- 71431 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 71468 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 71486 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 71504 glebglazov (git)
 | |     |--- 71541 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 71559 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 71577 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 71595 glebglazov (git)
 | |     |--- 71631 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 71649 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 71667 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 71685 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 71721 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 71757 glebglazov /Library/Developer/CommandLineTools/usr/bin/git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 71775 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 71793 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 71811 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 71829 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 71847 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 71865 glebglazov /Library/Developer/CommandLineTools/usr/bin/git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 71883 glebglazov /Library/Developer/CommandLineTools/usr/bin/git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 71901 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 71919 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 71937 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 71955 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 71974 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 71992 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 72010 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 72028 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 72047 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 72065 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 72083 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 72104 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 72141 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 72159 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 72177 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 72195 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 72213 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 72231 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 72249 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 72270 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 72288 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 72306 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 72324 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 72342 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 72360 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 72378 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 72396 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 72414 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 72432 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 72450 glebglazov /Library/Developer/CommandLineTools/usr/bin/git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 72468 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 72486 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 72504 glebglazov (git)
 | |     |--- 72522 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 72540 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 72558 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 72576 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 72594 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 72612 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 72630 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 72648 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 72666 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 72684 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 72702 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 72720 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 72738 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 72756 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 72774 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 72792 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 72810 glebglazov /Library/Developer/CommandLineTools/usr/bin/git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 72828 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 72846 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 72864 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 72882 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 72900 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 72918 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 72954 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 72972 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 72990 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 73008 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 73027 glebglazov /Library/Developer/CommandLineTools/usr/bin/git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 73045 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 73081 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 73099 glebglazov /Library/Developer/CommandLineTools/usr/bin/git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 73117 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 73135 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 73153 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 73171 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 73189 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 73207 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 73225 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 73243 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 73261 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 73279 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 73297 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 73315 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 73333 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 73351 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 73369 glebglazov (git)
 | |     |--- 73387 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 73405 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 73423 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 73441 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 73459 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 73477 glebglazov (git)
 | |     |--- 73495 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 73513 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 73531 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 73549 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 73567 glebglazov (git)
 | |     |--- 73585 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 73603 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 73621 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 73639 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 73657 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 73675 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 73693 glebglazov /Library/Developer/CommandLineTools/usr/bin/git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 73729 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 73747 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 73765 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 73783 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 73801 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 73819 glebglazov (git)
 | |     |--- 73837 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 73855 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 73873 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 73891 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 73909 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 73927 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 73945 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 73963 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 73981 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 73999 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 74017 glebglazov /Library/Developer/CommandLineTools/usr/bin/git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
 | |     |--- 74035 glebglazov (git)
 | |     \--- 74053 glebglazov git --no-pager --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
TheLeoP commented 3 months ago

(I think I messed up the minimal.lua, but it's solved now)

TheLeoP commented 3 months ago

I think the problem comes from debounce_trailing. Since the watch callback is a libuv callback, it is outside of the Neovim event loop. This means that, while Neovim is still running the normal command in the repro, every 200ms watcher_handler is called again. From the debug_messages.txt file, we can see that it was called about 200 times.

The git command is asynchronous, but the code for processing their output isn't, that's where the freeze comes from.

A naive solution that I tried was to wrap watcher_handler_debounced in a vim.schedule_wrap:

local watcher_handler_debounced = vim.schedule_wrap(debounce_trailing(200, watcher_handler, 1))

The minimal repro now only starts a single git command. All of the watcher_handler_debounced get called after Neovim unfreezes from the normal command, so the first once is processed and the rest of them are debounced.

I don't think this approach is the best option, but at least it shows that the problem is related to the debounce_trailing logic.

lewis6991 commented 3 months ago

Since the watch callback is a libuv callback, it is outside of the Neovim event loop. This means that, while Neovim is still running the normal command in the repro, every 200ms watcher_handler is called again.

I'm not sure I understand.

Nvim is single threaded, so the luv callbacks can't occur whilst a normal command is executing.

From what I understand, the main difference bettwen fast event and main events, is that you can schedule multiple fast events per loop iteration, whereas only 1 main event will be processed per iteration.

lewis6991 commented 3 months ago

I was able to run the reproduction steps, but did not experience any lag (on MacOS), even after cranking su to 200.

Once the debouncer has launched the function, it is immediately scheduled onto the main loop, and I doubt the overhead of the debouncer would cause any kind of lag with only a few hundred calls.

~@glebglazov I think your issue may be different, as the debouncer should prevent that many git calls. Can you try the repro steps in the OP or provide your own? :Gitsigns debug_messages will list all the git calls that happen.~

EDIT: after looking at the provided debug messages, I can see lots of git calls, which doesn't happen when I run the repro steps. This suggests the debouncer isn't doing its job, or the debounce delay (200ms) isn't large enough for your machine.

Could one of you perhaps add some instrumentation to the handler to determine the time intervals between the uv callbacks?

lewis6991 commented 3 months ago

I've updated Gitsigns to add timestamps to the log messages. Would someone be able to provide their debug messages after the freeze happens?

TheLeoP commented 3 months ago

log.txt

lewis6991 commented 3 months ago

Yep, it looks like the 200ms debounce delay isn't long enough for your system. From the log there are at least 8 callbacks that I can see from inspection that should get through, though 25 do in total, but there are many intervals that are very close to 200ms apart.

Throttling the watcher callback instead of debouncing might be a better solution.

lewis6991 commented 3 months ago

Can you try #1036?

TheLeoP commented 3 months ago

It still frezes and now I received a bunch of errors that looked like

Error executing luv callback:
...ktop\test\gitsigns_issue\gitsigns/lua/gitsigns/async.lua:85: The coroutine failed with this message: ...esktop\test\gitsigns_issue\gitsigns/lua/gitsigns/git.lua:466: (ERROR) ...esktop\tes
t\gitsigns_issue\gitsigns/lua/gitsigns/git.lua(466): fatal: fsmonitor--daemon is already running 'C:/Users/pcx/Desktop/test/refactoring'

stack traceback:
        [C]: in function 'error'
        ...\test\gitsigns_issue\gitsigns/lua/gitsigns/debug/log.lua:124: in function 'eprint'
        ...\test\gitsigns_issue\gitsigns/lua/gitsigns/debug/log.lua:129: in function 'eprint'
        ...esktop\test\gitsigns_issue\gitsigns/lua/gitsigns/git.lua:466: in function 'file_info'
        ...esktop\test\gitsigns_issue\gitsigns/lua/gitsigns/git.lua:405: in function 'update'
        ...op\test\gitsigns_issue\gitsigns/lua/gitsigns/watcher.lua:90: in function <...op\test\gitsigns_issue\gitsigns/lua/gitsigns/watcher.lua:68>
stack traceback:
        [C]: in function 'error'
        ...ktop\test\gitsigns_issue\gitsigns/lua/gitsigns/async.lua:85: in function 'cb'
        ...ktop\test\gitsigns_issue\gitsigns/lua/gitsigns/async.lua:127: in function 'on_exit'
        ...gram Files\Neovim\share\nvim\runtime/lua/vim/_system.lua:300: in function <...gram Files\Neovim\share\nvim\runtime/lua/vim/_system.lua:270>

log.txt

lewis6991 commented 3 months ago

Ah sorry I made a small mistake there, updated the PR.

The fsmonitor errors are interesting though. I wonder if that has some overhead we can avoid.

TheLeoP commented 3 months ago

Still freezes (maybe even more(?)).

log.txt

TheLeoP commented 3 months ago

By the ways, thanks for taking the time to debug/solve this

lewis6991 commented 3 months ago

Still freezes (maybe even more(?)).

Can you double check? The way to repro the issue on my machine is to reduce/remove the debounce delay. Then I get the call spam (though no freeze).

With the added throttle, that should reduce down the calls significantly, and the original debounce should reduce it even more.

With the debounce reduced to 10ms I get the following debug:

[10051.681] watcher_cb(1): Git dir update: 'HEAD.lock' { rename = true } (ignoring)
[10051.684] watcher_cb(1): Git dir update: 'AUTO_MERGE.lock' { rename = true } (ignoring)
[10051.688] watcher_cb(1): Git dir update: 'packed-refs.lock' { rename = true } (ignoring)
[10051.691] watcher_cb(1): Git dir update: 'AUTO_MERGE.lock' { rename = true } (ignoring)
[10051.694] watcher_cb(1): Git dir update: 'packed-refs.lock' { rename = true } (ignoring)
[10102.306] watcher_cb(1): Git dir update: 'index.lock' { rename = true } (ignoring)
[10102.315] watcher_cb(1): Git dir update: 'index' { rename = true }
[10102.322] watcher_cb(1): Git dir update: 'index' { rename = true }
[10152.865] watcher_cb(1): Git dir update: 'index.lock' { rename = true } (ignoring)
[10152.871] watcher_cb(1): Git dir update: 'index' { rename = true }
[10152.878] watcher_cb(1): Git dir update: 'index' { rename = true }
[10152.882] watcher_cb(1): Git dir update: 'ORIG_HEAD.lock' { rename = true } (ignoring)
[10152.885] watcher_cb(1): Git dir update: 'HEAD.lock' { rename = true } (ignoring)
[10152.889] watcher_cb(1): Git dir update: 'AUTO_MERGE.lock' { rename = true } (ignoring)
[10152.892] watcher_cb(1): Git dir update: 'packed-refs.lock' { rename = true } (ignoring)
[10152.895] watcher_cb(1): Git dir update: 'AUTO_MERGE.lock' { rename = true } (ignoring)
[10152.897] watcher_cb(1): Git dir update: 'packed-refs.lock' { rename = true } (ignoring)
[10160.674] run_job: git --no-pager --no-optional-locks --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
[10172.683] run_job: git --no-pager --no-optional-locks --literal-pathspecs -c gc.auto=0 --git-dir /Users/lewrus01/projects/gitsigns.nvim/refactoring/.git -c core.quotepath=off ls -files --stage --others --exclude-standard --eol /Users/lewrus01/projects/gitsigns.nvim/refactoring/lua/refactoring/tests/refactor/106/py/with-decorators/extract.start.py
[10179.223] run_job: git --no-pager --no-optional-locks --literal-pathspecs -c gc.auto=0 --git-dir /Users/lewrus01/projects/gitsigns.nvim/refactoring/.git show 08174edffba398010e3 819643a464ab1838a419e
[10186.357] run_job: git --no-pager --no-optional-locks --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
[10192.240] run_job: git --no-pager --no-optional-locks --literal-pathspecs -c gc.auto=0 --git-dir /Users/lewrus01/projects/gitsigns.nvim/refactoring/.git -c core.quotepath=off ls -files --stage --others --exclude-standard --eol /Users/lewrus01/projects/gitsigns.nvim/refactoring/lua/refactoring/tests/refactor/106/py/with-decorators/extract.start.py
[10198.817] run_job: git --no-pager --no-optional-locks --literal-pathspecs -c gc.auto=0 --git-dir /Users/lewrus01/projects/gitsigns.nvim/refactoring/.git show 08174edffba398010e3 819643a464ab1838a419e
[14796.898] cli.run: Running action 'debug_messages' with arguments {}

Notice it now only calls 6 git commands which is the watcher handler running twice, back to back, not interleaved like before.

TheLeoP commented 3 months ago

Yup, double checked. Simply the watcher_cb seems to take about 2 seconds. From

[10702.150] watcher_cb(1): Git dir update: 'index.lock' { rename = true } (ignoring)

until

[31642.229] watcher_cb(1): Git dir update: 'HEAD.lock' { rename = true } (ignoring)

my log has only watcher_cb calls every 200ish ms sometimes with 2 or 3 being executed withing the same ms.

Then, 200ish git commands every 2-5 ms.

TheLeoP commented 3 months ago

Maybe this may have something to do with file operations being way slower on Windows (?)

TheLeoP commented 3 months ago

I just tested the repro again with the master branch (which contains the throtle PR that I had already tested) and this seems to be solved. I must have messed something when trying the repro last time.

TheLeoP commented 3 months ago

Thanks for solving this and sorry :/

lewis6991 commented 3 months ago

No worries. Glad to know it's resolved.