Skip to content

Commit 819807b

Browse files
derrickstoleegitster
authored andcommitted
ref-filter: use generation number for --contains
A commit A can reach a commit B only if the generation number of A is strictly larger than the generation number of B. This condition allows significantly short-circuiting commit-graph walks. Use generation number for '--contains' type queries. On a copy of the Linux repository where HEAD is contained in v4.13 but no earlier tag, the command 'git tag --contains HEAD' had the following peformance improvement: Before: 0.81s After: 0.04s Rel %: -95% Helped-by: Jeff King <[email protected]> Signed-off-by: Derrick Stolee <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent e2838d8 commit 819807b

File tree

1 file changed

+20
-4
lines changed

1 file changed

+20
-4
lines changed

ref-filter.c

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "trailer.h"
1717
#include "wt-status.h"
1818
#include "commit-slab.h"
19+
#include "commit-graph.h"
1920

2021
static struct ref_msg {
2122
const char *gone;
@@ -1587,7 +1588,8 @@ static int in_commit_list(const struct commit_list *want, struct commit *c)
15871588
*/
15881589
static enum contains_result contains_test(struct commit *candidate,
15891590
const struct commit_list *want,
1590-
struct contains_cache *cache)
1591+
struct contains_cache *cache,
1592+
uint32_t cutoff)
15911593
{
15921594
enum contains_result *cached = contains_cache_at(cache, candidate);
15931595

@@ -1603,6 +1605,10 @@ static enum contains_result contains_test(struct commit *candidate,
16031605

16041606
/* Otherwise, we don't know; prepare to recurse */
16051607
parse_commit_or_die(candidate);
1608+
1609+
if (candidate->generation < cutoff)
1610+
return CONTAINS_NO;
1611+
16061612
return CONTAINS_UNKNOWN;
16071613
}
16081614

@@ -1618,8 +1624,18 @@ static enum contains_result contains_tag_algo(struct commit *candidate,
16181624
struct contains_cache *cache)
16191625
{
16201626
struct contains_stack contains_stack = { 0, 0, NULL };
1621-
enum contains_result result = contains_test(candidate, want, cache);
1627+
enum contains_result result;
1628+
uint32_t cutoff = GENERATION_NUMBER_INFINITY;
1629+
const struct commit_list *p;
1630+
1631+
for (p = want; p; p = p->next) {
1632+
struct commit *c = p->item;
1633+
load_commit_graph_info(c);
1634+
if (c->generation < cutoff)
1635+
cutoff = c->generation;
1636+
}
16221637

1638+
result = contains_test(candidate, want, cache, cutoff);
16231639
if (result != CONTAINS_UNKNOWN)
16241640
return result;
16251641

@@ -1637,7 +1653,7 @@ static enum contains_result contains_tag_algo(struct commit *candidate,
16371653
* If we just popped the stack, parents->item has been marked,
16381654
* therefore contains_test will return a meaningful yes/no.
16391655
*/
1640-
else switch (contains_test(parents->item, want, cache)) {
1656+
else switch (contains_test(parents->item, want, cache, cutoff)) {
16411657
case CONTAINS_YES:
16421658
*contains_cache_at(cache, commit) = CONTAINS_YES;
16431659
contains_stack.nr--;
@@ -1651,7 +1667,7 @@ static enum contains_result contains_tag_algo(struct commit *candidate,
16511667
}
16521668
}
16531669
free(contains_stack.contains_stack);
1654-
return contains_test(candidate, want, cache);
1670+
return contains_test(candidate, want, cache, cutoff);
16551671
}
16561672

16571673
static int commit_contains(struct ref_filter *filter, struct commit *commit,

0 commit comments

Comments
 (0)