{"record":{"id":"a98d77a995db9595","repo":"nikivdev/code","slug":"git-config-global-unset-failed","errorCode":null,"errorMessage":"git config --global --unset {} failed","messagePattern":"git config --global --unset (.+?) failed","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/push_hook.rs","lineNumber":205,"sourceCode":"\nfn git_config_global_set(key: &str, value: &Path) -> Result<()> {\n    let status = Command::new(\"git\")\n        .args([\"config\", \"--global\", key, &value.to_string_lossy()])\n        .status()\n        .with_context(|| format!(\"failed to set git config {key}\"))?;\n    if !status.success() {\n        bail!(\"git config --global {} failed\", key);\n    }\n    Ok(())\n}\n\nfn git_config_global_unset(key: &str) -> Result<()> {\n    let status = Command::new(\"git\")\n        .args([\"config\", \"--global\", \"--unset\", key])\n        .status()\n        .with_context(|| format!(\"failed to unset git config {key}\"))?;\n    if !status.success() {\n        bail!(\"git config --global --unset {} failed\", key);\n    }\n    Ok(())\n}\n\nfn resolve_repo_root() -> Result<PathBuf> {\n    let output = Command::new(\"git\")\n        .args([\"rev-parse\", \"--show-toplevel\"])\n        .output()\n        .context(\"failed to resolve git repo root\")?;\n    if output.status.success() {\n        let value = String::from_utf8_lossy(&output.stdout).trim().to_string();\n        if !value.is_empty() {\n            return Ok(PathBuf::from(value));\n        }\n    }\n\n    env::current_dir().context(\"failed to resolve current directory\")\n}","sourceCodeStart":187,"sourceCodeEnd":223,"githubUrl":"https://github.com/nikivdev/code/blob/a747e741ae92c09071d0ae946ab48488adcff1ce/src/push_hook.rs#L187-L223","documentation":"`git_config_global_unset` runs `git config --global --unset core.hooksPath` and bails when git exits non-zero. The most common non-zero case is git's exit code 5: the key is not set, so there is nothing to unset.","triggerScenarios":"Calling `uninstall_hooks` when the config pointed at by current_hooks_path matches but `git config --global --unset core.hooksPath` fails — typically because the key was already removed (race or a second uninstall run), or the global config is unwritable/corrupt.","commonSituations":"Running uninstall twice in a row or in parallel; uninstalling from a second shell after hooksPath was manually unset; CI cleanup steps running concurrently; read-only HOME during teardown.","solutions":["Check `git config --global --get core.hooksPath`; if unset, the goal is already achieved and the error can be ignored","Verify ~/.gitconfig is writable (`ls -l ~/.gitconfig`) and fix permissions","Wrap the uninstall call to tolerate git exit code 5 (key not present)","Avoid running uninstall concurrently; serialize cleanup steps in CI"],"exampleFix":"// before: unconditional cleanup step fails on second run\n- run: f push hooks uninstall\n// after: tolerate already-unset\n- run: f push hooks uninstall || git config --global --get core.hooksPath | grep -q . && exit 1 || exit 0","handlingStrategy":"try-catch","validationCode":"// preflight: check whether the key is set before unsetting\nlet out = std::process::Command::new(\"git\")\n    .args([\"config\", \"--global\", \"--get\", \"core.hooksPath\"])\n    .output()?;\nlet is_set = out.status.success() && !out.stdout.is_empty();\nif !is_set { eprintln!(\"core.hooksPath already unset; skipping uninstall\"); }","typeGuard":null,"tryCatchPattern":"match uninstall_hooks() {\n    Ok(()) => {},\n    Err(e) if e.to_string().contains(\"--unset\") => {\n        // often just 'key not set' (git exit code 5) — treat as already-clean\n        eprintln!(\"unset failed (possibly already unset): {e}\");\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Make uninstall idempotent: check --get before --unset","Don't run uninstall concurrently from multiple CI jobs","Ignore git exit code 5 (key absent) as a success condition in wrappers","Verify config file permissions in teardown scripts"],"tags":["git","config","subprocess","idempotency"],"backgroundTag":"git-config-unset-failed","analyzedSha":"a747e741ae92c09071d0ae946ab48488adcff1ce","analyzedAt":"2026-09-01T22:43:55.719Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}