Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [jgit-dev] Git Notes Support?

Chris Aniszczyk <caniszczyk@xxxxxxxxx> wrote:
> As an exercise in learning more of the JGit internals, I'm looking at
> implementing git-notes support.
> 
> The way I understand it, under the covers, when you add a "note" to an
> object, that note is represented by a commit the message as a blob,
> correct? So there's no special object type (e.g., blob, tree, commit,
> tag)? From my investigation after doing a couple tags... you get
> objects that look like this...

Right.  The notes content is stored as a blob, and then the ObjectId
of the thing the note applies to (so say the commit ObjectId)
is used as the file path in the tree of the notes commit graph.
This tree is broken up with a fanout system, each time there are
256+ entries in a tree the tree is split using the next two bytes
of the name as the subdirectory names.
 
> Although it seems notes can be added to
> any object in Git...

Yes, that is true, and we should support it.  Though the more common
usage is on commits.

> So does it make more sense to modify RevCommit (or RevObject) or
> create a new RevNotes object?

Probably none of the above.  :-)

Maybe something more like:

  public class NoteMap {
    private ObjectIdSubclassMap<Note> notes;
    private ObjectReader reader;

    public NoteMap(ObjectReader reader, ObjectId noteTree);

    public Note lookup(RevObject obj) throws IOException;
  }

  public class Note extends RevBlob {
    public String getFullMessage();
  }

Callers who want/need note support would create a NoteMap parallel
to their RevWalk and lookup notes as they go:

  ObjectReader reader = repo.newObjectReader();
  RevWalk rw = new RevWalk(reader);
  NoteMap notes = new NoteMap(reader, repo.resolve("refs/notes/commits"));
  ...
  for (;;) {
    RevCommit c = rw.next();
    if (c == null)
      break;

    System.out.println(c.getFullMessage());

    Note note = notes.lookup(c);
    if (note != null)
      System.out.println(note.getFullMessage());
  }


A naive NoteMap implementation would scan its tree with a TreeWalk
recursively and load everything up front.  A smarter implementation
would try to lazily unfold subtrees as it gets misses.  This way
"top N" sorts of requests like the History pane rendering only 1
full commit, or rendering the 15 lines that are currently visible,
don't have to open the entire note tree.  Just the N or so subtrees
that are really relevant.

That does make the implementation harder because you aren't quite
caching via an ObjectIdSubclassMap.  You need some sort of fanout
structure that matches the fanout you are observing in your tree
as you iterate it with a TreeWalk.


Editing/writing the notes is a whole different animal, but has a
similar performance curve problem.  You want to only muck with the
section you really need to touch.

-- 
Shawn.


Back to the top