[PATCH] git-blame: Make the output human readable

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

 



The default output mode is slightly different from git-annotate's.
However, git-annotate's output mode can be obtained by using the
'-c' flag.

Signed-off-by: Fredrik Kuivinen <freku045@xxxxxxxxxxxxxx>


---

 Makefile |    4 ++
 blame.c  |  164 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
 2 files changed, 149 insertions(+), 19 deletions(-)

3459b7c5032d1462d5857cf6afc2d3e3ef61b93b
diff --git a/Makefile b/Makefile
index b6d8804..eb1887d 100644
--- a/Makefile
+++ b/Makefile
@@ -534,6 +534,10 @@ git-rev-list$X: rev-list.o $(LIB_FILE)
 	$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
 		$(LIBS) $(OPENSSL_LIBSSL)
 
+git-blame$X: blame.o $(LIB_FILE)
+	$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
+		$(LIBS) -lm
+
 init-db.o: init-db.c
 	$(CC) -c $(ALL_CFLAGS) \
 		-DDEFAULT_GIT_TEMPLATE_DIR='"$(template_dir_SQ)"' $*.c
diff --git a/blame.c b/blame.c
index 7308c36..6dccae5 100644
--- a/blame.c
+++ b/blame.c
@@ -5,6 +5,7 @@
 #include <assert.h>
 #include <time.h>
 #include <sys/time.h>
+#include <math.h>
 
 #include "cache.h"
 #include "refs.h"
@@ -17,8 +18,15 @@
 
 #define DEBUG 0
 
-struct commit **blame_lines;
-int num_blame_lines;
+static const char blame_usage[] = "[-c] [-l] [--] file [commit]\n"
+	"  -c, --compability Use the same output mode as git-annotate (Default: off)\n"
+	"  -l, --long        Show long commit SHA1 (Default: off)\n"
+	"  -h, --help        This message";
+
+static struct commit **blame_lines;
+static int num_blame_lines;
+static char* blame_contents;
+static int blame_len;
 
 struct util_info {
 	int *line_map;
@@ -388,9 +396,8 @@ static void init_first_commit(struct com
 	alloc_line_map(commit);
 
 	util = commit->object.util;
-	num_blame_lines = util->num_lines;
 
-	for (i = 0; i < num_blame_lines; i++)
+	for (i = 0; i < util->num_lines; i++)
 		util->line_map[i] = i;
 }
 
@@ -412,6 +419,9 @@ static void process_commits(struct rev_i
 	util = commit->object.util;
 	num_blame_lines = util->num_lines;
 	blame_lines = xmalloc(sizeof(struct commit *) * num_blame_lines);
+	blame_contents = util->buf;
+	blame_len = util->size;
+
 	for (i = 0; i < num_blame_lines; i++)
 		blame_lines[i] = NULL;
 
@@ -499,32 +509,128 @@ static void process_commits(struct rev_i
 	} while ((commit = get_revision(rev)) != NULL);
 }
 
+struct commit_info
+{
+	char* author;
+	char* author_mail;
+	unsigned long author_time;
+	char* author_tz;
+};
+
+static void get_commit_info(struct commit* commit, struct commit_info* ret)
+{
+	int len;
+	char* tmp;
+	static char author_buf[1024];
+
+	tmp = strstr(commit->buffer, "\nauthor ") + 8;
+	len = index(tmp, '\n') - tmp;
+	ret->author = author_buf;
+	memcpy(ret->author, tmp, len);
+
+	tmp = ret->author;
+	tmp += len;
+	*tmp = 0;
+	while(*tmp != ' ')
+		tmp--;
+	ret->author_tz = tmp+1;
+
+	*tmp = 0;
+	while(*tmp != ' ')
+		tmp--;
+	ret->author_time = strtoul(tmp, NULL, 10);
+
+	*tmp = 0;
+	while(*tmp != ' ')
+		tmp--;
+	ret->author_mail = tmp + 1;
+
+	*tmp = 0;
+}
+
+char* format_time(unsigned long time, const char* tz)
+{
+	static char time_buf[128];
+	time_t t = time;
+
+	strftime(time_buf, sizeof(time_buf), "%Y-%m-%d %H:%M:%S ", gmtime(&t));
+	strcat(time_buf, tz);
+	return time_buf;
+}
+
 int main(int argc, const char **argv)
 {
 	int i;
 	struct commit *initial = NULL;
 	unsigned char sha1[20];
-	const char* filename;
+
+	const char *filename = NULL, *commit = NULL;
+	char filename_buf[256];
+	int sha1_len = 8;
+	int compability = 0;
+	int options = 1;
+
 	int num_args;
 	const char* args[10];
 	struct rev_info rev;
 
-	setup_git_directory();
-
-	if (argc != 3)
-		die("Usage: blame commit-ish file");
+	struct commit_info ci;
+	const char *buf;
+	int max_digits;
+
+	const char* prefix = setup_git_directory();
+
+	for(i = 1; i < argc; i++) {
+		if(options) {
+			if(!strcmp(argv[i], "-h") ||
+			   !strcmp(argv[i], "--help"))
+				usage(blame_usage);
+			else if(!strcmp(argv[i], "-l") ||
+				!strcmp(argv[i], "--long")) {
+				sha1_len = 20;
+				continue;
+			} else if(!strcmp(argv[i], "-c") ||
+				  !strcmp(argv[i], "--compability")) {
+				compability = 1;
+				continue;
+			} else if(!strcmp(argv[i], "--")) {
+				options = 0;
+				continue;
+			} else if(argv[i][0] == '-')
+				usage(blame_usage);
+			else
+				options = 0;
+		}
 
+		if(!options) {
+			if(!filename)
+				filename = argv[i];
+			else if(!commit)
+				commit = argv[i];
+			else
+				usage(blame_usage);
+		}
+	}
 
-	filename = argv[2];
+	if(!filename)
+		usage(blame_usage);
+	if(!commit)
+		commit = "HEAD";
+
+	if(prefix)
+		sprintf(filename_buf, "%s%s", prefix, filename);
+	else
+		strcpy(filename_buf, filename);
+	filename = filename_buf;
 
 	{
-		struct commit* commit;
-		if (get_sha1(argv[1], sha1))
-			die("get_sha1 failed");
-		commit = lookup_commit_reference(sha1);
+		struct commit* c;
+		if (get_sha1(commit, sha1))
+			die("get_sha1 failed, commit '%s' not found", commit);
+		c = lookup_commit_reference(sha1);
 
-		if (fill_util_info(commit, filename)) {
-			printf("%s not found in %s\n", filename, argv[1]);
+		if (fill_util_info(c, filename)) {
+			printf("%s not found in %s\n", filename, commit);
 			return 1;
 		}
 	}
@@ -533,7 +639,7 @@ int main(int argc, const char **argv)
 	args[num_args++] = NULL;
 	args[num_args++] = "--topo-order";
 	args[num_args++] = "--remove-empty";
-	args[num_args++] = argv[1];
+	args[num_args++] = commit;
 	args[num_args++] = "--";
 	args[num_args++] = filename;
 	args[num_args] = NULL;
@@ -542,13 +648,33 @@ int main(int argc, const char **argv)
 	prepare_revision_walk(&rev);
 	process_commits(&rev, filename, &initial);
 
+	buf = blame_contents;
+	max_digits = 1 + log(num_blame_lines+1)/log(10);
 	for (i = 0; i < num_blame_lines; i++) {
 		struct commit *c = blame_lines[i];
 		if (!c)
 			c = initial;
 
-		printf("%d %.8s\n", i, sha1_to_hex(c->object.sha1));
-// printf("%d %s\n", i, find_unique_abbrev(blame_lines[i]->object.sha1, 6));
+		get_commit_info(c, &ci);
+		fwrite(sha1_to_hex(c->object.sha1), sha1_len, 1, stdout);
+		if(compability)
+			printf("\t(%10s\t%10s\t%d)", ci.author,
+			       format_time(ci.author_time, ci.author_tz), i+1);
+		else
+			printf(" (%-15.15s %10s %*d) ", ci.author,
+			       format_time(ci.author_time, ci.author_tz),
+			       max_digits, i+1);
+
+		if(i == num_blame_lines - 1) {
+			fwrite(buf, blame_len - (buf - blame_contents),
+			       1, stdout);
+			if(blame_contents[blame_len-1] != '\n')
+				putc('\n', stdout);
+		} else {
+			char* next_buf = index(buf, '\n') + 1;
+			fwrite(buf, next_buf - buf, 1, stdout);
+			buf = next_buf;
+		}
 	}
 
 	if (DEBUG) {
-- 
1.2.4.g4644-dirty

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

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