Commit a97a7468 authored by Johannes Schindelin's avatar Johannes Schindelin Committed by Junio C Hamano

Introduce commit notes

Commit notes are blobs which are shown together with the commit
message.  These blobs are taken from the notes ref, which you can
configure by the config variable core.notesRef, which in turn can
be overridden by the environment variable GIT_NOTES_REF.

The notes ref is a branch which contains "files" whose names are
the names of the corresponding commits (i.e. the SHA-1).

The rationale for putting this information into a ref is this: we
want to be able to fetch and possibly union-merge the notes,
maybe even look at the date when a note was introduced, and we
want to store them efficiently together with the other objects.

This patch has been improved by the following contributions:
- Thomas Rast: fix core.notesRef documentation
- Tor Arne Vestbø: fix printing of multi-line notes
- Alex Riesen: Using char array instead of char pointer costs less BSS
- Johan Herland: Plug leak when msg is good, but msglen or type causes return
Signed-off-by: Johannes Schindelin's avatarJohannes Schindelin <[email protected]>
Signed-off-by: default avatarThomas Rast <[email protected]>
Signed-off-by: default avatarTor Arne Vestbø <[email protected]>
Signed-off-by: default avatarJohan Herland <[email protected]>
Signed-off-by: default avatarJunio C Hamano <[email protected]>

get_commit_notes(): Plug memory leak when 'if' triggers, but not because of read_sha1_file() failure
parent 78d553b7
......@@ -454,6 +454,19 @@ On some file system/operating system combinations, this is unreliable.
Set this config setting to 'rename' there; However, This will remove the
check that makes sure that existing object files will not get overwritten.
When showing commit messages, also show notes which are stored in
the given ref. This ref is expected to contain files named
after the full SHA-1 of the commit they annotate.
If such a file exists in the given ref, the referenced blob is read, and
appended to the commit message, separated by a "Notes:" line. If the
given ref itself does not exist, it is not an error, but means that no
notes should be printed.
This setting defaults to "refs/notes/commits", and can be overridden by
the `GIT_NOTES_REF` environment variable.
Tells 'git-add' to continue adding files when some files cannot be
added due to indexing errors. Equivalent to the '--ignore-errors'
......@@ -432,6 +432,7 @@ LIB_H += ll-merge.h
LIB_H += log-tree.h
LIB_H += mailmap.h
LIB_H += merge-recursive.h
LIB_H += notes.h
LIB_H += object.h
LIB_H += pack.h
LIB_H += pack-refs.h
......@@ -516,6 +517,7 @@ LIB_OBJS += match-trees.o
LIB_OBJS += merge-file.o
LIB_OBJS += merge-recursive.o
LIB_OBJS += name-hash.o
LIB_OBJS += notes.o
LIB_OBJS += object.o
LIB_OBJS += pack-check.o
LIB_OBJS += pack-refs.o
......@@ -372,6 +372,8 @@ static inline enum object_type object_type(unsigned int mode)
#define GITATTRIBUTES_FILE ".gitattributes"
#define INFOATTRIBUTES_FILE "info/attributes"
#define GIT_NOTES_DEFAULT_REF "refs/notes/commits"
extern int is_bare_repository_cfg;
extern int is_bare_repository(void);
......@@ -567,6 +569,8 @@ enum object_creation_mode {
extern enum object_creation_mode object_creation_mode;
extern char *notes_ref_name;
extern int grafts_replace_parents;
......@@ -5,6 +5,7 @@
#include "utf8.h"
#include "diff.h"
#include "revision.h"
#include "notes.h"
int save_commit_buffer = 1;
......@@ -467,6 +467,11 @@ static int git_default_core_config(const char *var, const char *value)
return 0;
if (!strcmp(var, "core.notesref")) {
notes_ref_name = xstrdup(value);
return 0;
if (!strcmp(var, "core.pager"))
return git_config_string(&pager_program, var, value);
......@@ -49,6 +49,7 @@ enum push_default_type push_default = PUSH_DEFAULT_MATCHING;
enum object_creation_mode object_creation_mode = OBJECT_CREATION_MODE;
char *notes_ref_name;
int grafts_replace_parents = 1;
/* Parallel index stat data preload? */
#include "cache.h"
#include "commit.h"
#include "notes.h"
#include "refs.h"
#include "utf8.h"
#include "strbuf.h"
static int initialized;
void get_commit_notes(const struct commit *commit, struct strbuf *sb,
const char *output_encoding)
static const char utf8[] = "utf-8";
struct strbuf name = STRBUF_INIT;
unsigned char sha1[20];
char *msg, *msg_p;
unsigned long linelen, msglen;
enum object_type type;
if (!initialized) {
const char *env = getenv(GIT_NOTES_REF_ENVIRONMENT);
if (env)
notes_ref_name = getenv(GIT_NOTES_REF_ENVIRONMENT);
else if (!notes_ref_name)
notes_ref_name = GIT_NOTES_DEFAULT_REF;
if (notes_ref_name && read_ref(notes_ref_name, sha1))
notes_ref_name = NULL;
initialized = 1;
if (!notes_ref_name)
strbuf_addf(&name, "%s:%s", notes_ref_name,
if (get_sha1(name.buf, sha1))
if (!(msg = read_sha1_file(sha1, &type, &msglen)) || !msglen ||
type != OBJ_BLOB) {
if (output_encoding && *output_encoding &&
strcmp(utf8, output_encoding)) {
char *reencoded = reencode_string(msg, output_encoding, utf8);
if (reencoded) {
msg = reencoded;
msglen = strlen(msg);
/* we will end the annotation by a newline anyway */
if (msglen && msg[msglen - 1] == '\n')
strbuf_addstr(sb, "\nNotes:\n");
for (msg_p = msg; msg_p < msg + msglen; msg_p += linelen + 1) {
linelen = strchrnul(msg_p, '\n') - msg_p;
strbuf_addstr(sb, " ");
strbuf_add(sb, msg_p, linelen);
strbuf_addch(sb, '\n');
#ifndef NOTES_H
#define NOTES_H
void get_commit_notes(const struct commit *commit, struct strbuf *sb,
const char *output_encoding);
......@@ -6,6 +6,7 @@
#include "string-list.h"
#include "mailmap.h"
#include "log-tree.h"
#include "notes.h"
#include "color.h"
static char *user_format;
......@@ -975,5 +976,9 @@ void pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit,
if (fmt == CMIT_FMT_EMAIL && sb->len <= beginning_of_body)
strbuf_addch(sb, '\n');
if (fmt != CMIT_FMT_ONELINE)
get_commit_notes(commit, sb, encoding);
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment