git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH 08/15] git-note: (Decorations) Add note decorations to "git-{log,show,whatchanged} --decorate"

From
Johan Herland <johan@herland.net>
Date
May 27, 2007, 14:14 UTC
Message-ID
<200705271614.01462.johan@herland.net>
In-Reply-To
<200705271608.02122.johan@herland.net>

Introduce the concept of note decorations (supplementing the existing name decorations), and teach the code handling the --decorate option how to display note decorations.

The result is that notes are displayed below the commit message for
these commands:
- git-log --decorate
- git-show --decorate
- git-whatchanged --decorate
Signed-off-by: Johan Herland <johan@herland.net>
---
 builtin-log.c |  108 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 commit.h      |    7 ++++
 log-tree.c    |   67 +++++++++++++++++++++++++++++++++--
 3 files changed, 178 insertions(+), 4 deletions(-)
diff --git a/builtin-log.c b/builtin-log.c
index 3744712..ee10f2a 100644
--- a/builtin-log.c
+++ b/builtin-log.c
@@ -20,6 +20,108 @@ static int default_show_root = 1;
 /* this is in builtin-diff.c */
 void add_head(struct rev_info *revs);
 
+static int get_note_decoration_data(const char *data, unsigned long data_len, const char **author, unsigned long *author_len, const char **date, unsigned long *date_len, const char **msg, unsigned long *msg_len)
+{
+	/*
+	 * Set author, date and msg pointers to their appropriate positions
+	 * within the given data buffer (tag object data). Also set the
+	 * appropriate lengths, respectively.
+	 */
+	const char *p, *q, *end = data + data_len;
+	if (!data || !data_len)
+		return 1;
+	p = data;
+	end = data + data_len;
+	do {
+		if (end - p >= 7 && !memcmp("tagger ", p, 7)) {
+			*author = p + 7;
+			if ((q = memchr(*author, '>', end - *author))) {
+				*author_len = ++q - *author;
+				*date = ++q;
+				q = memchr(*date, '\n', end - *date);
+				*date_len = q ? q - *date : 0;
+			}
+			else if ((q = memchr(*author, '\n', end - *author)))
+				*author_len = q - *author;
+			else
+				*author_len = 0;
+		}
+		else if (end - p >= 1 && !memcmp("\n", p, 1)) {
+			*msg = ++p;
+			*msg_len = end - *msg;
+			break;
+		}
+		p = memchr(p, '\n', end - p);
+	} while (p++);
+	return 0;
+}
+
+static int add_note_decoration(const char *refname, const unsigned char *sha1, int flags, void *cb_data)
+{
+	struct object *obj;
+	struct tag *note;
+	struct note_decoration *res;
+	enum object_type data_type;
+	char *data;
+	const char   *author = "",   *date = "",   *msg = "";
+	unsigned long author_len = 0, date_len = 0, msg_len = 0;
+	unsigned long note_len, data_len;
+	unsigned long time = 0;
+
+	/* Get object pointed to by note */
+	obj = parse_object(sha1);
+	if (!obj)
+		return 0;
+	if (obj->type != OBJ_TAG)
+		return 0;
+
+	note = (struct tag *)obj;
+	obj = note->tagged;
+	if (!obj)
+		return 0;
+
+	/* Generate note decoration from note data */
+	data = read_sha1_file(note->object.sha1, &data_type, &data_len);
+	if (!data || !data_len)
+		return 0;
+	if (data_type != OBJ_TAG) {
+		free(data);
+		return 0; /* should not happen */
+	}
+
+	if (get_note_decoration_data(data,  data_len,
+			&author, &author_len, &date, &date_len, &msg, &msg_len))
+	{
+		free(data);
+		return 0; /* should not happen */
+	}
+	if (date && *date && date_len) { /* Found date; prettify it */
+		char *tz_p, *end;
+		int tz;
+		time = strtoul(date, &tz_p, 10);
+		tz = strtol(tz_p, &end, 10);
+		if (end - date > date_len) {
+			free(data);
+			return 0; /* overflowed; should not happen */
+		}
+		date = show_date(time, tz, DATE_NORMAL);
+		date_len = strlen(date);
+	}
+	note_len = 10 + author_len + date_len + msg_len;
+	res = xmalloc(sizeof(struct note_decoration) + note_len);
+	snprintf(res->note, note_len + 1, "\n--- by %.*s %.*s\n%.*s",
+			(int) author_len, author,
+			(int)   date_len,   date,
+			(int)    msg_len,    msg);
+	res->sort_hint = time;
+
+	/* Add note decoration to object that note points to */
+	res->next = add_decoration(&note_decoration, obj, res);
+
+	free(data);
+	return 0;
+}
+
 static void add_name_decoration(const char *prefix, const char *name, struct object *obj)
 {
 	int plen = strlen(prefix);
@@ -35,6 +137,8 @@ static int add_ref_decoration(const char *refname, const unsigned char *sha1, in
 	struct object *obj = parse_object(sha1);
 	if (!obj)
 		return 0;
+	if (!prefixcmp(refname, "refs/notes/"))
+		return 0; /* notes shouldn't show up here */
 	add_name_decoration("", refname, obj);
 	while (obj->type == OBJ_TAG) {
 		obj = ((struct tag *)obj)->tagged;
@@ -67,8 +171,10 @@ static void cmd_log_init(int argc, const char **argv, const char *prefix,
 			else
 				git_log_output_encoding = "";
 		} else if (!strcmp(arg, "--decorate")) {
-			if (!decorate)
+			if (!decorate) {
 				for_each_ref(add_ref_decoration, NULL);
+				for_each_note_ref(add_note_decoration, NULL);
+			}
 			decorate = 1;
 		} else
 			die("unrecognized argument: %s", arg);
diff --git a/commit.h b/commit.h
index 86e8dca..93cac79 100644
--- a/commit.h
+++ b/commit.h
@@ -28,6 +28,13 @@ struct name_decoration {
 	struct name_decoration *next;
 	char name[1];
 };
+/* While we can decorate any object with a note, it's only used for commits.. */
+extern struct decoration note_decoration;
+struct note_decoration {
+	struct note_decoration *next;
+	unsigned long sort_hint;
+	char note[1];
+};
 
 struct commit *lookup_commit(const unsigned char *sha1);
 struct commit *lookup_commit_reference(const unsigned char *sha1);
diff --git a/log-tree.c b/log-tree.c
index 4bef909..dccaca2 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -5,6 +5,7 @@
 #include "reflog-walk.h"
 
 struct decoration name_decoration = { "object names" };
+struct decoration note_decoration = { "object notes" };
 
 static void show_parents(struct commit *commit, int abbrev)
 {
@@ -15,7 +16,7 @@ static void show_parents(struct commit *commit, int abbrev)
 	}
 }
 
-static void show_decorations(struct commit *commit)
+static void show_name_decorations(struct commit *commit)
 {
 	const char *prefix;
 	struct name_decoration *decoration;
@@ -32,6 +33,65 @@ static void show_decorations(struct commit *commit)
 	putchar(')');
 }
 
+static int compare_note_decorations(const void *a, const void *b)
+{
+	const struct note_decoration *na = *((const struct note_decoration **) a);
+	const struct note_decoration *nb = *((const struct note_decoration **) b);
+	if (na->sort_hint < nb->sort_hint)
+		return -1;
+	else if (na->sort_hint == nb->sort_hint)
+		return 0;
+	return 1;
+}
+
+static void show_note_decorations(struct commit *commit)
+{
+	struct note_decoration *decoration;
+	struct note_decoration **decoArray;
+	unsigned int numDecorations = 0, i;
+
+	decoration = lookup_decoration(&note_decoration, &commit->object);
+	if (!decoration)
+		return;
+
+	/* Sort notes */
+	while (decoration) {
+		++numDecorations;
+		decoration = decoration->next;
+	}
+	decoration = lookup_decoration(&note_decoration, &commit->object);
+	decoArray = xmalloc(sizeof(struct note_decoration *) * numDecorations);
+	i = 0;
+	while (decoration) {
+		decoArray[i++] = decoration;
+		decoration = decoration->next;
+	}
+	qsort(decoArray, numDecorations, sizeof(struct note_decoration *), compare_note_decorations);
+
+	/* Print notes */
+	puts("\nNotes:");
+	for (i = 0; i < numDecorations; ++i) {
+		const char *p, *q;
+		decoration = decoArray[i];
+		p = decoration->note;
+		while (1) {
+			/* print everything indented by 4 spaces */
+			q = strchr(p, '\n');
+			if (!q)
+				q = p + strlen(p);
+			if (q - p)
+				printf("    %.*s\n", q - p, p);
+			else
+				printf("\n");
+			if (!*q || !*(q + 1))
+				break;
+			p = q + 1;
+		}
+	}
+
+	free(decoArray);
+}
+
 /*
  * Search for "^[-A-Za-z]+: [^@]+@" pattern. It usually matches
  * Signed-off-by: and Acked-by: lines.
@@ -155,7 +215,7 @@ void show_log(struct rev_info *opt, const char *sep)
 		fputs(diff_unique_abbrev(commit->object.sha1, abbrev_commit), stdout);
 		if (opt->parents)
 			show_parents(commit, abbrev_commit);
-		show_decorations(commit);
+		show_name_decorations(commit);
 		putchar(opt->diffopt.line_termination);
 		return;
 	}
@@ -260,7 +320,7 @@ void show_log(struct rev_info *opt, const char *sep)
 			printf(" (from %s)",
 			       diff_unique_abbrev(parent->object.sha1,
 						  abbrev_commit));
-		show_decorations(commit);
+		show_name_decorations(commit);
 		printf("%s",
 		       diff_get_color(opt->diffopt.color_diff, DIFF_RESET));
 		putchar(opt->commit_format == CMIT_FMT_ONELINE ? ' ' : '\n');
@@ -286,6 +346,7 @@ void show_log(struct rev_info *opt, const char *sep)
 		len = append_signoff(this_header, sizeof(this_header), len,
 				     opt->add_signoff);
 	printf("%s%s%s", this_header, extra, sep);
+	show_note_decorations(commit);
 }
 
 int log_tree_diff_flush(struct rev_info *opt)
-- 
1.5.2.101.gee49f
Previous: Johan HerlandNext: Johan Herland
Message 18 of 53 in “[RFC] Second parent for reverts”
  1. Daniel BarkalowMay 9, 2007
  2. Johannes SchindelinMay 9, 2007
  3. Shawn O. PearceMay 9, 2007
  4. Johan HerlandMay 9, 2007
  5. Junio C HamanoMay 9, 2007
  6. Linus TorvaldsMay 9, 2007
  7. Linus TorvaldsMay 10, 2007
  8. Johan HerlandMay 10, 2007
  9. Linus TorvaldsMay 10, 2007
  10. 00/15 git-note: A mechanisim for providing free-form after-the-fact annotations on commitsJohan Herland, May 27, 2007
  11. 01/15 git-note: Add git-note command for adding/listing/deleting git notesJohan Herland, May 27, 2007
  12. 02/15 git-note: (Documentation) Add git-note manual pageJohan Herland, May 27, 2007
  13. 03/15 git-note: (Administrivia) Add git-note to Makefile, .gitignore, etc.Johan Herland, May 27, 2007
  14. 04/15 git-note: (Plumbing) Add plumbing-level support for git notesJohan Herland, May 27, 2007
  15. 05/15 git-note: (Plumbing) Add support for git notes to git-rev-parse and git-show-refJohan Herland, May 27, 2007
  16. 06/15 git-note: (Documentation) Explain the new '--notes' option to git-rev-parse and git-show-refJohan Herland, May 27, 2007
  17. 07/15 git-note: (Almost plumbing) Add support for git notes to git-pack-refs and git-fsckJohan Herland, May 27, 2007
  18. 08/15 git-note: (Decorations) Add note decorations to "git-{log,show,whatchanged} --decorate"Johan Herland, May 27, 2007
  19. 09/15 git-note: (Documentation) Explain new behaviour of --decorate in git-{log,show,whatchanged}Johan Herland, May 27, 2007
  20. 10/15 git-note: (Transfer) Teach git-clone how to clone notesJohan Herland, May 27, 2007
  21. 11/15 git-note: (Transfer) Teach git-fetch to auto-follow notesJohan Herland, May 27, 2007
  22. 12/15 git-note: (Transfer) Teach git-push to push notes when --all or --notes is givenJohan Herland, May 27, 2007
  23. 13/15 git-note: (Documentation) Explain the new --notes option to git-pushJohan Herland, May 27, 2007
  24. 14/15 git-note: (Tests) Add tests for git-note and associated functionalityJohan Herland, May 27, 2007
  25. 15/15 git-note: Add display of notes to gitkJohan Herland, May 27, 2007
  26. Junio C HamanoMay 27, 2007
  27. Johan HerlandMay 28, 2007
  28. Jakub NarebskiMay 28, 2007
  29. Linus TorvaldsMay 28, 2007
  30. Johan HerlandMay 28, 2007
  31. Linus TorvaldsMay 28, 2007
  32. Johan HerlandMay 28, 2007
  33. Linus TorvaldsMay 28, 2007
  34. Johan HerlandMay 28, 2007
  35. Junio C HamanoMay 28, 2007
  36. Shawn O. PearceMay 28, 2007
  37. Johannes SchindelinMay 28, 2007
  38. Linus TorvaldsMay 29, 2007
  39. Shawn O. PearceMay 29, 2007
  40. Jakub NarebskiMay 29, 2007
  41. Andy ParkinsMay 29, 2007
  42. Johannes SchindelinMay 29, 2007
  43. Johan HerlandMay 29, 2007
  44. Jeff KingMay 29, 2007
  45. Johan HerlandMay 29, 2007
  46. Junio C HamanoMay 28, 2007
  47. Shawn O. PearceMay 28, 2007
  48. Add fsck_verify_ref_to_tag_object() to verify that refname matches name stored in tag objectJohan Herland, May 28, 2007
  49. Michael S. TsirkinMay 28, 2007
  50. Michael S. TsirkinMay 28, 2007
  51. Johan HerlandMay 28, 2007
  52. Martin LanghoffMay 10, 2007
  53. Junio C HamanoMay 10, 2007

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.