[PATCH] git-name-rev: accept list of refs from user

From: Jeff King <peff@peff.net>
Date: 2007-02-18 10:13:28
This lets you do things like

  git show-ref | grep /v1 | git name-rev --refs-from=- $commit

or even

  git show-ref | ./some_complex_ref_filter >refs
  git name-rev --refs-from=refs --stdin <list_of_commits

Signed-off-by: Jeff King <peff@peff.net>
---
On Sat, Feb 17, 2007 at 10:25:00AM -0800, Junio C Hamano wrote:
>> git show-ref | grep tags/v1.4 | git name-rev --stdin-refs 33db5f4d
> FWIW, I like that.

Here it is (I chose --refs-from= so you could use it with the existing
--stdin flag). We might want to do the same for git-describe, I would
think (they can probably share the for_each_ref_from_file code).

The input format is "sha1 ref"; clearly it could also accept just "ref",
and look up the sha1, but I expect most people will just be piping from
git-show-ref anyway.

 Documentation/git-name-rev.txt |   16 +++++++++++-
 builtin-name-rev.c             |   54 ++++++++++++++++++++++++++++++++++++++-
 2 files changed, 67 insertions(+), 3 deletions(-)

diff --git a/Documentation/git-name-rev.txt b/Documentation/git-name-rev.txt
index 37fbf66..d2fb3bb 100644
--- a/Documentation/git-name-rev.txt
+++ b/Documentation/git-name-rev.txt
@@ -8,7 +8,7 @@ git-name-rev - Find symbolic names for given revs
 
 SYNOPSIS
 --------
-'git-name-rev' [--tags] ( --all | --stdin | <committish>... )
+'git-name-rev' [--tags] [--refs-from=<file>] ( --all | --stdin | <committish>... )
 
 DESCRIPTION
 -----------
@@ -22,6 +22,13 @@ OPTIONS
 --tags::
 	Do not use branch names, but only tags to name the commits
 
+--refs-from=<file>::
+	Instead of choosing a name based on all refs, read refs from <file>,
+	one per line, in the form "sha1 ref". This is the same as the
+	default output generated by "git show-ref". If <file> is "-",
+	read from stdin. The --tags option is still respected when using
+	--refs-from.
+
 --all::
 	List all commits reachable from all refs
 
@@ -52,6 +59,13 @@ Another nice thing you can do is:
 % git log | git name-rev --stdin
 ------------
 
+You can filter the commits used to describe a commit using the --refs-from
+option:
+
+------------
+% git show-ref | grep tags/v1 | git name-rev --refs-from=- 26cfcfbf
+------------
+
 
 Author
 ------
diff --git a/builtin-name-rev.c b/builtin-name-rev.c
index b4f15cc..c8480d2 100644
--- a/builtin-name-rev.c
+++ b/builtin-name-rev.c
@@ -5,7 +5,7 @@
 #include "refs.h"
 
 static const char name_rev_usage[] =
-	"git-name-rev [--tags] ( --all | --stdin | committish [committish...] )\n";
+"git-name-rev [--tags] [--refs-from=<file>] ( --all | --stdin | committish ... )";
 
 typedef struct rev_name {
 	const char *tip_name;
@@ -14,6 +14,7 @@ typedef struct rev_name {
 } rev_name;
 
 static long cutoff = LONG_MAX;
+static const char *refs_from = NULL;
 
 static void name_rev(struct commit *commit,
 		const char *tip_name, int merge_traversals, int generation,
@@ -103,6 +104,46 @@ static int name_ref(const char *path, const unsigned char *sha1, int flags, void
 	return 0;
 }
 
+static void trim_trailing_whitespace(char *buf)
+{
+	int i = strlen(buf) - 1;
+	while(i >= 0 && isspace(buf[i]))
+		buf[i--] = '\0';
+}
+
+static void for_each_ref_from_file(const char *filename, each_ref_fn fn, void *data)
+{
+	FILE *fh;
+	char buf[PATH_MAX + 40 + 3]; /* "PATH SHA1\n\0" */
+	unsigned char sha1[20];
+
+	if (!strcmp(filename, "-"))
+		fh = stdin;
+	else {
+		fh = fopen(filename, "r");
+		if (!fh)
+			die("unable to open %s: %s", filename, strerror(errno));
+	}
+
+	while (fgets(buf, sizeof buf, fh)) {
+		char *name;
+
+		trim_trailing_whitespace(buf);
+
+		name = strchr(buf, ' ');
+		if (!name)
+			die("invalid input ref format: %s\n", buf);
+		*name++ = '\0';
+
+		if (get_sha1_hex(buf, sha1) < 0)
+			die("invalid sha1: %s\n", buf);
+
+		name_ref(name, sha1, 0, data);
+	}
+
+	fclose(fh);
+}
+
 /* returns a static buffer */
 static const char* get_rev_name(struct object *o)
 {
@@ -160,6 +201,9 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix)
 				transform_stdin = 1;
 				cutoff = 0;
 				continue;
+			} else if (!strncmp(*argv, "--refs-from=", 12)) {
+				refs_from = (*argv)+12;
+				continue;
 			}
 			usage(name_rev_usage);
 		}
@@ -185,7 +229,13 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix)
 		add_object_array((struct object *)commit, *argv, &revs);
 	}
 
-	for_each_ref(name_ref, &tags_only);
+	if (refs_from && !strcmp(refs_from, "-") && transform_stdin)
+		die("--refs-from=- and --stdin are incompatible!");
+
+	if (refs_from)
+		for_each_ref_from_file(refs_from, name_ref, &tags_only);
+	else
+		for_each_ref(name_ref, &tags_only);
 
 	if (transform_stdin) {
 		char buffer[2048];
-- 
1.5.0.552.ge1b1c-dirty
-
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Received on Sun Feb 18 10:13:45 2007

This archive was generated by hypermail 2.1.8 : 2007-02-18 10:15:42 EST