Release: gitgrip 1.3.0 - #916
Merged
Merged
Conversation
An unknown --repo name matched zero repositories and the command reported success having done nothing. With a modified file present in the worktree, `gr add . --repo missing` printed "No changes to stage." and exited 0. There was a change to stage; gr said there was not. That is a false claim about the working tree, which is what justifies a fix rather than a documentation note. validate_repo_filters_known already existed in src/core/repo.rs, already produced the right diagnostic, and already carried a basename-matching branch that names the intended repository. It was not called from add, commit, or push. This calls it from all three. Wired to CliOutcomeError::refusal. outcome.rs defines EXIT_REFUSED = 2 and carries a test named refusal_is_distinct_from_operational_failure, so the codebase already separates a refusal from an operational failure. pr/merge uses the same mapping. Three regression tests assert that an unknown --repo name exits 2 with the diagnostic, one per verb. A control asserts that a KNOWN name still reaches the work: it writes a file, runs the command, and asserts that file is present in the repository's index. It asserts the destination rather than the absence of a message. Mutation-verified in both directions. Removing add.rs's validation call turns exactly the add rejection test red while commit and push stay green. Making run_add return early after validation turns exactly the control red while the three rejection tests stay green. Other commands accept a repo filter without validating it. Identifying which requires reading each command's behavior rather than grepping an identifier, and is deliberately left to a follow-on so each batch is reviewed on its own. Ref #886 — closes at promotion. Premium boundary: grip is OSS — local workspace orchestration, no identity, org, or entitlement semantics.
fix(cli): refuse an unknown --repo filter on add, commit, and push
…arget `gr prune --execute` deleted the local `main` on any repo whose manifest target is not `main`. The guard skipped exactly two branches -- the one checked out and `repo.target_branch()` -- so once the integration target moved to `dev`, `main` was neither and fell out of protection. Nothing was edited to cause this: `main` had been protected only by coincidence, because target and default used to be the same value. Scope of the defect, measured rather than assumed: LOCAL ONLY. The `--remote` path is `git fetch --prune`, which prunes stale remote-tracking refs and does not delete remote branches, so the worst outcome was a local branch recreated from the remote. The fix protects a SET of three: current, target, and the remote's default branch read from `refs/remotes/<remote>/HEAD`. The default is the only one of the three that asserts "permanent" rather than "currently interesting", which is the property a cleanup rule needs. Resolution is local -- a cleanup verb should not acquire a network failure mode. When the default cannot be resolved, the protected set GROWS rather than shrinks: `main` and `dev` are protected by name and the run says so. A resolution failure that silently dropped a branch would reproduce this exact defect inside its own fix, and would do it with nothing going red. Two witnesses, each killed by exactly one mutation: - target=dev with `main` present: `main` and `dev` survive while a genuinely merged branch is still deleted. That last assertion is a positive control; without it the test would pass against a guard that protected everything. - `origin/HEAD` deleted from a real clone, so resolution genuinely fails rather than being stubbed: both branches survive AND the output states the default could not be determined. A protected-more that is silent still reads as "the default resolved fine" to the next reader. The pre-existing `test_prune_skips_current_and_default` is left in place but does not cover any of this: its fixture has current == target == `main`, so `main` is protected twice over and the test passes with EITHER clause of the old guard removed. It kills no mutant while carrying the name of the guarantee it fails to check. Co-Authored-By: Claude <noreply@anthropic.com>
…anch fix(prune): protect the remote default branch, not just current and target
feat(spawn): pass Codex startup prompts as developer instructions
chore(release): prepare gitgrip 1.3.0
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Promotes the current dev tip to main for gitgrip 1.3.0. The promotion branch adds no bytes. Release metadata was independently ratified by Sentinel, with cargo formatting, 739 library tests, all-target checking, and crate packaging green.