Add receive.preferatomicpush setting to receive-pack.c. This triggers
a new capability "prefer-atomic-push" to be sent back to the send-pack
client, requesting the client, if it supports it, to request
an atomic push.

This is an alternative way to trigger an atomic push instead of having
to rely of the user using the --atomic-push command line argument.
For backward compatibility, this is only a hint to the client that is should
request atomic pushes if it can. Old clients that do not support atomic pushes
will just ignore this capability and use a normal push.

The reason we need to signal this capability back to the client is due
to that send_pack() has push failure modes where it will detect that
certain refs can not be pushed and fail them early. Those refs would not
even be sent by the client unless atomic-pushes are activated.
This means that IF we activate this feature from the server side we must
tell the client to not fail refs early and use an atomic push. We can not
enforce this on the server side only.

Change-Id: I6677cd565f48a09bb552fe3f4c00bbb6d343c224
Signed-off-by: Ronnie Sahlberg <sahlb...@google.com>
---
 Documentation/config.txt                          |  4 +++
 Documentation/technical/protocol-capabilities.txt | 13 ++++++---
 builtin/receive-pack.c                            |  8 ++++++
 send-pack.c                                       |  2 ++
 t/t5543-atomic-push.sh                            | 32 +++++++++++++++++++++++
 5 files changed, 56 insertions(+), 3 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 400dcad..78c427e 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -2135,6 +2135,10 @@ receive.shallowupdate::
        If set to true, .git/shallow can be updated when new refs
        require new shallow roots. Otherwise those refs are rejected.
 
+receive.preferatomicpush::
+       This option is used in receive-pack to tell the client to try
+       to use an atomic push, if the client supports it.
+
 remote.pushdefault::
        The remote to push to by default.  Overrides
        `branch.<name>.remote` for all branches, and is overridden by
diff --git a/Documentation/technical/protocol-capabilities.txt 
b/Documentation/technical/protocol-capabilities.txt
index 26bc5b1..78c5469 100644
--- a/Documentation/technical/protocol-capabilities.txt
+++ b/Documentation/technical/protocol-capabilities.txt
@@ -18,9 +18,9 @@ was sent.  Server MUST NOT ignore capabilities that client 
requested
 and server advertised.  As a consequence of these rules, server MUST
 NOT advertise capabilities it does not understand.
 
-The 'atomic-push', 'report-status', 'delete-refs', 'quiet', and 'push-cert'
-capabilities are sent and recognized by the receive-pack (push to server)
-process.
+The 'atomic-push', 'report-status', 'delete-refs', 'prefer-atomic-push',
+'quiet', and 'push-cert' capabilities are sent and recognized by the
+receive-pack (push to server) process.
 
 The 'ofs-delta' and 'side-band-64k' capabilities are sent and recognized
 by both upload-pack and receive-pack protocols.  The 'agent' capability
@@ -252,6 +252,13 @@ If the server sends the 'atomic-push' capability, it means 
it is
 capable of accepting atomic pushes. If the pushing client requests this
 capability, the server will update the refs in one single atomic transaction.
 
+prefer-atomic-push
+------------------
+
+If the receive-pack server advertises the 'prefer-atomic-push' capability,
+it means that the client should use an atomic push, if the client supports it,
+even if the user did not request it explicitly.
+
 allow-tip-sha1-in-want
 ----------------------
 
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index 6991d22..697f102 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -52,6 +52,7 @@ static const char *head_name;
 static void *head_name_to_free;
 static int sent_capabilities;
 static int shallow_update;
+static int prefer_atomic_push;
 static const char *alt_shallow_file;
 static struct strbuf push_cert = STRBUF_INIT;
 static unsigned char push_cert_sha1[20];
@@ -160,6 +161,11 @@ static int receive_pack_config(const char *var, const char 
*value, void *cb)
                return 0;
        }
 
+       if (strcmp(var, "receive.preferatomicpush") == 0) {
+               prefer_atomic_push = git_config_bool(var, value);
+               return 0;
+       }
+
        return git_default_config(var, value, cb);
 }
 
@@ -178,6 +184,8 @@ static void show_ref(const char *path, const unsigned char 
*sha1)
                              "atomic-push");
                if (prefer_ofs_delta)
                        strbuf_addstr(&cap, " ofs-delta");
+               if (prefer_atomic_push)
+                       strbuf_addstr(&cap, " prefer-atomic-push");
                if (push_cert_nonce)
                        strbuf_addf(&cap, " push-cert=%s", push_cert_nonce);
                strbuf_addf(&cap, " agent=%s", git_user_agent_sanitized());
diff --git a/send-pack.c b/send-pack.c
index 5208305..c5e0539 100644
--- a/send-pack.c
+++ b/send-pack.c
@@ -325,6 +325,8 @@ int send_pack(struct send_pack_args *args,
                args->use_thin_pack = 0;
        if (server_supports("atomic-push"))
                atomic_push_supported = 1;
+       if (server_supports("prefer-atomic-push"))
+               args->use_atomic_push = 1;
        if (args->push_cert) {
                int len;
 
diff --git a/t/t5543-atomic-push.sh b/t/t5543-atomic-push.sh
index 4903227..3feb22e 100755
--- a/t/t5543-atomic-push.sh
+++ b/t/t5543-atomic-push.sh
@@ -98,4 +98,36 @@ test_expect_success 'atomic push fails if one branch fails' '
        test "$master_second" != "$mirror_second"
 '
 
+test_expect_success 'atomic push fails (receive.preferatomicpush)' '
+       mk_repo_pair &&
+       (
+               cd master &&
+               echo one >foo && git add foo && git commit -m one &&
+               git branch second &&
+               git checkout second &&
+               echo two >foo && git add foo && git commit -m two &&
+               echo three >foo && git add foo && git commit -m three &&
+               echo four >foo && git add foo && git commit -m four &&
+               git push --mirror up
+               git reset --hard HEAD~2 &&
+               git checkout master
+               echo five >foo && git add foo && git commit -m five
+       ) &&
+       (
+               cd mirror &&
+               git config --add receive.preferatomicpush true
+       ) &&
+       (
+               cd master &&
+               ! git push --atomic-push --all up
+       ) &&
+       master_master=$(cd master && git show-ref -s --verify 
refs/heads/master) &&
+       mirror_master=$(cd mirror && git show-ref -s --verify 
refs/heads/master) &&
+       test "$master_master" != "$mirror_master" &&
+
+       master_second=$(cd master && git show-ref -s --verify 
refs/heads/second) &&
+       mirror_second=$(cd mirror && git show-ref -s --verify 
refs/heads/second) &&
+       test "$master_second" != "$mirror_second"
+'
+
 test_done
-- 
2.1.0.rc2.206.gedb03e5

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to