From: Stefan Naewe <hidden> Date: 2016-06-15 22:49:25
Hi,
I was playing around with 'git notes' these days (after reading S.Chacons
post to this list and hist blog post at progit.org).
Some things came to my mind when doing some 'git notes add' and
'git notes remove':
How do I really get rid of git notes ? 'git notes remove' doesn't really
remove the notes but creates a new commit (like 'git rm file ; git commit..' does).
And why does 'git remove' do that repetetively (is that even a word...?), i.e.
'git add -m"Note" ; git remove; git remove; git remove; git remove' creates 5
commit objects under 'refs/notes/commits' Is that the intended behaviour ?
I'm a little bit puzzled....
Regards,
Stefan
--
----------------------------------------------------------------
/dev/random says: It's not the principle of the thing, it's the money
From: Johan Herland <hidden> Date: 2016-06-15 22:49:25
On Tuesday 31 August 2010, Stefan Naewe wrote:
Hi,
I was playing around with 'git notes' these days (after reading S.Chacons
post to this list and hist blog post at progit.org).
Some things came to my mind when doing some 'git notes add' and
'git notes remove':
How do I really get rid of git notes ? 'git notes remove' doesn't really
remove the notes but creates a new commit (like 'git rm file ; git
commit..' does).
Well, how do you "really" get rid of a file on a "regular" Git branch? The
answer is that Git doesn't let you do this without rewriting history (e.g.
using 'git filter-branch' to create a new history where that file never
existed). The same argument goes for notes: If you want to remove all traces
of notes for a given object, you must rewrite the notes history so that
those notes never existed.
At least that's how the 'git notes' porcelain behaves. At the plumbing
level, it's possible to create notes commits that don't point to the
preceding notes history (every notes commit is a root commit), and thus end
up with "history-less" notes. An example of this is the notes-cache code.
And why does 'git remove' do that repetetively (is that even a word...?),
i.e. 'git add -m"Note" ; git remove; git remove; git remove; git remove'
creates 5 commit objects under 'refs/notes/commits' Is that the intended
behaviour ?
(I assume your meant to put "notes" in all those commands: git notes add,
git notes remove, etc.)
Yes, this is the intended behaviour. Otherwise you would need a separate
notes index where you could stage notes changes (with git notes add/remove),
and then later commit those notes changes with (the imaginary) git notes
commit. This was deemed too cumbersome/complicated, and we settled for the
current approach instead.
If you want to make several adds/removes per notes commit, you could:
1. Use git-fast-import and its 'N' command (search the manual page for
"notemodify").
2. Check out the notes ref into your working tree ("git checkout
refs/notes/commits"). You can now edit notes directly, like you would edit
your "regular" files. (Ideally, you should have some knowledge about the
format of notes trees before you add/rename files). When you're done, you
stage and commit as you would do in your regular checkout.
I'm a little bit puzzled....
Hope this helps, :)
...Johan
--
Johan Herland, [off-list ref]
www.herland.net
From: Stefan Naewe <hidden> Date: 2016-06-15 22:49:25
On 8/31/2010 11:07 AM, Johan Herland wrote:
On Tuesday 31 August 2010, Stefan Naewe wrote:
quoted
Hi,
I was playing around with 'git notes' these days (after reading S.Chacons
post to this list and hist blog post at progit.org).
Some things came to my mind when doing some 'git notes add' and
'git notes remove':
How do I really get rid of git notes ? 'git notes remove' doesn't really
remove the notes but creates a new commit (like 'git rm file ; git
commit..' does).
Well, how do you "really" get rid of a file on a "regular" Git branch? The
answer is that Git doesn't let you do this without rewriting history (e.g.
using 'git filter-branch' to create a new history where that file never
existed). The same argument goes for notes: If you want to remove all traces
of notes for a given object, you must rewrite the notes history so that
those notes never existed.
OK. Understood.
At least that's how the 'git notes' porcelain behaves. At the plumbing
level, it's possible to create notes commits that don't point to the
preceding notes history (every notes commit is a root commit), and thus end
up with "history-less" notes. An example of this is the notes-cache code.
quoted
And why does 'git remove' do that repetetively (is that even a word...?),
i.e. 'git add -m"Note" ; git remove; git remove; git remove; git remove'
creates 5 commit objects under 'refs/notes/commits' Is that the intended
behaviour ?
(I assume your meant to put "notes" in all those commands: git notes add,
git notes remove, etc.)
Yes, sorry.
Yes, this is the intended behaviour. Otherwise you would need a separate
notes index where you could stage notes changes (with git notes add/remove),
and then later commit those notes changes with (the imaginary) git notes
commit. This was deemed too cumbersome/complicated, and we settled for the
current approach instead.
But if I do:
$ touch file ; git add file ; git commit -m"add file"
and then
$ for n in 1 2 3; do git rm file; git commit -m"rm file"; done
I get:
rm 'file'
[master 5b24511] rm file
0 files changed, 0 insertions(+), 0 deletions(-)
delete mode 100644 file
fatal: pathspec 'file' did not match any files
# On branch master
nothing to commit (working directory clean)
fatal: pathspec 'file' did not match any files
# On branch master
nothing to commit (working directory clean)
I don't get 4 commits. That's the part I don't understand :-(
If you want to make several adds/removes per notes commit, you could:
1. Use git-fast-import and its 'N' command (search the manual page for
"notemodify").
OK. Thanks. Didn't know that.
2. Check out the notes ref into your working tree ("git checkout
refs/notes/commits"). You can now edit notes directly, like you would edit
your "regular" files. (Ideally, you should have some knowledge about the
format of notes trees before you add/rename files). When you're done, you
stage and commit as you would do in your regular checkout.
OK. I already tried that.
And to delete the 'notes branch' I can only use 'git update-ref' ?!
Thanks for your answer
Stefan
--
----------------------------------------------------------------
/dev/random says: Nostalgia isn't what it used to be.
From: Stefan Naewe <hidden> Date: 2016-06-15 22:49:25
On 8/31/2010 12:13 PM, Stefan Naewe wrote:
But if I do:
$ touch file ; git add file ; git commit -m"add file"
and then
$ for n in 1 2 3; do git rm file; git commit -m"rm file"; done
I get:
rm 'file'
[master 5b24511] rm file
0 files changed, 0 insertions(+), 0 deletions(-)
delete mode 100644 file
fatal: pathspec 'file' did not match any files
# On branch master
nothing to commit (working directory clean)
fatal: pathspec 'file' did not match any files
# On branch master
nothing to commit (working directory clean)
I don't get 4 commits. That's the part I don't understand :-(
Just to be clear:
Of course I do understand why I don't get 4 commits here - I just don't
understand why I get a commit for every 'git notes remove' even if there's
nothing to remove.
Stefan
--
----------------------------------------------------------------
/dev/random says: This tagl ineh asto oman yfou rlet terw ords.
From: Michael J Gruber <hidden> Date: 2016-06-15 22:49:25
Currently, "git notes" behaves like "git commit --allow-empty" when
committing notes trees. In particular, removing nonexisting notes leads
to empty commits "commits with no diff".
Change this to avoid unnecessary notes commits.
Signed-off-by: Michael J Gruber <redacted>
---
I can't believe there's no easier way to lookup the sha1 of a tree of a commit
but I didn't find any, and I did not want to employ the diff machinery for diffing
the trees when their sha1 is (should be) known.
builtin/notes.c | 14 +++++++++-----
1 files changed, 9 insertions(+), 5 deletions(-)
@@ -303,11 +303,15 @@ int commit_notes(struct notes_tree *t, const char *msg)hashclr(prev_commit);parent=NULL;}-if(commit_tree(buf.buf+7,tree_sha1,parent,new_commit,NULL))-die("Failed to commit notes tree to database");--/* Update notes ref with new commit */-update_ref(buf.buf,t->ref,new_commit,prev_commit,0,DIE_ON_ERR);+if(!parent||parse_commit(parent->item)||parse_tree(parent->item->tree)||+hashcmp(parent->item->tree->object.sha1,tree_sha1)){+/* avoid recommitting the same tree */+if(commit_tree(buf.buf+7,tree_sha1,parent,new_commit,NULL))+die("Failed to commit notes tree to database");++/* Update notes ref with new commit */+update_ref(buf.buf,t->ref,new_commit,prev_commit,0,DIE_ON_ERR);+}strbuf_release(&buf);return0;
From: Johan Herland <hidden> Date: 2016-06-15 22:49:25
On Tuesday 31 August 2010, Stefan Naewe wrote:
On 8/31/2010 11:07 AM, Johan Herland wrote:
quoted
On Tuesday 31 August 2010, Stefan Naewe wrote:
quoted
And why does 'git remove' do that repetetively (is that even a
word...?), i.e. 'git add -m"Note" ; git remove; git remove; git
remove; git remove' creates 5 commit objects under
'refs/notes/commits' Is that the intended behaviour ?
Yes, this is the intended behaviour. Otherwise you would need a
separate notes index where you could stage notes changes (with git
notes add/remove), and then later commit those notes changes with
(the imaginary) git notes commit. This was deemed too
cumbersome/complicated, and we settled for the current approach
instead.
But if I do:
$ touch file ; git add file ; git commit -m"add file"
and then
$ for n in 1 2 3; do git rm file; git commit -m"rm file"; done
I get:
rm 'file'
[master 5b24511] rm file
0 files changed, 0 insertions(+), 0 deletions(-)
delete mode 100644 file
fatal: pathspec 'file' did not match any files
# On branch master
nothing to commit (working directory clean)
fatal: pathspec 'file' did not match any files
# On branch master
nothing to commit (working directory clean)
I don't get 4 commits. That's the part I don't understand :-(
Just to be clear:
Of course I do understand why I don't get 4 commits here - I just
don't understand why I get a commit for every 'git notes remove' even
if there's nothing to remove.
Ah, that would be a bug in 'git notes remove'. Patch coming soon.
And to delete the 'notes branch' I can only use 'git update-ref' ?!
Yes, 'git update-ref -d refs/notes/foo' will delete the "foo" notes
branch.
...Johan
--
Johan Herland, [off-list ref]
www.herland.net
From: Johan Herland <hidden> Date: 2016-06-15 22:49:25
Extend remove_note() in the notes API to return whether or not a note was
actually removed. Use this in 'git notes remove' to skip the creation of
a notes commit when no notes were actually removed.
Also add a test illustrating the change in behavior.
Signed-off-by: Johan Herland <redacted>
---
This patch is against master.
builtin/notes.c | 14 ++++++++++----
notes.c | 14 ++++++++++----
notes.h | 4 +++-
t/t3301-notes.sh | 7 +++++++
4 files changed, 30 insertions(+), 9 deletions(-)
@@ -263,11 +263,13 @@ static int note_tree_consolidate(struct int_node *tree,*Toremovealeaf_node:*Searchtothetreelocationappropriateforthegivenleaf_node'skey:*-Iflocationdoesnotholdamatchingentry,abortanddonothing.+*-Copythematchingentry'svalueintothegivenentry.*-Replacethematchingleaf_nodewithaNULLentry(andfreetheleaf_node).*-Consolidateint_nodesrepeatedly,whilewalkingupthetreetowardsroot.*/-staticvoidnote_tree_remove(structnotes_tree*t,structint_node*tree,-unsignedcharn,structleaf_node*entry)+staticvoidnote_tree_remove(structnotes_tree*t,+structint_node*tree,unsignedcharn,+structleaf_node*entry){structleaf_node*l;structint_node*parent_stack[20];
@@ -282,6 +284,7 @@ static void note_tree_remove(struct notes_tree *t, struct int_node *tree,return;/* key mismatch, nothing to remove *//* we have found a matching entry */+hashcpy(entry->val_sha1,l->val_sha1);free(l);*p=SET_PTR_TYPE(NULL,PTR_TYPE_NULL);
@@ -1003,17 +1006,20 @@ void add_note(struct notes_tree *t, const unsigned char *object_sha1,note_tree_insert(t,t->root,0,l,PTR_TYPE_NOTE,combine_notes);}-voidremove_note(structnotes_tree*t,constunsignedchar*object_sha1)+intremove_note(structnotes_tree*t,constunsignedchar*object_sha1){structleaf_nodel;if(!t)t=&default_notes_tree;assert(t->initialized);-t->dirty=1;hashcpy(l.key_sha1,object_sha1);hashclr(l.val_sha1);note_tree_remove(t,t->root,0,&l);+if(is_null_sha1(l.val_sha1))// no note was removed+return1;+t->dirty=1;+return0;}constunsignedchar*get_note(structnotes_tree*t,
From: Johan Herland <hidden> Date: 2016-06-15 22:49:25
It might be useful to identify which note was removed by a call to
remove_note(). Add an optional parameter to remove_note() for recording
the SHA1 of the removed note object. If no note is removed by remove_note(),
null_sha1 is stored in this parameter.
Signed-off-by: Johan Herland <redacted>
---
This patch is very much optional. It adds a small API extension that
_might_ be useful in the future.
builtin/notes.c | 6 +++---
notes.c | 7 +++++--
notes.h | 6 +++++-
3 files changed, 13 insertions(+), 6 deletions(-)
From: Jeff King <hidden> Date: 2016-06-15 22:49:25
On Tue, Aug 31, 2010 at 05:16:17PM +0200, Michael J Gruber wrote:
Currently, "git notes" behaves like "git commit --allow-empty" when
committing notes trees. In particular, removing nonexisting notes leads
to empty commits "commits with no diff".
Change this to avoid unnecessary notes commits.
Is this a sufficient check in the case of notes? Is it possible that we
re-balanced the fanout of the notes tree and got a different tree sha1,
even though there is nothing interesting to commit?
From: Johan Herland <hidden> Date: 2016-06-15 22:49:25
On Tuesday 31 August 2010, Michael J Gruber wrote:
Currently, "git notes" behaves like "git commit --allow-empty" when
committing notes trees. In particular, removing nonexisting notes
leads to empty commits "commits with no diff".
Change this to avoid unnecessary notes commits.
Signed-off-by: Michael J Gruber <redacted>
I just posted a patch with the same objective, but with a different
approach. Instead of parsing the previous commit and comparing tree
object SHA1s, I add a few lines of notes code to let remove_note()
report whether it removed a note or not (thus determining whether a
commit is necessary or not).
In general, the notes_tree.dirty flag should be sufficient to determine
whether a commit is needed or not (remove_note()'s unconditional
setting of this flag is also fixed in my patch).
...Johan
quoted hunk
---
I can't believe there's no easier way to lookup the sha1 of a tree of
a commit but I didn't find any, and I did not want to employ the diff
machinery for diffing the trees when their sha1 is (should be) known.
builtin/notes.c | 14 +++++++++-----
1 files changed, 9 insertions(+), 5 deletions(-)
From: Michael J Gruber <hidden> Date: 2016-06-15 22:49:25
Jeff King venit, vidit, dixit 31.08.2010 18:01:
On Tue, Aug 31, 2010 at 05:16:17PM +0200, Michael J Gruber wrote:
quoted
Currently, "git notes" behaves like "git commit --allow-empty" when
committing notes trees. In particular, removing nonexisting notes leads
to empty commits "commits with no diff".
Change this to avoid unnecessary notes commits.
Is this a sufficient check in the case of notes? Is it possible that we
re-balanced the fanout of the notes tree and got a different tree sha1,
even though there is nothing interesting to commit?
Yes, but I don't think this hurts. The main thrust here is to catch the
case of repeated "git notes remove". Also, we might even want to record
the history when there is rebalancing since this is indeed a tree change.
Johan's (later ;) ) approach, while being more intrusive, catches this
at the point of removal - if there's nothing to remove, nothing gets
rewritten.
I didn't check, but I can imagine you can drop the parse_tree here. We
should know the object sha1 once the commit is parsed.
parse_commit() does a lookup_tree() but I don't think that it parses the
tree, i.e. I don't hink it fills in tree->object.sha1. At least it
segfaulted without that ;)
Michael