abhigyanpatwari/GitNexus · error
Refusing to update ${safeTarget}: local changes detected. Se
Error message
Refusing to update ${safeTarget}: local changes detected. Set overwrite_local_changes: true to overwrite them. What it means
During a pull/update, cloneOrPull runs 'git status --porcelain' in the existing target; if the output is non-empty the working tree has local modifications, and the update is refused rather than silently clobbered. The error tells you to opt in explicitly with overwrite_local_changes: true. It protects uncommitted user work in the clone.
Source
Thrown at gitnexus/src/server/git-clone.ts:393
if (options?.allowedCloneRoot) {
await assertNoSymlinkPath(cloneRoot, path.join(safeTarget, '.git'), true);
}
await assertPostRealpathContainment(cloneRoot, safeTarget);
// Confirm the existing clone is actually the same repository the caller
// requested. Without this check, a pull would silently succeed against
// whatever remote the dir was originally cloned from.
await assertRemoteMatchesRequestedUrl(safeTarget, url, options?.timeoutMs);
onProgress?.({ phase: 'pulling', message: 'Pulling latest changes...' });
const runGitImpl = options?.runGitForTest ?? runGit;
if (options?.branch) {
if (!options.overwriteLocalChanges) {
const status = await runGitImpl(['status', '--porcelain'], safeTarget, {
token: options?.token,
url,
timeoutMs: options?.timeoutMs,
});
if (status.trim()) {
throw new Error(
`Refusing to update ${safeTarget}: local changes detected. Set overwrite_local_changes: true to overwrite them.`,
);
}
}
await runGitImpl(
[
'fetch',
'--depth',
'1',
'origin',
`refs/heads/${options.branch}:refs/remotes/origin/${options.branch}`,
],
safeTarget,
{
token: options?.token,
url,
timeoutMs: options?.timeoutMs,
},View on GitHub (pinned to 0d1aed942f)
Solutions
- Commit or discard the local changes in the target repo, then retry the sync.
- Pass overwrite_local_changes: true in the cloneOrPull options if the changes are disposable.
- Move/stash the changes (git stash) or copy them aside before re-running the sync.
- Clean untracked files (git clean -fd) if they are the trigger and are not needed.
Example fix
// before
await cloneOrPull({ url, targetDir });
// after (changes are intentionally disposable)
await cloneOrPull({ url, targetDir, overwrite_local_changes: true }); Defensive patterns
Strategy: try-catch
Validate before calling
const { stdout } = await exec('git status --porcelain', { cwd: targetDir });
if (stdout.trim()) {
console.warn('target has local changes; commit, stash, or set overwrite_local_changes: true');
}
await cloneOrPull({ url, targetDir, overwrite_local_changes: stdout.trim() ? true : false }); Try / catch
try {
await cloneOrPull(opts);
} catch (err) {
if ((err as Error).message.includes('local changes detected')) {
// surface to operator instead of silently overwriting
throw new Error(`Sync blocked: ${opts.targetDir} has uncommitted work. Resolve or set overwrite_local_changes.`, { cause: err });
}
throw err;
} Prevention
- Never edit auto-synced clones directly; work in separate worktrees.
- Add the clone dir to .gitignore hygiene so generated files do not accumulate as untracked changes.
- Run git status before scheduled syncs and alert instead of force-overwriting.
- Only set overwrite_local_changes: true after confirming the changes are disposable.
When it happens
Trigger: Calling cloneOrPull for a repo whose targetDir already exists as a git repo with uncommitted modifications or untracked files, without overwrite_local_changes: true.
Common situations: A developer edited files inside the auto-synced clone; build artifacts or generated files left untracked in the target; a crashed previous run left partial edits; hotfixes applied directly in the synced checkout.
Understand the failure class
Background: "git command failed": what it means when a tool shells out to git and git exits non-zero — this error's family across 21 libraries.
Related errors
- [group/sync] manifest link ${link.type}:${link.contract} ref
- gitnexus: --self-commit skipping file(s) with uncommitted ch
- Existing clone at ${targetDir} has remote ${stripUrlCredenti
- Branch "${branch}" is not indexed for "${handle.name}". Inde
- must not include query strings or fragments
AI-assisted analysis of abhigyanpatwari/GitNexus@0d1aed942f (2026-09-08).
Data as JSON: /api/errors/f914338c929507e0.
Report an issue: GitHub.