go-git icon indicating copy to clipboard operation
go-git copied to clipboard

`worktree.Status()` not respecting .gitignore

Open acumino opened this issue 3 years ago • 6 comments

When we have multi nested directory and the .gitignore file is inside that. The wroktree.Status() is not respecting patterns inside .gitignore that can cause the git status to dirty.

How to reproduce

Check this repo https://github.com/acumino/git-status. When we run $ go run ./test.go which is basically checking the status and returning an error if status is not clean.

wt, err := repo.Worktree()
	if err != nil {
		fmt.Printf("failed to get git worktree: %v", err)
	}
if stat, err := wt.Status(); err != nil {
		fmt.Printf("failed to get git status: %v", err)
	} else if !stat.IsClean() {
		fmt.Printf("%v\n%v", err, stat)
	}

It throws an error and ideally it should not.

?? pp/hh/hack1/configs/authwebhook.yaml

Explanation

The issue is happening because append() is being used for the slice in recursion at line 64. https://github.com/go-git/go-git/blob/c785af3f4559ebac52c42f12d17cb118aac383ad/plumbing/format/gitignore/dir.go#L49-L76

The passed value of fs is being changed with appends and is being used as domain here https://github.com/go-git/go-git/blob/c785af3f4559ebac52c42f12d17cb118aac383ad/plumbing/format/gitignore/pattern.go#L42

So when this fs is updated next time with append it is causing overwrite to previously written domain values leading to previously added pattern's domain to overwritten. So git status basically at the end store wrong pattern to ignore, leading to dirty git status.

An explanation of how slices are passed in function and are used internally golang https://stackoverflow.com/questions/39993688/are-slices-passed-by-value.

Solution

Instead to passing append(path, fi.Name()) in ReadPatterns() every times a new copy of slice should be passed.

acumino avatar Mar 24 '22 14:03 acumino

cc - @mcuadros

acumino avatar Mar 24 '22 14:03 acumino

I was trying to follow along here because I had a similar theory. https://go.dev/play/p/pjtX_coRiQ8

package main

import "fmt"

func recurse(a []string) []string {
	if len(a) == 3 {
		return a
	}

	return recurse(append(a, "test"))
}

func main() {
	a := []string{"a"}
	b := recurse(a)
	fmt.Println(a, b)
}

My assumption was that because Go slices are pass-by-value that a and b would have the same contents. They do not in this case. This program evaluated to.

[a] [a test test]

Program exited.

The return value of append will be a slice that points to the newly allocated array. I could be widely misunderstanding the issue though.

sourcec0de avatar Apr 05 '22 02:04 sourcec0de

Please check this issue https://github.com/golang/go/issues/52152 for examples.

acumino avatar Apr 05 '22 05:04 acumino

As suggested in the issue https://github.com/golang/go/issues/52152 there is nothing that can be done from the go side. If needed I can open a PR with a possible workaround.

acumino avatar Apr 05 '22 05:04 acumino

@acumino , I have no association with this repo, but I think a PR would be welcome. Do you have a fork with your copy-based workaround?

I've run into the issue where there's a large directory (~300M of contents) that is in the .gitignore file. The worktree.Status() call takes anywhere from 1.6s (with repeated calls so that the kernel is caching the directory contents I'm guessing), to 15s, whereas if I delete that directory, the call takes ~300ms (with repeated calls).

For comparison, the git status command returns in <20ms

I'm guessing respecting the .gitignore would be a non-trivial performance improvement.

TopherIsSwell avatar Apr 22 '22 22:04 TopherIsSwell

@acumino another issue I spot on .gitignore is that a global .gitignore doesn't take effect.

tisonkun avatar Sep 04 '22 13:09 tisonkun

I think I'm seeing the same as @tisonkun, with my attempts at debugging reported here. Copying my gitignore file into the directory that I've specified as the Path in my Add/AddOptions doesn't seem to have any impact though.

jghal avatar Oct 20 '22 18:10 jghal

as @tisonkun mentioned, we're seeing the same issue in #597

mieubrisse avatar Oct 28 '22 17:10 mieubrisse