Skip to content

Commit 370855e

Browse files
committed
Merge branch 'jc/push-reject-reasons'
Improve error and advice messages given locally when "git push" refuses when it cannot compute fast-forwardness by separating these cases from the normal "not a fast-forward; merge first and push again" case. * jc/push-reject-reasons: push: finishing touches to explain REJECT_ALREADY_EXISTS better push: introduce REJECT_FETCH_FIRST and REJECT_NEEDS_FORCE push: further simplify the logic to assign rejection reason push: further clean up fields of "struct ref"
2 parents 099ba55 + b4cf8db commit 370855e

File tree

11 files changed

+107
-30
lines changed

11 files changed

+107
-30
lines changed

Documentation/config.txt

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,8 @@ advice.*::
143143
pushUpdateRejected::
144144
Set this variable to 'false' if you want to disable
145145
'pushNonFFCurrent', 'pushNonFFDefault',
146-
'pushNonFFMatching', and 'pushAlreadyExists'
146+
'pushNonFFMatching', 'pushAlreadyExists',
147+
'pushFetchFirst', and 'pushNeedsForce'
147148
simultaneously.
148149
pushNonFFCurrent::
149150
Advice shown when linkgit:git-push[1] fails due to a
@@ -162,6 +163,15 @@ advice.*::
162163
pushAlreadyExists::
163164
Shown when linkgit:git-push[1] rejects an update that
164165
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.
165175
statusHints::
166176
Show directions on how to proceed from the current
167177
state in the output of linkgit:git-status[1], in

advice.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ int advice_push_non_ff_current = 1;
55
int advice_push_non_ff_default = 1;
66
int advice_push_non_ff_matching = 1;
77
int advice_push_already_exists = 1;
8+
int advice_push_fetch_first = 1;
9+
int advice_push_needs_force = 1;
810
int advice_status_hints = 1;
911
int advice_commit_before_merge = 1;
1012
int advice_resolve_conflict = 1;
@@ -20,6 +22,8 @@ static struct {
2022
{ "pushnonffdefault", &advice_push_non_ff_default },
2123
{ "pushnonffmatching", &advice_push_non_ff_matching },
2224
{ "pushalreadyexists", &advice_push_already_exists },
25+
{ "pushfetchfirst", &advice_push_fetch_first },
26+
{ "pushneedsforce", &advice_push_needs_force },
2327
{ "statushints", &advice_status_hints },
2428
{ "commitbeforemerge", &advice_commit_before_merge },
2529
{ "resolveconflict", &advice_resolve_conflict },

advice.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ extern int advice_push_non_ff_current;
88
extern int advice_push_non_ff_default;
99
extern int advice_push_non_ff_matching;
1010
extern int advice_push_already_exists;
11+
extern int advice_push_fetch_first;
12+
extern int advice_push_needs_force;
1113
extern int advice_status_hints;
1214
extern int advice_commit_before_merge;
1315
extern int advice_resolve_conflict;

builtin/push.c

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -220,9 +220,20 @@ static const char message_advice_checkout_pull_push[] =
220220
"(e.g. 'git pull') before pushing again.\n"
221221
"See the 'Note about fast-forwards' in 'git push --help' for details.");
222222

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+
223230
static const char message_advice_ref_already_exists[] =
224-
N_("Updates were rejected because the destination reference already exists\n"
225-
"in the remote.");
231+
N_("Updates were rejected because the tag already exists in the remote.");
232+
233+
static const char message_advice_ref_needs_force[] =
234+
N_("You cannot update a remote ref that points at a non-commit object,\n"
235+
"or update a remote ref to make it point at a non-commit object,\n"
236+
"without using the '--force' option.\n");
226237

227238
static void advise_pull_before_push(void)
228239
{
@@ -252,6 +263,20 @@ static void advise_ref_already_exists(void)
252263
advise(_(message_advice_ref_already_exists));
253264
}
254265

266+
static void advise_ref_fetch_first(void)
267+
{
268+
if (!advice_push_fetch_first || !advice_push_update_rejected)
269+
return;
270+
advise(_(message_advice_ref_fetch_first));
271+
}
272+
273+
static void advise_ref_needs_force(void)
274+
{
275+
if (!advice_push_needs_force || !advice_push_update_rejected)
276+
return;
277+
advise(_(message_advice_ref_needs_force));
278+
}
279+
255280
static int push_with_options(struct transport *transport, int flags)
256281
{
257282
int err;
@@ -285,6 +310,10 @@ static int push_with_options(struct transport *transport, int flags)
285310
advise_checkout_pull_push();
286311
} else if (reject_reasons & REJECT_ALREADY_EXISTS) {
287312
advise_ref_already_exists();
313+
} else if (reject_reasons & REJECT_FETCH_FIRST) {
314+
advise_ref_fetch_first();
315+
} else if (reject_reasons & REJECT_NEEDS_FORCE) {
316+
advise_ref_needs_force();
288317
}
289318

290319
return 1;

builtin/send-pack.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,16 @@ static void print_helper_status(struct ref *ref)
4444
msg = "non-fast forward";
4545
break;
4646

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+
4757
case REF_STATUS_REJECT_ALREADY_EXISTS:
4858
res = "error";
4959
msg = "already exists";

cache.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1015,17 +1015,17 @@ struct ref {
10151015
char *symref;
10161016
unsigned int
10171017
force:1,
1018-
requires_force:1,
1018+
forced_update:1,
10191019
merge:1,
1020-
nonfastforward:1,
1021-
update:1,
10221020
deletion:1;
10231021
enum {
10241022
REF_STATUS_NONE = 0,
10251023
REF_STATUS_OK,
10261024
REF_STATUS_REJECT_NONFASTFORWARD,
10271025
REF_STATUS_REJECT_ALREADY_EXISTS,
10281026
REF_STATUS_REJECT_NODELETE,
1027+
REF_STATUS_REJECT_FETCH_FIRST,
1028+
REF_STATUS_REJECT_NEEDS_FORCE,
10291029
REF_STATUS_UPTODATE,
10301030
REF_STATUS_REMOTE_REJECT,
10311031
REF_STATUS_EXPECTING_REPORT

remote.c

Lines changed: 19 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1317,28 +1317,23 @@ void set_ref_status_for_push(struct ref *remote_refs, int send_mirror,
13171317
* passing the --force argument
13181318
*/
13191319

1320-
ref->update =
1321-
!ref->deletion &&
1322-
!is_null_sha1(ref->old_sha1);
1323-
1324-
if (ref->update) {
1325-
ref->nonfastforward =
1326-
!has_sha1_file(ref->old_sha1)
1327-
|| !ref_newer(ref->new_sha1, ref->old_sha1);
1328-
1329-
if (!prefixcmp(ref->name, "refs/tags/")) {
1330-
ref->requires_force = 1;
1331-
if (!force_ref_update) {
1332-
ref->status = REF_STATUS_REJECT_ALREADY_EXISTS;
1333-
continue;
1334-
}
1335-
} else if (ref->nonfastforward) {
1336-
ref->requires_force = 1;
1337-
if (!force_ref_update) {
1338-
ref->status = REF_STATUS_REJECT_NONFASTFORWARD;
1339-
continue;
1340-
}
1341-
}
1320+
if (!ref->deletion && !is_null_sha1(ref->old_sha1)) {
1321+
int why = 0; /* why would this push require --force? */
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+
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)
1334+
ref->status = why;
1335+
else if (why)
1336+
ref->forced_update = 1;
13421337
}
13431338
}
13441339
}
@@ -1532,7 +1527,8 @@ int ref_newer(const unsigned char *new_sha1, const unsigned char *old_sha1)
15321527
struct commit_list *list, *used;
15331528
int found = 0;
15341529

1535-
/* Both new and old must be commit-ish and new is descendant of
1530+
/*
1531+
* Both new and old must be commit-ish and new is descendant of
15361532
* old. Otherwise we require --force.
15371533
*/
15381534
o = deref_tag(parse_object(old_sha1), NULL, 0);

send-pack.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,8 @@ int send_pack(struct send_pack_args *args,
230230
switch (ref->status) {
231231
case REF_STATUS_REJECT_NONFASTFORWARD:
232232
case REF_STATUS_REJECT_ALREADY_EXISTS:
233+
case REF_STATUS_REJECT_FETCH_FIRST:
234+
case REF_STATUS_REJECT_NEEDS_FORCE:
233235
case REF_STATUS_UPTODATE:
234236
continue;
235237
default:

transport-helper.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -666,6 +666,16 @@ static void push_update_ref_status(struct strbuf *buf,
666666
free(msg);
667667
msg = NULL;
668668
}
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+
}
669679
}
670680

671681
if (*ref)

transport.c

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -659,7 +659,7 @@ static void print_ok_ref_status(struct ref *ref, int porcelain)
659659
const char *msg;
660660

661661
strcpy(quickref, status_abbrev(ref->old_sha1));
662-
if (ref->requires_force) {
662+
if (ref->forced_update) {
663663
strcat(quickref, "...");
664664
type = '+';
665665
msg = "forced update";
@@ -699,6 +699,14 @@ static int print_one_push_status(struct ref *ref, const char *dest, int count, i
699699
print_ref_status('!', "[rejected]", ref, ref->peer_ref,
700700
"already exists", porcelain);
701701
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;
702710
case REF_STATUS_REMOTE_REJECT:
703711
print_ref_status('!', "[remote rejected]", ref,
704712
ref->deletion ? NULL : ref->peer_ref,
@@ -750,6 +758,10 @@ void transport_print_push_status(const char *dest, struct ref *refs,
750758
*reject_reasons |= REJECT_NON_FF_OTHER;
751759
} else if (ref->status == REF_STATUS_REJECT_ALREADY_EXISTS) {
752760
*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;
753765
}
754766
}
755767
}

0 commit comments

Comments
 (0)