Skip to content

Worktree.Status() iterates through directories that are ignored in another .gitignore #736

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

Open
svenliebig opened this issue Apr 4, 2023 · 3 comments

Comments

@svenliebig
Copy link

The Worktree.Status() implementation does not ignore directories that are previously excluded by another .gitignore, for example it will iterate through all node_modules in a repository, even when these node_modules are ignored in the root .gitignore.

This leads to a funny behauvior, when you define another .gitignore, in an ignored sub directory, you can include files again with the ! operator in the second git ignore, which is respected by go git, but not by git status CLI.

An example:

My root .gitignore contains the directory sub

# .gitignore
sub

While in the directory sub, we have another .gitignore, which has this content:

# sub/.gitignore
!file.txt

And we have a file.txt in the sub directory aswell:

# sub/file.txt
hello world

The implementation of go git will now show, that we have an unstaged file in sub/file.txt, while git itself does not have this behaviour when we use git status.

I created a repository to reproduce this issue with an example: https://github.com/svenliebig/gogit-status-problem-example

git clone https://github.com/svenliebig/gogit-status-problem-example.git
cd gogit-status-problem-example
git status
go run main.go

You'll see that both implementation return that no changes are made.

Let's run scripts.sh, this will create a file.txt in the directory sub, and add the directory to the .gitignore in the root.

./scripts.sh
git status
go run main.go

git status now shows that we have a change in .gitignore, while the implementation of go-git also shows the file.txt in their status implementation.

This behaviour is produced in this dir.go file, where we iterate over all directories regardless if they where previously ignored or not.

@dbergamin
Copy link

dbergamin commented Sep 16, 2024

It looks like this has already been fixed by @Achilleshiel in #1114 -- presumably should be picked up in 5.13.

@motoki317
Copy link

motoki317 commented Nov 25, 2024

While #1114 seems to partially fix this problem, it still does not consider global gitignore files (e.g. ~/.config/git/ignore is default), therefore differs from the original git status command.
Is this intended?

EDIT: I noticed the gitignore.LoadSystemPatterns() and gitignore.LoadGlobalPatterns() methods.
It seems I can call these by my own and append these to worktree.Excludes so Status() method considers it.

@daniel-weisse
Copy link

From what I can tell, the fix in #1114 does not work if a directory that is not in the repo root (i.e. its in a another directory) has been ignored and contains a .gitignore file with include rules.

Assuming we have a repo with the following structure:

foo 
├ bar    
└ .gitignore
subdir
└ foo
   ├ bar
   └.gitignore
.gitignore

Where the top level .gitignore excludes the directory foo:

foo

and the other two .gitignore files explicitly include bar:

!bar

If we then check the status of the repo, git will report the working tree as clean.
Checking the status using go-git on commit b2aea86f9eef7b21b6c0be6560371653d45abc17 correctly ignores foor/bar, but claims the tree is not clean because of subdir/foo/bar.

func main() {
	repo, _ := git.PlainOpen(".")
	wt, _ := repo.Worktree()
	status, _ := wt.Status()
	fmt.Println(status) // Outputs: ?? subdir/foo/bar
	fmt.Println(status.IsClean()) // Outputs: false
}

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

No branches or pull requests

4 participants