@matheusbsbs / matheus-bagliano / commits / 3b990aa645
Fork 0

push: parse and set flag for "--force-if-includes"

The previous commit added the necessary machinery to implement the "--force-if-includes" protection, when "--force-with-lease" is used without giving exact object the remote still ought to have. Surface the feature by adding a command line option and a configuration variable to enable it. - Add a flag: "TRANSPORT_PUSH_FORCE_IF_INCLUDES" to indicate that the new option was passed from the command line of via configuration settings; update command line and configuration parsers to set the new flag accordingly. - Introduce a new configuration option "push.useForceIfIncludes", which is equivalent to setting "--force-if-includes" in the command line. - Update "remote-curl" to recognize and pass this option to "send-pack" when enabled. - Update "advise" to catch the reject reason "REJECT_REF_NEEDS_UPDATE", set when the ref status is "REF_STATUS_REJECT_REMOTE_UPDATED" and (optionally) print a help message when the push fails. - The new option is a "no-op" in the following scenarios: * When used without "--force-with-lease". * When used with "--force-with-lease", and if the expected commit on the remote side is specified as an argument. Signed-off-by: Srinidhi Kaushik <shrinidhi.kaushik@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Srinidhi Kaushik committed Oct 3, 2020 at 17:40 UTC 3b990aa645d1169b7373d12cbf1511ca4633e349
8 files changed +68 -6
advice.c
+3
@@ -11,6 +11,7 @@ int advice_push_already_exists = 1;
11 int advice_push_fetch_first = 1;
12 int advice_push_needs_force = 1;
13 int advice_push_unqualified_ref_name = 1;
14 +int advice_push_ref_needs_update = 1;
15 int advice_status_hints = 1;
16 int advice_status_u_option = 1;
17 int advice_status_ahead_behind_warning = 1;
@@ -72,6 +73,7 @@ static struct {
73 { "pushFetchFirst", &advice_push_fetch_first },
74 { "pushNeedsForce", &advice_push_needs_force },
75 { "pushUnqualifiedRefName", &advice_push_unqualified_ref_name },
76 + { "pushRefNeedsUpdate", &advice_push_ref_needs_update },
77 { "statusHints", &advice_status_hints },
78 { "statusUoption", &advice_status_u_option },
79 { "statusAheadBehindWarning", &advice_status_ahead_behind_warning },
@@ -116,6 +118,7 @@ static struct {
118 [ADVICE_PUSH_ALREADY_EXISTS] = { "pushAlreadyExists", 1 },
119 [ADVICE_PUSH_FETCH_FIRST] = { "pushFetchFirst", 1 },
120 [ADVICE_PUSH_NEEDS_FORCE] = { "pushNeedsForce", 1 },
121 + [ADVICE_PUSH_REF_NEEDS_UPDATE] = { "pushRefNeedsUpdate", 1 },
122
123 /* make this an alias for backward compatibility */
124 [ADVICE_PUSH_UPDATE_REJECTED_ALIAS] = { "pushNonFastForward", 1 },
advice.h
+2
@@ -11,6 +11,7 @@ extern int advice_push_already_exists;
11 extern int advice_push_fetch_first;
12 extern int advice_push_needs_force;
13 extern int advice_push_unqualified_ref_name;
14 +extern int advice_push_ref_needs_update;
15 extern int advice_status_hints;
16 extern int advice_status_u_option;
17 extern int advice_status_ahead_behind_warning;
@@ -60,6 +61,7 @@ extern int advice_add_empty_pathspec;
61 ADVICE_PUSH_UNQUALIFIED_REF_NAME,
62 ADVICE_PUSH_UPDATE_REJECTED_ALIAS,
63 ADVICE_PUSH_UPDATE_REJECTED,
64 + ADVICE_PUSH_REF_NEEDS_UPDATE,
65 ADVICE_RESET_QUIET_WARNING,
66 ADVICE_RESOLVE_CONFLICT,
67 ADVICE_RM_HINTS,
builtin/push.c
+27
@@ -290,6 +290,12 @@ static const char message_advice_ref_needs_force[] =
290 "or update a remote ref to make it point at a non-commit object,\n"
291 "without using the '--force' option.\n");
292
293 +static const char message_advice_ref_needs_update[] =
294 + N_("Updates were rejected because the tip of the remote-tracking\n"
295 + "branch has been updated since the last checkout. You may want\n"
296 + "to integrate those changes locally (e.g., 'git pull ...')\n"
297 + "before forcing an update.\n");
298 +
299 static void advise_pull_before_push(void)
300 {
301 if (!advice_push_non_ff_current || !advice_push_update_rejected)
@@ -325,6 +331,13 @@ static void advise_ref_needs_force(void)
331 advise(_(message_advice_ref_needs_force));
332 }
333
334 +static void advise_ref_needs_update(void)
335 +{
336 + if (!advice_push_ref_needs_update || !advice_push_update_rejected)
337 + return;
338 + advise(_(message_advice_ref_needs_update));
339 +}
340 +
341 static int push_with_options(struct transport *transport, struct refspec *rs,
342 int flags)
343 {
@@ -374,6 +387,8 @@ static int push_with_options(struct transport *transport, struct refspec *rs,
387 advise_ref_fetch_first();
388 } else if (reject_reasons & REJECT_NEEDS_FORCE) {
389 advise_ref_needs_force();
390 + } else if (reject_reasons & REJECT_REF_NEEDS_UPDATE) {
391 + advise_ref_needs_update();
392 }
393
394 return 1;
@@ -510,6 +525,12 @@ static int git_push_config(const char *k, const char *v, void *cb)
525 if (!v)
526 return config_error_nonbool(k);
527 return color_parse(v, push_colors[slot]);
528 + } else if (!strcmp(k, "push.useforceifincludes")) {
529 + if (git_config_bool(k, v))
530 + *flags |= TRANSPORT_PUSH_FORCE_IF_INCLUDES;
531 + else
532 + *flags &= ~TRANSPORT_PUSH_FORCE_IF_INCLUDES;
533 + return 0;
534 }
535
536 return git_default_config(k, v, NULL);
@@ -541,6 +562,9 @@ int cmd_push(int argc, const char **argv, const char *prefix)
562 OPT_CALLBACK_F(0, CAS_OPT_NAME, &cas, N_("<refname>:<expect>"),
563 N_("require old value of ref to be at this value"),
564 PARSE_OPT_OPTARG | PARSE_OPT_LITERAL_ARGHELP, parseopt_push_cas_option),
565 + OPT_BIT(0, TRANS_OPT_FORCE_IF_INCLUDES, &flags,
566 + N_("require remote updates to be integrated locally"),
567 + TRANSPORT_PUSH_FORCE_IF_INCLUDES),
568 OPT_CALLBACK(0, "recurse-submodules", &recurse_submodules, "(check|on-demand|no)",
569 N_("control recursive pushing of submodules"), option_parse_recurse_submodules),
570 OPT_BOOL_F( 0 , "thin", &thin, N_("use thin pack"), PARSE_OPT_NOCOMPLETE),
@@ -625,6 +649,9 @@ int cmd_push(int argc, const char **argv, const char *prefix)
649 if ((flags & TRANSPORT_PUSH_ALL) && (flags & TRANSPORT_PUSH_MIRROR))
650 die(_("--all and --mirror are incompatible"));
651
652 + if (!is_empty_cas(&cas) && (flags & TRANSPORT_PUSH_FORCE_IF_INCLUDES))
653 + cas.use_force_if_includes = 1;
654 +
655 for_each_string_list_item(item, push_options)
656 if (strchr(item->string, '\n'))
657 die(_("push options must not have new line characters"));
builtin/send-pack.c
+6
@@ -178,6 +178,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
178 int progress = -1;
179 int from_stdin = 0;
180 struct push_cas_option cas = {0};
181 + int force_if_includes = 0;
182 struct packet_reader reader;
183
184 struct option options[] = {
@@ -203,6 +204,8 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
204 OPT_CALLBACK_F(0, CAS_OPT_NAME, &cas, N_("<refname>:<expect>"),
205 N_("require old value of ref to be at this value"),
206 PARSE_OPT_OPTARG, parseopt_push_cas_option),
207 + OPT_BOOL(0, TRANS_OPT_FORCE_IF_INCLUDES, &force_if_includes,
208 + N_("require remote updates to be integrated locally")),
209 OPT_END()
210 };
211
@@ -304,6 +307,9 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
307 if (!is_empty_cas(&cas))
308 apply_push_cas(&cas, remote, remote_refs);
309
310 + if (!is_empty_cas(&cas) && force_if_includes)
311 + cas.use_force_if_includes = 1;
312 +
313 set_ref_status_for_push(remote_refs, args.send_mirror,
314 args.force_update);
315
remote-curl.c
+13 -1
@@ -44,7 +44,8 @@ struct options {
44 from_promisor : 1,
45
46 atomic : 1,
47 - object_format : 1;
47 + object_format : 1,
48 + force_if_includes : 1;
49 const struct git_hash_algo *hash_algo;
50 };
51 static struct options options;
@@ -131,6 +132,14 @@ static int set_option(const char *name, const char *value)
132 string_list_append(&cas_options, val.buf);
133 strbuf_release(&val);
134 return 0;
135 + } else if (!strcmp(name, TRANS_OPT_FORCE_IF_INCLUDES)) {
136 + if (!strcmp(value, "true"))
137 + options.force_if_includes = 1;
138 + else if (!strcmp(value, "false"))
139 + options.force_if_includes = 0;
140 + else
141 + return -1;
142 + return 0;
143 } else if (!strcmp(name, "cloning")) {
144 if (!strcmp(value, "true"))
145 options.cloning = 1;
@@ -1318,6 +1327,9 @@ static int push_git(struct discovery *heads, int nr_spec, const char **specs)
1327 strvec_push(&args, cas_option->string);
1328 strvec_push(&args, url.buf);
1329
1330 + if (options.force_if_includes)
1331 + strvec_push(&args, "--force-if-includes");
1332 +
1333 strvec_push(&args, "--stdin");
1334 for (i = 0; i < nr_spec; i++)
1335 packet_buf_write(&preamble, "%s\n", specs[i]);
transport-helper.c
+5
@@ -938,6 +938,11 @@ static void set_common_push_options(struct transport *transport,
938 if (set_helper_option(transport, TRANS_OPT_ATOMIC, "true") != 0)
939 die(_("helper %s does not support --atomic"), name);
940
941 + if (flags & TRANSPORT_PUSH_FORCE_IF_INCLUDES)
942 + if (set_helper_option(transport, TRANS_OPT_FORCE_IF_INCLUDES, "true") != 0)
943 + die(_("helper %s does not support --%s"),
944 + name, TRANS_OPT_FORCE_IF_INCLUDES);
945 +
946 if (flags & TRANSPORT_PUSH_OPTIONS) {
947 struct string_list_item *item;
948 for_each_string_list_item(item, transport->push_options)
transport.c
+2
@@ -748,6 +748,8 @@ void transport_print_push_status(const char *dest, struct ref *refs,
748 *reject_reasons |= REJECT_FETCH_FIRST;
749 } else if (ref->status == REF_STATUS_REJECT_NEEDS_FORCE) {
750 *reject_reasons |= REJECT_NEEDS_FORCE;
751 + } else if (ref->status == REF_STATUS_REJECT_REMOTE_UPDATED) {
752 + *reject_reasons |= REJECT_REF_NEEDS_UPDATE;
753 }
754 }
755 free(head);
transport.h
+10 -5
@@ -136,6 +136,7 @@ struct transport {
136 #define TRANSPORT_PUSH_ATOMIC (1<<13)
137 #define TRANSPORT_PUSH_OPTIONS (1<<14)
138 #define TRANSPORT_RECURSE_SUBMODULES_ONLY (1<<15)
139 +#define TRANSPORT_PUSH_FORCE_IF_INCLUDES (1<<16)
140
141 int transport_summary_width(const struct ref *refs);
142
@@ -208,6 +209,9 @@ void transport_check_allowed(const char *type);
209 /* Request atomic (all-or-nothing) updates when pushing */
210 #define TRANS_OPT_ATOMIC "atomic"
211
212 +/* Require remote changes to be integrated locally. */
213 +#define TRANS_OPT_FORCE_IF_INCLUDES "force-if-includes"
214 +
215 /**
216 * Returns 0 if the option was used, non-zero otherwise. Prints a
217 * message to stderr if the option is not used.
@@ -217,11 +221,12 @@ int transport_set_option(struct transport *transport, const char *name,
221 void transport_set_verbosity(struct transport *transport, int verbosity,
222 int force_progress);
223
220 -#define REJECT_NON_FF_HEAD 0x01
221 -#define REJECT_NON_FF_OTHER 0x02
222 -#define REJECT_ALREADY_EXISTS 0x04
223 -#define REJECT_FETCH_FIRST 0x08
224 -#define REJECT_NEEDS_FORCE 0x10
224 +#define REJECT_NON_FF_HEAD 0x01
225 +#define REJECT_NON_FF_OTHER 0x02
226 +#define REJECT_ALREADY_EXISTS 0x04
227 +#define REJECT_FETCH_FIRST 0x08
228 +#define REJECT_NEEDS_FORCE 0x10
229 +#define REJECT_REF_NEEDS_UPDATE 0x20
230
231 int transport_push(struct repository *repo,
232 struct transport *connection,