[PATCH 1/3] for-each-ref: utilize core.warnambiguousrefs for strict refname:short format

Subsystems: documentation, the rest

STALE3736d

12 messages, 3 authors, 2016-06-15 · open the first message on its own page

[PATCH 1/3] for-each-ref: utilize core.warnambiguousrefs for strict refname:short format

From: Bert Wesarg <hidden>
Date: 2016-06-15 22:45:23

core.warnambiguousrefs is used to enable strict mode for the
abbreviation.

In strict mode, the abbreviated ref will never trigger the
'warn_ambiguous_refs' warning. I.e. for these refs:

  refs/heads/xyzzy
  refs/tags/xyzzy

the abbreviated forms are:

  heads/xyzzy
  tags/xyzzy


Signed-off-by: Bert Wesarg <redacted>

---

On Tue, Sep 9, 2008 at 10:05, Junio C Hamano [off-list ref] wrote:
"Bert Wesarg" [off-list ref] writes:
quoted
Any opinions, whether we want the 'strict' mode? i.e.:

for refs/heads/xyzzy and refs/tags/xyzzy:

loose mode (current implementation):

  refs/heads/xyzzy => heads/xyzzy
  refs/tags/xyzzy  => xyzzy

there would be a ambiguous warning (if enabled) if you use xyzzy as a
tag, but it resolves correctly to the tag.

strict mode:

  refs/heads/xyzzy => heads/xyzzy
  refs/tags/xyzzy  => tags/xyzzy

will always produce a non-ambiguous short forms.
I have no strong opinions either way, but if we want to pick only one, I
suspect that the loose mode would be more appropriate for bash completion
purposes exactly because:

 (1) the shorter form would match the users' expectations, and;

 (2) if it triggers ambiguity warning to use that result that matches
    users' expectations, it is a *good thing* --- it reminds the user
    that s/he is playing with fire _if_ the user is of careful type who
    enables the ambiguity warning.

Thinking about it from a different angle, it would make more sense to use
loose mode if the user does not have ambiguity warning configured, and use
strict mode if the warning is enabled.  Then people who will get warnings
from ambiguity will not get an ambiguous completion, and people who won't
will get shorter but still unambiguous completion.
Cc: git@vger.kernel.org
Cc: szeder@ira.uka.de
Cc: "Shawn O. Pearce" <redacted>

 Documentation/git-for-each-ref.txt |    2 +
 builtin-for-each-ref.c             |   43 ++++++++++++++++++++++-------------
 2 files changed, 29 insertions(+), 16 deletions(-)
diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt
index 5061d3e..265bbf3 100644
--- a/Documentation/git-for-each-ref.txt
+++ b/Documentation/git-for-each-ref.txt
@@ -75,6 +75,8 @@ For all objects, the following names can be used:
 refname::
 	The name of the ref (the part after $GIT_DIR/).
 	For a non-ambiguous short name of the ref append `:short`.
+	The option core.warnambiguousrefs is used to enable the strict mode
+	for the abbretiation.
 
 objecttype::
 	The type of the object (`blob`, `tree`, `commit`, `tag`).
diff --git a/builtin-for-each-ref.c b/builtin-for-each-ref.c
index 9b44092..e7b7712 100644
--- a/builtin-for-each-ref.c
+++ b/builtin-for-each-ref.c
@@ -571,7 +571,7 @@ static void gen_scanf_fmt(char *scanf_fmt, const char *rule)
 /*
  * Shorten the refname to an non-ambiguous form
  */
-static char *get_short_ref(struct refinfo *ref)
+static void get_short_ref(struct refinfo *ref, int strict, char **short_ref)
 {
 	int i;
 	static char **scanf_fmts;
@@ -598,16 +598,16 @@ static char *get_short_ref(struct refinfo *ref)
 		}
 	}
 
-	/* bail out if there are no rules */
-	if (!nr_rules)
-		return ref->refname;
-
 	/* buffer for scanf result, at most ref->refname must fit */
 	short_name = xstrdup(ref->refname);
+	*short_ref = short_name;
 
-	/* skip first rule, it will always match */
-	for (i = nr_rules - 1; i > 0 ; --i) {
-		int j;
+	/* bail out if there are no rules */
+	if (!nr_rules)
+		return;
+
+	for (i = nr_rules - 1; i >= 0 ; --i) {
+		int j, rules_to_fail = i;
 		int short_name_len;
 
 		if (1 != sscanf(ref->refname, scanf_fmts[i], short_name))
@@ -616,13 +616,23 @@ static char *get_short_ref(struct refinfo *ref)
 		short_name_len = strlen(short_name);
 
 		/*
+		 * in strict mode, all (except the matched one) rules
+		 * must fail to resolve to a valid ref
+		 */
+		if (strict)
+			rules_to_fail = nr_rules;
+		/*
 		 * check if the short name resolves to a valid ref,
 		 * but use only rules prior to the matched one
 		 */
-		for (j = 0; j < i; j++) {
+		for (j = 0; j < rules_to_fail; j++) {
 			const char *rule = ref_rev_parse_rules[j];
 			unsigned char short_objectname[20];
 
+			/* skip matched rule */
+			if (i == j)
+				continue;
+
 			/*
 			 * the short name is ambiguous, if it resolves
 			 * (with this previous rule) to a valid ref
@@ -635,14 +645,14 @@ static char *get_short_ref(struct refinfo *ref)
 
 		/*
 		 * short name is non-ambiguous if all previous rules
-		 * haven't resolved to a valid ref
+		 * doesn't resolved to a valid ref
 		 */
-		if (j == i)
-			return short_name;
+		if (j == rules_to_fail)
+			return;
 	}
 
-	free(short_name);
-	return ref->refname;
+	/* can't abbreviate refname, return full name */
+	strcpy(short_name, ref->refname);
 }
 
 
@@ -678,13 +688,14 @@ static void populate_value(struct refinfo *ref)
 		}
 		if (!prefixcmp(name, "refname")) {
 			const char *formatp = strchr(name, ':');
-			const char *refname = ref->refname;
+			char *refname = ref->refname;
 
 			/* look for "short" refname format */
 			if (formatp) {
 				formatp++;
 				if (!strcmp(formatp, "short"))
-					refname = get_short_ref(ref);
+					get_short_ref(ref, warn_ambiguous_refs,
+						      &refname);
 				else
 					die("unknown refname format %s",
 					    formatp);
-- 
1.6.0.1

[PATCH 2/3] for-each-ref: factor out get_short_ref() into refs.c:abbreviate_refname()

From: Bert Wesarg <hidden>
Date: 2016-06-15 22:45:23

Moves the function get_short_ref() from builtin-for-each-ref.c into refs.c
as function abbreviate_refname().

Signed-off-by: Bert Wesarg <redacted>
---

Cc: git@vger.kernel.org
Cc: szeder@ira.uka.de
Cc: "Shawn O. Pearce" <redacted>

 builtin-for-each-ref.c |  116 +----------------------------------------------
 cache.h                |    1 +
 refs.c                 |  110 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 114 insertions(+), 113 deletions(-)
diff --git a/builtin-for-each-ref.c b/builtin-for-each-ref.c
index e7b7712..06fd6a2 100644
--- a/builtin-for-each-ref.c
+++ b/builtin-for-each-ref.c
@@ -546,117 +546,6 @@ static void grab_values(struct atom_value *val, int deref, struct object *obj, v
 }
 
 /*
- * generate a format suitable for scanf from a ref_rev_parse_rules
- * rule, that is replace the "%.*s" spec with a "%s" spec
- */
-static void gen_scanf_fmt(char *scanf_fmt, const char *rule)
-{
-	char *spec;
-
-	spec = strstr(rule, "%.*s");
-	if (!spec || strstr(spec + 4, "%.*s"))
-		die("invalid rule in ref_rev_parse_rules: %s", rule);
-
-	/* copy all until spec */
-	strncpy(scanf_fmt, rule, spec - rule);
-	scanf_fmt[spec - rule] = '\0';
-	/* copy new spec */
-	strcat(scanf_fmt, "%s");
-	/* copy remaining rule */
-	strcat(scanf_fmt, spec + 4);
-
-	return;
-}
-
-/*
- * Shorten the refname to an non-ambiguous form
- */
-static void get_short_ref(struct refinfo *ref, int strict, char **short_ref)
-{
-	int i;
-	static char **scanf_fmts;
-	static int nr_rules;
-	char *short_name;
-
-	/* pre generate scanf formats from ref_rev_parse_rules[] */
-	if (!nr_rules) {
-		size_t total_len = 0;
-
-		/* the rule list is NULL terminated, count them first */
-		for (; ref_rev_parse_rules[nr_rules]; nr_rules++)
-			/* no +1 because strlen("%s") < strlen("%.*s") */
-			total_len += strlen(ref_rev_parse_rules[nr_rules]);
-
-		scanf_fmts = xmalloc(nr_rules * sizeof(char *) + total_len);
-
-		total_len = 0;
-		for (i = 0; i < nr_rules; i++) {
-			scanf_fmts[i] = (char *)&scanf_fmts[nr_rules]
-					+ total_len;
-			gen_scanf_fmt(scanf_fmts[i], ref_rev_parse_rules[i]);
-			total_len += strlen(ref_rev_parse_rules[i]);
-		}
-	}
-
-	/* buffer for scanf result, at most ref->refname must fit */
-	short_name = xstrdup(ref->refname);
-	*short_ref = short_name;
-
-	/* bail out if there are no rules */
-	if (!nr_rules)
-		return;
-
-	for (i = nr_rules - 1; i >= 0 ; --i) {
-		int j, rules_to_fail = i;
-		int short_name_len;
-
-		if (1 != sscanf(ref->refname, scanf_fmts[i], short_name))
-			continue;
-
-		short_name_len = strlen(short_name);
-
-		/*
-		 * in strict mode, all (except the matched one) rules
-		 * must fail to resolve to a valid ref
-		 */
-		if (strict)
-			rules_to_fail = nr_rules;
-		/*
-		 * check if the short name resolves to a valid ref,
-		 * but use only rules prior to the matched one
-		 */
-		for (j = 0; j < rules_to_fail; j++) {
-			const char *rule = ref_rev_parse_rules[j];
-			unsigned char short_objectname[20];
-
-			/* skip matched rule */
-			if (i == j)
-				continue;
-
-			/*
-			 * the short name is ambiguous, if it resolves
-			 * (with this previous rule) to a valid ref
-			 * read_ref() returns 0 on success
-			 */
-			if (!read_ref(mkpath(rule, short_name_len, short_name),
-				      short_objectname))
-				break;
-		}
-
-		/*
-		 * short name is non-ambiguous if all previous rules
-		 * doesn't resolved to a valid ref
-		 */
-		if (j == rules_to_fail)
-			return;
-	}
-
-	/* can't abbreviate refname, return full name */
-	strcpy(short_name, ref->refname);
-}
-
-
-/*
  * Parse the object referred by ref, and grab needed value.
  */
 static void populate_value(struct refinfo *ref)
@@ -694,8 +583,9 @@ static void populate_value(struct refinfo *ref)
 			if (formatp) {
 				formatp++;
 				if (!strcmp(formatp, "short"))
-					get_short_ref(ref, warn_ambiguous_refs,
-						      &refname);
+					abbreviate_refname(ref->refname,
+							   warn_ambiguous_refs,
+							   &refname);
 				else
 					die("unknown refname format %s",
 					    formatp);
diff --git a/cache.h b/cache.h
index de8c2b6..8a128a5 100644
--- a/cache.h
+++ b/cache.h
@@ -582,6 +582,7 @@ extern int dwim_log(const char *str, int len, unsigned char *sha1, char **ref);
 extern int refname_match(const char *abbrev_name, const char *full_name, const char **rules);
 extern const char *ref_rev_parse_rules[];
 extern const char *ref_fetch_rules[];
+extern void abbreviate_refname(const char *refname, int strict, char **abbrev_name);
 
 extern int create_symref(const char *ref, const char *refs_heads_master, const char *logmsg);
 extern int validate_headref(const char *ref);
diff --git a/refs.c b/refs.c
index b680750..f370081 100644
--- a/refs.c
+++ b/refs.c
@@ -730,6 +730,116 @@ int refname_match(const char *abbrev_name, const char *full_name, const char **r
 	return 0;
 }
 
+/*
+ * generate a format suitable for scanf from a ref_rev_parse_rules rule
+ * that is replace the "%.*s" spec with a "%s" spec
+ */
+static void gen_scanf_fmt(char *scanf_fmt, const char *rule)
+{
+	char *spec;
+
+	spec = strstr(rule, "%.*s");
+	if (!spec || strstr(spec + 4, "%.*s"))
+		die("invalid rule in ref_rev_parse_rules: %s", rule);
+
+	/* copy all until spec */
+	strncpy(scanf_fmt, rule, spec - rule);
+	scanf_fmt[spec - rule] = '\0';
+	/* copy new spec */
+	strcat(scanf_fmt, "%s");
+	/* copy remaining rule */
+	strcat(scanf_fmt, spec + 4);
+}
+
+/*
+ * Abbreviate refname to an non-ambiguous form, undefined if refname is not
+ * a fully quallified refname
+ */
+void abbreviate_refname(const char *refname, int strict, char **abbrev_name)
+{
+	int i;
+	static char **scanf_fmts;
+	static int nr_rules;
+	char *abbrev;
+
+	/* pre generate scanf formats from ref_rev_parse_rules[] */
+	if (!nr_rules) {
+		size_t total_len = 0;
+
+		/* the rule list is NULL terminated, count them first */
+		for (; ref_rev_parse_rules[nr_rules]; nr_rules++)
+			/* no +1 because strlen("%s") < strlen("%.*s") */
+			total_len += strlen(ref_rev_parse_rules[nr_rules]);
+
+		scanf_fmts = xmalloc(nr_rules * sizeof(char *) + total_len);
+
+		total_len = 0;
+		for (i = 0; i < nr_rules; i++) {
+			scanf_fmts[i] = (char *)&scanf_fmts[nr_rules]
+					+ total_len;
+			gen_scanf_fmt(scanf_fmts[i], ref_rev_parse_rules[i]);
+			total_len += strlen(ref_rev_parse_rules[i]);
+		}
+	}
+
+	/* buffer for scanf result, at most refname must fit */
+	abbrev = xstrdup(refname);
+	*abbrev_name = abbrev;
+
+	/* bail out if there are no rules */
+	if (!nr_rules)
+		return;
+
+	for (i = nr_rules - 1; i >= 0 ; --i) {
+		int j, rules_to_fail = i;
+		int abbrev_len;
+
+		if (1 != sscanf(refname, scanf_fmts[i], abbrev))
+			continue;
+
+		abbrev_len = strlen(abbrev);
+
+		/*
+		 * in strict mode, all (except the matched one) rules
+		 * must fail to resolve to a valid ref
+		 */
+		if (strict)
+			rules_to_fail = nr_rules;
+
+		/*
+		 * check if the short name resolves to a valid ref,
+		 */
+		for (j = 0; j < rules_to_fail; j++) {
+			const char *rule = ref_rev_parse_rules[j];
+			unsigned char abbrev_objectname[20];
+
+			/* skip matched rule */
+			if (i == j)
+				continue;
+
+			/*
+			 * the abbreviated name is ambiguous,
+			 * if it resolves to a valid ref
+			 *
+			 * read_ref() returns 0 on success
+			 */
+			if (!read_ref(mkpath(rule, abbrev_len, abbrev),
+				      abbrev_objectname))
+				break;
+		}
+
+		/*
+		 * abbrev is non-ambiguous if all rules
+		 * doesn't resolved to a valid ref
+		 */
+		if (j == rules_to_fail)
+			return;
+	}
+
+	/* can't abbreviate refname, return full name */
+	strcpy(abbrev, refname);
+}
+
 static struct ref_lock *verify_lock(struct ref_lock *lock,
 	const unsigned char *old_sha1, int mustexist)
 {
-- 
1.6.0.1

[PATCH 3/3] git abbref-ref: new porcelain for abbreviate_ref()

From: Bert Wesarg <hidden>
Date: 2016-06-15 22:45:23

This gives direct access to the abbreviate_ref() function. The operation
mode defaults to the core.warnambiguousrefs value, like the refname:short
format, but can be explicitly changed with the --{,no}-strict option.

The bash completion script utilizes this new command.

Signed-off-by: Bert Wesarg <redacted>
---

Junio, if this is not a porcelain, tell me.

Cc: git@vger.kernel.org
Cc: szeder@ira.uka.de
Cc: "Shawn O. Pearce" <redacted>

 .gitignore                             |    1 +
 Documentation/git-abbrev-ref.txt       |   34 +++++++++++++++++++++++++++
 Makefile                               |    1 +
 builtin-abbrev-ref.c                   |   40 ++++++++++++++++++++++++++++++++
 builtin.h                              |    1 +
 contrib/completion/git-completion.bash |   16 ++++++------
 git.c                                  |    1 +
 7 files changed, 86 insertions(+), 8 deletions(-)
 create mode 100644 Documentation/git-abbrev-ref.txt
 create mode 100644 builtin-abbrev-ref.c
diff --git a/.gitignore b/.gitignore
index bbaf9de..c2d0ce4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,6 +3,7 @@ GIT-CFLAGS
 GIT-GUI-VARS
 GIT-VERSION-FILE
 git
+git-abbrev-ref
 git-add
 git-add--interactive
 git-am
diff --git a/Documentation/git-abbrev-ref.txt b/Documentation/git-abbrev-ref.txt
new file mode 100644
index 0000000..67f6733
--- /dev/null
+++ b/Documentation/git-abbrev-ref.txt
@@ -0,0 +1,34 @@
+git-abbrev-ref(1)
+=================
+
+NAME
+----
+git-abbrev-ref - Abbreviate a named ref
+
+SYNOPSIS
+--------
+'git abbrev-ref' [--strict] <ref>...
+
+DESCRIPTION
+-----------
+
+
+OPTIONS
+-------
+<ref>...::
+	Refnames to be abbreviated.
+
+--strict::
+	Operates in strict mode. Defaults to core.warnambiguousrefs.
+
+Author
+------
+Written by Bert Wesarg <bert.wesarg@googlemail.com>
+
+Documentation
+--------------
+Documentation by Bert Wesarg and the git-list <git@vger.kernel.org>.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Makefile b/Makefile
index 3c0664a..f78e75f 100644
--- a/Makefile
+++ b/Makefile
@@ -493,6 +493,7 @@ LIB_OBJS += ws.o
 LIB_OBJS += wt-status.o
 LIB_OBJS += xdiff-interface.o
 
+BUILTIN_OBJS += builtin-abbrev-ref.o
 BUILTIN_OBJS += builtin-add.o
 BUILTIN_OBJS += builtin-annotate.o
 BUILTIN_OBJS += builtin-apply.o
diff --git a/builtin-abbrev-ref.c b/builtin-abbrev-ref.c
new file mode 100644
index 0000000..4c4d42c
--- /dev/null
+++ b/builtin-abbrev-ref.c
@@ -0,0 +1,40 @@
+#include "builtin.h"
+#include "cache.h"
+#include "refs.h"
+#include "parse-options.h"
+
+static const char * const git_abbrev_ref_usage[] = {
+	"git abbrev-ref [options] ref...",
+	NULL
+};
+
+int cmd_abbrev_ref(int argc, const char **argv, const char *prefix)
+{
+	int i;
+	int strict = 0;
+	struct option options[] = {
+		OPT_BOOLEAN( 0 , "strict", &strict, "use strict mode"),
+		OPT_END(),
+	};
+
+	git_config(git_default_config, NULL);
+	strict = warn_ambiguous_refs;
+	argc = parse_options(argc, argv, options, git_abbrev_ref_usage, 0);
+
+	for (i = 0; i < argc; i++) {
+		unsigned char sha1[20];
+		char *ref;
+		char *abbrev_ref;
+
+		if (!dwim_ref(argv[i], strlen(argv[i]), sha1, &ref))
+			die("No such ref %s", argv[i]);
+
+		abbreviate_refname(ref, strict, &abbrev_ref);
+		puts(abbrev_ref);
+
+		free(ref);
+		free(abbrev_ref);
+	}
+
+	return 0;
+}
diff --git a/builtin.h b/builtin.h
index e67cb20..8271a4e 100644
--- a/builtin.h
+++ b/builtin.h
@@ -20,6 +20,7 @@ extern int commit_tree(const char *msg, unsigned char *tree,
 		struct commit_list *parents, unsigned char *ret);
 extern int check_pager_config(const char *cmd);
 
+extern int cmd_abbrev_ref(int argc, const char **argv, const char *prefix);
 extern int cmd_add(int argc, const char **argv, const char *prefix);
 extern int cmd_annotate(int argc, const char **argv, const char *prefix);
 extern int cmd_apply(int argc, const char **argv, const char *prefix);
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index 93f0881..7f002c0 100755
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -112,9 +112,9 @@ __git_ps1 ()
 		fi
 
 		if [ -n "$1" ]; then
-			printf "$1" "${b##refs/heads/}$r"
+			printf "$1" "$(git abbrev-ref $b)$r"
 		else
-			printf " (%s)" "${b##refs/heads/}$r"
+			printf " (%s)" "$(git abbrev-ref $b)$r"
 		fi
 	fi
 }
@@ -162,7 +162,7 @@ __git_heads ()
 		case "$is_hash,$i" in
 		y,*) is_hash=n ;;
 		n,*^{}) is_hash=y ;;
-		n,refs/heads/*) is_hash=y; echo "${i#refs/heads/}" ;;
+		n,refs/heads/*) is_hash=y; echo "$(git abbrev-ref $i)" ;;
 		n,*) is_hash=y; echo "$i" ;;
 		esac
 	done
@@ -180,7 +180,7 @@ __git_tags ()
 		case "$is_hash,$i" in
 		y,*) is_hash=n ;;
 		n,*^{}) is_hash=y ;;
-		n,refs/tags/*) is_hash=y; echo "${i#refs/tags/}" ;;
+		n,refs/tags/*) is_hash=y; echo "$(git abbrev-ref $i)" ;;
 		n,*) is_hash=y; echo "$i" ;;
 		esac
 	done
@@ -199,9 +199,9 @@ __git_refs ()
 		case "$is_hash,$i" in
 		y,*) is_hash=n ;;
 		n,*^{}) is_hash=y ;;
-		n,refs/tags/*) is_hash=y; echo "${i#refs/tags/}" ;;
-		n,refs/heads/*) is_hash=y; echo "${i#refs/heads/}" ;;
-		n,refs/remotes/*) is_hash=y; echo "${i#refs/remotes/}" ;;
+		n,refs/tags/*) is_hash=y; echo "$(git abbrev-ref $i)" ;;
+		n,refs/heads/*) is_hash=y; echo "$(git abbrev-ref $i)" ;;
+		n,refs/remotes/*) is_hash=y; echo "$(git abbrev-ref $i)" ;;
 		n,*) is_hash=y; echo "$i" ;;
 		esac
 	done
@@ -222,7 +222,7 @@ __git_refs_remotes ()
 		case "$is_hash,$i" in
 		n,refs/heads/*)
 			is_hash=y
-			echo "$i:refs/remotes/$1/${i#refs/heads/}"
+			echo "$i:refs/remotes/$1/$(git abbrev-ref $i)"
 			;;
 		y,*) is_hash=n ;;
 		n,*^{}) is_hash=y ;;
diff --git a/git.c b/git.c
index 905acc2..052ebb5 100644
--- a/git.c
+++ b/git.c
@@ -263,6 +263,7 @@ static void handle_internal_command(int argc, const char **argv)
 {
 	const char *cmd = argv[0];
 	static struct cmd_struct commands[] = {
+		{ "abbrev-ref", cmd_abbrev_ref, RUN_SETUP },
 		{ "add", cmd_add, RUN_SETUP | NEED_WORK_TREE },
 		{ "annotate", cmd_annotate, RUN_SETUP },
 		{ "apply", cmd_apply },
-- 
1.6.0.1

Re: [PATCH 3/3] git abbref-ref: new porcelain for abbreviate_ref()

From: Shawn O. Pearce <hidden>
Date: 2016-06-15 22:45:23

Bert Wesarg [off-list ref] wrote:
This gives direct access to the abbreviate_ref() function. The operation
mode defaults to the core.warnambiguousrefs value, like the refname:short
format, but can be explicitly changed with the --{,no}-strict option.

The bash completion script utilizes this new command.
And it slows down too, doesn't it?  Now we are doing a fork per
branch during completion.  Yikes.  Didn't you just post a series
about making completion faster?
 
Junio, if this is not a porcelain, tell me.
IMHO its plumbing.  Porcelain is used by a human.  Plumbing is the
bits needed to make human interfaces.
 
quoted hunk
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index 93f0881..7f002c0 100755
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -112,9 +112,9 @@ __git_ps1 ()
 		fi
 
 		if [ -n "$1" ]; then
-			printf "$1" "${b##refs/heads/}$r"
+			printf "$1" "$(git abbrev-ref $b)$r"
 		else
-			printf " (%s)" "${b##refs/heads/}$r"
+			printf " (%s)" "$(git abbrev-ref $b)$r"
 		fi
 	fi
 }
@@ -162,7 +162,7 @@ __git_heads ()
 		case "$is_hash,$i" in
 		y,*) is_hash=n ;;
 		n,*^{}) is_hash=y ;;
-		n,refs/heads/*) is_hash=y; echo "${i#refs/heads/}" ;;
+		n,refs/heads/*) is_hash=y; echo "$(git abbrev-ref $i)" ;;
 		n,*) is_hash=y; echo "$i" ;;
 		esac
 	done
@@ -180,7 +180,7 @@ __git_tags ()
 		case "$is_hash,$i" in
 		y,*) is_hash=n ;;
 		n,*^{}) is_hash=y ;;
-		n,refs/tags/*) is_hash=y; echo "${i#refs/tags/}" ;;
+		n,refs/tags/*) is_hash=y; echo "$(git abbrev-ref $i)" ;;
 		n,*) is_hash=y; echo "$i" ;;
 		esac
 	done
@@ -199,9 +199,9 @@ __git_refs ()
 		case "$is_hash,$i" in
 		y,*) is_hash=n ;;
 		n,*^{}) is_hash=y ;;
-		n,refs/tags/*) is_hash=y; echo "${i#refs/tags/}" ;;
-		n,refs/heads/*) is_hash=y; echo "${i#refs/heads/}" ;;
-		n,refs/remotes/*) is_hash=y; echo "${i#refs/remotes/}" ;;
+		n,refs/tags/*) is_hash=y; echo "$(git abbrev-ref $i)" ;;
+		n,refs/heads/*) is_hash=y; echo "$(git abbrev-ref $i)" ;;
+		n,refs/remotes/*) is_hash=y; echo "$(git abbrev-ref $i)" ;;
 		n,*) is_hash=y; echo "$i" ;;
 		esac
 	done
@@ -222,7 +222,7 @@ __git_refs_remotes ()
 		case "$is_hash,$i" in
 		n,refs/heads/*)
 			is_hash=y
-			echo "$i:refs/remotes/$1/${i#refs/heads/}"
+			echo "$i:refs/remotes/$1/$(git abbrev-ref $i)"
 			;;
 		y,*) is_hash=n ;;
 		n,*^{}) is_hash=y ;;
-- 
Shawn.

Re: [PATCH 3/3] git abbref-ref: new porcelain for abbreviate_ref()

From: Bert Wesarg <hidden>
Date: 2016-06-15 22:45:23

On Mon, Sep 22, 2008 at 17:32, Shawn O. Pearce [off-list ref] wrote:
Bert Wesarg [off-list ref] wrote:
quoted
This gives direct access to the abbreviate_ref() function. The operation
mode defaults to the core.warnambiguousrefs value, like the refname:short
format, but can be explicitly changed with the --{,no}-strict option.

The bash completion script utilizes this new command.
And it slows down too, doesn't it?  Now we are doing a fork per
branch during completion.  Yikes.  Didn't you just post a series
about making completion faster?
No, correctness was and is my concern, so this patch fits well into this.

Bert

Re: [PATCH 1/3] for-each-ref: utilize core.warnambiguousrefs for strict refname:short format

From: Junio C Hamano <hidden>
Date: 2016-06-15 22:45:30

Shawn, was there any issue with this one?  The patch changes the function
signature for no good reason (at least, it does not have anything to do
with the stated purpose of the change), but other than that, I think what
it attempts to do makes sense.

Re: [PATCH 1/3] for-each-ref: utilize core.warnambiguousrefs for strict refname:short format

From: Shawn O. Pearce <hidden>
Date: 2016-06-15 22:45:30

Junio C Hamano [off-list ref] wrote:
Shawn, was there any issue with this one?  The patch changes the function
signature for no good reason (at least, it does not have anything to do
with the stated purpose of the change), but other than that, I think what
it attempts to do makes sense.
No, aside from the signature issue I think its reasonable.

-- 
Shawn.

Re: [PATCH 1/3] for-each-ref: utilize core.warnambiguousrefs for strict refname:short format

From: Bert Wesarg <hidden>
Date: 2016-06-15 22:45:30

On Sat, Oct 18, 2008 at 03:50, Shawn O. Pearce [off-list ref] wrote:
Junio C Hamano [off-list ref] wrote:
quoted
Shawn, was there any issue with this one?  The patch changes the function
signature for no good reason (at least, it does not have anything to do
with the stated purpose of the change), but other than that, I think what
it attempts to do makes sense.
No, aside from the signature issue I think its reasonable.
Ok, I will post a new single patch, that does only this.

Bert
--
Shawn.

[PATCH&RFC] get_short_ref(): add strict mode

From: Bert Wesarg <hidden>
Date: 2016-06-15 22:46:35

Add the strict mode of abbreviation to get_short_ref(), i.e. the resulting ref
won't trigger the ambiguous ref warning.

The only user of this function ("refname:short") still uses the loose mode.

Signed-off-by: Bert Wesarg <redacted>
---
Cc: Junio C Hamano <redacted>
Cc: git@vger.kernel.org

I think of 3 alternatives to use this mode for the "refname" format (and
probably others):

  a) Use core.warnAmbiguousRefs to control strict mode.
     This would change the current default behaviour, because this is true
     by default.

  b) Introduce a new core config variable to control this, either for
     for-each-ref alone ore globally.

  c) Introduce a "refname:short-strict" format to get the strict abbreviation.

I'm currently slighty in favour for option b).

Regards,
Bert

 builtin-for-each-ref.c |   22 +++++++++++++++++-----
 1 files changed, 17 insertions(+), 5 deletions(-)
diff --git a/builtin-for-each-ref.c b/builtin-for-each-ref.c
index 5cbb4b0..2f323c6 100644
--- a/builtin-for-each-ref.c
+++ b/builtin-for-each-ref.c
@@ -569,7 +569,7 @@ static void gen_scanf_fmt(char *scanf_fmt, const char *rule)
 /*
  * Shorten the refname to an non-ambiguous form
  */
-static char *get_short_ref(struct refinfo *ref)
+static char *get_short_ref(struct refinfo *ref, int strict)
 {
 	int i;
 	static char **scanf_fmts;
@@ -606,6 +606,7 @@ static char *get_short_ref(struct refinfo *ref)
 	/* skip first rule, it will always match */
 	for (i = nr_rules - 1; i > 0 ; --i) {
 		int j;
+		int rules_to_fail = i;
 		int short_name_len;
 
 		if (1 != sscanf(ref->refname, scanf_fmts[i], short_name))
@@ -614,14 +615,25 @@ static char *get_short_ref(struct refinfo *ref)
 		short_name_len = strlen(short_name);
 
 		/*
+		 * in strict mode, all (except the matched one) rules
+		 * must fail to resolve to a valid non-ambiguous ref
+		 */
+		if (strict)
+			rules_to_fail = nr_rules;
+
+		/*
 		 * check if the short name resolves to a valid ref,
 		 * but use only rules prior to the matched one
 		 */
-		for (j = 0; j < i; j++) {
+		for (j = 0; j < rules_to_fail; j++) {
 			const char *rule = ref_rev_parse_rules[j];
 			unsigned char short_objectname[20];
 			char refname[PATH_MAX];
 
+			/* skip matched rule */
+			if (i == j)
+				continue;
+
 			/*
 			 * the short name is ambiguous, if it resolves
 			 * (with this previous rule) to a valid ref
@@ -635,9 +647,9 @@ static char *get_short_ref(struct refinfo *ref)
 
 		/*
 		 * short name is non-ambiguous if all previous rules
-		 * haven't resolved to a valid ref
+		 * doesn't resolved to a valid ref
 		 */
-		if (j == i)
+		if (j == rules_to_fail)
 			return short_name;
 	}
 
@@ -684,7 +696,7 @@ static void populate_value(struct refinfo *ref)
 			if (formatp) {
 				formatp++;
 				if (!strcmp(formatp, "short"))
-					refname = get_short_ref(ref);
+					refname = get_short_ref(ref, 0);
 				else
 					die("unknown refname format %s",
 					    formatp);
-- 
tg: (e37347b..) bw/short_ref-warnAmbiguousRefs (depends on: master)

Re: [PATCH&RFC] get_short_ref(): add strict mode

From: Junio C Hamano <hidden>
Date: 2016-06-15 22:46:35

Bert Wesarg [off-list ref] writes:
I think of 3 alternatives to use this mode for the "refname" format (and
probably others):

  a) Use core.warnAmbiguousRefs to control strict mode.
     This would change the current default behaviour, because this is true
     by default.

  b) Introduce a new core config variable to control this, either for
     for-each-ref alone ore globally.

  c) Introduce a "refname:short-strict" format to get the strict abbreviation.

I'm currently slighty in favour for option b).
Your earlier http://thread.gmane.org/gmane.comp.version-control.git/96464
made a lot of sense to me.  The request "refname:short" cannot be for use
by scripts (well, scripts may pass it to for-each-ref but that has to be
for final consumption by humans wanting to view the names in a format not
overly long, as opposed to scripts using for-each-ref to extract
unambiguous names to be used for further processing, in which case they
would be using "refname" without ":short"), so I do not see "change the
current default behaviour" is a bad thing at all.  If anything, it is an
improvement, isn't it?

Re: [PATCH&RFC] get_short_ref(): add strict mode

From: Bert Wesarg <hidden>
Date: 2016-06-15 22:46:35

On Sat, Apr 11, 2009 at 21:23, Junio C Hamano [off-list ref] wrote:
Bert Wesarg [off-list ref] writes:
quoted
I think of 3 alternatives to use this mode for the "refname" format (and
probably others):

  a) Use core.warnAmbiguousRefs to control strict mode.
     This would change the current default behaviour, because this is true
     by default.

  b) Introduce a new core config variable to control this, either for
     for-each-ref alone ore globally.

  c) Introduce a "refname:short-strict" format to get the strict abbreviation.

I'm currently slighty in favour for option b).
Your earlier http://thread.gmane.org/gmane.comp.version-control.git/96464
made a lot of sense to me.  The request "refname:short" cannot be for use
by scripts (well, scripts may pass it to for-each-ref but that has to be
for final consumption by humans wanting to view the names in a format not
overly long, as opposed to scripts using for-each-ref to extract
unambiguous names to be used for further processing, in which case they
would be using "refname" without ":short"), so I do not see "change the
current default behaviour" is a bad thing at all.  If anything, it is an
improvement, isn't it?
Sure it is. So you're still with option a) and I'm ok with this. I
prepare a patch.

Bert

[PATCH] for-each-ref: refname:short utilize core.warnAmbiguousRefs

From: Bert Wesarg <hidden>
Date: 2016-06-15 22:46:35

core.warnAmbiguousRefs is used to select strict mode for the
abbreviation for the "refname:short" format.

In strict mode, the abbreviated ref will never trigger the
'warn_ambiguous_refs' warning. I.e. for these refs:

  refs/heads/xyzzy
  refs/tags/xyzzy

the abbreviated forms are:

  heads/xyzzy
  tags/xyzzy

Signed-off-by: Bert Wesarg <redacted>
---

Cc: "Jeff King" <redacted>
Cc: git@vger.kernel.org
Cc: szeder@ira.uka.de
Cc: "Shawn O. Pearce" <redacted>

 Documentation/git-for-each-ref.txt |    2 ++
 builtin-for-each-ref.c             |    6 +++++-
 t/t6300-for-each-ref.sh            |   18 +++++++++++++++---
 3 files changed, 22 insertions(+), 4 deletions(-)
diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt
index 5061d3e..42cfad9 100644
--- a/Documentation/git-for-each-ref.txt
+++ b/Documentation/git-for-each-ref.txt
@@ -75,6 +75,8 @@ For all objects, the following names can be used:
 refname::
 	The name of the ref (the part after $GIT_DIR/).
 	For a non-ambiguous short name of the ref append `:short`.
+	The option core.warnAmbiguousRefs is used to select the strict
+	abbreviation mode.
 
 objecttype::
 	The type of the object (`blob`, `tree`, `commit`, `tag`).
diff --git a/builtin-for-each-ref.c b/builtin-for-each-ref.c
index 2f323c6..f2af55a 100644
--- a/builtin-for-each-ref.c
+++ b/builtin-for-each-ref.c
@@ -696,7 +696,8 @@ static void populate_value(struct refinfo *ref)
 			if (formatp) {
 				formatp++;
 				if (!strcmp(formatp, "short"))
-					refname = get_short_ref(ref, 0);
+					refname = get_short_ref(ref,
+						warn_ambiguous_refs);
 				else
 					die("unknown refname format %s",
 					    formatp);
@@ -1013,6 +1014,9 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
 		sort = default_sort();
 	sort_atom_limit = used_atom_cnt;
 
+	/* for warn_ambiguous_refs */
+	git_config(git_default_config, NULL);
+
 	memset(&cbdata, 0, sizeof(cbdata));
 	cbdata.grab_pattern = argv;
 	for_each_ref(grab_single_ref, &cbdata);
diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh
index 8bfae44..f83be5d 100755
--- a/t/t6300-for-each-ref.sh
+++ b/t/t6300-for-each-ref.sh
@@ -279,10 +279,11 @@ test_expect_success 'Check for invalid refname format' '
 
 cat >expected <<\EOF
 heads/master
-master
+tags/master
 EOF
 
-test_expect_success 'Check ambiguous head and tag refs' '
+test_expect_success 'Check ambiguous head and tag refs (strict)' '
+	git config --bool core.warnambiguousrefs true &&
 	git checkout -b newtag &&
 	echo "Using $datestamp" > one &&
 	git add one &&
@@ -294,11 +295,22 @@ test_expect_success 'Check ambiguous head and tag refs' '
 '
 
 cat >expected <<\EOF
+heads/master
+master
+EOF
+
+test_expect_success 'Check ambiguous head and tag refs (loose)' '
+	git config --bool core.warnambiguousrefs false &&
+	git for-each-ref --format "%(refname:short)" refs/heads/master refs/tags/master >actual &&
+	test_cmp expected actual
+'
+
+cat >expected <<\EOF
 heads/ambiguous
 ambiguous
 EOF
 
-test_expect_success 'Check ambiguous head and tag refs II' '
+test_expect_success 'Check ambiguous head and tag refs II (loose)' '
 	git checkout master &&
 	git tag ambiguous testtag^0 &&
 	git branch ambiguous testtag^0 &&
-- 
tg: (6750239..) bw/utilize-it (depends on: bw/short_ref-warnAmbiguousRefs)
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help