Skip to content

Fix rename detection for diffs without filename prefixes - #152

Open
CLCK0622 wants to merge 1 commit into
matiasb:mainfrom
CLCK0622:fix-no-prefix-rename-detection
Open

CLCK0622 wants to merge 1 commit into
matiasb:mainfrom
CLCK0622:fix-no-prefix-rename-detection

Conversation

@CLCK0622

Copy link
Copy Markdown

With git diff --no-prefix, is_rename unconditionally discards the first two filename characters, so a rename such as a.py to b.py goes undetected and path returns the source filename. Remove surrounding quotes for comparison and discard two characters only when both resulting paths start with a character followed by /; this retains custom prefixes such as x/ and y/. For equally quoted inputs, comparisons with two such prefixes remain equivalent to the original behavior; otherwise, results change only when the original strings differ but become equal after discarding their first two characters. This follows the target-path behavior discussed in #77 and implemented in #79. A no-prefix rename where both real directory names resemble single-character prefixes, such as a/x.py to b/x.py, remains ambiguous from the header and is unchanged.

Reproduce with an installed checkout:

python - <<'PY'
from unidiff import PatchSet

diff = """diff --git a.py b.py
similarity index 100%
rename from a.py
rename to b.py
"""
patched = PatchSet(diff)[0]
print(patched.is_rename, patched.path, patched.source_file, patched.target_file)
PY
Version Output
Before False a.py a.py b.py
After True b.py a.py b.py

Validation on macOS arm64:

  • Python 3.12.13 and 3.9.6: python -m unittest discover -s tests/ passes 72 tests (69 on the unchanged baseline); applying only the added tests produces 14 expected failures.
  • python -m mypy unidiff/ with mypy 2.4.0 on Python 3.12: no issues in 6 source files before and after.
  • Also checked against diffs generated by git diff with the default, --no-prefix, mnemonic, and custom --src-prefix/--dst-prefix settings; only no-prefix names that differ in their first two characters change.

The upstream CI matrix has not been run locally.

Manually written headers that quote only one side of otherwise equivalent filenames change from renames to non-renames; Git does not generate such output.

AI disclosure: Codex assisted with part of the code and this description.

With `git diff --no-prefix`, `is_rename` unconditionally discards the first two filename characters, so a rename such as `a.py` to `b.py` goes undetected and `path` returns the source filename. Remove surrounding quotes for comparison and discard two characters only when both resulting paths start with a character followed by `/`; this retains custom prefixes such as `x/` and `y/`. For equally quoted inputs, comparisons with two such prefixes remain equivalent to the original behavior; otherwise, results change only when the original strings differ but become equal after discarding their first two characters. This follows the target-path behavior discussed in [matiasb#77](matiasb#77) and implemented in [matiasb#79](matiasb#79). A no-prefix rename where both real directory names resemble single-character prefixes, such as `a/x.py` to `b/x.py`, remains ambiguous from the header and is unchanged.
Copilot AI balanced review requested due to automatic review settings October 25, 2026 18:16

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota.

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.

2 participants