path: root/t
diff options
authorbrian m. carlson <>2019-10-16 23:45:34 (GMT)
committerJunio C Hamano <>2019-10-17 07:08:22 (GMT)
commit6f1194246a514ba093a11dde73aabe4c0da5526f (patch)
treec77e309f8c9b926709aeb15bc3a13baa08f149e2 /t
parent5fa0f5238b0cd46cfe7f6fa76c3f526ea98148d9 (diff)
remote-curl: pass on atomic capability to remote side
When pushing more than one reference with the --atomic option, the server is supposed to perform a single atomic transaction to update the references, leaving them either all to succeed or all to fail. This works fine when pushing locally or over SSH, but when pushing over HTTP, we fail to pass the atomic capability to the remote side. In fact, we have not reported this capability to any remote helpers during the life of the feature. Now normally, things happen to work nevertheless, since we actually check for most types of failures, such as non-fast-forward updates, on the client side, and just abort the entire attempt. However, if the server side reports a problem, such as the inability to lock a ref, the transaction isn't atomic, because we haven't passed the appropriate capability over and the remote side has no way of knowing that we wanted atomic behavior. Fix this by passing the option from the transport code through to remote helpers, and from the HTTP remote helper down to send-pack. With this change, we can detect if the server side rejects the push and report back appropriately. Note the difference in the messages: the remote side reports "atomic transaction failed", while our own checking rejects pushes with the message "atomic push failed". Document the atomic option in the remote helper documentation, so other implementers can implement it if they like. Signed-off-by: brian m. carlson <> Signed-off-by: Junio C Hamano <>
Diffstat (limited to 't')
1 files changed, 38 insertions, 2 deletions
diff --git a/t/ b/t/
index b86ddb6..3aec962 100755
--- a/t/
+++ b/t/
@@ -184,11 +184,12 @@ test_expect_success 'push --atomic also prevents branch creation, reports collat
test_config -C "$d" http.receivepack true &&
up="$HTTPD_URL"/smart/atomic-branches.git &&
- # Tell "$up" about two branches for now
+ # Tell "$up" about three branches for now
test_commit atomic1 &&
test_commit atomic2 &&
git branch collateral &&
- git push "$up" master collateral &&
+ git branch other &&
+ git push "$up" master collateral other &&
# collateral is a valid push, but should be failed by atomic push
git checkout collateral &&
@@ -226,6 +227,41 @@ test_expect_success 'push --atomic also prevents branch creation, reports collat
grep "^ ! .*rejected.* collateral -> collateral .*atomic push failed" output
+test_expect_success 'push --atomic fails on server-side errors' '
+ # Use previously set up repository
+ d=$HTTPD_DOCUMENT_ROOT_PATH/atomic-branches.git &&
+ test_config -C "$d" http.receivepack true &&
+ up="$HTTPD_URL"/smart/atomic-branches.git &&
+ # break ref updates for other on the remote site
+ mkdir "$d/refs/heads/other.lock" &&
+ # add the new commit to other
+ git branch -f other collateral &&
+ # --atomic should cause entire push to be rejected
+ test_must_fail git push --atomic "$up" atomic other 2>output &&
+ # the new branch should not have been created upstream
+ test_must_fail git -C "$d" show-ref --verify refs/heads/atomic &&
+ # upstream should still reflect atomic2, the last thing we pushed
+ # successfully
+ git rev-parse atomic2 >expected &&
+ # other.
+ git -C "$d" rev-parse refs/heads/other >actual &&
+ test_cmp expected actual &&
+ # the new branch should not have been created upstream
+ test_must_fail git -C "$d" show-ref --verify refs/heads/atomic &&
+ # the failed refs should be indicated to the user
+ grep "^ ! .*rejected.* other -> other .*atomic transaction failed" output &&
+ # the collateral failure refs should be indicated to the user
+ grep "^ ! .*rejected.* atomic -> atomic .*atomic transaction failed" output
test_expect_success 'push --all can push to empty repo' '
d=$HTTPD_DOCUMENT_ROOT_PATH/empty-all.git &&
git init --bare "$d" &&