Skip to content

fix(git): show non-ASCII paths unescaped in git_status and git_diff* - #4879

Open
tsurutanmen wants to merge 1 commit into
modelcontextprotocol:mainfrom
tsurutanmen:fix/git-quotepath-non-ascii
Open

tsurutanmen wants to merge 1 commit into
modelcontextprotocol:mainfrom
tsurutanmen:fix/git-quotepath-non-ascii

Conversation

@tsurutanmen

Copy link
Copy Markdown

Description

git_status, git_diff_unstaged, git_diff_staged and git_diff return non-ASCII file names as quoted octal escapes, because git's default core.quotepath=true applies to their output. A file named 日本語.txt shows up as:

Untracked files:
	"\346\227\245\346\234\254\350\252\236.txt"

and in diffs as diff --git "a/\346\227\245\346\234\254\350\252\236.txt" .... An LLM client cannot map that back to the real file, so any follow-up call such as git_add with the escaped name fails. This PR runs these four commands with -c core.quotepath=false, so the same file shows up as 日本語.txt.

git_show is unchanged. It builds its output from GitPython's Diff objects, which already decode the paths.

Server Details

  • Server: git
  • Changes to: tools (git_status, git_diff_unstaged, git_diff_staged, git_diff)

Motivation and Context

This affects any repository with non-ASCII file names: Japanese, Chinese, Korean, accented Latin, emoji, and so on. The setting only changes how git prints paths. It does not touch repository config, and it does not change output for ASCII paths.

How Has This Been Tested?

  • Added 4 tests, one per tool, with a non-ASCII file name. They set core.quotepath=true in the test repository, so the result does not depend on the user's global config. All 4 fail without the fix and pass with it.
  • Full suite: 51 passed. pyright and ruff check are clean.
  • With an LLM client: I ran the server under claude -p (Claude Code) against a repository containing an untracked 日本語.txt and had the model call git_status. Before the fix, the output contained "\346\227\245\346\234\254\350\252\236.txt". After the fix, it contained 日本語.txt.

Tested on Windows 11 with git for Windows and Python 3.11. On Windows, the existing test_repository fixture teardown raises PermissionError from shutil.rmtree while GitPython still holds handles. This happens before and after this change and is unrelated to it. CI on Linux is not affected.

Breaking Changes

None. ASCII output is identical. Clients that were parsing the escaped form will now receive the real UTF-8 path.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Protocol Documentation
  • My changes follows MCP security best practices
  • I have updated the server's README accordingly
  • I have tested this with an LLM client
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have documented all environment variables and configuration options

Additional context

-c core.quotepath=false is passed per command through GitPython (repo.git(c=...)), so it applies only to that single invocation.

🤖 Generated with Claude Code

git's default core.quotepath=true makes `git status` and `git diff`
print non-ASCII paths as quoted octal escapes, e.g.
"\346\227\245\346\234\254\350\252\236.txt" for 日本語.txt. Clients
cannot map these back to the real file, so pass
`-c core.quotepath=false` for git_status, git_diff_unstaged,
git_diff_staged and git_diff. git_show already reports decoded paths
through GitPython's Diff objects and is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
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