{"record":{"id":"bcf2451dda7c802b","repo":"xai-org/grok-build","slug":"working-tree-is-not-clean-commit-or-discard-chang","errorCode":null,"errorMessage":"working tree is not clean; commit or discard changes before syncing the base","messagePattern":"working tree is not clean; commit or discard changes before syncing the base","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/codegen/xai-grok-workspace/src/session/git.rs","lineNumber":3041,"sourceCode":"        )\n    }\n    if abort {\n        let (_ok, out) = git_cli_raw_mut(git_root, &[\"merge\", \"--abort\"]).await?;\n        anyhow::ensure!(\n            !merge_in_progress(git_root).await?,\n            \"merge --abort failed: {out}\"\n        );\n        return Ok(GitSyncBaseResult {\n            outcome: GitSyncBaseOutcome::Aborted,\n        });\n    }\n    ensure_on_branch(git_root, expected_branch).await?;\n    anyhow::ensure!(\n        !merge_in_progress(git_root).await?,\n        \"a merge is already in progress; resolve it or call again with abort\"\n    );\n    let dirty = git_cli(git_root, &[\"status\", \"--porcelain\"]).await?;\n    anyhow::ensure!(\n        dirty.is_empty(),\n        \"working tree is not clean; commit or discard changes before syncing the base\"\n    );\n    let base = base_ref.unwrap_or(\"HEAD\");\n    let (fetched, fetch_out) = git_cli_raw_mut(git_root, &[\"fetch\", \"origin\", base]).await?;\n    anyhow::ensure!(fetched, \"fetch of base ref '{base}' failed: {fetch_out}\");\n    if git_cli_raw(\n        git_root,\n        &[\"merge-base\", \"--is-ancestor\", \"FETCH_HEAD\", \"HEAD\"],\n    )\n    .await?\n    .0\n    {\n        return Ok(GitSyncBaseResult {\n            outcome: GitSyncBaseOutcome::UpToDate,\n        });\n    }\n    let (merged, merge_out) =","sourceCodeStart":3023,"sourceCodeEnd":3059,"githubUrl":"https://github.com/xai-org/grok-build/blob/bc7f02eddd3d84085849dc19ed216f11c23b0571/crates/codegen/xai-grok-workspace/src/session/git.rs#L3023-L3059","documentation":"Sync-base checks `git status --porcelain` and refuses to run when the working tree is dirty, because merging a new base on top of uncommitted changes risks conflicts and data loss. This guard runs after the branch and merge-state checks.","triggerScenarios":"Calling sync-base with uncommitted modifications, staged changes, or untracked files present in the workspace.","commonSituations":"Agent edited files without committing before asking to rebase/sync onto the base branch; build artifacts or temp files left in the tree; a previous tool run left partial edits.","solutions":["Commit the changes (`git add -A && git commit`) then retry sync-base","Discard unneeded changes with `git checkout -- .` / `git clean -fd` if they are disposable","Stash with `git stash -u`, run sync-base, then `git stash pop`","Check `git status --porcelain` before invoking to confirm cleanliness"],"exampleFix":"// before\nsync_base(&git_root, req) // dirty tree\n// after\ngit_cli(&git_root, &[\"add\", \"-A\"]).await?;\ngit_cli(&git_root, &[\"commit\", \"-m\", \"wip\"]).await?;\nsync_base(&git_root, req)","handlingStrategy":"validation","validationCode":"let out = Command::new(\"git\").args([\"status\",\"--porcelain\"]).current_dir(git_root).output()?;\nif !out.stdout.is_empty() {\n    return Err(\"working tree dirty; commit, stash, or discard before sync\".into());\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Commit or stash edits before invoking sync-base","Add .gitignore entries for generated artifacts so they don't dirty the tree","Run `git status --porcelain` as a pre-flight in automation"],"tags":["git","dirty-working-tree","precondition"],"backgroundTag":"dirty-working-tree","analyzedSha":"bc7f02eddd3d84085849dc19ed216f11c23b0571","analyzedAt":"2026-08-31T04:59:42.031Z","schemaVersion":2},"datasetVersion":"2026-08-31T09:17:48.483Z"}