summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--commit-graph.c138
-rw-r--r--commit.h5
-rwxr-xr-xt/t5318-commit-graph.sh21
3 files changed, 125 insertions, 39 deletions
diff --git a/commit-graph.c b/commit-graph.c
index 36e481c67e..f70886c2d3 100644
--- a/commit-graph.c
+++ b/commit-graph.c
@@ -614,19 +614,29 @@ static struct commit_graph *load_commit_graph_chain(struct repository *r,
return graph_chain;
}
-static void validate_mixed_generation_chain(struct commit_graph *g)
+/*
+ * returns 1 if and only if all graphs in the chain have
+ * corrected commit dates stored in the generation_data chunk.
+ */
+static int validate_mixed_generation_chain(struct commit_graph *g)
{
- int read_generation_data;
+ int read_generation_data = 1;
+ struct commit_graph *p = g;
- if (!g)
- return;
+ while (read_generation_data && p) {
+ read_generation_data = p->read_generation_data;
+ p = p->base_graph;
+ }
- read_generation_data = !!g->chunk_generation_data;
+ if (read_generation_data)
+ return 1;
while (g) {
- g->read_generation_data = read_generation_data;
+ g->read_generation_data = 0;
g = g->base_graph;
}
+
+ return 0;
}
struct commit_graph *read_commit_graph_one(struct repository *r,
@@ -1026,7 +1036,8 @@ struct write_commit_graph_context {
split:1,
changed_paths:1,
order_by_pack:1,
- write_generation_data:1;
+ write_generation_data:1,
+ trust_generation_numbers:1;
struct topo_level_slab *topo_levels;
const struct commit_graph_opts *opts;
@@ -1098,7 +1109,7 @@ static int write_graph_chunk_data(struct hashfile *f,
uint32_t packedDate[2];
display_progress(ctx->progress, ++ctx->progress_cnt);
- if (parse_commit_no_graph(*list))
+ if (repo_parse_commit_no_graph(ctx->r, *list))
die(_("unable to parse commit %s"),
oid_to_hex(&(*list)->object.oid));
tree = get_commit_tree_oid(*list);
@@ -1193,7 +1204,9 @@ static int write_graph_chunk_generation_data(struct hashfile *f,
for (i = 0; i < ctx->commits.nr; i++) {
struct commit *c = ctx->commits.list[i];
- timestamp_t offset = commit_graph_data_at(c)->generation - c->date;
+ timestamp_t offset;
+ repo_parse_commit(ctx->r, c);
+ offset = commit_graph_data_at(c)->generation - c->date;
display_progress(ctx->progress, ++ctx->progress_cnt);
if (offset > GENERATION_NUMBER_V2_OFFSET_MAX) {
@@ -1411,11 +1424,11 @@ static void close_reachable(struct write_commit_graph_context *ctx)
if (!commit)
continue;
if (ctx->split) {
- if ((!parse_commit(commit) &&
+ if ((!repo_parse_commit(ctx->r, commit) &&
commit_graph_position(commit) == COMMIT_NOT_FROM_GRAPH) ||
flags == COMMIT_GRAPH_SPLIT_REPLACE)
add_missing_parents(ctx, commit);
- } else if (!parse_commit_no_graph(commit))
+ } else if (!repo_parse_commit_no_graph(ctx->r, commit))
add_missing_parents(ctx, commit);
}
stop_progress(&ctx->progress);
@@ -1434,38 +1447,38 @@ static void close_reachable(struct write_commit_graph_context *ctx)
stop_progress(&ctx->progress);
}
-static void compute_generation_numbers(struct write_commit_graph_context *ctx)
+static void compute_topological_levels(struct write_commit_graph_context *ctx)
{
int i;
struct commit_list *list = NULL;
if (ctx->report_progress)
ctx->progress = start_delayed_progress(
- _("Computing commit graph generation numbers"),
+ _("Computing commit graph topological levels"),
ctx->commits.nr);
for (i = 0; i < ctx->commits.nr; i++) {
- uint32_t level = *topo_level_slab_at(ctx->topo_levels, ctx->commits.list[i]);
- timestamp_t corrected_commit_date = commit_graph_data_at(ctx->commits.list[i])->generation;
+ struct commit *c = ctx->commits.list[i];
+ uint32_t level;
+
+ 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 &&
- corrected_commit_date != GENERATION_NUMBER_ZERO)
+ if (level != GENERATION_NUMBER_ZERO)
continue;
- commit_list_insert(ctx->commits.list[i], &list);
+ commit_list_insert(c, &list);
while (list) {
struct commit *current = list->item;
struct commit_list *parent;
int all_parents_computed = 1;
uint32_t max_level = 0;
- timestamp_t max_corrected_commit_date = 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);
- corrected_commit_date = commit_graph_data_at(parent->item)->generation;
- if (level == GENERATION_NUMBER_ZERO ||
- corrected_commit_date == GENERATION_NUMBER_ZERO) {
+ if (level == GENERATION_NUMBER_ZERO) {
all_parents_computed = 0;
commit_list_insert(parent->item, &list);
break;
@@ -1473,9 +1486,6 @@ static void compute_generation_numbers(struct write_commit_graph_context *ctx)
if (level > max_level)
max_level = level;
-
- if (corrected_commit_date > max_corrected_commit_date)
- max_corrected_commit_date = corrected_commit_date;
}
if (all_parents_computed) {
@@ -1484,6 +1494,64 @@ static void compute_generation_numbers(struct write_commit_graph_context *ctx)
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;
+ }
+ }
+ }
+ stop_progress(&ctx->progress);
+}
+
+static void compute_generation_numbers(struct write_commit_graph_context *ctx)
+{
+ int i;
+ struct commit_list *list = NULL;
+
+ if (ctx->report_progress)
+ ctx->progress = start_delayed_progress(
+ _("Computing commit graph generation numbers"),
+ ctx->commits.nr);
+
+ if (!ctx->trust_generation_numbers) {
+ for (i = 0; i < ctx->commits.nr; i++) {
+ struct commit *c = ctx->commits.list[i];
+ repo_parse_commit(ctx->r, c);
+ commit_graph_data_at(c)->generation = GENERATION_NUMBER_ZERO;
+ }
+ }
+
+ 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;
@@ -1710,9 +1778,9 @@ static void copy_oids_to_commits(struct write_commit_graph_context *ctx)
continue;
if (ctx->split && flags == COMMIT_GRAPH_SPLIT_REPLACE)
- parse_commit(ctx->commits.list[ctx->commits.nr]);
+ repo_parse_commit(ctx->r, ctx->commits.list[ctx->commits.nr]);
else
- parse_commit_no_graph(ctx->commits.list[ctx->commits.nr]);
+ repo_parse_commit_no_graph(ctx->r, ctx->commits.list[ctx->commits.nr]);
num_parents = commit_list_count(ctx->commits.list[ctx->commits.nr]->parents);
if (num_parents > 2)
@@ -2280,6 +2348,7 @@ int write_commit_graph(struct object_directory *odb,
init_topo_level_slab(&topo_levels);
ctx->topo_levels = &topo_levels;
+ prepare_commit_graph(ctx->r);
if (ctx->r->objects->commit_graph) {
struct commit_graph *g = ctx->r->objects->commit_graph;
@@ -2293,7 +2362,6 @@ int write_commit_graph(struct object_directory *odb,
ctx->changed_paths = 1;
if (!(flags & COMMIT_GRAPH_NO_WRITE_BLOOM_FILTERS)) {
struct commit_graph *g;
- prepare_commit_graph_one(ctx->r, ctx->odb);
g = ctx->r->objects->commit_graph;
@@ -2305,10 +2373,7 @@ int write_commit_graph(struct object_directory *odb,
}
if (ctx->split) {
- struct commit_graph *g;
- prepare_commit_graph(ctx->r);
-
- g = ctx->r->objects->commit_graph;
+ struct commit_graph *g = ctx->r->objects->commit_graph;
while (g) {
ctx->num_commit_graphs_before++;
@@ -2332,9 +2397,6 @@ int write_commit_graph(struct object_directory *odb,
ctx->approx_nr_objects = approximate_object_count();
- if (ctx->append)
- prepare_commit_graph_one(ctx->r, ctx->odb);
-
if (ctx->append && ctx->r->objects->commit_graph) {
struct commit_graph *g = ctx->r->objects->commit_graph;
for (i = 0; i < g->num_commits; i++) {
@@ -2381,9 +2443,11 @@ int write_commit_graph(struct object_directory *odb,
} else
ctx->num_commit_graphs_after = 1;
- validate_mixed_generation_chain(ctx->r->objects->commit_graph);
+ ctx->trust_generation_numbers = validate_mixed_generation_chain(ctx->r->objects->commit_graph);
- compute_generation_numbers(ctx);
+ compute_topological_levels(ctx);
+ if (ctx->write_generation_data)
+ compute_generation_numbers(ctx);
if (ctx->changed_paths)
compute_bloom_filters(ctx);
diff --git a/commit.h b/commit.h
index 0c9714827c..9e0c157bea 100644
--- a/commit.h
+++ b/commit.h
@@ -89,9 +89,10 @@ static inline int repo_parse_commit(struct repository *r, struct commit *item)
return repo_parse_commit_gently(r, item, 0);
}
-static inline int parse_commit_no_graph(struct commit *commit)
+static inline int repo_parse_commit_no_graph(struct repository *r,
+ struct commit *commit)
{
- return repo_parse_commit_internal(the_repository, commit, 0, 0);
+ return repo_parse_commit_internal(r, commit, 0, 0);
}
#ifndef NO_THE_REPOSITORY_COMPATIBILITY_MACROS
diff --git a/t/t5318-commit-graph.sh b/t/t5318-commit-graph.sh
index fa27df579a..5b15f1aa0f 100755
--- a/t/t5318-commit-graph.sh
+++ b/t/t5318-commit-graph.sh
@@ -446,6 +446,27 @@ test_expect_success 'warn on improper hash version' '
)
'
+test_expect_success 'lower layers have overflow chunk' '
+ cd "$TRASH_DIRECTORY/full" &&
+ UNIX_EPOCH_ZERO="@0 +0000" &&
+ FUTURE_DATE="@2147483646 +0000" &&
+ rm -f .git/objects/info/commit-graph &&
+ test_commit --date "$FUTURE_DATE" future-1 &&
+ test_commit --date "$UNIX_EPOCH_ZERO" old-1 &&
+ git commit-graph write --reachable &&
+ test_commit --date "$FUTURE_DATE" future-2 &&
+ test_commit --date "$UNIX_EPOCH_ZERO" old-2 &&
+ git commit-graph write --reachable --split=no-merge &&
+ test_commit extra &&
+ git commit-graph write --reachable --split=no-merge &&
+ git commit-graph write --reachable &&
+ graph_read_expect 16 "generation_data generation_data_overflow extra_edges" &&
+ mv .git/objects/info/commit-graph commit-graph-upgraded &&
+ git commit-graph write --reachable &&
+ graph_read_expect 16 "generation_data generation_data_overflow extra_edges" &&
+ test_cmp .git/objects/info/commit-graph commit-graph-upgraded
+'
+
# the verify tests below expect the commit-graph to contain
# exactly the commits reachable from the commits/8 branch.
# If the file changes the set of commits in the list, then the