describe a blob
v4 cover describe a blob
* omitted the check for options, none of them made sense.
* use of --reverse
* an additional test asked for by Jonathan
previous discussion
https://public-inbox.org/git/[email protected]/
interdiff to current queued patches below.
Thanks,
Stefan
Stefan Beller (7):
t6120: fix typo in test name
list-objects.c: factor out traverse_trees_and_blobs revision.h: introduce blob/tree walking in order of the commits builtin/describe.c: rename oid to avoid variable shadowing builtin/describe.c: print debug statements earlier builtin/describe.c: factor out describe_commit builtin/describe.c: describe a blob
Documentation/git-describe.txt | 13 +++- Documentation/rev-list-options.txt | 5 ++ builtin/describe.c | 126 ++++++++++++++++++++++++++++--------- list-objects.c | 52 +++++++++------ revision.c | 2 + revision.h | 3 +- t/t6100-rev-list-in-order.sh | 77 +++++++++++++++++++++++ t/t6120-describe.sh | 21 ++++++- 8 files changed, 249 insertions(+), 50 deletions(-) create mode 100755 t/t6100-rev-list-in-order.sh
Signature · 1 line
2.15.0.128.gcadd42da22
builtin/describe.c +3 -6
@@ -473,6 +473,7 @@ static void describe_blob(struct object_id oid, struct strbuf *dst)"--single-worktree" ,"--objects" ,"--in-commit-order" , +"--reverse" , NULL);init_revisions (&revs,NULL );
@@ -501,13 +502,9 @@ static void describe(const char *arg, int last_one)if (cmit)describe_commit (&oid, &sb); -else if (lookup_blob (&oid)) { -if (all || tags || longformat || first_parent || - patterns.nr || exclude_patterns.nr || - always || dirty || broken) -die (_ ("options not available for describing blobs" )); +else if (lookup_blob (&oid))describe_blob (oid, &sb); - }else +else die (_ ("%s is neither a commit nor blob" ), arg);puts (sb.buf);
t/t6100-rev-list-in-order.sh +32 -2
@@ -4,7 +4,7 @@ test_description='rev-list testing in-commit-order' . ./test-lib.sh -test_expect_success 'rev-list --in-commit-order' ' +test_expect_success 'setup a commit history with trees, blobs' ' for x in one two three four do echo $x >$x &&
@@ -17,7 +17,10 @@ test_expect_success 'rev-list --in-commit-order' ' git rm $x && git commit -m "remove $x" || return 1 - done && + done +' + +test_expect_success 'rev-list --in-commit-order' ' git rev-list --in-commit-order --objects HEAD >actual.raw && cut -c 1-40 >actual <actual.raw &&
@@ -44,4 +47,31 @@ test_expect_success 'rev-list --in-commit-order' ' test_cmp expect actual ' +test_expect_success 'rev-list lists blobs and trees after commits' ' + git rev-list --objects HEAD >actual.raw && + cut -c 1-40 >actual <actual.raw && + + git cat-file --batch-check="%(objectname)" >expect.raw <<-\EOF && + HEAD^{commit} + HEAD~1^{commit} + HEAD~2^{commit} + HEAD~3^{commit} + HEAD~4^{commit} + HEAD~5^{commit} + HEAD^{tree} + HEAD^{tree}:one + HEAD^{tree}:two + HEAD~1^{tree} + HEAD~1^{tree}:three + HEAD~2^{tree} + HEAD~2^{tree}:four + # HEAD~3^{tree} skipped, same as HEAD~1^{tree} + # HEAD~4^{tree} skipped, same as HEAD^{tree} + HEAD~5^{tree} + EOF + grep -v "#" >expect <expect.raw && + + test_cmp expect actual +' + test_done
t/t6120-describe.sh +6 -2
@@ -319,10 +319,14 @@ test_expect_success 'describe a blob at a tag' ' test_cmp expect actual ' -test_expect_success 'describe a blob with commit-ish' ' +test_expect_success 'describe a blob with its last introduction' ' + git commit --allow-empty -m "empty commit" && + git rm file && + git commit -m "delete blob" && + git revert HEAD && git commit --allow-empty -m "empty commit" && git describe HEAD:file >actual && - grep unique-file-1-g actual + grep unique-file-3-g actual ' test_expect_failure ULIMIT_STACK_SIZE 'name-rev works in a deep repo' '
PATCH v4 1/7 t6120: fix typo in test name
--- t/t6120-describe.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
t/t6120-describe.sh +1 -1
@@ -304,7 +304,7 @@ test_expect_success 'describe chokes on severely broken submodules' ' mv .git/modules/sub1/ .git/modules/sub_moved && test_must_fail git describe --dirty ' -test_expect_success 'describe ignoring a borken submodule' ' +test_expect_success 'describe ignoring a broken submodule' ' git describe --broken >out && test_when_finished "mv .git/modules/sub_moved .git/modules/sub1" && grep broken out
Signature · 1 line
2.15.0.128.gcadd42da22
PATCH v4 2/7 list-objects.c: factor out traverse_trees_and_blobs
In reply to Stefan BellerWith traverse_trees_and_blobs factored out of the main traverse function, the next patch can introduce an in-order revision walking with ease.
In the next patch we'll call traverse_trees_and_blobs from within the loop walking the commits, such that we'll have one invocation of that function per commit. That is why we do not want to have memory allocations in that function, such as we'd have if we were to use a strbuf locally. Pass a strbuf from traverse_commit_list into the blob and tree traversing function as a scratch pad that only needs to be allocated once.
--- list-objects.c | 50 +++++++++++++++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 19 deletions(-)
list-objects.c +31 -19
@@ -183,25 +183,15 @@ static void add_pending_tree(struct rev_info *revs, struct tree *tree)add_pending_object (revs, &tree->object,"" ); } -void traverse_commit_list (struct rev_info *revs, -show_commit_fn show_commit, -show_object_fn show_object, -void *data) +static void traverse_trees_and_blobs (struct rev_info *revs, +struct strbuf *base, +show_object_fn show_object, +void *data) {int i; -struct commit *commit; -struct strbuf base; -strbuf_init (&base,PATH_MAX ); -while ((commit =get_revision (revs)) !=NULL ) { -/* -* an uninteresting boundary commit may not have its tree -* parsed yet, but we are not going to show them anyway -*/ -if (commit->tree) -add_pending_tree (revs, commit->tree); -show_commit (commit, data); - } +assert (base->len ==0 ); +for (i =0 ; i < revs->pending.nr; i++) {struct object_array_entry *pending = revs->pending.objects + i;struct object *obj = pending->item;
@@ -218,17 +208,39 @@ void traverse_commit_list(struct rev_info *revs, path ="" ;if (obj->type ==OBJ_TREE ) {process_tree (revs, (struct tree *)obj, show_object, - &base, path, data); + base, path, data);continue ; }if (obj->type ==OBJ_BLOB ) {process_blob (revs, (struct blob *)obj, show_object, - &base, path, data); + base, path, data);continue ; }die ("unknown pending object %s (%s)" ,oid_to_hex (&obj->oid), name); }object_array_clear (&revs->pending); -strbuf_release (&base); +} + +void traverse_commit_list (struct rev_info *revs, +show_commit_fn show_commit, +show_object_fn show_object, +void *data) +{ +struct commit *commit; +struct strbuf csp;/* callee's scratch pad */ +strbuf_init (&csp,PATH_MAX ); + +while ((commit =get_revision (revs)) !=NULL ) { +/* +* an uninteresting boundary commit may not have its tree +* parsed yet, but we are not going to show them anyway +*/ +if (commit->tree) +add_pending_tree (revs, commit->tree); +show_commit (commit, data); + } +traverse_trees_and_blobs (revs, &csp, show_object, data); + +strbuf_release (&csp); }
Signature · 1 line
2.15.0.128.gcadd42da22
PATCH v4 3/7 revision.h: introduce blob/tree walking in order of the commits
In reply to Stefan BellerThe functionality to list tree objects in the order they were seen while traversing the commits will be used in one of the next commits, where we teach git describe to describe not only commits, but blobs, too.
The change in list-objects.c is rather minimal as we'll be re-using the infrastructure put in place of the revision walking machinery. For example one could expect that add_pending_tree is not called, but rather commit->tree is directly passed to the tree traversal function. This however requires a lot more code than just emptying the queue containing trees after each commit.
--- Documentation/rev-list-options.txt | 5 +++ list-objects.c | 2 + revision.c | 2 + revision.h | 3 +- t/t6100-rev-list-in-order.sh | 77 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 88 insertions(+), 1 deletion(-) create mode 100755 t/t6100-rev-list-in-order.sh
Documentation/rev-list-options.txt +5 -0
@@ -686,6 +686,11 @@ ifdef::git-rev-list[] all object IDs which I need to download if I have the commit object _bar_ but not _foo_''. +--in-commit-order:: + Print tree and blob ids in order of the commits. The tree + and blob ids are printed after they are first referenced + by a commit. + --objects-edge:: Similar to `--objects`, but also print the IDs of excluded commits prefixed with a ``-'' character. This is used by
list-objects.c +2 -0
@@ -239,6 +239,8 @@ void traverse_commit_list(struct rev_info *revs,if (commit->tree)add_pending_tree (revs, commit->tree);show_commit (commit, data); +if (revs->tree_blobs_in_commit_order) +traverse_trees_and_blobs (revs, &csp, show_object, data); }traverse_trees_and_blobs (revs, &csp, show_object, data);
revision.c +2 -0
@@ -1845,6 +1845,8 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg revs->dense =0 ; }else if (!strcmp (arg,"--show-all" )) { revs->show_all =1 ; + }else if (!strcmp (arg,"--in-commit-order" )) { + revs->tree_blobs_in_commit_order =1 ; }else if (!strcmp (arg,"--remove-empty" )) { revs->remove_empty_trees =1 ; }else if (!strcmp (arg,"--merges" )) {
revision.h +2 -1
@@ -121,7 +121,8 @@ struct rev_info { bisect:1, ancestry_path:1, first_parent_only:1, - line_level_traverse:1; + line_level_traverse:1, + tree_blobs_in_commit_order:1;/* Diff flags */ unsigned int diff:1,
t/t6100-rev-list-in-order.sh new file +77 -0
77 lines not on this page · raw message
Signature · 1 line
2.15.0.128.gcadd42da22
Re: [PATCHv4 3/7] revision.h: introduce blob/tree walking in order of the commits
Quoted 6 lines · On Tue, 14 Nov 2017 16:30:39 -0800 Stefan Beller <[email protected]> wrote:
The change in
list-objects.cis rather minimal as we'll be re-using the infrastructure put in place of the revision walking machinery. For example one could expect thatadd_pending_treeis not called, but rathercommit->treeis directly passed to the tree traversal function. This however requires a lot more code than just emptying the queue containing trees after each commit.
Ah, I see. You're calling add_pending_tree(), then traverse_trees_and_blobs() will immediately flush the list of pending trees.
I'm not sure that passing commit->tree directly to the tree traversal function will require a lot more code, but even if it does, you should at least add a NEEDSWORK - currently, flushing the list of pending trees frees the array containing the list of pending trees, so each invocation will need to reallocate a new array.
PATCH v4 4/7 builtin/describe.c: rename `oid` to avoid variable shadowing
In reply to Stefan BellerThe function describe has already a variable named oid declared at the beginning of the function for an object id. Do not shadow that variable with a pointer to an object id.
--- builtin/describe.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
builtin/describe.c +4 -4
@@ -381,9 +381,9 @@ static void describe(const char *arg, int last_one) }if (!match_cnt) { -struct object_id *oid = &cmit->object.oid; +struct object_id *cmit_oid = &cmit->object.oid;if (always) { -printf ("%s" ,find_unique_abbrev (oid->hash, abbrev)); +printf ("%s" ,find_unique_abbrev (cmit_oid->hash, abbrev));if (suffix)printf ("%s" , suffix);printf ("\n" );
@@ -392,11 +392,11 @@ static void describe(const char *arg, int last_one)if (unannotated_cnt)die (_ ("No annotated tags can describe '%s'.\n" "However, there were unannotated tags: try --tags." ), -oid_to_hex (oid)); +oid_to_hex (cmit_oid));else die (_ ("No tags can describe '%s'.\n" "Try --always, or create some tags." ), -oid_to_hex (oid)); +oid_to_hex (cmit_oid)); }QSORT (all_matches, match_cnt, compare_pt);
Signature · 1 line
2.15.0.128.gcadd42da22
PATCH v4 5/7 builtin/describe.c: print debug statements earlier
In reply to Stefan BellerFor debuggers aid we'd want to print debug statements early, so introduce a new line in the debug output that describes the whole function, and then change the next debug output to describe why we need to search. Conveniently drop the arg from the second line; which will be useful in a follow up commit, that refactors the describe function.
This re-arrangement of debug printing is solely done for a better refactoring in the next commit, not to aid debugging git-describe, which is expected to have the same information readily available with the new prints.
--- builtin/describe.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
builtin/describe.c +4 -1
@@ -293,6 +293,9 @@ static void describe(const char *arg, int last_one)unsigned long seen_commits =0 ;unsigned int unannotated_cnt =0 ; +if (debug) +fprintf (stderr,_ ("describe %s\n" ), arg); +if (get_oid (arg, &oid))die (_ ("Not a valid object name %s" ), arg); cmit =lookup_commit_reference (&oid);
@@ -316,7 +319,7 @@ static void describe(const char *arg, int last_one)if (!max_candidates)die (_ ("no tag exactly matches '%s'" ),oid_to_hex (&cmit->object.oid));if (debug) -fprintf (stderr,_ ("searching to describe %s\n" ), arg); +fprintf (stderr,_ ("No exact match on refs or tags, searching to describe\n" ));if (!have_util) {struct hashmap_iter iter;
Signature · 1 line
2.15.0.128.gcadd42da22
Re: [PATCHv4 5/7] builtin/describe.c: print debug statements earlier
Quoted 11 lines · On Tue, 14 Nov 2017 16:30:41 -0800 Stefan Beller <[email protected]> wrote:
For debuggers aid we'd want to print debug statements early, so introduce a new line in the debug output that describes the whole function, and then change the next debug output to describe why we need to search. Conveniently drop the arg from the second line; which will be useful in a follow up commit, that refactors the describe function.
This re-arrangement of debug printing is solely done for a better refactoring in the next commit, not to aid debugging git-describe, which is expected to have the same information readily available with the new prints.
This paragraph ("not to aid debugging") contradicts the previous one ("For debuggers aid").
Looking at this patch and the subsequent patches, I would write the commit message like this:
When debugging, print the received argument at the start of the function instead of in the middle. This ensures that the received argument is printed in all code paths, and also allows a subsequent refactoring to not need to move the "arg" parameter.
Also change the title to "print arg earlier when debugging" or something like that.
PATCH v4 6/7 builtin/describe.c: factor out describe_commit
In reply to Stefan BellerIn the next patch we'll learn how to describe more than just commits, so factor out describing commits into its own function. That will make the next patches easy as we still need to describe a commit as part of describing blobs.
While factoring out the functionality to describe_commit, make sure that any output to stdout is put into a strbuf, which we can print afterwards, using puts which also adds the line ending.
--- builtin/describe.c | 63 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 37 insertions(+), 26 deletions(-)
builtin/describe.c +37 -26
@@ -256,7 +256,7 @@ static unsigned long finish_depth_computation(return seen_commits; } -static void display_name (struct commit_name *n) +static void append_name (struct commit_name *n,struct strbuf *dst) {if (n->prio ==2 && !n->tag) { n->tag =lookup_tag (&n->oid);
@@ -272,19 +272,18 @@ static void display_name(struct commit_name *n) }if (n->tag) -printf ("%s" , n->tag->tag); +strbuf_addstr (dst, n->tag->tag);else -printf ("%s" , n->path); +strbuf_addstr (dst, n->path); } -static void show_suffix (int depth,const struct object_id *oid) +static void append_suffix (int depth,const struct object_id *oid,struct strbuf *dst) { -printf ("-%d-g%s" , depth,find_unique_abbrev (oid->hash, abbrev)); +strbuf_addf (dst,"-%d-g%s" , depth,find_unique_abbrev (oid->hash, abbrev)); } -static void describe (const char *arg,int last_one) +static void describe_commit (struct object_id *oid,struct strbuf *dst) { -struct object_id oid;struct commit *cmit, *gave_up_on =NULL ;struct commit_list *list;struct commit_name *n;
@@ -293,26 +292,18 @@ static void describe(const char *arg, int last_one)unsigned long seen_commits =0 ;unsigned int unannotated_cnt =0 ; -if (debug) -fprintf (stderr,_ ("describe %s\n" ), arg); - -if (get_oid (arg, &oid)) -die (_ ("Not a valid object name %s" ), arg); - cmit =lookup_commit_reference (&oid); -if (!cmit) -die (_ ("%s is not a valid '%s' object" ), arg, commit_type); + cmit =lookup_commit_reference (oid); n =find_commit_name (&cmit->object.oid);if (n && (tags || all || n->prio ==2 )) {/* * Exact match to an existing ref. */ -display_name (n); +append_name (n, dst);if (longformat) -show_suffix (0 , n->tag ? &n->tag->tagged->oid : &oid); +append_suffix (0 , n->tag ? &n->tag->tagged->oid : oid, dst);if (suffix) -printf ("%s" , suffix); -printf ("\n" ); +strbuf_addstr (dst, suffix);return ; }
@@ -386,10 +377,9 @@ static void describe(const char *arg, int last_one)if (!match_cnt) {struct object_id *cmit_oid = &cmit->object.oid;if (always) { -printf ("%s" ,find_unique_abbrev (cmit_oid->hash, abbrev)); +strbuf_addstr (dst,find_unique_abbrev (cmit_oid->hash, abbrev));if (suffix) -printf ("%s" , suffix); -printf ("\n" ); +strbuf_addstr (dst, suffix);return ; }if (unannotated_cnt)
@@ -437,15 +427,36 @@ static void describe(const char *arg, int last_one) } } -display_name (all_matches[0 ].name); +append_name (all_matches[0 ].name, dst);if (abbrev) -show_suffix (all_matches[0 ].depth, &cmit->object.oid); +append_suffix (all_matches[0 ].depth, &cmit->object.oid, dst);if (suffix) -printf ("%s" , suffix); -printf ("\n" ); +strbuf_addstr (dst, suffix); +} + +static void describe (const char *arg,int last_one) +{ +struct object_id oid; +struct commit *cmit; +struct strbuf sb =STRBUF_INIT ; + +if (debug) +fprintf (stderr,_ ("describe %s\n" ), arg); + +if (get_oid (arg, &oid)) +die (_ ("Not a valid object name %s" ), arg); + cmit =lookup_commit_reference (&oid); +if (!cmit) +die (_ ("%s is not a valid '%s' object" ), arg, commit_type); + +describe_commit (&oid, &sb); + +puts (sb.buf);if (!last_one)clear_commit_marks (cmit,-1 ); + +strbuf_release (&sb); }int cmd_describe (int argc,const char **argv,const char *prefix)
Signature · 1 line
2.15.0.128.gcadd42da22
Re: [PATCHv4 6/7] builtin/describe.c: factor out describe_commit
Quoted 8 lines · On Tue, 14 Nov 2017 16:30:42 -0800 Stefan Beller <[email protected]> wrote:
In the next patch we'll learn how to describe more than just commits, so factor out describing commits into its own function. That will make the next patches easy as we still need to describe a commit as part of describing blobs.
While factoring out the functionality to
describe_commit, make sure that any output to stdout is put into a strbuf, which we can print afterwards, using puts which also adds the line ending.
I think the sentences here are a bit jumbled. The aim is to make the next patch easier (your 2nd sentence), and how we accomplish that is by factoring out the description of commits (1st sentence) *and* by outputting to a strbuf because we need to postprocess the output further when describing a commit as part of describing a blob (3rd sentence).
PATCH v4 7/7 builtin/describe.c: describe a blob
In reply to Stefan BellerSometimes users are given a hash of an object and they want to identify it further (ex.: Use verify-pack to find the largest blobs, but what are these? or [1])
When describing commits, we try to anchor them to tags or refs, as these are conceptually on a higher level than the commit. And if there is no ref or tag that matches exactly, we're out of luck. So we employ a heuristic to make up a name for the commit. These names are ambiguous, there might be different tags or refs to anchor to, and there might be different path in the DAG to travel to arrive at the commit precisely.
When describing a blob, we want to describe the blob from a higher layer as well, which is a tuple of (commit, deep/path) as the tree objects involved are rather uninteresting. The same blob can be referenced by multiple commits, so how we decide which commit to use? This patch implements a rather naive approach on this: As there are no back pointers from blobs to commits in which the blob occurs, we'll start walking from any tips available, listing the blobs in-order of the commit and once we found the blob, we'll take the first commit that listed the blob. For example
git describe --tags v0.99:Makefile conversion-901-g7672db20c2:Makefile
tells us the Makefile as it was in v0.99 was introduced in commit 7672db20.
The walking is performed in reverse order to show the introduction of a blob rather than its last occurrence.
[1] https://stackoverflow.com/questions/223678/which-commit-has-this-blob
--- Documentation/git-describe.txt | 13 ++++++++- builtin/describe.c | 66 ++++++++++++++++++++++++++++++++++++++---- t/t6120-describe.sh | 19 ++++++++++++ 3 files changed, 92 insertions(+), 6 deletions(-)
Documentation/git-describe.txt +12 -1
@@ -3,7 +3,7 @@ git-describe(1) NAME ---- -git-describe - Describe a commit using the most recent tag reachable from it +git-describe - Describe a commit or blob using the graph relations SYNOPSIS
@@ -11,6 +11,7 @@ SYNOPSIS [verse] 'git describe' [--all] [--tags] [--contains] [--abbrev=<n>] [<commit-ish>...] 'git describe' [--all] [--tags] [--contains] [--abbrev=<n>] --dirty[=<mark>] +'git describe' <blob> DESCRIPTION -----------
@@ -24,6 +25,16 @@ By default (without --all or --tags) `git describe` only shows annotated tags. For more information about creating annotated tags see the -a and -s options to linkgit:git-tag[1]. +If the given object refers to a blob, it will be described +as `<commit-ish>:<path>`, such that the blob can be found +at `<path>` in the `<commit-ish>`. Note, that the commit is likely +not the commit that introduced the blob, but the one that was found +first; to find the commit that introduced the blob, you need to find +the commit that last touched the path, e.g. +`git log <commit-description> -- <path>`. +As blobs do not point at the commits they are contained in, +describing blobs is slow as we have to walk the whole graph. + OPTIONS ------- <commit-ish>...::
builtin/describe.c +61 -5
92 lines not on this page · raw message
t/t6120-describe.sh +19 -0
@@ -310,6 +310,25 @@ test_expect_success 'describe ignoring a broken submodule' ' grep broken out ' +test_expect_success 'describe a blob at a tag' ' + echo "make it a unique blob" >file && + git add file && git commit -m "content in file" && + git tag -a -m "latest annotated tag" unique-file && + git describe HEAD:file >actual && + echo "unique-file:file" >expect && + test_cmp expect actual +' + +test_expect_success 'describe a blob with its last introduction' ' + git commit --allow-empty -m "empty commit" && + git rm file && + git commit -m "delete blob" && + git revert HEAD && + git commit --allow-empty -m "empty commit" && + git describe HEAD:file >actual && + grep unique-file-3-g actual +' + test_expect_failure ULIMIT_STACK_SIZE 'name-rev works in a deep repo' ' i=1 && while test $i -lt 8000
Signature · 1 line
2.15.0.128.gcadd42da22
Re: [PATCHv4 7/7] builtin/describe.c: describe a blob
Quoted 2 lines · On Tue, 14 Nov 2017 16:30:43 -0800 Stefan Beller <[email protected]> wrote:
The walking is performed in reverse order to show the introduction of a blob rather than its last occurrence.
The code as implemented here does not do this - it instead shows the last occurrence.
Documentation/git-describe.txt git-describe(1) · line 6
Quoted 4 lines
NAME
----Documentation/git-describe.txt +1
-1-git-describe - Describe a commit using the most recent tag reachable from it +git-describe - Describe a commit or blob using the graph relations
I would write "Describe a commit or blob using a tag reachable from it".
Documentation/git-describe.txt By default (without --all or --tags) `git describe` only shows · line 36
Quoted 9 lines
Documentation/git-describe.txt +9
-0+If the given object refers to a blob, it will be described +as `<commit-ish>:<path>`, such that the blob can be found +at `<path>` in the `<commit-ish>`. Note, that the commit is likely +not the commit that introduced the blob, but the one that was found +first; to find the commit that introduced the blob, you need to find +the commit that last touched the path, e.g. +`git log <commit-description> -- <path>`. +As blobs do not point at the commits they are contained in, +describing blobs is slow as we have to walk the whole graph.
I think some of this needs to be updated?
builtin/describe.c static void describe_commit(struct object_id *oid, struct strbuf *dst) · line 462
Quoted 11 lines
builtin/describe.c +11
-0+static void process_object (struct object *obj,const char *path,void *data) +{ +struct process_commit_data *pcd = data; + +if (!oidcmp (&pcd->looking_for, &obj->oid) && !pcd->dst->len) { +reset_revision_walk (); +describe_commit (&pcd->current_commit, pcd->dst); +strbuf_addf (pcd->dst,":%s" , path); + pcd->revs->max_count =0 ; + } +}
Setting max_count to 0 does not work when reverse is used, because the commits are first buffered into revs->commits (see get_revision() in revision.c). There doesn't seem to be a convenient way to terminate the traversal immediately - I think setting revs->commits to NULL should work (but I didn't check). Remember to free revs->commits (using free_commit_list) first.
t/t6120-describe.sh test_expect_success 'describe ignoring a broken submodule' ' · line 320
Quoted 8 lines
t/t6120-describe.sh +8
-0+test_expect_success 'describe a blob at a tag' ' + echo "make it a unique blob" >file && + git add file && git commit -m "content in file" && + git tag -a -m "latest annotated tag" unique-file && + git describe HEAD:file >actual && + echo "unique-file:file" >expect && + test_cmp expect actual +'
This is probably better named "describe a blob at a directly tagged commit". (Should we also test the case where a blob is directly tagged?)
t/t6120-describe.sh test_expect_success 'describe ignoring a broken submodule' ' · line 330
Quoted 9 lines
t/t6120-describe.sh +9
-0+test_expect_success 'describe a blob with its last introduction' ' + git commit --allow-empty -m "empty commit" && + git rm file && + git commit -m "delete blob" && + git revert HEAD && + git commit --allow-empty -m "empty commit" && + git describe HEAD:file >actual && + grep unique-file-3-g actual +'
The description is not true: firstly, this shows the last occurrence, not the last introduction (you can verify this by adding another commit and noticing that the contents of "actual" changes), and what we want is not the last introduction anyway, but the first one.
Re: [PATCHv4 7/7] builtin/describe.c: describe a blob
Quoted 8 lines · Jonathan Tan
Quoted 2 lines · On Tue, 14 Nov 2017 16:30:43 -0800 Stefan Beller <[email protected]> wrote:
The walking is performed in reverse order to show the introduction of a blob rather than its last occurrence.
The code as implemented here does not do this - it instead shows the last occurrence.
fixed to show the first occurrence.
Quoted 7 lines
Documentation/git-describe.txt git-describe(1) · line 6
Quoted 5 lines
NAME
----Documentation/git-describe.txt +1
-1-git-describe - Describe a commit using the most recent tag reachable from it +git-describe - Describe a commit or blob using the graph relationsI would write "Describe a commit or blob using a tag reachable from it".
using a ref, as we also can use refs.
I think 'the graph' is technically correct here, but may be too confusing.
Quoted 12 lines
Documentation/git-describe.txt By default (without --all or --tags) `git describe` only shows · line 36
Quoted 10 lines
Documentation/git-describe.txt +9
-0+If the given object refers to a blob, it will be described +as `<commit-ish>:<path>`, such that the blob can be found +at `<path>` in the `<commit-ish>`. Note, that the commit is likely +not the commit that introduced the blob, but the one that was found +first; to find the commit that introduced the blob, you need to find +the commit that last touched the path, e.g. +`git log <commit-description> -- <path>`. +As blobs do not point at the commits they are contained in, +describing blobs is slow as we have to walk the whole graph.I think some of this needs to be updated?
fixed.
Quoted 11 lines
Quoted 11 lines
builtin/describe.c +10
-0+static void process_object (struct object *obj,const char *path,void *data) +{ +struct process_commit_data *pcd = data; + +if (!oidcmp (&pcd->looking_for, &obj->oid) && !pcd->dst->len) { +reset_revision_walk (); +describe_commit (&pcd->current_commit, pcd->dst); +strbuf_addf (pcd->dst,":%s" , path); + pcd->revs->max_count =0 ; + }
Quoted 8 lines
Quoted 1 line
+}
Setting
max_countto 0 does not work when reverse is used, because the commits are first buffered intorevs->commits(seeget_revision()inrevision.c). There doesn't seem to be a convenient way to terminate the traversal immediately - I think settingrevs->commitsto NULL should work (but I didn't check). Remember to freerevs->commits(usingfree_commit_list) first.
This does work indeed.
Quoted 10 lines
t/t6120-describe.sh test_expect_success 'describe ignoring a broken submodule' ' · line 320
Quoted 9 lines
t/t6120-describe.sh +8
-0+test_expect_success 'describe a blob at a tag' ' + echo "make it a unique blob" >file && + git add file && git commit -m "content in file" && + git tag -a -m "latest annotated tag" unique-file && + git describe HEAD:file >actual && + echo "unique-file:file" >expect && + test_cmp expect actual +'
Quoted 2 lines
This is probably better named "describe a blob at a directly tagged commit".
ok
Quoted 2 lines
(Should we also test the case where a blob is directly
tagged?)
We do a bad job at describing tags that point at a blob currently:
git tag test-blob HEAD:Makefile
git describe test-blob
error: object cd75985991f4535c45e2589222a9e6a38fb1d613 is a blob, not a commit
fatal: test-blob is not a valid 'commit' object
This series changes this to
git describe test-blob
v2.15.0-rc0-43-g54bd705a95:Makefile
which might not be expected (you'd expect "test-blob"), so I think I can write a test telling that this is suboptimal behavior?
Quoted 11 lines
t/t6120-describe.sh test_expect_success 'describe ignoring a broken submodule' ' · line 330
Quoted 10 lines
t/t6120-describe.sh +9
-0+test_expect_success 'describe a blob with its last introduction' ' + git commit --allow-empty -m "empty commit" && + git rm file && + git commit -m "delete blob" && + git revert HEAD && + git commit --allow-empty -m "empty commit" && + git describe HEAD:file >actual && + grep unique-file-3-g actual +'
Quoted 4 lines
The description is not true: firstly, this shows the last occurrence, not the last introduction (you can verify this by adding another commit and noticing that the contents of "actual" changes), and what we want is not the last introduction anyway, but the first one.
fixed.
Re: [PATCHv4 7/7] builtin/describe.c: describe a blob
Quoted 7 lines · Stefan Beller
Quoted 4 lines
Documentation/git-describe.txt git-describe(1) · line 6
Quoted 2 lines
Documentation/git-describe.txt +1
-1-git-describe - Describe a commit using the most recent tag reachable from it +git-describe - Describe a commit or blob using the graph relationsI would write "Describe a commit or blob using a tag reachable from it".
using a ref, as we also can use refs.
I think 'the graph' is technically correct here, but may be too confusing.
Without saying graph over what, "graph relations" is not just confusing but an insufficient explanation for a technically correct explanation. Even though we have "--contains", we say "reachable from" and nobody has complained---so perhaps we can keep the white lie to keep the synopsis simpler?
If I were writing this sentence from scratch, perhaps I wouldn't even use the word "describe". How about
Give an object a human readable name based on an available ref
or something like that?
Quoted 10 lines
Quoted 2 lines
(Should we also test the case where a blob is directly
tagged?)We do a bad job at describing tags that point at a blob currently:
git tag test-blob HEAD:Makefile
git describe test-blob
error: objectcd75985991f4535c45e2589222a9e6a38fb1d613is a blob, not a commit
fatal: test-blob is not a valid 'commit' object
Quoted 8 lines
This series changes this to
git describe test-blob
v2.15.0-rc0-43-g54bd705a95:Makefilewhich might not be expected (you'd expect "test-blob"), so I think I can write a test telling that this is suboptimal behavior?
Or a sentence in BUGS section.
A case (or two) I find more interesting is to see how the code behaves against these:
git tag -a -m "annotated blob" a-blob HEAD:Makefile git tag -a -m "annotated tree" a-tree HEAD:t git describe a-blob a-tree
Thanks.
Re: [PATCHv4 7/7] builtin/describe.c: describe a blob
Quoted 4 lines
Give an object a human readable name based on an available ref
or something like that?
will use
Quoted 1 line
Or a sentence in BUGS section.
will add.
Quoted 6 lines
A case (or two) I find more interesting is to see how the code behaves against these:
git tag -a -m "annotated blob" a-blob HEAD:Makefile git tag -a -m "annotated tree" a-tree HEAD:t git describe a-blob a-tree
Glad I added a test for exactly this (well only the a-blob case, but a-tree will be the same):
test_expect_success 'describe tag object' '
git tag test-blob-1 -a -m msg unique-file:file &&
test_must_fail git describe test-blob-1 2>actual &&
grep "fatal: test-blob-1 is neither a commit nor blob" actual'
Re: [PATCHv4 7/7] builtin/describe.c: describe a blob
Quoted 1 line · Stefan Beller
grep "fatal: test-blob-1 is neither a commit nor blob" actual
OK, that might be somewhat unsatisfying from end-user's point of view (logically "test-blob-1" is already a name based on the 'graph relations' that is satisfactory).
[side note] should that grep become test_i18ngrep?
If this machinery is to find an object that is *bad* (in the sense in one of your earlier messages), I suspect it may be quite easy to use the new mechanism added by the series to also locate a tree object and report "that tree appears in this commit at this path" and it would be equally useful as the feature to find a blob.
Thanks.
Re: [PATCHv4 7/7] builtin/describe.c: describe a blob
Quoted 7 lines · Junio C Hamano
Quoted 1 line · Stefan Beller
grep "fatal: test-blob-1 is neither a commit nor blob" actual
OK, that might be somewhat unsatisfying from end-user's point of view (logically "test-blob-1" is already a name based on the 'graph relations' that is satisfactory).
... but that is correct and I think we need any further updates to address it. If a user starts with a tag object, the user already has one usable human-readable name. By "unsatisfying", I didn't mean that it is something we need to spend more cycles.