status: add --[no-]ahead-behind to status and commit for V2 format.
Teach "git status" and "git commit" to accept "--no-ahead-behind" and "--ahead-behind" arguments to request quick or full ahead/behind reporting. When "--no-ahead-behind" is given, the existing porcelain V2 line "branch.ab +x -y" is replaced with a new "branch.ab +? -?" line. This indicates that the branch and its upstream are or are not equal without the expense of computing the full ahead/behind values. Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>maint
							parent
							
								
									d7d1b496ae
								
							
						
					
					
						commit
						fd9b544a29
					
				|  | @ -130,6 +130,11 @@ ignored, then the directory is not shown, but all contents are shown. | ||||||
| 	without options are equivalent to 'always' and 'never' | 	without options are equivalent to 'always' and 'never' | ||||||
| 	respectively. | 	respectively. | ||||||
|  |  | ||||||
|  | --ahead-behind:: | ||||||
|  | --no-ahead-behind:: | ||||||
|  | 	Display or do not display detailed ahead/behind counts for the | ||||||
|  | 	branch relative to its upstream branch.  Defaults to true. | ||||||
|  |  | ||||||
| <pathspec>...:: | <pathspec>...:: | ||||||
| 	See the 'pathspec' entry in linkgit:gitglossary[7]. | 	See the 'pathspec' entry in linkgit:gitglossary[7]. | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @ -1151,6 +1151,9 @@ static void finalize_deferred_config(struct wt_status *s) | ||||||
| 		s->show_branch = status_deferred_config.show_branch; | 		s->show_branch = status_deferred_config.show_branch; | ||||||
| 	if (s->show_branch < 0) | 	if (s->show_branch < 0) | ||||||
| 		s->show_branch = 0; | 		s->show_branch = 0; | ||||||
|  |  | ||||||
|  | 	if (s->ahead_behind_flags == AHEAD_BEHIND_UNSPECIFIED) | ||||||
|  | 		s->ahead_behind_flags = AHEAD_BEHIND_FULL; | ||||||
| } | } | ||||||
|  |  | ||||||
| static int parse_and_validate_options(int argc, const char *argv[], | static int parse_and_validate_options(int argc, const char *argv[], | ||||||
|  | @ -1365,6 +1368,8 @@ int cmd_status(int argc, const char **argv, const char *prefix) | ||||||
| 			 N_("show branch information")), | 			 N_("show branch information")), | ||||||
| 		OPT_BOOL(0, "show-stash", &s.show_stash, | 		OPT_BOOL(0, "show-stash", &s.show_stash, | ||||||
| 			 N_("show stash information")), | 			 N_("show stash information")), | ||||||
|  | 		OPT_BOOL(0, "ahead-behind", &s.ahead_behind_flags, | ||||||
|  | 			 N_("compute full ahead/behind values")), | ||||||
| 		{ OPTION_CALLBACK, 0, "porcelain", &status_format, | 		{ OPTION_CALLBACK, 0, "porcelain", &status_format, | ||||||
| 		  N_("version"), N_("machine-readable output"), | 		  N_("version"), N_("machine-readable output"), | ||||||
| 		  PARSE_OPT_OPTARG, opt_parse_porcelain }, | 		  PARSE_OPT_OPTARG, opt_parse_porcelain }, | ||||||
|  | @ -1648,6 +1653,8 @@ int cmd_commit(int argc, const char **argv, const char *prefix) | ||||||
| 		OPT_SET_INT(0, "short", &status_format, N_("show status concisely"), | 		OPT_SET_INT(0, "short", &status_format, N_("show status concisely"), | ||||||
| 			    STATUS_FORMAT_SHORT), | 			    STATUS_FORMAT_SHORT), | ||||||
| 		OPT_BOOL(0, "branch", &s.show_branch, N_("show branch information")), | 		OPT_BOOL(0, "branch", &s.show_branch, N_("show branch information")), | ||||||
|  | 		OPT_BOOL(0, "ahead-behind", &s.ahead_behind_flags, | ||||||
|  | 			 N_("compute full ahead/behind values")), | ||||||
| 		OPT_SET_INT(0, "porcelain", &status_format, | 		OPT_SET_INT(0, "porcelain", &status_format, | ||||||
| 			    N_("machine-readable output"), STATUS_FORMAT_PORCELAIN), | 			    N_("machine-readable output"), STATUS_FORMAT_PORCELAIN), | ||||||
| 		OPT_SET_INT(0, "long", &status_format, | 		OPT_SET_INT(0, "long", &status_format, | ||||||
|  |  | ||||||
							
								
								
									
										2
									
								
								remote.c
								
								
								
								
							
							
						
						
									
										2
									
								
								remote.c
								
								
								
								
							|  | @ -2058,6 +2058,8 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs, | ||||||
| 		return 0; | 		return 0; | ||||||
| 	if (abf == AHEAD_BEHIND_QUICK) | 	if (abf == AHEAD_BEHIND_QUICK) | ||||||
| 		return 1; | 		return 1; | ||||||
|  | 	if (abf != AHEAD_BEHIND_FULL) | ||||||
|  | 		BUG("stat_tracking_info: invalid abf '%d'", abf); | ||||||
|  |  | ||||||
| 	/* Run "rev-list --left-right ours...theirs" internally... */ | 	/* Run "rev-list --left-right ours...theirs" internally... */ | ||||||
| 	argv_array_push(&argv, ""); /* ignored */ | 	argv_array_push(&argv, ""); /* ignored */ | ||||||
|  |  | ||||||
							
								
								
									
										5
									
								
								remote.h
								
								
								
								
							
							
						
						
									
										5
									
								
								remote.h
								
								
								
								
							|  | @ -259,8 +259,9 @@ enum match_refs_flags { | ||||||
|  |  | ||||||
| /* Flags for --ahead-behind option. */ | /* Flags for --ahead-behind option. */ | ||||||
| enum ahead_behind_flags { | enum ahead_behind_flags { | ||||||
| 	AHEAD_BEHIND_QUICK = 0,  /* just eq/neq reporting */ | 	AHEAD_BEHIND_UNSPECIFIED = -1, | ||||||
| 	AHEAD_BEHIND_FULL  = 1,  /* traditional a/b reporting */ | 	AHEAD_BEHIND_QUICK       =  0,  /* just eq/neq reporting */ | ||||||
|  | 	AHEAD_BEHIND_FULL        =  1,  /* traditional a/b reporting */ | ||||||
| }; | }; | ||||||
|  |  | ||||||
| /* Reporting of tracking info */ | /* Reporting of tracking info */ | ||||||
|  |  | ||||||
|  | @ -390,6 +390,68 @@ test_expect_success 'verify upstream fields in branch header' ' | ||||||
| 	) | 	) | ||||||
| ' | ' | ||||||
|  |  | ||||||
|  | test_expect_success 'verify --[no-]ahead-behind with V2 format' ' | ||||||
|  | 	git checkout master && | ||||||
|  | 	test_when_finished "rm -rf sub_repo" && | ||||||
|  | 	git clone . sub_repo && | ||||||
|  | 	( | ||||||
|  | 		## Confirm local master tracks remote master. | ||||||
|  | 		cd sub_repo && | ||||||
|  | 		HUF=$(git rev-parse HEAD) && | ||||||
|  |  | ||||||
|  | 		# Confirm --no-ahead-behind reports traditional branch.ab with 0/0 for equal branches. | ||||||
|  | 		cat >expect <<-EOF && | ||||||
|  | 		# branch.oid $HUF | ||||||
|  | 		# branch.head master | ||||||
|  | 		# branch.upstream origin/master | ||||||
|  | 		# branch.ab +0 -0 | ||||||
|  | 		EOF | ||||||
|  |  | ||||||
|  | 		git status --no-ahead-behind --porcelain=v2 --branch --untracked-files=all >actual && | ||||||
|  | 		test_cmp expect actual && | ||||||
|  |  | ||||||
|  | 		# Confirm --ahead-behind reports traditional branch.ab with 0/0. | ||||||
|  | 		cat >expect <<-EOF && | ||||||
|  | 		# branch.oid $HUF | ||||||
|  | 		# branch.head master | ||||||
|  | 		# branch.upstream origin/master | ||||||
|  | 		# branch.ab +0 -0 | ||||||
|  | 		EOF | ||||||
|  |  | ||||||
|  | 		git status --ahead-behind --porcelain=v2 --branch --untracked-files=all >actual && | ||||||
|  | 		test_cmp expect actual && | ||||||
|  |  | ||||||
|  | 		## Test non-equal ahead/behind. | ||||||
|  | 		echo xyz >file_xyz && | ||||||
|  | 		git add file_xyz && | ||||||
|  | 		git commit -m xyz && | ||||||
|  |  | ||||||
|  | 		HUF=$(git rev-parse HEAD) && | ||||||
|  |  | ||||||
|  | 		# Confirm --no-ahead-behind reports branch.ab with ?/? for non-equal branches. | ||||||
|  | 		cat >expect <<-EOF && | ||||||
|  | 		# branch.oid $HUF | ||||||
|  | 		# branch.head master | ||||||
|  | 		# branch.upstream origin/master | ||||||
|  | 		# branch.ab +? -? | ||||||
|  | 		EOF | ||||||
|  |  | ||||||
|  | 		git status --no-ahead-behind --porcelain=v2 --branch --untracked-files=all >actual && | ||||||
|  | 		test_cmp expect actual && | ||||||
|  |  | ||||||
|  | 		# Confirm --ahead-behind reports traditional branch.ab with 1/0. | ||||||
|  | 		cat >expect <<-EOF && | ||||||
|  | 		# branch.oid $HUF | ||||||
|  | 		# branch.head master | ||||||
|  | 		# branch.upstream origin/master | ||||||
|  | 		# branch.ab +1 -0 | ||||||
|  | 		EOF | ||||||
|  |  | ||||||
|  | 		git status --ahead-behind --porcelain=v2 --branch --untracked-files=all >actual && | ||||||
|  | 		test_cmp expect actual | ||||||
|  | 	) | ||||||
|  | ' | ||||||
|  |  | ||||||
| test_expect_success 'create and add submodule, submodule appears clean (A. S...)' ' | test_expect_success 'create and add submodule, submodule appears clean (A. S...)' ' | ||||||
| 	git checkout master && | 	git checkout master && | ||||||
| 	git clone . sub_repo && | 	git clone . sub_repo && | ||||||
|  |  | ||||||
							
								
								
									
										30
									
								
								wt-status.c
								
								
								
								
							
							
						
						
									
										30
									
								
								wt-status.c
								
								
								
								
							|  | @ -136,6 +136,7 @@ void wt_status_prepare(struct wt_status *s) | ||||||
| 	s->ignored.strdup_strings = 1; | 	s->ignored.strdup_strings = 1; | ||||||
| 	s->show_branch = -1;  /* unspecified */ | 	s->show_branch = -1;  /* unspecified */ | ||||||
| 	s->show_stash = 0; | 	s->show_stash = 0; | ||||||
|  | 	s->ahead_behind_flags = AHEAD_BEHIND_UNSPECIFIED; | ||||||
| 	s->display_comment_prefix = 0; | 	s->display_comment_prefix = 0; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1883,18 +1884,19 @@ static void wt_porcelain_print(struct wt_status *s) | ||||||
|  * |  * | ||||||
|  *    <upstream> ::= the upstream branch name, when set. |  *    <upstream> ::= the upstream branch name, when set. | ||||||
|  * |  * | ||||||
|  *       <ahead> ::= integer ahead value, when upstream set |  *       <ahead> ::= integer ahead value or '?'. | ||||||
|  *                   and the commit is present (not gone). |  | ||||||
|  * |  | ||||||
|  *      <behind> ::= integer behind value, when upstream set |  | ||||||
|  *                   and commit is present. |  | ||||||
|  * |  * | ||||||
|  |  *      <behind> ::= integer behind value or '?'. | ||||||
|  * |  * | ||||||
|  * The end-of-line is defined by the -z flag. |  * The end-of-line is defined by the -z flag. | ||||||
|  * |  * | ||||||
|  *                 <eol> ::= NUL when -z, |  *                 <eol> ::= NUL when -z, | ||||||
|  *                           LF when NOT -z. |  *                           LF when NOT -z. | ||||||
|  * |  * | ||||||
|  |  * When an upstream is set and present, the 'branch.ab' line will | ||||||
|  |  * be printed with the ahead/behind counts for the branch and the | ||||||
|  |  * upstream.  When AHEAD_BEHIND_QUICK is requested and the branches | ||||||
|  |  * are different, '?' will be substituted for the actual count. | ||||||
|  */ |  */ | ||||||
| static void wt_porcelain_v2_print_tracking(struct wt_status *s) | static void wt_porcelain_v2_print_tracking(struct wt_status *s) | ||||||
| { | { | ||||||
|  | @ -1934,15 +1936,25 @@ static void wt_porcelain_v2_print_tracking(struct wt_status *s) | ||||||
| 		/* Lookup stats on the upstream tracking branch, if set. */ | 		/* Lookup stats on the upstream tracking branch, if set. */ | ||||||
| 		branch = branch_get(branch_name); | 		branch = branch_get(branch_name); | ||||||
| 		base = NULL; | 		base = NULL; | ||||||
| 		ab_info = (stat_tracking_info(branch, &nr_ahead, &nr_behind, | 		ab_info = stat_tracking_info(branch, &nr_ahead, &nr_behind, | ||||||
| 					      &base, AHEAD_BEHIND_FULL) >= 0); | 					     &base, s->ahead_behind_flags); | ||||||
| 		if (base) { | 		if (base) { | ||||||
| 			base = shorten_unambiguous_ref(base, 0); | 			base = shorten_unambiguous_ref(base, 0); | ||||||
| 			fprintf(s->fp, "# branch.upstream %s%c", base, eol); | 			fprintf(s->fp, "# branch.upstream %s%c", base, eol); | ||||||
| 			free((char *)base); | 			free((char *)base); | ||||||
|  |  | ||||||
| 			if (ab_info) | 			if (ab_info > 0) { | ||||||
| 				fprintf(s->fp, "# branch.ab +%d -%d%c", nr_ahead, nr_behind, eol); | 				/* different */ | ||||||
|  | 				if (nr_ahead || nr_behind) | ||||||
|  | 					fprintf(s->fp, "# branch.ab +%d -%d%c", | ||||||
|  | 						nr_ahead, nr_behind, eol); | ||||||
|  | 				else | ||||||
|  | 					fprintf(s->fp, "# branch.ab +? -?%c", | ||||||
|  | 						eol); | ||||||
|  | 			} else if (!ab_info) { | ||||||
|  | 				/* same */ | ||||||
|  | 				fprintf(s->fp, "# branch.ab +0 -0%c", eol); | ||||||
|  | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @ -5,6 +5,7 @@ | ||||||
| #include "string-list.h" | #include "string-list.h" | ||||||
| #include "color.h" | #include "color.h" | ||||||
| #include "pathspec.h" | #include "pathspec.h" | ||||||
|  | #include "remote.h" | ||||||
|  |  | ||||||
| struct worktree; | struct worktree; | ||||||
|  |  | ||||||
|  | @ -86,6 +87,7 @@ struct wt_status { | ||||||
| 	int show_branch; | 	int show_branch; | ||||||
| 	int show_stash; | 	int show_stash; | ||||||
| 	int hints; | 	int hints; | ||||||
|  | 	enum ahead_behind_flags ahead_behind_flags; | ||||||
|  |  | ||||||
| 	enum wt_status_format status_format; | 	enum wt_status_format status_format; | ||||||
| 	unsigned char sha1_commit[GIT_MAX_RAWSZ]; /* when not Initial */ | 	unsigned char sha1_commit[GIT_MAX_RAWSZ]; /* when not Initial */ | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	 Jeff Hostetler
						Jeff Hostetler