google-gemini / google-gemini/gemini-cli

Nested .gitignore: patterns with only a trailing slash (e.g. build/) are anchored instead of matching at any depth

Open
#29,290 9 comments 0 reactions 0 assignees View on GitHub
area/core effort/small kind/bug priority/p2 status/bot-triaged status/need-information
Dominant language
TypeScript
Stars
107k
Forks
14.6k
Avg merge
2d 3h
Merged PRs (30d)
45

Description

### What happened?

A pattern with only a trailing slash in a nested `.gitignore`, such as `build/`, only ignores the `build` directory sitting next to that `.gitignore`. Directories with the same name further down are still returned by file discovery.

With `pkg/.gitignore` containing `build/`:

- `pkg/build/out.js` is ignored, as expected.
- `pkg/tools/build/out.js` is **not** ignored, so it still shows up through `glob`, `ls`, `read_many_files`, ripGrep and `@` completion.

It comes from `GitIgnoreParser.processPatterns` in `packages/core/src/utils/gitIgnoreParser.ts`. For a nested `.gitignore`, the pattern is only prefixed with `**/` when it contains no `/` at all:

```ts
if (!isAnchoredInFile && !p.includes('/')) {
newPattern = path.posix.join('**', p);
}
```

A trailing slash counts as a slash here, so `build/` is rewritten to `/pkg/build/` instead of `/pkg/**/build/`. The root `.gitignore` and `.geminiignore` go through another branch and are not affected.

Minimal reproduction:

```
mkdir -p repro/pkg/build repro/pkg/tools/build
printf 'build/\n' > repro/pkg/.gitignore
touch repro/pkg/build/out.js repro/pkg/tools/build/out.js
```

`new GitIgnoreParser('repro').isIgnored('pkg/tools/build/out.js', false)` returns `false`.

This affects the common case: any subdirectory `.gitignore` listing `node_modules/`, `__pycache__/`, `build/`, `dist/`, `.venv/` and so on.

### What did you expect to happen?

The same result as git. gitignore(5) says a trailing slash only restricts the pattern to directories, and that "frotz/ matches frotz and a/frotz that is a directory". In a real repository with the same layout:

```
$ git check-ignore -v pkg/build/out.js pkg/tools/build/out.js
pkg/.gitignore:1:build/ pkg/build/out.js
pkg/.gitignore:1:build/ pkg/tools/build/out.js
```

So `pkg/tools/build/out.js` should be ignored too.

### Client information

Found by reading the code on `main` at `bfb71fd2b` and reproduced with the unit tests of `packages/core` on Linux, rather than through a released client, so I have no `/about` output to paste. The affected code is unchanged on `main` at the time of writing.

### Login information

Not relevant: this is local file filtering, no auth involved.

### Anything else we need to know?

I have a small fix with a regression test. When deciding whether to anchor the pattern, count only the slashes before the last character:

```ts
if (!isAnchoredInFile && !p.slice(0, -1).includes('/')) {
```

`build/` then becomes `/pkg/**/build/`. Patterns with a leading or middle slash (`/c`, `c/d`, `c/d/`) are anchored exactly as before.

Checks I ran: the new test fails on `main` at `pkg/deep/build/out.js` and passes with the change; `FileDiscoveryService.filterFiles` stops returning `pkg/tools/build/out.js`; the 18 core test files that use `GitIgnoreParser` or `FileDiscoveryService` pass (716 tests); eslint, prettier and `tsc --noEmit` on `packages/core` are clean. I did not run the full preflight.

The branch is here, in case it is useful: https://github.com/google-gemini/gemini-cli/compare/main...Dev-next-gen:gemini-cli:fix/nested-gitignore-trailing-slash

I read in CONTRIBUTING that pull requests need an issue with the `help wanted` label first, so I am filing this rather than opening the PR. Happy to open it if you would like the fix.

AI tools used

Contributor guide

Open the contributing guide

Research direction

Start in packages/core/src/utils/gitIgnoreParser.ts, especially GitIgnoreParser.processPatterns, and run the relevant GitIgnoreParser and FileDiscoveryService unit tests in packages/core. Reproduce the nested .gitignore case described in the issue, then verify that matching directories at any depth are excluded while anchored and middle-slash patterns retain their existing behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
git, typescript
Domain
cli, tooling
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.