* [PATCH 01/15] git-note: Add git-note command for adding/listing/deleting git notes
2007-05-27 14:08 ` [PATCH 00/15] git-note: A mechanisim for providing free-form after-the-fact annotations on commits Johan Herland
@ 2007-05-27 14:09 ` Johan Herland
2007-05-27 14:10 ` [PATCH 02/15] git-note: (Documentation) Add git-note manual page Johan Herland
` (15 subsequent siblings)
16 siblings, 0 replies; 53+ messages in thread
From: Johan Herland @ 2007-05-27 14:09 UTC (permalink / raw)
To: git; +Cc: Linus Torvalds, Junio C Hamano
Synopsis:
'git-note' [-m <msg> | -F <file>] [<head>]
'git-note' -l [<name>...]
'git-note' -d <name>...
'git-note' without any parameters creates 'note' associated with HEAD.
Specifying an object name/ref to 'git-note' will cause the note to
be associated with that object instead.
`git-note -l [<name>...]` lists notes associated with the given <name>s.
If no <name> is given, all notes are listed. The given <name> may itself
be a note object, in which case it is listed along with its associated
notes (if any).
`git-note -d <name>...` deletes the notes associated with the given
<name>s. The given <name> may itself be a note object, in which case it is
deleted along with its associated notes (if any).
git-note.sh is partly based on git-tag.sh
Signed-off-by: Johan Herland <johan@herland.net>
---
git-note.sh | 227 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 227 insertions(+), 0 deletions(-)
create mode 100755 git-note.sh
diff --git a/git-note.sh b/git-note.sh
new file mode 100755
index 0000000..4f539e2
--- /dev/null
+++ b/git-note.sh
@@ -0,0 +1,227 @@
+#!/bin/sh
+
+USAGE='-l [<name>...] | -d <name>... | [-m <msg> | -F <file>] [<head>]'
+LONG_USAGE='Add, delete and show git object notes
+ -l list/show notes associated with the given object.
+ -d delete the notes associated with the given object.
+ -m use the given note message (instead of prompting).
+ -F Take the note message from the given file (instead of prompting).
+For -l and -d, the given <name> may be a note object itself, in which case
+it will be included in the listing/deletion.
+When <head> is not given, it defaults to HEAD.'
+SUBDIRECTORY_OK='Yes'
+. git-sh-setup
+
+
+# Show the note identified by $1
+show_note () {
+ authordate=$(git-cat-file -p $1 | grep -m1 '^tagger ' | cut -c8-)
+ echo
+ echo "--- by $authordate"
+ git-cat-file -p $1 | tail -n+6
+ return 0
+}
+
+# Show notes below the refs/notes directory given in $1
+show_notes_below_dir () {
+ prev_object=
+ for note_data in $(git-for-each-ref --shell \
+ --sort=-taggerdate --sort=*authordate \
+ --format='note=%(objectname);object=%(*objectname);object_type=%(*objecttype);object_tag=%(*tag);' \
+ $1)
+ do
+ eval "$note_data"
+
+ # Separate note objects from regular tags
+ if test "$object_type" = "tag" -a -n "$(echo "$object_tag" | grep '^note-')"; then
+ object_type="note"
+ object_tag=""
+ fi
+
+ description=
+ # Create description based on object type
+ case "$object_type" in
+ commit)
+ description="$(git-show --pretty='format:%h (%s) by %an <%ae> on %aD' $object | head -n1)"
+ ;;
+ tag)
+ description="$object ($object_tag)"
+ ;;
+ *)
+ description="$object"
+ ;;
+ esac
+
+ if test "$object" != "$prev_object"; then
+ test -z "$prev_object" || echo
+ echo "=== Notes on $object_type $description"
+ fi
+ show_note $note
+ prev_object="$object"
+ done
+ return 0
+}
+
+# Show the notes associated with the objects in $@
+show_associated_notes () {
+ if test "$#" = "0"; then
+ show_notes_below_dir "refs/notes"
+ return 0
+ fi
+
+ while case "$#" in 0) break ;; esac
+ do
+ obj=$(git-rev-parse --verify "$1") || \
+ die "error: failed to find object named '$1'"
+
+ # If $obj is a note itself, handle it first
+ if test "$(git-cat-file -t $obj)" = "tag"; then
+ if test -n "$(git-cat-file -p $obj | grep '^tag note-')"; then
+ echo
+ echo "=== Note $obj"
+ show_note "$obj"
+ fi
+ fi
+
+ # List all notes associated with $obj.
+ show_notes_below_dir "refs/notes/$obj"
+
+ shift
+ done
+ return 0
+}
+
+# Delete the noteref in $1 pointing to the note identified by the SHA1 in $2
+delete_note () {
+ git-update-ref -m "note: delete" -d "$1" "$2"
+ return 0
+}
+
+# Delete all notes associated with object in $1
+delete_object_notes () {
+ for note_data in $(git-for-each-ref --shell \
+ --sort=taggerdate --sort=*authordate \
+ --format='note=%(objectname);object=%(*objectname);object_type=%(*objecttype);noteref=%(refname)' \
+ refs/notes/$1)
+ do
+ eval "$note_data"
+ echo "Deleting note $note associated with $object_type $object"
+ delete_note "$noteref" "$note"
+ done
+
+ # Try to get rid of $object's directory below refs/notes as well
+ if test -d "$GIT_DIR/refs/notes/$1"; then
+ rmdir "$GIT_DIR/refs/notes/$1"
+ fi
+ return 0
+}
+
+# Delete the notes associated with the objects in $@
+delete_associated_notes () {
+ while case "$#" in 0) break ;; esac
+ do
+ obj=$(git-rev-parse --verify "$1") || \
+ die "error: failed to find object named '$1'"
+
+ # If $obj is a note itself, handle it first
+ if test "$(git-cat-file -t $obj)" = "tag"; then
+ objref="$(git-cat-file -p $obj | grep -m1 '^object ' | cut -c8-)"
+ if test -n "$objref"; then
+ echo "Deleting note $obj"
+ delete_note "refs/notes/$objref/$obj" "$obj"
+ fi
+ fi
+
+ # Delete all notes associated with $obj
+ delete_object_notes "$obj"
+
+ shift
+ done
+ return 0
+}
+
+message_given=
+message=
+while case "$#" in 0) break ;; esac
+do
+ case "$1" in
+ -l)
+ shift
+ show_associated_notes "$@"
+ exit $?
+ ;;
+ -d)
+ shift
+ if test "$#" = "0"; then
+ die "error: option -d needs one or more objects"
+ fi
+ delete_associated_notes "$@"
+ exit $?
+ ;;
+ -m)
+ shift
+ message="$1"
+ if test "$#" = "0"; then
+ die "error: option -m needs an argument"
+ else
+ message_given=1
+ fi
+ ;;
+ -F)
+ shift
+ if test "$#" = "0"; then
+ die "error: option -F needs an argument"
+ else
+ message="$(cat "$1")"
+ message_given=1
+ fi
+ ;;
+ -*)
+ usage
+ ;;
+ *)
+ break
+ ;;
+ esac
+ shift
+done
+
+object=$(git-rev-parse --verify --default HEAD "$@") || exit 1
+type=$(git-cat-file -t $object) || exit 1
+tagger=$(git-var GIT_COMMITTER_IDENT) || exit 1
+
+# Process note message
+trap 'rm -f "$GIT_DIR"/NOTE_TMP* "$GIT_DIR"/NOTE_FINALMSG "$GIT_DIR"/NOTE_EDITMSG' 0
+
+if test -z "$message_given"; then
+ ( echo ""
+ echo "#"
+ echo "# Write a note on $type $object"
+ echo "#" ) > "$GIT_DIR/NOTE_EDITMSG"
+ ${VISUAL:-${EDITOR:-vi}} "$GIT_DIR/NOTE_EDITMSG" || exit
+else
+ printf '%s\n' "$message" >"$GIT_DIR/NOTE_EDITMSG"
+fi
+
+grep -v '^#' <"$GIT_DIR/NOTE_EDITMSG" |
+git-stripspace >"$GIT_DIR/NOTE_FINALMSG"
+
+test -s "$GIT_DIR/NOTE_FINALMSG" -o -n "$message_given" || {
+ echo >&2 "No note?"
+ exit 1
+}
+
+name="note-`( printf 'object %s\ntagger %s\n\n' "$tagger"; \
+ cat "$GIT_DIR/NOTE_FINALMSG" ) \
+ | sha1sum | cut -d" " -f1`"
+
+git-check-ref-format "notes/$object/$name" ||
+ die "Failed to create a valid note name. (internal git-note error)"
+
+( printf 'object %s\ntype %s\ntag %s\ntagger %s\n\n' \
+ "$object" "$type" "$name" "$tagger";
+ cat "$GIT_DIR/NOTE_FINALMSG" ) >"$GIT_DIR/NOTE_TMP"
+rm -f "$GIT_DIR/NOTE_FINALMSG"
+note=$(git-mktag < "$GIT_DIR/NOTE_TMP")
+
+git-update-ref "refs/notes/$object/$note" "$note"
--
1.5.2.101.gee49f
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH 02/15] git-note: (Documentation) Add git-note manual page
2007-05-27 14:08 ` [PATCH 00/15] git-note: A mechanisim for providing free-form after-the-fact annotations on commits Johan Herland
2007-05-27 14:09 ` [PATCH 01/15] git-note: Add git-note command for adding/listing/deleting git notes Johan Herland
@ 2007-05-27 14:10 ` Johan Herland
2007-05-27 14:11 ` [PATCH 03/15] git-note: (Administrivia) Add git-note to Makefile, .gitignore, etc Johan Herland
` (14 subsequent siblings)
16 siblings, 0 replies; 53+ messages in thread
From: Johan Herland @ 2007-05-27 14:10 UTC (permalink / raw)
To: git; +Cc: Linus Torvalds, Junio C Hamano
The manual page describes the operation of the git-note command, as well
as some discussion around the design and usage of git notes.
Signed-off-by: Johan Herland <johan@herland.net>
---
Documentation/git-note.txt | 95 ++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 95 insertions(+), 0 deletions(-)
create mode 100644 Documentation/git-note.txt
diff --git a/Documentation/git-note.txt b/Documentation/git-note.txt
new file mode 100644
index 0000000..077d526
--- /dev/null
+++ b/Documentation/git-note.txt
@@ -0,0 +1,95 @@
+git-note(1)
+===========
+
+NAME
+----
+git-note - Create, list or delete git note objects
+
+
+SYNOPSIS
+--------
+[verse]
+'git-note' [-m <msg> | -F <file>] [<head>]
+'git-note' -l [<name>...]
+'git-note' -d <name>...
+
+
+DESCRIPTION
+-----------
+Adds a 'note' in `.git/refs/notes/` on an existing git object.
+
+A 'note' is an annotation associated with an existing git object.
+The note is similar in form to a commit message.
+
+Unless `-l` or `-d` is passed, the command creates a 'note' object,
+and requires the note message. Unless `-m <msg>` or `-F <file>` is
+given, an editor is started for the user to type in the note message.
+
+`-l [<name>...]` lists notes associated with the given <name>s. If no
+<name> is given, all notes are listed. The given <name> may itself be
+a note object, in which case it is listed along with its associated
+notes (if any).
+
+`-d <name>...` deletes the notes associated with the given <name>s.
+The given <name> may itself be a note object, in which case it is
+deleted along with its associated notes (if any).
+
+
+OPTIONS
+-------
+-d <name>...::
+ Delete existing notes associated with the given name(s).
+
+-l [<name>...]::
+ List notes associated with the given name(s). List all notes id no
+ name is given.
+
+-m <msg>::
+ Use the given note message (instead of prompting)
+
+-F <file>::
+ Take the note message from the given file (instead of prompting).
+ Use '-' to read the message from the standard input.
+
+
+DISCUSSION
+----------
+A git note provides an after-the-fact text annotation associated with an
+exiting object in the git object database. The note itself is also stored
+in the database (as a special case of a tag object). Note object are therefore
+-- as all other objects in the database -- immutable, i.e. once added they
+cannot be edited, although they can be deleted.
+
+As with regular tag objects, notes are useless unless they have a
+corresponding reference stored in `.git/refs`. For notes, these references
+are stored in a hierarchy under `.git/refs/notes`. For each object that has
+one or more associated notes, there is a subdirectory under
+`.git/refs/notes` named after the object identifier (SHA1 sum). The
+object's subdirectory contains one file per note associated with that object.
+The end result is that notes are easily accessible from the name/identifier
+of the object they are associated with.
+
+Note that deleting a note with `git-note -d` only deletes the reference to
+the note. The note itself is still present in the object database, but will
+be considered unreachable by gitlink:git-fsck[1], and may be removed with
+gitlink:git-prune[1].
+
+
+USE CASE
+--------
+Notes may be used to add any kind of extra information to existing git
+objects that may not become apparent until 'after' the original object is
+created. A common use case is to add -- for example -- information on bugs
+to existing commit objects. E.g. making notes like "This commit closes
+bug #123", or "This commit opens bug #456". These messages may then be
+parsed by custom tools that interoperate with a bug tracker, etc.
+
+
+Author
+------
+Written by Johan Herland <johan@herland.net>.
+
+
+GIT
+---
+Part of the gitlink:git[7] suite
--
1.5.2.101.gee49f
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH 03/15] git-note: (Administrivia) Add git-note to Makefile, .gitignore, etc.
2007-05-27 14:08 ` [PATCH 00/15] git-note: A mechanisim for providing free-form after-the-fact annotations on commits Johan Herland
2007-05-27 14:09 ` [PATCH 01/15] git-note: Add git-note command for adding/listing/deleting git notes Johan Herland
2007-05-27 14:10 ` [PATCH 02/15] git-note: (Documentation) Add git-note manual page Johan Herland
@ 2007-05-27 14:11 ` Johan Herland
2007-05-27 14:11 ` [PATCH 04/15] git-note: (Plumbing) Add plumbing-level support for git notes Johan Herland
` (13 subsequent siblings)
16 siblings, 0 replies; 53+ messages in thread
From: Johan Herland @ 2007-05-27 14:11 UTC (permalink / raw)
To: git; +Cc: Linus Torvalds, Junio C Hamano
Teach Makefile, .gitignore, Documentation/cmd-list.perl and
generate-cmdlist.sh on the existence of the git-note command.
The patch also does some unrelated whitespace cleanup in
Documentation/cmd-list.perl and an alphabetizing fix in .gitignore,
just to keep things neat and tidy.
Signed-off-by: Johan Herland <johan@herland.net>
---
.gitignore | 3 ++-
Documentation/cmd-list.perl | 5 +++--
Makefile | 2 +-
generate-cmdlist.sh | 1 +
4 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/.gitignore b/.gitignore
index 4dc0c39..0f34b94 100644
--- a/.gitignore
+++ b/.gitignore
@@ -82,8 +82,9 @@ git-merge-subtree
git-mergetool
git-mktag
git-mktree
-git-name-rev
git-mv
+git-name-rev
+git-note
git-pack-redundant
git-pack-objects
git-pack-refs
diff --git a/Documentation/cmd-list.perl b/Documentation/cmd-list.perl
index 443802a..dc7e8b3 100755
--- a/Documentation/cmd-list.perl
+++ b/Documentation/cmd-list.perl
@@ -103,13 +103,13 @@ git-diff-files plumbinginterrogators
git-diff-index plumbinginterrogators
git-diff mainporcelain
git-diff-tree plumbinginterrogators
-git-fast-import ancillarymanipulators
+git-fast-import ancillarymanipulators
git-fetch mainporcelain
git-fetch-pack synchingrepositories
git-fmt-merge-msg purehelpers
git-for-each-ref plumbinginterrogators
git-format-patch mainporcelain
-git-fsck ancillaryinterrogators
+git-fsck ancillaryinterrogators
git-gc mainporcelain
git-get-tar-commit-id ancillaryinterrogators
git-grep mainporcelain
@@ -140,6 +140,7 @@ git-mktag plumbingmanipulators
git-mktree plumbingmanipulators
git-mv mainporcelain
git-name-rev plumbinginterrogators
+git-note mainporcelain
git-pack-objects plumbingmanipulators
git-pack-redundant plumbinginterrogators
git-pack-refs ancillarymanipulators
diff --git a/Makefile b/Makefile
index 29243c6..c2f9f22 100644
--- a/Makefile
+++ b/Makefile
@@ -209,7 +209,7 @@ SCRIPT_SH = \
git-applymbox.sh git-applypatch.sh git-am.sh \
git-merge.sh git-merge-stupid.sh git-merge-octopus.sh \
git-merge-resolve.sh git-merge-ours.sh \
- git-lost-found.sh git-quiltimport.sh
+ git-lost-found.sh git-quiltimport.sh git-note.sh
SCRIPT_PERL = \
git-add--interactive.perl \
diff --git a/generate-cmdlist.sh b/generate-cmdlist.sh
index 975777f..0a37fd0 100755
--- a/generate-cmdlist.sh
+++ b/generate-cmdlist.sh
@@ -26,6 +26,7 @@ init
log
merge
mv
+note
prune
pull
push
--
1.5.2.101.gee49f
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH 04/15] git-note: (Plumbing) Add plumbing-level support for git notes
2007-05-27 14:08 ` [PATCH 00/15] git-note: A mechanisim for providing free-form after-the-fact annotations on commits Johan Herland
` (2 preceding siblings ...)
2007-05-27 14:11 ` [PATCH 03/15] git-note: (Administrivia) Add git-note to Makefile, .gitignore, etc Johan Herland
@ 2007-05-27 14:11 ` Johan Herland
2007-05-27 14:12 ` [PATCH 05/15] git-note: (Plumbing) Add support for git notes to git-rev-parse and git-show-ref Johan Herland
` (12 subsequent siblings)
16 siblings, 0 replies; 53+ messages in thread
From: Johan Herland @ 2007-05-27 14:11 UTC (permalink / raw)
To: git; +Cc: Linus Torvalds, Junio C Hamano
This patch declares and implements two functions:
1. for_each_note_ref() - for iterating over note references in refs/notes.
This is analogous to for_each_tag_ref(), for_each_branch_ref() and
for_each_remote_ref(), which is already present.
2. cleanup_notes_subdirs() - a convenience function for removing empty
subdirectories from refs/notes. These subdirectories would otherwise be
left behind after removing notes, or after packing note refs.
The above functions will be used by subsequent git-note patches.
Signed-off-by: Johan Herland <johan@herland.net>
---
refs.c | 20 ++++++++++++++++++++
refs.h | 4 ++++
2 files changed, 24 insertions(+), 0 deletions(-)
diff --git a/refs.c b/refs.c
index 2ae3235..f0abfcd 100644
--- a/refs.c
+++ b/refs.c
@@ -569,6 +569,11 @@ int for_each_tag_ref(each_ref_fn fn, void *cb_data)
return do_for_each_ref("refs/tags/", fn, 10, cb_data);
}
+int for_each_note_ref(each_ref_fn fn, void *cb_data)
+{
+ return do_for_each_ref("refs/notes/", fn, 11, cb_data);
+}
+
int for_each_branch_ref(each_ref_fn fn, void *cb_data)
{
return do_for_each_ref("refs/heads/", fn, 11, cb_data);
@@ -1433,3 +1438,18 @@ int for_each_reflog(each_ref_fn fn, void *cb_data)
{
return do_for_each_reflog("", fn, cb_data);
}
+
+void cleanup_notes_subdirs ()
+{
+ DIR *dir = opendir(git_path("refs/notes/"));
+
+ if (dir) {
+ struct dirent *de;
+ while ((de = readdir(dir)) != NULL) {
+ if (de->d_name[0] == '.')
+ continue;
+ rmdir(git_path("refs/notes/%s", de->d_name));
+ }
+ closedir(dir);
+ }
+}
diff --git a/refs.h b/refs.h
index f234eb7..6175bfb 100644
--- a/refs.h
+++ b/refs.h
@@ -21,6 +21,7 @@ typedef int each_ref_fn(const char *refname, const unsigned char *sha1, int flag
extern int head_ref(each_ref_fn, void *);
extern int for_each_ref(each_ref_fn, void *);
extern int for_each_tag_ref(each_ref_fn, void *);
+extern int for_each_note_ref(each_ref_fn, void *);
extern int for_each_branch_ref(each_ref_fn, void *);
extern int for_each_remote_ref(each_ref_fn, void *);
@@ -64,4 +65,7 @@ extern int rename_ref(const char *oldref, const char *newref, const char *logmsg
/** resolve ref in nested "gitlink" repository */
extern int resolve_gitlink_ref(const char *name, const char *refname, unsigned char *result);
+/** clean up empty subdirs below "refs/notes/" */
+extern void cleanup_notes_subdirs();
+
#endif /* REFS_H */
--
1.5.2.101.gee49f
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH 05/15] git-note: (Plumbing) Add support for git notes to git-rev-parse and git-show-ref
2007-05-27 14:08 ` [PATCH 00/15] git-note: A mechanisim for providing free-form after-the-fact annotations on commits Johan Herland
` (3 preceding siblings ...)
2007-05-27 14:11 ` [PATCH 04/15] git-note: (Plumbing) Add plumbing-level support for git notes Johan Herland
@ 2007-05-27 14:12 ` Johan Herland
2007-05-27 14:13 ` [PATCH 06/15] git-note: (Documentation) Explain the new '--notes' option " Johan Herland
` (11 subsequent siblings)
16 siblings, 0 replies; 53+ messages in thread
From: Johan Herland @ 2007-05-27 14:12 UTC (permalink / raw)
To: git; +Cc: Linus Torvalds, Junio C Hamano
Teach git-rev-parse and git-show-ref to show notes by adding a '--notes'
option. The '--notes' option is analogous to the '--tags' option for the
respective commands.
Signed-off-by: Johan Herland <johan@herland.net>
---
builtin-rev-parse.c | 5 +++++
builtin-show-ref.c | 16 +++++++++++-----
2 files changed, 16 insertions(+), 5 deletions(-)
diff --git a/builtin-rev-parse.c b/builtin-rev-parse.c
index 37addb2..4ab88af 100644
--- a/builtin-rev-parse.c
+++ b/builtin-rev-parse.c
@@ -43,6 +43,7 @@ static int is_rev_argument(const char *arg)
"--max-count=",
"--min-age=",
"--no-merges",
+ "--notes",
"--objects",
"--objects-edge",
"--parents",
@@ -310,6 +311,10 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
for_each_tag_ref(show_reference, NULL);
continue;
}
+ if (!strcmp(arg, "--notes")) {
+ for_each_note_ref(show_reference, NULL);
+ continue;
+ }
if (!strcmp(arg, "--remotes")) {
for_each_remote_ref(show_reference, NULL);
continue;
diff --git a/builtin-show-ref.c b/builtin-show-ref.c
index 9463ff0..8a7d0e7 100644
--- a/builtin-show-ref.c
+++ b/builtin-show-ref.c
@@ -4,10 +4,11 @@
#include "tag.h"
#include "path-list.h"
-static const char show_ref_usage[] = "git show-ref [-q|--quiet] [--verify] [-h|--head] [-d|--dereference] [-s|--hash[=<length>]] [--abbrev[=<length>]] [--tags] [--heads] [--] [pattern*] < ref-list";
+static const char show_ref_usage[] = "git show-ref [-q|--quiet] [--verify] [-h|--head] [-d|--dereference] [-s|--hash[=<length>]] [--abbrev[=<length>]] [--tags] [--heads] [--notes] [--] [pattern*] < ref-list";
static int deref_tags = 0, show_head = 0, tags_only = 0, heads_only = 0,
- found_match = 0, verify = 0, quiet = 0, hash_only = 0, abbrev = 0;
+ notes_only = 0, found_match = 0, verify = 0, quiet = 0, hash_only = 0,
+ abbrev = 0;
static const char **pattern;
static void show_one(const char *refname, const unsigned char *sha1)
@@ -25,11 +26,12 @@ static int show_ref(const char *refname, const unsigned char *sha1, int flag, vo
const char *hex;
unsigned char peeled[20];
- if (tags_only || heads_only) {
+ if (tags_only || heads_only || notes_only) {
int match;
- match = heads_only && !prefixcmp(refname, "refs/heads/");
- match |= tags_only && !prefixcmp(refname, "refs/tags/");
+ match = heads_only && !prefixcmp(refname, "refs/heads/");
+ match |= tags_only && !prefixcmp(refname, "refs/tags/");
+ match |= notes_only && !prefixcmp(refname, "refs/notes/");
if (!match)
return 0;
}
@@ -213,6 +215,10 @@ int cmd_show_ref(int argc, const char **argv, const char *prefix)
heads_only = 1;
continue;
}
+ if (!strcmp(arg, "--notes")) {
+ notes_only = 1;
+ continue;
+ }
if (!strcmp(arg, "--exclude-existing"))
return exclude_existing(NULL);
if (!prefixcmp(arg, "--exclude-existing="))
--
1.5.2.101.gee49f
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH 06/15] git-note: (Documentation) Explain the new '--notes' option to git-rev-parse and git-show-ref
2007-05-27 14:08 ` [PATCH 00/15] git-note: A mechanisim for providing free-form after-the-fact annotations on commits Johan Herland
` (4 preceding siblings ...)
2007-05-27 14:12 ` [PATCH 05/15] git-note: (Plumbing) Add support for git notes to git-rev-parse and git-show-ref Johan Herland
@ 2007-05-27 14:13 ` Johan Herland
2007-05-27 14:13 ` [PATCH 07/15] git-note: (Almost plumbing) Add support for git notes to git-pack-refs and git-fsck Johan Herland
` (10 subsequent siblings)
16 siblings, 0 replies; 53+ messages in thread
From: Johan Herland @ 2007-05-27 14:13 UTC (permalink / raw)
To: git; +Cc: Linus Torvalds, Junio C Hamano
Signed-off-by: Johan Herland <johan@herland.net>
---
Documentation/git-rev-parse.txt | 5 ++++-
Documentation/git-show-ref.txt | 14 +++++++-------
2 files changed, 11 insertions(+), 8 deletions(-)
diff --git a/Documentation/git-rev-parse.txt b/Documentation/git-rev-parse.txt
index 7757abe..7d36011 100644
--- a/Documentation/git-rev-parse.txt
+++ b/Documentation/git-rev-parse.txt
@@ -73,8 +73,11 @@ OPTIONS
--tags::
Show tag refs found in `$GIT_DIR/refs/tags`.
+--notes::
+ Show note refs found in `$GIT_DIR/refs/notes`.
+
--remotes::
- Show tag refs found in `$GIT_DIR/refs/remotes`.
+ Show refs found in `$GIT_DIR/refs/remotes`.
--show-prefix::
When the command is invoked from a subdirectory, show the
diff --git a/Documentation/git-show-ref.txt b/Documentation/git-show-ref.txt
index 2355aa5..7e204f0 100644
--- a/Documentation/git-show-ref.txt
+++ b/Documentation/git-show-ref.txt
@@ -9,7 +9,7 @@ SYNOPSIS
--------
[verse]
'git-show-ref' [-q|--quiet] [--verify] [-h|--head] [-d|--dereference]
- [-s|--hash] [--abbrev] [--tags] [--heads] [--] <pattern>...
+ [-s|--hash] [--abbrev] [--tags] [--heads] [--notes] [--] <pattern>...
'git-show-ref' --exclude-existing[=pattern]
DESCRIPTION
@@ -33,16 +33,16 @@ OPTIONS
Show the HEAD reference.
---tags, --heads::
+--heads, --tags, --notes::
- Limit to only "refs/heads" and "refs/tags", respectively. These
- options are not mutually exclusive; when given both, references stored
- in "refs/heads" and "refs/tags" are displayed.
+ Limit to only "refs/heads", "refs/tags" and "refs/notes", respectively.
+ These options are not mutually exclusive; when given more than one,
+ references classified as any of them are displayed.
-d, --dereference::
- Dereference tags into object IDs as well. They will be shown with "^{}"
- appended.
+ Dereference tags and notes into object IDs as well. They will be shown
+ with "^{}" appended.
-s, --hash::
--
1.5.2.101.gee49f
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH 07/15] git-note: (Almost plumbing) Add support for git notes to git-pack-refs and git-fsck
2007-05-27 14:08 ` [PATCH 00/15] git-note: A mechanisim for providing free-form after-the-fact annotations on commits Johan Herland
` (5 preceding siblings ...)
2007-05-27 14:13 ` [PATCH 06/15] git-note: (Documentation) Explain the new '--notes' option " Johan Herland
@ 2007-05-27 14:13 ` Johan Herland
2007-05-27 14:14 ` [PATCH 08/15] git-note: (Decorations) Add note decorations to "git-{log,show,whatchanged} --decorate" Johan Herland
` (9 subsequent siblings)
16 siblings, 0 replies; 53+ messages in thread
From: Johan Herland @ 2007-05-27 14:13 UTC (permalink / raw)
To: git; +Cc: Linus Torvalds, Junio C Hamano
Teach git-pack-refs to pack note refs in the same way that regular
tag refs are packed. Also, make sure to clean up empty subdirs in
refs/notes after packing note refs.
Teach git-fsck some extra checking of note refs.
Signed-off-by: Johan Herland <johan@herland.net>
---
builtin-fsck.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++
builtin-pack-refs.c | 5 +++-
2 files changed, 65 insertions(+), 1 deletions(-)
diff --git a/builtin-fsck.c b/builtin-fsck.c
index cbbcaf0..edbb976 100644
--- a/builtin-fsck.c
+++ b/builtin-fsck.c
@@ -522,9 +522,70 @@ static int fsck_handle_ref(const char *refname, const unsigned char *sha1, int f
return 0;
}
+static int fsck_handle_note_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
+{
+ /*
+ * - Verify that refname has format $object/$note
+ * - Verify that contents of $object/$note == $note
+ * - Verify that $object/$note references a tag object
+ * - Verify that the tag object points to $object
+ * - Verify that $object exists. (already done by fsck_tag())
+ */
+ /* Even on error, we still return 0 to keep for_each_ref() going. */
+
+ const char *object_name = refname;
+ const char *note_name = strchr(object_name, '/');
+ size_t object_name_len, note_name_len;
+ unsigned char object_sha1[20], note_sha1[20];
+ struct object *note_obj;
+ struct tag *note;
+
+ if (!note_name) {
+ error("%s: invalid note refname; missing note part", refname);
+ return 0;
+ }
+ object_name_len = note_name - object_name;
+ note_name_len = strlen(++note_name);
+ if (object_name_len != 40 || get_sha1_hex(object_name, object_sha1)) {
+ error("%s: invalid note refname; object part not valid SHA1 sum", refname);
+ return 0;
+ }
+ if (note_name_len != 40 || get_sha1_hex(note_name, note_sha1)) {
+ error("%s: invalid note refname; note part not valid SHA1 sum", refname);
+ return 0;
+ }
+ if (hashcmp(note_sha1, sha1)) {
+ error("%s: invalid note ref; note part not identical to note's SHA1 sum (%s)",
+ refname, sha1_to_hex(sha1));
+ return 0;
+ }
+ note_obj = lookup_object(sha1);
+ if (!note_obj) { /* Couldn't find note object... */
+ if (!has_sha1_file(sha1)) /* ...and it's not hidden in a pack */
+ error("%s: invalid note ref; must point at a valid object",
+ refname);
+ return 0; /* Return even if in a pack. */
+ }
+ if (note_obj->type != OBJ_TAG) {
+ error("%s: invalid note ref; must point at tag object (type == %s)",
+ refname, typename(note_obj->type));
+ return 0;
+ }
+ note = (struct tag *) parse_object(sha1);
+ if (hashcmp(note->tagged->sha1, object_sha1)) {
+ error("%s: invalid note ref; "
+ "object part not identical to tagged object (%s)",
+ refname, sha1_to_hex(note->tagged->sha1));
+ return 0;
+ }
+
+ return 0;
+}
+
static void get_default_heads(void)
{
for_each_ref(fsck_handle_ref, NULL);
+ for_each_note_ref(fsck_handle_note_ref, NULL);
if (include_reflogs)
for_each_reflog(fsck_handle_reflog, NULL);
diff --git a/builtin-pack-refs.c b/builtin-pack-refs.c
index 1952950..57b9fee 100644
--- a/builtin-pack-refs.c
+++ b/builtin-pack-refs.c
@@ -39,6 +39,7 @@ static int handle_one_ref(const char *path, const unsigned char *sha1,
if ((flags & REF_ISSYMREF))
return 0;
is_tag_ref = !prefixcmp(path, "refs/tags/");
+ is_tag_ref |= !prefixcmp(path, "refs/notes/");
/* ALWAYS pack refs that were already packed or are tags */
if (!(cb->flags & PACK_REFS_ALL) && !is_tag_ref && !(flags & REF_ISPACKED))
@@ -109,8 +110,10 @@ static int pack_refs(unsigned int flags)
die("failed to write ref-pack file (%s)", strerror(errno));
if (commit_lock_file(&packed) < 0)
die("unable to overwrite old ref-pack file (%s)", strerror(errno));
- if (cbdata.flags & PACK_REFS_PRUNE)
+ if (cbdata.flags & PACK_REFS_PRUNE) {
prune_refs(cbdata.ref_to_prune);
+ cleanup_notes_subdirs();
+ }
return 0;
}
--
1.5.2.101.gee49f
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH 08/15] git-note: (Decorations) Add note decorations to "git-{log,show,whatchanged} --decorate"
2007-05-27 14:08 ` [PATCH 00/15] git-note: A mechanisim for providing free-form after-the-fact annotations on commits Johan Herland
` (6 preceding siblings ...)
2007-05-27 14:13 ` [PATCH 07/15] git-note: (Almost plumbing) Add support for git notes to git-pack-refs and git-fsck Johan Herland
@ 2007-05-27 14:14 ` Johan Herland
2007-05-27 14:14 ` [PATCH 09/15] git-note: (Documentation) Explain new behaviour of --decorate in git-{log,show,whatchanged} Johan Herland
` (8 subsequent siblings)
16 siblings, 0 replies; 53+ messages in thread
From: Johan Herland @ 2007-05-27 14:14 UTC (permalink / raw)
To: git; +Cc: Linus Torvalds, Junio C Hamano
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(¬e_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(¬e_decoration, &commit->object);
+ if (!decoration)
+ return;
+
+ /* Sort notes */
+ while (decoration) {
+ ++numDecorations;
+ decoration = decoration->next;
+ }
+ decoration = lookup_decoration(¬e_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
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH 09/15] git-note: (Documentation) Explain new behaviour of --decorate in git-{log,show,whatchanged}
2007-05-27 14:08 ` [PATCH 00/15] git-note: A mechanisim for providing free-form after-the-fact annotations on commits Johan Herland
` (7 preceding siblings ...)
2007-05-27 14:14 ` [PATCH 08/15] git-note: (Decorations) Add note decorations to "git-{log,show,whatchanged} --decorate" Johan Herland
@ 2007-05-27 14:14 ` Johan Herland
2007-05-27 14:15 ` [PATCH 10/15] git-note: (Transfer) Teach git-clone how to clone notes Johan Herland
` (7 subsequent siblings)
16 siblings, 0 replies; 53+ messages in thread
From: Johan Herland @ 2007-05-27 14:14 UTC (permalink / raw)
To: git; +Cc: Linus Torvalds, Junio C Hamano
The addition of git notes to --decorate output is noted on the git-log
manual page. In addition, the --decorate documentation is copied to the
git-show and git-whatchanged manual pages, where any mention of --decorate
have been missing until now.
Signed-off-by: Johan Herland <johan@herland.net>
---
Documentation/git-log.txt | 3 ++-
Documentation/git-show.txt | 4 ++++
Documentation/git-whatchanged.txt | 4 ++++
3 files changed, 10 insertions(+), 1 deletions(-)
diff --git a/Documentation/git-log.txt b/Documentation/git-log.txt
index 0f353f6..1168372 100644
--- a/Documentation/git-log.txt
+++ b/Documentation/git-log.txt
@@ -52,7 +52,8 @@ include::pretty-options.txt[]
See also gitlink:git-reflog[1].
--decorate::
- Print out the ref names of any commits that are shown.
+ Print out the ref names and notes associated with any commits that are
+ shown.
<paths>...::
Show only commits that affect the specified paths.
diff --git a/Documentation/git-show.txt b/Documentation/git-show.txt
index 34c5caf..a31ba6b 100644
--- a/Documentation/git-show.txt
+++ b/Documentation/git-show.txt
@@ -38,6 +38,10 @@ OPTIONS
For a more complete list of ways to spell object names, see
"SPECIFYING REVISIONS" section in gitlink:git-rev-parse[1].
+--decorate::
+ Print out the ref names and notes associated with any commits that are
+ shown.
+
include::pretty-options.txt[]
diff --git a/Documentation/git-whatchanged.txt b/Documentation/git-whatchanged.txt
index 399bff3..3f77b3d 100644
--- a/Documentation/git-whatchanged.txt
+++ b/Documentation/git-whatchanged.txt
@@ -43,6 +43,10 @@ OPTIONS
<format> can be one of 'raw', 'medium', 'short', 'full',
and 'oneline'.
+--decorate::
+ Print out the ref names and notes associated with any commits that are
+ shown.
+
-m::
By default, differences for merge commits are not shown.
With this flag, show differences to that commit from all
--
1.5.2.101.gee49f
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH 10/15] git-note: (Transfer) Teach git-clone how to clone notes
2007-05-27 14:08 ` [PATCH 00/15] git-note: A mechanisim for providing free-form after-the-fact annotations on commits Johan Herland
` (8 preceding siblings ...)
2007-05-27 14:14 ` [PATCH 09/15] git-note: (Documentation) Explain new behaviour of --decorate in git-{log,show,whatchanged} Johan Herland
@ 2007-05-27 14:15 ` Johan Herland
2007-05-27 14:15 ` [PATCH 11/15] git-note: (Transfer) Teach git-fetch to auto-follow notes Johan Herland
` (6 subsequent siblings)
16 siblings, 0 replies; 53+ messages in thread
From: Johan Herland @ 2007-05-27 14:15 UTC (permalink / raw)
To: git; +Cc: Linus Torvalds, Junio C Hamano
This patch causes git notes to be cloned in the same way that tags are
cloned.
Signed-off-by: Johan Herland <johan@herland.net>
---
git-clone.sh | 5 ++++-
1 files changed, 4 insertions(+), 1 deletions(-)
diff --git a/git-clone.sh b/git-clone.sh
index fdd354f..6bb2fd5 100755
--- a/git-clone.sh
+++ b/git-clone.sh
@@ -57,7 +57,7 @@ Perhaps git-update-server-info needs to be run there?"
*^*) continue;;
esac
case "$bare,$name" in
- yes,* | ,heads/* | ,tags/*) ;;
+ yes,* | ,heads/* | ,tags/* | ,notes/*) ;;
*) continue ;;
esac
if test -n "$use_separate_remote" &&
@@ -320,6 +320,7 @@ then
branch_top="heads"
fi
tag_top="tags"
+ note_top="notes"
while read sha1 name
do
case "$name" in
@@ -331,6 +332,8 @@ then
destname="refs/$branch_top/${name#refs/heads/}" ;;
refs/tags/*)
destname="refs/$tag_top/${name#refs/tags/}" ;;
+ refs/notes/*)
+ destname="refs/$note_top/${name#refs/notes/}" ;;
*)
continue ;;
esac
--
1.5.2.101.gee49f
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH 11/15] git-note: (Transfer) Teach git-fetch to auto-follow notes
2007-05-27 14:08 ` [PATCH 00/15] git-note: A mechanisim for providing free-form after-the-fact annotations on commits Johan Herland
` (9 preceding siblings ...)
2007-05-27 14:15 ` [PATCH 10/15] git-note: (Transfer) Teach git-clone how to clone notes Johan Herland
@ 2007-05-27 14:15 ` Johan Herland
2007-05-27 14:15 ` [PATCH 12/15] git-note: (Transfer) Teach git-push to push notes when --all or --notes is given Johan Herland
` (5 subsequent siblings)
16 siblings, 0 replies; 53+ messages in thread
From: Johan Herland @ 2007-05-27 14:15 UTC (permalink / raw)
To: git; +Cc: Linus Torvalds, Junio C Hamano
This causes git-fetch to auto-follow notes in the same fashion that tags
are auto-followed by default.
Pretty much all the code in this patch is about doing the same thing for
notes as what is already done for tags.
Signed-off-by: Johan Herland <johan@herland.net>
---
builtin-fetch--tool.c | 11 +++++++++++
git-fetch.sh | 27 +++++++++++++++++++++++++++
git-parse-remote.sh | 4 ++--
3 files changed, 40 insertions(+), 2 deletions(-)
diff --git a/builtin-fetch--tool.c b/builtin-fetch--tool.c
index ed4d5de..71ddc6d 100644
--- a/builtin-fetch--tool.c
+++ b/builtin-fetch--tool.c
@@ -82,6 +82,8 @@ static int update_local_ref(const char *name,
/* new ref */
if (!strncmp(name, "refs/tags/", 10))
msg = "storing tag";
+ else if (!strncmp(name, "refs/notes/", 11))
+ msg = "storing note";
else
msg = "storing head";
fprintf(stderr, "* %s: storing %s\n",
@@ -103,6 +105,11 @@ static int update_local_ref(const char *name,
show_new(type, sha1_new);
return update_ref("updating tag", name, sha1_new, NULL);
}
+ else if (!strncmp(name, "refs/notes/", 11)) {
+ fprintf(stderr, "* %s: updating with %s\n", name, note);
+ show_new(type, sha1_new);
+ return update_ref("updating note", name, sha1_new, NULL);
+ }
current = lookup_commit_reference(sha1_old);
updated = lookup_commit_reference(sha1_new);
@@ -163,6 +170,10 @@ static int append_fetch_head(FILE *fp,
kind = "tag";
what = remote_name + 10;
}
+ else if (!strncmp(remote_name, "refs/notes/", 11)) {
+ kind = "note";
+ what = remote_name + 11;
+ }
else if (!strncmp(remote_name, "refs/remotes/", 13)) {
kind = "remote branch";
what = remote_name + 13;
diff --git a/git-fetch.sh b/git-fetch.sh
index 0e05cf1..a2a7874 100755
--- a/git-fetch.sh
+++ b/git-fetch.sh
@@ -353,6 +353,33 @@ case "$no_tags$tags" in
esac
esac
+# automated note following
+case "" in # --notes and --no-notes options?
+'')
+ case "$reflist" in
+ *:refs/*)
+ # effective only when we are following remote branch
+ # using local tracking branch.
+ notelist=$(IFS=' ' &&
+ echo "$ls_remote_result" |
+ git-show-ref --exclude-existing=refs/notes/ |
+ while read sha1 name
+ do
+ git-cat-file -t "$sha1" >/dev/null 2>&1 || continue
+ echo >&2 "Auto-following $name"
+ echo ".${name}:${name}"
+ done)
+ esac
+ case "$notelist" in
+ '') ;;
+ ?*)
+ # do not deepen a shallow tree when following notes
+ shallow_depth=
+ fetch_main "$notelist" || exit ;;
+ esac
+esac
+
+
# If the original head was empty (i.e. no "master" yet), or
# if we were told not to worry, we do not have to check.
case "$orig_head" in
diff --git a/git-parse-remote.sh b/git-parse-remote.sh
index 0506b12..95dcc10 100755
--- a/git-parse-remote.sh
+++ b/git-parse-remote.sh
@@ -144,13 +144,13 @@ canon_refs_list_for_fetch () {
case "$remote" in
'' | HEAD ) remote=HEAD ;;
refs/*) ;;
- heads/* | tags/* | remotes/* ) remote="refs/$remote" ;;
+ heads/* | tags/* | notes/* | remotes/* ) remote="refs/$remote" ;;
*) remote="refs/heads/$remote" ;;
esac
case "$local" in
'') local= ;;
refs/*) ;;
- heads/* | tags/* | remotes/* ) local="refs/$local" ;;
+ heads/* | tags/* | notes/* | remotes/* ) local="refs/$local" ;;
*) local="refs/heads/$local" ;;
esac
--
1.5.2.101.gee49f
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH 12/15] git-note: (Transfer) Teach git-push to push notes when --all or --notes is given
2007-05-27 14:08 ` [PATCH 00/15] git-note: A mechanisim for providing free-form after-the-fact annotations on commits Johan Herland
` (10 preceding siblings ...)
2007-05-27 14:15 ` [PATCH 11/15] git-note: (Transfer) Teach git-fetch to auto-follow notes Johan Herland
@ 2007-05-27 14:15 ` Johan Herland
2007-05-27 14:16 ` [PATCH 13/15] git-note: (Documentation) Explain the new --notes option to git-push Johan Herland
` (4 subsequent siblings)
16 siblings, 0 replies; 53+ messages in thread
From: Johan Herland @ 2007-05-27 14:15 UTC (permalink / raw)
To: git; +Cc: Linus Torvalds, Junio C Hamano
As with tags, git-push will not push notes by default. However, if --all
or --notes (new) is given, git-push will now push notes (similary to tags,
if --all or --tags is given).
Signed-off-by: Johan Herland <johan@herland.net>
---
builtin-push.c | 20 ++++++++++++--------
1 files changed, 12 insertions(+), 8 deletions(-)
diff --git a/builtin-push.c b/builtin-push.c
index cb78401..e3d6a21 100644
--- a/builtin-push.c
+++ b/builtin-push.c
@@ -8,9 +8,9 @@
#define MAX_URI (16)
-static const char push_usage[] = "git-push [--all] [--tags] [--receive-pack=<git-receive-pack>] [--repo=all] [-f | --force] [-v] [<repository> <refspec>...]";
+static const char push_usage[] = "git-push [--all] [--tags] [--notes] [--receive-pack=<git-receive-pack>] [--repo=all] [-f | --force] [-v] [<repository> <refspec>...]";
-static int all, tags, force, thin = 1, verbose;
+static int all, tags, notes, force, thin = 1, verbose;
static const char *receivepack;
#define BUF_SIZE (2084)
@@ -32,7 +32,8 @@ static int expand_one_ref(const char *ref, const unsigned char *sha1, int flag,
/* Ignore the "refs/" at the beginning of the refname */
ref += 5;
- if (!prefixcmp(ref, "tags/"))
+ if ((tags && !prefixcmp(ref, "tags/")) ||
+ (notes && !prefixcmp(ref, "notes/")))
add_refspec(xstrdup(ref));
return 0;
}
@@ -49,9 +50,8 @@ static void expand_refspecs(void)
*/
return;
}
- if (!tags)
- return;
- for_each_ref(expand_one_ref, NULL);
+ if (tags || notes)
+ for_each_ref(expand_one_ref, NULL);
}
struct wildcard_cb {
@@ -141,7 +141,7 @@ static int get_remotes_uri(const char *repo, const char *uri[MAX_URI])
{
int n = 0;
FILE *f = fopen(git_path("remotes/%s", repo), "r");
- int has_explicit_refspec = refspec_nr || all || tags;
+ int has_explicit_refspec = refspec_nr || all || tags || notes;
if (!f)
return -1;
@@ -227,7 +227,7 @@ static int get_config_remotes_uri(const char *repo, const char *uri[MAX_URI])
config_repo = repo;
config_current_uri = 0;
config_uri = uri;
- config_get_refspecs = !(refspec_nr || all || tags);
+ config_get_refspecs = !(refspec_nr || all || tags || notes);
config_get_receivepack = (receivepack == NULL);
git_config(get_remote_config);
@@ -388,6 +388,10 @@ int cmd_push(int argc, const char **argv, const char *prefix)
tags = 1;
continue;
}
+ if (!strcmp(arg, "--notes")) {
+ notes = 1;
+ continue;
+ }
if (!strcmp(arg, "--force") || !strcmp(arg, "-f")) {
force = 1;
continue;
--
1.5.2.101.gee49f
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH 13/15] git-note: (Documentation) Explain the new --notes option to git-push
2007-05-27 14:08 ` [PATCH 00/15] git-note: A mechanisim for providing free-form after-the-fact annotations on commits Johan Herland
` (11 preceding siblings ...)
2007-05-27 14:15 ` [PATCH 12/15] git-note: (Transfer) Teach git-push to push notes when --all or --notes is given Johan Herland
@ 2007-05-27 14:16 ` Johan Herland
2007-05-27 14:16 ` [PATCH 14/15] git-note: (Tests) Add tests for git-note and associated functionality Johan Herland
` (3 subsequent siblings)
16 siblings, 0 replies; 53+ messages in thread
From: Johan Herland @ 2007-05-27 14:16 UTC (permalink / raw)
To: git; +Cc: Linus Torvalds, Junio C Hamano
Signed-off-by: Johan Herland <johan@herland.net>
---
Documentation/git-push.txt | 7 ++++++-
1 files changed, 6 insertions(+), 1 deletions(-)
diff --git a/Documentation/git-push.txt b/Documentation/git-push.txt
index e9ad106..2e98844 100644
--- a/Documentation/git-push.txt
+++ b/Documentation/git-push.txt
@@ -9,7 +9,7 @@ git-push - Update remote refs along with associated objects
SYNOPSIS
--------
[verse]
-'git-push' [--all] [--tags] [--receive-pack=<git-receive-pack>]
+'git-push' [--all] [--tags] [--notes] [--receive-pack=<git-receive-pack>]
[--repo=all] [-f | --force] [-v] [<repository> <refspec>...]
DESCRIPTION
@@ -69,6 +69,11 @@ the remote repository.
addition to refspecs explicitly listed on the command
line.
+\--notes::
+ All refs under `$GIT_DIR/refs/notes` are pushed, in
+ addition to refspecs explicitly listed on the command
+ line.
+
\--receive-pack=<git-receive-pack>::
Path to the 'git-receive-pack' program on the remote
end. Sometimes useful when pushing to a remote
--
1.5.2.101.gee49f
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH 14/15] git-note: (Tests) Add tests for git-note and associated functionality
2007-05-27 14:08 ` [PATCH 00/15] git-note: A mechanisim for providing free-form after-the-fact annotations on commits Johan Herland
` (12 preceding siblings ...)
2007-05-27 14:16 ` [PATCH 13/15] git-note: (Documentation) Explain the new --notes option to git-push Johan Herland
@ 2007-05-27 14:16 ` Johan Herland
2007-05-27 14:17 ` [PATCH 15/15] git-note: Add display of notes to gitk Johan Herland
` (2 subsequent siblings)
16 siblings, 0 replies; 53+ messages in thread
From: Johan Herland @ 2007-05-27 14:16 UTC (permalink / raw)
To: git; +Cc: Linus Torvalds, Junio C Hamano
This test script add tests for:
- git-note (including -l and -d options)
- State of note/tag objects
- git-show-ref --notes
- git-for-each-ref refs/notes
- git-{log,show,whatchanged} --decorate
Signed-off-by: Johan Herland <johan@herland.net>
---
t/t3850-note.sh | 303 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 303 insertions(+), 0 deletions(-)
create mode 100755 t/t3850-note.sh
diff --git a/t/t3850-note.sh b/t/t3850-note.sh
new file mode 100755
index 0000000..f737f7c
--- /dev/null
+++ b/t/t3850-note.sh
@@ -0,0 +1,303 @@
+#!/bin/sh
+#
+# Copyright (c) 2007 Johan Herland
+#
+
+test_description='Test of git-note'
+
+. ./test-lib.sh
+
+
+# Prepare repo and create some notes
+
+test_expect_success 'Preparing for test' '
+ echo "foo" > foo &&
+ git-add foo &&
+ test_tick &&
+ git-commit -m "Initial commit" &&
+ echo "bar" >> foo
+ test_tick &&
+ git-commit -m "Second commit" foo
+'
+test_expect_success 'Testing git-note -m' '
+ test_tick &&
+ git-note -m "spam"
+'
+test_expect_success 'Testing git-note -F' '
+ echo "spam spam" > note.msg &&
+ test_tick &&
+ git-note -F note.msg
+'
+test_expect_success 'Testing git-note <commit>' '
+ test_tick &&
+ git-note -m "spam spam spam" 301711b66fe71164f646b798706a2c1f7024da8d
+'
+
+# At this point we should have:
+# - commit @ 301711b66fe71164f646b798706a2c1f7024da8d ("Initial commit")
+# - note @ 93bbbc95a42852552494327537263d475aac1789 ("spam spam spam")
+# - commit @ 9671cbee7ad26528645b2665c8f74d39a6288864 ("Second commit")
+# - note @ 1245491fece5910086bc1870a4a746256f8a7ecf ("spam")
+# - note @ 466f861dde008d3905d320225eebef727665a3f0 ("spam spam")
+
+# Verify note objects
+
+test_expect_success 'Testing git-cat-file tag <note>' '
+ cat > note.expect << EOF &&
+object 9671cbee7ad26528645b2665c8f74d39a6288864
+type commit
+tag note-14669883eb004f12636307269f537d59eb143125
+tagger C O Mitter <committer@example.com> 1112912113 -0700
+
+spam
+EOF
+ git-cat-file tag 1245491fece5910086bc1870a4a746256f8a7ecf > note.output &&
+ cmp note.expect note.output &&
+ cat > note.expect << EOF &&
+object 9671cbee7ad26528645b2665c8f74d39a6288864
+type commit
+tag note-ad2099b641be660c4e616bf0b46dcaca391764af
+tagger C O Mitter <committer@example.com> 1112912173 -0700
+
+spam spam
+EOF
+ git-cat-file tag 466f861dde008d3905d320225eebef727665a3f0 > note.output &&
+ cmp note.expect note.output &&
+ cat > note.expect << EOF &&
+object 301711b66fe71164f646b798706a2c1f7024da8d
+type commit
+tag note-c1afd1d9a4e2df7efbb29ff88e50e866e88eb108
+tagger C O Mitter <committer@example.com> 1112912233 -0700
+
+spam spam spam
+EOF
+ git-cat-file tag 93bbbc95a42852552494327537263d475aac1789 > note.output &&
+ cmp note.expect note.output
+'
+
+# Verify output from git-note -l
+
+test_expect_success 'Testing git-note -l' '
+ cat > note.expect << EOF &&
+=== Notes on commit 9671cbe (Second commit) by A U Thor <author@example.com> on Thu, 7 Apr 2005 15:14:13 -0700
+
+--- by C O Mitter <committer@example.com> Thu Apr 7 15:15:13 2005 -0700
+spam
+
+--- by C O Mitter <committer@example.com> Thu Apr 7 15:16:13 2005 -0700
+spam spam
+
+=== Notes on commit 301711b (Initial commit) by A U Thor <author@example.com> on Thu, 7 Apr 2005 15:13:13 -0700
+
+--- by C O Mitter <committer@example.com> Thu Apr 7 15:17:13 2005 -0700
+spam spam spam
+EOF
+ git-note -l > note.output &&
+ cmp note.expect note.output
+'
+test_expect_success 'Testing git-note -l <commit>' '
+ cat > note.expect << EOF &&
+=== Notes on commit 9671cbe (Second commit) by A U Thor <author@example.com> on Thu, 7 Apr 2005 15:14:13 -0700
+
+--- by C O Mitter <committer@example.com> Thu Apr 7 15:15:13 2005 -0700
+spam
+
+--- by C O Mitter <committer@example.com> Thu Apr 7 15:16:13 2005 -0700
+spam spam
+EOF
+ git-note -l 9671cbee7ad26528645b2665c8f74d39a6288864 > note.output &&
+ cmp note.expect note.output &&
+ cat > note.expect << EOF &&
+=== Notes on commit 301711b (Initial commit) by A U Thor <author@example.com> on Thu, 7 Apr 2005 15:13:13 -0700
+
+--- by C O Mitter <committer@example.com> Thu Apr 7 15:17:13 2005 -0700
+spam spam spam
+EOF
+ git-note -l 301711b66fe71164f646b798706a2c1f7024da8d > note.output &&
+ cmp note.expect note.output
+'
+test_expect_success 'Testing git-note -l <note> <note> <note>' '
+ cat > note.expect << EOF &&
+
+=== Note 93bbbc95a42852552494327537263d475aac1789
+
+--- by C O Mitter <committer@example.com> Thu Apr 7 15:17:13 2005 -0700
+spam spam spam
+
+=== Note 466f861dde008d3905d320225eebef727665a3f0
+
+--- by C O Mitter <committer@example.com> Thu Apr 7 15:16:13 2005 -0700
+spam spam
+
+=== Note 1245491fece5910086bc1870a4a746256f8a7ecf
+
+--- by C O Mitter <committer@example.com> Thu Apr 7 15:15:13 2005 -0700
+spam
+EOF
+ git-note -l 93bbbc95a42852552494327537263d475aac1789 \
+ 466f861dde008d3905d320225eebef727665a3f0 \
+ 1245491fece5910086bc1870a4a746256f8a7ecf > note.output &&
+ cmp note.expect note.output
+'
+
+# Verify that notes show up in git-show-ref and git-for-each-ref
+
+test_expect_success 'Testing git-show-ref with notes' '
+ cat > note.expect << EOF &&
+9671cbee7ad26528645b2665c8f74d39a6288864 refs/heads/master
+93bbbc95a42852552494327537263d475aac1789 refs/notes/301711b66fe71164f646b798706a2c1f7024da8d/93bbbc95a42852552494327537263d475aac1789
+1245491fece5910086bc1870a4a746256f8a7ecf refs/notes/9671cbee7ad26528645b2665c8f74d39a6288864/1245491fece5910086bc1870a4a746256f8a7ecf
+466f861dde008d3905d320225eebef727665a3f0 refs/notes/9671cbee7ad26528645b2665c8f74d39a6288864/466f861dde008d3905d320225eebef727665a3f0
+EOF
+ git-show-ref > note.output &&
+ cmp note.expect note.output
+'
+test_expect_success 'Testing git-show-ref --notes' '
+ cat > note.expect << EOF &&
+93bbbc95a42852552494327537263d475aac1789 refs/notes/301711b66fe71164f646b798706a2c1f7024da8d/93bbbc95a42852552494327537263d475aac1789
+1245491fece5910086bc1870a4a746256f8a7ecf refs/notes/9671cbee7ad26528645b2665c8f74d39a6288864/1245491fece5910086bc1870a4a746256f8a7ecf
+466f861dde008d3905d320225eebef727665a3f0 refs/notes/9671cbee7ad26528645b2665c8f74d39a6288864/466f861dde008d3905d320225eebef727665a3f0
+EOF
+ git-show-ref --notes > note.output &&
+ cmp note.expect note.output
+'
+test_expect_success 'Testing git-for-each-ref refs/notes' '
+ cat > note.expect << EOF &&
+93bbbc95a42852552494327537263d475aac1789 tag refs/notes/301711b66fe71164f646b798706a2c1f7024da8d/93bbbc95a42852552494327537263d475aac1789
+1245491fece5910086bc1870a4a746256f8a7ecf tag refs/notes/9671cbee7ad26528645b2665c8f74d39a6288864/1245491fece5910086bc1870a4a746256f8a7ecf
+466f861dde008d3905d320225eebef727665a3f0 tag refs/notes/9671cbee7ad26528645b2665c8f74d39a6288864/466f861dde008d3905d320225eebef727665a3f0
+EOF
+ git-for-each-ref refs/notes > note.output &&
+ cmp note.expect note.output
+'
+
+# Verify output from git-log/git-show/git-whatchanged --decorate
+
+test_expect_success 'Testing git-log --decorate' '
+ cat > note.expect << EOF &&
+commit 9671cbee7ad26528645b2665c8f74d39a6288864 (refs/heads/master)
+Author: A U Thor <author@example.com>
+Date: Thu Apr 7 15:14:13 2005 -0700
+
+ Second commit
+
+Notes:
+
+ --- by C O Mitter <committer@example.com> Thu Apr 7 15:15:13 2005 -0700
+ spam
+
+ --- by C O Mitter <committer@example.com> Thu Apr 7 15:16:13 2005 -0700
+ spam spam
+
+commit 301711b66fe71164f646b798706a2c1f7024da8d
+Author: A U Thor <author@example.com>
+Date: Thu Apr 7 15:13:13 2005 -0700
+
+ Initial commit
+
+Notes:
+
+ --- by C O Mitter <committer@example.com> Thu Apr 7 15:17:13 2005 -0700
+ spam spam spam
+EOF
+ git-log --decorate > note.output &&
+ cmp note.expect note.output
+'
+test_expect_success 'Testing git-show --decorate' '
+ cat > note.expect << EOF &&
+commit 9671cbee7ad26528645b2665c8f74d39a6288864 (refs/heads/master)
+Author: A U Thor <author@example.com>
+Date: Thu Apr 7 15:14:13 2005 -0700
+
+ Second commit
+
+Notes:
+
+ --- by C O Mitter <committer@example.com> Thu Apr 7 15:15:13 2005 -0700
+ spam
+
+ --- by C O Mitter <committer@example.com> Thu Apr 7 15:16:13 2005 -0700
+ spam spam
+
+diff --git a/foo b/foo
+index 257cc56..3bd1f0e 100644
+--- a/foo
++++ b/foo
+@@ -1 +1,2 @@
+ foo
++bar
+EOF
+ git-show --decorate > note.output &&
+ cmp note.expect note.output
+'
+test_expect_success 'Testing git-whatchanged --decorate' '
+ cat > note.expect << EOF &&
+commit 9671cbee7ad26528645b2665c8f74d39a6288864 (refs/heads/master)
+Author: A U Thor <author@example.com>
+Date: Thu Apr 7 15:14:13 2005 -0700
+
+ Second commit
+
+Notes:
+
+ --- by C O Mitter <committer@example.com> Thu Apr 7 15:15:13 2005 -0700
+ spam
+
+ --- by C O Mitter <committer@example.com> Thu Apr 7 15:16:13 2005 -0700
+ spam spam
+
+:100644 100644 257cc56... 3bd1f0e... M foo
+
+commit 301711b66fe71164f646b798706a2c1f7024da8d
+Author: A U Thor <author@example.com>
+Date: Thu Apr 7 15:13:13 2005 -0700
+
+ Initial commit
+
+Notes:
+
+ --- by C O Mitter <committer@example.com> Thu Apr 7 15:17:13 2005 -0700
+ spam spam spam
+
+:000000 100644 0000000... 257cc56... A foo
+EOF
+ git-whatchanged --decorate > note.output &&
+ cmp note.expect note.output
+'
+
+# Verify successful removal of notes
+
+test_expect_success 'Testing git-note -d <note>' '
+ cat > note.expect << EOF &&
+Deleting note 93bbbc95a42852552494327537263d475aac1789
+EOF
+ git-note -d 93bbbc95a42852552494327537263d475aac1789 > note.output &&
+ cmp note.expect note.output
+'
+test_expect_success 'Verify repo state after git-note -d <note>' '
+ cat > note.expect << EOF &&
+1245491fece5910086bc1870a4a746256f8a7ecf refs/notes/9671cbee7ad26528645b2665c8f74d39a6288864/1245491fece5910086bc1870a4a746256f8a7ecf
+466f861dde008d3905d320225eebef727665a3f0 refs/notes/9671cbee7ad26528645b2665c8f74d39a6288864/466f861dde008d3905d320225eebef727665a3f0
+EOF
+ git-show-ref --notes > note.output &&
+ cmp note.expect note.output
+'
+test_expect_success 'Testing git-note -d <commit>' '
+ cat > note.expect << EOF &&
+Deleting note 1245491fece5910086bc1870a4a746256f8a7ecf associated with commit 9671cbee7ad26528645b2665c8f74d39a6288864
+Deleting note 466f861dde008d3905d320225eebef727665a3f0 associated with commit 9671cbee7ad26528645b2665c8f74d39a6288864
+EOF
+ git-note -d 9671cbee7ad26528645b2665c8f74d39a6288864 > note.output &&
+ cmp note.expect note.output
+'
+test_expect_success 'Verify repo state after git-note -d <commit>' '
+ cat > note.expect << EOF &&
+EOF
+ git-show-ref --notes > note.output
+ test "$?" == "1" &&
+ cmp note.expect note.output
+'
+
+# Testing of clone/fetch/push?
+
+test_done
--
1.5.2.101.gee49f
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH 15/15] git-note: Add display of notes to gitk
2007-05-27 14:08 ` [PATCH 00/15] git-note: A mechanisim for providing free-form after-the-fact annotations on commits Johan Herland
` (13 preceding siblings ...)
2007-05-27 14:16 ` [PATCH 14/15] git-note: (Tests) Add tests for git-note and associated functionality Johan Herland
@ 2007-05-27 14:17 ` Johan Herland
2007-05-27 20:09 ` [PATCH 00/15] git-note: A mechanisim for providing free-form after-the-fact annotations on commits Junio C Hamano
2007-05-28 4:37 ` Linus Torvalds
16 siblings, 0 replies; 53+ messages in thread
From: Johan Herland @ 2007-05-27 14:17 UTC (permalink / raw)
To: git; +Cc: Linus Torvalds, Junio C Hamano
Teach gitk to display notes below the commit message similarly to how
notes are displayed when using --decorate with git-{log,show,whatchanged}.
Signed-off-by: Johan Herland <johan@herland.net>
---
gitk | 38 +++++++++++++++++++++++++++++++++++---
1 files changed, 35 insertions(+), 3 deletions(-)
diff --git a/gitk b/gitk
index a57e84c..7bed56b 100755
--- a/gitk
+++ b/gitk
@@ -303,7 +303,7 @@ proc getcommit {id} {
}
proc readrefs {} {
- global tagids idtags headids idheads tagcontents
+ global tagids idtags idnotes headids idheads tagcontents
global otherrefids idotherrefs mainhead
foreach v {tagids idtags headids idheads otherrefids idotherrefs} {
@@ -318,7 +318,7 @@ proc readrefs {} {
if {[regexp {^remotes/.*/HEAD$} $path match]} {
continue
}
- if {![regexp {^(tags|heads)/(.*)$} $path match type name]} {
+ if {![regexp {^(tags|notes|heads)/(.*)$} $path match type name]} {
set type others
set name $path
}
@@ -341,6 +341,18 @@ proc readrefs {} {
catch {
set tagcontents($name) [exec git cat-file tag $id]
}
+ } elseif { $type == "notes" } {
+ puts stderr "note name = '$name', id = '$id'"
+ lappend idnotes($id) $name
+ set obj {}
+ set type {}
+ set tag {}
+ catch {
+ set commit [exec git rev-parse "$id^0"]
+ if {$commit != $id} {
+ lappend idnotes($commit) $id
+ }
+ }
} elseif { $type == "heads" } {
set headids($name) $id
lappend idheads($id) $name
@@ -3864,7 +3876,7 @@ proc selectline {l isnew} {
global displayorder linehtag linentag linedtag
global canvy0 linespc parentlist childlist
global currentid sha1entry
- global commentend idtags linknum
+ global commentend idtags idnotes linknum
global mergemax numcommits pending_select
global cmitmode desc_tags anc_tags showneartags allcommits desc_heads
@@ -4009,6 +4021,26 @@ proc selectline {l isnew} {
$ctext insert end "\n"
appendwithlinks [lindex $info 5] {comment}
+ if {[info exists idnotes($id)]} {
+ $ctext insert end "\nNotes:\n"
+ set notes [exec git note -l "$id"]
+ # strip first line.
+ set firstLineEnd [string first "\n" $notes]
+ if {$firstLineEnd < 0} {
+ # should never happen...
+ set hdrend 0
+ }
+ set newnotes [string range $notes [expr {$firstLineEnd + 1}] end]
+ # Indent everything by 4 spaces
+ set notes {}
+ foreach line [split $newnotes "\n"] {
+ append notes " $line\n"
+ }
+ # Append to $ctext with auto-highlighting of SHA1 IDs.
+ appendwithlinks $notes {comment}
+ $ctext insert end "\n"
+ }
+
$ctext tag delete Comments
$ctext tag remove found 1.0 end
$ctext conf -state disabled
--
1.5.2.101.gee49f
^ permalink raw reply related [flat|nested] 53+ messages in thread
* Re: [PATCH 00/15] git-note: A mechanisim for providing free-form after-the-fact annotations on commits
2007-05-27 14:08 ` [PATCH 00/15] git-note: A mechanisim for providing free-form after-the-fact annotations on commits Johan Herland
` (14 preceding siblings ...)
2007-05-27 14:17 ` [PATCH 15/15] git-note: Add display of notes to gitk Johan Herland
@ 2007-05-27 20:09 ` Junio C Hamano
2007-05-28 0:29 ` Johan Herland
2007-05-28 0:59 ` Jakub Narebski
2007-05-28 4:37 ` Linus Torvalds
16 siblings, 2 replies; 53+ messages in thread
From: Junio C Hamano @ 2007-05-27 20:09 UTC (permalink / raw)
To: Johan Herland; +Cc: git, Linus Torvalds
Johan Herland <johan@herland.net> writes:
> I've been working on combining tag objects and --decorate into a useful
> proof-of-concept that provides the after-the-fact commit annotations I
> requested above, and here's the result:
> ...
Very nicely presented. I appreciate [PATCH 0/N] summary for a
series like this that talks about not just what and how it does,
but focus more on why it does it in a particular way, on design
issues, and decisions. It makes it very pleasant to comment on
the series to have a well written summary like this, because in
the early stage of a review cycle, we would want to talk about
the design, ignoring implementation details.
> However, there are still some remaining questions:
>
> - Is the creation of a unique tag name (i.e. the 'tag' field _inside_ the
> object) for note objects really necessary? Which parts of the system rely
> on these names to be unique across tag objects?
None. Although your use of note-X{40} would make "recovering"
easier, I would imagine.
> - Should notes have their own object type instead of piggy-backing on "tag"?
>
> - What about having a note object type with minimal header fields, and make
> tags just a special case of a note object with an extra tag name header?
Two things struck me:
- The "reverse" mapping 'note' tag uses uses FS as a database.
Clever but would not scale well.
- *BUT* the reverse mapping 'note' tag uses is exactly what we
would want to use for tags that are not notes, for tools
like gitk to attach little flags to commits.
So maybe we _should_ not even need to call this a new 'notes'
system. I am just saying your second point above in a different
way, but I suspect all what is needed is to make the filtering
and presentation of tag objects a bit more flexible, and making
use of the 'peeled' (see .git/packed-refs, for example) mapping
ultra cheap for ordinary tags.
What you would need are:
- Ultra-cheap reverse lookup: "I have an object; which tags
point at this?"
You solved it with refs/notes/<sha1-of-tagged>/, but it would
be useful to extend this to any tag in general.
- Easy way to filter the above question: "I have an object;
which tags of this particlar class point at this?"
You are essentially prefiltering by only making notes tags
available via refs/notes/ hierarchy, but you can also filter
with your naming convention "tag notes-<sha1>". We _could_
(I am not seriously suggesting this yet as I haven't thought
through the issues yet) allow "keyword" header to tag
objects, and allow --decorate='kwd1,kwd2,...' to limit the
tags we take object decorations from the ones that has one of
the specified keywords. If we do that, I suspect your
'notes' system would naturally fall out as regular tags that
happen to have a keyword header with 'note' on it.
> - What about notes on notes? How are tags on tags treated? How should they be
> treated?
You can create a tag object that points at another tag. When we
peel a tag using "^{}" notation, currently it is peeled all the
way until we hit a non tag, so if you need to look at
intermediate tags, you need to parse them yourself. IOW, there
is no Porcelain feature to let you take advantage of this
capability, easily. But we could use this to say "I attest that
he tagged that object".
> - Currently noted objects (notees?) are treated as reachable from their
> associated notes, i.e. like tags. This means that an otherwise dangling
> object will not be detected and removed if it has associated notes.
I think it largely depends on how you intend to use 'notes' if
this is a problem.
The reachability issue is not limited to cruft removal; it also
affects the fetching.
I would imagine the intended use of a 'note' is to annotate
objects (mostly commits, but not necessarily) after the fact,
e.g. "this is reported to fix the issue 35833". You may or may
not want to propagate this across repositories, and the way you
implemented it is to have a ref pointing at the note -- then it
would make it fetchable by other people. Otherwise it would not.
With your implementation, unfortunately, not having a ref under
refs/notes/ would also make the information unavailable to
yourself.
I think the semantics you would want, when a 'note' object that
points at another object (pointee) exists, is to allow creating
a fake (reverse) reachability that says "pointee points at the
note". When such a reachability exists:
- A fetch from such a repository that transfers out the pointee
will drag the note attached to it along with it (so you would
teach rev-list/upload-pack about the extended reachability).
- Incidentally, having a ref that points at the pointee is
enough to protect the note that points at the pointee from
getting pruned (so you would teach fsck/prune about the
extended reachability).
Othewise, the 'note' is subject to garbage collection. This is
pretty much an extension to the existing 'grafts' mechanism,
which can only override commit and its parents; what is done in
the above is to add (not override) to existing reachability to
any object (not just commit, but anything that can get 'noted').
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH 00/15] git-note: A mechanisim for providing free-form after-the-fact annotations on commits
2007-05-27 20:09 ` [PATCH 00/15] git-note: A mechanisim for providing free-form after-the-fact annotations on commits Junio C Hamano
@ 2007-05-28 0:29 ` Johan Herland
2007-05-28 0:59 ` Jakub Narebski
1 sibling, 0 replies; 53+ messages in thread
From: Johan Herland @ 2007-05-28 0:29 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git, Linus Torvalds
On Sunday 27 May 2007, Junio C Hamano wrote:
> Johan Herland <johan@herland.net> writes:
>
> > I've been working on combining tag objects and --decorate into a useful
> > proof-of-concept that provides the after-the-fact commit annotations I
> > requested above, and here's the result:
> > ...
>
> Very nicely presented. I appreciate [PATCH 0/N] summary for a
> series like this that talks about not just what and how it does,
> but focus more on why it does it in a particular way, on design
> issues, and decisions. It makes it very pleasant to comment on
> the series to have a well written summary like this, because in
> the early stage of a review cycle, we would want to talk about
> the design, ignoring implementation details.
Thanks, no problem. You're doing a really good job keeping all this crazy
development on track. The very least I can do is make your job easier. :)
> > However, there are still some remaining questions:
> >
> > - Is the creation of a unique tag name (i.e. the 'tag' field _inside_ the
> > object) for note objects really necessary? Which parts of the system rely
> > on these names to be unique across tag objects?
>
> None. Although your use of note-X{40} would make "recovering"
> easier, I would imagine.
Yeah, I'd rather just use _one_ identifier for all notes, instead of
generating yet another SHA1 sum, just to make each note (unecessarily)
unique.
> > - Should notes have their own object type instead of piggy-backing on "tag"?
> >
> > - What about having a note object type with minimal header fields, and make
> > tags just a special case of a note object with an extra tag name header?
>
> Two things struck me:
>
> - The "reverse" mapping 'note' tag uses uses FS as a database.
> Clever but would not scale well.
Agreed.
> - *BUT* the reverse mapping 'note' tag uses is exactly what we
> would want to use for tags that are not notes, for tools
> like gitk to attach little flags to commits.
For notes, it's obvious, as they aren't very useful unless we have a fast
reverse mapping, but it makes sense that other types of tag objects would
want this as well.
> So maybe we _should_ not even need to call this a new 'notes'
> system. I am just saying your second point above in a different
> way, but I suspect all what is needed is to make the filtering
> and presentation of tag objects a bit more flexible, and making
> use of the 'peeled' (see .git/packed-refs, for example) mapping
> ultra cheap for ordinary tags.
Agreed. The peeled mapping makes a lot of sense here. I didn't know
about it when I first designed this, and I somehow managed to miss it
when I made the patches to pack-refs and show-refs.
Actually, I thought about something similar to the peeled mapping when
I designed the note refs. I basically had 3 reverse mapping options lined
up:
1. Put _all_ note refs in a single two-column file, noted objects
("notees") in the first column, and note objects in the second.
Keep the file sorted by object name (first column), and keep the
notes per object sorted chronologically. This would provide one of
the fastest possible lookups for "git-note -l". However, the file
would probably grow extremely large, slowing down insertion (and
lookup) considerably.
2. One file per object with notes. Notes sorted chronologically within
that file. This is sort of an intermediate between (1) and (3).
3. Keep a two-level hierarchy with one subdir per noted object, and one
file per note. This is what I ended up with, mostly because it fit
perfectly into the existing layout of refs/, and required very little
code to implement.
Of course, now that I know about the peeled mapping, it makes more sense
to use a variation on that (maybe together with (1) or (2)).
> What you would need are:
>
> - Ultra-cheap reverse lookup: "I have an object; which tags
> point at this?"
>
> You solved it with refs/notes/<sha1-of-tagged>/, but it would
> be useful to extend this to any tag in general.
>
> - Easy way to filter the above question: "I have an object;
> which tags of this particlar class point at this?"
>
> You are essentially prefiltering by only making notes tags
> available via refs/notes/ hierarchy, but you can also filter
> with your naming convention "tag notes-<sha1>". We _could_
> (I am not seriously suggesting this yet as I haven't thought
> through the issues yet) allow "keyword" header to tag
> objects, and allow --decorate='kwd1,kwd2,...' to limit the
> tags we take object decorations from the ones that has one of
> the specified keywords. If we do that, I suspect your
> 'notes' system would naturally fall out as regular tags that
> happen to have a keyword header with 'note' on it.
Yeah, I was thinking somewhat similarly; basically making tag objects
simpler and more versatile by replacing the "tag" header (which is
fundamentally unimportant to my notes) with a "tagtype" header which
could be set to "tag" for tag objects, "note" for note objects, etc.
Each tagtype could then further define headers specific to that tagtype.
For example could "tagtype == tag" objects reintroduce the "tag" header.
The tagtype field could then serve pretty much the same purpose as the
keyword header you suggest above.
> > - What about notes on notes? How are tags on tags treated? How should they be
> > treated?
>
> You can create a tag object that points at another tag. When we
> peel a tag using "^{}" notation, currently it is peeled all the
> way until we hit a non tag, so if you need to look at
> intermediate tags, you need to parse them yourself. IOW, there
> is no Porcelain feature to let you take advantage of this
> capability, easily. But we could use this to say "I attest that
> he tagged that object".
Yeah, I'm still undecided on whether we want to allow notes on notes.
Some might argue that a note on a note should really be just another note
on the original noted object, and that nested notes doesn't make sense.
But then, on the other hand, there might be a use for nested notes.
Say, what about allowing threaded discussion on commits represented as
nested note objects? ;-P
In my current implementation, "git-note <tag>" will create a note on the
tag object, and not on the commit pointed to by the tag object. I'm not
sure that's the default behaviour I want; at least I would probably want
the note to show up when looking at the commit pointed to by that tag
> > - Currently noted objects (notees?) are treated as reachable from their
> > associated notes, i.e. like tags. This means that an otherwise dangling
> > object will not be detected and removed if it has associated notes.
>
> I think it largely depends on how you intend to use 'notes' if
> this is a problem.
>
> The reachability issue is not limited to cruft removal; it also
> affects the fetching.
>
> I would imagine the intended use of a 'note' is to annotate
> objects (mostly commits, but not necessarily) after the fact,
> e.g. "this is reported to fix the issue 35833".
Yep, sounds about right, although other people might have other,
just as valid, ideas.
> You may or may
> not want to propagate this across repositories, and the way you
> implemented it is to have a ref pointing at the note -- then it
> would make it fetchable by other people. Otherwise it would not.
> With your implementation, unfortunately, not having a ref under
> refs/notes/ would also make the information unavailable to
> yourself.
>
> I think the semantics you would want, when a 'note' object that
> points at another object (pointee) exists, is to allow creating
> a fake (reverse) reachability that says "pointee points at the
> note". When such a reachability exists:
>
> - A fetch from such a repository that transfers out the pointee
> will drag the note attached to it along with it (so you would
> teach rev-list/upload-pack about the extended reachability).
>
> - Incidentally, having a ref that points at the pointee is
> enough to protect the note that points at the pointee from
> getting pruned (so you would teach fsck/prune about the
> extended reachability).
>
> Othewise, the 'note' is subject to garbage collection.
Yeah, the current implementation does not allow for this reverse/weaker
relationship at all.
I agree that fetchability and prunability of a note depends on the
fetch-/prunability of its pointee. Furthermore, a note on an otherwise
dangling object should not keep that object alive, but rather allow that
object to be pruned (automatically causing the note to be pruned as well).
> This is
> pretty much an extension to the existing 'grafts' mechanism,
> which can only override commit and its parents; what is done in
> the above is to add (not override) to existing reachability to
> any object (not just commit, but anything that can get 'noted').
I'll have to read up on the 'grafts' mechanism, but it already sounds
like a much better way to encode these relationships than my crude
attempts in 'refs/notes'.
Thanks a lot for the feedback.
Have fun!
...Johan
--
Johan Herland, <johan@herland.net>
www.herland.net
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH 00/15] git-note: A mechanisim for providing free-form after-the-fact annotations on commits
2007-05-27 20:09 ` [PATCH 00/15] git-note: A mechanisim for providing free-form after-the-fact annotations on commits Junio C Hamano
2007-05-28 0:29 ` Johan Herland
@ 2007-05-28 0:59 ` Jakub Narebski
1 sibling, 0 replies; 53+ messages in thread
From: Jakub Narebski @ 2007-05-28 0:59 UTC (permalink / raw)
To: git
Junio C Hamano wrote:
> You can create a tag object that points at another tag. When we
> peel a tag using "^{}" notation, currently it is peeled all the
> way until we hit a non tag, so if you need to look at
> intermediate tags, you need to parse them yourself. IOW, there
> is no Porcelain feature to let you take advantage of this
> capability, easily. But we could use this to say "I attest that
> he tagged that object".
Hmmm... I wonder why "git show exaples/tag" (where 'examples/tag' is
tag to tag) does show empty output, and why "git show examples/tag^{tag}"
does not work...
--
Jakub Narebski
Warsaw, Poland
ShadeHawk on #git
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH 00/15] git-note: A mechanisim for providing free-form after-the-fact annotations on commits
2007-05-27 14:08 ` [PATCH 00/15] git-note: A mechanisim for providing free-form after-the-fact annotations on commits Johan Herland
` (15 preceding siblings ...)
2007-05-27 20:09 ` [PATCH 00/15] git-note: A mechanisim for providing free-form after-the-fact annotations on commits Junio C Hamano
@ 2007-05-28 4:37 ` Linus Torvalds
2007-05-28 10:54 ` Johan Herland
2007-05-28 17:29 ` [PATCH 00/15] git-note: A mechanisim for providing free-form after-the-fact annotations on commits Michael S. Tsirkin
16 siblings, 2 replies; 53+ messages in thread
From: Linus Torvalds @ 2007-05-28 4:37 UTC (permalink / raw)
To: Johan Herland; +Cc: git, Junio C Hamano
On Sun, 27 May 2007, Johan Herland wrote:
>
> I've been working on combining tag objects and --decorate into a useful
> proof-of-concept that provides the after-the-fact commit annotations I
> requested above, and here's the result:
Ok, looks fine to me. I do have a few questions:
- why don't you just let people name their notes, the same way we name
tags (and then actually using it as the note name?)
Putting them in the refs/notes/ filesystem by their SHA1 seems a bit
wasteful, and it would seem that it could be quite nice to name the
notes some way?
- This will probably scale horribly badly if you have tens of thousands
of notes, even when they are packed. Do we care?
Other than that, it looks straightforward and sane.
Linus
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH 00/15] git-note: A mechanisim for providing free-form after-the-fact annotations on commits
2007-05-28 4:37 ` Linus Torvalds
@ 2007-05-28 10:54 ` Johan Herland
2007-05-28 16:28 ` Linus Torvalds
2007-05-28 20:45 ` Junio C Hamano
2007-05-28 17:29 ` [PATCH 00/15] git-note: A mechanisim for providing free-form after-the-fact annotations on commits Michael S. Tsirkin
1 sibling, 2 replies; 53+ messages in thread
From: Johan Herland @ 2007-05-28 10:54 UTC (permalink / raw)
To: Linus Torvalds; +Cc: git, Junio C Hamano
On Monday 28 May 2007, Linus Torvalds wrote:
>
> On Sun, 27 May 2007, Johan Herland wrote:
> >
> > I've been working on combining tag objects and --decorate into a useful
> > proof-of-concept that provides the after-the-fact commit annotations I
> > requested above, and here's the result:
>
> Ok, looks fine to me. I do have a few questions:
> - why don't you just let people name their notes, the same way we name
> tags (and then actually using it as the note name?)
>
> Putting them in the refs/notes/ filesystem by their SHA1 seems a bit
> wasteful, and it would seem that it could be quite nice to name the
> notes some way?
Well, when I first designed them, I thought of notes more as an extension
to the commit message than as a special case of tags. Therefore naming
them didn't seem natural at that point. But now that it all seems to
blend together (cf. Junio's answer), I'm not opposed to putting names
on notes at all. But I don't want to make naming mandatory. It should
still be possible to add a note like "Fixes bug #12345" in a jiffy,
without having to think up a note name as well (or having a badly
thought-up name pollute some namespace).
So I guess we end up with two kinds of objects/entities:
1. tags, with mandatory naming and optional comment/message
2. notes, with optional naming and mandatory comment/message
To some degree we can say that the name is the ref, and the
comment/message is the object. We therefore get:
1. tags, with mandatory ref and optional tag object (we have this today)
2. notes, with optional ref and mandatory object
Today, a note needs its ref in order to stay alive, but this is purely a
(badly designed) technical measure. When we get the proper reverse mapping
done (as discussed in Junio's answer), notes will stop polluting refs/ and
we can instead allow naming of notes by adding simple (tag-type) refs to
note objects.
Also, as mentioned by Junio, we want to do the reverse mapping for regular
tags as well.
At this point, there's no real difference between tags and notes (some
would say there never were a difference), and we can stop caring about
whether a note is a note or a tag, etc, at least in the plumbing.
We may still want to enforce a difference in the procelain, though.
When presenting tags/notes (e.g. with --decorate), users might be
interested in classifying and filtering their tags/notes in different
categories. Categories might be ("note", "tag"), or we can make it
user-extensible, like Junio's "keyword" idea). Either way, we'll have
to make room for this classification in the tag object by adding another
header ("tagtype", "keyword", whatever...).
And while we're on the subject of changing the tag object, I'd like for
the "tag" header (the one holding the tag name) to become optional.
When doing my ref <-> name trick above, I conveniently forgot this little
bugger. Basically the only reason for this one to exist is to include the
name of the tag in the data passed to gpg for signing. This is of course
necesssary in order to make renaming a signed tag impossible. (Allowing
renaming would make it possible to replace it with a malicious tag with
the original name.) Therefore the "tag" header must be mandatory for
signed tags. But for all other tags (including notes) this header is
pretty much useless.
> - This will probably scale horribly badly if you have tens of thousands
> of notes, even when they are packed. Do we care?
I can't see why the current implementation would scale any worse than an
equivalent number of (annotated/signed) tags. But then again, the tag
system might not have been designed with tens of thousands of tag objects
in mind. :)
> Other than that, it looks straightforward and sane.
Thanks for the feedback
Have fun!
...Johan
--
Johan Herland, <johan@herland.net>
www.herland.net
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH 00/15] git-note: A mechanisim for providing free-form after-the-fact annotations on commits
2007-05-28 10:54 ` Johan Herland
@ 2007-05-28 16:28 ` Linus Torvalds
2007-05-28 16:40 ` Johan Herland
2007-05-28 20:45 ` Junio C Hamano
1 sibling, 1 reply; 53+ messages in thread
From: Linus Torvalds @ 2007-05-28 16:28 UTC (permalink / raw)
To: Johan Herland; +Cc: git, Junio C Hamano
On Mon, 28 May 2007, Johan Herland wrote:
>
> > - This will probably scale horribly badly if you have tens of thousands
> > of notes, even when they are packed. Do we care?
>
> I can't see why the current implementation would scale any worse than an
> equivalent number of (annotated/signed) tags. But then again, the tag
> system might not have been designed with tens of thousands of tag objects
> in mind. :)
Right. I was more thinking that this "notes" thing could potentially be a
very useful thing for some random workflow - using notes to indicate that
some commit has been vetted by somebody, for example (ie adding things
like "Acked-by:" after-the-fact, which happens for the kernel).
And once you start using notes for something like that, I think you're
going to end up with a set of notes that grows with history, and
potentially grows quite quickly.
So I can see people having thousands of tags, but usually you only tag
releases. In contrast, I can see notes being used not as a "per release"
thing, but closer to a "per commit" thing. And that kind of worries me, I
can see workflows where you end up having tons and tons of notes.
But hey, maybe I just worry unnecessarily.
Linus
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH 00/15] git-note: A mechanisim for providing free-form after-the-fact annotations on commits
2007-05-28 16:28 ` Linus Torvalds
@ 2007-05-28 16:40 ` Johan Herland
2007-05-28 16:58 ` Linus Torvalds
0 siblings, 1 reply; 53+ messages in thread
From: Johan Herland @ 2007-05-28 16:40 UTC (permalink / raw)
To: Linus Torvalds; +Cc: git, Junio C Hamano
On Monday 28 May 2007, Linus Torvalds wrote:
> > I can't see why the current implementation would scale any worse than an
> > equivalent number of (annotated/signed) tags. But then again, the tag
> > system might not have been designed with tens of thousands of tag objects
> > in mind. :)
>
> Right. I was more thinking that this "notes" thing could potentially be a
> very useful thing for some random workflow - using notes to indicate that
> some commit has been vetted by somebody, for example (ie adding things
> like "Acked-by:" after-the-fact, which happens for the kernel).
>
> And once you start using notes for something like that, I think you're
> going to end up with a set of notes that grows with history, and
> potentially grows quite quickly.
>
> So I can see people having thousands of tags, but usually you only tag
> releases. In contrast, I can see notes being used not as a "per release"
> thing, but closer to a "per commit" thing. And that kind of worries me, I
> can see workflows where you end up having tons and tons of notes.
>
> But hey, maybe I just worry unnecessarily.
I still don't see what makes note objects inherently more expensive than
commit objects. Except for the refs, of course, but we're getting rid
of those (at least replacing them with a more efficient reverse mapping).
And even if we _do_ end up with 10 notes per commit, we could always
design some kind of "supernote" that lets "git-gc" pack all the notes
related to a commit into _one_ object.
Have fun!
...Johan
--
Johan Herland, <johan@herland.net>
www.herland.net
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH 00/15] git-note: A mechanisim for providing free-form after-the-fact annotations on commits
2007-05-28 16:40 ` Johan Herland
@ 2007-05-28 16:58 ` Linus Torvalds
2007-05-28 17:48 ` Johan Herland
0 siblings, 1 reply; 53+ messages in thread
From: Linus Torvalds @ 2007-05-28 16:58 UTC (permalink / raw)
To: Johan Herland; +Cc: git, Junio C Hamano
On Mon, 28 May 2007, Johan Herland wrote:
>
> I still don't see what makes note objects inherently more expensive than
> commit objects. Except for the refs, of course, but we're getting rid
> of those (at least replacing them with a more efficient reverse mapping).
It's exactly the refs that I worry about.
Anything that needs to read in all notes at startup is going to be _slow_.
In contrast, commits we read when (and only when) we need them.
Linus
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH 00/15] git-note: A mechanisim for providing free-form after-the-fact annotations on commits
2007-05-28 16:58 ` Linus Torvalds
@ 2007-05-28 17:48 ` Johan Herland
2007-05-28 20:45 ` Junio C Hamano
0 siblings, 1 reply; 53+ messages in thread
From: Johan Herland @ 2007-05-28 17:48 UTC (permalink / raw)
To: Linus Torvalds; +Cc: git, Junio C Hamano
On Monday 28 May 2007, Linus Torvalds wrote:
>
> On Mon, 28 May 2007, Johan Herland wrote:
> >
> > I still don't see what makes note objects inherently more expensive than
> > commit objects. Except for the refs, of course, but we're getting rid
> > of those (at least replacing them with a more efficient reverse mapping).
>
> It's exactly the refs that I worry about.
>
> Anything that needs to read in all notes at startup is going to be _slow_.
>
> In contrast, commits we read when (and only when) we need them.
Ok. But the reverse mapping will help with this, won't it?
We'll look up the interesting commits and find their associated
note objects directly.
BTW, if you use "git-note -l <commit>" it'll go directly to <commit>'s
subdir in refs/notes and never look at any other notes.
Of course, this currently does not help the plumbing much, which uses
for_each_note_ref() instead...
...Johan
--
Johan Herland, <johan@herland.net>
www.herland.net
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH 00/15] git-note: A mechanisim for providing free-form after-the-fact annotations on commits
2007-05-28 17:48 ` Johan Herland
@ 2007-05-28 20:45 ` Junio C Hamano
2007-05-28 21:35 ` Shawn O. Pearce
2007-05-29 7:06 ` Johan Herland
0 siblings, 2 replies; 53+ messages in thread
From: Junio C Hamano @ 2007-05-28 20:45 UTC (permalink / raw)
To: Johan Herland; +Cc: Linus Torvalds, git
Johan Herland <johan@herland.net> writes:
> On Monday 28 May 2007, Linus Torvalds wrote:
>>
>> On Mon, 28 May 2007, Johan Herland wrote:
>> >
>> > I still don't see what makes note objects inherently more expensive than
>> > commit objects. Except for the refs, of course, but we're getting rid
>> > of those (at least replacing them with a more efficient reverse mapping).
>>
>> It's exactly the refs that I worry about.
>>
>> Anything that needs to read in all notes at startup is going to be _slow_.
>>
>> In contrast, commits we read when (and only when) we need them.
>
> Ok. But the reverse mapping will help with this, won't it?
> We'll look up the interesting commits and find their associated
> note objects directly.
The issue Linus brought up worries me, too.
The "efficient reverse mapping" is still handwaving at this
stage. What it needs to do is an equivalent to your
implementation with "refs/notes/<a dir per commit>/<note>". The
"efficient" one might do a flat file that says "notee note" per
line sorted by notee, or it might use BDB or sqlite, but the
amount of the data and complexity of the look-up is really the
same. A handful notes per each commit in the history (I think
Linus's "Acked-by after the fact" example a very sensible thing
to want from this subsystem).
I am not saying that it is impossible to make the set-up cost
for the "efficient lookup" almost zero, and to make it lazy and
on-demand. The concern above just adds one design constraints
to that "efficient reverse mapping" code yet to come.
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH 00/15] git-note: A mechanisim for providing free-form after-the-fact annotations on commits
2007-05-28 20:45 ` Junio C Hamano
@ 2007-05-28 21:35 ` Shawn O. Pearce
2007-05-28 23:37 ` Johannes Schindelin
2007-05-29 3:12 ` Linus Torvalds
2007-05-29 7:06 ` Johan Herland
1 sibling, 2 replies; 53+ messages in thread
From: Shawn O. Pearce @ 2007-05-28 21:35 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Johan Herland, Linus Torvalds, git
Junio C Hamano <junkio@cox.net> wrote:
> Johan Herland <johan@herland.net> writes:
> > Ok. But the reverse mapping will help with this, won't it?
> > We'll look up the interesting commits and find their associated
> > note objects directly.
>
> The issue Linus brought up worries me, too.
>
> The "efficient reverse mapping" is still handwaving at this
> stage. What it needs to do is an equivalent to your
> implementation with "refs/notes/<a dir per commit>/<note>". The
> "efficient" one might do a flat file that says "notee note" per
> line sorted by notee, or it might use BDB or sqlite, but the
> amount of the data and complexity of the look-up is really the
> same. A handful notes per each commit in the history (I think
> Linus's "Acked-by after the fact" example a very sensible thing
> to want from this subsystem).
Please, don't use BDB or sqllite. I really don't trust either.
I've lost data to both. I've *never* lost data to a Git packfile.
;-)
I'm actually thinking pack v4. OK, I know its just a virtual hand
waving thing still, but there's really no reason Nico and I cannot
get the damn thing finished before we both wind up buying the farm.
What if we use a "slow" storage by "refs/notes/$objname/$notename",
and we also allow them to appear in the packed-refs file. But during
a repack we instead stick the annotations into the same packfile as
$objname, and we also include a list of $notename after $objname's
other data.
This way we have quick access to the $notename(s) of all notes of
$objname through the pack, and we can lazily go get the notes raw
data if we need them. This isn't too different from what we do
with parent fields. We initialize the commit_list when we parse
the commit but we don't parse the parents until we really need them.
Once packed we delete the note ref (if loose) and during a repack
of the packed-refs file we delete the note if $notename exists in
the packfile.
If someone wants notes we can check to see if refs/notes exists; if
it does then we enumerate all refs and catalog the notes we found
in memory. Note search then works off the in-memory list and off
the packfiles. If refs/notes doesn't exist (and we should delete it
when we prune away those ref files or prune them out of packed-refs)
then we can skip the ref enumeration and just go straight to the
packfile(s). Most notes will be in the packfiles. I think most
people repack often enough that the handful of unpacked notes before
the next repack won't be a major bottleneck. Especially since we
can get the target $objname directly from a readdir() call, or by
splitting the string in the packed-refs file.
>From an object enumeration standpoint during packfile generation
the notes for a given object are treated like the parent fields in
a commit; they come after the object itself, but unlike the parent
fields they are always output if the object itself was output.
(Hence an --objects-edge enumeration would include the notes only
if the commit itself had been included.)
Unfortunately that doesn't cover the case of a note being added
months later and needing to distribute it to clients that already
have the object the note is attached to.
I haven't been following this discussion very closely, but I'd also
like to suggest that if annotated tags are being used for notes
that the "tag <name>" field be left out of them. I don't see why
a note should be given a specific name that sits in a (roughly)
global namespace.
--
Shawn.
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH 00/15] git-note: A mechanisim for providing free-form after-the-fact annotations on commits
2007-05-28 21:35 ` Shawn O. Pearce
@ 2007-05-28 23:37 ` Johannes Schindelin
2007-05-29 3:12 ` Linus Torvalds
1 sibling, 0 replies; 53+ messages in thread
From: Johannes Schindelin @ 2007-05-28 23:37 UTC (permalink / raw)
To: Shawn O. Pearce; +Cc: Junio C Hamano, Johan Herland, Linus Torvalds, git
Hi,
On Mon, 28 May 2007, Shawn O. Pearce wrote:
> Junio C Hamano <junkio@cox.net> wrote:
> > Johan Herland <johan@herland.net> writes:
> > > Ok. But the reverse mapping will help with this, won't it?
> > > We'll look up the interesting commits and find their associated
> > > note objects directly.
> >
> > The issue Linus brought up worries me, too.
> >
> > The "efficient reverse mapping" is still handwaving at this
> > stage. What it needs to do is an equivalent to your
> > implementation with "refs/notes/<a dir per commit>/<note>". The
> > "efficient" one might do a flat file that says "notee note" per
> > line sorted by notee, or it might use BDB or sqlite, but the
> > amount of the data and complexity of the look-up is really the
> > same. A handful notes per each commit in the history (I think
> > Linus's "Acked-by after the fact" example a very sensible thing
> > to want from this subsystem).
>
> Please, don't use BDB or sqllite. I really don't trust either.
> I've lost data to both. I've *never* lost data to a Git packfile.
> ;-)
Also, there is the question of dependencies. We don't have to repeat SVN's
errors.
As for sqllite: the only reason I was _not_ horrified when I realized that
cvsserver needs sqllite was that it is not really important for the
common user.
> I'm actually thinking pack v4. OK, I know its just a virtual hand
> waving thing still, but there's really no reason Nico and I cannot
> get the damn thing finished before we both wind up buying the farm.
Maybe I am missing something important here, but I think we do not at all
need a generic database here. Just a key/value store.
As it happens, we already have such a beast. It is called object store
here.
Now, the only reason we cannot do something like "SHA-1 ^ 0xff[...]ff" is
the SHA-1 for the note for that commit, is that you could possibly have
more than one note for the commit.
Of course, without that restriction, we could reuse our object store logic
for notes.
Side note: the more I think about this notes thing, the more I get
disgusted by the deep changes we'd have to do just to accomodate for them.
Are they really worth it? Or would something like a pseudo-branch suffice,
being one strand of notes (commits), where the second commit parent is
actually the commit the note is for?
Ciao,
Dscho
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH 00/15] git-note: A mechanisim for providing free-form after-the-fact annotations on commits
2007-05-28 21:35 ` Shawn O. Pearce
2007-05-28 23:37 ` Johannes Schindelin
@ 2007-05-29 3:12 ` Linus Torvalds
2007-05-29 3:22 ` Shawn O. Pearce
2007-05-29 11:04 ` Andy Parkins
1 sibling, 2 replies; 53+ messages in thread
From: Linus Torvalds @ 2007-05-29 3:12 UTC (permalink / raw)
To: Shawn O. Pearce; +Cc: Junio C Hamano, Johan Herland, git
On Mon, 28 May 2007, Shawn O. Pearce wrote:
>
> What if we use a "slow" storage by "refs/notes/$objname/$notename",
This _really_ won't scale. Even if the notes don't exist, just doing the
lookup (which will fail for most commits) will be horribly slow, and will
populate the dentry cache with negative entries.
To get good filesystem performance, you have to
- have reasonable hit-rates (and looking it up for each commit is _not_
going to do that)
- not have millions of objects.
So you'd have to have a separate database. You could do it with a separate
index file (or mixing it up with the "index v4" and doing it with a single
index file that also contains normal objects), but the point is, it's
going to be a real separate database.
The current "decorations" approach is actually much more efficient with
packed refs (dense in the filesystem), and probably not very bad at all
for a smallish set (ie a few hundred to a few thousand) objects, but just
reading all the decorations ends up being an overhead at some point.
Linus
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH 00/15] git-note: A mechanisim for providing free-form after-the-fact annotations on commits
2007-05-29 3:12 ` Linus Torvalds
@ 2007-05-29 3:22 ` Shawn O. Pearce
2007-05-29 7:04 ` Jakub Narebski
2007-05-29 11:04 ` Andy Parkins
1 sibling, 1 reply; 53+ messages in thread
From: Shawn O. Pearce @ 2007-05-29 3:22 UTC (permalink / raw)
To: Linus Torvalds; +Cc: Junio C Hamano, Johan Herland, git
Linus Torvalds <torvalds@linux-foundation.org> wrote:
>
> On Mon, 28 May 2007, Shawn O. Pearce wrote:
> >
> > What if we use a "slow" storage by "refs/notes/$objname/$notename",
>
> This _really_ won't scale. Even if the notes don't exist, just doing the
> lookup (which will fail for most commits) will be horribly slow, and will
> populate the dentry cache with negative entries.
Yes.
I think you missed what I was trying to say. We *definately* do not
want to probe the OS and ask "do you have $objname1? $objname2?"
for exactly the reason you just stated. (Though you being some
sort of kernel guru means you know a hellva lot more about that
dentry cache thing than I do!)
What I meant was something more like:
DIR *d = opendir("refs/notes");
if (d) {
... notes can exist in both packfiles and "loose" ...
only_packed_notes = 0;
while (readdir(d)) {
... the entry name here is the name of an object ...
... stuff into a hash table, we can come back later ...
... for the subdirectory contents if we need it ...
}
closedir(d);
... also examine "packed-refs", in case any are there ...
} else {
only_packed_notes = 1;
... we *only* have notes in packfiles, if we have any at all...
}
Then looking up a note is just a probe into our in-memory hash
(if only_packed_notes is false) and a probe into the packfile(s) to
find the notes for the object. Not very expensive if the packfiles
have the reverse obj->tag mappings indexed within them.
> To get good filesystem performance, you have to
> - have reasonable hit-rates (and looking it up for each commit is _not_
> going to do that)
> - not have millions of objects.
Which is why we:
a) allow these things to migrate into packed-refs, because
getting into there is a hellva lot cheaper than getting into
a packfile;
b) move them into a packfile when we repack loose objects,
because then we have really good access.
c) take them out of packed-refs once they are into a packfile,
and get them out of the loose refs/notes directory as early as
possible.
--
Shawn.
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH 00/15] git-note: A mechanisim for providing free-form after-the-fact annotations on commits
2007-05-29 3:22 ` Shawn O. Pearce
@ 2007-05-29 7:04 ` Jakub Narebski
0 siblings, 0 replies; 53+ messages in thread
From: Jakub Narebski @ 2007-05-29 7:04 UTC (permalink / raw)
To: git
Shawn O. Pearce wrote:
> Which is why we:
>
> a) allow these things to migrate into packed-refs, because
> getting into there is a hellva lot cheaper than getting into
> a packfile;
>
> b) move them into a packfile when we repack loose objects,
> because then we have really good access.
>
> c) take them out of packed-refs once they are into a packfile,
> and get them out of the loose refs/notes directory as early as
> possible.
Three-tier layout? Loose note refs -> packed refs -> packfile?
--
Jakub Narebski
Warsaw, Poland
ShadeHawk on #git
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH 00/15] git-note: A mechanisim for providing free-form after-the-fact annotations on commits
2007-05-29 3:12 ` Linus Torvalds
2007-05-29 3:22 ` Shawn O. Pearce
@ 2007-05-29 11:04 ` Andy Parkins
2007-05-29 11:12 ` Johannes Schindelin
1 sibling, 1 reply; 53+ messages in thread
From: Andy Parkins @ 2007-05-29 11:04 UTC (permalink / raw)
To: git; +Cc: Linus Torvalds, Shawn O. Pearce, Junio C Hamano, Johan Herland
On Tuesday 2007 May 29, Linus Torvalds wrote:
> So you'd have to have a separate database. You could do it with a separate
> index file (or mixing it up with the "index v4" and doing it with a single
> index file that also contains normal objects), but the point is, it's
> going to be a real separate database.
This is an off-the-wall suggestion; but why not use the object database a bit
more strongly than just for storing the notes? The original method was to
use the filesystem to store refs/notes/$SHA1, which was essentially annotated
tags. The object database has been designed for storing thousands of
hierarchically organised files, so why not use that instead of the refs/
tree?
That is to say, make a "private" branch, independent of any real repository
branches. I'll call it "notes". Then each commit in that branch represents
a change to a note (or multiple notes). The tree attached to each commit
provides the reverse lookup that's wanted, and also maps to the object
itself. So where a normal tree has
100644 blob 156e952df8603c72532bcda95ddcd3bcb16ec5fd somefile
A "notes" tree would have
100644 blob 156e952df8603c72532bcda95ddcd3bcb16ec5fd $SHA1_OF_TARGET_COMMIT1
100644 blob 97e08b0ab483146cb8fff31138eaa828c24ac84f $SHA1_OF_TARGET_COMMIT2
All the "notes" tools could now use the standard git tools to look up a note.
The notes would be version controlled (which is impressive in itself), and
reverse lookup is the same as path-limited git-rev-list.
The tree objects are (I guess) stored alphabetically, so the reverse lookup
could be done with a binary search. If a user really wanted to, they could
check out the "notes" branch and edit the files directly.
Madness? I'm sure.
Andy
--
Dr Andy Parkins, M Eng (hons), MIET
andyparkins@gmail.com
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH 00/15] git-note: A mechanisim for providing free-form after-the-fact annotations on commits
2007-05-29 11:04 ` Andy Parkins
@ 2007-05-29 11:12 ` Johannes Schindelin
0 siblings, 0 replies; 53+ messages in thread
From: Johannes Schindelin @ 2007-05-29 11:12 UTC (permalink / raw)
To: Andy Parkins
Cc: git, Linus Torvalds, Shawn O. Pearce, Junio C Hamano,
Johan Herland
Hi,
On Tue, 29 May 2007, Andy Parkins wrote:
> On Tuesday 2007 May 29, Linus Torvalds wrote:
>
> > So you'd have to have a separate database. You could do it with a
> > separate index file (or mixing it up with the "index v4" and doing it
> > with a single index file that also contains normal objects), but the
> > point is, it's going to be a real separate database.
>
> This is an off-the-wall suggestion; but why not use the object database
> a bit more strongly than just for storing the notes?
I alluded to the same yesterday.
However, just before waking up, I had the same idea as you, using a
branch.
> So where a normal tree has
>
> 100644 blob 156e952df8603c72532bcda95ddcd3bcb16ec5fd somefile
>
> A "notes" tree would have
>
> 100644 blob 156e952df8603c72532bcda95ddcd3bcb16ec5fd $SHA1_OF_TARGET_COMMIT1
> 100644 blob 97e08b0ab483146cb8fff31138eaa828c24ac84f $SHA1_OF_TARGET_COMMIT2
Actually, just throw in one fan-out stage, and you should be fine,
performance-wise.
And what is best: you could merge notes from somebody else easily,
_exactly_ because it is a proper branch now.
Ciao,
Dscho
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH 00/15] git-note: A mechanisim for providing free-form after-the-fact annotations on commits
2007-05-28 20:45 ` Junio C Hamano
2007-05-28 21:35 ` Shawn O. Pearce
@ 2007-05-29 7:06 ` Johan Herland
2007-05-29 8:22 ` Jeff King
1 sibling, 1 reply; 53+ messages in thread
From: Johan Herland @ 2007-05-29 7:06 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Linus Torvalds, git
On Monday 28 May 2007, Junio C Hamano wrote:
> Johan Herland <johan@herland.net> writes:
> > On Monday 28 May 2007, Linus Torvalds wrote:
> >> On Mon, 28 May 2007, Johan Herland wrote:
> >> > I still don't see what makes note objects inherently more expensive than
> >> > commit objects. Except for the refs, of course, but we're getting rid
> >> > of those (at least replacing them with a more efficient reverse mapping).
> >>
> >> It's exactly the refs that I worry about.
> >>
> >> Anything that needs to read in all notes at startup is going to be _slow_.
> >>
> >> In contrast, commits we read when (and only when) we need them.
> >
> > Ok. But the reverse mapping will help with this, won't it?
> > We'll look up the interesting commits and find their associated
> > note objects directly.
>
> The issue Linus brought up worries me, too.
>
> The "efficient reverse mapping" is still handwaving at this
> stage. What it needs to do is an equivalent to your
> implementation with "refs/notes/<a dir per commit>/<note>". The
> "efficient" one might do a flat file that says "notee note" per
> line sorted by notee, or it might use BDB or sqlite, but the
> amount of the data and complexity of the look-up is really the
> same. A handful notes per each commit in the history (I think
> Linus's "Acked-by after the fact" example a very sensible thing
> to want from this subsystem).
>
> I am not saying that it is impossible to make the set-up cost
> for the "efficient lookup" almost zero, and to make it lazy and
> on-demand. The concern above just adds one design constraints
> to that "efficient reverse mapping" code yet to come.
Ok, here's what I'm thinking so far on that reverse mapping:
1. Keep a file, ".git/reverse_tagmap_sorted" with one entry of the form
"pointee pointer" per line. The file is sorted on "pointee", so we can
easily do the radix-256-fan-out-followed-by-binary-search trick that
Linus mentioned in another thread. This should hopefully make lookup
fairly cheap. BTW, if there is a similar "pointee pointer"-type format
already being used in git, I'd be happy to use that instead. I looked
at the "peeled" format being used by packed-refs, but using that
directly doesn't sound like a good idea, since the refname causes the
entries to be of variable length, and the refnames are not interesting
to me at all.
2. Keep another file, ".git/reverse_tagmap_unsorted" in front of (1).
This file has exactly the same format, minus the sorting. It exists just
to make insertion cheap. Once this file reaches a certain size (i.e.
when trawling it on lookup becomes slightly painful), we shuffle the
entries into the sorted file (this would happen automatically on
insertion of an entry, and should _not_ have to be triggered by 'git-gc'
etc.).
Of course, if we think insertion directly into (1) will never be too
expensive, we can drop (2) altogether.
I don't know enough about packing to have a good idea on how to pack
these reverse tagmaps, but Shawn's thoughts about keeping associated
tags/notes and objects close together makes a lot of sense. I'm just
not sure yet where these reverse tagmaps fit into the whole picture.
Currently, AFAICS, the packed-refs file is never propagated into the
packs, but stays separate for the lifetime of the repo, but then it
seems we're designing these reverse tagmaps for managing a handful of
notes per commit, i.e. to hold a couple of orders of magnitude more
entries than the packed-refs file.
Maybe each pack should keep the reverse tagmap for all the object->note
relationships internal to that pack? Everything else (unpacked notes,
and object->note relationships spanning packs) would be kept in (1).
Of course, when repacking, we'd try to keep objects and their notes
together as much as possible, to maximize the in-pack reverse tagmap,
and minimize the number of entries left behind in (1).
Have fun!
...Johan
--
Johan Herland, <johan@herland.net>
www.herland.net
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH 00/15] git-note: A mechanisim for providing free-form after-the-fact annotations on commits
2007-05-29 7:06 ` Johan Herland
@ 2007-05-29 8:22 ` Jeff King
2007-05-29 9:23 ` Johan Herland
0 siblings, 1 reply; 53+ messages in thread
From: Jeff King @ 2007-05-29 8:22 UTC (permalink / raw)
To: Johan Herland; +Cc: Junio C Hamano, Linus Torvalds, git
On Tue, May 29, 2007 at 09:06:29AM +0200, Johan Herland wrote:
> 1. Keep a file, ".git/reverse_tagmap_sorted" with one entry of the form
> "pointee pointer" per line. The file is sorted on "pointee", so we can
> easily do the radix-256-fan-out-followed-by-binary-search trick that
> Linus mentioned in another thread. This should hopefully make lookup
> fairly cheap. BTW, if there is a similar "pointee pointer"-type format
> already being used in git, I'd be happy to use that instead. I looked
I did a similar thing (though rather than having "lines" at all, they
were fixed-length pairs of binary sha1 hashes) to implement a negative
delta cache (which turned out to be a stupid idea, but the
implementation worked):
http://www.gelato.unsw.edu.au/archives/git/0606/23229.html
> 2. Keep another file, ".git/reverse_tagmap_unsorted" in front of (1).
> This file has exactly the same format, minus the sorting. It exists just
> to make insertion cheap. Once this file reaches a certain size (i.e.
> when trawling it on lookup becomes slightly painful), we shuffle the
> entries into the sorted file (this would happen automatically on
> insertion of an entry, and should _not_ have to be triggered by 'git-gc'
> etc.).
The implementation I mentioned above collects several "to be inserted"
entries (in memory) and then merge sorts the two lists into a new file.
So it was fast in terms of comparisons, but it involved writing O(n)
entries, which is probably bad for creating a single note.
> Of course, if we think insertion directly into (1) will never be too
> expensive, we can drop (2) altogether.
You can always find the right spot, memmove everything down one slot,
and insert. But that means:
- the cost of insertion will be proportional to the number of items,
whereas using an unsorted journal you get to amortize that cost over
many insertions
- if you update in place, you have to lock the db for reading while
you are moving around. If you are always either appending to the
journal or merging into a new file, you can avoid this.
-Peff
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH 00/15] git-note: A mechanisim for providing free-form after-the-fact annotations on commits
2007-05-29 8:22 ` Jeff King
@ 2007-05-29 9:23 ` Johan Herland
0 siblings, 0 replies; 53+ messages in thread
From: Johan Herland @ 2007-05-29 9:23 UTC (permalink / raw)
To: Jeff King; +Cc: Junio C Hamano, Linus Torvalds, git
On Tuesday 29 May 2007, Jeff King wrote:
> On Tue, May 29, 2007 at 09:06:29AM +0200, Johan Herland wrote:
>
> > 1. Keep a file, ".git/reverse_tagmap_sorted" with one entry of the form
> > "pointee pointer" per line. The file is sorted on "pointee", so we can
> > easily do the radix-256-fan-out-followed-by-binary-search trick that
> > Linus mentioned in another thread. This should hopefully make lookup
> > fairly cheap. BTW, if there is a similar "pointee pointer"-type format
> > already being used in git, I'd be happy to use that instead. I looked
>
> I did a similar thing (though rather than having "lines" at all, they
> were fixed-length pairs of binary sha1 hashes) to implement a negative
> delta cache (which turned out to be a stupid idea, but the
> implementation worked):
>
> http://www.gelato.unsw.edu.au/archives/git/0606/23229.html
Cool. It won't give a big-Oh improvement, but it might give a worthwile
boost anyway. I guess it's the usual tradeoff between speed and
maintainability/transparency/readability.
> > 2. Keep another file, ".git/reverse_tagmap_unsorted" in front of (1).
> > This file has exactly the same format, minus the sorting. It exists just
> > to make insertion cheap. Once this file reaches a certain size (i.e.
> > when trawling it on lookup becomes slightly painful), we shuffle the
> > entries into the sorted file (this would happen automatically on
> > insertion of an entry, and should _not_ have to be triggered by 'git-gc'
> > etc.).
>
> The implementation I mentioned above collects several "to be inserted"
> entries (in memory) and then merge sorts the two lists into a new file.
> So it was fast in terms of comparisons, but it involved writing O(n)
> entries, which is probably bad for creating a single note.
>
> > Of course, if we think insertion directly into (1) will never be too
> > expensive, we can drop (2) altogether.
>
> You can always find the right spot, memmove everything down one slot,
> and insert. But that means:
> - the cost of insertion will be proportional to the number of items,
> whereas using an unsorted journal you get to amortize that cost over
> many insertions
> - if you update in place, you have to lock the db for reading while
> you are moving around. If you are always either appending to the
> journal or merging into a new file, you can avoid this.
Yep, I'm thinking (2) will be worth it in the end. O(#notes) per note
insertion doesn't sound appealing at all, especially not if we're
expecting a handful of notes per commit.
Have fun!
...Johan
--
Johan Herland, <johan@herland.net>
www.herland.net
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH 00/15] git-note: A mechanisim for providing free-form after-the-fact annotations on commits
2007-05-28 10:54 ` Johan Herland
2007-05-28 16:28 ` Linus Torvalds
@ 2007-05-28 20:45 ` Junio C Hamano
2007-05-28 21:19 ` Shawn O. Pearce
2007-05-28 23:46 ` [PATCH] Add fsck_verify_ref_to_tag_object() to verify that refname matches name stored in tag object Johan Herland
1 sibling, 2 replies; 53+ messages in thread
From: Junio C Hamano @ 2007-05-28 20:45 UTC (permalink / raw)
To: Johan Herland; +Cc: Linus Torvalds, git
Johan Herland <johan@herland.net> writes:
> And while we're on the subject of changing the tag object, I'd like for
> the "tag" header (the one holding the tag name) to become optional.
> When doing my ref <-> name trick above, I conveniently forgot this little
> bugger. Basically the only reason for this one to exist is to include the
> name of the tag in the data passed to gpg for signing. This is of course
> necesssary in order to make renaming a signed tag impossible. (Allowing
> renaming would make it possible to replace it with a malicious tag with
> the original name.) Therefore the "tag" header must be mandatory for
> signed tags. But for all other tags (including notes) this header is
> pretty much useless.
This brings up an interesting point, by the way.
Currently when you say
$ git show v2.6.22
we "dwim_ref" v2.6.22. That is, we try to see if ".git/v2.6.22"
is there (it isn't), check ".git/refs/v2.6.22" (no, again), then
happily find that ".git/refs/tags/v2.6.22" is there and use it.
During this process we _never_ check if the tag object pointed
at by the ref v2.6.22 has tagname v2.6.22 at all.
I do not think it is a problem at all that we do not use "tag"
name during the look-up process. However it would be a good
idea to add logic to fsck to warn upon inconsistencis (perhaps
by mistake) between refname and tag's true name.
The check would say something like:
If an annotated (signed or unsigned) tag has a "tag"
line to give it the official $name, and if it is pointed
at by a ref, the refname must end with "/$name".
Otherwise we warn.
Trivially, the above rule says that having v2.6.22 tag under
refs/tags/v2.6.20 is a mistake we would want to be warned upon.
The "/$name" part is to support merging a separate project into
another project after the fact better. Shawn graciously names
his tags in git-gui project "gitgui-0.7.1", to avoid tag name
collisions with "v1.5.0" style tag names in git.git project, but
we could have stored his v0.7.1 tag as refs/tags/gitgui/v0.7.1
to differenciate the tag namespace (this needs an update to the
"tag following" code in git-fetch with a new configuration).
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH 00/15] git-note: A mechanisim for providing free-form after-the-fact annotations on commits
2007-05-28 20:45 ` Junio C Hamano
@ 2007-05-28 21:19 ` Shawn O. Pearce
2007-05-28 23:46 ` [PATCH] Add fsck_verify_ref_to_tag_object() to verify that refname matches name stored in tag object Johan Herland
1 sibling, 0 replies; 53+ messages in thread
From: Shawn O. Pearce @ 2007-05-28 21:19 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Johan Herland, Linus Torvalds, git
Junio C Hamano <junkio@cox.net> wrote:
> Shawn graciously names
> his tags in git-gui project "gitgui-0.7.1", to avoid tag name
> collisions with "v1.5.0" style tag names in git.git project, but
> we could have stored his v0.7.1 tag as refs/tags/gitgui/v0.7.1
> to differenciate the tag namespace (this needs an update to the
> "tag following" code in git-fetch with a new configuration).
Actually I use that same naming convention everywhere else except
in egit. I've found it easier to have the "major project name"
prefixed in front of the version number as it sort of reminds me
of what I'm looking at... yes, I get confused easily. There are
far too many "v1.0.0", "v1.0.1" around... ;-)
--
Shawn.
^ permalink raw reply [flat|nested] 53+ messages in thread
* [PATCH] Add fsck_verify_ref_to_tag_object() to verify that refname matches name stored in tag object
2007-05-28 20:45 ` Junio C Hamano
2007-05-28 21:19 ` Shawn O. Pearce
@ 2007-05-28 23:46 ` Johan Herland
1 sibling, 0 replies; 53+ messages in thread
From: Johan Herland @ 2007-05-28 23:46 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, Linus Torvalds
On Monday 28 May 2007, Junio C Hamano wrote:
> However it would be a good
> idea to add logic to fsck to warn upon inconsistencis (perhaps
> by mistake) between refname and tag's true name.
>
> The check would say something like:
>
> If an annotated (signed or unsigned) tag has a "tag"
> line to give it the official $name, and if it is pointed
> at by a ref, the refname must end with "/$name".
> Otherwise we warn.
>
> Trivially, the above rule says that having v2.6.22 tag under
> refs/tags/v2.6.20 is a mistake we would want to be warned upon.
This patch adds the check described by Junio.
It is assumed that the "tag" header is mandatory for all tag objects.
This might change in the future, at which point this patch should be
revised.
Signed-off-by: Johan Herland <johan@herland.net>
---
I hope this is what you had in mind :)
Have fun!
...Johan
builtin-fsck.c | 19 +++++++++++++++++++
1 files changed, 19 insertions(+), 0 deletions(-)
diff --git a/builtin-fsck.c b/builtin-fsck.c
index cbbcaf0..3594bd3 100644
--- a/builtin-fsck.c
+++ b/builtin-fsck.c
@@ -501,6 +501,23 @@ static int fsck_handle_reflog(const char *logname, const unsigned char *sha1, in
return 0;
}
+static void fsck_verify_ref_to_tag_object(const char *refname, struct object *obj)
+{
+ /* Verify that refname matches the name stored in obj's "tag" header */
+ struct tag *tagobj = (struct tag *) parse_object(obj->sha1);
+ size_t tagname_len = strlen(tagobj->tag);
+ size_t refname_len = strlen(refname);
+
+ if (tagname_len < refname_len &&
+ !memcmp(tagobj->tag, refname + (refname_len - tagname_len), tagname_len) &&
+ refname[(refname_len - tagname_len) - 1] == '/') {
+ /* OK: tag name is "$name", and refname ends with "/$name" */
+ return;
+ }
+ else
+ error("%s: Mismatch between tag ref and tag object's name %s", refname, tagobj->tag);
+}
+
static int fsck_handle_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
{
struct object *obj;
@@ -515,6 +532,8 @@ static int fsck_handle_ref(const char *refname, const unsigned char *sha1, int f
/* We'll continue with the rest despite the error.. */
return 0;
}
+ if (obj->type == OBJ_TAG) /* ref to tag object */
+ fsck_verify_ref_to_tag_object(refname, obj);
default_refs++;
obj->used = 1;
mark_reachable(obj, REACHABLE);
--
1.5.2.87.g875de-dirty
^ permalink raw reply related [flat|nested] 53+ messages in thread
* Re: [PATCH 00/15] git-note: A mechanisim for providing free-form after-the-fact annotations on commits
2007-05-28 4:37 ` Linus Torvalds
2007-05-28 10:54 ` Johan Herland
@ 2007-05-28 17:29 ` Michael S. Tsirkin
2007-05-28 17:42 ` Michael S. Tsirkin
1 sibling, 1 reply; 53+ messages in thread
From: Michael S. Tsirkin @ 2007-05-28 17:29 UTC (permalink / raw)
To: Linus Torvalds; +Cc: Johan Herland, git, Junio C Hamano
> Quoting Linus Torvalds <torvalds@linux-foundation.org>:
> Subject: Re: [PATCH 00/15] git-note: A mechanisim for providing free-form after-the-fact annotations on commits
>
>
>
> On Sun, 27 May 2007, Johan Herland wrote:
> >
> > I've been working on combining tag objects and --decorate into a useful
> > proof-of-concept that provides the after-the-fact commit annotations I
> > requested above, and here's the result:
>
> Ok, looks fine to me. I do have a few questions:
> - why don't you just let people name their notes, the same way we name
> tags (and then actually using it as the note name?)
>
> Putting them in the refs/notes/ filesystem by their SHA1 seems a bit
> wasteful, and it would seem that it could be quite nice to name the
> notes some way?
>
> - This will probably scale horribly badly if you have tens of thousands
> of notes, even when they are packed. Do we care?
Maybe note names could include the object they point to?
Would this help with the scalability too (i.e. only get
names for objects we want)?
--
MST
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH 00/15] git-note: A mechanisim for providing free-form after-the-fact annotations on commits
2007-05-28 17:29 ` [PATCH 00/15] git-note: A mechanisim for providing free-form after-the-fact annotations on commits Michael S. Tsirkin
@ 2007-05-28 17:42 ` Michael S. Tsirkin
2007-05-28 17:58 ` Johan Herland
0 siblings, 1 reply; 53+ messages in thread
From: Michael S. Tsirkin @ 2007-05-28 17:42 UTC (permalink / raw)
To: Michael S. Tsirkin; +Cc: Linus Torvalds, Johan Herland, git, Junio C Hamano
> Quoting Michael S. Tsirkin <mst@dev.mellanox.co.il>:
> Subject: Re: [PATCH 00/15] git-note: A mechanisim for providing free-form after-the-fact annotations on commits
>
> > Quoting Linus Torvalds <torvalds@linux-foundation.org>:
> > Subject: Re: [PATCH 00/15] git-note: A mechanisim for providing free-form after-the-fact annotations on commits
> >
> >
> >
> > On Sun, 27 May 2007, Johan Herland wrote:
> > >
> > > I've been working on combining tag objects and --decorate into a useful
> > > proof-of-concept that provides the after-the-fact commit annotations I
> > > requested above, and here's the result:
> >
> > Ok, looks fine to me. I do have a few questions:
> > - why don't you just let people name their notes, the same way we name
> > tags (and then actually using it as the note name?)
> >
> > Putting them in the refs/notes/ filesystem by their SHA1 seems a bit
> > wasteful, and it would seem that it could be quite nice to name the
> > notes some way?
> >
> > - This will probably scale horribly badly if you have tens of thousands
> > of notes, even when they are packed. Do we care?
>
> Maybe note names could include the object they point to?
> Would this help with the scalability too (i.e. only get
> names for objects we want)?
Hmm, I just noticed there's refs/notes/{object-sha}/{note-sha}
that does exactly that. So - this seems to be clear to everyone
else, but I seem to miss the reason why does this not scale well?
We can just get the notes for objects we pull, right?
--
MST
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH 00/15] git-note: A mechanisim for providing free-form after-the-fact annotations on commits
2007-05-28 17:42 ` Michael S. Tsirkin
@ 2007-05-28 17:58 ` Johan Herland
0 siblings, 0 replies; 53+ messages in thread
From: Johan Herland @ 2007-05-28 17:58 UTC (permalink / raw)
To: git, Michael S. Tsirkin; +Cc: Linus Torvalds, Junio C Hamano
On Monday 28 May 2007, Michael S. Tsirkin wrote:
> Quoting Michael S. Tsirkin <mst@dev.mellanox.co.il>:
> > Maybe note names could include the object they point to?
> > Would this help with the scalability too (i.e. only get
> > names for objects we want)?
>
> Hmm, I just noticed there's refs/notes/{object-sha}/{note-sha}
> that does exactly that. So - this seems to be clear to everyone
> else, but I seem to miss the reason why does this not scale well?
> We can just get the notes for objects we pull, right?
Currently, only "git-note -l" (and by extension gitk) uses the shortcut
through refs/notes/{object-sha}/...
The --decorate code and everybody else goes through for_each_note_ref()
which looks up every note ref in the repo.
...Johan
--
Johan Herland, <johan@herland.net>
www.herland.net
^ permalink raw reply [flat|nested] 53+ messages in thread