Merge branch 'ct/advise-push-default' into maint
The cases "git push" fails due to non-ff can be broken into three categories; each case is given a separate advise message. By Christopher Tiwald (2) and Jeff King (1) * ct/advise-push-default: Fix httpd tests that broke when non-ff push advice changed clean up struct ref's nonfastforward field push: Provide situational hints for non-fast-forward errorsmaint
						commit
						07e74b0da2
					
				|  | @ -141,8 +141,23 @@ advice.*:: | |||
| + | ||||
| -- | ||||
| 	pushNonFastForward:: | ||||
| 		Advice shown when linkgit:git-push[1] refuses | ||||
| 		non-fast-forward refs. | ||||
| 		Set this variable to 'false' if you want to disable | ||||
| 		'pushNonFFCurrent', 'pushNonFFDefault', and | ||||
| 		'pushNonFFMatching' simultaneously. | ||||
| 	pushNonFFCurrent:: | ||||
| 		Advice shown when linkgit:git-push[1] fails due to a | ||||
| 		non-fast-forward update to the current branch. | ||||
| 	pushNonFFDefault:: | ||||
| 		Advice to set 'push.default' to 'upstream' or 'current' | ||||
| 		when you ran linkgit:git-push[1] and pushed 'matching | ||||
| 		refs' by default (i.e. you did not provide an explicit | ||||
| 		refspec, and no 'push.default' configuration was set) | ||||
| 		and it resulted in a non-fast-forward error. | ||||
| 	pushNonFFMatching:: | ||||
| 		Advice shown when you ran linkgit:git-push[1] and pushed | ||||
| 		'matching refs' explicitly (i.e. you used ':', or | ||||
| 		specified a refspec that isn't your current branch) and | ||||
| 		it resulted in a non-fast-forward error. | ||||
| 	statusHints:: | ||||
| 		Directions on how to stage/unstage/add shown in the | ||||
| 		output of linkgit:git-status[1] and the template shown | ||||
|  |  | |||
							
								
								
									
										6
									
								
								advice.c
								
								
								
								
							
							
						
						
									
										6
									
								
								advice.c
								
								
								
								
							|  | @ -1,6 +1,9 @@ | |||
| #include "cache.h" | ||||
|  | ||||
| int advice_push_nonfastforward = 1; | ||||
| int advice_push_non_ff_current = 1; | ||||
| int advice_push_non_ff_default = 1; | ||||
| int advice_push_non_ff_matching = 1; | ||||
| int advice_status_hints = 1; | ||||
| int advice_commit_before_merge = 1; | ||||
| int advice_resolve_conflict = 1; | ||||
|  | @ -12,6 +15,9 @@ static struct { | |||
| 	int *preference; | ||||
| } advice_config[] = { | ||||
| 	{ "pushnonfastforward", &advice_push_nonfastforward }, | ||||
| 	{ "pushnonffcurrent", &advice_push_non_ff_current }, | ||||
| 	{ "pushnonffdefault", &advice_push_non_ff_default }, | ||||
| 	{ "pushnonffmatching", &advice_push_non_ff_matching }, | ||||
| 	{ "statushints", &advice_status_hints }, | ||||
| 	{ "commitbeforemerge", &advice_commit_before_merge }, | ||||
| 	{ "resolveconflict", &advice_resolve_conflict }, | ||||
|  |  | |||
							
								
								
									
										3
									
								
								advice.h
								
								
								
								
							
							
						
						
									
										3
									
								
								advice.h
								
								
								
								
							|  | @ -4,6 +4,9 @@ | |||
| #include "git-compat-util.h" | ||||
|  | ||||
| extern int advice_push_nonfastforward; | ||||
| extern int advice_push_non_ff_current; | ||||
| extern int advice_push_non_ff_default; | ||||
| extern int advice_push_non_ff_matching; | ||||
| extern int advice_status_hints; | ||||
| extern int advice_commit_before_merge; | ||||
| extern int advice_resolve_conflict; | ||||
|  |  | |||
|  | @ -24,6 +24,7 @@ static int progress = -1; | |||
| static const char **refspec; | ||||
| static int refspec_nr; | ||||
| static int refspec_alloc; | ||||
| static int default_matching_used; | ||||
|  | ||||
| static void add_refspec(const char *ref) | ||||
| { | ||||
|  | @ -111,6 +112,9 @@ static void setup_default_push_refspecs(struct remote *remote) | |||
| { | ||||
| 	switch (push_default) { | ||||
| 	default: | ||||
| 	case PUSH_DEFAULT_UNSPECIFIED: | ||||
| 		default_matching_used = 1; | ||||
| 		/* fallthru */ | ||||
| 	case PUSH_DEFAULT_MATCHING: | ||||
| 		add_refspec(":"); | ||||
| 		break; | ||||
|  | @ -130,6 +134,45 @@ static void setup_default_push_refspecs(struct remote *remote) | |||
| 	} | ||||
| } | ||||
|  | ||||
| static const char message_advice_pull_before_push[] = | ||||
| 	N_("Updates were rejected because the tip of your current branch is behind\n" | ||||
| 	   "its remote counterpart. Merge the remote changes (e.g. 'git pull')\n" | ||||
| 	   "before pushing again.\n" | ||||
| 	   "See the 'Note about fast-forwards' in 'git push --help' for details."); | ||||
|  | ||||
| static const char message_advice_use_upstream[] = | ||||
| 	N_("Updates were rejected because a pushed branch tip is behind its remote\n" | ||||
| 	   "counterpart. If you did not intend to push that branch, you may want to\n" | ||||
| 	   "specify branches to push or set the 'push.default' configuration\n" | ||||
| 	   "variable to 'current' or 'upstream' to push only the current branch."); | ||||
|  | ||||
| static const char message_advice_checkout_pull_push[] = | ||||
| 	N_("Updates were rejected because a pushed branch tip is behind its remote\n" | ||||
| 	   "counterpart. Check out this branch and merge the remote changes\n" | ||||
| 	   "(e.g. 'git pull') before pushing again.\n" | ||||
| 	   "See the 'Note about fast-forwards' in 'git push --help' for details."); | ||||
|  | ||||
| static void advise_pull_before_push(void) | ||||
| { | ||||
| 	if (!advice_push_non_ff_current || !advice_push_nonfastforward) | ||||
| 		return; | ||||
| 	advise(_(message_advice_pull_before_push)); | ||||
| } | ||||
|  | ||||
| static void advise_use_upstream(void) | ||||
| { | ||||
| 	if (!advice_push_non_ff_default || !advice_push_nonfastforward) | ||||
| 		return; | ||||
| 	advise(_(message_advice_use_upstream)); | ||||
| } | ||||
|  | ||||
| static void advise_checkout_pull_push(void) | ||||
| { | ||||
| 	if (!advice_push_non_ff_matching || !advice_push_nonfastforward) | ||||
| 		return; | ||||
| 	advise(_(message_advice_checkout_pull_push)); | ||||
| } | ||||
|  | ||||
| static int push_with_options(struct transport *transport, int flags) | ||||
| { | ||||
| 	int err; | ||||
|  | @ -151,14 +194,21 @@ static int push_with_options(struct transport *transport, int flags) | |||
| 		error(_("failed to push some refs to '%s'"), transport->url); | ||||
|  | ||||
| 	err |= transport_disconnect(transport); | ||||
|  | ||||
| 	if (!err) | ||||
| 		return 0; | ||||
|  | ||||
| 	if (nonfastforward && advice_push_nonfastforward) { | ||||
| 		fprintf(stderr, _("To prevent you from losing history, non-fast-forward updates were rejected\n" | ||||
| 				"Merge the remote changes (e.g. 'git pull') before pushing again.  See the\n" | ||||
| 				"'Note about fast-forwards' section of 'git push --help' for details.\n")); | ||||
| 	switch (nonfastforward) { | ||||
| 	default: | ||||
| 		break; | ||||
| 	case NON_FF_HEAD: | ||||
| 		advise_pull_before_push(); | ||||
| 		break; | ||||
| 	case NON_FF_OTHER: | ||||
| 		if (default_matching_used) | ||||
| 			advise_use_upstream(); | ||||
| 		else | ||||
| 			advise_checkout_pull_push(); | ||||
| 		break; | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
|  |  | |||
							
								
								
									
										3
									
								
								cache.h
								
								
								
								
							
							
						
						
									
										3
									
								
								cache.h
								
								
								
								
							|  | @ -625,7 +625,8 @@ enum push_default_type { | |||
| 	PUSH_DEFAULT_NOTHING = 0, | ||||
| 	PUSH_DEFAULT_MATCHING, | ||||
| 	PUSH_DEFAULT_UPSTREAM, | ||||
| 	PUSH_DEFAULT_CURRENT | ||||
| 	PUSH_DEFAULT_CURRENT, | ||||
| 	PUSH_DEFAULT_UNSPECIFIED | ||||
| }; | ||||
|  | ||||
| extern enum branch_track git_branch_track; | ||||
|  |  | |||
|  | @ -52,7 +52,7 @@ enum safe_crlf safe_crlf = SAFE_CRLF_WARN; | |||
| unsigned whitespace_rule_cfg = WS_DEFAULT_RULE; | ||||
| enum branch_track git_branch_track = BRANCH_TRACK_REMOTE; | ||||
| enum rebase_setup_type autorebase = AUTOREBASE_NEVER; | ||||
| enum push_default_type push_default = PUSH_DEFAULT_MATCHING; | ||||
| enum push_default_type push_default = PUSH_DEFAULT_UNSPECIFIED; | ||||
| #ifndef OBJECT_CREATION_MODE | ||||
| #define OBJECT_CREATION_MODE OBJECT_CREATION_USES_HARDLINKS | ||||
| #endif | ||||
|  |  | |||
|  | @ -160,6 +160,6 @@ test_http_push_nonff() { | |||
| 	' | ||||
|  | ||||
| 	test_expect_success 'non-fast-forward push shows help message' ' | ||||
| 		test_i18ngrep "To prevent you from losing history, non-fast-forward updates were rejected" output | ||||
| 		test_i18ngrep "Updates were rejected because" output | ||||
| 	' | ||||
| } | ||||
|  |  | |||
|  | @ -168,7 +168,7 @@ test_expect_success 'push fails for non-fast-forward refs unmatched by remote he | |||
| ' | ||||
|  | ||||
| test_expect_success 'push fails for non-fast-forward refs unmatched by remote helper: our output' ' | ||||
| 	test_i18ngrep "To prevent you from losing history, non-fast-forward updates were rejected" \ | ||||
| 	test_i18ngrep "Updates were rejected because" \ | ||||
| 		output | ||||
| ' | ||||
|  | ||||
|  |  | |||
							
								
								
									
										13
									
								
								transport.c
								
								
								
								
							
							
						
						
									
										13
									
								
								transport.c
								
								
								
								
							|  | @ -721,6 +721,10 @@ void transport_print_push_status(const char *dest, struct ref *refs, | |||
| { | ||||
| 	struct ref *ref; | ||||
| 	int n = 0; | ||||
| 	unsigned char head_sha1[20]; | ||||
| 	char *head; | ||||
|  | ||||
| 	head = resolve_refdup("HEAD", head_sha1, 1, NULL); | ||||
|  | ||||
| 	if (verbose) { | ||||
| 		for (ref = refs; ref; ref = ref->next) | ||||
|  | @ -738,8 +742,13 @@ void transport_print_push_status(const char *dest, struct ref *refs, | |||
| 		    ref->status != REF_STATUS_UPTODATE && | ||||
| 		    ref->status != REF_STATUS_OK) | ||||
| 			n += print_one_push_status(ref, dest, n, porcelain); | ||||
| 		if (ref->status == REF_STATUS_REJECT_NONFASTFORWARD) | ||||
| 			*nonfastforward = 1; | ||||
| 		if (ref->status == REF_STATUS_REJECT_NONFASTFORWARD && | ||||
| 		    *nonfastforward != NON_FF_HEAD) { | ||||
| 			if (!strcmp(head, ref->name)) | ||||
| 				*nonfastforward = NON_FF_HEAD; | ||||
| 			else | ||||
| 				*nonfastforward = NON_FF_OTHER; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
|  |  | |||
|  | @ -138,6 +138,8 @@ int transport_set_option(struct transport *transport, const char *name, | |||
| void transport_set_verbosity(struct transport *transport, int verbosity, | ||||
| 	int force_progress); | ||||
|  | ||||
| #define NON_FF_HEAD 1 | ||||
| #define NON_FF_OTHER 2 | ||||
| int transport_push(struct transport *connection, | ||||
| 		   int refspec_nr, const char **refspec, int flags, | ||||
| 		   int * nonfastforward); | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 Junio C Hamano
						Junio C Hamano