{"thread":{"id":"35845","subject":"git-note -C changes commit type?","startedAt":"2014-02-11T17:23:27Z","lastAt":"2014-02-14T16:19:44Z","messageCount":11,"participants":["Joachim Breitner","Johan Herland","Junio C Hamano","Kyle J. McKay","Eric Sunshine"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"234618","messageId":"1392139407.12790.7.camel@kirk","threadId":"35845","inReplyTo":null,"subject":"git-note -C changes commit type?","fromName":"Joachim Breitner","fromEmail":"mail@joachim-breitner.de","sentAt":"2014-02-11T17:23:27Z","receivedAt":"2014-02-11T17:23:27Z","isPatch":false,"sender":{"key":"mail@joachim-breitner.de","avatar":"https://gravatar.com/avatar/1e9dd229978aa44811b44fc08a445cd1950a092f74fe2f5539d881f1c1b46fbf?d=mp&s=160"},"body":"Hi,\n\njudging from the documentation I got the impression that I can pass any\ngit object has to \"git note -C <hash>\" and it would stored as-is. But it\nseems the objects gets mangled somehow...\n\n(I want to attach a commit object as a note, to reference the history of\na feature before the final cleanup rebase. For that I turn the reflog\ninto a series of commits, and the final commit is the one I want to\nstore there.)\n\n$ mkdir foo\n$ cd foo/\n$ echo foo > a\n$ git init\nInitialisierte leeres Git-Repository in /tmp/foo/.git/\n$ git add a\n$ git commit -m 'A commit'\n[master (Basis-Commit) 3d7de37] A commit\n 1 file changed, 1 insertion(+)\n create mode 100644 a\n$ echo foo2 > a\n$ git commit -m 'A commit 2' -a\n[master e1bfac4] A commit 2\n 1 file changed, 1 insertion(+), 1 deletion(-)\n$ git notes --ref history add -C 3d7de37 e1bfac4\n$ git ls-tree notes/history\n100644 blob 5b73d5152e6207e3a2b67e57ca3a2cb94d12061e e1bfac434ebd3135a3784f6fc802f235098eebd0\n\nI was expecting 3d7de37 to be referenced here.\n\nIs that a bug, or is storing commits as notes not supported?\n\nThanks,\nJoachim\n\n\n-- \nJoachim “nomeata” Breitner\n  mail@joachim-breitner.de • http://www.joachim-breitner.de/\n  Jabber: nomeata@joachim-breitner.de  • GPG-Key: 0x4743206C\n  Debian Developer: nomeata@debian.org\n"},{"id":"234630","messageId":"CALKQrgcM7JpZCk4amjo_rwg5uuuWNg-5yd1NXB5p7EtrU9WBGg@mail.gmail.com","threadId":"35845","inReplyTo":"1392139407.12790.7.camel@kirk","subject":"Re: git-note -C changes commit type?","fromName":"Johan Herland","fromEmail":"johan@herland.net","sentAt":"2014-02-11T23:52:51Z","receivedAt":"2014-02-11T23:52:51Z","isPatch":false,"sender":{"key":"johan@herland.net","avatar":"https://avatars.githubusercontent.com/u/547031?v=4"},"body":"On Tue, Feb 11, 2014 at 6:23 PM, Joachim Breitner\n<mail@joachim-breitner.de> wrote:\n> Hi,\n>\n> judging from the documentation I got the impression that I can pass any\n> git object has to \"git note -C <hash>\" and it would stored as-is. But it\n> seems the objects gets mangled somehow...\n\n...well... the documentation does not say \"any object\", it actually\nexplicitly says \"blob object\"... ;)\n\n> (I want to attach a commit object as a note, to reference the history of\n> a feature before the final cleanup rebase. For that I turn the reflog\n> into a series of commits, and the final commit is the one I want to\n> store there.)\n>\n> $ mkdir foo\n> $ cd foo/\n> $ echo foo > a\n> $ git init\n> Initialisierte leeres Git-Repository in /tmp/foo/.git/\n> $ git add a\n> $ git commit -m 'A commit'\n> [master (Basis-Commit) 3d7de37] A commit\n>  1 file changed, 1 insertion(+)\n>  create mode 100644 a\n> $ echo foo2 > a\n> $ git commit -m 'A commit 2' -a\n> [master e1bfac4] A commit 2\n>  1 file changed, 1 insertion(+), 1 deletion(-)\n> $ git notes --ref history add -C 3d7de37 e1bfac4\n> $ git ls-tree notes/history\n> 100644 blob 5b73d5152e6207e3a2b67e57ca3a2cb94d12061e e1bfac434ebd3135a3784f6fc802f235098eebd0\n>\n> I was expecting 3d7de37 to be referenced here.\n>\n> Is that a bug, or is storing commits as notes not supported?\n\nI guess it depends on your POV... The current documentation says \"blob\nobject\", and what actually happens (in builtin/notes.c) is that the\ngiven object (3d7de37 in your example) is read into a strbuf (in\nparse_reuse_arg()) and stored back into a note object (in\ncreate_note()), without preserving the object type (\"blob\" type is\nhardcoded). This means an incoming blob object (as documented) will be\npreserved (i.e. reuse the same SHA-1), but for any other object type,\nthe object bits will be read, and stored back into a blob object. This\nis why your commit (or any other non-blob) ends up with a different\nSHA-1 when stored as a note: It is the same bytes, but in a blob\nobject instead of a commit object.\n\nThere is currently no way the \"git notes\" commands will allow you to\nstore the 3d7de37 commit object directly as a note. There is also\n(AFAICS) no easy workaround (git fast-import could've been a\nworkaround if it did not already require the first N/notemodify\nargument to be a blob object). The best alternative, off the top of my\nhead, would be to write your own program using the notes.h API to\nmanipulate the notes tree directly (or - suboptimally - use other\nlow-level Git operations to do the same).\n\nHowever before you go there, let's take a step back, and look at what\nthe result would look like (if you were allowed to store a commit\nobject directly as a note):\n\nYou would have a notes ref \"refs/notes/history\" whose tree would\ncontain an entry named e1bfac434ebd3135a3784f6fc802f235098eebd0\npointing to a _commit_ (3d7de37...). Obviously, it would not make\nsense to use refs/notes/history while displaying the commit log (\"git\nlog --notes=history\"), as the raw commit object would be shown in the\nlog. However, more fundamentally: a tree referring to a _commit_ is\nusually how Git stores _submodule_ links (i.e. which revision of the\nnamed submodule is to be used by this super-repo tree), and I'm (off\nthe top of my head) not at all sure that such a submodule link in a\nnotes tree is handled \"sanely\" by Git - or even that it makes sense at\nall. For one, I'm not sure that Git requires (or even expects) the\ncommit object referenced by a tree to be present in the same object\nDB. So if you share your notes, I don't know whether or not the\nfetch/push machinery will include the commit object in the shared\nnotes... These are questions that should be answered before we decide\nwhether using commits directly as notes makes sense.\n\nIf we do figure out that storing commits as note objects is desirable\n(and does not have too nasty side-effects), then I am not opposed to\nfixing builtin/notes.c to preserve type of the object passed in -C.\nCertainly, the current behavior for non-blobs (i.e. copy the object\nbytes, but not the object type) is probably not useful to anyone...\n\nThat said, there may be other ways to solve your immediate problem:\nInstead of storing the commit object directly as a note, you could\nstore the commit SHA-1 into a blob, and use that as the blob object.\nThat would also allow you to store multiple commits in the note for\ne1bfac4 (in case you had several cleanup rebases leading to the final\ncommit), or you could store other kinds of metadata in the same note.\nOr do you have a requirement that the reflog history (presumably\nreachable from 3d7de37) need to be shared (or otherwise kept\nreachable)? In that case, you might be better off using an explicit\nref to keep that history alive; e.g. you could create\nrefs/history/e1bfac4 to point to 3d7de37 (\"git update-ref\nrefs/history/e1bfac4 3d7de37\"), and keep everything\nalive/reachable/shareable that way...\n\n\nHope this helps,\n\n...Johan\n\n-- \nJohan Herland, <johan@herland.net>\nwww.herland.net\n"},{"id":"234632","messageId":"xmqqvbwlnqi1.fsf@gitster.dls.corp.google.com","threadId":"35845","inReplyTo":"CALKQrgcM7JpZCk4amjo_rwg5uuuWNg-5yd1NXB5p7EtrU9WBGg@mail.gmail.com","subject":"Re: git-note -C changes commit type?","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2014-02-12T00:06:46Z","receivedAt":"2014-02-12T00:06:46Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johan Herland <johan@herland.net> writes:\n\n> There is currently no way the \"git notes\" commands will allow you to\n> store the 3d7de37 commit object directly as a note. There is also\n> (AFAICS) no easy workaround (git fast-import could've been a\n> workaround if it did not already require the first N/notemodify\n> argument to be a blob object). The best alternative, off the top of my\n> head, would be to write your own program using the notes.h API to\n> manipulate the notes tree directly (or - suboptimally - use other\n> low-level Git operations to do the same).\n\nEven worse. I do not think such a non-blob object in the notes tree\ndoes not participate in the reachability at all, so you won't be\nable to fetch \"refs/notes/whatever\" and expect to get a useful\nresult.  I do not think storing the raw bits of commit object as a\nblob in the notes tree is useful behaviour, either.  The command\nprobably should refuse to get anything non-blob via that option.\n\nPerhaps the notes entry should just note the object name of whatever\ncommit it wants to refer to in a *blob*?\n"},{"id":"234639","messageId":"8E256253-7470-4195-9A62-489870530915@gmail.com","threadId":"35845","inReplyTo":"xmqqvbwlnqi1.fsf@gitster.dls.corp.google.com","subject":"Re: git-note -C changes commit type?","fromName":"Kyle J. McKay","fromEmail":"mackyle@gmail.com","sentAt":"2014-02-12T05:16:44Z","receivedAt":"2014-02-12T05:16:44Z","isPatch":false,"sender":{"key":"mackyle@gmail.com","avatar":"https://avatars.githubusercontent.com/u/813346?v=4"},"body":"On Feb 11, 2014, at 16:06, Junio C Hamano wrote:\n> Johan Herland <johan@herland.net> writes:\n>\n>> There is currently no way the \"git notes\" commands will allow you to\n>> store the 3d7de37 commit object directly as a note. There is also\n>> (AFAICS) no easy workaround (git fast-import could've been a\n>> workaround if it did not already require the first N/notemodify\n>> argument to be a blob object). The best alternative, off the top of  \n>> my\n>> head, would be to write your own program using the notes.h API to\n>> manipulate the notes tree directly (or - suboptimally - use other\n>> low-level Git operations to do the same).\n>\n> Even worse. I do not think such a non-blob object in the notes tree\n> does not participate in the reachability at all, so you won't be\n> able to fetch \"refs/notes/whatever\" and expect to get a useful\n> result.  I do not think storing the raw bits of commit object as a\n> blob in the notes tree is useful behaviour, either.  The command\n> probably should refuse to get anything non-blob via that option.\n\nIt would be nice if it let you store a tree or a blob, but I agree  \nthat it should complain about anything non-blob by default and if tree  \nwere to be allowed, that should require a special option.\n\nIf you do manually construct a notes tree that has a 'tree' entry  \ninstead of a blob, as soon as you add a new note, that 'tree' gets  \nturned back into a blob again.  I was trying to attach a 'tree' as my  \nnote a while back and decided not to pursue it further after I found  \nit got transformed into a 'blob' on the next notes modification.\n"},{"id":"234644","messageId":"1392195218.2546.7.camel@kirk","threadId":"35845","inReplyTo":"CALKQrgcM7JpZCk4amjo_rwg5uuuWNg-5yd1NXB5p7EtrU9WBGg@mail.gmail.com","subject":"Re: git-note -C changes commit type?","fromName":"Joachim Breitner","fromEmail":"mail@joachim-breitner.de","sentAt":"2014-02-12T08:53:38Z","receivedAt":"2014-02-12T08:53:38Z","isPatch":false,"sender":{"key":"mail@joachim-breitner.de","avatar":"https://gravatar.com/avatar/1e9dd229978aa44811b44fc08a445cd1950a092f74fe2f5539d881f1c1b46fbf?d=mp&s=160"},"body":"Dear Johan,\n\nAm Mittwoch, den 12.02.2014, 00:52 +0100 schrieb Johan Herland:\n> On Tue, Feb 11, 2014 at 6:23 PM, Joachim Breitner\n> <mail@joachim-breitner.de> wrote:\n> > judging from the documentation I got the impression that I can pass any\n> > git object has to \"git note -C <hash>\" and it would stored as-is. But it\n> > seems the objects gets mangled somehow...\n> \n> ...well... the documentation does not say \"any object\", it actually\n> explicitly says \"blob object\"... ;)\n\nok, my bad; guess I’m not fully versed with gits terminology.\n\n> You would have a notes ref \"refs/notes/history\" whose tree would\n> contain an entry named e1bfac434ebd3135a3784f6fc802f235098eebd0\n> pointing to a _commit_ (3d7de37...). Obviously, it would not make\n> sense to use refs/notes/history while displaying the commit log (\"git\n> log --notes=history\"), as the raw commit object would be shown in the\n> log. However, more fundamentally: a tree referring to a _commit_ is\n> usually how Git stores _submodule_ links (i.e. which revision of the\n> named submodule is to be used by this super-repo tree), and I'm (off\n> the top of my head) not at all sure that such a submodule link in a\n> notes tree is handled \"sanely\" by Git - or even that it makes sense at\n> all. For one, I'm not sure that Git requires (or even expects) the\n> commit object referenced by a tree to be present in the same object\n> DB. So if you share your notes, I don't know whether or not the\n> fetch/push machinery will include the commit object in the shared\n> notes... These are questions that should be answered before we decide\n> whether using commits directly as notes makes sense.\n\nIf that is the case, then my approach is indeed flawed. The main point\nof the exercise is to have a tree that follows another commit (or, as a\nnext-best approximation, a note attached to that commit) around.\n\n> In that case, you might be better off using an explicit\n> ref to keep that history alive; e.g. you could create\n> refs/history/e1bfac4 to point to 3d7de37 (\"git update-ref\n> refs/history/e1bfac4 3d7de37\"), and keep everything\n> alive/reachable/shareable that way...\n\nThat’s an interesting idea; instead of relying on the notes feature\nputting the hash in the ref name. But I wonder how that scales – imagine\nevery second feature merged into Linux¹ also having such a history ref? \n\nI guess having a way for a tree to reference commits in a way that is\nfollowed by git gc, i.e. separate from submodules, would allow a less\nnoisy implementation, and possibly create the opportunity for many other\nstrange uses of git :-)\n\nGreetings,\nJoachim\n\n¹ I’m not proposing for anyone else but me to use this, at the moment,\ndon’t worry :-). But I am considering to use it in the context of GHC,\nwhich isn’t a small project either.\n\n-- \nJoachim “nomeata” Breitner\n  mail@joachim-breitner.de • http://www.joachim-breitner.de/\n  Jabber: nomeata@joachim-breitner.de  • GPG-Key: 0x4743206C\n  Debian Developer: nomeata@debian.org\n"},{"id":"234646","messageId":"CALKQrgdnGhc-y3WMf+zej4M+O4NMhLKusE-N6dX_xKVViZmQzA@mail.gmail.com","threadId":"35845","inReplyTo":"xmqqvbwlnqi1.fsf@gitster.dls.corp.google.com","subject":"Re: git-note -C changes commit type?","fromName":"Johan Herland","fromEmail":"johan@herland.net","sentAt":"2014-02-12T09:50:50Z","receivedAt":"2014-02-12T09:50:50Z","isPatch":false,"sender":{"key":"johan@herland.net","avatar":"https://avatars.githubusercontent.com/u/547031?v=4"},"body":"On Wed, Feb 12, 2014 at 1:06 AM, Junio C Hamano <gitster@pobox.com> wrote:\n> Johan Herland <johan@herland.net> writes:\n>> There is currently no way the \"git notes\" commands will allow you to\n>> store the 3d7de37 commit object directly as a note. There is also\n>> (AFAICS) no easy workaround (git fast-import could've been a\n>> workaround if it did not already require the first N/notemodify\n>> argument to be a blob object). The best alternative, off the top of my\n>> head, would be to write your own program using the notes.h API to\n>> manipulate the notes tree directly (or - suboptimally - use other\n>> low-level Git operations to do the same).\n>\n> Even worse. I do not think such a non-blob object in the notes tree\n> does not participate in the reachability at all, so you won't be\n> able to fetch \"refs/notes/whatever\" and expect to get a useful\n> result.\n\ns/non-blob/non-(blob-or-tree)/\n\nAny object type that is deemed reachable by reference from a regular\ngit tree object will also be usable (as far as reachability goes) in a\nnotes tree.\n\n> I do not think storing the raw bits of commit object as a\n> blob in the notes tree is useful behaviour, either.  The command\n> probably should refuse to get anything non-blob via that option.\n\nPatch coming up...\n\n> Perhaps the notes entry should just note the object name of whatever\n> commit it wants to refer to in a *blob*?\n\nAgreed.\n\n...Johan\n\n-- \nJohan Herland, <johan@herland.net>\nwww.herland.net\n"},{"id":"234647","messageId":"1392198856-3908-1-git-send-email-johan@herland.net","threadId":"35845","inReplyTo":"CALKQrgdnGhc-y3WMf+zej4M+O4NMhLKusE-N6dX_xKVViZmQzA@mail.gmail.com","subject":"[PATCH] notes: Disallow reusing non-blob as a note object","fromName":"Johan Herland","fromEmail":"johan@herland.net","sentAt":"2014-02-12T09:54:16Z","receivedAt":"2014-02-12T09:54:16Z","isPatch":true,"sender":{"key":"johan@herland.net","avatar":"https://avatars.githubusercontent.com/u/547031?v=4"},"body":"Currently \"git notes add -C $object\" will read the raw bytes from $object,\nand then copy those bytes into the note object, which is hardcoded to be\nof type blob. This means that if the given $object is a non-blob (e.g.\ntree or commit), the raw bytes from that object is copied into a blob\nobject. This is probably not useful, and certainly not what any sane\nuser would expect. So disallow it, by erroring out if the $object passed\nto the -C option is not a blob.\n\nThe fix also applies to the -c option (in which the user is prompted to\nedit/verify the note contents in a text editor), and also when -c/-C is\npassed to \"git notes append\" (which appends the $object contents to an\nexisting note object). In both cases, passing a non-blob $object does not\nmake sense.\n\nAlso add a couple of tests demonstrating expected behavior.\n\nSuggested-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Johan Herland <johan@herland.net>\n---\n builtin/notes.c  |  6 +++++-\n t/t3301-notes.sh | 27 +++++++++++++++++++++++++++\n 2 files changed, 32 insertions(+), 1 deletion(-)\n\ndiff --git a/builtin/notes.c b/builtin/notes.c\nindex 2b24d05..bb89930 100644\n--- a/builtin/notes.c\n+++ b/builtin/notes.c\n@@ -269,7 +269,11 @@ static int parse_reuse_arg(const struct option *opt, const char *arg, int unset)\n \t\tdie(_(\"Failed to resolve '%s' as a valid ref.\"), arg);\n \tif (!(buf = read_sha1_file(object, &type, &len)) || !len) {\n \t\tfree(buf);\n-\t\tdie(_(\"Failed to read object '%s'.\"), arg);;\n+\t\tdie(_(\"Failed to read object '%s'.\"), arg);\n+\t}\n+\tif (type != OBJ_BLOB) {\n+\t\tfree(buf);\n+\t\tdie(_(\"Cannot read note data from non-blob object '%s'.\"), arg);\n \t}\n \tstrbuf_add(&(msg->buf), buf, len);\n \tfree(buf);\ndiff --git a/t/t3301-notes.sh b/t/t3301-notes.sh\nindex 16de05a..3bb79a4 100755\n--- a/t/t3301-notes.sh\n+++ b/t/t3301-notes.sh\n@@ -812,6 +812,33 @@ test_expect_success 'create note from non-existing note with \"git notes add -C\"\n \ttest_must_fail git notes list HEAD\n '\n \n+test_expect_success 'create note from non-blob with \"git notes add -C\" fails' '\n+\tcommit=$(git rev-parse --verify HEAD) &&\n+\ttree=$(git rev-parse --verify HEAD:) &&\n+\ttest_must_fail git notes add -C $commit &&\n+\ttest_must_fail git notes add -C $tree &&\n+\ttest_must_fail git notes list HEAD\n+'\n+\n+cat > expect << EOF\n+commit 80d796defacd5db327b7a4e50099663902fbdc5c\n+Author: A U Thor <author@example.com>\n+Date:   Thu Apr 7 15:20:13 2005 -0700\n+\n+    8th\n+\n+Notes (other):\n+    This is a blob object\n+EOF\n+\n+test_expect_success 'create note from blob with \"git notes add -C\" reuses blob id' '\n+\tblob=$(echo \"This is a blob object\" | git hash-object -w --stdin) &&\n+\tgit notes add -C $blob &&\n+\tgit log -1 > actual &&\n+\ttest_cmp expect actual &&\n+\ttest \"$(git notes list HEAD)\" = \"$blob\"\n+'\n+\n cat > expect << EOF\n commit 016e982bad97eacdbda0fcbd7ce5b0ba87c81f1b\n Author: A U Thor <author@example.com>\n-- \n1.8.4.653.g2df02b3\n"},{"id":"234648","messageId":"CALKQrgfRD2_Z4u3QoqoONv_Ydp-YAv66oXrPda=YDBX-Dn145w@mail.gmail.com","threadId":"35845","inReplyTo":"1392195218.2546.7.camel@kirk","subject":"Re: git-note -C changes commit type?","fromName":"Johan Herland","fromEmail":"johan@herland.net","sentAt":"2014-02-12T10:26:46Z","receivedAt":"2014-02-12T10:26:46Z","isPatch":false,"sender":{"key":"johan@herland.net","avatar":"https://avatars.githubusercontent.com/u/547031?v=4"},"body":"On Wed, Feb 12, 2014 at 9:53 AM, Joachim Breitner\n<mail@joachim-breitner.de> wrote:\n> Am Mittwoch, den 12.02.2014, 00:52 +0100 schrieb Johan Herland:\n>> You would have a notes ref \"refs/notes/history\" whose tree would\n>> contain an entry named e1bfac434ebd3135a3784f6fc802f235098eebd0\n>> pointing to a _commit_ (3d7de37...). Obviously, it would not make\n>> sense to use refs/notes/history while displaying the commit log (\"git\n>> log --notes=history\"), as the raw commit object would be shown in the\n>> log. However, more fundamentally: a tree referring to a _commit_ is\n>> usually how Git stores _submodule_ links (i.e. which revision of the\n>> named submodule is to be used by this super-repo tree), and I'm (off\n>> the top of my head) not at all sure that such a submodule link in a\n>> notes tree is handled \"sanely\" by Git - or even that it makes sense at\n>> all. For one, I'm not sure that Git requires (or even expects) the\n>> commit object referenced by a tree to be present in the same object\n>> DB. So if you share your notes, I don't know whether or not the\n>> fetch/push machinery will include the commit object in the shared\n>> notes... These are questions that should be answered before we decide\n>> whether using commits directly as notes makes sense.\n>\n> If that is the case, then my approach is indeed flawed. The main point\n> of the exercise is to have a tree that follows another commit (or, as a\n> next-best approximation, a note attached to that commit) around.\n>\n>> In that case, you might be better off using an explicit\n>> ref to keep that history alive; e.g. you could create\n>> refs/history/e1bfac4 to point to 3d7de37 (\"git update-ref\n>> refs/history/e1bfac4 3d7de37\"), and keep everything\n>> alive/reachable/shareable that way...\n>\n> That’s an interesting idea; instead of relying on the notes feature\n> putting the hash in the ref name. But I wonder how that scales – imagine\n> every second feature merged into Linux¹ also having such a history ref?\n\nAh, that will probably not scale very well.\n\n> I guess having a way for a tree to reference commits in a way that is\n> followed by git gc, i.e. separate from submodules, would allow a less\n> noisy implementation, and possibly create the opportunity for many other\n> strange uses of git :-)\n\nHere's another way to solve your problem, which should be fairly\ntransparent and performant:\n\nWhenever you want to reference \"history\" of a commit (I'm using quotes\nhere, because we're not talking about the \"regular\" git sense of\nhistory, i.e. the commit graph), you perform the following two steps:\n\n1. Append the \"historical\" commit SHA-1 (3d7de37 in your example) to a\nnote on the \"current\" commit (e1bfac4). E.g.:\n\n    git notes --ref history append -m 3d7de37... e1bfac4...\n\n2. Perform some automated merge into a \"history\"-tracking ref (e.g.\nrefs/history), to keep the \"historical\" commits reachable.\n\n(You can easily wrap both steps into a script to automate things.)\n\nStep #1 encodes the \"history\" of a commit in a note, but does not keep\nthe \"history\" reachable.\n\nStep #2 keeps all \"historical\" commits reachable by making them part\nof the history (in the git sense - without quotes) of a proper ref\n(refs/history). The actual result/outcome of the merge is not\ninteresting. It only exists to insert the \"historical\" commit\n(3d7de37) into the ancestry for refs/history. Since the actual merge\nitself is uninteresting, you should probably use a merge strategy that\nnever yields conflicts, e.g. \"-s ours\"\n\nYou can now share the \"history\" by pushing/fetching the two refs\nrefs/notes/history and refs/history.\n\n(In theory, you might even be able to combine the two refs, by\nperforming the merge directly into refs/notes/history, always taking\ncare to retain the notes tree contents as the result of the merge. In\nother words, after you do step #1 (append the note), you manually\nrewrite the just-created tip of refs/notes/history to include 3d7de37\nas a second parent. This keeps 3d7de37 reachable (and it will be\nshared when you share refs/notes/history), and it should not interfere\nwith the notes infrastructure, as they only look at the current state\nof the notes tree.)\n\n\nHope this helps,\n\n...Johan\n\n-- \nJohan Herland, <johan@herland.net>\nwww.herland.net\n"},{"id":"234649","messageId":"1392201187.2546.13.camel@kirk","threadId":"35845","inReplyTo":"CALKQrgfRD2_Z4u3QoqoONv_Ydp-YAv66oXrPda=YDBX-Dn145w@mail.gmail.com","subject":"Re: git-note -C changes commit type?","fromName":"Joachim Breitner","fromEmail":"mail@joachim-breitner.de","sentAt":"2014-02-12T10:33:07Z","receivedAt":"2014-02-12T10:33:07Z","isPatch":false,"sender":{"key":"mail@joachim-breitner.de","avatar":"https://gravatar.com/avatar/1e9dd229978aa44811b44fc08a445cd1950a092f74fe2f5539d881f1c1b46fbf?d=mp&s=160"},"body":"Dear Johan,\n\nthanks for the patch!\n\nAm Mittwoch, den 12.02.2014, 11:26 +0100 schrieb Johan Herland:\n> Here's another way to solve your problem, which should be fairly\n> transparent and performant:\n> \n> Whenever you want to reference \"history\" of a commit (I'm using quotes\n> here, because we're not talking about the \"regular\" git sense of\n> history, i.e. the commit graph), you perform the following two steps:\n> \n> 1. Append the \"historical\" commit SHA-1 (3d7de37 in your example) to a\n> note on the \"current\" commit (e1bfac4). E.g.:\n> \n>     git notes --ref history append -m 3d7de37... e1bfac4...\n> \n> 2. Perform some automated merge into a \"history\"-tracking ref (e.g.\n> refs/history), to keep the \"historical\" commits reachable.\n> \n> (You can easily wrap both steps into a script to automate things.)\n> \n> Step #1 encodes the \"history\" of a commit in a note, but does not keep\n> the \"history\" reachable.\n> \n> Step #2 keeps all \"historical\" commits reachable by making them part\n> of the history (in the git sense - without quotes) of a proper ref\n> (refs/history). The actual result/outcome of the merge is not\n> interesting. It only exists to insert the \"historical\" commit\n> (3d7de37) into the ancestry for refs/history. Since the actual merge\n> itself is uninteresting, you should probably use a merge strategy that\n> never yields conflicts, e.g. \"-s ours\"\n> \n> You can now share the \"history\" by pushing/fetching the two refs\n> refs/notes/history and refs/history.\n>\n> (In theory, you might even be able to combine the two refs, by\n> performing the merge directly into refs/notes/history, always taking\n> care to retain the notes tree contents as the result of the merge. In\n> other words, after you do step #1 (append the note), you manually\n> rewrite the just-created tip of refs/notes/history to include 3d7de37\n> as a second parent. This keeps 3d7de37 reachable (and it will be\n> shared when you share refs/notes/history), and it should not interfere\n> with the notes infrastructure, as they only look at the current state\n> of the notes tree.)\n\nThat is quite a good approximation. What it doesn’t do is dropping\nhistory (in the refs/history sense) of commits that disappear, but the\nsame problem exists with notes. Thanks!\n\n\nI guess there are no plans to make the commit object format itself\nextensible, are they? Extensible in the sense that I can add a custom\nfield to it (e.g. history:). Git would not have to know anything about\nthe field besides its type, i.e. that it contains refs that it has to\nfollow. Very much like \"parent:\", just without the semantics of it wrt.\n\"git log\" and the like.\n\n\nGreetings,\nJoachim\n-- \nJoachim “nomeata” Breitner\n  mail@joachim-breitner.de • http://www.joachim-breitner.de/\n  Jabber: nomeata@joachim-breitner.de  • GPG-Key: 0x4743206C\n  Debian Developer: nomeata@debian.org\n"},{"id":"234768","messageId":"CAPig+cSQ12Ga4kEnNrspzru2F3p0jWb2i=1GRX84k0am5AA6Bw@mail.gmail.com","threadId":"35845","inReplyTo":"1392198856-3908-1-git-send-email-johan@herland.net","subject":"Re: [PATCH] notes: Disallow reusing non-blob as a note object","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2014-02-14T15:19:22Z","receivedAt":"2014-02-14T15:19:22Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Wed, Feb 12, 2014 at 4:54 AM, Johan Herland <johan@herland.net> wrote:\n> Currently \"git notes add -C $object\" will read the raw bytes from $object,\n> and then copy those bytes into the note object, which is hardcoded to be\n> of type blob. This means that if the given $object is a non-blob (e.g.\n> tree or commit), the raw bytes from that object is copied into a blob\n> object. This is probably not useful, and certainly not what any sane\n> user would expect. So disallow it, by erroring out if the $object passed\n> to the -C option is not a blob.\n>\n> The fix also applies to the -c option (in which the user is prompted to\n> edit/verify the note contents in a text editor), and also when -c/-C is\n> passed to \"git notes append\" (which appends the $object contents to an\n> existing note object). In both cases, passing a non-blob $object does not\n> make sense.\n>\n> Also add a couple of tests demonstrating expected behavior.\n>\n> Suggested-by: Junio C Hamano <gitster@pobox.com>\n> Signed-off-by: Johan Herland <johan@herland.net>\n> ---\n>  builtin/notes.c  |  6 +++++-\n>  t/t3301-notes.sh | 27 +++++++++++++++++++++++++++\n>  2 files changed, 32 insertions(+), 1 deletion(-)\n>\n> diff --git a/builtin/notes.c b/builtin/notes.c\n> index 2b24d05..bb89930 100644\n> --- a/builtin/notes.c\n> +++ b/builtin/notes.c\n> @@ -269,7 +269,11 @@ static int parse_reuse_arg(const struct option *opt, const char *arg, int unset)\n>                 die(_(\"Failed to resolve '%s' as a valid ref.\"), arg);\n>         if (!(buf = read_sha1_file(object, &type, &len)) || !len) {\n>                 free(buf);\n> -               die(_(\"Failed to read object '%s'.\"), arg);;\n> +               die(_(\"Failed to read object '%s'.\"), arg);\n> +       }\n> +       if (type != OBJ_BLOB) {\n> +               free(buf);\n> +               die(_(\"Cannot read note data from non-blob object '%s'.\"), arg);\n\nThe way this diagnostic is worded, it sound as if the 'read' failed\nrather than that the user specified an incorrect object type. Perhaps\n\"Object is not a blob '%s'\" or \"Expected blob but '%s' has type '%s'\"\nor something along those lines?\n\n>         }\n>         strbuf_add(&(msg->buf), buf, len);\n>         free(buf);\n"},{"id":"234773","messageId":"xmqq7g8xk6ov.fsf@gitster.dls.corp.google.com","threadId":"35845","inReplyTo":"CAPig+cSQ12Ga4kEnNrspzru2F3p0jWb2i=1GRX84k0am5AA6Bw@mail.gmail.com","subject":"Re: [PATCH] notes: Disallow reusing non-blob as a note object","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2014-02-14T16:19:44Z","receivedAt":"2014-02-14T16:19:44Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Eric Sunshine <sunshine@sunshineco.com> writes:\n\n>> +       if (type != OBJ_BLOB) {\n>> +               free(buf);\n>> +               die(_(\"Cannot read note data from non-blob object '%s'.\"), arg);\n>\n> The way this diagnostic is worded, it sound as if the 'read' failed\n> rather than that the user specified an incorrect object type. Perhaps\n> \"Object is not a blob '%s'\" or \"Expected blob but '%s' has type '%s'\"\n> or something along those lines?\n\nYeah, sounds good.  You also need to say what expects a blob, too.\nPerhaps something like this?\n\n builtin/notes.c | 4 +++-\n 1 file changed, 3 insertions(+), 1 deletion(-)\n\ndiff --git a/builtin/notes.c b/builtin/notes.c\nindex c11d6e6..a16bc00 100644\n--- a/builtin/notes.c\n+++ b/builtin/notes.c\n@@ -272,8 +272,10 @@ static int parse_reuse_arg(const struct option *opt, const char *arg, int unset)\n \t\tdie(_(\"Failed to read object '%s'.\"), arg);\n \t}\n \tif (type != OBJ_BLOB) {\n+\t\tstruct msg_arg *msg = opt->value;\n \t\tfree(buf);\n-\t\tdie(_(\"Cannot read note data from non-blob object '%s'.\"), arg);\n+\t\tdie(_(\"The -%c option takes a blob, which '%s' is not.\",\n+\t\t      msg->use_editor ? 'c' : 'C', arg));\n \t}\n \tstrbuf_add(&(msg->buf), buf, len);\n \tfree(buf);\n"}]}