{"record":{"id":"8907e75a32f8a7b4","repo":"jdx/mise","slug":"existing-file-conflicts-with-adoption-entry","errorCode":null,"errorMessage":"existing file conflicts with adoption: {entry}","messagePattern":"existing file conflicts with adoption: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/remote_repository.rs","lineNumber":338,"sourceCode":"        return Ok(destination.to_path_buf());\n    }\n    let nonempty = destination.exists() && destination.read_dir()?.next().is_some();\n    if nonempty {\n        for entry in entries.split('\\0').filter(|s| !s.is_empty()) {\n            let mut ancestor = destination.to_path_buf();\n            for component in Path::new(entry).components() {\n                ancestor.push(component);\n                if ancestor.is_symlink() {\n                    bail!(\"existing symbolic link conflicts with adoption: {entry}\");\n                }\n            }\n            let existing = destination.join(entry);\n            if existing.exists()\n                && (checkout.join(entry).is_symlink()\n                    || !existing.is_file()\n                    || std::fs::read(&existing)? != std::fs::read(checkout.join(entry))?)\n            {\n                bail!(\"existing file conflicts with adoption: {entry}\");\n            }\n        }\n        if dry_run {\n            let new_files = entries\n                .split('\\0')\n                .filter(|s| !s.is_empty())\n                .filter(|entry| !destination.join(entry).exists())\n                .count();\n            miseprintln!(\n                \"Would adopt {shown} as the global configuration repository ({new_files} new file(s); existing files and local overrides preserved)\"\n            );\n            return Ok(destination.to_path_buf());\n        }\n        eprintln!(\n            \"Adopt existing global configuration at {} (preserving existing files and local overrides)\",\n            destination.display()\n        );\n        if !yes","sourceCodeStart":320,"sourceCodeEnd":356,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/system/remote_repository.rs#L320-L356","documentation":"During adoption of a non-empty destination (no `.git`), install_at compares each transferred file with any existing file at the same relative path. Adoption only proceeds when the existing file is a regular file with byte-identical content and the transferred entry is not itself a symlink; anything else — differing content, a directory in the way, or a symlink on either side — aborts the adoption. This guarantees adoption never overwrites or clobbers user data.","triggerScenarios":"Installing into an existing non-empty directory where `destination/<entry>` already exists and differs from the checkout's version: different bytes, existing path is a directory, or the transferred (or existing) entry is a symlink.","commonSituations":"User already has their own config.toml with different settings at the destination; a previous partial adoption left files behind that have since been edited; the source repo gained a symlink where the user has a real file.","solutions":["Diff the conflicting files (`diff <destination>/<entry> <source-repo>/<entry>`) and reconcile them in the source repository, then re-transfer.","If the local version should win, copy it into the source repo, commit, and regenerate the bundle so contents match.","If the transferred version should win, back up and remove the differing local file before retrying.","Remove unrelated stale files/directories that occupy transferred entry paths (e.g. leftover directories where the transfer expects a file)."],"exampleFix":"// before: existing config.toml differs from transferred one\ndiff ~/.config/mise/config.toml ./source/config.toml\n# reconcile edits in the source repo, commit, then:\ncp ./source/config.toml ~/.config/mise/config.toml\n// after: files are byte-identical; adoption succeeds","handlingStrategy":"validation","validationCode":"const { execFileSync } = require('child_process');\nconst entries = execFileSync('git', ['-C', checkout, 'ls-tree', '-r', '--name-only', 'HEAD']).toString().split('\\n');\nfor (const e of entries.filter(Boolean)) {\n  const existing = path.join(dest, e);\n  if (fs.existsSync(existing) && !fs.statSync(existing).isFile()) throw new Error(`conflict at ${e}`);\n  if (fs.existsSync(existing) && !fs.readFileSync(existing).equals(fs.readFileSync(path.join(checkout, e)))) throw new Error(`content differs at ${e}`);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Preview the adoption (dry run) before executing it.","Keep local overrides in `*.local.toml` files rather than editing tracked files.","Reconcile divergent copies by committing local content into the source repo before transferring."],"tags":["git","file-conflict","adoption"],"backgroundTag":"file-already-exists","analyzedSha":"afd2eddd3a50c16190efc1c7e94404b48f72af57","analyzedAt":"2026-09-09T01:38:25.179Z","contentChangedAt":"2026-09-09T01:38:25.179Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}