All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v4 0/8] port the filtering part of branch.c to use ref-filter APIs
@ 2015-09-13  7:23 Karthik Nayak
  2015-09-13  7:23 ` [PATCH v4 1/8] branch: refactor width computation Karthik Nayak
                   ` (8 more replies)
  0 siblings, 9 replies; 38+ messages in thread
From: Karthik Nayak @ 2015-09-13  7:23 UTC (permalink / raw)
  To: git; +Cc: christian.couder, Matthieu.Moy, gitster, Karthik Nayak

This makes branch.c use the ref-filter APIs for filtering of
refs for 'git branch -l'. This is part of the series of unification
of code of 'git branch -l, git tag -l and git for-each-ref'.

The previous version can be found here:
http://thread.gmane.org/gmane.comp.version-control.git/276377

The changes in this version are:
[7/8]: Change the tests check for stdout and stderr. (check interdiff)

Karthik Nayak (8):
  branch: refactor width computation
  branch: bump get_head_description() to the top
  branch: roll show_detached HEAD into regular ref_list
  branch: move 'current' check down to the presentation layer
  branch: drop non-commit error reporting
  branch.c: use 'ref-filter' data structures
  branch.c: use 'ref-filter' APIs
  branch: add '--points-at' option

 Documentation/git-branch.txt |  13 +-
 builtin/branch.c             | 506 +++++++++++++------------------------------
 ref-filter.c                 |   4 +-
 ref-filter.h                 |   8 +-
 t/t1430-bad-ref-name.sh      |  31 ++-
 t/t3203-branch-output.sh     |  20 ++
 6 files changed, 216 insertions(+), 366 deletions(-)

interdiff:

diff --git a/t/t1430-bad-ref-name.sh b/t/t1430-bad-ref-name.sh
index db3627e..070cf06 100755
--- a/t/t1430-bad-ref-name.sh
+++ b/t/t1430-bad-ref-name.sh
@@ -38,18 +38,20 @@ test_expect_success 'fast-import: fail on invalid branch name "bad[branch]name"'
 	test_must_fail git fast-import <input
 '
 
-test_expect_success 'git branch shows badly named ref' '
+test_expect_success 'git branch shows badly named ref as warning' '
 	cp .git/refs/heads/master .git/refs/heads/broken...ref &&
 	test_when_finished "rm -f .git/refs/heads/broken...ref" &&
-	git branch 2>output &&
-	grep -e "broken\.\.\.ref" output
+	git branch >output 2>error &&
+	grep -e "broken\.\.\.ref" error &&
+	! grep -e "broken\.\.\.ref" output
 '
 
 test_expect_success 'branch -d can delete badly named ref' '
 	cp .git/refs/heads/master .git/refs/heads/broken...ref &&
 	test_when_finished "rm -f .git/refs/heads/broken...ref" &&
 	git branch -d broken...ref &&
-	git branch >output &&
+	git branch >output 2>error &&
+	! grep -e "broken\.\.\.ref" error &&
 	! grep -e "broken\.\.\.ref" output
 '
 
@@ -57,7 +59,8 @@ test_expect_success 'branch -D can delete badly named ref' '
 	cp .git/refs/heads/master .git/refs/heads/broken...ref &&
 	test_when_finished "rm -f .git/refs/heads/broken...ref" &&
 	git branch -D broken...ref &&
-	ngit branch >output &&
+	git branch >output 2>error &&
+	! grep -e "broken\.\.\.ref" error &&
 	! grep -e "broken\.\.\.ref" output
 '
 
@@ -85,7 +88,8 @@ test_expect_success 'branch -D cannot delete absolute path' '
 test_expect_success 'git branch cannot create a badly named ref' '
 	test_when_finished "rm -f .git/refs/heads/broken...ref" &&
 	test_must_fail git branch broken...ref &&
-	git branch >output &&
+	git branch >output 2>error &&
+	! grep -e "broken\.\.\.ref" error &&
 	! grep -e "broken\.\.\.ref" output
 '
 
@@ -95,7 +99,8 @@ test_expect_success 'branch -m cannot rename to a bad ref name' '
 	git branch goodref &&
 	test_must_fail git branch -m goodref broken...ref &&
 	test_cmp_rev master goodref &&
-	git branch >output &&
+	git branch >output 2>error &&
+	! grep -e "broken\.\.\.ref" error &&
 	! grep -e "broken\.\.\.ref" output
 '
 
@@ -104,14 +109,16 @@ test_expect_failure 'branch -m can rename from a bad ref name' '
 	test_when_finished "rm -f .git/refs/heads/broken...ref" &&
 	git branch -m broken...ref renamed &&
 	test_cmp_rev master renamed &&
-	git branch >output &&
+	git branch >output 2>error &&
+	! grep -e "broken\.\.\.ref" error &&
 	! grep -e "broken\.\.\.ref" output
 '
 
 test_expect_success 'push cannot create a badly named ref' '
 	test_when_finished "rm -f .git/refs/heads/broken...ref" &&
 	test_must_fail git push "file://$(pwd)" HEAD:refs/heads/broken...ref &&
-	git branch >output &&
+	git branch >output 2>error &&
+	! grep -e "broken\.\.\.ref" error &&
 	! grep -e "broken\.\.\.ref" output
 '
 
@@ -131,7 +138,8 @@ test_expect_failure 'push --mirror can delete badly named ref' '
 		cp .git/refs/heads/master .git/refs/heads/broken...ref
 	) &&
 	git -C src push --mirror "file://$top/dest" &&
-	git -C dest branch >output &&
+	git -C dest branch >output 2>error &&
+	! grep -e "broken\.\.\.ref" error
 	! grep -e "broken\.\.\.ref" output
 '
 
@@ -159,7 +167,8 @@ test_expect_success 'update-ref -d can delete broken name' '
 	cp .git/refs/heads/master .git/refs/heads/broken...ref &&
 	test_when_finished "rm -f .git/refs/heads/broken...ref" &&
 	git update-ref -d refs/heads/broken...ref &&
-	git branch >output &&
+	git branch >output 2>error &&
+	! grep -e "broken\.\.\.ref" error &&
 	! grep -e "broken\.\.\.ref" output
 '

-- 
2.5.1

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v4 1/8] branch: refactor width computation
  2015-09-13  7:23 [PATCH v4 0/8] port the filtering part of branch.c to use ref-filter APIs Karthik Nayak
@ 2015-09-13  7:23 ` Karthik Nayak
  2015-09-13 11:51   ` Matthieu Moy
  2015-09-13  7:23 ` [PATCH v4 2/8] branch: bump get_head_description() to the top Karthik Nayak
                   ` (7 subsequent siblings)
  8 siblings, 1 reply; 38+ messages in thread
From: Karthik Nayak @ 2015-09-13  7:23 UTC (permalink / raw)
  To: git; +Cc: christian.couder, Matthieu.Moy, gitster, Karthik Nayak

From: Karthik Nayak <karthik.188@gmail.com>

Remove unnecessary variables from ref_list and ref_item which were
used for width computation. This is to make ref_item similar to
ref-filter's ref_array_item. This will ensure a smooth port of
branch.c to use ref-filter APIs in further patches.

Previously the maxwidth was computed when inserting the refs into the
ref_list. Now, we obtain the entire ref_list and then compute
maxwidth.

Based-on-patch-by: Jeff King <peff@peff.net>
Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>
Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
---
 builtin/branch.c | 64 ++++++++++++++++++++++++++++++--------------------------
 1 file changed, 34 insertions(+), 30 deletions(-)

diff --git a/builtin/branch.c b/builtin/branch.c
index 4fc8beb..28a10d6 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -282,14 +282,14 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
 struct ref_item {
 	char *name;
 	char *dest;
-	unsigned int kind, width;
+	unsigned int kind;
 	struct commit *commit;
 	int ignore;
 };
 
 struct ref_list {
 	struct rev_info revs;
-	int index, alloc, maxwidth, verbose, abbrev;
+	int index, alloc, verbose, abbrev;
 	struct ref_item *list;
 	struct commit_list *with_commit;
 	int kinds;
@@ -386,15 +386,8 @@ static int append_ref(const char *refname, const struct object_id *oid, int flag
 	newitem->name = xstrdup(refname);
 	newitem->kind = kind;
 	newitem->commit = commit;
-	newitem->width = utf8_strwidth(refname);
 	newitem->dest = resolve_symref(orig_refname, prefix);
 	newitem->ignore = 0;
-	/* adjust for "remotes/" */
-	if (newitem->kind == REF_REMOTE_BRANCH &&
-	    ref_list->kinds != REF_REMOTE_BRANCH)
-		newitem->width += 8;
-	if (newitem->width > ref_list->maxwidth)
-		ref_list->maxwidth = newitem->width;
 
 	return 0;
 }
@@ -505,11 +498,12 @@ static void add_verbose_info(struct strbuf *out, struct ref_item *item,
 }
 
 static void print_ref_item(struct ref_item *item, int maxwidth, int verbose,
-			   int abbrev, int current, char *prefix)
+			   int abbrev, int current, const char *remote_prefix)
 {
 	char c;
 	int color;
 	struct strbuf out = STRBUF_INIT, name = STRBUF_INIT;
+	const char *prefix = "";
 
 	if (item->ignore)
 		return;
@@ -520,6 +514,7 @@ static void print_ref_item(struct ref_item *item, int maxwidth, int verbose,
 		break;
 	case REF_REMOTE_BRANCH:
 		color = BRANCH_COLOR_REMOTE;
+		prefix = remote_prefix;
 		break;
 	default:
 		color = BRANCH_COLOR_PLAIN;
@@ -557,16 +552,22 @@ static void print_ref_item(struct ref_item *item, int maxwidth, int verbose,
 	strbuf_release(&out);
 }
 
-static int calc_maxwidth(struct ref_list *refs)
+static int calc_maxwidth(struct ref_list *refs, int remote_bonus)
 {
-	int i, w = 0;
+	int i, max = 0;
 	for (i = 0; i < refs->index; i++) {
-		if (refs->list[i].ignore)
+		struct ref_item *it = &refs->list[i];
+		int w;
+
+		if (it->ignore)
 			continue;
-		if (refs->list[i].width > w)
-			w = refs->list[i].width;
+		w = utf8_strwidth(it->name);
+		if (it->kind == REF_REMOTE_BRANCH)
+			w += remote_bonus;
+		if (w > max)
+			max = w;
 	}
-	return w;
+	return max;
 }
 
 static char *get_head_description(void)
@@ -600,21 +601,18 @@ static char *get_head_description(void)
 	return strbuf_detach(&desc, NULL);
 }
 
-static void show_detached(struct ref_list *ref_list)
+static void show_detached(struct ref_list *ref_list, int maxwidth)
 {
 	struct commit *head_commit = lookup_commit_reference_gently(head_sha1, 1);
 
 	if (head_commit && is_descendant_of(head_commit, ref_list->with_commit)) {
 		struct ref_item item;
 		item.name = get_head_description();
-		item.width = utf8_strwidth(item.name);
 		item.kind = REF_LOCAL_BRANCH;
 		item.dest = NULL;
 		item.commit = head_commit;
 		item.ignore = 0;
-		if (item.width > ref_list->maxwidth)
-			ref_list->maxwidth = item.width;
-		print_ref_item(&item, ref_list->maxwidth, ref_list->verbose, ref_list->abbrev, 1, "");
+		print_ref_item(&item, maxwidth, ref_list->verbose, ref_list->abbrev, 1, "");
 		free(item.name);
 	}
 }
@@ -624,6 +622,16 @@ static int print_ref_list(int kinds, int detached, int verbose, int abbrev, stru
 	int i;
 	struct append_ref_cb cb;
 	struct ref_list ref_list;
+	int maxwidth = 0;
+	const char *remote_prefix = "";
+
+	/*
+	 * If we are listing more than just remote branches,
+	 * then remote branches will have a "remotes/" prefix.
+	 * We need to account for this in the width.
+	 */
+	if (kinds != REF_REMOTE_BRANCH)
+		remote_prefix = "remotes/";
 
 	memset(&ref_list, 0, sizeof(ref_list));
 	ref_list.kinds = kinds;
@@ -667,26 +675,22 @@ static int print_ref_list(int kinds, int detached, int verbose, int abbrev, stru
 			clear_commit_marks(item->commit, ALL_REV_FLAGS);
 		}
 		clear_commit_marks(filter, ALL_REV_FLAGS);
-
-		if (verbose)
-			ref_list.maxwidth = calc_maxwidth(&ref_list);
 	}
+	if (verbose)
+		maxwidth = calc_maxwidth(&ref_list, strlen(remote_prefix));
 
 	qsort(ref_list.list, ref_list.index, sizeof(struct ref_item), ref_cmp);
 
 	detached = (detached && (kinds & REF_LOCAL_BRANCH));
 	if (detached && match_patterns(pattern, "HEAD"))
-		show_detached(&ref_list);
+		show_detached(&ref_list, maxwidth);
 
 	for (i = 0; i < ref_list.index; i++) {
 		int current = !detached &&
 			(ref_list.list[i].kind == REF_LOCAL_BRANCH) &&
 			!strcmp(ref_list.list[i].name, head);
-		char *prefix = (kinds != REF_REMOTE_BRANCH &&
-				ref_list.list[i].kind == REF_REMOTE_BRANCH)
-				? "remotes/" : "";
-		print_ref_item(&ref_list.list[i], ref_list.maxwidth, verbose,
-			       abbrev, current, prefix);
+		print_ref_item(&ref_list.list[i], maxwidth, verbose,
+			       abbrev, current, remote_prefix);
 	}
 
 	free_ref_list(&ref_list);
-- 
2.5.1

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v4 2/8] branch: bump get_head_description() to the top
  2015-09-13  7:23 [PATCH v4 0/8] port the filtering part of branch.c to use ref-filter APIs Karthik Nayak
  2015-09-13  7:23 ` [PATCH v4 1/8] branch: refactor width computation Karthik Nayak
@ 2015-09-13  7:23 ` Karthik Nayak
  2015-09-13  7:23 ` [PATCH v4 3/8] branch: roll show_detached HEAD into regular ref_list Karthik Nayak
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 38+ messages in thread
From: Karthik Nayak @ 2015-09-13  7:23 UTC (permalink / raw)
  To: git; +Cc: christian.couder, Matthieu.Moy, gitster, Karthik Nayak, Karthik Nayak

This is a preperatory patch for 'roll show_detached HEAD into regular
ref_list'. This patch moves get_head_description() to the top so that
it can be used in print_ref_item().

Based-on-patch-by: Jeff King <peff@peff.net>
Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>
Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
---
 builtin/branch.c | 62 ++++++++++++++++++++++++++++----------------------------
 1 file changed, 31 insertions(+), 31 deletions(-)

diff --git a/builtin/branch.c b/builtin/branch.c
index 28a10d6..193296a 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -497,6 +497,37 @@ static void add_verbose_info(struct strbuf *out, struct ref_item *item,
 	strbuf_release(&subject);
 }
 
+static char *get_head_description(void)
+{
+	struct strbuf desc = STRBUF_INIT;
+	struct wt_status_state state;
+	memset(&state, 0, sizeof(state));
+	wt_status_get_state(&state, 1);
+	if (state.rebase_in_progress ||
+	    state.rebase_interactive_in_progress)
+		strbuf_addf(&desc, _("(no branch, rebasing %s)"),
+			    state.branch);
+	else if (state.bisect_in_progress)
+		strbuf_addf(&desc, _("(no branch, bisect started on %s)"),
+			    state.branch);
+	else if (state.detached_from) {
+		/* TRANSLATORS: make sure these match _("HEAD detached at ")
+		   and _("HEAD detached from ") in wt-status.c */
+		if (state.detached_at)
+			strbuf_addf(&desc, _("(HEAD detached at %s)"),
+				state.detached_from);
+		else
+			strbuf_addf(&desc, _("(HEAD detached from %s)"),
+				state.detached_from);
+	}
+	else
+		strbuf_addstr(&desc, _("(no branch)"));
+	free(state.branch);
+	free(state.onto);
+	free(state.detached_from);
+	return strbuf_detach(&desc, NULL);
+}
+
 static void print_ref_item(struct ref_item *item, int maxwidth, int verbose,
 			   int abbrev, int current, const char *remote_prefix)
 {
@@ -570,37 +601,6 @@ static int calc_maxwidth(struct ref_list *refs, int remote_bonus)
 	return max;
 }
 
-static char *get_head_description(void)
-{
-	struct strbuf desc = STRBUF_INIT;
-	struct wt_status_state state;
-	memset(&state, 0, sizeof(state));
-	wt_status_get_state(&state, 1);
-	if (state.rebase_in_progress ||
-	    state.rebase_interactive_in_progress)
-		strbuf_addf(&desc, _("(no branch, rebasing %s)"),
-			    state.branch);
-	else if (state.bisect_in_progress)
-		strbuf_addf(&desc, _("(no branch, bisect started on %s)"),
-			    state.branch);
-	else if (state.detached_from) {
-		/* TRANSLATORS: make sure these match _("HEAD detached at ")
-		   and _("HEAD detached from ") in wt-status.c */
-		if (state.detached_at)
-			strbuf_addf(&desc, _("(HEAD detached at %s)"),
-				state.detached_from);
-		else
-			strbuf_addf(&desc, _("(HEAD detached from %s)"),
-				state.detached_from);
-	}
-	else
-		strbuf_addstr(&desc, _("(no branch)"));
-	free(state.branch);
-	free(state.onto);
-	free(state.detached_from);
-	return strbuf_detach(&desc, NULL);
-}
-
 static void show_detached(struct ref_list *ref_list, int maxwidth)
 {
 	struct commit *head_commit = lookup_commit_reference_gently(head_sha1, 1);
-- 
2.5.1

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v4 3/8] branch: roll show_detached HEAD into regular ref_list
  2015-09-13  7:23 [PATCH v4 0/8] port the filtering part of branch.c to use ref-filter APIs Karthik Nayak
  2015-09-13  7:23 ` [PATCH v4 1/8] branch: refactor width computation Karthik Nayak
  2015-09-13  7:23 ` [PATCH v4 2/8] branch: bump get_head_description() to the top Karthik Nayak
@ 2015-09-13  7:23 ` Karthik Nayak
  2015-09-13 12:12   ` Matthieu Moy
  2015-09-14 19:35   ` Junio C Hamano
  2015-09-13  7:23 ` [PATCH v4 4/8] branch: move 'current' check down to the presentation layer Karthik Nayak
                   ` (5 subsequent siblings)
  8 siblings, 2 replies; 38+ messages in thread
From: Karthik Nayak @ 2015-09-13  7:23 UTC (permalink / raw)
  To: git; +Cc: christian.couder, Matthieu.Moy, gitster, Karthik Nayak, Karthik Nayak

Remove show_detached() and make detached HEAD to be rolled into
regular ref_list by adding REF_DETACHED_HEAD as a kind of branch and
supporting the same in append_ref(). This eliminates the need for an
extra function and helps in easier porting of branch.c to use
ref-filter APIs.

Before show_detached() used to check if the HEAD branch satisfies the
'--contains' option, now that is taken care by append_ref().

Based-on-patch-by: Jeff King <peff@peff.net>
Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>
Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
---
 builtin/branch.c | 68 +++++++++++++++++++++++++++++++++-----------------------
 1 file changed, 40 insertions(+), 28 deletions(-)

diff --git a/builtin/branch.c b/builtin/branch.c
index 193296a..6ba7a3f 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -30,6 +30,7 @@ static const char * const builtin_branch_usage[] = {
 
 #define REF_LOCAL_BRANCH    0x01
 #define REF_REMOTE_BRANCH   0x02
+#define REF_DETACHED_HEAD   0x04
 
 static const char *head;
 static unsigned char head_sha1[20];
@@ -352,8 +353,12 @@ static int append_ref(const char *refname, const struct object_id *oid, int flag
 			break;
 		}
 	}
-	if (ARRAY_SIZE(ref_kind) <= i)
-		return 0;
+	if (ARRAY_SIZE(ref_kind) <= i) {
+		if (!strcmp(refname, "HEAD"))
+			kind = REF_DETACHED_HEAD;
+		else
+			return 0;
+	}
 
 	/* Don't add types the caller doesn't want */
 	if ((kind & ref_list->kinds) == 0)
@@ -535,6 +540,8 @@ static void print_ref_item(struct ref_item *item, int maxwidth, int verbose,
 	int color;
 	struct strbuf out = STRBUF_INIT, name = STRBUF_INIT;
 	const char *prefix = "";
+	const char *desc = item->name;
+	char *to_free = NULL;
 
 	if (item->ignore)
 		return;
@@ -547,6 +554,10 @@ static void print_ref_item(struct ref_item *item, int maxwidth, int verbose,
 		color = BRANCH_COLOR_REMOTE;
 		prefix = remote_prefix;
 		break;
+	case REF_DETACHED_HEAD:
+		color = BRANCH_COLOR_CURRENT;
+		desc = to_free = get_head_description();
+		break;
 	default:
 		color = BRANCH_COLOR_PLAIN;
 		break;
@@ -558,7 +569,7 @@ static void print_ref_item(struct ref_item *item, int maxwidth, int verbose,
 		color = BRANCH_COLOR_CURRENT;
 	}
 
-	strbuf_addf(&name, "%s%s", prefix, item->name);
+	strbuf_addf(&name, "%s%s", prefix, desc);
 	if (verbose) {
 		int utf8_compensation = strlen(name.buf) - utf8_strwidth(name.buf);
 		strbuf_addf(&out, "%c %s%-*s%s", c, branch_get_color(color),
@@ -581,6 +592,7 @@ static void print_ref_item(struct ref_item *item, int maxwidth, int verbose,
 	}
 	strbuf_release(&name);
 	strbuf_release(&out);
+	free(to_free);
 }
 
 static int calc_maxwidth(struct ref_list *refs, int remote_bonus)
@@ -601,25 +613,9 @@ static int calc_maxwidth(struct ref_list *refs, int remote_bonus)
 	return max;
 }
 
-static void show_detached(struct ref_list *ref_list, int maxwidth)
-{
-	struct commit *head_commit = lookup_commit_reference_gently(head_sha1, 1);
-
-	if (head_commit && is_descendant_of(head_commit, ref_list->with_commit)) {
-		struct ref_item item;
-		item.name = get_head_description();
-		item.kind = REF_LOCAL_BRANCH;
-		item.dest = NULL;
-		item.commit = head_commit;
-		item.ignore = 0;
-		print_ref_item(&item, maxwidth, ref_list->verbose, ref_list->abbrev, 1, "");
-		free(item.name);
-	}
-}
-
 static int print_ref_list(int kinds, int detached, int verbose, int abbrev, struct commit_list *with_commit, const char **pattern)
 {
-	int i;
+	int i, index;
 	struct append_ref_cb cb;
 	struct ref_list ref_list;
 	int maxwidth = 0;
@@ -643,7 +639,14 @@ static int print_ref_list(int kinds, int detached, int verbose, int abbrev, stru
 	cb.ref_list = &ref_list;
 	cb.pattern = pattern;
 	cb.ret = 0;
+	/*
+	 * First we obtain all regular branch refs and if the HEAD is
+	 * detached then we insert that ref to the end of the ref_fist
+	 * so that it can be printed and removed first.
+	 */
 	for_each_rawref(append_ref, &cb);
+	if (detached)
+		head_ref(append_ref, &cb);
 	/*
 	 * The following implementation is currently duplicated in ref-filter. It
 	 * will eventually be removed when we port branch.c to use ref-filter APIs.
@@ -679,15 +682,20 @@ static int print_ref_list(int kinds, int detached, int verbose, int abbrev, stru
 	if (verbose)
 		maxwidth = calc_maxwidth(&ref_list, strlen(remote_prefix));
 
-	qsort(ref_list.list, ref_list.index, sizeof(struct ref_item), ref_cmp);
+	index = ref_list.index;
+
+	/* Print detached HEAD before sorting and printing the rest */
+	if (detached && (ref_list.list[index - 1].kind == REF_DETACHED_HEAD) &&
+	    !strcmp(ref_list.list[index - 1].name, head)) {
+		print_ref_item(&ref_list.list[index - 1], maxwidth, verbose, abbrev,
+			       1, remote_prefix);
+		index -= 1;
+	}
 
-	detached = (detached && (kinds & REF_LOCAL_BRANCH));
-	if (detached && match_patterns(pattern, "HEAD"))
-		show_detached(&ref_list, maxwidth);
+	qsort(ref_list.list, index, sizeof(struct ref_item), ref_cmp);
 
-	for (i = 0; i < ref_list.index; i++) {
-		int current = !detached &&
-			(ref_list.list[i].kind == REF_LOCAL_BRANCH) &&
+	for (i = 0; i < index; i++) {
+		int current = !detached && (ref_list.list[i].kind == REF_LOCAL_BRANCH) &&
 			!strcmp(ref_list.list[i].name, head);
 		print_ref_item(&ref_list.list[i], maxwidth, verbose,
 			       abbrev, current, remote_prefix);
@@ -914,7 +922,11 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
 			die(_("branch name required"));
 		return delete_branches(argc, argv, delete > 1, kinds, quiet);
 	} else if (list) {
-		int ret = print_ref_list(kinds, detached, verbose, abbrev,
+		int ret;
+		/*  git branch --local also shows HEAD when it is detached */
+		if (kinds & REF_LOCAL_BRANCH)
+			kinds |= REF_DETACHED_HEAD;
+		ret = print_ref_list(kinds, detached, verbose, abbrev,
 					 with_commit, argv);
 		print_columns(&output, colopts, NULL);
 		string_list_clear(&output, 0);
-- 
2.5.1

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v4 4/8] branch: move 'current' check down to the presentation layer
  2015-09-13  7:23 [PATCH v4 0/8] port the filtering part of branch.c to use ref-filter APIs Karthik Nayak
                   ` (2 preceding siblings ...)
  2015-09-13  7:23 ` [PATCH v4 3/8] branch: roll show_detached HEAD into regular ref_list Karthik Nayak
@ 2015-09-13  7:23 ` Karthik Nayak
  2015-09-13 12:15   ` Matthieu Moy
  2015-09-13 15:35   ` Karthik Nayak
  2015-09-13  7:23 ` [PATCH v4 5/8] branch: drop non-commit error reporting Karthik Nayak
                   ` (4 subsequent siblings)
  8 siblings, 2 replies; 38+ messages in thread
From: Karthik Nayak @ 2015-09-13  7:23 UTC (permalink / raw)
  To: git; +Cc: christian.couder, Matthieu.Moy, gitster, Karthik Nayak, Karthik Nayak

We check if given ref is the current branch in print_ref_list(). Move
this check to print_ref_item() where it is checked right before
printing.

Based-on-patch-by: Jeff King <peff@peff.net>
Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>
Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
---
 builtin/branch.c | 22 +++++++++++-----------
 1 file changed, 11 insertions(+), 11 deletions(-)

diff --git a/builtin/branch.c b/builtin/branch.c
index 6ba7a3f..4d9e4d0 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -534,9 +534,10 @@ static char *get_head_description(void)
 }
 
 static void print_ref_item(struct ref_item *item, int maxwidth, int verbose,
-			   int abbrev, int current, const char *remote_prefix)
+			   int abbrev, int detached, const char *remote_prefix)
 {
 	char c;
+	int current = 0;
 	int color;
 	struct strbuf out = STRBUF_INIT, name = STRBUF_INIT;
 	const char *prefix = "";
@@ -548,15 +549,18 @@ static void print_ref_item(struct ref_item *item, int maxwidth, int verbose,
 
 	switch (item->kind) {
 	case REF_LOCAL_BRANCH:
-		color = BRANCH_COLOR_LOCAL;
+		if (!detached && !strcmp(item->name, head))
+			current = 1;
+		else
+			color = BRANCH_COLOR_LOCAL;
 		break;
 	case REF_REMOTE_BRANCH:
 		color = BRANCH_COLOR_REMOTE;
 		prefix = remote_prefix;
 		break;
 	case REF_DETACHED_HEAD:
-		color = BRANCH_COLOR_CURRENT;
 		desc = to_free = get_head_description();
+		current = 1;
 		break;
 	default:
 		color = BRANCH_COLOR_PLAIN;
@@ -685,21 +689,17 @@ static int print_ref_list(int kinds, int detached, int verbose, int abbrev, stru
 	index = ref_list.index;
 
 	/* Print detached HEAD before sorting and printing the rest */
-	if (detached && (ref_list.list[index - 1].kind == REF_DETACHED_HEAD) &&
-	    !strcmp(ref_list.list[index - 1].name, head)) {
+	if (detached) {
 		print_ref_item(&ref_list.list[index - 1], maxwidth, verbose, abbrev,
-			       1, remote_prefix);
+			       detached, remote_prefix);
 		index -= 1;
 	}
 
 	qsort(ref_list.list, index, sizeof(struct ref_item), ref_cmp);
 
-	for (i = 0; i < index; i++) {
-		int current = !detached && (ref_list.list[i].kind == REF_LOCAL_BRANCH) &&
-			!strcmp(ref_list.list[i].name, head);
+	for (i = 0; i < index; i++)
 		print_ref_item(&ref_list.list[i], maxwidth, verbose,
-			       abbrev, current, remote_prefix);
-	}
+			       abbrev, detached, remote_prefix);
 
 	free_ref_list(&ref_list);
 
-- 
2.5.1

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v4 5/8] branch: drop non-commit error reporting
  2015-09-13  7:23 [PATCH v4 0/8] port the filtering part of branch.c to use ref-filter APIs Karthik Nayak
                   ` (3 preceding siblings ...)
  2015-09-13  7:23 ` [PATCH v4 4/8] branch: move 'current' check down to the presentation layer Karthik Nayak
@ 2015-09-13  7:23 ` Karthik Nayak
  2015-09-14 19:49   ` Junio C Hamano
  2015-09-13  7:23 ` [PATCH v4 6/8] branch.c: use 'ref-filter' data structures Karthik Nayak
                   ` (3 subsequent siblings)
  8 siblings, 1 reply; 38+ messages in thread
From: Karthik Nayak @ 2015-09-13  7:23 UTC (permalink / raw)
  To: git; +Cc: christian.couder, Matthieu.Moy, gitster, Karthik Nayak, Karthik Nayak

Remove the error reporting variable to make the code easier to port
over to using ref-filter APIs. This variable is not required as in
ref-filter we already check for possible errors and report them.

Based-on-patch-by: Jeff King <peff@peff.net>
Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>
Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
---
 builtin/branch.c | 18 ++++--------------
 1 file changed, 4 insertions(+), 14 deletions(-)

diff --git a/builtin/branch.c b/builtin/branch.c
index 4d9e4d0..8b9da60 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -313,7 +313,6 @@ static char *resolve_symref(const char *src, const char *prefix)
 struct append_ref_cb {
 	struct ref_list *ref_list;
 	const char **pattern;
-	int ret;
 };
 
 static int match_patterns(const char **pattern, const char *refname)
@@ -370,10 +369,8 @@ static int append_ref(const char *refname, const struct object_id *oid, int flag
 	commit = NULL;
 	if (ref_list->verbose || ref_list->with_commit || merge_filter != NO_FILTER) {
 		commit = lookup_commit_reference_gently(oid->hash, 1);
-		if (!commit) {
-			cb->ret = error(_("branch '%s' does not point at a commit"), refname);
+		if (!commit)
 			return 0;
-		}
 
 		/* Filter with with_commit if specified */
 		if (!is_descendant_of(commit, ref_list->with_commit))
@@ -617,7 +614,7 @@ static int calc_maxwidth(struct ref_list *refs, int remote_bonus)
 	return max;
 }
 
-static int print_ref_list(int kinds, int detached, int verbose, int abbrev, struct commit_list *with_commit, const char **pattern)
+static void print_ref_list(int kinds, int detached, int verbose, int abbrev, struct commit_list *with_commit, const char **pattern)
 {
 	int i, index;
 	struct append_ref_cb cb;
@@ -642,7 +639,6 @@ static int print_ref_list(int kinds, int detached, int verbose, int abbrev, stru
 		init_revisions(&ref_list.revs, NULL);
 	cb.ref_list = &ref_list;
 	cb.pattern = pattern;
-	cb.ret = 0;
 	/*
 	 * First we obtain all regular branch refs and if the HEAD is
 	 * detached then we insert that ref to the end of the ref_fist
@@ -702,11 +698,6 @@ static int print_ref_list(int kinds, int detached, int verbose, int abbrev, stru
 			       abbrev, detached, remote_prefix);
 
 	free_ref_list(&ref_list);
-
-	if (cb.ret)
-		error(_("some refs could not be read"));
-
-	return cb.ret;
 }
 
 static void rename_branch(const char *oldname, const char *newname, int force)
@@ -922,15 +913,14 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
 			die(_("branch name required"));
 		return delete_branches(argc, argv, delete > 1, kinds, quiet);
 	} else if (list) {
-		int ret;
 		/*  git branch --local also shows HEAD when it is detached */
 		if (kinds & REF_LOCAL_BRANCH)
 			kinds |= REF_DETACHED_HEAD;
-		ret = print_ref_list(kinds, detached, verbose, abbrev,
+		print_ref_list(kinds, detached, verbose, abbrev,
 					 with_commit, argv);
 		print_columns(&output, colopts, NULL);
 		string_list_clear(&output, 0);
-		return ret;
+		return 0;
 	}
 	else if (edit_description) {
 		const char *branch_name;
-- 
2.5.1

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v4 6/8] branch.c: use 'ref-filter' data structures
  2015-09-13  7:23 [PATCH v4 0/8] port the filtering part of branch.c to use ref-filter APIs Karthik Nayak
                   ` (4 preceding siblings ...)
  2015-09-13  7:23 ` [PATCH v4 5/8] branch: drop non-commit error reporting Karthik Nayak
@ 2015-09-13  7:23 ` Karthik Nayak
  2015-09-13 12:26   ` Matthieu Moy
  2015-09-13  7:23 ` Karthik Nayak
                   ` (2 subsequent siblings)
  8 siblings, 1 reply; 38+ messages in thread
From: Karthik Nayak @ 2015-09-13  7:23 UTC (permalink / raw)
  To: git; +Cc: christian.couder, Matthieu.Moy, gitster, Karthik Nayak, Karthik Nayak

Make 'branch.c' use 'ref-filter' data structures and make changes to
support the new data structures. This is a part of the process of
porting 'branch.c' to use 'ref-filter' APIs.

This is a temporary step before porting 'branch.c' to use 'ref-filter'
completely. As this is a temporary step, most of the code introduced
here will be removed when 'branch.c' is ported over to use
'ref-filter' APIs.

Make 'free_array_item()' of ref-filter.c a non static function. This
is used to free memory allocated to a detached head ref, before we
print other refs.

Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>
Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
---
 builtin/branch.c | 328 ++++++++++++++++++++++---------------------------------
 ref-filter.c     |   2 +-
 ref-filter.h     |   9 +-
 3 files changed, 141 insertions(+), 198 deletions(-)

diff --git a/builtin/branch.c b/builtin/branch.c
index 8b9da60..5cb7ef0 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -19,6 +19,7 @@
 #include "column.h"
 #include "utf8.h"
 #include "wt-status.h"
+#include "ref-filter.h"
 
 static const char * const builtin_branch_usage[] = {
 	N_("git branch [<options>] [-r | -a] [--merged | --no-merged]"),
@@ -28,10 +29,6 @@ static const char * const builtin_branch_usage[] = {
 	NULL
 };
 
-#define REF_LOCAL_BRANCH    0x01
-#define REF_REMOTE_BRANCH   0x02
-#define REF_DETACHED_HEAD   0x04
-
 static const char *head;
 static unsigned char head_sha1[20];
 
@@ -53,13 +50,6 @@ enum color_branch {
 	BRANCH_COLOR_UPSTREAM = 5
 };
 
-static enum merge_filter {
-	NO_FILTER = 0,
-	SHOW_NOT_MERGED,
-	SHOW_MERGED
-} merge_filter;
-static unsigned char merge_filter_ref[20];
-
 static struct string_list output = STRING_LIST_INIT_DUP;
 static unsigned int colopts;
 
@@ -122,7 +112,7 @@ static int branch_merged(int kind, const char *name,
 	void *reference_name_to_free = NULL;
 	int merged;
 
-	if (kind == REF_LOCAL_BRANCH) {
+	if (kind == FILTER_REFS_BRANCHES) {
 		struct branch *branch = branch_get(name);
 		const char *upstream = branch_get_upstream(branch, NULL);
 		unsigned char sha1[20];
@@ -200,14 +190,14 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
 	struct strbuf bname = STRBUF_INIT;
 
 	switch (kinds) {
-	case REF_REMOTE_BRANCH:
+	case FILTER_REFS_REMOTES:
 		fmt = "refs/remotes/%s";
 		/* For subsequent UI messages */
 		remote_branch = 1;
 
 		force = 1;
 		break;
-	case REF_LOCAL_BRANCH:
+	case FILTER_REFS_BRANCHES:
 		fmt = "refs/heads/%s";
 		break;
 	default:
@@ -224,7 +214,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
 		int flags = 0;
 
 		strbuf_branchname(&bname, argv[i]);
-		if (kinds == REF_LOCAL_BRANCH && !strcmp(head, bname.buf)) {
+		if (kinds == FILTER_REFS_BRANCHES && !strcmp(head, bname.buf)) {
 			error(_("Cannot delete the branch '%s' "
 			      "which you are currently on."), bname.buf);
 			ret = 1;
@@ -280,22 +270,6 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
 	return(ret);
 }
 
-struct ref_item {
-	char *name;
-	char *dest;
-	unsigned int kind;
-	struct commit *commit;
-	int ignore;
-};
-
-struct ref_list {
-	struct rev_info revs;
-	int index, alloc, verbose, abbrev;
-	struct ref_item *list;
-	struct commit_list *with_commit;
-	int kinds;
-};
-
 static char *resolve_symref(const char *src, const char *prefix)
 {
 	unsigned char sha1[20];
@@ -310,11 +284,6 @@ static char *resolve_symref(const char *src, const char *prefix)
 	return xstrdup(dst);
 }
 
-struct append_ref_cb {
-	struct ref_list *ref_list;
-	const char **pattern;
-};
-
 static int match_patterns(const char **pattern, const char *refname)
 {
 	if (!*pattern)
@@ -327,11 +296,29 @@ static int match_patterns(const char **pattern, const char *refname)
 	return 0;
 }
 
+/*
+ * Allocate memory for a new ref_array_item and insert that into the
+ * given ref_array. Doesn't take the objectname unlike
+ * new_ref_array_item(). This is a temporary function which will be
+ * removed when we port branch.c to use ref-filter APIs.
+ */
+static struct ref_array_item *ref_array_append(struct ref_array *array, const char *refname)
+{
+	size_t len = strlen(refname);
+	struct ref_array_item *ref = xcalloc(1, sizeof(struct ref_array_item) + len + 1);
+	memcpy(ref->refname, refname, len);
+	ref->refname[len] = '\0';
+	REALLOC_ARRAY(array->items, array->nr + 1);
+	array->items[array->nr++] = ref;
+	return ref;
+}
+
 static int append_ref(const char *refname, const struct object_id *oid, int flags, void *cb_data)
 {
-	struct append_ref_cb *cb = (struct append_ref_cb *)(cb_data);
-	struct ref_list *ref_list = cb->ref_list;
-	struct ref_item *newitem;
+	struct ref_filter_cbdata *cb = (struct ref_filter_cbdata *)(cb_data);
+	struct ref_filter *filter = cb->filter;
+	struct ref_array *array = cb->array;
+	struct ref_array_item *item;
 	struct commit *commit;
 	int kind, i;
 	const char *prefix, *orig_refname = refname;
@@ -340,8 +327,8 @@ static int append_ref(const char *refname, const struct object_id *oid, int flag
 		int kind;
 		const char *prefix;
 	} ref_kind[] = {
-		{ REF_LOCAL_BRANCH, "refs/heads/" },
-		{ REF_REMOTE_BRANCH, "refs/remotes/" },
+		{ FILTER_REFS_BRANCHES, "refs/heads/" },
+		{ FILTER_REFS_REMOTES, "refs/remotes/" },
 	};
 
 	/* Detect kind */
@@ -354,65 +341,52 @@ static int append_ref(const char *refname, const struct object_id *oid, int flag
 	}
 	if (ARRAY_SIZE(ref_kind) <= i) {
 		if (!strcmp(refname, "HEAD"))
-			kind = REF_DETACHED_HEAD;
+			kind = FILTER_REFS_DETACHED_HEAD;
 		else
 			return 0;
 	}
 
 	/* Don't add types the caller doesn't want */
-	if ((kind & ref_list->kinds) == 0)
+	if ((kind & filter->kind) == 0)
 		return 0;
 
-	if (!match_patterns(cb->pattern, refname))
+	if (!match_patterns(filter->name_patterns, refname))
 		return 0;
 
 	commit = NULL;
-	if (ref_list->verbose || ref_list->with_commit || merge_filter != NO_FILTER) {
+	if (filter->verbose || filter->with_commit || filter->merge != REF_FILTER_MERGED_NONE) {
 		commit = lookup_commit_reference_gently(oid->hash, 1);
 		if (!commit)
 			return 0;
 
 		/* Filter with with_commit if specified */
-		if (!is_descendant_of(commit, ref_list->with_commit))
+		if (!is_descendant_of(commit, filter->with_commit))
 			return 0;
 
-		if (merge_filter != NO_FILTER)
-			add_pending_object(&ref_list->revs,
+		if (filter->merge != REF_FILTER_MERGED_NONE)
+			add_pending_object(array->revs,
 					   (struct object *)commit, refname);
 	}
 
-	ALLOC_GROW(ref_list->list, ref_list->index + 1, ref_list->alloc);
+	item = ref_array_append(array, refname);
 
 	/* Record the new item */
-	newitem = &(ref_list->list[ref_list->index++]);
-	newitem->name = xstrdup(refname);
-	newitem->kind = kind;
-	newitem->commit = commit;
-	newitem->dest = resolve_symref(orig_refname, prefix);
-	newitem->ignore = 0;
+	item->kind = kind;
+	item->commit = commit;
+	item->symref = resolve_symref(orig_refname, prefix);
+	item->ignore = 0;
 
 	return 0;
 }
 
-static void free_ref_list(struct ref_list *ref_list)
-{
-	int i;
-
-	for (i = 0; i < ref_list->index; i++) {
-		free(ref_list->list[i].name);
-		free(ref_list->list[i].dest);
-	}
-	free(ref_list->list);
-}
-
 static int ref_cmp(const void *r1, const void *r2)
 {
-	struct ref_item *c1 = (struct ref_item *)(r1);
-	struct ref_item *c2 = (struct ref_item *)(r2);
+	struct ref_array_item *c1 = *((struct ref_array_item **)r1);
+	struct ref_array_item *c2 = *((struct ref_array_item **)r2);
 
 	if (c1->kind != c2->kind)
 		return c1->kind - c2->kind;
-	return strcmp(c1->name, c2->name);
+	return strcmp(c1->refname, c2->refname);
 }
 
 static void fill_tracking_info(struct strbuf *stat, const char *branch_name,
@@ -477,8 +451,8 @@ static void fill_tracking_info(struct strbuf *stat, const char *branch_name,
 	free(ref);
 }
 
-static void add_verbose_info(struct strbuf *out, struct ref_item *item,
-			     int verbose, int abbrev)
+static void add_verbose_info(struct strbuf *out, struct ref_array_item *item,
+			     struct ref_filter *filter)
 {
 	struct strbuf subject = STRBUF_INIT, stat = STRBUF_INIT;
 	const char *sub = _(" **** invalid ref ****");
@@ -489,11 +463,11 @@ static void add_verbose_info(struct strbuf *out, struct ref_item *item,
 		sub = subject.buf;
 	}
 
-	if (item->kind == REF_LOCAL_BRANCH)
-		fill_tracking_info(&stat, item->name, verbose > 1);
+	if (item->kind == FILTER_REFS_BRANCHES)
+		fill_tracking_info(&stat, item->refname, filter->verbose > 1);
 
 	strbuf_addf(out, " %s %s%s",
-		find_unique_abbrev(item->commit->object.sha1, abbrev),
+		find_unique_abbrev(item->commit->object.sha1, filter->abbrev),
 		stat.buf, sub);
 	strbuf_release(&stat);
 	strbuf_release(&subject);
@@ -530,32 +504,32 @@ static char *get_head_description(void)
 	return strbuf_detach(&desc, NULL);
 }
 
-static void print_ref_item(struct ref_item *item, int maxwidth, int verbose,
-			   int abbrev, int detached, const char *remote_prefix)
+static void print_ref_item(struct ref_array_item *item, int maxwidth,
+			   struct ref_filter *filter, const char *remote_prefix)
 {
 	char c;
 	int current = 0;
 	int color;
 	struct strbuf out = STRBUF_INIT, name = STRBUF_INIT;
 	const char *prefix = "";
-	const char *desc = item->name;
+	const char *desc = item->refname;
 	char *to_free = NULL;
 
 	if (item->ignore)
 		return;
 
 	switch (item->kind) {
-	case REF_LOCAL_BRANCH:
-		if (!detached && !strcmp(item->name, head))
+	case FILTER_REFS_BRANCHES:
+		if (!filter->detached && !strcmp(item->refname, head))
 			current = 1;
 		else
 			color = BRANCH_COLOR_LOCAL;
 		break;
-	case REF_REMOTE_BRANCH:
+	case FILTER_REFS_REMOTES:
 		color = BRANCH_COLOR_REMOTE;
 		prefix = remote_prefix;
 		break;
-	case REF_DETACHED_HEAD:
+	case FILTER_REFS_DETACHED_HEAD:
 		desc = to_free = get_head_description();
 		current = 1;
 		break;
@@ -571,7 +545,7 @@ static void print_ref_item(struct ref_item *item, int maxwidth, int verbose,
 	}
 
 	strbuf_addf(&name, "%s%s", prefix, desc);
-	if (verbose) {
+	if (filter->verbose) {
 		int utf8_compensation = strlen(name.buf) - utf8_strwidth(name.buf);
 		strbuf_addf(&out, "%c %s%-*s%s", c, branch_get_color(color),
 			    maxwidth + utf8_compensation, name.buf,
@@ -580,13 +554,13 @@ static void print_ref_item(struct ref_item *item, int maxwidth, int verbose,
 		strbuf_addf(&out, "%c %s%s%s", c, branch_get_color(color),
 			    name.buf, branch_get_color(BRANCH_COLOR_RESET));
 
-	if (item->dest)
-		strbuf_addf(&out, " -> %s", item->dest);
-	else if (verbose)
+	if (item->symref)
+		strbuf_addf(&out, " -> %s", item->symref);
+	else if (filter->verbose)
 		/* " f7c0c00 [ahead 58, behind 197] vcs-svn: drop obj_pool.h" */
-		add_verbose_info(&out, item, verbose, abbrev);
+		add_verbose_info(&out, item, filter);
 	if (column_active(colopts)) {
-		assert(!verbose && "--column and --verbose are incompatible");
+		assert(!filter->verbose && "--column and --verbose are incompatible");
 		string_list_append(&output, out.buf);
 	} else {
 		printf("%s\n", out.buf);
@@ -596,17 +570,17 @@ static void print_ref_item(struct ref_item *item, int maxwidth, int verbose,
 	free(to_free);
 }
 
-static int calc_maxwidth(struct ref_list *refs, int remote_bonus)
+static int calc_maxwidth(struct ref_array *refs, int remote_bonus)
 {
 	int i, max = 0;
-	for (i = 0; i < refs->index; i++) {
-		struct ref_item *it = &refs->list[i];
+	for (i = 0; i < refs->nr; i++) {
+		struct ref_array_item *it = refs->items[i];
 		int w;
 
 		if (it->ignore)
 			continue;
-		w = utf8_strwidth(it->name);
-		if (it->kind == REF_REMOTE_BRANCH)
+		w = utf8_strwidth(it->refname);
+		if (it->kind == FILTER_REFS_REMOTES)
 			w += remote_bonus;
 		if (w > max)
 			max = w;
@@ -614,90 +588,80 @@ static int calc_maxwidth(struct ref_list *refs, int remote_bonus)
 	return max;
 }
 
-static void print_ref_list(int kinds, int detached, int verbose, int abbrev, struct commit_list *with_commit, const char **pattern)
+static void print_ref_list(struct ref_filter *filter)
 {
-	int i, index;
-	struct append_ref_cb cb;
-	struct ref_list ref_list;
+	int i;
+	struct ref_array array;
+	struct ref_filter_cbdata data;
 	int maxwidth = 0;
 	const char *remote_prefix = "";
+	struct rev_info revs;
 
 	/*
 	 * If we are listing more than just remote branches,
 	 * then remote branches will have a "remotes/" prefix.
 	 * We need to account for this in the width.
 	 */
-	if (kinds != REF_REMOTE_BRANCH)
+	if (filter->kind != FILTER_REFS_REMOTES)
 		remote_prefix = "remotes/";
 
-	memset(&ref_list, 0, sizeof(ref_list));
-	ref_list.kinds = kinds;
-	ref_list.verbose = verbose;
-	ref_list.abbrev = abbrev;
-	ref_list.with_commit = with_commit;
-	if (merge_filter != NO_FILTER)
-		init_revisions(&ref_list.revs, NULL);
-	cb.ref_list = &ref_list;
-	cb.pattern = pattern;
+	memset(&array, 0, sizeof(array));
+	if (filter->merge != REF_FILTER_MERGED_NONE)
+		init_revisions(&revs, NULL);
+
+	data.array = &array;
+	data.filter = filter;
+	array.revs = &revs;
+
 	/*
 	 * First we obtain all regular branch refs and if the HEAD is
 	 * detached then we insert that ref to the end of the ref_fist
 	 * so that it can be printed and removed first.
 	 */
-	for_each_rawref(append_ref, &cb);
-	if (detached)
-		head_ref(append_ref, &cb);
+	for_each_rawref(append_ref, &data);
+	if (filter->detached)
+		head_ref(append_ref, &data);
 	/*
 	 * The following implementation is currently duplicated in ref-filter. It
 	 * will eventually be removed when we port branch.c to use ref-filter APIs.
 	 */
-	if (merge_filter != NO_FILTER) {
-		struct commit *filter;
-		filter = lookup_commit_reference_gently(merge_filter_ref, 0);
-		if (!filter)
-			die(_("object '%s' does not point to a commit"),
-			    sha1_to_hex(merge_filter_ref));
-
-		filter->object.flags |= UNINTERESTING;
-		add_pending_object(&ref_list.revs,
-				   (struct object *) filter, "");
-		ref_list.revs.limited = 1;
-
-		if (prepare_revision_walk(&ref_list.revs))
+	if (filter->merge != REF_FILTER_MERGED_NONE) {
+		filter->merge_commit->object.flags |= UNINTERESTING;
+		add_pending_object(&revs, &filter->merge_commit->object, "");
+		revs.limited = 1;
+
+		if (prepare_revision_walk(&revs))
 			die(_("revision walk setup failed"));
 
-		for (i = 0; i < ref_list.index; i++) {
-			struct ref_item *item = &ref_list.list[i];
+		for (i = 0; i < array.nr; i++) {
+			struct ref_array_item *item = array.items[i];
 			struct commit *commit = item->commit;
 			int is_merged = !!(commit->object.flags & UNINTERESTING);
-			item->ignore = is_merged != (merge_filter == SHOW_MERGED);
+			item->ignore = is_merged != (filter->merge == REF_FILTER_MERGED_INCLUDE);
 		}
 
-		for (i = 0; i < ref_list.index; i++) {
-			struct ref_item *item = &ref_list.list[i];
+		for (i = 0; i < array.nr; i++) {
+			struct ref_array_item *item = array.items[i];
 			clear_commit_marks(item->commit, ALL_REV_FLAGS);
 		}
-		clear_commit_marks(filter, ALL_REV_FLAGS);
+		clear_commit_marks(filter->merge_commit, ALL_REV_FLAGS);
 	}
-	if (verbose)
-		maxwidth = calc_maxwidth(&ref_list, strlen(remote_prefix));
-
-	index = ref_list.index;
+	if (filter->verbose)
+		maxwidth = calc_maxwidth(&array, strlen(remote_prefix));
 
 	/* Print detached HEAD before sorting and printing the rest */
-	if (detached) {
-		print_ref_item(&ref_list.list[index - 1], maxwidth, verbose, abbrev,
-			       detached, remote_prefix);
-		index -= 1;
+	if (filter->kind & FILTER_REFS_DETACHED_HEAD) {
+		print_ref_item(array.items[array.nr - 1], maxwidth, filter, remote_prefix);
+		free_array_item(array.items[array.nr - 1]);
+		array.nr--;
 	}
 
-	qsort(ref_list.list, index, sizeof(struct ref_item), ref_cmp);
+	qsort(array.items, array.nr, sizeof(struct ref_array_item *), ref_cmp);
 
-	for (i = 0; i < index; i++)
-		print_ref_item(&ref_list.list[i], maxwidth, verbose,
-			       abbrev, detached, remote_prefix);
+	for (i = 0; i < array.nr; i++)
+		print_ref_item(array.items[i], maxwidth, filter, remote_prefix);
 
-	free_ref_list(&ref_list);
+	ref_array_clear(&array);
 }
 
 static void rename_branch(const char *oldname, const char *newname, int force)
@@ -753,24 +717,6 @@ static void rename_branch(const char *oldname, const char *newname, int force)
 	strbuf_release(&newsection);
 }
 
-/*
- * This function is duplicated in ref-filter. It will eventually be removed
- * when we port branch.c to use ref-filter APIs.
- */
-static int opt_parse_merge_filter(const struct option *opt, const char *arg, int unset)
-{
-	merge_filter = ((opt->long_name[0] == 'n')
-			? SHOW_NOT_MERGED
-			: SHOW_MERGED);
-	if (unset)
-		merge_filter = SHOW_NOT_MERGED; /* b/c for --no-merged */
-	if (!arg)
-		arg = "HEAD";
-	if (get_sha1(arg, merge_filter_ref))
-		die(_("malformed object name %s"), arg);
-	return 0;
-}
-
 static const char edit_description[] = "BRANCH_DESCRIPTION";
 
 static int edit_branch_description(const char *branch_name)
@@ -810,17 +756,15 @@ static int edit_branch_description(const char *branch_name)
 int cmd_branch(int argc, const char **argv, const char *prefix)
 {
 	int delete = 0, rename = 0, force = 0, list = 0;
-	int verbose = 0, abbrev = -1, detached = 0;
 	int reflog = 0, edit_description = 0;
 	int quiet = 0, unset_upstream = 0;
 	const char *new_upstream = NULL;
 	enum branch_track track;
-	int kinds = REF_LOCAL_BRANCH;
-	struct commit_list *with_commit = NULL;
+	struct ref_filter filter;
 
 	struct option options[] = {
 		OPT_GROUP(N_("Generic options")),
-		OPT__VERBOSE(&verbose,
+		OPT__VERBOSE(&filter.verbose,
 			N_("show hash and subject, give twice for upstream branch")),
 		OPT__QUIET(&quiet, N_("suppress informational messages")),
 		OPT_SET_INT('t', "track",  &track, N_("set up tracking mode (see git-pull(1))"),
@@ -830,15 +774,15 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
 		OPT_STRING('u', "set-upstream-to", &new_upstream, "upstream", "change the upstream info"),
 		OPT_BOOL(0, "unset-upstream", &unset_upstream, "Unset the upstream info"),
 		OPT__COLOR(&branch_use_color, N_("use colored output")),
-		OPT_SET_INT('r', "remotes",     &kinds, N_("act on remote-tracking branches"),
-			REF_REMOTE_BRANCH),
-		OPT_CONTAINS(&with_commit, N_("print only branches that contain the commit")),
-		OPT_WITH(&with_commit, N_("print only branches that contain the commit")),
-		OPT__ABBREV(&abbrev),
+		OPT_SET_INT('r', "remotes",     &filter.kind, N_("act on remote-tracking branches"),
+			FILTER_REFS_REMOTES),
+		OPT_CONTAINS(&filter.with_commit, N_("print only branches that contain the commit")),
+		OPT_WITH(&filter.with_commit, N_("print only branches that contain the commit")),
+		OPT__ABBREV(&filter.abbrev),
 
 		OPT_GROUP(N_("Specific git-branch actions:")),
-		OPT_SET_INT('a', "all", &kinds, N_("list both remote-tracking and local branches"),
-			REF_REMOTE_BRANCH | REF_LOCAL_BRANCH),
+		OPT_SET_INT('a', "all", &filter.kind, N_("list both remote-tracking and local branches"),
+			FILTER_REFS_REMOTES | FILTER_REFS_BRANCHES),
 		OPT_BIT('d', "delete", &delete, N_("delete fully merged branch"), 1),
 		OPT_BIT('D', NULL, &delete, N_("delete branch (even if not merged)"), 2),
 		OPT_BIT('m', "move", &rename, N_("move/rename a branch and its reflog"), 1),
@@ -848,22 +792,16 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
 		OPT_BOOL(0, "edit-description", &edit_description,
 			 N_("edit the description for the branch")),
 		OPT__FORCE(&force, N_("force creation, move/rename, deletion")),
-		{
-			OPTION_CALLBACK, 0, "no-merged", &merge_filter_ref,
-			N_("commit"), N_("print only not merged branches"),
-			PARSE_OPT_LASTARG_DEFAULT | PARSE_OPT_NONEG,
-			opt_parse_merge_filter, (intptr_t) "HEAD",
-		},
-		{
-			OPTION_CALLBACK, 0, "merged", &merge_filter_ref,
-			N_("commit"), N_("print only merged branches"),
-			PARSE_OPT_LASTARG_DEFAULT | PARSE_OPT_NONEG,
-			opt_parse_merge_filter, (intptr_t) "HEAD",
-		},
+		OPT_MERGED(&filter, N_("print only branches that are merged")),
+		OPT_NO_MERGED(&filter, N_("print only branches that are not merged")),
 		OPT_COLUMN(0, "column", &colopts, N_("list branches in columns")),
 		OPT_END(),
 	};
 
+	memset(&filter, 0, sizeof(filter));
+	filter.kind = FILTER_REFS_BRANCHES;
+	filter.abbrev = -1;
+
 	if (argc == 2 && !strcmp(argv[1], "-h"))
 		usage_with_options(builtin_branch_usage, options);
 
@@ -875,11 +813,9 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
 	if (!head)
 		die(_("Failed to resolve HEAD as a valid ref."));
 	if (!strcmp(head, "HEAD"))
-		detached = 1;
+		filter.detached = 1;
 	else if (!skip_prefix(head, "refs/heads/", &head))
 		die(_("HEAD not found below refs/heads!"));
-	hashcpy(merge_filter_ref, head_sha1);
-
 
 	argc = parse_options(argc, argv, prefix, options, builtin_branch_usage,
 			     0);
@@ -887,17 +823,17 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
 	if (!delete && !rename && !edit_description && !new_upstream && !unset_upstream && argc == 0)
 		list = 1;
 
-	if (with_commit || merge_filter != NO_FILTER)
+	if (filter.with_commit || filter.merge != REF_FILTER_MERGED_NONE)
 		list = 1;
 
 	if (!!delete + !!rename + !!new_upstream +
 	    list + unset_upstream > 1)
 		usage_with_options(builtin_branch_usage, options);
 
-	if (abbrev == -1)
-		abbrev = DEFAULT_ABBREV;
+	if (filter.abbrev == -1)
+		filter.abbrev = DEFAULT_ABBREV;
 	finalize_colopts(&colopts, -1);
-	if (verbose) {
+	if (filter.verbose) {
 		if (explicitly_enable_column(colopts))
 			die(_("--column and --verbose are incompatible"));
 		colopts = 0;
@@ -911,13 +847,13 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
 	if (delete) {
 		if (!argc)
 			die(_("branch name required"));
-		return delete_branches(argc, argv, delete > 1, kinds, quiet);
+		return delete_branches(argc, argv, delete > 1, filter.kind, quiet);
 	} else if (list) {
 		/*  git branch --local also shows HEAD when it is detached */
-		if (kinds & REF_LOCAL_BRANCH)
-			kinds |= REF_DETACHED_HEAD;
-		print_ref_list(kinds, detached, verbose, abbrev,
-					 with_commit, argv);
+		if ((filter.kind & FILTER_REFS_BRANCHES) && filter.detached)
+			filter.kind |= FILTER_REFS_DETACHED_HEAD;
+		filter.name_patterns = argv;
+		print_ref_list(&filter);
 		print_columns(&output, colopts, NULL);
 		string_list_clear(&output, 0);
 		return 0;
@@ -927,7 +863,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
 		struct strbuf branch_ref = STRBUF_INIT;
 
 		if (!argc) {
-			if (detached)
+			if (filter.detached)
 				die(_("Cannot give description to detached HEAD"));
 			branch_name = head;
 		} else if (argc == 1)
@@ -1015,7 +951,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
 		if (!branch)
 			die(_("no such branch '%s'"), argv[0]);
 
-		if (kinds != REF_LOCAL_BRANCH)
+		if (filter.kind != FILTER_REFS_BRANCHES)
 			die(_("-a and -r options to 'git branch' do not make sense with a branch name"));
 
 		if (track == BRANCH_TRACK_OVERRIDE)
diff --git a/ref-filter.c b/ref-filter.c
index fd839ac..c059d87 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -1356,7 +1356,7 @@ static int ref_filter_handler(const char *refname, const struct object_id *oid,
 }
 
 /*  Free memory allocated for a ref_array_item */
-static void free_array_item(struct ref_array_item *item)
+void free_array_item(struct ref_array_item *item)
 {
 	free((char *)item->symref);
 	free(item);
diff --git a/ref-filter.h b/ref-filter.h
index a5cfa5e..56980a3 100644
--- a/ref-filter.h
+++ b/ref-filter.h
@@ -36,6 +36,7 @@ struct ref_array_item {
 	unsigned char objectname[20];
 	int flag;
 	unsigned int kind;
+	int ignore : 1; /* To be removed in the next patch */
 	const char *symref;
 	struct commit *commit;
 	struct atom_value *value;
@@ -45,6 +46,7 @@ struct ref_array_item {
 struct ref_array {
 	int nr, alloc;
 	struct ref_array_item **items;
+	struct rev_info *revs;
 };
 
 struct ref_filter {
@@ -60,9 +62,12 @@ struct ref_filter {
 	struct commit *merge_commit;
 
 	unsigned int with_commit_tag_algo : 1,
-		match_as_path : 1;
+		match_as_path : 1,
+		detached : 1;
 	unsigned int kind,
 		lines;
+	int abbrev,
+		verbose;
 };
 
 struct ref_filter_cbdata {
@@ -86,6 +91,8 @@ struct ref_filter_cbdata {
  * filtered refs in the ref_array structure.
  */
 int filter_refs(struct ref_array *array, struct ref_filter *filter, unsigned int type);
+/*  Clear memory allocated to a ref_array_item */
+void free_array_item(struct ref_array_item *item);
 /*  Clear all memory allocated to ref_array */
 void ref_array_clear(struct ref_array *array);
 /*  Parse format string and sort specifiers */
-- 
2.5.1

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v4 6/8] branch.c: use 'ref-filter' data structures
  2015-09-13  7:23 [PATCH v4 0/8] port the filtering part of branch.c to use ref-filter APIs Karthik Nayak
                   ` (5 preceding siblings ...)
  2015-09-13  7:23 ` [PATCH v4 6/8] branch.c: use 'ref-filter' data structures Karthik Nayak
@ 2015-09-13  7:23 ` Karthik Nayak
  2015-09-13  7:32   ` Karthik Nayak
  2015-09-13  7:23 ` [PATCH v4 8/8] branch: add '--points-at' option Karthik Nayak
  2015-09-13  7:29 ` [PATCH v4 7/8] branch.c: use 'ref-filter' APIs Karthik Nayak
  8 siblings, 1 reply; 38+ messages in thread
From: Karthik Nayak @ 2015-09-13  7:23 UTC (permalink / raw)
  To: git; +Cc: christian.couder, Matthieu.Moy, gitster, Karthik Nayak

Make 'branch.c' use 'ref-filter' APIs for iterating through refs
sorting. This removes most of the code used in 'branch.c' replacing it
with calls to the 'ref-filter' library.

Make 'branch.c' use the 'filter_refs()' function provided by 'ref-filter'
to filter out tags based on the options set.

We provide a sorting option provided for 'branch.c' by using the sorting
options provided by 'ref-filter'.

Also remove the 'ignore' variable from ref_array_item as it was
previously used for the '--merged' option and now that is handled by
ref-filter.

The test t1430 'git branch shows badly named ref' has been changed to
check the stderr for the warning regarding the broken ref. This is
done as ref-filter throws a warning for broken refs rather than
directly printing them.

Modify documentation and add tests for the same.

Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>
Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
---
 Documentation/git-branch.txt |   9 +-
 builtin/branch.c             | 213 +++++++------------------------------------
 ref-filter.c                 |   2 +-
 ref-filter.h                 |   1 -
 t/t1430-bad-ref-name.sh      |  19 ++--
 t/t3203-branch-output.sh     |  11 +++
 6 files changed, 65 insertions(+), 190 deletions(-)

diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt
index a67138a..897cd81 100644
--- a/Documentation/git-branch.txt
+++ b/Documentation/git-branch.txt
@@ -11,7 +11,7 @@ SYNOPSIS
 'git branch' [--color[=<when>] | --no-color] [-r | -a]
 	[--list] [-v [--abbrev=<length> | --no-abbrev]]
 	[--column[=<options>] | --no-column]
-	[(--merged | --no-merged | --contains) [<commit>]] [<pattern>...]
+	[(--merged | --no-merged | --contains) [<commit>]] [--sort=<key>] [<pattern>...]
 'git branch' [--set-upstream | --track | --no-track] [-l] [-f] <branchname> [<start-point>]
 'git branch' (--set-upstream-to=<upstream> | -u <upstream>) [<branchname>]
 'git branch' --unset-upstream [<branchname>]
@@ -229,6 +229,13 @@ start-point is either a local or remote-tracking branch.
 	The new name for an existing branch. The same restrictions as for
 	<branchname> apply.
 
+--sort=<key>::
+	Sort based on the key given. Prefix `-` to sort in descending
+	order of the value. You may use the --sort=<key> option
+	multiple times, in which case the last key becomes the primary
+	key. The keys supported are the same as those in `git
+	for-each-ref`. Sort order defaults to sorting based on branch
+	type.
 
 Examples
 --------
diff --git a/builtin/branch.c b/builtin/branch.c
index 5cb7ef0..e0aa44c 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -270,125 +270,6 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
 	return(ret);
 }
 
-static char *resolve_symref(const char *src, const char *prefix)
-{
-	unsigned char sha1[20];
-	int flag;
-	const char *dst;
-
-	dst = resolve_ref_unsafe(src, 0, sha1, &flag);
-	if (!(dst && (flag & REF_ISSYMREF)))
-		return NULL;
-	if (prefix)
-		skip_prefix(dst, prefix, &dst);
-	return xstrdup(dst);
-}
-
-static int match_patterns(const char **pattern, const char *refname)
-{
-	if (!*pattern)
-		return 1; /* no pattern always matches */
-	while (*pattern) {
-		if (!wildmatch(*pattern, refname, 0, NULL))
-			return 1;
-		pattern++;
-	}
-	return 0;
-}
-
-/*
- * Allocate memory for a new ref_array_item and insert that into the
- * given ref_array. Doesn't take the objectname unlike
- * new_ref_array_item(). This is a temporary function which will be
- * removed when we port branch.c to use ref-filter APIs.
- */
-static struct ref_array_item *ref_array_append(struct ref_array *array, const char *refname)
-{
-	size_t len = strlen(refname);
-	struct ref_array_item *ref = xcalloc(1, sizeof(struct ref_array_item) + len + 1);
-	memcpy(ref->refname, refname, len);
-	ref->refname[len] = '\0';
-	REALLOC_ARRAY(array->items, array->nr + 1);
-	array->items[array->nr++] = ref;
-	return ref;
-}
-
-static int append_ref(const char *refname, const struct object_id *oid, int flags, void *cb_data)
-{
-	struct ref_filter_cbdata *cb = (struct ref_filter_cbdata *)(cb_data);
-	struct ref_filter *filter = cb->filter;
-	struct ref_array *array = cb->array;
-	struct ref_array_item *item;
-	struct commit *commit;
-	int kind, i;
-	const char *prefix, *orig_refname = refname;
-
-	static struct {
-		int kind;
-		const char *prefix;
-	} ref_kind[] = {
-		{ FILTER_REFS_BRANCHES, "refs/heads/" },
-		{ FILTER_REFS_REMOTES, "refs/remotes/" },
-	};
-
-	/* Detect kind */
-	for (i = 0; i < ARRAY_SIZE(ref_kind); i++) {
-		prefix = ref_kind[i].prefix;
-		if (skip_prefix(refname, prefix, &refname)) {
-			kind = ref_kind[i].kind;
-			break;
-		}
-	}
-	if (ARRAY_SIZE(ref_kind) <= i) {
-		if (!strcmp(refname, "HEAD"))
-			kind = FILTER_REFS_DETACHED_HEAD;
-		else
-			return 0;
-	}
-
-	/* Don't add types the caller doesn't want */
-	if ((kind & filter->kind) == 0)
-		return 0;
-
-	if (!match_patterns(filter->name_patterns, refname))
-		return 0;
-
-	commit = NULL;
-	if (filter->verbose || filter->with_commit || filter->merge != REF_FILTER_MERGED_NONE) {
-		commit = lookup_commit_reference_gently(oid->hash, 1);
-		if (!commit)
-			return 0;
-
-		/* Filter with with_commit if specified */
-		if (!is_descendant_of(commit, filter->with_commit))
-			return 0;
-
-		if (filter->merge != REF_FILTER_MERGED_NONE)
-			add_pending_object(array->revs,
-					   (struct object *)commit, refname);
-	}
-
-	item = ref_array_append(array, refname);
-
-	/* Record the new item */
-	item->kind = kind;
-	item->commit = commit;
-	item->symref = resolve_symref(orig_refname, prefix);
-	item->ignore = 0;
-
-	return 0;
-}
-
-static int ref_cmp(const void *r1, const void *r2)
-{
-	struct ref_array_item *c1 = *((struct ref_array_item **)r1);
-	struct ref_array_item *c2 = *((struct ref_array_item **)r2);
-
-	if (c1->kind != c2->kind)
-		return c1->kind - c2->kind;
-	return strcmp(c1->refname, c2->refname);
-}
-
 static void fill_tracking_info(struct strbuf *stat, const char *branch_name,
 		int show_upstream_ref)
 {
@@ -452,7 +333,7 @@ static void fill_tracking_info(struct strbuf *stat, const char *branch_name,
 }
 
 static void add_verbose_info(struct strbuf *out, struct ref_array_item *item,
-			     struct ref_filter *filter)
+			     struct ref_filter *filter, const char *refname)
 {
 	struct strbuf subject = STRBUF_INIT, stat = STRBUF_INIT;
 	const char *sub = _(" **** invalid ref ****");
@@ -464,7 +345,7 @@ static void add_verbose_info(struct strbuf *out, struct ref_array_item *item,
 	}
 
 	if (item->kind == FILTER_REFS_BRANCHES)
-		fill_tracking_info(&stat, item->refname, filter->verbose > 1);
+		fill_tracking_info(&stat, refname, filter->verbose > 1);
 
 	strbuf_addf(out, " %s %s%s",
 		find_unique_abbrev(item->commit->object.sha1, filter->abbrev),
@@ -504,8 +385,8 @@ static char *get_head_description(void)
 	return strbuf_detach(&desc, NULL);
 }
 
-static void print_ref_item(struct ref_array_item *item, int maxwidth,
-			   struct ref_filter *filter, const char *remote_prefix)
+static void format_and_print_ref_item(struct ref_array_item *item, int maxwidth,
+				      struct ref_filter *filter, const char *remote_prefix)
 {
 	char c;
 	int current = 0;
@@ -515,17 +396,16 @@ static void print_ref_item(struct ref_array_item *item, int maxwidth,
 	const char *desc = item->refname;
 	char *to_free = NULL;
 
-	if (item->ignore)
-		return;
-
 	switch (item->kind) {
 	case FILTER_REFS_BRANCHES:
-		if (!filter->detached && !strcmp(item->refname, head))
+		skip_prefix(desc, "refs/heads/", &desc);
+		if (!filter->detached && !strcmp(desc, head))
 			current = 1;
 		else
 			color = BRANCH_COLOR_LOCAL;
 		break;
 	case FILTER_REFS_REMOTES:
+		skip_prefix(desc, "refs/remotes/", &desc);
 		color = BRANCH_COLOR_REMOTE;
 		prefix = remote_prefix;
 		break;
@@ -554,11 +434,13 @@ static void print_ref_item(struct ref_array_item *item, int maxwidth,
 		strbuf_addf(&out, "%c %s%s%s", c, branch_get_color(color),
 			    name.buf, branch_get_color(BRANCH_COLOR_RESET));
 
-	if (item->symref)
-		strbuf_addf(&out, " -> %s", item->symref);
+	if (item->symref) {
+		skip_prefix(item->symref, "refs/remotes/", &desc);
+		strbuf_addf(&out, " -> %s", desc);
+	}
 	else if (filter->verbose)
 		/* " f7c0c00 [ahead 58, behind 197] vcs-svn: drop obj_pool.h" */
-		add_verbose_info(&out, item, filter);
+		add_verbose_info(&out, item, filter, desc);
 	if (column_active(colopts)) {
 		assert(!filter->verbose && "--column and --verbose are incompatible");
 		string_list_append(&output, out.buf);
@@ -575,11 +457,13 @@ static int calc_maxwidth(struct ref_array *refs, int remote_bonus)
 	int i, max = 0;
 	for (i = 0; i < refs->nr; i++) {
 		struct ref_array_item *it = refs->items[i];
+		const char *desc = it->refname;
 		int w;
 
-		if (it->ignore)
-			continue;
-		w = utf8_strwidth(it->refname);
+		skip_prefix(it->refname, "refs/heads/", &desc);
+		skip_prefix(it->refname, "refs/remotes/", &desc);
+		w = utf8_strwidth(desc);
+
 		if (it->kind == FILTER_REFS_REMOTES)
 			w += remote_bonus;
 		if (w > max)
@@ -588,14 +472,14 @@ static int calc_maxwidth(struct ref_array *refs, int remote_bonus)
 	return max;
 }
 
-static void print_ref_list(struct ref_filter *filter)
+static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sorting)
 {
 	int i;
 	struct ref_array array;
-	struct ref_filter_cbdata data;
 	int maxwidth = 0;
 	const char *remote_prefix = "";
-	struct rev_info revs;
+	struct ref_sorting def_sorting;
+	const char *sort_type = "type";
 
 	/*
 	 * If we are listing more than just remote branches,
@@ -606,60 +490,30 @@ static void print_ref_list(struct ref_filter *filter)
 		remote_prefix = "remotes/";
 
 	memset(&array, 0, sizeof(array));
-	if (filter->merge != REF_FILTER_MERGED_NONE)
-		init_revisions(&revs, NULL);
-
-	data.array = &array;
-	data.filter = filter;
-	array.revs = &revs;
 
-	/*
-	 * First we obtain all regular branch refs and if the HEAD is
-	 * detached then we insert that ref to the end of the ref_fist
-	 * so that it can be printed and removed first.
-	 */
-	for_each_rawref(append_ref, &data);
-	if (filter->detached)
-		head_ref(append_ref, &data);
-	/*
-	 * The following implementation is currently duplicated in ref-filter. It
-	 * will eventually be removed when we port branch.c to use ref-filter APIs.
-	 */
-	if (filter->merge != REF_FILTER_MERGED_NONE) {
-		filter->merge_commit->object.flags |= UNINTERESTING;
-		add_pending_object(&revs, &filter->merge_commit->object, "");
-		revs.limited = 1;
-
-		if (prepare_revision_walk(&revs))
-			die(_("revision walk setup failed"));
-
-		for (i = 0; i < array.nr; i++) {
-			struct ref_array_item *item = array.items[i];
-			struct commit *commit = item->commit;
-			int is_merged = !!(commit->object.flags & UNINTERESTING);
-			item->ignore = is_merged != (filter->merge == REF_FILTER_MERGED_INCLUDE);
-		}
+	verify_ref_format("%(refname)%(symref)");
+	filter_refs(&array, filter, filter->kind | FILTER_REFS_INCLUDE_BROKEN);
 
-		for (i = 0; i < array.nr; i++) {
-			struct ref_array_item *item = array.items[i];
-			clear_commit_marks(item->commit, ALL_REV_FLAGS);
-		}
-		clear_commit_marks(filter->merge_commit, ALL_REV_FLAGS);
-	}
 	if (filter->verbose)
 		maxwidth = calc_maxwidth(&array, strlen(remote_prefix));
 
 	/* Print detached HEAD before sorting and printing the rest */
 	if (filter->kind & FILTER_REFS_DETACHED_HEAD) {
-		print_ref_item(array.items[array.nr - 1], maxwidth, filter, remote_prefix);
+		format_and_print_ref_item(array.items[array.nr - 1], maxwidth, filter, remote_prefix);
 		free_array_item(array.items[array.nr - 1]);
 		array.nr--;
 	}
 
-	qsort(array.items, array.nr, sizeof(struct ref_array_item *), ref_cmp);
+	if (!sorting) {
+		def_sorting.next = NULL;
+		def_sorting.atom = parse_ref_filter_atom(sort_type,
+							 sort_type + strlen(sort_type));
+		sorting = &def_sorting;
+	}
+	ref_array_sort(sorting, &array);
 
 	for (i = 0; i < array.nr; i++)
-		print_ref_item(array.items[i], maxwidth, filter, remote_prefix);
+		format_and_print_ref_item(array.items[i], maxwidth, filter, remote_prefix);
 
 	ref_array_clear(&array);
 }
@@ -761,6 +615,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
 	const char *new_upstream = NULL;
 	enum branch_track track;
 	struct ref_filter filter;
+	static struct ref_sorting *sorting = NULL, **sorting_tail = &sorting;
 
 	struct option options[] = {
 		OPT_GROUP(N_("Generic options")),
@@ -795,6 +650,8 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
 		OPT_MERGED(&filter, N_("print only branches that are merged")),
 		OPT_NO_MERGED(&filter, N_("print only branches that are not merged")),
 		OPT_COLUMN(0, "column", &colopts, N_("list branches in columns")),
+		OPT_CALLBACK(0 , "sort", sorting_tail, N_("key"),
+			     N_("field name to sort on"), &parse_opt_ref_sorting),
 		OPT_END(),
 	};
 
@@ -853,7 +710,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
 		if ((filter.kind & FILTER_REFS_BRANCHES) && filter.detached)
 			filter.kind |= FILTER_REFS_DETACHED_HEAD;
 		filter.name_patterns = argv;
-		print_ref_list(&filter);
+		print_ref_list(&filter, sorting);
 		print_columns(&output, colopts, NULL);
 		string_list_clear(&output, 0);
 		return 0;
diff --git a/ref-filter.c b/ref-filter.c
index c059d87..c536aea 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -1331,7 +1331,7 @@ static int ref_filter_handler(const char *refname, const struct object_id *oid,
 	 * obtain the commit using the 'oid' available and discard all
 	 * non-commits early. The actual filtering is done later.
 	 */
-	if (filter->merge_commit || filter->with_commit) {
+	if (filter->merge_commit || filter->with_commit || filter->verbose) {
 		commit = lookup_commit_reference_gently(oid->hash, 1);
 		if (!commit)
 			return 0;
diff --git a/ref-filter.h b/ref-filter.h
index 56980a3..9316031 100644
--- a/ref-filter.h
+++ b/ref-filter.h
@@ -36,7 +36,6 @@ struct ref_array_item {
 	unsigned char objectname[20];
 	int flag;
 	unsigned int kind;
-	int ignore : 1; /* To be removed in the next patch */
 	const char *symref;
 	struct commit *commit;
 	struct atom_value *value;
diff --git a/t/t1430-bad-ref-name.sh b/t/t1430-bad-ref-name.sh
index 16d0b8b..dacc186 100755
--- a/t/t1430-bad-ref-name.sh
+++ b/t/t1430-bad-ref-name.sh
@@ -38,11 +38,12 @@ test_expect_success 'fast-import: fail on invalid branch name "bad[branch]name"'
 	test_must_fail git fast-import <input
 '
 
-test_expect_success 'git branch shows badly named ref' '
+test_expect_success 'git branch shows badly named ref as warning' '
 	cp .git/refs/heads/master .git/refs/heads/broken...ref &&
 	test_when_finished "rm -f .git/refs/heads/broken...ref" &&
-	git branch >output &&
-	grep -e "broken\.\.\.ref" output
+	git branch >output 2>error &&
+	grep -e "broken\.\.\.ref" error &&
+	! grep -e "broken\.\.\.ref" output
 '
 
 test_expect_success 'branch -d can delete badly named ref' '
@@ -95,8 +96,8 @@ test_expect_success 'branch -m cannot rename to a bad ref name' '
 	git branch goodref &&
 	test_must_fail git branch -m goodref broken...ref &&
 	test_cmp_rev master goodref &&
-	git branch >output &&
-	! grep -e "broken\.\.\.ref" output
+	git branch >output 2>error &&
+	! grep -e "broken\.\.\.ref" error
 '
 
 test_expect_failure 'branch -m can rename from a bad ref name' '
@@ -104,8 +105,8 @@ test_expect_failure 'branch -m can rename from a bad ref name' '
 	test_when_finished "rm -f .git/refs/heads/broken...ref" &&
 	git branch -m broken...ref renamed &&
 	test_cmp_rev master renamed &&
-	git branch >output &&
-	! grep -e "broken\.\.\.ref" output
+	git branch >output 2>error &&
+	! grep -e "broken\.\.\.ref" error
 '
 
 test_expect_success 'push cannot create a badly named ref' '
@@ -131,8 +132,8 @@ test_expect_failure 'push --mirror can delete badly named ref' '
 		cp .git/refs/heads/master .git/refs/heads/broken...ref
 	) &&
 	git -C src push --mirror "file://$top/dest" &&
-	git -C dest branch >output &&
-	! grep -e "broken\.\.\.ref" output
+	git -C dest branch >output 2>error &&
+	! grep -e "broken\.\.\.ref" error
 '
 
 test_expect_success 'rev-parse skips symref pointing to broken name' '
diff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh
index f51d0f3..53d166d 100755
--- a/t/t3203-branch-output.sh
+++ b/t/t3203-branch-output.sh
@@ -143,4 +143,15 @@ EOF
 	test_i18ncmp expect actual
 '
 
+test_expect_success 'git branch `--sort` option' '
+	cat >expect <<-\EOF &&
+	* (HEAD detached from fromtag)
+	  branch-two
+	  branch-one
+	  master
+	EOF
+	git branch --sort=objectsize >actual &&
+	test_i18ncmp expect actual
+'
+
 test_done
-- 
2.5.1

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v4 8/8] branch: add '--points-at' option
  2015-09-13  7:23 [PATCH v4 0/8] port the filtering part of branch.c to use ref-filter APIs Karthik Nayak
                   ` (6 preceding siblings ...)
  2015-09-13  7:23 ` Karthik Nayak
@ 2015-09-13  7:23 ` Karthik Nayak
  2015-09-13  7:29 ` [PATCH v4 7/8] branch.c: use 'ref-filter' APIs Karthik Nayak
  8 siblings, 0 replies; 38+ messages in thread
From: Karthik Nayak @ 2015-09-13  7:23 UTC (permalink / raw)
  To: git; +Cc: christian.couder, Matthieu.Moy, gitster, Karthik Nayak, Karthik Nayak

Add the '--points-at' option provided by 'ref-filter'. The option lets
the user to list only branches which points at the given object.

Add documentation and tests for the same.

Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>
Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
---
 Documentation/git-branch.txt | 6 +++++-
 builtin/branch.c             | 7 ++++++-
 t/t3203-branch-output.sh     | 9 +++++++++
 3 files changed, 20 insertions(+), 2 deletions(-)

diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt
index 897cd81..211cfc3 100644
--- a/Documentation/git-branch.txt
+++ b/Documentation/git-branch.txt
@@ -11,7 +11,8 @@ SYNOPSIS
 'git branch' [--color[=<when>] | --no-color] [-r | -a]
 	[--list] [-v [--abbrev=<length> | --no-abbrev]]
 	[--column[=<options>] | --no-column]
-	[(--merged | --no-merged | --contains) [<commit>]] [--sort=<key>] [<pattern>...]
+	[(--merged | --no-merged | --contains) [<commit>]] [--sort=<key>]
+	[--points-at <object>] [<pattern>...]
 'git branch' [--set-upstream | --track | --no-track] [-l] [-f] <branchname> [<start-point>]
 'git branch' (--set-upstream-to=<upstream> | -u <upstream>) [<branchname>]
 'git branch' --unset-upstream [<branchname>]
@@ -237,6 +238,9 @@ start-point is either a local or remote-tracking branch.
 	for-each-ref`. Sort order defaults to sorting based on branch
 	type.
 
+--points-at <object>::
+	Only list branches of the given object.
+
 Examples
 --------
 
diff --git a/builtin/branch.c b/builtin/branch.c
index e0aa44c..32a0d11 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -26,6 +26,7 @@ static const char * const builtin_branch_usage[] = {
 	N_("git branch [<options>] [-l] [-f] <branch-name> [<start-point>]"),
 	N_("git branch [<options>] [-r] (-d | -D) <branch-name>..."),
 	N_("git branch [<options>] (-m | -M) [<old-branch>] <new-branch>"),
+	N_("git branch [<options>] [-r | -a] [--points-at]"),
 	NULL
 };
 
@@ -652,6 +653,10 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
 		OPT_COLUMN(0, "column", &colopts, N_("list branches in columns")),
 		OPT_CALLBACK(0 , "sort", sorting_tail, N_("key"),
 			     N_("field name to sort on"), &parse_opt_ref_sorting),
+		{
+			OPTION_CALLBACK, 0, "points-at", &filter.points_at, N_("object"),
+			N_("print only branches of the object"), 0, parse_opt_object_name
+		},
 		OPT_END(),
 	};
 
@@ -680,7 +685,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
 	if (!delete && !rename && !edit_description && !new_upstream && !unset_upstream && argc == 0)
 		list = 1;
 
-	if (filter.with_commit || filter.merge != REF_FILTER_MERGED_NONE)
+	if (filter.with_commit || filter.merge != REF_FILTER_MERGED_NONE || filter.points_at.nr)
 		list = 1;
 
 	if (!!delete + !!rename + !!new_upstream +
diff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh
index 53d166d..c819f3e 100755
--- a/t/t3203-branch-output.sh
+++ b/t/t3203-branch-output.sh
@@ -154,4 +154,13 @@ test_expect_success 'git branch `--sort` option' '
 	test_i18ncmp expect actual
 '
 
+test_expect_success 'git branch --points-at option' '
+	cat >expect <<-\EOF &&
+	  master
+	  branch-one
+	EOF
+	git branch --points-at=branch-one >actual &&
+	test_cmp expect actual
+'
+
 test_done
-- 
2.5.1

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v4 7/8] branch.c: use 'ref-filter' APIs
  2015-09-13  7:23 [PATCH v4 0/8] port the filtering part of branch.c to use ref-filter APIs Karthik Nayak
                   ` (7 preceding siblings ...)
  2015-09-13  7:23 ` [PATCH v4 8/8] branch: add '--points-at' option Karthik Nayak
@ 2015-09-13  7:29 ` Karthik Nayak
  8 siblings, 0 replies; 38+ messages in thread
From: Karthik Nayak @ 2015-09-13  7:29 UTC (permalink / raw)
  To: git; +Cc: christian.couder, Matthieu.Moy, gitster, Karthik Nayak, Karthik Nayak

Make 'branch.c' use 'ref-filter' APIs for iterating through refs
sorting. This removes most of the code used in 'branch.c' replacing it
with calls to the 'ref-filter' library.

Make 'branch.c' use the 'filter_refs()' function provided by 'ref-filter'
to filter out tags based on the options set.

We provide a sorting option provided for 'branch.c' by using the sorting
options provided by 'ref-filter'.

Also remove the 'ignore' variable from ref_array_item as it was
previously used for the '--merged' option and now that is handled by
ref-filter.

The test t1430 'git branch shows badly named ref' has been changed to
check the stderr for the warning regarding the broken ref. This is
done as ref-filter throws a warning for broken refs rather than
directly printing them.

Modify documentation and add tests for the same.

Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>
Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
---
 Documentation/git-branch.txt |   9 +-
 builtin/branch.c             | 213 +++++++------------------------------------
 ref-filter.c                 |   2 +-
 ref-filter.h                 |   1 -
 t/t1430-bad-ref-name.sh      |  19 ++--
 t/t3203-branch-output.sh     |  11 +++
 6 files changed, 65 insertions(+), 190 deletions(-)

diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt
index a67138a..897cd81 100644
--- a/Documentation/git-branch.txt
+++ b/Documentation/git-branch.txt
@@ -11,7 +11,7 @@ SYNOPSIS
 'git branch' [--color[=<when>] | --no-color] [-r | -a]
 	[--list] [-v [--abbrev=<length> | --no-abbrev]]
 	[--column[=<options>] | --no-column]
-	[(--merged | --no-merged | --contains) [<commit>]] [<pattern>...]
+	[(--merged | --no-merged | --contains) [<commit>]] [--sort=<key>] [<pattern>...]
 'git branch' [--set-upstream | --track | --no-track] [-l] [-f] <branchname> [<start-point>]
 'git branch' (--set-upstream-to=<upstream> | -u <upstream>) [<branchname>]
 'git branch' --unset-upstream [<branchname>]
@@ -229,6 +229,13 @@ start-point is either a local or remote-tracking branch.
 	The new name for an existing branch. The same restrictions as for
 	<branchname> apply.
 
+--sort=<key>::
+	Sort based on the key given. Prefix `-` to sort in descending
+	order of the value. You may use the --sort=<key> option
+	multiple times, in which case the last key becomes the primary
+	key. The keys supported are the same as those in `git
+	for-each-ref`. Sort order defaults to sorting based on branch
+	type.
 
 Examples
 --------
diff --git a/builtin/branch.c b/builtin/branch.c
index 5cb7ef0..e0aa44c 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -270,125 +270,6 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
 	return(ret);
 }
 
-static char *resolve_symref(const char *src, const char *prefix)
-{
-	unsigned char sha1[20];
-	int flag;
-	const char *dst;
-
-	dst = resolve_ref_unsafe(src, 0, sha1, &flag);
-	if (!(dst && (flag & REF_ISSYMREF)))
-		return NULL;
-	if (prefix)
-		skip_prefix(dst, prefix, &dst);
-	return xstrdup(dst);
-}
-
-static int match_patterns(const char **pattern, const char *refname)
-{
-	if (!*pattern)
-		return 1; /* no pattern always matches */
-	while (*pattern) {
-		if (!wildmatch(*pattern, refname, 0, NULL))
-			return 1;
-		pattern++;
-	}
-	return 0;
-}
-
-/*
- * Allocate memory for a new ref_array_item and insert that into the
- * given ref_array. Doesn't take the objectname unlike
- * new_ref_array_item(). This is a temporary function which will be
- * removed when we port branch.c to use ref-filter APIs.
- */
-static struct ref_array_item *ref_array_append(struct ref_array *array, const char *refname)
-{
-	size_t len = strlen(refname);
-	struct ref_array_item *ref = xcalloc(1, sizeof(struct ref_array_item) + len + 1);
-	memcpy(ref->refname, refname, len);
-	ref->refname[len] = '\0';
-	REALLOC_ARRAY(array->items, array->nr + 1);
-	array->items[array->nr++] = ref;
-	return ref;
-}
-
-static int append_ref(const char *refname, const struct object_id *oid, int flags, void *cb_data)
-{
-	struct ref_filter_cbdata *cb = (struct ref_filter_cbdata *)(cb_data);
-	struct ref_filter *filter = cb->filter;
-	struct ref_array *array = cb->array;
-	struct ref_array_item *item;
-	struct commit *commit;
-	int kind, i;
-	const char *prefix, *orig_refname = refname;
-
-	static struct {
-		int kind;
-		const char *prefix;
-	} ref_kind[] = {
-		{ FILTER_REFS_BRANCHES, "refs/heads/" },
-		{ FILTER_REFS_REMOTES, "refs/remotes/" },
-	};
-
-	/* Detect kind */
-	for (i = 0; i < ARRAY_SIZE(ref_kind); i++) {
-		prefix = ref_kind[i].prefix;
-		if (skip_prefix(refname, prefix, &refname)) {
-			kind = ref_kind[i].kind;
-			break;
-		}
-	}
-	if (ARRAY_SIZE(ref_kind) <= i) {
-		if (!strcmp(refname, "HEAD"))
-			kind = FILTER_REFS_DETACHED_HEAD;
-		else
-			return 0;
-	}
-
-	/* Don't add types the caller doesn't want */
-	if ((kind & filter->kind) == 0)
-		return 0;
-
-	if (!match_patterns(filter->name_patterns, refname))
-		return 0;
-
-	commit = NULL;
-	if (filter->verbose || filter->with_commit || filter->merge != REF_FILTER_MERGED_NONE) {
-		commit = lookup_commit_reference_gently(oid->hash, 1);
-		if (!commit)
-			return 0;
-
-		/* Filter with with_commit if specified */
-		if (!is_descendant_of(commit, filter->with_commit))
-			return 0;
-
-		if (filter->merge != REF_FILTER_MERGED_NONE)
-			add_pending_object(array->revs,
-					   (struct object *)commit, refname);
-	}
-
-	item = ref_array_append(array, refname);
-
-	/* Record the new item */
-	item->kind = kind;
-	item->commit = commit;
-	item->symref = resolve_symref(orig_refname, prefix);
-	item->ignore = 0;
-
-	return 0;
-}
-
-static int ref_cmp(const void *r1, const void *r2)
-{
-	struct ref_array_item *c1 = *((struct ref_array_item **)r1);
-	struct ref_array_item *c2 = *((struct ref_array_item **)r2);
-
-	if (c1->kind != c2->kind)
-		return c1->kind - c2->kind;
-	return strcmp(c1->refname, c2->refname);
-}
-
 static void fill_tracking_info(struct strbuf *stat, const char *branch_name,
 		int show_upstream_ref)
 {
@@ -452,7 +333,7 @@ static void fill_tracking_info(struct strbuf *stat, const char *branch_name,
 }
 
 static void add_verbose_info(struct strbuf *out, struct ref_array_item *item,
-			     struct ref_filter *filter)
+			     struct ref_filter *filter, const char *refname)
 {
 	struct strbuf subject = STRBUF_INIT, stat = STRBUF_INIT;
 	const char *sub = _(" **** invalid ref ****");
@@ -464,7 +345,7 @@ static void add_verbose_info(struct strbuf *out, struct ref_array_item *item,
 	}
 
 	if (item->kind == FILTER_REFS_BRANCHES)
-		fill_tracking_info(&stat, item->refname, filter->verbose > 1);
+		fill_tracking_info(&stat, refname, filter->verbose > 1);
 
 	strbuf_addf(out, " %s %s%s",
 		find_unique_abbrev(item->commit->object.sha1, filter->abbrev),
@@ -504,8 +385,8 @@ static char *get_head_description(void)
 	return strbuf_detach(&desc, NULL);
 }
 
-static void print_ref_item(struct ref_array_item *item, int maxwidth,
-			   struct ref_filter *filter, const char *remote_prefix)
+static void format_and_print_ref_item(struct ref_array_item *item, int maxwidth,
+				      struct ref_filter *filter, const char *remote_prefix)
 {
 	char c;
 	int current = 0;
@@ -515,17 +396,16 @@ static void print_ref_item(struct ref_array_item *item, int maxwidth,
 	const char *desc = item->refname;
 	char *to_free = NULL;
 
-	if (item->ignore)
-		return;
-
 	switch (item->kind) {
 	case FILTER_REFS_BRANCHES:
-		if (!filter->detached && !strcmp(item->refname, head))
+		skip_prefix(desc, "refs/heads/", &desc);
+		if (!filter->detached && !strcmp(desc, head))
 			current = 1;
 		else
 			color = BRANCH_COLOR_LOCAL;
 		break;
 	case FILTER_REFS_REMOTES:
+		skip_prefix(desc, "refs/remotes/", &desc);
 		color = BRANCH_COLOR_REMOTE;
 		prefix = remote_prefix;
 		break;
@@ -554,11 +434,13 @@ static void print_ref_item(struct ref_array_item *item, int maxwidth,
 		strbuf_addf(&out, "%c %s%s%s", c, branch_get_color(color),
 			    name.buf, branch_get_color(BRANCH_COLOR_RESET));
 
-	if (item->symref)
-		strbuf_addf(&out, " -> %s", item->symref);
+	if (item->symref) {
+		skip_prefix(item->symref, "refs/remotes/", &desc);
+		strbuf_addf(&out, " -> %s", desc);
+	}
 	else if (filter->verbose)
 		/* " f7c0c00 [ahead 58, behind 197] vcs-svn: drop obj_pool.h" */
-		add_verbose_info(&out, item, filter);
+		add_verbose_info(&out, item, filter, desc);
 	if (column_active(colopts)) {
 		assert(!filter->verbose && "--column and --verbose are incompatible");
 		string_list_append(&output, out.buf);
@@ -575,11 +457,13 @@ static int calc_maxwidth(struct ref_array *refs, int remote_bonus)
 	int i, max = 0;
 	for (i = 0; i < refs->nr; i++) {
 		struct ref_array_item *it = refs->items[i];
+		const char *desc = it->refname;
 		int w;
 
-		if (it->ignore)
-			continue;
-		w = utf8_strwidth(it->refname);
+		skip_prefix(it->refname, "refs/heads/", &desc);
+		skip_prefix(it->refname, "refs/remotes/", &desc);
+		w = utf8_strwidth(desc);
+
 		if (it->kind == FILTER_REFS_REMOTES)
 			w += remote_bonus;
 		if (w > max)
@@ -588,14 +472,14 @@ static int calc_maxwidth(struct ref_array *refs, int remote_bonus)
 	return max;
 }
 
-static void print_ref_list(struct ref_filter *filter)
+static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sorting)
 {
 	int i;
 	struct ref_array array;
-	struct ref_filter_cbdata data;
 	int maxwidth = 0;
 	const char *remote_prefix = "";
-	struct rev_info revs;
+	struct ref_sorting def_sorting;
+	const char *sort_type = "type";
 
 	/*
 	 * If we are listing more than just remote branches,
@@ -606,60 +490,30 @@ static void print_ref_list(struct ref_filter *filter)
 		remote_prefix = "remotes/";
 
 	memset(&array, 0, sizeof(array));
-	if (filter->merge != REF_FILTER_MERGED_NONE)
-		init_revisions(&revs, NULL);
-
-	data.array = &array;
-	data.filter = filter;
-	array.revs = &revs;
 
-	/*
-	 * First we obtain all regular branch refs and if the HEAD is
-	 * detached then we insert that ref to the end of the ref_fist
-	 * so that it can be printed and removed first.
-	 */
-	for_each_rawref(append_ref, &data);
-	if (filter->detached)
-		head_ref(append_ref, &data);
-	/*
-	 * The following implementation is currently duplicated in ref-filter. It
-	 * will eventually be removed when we port branch.c to use ref-filter APIs.
-	 */
-	if (filter->merge != REF_FILTER_MERGED_NONE) {
-		filter->merge_commit->object.flags |= UNINTERESTING;
-		add_pending_object(&revs, &filter->merge_commit->object, "");
-		revs.limited = 1;
-
-		if (prepare_revision_walk(&revs))
-			die(_("revision walk setup failed"));
-
-		for (i = 0; i < array.nr; i++) {
-			struct ref_array_item *item = array.items[i];
-			struct commit *commit = item->commit;
-			int is_merged = !!(commit->object.flags & UNINTERESTING);
-			item->ignore = is_merged != (filter->merge == REF_FILTER_MERGED_INCLUDE);
-		}
+	verify_ref_format("%(refname)%(symref)");
+	filter_refs(&array, filter, filter->kind | FILTER_REFS_INCLUDE_BROKEN);
 
-		for (i = 0; i < array.nr; i++) {
-			struct ref_array_item *item = array.items[i];
-			clear_commit_marks(item->commit, ALL_REV_FLAGS);
-		}
-		clear_commit_marks(filter->merge_commit, ALL_REV_FLAGS);
-	}
 	if (filter->verbose)
 		maxwidth = calc_maxwidth(&array, strlen(remote_prefix));
 
 	/* Print detached HEAD before sorting and printing the rest */
 	if (filter->kind & FILTER_REFS_DETACHED_HEAD) {
-		print_ref_item(array.items[array.nr - 1], maxwidth, filter, remote_prefix);
+		format_and_print_ref_item(array.items[array.nr - 1], maxwidth, filter, remote_prefix);
 		free_array_item(array.items[array.nr - 1]);
 		array.nr--;
 	}
 
-	qsort(array.items, array.nr, sizeof(struct ref_array_item *), ref_cmp);
+	if (!sorting) {
+		def_sorting.next = NULL;
+		def_sorting.atom = parse_ref_filter_atom(sort_type,
+							 sort_type + strlen(sort_type));
+		sorting = &def_sorting;
+	}
+	ref_array_sort(sorting, &array);
 
 	for (i = 0; i < array.nr; i++)
-		print_ref_item(array.items[i], maxwidth, filter, remote_prefix);
+		format_and_print_ref_item(array.items[i], maxwidth, filter, remote_prefix);
 
 	ref_array_clear(&array);
 }
@@ -761,6 +615,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
 	const char *new_upstream = NULL;
 	enum branch_track track;
 	struct ref_filter filter;
+	static struct ref_sorting *sorting = NULL, **sorting_tail = &sorting;
 
 	struct option options[] = {
 		OPT_GROUP(N_("Generic options")),
@@ -795,6 +650,8 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
 		OPT_MERGED(&filter, N_("print only branches that are merged")),
 		OPT_NO_MERGED(&filter, N_("print only branches that are not merged")),
 		OPT_COLUMN(0, "column", &colopts, N_("list branches in columns")),
+		OPT_CALLBACK(0 , "sort", sorting_tail, N_("key"),
+			     N_("field name to sort on"), &parse_opt_ref_sorting),
 		OPT_END(),
 	};
 
@@ -853,7 +710,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
 		if ((filter.kind & FILTER_REFS_BRANCHES) && filter.detached)
 			filter.kind |= FILTER_REFS_DETACHED_HEAD;
 		filter.name_patterns = argv;
-		print_ref_list(&filter);
+		print_ref_list(&filter, sorting);
 		print_columns(&output, colopts, NULL);
 		string_list_clear(&output, 0);
 		return 0;
diff --git a/ref-filter.c b/ref-filter.c
index c059d87..c536aea 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -1331,7 +1331,7 @@ static int ref_filter_handler(const char *refname, const struct object_id *oid,
 	 * obtain the commit using the 'oid' available and discard all
 	 * non-commits early. The actual filtering is done later.
 	 */
-	if (filter->merge_commit || filter->with_commit) {
+	if (filter->merge_commit || filter->with_commit || filter->verbose) {
 		commit = lookup_commit_reference_gently(oid->hash, 1);
 		if (!commit)
 			return 0;
diff --git a/ref-filter.h b/ref-filter.h
index 56980a3..9316031 100644
--- a/ref-filter.h
+++ b/ref-filter.h
@@ -36,7 +36,6 @@ struct ref_array_item {
 	unsigned char objectname[20];
 	int flag;
 	unsigned int kind;
-	int ignore : 1; /* To be removed in the next patch */
 	const char *symref;
 	struct commit *commit;
 	struct atom_value *value;
diff --git a/t/t1430-bad-ref-name.sh b/t/t1430-bad-ref-name.sh
index 16d0b8b..dacc186 100755
--- a/t/t1430-bad-ref-name.sh
+++ b/t/t1430-bad-ref-name.sh
@@ -38,11 +38,12 @@ test_expect_success 'fast-import: fail on invalid branch name "bad[branch]name"'
 	test_must_fail git fast-import <input
 '
 
-test_expect_success 'git branch shows badly named ref' '
+test_expect_success 'git branch shows badly named ref as warning' '
 	cp .git/refs/heads/master .git/refs/heads/broken...ref &&
 	test_when_finished "rm -f .git/refs/heads/broken...ref" &&
-	git branch >output &&
-	grep -e "broken\.\.\.ref" output
+	git branch >output 2>error &&
+	grep -e "broken\.\.\.ref" error &&
+	! grep -e "broken\.\.\.ref" output
 '
 
 test_expect_success 'branch -d can delete badly named ref' '
@@ -95,8 +96,8 @@ test_expect_success 'branch -m cannot rename to a bad ref name' '
 	git branch goodref &&
 	test_must_fail git branch -m goodref broken...ref &&
 	test_cmp_rev master goodref &&
-	git branch >output &&
-	! grep -e "broken\.\.\.ref" output
+	git branch >output 2>error &&
+	! grep -e "broken\.\.\.ref" error
 '
 
 test_expect_failure 'branch -m can rename from a bad ref name' '
@@ -104,8 +105,8 @@ test_expect_failure 'branch -m can rename from a bad ref name' '
 	test_when_finished "rm -f .git/refs/heads/broken...ref" &&
 	git branch -m broken...ref renamed &&
 	test_cmp_rev master renamed &&
-	git branch >output &&
-	! grep -e "broken\.\.\.ref" output
+	git branch >output 2>error &&
+	! grep -e "broken\.\.\.ref" error
 '
 
 test_expect_success 'push cannot create a badly named ref' '
@@ -131,8 +132,8 @@ test_expect_failure 'push --mirror can delete badly named ref' '
 		cp .git/refs/heads/master .git/refs/heads/broken...ref
 	) &&
 	git -C src push --mirror "file://$top/dest" &&
-	git -C dest branch >output &&
-	! grep -e "broken\.\.\.ref" output
+	git -C dest branch >output 2>error &&
+	! grep -e "broken\.\.\.ref" error
 '
 
 test_expect_success 'rev-parse skips symref pointing to broken name' '
diff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh
index f51d0f3..53d166d 100755
--- a/t/t3203-branch-output.sh
+++ b/t/t3203-branch-output.sh
@@ -143,4 +143,15 @@ EOF
 	test_i18ncmp expect actual
 '
 
+test_expect_success 'git branch `--sort` option' '
+	cat >expect <<-\EOF &&
+	* (HEAD detached from fromtag)
+	  branch-two
+	  branch-one
+	  master
+	EOF
+	git branch --sort=objectsize >actual &&
+	test_i18ncmp expect actual
+'
+
 test_done
-- 
2.5.1

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* Re: [PATCH v4 6/8] branch.c: use 'ref-filter' data structures
  2015-09-13  7:23 ` Karthik Nayak
@ 2015-09-13  7:32   ` Karthik Nayak
  0 siblings, 0 replies; 38+ messages in thread
From: Karthik Nayak @ 2015-09-13  7:32 UTC (permalink / raw)
  To: Git; +Cc: Christian Couder, Matthieu Moy, Junio C Hamano, Karthik Nayak

On Sun, Sep 13, 2015 at 12:53 PM, Karthik Nayak <karthik.188@gmail.com> wrote:
> Make 'branch.c' use 'ref-filter' APIs for iterating through refs
> sorting. This removes most of the code used in 'branch.c' replacing it
> with calls to the 'ref-filter' library.
>
> Make 'branch.c' use the 'filter_refs()' function provided by 'ref-filter'
> to filter out tags based on the options set.
>
> We provide a sorting option provided for 'branch.c' by using the sorting
> options provided by 'ref-filter'.
>
> Also remove the 'ignore' variable from ref_array_item as it was
> previously used for the '--merged' option and now that is handled by
> ref-filter.
>
> The test t1430 'git branch shows badly named ref' has been changed to
> check the stderr for the warning regarding the broken ref. This is
> done as ref-filter throws a warning for broken refs rather than
> directly printing them.
>
> Modify documentation and add tests for the same.
>
> Mentored-by: Christian Couder <christian.couder@gmail.com>
> Mentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>
> Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
> ---
>  Documentation/git-branch.txt |   9 +-
>  builtin/branch.c             | 213 +++++++------------------------------------
>  ref-filter.c                 |   2 +-
>  ref-filter.h                 |   1 -
>  t/t1430-bad-ref-name.sh      |  19 ++--
>  t/t3203-branch-output.sh     |  11 +++
>  6 files changed, 65 insertions(+), 190 deletions(-)
>
> diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt
> index a67138a..897cd81 100644
> --- a/Documentation/git-branch.txt
> +++ b/Documentation/git-branch.txt
> @@ -11,7 +11,7 @@ SYNOPSIS
>  'git branch' [--color[=<when>] | --no-color] [-r | -a]
>         [--list] [-v [--abbrev=<length> | --no-abbrev]]
>         [--column[=<options>] | --no-column]
> -       [(--merged | --no-merged | --contains) [<commit>]] [<pattern>...]
> +       [(--merged | --no-merged | --contains) [<commit>]] [--sort=<key>] [<pattern>...]
>  'git branch' [--set-upstream | --track | --no-track] [-l] [-f] <branchname> [<start-point>]
>  'git branch' (--set-upstream-to=<upstream> | -u <upstream>) [<branchname>]
>  'git branch' --unset-upstream [<branchname>]
> @@ -229,6 +229,13 @@ start-point is either a local or remote-tracking branch.
>         The new name for an existing branch. The same restrictions as for
>         <branchname> apply.
>
> +--sort=<key>::
> +       Sort based on the key given. Prefix `-` to sort in descending
> +       order of the value. You may use the --sort=<key> option
> +       multiple times, in which case the last key becomes the primary
> +       key. The keys supported are the same as those in `git
> +       for-each-ref`. Sort order defaults to sorting based on branch
> +       type.
>
>  Examples
>  --------
> diff --git a/builtin/branch.c b/builtin/branch.c
> index 5cb7ef0..e0aa44c 100644
> --- a/builtin/branch.c
> +++ b/builtin/branch.c
> @@ -270,125 +270,6 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
>         return(ret);
>  }
>
> -static char *resolve_symref(const char *src, const char *prefix)
> -{
> -       unsigned char sha1[20];
> -       int flag;
> -       const char *dst;
> -
> -       dst = resolve_ref_unsafe(src, 0, sha1, &flag);
> -       if (!(dst && (flag & REF_ISSYMREF)))
> -               return NULL;
> -       if (prefix)
> -               skip_prefix(dst, prefix, &dst);
> -       return xstrdup(dst);
> -}
> -
> -static int match_patterns(const char **pattern, const char *refname)
> -{
> -       if (!*pattern)
> -               return 1; /* no pattern always matches */
> -       while (*pattern) {
> -               if (!wildmatch(*pattern, refname, 0, NULL))
> -                       return 1;
> -               pattern++;
> -       }
> -       return 0;
> -}
> -
> -/*
> - * Allocate memory for a new ref_array_item and insert that into the
> - * given ref_array. Doesn't take the objectname unlike
> - * new_ref_array_item(). This is a temporary function which will be
> - * removed when we port branch.c to use ref-filter APIs.
> - */
> -static struct ref_array_item *ref_array_append(struct ref_array *array, const char *refname)
> -{
> -       size_t len = strlen(refname);
> -       struct ref_array_item *ref = xcalloc(1, sizeof(struct ref_array_item) + len + 1);
> -       memcpy(ref->refname, refname, len);
> -       ref->refname[len] = '\0';
> -       REALLOC_ARRAY(array->items, array->nr + 1);
> -       array->items[array->nr++] = ref;
> -       return ref;
> -}
> -
> -static int append_ref(const char *refname, const struct object_id *oid, int flags, void *cb_data)
> -{
> -       struct ref_filter_cbdata *cb = (struct ref_filter_cbdata *)(cb_data);
> -       struct ref_filter *filter = cb->filter;
> -       struct ref_array *array = cb->array;
> -       struct ref_array_item *item;
> -       struct commit *commit;
> -       int kind, i;
> -       const char *prefix, *orig_refname = refname;
> -
> -       static struct {
> -               int kind;
> -               const char *prefix;
> -       } ref_kind[] = {
> -               { FILTER_REFS_BRANCHES, "refs/heads/" },
> -               { FILTER_REFS_REMOTES, "refs/remotes/" },
> -       };
> -
> -       /* Detect kind */
> -       for (i = 0; i < ARRAY_SIZE(ref_kind); i++) {
> -               prefix = ref_kind[i].prefix;
> -               if (skip_prefix(refname, prefix, &refname)) {
> -                       kind = ref_kind[i].kind;
> -                       break;
> -               }
> -       }
> -       if (ARRAY_SIZE(ref_kind) <= i) {
> -               if (!strcmp(refname, "HEAD"))
> -                       kind = FILTER_REFS_DETACHED_HEAD;
> -               else
> -                       return 0;
> -       }
> -
> -       /* Don't add types the caller doesn't want */
> -       if ((kind & filter->kind) == 0)
> -               return 0;
> -
> -       if (!match_patterns(filter->name_patterns, refname))
> -               return 0;
> -
> -       commit = NULL;
> -       if (filter->verbose || filter->with_commit || filter->merge != REF_FILTER_MERGED_NONE) {
> -               commit = lookup_commit_reference_gently(oid->hash, 1);
> -               if (!commit)
> -                       return 0;
> -
> -               /* Filter with with_commit if specified */
> -               if (!is_descendant_of(commit, filter->with_commit))
> -                       return 0;
> -
> -               if (filter->merge != REF_FILTER_MERGED_NONE)
> -                       add_pending_object(array->revs,
> -                                          (struct object *)commit, refname);
> -       }
> -
> -       item = ref_array_append(array, refname);
> -
> -       /* Record the new item */
> -       item->kind = kind;
> -       item->commit = commit;
> -       item->symref = resolve_symref(orig_refname, prefix);
> -       item->ignore = 0;
> -
> -       return 0;
> -}
> -
> -static int ref_cmp(const void *r1, const void *r2)
> -{
> -       struct ref_array_item *c1 = *((struct ref_array_item **)r1);
> -       struct ref_array_item *c2 = *((struct ref_array_item **)r2);
> -
> -       if (c1->kind != c2->kind)
> -               return c1->kind - c2->kind;
> -       return strcmp(c1->refname, c2->refname);
> -}
> -
>  static void fill_tracking_info(struct strbuf *stat, const char *branch_name,
>                 int show_upstream_ref)
>  {
> @@ -452,7 +333,7 @@ static void fill_tracking_info(struct strbuf *stat, const char *branch_name,
>  }
>
>  static void add_verbose_info(struct strbuf *out, struct ref_array_item *item,
> -                            struct ref_filter *filter)
> +                            struct ref_filter *filter, const char *refname)
>  {
>         struct strbuf subject = STRBUF_INIT, stat = STRBUF_INIT;
>         const char *sub = _(" **** invalid ref ****");
> @@ -464,7 +345,7 @@ static void add_verbose_info(struct strbuf *out, struct ref_array_item *item,
>         }
>
>         if (item->kind == FILTER_REFS_BRANCHES)
> -               fill_tracking_info(&stat, item->refname, filter->verbose > 1);
> +               fill_tracking_info(&stat, refname, filter->verbose > 1);
>
>         strbuf_addf(out, " %s %s%s",
>                 find_unique_abbrev(item->commit->object.sha1, filter->abbrev),
> @@ -504,8 +385,8 @@ static char *get_head_description(void)
>         return strbuf_detach(&desc, NULL);
>  }
>
> -static void print_ref_item(struct ref_array_item *item, int maxwidth,
> -                          struct ref_filter *filter, const char *remote_prefix)
> +static void format_and_print_ref_item(struct ref_array_item *item, int maxwidth,
> +                                     struct ref_filter *filter, const char *remote_prefix)
>  {
>         char c;
>         int current = 0;
> @@ -515,17 +396,16 @@ static void print_ref_item(struct ref_array_item *item, int maxwidth,
>         const char *desc = item->refname;
>         char *to_free = NULL;
>
> -       if (item->ignore)
> -               return;
> -
>         switch (item->kind) {
>         case FILTER_REFS_BRANCHES:
> -               if (!filter->detached && !strcmp(item->refname, head))
> +               skip_prefix(desc, "refs/heads/", &desc);
> +               if (!filter->detached && !strcmp(desc, head))
>                         current = 1;
>                 else
>                         color = BRANCH_COLOR_LOCAL;
>                 break;
>         case FILTER_REFS_REMOTES:
> +               skip_prefix(desc, "refs/remotes/", &desc);
>                 color = BRANCH_COLOR_REMOTE;
>                 prefix = remote_prefix;
>                 break;
> @@ -554,11 +434,13 @@ static void print_ref_item(struct ref_array_item *item, int maxwidth,
>                 strbuf_addf(&out, "%c %s%s%s", c, branch_get_color(color),
>                             name.buf, branch_get_color(BRANCH_COLOR_RESET));
>
> -       if (item->symref)
> -               strbuf_addf(&out, " -> %s", item->symref);
> +       if (item->symref) {
> +               skip_prefix(item->symref, "refs/remotes/", &desc);
> +               strbuf_addf(&out, " -> %s", desc);
> +       }
>         else if (filter->verbose)
>                 /* " f7c0c00 [ahead 58, behind 197] vcs-svn: drop obj_pool.h" */
> -               add_verbose_info(&out, item, filter);
> +               add_verbose_info(&out, item, filter, desc);
>         if (column_active(colopts)) {
>                 assert(!filter->verbose && "--column and --verbose are incompatible");
>                 string_list_append(&output, out.buf);
> @@ -575,11 +457,13 @@ static int calc_maxwidth(struct ref_array *refs, int remote_bonus)
>         int i, max = 0;
>         for (i = 0; i < refs->nr; i++) {
>                 struct ref_array_item *it = refs->items[i];
> +               const char *desc = it->refname;
>                 int w;
>
> -               if (it->ignore)
> -                       continue;
> -               w = utf8_strwidth(it->refname);
> +               skip_prefix(it->refname, "refs/heads/", &desc);
> +               skip_prefix(it->refname, "refs/remotes/", &desc);
> +               w = utf8_strwidth(desc);
> +
>                 if (it->kind == FILTER_REFS_REMOTES)
>                         w += remote_bonus;
>                 if (w > max)
> @@ -588,14 +472,14 @@ static int calc_maxwidth(struct ref_array *refs, int remote_bonus)
>         return max;
>  }
>
> -static void print_ref_list(struct ref_filter *filter)
> +static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sorting)
>  {
>         int i;
>         struct ref_array array;
> -       struct ref_filter_cbdata data;
>         int maxwidth = 0;
>         const char *remote_prefix = "";
> -       struct rev_info revs;
> +       struct ref_sorting def_sorting;
> +       const char *sort_type = "type";
>
>         /*
>          * If we are listing more than just remote branches,
> @@ -606,60 +490,30 @@ static void print_ref_list(struct ref_filter *filter)
>                 remote_prefix = "remotes/";
>
>         memset(&array, 0, sizeof(array));
> -       if (filter->merge != REF_FILTER_MERGED_NONE)
> -               init_revisions(&revs, NULL);
> -
> -       data.array = &array;
> -       data.filter = filter;
> -       array.revs = &revs;
>
> -       /*
> -        * First we obtain all regular branch refs and if the HEAD is
> -        * detached then we insert that ref to the end of the ref_fist
> -        * so that it can be printed and removed first.
> -        */
> -       for_each_rawref(append_ref, &data);
> -       if (filter->detached)
> -               head_ref(append_ref, &data);
> -       /*
> -        * The following implementation is currently duplicated in ref-filter. It
> -        * will eventually be removed when we port branch.c to use ref-filter APIs.
> -        */
> -       if (filter->merge != REF_FILTER_MERGED_NONE) {
> -               filter->merge_commit->object.flags |= UNINTERESTING;
> -               add_pending_object(&revs, &filter->merge_commit->object, "");
> -               revs.limited = 1;
> -
> -               if (prepare_revision_walk(&revs))
> -                       die(_("revision walk setup failed"));
> -
> -               for (i = 0; i < array.nr; i++) {
> -                       struct ref_array_item *item = array.items[i];
> -                       struct commit *commit = item->commit;
> -                       int is_merged = !!(commit->object.flags & UNINTERESTING);
> -                       item->ignore = is_merged != (filter->merge == REF_FILTER_MERGED_INCLUDE);
> -               }
> +       verify_ref_format("%(refname)%(symref)");
> +       filter_refs(&array, filter, filter->kind | FILTER_REFS_INCLUDE_BROKEN);
>
> -               for (i = 0; i < array.nr; i++) {
> -                       struct ref_array_item *item = array.items[i];
> -                       clear_commit_marks(item->commit, ALL_REV_FLAGS);
> -               }
> -               clear_commit_marks(filter->merge_commit, ALL_REV_FLAGS);
> -       }
>         if (filter->verbose)
>                 maxwidth = calc_maxwidth(&array, strlen(remote_prefix));
>
>         /* Print detached HEAD before sorting and printing the rest */
>         if (filter->kind & FILTER_REFS_DETACHED_HEAD) {
> -               print_ref_item(array.items[array.nr - 1], maxwidth, filter, remote_prefix);
> +               format_and_print_ref_item(array.items[array.nr - 1], maxwidth, filter, remote_prefix);
>                 free_array_item(array.items[array.nr - 1]);
>                 array.nr--;
>         }
>
> -       qsort(array.items, array.nr, sizeof(struct ref_array_item *), ref_cmp);
> +       if (!sorting) {
> +               def_sorting.next = NULL;
> +               def_sorting.atom = parse_ref_filter_atom(sort_type,
> +                                                        sort_type + strlen(sort_type));
> +               sorting = &def_sorting;
> +       }
> +       ref_array_sort(sorting, &array);
>
>         for (i = 0; i < array.nr; i++)
> -               print_ref_item(array.items[i], maxwidth, filter, remote_prefix);
> +               format_and_print_ref_item(array.items[i], maxwidth, filter, remote_prefix);
>
>         ref_array_clear(&array);
>  }
> @@ -761,6 +615,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
>         const char *new_upstream = NULL;
>         enum branch_track track;
>         struct ref_filter filter;
> +       static struct ref_sorting *sorting = NULL, **sorting_tail = &sorting;
>
>         struct option options[] = {
>                 OPT_GROUP(N_("Generic options")),
> @@ -795,6 +650,8 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
>                 OPT_MERGED(&filter, N_("print only branches that are merged")),
>                 OPT_NO_MERGED(&filter, N_("print only branches that are not merged")),
>                 OPT_COLUMN(0, "column", &colopts, N_("list branches in columns")),
> +               OPT_CALLBACK(0 , "sort", sorting_tail, N_("key"),
> +                            N_("field name to sort on"), &parse_opt_ref_sorting),
>                 OPT_END(),
>         };
>
> @@ -853,7 +710,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
>                 if ((filter.kind & FILTER_REFS_BRANCHES) && filter.detached)
>                         filter.kind |= FILTER_REFS_DETACHED_HEAD;
>                 filter.name_patterns = argv;
> -               print_ref_list(&filter);
> +               print_ref_list(&filter, sorting);
>                 print_columns(&output, colopts, NULL);
>                 string_list_clear(&output, 0);
>                 return 0;
> diff --git a/ref-filter.c b/ref-filter.c
> index c059d87..c536aea 100644
> --- a/ref-filter.c
> +++ b/ref-filter.c
> @@ -1331,7 +1331,7 @@ static int ref_filter_handler(const char *refname, const struct object_id *oid,
>          * obtain the commit using the 'oid' available and discard all
>          * non-commits early. The actual filtering is done later.
>          */
> -       if (filter->merge_commit || filter->with_commit) {
> +       if (filter->merge_commit || filter->with_commit || filter->verbose) {
>                 commit = lookup_commit_reference_gently(oid->hash, 1);
>                 if (!commit)
>                         return 0;
> diff --git a/ref-filter.h b/ref-filter.h
> index 56980a3..9316031 100644
> --- a/ref-filter.h
> +++ b/ref-filter.h
> @@ -36,7 +36,6 @@ struct ref_array_item {
>         unsigned char objectname[20];
>         int flag;
>         unsigned int kind;
> -       int ignore : 1; /* To be removed in the next patch */
>         const char *symref;
>         struct commit *commit;
>         struct atom_value *value;
> diff --git a/t/t1430-bad-ref-name.sh b/t/t1430-bad-ref-name.sh
> index 16d0b8b..dacc186 100755
> --- a/t/t1430-bad-ref-name.sh
> +++ b/t/t1430-bad-ref-name.sh
> @@ -38,11 +38,12 @@ test_expect_success 'fast-import: fail on invalid branch name "bad[branch]name"'
>         test_must_fail git fast-import <input
>  '
>
> -test_expect_success 'git branch shows badly named ref' '
> +test_expect_success 'git branch shows badly named ref as warning' '
>         cp .git/refs/heads/master .git/refs/heads/broken...ref &&
>         test_when_finished "rm -f .git/refs/heads/broken...ref" &&
> -       git branch >output &&
> -       grep -e "broken\.\.\.ref" output
> +       git branch >output 2>error &&
> +       grep -e "broken\.\.\.ref" error &&
> +       ! grep -e "broken\.\.\.ref" output
>  '
>
>  test_expect_success 'branch -d can delete badly named ref' '
> @@ -95,8 +96,8 @@ test_expect_success 'branch -m cannot rename to a bad ref name' '
>         git branch goodref &&
>         test_must_fail git branch -m goodref broken...ref &&
>         test_cmp_rev master goodref &&
> -       git branch >output &&
> -       ! grep -e "broken\.\.\.ref" output
> +       git branch >output 2>error &&
> +       ! grep -e "broken\.\.\.ref" error
>  '
>
>  test_expect_failure 'branch -m can rename from a bad ref name' '
> @@ -104,8 +105,8 @@ test_expect_failure 'branch -m can rename from a bad ref name' '
>         test_when_finished "rm -f .git/refs/heads/broken...ref" &&
>         git branch -m broken...ref renamed &&
>         test_cmp_rev master renamed &&
> -       git branch >output &&
> -       ! grep -e "broken\.\.\.ref" output
> +       git branch >output 2>error &&
> +       ! grep -e "broken\.\.\.ref" error
>  '
>
>  test_expect_success 'push cannot create a badly named ref' '
> @@ -131,8 +132,8 @@ test_expect_failure 'push --mirror can delete badly named ref' '
>                 cp .git/refs/heads/master .git/refs/heads/broken...ref
>         ) &&
>         git -C src push --mirror "file://$top/dest" &&
> -       git -C dest branch >output &&
> -       ! grep -e "broken\.\.\.ref" output
> +       git -C dest branch >output 2>error &&
> +       ! grep -e "broken\.\.\.ref" error
>  '
>
>  test_expect_success 'rev-parse skips symref pointing to broken name' '
> diff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh
> index f51d0f3..53d166d 100755
> --- a/t/t3203-branch-output.sh
> +++ b/t/t3203-branch-output.sh
> @@ -143,4 +143,15 @@ EOF
>         test_i18ncmp expect actual
>  '
>
> +test_expect_success 'git branch `--sort` option' '
> +       cat >expect <<-\EOF &&
> +       * (HEAD detached from fromtag)
> +         branch-two
> +         branch-one
> +         master
> +       EOF
> +       git branch --sort=objectsize >actual &&
> +       test_i18ncmp expect actual
> +'
> +
>  test_done
> --
> 2.5.1
>

This is [7/8] which is repeated, not sure why this happened, ignore this.

-- 
Regards,
Karthik Nayak

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v4 1/8] branch: refactor width computation
  2015-09-13  7:23 ` [PATCH v4 1/8] branch: refactor width computation Karthik Nayak
@ 2015-09-13 11:51   ` Matthieu Moy
  2015-09-13 12:23     ` Karthik Nayak
  0 siblings, 1 reply; 38+ messages in thread
From: Matthieu Moy @ 2015-09-13 11:51 UTC (permalink / raw)
  To: Karthik Nayak; +Cc: git, christian.couder, gitster

Karthik Nayak <karthik.188@gmail.com> writes:

> @@ -667,26 +675,22 @@ static int print_ref_list(int kinds, int detached, int verbose, int abbrev, stru
>  			clear_commit_marks(item->commit, ALL_REV_FLAGS);
>  		}
>  		clear_commit_marks(filter, ALL_REV_FLAGS);
> -
> -		if (verbose)
> -			ref_list.maxwidth = calc_maxwidth(&ref_list);
>  	}
> +	if (verbose)
> +		maxwidth = calc_maxwidth(&ref_list, strlen(remote_prefix));

I don't understand this hunk. To give a bit more context, the closing
brace corresponds to:

	if (merge_filter != NO_FILTER) {

Hence this patch gets the two lines out of this "if". Actually, I don't
understand how it could work previously. Wasn't this "calc_maxwidth"
needed regardless of merge_filter from the beginning?

In any case, that remark is not an objection on your patch, but I'd like
to understand.

-- 
Matthieu Moy
http://www-verimag.imag.fr/~moy/

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v4 3/8] branch: roll show_detached HEAD into regular ref_list
  2015-09-13  7:23 ` [PATCH v4 3/8] branch: roll show_detached HEAD into regular ref_list Karthik Nayak
@ 2015-09-13 12:12   ` Matthieu Moy
  2015-09-13 13:24     ` Karthik Nayak
  2015-09-13 16:46     ` Eric Sunshine
  2015-09-14 19:35   ` Junio C Hamano
  1 sibling, 2 replies; 38+ messages in thread
From: Matthieu Moy @ 2015-09-13 12:12 UTC (permalink / raw)
  To: Karthik Nayak; +Cc: git, christian.couder, gitster

Karthik Nayak <karthik.188@gmail.com> writes:

> @@ -679,15 +682,20 @@ static int print_ref_list(int kinds, int detached, int verbose, int abbrev, stru
>  	if (verbose)
>  		maxwidth = calc_maxwidth(&ref_list, strlen(remote_prefix));
>  
> -	qsort(ref_list.list, ref_list.index, sizeof(struct ref_item), ref_cmp);
> +	index = ref_list.index;
> +
> +	/* Print detached HEAD before sorting and printing the rest */
> +	if (detached && (ref_list.list[index - 1].kind == REF_DETACHED_HEAD) &&
> +	    !strcmp(ref_list.list[index - 1].name, head)) {
> +		print_ref_item(&ref_list.list[index - 1], maxwidth, verbose, abbrev,
> +			       1, remote_prefix);
> +		index -= 1;
> +	}

I think Eric already mentionned it, but I don't remember the conclusion
and can't find it in the archives. Wouldn't it be cleaner to actually
remove the detached head from the array (do "ref_list.index -= 1"
instead of "index -= 1", and possibly free() what needs to be freed?

If you did so, you wouldn't have any possible confusion between the
local variable "index" and ref_list.index in the code below:

> -	detached = (detached && (kinds & REF_LOCAL_BRANCH));
> -	if (detached && match_patterns(pattern, "HEAD"))
> -		show_detached(&ref_list, maxwidth);
> +	qsort(ref_list.list, index, sizeof(struct ref_item), ref_cmp);
>  
> -	for (i = 0; i < ref_list.index; i++) {
> -		int current = !detached &&
> -			(ref_list.list[i].kind == REF_LOCAL_BRANCH) &&
> +	for (i = 0; i < index; i++) {
> +		int current = !detached && (ref_list.list[i].kind == REF_LOCAL_BRANCH) &&
>  			!strcmp(ref_list.list[i].name, head);
>  		print_ref_item(&ref_list.list[i], maxwidth, verbose,
>  			       abbrev, current, remote_prefix);

-- 
Matthieu Moy
http://www-verimag.imag.fr/~moy/

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v4 4/8] branch: move 'current' check down to the presentation layer
  2015-09-13  7:23 ` [PATCH v4 4/8] branch: move 'current' check down to the presentation layer Karthik Nayak
@ 2015-09-13 12:15   ` Matthieu Moy
  2015-09-13 13:22     ` Karthik Nayak
  2015-09-13 15:35   ` Karthik Nayak
  1 sibling, 1 reply; 38+ messages in thread
From: Matthieu Moy @ 2015-09-13 12:15 UTC (permalink / raw)
  To: Karthik Nayak; +Cc: git, christian.couder, gitster

Karthik Nayak <karthik.188@gmail.com> writes:

> We check if given ref is the current branch in print_ref_list(). Move
> this check to print_ref_item() where it is checked right before
> printing.

You may want to add a sentence saying why this is good. Given the
context, it's relatively clear that this makes the code closer to the
shape expected by ref-filter, but if you imagine someone bisecting or
blaming and finding this commit in another context, that person may
appreciate more explanation.

-- 
Matthieu Moy
http://www-verimag.imag.fr/~moy/

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v4 1/8] branch: refactor width computation
  2015-09-13 11:51   ` Matthieu Moy
@ 2015-09-13 12:23     ` Karthik Nayak
  2015-09-13 12:33       ` Matthieu Moy
  0 siblings, 1 reply; 38+ messages in thread
From: Karthik Nayak @ 2015-09-13 12:23 UTC (permalink / raw)
  To: Matthieu Moy; +Cc: Git, Christian Couder, Junio C Hamano

On Sun, Sep 13, 2015 at 5:21 PM, Matthieu Moy
<Matthieu.Moy@grenoble-inp.fr> wrote:
> Karthik Nayak <karthik.188@gmail.com> writes:
>
>> @@ -667,26 +675,22 @@ static int print_ref_list(int kinds, int detached, int verbose, int abbrev, stru
>>                       clear_commit_marks(item->commit, ALL_REV_FLAGS);
>>               }
>>               clear_commit_marks(filter, ALL_REV_FLAGS);
>> -
>> -             if (verbose)
>> -                     ref_list.maxwidth = calc_maxwidth(&ref_list);
>>       }
>> +     if (verbose)
>> +             maxwidth = calc_maxwidth(&ref_list, strlen(remote_prefix));
>
> I don't understand this hunk. To give a bit more context, the closing
> brace corresponds to:
>
>         if (merge_filter != NO_FILTER) {
>
> Hence this patch gets the two lines out of this "if". Actually, I don't
> understand how it could work previously. Wasn't this "calc_maxwidth"
> needed regardless of merge_filter from the beginning?

Previously, we used to compute and store each item's width in append_ref()
and change the ref_list.maxwidth only if we find a new maxwidth (all
within append_ref()).
Although the maxwidth variable is only needed when we use the verbose
option this is computed otherwise also (without the usage of calc_maxwidth()).
When using the merge option with verbose the maxwidth would need to be
recalculated. Hence we compute the maxwidth again using
calc_maxwidth() within the
if block.

Currently we only compute and store maxwidth if required, after
obtaining required refs.

>
> In any case, that remark is not an objection on your patch, but I'd like
> to understand.
>

Happy to explain.

-- 
Regards,
Karthik Nayak

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v4 6/8] branch.c: use 'ref-filter' data structures
  2015-09-13  7:23 ` [PATCH v4 6/8] branch.c: use 'ref-filter' data structures Karthik Nayak
@ 2015-09-13 12:26   ` Matthieu Moy
  2015-09-13 13:19     ` Karthik Nayak
  0 siblings, 1 reply; 38+ messages in thread
From: Matthieu Moy @ 2015-09-13 12:26 UTC (permalink / raw)
  To: Karthik Nayak; +Cc: git, christian.couder, gitster

Karthik Nayak <karthik.188@gmail.com> writes:

>  	/* Print detached HEAD before sorting and printing the rest */
> -	if (detached) {
> -		print_ref_item(&ref_list.list[index - 1], maxwidth, verbose, abbrev,
> -			       detached, remote_prefix);
> -		index -= 1;
> +	if (filter->kind & FILTER_REFS_DETACHED_HEAD) {
> +		print_ref_item(array.items[array.nr - 1], maxwidth, filter, remote_prefix);
> +		free_array_item(array.items[array.nr - 1]);
> +		array.nr--;

Ah, this answers my previous remark: indeed, you are removing the
element from the array completely after this patch. You may want to
modify the previous patch to start doing it earlier, but I think it's
not worth the trouble: I agree with the final state, only the
intermediate state is suboptimal (but still acceptable to me at least).

-- 
Matthieu Moy
http://www-verimag.imag.fr/~moy/

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v4 1/8] branch: refactor width computation
  2015-09-13 12:23     ` Karthik Nayak
@ 2015-09-13 12:33       ` Matthieu Moy
  0 siblings, 0 replies; 38+ messages in thread
From: Matthieu Moy @ 2015-09-13 12:33 UTC (permalink / raw)
  To: Karthik Nayak; +Cc: Git, Christian Couder, Junio C Hamano

Karthik Nayak <karthik.188@gmail.com> writes:

> Happy to explain.

Thanks for the clarification.

-- 
Matthieu Moy
http://www-verimag.imag.fr/~moy/

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v4 6/8] branch.c: use 'ref-filter' data structures
  2015-09-13 12:26   ` Matthieu Moy
@ 2015-09-13 13:19     ` Karthik Nayak
  2015-09-13 17:49       ` Matthieu Moy
  0 siblings, 1 reply; 38+ messages in thread
From: Karthik Nayak @ 2015-09-13 13:19 UTC (permalink / raw)
  To: Matthieu Moy; +Cc: Git, Christian Couder, Junio C Hamano

On Sun, Sep 13, 2015 at 5:56 PM, Matthieu Moy
<Matthieu.Moy@grenoble-inp.fr> wrote:
> Karthik Nayak <karthik.188@gmail.com> writes:
>
>>       /* Print detached HEAD before sorting and printing the rest */
>> -     if (detached) {
>> -             print_ref_item(&ref_list.list[index - 1], maxwidth, verbose, abbrev,
>> -                            detached, remote_prefix);
>> -             index -= 1;
>> +     if (filter->kind & FILTER_REFS_DETACHED_HEAD) {
>> +             print_ref_item(array.items[array.nr - 1], maxwidth, filter, remote_prefix);
>> +             free_array_item(array.items[array.nr - 1]);
>> +             array.nr--;
>
> Ah, this answers my previous remark: indeed, you are removing the
> element from the array completely after this patch. You may want to
> modify the previous patch to start doing it earlier, but I think it's
> not worth the trouble: I agree with the final state, only the
> intermediate state is suboptimal (but still acceptable to me at least).
>

Yes! Eric suggested this. It doesn't make much sense in the previous
patch, cause I'd have to introduce something along the lines of
free_array_item() only to be removed/replaced here.

-- 
Regards,
Karthik Nayak

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v4 4/8] branch: move 'current' check down to the presentation layer
  2015-09-13 12:15   ` Matthieu Moy
@ 2015-09-13 13:22     ` Karthik Nayak
  0 siblings, 0 replies; 38+ messages in thread
From: Karthik Nayak @ 2015-09-13 13:22 UTC (permalink / raw)
  To: Matthieu Moy; +Cc: Git, Christian Couder, Junio C Hamano

On Sun, Sep 13, 2015 at 5:45 PM, Matthieu Moy
<Matthieu.Moy@grenoble-inp.fr> wrote:
> Karthik Nayak <karthik.188@gmail.com> writes:
>
>> We check if given ref is the current branch in print_ref_list(). Move
>> this check to print_ref_item() where it is checked right before
>> printing.
>
> You may want to add a sentence saying why this is good. Given the
> context, it's relatively clear that this makes the code closer to the
> shape expected by ref-filter, but if you imagine someone bisecting or
> blaming and finding this commit in another context, that person may
> appreciate more explanation.
>

Will do.

-- 
Regards,
Karthik Nayak

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v4 3/8] branch: roll show_detached HEAD into regular ref_list
  2015-09-13 12:12   ` Matthieu Moy
@ 2015-09-13 13:24     ` Karthik Nayak
  2015-09-13 16:46     ` Eric Sunshine
  1 sibling, 0 replies; 38+ messages in thread
From: Karthik Nayak @ 2015-09-13 13:24 UTC (permalink / raw)
  To: Matthieu Moy; +Cc: Git, Christian Couder, Junio C Hamano

On Sun, Sep 13, 2015 at 5:42 PM, Matthieu Moy
<Matthieu.Moy@grenoble-inp.fr> wrote:
> Karthik Nayak <karthik.188@gmail.com> writes:
>
>> @@ -679,15 +682,20 @@ static int print_ref_list(int kinds, int detached, int verbose, int abbrev, stru
>>       if (verbose)
>>               maxwidth = calc_maxwidth(&ref_list, strlen(remote_prefix));
>>
>> -     qsort(ref_list.list, ref_list.index, sizeof(struct ref_item), ref_cmp);
>> +     index = ref_list.index;
>> +
>> +     /* Print detached HEAD before sorting and printing the rest */
>> +     if (detached && (ref_list.list[index - 1].kind == REF_DETACHED_HEAD) &&
>> +         !strcmp(ref_list.list[index - 1].name, head)) {
>> +             print_ref_item(&ref_list.list[index - 1], maxwidth, verbose, abbrev,
>> +                            1, remote_prefix);
>> +             index -= 1;
>> +     }
>
> I think Eric already mentionned it, but I don't remember the conclusion
> and can't find it in the archives. Wouldn't it be cleaner to actually
> remove the detached head from the array (do "ref_list.index -= 1"
> instead of "index -= 1", and possibly free() what needs to be freed?
>
> If you did so, you wouldn't have any possible confusion between the
> local variable "index" and ref_list.index in the code below:

This is cleared out in [PATCH 6/8].

-- 
Regards,
Karthik Nayak

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH v4 4/8] branch: move 'current' check down to the presentation layer
  2015-09-13  7:23 ` [PATCH v4 4/8] branch: move 'current' check down to the presentation layer Karthik Nayak
  2015-09-13 12:15   ` Matthieu Moy
@ 2015-09-13 15:35   ` Karthik Nayak
  1 sibling, 0 replies; 38+ messages in thread
From: Karthik Nayak @ 2015-09-13 15:35 UTC (permalink / raw)
  To: git; +Cc: christian.couder, Matthieu.Moy, gitster, Karthik Nayak, Karthik Nayak

We check if given ref is the current branch in print_ref_list(). Move
this check to print_ref_item() where it is checked right before
printing. This enables a smooth transition to using ref-filter APIs,
as we can later replace the current check while printing to just check
for FILTER_REFS_DETACHED instead.

Based-on-patch-by: Jeff King <peff@peff.net>
Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>
Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
---

Change the commit message to explain the need for this patch.

 builtin/branch.c | 22 +++++++++++-----------
 1 file changed, 11 insertions(+), 11 deletions(-)

diff --git a/builtin/branch.c b/builtin/branch.c
index 6ba7a3f..4d9e4d0 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -534,9 +534,10 @@ static char *get_head_description(void)
 }
 
 static void print_ref_item(struct ref_item *item, int maxwidth, int verbose,
-			   int abbrev, int current, const char *remote_prefix)
+			   int abbrev, int detached, const char *remote_prefix)
 {
 	char c;
+	int current = 0;
 	int color;
 	struct strbuf out = STRBUF_INIT, name = STRBUF_INIT;
 	const char *prefix = "";
@@ -548,15 +549,18 @@ static void print_ref_item(struct ref_item *item, int maxwidth, int verbose,
 
 	switch (item->kind) {
 	case REF_LOCAL_BRANCH:
-		color = BRANCH_COLOR_LOCAL;
+		if (!detached && !strcmp(item->name, head))
+			current = 1;
+		else
+			color = BRANCH_COLOR_LOCAL;
 		break;
 	case REF_REMOTE_BRANCH:
 		color = BRANCH_COLOR_REMOTE;
 		prefix = remote_prefix;
 		break;
 	case REF_DETACHED_HEAD:
-		color = BRANCH_COLOR_CURRENT;
 		desc = to_free = get_head_description();
+		current = 1;
 		break;
 	default:
 		color = BRANCH_COLOR_PLAIN;
@@ -685,21 +689,17 @@ static int print_ref_list(int kinds, int detached, int verbose, int abbrev, stru
 	index = ref_list.index;
 
 	/* Print detached HEAD before sorting and printing the rest */
-	if (detached && (ref_list.list[index - 1].kind == REF_DETACHED_HEAD) &&
-	    !strcmp(ref_list.list[index - 1].name, head)) {
+	if (detached) {
 		print_ref_item(&ref_list.list[index - 1], maxwidth, verbose, abbrev,
-			       1, remote_prefix);
+			       detached, remote_prefix);
 		index -= 1;
 	}
 
 	qsort(ref_list.list, index, sizeof(struct ref_item), ref_cmp);
 
-	for (i = 0; i < index; i++) {
-		int current = !detached && (ref_list.list[i].kind == REF_LOCAL_BRANCH) &&
-			!strcmp(ref_list.list[i].name, head);
+	for (i = 0; i < index; i++)
 		print_ref_item(&ref_list.list[i], maxwidth, verbose,
-			       abbrev, current, remote_prefix);
-	}
+			       abbrev, detached, remote_prefix);
 
 	free_ref_list(&ref_list);
 
-- 
2.5.1

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* Re: [PATCH v4 3/8] branch: roll show_detached HEAD into regular ref_list
  2015-09-13 12:12   ` Matthieu Moy
  2015-09-13 13:24     ` Karthik Nayak
@ 2015-09-13 16:46     ` Eric Sunshine
  2015-09-13 18:31       ` Eric Sunshine
  1 sibling, 1 reply; 38+ messages in thread
From: Eric Sunshine @ 2015-09-13 16:46 UTC (permalink / raw)
  To: Matthieu Moy; +Cc: Karthik Nayak, Git List, Christian Couder, Junio C Hamano

On Sun, Sep 13, 2015 at 8:12 AM, Matthieu Moy
<Matthieu.Moy@grenoble-inp.fr> wrote:
> Karthik Nayak <karthik.188@gmail.com> writes:
>
>> @@ -679,15 +682,20 @@ static int print_ref_list(int kinds, int detached, int verbose, int abbrev, stru
>>       if (verbose)
>>               maxwidth = calc_maxwidth(&ref_list, strlen(remote_prefix));
>>
>> -     qsort(ref_list.list, ref_list.index, sizeof(struct ref_item), ref_cmp);
>> +     index = ref_list.index;
>> +
>> +     /* Print detached HEAD before sorting and printing the rest */
>> +     if (detached && (ref_list.list[index - 1].kind == REF_DETACHED_HEAD) &&
>> +         !strcmp(ref_list.list[index - 1].name, head)) {
>> +             print_ref_item(&ref_list.list[index - 1], maxwidth, verbose, abbrev,
>> +                            1, remote_prefix);
>> +             index -= 1;
>> +     }
>
> I think Eric already mentionned it, but I don't remember the conclusion
> and can't find it in the archives. Wouldn't it be cleaner to actually
> remove the detached head from the array (do "ref_list.index -= 1"
> instead of "index -= 1", and possibly free() what needs to be freed?

I think Michael Haggerty mentioned something along those lines...

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v4 6/8] branch.c: use 'ref-filter' data structures
  2015-09-13 13:19     ` Karthik Nayak
@ 2015-09-13 17:49       ` Matthieu Moy
  0 siblings, 0 replies; 38+ messages in thread
From: Matthieu Moy @ 2015-09-13 17:49 UTC (permalink / raw)
  To: Karthik Nayak; +Cc: Git, Christian Couder, Junio C Hamano

Karthik Nayak <karthik.188@gmail.com> writes:

> On Sun, Sep 13, 2015 at 5:56 PM, Matthieu Moy
> <Matthieu.Moy@grenoble-inp.fr> wrote:
>> Karthik Nayak <karthik.188@gmail.com> writes:
>>
>>>       /* Print detached HEAD before sorting and printing the rest */
>>> -     if (detached) {
>>> -             print_ref_item(&ref_list.list[index - 1], maxwidth, verbose, abbrev,
>>> -                            detached, remote_prefix);
>>> -             index -= 1;
>>> +     if (filter->kind & FILTER_REFS_DETACHED_HEAD) {
>>> +             print_ref_item(array.items[array.nr - 1], maxwidth, filter, remote_prefix);
>>> +             free_array_item(array.items[array.nr - 1]);
>>> +             array.nr--;
>>
>> Ah, this answers my previous remark: indeed, you are removing the
>> element from the array completely after this patch. You may want to
>> modify the previous patch to start doing it earlier, but I think it's
>> not worth the trouble: I agree with the final state, only the
>> intermediate state is suboptimal (but still acceptable to me at least).
>
> Yes! Eric suggested this. It doesn't make much sense in the previous
> patch, cause I'd have to introduce something along the lines of
> free_array_item() only to be removed/replaced here.

OK, it makes sense.

-- 
Matthieu Moy
http://www-verimag.imag.fr/~moy/

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v4 3/8] branch: roll show_detached HEAD into regular ref_list
  2015-09-13 16:46     ` Eric Sunshine
@ 2015-09-13 18:31       ` Eric Sunshine
  2015-09-14 14:48         ` Karthik Nayak
  0 siblings, 1 reply; 38+ messages in thread
From: Eric Sunshine @ 2015-09-13 18:31 UTC (permalink / raw)
  To: Matthieu Moy; +Cc: Karthik Nayak, Git List, Christian Couder, Junio C Hamano

On Sun, Sep 13, 2015 at 12:46 PM, Eric Sunshine <sunshine@sunshineco.com> wrote:
> On Sun, Sep 13, 2015 at 8:12 AM, Matthieu Moy
> <Matthieu.Moy@grenoble-inp.fr> wrote:
>> Karthik Nayak <karthik.188@gmail.com> writes:
>>
>>> @@ -679,15 +682,20 @@ static int print_ref_list(int kinds, int detached, int verbose, int abbrev, stru
>>>       if (verbose)
>>>               maxwidth = calc_maxwidth(&ref_list, strlen(remote_prefix));
>>>
>>> -     qsort(ref_list.list, ref_list.index, sizeof(struct ref_item), ref_cmp);
>>> +     index = ref_list.index;
>>> +
>>> +     /* Print detached HEAD before sorting and printing the rest */
>>> +     if (detached && (ref_list.list[index - 1].kind == REF_DETACHED_HEAD) &&
>>> +         !strcmp(ref_list.list[index - 1].name, head)) {
>>> +             print_ref_item(&ref_list.list[index - 1], maxwidth, verbose, abbrev,
>>> +                            1, remote_prefix);
>>> +             index -= 1;
>>> +     }
>>
>> I think Eric already mentionned it, but I don't remember the conclusion
>> and can't find it in the archives. Wouldn't it be cleaner to actually
>> remove the detached head from the array (do "ref_list.index -= 1"
>> instead of "index -= 1", and possibly free() what needs to be freed?
>
> I think Michael Haggerty mentioned something along those lines...

Specifically, I think you're referring to [1] (?).

[1]: http://thread.gmane.org/gmane.comp.version-control.git/276363/focus=276676

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v4 3/8] branch: roll show_detached HEAD into regular ref_list
  2015-09-13 18:31       ` Eric Sunshine
@ 2015-09-14 14:48         ` Karthik Nayak
  2015-09-14 14:54           ` Matthieu Moy
  0 siblings, 1 reply; 38+ messages in thread
From: Karthik Nayak @ 2015-09-14 14:48 UTC (permalink / raw)
  To: Eric Sunshine; +Cc: Matthieu Moy, Git List, Christian Couder, Junio C Hamano

On Mon, Sep 14, 2015 at 12:01 AM, Eric Sunshine <sunshine@sunshineco.com> wrote:
> On Sun, Sep 13, 2015 at 12:46 PM, Eric Sunshine <sunshine@sunshineco.com> wrote:
>> On Sun, Sep 13, 2015 at 8:12 AM, Matthieu Moy
>> <Matthieu.Moy@grenoble-inp.fr> wrote:
>>> Karthik Nayak <karthik.188@gmail.com> writes:
>>>
>>>> @@ -679,15 +682,20 @@ static int print_ref_list(int kinds, int detached, int verbose, int abbrev, stru
>>>>       if (verbose)
>>>>               maxwidth = calc_maxwidth(&ref_list, strlen(remote_prefix));
>>>>
>>>> -     qsort(ref_list.list, ref_list.index, sizeof(struct ref_item), ref_cmp);
>>>> +     index = ref_list.index;
>>>> +
>>>> +     /* Print detached HEAD before sorting and printing the rest */
>>>> +     if (detached && (ref_list.list[index - 1].kind == REF_DETACHED_HEAD) &&
>>>> +         !strcmp(ref_list.list[index - 1].name, head)) {
>>>> +             print_ref_item(&ref_list.list[index - 1], maxwidth, verbose, abbrev,
>>>> +                            1, remote_prefix);
>>>> +             index -= 1;
>>>> +     }
>>>
>>> I think Eric already mentionned it, but I don't remember the conclusion
>>> and can't find it in the archives. Wouldn't it be cleaner to actually
>>> remove the detached head from the array (do "ref_list.index -= 1"
>>> instead of "index -= 1", and possibly free() what needs to be freed?
>>
>> I think Michael Haggerty mentioned something along those lines...
>
> Specifically, I think you're referring to [1] (?).
>
> [1]: http://thread.gmane.org/gmane.comp.version-control.git/276363/focus=276676

No not that, that is handled in the previous patch series.

I can't find the reference either, but the comment was along the lines of what
Matthieu just mentioned above, But like I replied on [Patch 6/8] Its
taken care of
in that particular patch. Here it doesn't seem to be needed.

-- 
Regards,
Karthik Nayak

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v4 3/8] branch: roll show_detached HEAD into regular ref_list
  2015-09-14 14:48         ` Karthik Nayak
@ 2015-09-14 14:54           ` Matthieu Moy
  0 siblings, 0 replies; 38+ messages in thread
From: Matthieu Moy @ 2015-09-14 14:54 UTC (permalink / raw)
  To: Karthik Nayak; +Cc: Eric Sunshine, Git List, Christian Couder, Junio C Hamano

Karthik Nayak <karthik.188@gmail.com> writes:

> On Mon, Sep 14, 2015 at 12:01 AM, Eric Sunshine <sunshine@sunshineco.com> wrote:
>> Specifically, I think you're referring to [1] (?).
>>
>> [1]: http://thread.gmane.org/gmane.comp.version-control.git/276363/focus=276676
>
> No not that, that is handled in the previous patch series.
>
> I can't find the reference either, but the comment was along the lines of what
> Matthieu just mentioned above,

I had another message in mind too. Never mind, the comment is addressed,
we don't need to know if it was a real message or a collective
hallucination ;-).

-- 
Matthieu Moy
http://www-verimag.imag.fr/~moy/

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v4 3/8] branch: roll show_detached HEAD into regular ref_list
  2015-09-13  7:23 ` [PATCH v4 3/8] branch: roll show_detached HEAD into regular ref_list Karthik Nayak
  2015-09-13 12:12   ` Matthieu Moy
@ 2015-09-14 19:35   ` Junio C Hamano
  2015-09-16  6:23     ` Karthik Nayak
  1 sibling, 1 reply; 38+ messages in thread
From: Junio C Hamano @ 2015-09-14 19:35 UTC (permalink / raw)
  To: Karthik Nayak; +Cc: git, christian.couder, Matthieu.Moy

Karthik Nayak <karthik.188@gmail.com> writes:

> +	/*
> +	 * First we obtain all regular branch refs and if the HEAD is
> +	 * detached then we insert that ref to the end of the ref_fist
> +	 * so that it can be printed and removed first.
> +	 */
>  	for_each_rawref(append_ref, &cb);
> +	if (detached)
> +		head_ref(append_ref, &cb);
> +	index = ref_list.index;
> +
> +	/* Print detached HEAD before sorting and printing the rest */
> +	if (detached && (ref_list.list[index - 1].kind == REF_DETACHED_HEAD) &&
> +	    !strcmp(ref_list.list[index - 1].name, head)) {
> +		print_ref_item(&ref_list.list[index - 1], maxwidth, verbose, abbrev,
> +			       1, remote_prefix);
> +		index -= 1;
> +	}
>  
> +	qsort(ref_list.list, index, sizeof(struct ref_item), ref_cmp);

This looks somewhat strange.  Wouldn't it be more consistent to
teach ref_cmp that HEAD sorts where in the collection of refs (I
presume that kind is checked first and then name, so if you give
REF_DETACHED_HEAD a low number than others, it would automatically
give you the ordering you want) without all of the above special
casing?

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v4 5/8] branch: drop non-commit error reporting
  2015-09-13  7:23 ` [PATCH v4 5/8] branch: drop non-commit error reporting Karthik Nayak
@ 2015-09-14 19:49   ` Junio C Hamano
  2015-09-16  6:04     ` Karthik Nayak
  0 siblings, 1 reply; 38+ messages in thread
From: Junio C Hamano @ 2015-09-14 19:49 UTC (permalink / raw)
  To: Karthik Nayak; +Cc: git, christian.couder, Matthieu.Moy

Karthik Nayak <karthik.188@gmail.com> writes:

> Remove the error reporting variable to make the code easier to port
> over to using ref-filter APIs. This variable is not required as in
> ref-filter we already check for possible errors and report them.

Hmmmm.  What do you exactly mean "possible errors" here?

Unlike generic refs that can point at anything, refs/heads/* refs
must point at a commit [*1*], and that is why the error message says
'does not point at a commit'.

Does ref-filter API have corresponding check to treat the local and
remote branch hierarchies differently from tags and others?

[Footnote]

*1* Strictly speaking, use of lookup_commit_reference_gently() in
    the existing code allows a committish to be there and does not
    limit the tip objects to be commits, but I think it is a bug.
    At least, even with deref_tag(), we reject non committish found
    at the tip of branch refs and explain with the error message
    this patch removes.

> Based-on-patch-by: Jeff King <peff@peff.net>
> Mentored-by: Christian Couder <christian.couder@gmail.com>
> Mentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>
> Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
> ---
>  builtin/branch.c | 18 ++++--------------
>  1 file changed, 4 insertions(+), 14 deletions(-)
>
> diff --git a/builtin/branch.c b/builtin/branch.c
> index 4d9e4d0..8b9da60 100644
> --- a/builtin/branch.c
> +++ b/builtin/branch.c
> @@ -313,7 +313,6 @@ static char *resolve_symref(const char *src, const char *prefix)
>  struct append_ref_cb {
>  	struct ref_list *ref_list;
>  	const char **pattern;
> -	int ret;
>  };
>  
>  static int match_patterns(const char **pattern, const char *refname)
> @@ -370,10 +369,8 @@ static int append_ref(const char *refname, const struct object_id *oid, int flag
>  	commit = NULL;
>  	if (ref_list->verbose || ref_list->with_commit || merge_filter != NO_FILTER) {
>  		commit = lookup_commit_reference_gently(oid->hash, 1);
> -		if (!commit) {
> -			cb->ret = error(_("branch '%s' does not point at a commit"), refname);
> +		if (!commit)
>  			return 0;
> -		}
>  
>  		/* Filter with with_commit if specified */
>  		if (!is_descendant_of(commit, ref_list->with_commit))
> @@ -617,7 +614,7 @@ static int calc_maxwidth(struct ref_list *refs, int remote_bonus)
>  	return max;
>  }
>  
> -static int print_ref_list(int kinds, int detached, int verbose, int abbrev, struct commit_list *with_commit, const char **pattern)
> +static void print_ref_list(int kinds, int detached, int verbose, int abbrev, struct commit_list *with_commit, const char **pattern)
>  {
>  	int i, index;
>  	struct append_ref_cb cb;
> @@ -642,7 +639,6 @@ static int print_ref_list(int kinds, int detached, int verbose, int abbrev, stru
>  		init_revisions(&ref_list.revs, NULL);
>  	cb.ref_list = &ref_list;
>  	cb.pattern = pattern;
> -	cb.ret = 0;
>  	/*
>  	 * First we obtain all regular branch refs and if the HEAD is
>  	 * detached then we insert that ref to the end of the ref_fist
> @@ -702,11 +698,6 @@ static int print_ref_list(int kinds, int detached, int verbose, int abbrev, stru
>  			       abbrev, detached, remote_prefix);
>  
>  	free_ref_list(&ref_list);
> -
> -	if (cb.ret)
> -		error(_("some refs could not be read"));
> -
> -	return cb.ret;
>  }
>  
>  static void rename_branch(const char *oldname, const char *newname, int force)
> @@ -922,15 +913,14 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
>  			die(_("branch name required"));
>  		return delete_branches(argc, argv, delete > 1, kinds, quiet);
>  	} else if (list) {
> -		int ret;
>  		/*  git branch --local also shows HEAD when it is detached */
>  		if (kinds & REF_LOCAL_BRANCH)
>  			kinds |= REF_DETACHED_HEAD;
> -		ret = print_ref_list(kinds, detached, verbose, abbrev,
> +		print_ref_list(kinds, detached, verbose, abbrev,
>  					 with_commit, argv);
>  		print_columns(&output, colopts, NULL);
>  		string_list_clear(&output, 0);
> -		return ret;
> +		return 0;
>  	}
>  	else if (edit_description) {
>  		const char *branch_name;

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v4 5/8] branch: drop non-commit error reporting
  2015-09-14 19:49   ` Junio C Hamano
@ 2015-09-16  6:04     ` Karthik Nayak
  0 siblings, 0 replies; 38+ messages in thread
From: Karthik Nayak @ 2015-09-16  6:04 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Git, Christian Couder, Matthieu Moy

On Tue, Sep 15, 2015 at 1:19 AM, Junio C Hamano <gitster@pobox.com> wrote:
> Karthik Nayak <karthik.188@gmail.com> writes:
>
>> Remove the error reporting variable to make the code easier to port
>> over to using ref-filter APIs. This variable is not required as in
>> ref-filter we already check for possible errors and report them.
>
> Hmmmm.  What do you exactly mean "possible errors" here?
>

The checking if it points to a commit.

> Unlike generic refs that can point at anything, refs/heads/* refs
> must point at a commit [*1*], and that is why the error message says
> 'does not point at a commit'.
>
> Does ref-filter API have corresponding check to treat the local and
> remote branch hierarchies differently from tags and others?
>

This check in the existing code is only done when one of these holds:
ref_list->verbose || ref_list->with_commit || merge_filter != NO_FILTER

There is a similar check in ref-filter when we filter and obtain refs.

    if (filter->merge_commit || filter->with_commit || filter->verbose) {
        commit = lookup_commit_reference_gently(oid->hash, 1);
        if (!commit)
            return 0;
        /* We perform the filtering for the '--contains' option */
        if (filter->with_commit &&
            !commit_contains(filter, commit))
            return 0;
    }

> [Footnote]
>
> *1* Strictly speaking, use of lookup_commit_reference_gently() in
>     the existing code allows a committish to be there and does not
>     limit the tip objects to be commits, but I think it is a bug.
>     At least, even with deref_tag(), we reject non committish found
>     at the tip of branch refs and explain with the error message
>     this patch removes.

Ah, didn't go through this.

-- 
Regards,
Karthik Nayak

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v4 3/8] branch: roll show_detached HEAD into regular ref_list
  2015-09-14 19:35   ` Junio C Hamano
@ 2015-09-16  6:23     ` Karthik Nayak
  2015-09-17  9:47       ` Karthik Nayak
  0 siblings, 1 reply; 38+ messages in thread
From: Karthik Nayak @ 2015-09-16  6:23 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Git, Christian Couder, Matthieu Moy

On Tue, Sep 15, 2015 at 1:05 AM, Junio C Hamano <gitster@pobox.com> wrote:
> Karthik Nayak <karthik.188@gmail.com> writes:
>
>> +     /*
>> +      * First we obtain all regular branch refs and if the HEAD is
>> +      * detached then we insert that ref to the end of the ref_fist
>> +      * so that it can be printed and removed first.
>> +      */
>>       for_each_rawref(append_ref, &cb);
>> +     if (detached)
>> +             head_ref(append_ref, &cb);
>> +     index = ref_list.index;
>> +
>> +     /* Print detached HEAD before sorting and printing the rest */
>> +     if (detached && (ref_list.list[index - 1].kind == REF_DETACHED_HEAD) &&
>> +         !strcmp(ref_list.list[index - 1].name, head)) {
>> +             print_ref_item(&ref_list.list[index - 1], maxwidth, verbose, abbrev,
>> +                            1, remote_prefix);
>> +             index -= 1;
>> +     }
>>
>> +     qsort(ref_list.list, index, sizeof(struct ref_item), ref_cmp);
>
> This looks somewhat strange.  Wouldn't it be more consistent to
> teach ref_cmp that HEAD sorts where in the collection of refs (I
> presume that kind is checked first and then name, so if you give
> REF_DETACHED_HEAD a low number than others, it would automatically
> give you the ordering you want) without all of the above special
> casing?

Thats nice, we could do that, something like this perhaps:

    qsort(ref_list.list, ref_list.index, sizeof(struct ref_item), ref_cmp);

    for (i = 0; i < ref_list.index; i++) {
        int current = !detached && (ref_list.list[i].kind ==
REF_LOCAL_BRANCH) &&
            !strcmp(ref_list.list[i].name, head);
        /*  If detached the first ref_item is the current ref */
        if (detached && i == 0)
            current = 1;
        print_ref_item(&ref_list.list[i], maxwidth, verbose,
                   abbrev, current, remote_prefix);
    }

-- 
Regards,
Karthik Nayak

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v4 3/8] branch: roll show_detached HEAD into regular ref_list
  2015-09-16  6:23     ` Karthik Nayak
@ 2015-09-17  9:47       ` Karthik Nayak
  2015-09-17 14:18         ` Matthieu Moy
  0 siblings, 1 reply; 38+ messages in thread
From: Karthik Nayak @ 2015-09-17  9:47 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Git, Christian Couder, Matthieu Moy

On Wed, Sep 16, 2015 at 11:53 AM, Karthik Nayak <karthik.188@gmail.com> wrote:
> On Tue, Sep 15, 2015 at 1:05 AM, Junio C Hamano <gitster@pobox.com> wrote:
>> Karthik Nayak <karthik.188@gmail.com> writes:
>>
>>> +     /*
>>> +      * First we obtain all regular branch refs and if the HEAD is
>>> +      * detached then we insert that ref to the end of the ref_fist
>>> +      * so that it can be printed and removed first.
>>> +      */
>>>       for_each_rawref(append_ref, &cb);
>>> +     if (detached)
>>> +             head_ref(append_ref, &cb);
>>> +     index = ref_list.index;
>>> +
>>> +     /* Print detached HEAD before sorting and printing the rest */
>>> +     if (detached && (ref_list.list[index - 1].kind == REF_DETACHED_HEAD) &&
>>> +         !strcmp(ref_list.list[index - 1].name, head)) {
>>> +             print_ref_item(&ref_list.list[index - 1], maxwidth, verbose, abbrev,
>>> +                            1, remote_prefix);
>>> +             index -= 1;
>>> +     }
>>>
>>> +     qsort(ref_list.list, index, sizeof(struct ref_item), ref_cmp);
>>
>> This looks somewhat strange.  Wouldn't it be more consistent to
>> teach ref_cmp that HEAD sorts where in the collection of refs (I
>> presume that kind is checked first and then name, so if you give
>> REF_DETACHED_HEAD a low number than others, it would automatically
>> give you the ordering you want) without all of the above special
>> casing?
>
> Thats nice, we could do that, something like this perhaps:
>
>     qsort(ref_list.list, ref_list.index, sizeof(struct ref_item), ref_cmp);
>
>     for (i = 0; i < ref_list.index; i++) {
>         int current = !detached && (ref_list.list[i].kind ==
> REF_LOCAL_BRANCH) &&
>             !strcmp(ref_list.list[i].name, head);
>         /*  If detached the first ref_item is the current ref */
>         if (detached && i == 0)
>             current = 1;
>         print_ref_item(&ref_list.list[i], maxwidth, verbose,
>                    abbrev, current, remote_prefix);
>     }
>

Although this solves the problem here, we'd still need to do something
similar when we use ref-filter APIs as in [PATCH 7/8].

So either we could introduce a new atom for sorting something like
`branch_sort` which uses the FILTER_REFS_(DETACHED_HEAD | BRANCHES | REMOTES)
to sort or we could sort after printing the detached head, as done in
this series.
I'm ok with either.

-- 
Regards,
Karthik Nayak

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v4 3/8] branch: roll show_detached HEAD into regular ref_list
  2015-09-17  9:47       ` Karthik Nayak
@ 2015-09-17 14:18         ` Matthieu Moy
  2015-09-17 15:15           ` Junio C Hamano
  0 siblings, 1 reply; 38+ messages in thread
From: Matthieu Moy @ 2015-09-17 14:18 UTC (permalink / raw)
  To: Karthik Nayak; +Cc: Junio C Hamano, Git, Christian Couder

Karthik Nayak <karthik.188@gmail.com> writes:

> So either we could introduce a new atom for sorting something like
> `branch_sort` which uses the FILTER_REFS_(DETACHED_HEAD | BRANCHES |
> REMOTES)

I don't think you need a new atom. You can just change the sorting
function to consider that detached HEAD is always first, and when
comparing two non-detached-HEAD branches, use the atom supplied by the
user.

That would mean the detached HEAD would be displayed first regardless of
--sort (which is the case right now).

Introducing a new atom would mean that "git branch --sort authorname"
would not use this new atom, hence the HEAD would be sorted like the
others. I don't know if this is good or bad.

-- 
Matthieu Moy
http://www-verimag.imag.fr/~moy/

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v4 3/8] branch: roll show_detached HEAD into regular ref_list
  2015-09-17 14:18         ` Matthieu Moy
@ 2015-09-17 15:15           ` Junio C Hamano
  2015-09-17 15:43             ` Matthieu Moy
  0 siblings, 1 reply; 38+ messages in thread
From: Junio C Hamano @ 2015-09-17 15:15 UTC (permalink / raw)
  To: Matthieu Moy; +Cc: Karthik Nayak, Git, Christian Couder

Matthieu Moy <Matthieu.Moy@grenoble-inp.fr> writes:

> Karthik Nayak <karthik.188@gmail.com> writes:
>
>> So either we could introduce a new atom for sorting something like
>> `branch_sort` which uses the FILTER_REFS_(DETACHED_HEAD | BRANCHES |
>> REMOTES)
>
> I don't think you need a new atom. You can just change the sorting
> function to consider that detached HEAD is always first, and when
> comparing two non-detached-HEAD branches, use the atom supplied by the
> user.
>
> That would mean the detached HEAD would be displayed first regardless of
> --sort (which is the case right now).

I am a bit fuzzy about this.  I do not understand why Karthik thinks
a new atom is necessary in the first place, and I do agree that the
best way to go would be to teach the sort function to do "the right
thing", but I am not sure why it has to be "regardless of --sort".

In the original for-each-ref (before it was butchered^W updated with
ref-filter), we grab refs and sort with default_sort() when "--sort"
is not given.  When --sort is given, we just use atoms to compare.

I do not think ref-filter broke that pattern, and as long as it kept
that pattern, I do not think the solution has to be more than just
"teach that default_sort() function, which sorts by refname, to
always show HEAD first".  When you throw HEAD into the mix, instead
of grabbing only from refs/*, you can still give that set to a
sorting function, which by default puts "HEAD" before others (just
like the sorting function for "branch -a" by default puts local
before remote-tracking), and you are done, no?

When the user does give a custom --sort criteria, the logic in
default_sort() would not kick in, so there is no need for special
casing for "HEAD" like the code I questioned in this thread.

What am I missing?

> Introducing a new atom would mean that "git branch --sort authorname"
> would not use this new atom, hence the HEAD would be sorted like the
> others.

I think that is exactly what people would expect.

Perhaps a slightly tricky would be "git branch -a --sort refname".
If you have HEAD, refs/heads/master, and refs/remotes/origin/master,
I'd expect that it would sort these in that order purely because
that is the textual/ascii sort order of the FULL refname.

And then at the presentation level you would strip refs/heads and
refs/remotes from local and remote-tracking branches, just like "git
branch -a" output has always done, from the sorted result when
showing.

"git branch -a --sort refname:short" would sort using HEAD vs master
vs origin/master in the above example and would end up mixing loal
and remote-tracking together, but that is what the user is asking
for, and the user deserves to get what s/he asked for.

Somewhat confused....

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v4 3/8] branch: roll show_detached HEAD into regular ref_list
  2015-09-17 15:15           ` Junio C Hamano
@ 2015-09-17 15:43             ` Matthieu Moy
  2015-09-17 16:49               ` Junio C Hamano
  0 siblings, 1 reply; 38+ messages in thread
From: Matthieu Moy @ 2015-09-17 15:43 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Karthik Nayak, Git, Christian Couder

Junio C Hamano <gitster@pobox.com> writes:

> Matthieu Moy <Matthieu.Moy@grenoble-inp.fr> writes:
>
>> Karthik Nayak <karthik.188@gmail.com> writes:
>>
>>> So either we could introduce a new atom for sorting something like
>>> `branch_sort` which uses the FILTER_REFS_(DETACHED_HEAD | BRANCHES |
>>> REMOTES)
>>
>> I don't think you need a new atom. You can just change the sorting
>> function to consider that detached HEAD is always first, and when
>> comparing two non-detached-HEAD branches, use the atom supplied by the
>> user.
>>
>> That would mean the detached HEAD would be displayed first regardless of
>> --sort (which is the case right now).
>
> I am a bit fuzzy about this.  I do not understand why Karthik thinks
> a new atom is necessary in the first place, and I do agree that the
> best way to go would be to teach the sort function to do "the right
> thing", but I am not sure why it has to be "regardless of --sort".

I think Karthik meant that branch could default to
"--sort=my_magic_atom_that_does_the_right_thing". In this case, the
default would be to show HEAD first, but using "--sort" explicitly would
change the order and interleave HEAD within other branches.

IOW, we have:

struct ref_sorting *ref_default_sorting(void)
{
	static const char cstr_name[] = "refname";

	struct ref_sorting *sorting = xcalloc(1, sizeof(*sorting));

	sorting->next = NULL;
	sorting->atom = parse_ref_filter_atom(cstr_name, cstr_name + strlen(cstr_name));
	return sorting;
}

and we could

-	static const char cstr_name[] = "refname";
+	static const char cstr_name[] = "some_magic_atom";

But you convinced me that this is not a good idea.

> When the user does give a custom --sort criteria, the logic in
> default_sort()

The logic itself is not in ref_default_sorting() (I guess this is what
you meant by "default_sort"): this function just builds a struct
ref_sorting that is later used by the more general cmp_ref_sorting.

But that's still workable: struct ref_sorting could contain a flag
"head_first" that would be set by ref_default_sorting() and only it, and
then read by cmp_ref_sorting.

-- 
Matthieu Moy
http://www-verimag.imag.fr/~moy/

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v4 3/8] branch: roll show_detached HEAD into regular ref_list
  2015-09-17 15:43             ` Matthieu Moy
@ 2015-09-17 16:49               ` Junio C Hamano
  2015-09-17 17:08                 ` Matthieu Moy
  0 siblings, 1 reply; 38+ messages in thread
From: Junio C Hamano @ 2015-09-17 16:49 UTC (permalink / raw)
  To: Matthieu Moy; +Cc: Karthik Nayak, Git, Christian Couder

Matthieu Moy <Matthieu.Moy@grenoble-inp.fr> writes:

> But that's still workable: struct ref_sorting could contain a flag
> "head_first" that would be set by ref_default_sorting() and only it, and
> then read by cmp_ref_sorting.

Hmm, I am still puzzled.  "refname" atom would expand to things like
"HEAD", "refs/heads/master", etc., so I still do not see a need for
head_first option at all.  "HEAD" will sort before "refs/anything"
always, no?

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v4 3/8] branch: roll show_detached HEAD into regular ref_list
  2015-09-17 16:49               ` Junio C Hamano
@ 2015-09-17 17:08                 ` Matthieu Moy
  2015-09-17 17:21                   ` Junio C Hamano
  2015-09-17 18:25                   ` Karthik Nayak
  0 siblings, 2 replies; 38+ messages in thread
From: Matthieu Moy @ 2015-09-17 17:08 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Karthik Nayak, Git, Christian Couder

Junio C Hamano <gitster@pobox.com> writes:

> Matthieu Moy <Matthieu.Moy@grenoble-inp.fr> writes:
>
>> But that's still workable: struct ref_sorting could contain a flag
>> "head_first" that would be set by ref_default_sorting() and only it, and
>> then read by cmp_ref_sorting.
>
> Hmm, I am still puzzled.  "refname" atom would expand to things like
> "HEAD", "refs/heads/master", etc., so I still do not see a need for
> head_first option at all.  "HEAD" will sort before "refs/anything"
> always, no?

Ah, you mean, the alphabetic order on refname already sorts HEAD first
because other refs will start with "refs/"? So, there's no need for any
special case at all indeed. Nothing to teach compare_refs, it's already
doing it.

However, just relying on this seems a bit fragile to me: if we ever
allow listing e.g. FETCH_HEAD as a reference, then we would get

  FETCH_HEAD
* (HEAD detached at ...)
  master

which seems weird to me. But we can decide "if sorting on refname, then
HEAD always comes first anyway".

-- 
Matthieu Moy
http://www-verimag.imag.fr/~moy/

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v4 3/8] branch: roll show_detached HEAD into regular ref_list
  2015-09-17 17:08                 ` Matthieu Moy
@ 2015-09-17 17:21                   ` Junio C Hamano
  2015-09-17 18:25                   ` Karthik Nayak
  1 sibling, 0 replies; 38+ messages in thread
From: Junio C Hamano @ 2015-09-17 17:21 UTC (permalink / raw)
  To: Matthieu Moy; +Cc: Karthik Nayak, Git, Christian Couder

Matthieu Moy <Matthieu.Moy@grenoble-inp.fr> writes:

> ... But we can decide "if sorting on refname, then
> HEAD always comes first anyway".

Sure.

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v4 3/8] branch: roll show_detached HEAD into regular ref_list
  2015-09-17 17:08                 ` Matthieu Moy
  2015-09-17 17:21                   ` Junio C Hamano
@ 2015-09-17 18:25                   ` Karthik Nayak
  1 sibling, 0 replies; 38+ messages in thread
From: Karthik Nayak @ 2015-09-17 18:25 UTC (permalink / raw)
  To: Matthieu Moy; +Cc: Junio C Hamano, Git, Christian Couder

On Thu, Sep 17, 2015 at 10:38 PM, Matthieu Moy
<Matthieu.Moy@grenoble-inp.fr> wrote:
> Junio C Hamano <gitster@pobox.com> writes:
>
>> Matthieu Moy <Matthieu.Moy@grenoble-inp.fr> writes:
>>
>>> But that's still workable: struct ref_sorting could contain a flag
>>> "head_first" that would be set by ref_default_sorting() and only it, and
>>> then read by cmp_ref_sorting.
>>
>> Hmm, I am still puzzled.  "refname" atom would expand to things like
>> "HEAD", "refs/heads/master", etc., so I still do not see a need for
>> head_first option at all.  "HEAD" will sort before "refs/anything"
>> always, no?
>
> Ah, you mean, the alphabetic order on refname already sorts HEAD first
> because other refs will start with "refs/"? So, there's no need for any
> special case at all indeed. Nothing to teach compare_refs, it's already
> doing it.
>
> However, just relying on this seems a bit fragile to me: if we ever
> allow listing e.g. FETCH_HEAD as a reference, then we would get
>
>   FETCH_HEAD
> * (HEAD detached at ...)
>   master
>
> which seems weird to me. But we can decide "if sorting on refname, then
> HEAD always comes first anyway".

Thanks for explaining what I had in mind, Seems like the confusion is sorted,
I have nothing more to add to this discussion. Junio is right, sorting
by "refname"
would indeed work, I was just thinking along the lines of what you're ;)

-- 
Regards,
Karthik Nayak

^ permalink raw reply	[flat|nested] 38+ messages in thread

end of thread, other threads:[~2015-09-17 18:26 UTC | newest]

Thread overview: 38+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-09-13  7:23 [PATCH v4 0/8] port the filtering part of branch.c to use ref-filter APIs Karthik Nayak
2015-09-13  7:23 ` [PATCH v4 1/8] branch: refactor width computation Karthik Nayak
2015-09-13 11:51   ` Matthieu Moy
2015-09-13 12:23     ` Karthik Nayak
2015-09-13 12:33       ` Matthieu Moy
2015-09-13  7:23 ` [PATCH v4 2/8] branch: bump get_head_description() to the top Karthik Nayak
2015-09-13  7:23 ` [PATCH v4 3/8] branch: roll show_detached HEAD into regular ref_list Karthik Nayak
2015-09-13 12:12   ` Matthieu Moy
2015-09-13 13:24     ` Karthik Nayak
2015-09-13 16:46     ` Eric Sunshine
2015-09-13 18:31       ` Eric Sunshine
2015-09-14 14:48         ` Karthik Nayak
2015-09-14 14:54           ` Matthieu Moy
2015-09-14 19:35   ` Junio C Hamano
2015-09-16  6:23     ` Karthik Nayak
2015-09-17  9:47       ` Karthik Nayak
2015-09-17 14:18         ` Matthieu Moy
2015-09-17 15:15           ` Junio C Hamano
2015-09-17 15:43             ` Matthieu Moy
2015-09-17 16:49               ` Junio C Hamano
2015-09-17 17:08                 ` Matthieu Moy
2015-09-17 17:21                   ` Junio C Hamano
2015-09-17 18:25                   ` Karthik Nayak
2015-09-13  7:23 ` [PATCH v4 4/8] branch: move 'current' check down to the presentation layer Karthik Nayak
2015-09-13 12:15   ` Matthieu Moy
2015-09-13 13:22     ` Karthik Nayak
2015-09-13 15:35   ` Karthik Nayak
2015-09-13  7:23 ` [PATCH v4 5/8] branch: drop non-commit error reporting Karthik Nayak
2015-09-14 19:49   ` Junio C Hamano
2015-09-16  6:04     ` Karthik Nayak
2015-09-13  7:23 ` [PATCH v4 6/8] branch.c: use 'ref-filter' data structures Karthik Nayak
2015-09-13 12:26   ` Matthieu Moy
2015-09-13 13:19     ` Karthik Nayak
2015-09-13 17:49       ` Matthieu Moy
2015-09-13  7:23 ` Karthik Nayak
2015-09-13  7:32   ` Karthik Nayak
2015-09-13  7:23 ` [PATCH v4 8/8] branch: add '--points-at' option Karthik Nayak
2015-09-13  7:29 ` [PATCH v4 7/8] branch.c: use 'ref-filter' APIs Karthik Nayak

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.