Claude Code Says Edit Succeeded but Git Diff Is Empty?

Claude Code Says Edit Succeeded but Git Diff Is Empty?

Aident AI

A translucent cyan sheet hovers above a cobalt slab beside a coral fold and chartreuse stone on indigo.

Claude Code Says Edit Succeeded but Git Diff Is Empty?

If Claude Code says a file was updated but git diff is empty, do not commit, push, or ask the same session to repeat the edit. First compare the real working-tree file with HEAD from the shell. A fresh Anthropic issue reports a narrower and more dangerous variant: the Edit tool returned success and its own Read tool showed the new text, while grep, git diff, stat, Node, and Python all saw the original file on disk.

The report involved a Git worktree and a PreToolUse hook for Edit|Write|MultiEdit. It does not establish a universal root cause. Similar no-write reports have appeared after context compaction and after a subagent changed worktrees, so diagnose the exact boundary before changing hooks or files.

Stop Before an Empty Commit

Pause the affected Claude Code session and any other agent that can write to the same worktree. Preserve the current state:

git status --short --branch
git diff --name-status
git diff --stat

Do not run git reset --hard, git restore ., git checkout -- ., or a broad git add .. Those commands do not recover the missing edit, and they can discard unrelated work that actually reached disk.

Choose one file Claude said it changed. Quote the path and run the checks from an ordinary shell in the affected worktree:

File='path/to/affected-file.ts'

git status --short -- "$File"
git diff --no-ext-diff -- "$File"
git hash-object -- "$File"
git rev-parse "HEAD:$File"
wc -c < "$File"

The two hashes will differ when the working file's bytes differ from the blob in HEAD. Matching hashes mean the tracked file is byte-for-byte unchanged, even if the Edit result and a later in-session Read displayed different text.

If the intended change adds a distinctive nonsecret string, verify it through the shell too:

rg -n --fixed-strings 'expected marker' "$File"

Do not use a password, token, customer record, or proprietary string as the marker. An absent marker plus matching Git object hashes is strong evidence that the edit did not land.

Distinguish a Phantom Edit From a Normal No-op

An empty diff has several possible explanations:

Observation

Likely interpretation

Next check

Working hash equals HEAD, marker absent

The intended edit is not on disk

Stop the session and preserve the transcript

Working hash differs from HEAD

A real change exists

Inspect the exact diff and tests

Marker already exists in HEAD

The requested edit may have been a no-op

Compare the prompt with the committed file

File is untracked

git diff alone will omit it

Use git status --short and inspect the file

A different worktree contains the change

The write landed elsewhere

Compare absolute paths and git worktree list

The last row matters in agent workflows. Run:

pwd -P
git rev-parse --show-toplevel
git worktree list --porcelain

Compare the absolute worktree root with the path shown in Claude Code. Do not copy or delete anything until you know whether another worktree contains a real edit. For preventive isolation, see how to run parallel Claude Code agents in separate Git worktrees.

Treat Claude's Readback as Correlated Evidence

In issue 85700, Edit reported success and Read showed the edited content, but every independent filesystem observer saw the original file. That means an Edit-plus-Read sequence is not an independent verification for this failure mode.

Use at least one observer outside the affected tool path:

  • git diff --no-ext-diff -- <file> for the working-tree delta;

  • git hash-object -- <file> versus git rev-parse HEAD:<file> for exact bytes;

  • rg or another shell reader for one expected marker;

  • the repository's tests, typecheck, or formatter after the real diff exists.

Git documents git diff as a comparison between the working tree, index, and commits. Its --exit-code mode returns 1 when differences exist and 0 when none exist. If you automate a guard, handle that contract deliberately rather than treating every nonzero result as a tool crash.

Preserve the Hook Instead of Bypassing It

The current report reproduced the phantom write when a pre-existing tracked file reached the full evaluation path of a PreToolUse hook. New files and exempt paths behaved differently. That is useful isolation evidence, not proof that the hook itself is wrong.

Do not disable a safety hook across the repository just to make the symptom disappear. Instead, record a redacted copy of:

  • Claude Code version and operating system;

  • worktree root and target path shape without personal directories;

  • hook event and matcher;

  • whether the target used an early-exit or full-evaluation branch;

  • hook exit code;

  • Edit result, shell hash comparison, and git diff result;

  • whether a brand-new disposable file behaves differently.

Test hook changes only in a disposable repository with nonsecret content. If the hook makes an authorization decision, preserve that decision while investigating the write path.

Recover the Intended Change in a Clean Worktree

Leave the affected worktree intact. Create a clean recovery worktree from the same commit:

git worktree add ../repo-edit-recovery -b edit-recovery HEAD

Review the intended diff from the conversation before carrying it over. Apply the smallest change with your trusted editor, or review a patch outside the repository and validate it before applying:

git apply --check /path/to/reviewed.patch
git apply /path/to/reviewed.patch
git diff --check
git diff --stat
git diff --no-ext-diff

The recovery worktree begins at HEAD; it will not include unrelated uncommitted edits from the affected worktree. Move each reviewed change deliberately. Run the repository's normal tests and inspect the final diff before committing.

If Claude Code reports success but the new worktree still has no shell-visible change, stop retrying. Update only through the supported Claude Code release path, retain the evidence, and add it to the matching upstream issue. Do not edit Claude's session files or internal caches to force the write.

Add a Filesystem Gate to Agent Work

For future coding-agent tasks, require this sequence before any commit:

git status --short
git diff --check
git diff --stat
git diff --no-ext-diff

Then run the exact tests for the edited code and verify that every intended file appears in the diff. A tool's success message is evidence of intent; the repository diff is evidence of state.

For broader safeguards, see how to stop Claude Code subagents from sharing a worktree and how to prevent a coding agent from deleting files.

Verify the Pushed PR With Aident Loadout

Local verification must happen before the push. After you push, Aident Loadout can add a second read-only check against GitHub.

Start with:

Follow https://aident.ai/SETUP.md

Then ask:

Check Aident Loadout authentication and Vault status. Discover the current GitHub Action that lists files in one pull request, inspect its schema, and preflight it for my repository and PR number. Execute only the read Action. Return the filenames, statuses, additions, and deletions, and confirm whether the intended file is present. Do not comment, review, merge, label, close, or modify the pull request.

This cannot prove what happened inside the original local session, but it can catch an empty or partial pushed PR before review.

Set up Aident Loadout for the read-only PR check.

Sources

Refresh this guide when issue 85700 changes state, Anthropic documents a write-verification fix, or Claude Code changes its worktree, Edit, Read, or PreToolUse contracts.

Home

Home

Home

Integrations

Integrations

Integrations

Vault

Vault

Vault

Audit

Audit

Audit

Arana Grande

Arana Grande

Arana Grande

Free

Free

Free

30-day audit summary

30-day audit summary

30-day audit summary

Daily action-call volume and the latest receipts from the Loadout audit trail.

Daily action-call volume and the latest receipts from the Loadout audit trail.

Daily action-call volume and the latest receipts from the Loadout audit trail.

View Audit

View Audit

View Audit

Loadout usage

Loadout usage

Loadout usage

617 action calls in the last 30 days

617 action calls in the last 30 days

617 action calls in the last 30 days

May 19 - Jun 17

May 19 - Jun 17

May 19 - Jun 17

10 active days

10 active days

10 active days

Less

Less

Less

More

More

More

Recent activity

Recent activity

Recent activity

Latest action-call receipts from connected agents

Latest action-call receipts from connected agents

Latest action-call receipts from connected agents

Apr 23, 09:23 AM

Apr 23, 09:23 AM

Apr 23, 09:23 AM

Shopify

Shopify

Shopify

Creates Or Updates An Asset For A Theme

Creates Or Updates An Asset For A Theme

Creates Or Updates An Asset For A Theme

Success

Success

Success

Apr 23, 09:21 AM

Apr 23, 09:21 AM

Apr 23, 09:21 AM

Shopify

Shopify

Shopify

Update Products Param Product Id

Update Products Param Product Id

Update Products Param Product Id

Success

Success

Success

Apr 23, 08:53 AM

Apr 23, 08:53 AM

Apr 23, 08:53 AM

Shopify

Shopify

Shopify

Update Products Param Product Id

Update Products Param Product Id

Update Products Param Product Id

Failed

Failed

Failed

Apr 22, 22:13 PM

Apr 22, 22:13 PM

Apr 22, 22:13 PM

Shopify

Shopify

Shopify

Create Product Image

Create Product Image

Create Product Image

Success

Success

Success

Apr 22, 22:12 PM

Apr 22, 22:12 PM

Apr 22, 22:12 PM

Shopify

Shopify

Shopify

Create Product Image

Create Product Image

Create Product Image

Success

Success

Success

Connected integration coverage

Connected integration coverage

Connected integration coverage

162

162

162

of 753 accessible connected

of 753 accessible connected

of 753 accessible connected

Callable actions

Callable actions

Callable actions

1,126

1,126

1,126

Vault credentials

Vault credentials

Vault credentials

8

8

8

Explore what's possible

Explore what's possible

Explore what's possible

See all Integrations

See all Integrations

See all Integrations

Google Ads

Google Ads

Google Ads

All available Goolge Ads tools via...

All available Goolge Ads tools via...

All available Goolge Ads tools via...

X (twitter)

X (twitter)

X (twitter)

All available X tools via...

All available X tools via...

All available X tools via...

Github

Github

Github

All available Github tools via...

All available Github tools via...

All available Github tools via...

Notion

Notion

Notion

All available Notion tools via...

All available Notion tools via...

All available Notion tools via...

Slack

Slack

Slack

All available Slack tools via...

All available Slack tools via...

All available Slack tools via...

Firecrawl

Firecrawl

Firecrawl

All available Firecrawl tools via...

All available Firecrawl tools via...

All available Firecrawl tools via...

753 integrations are available for loadouts.

753 integrations are available for loadouts.

753 integrations are available for loadouts.

The one tool

for every tool

your agent needs.

Give any AI agent real capabilities in seconds. Connect 1,000+ tools once, skip the setup headache, and let your agents execute.

Try Aident Loadout

Give your Agent real capabilities in minutes. Connect 1,000+ tools, and let your agents execute.

Try Aident Loadout

Give your Agent real capabilities in minutes. Connect 1,000+ tools, and let your agents execute.

Try Aident Loadout

Give your Agent real capabilities in minutes. Connect 1,000+ tools, and let your agents execute.