{"record":{"id":"c2dd313f5f0af98b","repo":"gitbutlerapp/gitbutler","slug":"non-main-worktrees-are-not-supported","errorCode":null,"errorMessage":"non-main worktrees are not supported","messagePattern":"non-main worktrees are not supported","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/gitbutler-project/src/project.rs","lineNumber":327,"sourceCode":"            AddProjectOutcome::Added(p) => p,\n            _ => panic!(\"called `AddProjectOutcome::unwrap_project()` on a non-project outcome\"),\n        }\n    }\n\n    /// Try to get the `Project`, returning an error if it was not added.\n    pub fn try_project(self) -> anyhow::Result<Project> {\n        match self {\n            AddProjectOutcome::Added(p) => Ok(p),\n            AddProjectOutcome::AlreadyExists(_) => Err(anyhow::anyhow!(\"project already exists\")),\n            AddProjectOutcome::PathNotFound => Err(anyhow::anyhow!(\"project path not found\")),\n            AddProjectOutcome::NotADirectory => {\n                Err(anyhow::anyhow!(\"project path is not a directory\"))\n            }\n            AddProjectOutcome::BareRepository => {\n                Err(anyhow::anyhow!(\"bare repositories are not supported\"))\n            }\n            AddProjectOutcome::NonMainWorktree => {\n                Err(anyhow::anyhow!(\"non-main worktrees are not supported\"))\n            }\n            AddProjectOutcome::NoWorkdir => Err(anyhow::anyhow!(\"no workdir found for repository\")),\n            AddProjectOutcome::NoDotGitDirectory => {\n                Err(anyhow::anyhow!(\"no .git directory found in repository\"))\n            }\n            AddProjectOutcome::ReftableRefFormatUnsupported => Err(anyhow::anyhow!(\n                \"unsupported repository reference format: reftable\"\n            )),\n            AddProjectOutcome::NotAGitRepository(msg) => {\n                Err(anyhow::anyhow!(\"not a git repository: {msg}\"))\n            }\n        }\n    }\n}\n","sourceCodeStart":309,"sourceCodeEnd":342,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/caf1f223d3cfb94488c9198ad34487c6006c648f/crates/gitbutler-project/src/project.rs#L309-L342","documentation":"AddProjectOutcome::NonMainWorktree mapped through try_project: the path is a git linked worktree (created with `git worktree add`), not the repository's main worktree. GitButler manages the main worktree (it writes refs and workspace state under the repo's primary .git dir) and rejects secondary worktrees.","triggerScenarios":"add_project on a directory whose .git is a file pointing at <main>/.git/worktrees/<name>; multiple `git worktree add` checkouts of the same repo; adding the same repository twice through two of its worktrees.","commonSituations":"Developers using linked worktrees for parallel branches trying to onboard each one; automation that picks an existing checkout which happens to be a linked worktree.","solutions":["Add the main worktree instead — resolve the main path with `git worktree list` and pass that directory","If you need an isolated checkout, clone the repository rather than using a linked worktree","Pre-detect: a `.git` regular file (not directory) containing `gitdir:` indicates a linked worktree"],"exampleFix":"// before\nlet project = add_project(&path, ...).try_project()?; // linked worktree -> rejected\n\n// after: resolve to the main worktree first\nfn main_worktree(path: &Path) -> Option<PathBuf> {\n    let out = std::process::Command::new(\"git\")\n        .args([\"-C\", path.to_str()?, \"worktree\", \"list\", \"--porcelain\"])\n        .output().ok()?;\n    let line = String::from_utf8(out.stdout).ok()?.lines().next()?;\n    line.strip_prefix(\"worktree \").map(PathBuf::from)\n}\nlet path = main_worktree(&path).unwrap_or(path);\nlet project = add_project(&path, ...).try_project()?;","handlingStrategy":"validation","validationCode":"// a linked worktree has a .git *file* pointing at the main repo's worktrees dir\nlet dot = path.join(\".git\");\nlet is_linked_worktree = dot.is_file()\n    && std::fs::read_to_string(&dot).map(|c| c.starts_with(\"gitdir:\")).unwrap_or(false);\nif is_linked_worktree {\n    // resolve the main worktree: git -C <path> worktree list --porcelain | head -1\n    anyhow::bail!(\"linked worktree — add the main worktree instead\");\n}","typeGuard":"fn is_main_worktree(path: &Path) -> bool {\n    let dot = path.join(\".git\");\n    dot.is_dir() // main worktrees have a .git directory; linked ones have a gitdir: file\n}","tryCatchPattern":"match add_project(&path, ...) {\n    AddProjectOutcome::NonMainWorktree => offer_to_add_main_worktree(&path), // resolve via `git worktree list`\n    outcome => outcome.try_project(),\n}","preventionTips":["Detect linked worktrees by the .git gitdir-pointer file and steer users to the main worktree","Remember the main worktree per repository so re-adds target it automatically","Prefer fresh clones over linked worktrees when isolated checkouts are needed"],"tags":["gitbutler","project","git","worktree","validation"],"backgroundTag":"linked-worktree-unsupported","analyzedSha":"caf1f223d3cfb94488c9198ad34487c6006c648f","analyzedAt":"2026-08-20T07:55:40.983Z","schemaVersion":2},"datasetVersion":"2026-08-23T16:17:53.355Z"}