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

[PATCH] Introduce light weight commit annotations

From
Johannes Schindelin <johannes.schindelin@gmx.de>
Date
Jun 9, 2007, 17:55 UTC
Message-ID
<Pine.LNX.4.64.0706091854330.4059@racer.site>

With the provided script, edit-commit-annotations, you can add after-the-fact annotations to commits, which will be shown by the log if the config variable core.showannotations is set.

The annotations are tracked in a new ref, refs/annotations/commits, in the same fan-out style as .git/objects/??/*, only that they only exist in the object database now.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
	I have the hunch that this will be relatively fast and scalable,
	since the tree objects are sorted by name (the name being the
	object name of the to-be-annotated commit).
	I'm on the run for 15 hours now, but please feel free to discuss
	and / or trash it while I'm away.
 cache.h                       |    1 +
 commit.c                      |   48 ++++++++++++++++++++++++++++++++++++++++-
 config.c                      |    5 ++++
 environment.c                 |    1 +
 git-edit-commit-annotation.sh |   46 +++++++++++++++++++++++++++++++++++++++
 5 files changed, 100 insertions(+), 1 deletions(-)
 create mode 100755 git-edit-commit-annotation.sh
diff --git a/cache.h b/cache.h
index bc6b8e8..4166888 100644
--- a/cache.h
+++ b/cache.h
@@ -288,6 +288,7 @@ extern size_t packed_git_window_size;
 extern size_t packed_git_limit;
 extern size_t delta_base_cache_limit;
 extern int auto_crlf;
+extern int show_commit_annotations;
 
 #define GIT_REPO_VERSION 0
 extern int repository_format_version;
diff --git a/commit.c b/commit.c
index 4ca4d44..409ebc8 100644
--- a/commit.c
+++ b/commit.c
@@ -911,6 +911,48 @@ static long format_commit_message(const struct commit *commit,
 	return strlen(buf);
 }
 
+static unsigned long show_annotations(const struct commit *commit,
+		char *buf, unsigned long space)
+{
+	char name[80];
+	const char *hex = sha1_to_hex(commit->object.sha1);
+	unsigned char sha1[20];
+	char *msg;
+	unsigned long offset = 0, msgoffset = 0, msglen;
+	enum object_type type;
+
+	snprintf(name, sizeof(name),
+			"refs/annotations/commits:%.*s/%.*s",
+			2, hex, 38, hex + 2);
+	if (get_sha1(name, sha1))
+		return 0;
+
+	if (!(msg = read_sha1_file(sha1, &type, &msglen)) || !msglen)
+		return 0;
+	/* we will end the annotation by a newline anyway. */
+	if (msg[msglen - 1] == '\n')
+		msglen--;
+
+	offset += snprintf(buf + offset, space - offset - 1,
+			"\nAnnotation:\n");
+
+	for (msgoffset = 0; msgoffset < msglen;) {
+		int linelen = get_one_line(msg + msgoffset, msglen);
+
+		offset += snprintf(buf + offset, space - offset - 1,
+			"    %.*s", linelen, msg + msgoffset);
+
+		if (offset + 1 >= space)
+			break;
+
+		msgoffset += linelen;
+	}
+	buf[offset++] = '\n';
+	free(msg);
+
+	return offset;
+}
+
 unsigned long pretty_print_commit(enum cmit_fmt fmt,
 				  const struct commit *commit,
 				  unsigned long len,
@@ -1098,8 +1140,12 @@ unsigned long pretty_print_commit(enum cmit_fmt fmt,
 	 */
 	if (fmt == CMIT_FMT_EMAIL && !body)
 		buf[offset++] = '\n';
-	buf[offset] = '\0';
 
+	if (fmt != CMIT_FMT_ONELINE && show_commit_annotations)
+		offset += show_annotations(commit,
+				buf + offset, space - offset);
+
+	buf[offset] = '\0';
 	free(reencoded);
 	return offset;
 }
diff --git a/config.c b/config.c
index 58d3ed5..34db9b2 100644
--- a/config.c
+++ b/config.c
@@ -356,6 +356,11 @@ int git_default_config(const char *var, const char *value)
 		return 0;
 	}
 
+	if (!strcmp(var, "core.showannotaions")) {
+		show_commit_annotations = git_config_bool(var, value);
+		return 0;
+	}
+
 	if (!strcmp(var, "user.name")) {
 		strlcpy(git_default_name, value, sizeof(git_default_name));
 		return 0;
diff --git a/environment.c b/environment.c
index 8b9b89d..c649f19 100644
--- a/environment.c
+++ b/environment.c
@@ -32,6 +32,7 @@ size_t delta_base_cache_limit = 16 * 1024 * 1024;
 int pager_in_use;
 int pager_use_color = 1;
 int auto_crlf = 0;	/* 1: both ways, -1: only when adding git objects */
+int show_commit_annotations;
 
 static const char *git_dir;
 static char *git_object_dir, *git_index_file, *git_refs_dir, *git_graft_file;
diff --git a/git-edit-commit-annotation.sh b/git-edit-commit-annotation.sh
new file mode 100755
index 0000000..2abcd34
--- /dev/null
+++ b/git-edit-commit-annotation.sh
@@ -0,0 +1,46 @@
+#!/bin/sh
+
+USAGE="[commit-name]"
+. git-sh-setup
+
+test -n "$2" && usage
+COMMIT=$(git rev-parse --verify --default HEAD "$@")
+NAME=$(echo $COMMIT | sed "s/^../&\//")
+
+MESSAGE="$GIT_DIR"/COMMIT_ANNOTATION.$$
+git log -1 $COMMIT | sed "s/^/#/" > "$MESSAGE"
+
+GIT_INDEX_FILE="$MESSAGE".idx
+export GIT_INDEX_FILE
+
+TIPNAME=refs/annotations/commits
+OLDTIP=$(git show-ref $TIPNAME | cut -f 1 -d ' ')
+if [ -z "$OLDTIP" ]; then
+	OLDTIP=0000000000000000000000000000000000000000
+else
+	PARENT="-p $OLDTIP"
+	git read-tree $TIPNAME || die "Could not read index"
+	git cat-file blob :$NAME >> "$MESSAGE" 2> /dev/null
+fi
+
+${VISUAL:-${EDITOR:-vi}} "$MESSAGE"
+
+grep -v ^# < "$MESSAGE" | git stripspace > "$MESSAGE".processed
+mv "$MESSAGE".processed "$MESSAGE"
+if [ -z "$(cat "$MESSAGE")" ]; then
+	case $OLDTIP in 0000000000000000000000000000000000000000)
+		echo "Will not initialise with empty tree"
+		exit 1
+	esac
+	git update-index --force-remove $NAME ||
+		die "Could not update index"
+else
+	BLOB=$(git hash-object -w "$MESSAGE") ||
+		die "Could not write into object database"
+	git update-index --add --cacheinfo 0644 $BLOB $NAME ||
+		die "Could not write index"
+fi
+
+TREE=$(git write-tree) || die "Could not write tree"
+NEWTIP=$(date | git commit-tree $TREE $PARENT) || die "Could not annotate"
+git update-ref $TIPNAME $NEWTIP $OLDTIP
-- 
1.5.2.1.2713.gbb6a-dirty
Next: Johan Herland
Message 1 of 18 in “Introduce light weight commit annotations”
  1. Introduce light weight commit annotationsJohannes Schindelin, Jun 9, 2007
  2. Johan HerlandJun 10, 2007
  3. Johannes SchindelinJun 10, 2007
  4. Johan HerlandJun 10, 2007
  5. Johannes SchindelinJun 10, 2007
  6. Junio C HamanoJun 10, 2007
  7. Johannes SchindelinJun 10, 2007
  8. Junio C HamanoJun 10, 2007
  9. Johannes SchindelinJun 11, 2007
  10. Johannes SchindelinJun 12, 2007
  11. Alex RiesenJun 10, 2007
  12. Alex RiesenJun 10, 2007
  13. Junio C HamanoJun 11, 2007
  14. Nicolas PitreJun 11, 2007
  15. Alex RiesenJun 11, 2007
  16. Junio C HamanoJun 11, 2007
  17. Alex RiesenJun 11, 2007
  18. Johannes SchindelinJun 11, 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.