Skip to content

Commit 30b1c7a

Browse files
Benno Eversgitster
authored andcommitted
describe: don't abort too early when searching tags
When searching the commit graph for tag candidates, `git-describe` will stop as soon as there is only one active branch left and it already found an annotated tag as a candidate. This works well as long as all branches eventually connect back to a common root, but if the tags are found across branches with no common ancestor B o----. \ o-----o---o----x A it can happen that the search on one branch terminates prematurely because a tag was found on another, independent branch. This scenario isn't quite as obscure as it sounds, since cloning with a limited depth often introduces many independent "dead ends" into the commit graph. The help text of `git-describe` states pretty clearly that when describing a commit D, the number appended to the emitted tag X should correspond to the number of commits found by `git log X..D`. Thus, this commit modifies the stopping condition to only abort the search when only one branch is left to search *and* all current best candidates are descendants from that branch. For repositories with a single root, this condition is always true: When the search is reduced to a single active branch, the current commit must be an ancestor of *all* tag candidates. This means that in the common case, this change will have no negative performance impact since the same number of commits as before will be traversed. Signed-off-by: Benno Evers <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 2d2118b commit 30b1c7a

File tree

2 files changed

+69
-4
lines changed

2 files changed

+69
-4
lines changed

builtin/describe.c

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -376,11 +376,25 @@ static void describe_commit(struct object_id *oid, struct strbuf *dst)
376376
if (!(c->object.flags & t->flag_within))
377377
t->depth++;
378378
}
379+
/* Stop if last remaining path already covered by best candidate(s) */
379380
if (annotated_cnt && !list) {
380-
if (debug)
381-
fprintf(stderr, _("finished search at %s\n"),
382-
oid_to_hex(&c->object.oid));
383-
break;
381+
int best_depth = INT_MAX;
382+
unsigned best_within = 0;
383+
for (cur_match = 0; cur_match < match_cnt; cur_match++) {
384+
struct possible_tag *t = &all_matches[cur_match];
385+
if (t->depth < best_depth) {
386+
best_depth = t->depth;
387+
best_within = t->flag_within;
388+
} else if (t->depth == best_depth) {
389+
best_within |= t->flag_within;
390+
}
391+
}
392+
if ((c->object.flags & best_within) == best_within) {
393+
if (debug)
394+
fprintf(stderr, _("finished search at %s\n"),
395+
oid_to_hex(&c->object.oid));
396+
break;
397+
}
384398
}
385399
while (parents) {
386400
struct commit *p = parents->item;

t/t6120-describe.sh

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -479,4 +479,55 @@ test_expect_success 'name-rev covers all conditions while looking at parents' '
479479
)
480480
'
481481

482+
# B
483+
# o
484+
# \
485+
# o-----o---o----x
486+
# A
487+
#
488+
test_expect_success 'describe commits with disjoint bases' '
489+
git init disjoint1 &&
490+
(
491+
cd disjoint1 &&
492+
493+
echo o >> file && git add file && git commit -m o &&
494+
echo A >> file && git add file && git commit -m A &&
495+
git tag A -a -m A &&
496+
echo o >> file && git add file && git commit -m o &&
497+
498+
git checkout --orphan branch && rm file &&
499+
echo B > file2 && git add file2 && git commit -m B &&
500+
git tag B -a -m B &&
501+
git merge --no-ff --allow-unrelated-histories master -m x &&
502+
503+
check_describe "A-3-*" HEAD
504+
)
505+
'
506+
507+
# B
508+
# o---o---o------------.
509+
# \
510+
# o---o---x
511+
# A
512+
#
513+
test_expect_success 'describe commits with disjoint bases 2' '
514+
git init disjoint2 &&
515+
(
516+
cd disjoint2 &&
517+
518+
echo A >> file && git add file && GIT_COMMITTER_DATE="2020-01-01 18:00" git commit -m A &&
519+
git tag A -a -m A &&
520+
echo o >> file && git add file && GIT_COMMITTER_DATE="2020-01-01 18:01" git commit -m o &&
521+
522+
git checkout --orphan branch &&
523+
echo o >> file2 && git add file2 && GIT_COMMITTER_DATE="2020-01-01 15:00" git commit -m o &&
524+
echo o >> file2 && git add file2 && GIT_COMMITTER_DATE="2020-01-01 15:01" git commit -m o &&
525+
echo B >> file2 && git add file2 && GIT_COMMITTER_DATE="2020-01-01 15:02" git commit -m B &&
526+
git tag B -a -m B &&
527+
git merge --no-ff --allow-unrelated-histories master -m x &&
528+
529+
check_describe "B-3-*" HEAD
530+
)
531+
'
532+
482533
test_done

0 commit comments

Comments
 (0)