Skip to content

Commit

Permalink
Merge branch 'jh/notes' (early part)
Browse files Browse the repository at this point in the history
* '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
  • Loading branch information
gitster committed Nov 21, 2009
2 parents 905bf77 + a099469 commit 885d492
Show file tree
Hide file tree
Showing 20 changed files with 1,408 additions and 10 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@
/git-mktree
/git-name-rev
/git-mv
/git-notes
/git-pack-redundant
/git-pack-objects
/git-pack-refs
Expand Down
13 changes: 13 additions & 0 deletions Documentation/config.txt
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,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.

core.notesRef::
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.

add.ignore-errors::
Tells 'git-add' to continue adding files when some files cannot be
added due to indexing errors. Equivalent to the '--ignore-errors'
Expand Down
45 changes: 39 additions & 6 deletions Documentation/git-fast-import.txt
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ change to the project.
data
('from' SP <committish> LF)?
('merge' SP <committish> LF)?
(filemodify | filedelete | filecopy | filerename | filedeleteall)*
(filemodify | filedelete | filecopy | filerename | filedeleteall | notemodify)*
LF?
....

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

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

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

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

`notemodify`
^^^^^^^^^^^^
Included in a `commit` command to add a new note (annotating a given
commit) or change the content of an existing note. This command has
two different means of specifying the content of the note.

External data format::
The data content for the note was already supplied by a prior
`blob` command. The frontend just needs to connect it to the
commit that is to be annotated.
+
....
'N' SP <dataref> SP <committish> LF
....
+
Here `<dataref>` can be either a mark reference (`:<idnum>`)
set by a prior `blob` command, or a full 40-byte SHA-1 of an
existing Git blob object.

Inline data format::
The data content for the note has not been supplied yet.
The frontend wants to supply it as part of this modify
command.
+
....
'N' SP 'inline' SP <committish> LF
data
....
+
See below for a detailed description of the `data` command.

In both formats `<committish>` is any of the commit specification
expressions also accepted by `from` (see above).

`mark`
~~~~~~
Arranges for fast-import to save a reference to the current object, allowing
Expand Down
60 changes: 60 additions & 0 deletions Documentation/git-notes.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
git-notes(1)
============

NAME
----
git-notes - Add/inspect commit notes

SYNOPSIS
--------
[verse]
'git-notes' (edit [-F <file> | -m <msg>] | show) [commit]

DESCRIPTION
-----------
This command allows you to add notes to commit messages, without
changing the commit. To discern these notes from the message stored
in the commit object, the notes are indented like the message, after
an unindented line saying "Notes:".

To disable commit notes, you have to set the config variable
core.notesRef to the empty string. Alternatively, you can set it
to a different ref, something like "refs/notes/bugzilla". This setting
can be overridden by the environment variable "GIT_NOTES_REF".


SUBCOMMANDS
-----------

edit::
Edit the notes for a given commit (defaults to HEAD).

show::
Show the notes for a given commit (defaults to HEAD).


OPTIONS
-------
-m <msg>::
Use the given note message (instead of prompting).
If multiple `-m` (or `-F`) options are given, their
values are concatenated as separate paragraphs.

-F <file>::
Take the note message from the given file. Use '-' to
read the note message from the standard input.
If multiple `-F` (or `-m`) options are given, their
values are concatenated as separate paragraphs.


Author
------
Written by Johannes Schindelin <johannes.schindelin@gmx.de>

Documentation
-------------
Documentation by Johannes Schindelin

GIT
---
Part of the linkgit:git[7] suite
1 change: 1 addition & 0 deletions Documentation/pretty-formats.txt
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ The placeholders are:
- '%s': subject
- '%f': sanitized subject line, suitable for a filename
- '%b': body
- '%N': commit notes
- '%gD': reflog selector, e.g., `refs/stash@\{1\}`
- '%gd': shortened reflog selector, e.g., `stash@\{1\}`
- '%gs': reflog subject
Expand Down
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,7 @@ SCRIPT_SH += git-merge-one-file.sh
SCRIPT_SH += git-merge-resolve.sh
SCRIPT_SH += git-mergetool.sh
SCRIPT_SH += git-mergetool--lib.sh
SCRIPT_SH += git-notes.sh
SCRIPT_SH += git-parse-remote.sh
SCRIPT_SH += git-pull.sh
SCRIPT_SH += git-quiltimport.sh
Expand Down Expand Up @@ -457,6 +458,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
Expand Down Expand Up @@ -542,6 +544,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
Expand Down
4 changes: 4 additions & 0 deletions cache.h
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,8 @@ static inline enum object_type object_type(unsigned int mode)
#define GITATTRIBUTES_FILE ".gitattributes"
#define INFOATTRIBUTES_FILE "info/attributes"
#define ATTRIBUTE_MACRO_PREFIX "[attr]"
#define GIT_NOTES_REF_ENVIRONMENT "GIT_NOTES_REF"
#define GIT_NOTES_DEFAULT_REF "refs/notes/commits"

extern int is_bare_repository_cfg;
extern int is_bare_repository(void);
Expand Down Expand Up @@ -568,6 +570,8 @@ enum object_creation_mode {

extern enum object_creation_mode object_creation_mode;

extern char *notes_ref_name;

extern int grafts_replace_parents;

#define GIT_REPO_VERSION 0
Expand Down
1 change: 1 addition & 0 deletions command-list.txt
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ git-mktag plumbingmanipulators
git-mktree plumbingmanipulators
git-mv mainporcelain common
git-name-rev plumbinginterrogators
git-notes mainporcelain
git-pack-objects plumbingmanipulators
git-pack-redundant plumbinginterrogators
git-pack-refs ancillarymanipulators
Expand Down
1 change: 1 addition & 0 deletions commit.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "utf8.h"
#include "diff.h"
#include "revision.h"
#include "notes.h"

int save_commit_buffer = 1;

Expand Down
5 changes: 5 additions & 0 deletions config.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
1 change: 1 addition & 0 deletions environment.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ enum push_default_type push_default = PUSH_DEFAULT_MATCHING;
#define OBJECT_CREATION_MODE OBJECT_CREATION_USES_HARDLINKS
#endif
enum object_creation_mode object_creation_mode = OBJECT_CREATION_MODE;
char *notes_ref_name;
int grafts_replace_parents = 1;

/* Parallel index stat data preload? */
Expand Down
88 changes: 84 additions & 4 deletions fast-import.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ Format of STDIN stream:
('author' sp name sp '<' email '>' sp when lf)?
'committer' sp name sp '<' email '>' sp when lf
commit_msg
('from' sp (ref_str | hexsha1 | sha1exp_str | idnum) lf)?
('merge' sp (ref_str | hexsha1 | sha1exp_str | idnum) lf)*
('from' sp committish lf)?
('merge' sp committish lf)*
file_change*
lf?;
commit_msg ::= data;
Expand All @@ -41,15 +41,18 @@ Format of STDIN stream:
file_obm ::= 'M' sp mode sp (hexsha1 | idnum) sp path_str lf;
file_inm ::= 'M' sp mode sp 'inline' sp path_str lf
data;
note_obm ::= 'N' sp (hexsha1 | idnum) sp committish lf;
note_inm ::= 'N' sp 'inline' sp committish lf
data;
new_tag ::= 'tag' sp tag_str lf
'from' sp (ref_str | hexsha1 | sha1exp_str | idnum) lf
'from' sp committish lf
('tagger' sp name sp '<' email '>' sp when lf)?
tag_msg;
tag_msg ::= data;
reset_branch ::= 'reset' sp ref_str lf
('from' sp (ref_str | hexsha1 | sha1exp_str | idnum) lf)?
('from' sp committish lf)?
lf?;
checkpoint ::= 'checkpoint' lf
Expand Down Expand Up @@ -88,6 +91,7 @@ Format of STDIN stream:
# stream formatting is: \, " and LF. Otherwise these values
# are UTF8.
#
committish ::= (ref_str | hexsha1 | sha1exp_str | idnum);
ref_str ::= ref;
sha1exp_str ::= sha1exp;
tag_str ::= tag;
Expand Down Expand Up @@ -2006,6 +2010,80 @@ static void file_change_cr(struct branch *b, int rename)
leaf.tree);
}

static void note_change_n(struct branch *b)
{
const char *p = command_buf.buf + 2;
static struct strbuf uq = STRBUF_INIT;
struct object_entry *oe = oe;
struct branch *s;
unsigned char sha1[20], commit_sha1[20];
uint16_t inline_data = 0;

/* <dataref> or 'inline' */
if (*p == ':') {
char *x;
oe = find_mark(strtoumax(p + 1, &x, 10));
hashcpy(sha1, oe->sha1);
p = x;
} else if (!prefixcmp(p, "inline")) {
inline_data = 1;
p += 6;
} else {
if (get_sha1_hex(p, sha1))
die("Invalid SHA1: %s", command_buf.buf);
oe = find_object(sha1);
p += 40;
}
if (*p++ != ' ')
die("Missing space after SHA1: %s", command_buf.buf);

/* <committish> */
s = lookup_branch(p);
if (s) {
hashcpy(commit_sha1, s->sha1);
} else if (*p == ':') {
uintmax_t commit_mark = strtoumax(p + 1, NULL, 10);
struct object_entry *commit_oe = find_mark(commit_mark);
if (commit_oe->type != OBJ_COMMIT)
die("Mark :%" PRIuMAX " not a commit", commit_mark);
hashcpy(commit_sha1, commit_oe->sha1);
} else if (!get_sha1(p, commit_sha1)) {
unsigned long size;
char *buf = read_object_with_reference(commit_sha1,
commit_type, &size, commit_sha1);
if (!buf || size < 46)
die("Not a valid commit: %s", p);
free(buf);
} else
die("Invalid ref name or SHA1 expression: %s", p);

if (inline_data) {
static struct strbuf buf = STRBUF_INIT;

if (p != uq.buf) {
strbuf_addstr(&uq, p);
p = uq.buf;
}
read_next_command();
parse_data(&buf);
store_object(OBJ_BLOB, &buf, &last_blob, sha1, 0);
} else if (oe) {
if (oe->type != OBJ_BLOB)
die("Not a blob (actually a %s): %s",
typename(oe->type), command_buf.buf);
} else {
enum object_type type = sha1_object_info(sha1, NULL);
if (type < 0)
die("Blob not found: %s", command_buf.buf);
if (type != OBJ_BLOB)
die("Not a blob (actually a %s): %s",
typename(type), command_buf.buf);
}

tree_content_set(&b->branch_tree, sha1_to_hex(commit_sha1), sha1,
S_IFREG | 0644, NULL);
}

static void file_change_deleteall(struct branch *b)
{
release_tree_content_recursive(b->branch_tree.tree);
Expand Down Expand Up @@ -2175,6 +2253,8 @@ static void parse_new_commit(void)
file_change_cr(b, 1);
else if (!prefixcmp(command_buf.buf, "C "))
file_change_cr(b, 0);
else if (!prefixcmp(command_buf.buf, "N "))
note_change_n(b);
else if (!strcmp("deleteall", command_buf.buf))
file_change_deleteall(b);
else {
Expand Down
Loading

0 comments on commit 885d492

Please sign in to comment.