Skip to content

Never delete empty files when deduplicating [patch] - #165

Merged
matt-edmondson merged 2 commits into
mainfrom
fix/keep-empty-files
Oct 6, 2026
Merged

matt-edmondson merged 2 commits into
mainfrom
fix/keep-empty-files

Conversation

@matt-edmondson

Copy link
Copy Markdown
Contributor

Fixes #151

What changed

Every zero-length file has the same SHA-256. That put __init__.py, .gitkeep and py.typed files from all over a tree into one group, and Deduplicate deleted all but one of them while reporting 0 B reclaimed.

  • Added Deduplicator.IsDeletable(group), which is false for a zero-length group.
  • DeleteDuplicates skips groups that aren't deletable, so their files are never deleted.
  • DuplicateReport.PlanDeletions, the listing DryRun and Deduplicate print, lists every file in an empty group as KEEP under "Empty files are never deleted", and counts none of them.
  • Scan marks those files [KEEP, empty] rather than [DELETE].
  • FindDuplicates is unchanged, so empty files are still reported as a group and EmptyFilesAreDuplicatesOfEachOther still holds.
  • DryRunEquivalenceTests.PredictedDeletions applies the same filter, so the preview and the deletion still agree.
  • Added a README note.

Tests

  • DeduplicatorTests.EmptyFilesAreNeverDeleted: two empty __init__.py files plus one real duplicate pair. Only the real duplicate is deleted.
  • DuplicateReportTests.PlanKeepsEveryEmptyFile: three empty files. The plan deletes 0 files and 0 bytes, and lists all three as KEEP.

With IsDeletable stubbed to always return true (the old behaviour), both new tests fail. With the fix, the full suite passes: 61 passed, 2 skipped. The 2 skips are pre-existing tests that need an unprivileged user. I also ran Deduplicate on a real tree holding three empty files and one duplicate pair: it deleted only the duplicate.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Q5ZFyLG9PgeKn5RpzhWEUQ


Generated by Claude Code

claude added 2 commits October 6, 2026 09:25
Every zero-length file hashes the same, so __init__.py, .gitkeep and
py.typed markers across a tree formed one duplicate group, and
Deduplicate deleted all but one of them while reclaiming 0 bytes.

Empty groups are still reported, but DeleteDuplicates, the deletion
plan that DryRun and Deduplicate print, and Scan's listing now keep
every copy.

Fixes #151

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q5ZFyLG9PgeKn5RpzhWEUQ
Addresses SonarCloud S3358 and MSTEST0037 on this PR.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q5ZFyLG9PgeKn5RpzhWEUQ
@sonarqubecloud

sonarqubecloud Bot commented Oct 6, 2026

Copy link
Copy Markdown

@matt-edmondson
matt-edmondson merged commit 3c09443 into main Oct 6, 2026
14 checks passed
@matt-edmondson
matt-edmondson deleted the fix/keep-empty-files branch October 6, 2026 12:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Deduplicate deletes all but one empty file (__init__.py, .gitkeep, py.typed) while reclaiming 0 bytes

2 participants