Skip to content

Commit 885d492

Browse files
committed
Merge branch 'jh/notes' (early part)
* 'jh/notes' (early part): Add selftests verifying concatenation of multiple notes for the same commit Refactor notes code to concatenate multiple notes annotating the same object Add selftests verifying that we can parse notes trees with various fanouts Teach the notes lookup code to parse notes trees with various fanout schemes Teach notes code to free its internal data structures on request Add '%N'-format for pretty-printing commit notes Add flags to get_commit_notes() to control the format of the note string t3302-notes-index-expensive: Speed up create_repo() fast-import: Add support for importing commit notes Teach "-m <msg>" and "-F <file>" to "git notes edit" Add an expensive test for git-notes Speed up git notes lookup Add a script to edit/inspect notes Introduce commit notes Conflicts: .gitignore Documentation/pretty-formats.txt pretty.c
2 parents 905bf77 + a099469 commit 885d492

20 files changed

+1408
-10
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@
8787
/git-mktree
8888
/git-name-rev
8989
/git-mv
90+
/git-notes
9091
/git-pack-redundant
9192
/git-pack-objects
9293
/git-pack-refs

Documentation/config.txt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -456,6 +456,19 @@ On some file system/operating system combinations, this is unreliable.
456456
Set this config setting to 'rename' there; However, This will remove the
457457
check that makes sure that existing object files will not get overwritten.
458458

459+
core.notesRef::
460+
When showing commit messages, also show notes which are stored in
461+
the given ref. This ref is expected to contain files named
462+
after the full SHA-1 of the commit they annotate.
463+
+
464+
If such a file exists in the given ref, the referenced blob is read, and
465+
appended to the commit message, separated by a "Notes:" line. If the
466+
given ref itself does not exist, it is not an error, but means that no
467+
notes should be printed.
468+
+
469+
This setting defaults to "refs/notes/commits", and can be overridden by
470+
the `GIT_NOTES_REF` environment variable.
471+
459472
add.ignore-errors::
460473
Tells 'git-add' to continue adding files when some files cannot be
461474
added due to indexing errors. Equivalent to the '--ignore-errors'

Documentation/git-fast-import.txt

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,7 @@ change to the project.
316316
data
317317
('from' SP <committish> LF)?
318318
('merge' SP <committish> LF)?
319-
(filemodify | filedelete | filecopy | filerename | filedeleteall)*
319+
(filemodify | filedelete | filecopy | filerename | filedeleteall | notemodify)*
320320
LF?
321321
....
322322

@@ -339,14 +339,13 @@ commit message use a 0 length data. Commit messages are free-form
339339
and are not interpreted by Git. Currently they must be encoded in
340340
UTF-8, as fast-import does not permit other encodings to be specified.
341341

342-
Zero or more `filemodify`, `filedelete`, `filecopy`, `filerename`
343-
and `filedeleteall` commands
342+
Zero or more `filemodify`, `filedelete`, `filecopy`, `filerename`,
343+
`filedeleteall` and `notemodify` commands
344344
may be included to update the contents of the branch prior to
345345
creating the commit. These commands may be supplied in any order.
346346
However it is recommended that a `filedeleteall` command precede
347-
all `filemodify`, `filecopy` and `filerename` commands in the same
348-
commit, as `filedeleteall`
349-
wipes the branch clean (see below).
347+
all `filemodify`, `filecopy`, `filerename` and `notemodify` commands in
348+
the same commit, as `filedeleteall` wipes the branch clean (see below).
350349

351350
The `LF` after the command is optional (it used to be required).
352351

@@ -595,6 +594,40 @@ more memory per active branch (less than 1 MiB for even most large
595594
projects); so frontends that can easily obtain only the affected
596595
paths for a commit are encouraged to do so.
597596

597+
`notemodify`
598+
^^^^^^^^^^^^
599+
Included in a `commit` command to add a new note (annotating a given
600+
commit) or change the content of an existing note. This command has
601+
two different means of specifying the content of the note.
602+
603+
External data format::
604+
The data content for the note was already supplied by a prior
605+
`blob` command. The frontend just needs to connect it to the
606+
commit that is to be annotated.
607+
+
608+
....
609+
'N' SP <dataref> SP <committish> LF
610+
....
611+
+
612+
Here `<dataref>` can be either a mark reference (`:<idnum>`)
613+
set by a prior `blob` command, or a full 40-byte SHA-1 of an
614+
existing Git blob object.
615+
616+
Inline data format::
617+
The data content for the note has not been supplied yet.
618+
The frontend wants to supply it as part of this modify
619+
command.
620+
+
621+
....
622+
'N' SP 'inline' SP <committish> LF
623+
data
624+
....
625+
+
626+
See below for a detailed description of the `data` command.
627+
628+
In both formats `<committish>` is any of the commit specification
629+
expressions also accepted by `from` (see above).
630+
598631
`mark`
599632
~~~~~~
600633
Arranges for fast-import to save a reference to the current object, allowing

Documentation/git-notes.txt

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
git-notes(1)
2+
============
3+
4+
NAME
5+
----
6+
git-notes - Add/inspect commit notes
7+
8+
SYNOPSIS
9+
--------
10+
[verse]
11+
'git-notes' (edit [-F <file> | -m <msg>] | show) [commit]
12+
13+
DESCRIPTION
14+
-----------
15+
This command allows you to add notes to commit messages, without
16+
changing the commit. To discern these notes from the message stored
17+
in the commit object, the notes are indented like the message, after
18+
an unindented line saying "Notes:".
19+
20+
To disable commit notes, you have to set the config variable
21+
core.notesRef to the empty string. Alternatively, you can set it
22+
to a different ref, something like "refs/notes/bugzilla". This setting
23+
can be overridden by the environment variable "GIT_NOTES_REF".
24+
25+
26+
SUBCOMMANDS
27+
-----------
28+
29+
edit::
30+
Edit the notes for a given commit (defaults to HEAD).
31+
32+
show::
33+
Show the notes for a given commit (defaults to HEAD).
34+
35+
36+
OPTIONS
37+
-------
38+
-m <msg>::
39+
Use the given note message (instead of prompting).
40+
If multiple `-m` (or `-F`) options are given, their
41+
values are concatenated as separate paragraphs.
42+
43+
-F <file>::
44+
Take the note message from the given file. Use '-' to
45+
read the note message from the standard input.
46+
If multiple `-F` (or `-m`) options are given, their
47+
values are concatenated as separate paragraphs.
48+
49+
50+
Author
51+
------
52+
Written by Johannes Schindelin <[email protected]>
53+
54+
Documentation
55+
-------------
56+
Documentation by Johannes Schindelin
57+
58+
GIT
59+
---
60+
Part of the linkgit:git[7] suite

Documentation/pretty-formats.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ The placeholders are:
123123
- '%s': subject
124124
- '%f': sanitized subject line, suitable for a filename
125125
- '%b': body
126+
- '%N': commit notes
126127
- '%gD': reflog selector, e.g., `refs/stash@\{1\}`
127128
- '%gd': shortened reflog selector, e.g., `stash@\{1\}`
128129
- '%gs': reflog subject

Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,7 @@ SCRIPT_SH += git-merge-one-file.sh
343343
SCRIPT_SH += git-merge-resolve.sh
344344
SCRIPT_SH += git-mergetool.sh
345345
SCRIPT_SH += git-mergetool--lib.sh
346+
SCRIPT_SH += git-notes.sh
346347
SCRIPT_SH += git-parse-remote.sh
347348
SCRIPT_SH += git-pull.sh
348349
SCRIPT_SH += git-quiltimport.sh
@@ -457,6 +458,7 @@ LIB_H += ll-merge.h
457458
LIB_H += log-tree.h
458459
LIB_H += mailmap.h
459460
LIB_H += merge-recursive.h
461+
LIB_H += notes.h
460462
LIB_H += object.h
461463
LIB_H += pack.h
462464
LIB_H += pack-refs.h
@@ -542,6 +544,7 @@ LIB_OBJS += match-trees.o
542544
LIB_OBJS += merge-file.o
543545
LIB_OBJS += merge-recursive.o
544546
LIB_OBJS += name-hash.o
547+
LIB_OBJS += notes.o
545548
LIB_OBJS += object.o
546549
LIB_OBJS += pack-check.o
547550
LIB_OBJS += pack-refs.o

cache.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,8 @@ static inline enum object_type object_type(unsigned int mode)
372372
#define GITATTRIBUTES_FILE ".gitattributes"
373373
#define INFOATTRIBUTES_FILE "info/attributes"
374374
#define ATTRIBUTE_MACRO_PREFIX "[attr]"
375+
#define GIT_NOTES_REF_ENVIRONMENT "GIT_NOTES_REF"
376+
#define GIT_NOTES_DEFAULT_REF "refs/notes/commits"
375377

376378
extern int is_bare_repository_cfg;
377379
extern int is_bare_repository(void);
@@ -568,6 +570,8 @@ enum object_creation_mode {
568570

569571
extern enum object_creation_mode object_creation_mode;
570572

573+
extern char *notes_ref_name;
574+
571575
extern int grafts_replace_parents;
572576

573577
#define GIT_REPO_VERSION 0

command-list.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ git-mktag plumbingmanipulators
7474
git-mktree plumbingmanipulators
7575
git-mv mainporcelain common
7676
git-name-rev plumbinginterrogators
77+
git-notes mainporcelain
7778
git-pack-objects plumbingmanipulators
7879
git-pack-redundant plumbinginterrogators
7980
git-pack-refs ancillarymanipulators

commit.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "utf8.h"
66
#include "diff.h"
77
#include "revision.h"
8+
#include "notes.h"
89

910
int save_commit_buffer = 1;
1011

config.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -467,6 +467,11 @@ static int git_default_core_config(const char *var, const char *value)
467467
return 0;
468468
}
469469

470+
if (!strcmp(var, "core.notesref")) {
471+
notes_ref_name = xstrdup(value);
472+
return 0;
473+
}
474+
470475
if (!strcmp(var, "core.pager"))
471476
return git_config_string(&pager_program, var, value);
472477

environment.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ enum push_default_type push_default = PUSH_DEFAULT_MATCHING;
4949
#define OBJECT_CREATION_MODE OBJECT_CREATION_USES_HARDLINKS
5050
#endif
5151
enum object_creation_mode object_creation_mode = OBJECT_CREATION_MODE;
52+
char *notes_ref_name;
5253
int grafts_replace_parents = 1;
5354

5455
/* Parallel index stat data preload? */

fast-import.c

Lines changed: 84 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ Format of STDIN stream:
2222
('author' sp name sp '<' email '>' sp when lf)?
2323
'committer' sp name sp '<' email '>' sp when lf
2424
commit_msg
25-
('from' sp (ref_str | hexsha1 | sha1exp_str | idnum) lf)?
26-
('merge' sp (ref_str | hexsha1 | sha1exp_str | idnum) lf)*
25+
('from' sp committish lf)?
26+
('merge' sp committish lf)*
2727
file_change*
2828
lf?;
2929
commit_msg ::= data;
@@ -41,15 +41,18 @@ Format of STDIN stream:
4141
file_obm ::= 'M' sp mode sp (hexsha1 | idnum) sp path_str lf;
4242
file_inm ::= 'M' sp mode sp 'inline' sp path_str lf
4343
data;
44+
note_obm ::= 'N' sp (hexsha1 | idnum) sp committish lf;
45+
note_inm ::= 'N' sp 'inline' sp committish lf
46+
data;
4447
4548
new_tag ::= 'tag' sp tag_str lf
46-
'from' sp (ref_str | hexsha1 | sha1exp_str | idnum) lf
49+
'from' sp committish lf
4750
('tagger' sp name sp '<' email '>' sp when lf)?
4851
tag_msg;
4952
tag_msg ::= data;
5053
5154
reset_branch ::= 'reset' sp ref_str lf
52-
('from' sp (ref_str | hexsha1 | sha1exp_str | idnum) lf)?
55+
('from' sp committish lf)?
5356
lf?;
5457
5558
checkpoint ::= 'checkpoint' lf
@@ -88,6 +91,7 @@ Format of STDIN stream:
8891
# stream formatting is: \, " and LF. Otherwise these values
8992
# are UTF8.
9093
#
94+
committish ::= (ref_str | hexsha1 | sha1exp_str | idnum);
9195
ref_str ::= ref;
9296
sha1exp_str ::= sha1exp;
9397
tag_str ::= tag;
@@ -2006,6 +2010,80 @@ static void file_change_cr(struct branch *b, int rename)
20062010
leaf.tree);
20072011
}
20082012

2013+
static void note_change_n(struct branch *b)
2014+
{
2015+
const char *p = command_buf.buf + 2;
2016+
static struct strbuf uq = STRBUF_INIT;
2017+
struct object_entry *oe = oe;
2018+
struct branch *s;
2019+
unsigned char sha1[20], commit_sha1[20];
2020+
uint16_t inline_data = 0;
2021+
2022+
/* <dataref> or 'inline' */
2023+
if (*p == ':') {
2024+
char *x;
2025+
oe = find_mark(strtoumax(p + 1, &x, 10));
2026+
hashcpy(sha1, oe->sha1);
2027+
p = x;
2028+
} else if (!prefixcmp(p, "inline")) {
2029+
inline_data = 1;
2030+
p += 6;
2031+
} else {
2032+
if (get_sha1_hex(p, sha1))
2033+
die("Invalid SHA1: %s", command_buf.buf);
2034+
oe = find_object(sha1);
2035+
p += 40;
2036+
}
2037+
if (*p++ != ' ')
2038+
die("Missing space after SHA1: %s", command_buf.buf);
2039+
2040+
/* <committish> */
2041+
s = lookup_branch(p);
2042+
if (s) {
2043+
hashcpy(commit_sha1, s->sha1);
2044+
} else if (*p == ':') {
2045+
uintmax_t commit_mark = strtoumax(p + 1, NULL, 10);
2046+
struct object_entry *commit_oe = find_mark(commit_mark);
2047+
if (commit_oe->type != OBJ_COMMIT)
2048+
die("Mark :%" PRIuMAX " not a commit", commit_mark);
2049+
hashcpy(commit_sha1, commit_oe->sha1);
2050+
} else if (!get_sha1(p, commit_sha1)) {
2051+
unsigned long size;
2052+
char *buf = read_object_with_reference(commit_sha1,
2053+
commit_type, &size, commit_sha1);
2054+
if (!buf || size < 46)
2055+
die("Not a valid commit: %s", p);
2056+
free(buf);
2057+
} else
2058+
die("Invalid ref name or SHA1 expression: %s", p);
2059+
2060+
if (inline_data) {
2061+
static struct strbuf buf = STRBUF_INIT;
2062+
2063+
if (p != uq.buf) {
2064+
strbuf_addstr(&uq, p);
2065+
p = uq.buf;
2066+
}
2067+
read_next_command();
2068+
parse_data(&buf);
2069+
store_object(OBJ_BLOB, &buf, &last_blob, sha1, 0);
2070+
} else if (oe) {
2071+
if (oe->type != OBJ_BLOB)
2072+
die("Not a blob (actually a %s): %s",
2073+
typename(oe->type), command_buf.buf);
2074+
} else {
2075+
enum object_type type = sha1_object_info(sha1, NULL);
2076+
if (type < 0)
2077+
die("Blob not found: %s", command_buf.buf);
2078+
if (type != OBJ_BLOB)
2079+
die("Not a blob (actually a %s): %s",
2080+
typename(type), command_buf.buf);
2081+
}
2082+
2083+
tree_content_set(&b->branch_tree, sha1_to_hex(commit_sha1), sha1,
2084+
S_IFREG | 0644, NULL);
2085+
}
2086+
20092087
static void file_change_deleteall(struct branch *b)
20102088
{
20112089
release_tree_content_recursive(b->branch_tree.tree);
@@ -2175,6 +2253,8 @@ static void parse_new_commit(void)
21752253
file_change_cr(b, 1);
21762254
else if (!prefixcmp(command_buf.buf, "C "))
21772255
file_change_cr(b, 0);
2256+
else if (!prefixcmp(command_buf.buf, "N "))
2257+
note_change_n(b);
21782258
else if (!strcmp("deleteall", command_buf.buf))
21792259
file_change_deleteall(b);
21802260
else {

0 commit comments

Comments
 (0)