{"record":{"id":"0d77c12b228cb937","repo":"gitbutlerapp/gitbutler","slug":"branch-is-pushed-but-its-remote-ancestry-doe","errorCode":null,"errorMessage":"Branch `{}` is pushed, but its remote ancestry does not match the reviewed workspace stack; push it and its ancestors before creating a review","messagePattern":"Branch `(.+?)` is pushed, but its remote ancestry does not match the reviewed workspace stack; push it and its ancestors before creating a review","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/but-api/src/legacy/forge.rs","lineNumber":2226,"sourceCode":"        .expect(\"a non-empty chain starts with the branch's own lane\");\n    let mut reviewed_ancestors = std::iter::once((*lane, selected_index + 1))\n        .chain(beneath.iter().copied())\n        .flat_map(|(lane, index)| &lane.segments[index..])\n        .filter(|segment| review_number(segment, &open_reviews).is_some())\n        .map(|segment| remote_head(&repo, segment))\n        .collect::<Result<Vec<_>>>()?;\n    reviewed_ancestors.reverse();\n    let selected = remote_head(&repo, &lane.segments[*selected_index])?;\n\n    for pair in reviewed_ancestors\n        .iter()\n        .map(|head| head.remote_tip)\n        .chain(std::iter::once(selected.remote_tip))\n        .collect::<Vec<_>>()\n        .windows(2)\n    {\n        if !remote_contains(&repo, pair[0], pair[1])? {\n            anyhow::bail!(\n                \"Branch `{}` is pushed, but its remote ancestry does not match the reviewed workspace stack; push it and its ancestors before creating a review\",\n                branch.shorten()\n            );\n        }\n    }\n\n    match reviewed_ancestors.pop() {\n        Some(nearest_reviewed_ancestor) => Ok(nearest_reviewed_ancestor.branch_name),\n        None => target_short_name(&ctx.project_meta()?, &repo),\n    }\n}\n\n#[derive(Debug)]\nstruct RemoteHead {\n    branch_name: String,\n    remote_tip: gix::ObjectId,\n}\n","sourceCodeStart":2208,"sourceCodeEnd":2244,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/58e5313667b857ef39a730e380af31816a7b1768/crates/but-api/src/legacy/forge.rs#L2208-L2244","documentation":"Before creating a review, the code verifies that the remote history of the selected branch matches the reviewed workspace stack ancestry. For each consecutive pair of tips in the lane chain it checks remote_contains; if the remote does not contain the parent tip, the branch is pushed but its ancestors are missing/diverged on the remote, and this error is thrown.","triggerScenarios":"Creating a review for a branch that is pushed, but whose ancestor commits in the workspace stack are not present on the remote (or remote ancestry diverged).","commonSituations":"User force-pushed or pushed only the top branch; a stacked branch was pushed from another machine; remote branch was rewritten causing ancestry mismatch.","solutions":["Push all ancestor branches of the stack: `git push <remote> <parent-branch>` for each link in the chain","Run `but push` / full stack push instead of pushing a single branch","If the remote diverged, reconcile with a fetch and re-push the correct history"],"exampleFix":"// before\ngit push origin feature-top;\n// after\ngit push origin base-branch feature-top","handlingStrategy":"validation","validationCode":"const parents = await getStackAncestors(projectId, branch);\nfor (const p of parents) {\n  if (!await isPushed(p)) await pushBranch(projectId, p);\n}","typeGuard":null,"tryCatchPattern":"try {\n  await createReview(projectId, branch);\n} catch (e) {\n  if (String(e).includes('remote ancestry does not match')) {\n    await pushEntireStack(projectId); // push branch + ancestors\n    await createReview(projectId, branch);\n  } else throw e;\n}","preventionTips":["Push whole stacks, not just the top branch","Avoid force-pushing reviewed branches from other machines","Fetch and reconcile remote state before creating reviews"],"tags":["rust","forge","git","push"],"backgroundTag":"git-command-failed","analyzedSha":"58e5313667b857ef39a730e380af31816a7b1768","analyzedAt":"2026-09-18T06:50:32.052Z","contentChangedAt":"2026-09-18T06:50:32.052Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}