Merge branch 'ds/ahead-behind'
"git for-each-ref" learns '%(ahead-behind:<base>)' that computes the distances from a single reference point in the history with bunch of commits in bulk. * ds/ahead-behind: commit-reach: add tips_reachable_from_bases() for-each-ref: add ahead-behind format atom commit-reach: implement ahead_behind() logic commit-graph: introduce `ensure_generations_valid()` commit-graph: return generation from memory commit-graph: simplify compute_generation_numbers() commit-graph: refactor compute_topological_levels() for-each-ref: explicitly test no matches for-each-ref: add --stdin option
This commit is contained in:
207
commit-graph.c
207
commit-graph.c
@ -117,12 +117,10 @@ timestamp_t commit_graph_generation(const struct commit *c)
|
||||
struct commit_graph_data *data =
|
||||
commit_graph_data_slab_peek(&commit_graph_data_slab, c);
|
||||
|
||||
if (!data)
|
||||
return GENERATION_NUMBER_INFINITY;
|
||||
else if (data->graph_pos == COMMIT_NOT_FROM_GRAPH)
|
||||
return GENERATION_NUMBER_INFINITY;
|
||||
if (data && data->generation)
|
||||
return data->generation;
|
||||
|
||||
return data->generation;
|
||||
return GENERATION_NUMBER_INFINITY;
|
||||
}
|
||||
|
||||
static struct commit_graph_data *commit_graph_data_at(const struct commit *c)
|
||||
@ -1447,24 +1445,52 @@ static void close_reachable(struct write_commit_graph_context *ctx)
|
||||
stop_progress(&ctx->progress);
|
||||
}
|
||||
|
||||
static void compute_topological_levels(struct write_commit_graph_context *ctx)
|
||||
struct compute_generation_info {
|
||||
struct repository *r;
|
||||
struct packed_commit_list *commits;
|
||||
struct progress *progress;
|
||||
int progress_cnt;
|
||||
|
||||
timestamp_t (*get_generation)(struct commit *c, void *data);
|
||||
void (*set_generation)(struct commit *c, timestamp_t gen, void *data);
|
||||
void *data;
|
||||
};
|
||||
|
||||
static timestamp_t compute_generation_from_max(struct commit *c,
|
||||
timestamp_t max_gen,
|
||||
int generation_version)
|
||||
{
|
||||
switch (generation_version) {
|
||||
case 1: /* topological levels */
|
||||
if (max_gen > GENERATION_NUMBER_V1_MAX - 1)
|
||||
max_gen = GENERATION_NUMBER_V1_MAX - 1;
|
||||
return max_gen + 1;
|
||||
|
||||
case 2: /* corrected commit date */
|
||||
if (c->date && c->date > max_gen)
|
||||
max_gen = c->date - 1;
|
||||
return max_gen + 1;
|
||||
|
||||
default:
|
||||
BUG("attempting unimplemented version");
|
||||
}
|
||||
}
|
||||
|
||||
static void compute_reachable_generation_numbers(
|
||||
struct compute_generation_info *info,
|
||||
int generation_version)
|
||||
{
|
||||
int i;
|
||||
struct commit_list *list = NULL;
|
||||
|
||||
if (ctx->report_progress)
|
||||
ctx->progress = start_delayed_progress(
|
||||
_("Computing commit graph topological levels"),
|
||||
ctx->commits.nr);
|
||||
for (i = 0; i < ctx->commits.nr; i++) {
|
||||
struct commit *c = ctx->commits.list[i];
|
||||
uint32_t level;
|
||||
for (i = 0; i < info->commits->nr; i++) {
|
||||
struct commit *c = info->commits->list[i];
|
||||
timestamp_t gen;
|
||||
repo_parse_commit(info->r, c);
|
||||
gen = info->get_generation(c, info->data);
|
||||
display_progress(info->progress, info->progress_cnt + 1);
|
||||
|
||||
repo_parse_commit(ctx->r, c);
|
||||
level = *topo_level_slab_at(ctx->topo_levels, c);
|
||||
|
||||
display_progress(ctx->progress, i + 1);
|
||||
if (level != GENERATION_NUMBER_ZERO)
|
||||
if (gen != GENERATION_NUMBER_ZERO && gen != GENERATION_NUMBER_INFINITY)
|
||||
continue;
|
||||
|
||||
commit_list_insert(c, &list);
|
||||
@ -1472,41 +1498,91 @@ static void compute_topological_levels(struct write_commit_graph_context *ctx)
|
||||
struct commit *current = list->item;
|
||||
struct commit_list *parent;
|
||||
int all_parents_computed = 1;
|
||||
uint32_t max_level = 0;
|
||||
uint32_t max_gen = 0;
|
||||
|
||||
for (parent = current->parents; parent; parent = parent->next) {
|
||||
repo_parse_commit(ctx->r, parent->item);
|
||||
level = *topo_level_slab_at(ctx->topo_levels, parent->item);
|
||||
repo_parse_commit(info->r, parent->item);
|
||||
gen = info->get_generation(parent->item, info->data);
|
||||
|
||||
if (level == GENERATION_NUMBER_ZERO) {
|
||||
if (gen == GENERATION_NUMBER_ZERO) {
|
||||
all_parents_computed = 0;
|
||||
commit_list_insert(parent->item, &list);
|
||||
break;
|
||||
}
|
||||
|
||||
if (level > max_level)
|
||||
max_level = level;
|
||||
if (gen > max_gen)
|
||||
max_gen = gen;
|
||||
}
|
||||
|
||||
if (all_parents_computed) {
|
||||
pop_commit(&list);
|
||||
|
||||
if (max_level > GENERATION_NUMBER_V1_MAX - 1)
|
||||
max_level = GENERATION_NUMBER_V1_MAX - 1;
|
||||
*topo_level_slab_at(ctx->topo_levels, current) = max_level + 1;
|
||||
gen = compute_generation_from_max(
|
||||
current, max_gen,
|
||||
generation_version);
|
||||
info->set_generation(current, gen, info->data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static timestamp_t get_topo_level(struct commit *c, void *data)
|
||||
{
|
||||
struct write_commit_graph_context *ctx = data;
|
||||
return *topo_level_slab_at(ctx->topo_levels, c);
|
||||
}
|
||||
|
||||
static void set_topo_level(struct commit *c, timestamp_t t, void *data)
|
||||
{
|
||||
struct write_commit_graph_context *ctx = data;
|
||||
*topo_level_slab_at(ctx->topo_levels, c) = (uint32_t)t;
|
||||
}
|
||||
|
||||
static void compute_topological_levels(struct write_commit_graph_context *ctx)
|
||||
{
|
||||
struct compute_generation_info info = {
|
||||
.r = ctx->r,
|
||||
.commits = &ctx->commits,
|
||||
.get_generation = get_topo_level,
|
||||
.set_generation = set_topo_level,
|
||||
.data = ctx,
|
||||
};
|
||||
|
||||
if (ctx->report_progress)
|
||||
info.progress = ctx->progress
|
||||
= start_delayed_progress(
|
||||
_("Computing commit graph topological levels"),
|
||||
ctx->commits.nr);
|
||||
|
||||
compute_reachable_generation_numbers(&info, 1);
|
||||
|
||||
stop_progress(&ctx->progress);
|
||||
}
|
||||
|
||||
static timestamp_t get_generation_from_graph_data(struct commit *c, void *data)
|
||||
{
|
||||
return commit_graph_data_at(c)->generation;
|
||||
}
|
||||
|
||||
static void set_generation_v2(struct commit *c, timestamp_t t, void *data)
|
||||
{
|
||||
struct commit_graph_data *g = commit_graph_data_at(c);
|
||||
g->generation = (uint32_t)t;
|
||||
}
|
||||
|
||||
static void compute_generation_numbers(struct write_commit_graph_context *ctx)
|
||||
{
|
||||
int i;
|
||||
struct commit_list *list = NULL;
|
||||
struct compute_generation_info info = {
|
||||
.r = ctx->r,
|
||||
.commits = &ctx->commits,
|
||||
.get_generation = get_generation_from_graph_data,
|
||||
.set_generation = set_generation_v2,
|
||||
.data = ctx,
|
||||
};
|
||||
|
||||
if (ctx->report_progress)
|
||||
ctx->progress = start_delayed_progress(
|
||||
info.progress = ctx->progress
|
||||
= start_delayed_progress(
|
||||
_("Computing commit graph generation numbers"),
|
||||
ctx->commits.nr);
|
||||
|
||||
@ -1518,47 +1594,7 @@ static void compute_generation_numbers(struct write_commit_graph_context *ctx)
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < ctx->commits.nr; i++) {
|
||||
struct commit *c = ctx->commits.list[i];
|
||||
timestamp_t corrected_commit_date;
|
||||
|
||||
repo_parse_commit(ctx->r, c);
|
||||
corrected_commit_date = commit_graph_data_at(c)->generation;
|
||||
|
||||
display_progress(ctx->progress, i + 1);
|
||||
if (corrected_commit_date != GENERATION_NUMBER_ZERO)
|
||||
continue;
|
||||
|
||||
commit_list_insert(c, &list);
|
||||
while (list) {
|
||||
struct commit *current = list->item;
|
||||
struct commit_list *parent;
|
||||
int all_parents_computed = 1;
|
||||
timestamp_t max_corrected_commit_date = 0;
|
||||
|
||||
for (parent = current->parents; parent; parent = parent->next) {
|
||||
repo_parse_commit(ctx->r, parent->item);
|
||||
corrected_commit_date = commit_graph_data_at(parent->item)->generation;
|
||||
|
||||
if (corrected_commit_date == GENERATION_NUMBER_ZERO) {
|
||||
all_parents_computed = 0;
|
||||
commit_list_insert(parent->item, &list);
|
||||
break;
|
||||
}
|
||||
|
||||
if (corrected_commit_date > max_corrected_commit_date)
|
||||
max_corrected_commit_date = corrected_commit_date;
|
||||
}
|
||||
|
||||
if (all_parents_computed) {
|
||||
pop_commit(&list);
|
||||
|
||||
if (current->date && current->date > max_corrected_commit_date)
|
||||
max_corrected_commit_date = current->date - 1;
|
||||
commit_graph_data_at(current)->generation = max_corrected_commit_date + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
compute_reachable_generation_numbers(&info, 2);
|
||||
|
||||
for (i = 0; i < ctx->commits.nr; i++) {
|
||||
struct commit *c = ctx->commits.list[i];
|
||||
@ -1569,6 +1605,35 @@ static void compute_generation_numbers(struct write_commit_graph_context *ctx)
|
||||
stop_progress(&ctx->progress);
|
||||
}
|
||||
|
||||
static void set_generation_in_graph_data(struct commit *c, timestamp_t t,
|
||||
void *data)
|
||||
{
|
||||
commit_graph_data_at(c)->generation = t;
|
||||
}
|
||||
|
||||
/*
|
||||
* After this method, all commits reachable from those in the given
|
||||
* list will have non-zero, non-infinite generation numbers.
|
||||
*/
|
||||
void ensure_generations_valid(struct repository *r,
|
||||
struct commit **commits, size_t nr)
|
||||
{
|
||||
int generation_version = get_configured_generation_version(r);
|
||||
struct packed_commit_list list = {
|
||||
.list = commits,
|
||||
.alloc = nr,
|
||||
.nr = nr,
|
||||
};
|
||||
struct compute_generation_info info = {
|
||||
.r = r,
|
||||
.commits = &list,
|
||||
.get_generation = get_generation_from_graph_data,
|
||||
.set_generation = set_generation_in_graph_data,
|
||||
};
|
||||
|
||||
compute_reachable_generation_numbers(&info, generation_version);
|
||||
}
|
||||
|
||||
static void trace2_bloom_filter_write_statistics(struct write_commit_graph_context *ctx)
|
||||
{
|
||||
trace2_data_intmax("commit-graph", ctx->r, "filter-computed",
|
||||
|
Reference in New Issue
Block a user