Plugin marketplace auto-update rewrites .git/config of the user's current working directory

Resolved 💬 1 comment Opened Jun 4, 2026 by jjnssko-wordpress Closed Jul 9, 2026

Plugin marketplace sync corrupts .git/config of the user's current working repo

Summary

When multiple plugin marketplaces are configured, Claude Code's marketplace auto-update appears to run git operations using the wrong working repository. As a result:

  1. remote.origin.url of the user's current working directory (a completely unrelated git repo) gets repeatedly rewritten to point at Claude marketplace repositories.
  2. Duplicate fetch = +refs/heads/master:refs/remotes/origin/master lines accumulate in [remote "origin"] of the same .git/config on every cycle.
  3. Duplicate active = . lines accumulate under [submodule] on every cycle.
  4. The marketplace install directories themselves (~/.claude/plugins/marketplaces/<name>/.git/config) all end up with the same wrong URL — every git-based marketplace I have points its origin at jetbrains/phpstorm-claude-marketplace.git, regardless of which marketplace the directory actually contains.

Net effect: I can no longer git push / git fetch against my actual project remote until I manually rewrite .git/config, and the corruption returns periodically while Claude Code is running.

Environment

  • Claude Code: 2.1.152
  • macOS: 26.5 (Darwin 25.5.0, arm64)
  • git: 2.53.0
  • Shell: zsh

Marketplaces configured

~/.claude/plugins/known_marketplaces.json:

{
  "claude-plugins-official": { "source": { "source": "github", "repo": "anthropics/claude-plugins-official" }, ... },
  "dev-marketplace":         { "source": { "source": "git", "url": "git@gitlab-shipmonk:shipmonk-company/platform/claude-marketplace-dev.git" }, "autoUpdate": true, ... },
  "phpstorm-marketplace":    { "source": { "source": "github", "repo": "jetbrains/phpstorm-claude-marketplace" }, "autoUpdate": true, ... },
  "shipmonk-corporate":      { "source": { "source": "git", "url": "git@github.com:shipmonk-rnd/claude-marketplace-corporate.git" }, "autoUpdate": true, ... }
}

Observed corruption — symptom A: cross-contaminated marketplace .git/config

After Claude Code has been running for a while:

$ for d in ~/.claude/plugins/marketplaces/*/; do
    echo "=== $d ==="
    echo "URL: $(git -C "$d" config --get remote.origin.url 2>/dev/null)"
  done

=== .../claude-plugins-official/ ===    URL:                                                      # no .git, uses GitHub API
=== .../dev-marketplace/ ===            URL: git@github.com:jetbrains/phpstorm-claude-marketplace.git   # ❌ wrong
=== .../phpstorm-marketplace/ ===       URL: git@github.com:jetbrains/phpstorm-claude-marketplace.git   # ✓
=== .../shipmonk-corporate/ ===         URL: git@github.com:jetbrains/phpstorm-claude-marketplace.git   # ❌ wrong

Two of the three git-based marketplace install directories have their remote.origin.url overwritten to point at a different marketplace's repo. They all "win" with whichever marketplace was synced last.

Observed corruption — symptom B: the user's CWD .git/config is also rewritten

I set up an fswatch on my project's .git/config (~/shipmonk/monorepo/.git/config) — an unrelated repo with no Claude marketplace anywhere near it. Captured diffs show the URL flipping between three values over the course of a Claude Code session:

- url = git@gitlab-shipmonk:shipmonk-company/shipmonk-fulfillment/shipmonk.git
+ url = git@gitlab-shipmonk:shipmonk-company/platform/claude-marketplace-dev.git
- url = git@gitlab-shipmonk:shipmonk-company/platform/claude-marketplace-dev.git
+ url = git@github.com:shipmonk-rnd/claude-marketplace-corporate.git

In the same window, an extra active = . keeps getting appended under [submodule] on every cycle:

 [submodule]
 	active = .
+	active = .

And on a related variant of the bug, a duplicate fetch refspec accumulates in [remote "origin"]:

[remote "origin"]
	url = ...
	fetch = +refs/heads/*:refs/remotes/origin/*
	fetch = +refs/heads/master:refs/remotes/origin/master     # appended over and over
	fetch = +refs/heads/master:refs/remotes/origin/master
	fetch = +refs/heads/master:refs/remotes/origin/master
	... (14× total observed)

Process snapshot taken at the moment fswatch fired

git -c credential.helper= -c core.quotepath=false -c log.showSignature=false ls-remote --heads origin master <my-feature-branches...>
  parent: git remote-https origin https://github.com/anthropics/claude-plugins-official.git

git pull origin HEAD
  parent: claude --dangerously-skip-permissions
  effective ssh: git@github.com:jetbrains/phpstorm-claude-marketplace.git

So Claude Code is invoking git ls-remote / git fetch / git pull against marketplace URLs but with the user's branch names (master, jv-...) — strongly suggesting it's running these commands inside the user's CWD .git, not the marketplace install directory.

Reproduction

  1. Have multiple plugin marketplaces registered with autoUpdate: true — at least one github-source and at least two distinct git-source URLs.
  2. Run claude from inside an unrelated git repository (any project repo).
  3. Leave Claude Code running and check git config --get remote.origin.url periodically.
  4. Within minutes, the URL gets swapped to one of the marketplace URLs, fetch refspecs duplicate, and [submodule] active = . accumulates.

Expected behavior

  • Marketplace sync should git-operate inside each marketplace's own install directory (~/.claude/plugins/marketplaces/<name>), never touching the user's CWD .git.
  • Each marketplace install dir's remote.origin.url should reflect that marketplace's configured source.url, not whichever marketplace was synced last.
  • Repeated syncs must be idempotent — no accumulation of duplicate fetch refspecs or [submodule] active = ..

Suspected root cause

Looks like the sync logic might be doing something like:

git remote set-url origin <marketplace-url>
git fetch

without -C <marketplace-dir> (or with cwd not switched), so the operation runs in whatever process.cwd() happens to be — i.e. the user's project. Additionally the URL is set-url'd into a shared variable / shared .git and not reset between marketplaces, which is why all three install dirs end up with the same URL.

Workaround

A shell function to undo the damage:

git-fix-fetch() {
    local expected="<correct-origin-url>"
    local wildcard="+refs/heads/*:refs/remotes/origin/*"

    local current
    current=$(git config --get remote.origin.url)
    if [ "$current" != "$expected" ]; then
        git remote set-url origin "$expected"
    fi

    # Reset ALL fetch refspecs and re-add only the wildcard
    git config --unset-all remote.origin.fetch 2>/dev/null
    git config --add remote.origin.fetch "$wildcard"

    git fetch origin
}

This needs to be re-run every time the corruption returns, which is roughly every plugin auto-update cycle.

Logs

Happy to share full fswatch log and snapshots privately if helpful.

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗