Executes one coalesced debounce cycle: proactively track new worktrees, sync affected branches / the current branch, and mark GC eligibility.
(
inner: &Arc<GitWatcherInner>,
state: &Arc<WatchState>,
common: &Path,
plan: DirtyPlan,
)
| 571 | /// Executes one coalesced debounce cycle: proactively track new worktrees, sync |
| 572 | /// affected branches / the current branch, and mark GC eligibility. |
| 573 | async fn execute_plan( |
| 574 | inner: &Arc<GitWatcherInner>, |
| 575 | state: &Arc<WatchState>, |
| 576 | common: &Path, |
| 577 | plan: DirtyPlan, |
| 578 | ) { |
| 579 | let root = &state.project_root; |
| 580 | let opts = TraceDecayOpenOptions::default(); |
| 581 | |
| 582 | // 1. Proactively track newly-created linked worktrees. |
| 583 | for name in &plan.new_worktrees { |
| 584 | if let Some((wt_root, branch)) = resolve_worktree(common, name) { |
| 585 | let _permit = inner.sync_semaphore.acquire().await; |
| 586 | match track_worktree_branch(wt_root.clone(), branch.clone()).await { |
| 587 | Some(outcome) => { |
| 588 | log_daemon_event( |
| 589 | "git_watch_synced", |
| 590 | &[ |
| 591 | ("project", root.display().to_string()), |
| 592 | ("action", "worktree_tracked".to_string()), |
| 593 | ("worktree", wt_root.display().to_string()), |
| 594 | ("branch", branch), |
| 595 | ("outcome", outcome), |
| 596 | ], |
| 597 | ); |
| 598 | } |
| 599 | None => log_daemon_event( |
| 600 | "git_watch_degraded", |
| 601 | &[ |
| 602 | ("project", root.display().to_string()), |
| 603 | ("reason", "worktree_track_failed".to_string()), |
| 604 | ], |
| 605 | ), |
| 606 | } |
| 607 | } |
| 608 | } |
| 609 | |
| 610 | // 2. Sync the CURRENT branch's store (HEAD move / general dirtiness). |
| 611 | // |
| 612 | // `sync_project` opens the project root, which resolves to whichever |
| 613 | // branch HEAD currently points at, and diffs against the working tree. |
| 614 | // It therefore can only refresh the checked-out branch's store — a |
| 615 | // ref update to a tracked-but-not-checked-out branch (e.g. `git fetch` |
| 616 | // advancing `refs/heads/feature` while on `main`, or a branch moved in |
| 617 | // another worktree) has no working tree here to diff against, so its own |
| 618 | // store cannot be incrementally synced from this checkout. Those stores |
| 619 | // recover on the next on-read sync (when that branch is checked out / |
| 620 | // opened) or via the backstop. We only report the branch we actually |
| 621 | // refreshed, so the log never claims a sync that did not happen. |
| 622 | let current_branch = if plan.dirty { |
| 623 | crate::branch::current_branch(root) |
| 624 | } else { |
| 625 | None |
| 626 | }; |
| 627 | // Non-current tracked branches whose refs changed: recorded but NOT synced |
| 628 | // here (see above). Kept distinct from `current_branch` for honest logging. |
| 629 | let other_changed_branches: Vec<String> = plan |
| 630 | .branches |
no test coverage detected