Expand description
The push a merge, pull, cherry-pick, revert or am hands to the service when it leaves the branch ahead of its upstream.
What:
Hands a push to the commit service after a command other than git commit added commits to the branch: a merge, a
pull’s merge, a cherry-pick, a revert or an applied patch.
Why:
A clean git merge used to stay local until the next commit pushed it. The owner chose (2026-11-02) that any command
adding commits queues the push as a commit does, when the branch tip moved and the branch is now ahead of its upstream
and not diverged from it, and that a rebase does not, because a rebased branch would need a forced push.
The check reads the branch, its upstream tracking ref and the commit parents from the files, with no Git process:
the tip is read before and after the forwarded command, and the push is handed over only when the old tip and the
upstream tip are both ancestors of the new tip. The old tip being an ancestor is what leaves a rebase (a rewritten
branch) out, pull --rebase and pull.rebase included, without reading the configuration for it.
In TS you’d write (pseudocode):
const watch = watchTip(worktree); await runGit(args); if (exitCode === 0) await watch.handOverIfAhead();Structs§
- Declined
- Why the trigger did nothing: the step that declined, as a stable word, and the facts a person needs to see why.
- TipWatch
- What the branch looked like before the command: where it pointed and where its repository is.
Constants§
- WALK_
BUDGET - The most commits the walk from a tip reads before it gives up and hands nothing over: a branch far ahead, or a history
that never reaches the upstream, is not worth a long walk after every merge. Measured: the 439 most recent merges on
mainof this repository brought in a median of 8 commits (90th percentile 50, 99th percentile 317, largest 6,542), and only 1 exceeded this budget, so 438 of 439 are walked in full. Kept as the coordinator’s pick under the owner’s delegation, open to the owner’s veto (doc/planning/cli-git-shipped-limits-audit.md, “Sizes and ages of the service’s own housekeeping”).
Functions§
- hand_
over_ if_ ahead - What:
After a command that succeeded: hand the push over when the branch grew and is ahead of its upstream.
Why:
The person’s command already finished; a service that cannot be reached is said plainly and changes nothing.
The record is the same push record a commit leaves, so the service pushes the branch by name and coalesces it.
Every ending is recorded with its reason (
push_trigger_log.rs), so a push that did not happen can be explained. - reaches
- What:
Whether
targetisfromor one of its ancestors, within the walk budget; nothing when the walk could not tell. Why: Ahead and not diverged is “the upstream tip is an ancestor of the branch tip”; the walk goes from the branch tip, which reaches the upstream within the commits the branch is ahead by, and stops at the budget on a history that never does. - tip_
to_ push tip_to_push_or_whywithout the reason.- tip_
to_ push_ or_ why - What: The tip to hand over after the command, or the step that found the branch not a case the owner chose. Why: The branch must be the same one, its tip must have moved forward from the old tip (a rewritten branch is a rebase), and the new tip must be ahead of its upstream and not diverged: the upstream tip is an ancestor of it and not it.
- try_
watch_ tip - What:
Start watching the branch of a worktree before a command runs.
Why:
The command may be a merge or a pull, which move the tip; what the tip was is what a rebase is told apart by.
The layout is read as for a caller that follows a Git run that succeeds (
read_layout_after_success): a configuration value the reader cannot prove is no reason not to push once the command that moved the tip succeeded (the files are read again, not the snapshot that command saw, and the final push is Git’s). - watch_
tip try_watch_tipwithout the reason: nothing when the watch could not start.