Repository navigation
Restore the carrier checkout after a failed publish and report real push errors - #21
Merged
Merged
Conversation
…ush errors A carrier compare-and-swap wrote the new HEAD into its checkout and committed it locally before pushing, and left both in place when the push failed. Reads on the same storage then saw the unpublished manifest as the current head, so in a helper push batch a ref that Git had been told failed was published together with the next ref. publish_checkout_head now restores the checkout to the last published commit on any failure, including removing the failed publication's staged objects. Every failed push was also reported as a CAS conflict and its stderr discarded, so an authentication failure or hook rejection told the user to git pull. After a failed push the branch is fetched again: a tip equal to the new commit means the push landed, a tip equal to the base means an ordinary error carrying git's stderr, and any other tip is a CAS conflict. A stale compare-and-swap against a remote whose HEAD file is malformed now reports a conflict instead of a parse error.
…ailure # Conflicts: # tests/carrier_git.rs
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.
Fixes A1, C1 and C3 from the implementation review. All three were reproduced on
mainbefore the fix.A1 (high): a ref Git was told failed got published with the next ref
publish_checkout_headwrote HEAD and made a local commit beforegit push, and undid neither when the push failed.local_head()reads the working-tree HEAD first, so the unpublished manifest became the "current" head. The helper handles a whole push batch on one storage instance.Reproduced:
git push private main:refs/heads/a main:refs/heads/bwith the first publish rejected by a hook. Git reportedaas failed, yet the final manifest helda,bandmain.Fix:
publish_checkout_headwraps a newcommit_and_push_head. On any error,restore_checkout(base_commit)puts the checkout back to the last published commit:README.md,FORMAT,manifests/andpacks/, so the failed publication's objects are not uploaded later.If the restore itself fails, its error is attached to the original one.
C1 (medium): every push failure looked like a CAS conflict
Every failed push became
CasConflictand stderr was dropped. Since #14 the helper maps that tofetch first, so a hook rejection or an authentication failure showed[rejected] (fetch first)and thegit pullhint.Fix: after a failed push, the branch is fetched again and the code acts on the observed tip, not on stderr text:
git push carrier branch failed: <stderr>;CasConflict;C3 (low): a garbage remote HEAD hid the conflict
head_at_commitvalidated the remote HEAD while building the conflict, so a stale CAS against a malformed HEAD returnedinvalid opaque object id. It is replaced byconflicting_head(commit) -> Option<String>, used only to fillCasConflict.actual. Reads that need a valid HEAD still validate it.Tests
rejected_carrier_publish_restores_the_published_headrejected_carrier_genesis_leaves_an_uninitialized_checkoutfailed_ref_in_a_helper_push_batch_is_not_published_by_the_next_ref. It locates the failed ref from--porcelainoutput and checks that the hook's message appears andfetch firstdoes not.stale_compare_and_swap_conflicts_even_when_the_remote_head_is_garbageCasConflict.cargo fmt --check,cargo clippy --all-targets -- -D warnings,cargo test --all-targets(144 passed).Limits
CasConflict. The tip did move, so this is accepted.