From 436e53e61495ddcd15b8a5cab4c4edd63af37753 Mon Sep 17 00:00:00 2001 From: poketopa Date: Mon, 19 Oct 2026 18:09:31 +0900 Subject: [PATCH 1/2] test(diff): cover renamesFromRewrites in findSimilar Add two cases for Diff#findSimilar: - With renamesFromRewrites, the old side of a rewritten file is a rename source, so moving its content to a new path is reported as Added + Renamed. - renamesFromRewrites: false must not clear renames. Both fail on main, where renamesFromRewrites is passed to renames(). --- tests/diff.spec.ts | 47 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/tests/diff.spec.ts b/tests/diff.spec.ts index 0ee56fca..80b101f8 100644 --- a/tests/diff.spec.ts +++ b/tests/diff.spec.ts @@ -231,4 +231,51 @@ B expect(deltas.length).toBe(expected.length); expect(deltas.map(flattenDiffDelta)).toEqual(expect.arrayContaining(expected)); }); + + it('find renamed diff delta from rewritten file', async () => { + const p = await useFixture('diff'); + const repo = await openRepository(p); + const original = Array.from({ length: 30 }, (_, i) => `original line ${i + 1}\n`).join(''); + const rewritten = Array.from({ length: 30 }, (_, i) => `rewritten line ${i + 1}\n`).join(''); + const index = repo.index(); + await fs.writeFile(path.join(p, 'A'), original); + index.addPath('A'); + const oldTree = repo.getTree(index.writeTree()); + await fs.writeFile(path.join(p, 'A'), rewritten); + await fs.writeFile(path.join(p, 'A-renamed'), original); + index.addPath('A'); + index.addPath('A-renamed'); + const newTree = repo.getTree(index.writeTree()); + const diff = repo.diffTreeToTree(oldTree, newTree); + diff.findSimilar({ renamesFromRewrites: true }); + const deltas = [...diff.deltas()].map(delta => ({ + status: delta.status(), + oldPath: delta.oldFile().path(), + newPath: delta.newFile().path(), + })); + expect(deltas).toEqual([ + { status: 'Added', oldPath: 'A', newPath: 'A' }, + { status: 'Renamed', oldPath: 'A', newPath: 'A-renamed' }, + ]); + }); + + it('find renamed diff delta with renamesFromRewrites disabled', async () => { + const p = await useFixture('diff'); + const repo = await openRepository(p); + // libgit2 falls back to `diff.renames` when no find flag is set. + repo.config().setBool('diff.renames', false); + const headTree = repo.head().peelToTree(); + await fs.rename(path.join(p, 'A'), path.join(p, 'A-renamed')); + const index = repo.index(); + index.addPath('A-renamed'); + index.write(); + const diff = repo.diffTreeToWorkdirWithIndex(headTree); + diff.findSimilar({ renames: true, renamesFromRewrites: false }); + const deltas = [...diff.deltas()].map(delta => ({ + status: delta.status(), + oldPath: delta.oldFile().path(), + newPath: delta.newFile().path(), + })); + expect(deltas).toEqual([{ status: 'Renamed', oldPath: 'A', newPath: 'A-renamed' }]); + }); }); From 695fefe1c6a6babd55f9895c77a10b9494adc233 Mon Sep 17 00:00:00 2001 From: poketopa Date: Mon, 19 Oct 2026 18:09:31 +0900 Subject: [PATCH 2/2] fix(diff): honor renamesFromRewrites in findSimilar DiffFindOptions.renamesFromRewrites was forwarded to git2::DiffFindOptions::renames(), so it toggled GIT_DIFF_FIND_RENAMES instead of GIT_DIFF_FIND_RENAMES_FROM_REWRITES. Setting it to true never used rewritten files as rename sources, and setting it to false cleared an explicit renames: true. Forward it to renames_from_rewrites(), as StatusOptions already does. --- src/diff.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/diff.rs b/src/diff.rs index 13a852b8..b822b72c 100644 --- a/src/diff.rs +++ b/src/diff.rs @@ -218,7 +218,7 @@ impl From for git2::DiffFindOptions { opts.renames(flag); } if let Some(flag) = value.renames_from_rewrites { - opts.renames(flag); + opts.renames_from_rewrites(flag); } if let Some(flag) = value.copies { opts.copies(flag);