fix(snapshot): complete gitignore respect for previously tracked files (#22172)
This commit is contained in:
@@ -180,6 +180,7 @@ export namespace Snapshot {
|
|||||||
// Filter out files that are now gitignored even if previously tracked
|
// Filter out files that are now gitignored even if previously tracked
|
||||||
// Files may have been tracked before being gitignored, so we need to check
|
// Files may have been tracked before being gitignored, so we need to check
|
||||||
// against the source project's current gitignore rules
|
// against the source project's current gitignore rules
|
||||||
|
// Use --no-index to check purely against patterns (ignoring whether file is tracked)
|
||||||
const checkArgs = [
|
const checkArgs = [
|
||||||
...quote,
|
...quote,
|
||||||
"--git-dir",
|
"--git-dir",
|
||||||
@@ -187,6 +188,7 @@ export namespace Snapshot {
|
|||||||
"--work-tree",
|
"--work-tree",
|
||||||
state.worktree,
|
state.worktree,
|
||||||
"check-ignore",
|
"check-ignore",
|
||||||
|
"--no-index",
|
||||||
"--",
|
"--",
|
||||||
...all,
|
...all,
|
||||||
]
|
]
|
||||||
@@ -303,6 +305,7 @@ export namespace Snapshot {
|
|||||||
"--work-tree",
|
"--work-tree",
|
||||||
state.worktree,
|
state.worktree,
|
||||||
"check-ignore",
|
"check-ignore",
|
||||||
|
"--no-index",
|
||||||
"--",
|
"--",
|
||||||
...files,
|
...files,
|
||||||
]
|
]
|
||||||
@@ -669,6 +672,30 @@ export namespace Snapshot {
|
|||||||
} satisfies Row,
|
} satisfies Row,
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Filter out files that are now gitignored
|
||||||
|
if (rows.length > 0) {
|
||||||
|
const files = rows.map((r) => r.file)
|
||||||
|
const checkArgs = [
|
||||||
|
...quote,
|
||||||
|
"--git-dir",
|
||||||
|
path.join(state.worktree, ".git"),
|
||||||
|
"--work-tree",
|
||||||
|
state.worktree,
|
||||||
|
"check-ignore",
|
||||||
|
"--no-index",
|
||||||
|
"--",
|
||||||
|
...files,
|
||||||
|
]
|
||||||
|
const check = yield* git(checkArgs, { cwd: state.directory })
|
||||||
|
if (check.code === 0) {
|
||||||
|
const ignored = new Set(check.text.trim().split("\n").filter(Boolean))
|
||||||
|
const filtered = rows.filter((r) => !ignored.has(r.file))
|
||||||
|
rows.length = 0
|
||||||
|
rows.push(...filtered)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const step = 100
|
const step = 100
|
||||||
const patch = (file: string, before: string, after: string) =>
|
const patch = (file: string, before: string, after: string) =>
|
||||||
formatPatch(structuredPatch(file, file, before, after, "", "", { context: Number.MAX_SAFE_INTEGER }))
|
formatPatch(structuredPatch(file, file, before, after, "", "", { context: Number.MAX_SAFE_INTEGER }))
|
||||||
|
|||||||
@@ -612,6 +612,41 @@ test("files tracked in snapshot but now gitignored are filtered out", async () =
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test("gitignore updated between track calls filters from diff", async () => {
|
||||||
|
await using tmp = await bootstrap()
|
||||||
|
await Instance.provide({
|
||||||
|
directory: tmp.path,
|
||||||
|
fn: async () => {
|
||||||
|
// a.txt is already committed from bootstrap - track it in snapshot
|
||||||
|
const before = await Snapshot.track()
|
||||||
|
expect(before).toBeTruthy()
|
||||||
|
|
||||||
|
// Modify a.txt (so it appears in diff-files)
|
||||||
|
await Filesystem.write(`${tmp.path}/a.txt`, "modified content")
|
||||||
|
|
||||||
|
// Now add gitignore that would exclude a.txt
|
||||||
|
await Filesystem.write(`${tmp.path}/.gitignore`, "a.txt\n")
|
||||||
|
|
||||||
|
// Also modify b.txt which is not gitignored
|
||||||
|
await Filesystem.write(`${tmp.path}/b.txt`, "also modified")
|
||||||
|
|
||||||
|
// Second track - should not include a.txt even though it changed
|
||||||
|
const after = await Snapshot.track()
|
||||||
|
expect(after).toBeTruthy()
|
||||||
|
|
||||||
|
// Verify a.txt is NOT in the diff between snapshots
|
||||||
|
const diffs = await Snapshot.diffFull(before!, after!)
|
||||||
|
expect(diffs.some((x) => x.file === "a.txt")).toBe(false)
|
||||||
|
|
||||||
|
// But .gitignore should be in the diff
|
||||||
|
expect(diffs.some((x) => x.file === ".gitignore")).toBe(true)
|
||||||
|
|
||||||
|
// b.txt should be in the diff (not gitignored)
|
||||||
|
expect(diffs.some((x) => x.file === "b.txt")).toBe(true)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
test("git info exclude changes", async () => {
|
test("git info exclude changes", async () => {
|
||||||
await using tmp = await bootstrap()
|
await using tmp = await bootstrap()
|
||||||
await Instance.provide({
|
await Instance.provide({
|
||||||
|
|||||||
Reference in New Issue
Block a user