builtin/commit-graph.c: introduce split strategy 'no-merge'

In the previous commit, we laid the groundwork for supporting different
splitting strategies. In this commit, we introduce the first splitting
strategy: 'no-merge'.

Passing '--split=no-merge' is useful for callers which wish to write a
new incremental commit-graph, but do not want to spend effort condensing
the incremental chain [1]. Previously, this was possible by passing
'--size-multiple=0', but this no longer the case following 63020f175f
(commit-graph: prefer default size_mult when given zero, 2020-01-02).

When '--split=no-merge' is given, the commit-graph machinery will never
condense an existing chain, and it will always write a new incremental.

[1]: This might occur when, for example, a server administrator running
some program after each push may want to ensure that each job runs
proportional in time to the size of the push, and does not "jump" when
the commit-graph machinery decides to trigger a merge.

Signed-off-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Taylor Blau 2020-04-13 22:04:12 -06:00 committed by Junio C Hamano
parent 4f027355f6
commit fdbde82fe5
5 changed files with 36 additions and 9 deletions

View File

@ -63,6 +63,11 @@ chain of multiple commit-graph files stored in
strategy and other splitting options. The new commits not already in the
commit-graph are added in a new "tip" file. This file is merged with the
existing file if the following merge conditions are met:
* If `--split=no-merge` is specified, a merge is never performed, and
the remaining options are ignored. A bare `--split` defers to the
remaining options. (Note that merging a chain of commit graphs replaces
the existing chain with a length-1 chain where the first and only
incremental holds the entire graph).
+
* If `--size-multiple=<X>` is not specified, let `X` equal 2. If the new
tip file would have `N` commits and the previous tip has `M` commits and

View File

@ -118,11 +118,16 @@ static struct split_commit_graph_opts split_opts;
static int write_option_parse_split(const struct option *opt, const char *arg,
int unset)
{
enum commit_graph_split_flags *flags = opt->value;
opts.split = 1;
if (!arg)
return 0;
die(_("unrecognized --split argument, %s"), arg);
if (!strcmp(arg, "no-merge"))
*flags = COMMIT_GRAPH_SPLIT_MERGE_PROHIBITED;
else
die(_("unrecognized --split argument, %s"), arg);
return 0;
}

View File

@ -1529,6 +1529,7 @@ static void split_graph_merge_strategy(struct write_commit_graph_context *ctx)
{
struct commit_graph *g;
uint32_t num_commits;
enum commit_graph_split_flags flags = COMMIT_GRAPH_SPLIT_UNSPECIFIED;
uint32_t i;
int max_commits = 0;
@ -1539,21 +1540,25 @@ static void split_graph_merge_strategy(struct write_commit_graph_context *ctx)
if (ctx->split_opts->size_multiple)
size_mult = ctx->split_opts->size_multiple;
flags = ctx->split_opts->flags;
}
g = ctx->r->objects->commit_graph;
num_commits = ctx->commits.nr;
ctx->num_commit_graphs_after = ctx->num_commit_graphs_before + 1;
while (g && (g->num_commits <= size_mult * num_commits ||
(max_commits && num_commits > max_commits))) {
if (g->odb != ctx->odb)
break;
if (flags != COMMIT_GRAPH_SPLIT_MERGE_PROHIBITED) {
while (g && (g->num_commits <= size_mult * num_commits ||
(max_commits && num_commits > max_commits))) {
if (g->odb != ctx->odb)
break;
num_commits += g->num_commits;
g = g->base_graph;
num_commits += g->num_commits;
g = g->base_graph;
ctx->num_commit_graphs_after--;
ctx->num_commit_graphs_after--;
}
}
ctx->new_base_graph = g;

View File

@ -83,7 +83,8 @@ enum commit_graph_write_flags {
};
enum commit_graph_split_flags {
COMMIT_GRAPH_SPLIT_UNSPECIFIED = 0
COMMIT_GRAPH_SPLIT_UNSPECIFIED = 0,
COMMIT_GRAPH_SPLIT_MERGE_PROHIBITED = 1
};
struct split_commit_graph_opts {

View File

@ -344,4 +344,15 @@ test_expect_success 'split across alternate where alternate is not split' '
test_cmp commit-graph .git/objects/info/commit-graph
'
test_expect_success '--split=no-merge always writes an incremental' '
test_when_finished rm -rf a b &&
rm -rf $graphdir $infodir/commit-graph &&
git reset --hard commits/2 &&
git rev-list HEAD~1 >a &&
git rev-list HEAD >b &&
git commit-graph write --split --stdin-commits <a &&
git commit-graph write --split=no-merge --stdin-commits <b &&
test_line_count = 2 $graphdir/commit-graph-chain
'
test_done