Skip to content
This repository has been archived by the owner on Sep 11, 2020. It is now read-only.

repo.Head() fails when referenced from a linked worktree after being garbage collected #1252

Open
nicerobot opened this issue Dec 1, 2019 · 2 comments

Comments

@nicerobot
Copy link

nicerobot commented Dec 1, 2019

When a linked worktree's HEAD ref is a tracking-branch, this code will attempt to open the ref using the path in the .git/worktree which is not where the refs are stored.

path = d.fs.Join(path, d.fs.Join(strings.Split(name, "/")...))
f, err := d.fs.Open(path)
if err != nil {
return nil, err
}

Example

Demo

This example doesn't technically git gc the worktree but the scenario is the same.

Output

$ make
git clone git@github.com:src-d/go-git.git
Cloning into 'go-git'...
cd go-git; git fetch --all
go-git-bug/go-git
Fetching origin
cd go-git; git worktree add -b new-ref ../go-git-linked/
go-git-bug/go-git
Preparing worktree (new branch 'new-ref')
HEAD is now at 1a7db85bca70 Merge pull request #1231 from alexandear/fix-typos
go build -o bugged


---- Works as expected
go-git-bug/go-git
git rev-parse --git-dir
.git
git rev-parse HEAD
1a7db85bca7027d90afdb5ce711622aaac9feaed
2019/12/01 11:39:36 worktree: go-git-bug/go-git
2019/12/01 11:39:36 1a7db85bca7027d90afdb5ce711622aaac9feaed refs/heads/master
2019/12/01 11:39:36 1a7db85bca7027d90afdb5ce711622aaac9feaed refs/heads/new-ref
2019/12/01 11:39:36 head: 1a7db85bca7027d90afdb5ce711622aaac9feaed refs/heads/master


---- Bug this does not work as expected
go-git-bug/go-git-linked
git rev-parse --git-dir
go-git-bug/go-git/.git/worktrees/go-git-linked
git rev-parse HEAD
1a7db85bca7027d90afdb5ce711622aaac9feaed
2019/12/01 11:39:36 worktree: go-git-bug/go-git-linked
2019/12/01 11:39:36 head: reference not found
make: *** [bug] Error 1

Call-stack

repo, err := git.PlainOpenWithOptions(".", &git.PlainOpenOptions{DetectDotGit: true})
repo.Head()
storer.ResolveReference(r.Storer, plumbing.HEAD)
resolveReference(s, r, 0)
s.Reference(r.Target())
r.dir.Ref(n) // <- `n` (i.e. `r.Target()`) is `ref/heads/new-ref`
d.readReferenceFile(".", name.String())
d.fs.Open(path) // <- this `path` is wrong: go-git/.git/worktrees/go-git-linked/refs/heads/new-ref

Additionally

There is also a scenario for linked worktrees when the worktree's .git/ref/heads file can be garbage collected (git gc in the worktree, because it is the same as a ref/remotes?) so the above will always fail.

@nicerobot nicerobot changed the title This is wrong when referenced from a linked worktree repo.Head() fails when referenced from a linked worktree after being garbage collected Dec 1, 2019
@nicerobot
Copy link
Author

nicerobot commented Dec 30, 2019

The problem appears to be:

return &Storage{
fs: fs,
dir: dir,
ObjectStorage: *NewObjectStorageWithOptions(dir, cache, ops),
ReferenceStorage: ReferenceStorage{dir: dir},
IndexStorage: IndexStorage{dir: dir},
ShallowStorage: ShallowStorage{dir: dir},
ConfigStorage: ConfigStorage{dir: dir},
ModuleStorage: ModuleStorage{dir: dir},
}

In this linked worktree example, the ObjectStorage and ReferenceStorage should be based on the contents of the go-git/.git/worktrees/go-git-linked/gitdir file.

@AlexandreCarlton
Copy link

AlexandreCarlton commented Jan 26, 2020

It looks like this would be solved by parsing commondir in the worktree folder (i.e. .git/worktrees/<worktree>/commondir) which points back to the main .git folder. While #1098 parses this, it hasn't been touched in almost a year.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants