Skip to content

Fix graph routing for dirty worktrees#56

Open
noahbclarkson wants to merge 1 commit into
mainfrom
codex/fix-worktree-graph-routing
Open

Fix graph routing for dirty worktrees#56
noahbclarkson wants to merge 1 commit into
mainfrom
codex/fix-worktree-graph-routing

Conversation

@noahbclarkson

Copy link
Copy Markdown
Owner

Summary

Fixes graph rendering for dirty (uncommitted-changes) worktrees so a worktree's pending-changes pseudo-node is drawn as a proper child of its HEAD commit rather than being spliced inline onto an existing child→parent path.

Previously, when a worktree's HEAD already had a real child commit visible in the graph, the pending-changes node was placed on the HEAD's own lane. It then visually consumed the real child's incoming edge, producing crossed/overlapping lines and a misleading "the worktree is the parent of this commit" layout.

What changed

All logic lives in crates/rgitui_graph/src/lib.rs.

  • Lane selection is now relative to the real commit graph. A worktree reuses its HEAD's lane only when the HEAD has no visible incoming child edge and no earlier worktree already claimed that lane. Otherwise it takes the first lane beyond the commit graph (graph_lane_count) and carries an explicit edge back to parent_lane.
  • WorktreeRowPosition gained parent_lane: Option<usize> — the lane of the visible HEAD commit the pseudo-node descends from. None for orphan worktrees (unborn HEAD, or HEAD outside the loaded commit window), which intentionally draw no dangling parent edge.
  • Pass-through edges now keep every real lane (including the HEAD lane, when the worktree sits on a side lane) flowing across the virtual row, so the real child path is never swallowed by the pseudo-node.
  • Parent connector rendering replaces the old unconditional up/down line pair. It draws a tip→parent edge honoring the active GraphStyle (Curved quarter-arc, Rails mid-step, Angular elbow), and draws nothing for orphan rows.
  • Extracted pure helperscompute_worktree_row_positions, worktree_pass_through_edges, and worktree_targets_commit_immediately_above — out of GraphView methods and the render closure, so the routing logic is testable without a display.

Tests

Added unit tests covering the previously-broken cases:

  • dirty_worktree_beside_real_child_uses_sibling_lane — the original bug: worktree HEAD has a real child, so the pseudo-node takes a sibling lane with a parent edge instead of hijacking the child's lane.
  • dirty_worktree_at_branch_tip_reuses_tip_lane — a tip HEAD with no child keeps the natural lane.
  • worktrees_sharing_a_head_are_siblings_not_a_chain — multiple dirty worktrees on one HEAD stack as siblings; the current worktree keeps the natural lane.
  • unloaded_worktree_head_has_no_false_parent_edge — out-of-window HEAD becomes an orphan with no parent edge.

Test plan

  • cargo test -p rgitui_graph
  • cargo clippy --workspace --all-targets -- -D warnings
  • cargo fmt --all --check
  • Visual check: open a repo with a dirty worktree whose HEAD has a descendant commit and confirm the pending-changes node branches off cleanly.

🤖 Generated with Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants