Skip to content

RT-300: parse a file-to-symlink typechange's two diff blocks - #454

Merged
m4ttheweric merged 3 commits into
mainfrom
rt-300-typechange
Sep 25, 2026
Merged

m4ttheweric merged 3 commits into
mainfrom
rt-300-typechange

Conversation

@m4ttheweric

@m4ttheweric m4ttheweric commented Sep 25, 2026 •

Copy link
Copy Markdown
Collaborator

RT-300. When a file is replaced by a symlink (or back), git emits two diff --git blocks for that one path: a delete, then an add. The vendored GHD DiffParser threw "Invalid hunk header format" on the second header, so glitter could neither show nor stage the file.

What changed

git-core

  • new parseFileDiff (diff-hunks.ts) parses each block alone and joins the hunks, shifting unifiedDiffStart/End so every line keeps a unique selection index
  • stagingDiff and commitDiff both use it and set typechange: true on such a diff

glitter

  • buildDiffModel shows a typechange diff read-only (no stage bar, no line or hunk toggles)
  • it stages whole from its file-row checkbox, since half a file and half a symlink is not a state git can stage

Guards (from the Opus review standing in for rate-limited CodeRabbit)

  • stageSelection and discardSelection refuse a typechange (a leftover Partial reached git apply and wrote a corrupted regular file)
  • the commit-time index rebuild drops such a Partial to None and refuses the commit with a notice naming the file, so a retry commits the rest
  • blocks split at \n only, so a lone \r before diff --git in a content line never splits a block
  • commitDiff and the range diff pass -M, so a rename never reads as two blocks

Verification

  • sandbox tests: working-tree stagingDiff (hunks, unique indices, sources, stageFileFully gives 100644 -> 120000 T), a committed typechange through commitDiff, and the model's read-only flag; all three failed before the fix
  • live in glitter on a scratch repo: the diff shows -one -two -three then +other.txt, the file-row toggle works, committing gives :100644 120000 ... T f.txt, and History shows the committed typechange
  • git-core plus mission suites 567/567

🤖 Generated with Claude Code

git splits a typechange into a delete block and an add block for the one
path, and GHD's DiffParser threw "Invalid hunk header format" on the
second header, so glitter could neither show nor stage the file.

- git-core parseFileDiff parses each block alone and joins the hunks,
  shifting unifiedDiffStart/End so selection indices stay unique
- stagingDiff and commitDiff flag the result typechange
- glitter shows a typechange diff read-only; it stages whole from its
  file row, since half a file and half a symlink is no stageable state

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Sep 25, 2026 •

Copy link
Copy Markdown

Note

Reviews paused

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Comment @coderabbitai help to get the list of available commands.

@m4ttheweric

Copy link
Copy Markdown
Collaborator Author

@coderabbitai pause

Review of #454:
- a Partial selection left from before a file became a symlink reached
  stageSelection at commit, and git apply wrote a corrupted regular file;
  stageSelection and discardSelection now refuse a typechange, and the
  commit-time rebuild drops such a Partial to None
- the multiline ^ split also matched after a lone \r in a content line
- commitDiff passes -M so a rename never reads as two blocks

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Sep 25, 2026

Copy link
Copy Markdown
✅ Action performed

Reviews paused.

Re-review of #454: dropping the file silently left the commit either
missing it with no word, or failing with a bare "commit failed". The
rebuild now drops the Partial to None and refuses the commit with a
notice naming the file, so a retry commits the rest. The range diff
passes -M too.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@m4ttheweric
m4ttheweric merged commit 48ff2e4 into main Sep 25, 2026
7 checks passed
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.

1 participant