Skip to content

feat(core): respect git info exclude files#10121

Open
jongwan56 wants to merge 4 commits into
biomejs:nextfrom
jongwan56:fix/git-info-exclude
Open

feat(core): respect git info exclude files#10121
jongwan56 wants to merge 4 commits into
biomejs:nextfrom
jongwan56:fix/git-info-exclude

Conversation

@jongwan56
Copy link
Copy Markdown

@jongwan56 jongwan56 commented Apr 26, 2026

Fixes #4822

Summary

Makes vcs.useIgnoreFile include repository-local Git exclude patterns from .git/info/exclude. Linked worktrees are handled by resolving gitdir and commondir.

This PR was implemented with assistance from Codex. The contributor reviewed and validated the change.

Test Plan

  • just f
  • just l
  • cargo test -p biome_cli --test main vcs_ignored_files -- --nocapture

Docs

No documentation changes.

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Apr 26, 2026

🦋 Changeset detected

Latest commit: ec1b930

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 14 packages
Name Type
@biomejs/biome Minor
@biomejs/js-api Major
@biomejs/cli-win32-x64 Minor
@biomejs/cli-win32-arm64 Minor
@biomejs/cli-darwin-x64 Minor
@biomejs/cli-darwin-arm64 Minor
@biomejs/cli-linux-x64 Minor
@biomejs/cli-linux-arm64 Minor
@biomejs/cli-linux-x64-musl Minor
@biomejs/cli-linux-arm64-musl Minor
@biomejs/wasm-web Minor
@biomejs/wasm-bundler Minor
@biomejs/wasm-nodejs Minor
@biomejs/backend-jsonrpc Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions github-actions Bot added A-CLI Area: CLI A-Project Area: project labels Apr 26, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 26, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds Git’s local exclude (.git/info/exclude) to VCS ignore resolution in addition to .gitignore/.ignore. The server now reads ignore contents from multiple sources (including handling .git as a directory or a gitdir: pointer and following commondir indirection to locate the repository common dir), concatenates lines from all found sources into the ignore patterns, and only emits NoIgnoreFileFound when all sources are empty. Includes a changeset and two CLI snapshot tests covering direct and commondir-resolved info/exclude behaviour.

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarises the main change: enabling Biome to respect Git's local exclude file (.git/info/exclude) as part of VCS ignore handling.
Description check ✅ Passed The description is directly related to the changeset, explaining what was fixed (issue #4822), the implementation approach, and providing test instructions.
Linked Issues check ✅ Passed The PR successfully implements the requirements from issue #4822: it makes vcs.useIgnoreFile include .git/info/exclude patterns and handles linked worktrees via gitdir/commondir resolution.
Out of Scope Changes check ✅ Passed All changes are directly scoped to implementing .git/info/exclude support: a changeset entry, two test cases, workspace server logic for reading exclude files, and VCS configuration documentation.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
⚔️ Resolve merge conflicts
  • Resolve merge conflict in branch fix/git-info-exclude

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
crates/biome_service/src/workspace/server.rs (1)

163-178: Tiny tidy-up: collapse .ok() + let Some into let Ok.

Reads a touch nicer and saves one hop.

♻️ Suggested simplification
 fn resolve_git_common_dir(fs: &dyn FsWithResolverProxy, git_dir: &Utf8Path) -> Utf8PathBuf {
-    let Some(content) = fs
-        .read_file_from_path(git_dir.join("commondir").as_ref())
-        .ok()
-    else {
+    let Ok(content) = fs.read_file_from_path(git_dir.join("commondir").as_ref()) else {
         return git_dir.to_path_buf();
     };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/biome_service/src/workspace/server.rs` around lines 163 - 178, The
pattern in resolve_git_common_dir uses fs.read_file_from_path(...).ok() followed
by let Some(content) which can be simplified to use let Ok(content) =
fs.read_file_from_path(...) directly; update the early-return branch to match on
Ok and keep the existing return of git_dir.to_path_buf() on Err, preserving the
subsequent trimming/map/unwrap_or_else logic that calls resolve_git_path so the
behavior of resolve_git_common_dir and interaction with FsWithResolverProxy and
resolve_git_path remains identical.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@crates/biome_service/src/workspace/server.rs`:
- Around line 163-178: The pattern in resolve_git_common_dir uses
fs.read_file_from_path(...).ok() followed by let Some(content) which can be
simplified to use let Ok(content) = fs.read_file_from_path(...) directly; update
the early-return branch to match on Ok and keep the existing return of
git_dir.to_path_buf() on Err, preserving the subsequent
trimming/map/unwrap_or_else logic that calls resolve_git_path so the behavior of
resolve_git_common_dir and interaction with FsWithResolverProxy and
resolve_git_path remains identical.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 25f651b8-6be5-466e-972f-4506d257e7fe

📥 Commits

Reviewing files that changed from the base of the PR and between 895e809 and 31311f2.

⛔ Files ignored due to path filters (2)
  • crates/biome_cli/tests/snapshots/main_cases_vcs_ignored_files/ignore_git_common_info_exclude.snap is excluded by !**/*.snap and included by **
  • crates/biome_cli/tests/snapshots/main_cases_vcs_ignored_files/ignore_git_info_exclude.snap is excluded by !**/*.snap and included by **
📒 Files selected for processing (3)
  • .changeset/respect-git-info-exclude.md
  • crates/biome_cli/tests/cases/vcs_ignored_files.rs
  • crates/biome_service/src/workspace/server.rs

@jongwan56 jongwan56 force-pushed the fix/git-info-exclude branch from 31311f2 to fa839fc Compare April 26, 2026 16:10
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
crates/biome_cli/tests/cases/vcs_ignored_files.rs (1)

140-179: Worktree indirection scenario looks good.

The .git file → gitdircommondir chain is wired correctly (actual.git/worktrees/current + ../.. resolving to actual.git), exercising the new common-dir resolution path well.

One small optional thought: a third test where both .gitignore and .git/info/exclude are absent/empty would lock in the "emit NoIgnoreFileFound only when all sources are empty" branch from the server-side change. Not a blocker — should_fail_when_ignore_file_is_absent already partially covers it.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/biome_cli/tests/cases/vcs_ignored_files.rs` around lines 140 - 179,
Add an additional test that verifies the NoIgnoreFileFound emission only occurs
when all ignore sources are absent/empty: create a test analogous to
ignore_git_common_info_exclude (e.g., ignore_no_sources_emits_no_ignore) that
sets up a repo with vcs enabled and git clientKind but with both .gitignore and
actual.git/info/exclude missing or empty and without other ignore sources, run
run_cli_with_dyn_fs with the same Args::from(["format", "--write", ...])
pattern, and assert the CLI result and snapshot expect the NoIgnoreFileFound
behavior; this complements should_fail_when_ignore_file_is_absent and ensures
the server-side "all sources empty" branch is exercised.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@crates/biome_cli/tests/cases/vcs_ignored_files.rs`:
- Around line 140-179: Add an additional test that verifies the
NoIgnoreFileFound emission only occurs when all ignore sources are absent/empty:
create a test analogous to ignore_git_common_info_exclude (e.g.,
ignore_no_sources_emits_no_ignore) that sets up a repo with vcs enabled and git
clientKind but with both .gitignore and actual.git/info/exclude missing or empty
and without other ignore sources, run run_cli_with_dyn_fs with the same
Args::from(["format", "--write", ...]) pattern, and assert the CLI result and
snapshot expect the NoIgnoreFileFound behavior; this complements
should_fail_when_ignore_file_is_absent and ensures the server-side "all sources
empty" branch is exercised.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 09eebe88-1c53-4d23-9ccb-079cebb6f941

📥 Commits

Reviewing files that changed from the base of the PR and between 31311f2 and fa839fc.

⛔ Files ignored due to path filters (2)
  • crates/biome_cli/tests/snapshots/main_cases_vcs_ignored_files/ignore_git_common_info_exclude.snap is excluded by !**/*.snap and included by **
  • crates/biome_cli/tests/snapshots/main_cases_vcs_ignored_files/ignore_git_info_exclude.snap is excluded by !**/*.snap and included by **
📒 Files selected for processing (3)
  • .changeset/respect-git-info-exclude.md
  • crates/biome_cli/tests/cases/vcs_ignored_files.rs
  • crates/biome_service/src/workspace/server.rs
✅ Files skipped from review due to trivial changes (1)
  • .changeset/respect-git-info-exclude.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • crates/biome_service/src/workspace/server.rs

@dyc3
Copy link
Copy Markdown
Contributor

dyc3 commented Apr 26, 2026

Would you mind elaborating a bit more on how .git/info/exclude works and how it relates to worktrees? this would also be useful context as comments in the code.

@ematipico
Copy link
Copy Markdown
Member

This PR would close #4822

@jongwan56
Copy link
Copy Markdown
Author

Thanks, that makes sense.

I added comments around the Git directory resolution. Git treats $GIT_DIR/info/exclude as repository-local ignore rules, separate from version-controlled .gitignore files.

The worktree case matters because a linked worktree's .git entry points to a per-worktree gitdir, while info/exclude is resolved from the common Git directory via commondir. Without following commondir, Biome can miss ignore rules used by Git for linked worktrees.

I also updated the changeset and PR description to reference #4822.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@crates/biome_service/src/workspace/server.rs`:
- Around line 1356-1386: The pull request changes when the NoIgnoreFileFound
diagnostic is emitted by adding read_git_info_exclude(...) into the ignore-file
detection path, so update the repo changelog: add a
.changeset/respect-git-info-exclude.md entry that notes the behavioral change
(NoIgnoreFileFound now only fires if .gitignore, .ignore, and .git/info/exclude
are all missing/empty), reference the affected logic by name
(read_git_info_exclude, NoIgnoreFileFound, and store_root_ignore_patterns) and
briefly explain the user-visible impact for consumers who relied on the previous
diagnostic behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: a0acc62d-9748-4223-bde4-b12ef8d3f171

📥 Commits

Reviewing files that changed from the base of the PR and between fa839fc and 378b454.

📒 Files selected for processing (2)
  • .changeset/respect-git-info-exclude.md
  • crates/biome_service/src/workspace/server.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • .changeset/respect-git-info-exclude.md

Comment thread crates/biome_service/src/workspace/server.rs
Copy link
Copy Markdown
Member

@ematipico ematipico left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank for this, users will appreciate it.

However, this PR isn't a bug fix, but a new feature, because the VCS integration will do more than before, by default.

We need:

  • to update the changeset to be a minor and reword it entirely. Changeset are for our end-users, so we need to remove all technical words
  • update the documentation of the CLI arguments in the source code, specially the use_ignore_file field
  • send a PR to biomejs/website repository and update the section that talks about VCS integration
  • send the PR towards the next branch (this one and the one of the website)

We're close to our next minor, so let us know if you need help, or you can do everything yourself

let gitdir = line.strip_prefix("gitdir:")?.trim();
Some(resolve_git_path(directory, gitdir))
}),
Err(_) => Some(dot_git),
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is incorrect. It should return None. We shouldn't pretend that .git actually exists

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated. resolve_git_dir now returns None when .git is neither a readable gitdir: file nor an actual directory, so Biome no longer assumes a missing .git path exists.

{
ignore_file_contents.push(content);
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer if read_git_info_exclude wouldn't pollute ignore_file_contents, and instead it would read and parse the content, and would return the lines we need. It seems duplicate work, but it would make things well separated.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated. read_git_info_exclude_patterns now reads and parses .git/info/exclude separately and returns the patterns, so the root ignore file contents stay separate.

@jongwan56 jongwan56 force-pushed the fix/git-info-exclude branch from 58d8c5b to ec1b930 Compare April 27, 2026 08:00
@jongwan56 jongwan56 changed the title fix(core): respect git info exclude files feat(core): respect git info exclude files Apr 27, 2026
@jongwan56 jongwan56 changed the base branch from main to next April 27, 2026 08:00
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
crates/biome_cli/tests/cases/vcs_ignored_files.rs (1)

156-159: Optional: a one-liner explaining the worktree fixture would be lovely.

The fixture here is doing some clever sleight of hand — .git is a file pointing at a per-worktree gitdir, commondir then bounces back up to the shared actual.git, where info/exclude actually lives. Given the same question came up in PR review, a short comment in the test would save the next reader a Git-internals deep dive.

📝 Suggested comment
+    // Simulate a linked worktree: `.git` is a file pointing at the worktree's
+    // gitdir, whose `commondir` resolves back to the shared repository
+    // directory where `info/exclude` lives.
     fs.create_file(".gitignore", "");
     fs.create_file(".git", "gitdir: actual.git/worktrees/current\n");
     fs.create_file("actual.git/worktrees/current/commondir", "../..\n");
     fs.create_file("actual.git/info/exclude", "file2.js\n");
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/biome_cli/tests/cases/vcs_ignored_files.rs` around lines 156 - 159,
Add a one-line comment above the test fixture that creates ".gitignore", ".git",
"actual.git/worktrees/current/commondir", and "actual.git/info/exclude"
explaining that ".git" is a worktree pointer file pointing to a per-worktree
gitdir (actual.git/worktrees/current), that "commondir" points back to the
shared repository (../..) so the real excludes live in
"actual.git/info/exclude", and therefore the test uses this layout to simulate
Git worktree behavior for ignore resolution.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.changeset/respect-git-info-exclude.md:
- Line 2: Update the changeset entry that currently reads `"@biomejs/biome":
minor` to use the patch change type instead (i.e. `"@biomejs/biome": patch`)
because this PR is a bug fix targeting main (resolves `#4822`); locate the
changeset file containing the string `"@biomejs/biome": minor` and modify only
the change type token from minor to patch.
- Line 5: Update the changeset description to start with the required prefix
"Fixed [`#4822`](issue link):" so it follows the bug-fix convention; edit the
.changeset/respect-git-info-exclude.md content and prepend "Fixed [`#4822`](...):
" (replace ... with the actual issue URL) before the existing sentence about
applying Git's local exclude file.

---

Nitpick comments:
In `@crates/biome_cli/tests/cases/vcs_ignored_files.rs`:
- Around line 156-159: Add a one-line comment above the test fixture that
creates ".gitignore", ".git", "actual.git/worktrees/current/commondir", and
"actual.git/info/exclude" explaining that ".git" is a worktree pointer file
pointing to a per-worktree gitdir (actual.git/worktrees/current), that
"commondir" points back to the shared repository (../..) so the real excludes
live in "actual.git/info/exclude", and therefore the test uses this layout to
simulate Git worktree behavior for ignore resolution.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 903a2678-e0c9-4e0e-bcb1-840db323ecd1

📥 Commits

Reviewing files that changed from the base of the PR and between 58d8c5b and ec1b930.

⛔ Files ignored due to path filters (2)
  • crates/biome_cli/tests/snapshots/main_cases_vcs_ignored_files/ignore_git_common_info_exclude.snap is excluded by !**/*.snap and included by **
  • crates/biome_cli/tests/snapshots/main_cases_vcs_ignored_files/ignore_git_info_exclude.snap is excluded by !**/*.snap and included by **
📒 Files selected for processing (3)
  • .changeset/respect-git-info-exclude.md
  • crates/biome_cli/tests/cases/vcs_ignored_files.rs
  • crates/biome_configuration/src/vcs.rs
✅ Files skipped from review due to trivial changes (1)
  • crates/biome_configuration/src/vcs.rs

Comment thread .changeset/respect-git-info-exclude.md
"@biomejs/biome": minor
---

Biome now applies Git's local exclude file when VCS ignore files are enabled. Files listed in `.git/info/exclude` are skipped the same way as files listed in `.gitignore`, including in linked worktrees.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Lead with the Fixed [#4822](...) prefix.

Since issue #4822 exists for this bug, the changeset description should start with the standard Fixed [#NUMBER](issue link): ... form so it lines up with the rest of the changelog.

🩹 Suggested fix
-Biome now applies Git's local exclude file when VCS ignore files are enabled. Files listed in `.git/info/exclude` are skipped the same way as files listed in `.gitignore`, including in linked worktrees.
+Fixed [`#4822`](https://github.com/biomejs/biome/issues/4822): Biome now applies Git's local exclude file when VCS ignore files are enabled. Files listed in `.git/info/exclude` are skipped the same way as files listed in `.gitignore`, including in linked worktrees.

As per coding guidelines: "For bug fixes, start with 'Fixed [#NUMBER](issue link): ...'."

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Biome now applies Git's local exclude file when VCS ignore files are enabled. Files listed in `.git/info/exclude` are skipped the same way as files listed in `.gitignore`, including in linked worktrees.
Fixed [`#4822`](https://github.com/biomejs/biome/issues/4822): Biome now applies Git's local exclude file when VCS ignore files are enabled. Files listed in `.git/info/exclude` are skipped the same way as files listed in `.gitignore`, including in linked worktrees.
🧰 Tools
🪛 LanguageTool

[grammar] ~5-~5: There seems to be a noun/verb agreement error. Did you mean “excludes” or “excluded”?
Context: ...inor --- Biome now applies Git's local exclude file when VCS ignore files are enabled....

(SINGULAR_NOUN_VERB_AGREEMENT)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.changeset/respect-git-info-exclude.md at line 5, Update the changeset
description to start with the required prefix "Fixed [`#4822`](issue link):" so it
follows the bug-fix convention; edit the .changeset/respect-git-info-exclude.md
content and prepend "Fixed [`#4822`](...): " (replace ... with the actual issue
URL) before the existing sentence about applying Git's local exclude file.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-CLI Area: CLI A-Project Area: project

Projects

None yet

Development

Successfully merging this pull request may close these issues.

vcs.useIgnoreFile Git integration does not take .git/info/exclude into account

3 participants