15

On every tutorial site about git objects I'll see an example where git cat-file displays what the commit object itself looks like, and it's usually something like the following:

tree 552acd444696ccb1c3afe68a55ae8b20ece2b0e6
parent 6a1d380780a83ef5f49523777c5e8d801b7b9ba2
author John Doe <[email protected]> 1326496982 -0600
committer John Doe <[email protected]> 1326496982 -0600

Some commit message here.

If there were additional (single line) data fields at the top, would this confuse the git tools? I assume that even if it didn't, these fields wouldn't show up in git log.

If it can have additional fields, which git plumbing command would allow you to create that? git commit-tree doesn't seem that flexible.

6
  • 3
    See git help notes for a way to attach arbitrary text to a commit. Commented Nov 20, 2013 at 15:33
  • 1
    Also, the commit message portion of the commit object is pretty much free-form, so you can add whatever you want there, and just require your users to adhere to a particular format. There's no easy way to add your own headers, though. Commented Nov 20, 2013 at 15:40
  • 1
    @twalberg Is there a hard way to add your own headers? Commented Nov 20, 2013 at 16:42
  • 3
    @JohnO You can use git hash-object to create an object of any type (blob, tree, commit, tag) by hand, but you have to provide properly formatted input. I haven't looked into what kind of verification hash-object does on the various types of objects, and it's quite possible that it may reject a commit object that has extra headers. If that doesn't work, you can try to fake it by manually zlib compressing a file with correct headers prepended and naming it appropriately to be part of gits object database (based on sha1sum). That's quite low-level and brittle, though... Commented Nov 20, 2013 at 16:51
  • 3
    @twalberg git hash-object doesn't seem to object to an additional header. It doesn't confuse it either, still picks up where the commit message is... but as expected, git log of course doesn't show it. Does show up with a "git cat-file commit [hash]" at least... Commented Nov 20, 2013 at 17:51

4 Answers 4

13

The traditional way to attach data to a commit are "trailers": special formatted lines at the end of the commit message. The Signed-of-by line added by git commit -s (docu) is such a trailer.

Git has some direct support for these:

  • git interpret-trailers (docu) is a helper for adding or parsing these lines
  • git log has a format-placeholder %(trailers[:options]) (docu)
  • git for-each-ref also has a %(trailers) placeholder (docu)

Trailers have some differences to git notes:

  • The trailers are part of the commit message and hence covered by the hash. They are therefore immutable. git notes are add-ons to commits (or other stuff).
  • Trailer data is cloned and pushed to/from remote repositories. git notes not by default.
  • Trailer data is moved around by git cherry-pick, git rebase and others. git notes ... sometimes.
Sign up to request clarification or add additional context in comments.

1 Comment

Git notes are moved around (i.e. rewrite) by git-rebase(1) when notes.rewriteRef are in effect for the notes namespace in question. Git cherry-pick however doesn’t respect that configuration. This has caused problems for some people.
9

Yes, you can totally put more fields called “git commit extra headers” in there. They’ll show up with git cat-file -p, but the only way I see to get them in there in the first place with the standard git client is by editing the git source and recompiling.

In commit.h, there is a struct for extra headers, along with functions to add them when committing, and to read them out later.

struct commit_extra_header {
        struct commit_extra_header *next;
        char *key;
        char *value;
        size_t len;
};

int commit_tree_extended(const char *msg, size_t msg_len,
                        const struct object_id *tree,
                        struct commit_list *parents,
                        struct object_id *ret, const char *author,
                        const char *sign_commit,
                        struct commit_extra_header *);

struct commit_extra_header *read_commit_extra_headers(struct commit *, const char **);

commit.c contains a list of ‘standard’ header fields:

static inline int standard_header_field(const char *field, size_t len)
{
        return ((len == 4 && !memcmp(field, "tree", 4)) ||
                (len == 6 && !memcmp(field, "parent", 6)) ||
                (len == 6 && !memcmp(field, "author", 6)) ||
                (len == 9 && !memcmp(field, "committer", 9)) ||
                (len == 8 && !memcmp(field, "encoding", 8)));
}

with everything else showing up as an ‘extra’ header.

Doing a quick grep of the source code, the only current use I found of this is the gpgsig header used to include GPG signatures on commits.

Kiln Harmony, now discontinued, used fields such as kilnhgusername and kilnhgrawdescription here.

Comments

4

git notes will add an arbitrary note to any commit. Usage: git notes add <SHA>, e.g. git notes add HEAD. This will pull up the default text editor and allow you enter a note. You can also specify a message from the CLI in the same manner as you can with a commit, i.e. git notes add -m "my message" HEAD.

If you run a git log after taking a note, you will see:

commit 06ca03a20bb01203e2d6b8996e365f46cb6d59bd
Author: Example User <[email protected]>
Date:   Mon March 28 14:50:15 2016 -0700

    commit message

Notes:
    my message

Notes can be given namespaces as well. This article has the complete documentation.

2 Comments

The article link provided is stale. I found the git-notes page that might be the page referred to, but it doesn't mention namespaces. Can anyone point me in the right direction?
Notes are not stored in the commit object and can be edited after the fact without modifying the commit hash.
0

You can use git hash-object -t commit -w FILE to create your own commit object with your custom git headers from a file, it will print the commit id of the newly created commit to stdout. It's easiest if you start from an existing commit object, add your custom header, create a new commit object and reset your branch to point to the newly created commit object. You can dump a commit object to a file using git cat-file -p COMMIT_ID > FILE.

For example this one-liner adds "myheader foo bar" to the last commit:

git reset "$(git cat-file -p HEAD | sed -e '0,/^$/s/^$/myheader foo bar\n/' | git hash-object -t commit -w --stdin)"

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.