fix(snapshot): respect info exclude in snapshot staging (#13495)
This commit is contained in:
@@ -66,7 +66,7 @@ export namespace Snapshot {
|
|||||||
await $`git --git-dir ${git} config core.autocrlf false`.quiet().nothrow()
|
await $`git --git-dir ${git} config core.autocrlf false`.quiet().nothrow()
|
||||||
log.info("initialized")
|
log.info("initialized")
|
||||||
}
|
}
|
||||||
await $`git --git-dir ${git} --work-tree ${Instance.worktree} add .`.quiet().cwd(Instance.directory).nothrow()
|
await add(git)
|
||||||
const hash = await $`git --git-dir ${git} --work-tree ${Instance.worktree} write-tree`
|
const hash = await $`git --git-dir ${git} --work-tree ${Instance.worktree} write-tree`
|
||||||
.quiet()
|
.quiet()
|
||||||
.cwd(Instance.directory)
|
.cwd(Instance.directory)
|
||||||
@@ -84,7 +84,7 @@ export namespace Snapshot {
|
|||||||
|
|
||||||
export async function patch(hash: string): Promise<Patch> {
|
export async function patch(hash: string): Promise<Patch> {
|
||||||
const git = gitdir()
|
const git = gitdir()
|
||||||
await $`git --git-dir ${git} --work-tree ${Instance.worktree} add .`.quiet().cwd(Instance.directory).nothrow()
|
await add(git)
|
||||||
const result =
|
const result =
|
||||||
await $`git -c core.autocrlf=false -c core.quotepath=false --git-dir ${git} --work-tree ${Instance.worktree} diff --no-ext-diff --name-only ${hash} -- .`
|
await $`git -c core.autocrlf=false -c core.quotepath=false --git-dir ${git} --work-tree ${Instance.worktree} diff --no-ext-diff --name-only ${hash} -- .`
|
||||||
.quiet()
|
.quiet()
|
||||||
@@ -162,7 +162,7 @@ export namespace Snapshot {
|
|||||||
|
|
||||||
export async function diff(hash: string) {
|
export async function diff(hash: string) {
|
||||||
const git = gitdir()
|
const git = gitdir()
|
||||||
await $`git --git-dir ${git} --work-tree ${Instance.worktree} add .`.quiet().cwd(Instance.directory).nothrow()
|
await add(git)
|
||||||
const result =
|
const result =
|
||||||
await $`git -c core.autocrlf=false -c core.quotepath=false --git-dir ${git} --work-tree ${Instance.worktree} diff --no-ext-diff ${hash} -- .`
|
await $`git -c core.autocrlf=false -c core.quotepath=false --git-dir ${git} --work-tree ${Instance.worktree} diff --no-ext-diff ${hash} -- .`
|
||||||
.quiet()
|
.quiet()
|
||||||
@@ -253,4 +253,38 @@ export namespace Snapshot {
|
|||||||
const project = Instance.project
|
const project = Instance.project
|
||||||
return path.join(Global.Path.data, "snapshot", project.id)
|
return path.join(Global.Path.data, "snapshot", project.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function add(git: string) {
|
||||||
|
await syncExclude(git)
|
||||||
|
await $`git --git-dir ${git} --work-tree ${Instance.worktree} add .`.quiet().cwd(Instance.directory).nothrow()
|
||||||
|
}
|
||||||
|
|
||||||
|
async function syncExclude(git: string) {
|
||||||
|
const file = await excludes()
|
||||||
|
const target = path.join(git, "info", "exclude")
|
||||||
|
await fs.mkdir(path.join(git, "info"), { recursive: true })
|
||||||
|
if (!file) {
|
||||||
|
await Bun.write(target, "")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const text = await Bun.file(file)
|
||||||
|
.text()
|
||||||
|
.catch(() => "")
|
||||||
|
await Bun.write(target, text)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function excludes() {
|
||||||
|
const file = await $`git rev-parse --path-format=absolute --git-path info/exclude`
|
||||||
|
.quiet()
|
||||||
|
.cwd(Instance.worktree)
|
||||||
|
.nothrow()
|
||||||
|
.text()
|
||||||
|
if (!file.trim()) return
|
||||||
|
const exists = await fs
|
||||||
|
.stat(file.trim())
|
||||||
|
.then(() => true)
|
||||||
|
.catch(() => false)
|
||||||
|
if (!exists) return
|
||||||
|
return file.trim()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -508,6 +508,68 @@ test("gitignore changes", async () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test("git info exclude changes", async () => {
|
||||||
|
await using tmp = await bootstrap()
|
||||||
|
await Instance.provide({
|
||||||
|
directory: tmp.path,
|
||||||
|
fn: async () => {
|
||||||
|
const before = await Snapshot.track()
|
||||||
|
expect(before).toBeTruthy()
|
||||||
|
|
||||||
|
const file = `${tmp.path}/.git/info/exclude`
|
||||||
|
const text = await Bun.file(file).text()
|
||||||
|
await Bun.write(file, `${text.trimEnd()}\nignored.txt\n`)
|
||||||
|
await Bun.write(`${tmp.path}/ignored.txt`, "ignored content")
|
||||||
|
await Bun.write(`${tmp.path}/normal.txt`, "normal content")
|
||||||
|
|
||||||
|
const patch = await Snapshot.patch(before!)
|
||||||
|
expect(patch.files).toContain(`${tmp.path}/normal.txt`)
|
||||||
|
expect(patch.files).not.toContain(`${tmp.path}/ignored.txt`)
|
||||||
|
|
||||||
|
const after = await Snapshot.track()
|
||||||
|
const diffs = await Snapshot.diffFull(before!, after!)
|
||||||
|
expect(diffs.some((x) => x.file === "normal.txt")).toBe(true)
|
||||||
|
expect(diffs.some((x) => x.file === "ignored.txt")).toBe(false)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
test("git info exclude keeps global excludes", async () => {
|
||||||
|
await using tmp = await bootstrap()
|
||||||
|
await Instance.provide({
|
||||||
|
directory: tmp.path,
|
||||||
|
fn: async () => {
|
||||||
|
const global = `${tmp.path}/global.ignore`
|
||||||
|
const config = `${tmp.path}/global.gitconfig`
|
||||||
|
await Bun.write(global, "global.tmp\n")
|
||||||
|
await Bun.write(config, `[core]\n\texcludesFile = ${global}\n`)
|
||||||
|
|
||||||
|
const prev = process.env.GIT_CONFIG_GLOBAL
|
||||||
|
process.env.GIT_CONFIG_GLOBAL = config
|
||||||
|
try {
|
||||||
|
const before = await Snapshot.track()
|
||||||
|
expect(before).toBeTruthy()
|
||||||
|
|
||||||
|
const file = `${tmp.path}/.git/info/exclude`
|
||||||
|
const text = await Bun.file(file).text()
|
||||||
|
await Bun.write(file, `${text.trimEnd()}\ninfo.tmp\n`)
|
||||||
|
|
||||||
|
await Bun.write(`${tmp.path}/global.tmp`, "global content")
|
||||||
|
await Bun.write(`${tmp.path}/info.tmp`, "info content")
|
||||||
|
await Bun.write(`${tmp.path}/normal.txt`, "normal content")
|
||||||
|
|
||||||
|
const patch = await Snapshot.patch(before!)
|
||||||
|
expect(patch.files).toContain(`${tmp.path}/normal.txt`)
|
||||||
|
expect(patch.files).not.toContain(`${tmp.path}/global.tmp`)
|
||||||
|
expect(patch.files).not.toContain(`${tmp.path}/info.tmp`)
|
||||||
|
} finally {
|
||||||
|
if (prev) process.env.GIT_CONFIG_GLOBAL = prev
|
||||||
|
else delete process.env.GIT_CONFIG_GLOBAL
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
test("concurrent file operations during patch", async () => {
|
test("concurrent file operations during patch", async () => {
|
||||||
await using tmp = await bootstrap()
|
await using tmp = await bootstrap()
|
||||||
await Instance.provide({
|
await Instance.provide({
|
||||||
|
|||||||
Reference in New Issue
Block a user