{"record":{"id":"682b6c12f5b26841","repo":"angular/angular-cli","slug":"repository-is-not-clean-please-commit-or-stash-an","errorCode":null,"errorMessage":"Repository is not clean. Please commit or stash any changes before updating.","messagePattern":"Repository is not clean\\. Please commit or stash any changes before updating\\.","errorType":"validation","errorClass":"CommandModuleError","httpStatus":null,"severity":"error","filePath":"packages/angular/cli/src/commands/update/cli.ts","lineNumber":146,"sourceCode":"      .middleware((argv) => {\n        if (argv.name) {\n          argv['migrate-only'] = true;\n        }\n\n        // eslint-disable-next-line @typescript-eslint/no-explicit-any\n        return argv as any;\n      })\n      .check(({ packages, 'allow-dirty': allowDirty, 'migrate-only': migrateOnly }) => {\n        const { logger } = this.context;\n\n        // This allows the user to easily reset any changes from the update.\n        if (packages?.length && !checkCleanGit(this.context.root)) {\n          if (allowDirty) {\n            logger.warn(\n              'Repository is not clean. Update changes will be mixed with pre-existing changes.',\n            );\n          } else {\n            throw new CommandModuleError(\n              'Repository is not clean. Please commit or stash any changes before updating.',\n            );\n          }\n        }\n\n        if (migrateOnly) {\n          if (packages?.length !== 1) {\n            throw new CommandModuleError(\n              `A single package must be specified when using the 'migrate-only' option.`,\n            );\n          }\n        }\n\n        return true;\n      })\n      .strict();\n  }\n","sourceCodeStart":128,"sourceCodeEnd":164,"githubUrl":"https://github.com/angular/angular-cli/blob/bb72145f9ab45aee29f523236b3a25cd0813a841/packages/angular/cli/src/commands/update/cli.ts#L128-L164","documentation":"Before updating packages, the update command checks git cleanliness with checkCleanGit(context.root). If there are packages to install and the working tree is dirty, and --allow-dirty was not passed, it aborts with a CommandModuleError so update/migration changes won't mix with uncommitted work.","triggerScenarios":"Running `ng update <package>` with modified/untracked files in the repository without --allow-dirty; checkCleanGit returns false for the workspace root.","commonSituations":"Forgetting to commit before updating; CI checkouts with generated files or modified lockfiles; local WIP during dependency upgrades.","solutions":["Commit or stash all changes, then rerun `ng update ...`.","Pass --allow-dirty if you intentionally want to mix changes (warned but allowed).","In CI, ensure a clean checkout (no patching of package.json/lockfile before ng update)."],"exampleFix":"// before\ngit status -s  # M package.json\nng update @angular/core\n// after\ngit add -A && git commit -m \"wip\"\nng update @angular/core\n# or: ng update @angular/core --allow-dirty","handlingStrategy":"validation","validationCode":"import { execSync } from 'child_process';\nconst dirty = execSync('git status --porcelain', { cwd: repoRoot }).toString().trim();\nif (dirty && !allowDirty) {\n  throw new Error('Commit or stash changes before running ng update');\n}","typeGuard":null,"tryCatchPattern":"try {\n  await ngUpdate(packages);\n} catch (e) {\n  if (String(e.message).includes('Repository is not clean')) {\n    execSync('git stash', { cwd: repoRoot });\n    await ngUpdate(packages);\n    execSync('git stash pop', { cwd: repoRoot });\n  } else throw e;\n}","preventionTips":["Make `git status --porcelain` a preflight step in update scripts.","Commit or stash WIP before dependency upgrades.","Use --allow-dirty only in disposable CI environments."],"tags":["angular","cli","git","update","precondition"],"backgroundTag":"dirty-working-tree","analyzedSha":"bb72145f9ab45aee29f523236b3a25cd0813a841","analyzedAt":"2026-08-30T02:47:34.745Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}