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

vim-fugitive diffs result in error about invalid object name 0 #1185

Closed
jdrouhard opened this issue Jan 23, 2025 · 9 comments
Closed

vim-fugitive diffs result in error about invalid object name 0 #1185

jdrouhard opened this issue Jan 23, 2025 · 9 comments
Labels
bug Something isn't working

Comments

@jdrouhard
Copy link

Description

When viewing a diff with vim-fugitive, gitsigns throws this error:

Error executing callback:
.../gitsigns-repro/plugins/gitsigns//lua/gitsigns/async.lua:71: The async coroutine failed: ...ch/gitsigns-repro/plugins/gitsigns//lua/gitsigns/git.lua:206: fatal: Not a valid object name 0

stack traceback:
        [C]: in function 'error'
        ...signs-repro/plugins/gitsigns//lua/gitsigns/debug/log.lua:136: in function 'eprint'
        ...signs-repro/plugins/gitsigns//lua/gitsigns/debug/log.lua:141: in function 'eprint'
        ...ch/gitsigns-repro/plugins/gitsigns//lua/gitsigns/git.lua:206: in function 'file_info'
        ...ch/gitsigns-repro/plugins/gitsigns//lua/gitsigns/git.lua:82: in function 'update'
        ...ch/gitsigns-repro/plugins/gitsigns//lua/gitsigns/git.lua:431: in function 'new'
        ...gitsigns-repro/plugins/gitsigns//lua/gitsigns/attach.lua:218: in function 'fn'
        ...tsigns-repro/plugins/gitsigns//lua/gitsigns/debounce.lua:68: in function 'attach_throttled'
        ...gitsigns-repro/plugins/gitsigns//lua/gitsigns/attach.lua:371: in function <...gitsigns-repro/plugins/gitsigns//lua/gitsigns/attach.lua:370>
stack traceback:
        [C]: in function 'error'
        .../gitsigns-repro/plugins/gitsigns//lua/gitsigns/async.lua:71: in function 'callback'
        .../gitsigns-repro/plugins/gitsigns//lua/gitsigns/async.lua:107: in function 'on_exit'
        ...drouhard/.install/share/nvim/runtime/lua/vim/_system.lua:309: in function <...drouhard/.install/share/nvim/runtime/lua/vim/_system.lua:279>

Neovim version

NVIM v0.11.0-dev-1623+g34d808b73c

Operating system and version

RHEL 8

Expected behavior

No response

Actual behavior

Shouldn't error.

Minimal config

for name, url in pairs{
  gitsigns = 'https://github.com/lewis6991/gitsigns.nvim',
  fugitive = 'https://github.com/tpope/vim-fugitive',
} do
local install_path = vim.fn.fnamemodify('plugins/'..name, ':p')
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, -- You must add this to enable debug messages
}

Steps to reproduce

  1. mkdir gitsigns_issue
  2. cd gitsigns_issue
  3. git init
  4. touch file
  5. git add file
  6. git commit -m 'initial commit'
  7. nvim --clean -u minimal.lua file
  8. :Gvdiff

Gitsigns debug messages

8.38 D run_job: git --version
13.49 D run_job: git --no-pager --no-optional-locks --literal-pathspecs -c gc.auto=0 rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
15.53 D run_job: git --no-pager --no-optional-locks --literal-pathspecs -c gc.auto=0 --git-dir /home/jdrouhard/scratch/gitsigns-repro/.git config user.name
17.38 D run_job: git --no-pager --no-optional-locks --literal-pathspecs -c gc.auto=0 --git-dir /home/jdrouhard/scratch/gitsigns-repro/.git -c core.quotepath=off ls-files --stage --others --exclude-standard --eol /home/jdrouhard/scratch/gitsigns-repro/file
19.73 D watch_gitdir(1): Watching git dir
19.79 D run_job: git --no-pager --no-optional-locks --literal-pathspecs -c gc.auto=0 --git-dir /home/jdrouhard/scratch/gitsigns-repro/.git show e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
22.74 D run_job: git --no-pager --no-optional-locks --literal-pathspecs -c gc.auto=0 --git-dir /home/jdrouhard/scratch/gitsigns-repro/.git show HEAD:file
5994.38 D attach(2): Attaching (trigger=BufReadPost)
5994.51 D parse_git_path: Fugitive buffer for file 'file' from path 'nil' on commit '0'
5995.78 D run_job: git --no-pager --no-optional-locks --literal-pathspecs -c gc.auto=0 --git-dir /home/jdrouhard/scratch/gitsigns-repro/.git rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD
5997.92 D run_job: git --no-pager --no-optional-locks --literal-pathspecs -c gc.auto=0 --git-dir /home/jdrouhard/scratch/gitsigns-repro/.git -c core.quotepath=off ls-tree 0 file
5999.88 E ...ch/gitsigns-repro/plugins/gitsigns//lua/gitsigns/git.lua<206>: fatal: Not a valid object name 0

stack traceback:
        ...signs-repro/plugins/gitsigns//lua/gitsigns/debug/log.lua:134: in function 'eprint'
        ...signs-repro/plugins/gitsigns//lua/gitsigns/debug/log.lua:141: in function 'eprint'
        ...ch/gitsigns-repro/plugins/gitsigns//lua/gitsigns/git.lua:206: in function 'file_info'
        ...ch/gitsigns-repro/plugins/gitsigns//lua/gitsigns/git.lua:82: in function 'update'
        ...ch/gitsigns-repro/plugins/gitsigns//lua/gitsigns/git.lua:431: in function 'new'
        ...gitsigns-repro/plugins/gitsigns//lua/gitsigns/attach.lua:218: in function 'fn'
        ...tsigns-repro/plugins/gitsigns//lua/gitsigns/debounce.lua:68: in function 'attach_throttled'
        ...gitsigns-repro/plugins/gitsigns//lua/gitsigns/attach.lua:371: in function <...gitsigns-repro/plugins/gitsigns//lua/gitsigns/attach.lua:370>

Gitsigns cache

@jdrouhard jdrouhard added the bug Something isn't working label Jan 23, 2025
@lewis6991
Copy link
Owner

I can reproduce just by doing :Gvdiff. 👍

Just to ask, Is there any reason you use :Gvdiff over :Gitsigns diffthis? The latter should be a drop in replacement.

@jdrouhard
Copy link
Author

Honestly only reason is because the index buffer is a fugitive buffer, so it works with things like :Gwrite or other vim-fugitive commands that understand fugitive buffers /shrug. Visually, :Gitsigns diffthis is definitely equivalent!

@lewis6991
Copy link
Owner

lewis6991 commented Jan 23, 2025

Honestly only reason is because the index buffer is a fugitive buffer, so it works with things like :Gwrite

Not sure if you know, but the Gitsigns diff buffer is a normal buffer you can write (with :w) to stage the contents. Not sure if :Gwrite does anything more than this.

I'd been keen to know if there's anything else you'd like to see in this area.

@jdrouhard
Copy link
Author

With your most recent fix, now I get:

Error executing callback:
...cal/share/nvim/lazy/gitsigns.nvim/lua/gitsigns/async.lua:71: The async coroutine failed: ...local/share/nvim/lazy/gitsigns.nvim/lua/gitsigns/git.lua:154: fatal: empty string is not a valid pathspec. please use . instead if you meant to match all paths

When simply opening :G :(

Anyway...

:Gwrite on the diff buffer essentially "resets" the file since it writes the buffer contents directly to the index. I tried using :w on the gitsigns diff buffer and it didn't seem to do the same thing. It's a pretty neat command, as it basically lets you (in one step) write to the file in the workdir and immediately stage the whole file into the index:

:Gwrite                 Write to the current file's path and stage the results.
                        When run in a work tree file, it is effectively git
                        add.  Elsewhere, it is effectively git-checkout.  A
                        great deal of effort is expended to behave sensibly
                        when the work tree or index version of the file is
                        open in another buffer.

:Gwrite {path}          You can give |:Gwrite| an explicit path of where in
                        the work tree to write.  You can also give a path like
                        :0:foo.txt or :0:% to write to just that stage in
                        the index.

                                                *:Gwq*
:Gwq [path]             Like |:Gwrite| followed by |:quit| if the write
                        succeeded.

:Gwq! [path]            Like |:Gwrite|! followed by |:quit|! if the write
                        succeeded.

@lewis6991
Copy link
Owner

:Gwrite on the diff buffer essentially "resets" the file since it writes the buffer contents directly to the index.

Oh I see. Isn't that the same as :Gitsigns reset_buffer on the main buffer? From what I can tell, it never stages any changes when called inside the diff buffer.

I tried using :w on the gitsigns diff buffer and it didn't seem to do the same thing.

You need to edit the diff buffer first. When you save, it'll stage those edits. You can do this in fugitive diff buffers too.

lewis6991 added a commit that referenced this issue Jan 23, 2025
@lewis6991
Copy link
Owner

When simply opening :G :(

Fixed? 🤞

@jdrouhard
Copy link
Author

:Gwrite on the diff buffer essentially "resets" the file since it writes the buffer contents directly to the index.

Oh I see. Isn't that the same as :Gitsigns reset_buffer on the main buffer? From what I can tell, it never stages any changes when called inside the diff buffer.

Not exactly. Try it out. Make some changes in a file, but don't stage it or anything. Then do a :Gvdiff. Move the cursor to the index buffer, and then just do a :Gwrite!. It'll essentially do a checkout of the file by writing the version of the file from the index (the buffer contents) into the work tree copy and then staging it (which effectively undoes any uncommitted changes). But normal :w works just like the :Gitsigns diffthis index buffer where it'll write changes to the index directly (the staged file), but won't touch the work tree file.

Basically, :Gwrite is a neat way of interacting directly with the index. On a normal file, it saves it and immediately git-adds it (stages it). On anything else (a fugitive buffer viewing an index file), it's a git checkout to that version plus a git add (stage) of any changes made to that buffer.

I tried using :w on the gitsigns diff buffer and it didn't seem to do the same thing.

You need to edit the diff buffer first. When you save, it'll stage those edits. You can do this in fugitive diff buffers too.

Got it. Yeah, the :w behavior seems to be equivalent!

Fixed? 🤞

Yes! 🎉🚀 Thanks!

@lewis6991
Copy link
Owner

Make some changes in a file, but don't stage it or anything. Then do a :Gvdiff. Move the cursor to the index buffer, and then just do a :Gwrite!

If you don't make any changes to index buffer, then :Gwrite! is just resetting the file (no staging). From what I can tell, it does nothing to the index.

It'll essentially do a checkout of the file by writing the version of the file from the index (the buffer contents) into the work tree copy and then staging it

So the main difference is due to the fact that the index buffer may have unsaved edits? If not then it won't be staging anything, it'll just reset the working copy (and buffer), whereas :Gitsigns reset_buffer just resets the buffer.

@jdrouhard
Copy link
Author

Make some changes in a file, but don't stage it or anything. Then do a :Gvdiff. Move the cursor to the index buffer, and then just do a :Gwrite!

If you don't make any changes to index buffer, then :Gwrite! is just resetting the file (no staging). From what I can tell, it does nothing to the index.

It writes both. It doesn't appear to do anything to the index because you're writing exactly what's already in the index directly back into it. If the index buffer is an older version of the file (from :0Gclog or something), it'll write that version into the work tree file and the index. If you just make some edits on the index buffer and then do a :Gwrite!, it'll write the buffer contents to both the work tree file and the index, effectively staging whatever that index buffer currently contains (and overwriting any unstaged changes you may have in the work tree file if you use the bang, or erroring if you have unstaged changes in the work tree file without the bang).

It'll essentially do a checkout of the file by writing the version of the file from the index (the buffer contents) into the work tree copy and then staging it

So the main difference is due to the fact that the index buffer may have unsaved edits? If not then it won't be staging anything, it'll just reset the working copy (and buffer), whereas :Gitsigns reset_buffer just resets the buffer.

In a nutshell, it'll update the work tree file and the index to exactly the contents of the buffer you use :Gwrite! on, including any fugitive:// buffers showing the file as of various commits in the index (including the one at HEAD which is the default for the :Gdiff family).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants