{"record":{"id":"26f0758ec36a9b8d","repo":"jdx/mise","slug":"save-before-choosing-keep-local","errorCode":null,"errorMessage":"save {} before choosing --keep-local","messagePattern":"save (.+?) before choosing --keep-local","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/history/sync/apply.rs","lineNumber":161,"sourceCode":"        else {\n            continue;\n        };\n        if take_remote.contains(&local) || keep_local.contains(&local) {\n            if take_remote.contains(&local) && keep_local.contains(&local) {\n                bail!(\"choose only one resolution for {}\", display_path(&local));\n            }\n            let live = live_object(repo, &local)?;\n            let saved = shared.get(&conflict.branch_path).cloned();\n            let saved_mode = permissions_at(\n                repo,\n                planned_head.as_deref(),\n                &conflict.branch_path,\n                saved.as_ref(),\n            )?;\n            if keep_local.contains(&local)\n                && (live != saved || live_permissions(&local)? != saved_mode)\n            {\n                bail!(\"save {} before choosing --keep-local\", display_path(&local));\n            }\n            let remote = match status.upstream_commit.as_deref() {\n                Some(head) => repo\n                    .object_at(head, &conflict.branch_path)?\n                    .map(|object| {\n                        if !encrypted.contains(&conflict.branch_path) {\n                            return Ok(object);\n                        }\n                        super::files::decrypt(\n                            repo,\n                            &conflict.branch_path,\n                            &object,\n                            !req.automatic && console::user_attended_stderr(),\n                        )\n                    })\n                    .transpose()?,\n                None => None,\n            };","sourceCodeStart":143,"sourceCodeEnd":179,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/system/history/sync/apply.rs#L143-L179","documentation":"Resolving a conflict with --keep-local publishes the currently live file content as the resolution, so the on-disk file must exactly match the version that was last saved into the shared history store. If the live object or its permissions differ from the saved copy, mise refuses to silently pick up unsaved edits and asks you to save (re-sync) the file first. Nothing is written when this error fires.","triggerScenarios":"Running `mise bootstrap dotfiles pull --keep-local <path>` while the live file content or permissions differ from `shared.get(branch_path)` (the object recorded in the shared history store), i.e. the file was edited after the last successful sync/save.","commonSituations":"Editing a dotfile in an editor and immediately trying to resolve the conflict without saving it into the history; permission bits changed via chmod after enrollment; a previous pull/push failed midway leaving the saved copy stale; another tool rewrote the file between syncs.","solutions":["Save the current file into the sync store first (run a save/push sync step, or the save command of the history system), then re-run pull with --keep-local.","If the local edits should be discarded, resolve with --take-remote for this path instead of --keep-local.","Compare live vs saved state with a dry-run pull to see which paths are affected, restore expected permissions (chmod) if only the mode differs, then retry."],"exampleFix":"# before (file edited after last save)\nmise bootstrap dotfiles pull --keep-local ~/.zshrc\n# after: save the current state first, then resolve\nmise bootstrap dotfiles push ~/.zshrc\nmise bootstrap dotfiles pull --keep-local ~/.zshrc","handlingStrategy":"validation","validationCode":"# shell: ensure no unsaved drift before --keep-local\nmise bootstrap dotfiles pull --dry-run || true\n# compare live file with last saved state, e.g. via the status output, then save first\nmise bootstrap dotfiles push\nmise bootstrap dotfiles pull --keep-local \"$path\"","typeGuard":null,"tryCatchPattern":"try {\n  await pull({ keepLocal: [path] });\n} catch (e) {\n  if (/save .* before choosing --keep-local/.test(e.message)) {\n    await push();            // save live state into the sync store\n    await pull({ keepLocal: [path] });\n  } else throw e;\n}","preventionTips":["Always run a save/push after editing a tracked dotfile and before resolving conflicts.","Avoid chmod-ing tracked files without re-syncing.","Use --dry-run to detect live-vs-saved drift before choosing keep-local."],"tags":["sync","conflict-resolution","state-mismatch","dotfiles"],"backgroundTag":"invalid-state-transition","analyzedSha":"afd2eddd3a50c16190efc1c7e94404b48f72af57","analyzedAt":"2026-09-09T01:38:25.179Z","contentChangedAt":"2026-09-09T01:38:25.179Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}