angular/angular-cli · error · CommandModuleError

Repository is not clean. Please commit or stash any changes

Error message

Repository is not clean. Please commit or stash any changes before updating.

What it means

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.

Source

Thrown at packages/angular/cli/src/commands/update/cli.ts:146

      .middleware((argv) => {
        if (argv.name) {
          argv['migrate-only'] = true;
        }

        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        return argv as any;
      })
      .check(({ packages, 'allow-dirty': allowDirty, 'migrate-only': migrateOnly }) => {
        const { logger } = this.context;

        // This allows the user to easily reset any changes from the update.
        if (packages?.length && !checkCleanGit(this.context.root)) {
          if (allowDirty) {
            logger.warn(
              'Repository is not clean. Update changes will be mixed with pre-existing changes.',
            );
          } else {
            throw new CommandModuleError(
              'Repository is not clean. Please commit or stash any changes before updating.',
            );
          }
        }

        if (migrateOnly) {
          if (packages?.length !== 1) {
            throw new CommandModuleError(
              `A single package must be specified when using the 'migrate-only' option.`,
            );
          }
        }

        return true;
      })
      .strict();
  }

View on GitHub (pinned to bb72145f9a)

Solutions

  1. Commit or stash all changes, then rerun `ng update ...`.
  2. Pass --allow-dirty if you intentionally want to mix changes (warned but allowed).
  3. In CI, ensure a clean checkout (no patching of package.json/lockfile before ng update).

Example fix

// before
git status -s  # M package.json
ng update @angular/core
// after
git add -A && git commit -m "wip"
ng update @angular/core
# or: ng update @angular/core --allow-dirty
Defensive patterns

Strategy: validation

Validate before calling

import { execSync } from 'child_process';
const dirty = execSync('git status --porcelain', { cwd: repoRoot }).toString().trim();
if (dirty && !allowDirty) {
  throw new Error('Commit or stash changes before running ng update');
}

Try / catch

try {
  await ngUpdate(packages);
} catch (e) {
  if (String(e.message).includes('Repository is not clean')) {
    execSync('git stash', { cwd: repoRoot });
    await ngUpdate(packages);
    execSync('git stash pop', { cwd: repoRoot });
  } else throw e;
}

Prevention

When it happens

Trigger: Running `ng update <package>` with modified/untracked files in the repository without --allow-dirty; checkCleanGit returns false for the workspace root.

Common situations: Forgetting to commit before updating; CI checkouts with generated files or modified lockfiles; local WIP during dependency upgrades.

Related errors


AI-assisted analysis of angular/angular-cli@bb72145f9a (2026-08-30). Data as JSON: /api/errors/682b6c12f5b26841. Report an issue: GitHub.