You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Eight open issues in this repo describe the same defect in eight different verbs. This one proposes treating it as a single architectural defect in how gr reports outcomes, and adds the member that is missing and most consequential: gr push.
Filed separately across three weeks, each by whoever hit it. Read together they are not eight bugs.
The missing member: gr push
Two measurements, two different symptoms, same day.
Symptom A — reported success, remote did not move. A push was reported as successful; the remote ref stayed at its prior SHA. Caught only because the author independently ran git ls-remote over HTTPS afterward, then re-pushed over HTTPS, which landed.
Symptom B — non-zero failures, zero exit code. Measured on a separate run:
⚠ 1 pushed, 1 failed, 17 skipped
✗ <repo>: Error: Operation failed: fatal: could not read Username for '<host>': Device not configured
$ echo $?
0
The command printed its own failure and exited 0. Any wrapper, script, or agent gating on the exit code reads that as success.
Why push is the member that matters most
Every other instance in the table wastes time. This one loses work. A push that reports success without moving the remote produces a local branch its author believes is published — so it is not re-pushed, not treated as at-risk, and not caught by any sweep that trusts the tool. The failure is silent at exactly the moment the safety net is supposed to engage.
It also defeats the standard remedy. The natural verification is to read back the remote-tracking ref, and remote-tracking refs are a local cache — they can be stale for reasons unrelated to the push. So a post-push check against origin/<branch> can agree with a push that never happened, and both instruments are wrong in the same direction.
The shape underneath
Every instance is the same substitution: an outcome signal bound to something adjacent to the outcome. The verb reports that it ran, that it iterated, that it encountered no exception in its own frame — never that the intended state change is now true at the destination.
That is why fixing them one at a time has not converged. Eight fixes in eight verbs leave the ninth verb free to make the same substitution, because nothing in the design says what a success claim is required to be about.
Proposed contract
A gr verb's success claim binds to observed destination state, not to internal control flow.
The exit code is the disjunction of per-repo results. Any repo failing makes the process exit non-zero. Printing a failure and exiting 0 is the defect in its purest form. (Symptom B)
Remote verification does not use remote-tracking refs.push confirms against the remote itself, because the cache can agree with a push that did not happen.
Suggested disposition
Close the eight as children of this one if the contract is adopted, or keep them open and land the contract incrementally with each closing under it. Either is fine. What does not work is a ninth instance issue.
Cross-cutting, so the natural home is the verb-result layer rather than any single command.
Eight open issues in this repo describe the same defect in eight different verbs. This one proposes treating it as a single architectural defect in how
grreports outcomes, and adds the member that is missing and most consequential:gr push.The existing instances
gr sync --repo <unknown>gr branch --repo <unmatched>gr branch --repo <unmatched>gr rebase <branch>gr rebase --abortstate=rebasinggr synclink --applygh project item-add(adjacent tooling)Filed separately across three weeks, each by whoever hit it. Read together they are not eight bugs.
The missing member:
gr pushTwo measurements, two different symptoms, same day.
Symptom A — reported success, remote did not move. A push was reported as successful; the remote ref stayed at its prior SHA. Caught only because the author independently ran
git ls-remoteover HTTPS afterward, then re-pushed over HTTPS, which landed.Symptom B — non-zero failures, zero exit code. Measured on a separate run:
The command printed its own failure and exited 0. Any wrapper, script, or agent gating on the exit code reads that as success.
Why
pushis the member that matters mostEvery other instance in the table wastes time. This one loses work. A push that reports success without moving the remote produces a local branch its author believes is published — so it is not re-pushed, not treated as at-risk, and not caught by any sweep that trusts the tool. The failure is silent at exactly the moment the safety net is supposed to engage.
It also defeats the standard remedy. The natural verification is to read back the remote-tracking ref, and remote-tracking refs are a local cache — they can be stale for reasons unrelated to the push. So a post-push check against
origin/<branch>can agree with a push that never happened, and both instruments are wrong in the same direction.The shape underneath
Every instance is the same substitution: an outcome signal bound to something adjacent to the outcome. The verb reports that it ran, that it iterated, that it encountered no exception in its own frame — never that the intended state change is now true at the destination.
That is why fixing them one at a time has not converged. Eight fixes in eight verbs leave the ninth verb free to make the same substitution, because nothing in the design says what a success claim is required to be about.
Proposed contract
A
grverb's success claim binds to observed destination state, not to internal control flow.push, current branch forbranch, repo state forrebase --abort. (gr rebase --abort returns success but leaves repo in state=rebasing (cannot clear its own rebase metadata) #768, gr rebase <branch> targets the stale LOCAL ref and reports success on a no-op #814)gr syncreports success #873,gitgrip link --applycomposes from whatever a gripspace already has on disk and reports full success even when that content is behind upstream #883)pushconfirms against the remote itself, because the cache can agree with a push that did not happen.Suggested disposition
Close the eight as children of this one if the contract is adopted, or keep them open and land the contract incrementally with each closing under it. Either is fine. What does not work is a ninth instance issue.
Cross-cutting, so the natural home is the verb-result layer rather than any single command.