Guide
Why did Claude Code rewrite my whole file?
You asked for one change. The diff shows every line. Usually the content is fine and the damage is invisible: line endings, trailing spaces, a byte order mark. Sometimes the whole file really was replaced. Here is how to tell which, how to get your file back, and how to stop it next time.
Write and Edit are different tools
Claude Code changes files through a small set of built-in tools. Two matter here, and Anthropic's tools reference describes them precisely:
- Edit "performs exact string replacement. It takes an
old_stringand anew_stringand replaces the first with the second." Theold_stringmust match exactly and appear exactly once, unless Claude setsreplace_all. - Write "creates a new file or overwrites an existing one with the full content provided. It doesn't append or merge."
The docs add that "for partial changes to an existing file, Claude uses Edit instead of Write." That is the intended behaviour. In practice a Write to an existing file still happens: after a large refactor, when many scattered edits are easier to express as a new version, or when an Edit fails to match and the model decides to start over. When it does, Claude regenerates the whole file from what it has in context. Anything it did not reproduce byte for byte is now different, whether or not you asked for it.
Markdown files suffer most, because so much of their meaning lives in characters that are easy to regenerate slightly wrong: two trailing spaces that make a hard line break, a table's alignment, a frontmatter block, a long line someone deliberately did not wrap.
The invisible changes
Even a correct, small change can produce a whole-file diff if one of these happened along the way:
- Line endings. A file saved with Windows line endings (CRLF) comes back with Unix ones (LF), or the reverse. Every line differs to Git, but nothing looks different on screen. Files with mixed endings are the most fragile: in our testing for the AsItIs plugin, Claude Code's Edit normalises line breaks and writes them back in one style taken from the start of the file, so a one-word edit to a mixed file rewrites all of them.
- Trailing whitespace. Two spaces at the end of a markdown line are a hard line break. Strip them and the rendered document changes even though the text "looks" the same.
- Byte order mark. An invisible U+FEFF at the start of the file, common in files saved on Windows, added or removed. If the file starts with frontmatter, a BOM can stop some tools reading it.
- Final newline. Dropped or added at the end of the file.
- Encoding. A file with invalid UTF-8 bytes (often a stray Windows-1252 character) has those bytes replaced when any text tool rewrites it.
None of these are bugs in the sense of wrong content. They are the reason a two-word fix turns into a 400-line pull request that nobody can review, and why the real change hides inside the noise.
Find out what actually changed
Before undoing anything, find out whether the change is big or just noisy. Git can tell you:
git diff --stat -- notes.md # how many lines Git thinks changed
git diff --ignore-cr-at-eol -- notes.md # hide CRLF vs LF differences
git diff -w -- notes.md # hide all whitespace differences
git diff --word-diff -- notes.md # show changed words, not lines
file notes.md # "with CRLF line terminators", "with BOM" If git diff --stat says 300 lines and git diff -w shows three, the content change is small and everything else is line endings or whitespace. If git diff -w is still large, the file was really rewritten: compare it carefully, because a regenerated file can drop a paragraph or silently "improve" wording you wanted to keep.
Get your file back
- Throw the change away:
git restore notes.mdreturns the file to its last committed state. - Keep part of it:
git restore -p notes.mdwalks through each hunk and asks which to discard. - Keep the content, restore the line endings: if the file should be CRLF, convert it back (for example with
unix2dos), then checkgit diff --statagain. A.gitattributesentry such as*.md text eol=crlforeol=lfmakes the intended style explicit for the whole team. - Not committed yet? Run
/rewind(or press Esc twice with an empty prompt) and choose Restore code. The checkpointing docs say it tracks changes made by Claude's file editing tools, not files changed by Bash commands. Commit before asking for large changes, so Git has a copy too.
Prevent it
Say it in CLAUDE.md, knowing it is advice. A line such as "Edit markdown with minimal Edit calls; never rewrite a whole .md file; keep line endings, trailing spaces and frontmatter as they are" helps. But the memory docs are clear that Claude treats CLAUDE.md "as context, not enforced configuration."
Enforce it with a hook. The same docs point to the tool for things that must hold: "To block an action regardless of what Claude decides, use a PreToolUse hook." A PreToolUse hook runs "before a tool call executes" and can return a permissionDecision of allow, deny or ask; exit code 2 also blocks the call. A minimal settings entry looks like this:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Write|Edit",
"hooks": [{ "type": "command", "command": "node .claude/hooks/check-markdown.mjs" }]
}
]
}
} Your script receives the tool call as JSON on stdin and decides. Writing one that correctly models what an Edit will do to line endings, BOMs and frontmatter is the fiddly part, which is why we packaged one.
Keep the repository honest. A .gitattributes with explicit eol settings, and an .editorconfig that says whether trailing whitespace is trimmed (and turns it off for *.md), stop editors and agents from disagreeing about what "normal" is. Our guide on why editors change CLAUDE.md covers the editor side.
The AsItIs guard hook
The free AsItIs Claude Code plugin includes an optional PreToolUse hook on Write, Edit and MultiEdit. For an existing markdown file (.md, .mdc, .markdown, .mdx and the extensionless rule files) it warns when the change would:
- convert CRLF to LF or the reverse, flatten mixed line endings, or remove lone CRs;
- strip trailing whitespace;
- add or remove the BOM, or drop the final newline;
- move the frontmatter off line 1, remove its closing
---, drop keys or indent it with tabs; - rewrite more than 30% of a file of more than 20 lines;
- touch a file with invalid UTF-8 bytes.
Its guard_mode option is ask by default (you see the warning and allow or reject), deny (the change is blocked and Claude is told to retry with a minimal edit) or off. It never changes the tool call itself.
Be clear about what it is: an accident guard, not a security boundary. It does not see Bash (sed -i, redirects, scripts), other tools or other programs, and anything running as you can bypass it. The plugin also ships a skill that teaches Claude to edit minimal ranges in markdown, so the guard rarely has to step in.
Check your file
Before you hand a markdown file to an agent, the steering file checker shows its line endings, BOM, final newline, invalid bytes and frontmatter, the things a rewrite tends to change. It runs in your browser; nothing is uploaded.
Open the steering file checker
To check every steering file in a project from inside Claude Code, including links, @imports and what loads every session, install the free AsItIs plugin. It is read-only and makes no network calls.
claude plugin marketplace add Katta041/asitis-agent-tools
claude plugin install asitis@asitis About the pluginSource on GitHub
MIT licensed. A star on GitHub helps other people find it.
Sources, read on 6 October 2026: Claude Code docs, Tools reference (Edit and Write tool behaviour), Hooks and How Claude remembers your project. Quotes are exact. The guard's checks are listed in the plugin README.