Skip to main content

Module worktree_push

Module worktree_push 

Source
Expand description

Batch-publish a repository’s worktrees to their upstreams, force-pushing with a lease where history was rewritten (issue #1443).

This is the other half of worktree_rebase. A rebase rewrites history, so every already-published branch it touches is now diverged from its upstream and a plain git push is rejected — leaving the user to open a terminal in each worktree and force-push by hand. This engine closes that loop for a whole batch.

Split of concerns (see ADR-0003 and ADR-0061). Every git read — the checked-out branch, the upstream and its remote, the divergence, the repository’s remote default branch — goes through git2. The one mutation, the push itself, shells out to the user’s git: libgit2’s vendored build here has no reliable SSH transport (issue #903), the shell inherits the user’s ssh-agent / ~/.ssh/config / credential-helper configuration for free, and only real git implements the lease this engine depends on. The binary is resolved through crate::git::resolve_git_binary rather than by name, because the daemon’s PATH is minimal (ADR-0059 §3).

§Two rules this engine exists to enforce

1. Always --force-with-lease --force-if-includes, never --force. A bare --force-with-lease leases against the local remote-tracking ref, so any background fetch that refreshes refs/remotes/<remote>/<branch> silently renews the lease and a teammate’s unseen commit becomes overwritable. Per git-push(1), --force-if-includes additionally verifies that such implicitly updated remote-tracking refs were actually integrated locally — and it is not implied: it must be passed explicitly, and it is a documented no-op unless --force-with-lease is given in its valueless (or refname-only) form. The hazard is elevated in exactly the environment this ships into, since the built-in VS Code Git extension’s git.autofetch is precisely such a background fetch. --force is never emitted, and no option exposes it: a refused lease is the feature working.

2. Never force-push the repository’s remote default branch. ADR-0060 dropped the rebase engine’s main-working-tree gate; a force-push must invert that, and the gate is on the branch rather than the worktree’s structural role. A rebase rewrites only local history and is git reflog-recoverable; a force-push publishes that rewrite to everyone. A fast-forward onto the default branch stays allowed, because it is an ordinary push.

§Planning does not touch the network

Unlike worktree_rebase::plan, plan performs no fetch — which is why it takes no git binary at all. Classification reads the local refs/remotes/<remote>/<branch>, and that is exactly the ref the lease is checked against, so the plan the user confirms and the lease the push enforces agree by construction. A fetch here would refresh that ref — renewing the very lease rule 1 exists to protect. The cost is that a teammate’s unseen push reads as PushResult::WouldFastForward and is then refused by the remote, which is reported rather than forced.

Re-exports§

pub use crate::git::worktree_batch::Selection;

Structs§

Plan
The result of planning and (optionally) executing a batch push.
PushOptions
Knobs for a batch push.
WorktreeOutcome
What happened (or, in a plan, would happen) to one worktree.

Enums§

PushResult
The per-worktree classification and outcome.
SkipReason
Why a worktree was skipped rather than pushed.

Functions§

execute
Executes a Plan, publishing every worktree that still has something to push.
plan
Plans a batch push, classifying every selected worktree against its upstream.