Merge branch 'sb/atomic-push' into mh/ref-trans-value-check
* sb/atomic-push: Document receive.advertiseatomic t5543-atomic-push.sh: add basic tests for atomic pushes push.c: add an --atomic argument send-pack.c: add --atomic command line argument send-pack: rename ref_update_to_be_sent to check_to_send_update receive-pack.c: negotiate atomic push support receive-pack.c: add execute_commands_atomic function receive-pack.c: move transaction handling in a central place receive-pack.c: move iterating over all commands outside execute_commands receive-pack.c: die instead of error in case of possible future bug receive-pack.c: shorten the execute_commands loop over all commands
This commit is contained in:
@ -487,6 +487,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)
|
||||
int flags = 0;
|
||||
int tags = 0;
|
||||
int rc;
|
||||
int atomic = 0;
|
||||
const char *repo = NULL; /* default repository */
|
||||
struct option options[] = {
|
||||
OPT__VERBOSITY(&verbosity),
|
||||
@ -518,6 +519,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)
|
||||
OPT_BIT(0, "follow-tags", &flags, N_("push missing but relevant tags"),
|
||||
TRANSPORT_PUSH_FOLLOW_TAGS),
|
||||
OPT_BIT(0, "signed", &flags, N_("GPG sign the push"), TRANSPORT_PUSH_CERT),
|
||||
OPT_BOOL(0, "atomic", &atomic, N_("request atomic transaction on remote side")),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
@ -533,6 +535,9 @@ int cmd_push(int argc, const char **argv, const char *prefix)
|
||||
if (tags)
|
||||
add_refspec("refs/tags/*");
|
||||
|
||||
if (atomic)
|
||||
flags |= TRANSPORT_PUSH_ATOMIC;
|
||||
|
||||
if (argc > 0) {
|
||||
repo = argv[0];
|
||||
set_refspecs(argv + 1, argc - 1, repo);
|
||||
|
@ -38,9 +38,11 @@ static int receive_fsck_objects = -1;
|
||||
static int transfer_fsck_objects = -1;
|
||||
static int receive_unpack_limit = -1;
|
||||
static int transfer_unpack_limit = -1;
|
||||
static int advertise_atomic_push = 1;
|
||||
static int unpack_limit = 100;
|
||||
static int report_status;
|
||||
static int use_sideband;
|
||||
static int use_atomic;
|
||||
static int quiet;
|
||||
static int prefer_ofs_delta = 1;
|
||||
static int auto_update_server_info;
|
||||
@ -67,6 +69,7 @@ static const char *NONCE_SLOP = "SLOP";
|
||||
static const char *nonce_status;
|
||||
static long nonce_stamp_slop;
|
||||
static unsigned long nonce_stamp_slop_limit;
|
||||
static struct ref_transaction *transaction;
|
||||
|
||||
static enum deny_action parse_deny_action(const char *var, const char *value)
|
||||
{
|
||||
@ -160,6 +163,11 @@ static int receive_pack_config(const char *var, const char *value, void *cb)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strcmp(var, "receive.advertiseatomic") == 0) {
|
||||
advertise_atomic_push = git_config_bool(var, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return git_default_config(var, value, cb);
|
||||
}
|
||||
|
||||
@ -175,6 +183,8 @@ static void show_ref(const char *path, const unsigned char *sha1)
|
||||
|
||||
strbuf_addstr(&cap,
|
||||
"report-status delete-refs side-band-64k quiet");
|
||||
if (advertise_atomic_push)
|
||||
strbuf_addstr(&cap, " atomic");
|
||||
if (prefer_ofs_delta)
|
||||
strbuf_addstr(&cap, " ofs-delta");
|
||||
if (push_cert_nonce)
|
||||
@ -910,6 +920,7 @@ static const char *update(struct command *cmd, struct shallow_info *si)
|
||||
}
|
||||
|
||||
if (is_null_sha1(new_sha1)) {
|
||||
struct strbuf err = STRBUF_INIT;
|
||||
if (!parse_object(old_sha1)) {
|
||||
old_sha1 = NULL;
|
||||
if (ref_exists(name)) {
|
||||
@ -919,35 +930,36 @@ static const char *update(struct command *cmd, struct shallow_info *si)
|
||||
cmd->did_not_exist = 1;
|
||||
}
|
||||
}
|
||||
if (delete_ref(namespaced_name, old_sha1, 0)) {
|
||||
rp_error("failed to delete %s", name);
|
||||
if (ref_transaction_delete(transaction,
|
||||
namespaced_name,
|
||||
old_sha1,
|
||||
0, old_sha1 != NULL,
|
||||
"push", &err)) {
|
||||
rp_error("%s", err.buf);
|
||||
strbuf_release(&err);
|
||||
return "failed to delete";
|
||||
}
|
||||
strbuf_release(&err);
|
||||
return NULL; /* good */
|
||||
}
|
||||
else {
|
||||
struct strbuf err = STRBUF_INIT;
|
||||
struct ref_transaction *transaction;
|
||||
|
||||
if (shallow_update && si->shallow_ref[cmd->index] &&
|
||||
update_shallow_ref(cmd, si))
|
||||
return "shallow error";
|
||||
|
||||
transaction = ref_transaction_begin(&err);
|
||||
if (!transaction ||
|
||||
ref_transaction_update(transaction, namespaced_name,
|
||||
new_sha1, old_sha1, 0, 1, "push",
|
||||
&err) ||
|
||||
ref_transaction_commit(transaction, &err)) {
|
||||
ref_transaction_free(transaction);
|
||||
|
||||
if (ref_transaction_update(transaction,
|
||||
namespaced_name,
|
||||
new_sha1, old_sha1,
|
||||
0, 1, "push",
|
||||
&err)) {
|
||||
rp_error("%s", err.buf);
|
||||
strbuf_release(&err);
|
||||
|
||||
return "failed to update ref";
|
||||
}
|
||||
|
||||
ref_transaction_free(transaction);
|
||||
strbuf_release(&err);
|
||||
|
||||
return NULL; /* good */
|
||||
}
|
||||
}
|
||||
@ -1131,11 +1143,105 @@ static void reject_updates_to_hidden(struct command *commands)
|
||||
}
|
||||
}
|
||||
|
||||
static int should_process_cmd(struct command *cmd)
|
||||
{
|
||||
return !cmd->error_string && !cmd->skip_update;
|
||||
}
|
||||
|
||||
static void warn_if_skipped_connectivity_check(struct command *commands,
|
||||
struct shallow_info *si)
|
||||
{
|
||||
struct command *cmd;
|
||||
int checked_connectivity = 1;
|
||||
|
||||
for (cmd = commands; cmd; cmd = cmd->next) {
|
||||
if (should_process_cmd(cmd) && si->shallow_ref[cmd->index]) {
|
||||
error("BUG: connectivity check has not been run on ref %s",
|
||||
cmd->ref_name);
|
||||
checked_connectivity = 0;
|
||||
}
|
||||
}
|
||||
if (!checked_connectivity)
|
||||
die("BUG: connectivity check skipped???");
|
||||
}
|
||||
|
||||
static void execute_commands_non_atomic(struct command *commands,
|
||||
struct shallow_info *si)
|
||||
{
|
||||
struct command *cmd;
|
||||
struct strbuf err = STRBUF_INIT;
|
||||
|
||||
for (cmd = commands; cmd; cmd = cmd->next) {
|
||||
if (!should_process_cmd(cmd))
|
||||
continue;
|
||||
|
||||
transaction = ref_transaction_begin(&err);
|
||||
if (!transaction) {
|
||||
rp_error("%s", err.buf);
|
||||
strbuf_reset(&err);
|
||||
cmd->error_string = "transaction failed to start";
|
||||
continue;
|
||||
}
|
||||
|
||||
cmd->error_string = update(cmd, si);
|
||||
|
||||
if (!cmd->error_string
|
||||
&& ref_transaction_commit(transaction, &err)) {
|
||||
rp_error("%s", err.buf);
|
||||
strbuf_reset(&err);
|
||||
cmd->error_string = "failed to update ref";
|
||||
}
|
||||
ref_transaction_free(transaction);
|
||||
}
|
||||
strbuf_release(&err);
|
||||
}
|
||||
|
||||
static void execute_commands_atomic(struct command *commands,
|
||||
struct shallow_info *si)
|
||||
{
|
||||
struct command *cmd;
|
||||
struct strbuf err = STRBUF_INIT;
|
||||
const char *reported_error = "atomic push failure";
|
||||
|
||||
transaction = ref_transaction_begin(&err);
|
||||
if (!transaction) {
|
||||
rp_error("%s", err.buf);
|
||||
strbuf_reset(&err);
|
||||
reported_error = "transaction failed to start";
|
||||
goto failure;
|
||||
}
|
||||
|
||||
for (cmd = commands; cmd; cmd = cmd->next) {
|
||||
if (!should_process_cmd(cmd))
|
||||
continue;
|
||||
|
||||
cmd->error_string = update(cmd, si);
|
||||
|
||||
if (cmd->error_string)
|
||||
goto failure;
|
||||
}
|
||||
|
||||
if (ref_transaction_commit(transaction, &err)) {
|
||||
rp_error("%s", err.buf);
|
||||
reported_error = "atomic transaction failed";
|
||||
goto failure;
|
||||
}
|
||||
goto cleanup;
|
||||
|
||||
failure:
|
||||
for (cmd = commands; cmd; cmd = cmd->next)
|
||||
if (!cmd->error_string)
|
||||
cmd->error_string = reported_error;
|
||||
|
||||
cleanup:
|
||||
ref_transaction_free(transaction);
|
||||
strbuf_release(&err);
|
||||
}
|
||||
|
||||
static void execute_commands(struct command *commands,
|
||||
const char *unpacker_error,
|
||||
struct shallow_info *si)
|
||||
{
|
||||
int checked_connectivity;
|
||||
struct command *cmd;
|
||||
unsigned char sha1[20];
|
||||
struct iterate_data data;
|
||||
@ -1166,27 +1272,13 @@ static void execute_commands(struct command *commands,
|
||||
free(head_name_to_free);
|
||||
head_name = head_name_to_free = resolve_refdup("HEAD", 0, sha1, NULL);
|
||||
|
||||
checked_connectivity = 1;
|
||||
for (cmd = commands; cmd; cmd = cmd->next) {
|
||||
if (cmd->error_string)
|
||||
continue;
|
||||
if (use_atomic)
|
||||
execute_commands_atomic(commands, si);
|
||||
else
|
||||
execute_commands_non_atomic(commands, si);
|
||||
|
||||
if (cmd->skip_update)
|
||||
continue;
|
||||
|
||||
cmd->error_string = update(cmd, si);
|
||||
if (shallow_update && !cmd->error_string &&
|
||||
si->shallow_ref[cmd->index]) {
|
||||
error("BUG: connectivity check has not been run on ref %s",
|
||||
cmd->ref_name);
|
||||
checked_connectivity = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (shallow_update && !checked_connectivity)
|
||||
error("BUG: run 'git fsck' for safety.\n"
|
||||
"If there are errors, try to remove "
|
||||
"the reported refs above");
|
||||
if (shallow_update)
|
||||
warn_if_skipped_connectivity_check(commands, si);
|
||||
}
|
||||
|
||||
static struct command **queue_command(struct command **tail,
|
||||
@ -1268,6 +1360,9 @@ static struct command *read_head_info(struct sha1_array *shallow)
|
||||
use_sideband = LARGE_PACKET_MAX;
|
||||
if (parse_feature_request(feature_list, "quiet"))
|
||||
quiet = 1;
|
||||
if (advertise_atomic_push
|
||||
&& parse_feature_request(feature_list, "atomic"))
|
||||
use_atomic = 1;
|
||||
}
|
||||
|
||||
if (!strcmp(line, "push-cert")) {
|
||||
|
@ -13,7 +13,7 @@
|
||||
#include "sha1-array.h"
|
||||
|
||||
static const char send_pack_usage[] =
|
||||
"git send-pack [--all | --mirror] [--dry-run] [--force] [--receive-pack=<git-receive-pack>] [--verbose] [--thin] [<host>:]<directory> [<ref>...]\n"
|
||||
"git send-pack [--all | --mirror] [--dry-run] [--force] [--receive-pack=<git-receive-pack>] [--verbose] [--thin] [--atomic] [<host>:]<directory> [<ref>...]\n"
|
||||
" --all and explicit <ref> specification are mutually exclusive.";
|
||||
|
||||
static struct send_pack_args args;
|
||||
@ -170,6 +170,10 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
|
||||
args.use_thin_pack = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "--atomic")) {
|
||||
args.atomic = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "--stateless-rpc")) {
|
||||
args.stateless_rpc = 1;
|
||||
continue;
|
||||
|
Reference in New Issue
Block a user