push: introduce REJECT_FETCH_FIRST and REJECT_NEEDS_FORCE

When we push to update an existing ref, if: * the object at the tip of the remote is not a commit; or * the object we are pushing is not a commit, it won't be correct to suggest to fetch, integrate and push again, as the old and new objects will not "merge". We should explain that the push must be forced when there is a non-committish object is involved in such a case. If we do not have the current object at the tip of the remote, we do not even know that object, when fetched, is something that can be merged. In such a case, suggesting to pull first just like non-fast-forward case may not be technically correct, but in practice, most such failures are seen when you try to push your work to a branch without knowing that somebody else already pushed to update the same branch since you forked, so "pull first" would work as a suggestion most of the time. And if the object at the tip is not a commit, "pull first" will fail, without making any permanent damage. As a side effect, it also makes the error message the user will get during the next "push" attempt easier to understand, now the user is aware that a non-commit object is involved. In these cases, the current code already rejects such a push on the client end, but we used the same error and advice messages as the ones used when rejecting a non-fast-forward push, i.e. pull from there and integrate before pushing again. Introduce new rejection reasons and reword the messages appropriately. [jc: with help by Peff on message details] Signed-off-by: Junio C Hamano <gitster@pobox.com>

Junio C Hamano committed Jan 23, 2013 at 13:55 UTC 75e5c0dc5529aed42122b3a774e6b17383e51b66
11 files changed +93 -4
Documentation/config.txt
+11 -1
@@ -143,7 +143,8 @@ advice.*::
143 pushUpdateRejected::
144 Set this variable to 'false' if you want to disable
145 'pushNonFFCurrent', 'pushNonFFDefault',
146 - 'pushNonFFMatching', and 'pushAlreadyExists'
146 + 'pushNonFFMatching', 'pushAlreadyExists',
147 + 'pushFetchFirst', and 'pushNeedsForce'
148 simultaneously.
149 pushNonFFCurrent::
150 Advice shown when linkgit:git-push[1] fails due to a
@@ -162,6 +163,15 @@ advice.*::
163 pushAlreadyExists::
164 Shown when linkgit:git-push[1] rejects an update that
165 does not qualify for fast-forwarding (e.g., a tag.)
166 + pushFetchFirst::
167 + Shown when linkgit:git-push[1] rejects an update that
168 + tries to overwrite a remote ref that points at an
169 + object we do not have.
170 + pushNeedsForce::
171 + Shown when linkgit:git-push[1] rejects an update that
172 + tries to overwrite a remote ref that points at an
173 + object that is not a committish, or make the remote
174 + ref point at an object that is not a committish.
175 statusHints::
176 Show directions on how to proceed from the current
177 state in the output of linkgit:git-status[1] and in
advice.c
+4
@@ -5,6 +5,8 @@ int advice_push_non_ff_current = 1;
5 int advice_push_non_ff_default = 1;
6 int advice_push_non_ff_matching = 1;
7 int advice_push_already_exists = 1;
8 +int advice_push_fetch_first = 1;
9 +int advice_push_needs_force = 1;
10 int advice_status_hints = 1;
11 int advice_commit_before_merge = 1;
12 int advice_resolve_conflict = 1;
@@ -20,6 +22,8 @@ static struct {
22 { "pushnonffdefault", &advice_push_non_ff_default },
23 { "pushnonffmatching", &advice_push_non_ff_matching },
24 { "pushalreadyexists", &advice_push_already_exists },
25 + { "pushfetchfirst", &advice_push_fetch_first },
26 + { "pushneedsforce", &advice_push_needs_force },
27 { "statushints", &advice_status_hints },
28 { "commitbeforemerge", &advice_commit_before_merge },
29 { "resolveconflict", &advice_resolve_conflict },
advice.h
+2
@@ -8,6 +8,8 @@ extern int advice_push_non_ff_current;
8 extern int advice_push_non_ff_default;
9 extern int advice_push_non_ff_matching;
10 extern int advice_push_already_exists;
11 +extern int advice_push_fetch_first;
12 +extern int advice_push_needs_force;
13 extern int advice_status_hints;
14 extern int advice_commit_before_merge;
15 extern int advice_resolve_conflict;
builtin/push.c
+30
@@ -220,10 +220,22 @@ static const char message_advice_checkout_pull_push[] =
220 "(e.g. 'git pull') before pushing again.\n"
221 "See the 'Note about fast-forwards' in 'git push --help' for details.");
222
223 +static const char message_advice_ref_fetch_first[] =
224 + N_("Updates were rejected because the remote contains work that you do\n"
225 + "not have locally. This is usually caused by another repository pushing\n"
226 + "to the same ref. You may want to first merge the remote changes (e.g.,\n"
227 + "'git pull') before pushing again.\n"
228 + "See the 'Note about fast-forwards' in 'git push --help' for details.");
229 +
230 static const char message_advice_ref_already_exists[] =
231 N_("Updates were rejected because the destination reference already exists\n"
232 "in the remote.");
233
234 +static const char message_advice_ref_needs_force[] =
235 + N_("You cannot update a remote ref that points at a non-commit object,\n"
236 + "or update a remote ref to make it point at a non-commit object,\n"
237 + "without using the '--force' option.\n");
238 +
239 static void advise_pull_before_push(void)
240 {
241 if (!advice_push_non_ff_current || !advice_push_update_rejected)
@@ -252,6 +264,20 @@ static void advise_ref_already_exists(void)
264 advise(_(message_advice_ref_already_exists));
265 }
266
267 +static void advise_ref_fetch_first(void)
268 +{
269 + if (!advice_push_fetch_first || !advice_push_update_rejected)
270 + return;
271 + advise(_(message_advice_ref_fetch_first));
272 +}
273 +
274 +static void advise_ref_needs_force(void)
275 +{
276 + if (!advice_push_needs_force || !advice_push_update_rejected)
277 + return;
278 + advise(_(message_advice_ref_needs_force));
279 +}
280 +
281 static int push_with_options(struct transport *transport, int flags)
282 {
283 int err;
@@ -285,6 +311,10 @@ static int push_with_options(struct transport *transport, int flags)
311 advise_checkout_pull_push();
312 } else if (reject_reasons & REJECT_ALREADY_EXISTS) {
313 advise_ref_already_exists();
314 + } else if (reject_reasons & REJECT_FETCH_FIRST) {
315 + advise_ref_fetch_first();
316 + } else if (reject_reasons & REJECT_NEEDS_FORCE) {
317 + advise_ref_needs_force();
318 }
319
320 return 1;
builtin/send-pack.c
+10
@@ -44,6 +44,16 @@ static void print_helper_status(struct ref *ref)
44 msg = "non-fast forward";
45 break;
46
47 + case REF_STATUS_REJECT_FETCH_FIRST:
48 + res = "error";
49 + msg = "fetch first";
50 + break;
51 +
52 + case REF_STATUS_REJECT_NEEDS_FORCE:
53 + res = "error";
54 + msg = "needs force";
55 + break;
56 +
57 case REF_STATUS_REJECT_ALREADY_EXISTS:
58 res = "error";
59 msg = "already exists";
cache.h
+2
@@ -1010,6 +1010,8 @@ struct ref {
1010 REF_STATUS_REJECT_NONFASTFORWARD,
1011 REF_STATUS_REJECT_ALREADY_EXISTS,
1012 REF_STATUS_REJECT_NODELETE,
1013 + REF_STATUS_REJECT_FETCH_FIRST,
1014 + REF_STATUS_REJECT_NEEDS_FORCE,
1015 REF_STATUS_UPTODATE,
1016 REF_STATUS_REMOTE_REJECT,
1017 REF_STATUS_EXPECTING_REPORT
remote.c
+8 -3
@@ -1322,8 +1322,12 @@ void set_ref_status_for_push(struct ref *remote_refs, int send_mirror,
1322
1323 if (!prefixcmp(ref->name, "refs/tags/"))
1324 why = REF_STATUS_REJECT_ALREADY_EXISTS;
1325 - else if (!has_sha1_file(ref->old_sha1)
1326 - || !ref_newer(ref->new_sha1, ref->old_sha1))
1325 + else if (!has_sha1_file(ref->old_sha1))
1326 + why = REF_STATUS_REJECT_FETCH_FIRST;
1327 + else if (!lookup_commit_reference_gently(ref->old_sha1, 1) ||
1328 + !lookup_commit_reference_gently(ref->new_sha1, 1))
1329 + why = REF_STATUS_REJECT_NEEDS_FORCE;
1330 + else if (!ref_newer(ref->new_sha1, ref->old_sha1))
1331 why = REF_STATUS_REJECT_NONFASTFORWARD;
1332
1333 if (!force_ref_update)
@@ -1512,7 +1516,8 @@ int ref_newer(const unsigned char *new_sha1, const unsigned char *old_sha1)
1516 struct commit_list *list, *used;
1517 int found = 0;
1518
1515 - /* Both new and old must be commit-ish and new is descendant of
1519 + /*
1520 + * Both new and old must be commit-ish and new is descendant of
1521 * old. Otherwise we require --force.
1522 */
1523 o = deref_tag(parse_object(old_sha1), NULL, 0);
send-pack.c
+2
@@ -230,6 +230,8 @@ int send_pack(struct send_pack_args *args,
230 switch (ref->status) {
231 case REF_STATUS_REJECT_NONFASTFORWARD:
232 case REF_STATUS_REJECT_ALREADY_EXISTS:
233 + case REF_STATUS_REJECT_FETCH_FIRST:
234 + case REF_STATUS_REJECT_NEEDS_FORCE:
235 case REF_STATUS_UPTODATE:
236 continue;
237 default:
transport-helper.c
+10
@@ -666,6 +666,16 @@ static void push_update_ref_status(struct strbuf *buf,
666 free(msg);
667 msg = NULL;
668 }
669 + else if (!strcmp(msg, "fetch first")) {
670 + status = REF_STATUS_REJECT_FETCH_FIRST;
671 + free(msg);
672 + msg = NULL;
673 + }
674 + else if (!strcmp(msg, "needs force")) {
675 + status = REF_STATUS_REJECT_NEEDS_FORCE;
676 + free(msg);
677 + msg = NULL;
678 + }
679 }
680
681 if (*ref)
transport.c
+12
@@ -699,6 +699,14 @@ static int print_one_push_status(struct ref *ref, const char *dest, int count, i
699 print_ref_status('!', "[rejected]", ref, ref->peer_ref,
700 "already exists", porcelain);
701 break;
702 + case REF_STATUS_REJECT_FETCH_FIRST:
703 + print_ref_status('!', "[rejected]", ref, ref->peer_ref,
704 + "fetch first", porcelain);
705 + break;
706 + case REF_STATUS_REJECT_NEEDS_FORCE:
707 + print_ref_status('!', "[rejected]", ref, ref->peer_ref,
708 + "needs force", porcelain);
709 + break;
710 case REF_STATUS_REMOTE_REJECT:
711 print_ref_status('!', "[remote rejected]", ref,
712 ref->deletion ? NULL : ref->peer_ref,
@@ -750,6 +758,10 @@ void transport_print_push_status(const char *dest, struct ref *refs,
758 *reject_reasons |= REJECT_NON_FF_OTHER;
759 } else if (ref->status == REF_STATUS_REJECT_ALREADY_EXISTS) {
760 *reject_reasons |= REJECT_ALREADY_EXISTS;
761 + } else if (ref->status == REF_STATUS_REJECT_FETCH_FIRST) {
762 + *reject_reasons |= REJECT_FETCH_FIRST;
763 + } else if (ref->status == REF_STATUS_REJECT_NEEDS_FORCE) {
764 + *reject_reasons |= REJECT_NEEDS_FORCE;
765 }
766 }
767 }
transport.h
+2
@@ -143,6 +143,8 @@ void transport_set_verbosity(struct transport *transport, int verbosity,
143 #define REJECT_NON_FF_HEAD 0x01
144 #define REJECT_NON_FF_OTHER 0x02
145 #define REJECT_ALREADY_EXISTS 0x04
146 +#define REJECT_FETCH_FIRST 0x08
147 +#define REJECT_NEEDS_FORCE 0x10
148
149 int transport_push(struct transport *connection,
150 int refspec_nr, const char **refspec, int flags,