[PATCH v14 00/13] Port tag.c to use ref-filter.c

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is part of porting tag.c to ref-filter APIs.
Version 13 can be found:
thread.gmane.org/gmane.comp.version-control.git/276363

Changes in this version:
* Introduce format_ref_array_item() and make show_ref_array_item() a
wrapper around the same.
* Introduce %(contents:lines=X) which gets the first X lines from a
given object.
* Change code in 05/13 to make the code neater and consistent.
* %(align) without arguments fails now.
* Add test for nested alignment.
* We perform quoting on each layer of nested alignment. 

Karthik Nayak (13):
  ref-filter: move `struct atom_value` to ref-filter.c
  ref-filter: introduce ref_formatting_state and ref_formatting_stack
  utf8: add function to align a string into given strbuf
  ref-filter: implement an `align` atom
  ref-filter: add option to filter out tags, branches and remotes
  ref-filter: introduce format_ref_array_item()
  ref-filter: add support for %(contents:lines=X)
  ref-filter: add support to sort by version
  ref-filter: add option to match literal pattern
  tag.c: use 'ref-filter' data structures
  tag.c: use 'ref-filter' APIs
  tag.c: implement '--format' option
  tag.c: implement '--merged' and '--no-merged' options

 Documentation/git-for-each-ref.txt |  13 ++
 Documentation/git-tag.txt          |  27 ++-
 builtin/for-each-ref.c             |   1 +
 builtin/tag.c                      | 368 ++++++--------------------------
 ref-filter.c                       | 418 ++++++++++++++++++++++++++++++++-----
 ref-filter.h                       |  32 ++-
 refs.c                             |   9 +
 refs.h                             |   1 +
 t/t6302-for-each-ref-filter.sh     | 137 ++++++++++++
 t/t7004-tag.sh                     |  47 ++++-
 utf8.c                             |  21 ++
 utf8.h                             |  15 ++
 12 files changed, 712 insertions(+), 377 deletions(-)

Interdiff between version 13 and version 14

diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt
index 06d468e..1b48b95 100644
--- a/Documentation/git-for-each-ref.txt
+++ b/Documentation/git-for-each-ref.txt
@@ -149,6 +149,7 @@ Its first line is `contents:subject`, where subject is the concatenation
 of all lines of the commit message up to the first blank line.  The next
 line is 'contents:body', where body is all of the lines after the first
 blank line.  Finally, the optional GPG signature is `contents:signature`.
+The first `N` lines of the object is obtained using `contents:lines=N`.
 
 For sorting purposes, fields with numeric values sort in numeric
 order (`objectsize`, `authordate`, `committerdate`, `taggerdate`).
diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c
index 3ad6a64..4e9f6c2 100644
--- a/builtin/for-each-ref.c
+++ b/builtin/for-each-ref.c
@@ -75,7 +75,7 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
 	if (!maxcount || array.nr < maxcount)
 		maxcount = array.nr;
 	for (i = 0; i < maxcount; i++)
-		show_ref_array_item(array.items[i], format, quote_style, 0);
+		show_ref_array_item(array.items[i], format, quote_style);
 	ref_array_clear(&array);
 	return 0;
 }
diff --git a/builtin/tag.c b/builtin/tag.c
index bbbcaed..9fa1400 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -33,6 +33,7 @@ static unsigned int colopts;
 static int list_tags(struct ref_filter *filter, struct ref_sorting *sorting, const char *format)
 {
 	struct ref_array array;
+	char *to_free = NULL;
 	int i;
 
 	memset(&array, 0, sizeof(array));
@@ -42,7 +43,8 @@ static int list_tags(struct ref_filter *filter, struct ref_sorting *sorting, con
 
 	if (!format) {
 		if (filter->lines)
-			format = "%(align:16,left)%(refname:short)%(end)";
+			format = to_free = xstrfmt("%%(align:15,left)%%(refname:short)%%(end) %%(contents:lines=%d)",
+						   filter->lines);
 		else
 			format = "%(refname:short)";
 	}
@@ -52,8 +54,9 @@ static int list_tags(struct ref_filter *filter, struct ref_sorting *sorting, con
 	ref_array_sort(sorting, &array);
 
 	for (i = 0; i < array.nr; i++)
-		show_ref_array_item(array.items[i], format, QUOTE_NONE, filter->lines);
+		show_ref_array_item(array.items[i], format, 0);
 	ref_array_clear(&array);
+	free(to_free);
 
 	return 0;
 }
diff --git a/ref-filter.c b/ref-filter.c
index f8b8fb7..f268cd7 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -58,6 +58,7 @@ static struct {
 	{ "color" },
 	{ "align" },
 	{ "end" },
+	{ "contents:lines" },
 };
 
 struct align {
@@ -65,6 +66,11 @@ struct align {
 	unsigned int width;
 };
 
+struct contents {
+	unsigned int lines;
+	struct object_id oid;
+};
+
 #define REF_FORMATTING_STATE_INIT  { 0, NULL }
 
 struct ref_formatting_stack {
@@ -82,6 +88,7 @@ struct ref_formatting_state {
 struct atom_value {
 	const char *s;
 	struct align *align;
+	struct contents *contents;
 	void (*handler)(struct atom_value *atomv, struct ref_formatting_state *state);
 	unsigned long ul; /* used for sorting when not FIELD_STR */
 };
@@ -155,7 +162,28 @@ int parse_ref_filter_atom(const char *atom, const char *ep)
 	return at;
 }
 
-static void push_new_stack_element(struct ref_formatting_stack **stack)
+static void quote_formatting(struct strbuf *s, const char *str, int quote_style)
+{
+	switch (quote_style) {
+	case QUOTE_NONE:
+		strbuf_addstr(s, str);
+		break;
+	case QUOTE_SHELL:
+		sq_quote_buf(s, str);
+		break;
+	case QUOTE_PERL:
+		perl_quote_buf(s, str);
+		break;
+	case QUOTE_PYTHON:
+		python_quote_buf(s, str);
+		break;
+	case QUOTE_TCL:
+		tcl_quote_buf(s, str);
+		break;
+	}
+}
+
+static void push_stack_element(struct ref_formatting_stack **stack)
 {
 	struct ref_formatting_stack *s = xcalloc(1, sizeof(struct ref_formatting_stack));
 
@@ -550,6 +578,61 @@ static void find_subpos(const char *buf, unsigned long sz,
 	*nonsiglen = *sig - buf;
 }
 
+/*
+ * If 'lines' is greater than 0, append that many lines from the given
+ * object_id 'oid' to the given strbuf.
+ */
+static void append_tag_lines(struct strbuf *out, const struct object_id *oid, int lines)
+{
+	int i;
+	unsigned long size;
+	enum object_type type;
+	char *buf, *sp, *eol;
+	size_t len;
+
+	buf = read_sha1_file(oid->hash, &type, &size);
+	if (!buf)
+		die_errno("unable to read object %s", oid_to_hex(oid));
+	if (type != OBJ_COMMIT && type != OBJ_TAG)
+		goto free_return;
+	if (!size)
+		die("an empty %s object %s?",
+		    typename(type), oid_to_hex(oid));
+
+	/* skip header */
+	sp = strstr(buf, "\n\n");
+	if (!sp)
+		goto free_return;
+
+	/* only take up to "lines" lines, and strip the signature from a tag */
+	if (type == OBJ_TAG)
+		size = parse_signature(buf, size);
+	for (i = 0, sp += 2; i < lines && sp < buf + size; i++) {
+		if (i)
+			strbuf_addstr(out, "\n    ");
+		eol = memchr(sp, '\n', size - (sp - buf));
+		len = eol ? eol - sp : size - (sp - buf);
+		strbuf_add(out, sp, len);
+		if (!eol)
+			break;
+		sp = eol + 1;
+	}
+free_return:
+	free(buf);
+}
+
+static void contents_lines_handler(struct atom_value *atomv, struct ref_formatting_state *state)
+{
+	struct contents *contents = (struct contents *)atomv->contents;
+	struct strbuf s = STRBUF_INIT;
+
+	append_tag_lines(&s, &contents->oid, contents->lines);
+	quote_formatting(&state->stack->output, s.buf, state->quote_style);
+	strbuf_release(&s);
+
+	free(contents);
+}
+
 /* See grab_values */
 static void grab_sub_body_contents(struct atom_value *val, int deref, struct object *obj, void *buf, unsigned long sz)
 {
@@ -560,6 +643,7 @@ static void grab_sub_body_contents(struct atom_value *val, int deref, struct obj
 	for (i = 0; i < used_atom_cnt; i++) {
 		const char *name = used_atom[i];
 		struct atom_value *v = &val[i];
+		const char *valp = NULL;
 		if (!!deref != (*name == '*'))
 			continue;
 		if (deref)
@@ -569,7 +653,8 @@ static void grab_sub_body_contents(struct atom_value *val, int deref, struct obj
 		    strcmp(name, "contents") &&
 		    strcmp(name, "contents:subject") &&
 		    strcmp(name, "contents:body") &&
-		    strcmp(name, "contents:signature"))
+		    strcmp(name, "contents:signature") &&
+		    !starts_with(name, "contents:lines="))
 			continue;
 		if (!subpos)
 			find_subpos(buf, sz,
@@ -589,6 +674,15 @@ static void grab_sub_body_contents(struct atom_value *val, int deref, struct obj
 			v->s = xmemdupz(sigpos, siglen);
 		else if (!strcmp(name, "contents"))
 			v->s = xstrdup(subpos);
+		else if (skip_prefix(name, "contents:lines=", &valp)) {
+			struct contents *contents = xmalloc(sizeof(struct contents));
+
+			if (strtoul_ui(valp, 10, &contents->lines))
+				die(_("positive width expected align:%s"), valp);
+			hashcpy(contents->oid.hash, obj->sha1);
+			v->handler = contents_lines_handler;
+			v->contents = contents;
+		}
 	}
 }
 
@@ -661,13 +755,25 @@ static void align_atom_handler(struct atom_value *atomv, struct ref_formatting_s
 {
 	struct ref_formatting_stack *new;
 
-	push_new_stack_element(&state->stack);
+	push_stack_element(&state->stack);
 	new = state->stack;
 	new->at_end = align_handler;
 	new->cb_data = atomv->align;
 }
 
-static void perform_quote_formatting(struct strbuf *s, const char *str, int quote_style);
+static void append_atom(struct atom_value *v, struct ref_formatting_state *state)
+{
+	/*
+	 * Quote formatting is only done when the stack has a single
+	 * element. Otherwise quote formatting is done on the
+	 * element's entire output strbuf when the %(end) atom is
+	 * encountered.
+	 */
+	if (!state->stack->prev)
+		quote_formatting(&state->stack->output, v->s, state->quote_style);
+	else
+		strbuf_addstr(&state->stack->output, v->s);
+}
 
 static void end_atom_handler(struct atom_value *atomv, struct ref_formatting_state *state)
 {
@@ -682,8 +788,8 @@ static void end_atom_handler(struct atom_value *atomv, struct ref_formatting_sta
 	 * are using a certain modifier atom. In that case we need to
 	 * perform quote formatting.
 	 */
-	if (!state->stack->prev->prev) {
-		perform_quote_formatting(&s, current->output.buf, state->quote_style);
+	if (state->stack->prev) {
+		quote_formatting(&s, current->output.buf, state->quote_style);
 		strbuf_reset(&current->output);
 		strbuf_addbuf(&current->output, &s);
 	}
@@ -722,6 +828,8 @@ static void populate_value(struct ref_array_item *ref)
 		const char *valp;
 		struct branch *branch = NULL;
 
+		v->handler = append_atom;
+
 		if (*name == '*') {
 			deref = 1;
 			name++;
@@ -785,7 +893,9 @@ static void populate_value(struct ref_array_item *ref)
 			else
 				v->s = " ";
 			continue;
-		} else if (skip_prefix(name, "align:", &valp)) {
+		} else if (!strcmp(name, "align"))
+			die(_("format: incomplete use of the `align` atom"));
+		else if (skip_prefix(name, "align:", &valp)) {
 			struct align *align = xmalloc(sizeof(struct align));
 			struct strbuf **s = strbuf_split_str(valp, ',', 0);
 
@@ -1172,12 +1282,10 @@ static int filter_ref_kind(struct ref_filter *filter, const char *refname)
 		{ "refs/tags/", FILTER_REFS_TAGS}
 	};
 
-	if (filter->kind == FILTER_REFS_BRANCHES)
-		return FILTER_REFS_BRANCHES;
-	else if (filter->kind == FILTER_REFS_REMOTES)
-		return FILTER_REFS_REMOTES;
-	else if (filter->kind == FILTER_REFS_TAGS)
-		return FILTER_REFS_TAGS;
+	if (filter->kind == FILTER_REFS_BRANCHES ||
+	    filter->kind == FILTER_REFS_REMOTES ||
+	    filter->kind == FILTER_REFS_TAGS)
+		return filter->kind;
 	else if (!strcmp(refname, "HEAD"))
 		return FILTER_REFS_DETACHED_HEAD;
 
@@ -1211,6 +1319,11 @@ static int ref_filter_handler(const char *refname, const struct object_id *oid,
 		return 0;
 	}
 
+	/*
+	 * Get the current ref kind. If we're filtering tags, remotes or local branches
+	 * only then the current ref-kind is nothing but filter->kind and filter_ref_kind()
+	 * will only return that value.
+	 */
 	kind = filter_ref_kind(filter, refname);
 	if (!(kind & filter->kind))
 		return 0;
@@ -1328,25 +1441,26 @@ int filter_refs(struct ref_array *array, struct ref_filter *filter, unsigned int
 	ref_cbdata.array = array;
 	ref_cbdata.filter = filter;
 
-	/*  Simple per-ref filtering */
-	if (type & FILTER_REFS_INCLUDE_BROKEN) {
-		type &= ~FILTER_REFS_INCLUDE_BROKEN;
+	if (type & FILTER_REFS_INCLUDE_BROKEN)
 		broken = 1;
-	}
+	filter->kind = type & FILTER_REFS_KIND_MASK;
 
-	filter->kind = type;
-	if (type == FILTER_REFS_BRANCHES)
-		ret = for_each_reftype_fullpath(ref_filter_handler, "refs/heads/", broken, &ref_cbdata);
-	else if (type == FILTER_REFS_REMOTES)
-		ret = for_each_reftype_fullpath(ref_filter_handler, "refs/remotes/", broken, &ref_cbdata);
-	else if (type == FILTER_REFS_TAGS)
-		ret = for_each_reftype_fullpath(ref_filter_handler, "refs/tags/", broken, &ref_cbdata);
-	else if (type & FILTER_REFS_ALL) {
-		ret = for_each_reftype_fullpath(ref_filter_handler, "", broken, &ref_cbdata);
-		if (type & FILTER_REFS_DETACHED_HEAD)
-			head_ref(ref_filter_handler, &ref_cbdata);
-	} else
+	/*  Simple per-ref filtering */
+	if (!filter->kind)
 		die("filter_refs: invalid type");
+	else {
+		if (filter->kind == FILTER_REFS_BRANCHES)
+			ret = for_each_fullref_in("refs/heads/", ref_filter_handler, &ref_cbdata, broken);
+		else if (filter->kind == FILTER_REFS_REMOTES)
+			ret = for_each_fullref_in("refs/remotes/", ref_filter_handler, &ref_cbdata, broken);
+		else if (filter->kind == FILTER_REFS_TAGS)
+			ret = for_each_fullref_in("refs/tags/", ref_filter_handler, &ref_cbdata, broken);
+		else if (filter->kind & FILTER_REFS_ALL)
+			ret = for_each_fullref_in("", ref_filter_handler, &ref_cbdata, broken);
+		if (!ret && (filter->kind & FILTER_REFS_DETACHED_HEAD))
+			head_ref(ref_filter_handler, &ref_cbdata);
+	}
+
 
 	/*  Filters that need revision walking */
 	if (filter->merge_commit)
@@ -1400,33 +1514,6 @@ void ref_array_sort(struct ref_sorting *sorting, struct ref_array *array)
 	qsort(array->items, array->nr, sizeof(struct ref_array_item *), compare_refs);
 }
 
-static void perform_quote_formatting(struct strbuf *s, const char *str, int quote_style)
-{
-	switch (quote_style) {
-	case QUOTE_NONE:
-		strbuf_addstr(s, str);
-		break;
-	case QUOTE_SHELL:
-		sq_quote_buf(s, str);
-		break;
-	case QUOTE_PERL:
-		perl_quote_buf(s, str);
-		break;
-	case QUOTE_PYTHON:
-		python_quote_buf(s, str);
-		break;
-	case QUOTE_TCL:
-		tcl_quote_buf(s, str);
-		break;
-	}
-}
-
-static void append_atom(struct atom_value *v, struct ref_formatting_state *state)
-{
-	struct strbuf *s = &state->stack->output;
-	perform_quote_formatting(s, v->s, state->quote_style);
-}
-
 static int hex1(char ch)
 {
 	if ('0' <= ch && ch <= '9')
@@ -1467,58 +1554,14 @@ static void append_literal(const char *cp, const char *ep, struct ref_formatting
 	}
 }
 
-/*
- * If 'lines' is greater than 0, print that many lines from the given
- * object_id 'oid'.
- */
-static void show_tag_lines(const struct object_id *oid, int lines)
-{
-	int i;
-	unsigned long size;
-	enum object_type type;
-	char *buf, *sp, *eol;
-	size_t len;
-
-	buf = read_sha1_file(oid->hash, &type, &size);
-	if (!buf)
-		die_errno("unable to read object %s", oid_to_hex(oid));
-	if (type != OBJ_COMMIT && type != OBJ_TAG)
-		goto free_return;
-	if (!size)
-		die("an empty %s object %s?",
-		    typename(type), oid_to_hex(oid));
-
-	/* skip header */
-	sp = strstr(buf, "\n\n");
-	if (!sp)
-		goto free_return;
-
-	/* only take up to "lines" lines, and strip the signature from a tag */
-	if (type == OBJ_TAG)
-		size = parse_signature(buf, size);
-	for (i = 0, sp += 2; i < lines && sp < buf + size; i++) {
-		if (i)
-			printf("\n    ");
-		eol = memchr(sp, '\n', size - (sp - buf));
-		len = eol ? eol - sp : size - (sp - buf);
-		fwrite(sp, len, 1, stdout);
-		if (!eol)
-			break;
-		sp = eol + 1;
-	}
-free_return:
-	free(buf);
-}
-
-void show_ref_array_item(struct ref_array_item *info, const char *format,
-			 int quote_style, unsigned int lines)
+void format_ref_array_item(struct strbuf *out, struct ref_array_item *info,
+			   const char *format, int quote_style)
 {
 	const char *cp, *sp, *ep;
-	struct strbuf *final_buf;
 	struct ref_formatting_state state = REF_FORMATTING_STATE_INIT;
 
 	state.quote_style = quote_style;
-	push_new_stack_element(&state.stack);
+	push_stack_element(&state.stack);
 
 	for (cp = format; *cp && (sp = find_next(cp)); cp = ep + 1) {
 		struct atom_value *atomv;
@@ -1527,18 +1570,7 @@ void show_ref_array_item(struct ref_array_item *info, const char *format,
 		if (cp < sp)
 			append_literal(cp, sp, &state);
 		get_ref_atom_value(info, parse_ref_filter_atom(sp + 2, ep), &atomv);
-		/*
-		 * If the atom is a modifier atom, then call the handler function.
-		 * Else, if this is the first element on the stack, then we need to
-		 * format the atom as per the given quote. Else we just add the atom value
-		 * to the current stack element and handle quote formatting at the end.
-		 */
-		if (atomv->handler)
-			atomv->handler(atomv, &state);
-		else if (!state.stack->prev)
-			append_atom(atomv, &state);
-		else
-			strbuf_addstr(&state.stack->output, atomv->s);
+		atomv->handler(atomv, &state);
 	}
 	if (*cp) {
 		sp = cp + strlen(cp);
@@ -1555,15 +1587,17 @@ void show_ref_array_item(struct ref_array_item *info, const char *format,
 	}
 	if (state.stack->prev)
 		die(_("format: `end` atom missing"));
-	final_buf = &state.stack->output;
-	fwrite(final_buf->buf, 1, final_buf->len, stdout);
+	strbuf_addbuf(out, &state.stack->output);
 	pop_stack_element(&state.stack);
-	if (lines > 0) {
-		struct object_id oid;
-		hashcpy(oid.hash, info->objectname);
-		show_tag_lines(&oid, lines);
-	}
-	putchar('\n');
+}
+
+void show_ref_array_item(struct ref_array_item *item, const char *format, unsigned int quote_style)
+{
+	struct strbuf out = STRBUF_INIT;
+	format_ref_array_item(&out, item, format, quote_style);
+	fwrite(out.buf, out.len, 1, stdout);
+	printf("\n");
+	strbuf_release(&out);
 }
 
 /*  If no sorting option is given, use refname to sort as default */
diff --git a/ref-filter.h b/ref-filter.h
index 8241066..179944c 100644
--- a/ref-filter.h
+++ b/ref-filter.h
@@ -21,6 +21,7 @@
 #define FILTER_REFS_ALL            (FILTER_REFS_TAGS | FILTER_REFS_BRANCHES | \
 				    FILTER_REFS_REMOTES | FILTER_REFS_OTHERS)
 #define FILTER_REFS_DETACHED_HEAD  0x0020
+#define FILTER_REFS_KIND_MASK      (FILTER_REFS_ALL | FILTER_REFS_DETACHED_HEAD)
 
 struct atom_value;
 
@@ -93,12 +94,11 @@ int parse_ref_filter_atom(const char *atom, const char *ep);
 int verify_ref_format(const char *format);
 /*  Sort the given ref_array as per the ref_sorting provided */
 void ref_array_sort(struct ref_sorting *sort, struct ref_array *array);
-/*
- * Print the ref using the given format and quote_style. If 'lines' > 0,
- * print that many lines of the the given ref.
- */
-void show_ref_array_item(struct ref_array_item *info, const char *format,
-			 int quote_style, unsigned int lines);
+/*  Format the ref as per given format and quote_style and store it into the strbuf */
+void format_ref_array_item(struct strbuf *out, struct ref_array_item *info,
+			   const char *format, int quote_style);
+/*  Wrapper around format_ref_array_item() which prints the given ref_array_item */
+void show_ref_array_item(struct ref_array_item *item, const char *format, unsigned int quote_style);
 /*  Callback function for parsing the sort option */
 int parse_opt_ref_sorting(const struct option *opt, const char *arg, int unset);
 /*  Default sort option based on refname */
diff --git a/refs.c b/refs.c
index 3266617..a9469c2 100644
--- a/refs.c
+++ b/refs.c
@@ -2108,6 +2108,15 @@ int for_each_ref_in(const char *prefix, each_ref_fn fn, void *cb_data)
 	return do_for_each_ref(&ref_cache, prefix, fn, strlen(prefix), 0, cb_data);
 }
 
+int for_each_fullref_in(const char *prefix, each_ref_fn fn, void *cb_data, unsigned int broken)
+{
+	unsigned int flag = 0;
+
+	if (broken)
+		flag = DO_FOR_EACH_INCLUDE_BROKEN;
+	return do_for_each_ref(&ref_cache, prefix, fn, 0, flag, cb_data);
+}
+
 int for_each_ref_in_submodule(const char *submodule, const char *prefix,
 		each_ref_fn fn, void *cb_data)
 {
@@ -2150,15 +2159,6 @@ int for_each_replace_ref(each_ref_fn fn, void *cb_data)
 			       strlen(git_replace_ref_base), 0, cb_data);
 }
 
-int for_each_reftype_fullpath(each_ref_fn fn, char *type, unsigned int broken, void *cb_data)
-{
-	unsigned int flag = 0;
-
-	if (broken)
-		flag = DO_FOR_EACH_INCLUDE_BROKEN;
-	return do_for_each_ref(&ref_cache, type, fn, 0, flag, cb_data);
-}
-
 int head_ref_namespaced(each_ref_fn fn, void *cb_data)
 {
 	struct strbuf buf = STRBUF_INIT;
diff --git a/refs.h b/refs.h
index 6e913ee..6d30c98 100644
--- a/refs.h
+++ b/refs.h
@@ -173,13 +173,13 @@ typedef int each_ref_fn(const char *refname,
 extern int head_ref(each_ref_fn fn, void *cb_data);
 extern int for_each_ref(each_ref_fn fn, void *cb_data);
 extern int for_each_ref_in(const char *prefix, each_ref_fn fn, void *cb_data);
+extern int for_each_fullref_in(const char *prefix, each_ref_fn fn, void *cb_data, unsigned int broken);
 extern int for_each_tag_ref(each_ref_fn fn, void *cb_data);
 extern int for_each_branch_ref(each_ref_fn fn, void *cb_data);
 extern int for_each_remote_ref(each_ref_fn fn, void *cb_data);
 extern int for_each_replace_ref(each_ref_fn fn, void *cb_data);
 extern int for_each_glob_ref(each_ref_fn fn, const char *pattern, void *cb_data);
 extern int for_each_glob_ref_in(each_ref_fn fn, const char *pattern, const char *prefix, void *cb_data);
-extern int for_each_reftype_fullpath(each_ref_fn fn, char *type, unsigned int broken, void *cb_data);
 
 extern int head_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data);
 extern int for_each_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data);
diff --git a/t/t6302-for-each-ref-filter.sh b/t/t6302-for-each-ref-filter.sh
index 38c99c9..8f18f86 100755
--- a/t/t6302-for-each-ref-filter.sh
+++ b/t/t6302-for-each-ref-filter.sh
@@ -150,6 +150,38 @@ test_expect_success 'alignment with format quote' '
 	test_cmp expect actual
 '
 
+test_expect_success 'nested alignment' '
+	cat >expect <<-\EOF &&
+	|         master               |
+	|           side               |
+	|       odd/spot               |
+	|     double-tag               |
+	|           four               |
+	|            one               |
+	|     signed-tag               |
+	|          three               |
+	|            two               |
+	EOF
+	git for-each-ref --format="|%(align:30,left)%(align:15,right)%(refname:short)%(end)%(end)|" >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'check `%(contents:lines=X)`' '
+	cat >expect <<-\EOF &&
+	master three
+	side four
+	odd/spot three
+	double-tag Annonated doubly
+	four four
+	one one
+	signed-tag A signed tag message
+	three three
+	two two
+	EOF
+	git for-each-ref --format="%(refname:short) %(contents:lines=1)" >actual &&
+	test_cmp expect actual
+'
+
 test_expect_success 'setup for version sort' '
 	test_commit foo1.3 &&
 	test_commit foo1.6 &&


-- 
2.5.0

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]