Skip to content

Commit 996e90e

Browse files
committed
Merge branch 'tb/commit-graph-split-merge' into pu
The code to write out the commit-graph has been taught a few options to control if the resulting graph chains should be merged or a single new incremental graph is created. * tb/commit-graph-split-merge: builtin/commit-graph.c: support '--input=none' builtin/commit-graph.c: introduce '--input=<source>' builtin/commit-graph.c: support '--split[=<strategy>]'
2 parents dd45f00 + 59dd3aa commit 996e90e

File tree

6 files changed

+206
-56
lines changed

6 files changed

+206
-56
lines changed

Documentation/git-commit-graph.txt

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -39,34 +39,46 @@ COMMANDS
3939
--------
4040
'write'::
4141

42-
Write a commit-graph file based on the commits found in packfiles.
42+
Write a commit-graph file based on the specified sources of input:
4343
+
44-
With the `--stdin-packs` option, generate the new commit graph by
44+
With the `--input=stdin-packs` option, generate the new commit graph by
4545
walking objects only in the specified pack-indexes. (Cannot be combined
46-
with `--stdin-commits` or `--reachable`.)
46+
with `--input=stdin-commits` or `--input=reachable`.)
4747
+
48-
With the `--stdin-commits` option, generate the new commit graph by
49-
walking commits starting at the commits specified in stdin as a list
48+
With the `--input=stdin-commits` option, generate the new commit graph
49+
by walking commits starting at the commits specified in stdin as a list
5050
of OIDs in hex, one OID per line. (Cannot be combined with
51-
`--stdin-packs` or `--reachable`.)
51+
`--input=stdin-packs` or `--input=reachable`.)
5252
+
53-
With the `--reachable` option, generate the new commit graph by walking
54-
commits starting at all refs. (Cannot be combined with `--stdin-commits`
55-
or `--stdin-packs`.)
53+
With the `--input=reachable` option, generate the new commit graph by
54+
walking commits starting at all refs. (Cannot be combined with
55+
`--input=stdin-commits` or `--input=stdin-packs`.)
5656
+
57-
With the `--append` option, include all commits that are present in the
58-
existing commit-graph file.
57+
With the `--input=append` option, include all commits that are present
58+
in the existing commit-graph file.
5959
+
6060
With the `--changed-paths` option, compute and write information about the
6161
paths changed between a commit and it's first parent. This operation can
6262
take a while on large repositories. It provides significant performance gains
6363
for getting history of a directory or a file with `git log -- <path>`.
6464
+
65-
With the `--split` option, write the commit-graph as a chain of multiple
66-
commit-graph files stored in `<dir>/info/commit-graphs`. The new commits
67-
not already in the commit-graph are added in a new "tip" file. This file
68-
is merged with the existing file if the following merge conditions are
69-
met:
65+
With the `--input=none` option, behave as if `--input=append` were
66+
given, but do not walk other packs to find additional commits.
67+
68+
If none of the above options are given, then generate the new
69+
commit-graph by walking over all pack-indexes.
70+
+
71+
With the `--split[=<strategy>]` option, write the commit-graph as a
72+
chain of multiple commit-graph files stored in
73+
`<dir>/info/commit-graphs`. Commit-graph layers are merged based on the
74+
strategy and other splitting options. The new commits not already in the
75+
commit-graph are added in a new "tip" file. This file is merged with the
76+
existing file if the following merge conditions are met:
77+
* If `--split=merge-always` is specified, then a merge is always
78+
conducted, and the remaining options are ignored. Conversely, if
79+
`--split=no-merge` is specified, a merge is never performed, and the
80+
remaining options are ignored. A bare `--split` defers to the remaining
81+
options.
7082
+
7183
* If `--size-multiple=<X>` is not specified, let `X` equal 2. If the new
7284
tip file would have `N` commits and the previous tip has `M` commits and
@@ -104,20 +116,20 @@ $ git commit-graph write
104116
using commits in `<pack-index>`.
105117
+
106118
------------------------------------------------
107-
$ echo <pack-index> | git commit-graph write --stdin-packs
119+
$ echo <pack-index> | git commit-graph write --input=stdin-packs
108120
------------------------------------------------
109121

110122
* Write a commit-graph file containing all reachable commits.
111123
+
112124
------------------------------------------------
113-
$ git show-ref -s | git commit-graph write --stdin-commits
125+
$ git show-ref -s | git commit-graph write --input=stdin-commits
114126
------------------------------------------------
115127

116128
* Write a commit-graph file containing all commits in the current
117129
commit-graph file along with those reachable from `HEAD`.
118130
+
119131
------------------------------------------------
120-
$ git rev-parse HEAD | git commit-graph write --stdin-commits --append
132+
$ git rev-parse HEAD | git commit-graph write --input=stdin-commits --input=append
121133
------------------------------------------------
122134

123135

builtin/commit-graph.c

Lines changed: 94 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,11 @@
99

1010
static char const * const builtin_commit_graph_usage[] = {
1111
N_("git commit-graph verify [--object-dir <objdir>] [--shallow] [--[no-]progress]"),
12-
N_("git commit-graph write [--object-dir <objdir>] [--append|--split] [--reachable|--stdin-packs|--stdin-commits] [--changed-paths] [--[no-]progress] <split options>"),
12+
N_("git commit-graph write [--object-dir <objdir>] "
13+
"[--split[=<strategy>]] "
14+
"[--input=<reachable|stdin-packs|stdin-commits|append|none>] "
15+
"[--changed-paths] "
16+
"[--[no-]progress] <split options>"),
1317
NULL
1418
};
1519

@@ -19,16 +23,25 @@ static const char * const builtin_commit_graph_verify_usage[] = {
1923
};
2024

2125
static const char * const builtin_commit_graph_write_usage[] = {
22-
N_("git commit-graph write [--object-dir <objdir>] [--append|--split] [--reachable|--stdin-packs|--stdin-commits] [--changed-paths] [--[no-]progress] <split options>"),
26+
N_("git commit-graph write [--object-dir <objdir>] "
27+
"[--split[=<strategy>]] "
28+
"[--input=<reachable|stdin-packs|stdin-commits|append|none>] "
29+
"[--changed-paths] "
30+
"[--[no-]progress] <split options>"),
2331
NULL
2432
};
2533

34+
enum commit_graph_input {
35+
COMMIT_GRAPH_INPUT_REACHABLE = (1 << 1),
36+
COMMIT_GRAPH_INPUT_STDIN_PACKS = (1 << 2),
37+
COMMIT_GRAPH_INPUT_STDIN_COMMITS = (1 << 3),
38+
COMMIT_GRAPH_INPUT_APPEND = (1 << 4),
39+
COMMIT_GRAPH_INPUT_NONE = (1 << 5)
40+
};
41+
2642
static struct opts_commit_graph {
2743
const char *obj_dir;
28-
int reachable;
29-
int stdin_packs;
30-
int stdin_commits;
31-
int append;
44+
enum commit_graph_input input;
3245
int split;
3346
int shallow;
3447
int progress;
@@ -54,6 +67,30 @@ static struct object_directory *find_odb(struct repository *r,
5467
return odb;
5568
}
5669

70+
static int option_parse_input(const struct option *opt, const char *arg,
71+
int unset)
72+
{
73+
enum commit_graph_input *to = opt->value;
74+
if (unset || !strcmp(arg, "packs")) {
75+
*to = 0;
76+
return 0;
77+
}
78+
79+
if (!strcmp(arg, "reachable"))
80+
*to |= COMMIT_GRAPH_INPUT_REACHABLE;
81+
else if (!strcmp(arg, "stdin-packs"))
82+
*to |= COMMIT_GRAPH_INPUT_STDIN_PACKS;
83+
else if (!strcmp(arg, "stdin-commits"))
84+
*to |= COMMIT_GRAPH_INPUT_STDIN_COMMITS;
85+
else if (!strcmp(arg, "append"))
86+
*to |= COMMIT_GRAPH_INPUT_APPEND;
87+
else if (!strcmp(arg, "none"))
88+
*to |= (COMMIT_GRAPH_INPUT_APPEND | COMMIT_GRAPH_INPUT_NONE);
89+
else
90+
die(_("unrecognized --input source, %s"), arg);
91+
return 0;
92+
}
93+
5794
static int graph_verify(int argc, const char **argv)
5895
{
5996
struct commit_graph *graph = NULL;
@@ -112,6 +149,27 @@ static int graph_verify(int argc, const char **argv)
112149
extern int read_replace_refs;
113150
static struct split_commit_graph_opts split_opts;
114151

152+
static int write_option_parse_split(const struct option *opt, const char *arg,
153+
int unset)
154+
{
155+
enum commit_graph_split_flags *flags = opt->value;
156+
157+
opts.split = 1;
158+
if (!arg) {
159+
*flags = COMMIT_GRAPH_SPLIT_MERGE_AUTO;
160+
return 0;
161+
}
162+
163+
if (!strcmp(arg, "merge-all"))
164+
*flags = COMMIT_GRAPH_SPLIT_MERGE_REQUIRED;
165+
else if (!strcmp(arg, "no-merge"))
166+
*flags = COMMIT_GRAPH_SPLIT_MERGE_PROHIBITED;
167+
else
168+
die(_("unrecognized --split argument, %s"), arg);
169+
170+
return 0;
171+
}
172+
115173
static int graph_write(int argc, const char **argv)
116174
{
117175
struct string_list *pack_indexes = NULL;
@@ -125,19 +183,28 @@ static int graph_write(int argc, const char **argv)
125183
OPT_STRING(0, "object-dir", &opts.obj_dir,
126184
N_("dir"),
127185
N_("The object directory to store the graph")),
128-
OPT_BOOL(0, "reachable", &opts.reachable,
129-
N_("start walk at all refs")),
130-
OPT_BOOL(0, "stdin-packs", &opts.stdin_packs,
131-
N_("scan pack-indexes listed by stdin for commits")),
132-
OPT_BOOL(0, "stdin-commits", &opts.stdin_commits,
133-
N_("start walk at commits listed by stdin")),
134-
OPT_BOOL(0, "append", &opts.append,
135-
N_("include all commits already in the commit-graph file")),
186+
OPT_CALLBACK(0, "input", &opts.input, NULL,
187+
N_("include commits from this source in the graph"),
188+
option_parse_input),
189+
OPT_BIT(0, "reachable", &opts.input,
190+
N_("start walk at all refs"),
191+
COMMIT_GRAPH_INPUT_REACHABLE),
192+
OPT_BIT(0, "stdin-packs", &opts.input,
193+
N_("scan pack-indexes listed by stdin for commits"),
194+
COMMIT_GRAPH_INPUT_STDIN_PACKS),
195+
OPT_BIT(0, "stdin-commits", &opts.input,
196+
N_("start walk at commits listed by stdin"),
197+
COMMIT_GRAPH_INPUT_STDIN_COMMITS),
198+
OPT_BIT(0, "append", &opts.input,
199+
N_("include all commits already in the commit-graph file"),
200+
COMMIT_GRAPH_INPUT_APPEND),
136201
OPT_BOOL(0, "changed-paths", &opts.enable_changed_paths,
137202
N_("enable computation for changed paths")),
138203
OPT_BOOL(0, "progress", &opts.progress, N_("force progress reporting")),
139-
OPT_BOOL(0, "split", &opts.split,
140-
N_("allow writing an incremental commit-graph file")),
204+
OPT_CALLBACK_F(0, "split", &split_opts.flags, NULL,
205+
N_("allow writing an incremental commit-graph file"),
206+
PARSE_OPT_OPTARG | PARSE_OPT_NONEG,
207+
write_option_parse_split),
141208
OPT_INTEGER(0, "max-commits", &split_opts.max_commits,
142209
N_("maximum number of commits in a non-base split commit-graph")),
143210
OPT_INTEGER(0, "size-multiple", &split_opts.size_multiple,
@@ -158,12 +225,16 @@ static int graph_write(int argc, const char **argv)
158225
builtin_commit_graph_write_options,
159226
builtin_commit_graph_write_usage, 0);
160227

161-
if (opts.reachable + opts.stdin_packs + opts.stdin_commits > 1)
162-
die(_("use at most one of --reachable, --stdin-commits, or --stdin-packs"));
228+
if ((!!(opts.input & COMMIT_GRAPH_INPUT_REACHABLE) +
229+
!!(opts.input & COMMIT_GRAPH_INPUT_STDIN_PACKS) +
230+
!!(opts.input & COMMIT_GRAPH_INPUT_STDIN_COMMITS)) > 1)
231+
die(_("use at most one of --input=reachable, --input=stdin-commits, or --input=stdin-packs"));
163232
if (!opts.obj_dir)
164233
opts.obj_dir = get_object_directory();
165-
if (opts.append)
234+
if (opts.input & COMMIT_GRAPH_INPUT_APPEND)
166235
flags |= COMMIT_GRAPH_WRITE_APPEND;
236+
if (opts.input & COMMIT_GRAPH_INPUT_NONE)
237+
flags |= COMMIT_GRAPH_WRITE_NO_INPUT;
167238
if (opts.split)
168239
flags |= COMMIT_GRAPH_WRITE_SPLIT;
169240
if (opts.progress)
@@ -175,22 +246,22 @@ static int graph_write(int argc, const char **argv)
175246
read_replace_refs = 0;
176247
odb = find_odb(the_repository, opts.obj_dir);
177248

178-
if (opts.reachable) {
249+
if (opts.input & COMMIT_GRAPH_INPUT_REACHABLE) {
179250
if (write_commit_graph_reachable(odb, flags, &split_opts))
180251
return 1;
181252
return 0;
182253
}
183254

184255
string_list_init(&lines, 0);
185-
if (opts.stdin_packs || opts.stdin_commits) {
256+
if (opts.input & (COMMIT_GRAPH_INPUT_STDIN_PACKS | COMMIT_GRAPH_INPUT_STDIN_COMMITS)) {
186257
struct strbuf buf = STRBUF_INIT;
187258

188259
while (strbuf_getline(&buf, stdin) != EOF)
189260
string_list_append(&lines, strbuf_detach(&buf, NULL));
190261

191-
if (opts.stdin_packs)
262+
if (opts.input & COMMIT_GRAPH_INPUT_STDIN_PACKS)
192263
pack_indexes = &lines;
193-
if (opts.stdin_commits) {
264+
if (opts.input & COMMIT_GRAPH_INPUT_STDIN_COMMITS) {
194265
commit_hex = &lines;
195266
flags |= COMMIT_GRAPH_WRITE_CHECK_OIDS;
196267
}

commit-graph.c

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -874,7 +874,8 @@ struct write_commit_graph_context {
874874
split:1,
875875
check_oids:1,
876876
changed_paths:1,
877-
order_by_pack:1;
877+
order_by_pack:1,
878+
no_input:1;
878879

879880
const struct split_commit_graph_opts *split_opts;
880881
uint32_t total_bloom_filter_data_size;
@@ -1727,27 +1728,33 @@ static void split_graph_merge_strategy(struct write_commit_graph_context *ctx)
17271728

17281729
int max_commits = 0;
17291730
int size_mult = 2;
1731+
enum commit_graph_split_flags flags = COMMIT_GRAPH_SPLIT_MERGE_AUTO;
17301732

17311733
if (ctx->split_opts) {
17321734
max_commits = ctx->split_opts->max_commits;
17331735

17341736
if (ctx->split_opts->size_multiple)
17351737
size_mult = ctx->split_opts->size_multiple;
1738+
1739+
flags = ctx->split_opts->flags;
17361740
}
17371741

17381742
g = ctx->r->objects->commit_graph;
17391743
num_commits = ctx->commits.nr;
17401744
ctx->num_commit_graphs_after = ctx->num_commit_graphs_before + 1;
17411745

1742-
while (g && (g->num_commits <= size_mult * num_commits ||
1743-
(max_commits && num_commits > max_commits))) {
1744-
if (g->odb != ctx->odb)
1745-
break;
1746+
if (flags != COMMIT_GRAPH_SPLIT_MERGE_PROHIBITED) {
1747+
while (g && (g->num_commits <= size_mult * num_commits ||
1748+
(max_commits && num_commits > max_commits) ||
1749+
(flags == COMMIT_GRAPH_SPLIT_MERGE_REQUIRED))) {
1750+
if (g->odb != ctx->odb)
1751+
break;
17461752

1747-
num_commits += g->num_commits;
1748-
g = g->base_graph;
1753+
num_commits += g->num_commits;
1754+
g = g->base_graph;
17491755

1750-
ctx->num_commit_graphs_after--;
1756+
ctx->num_commit_graphs_after--;
1757+
}
17511758
}
17521759

17531760
ctx->new_base_graph = g;
@@ -1975,6 +1982,7 @@ int write_commit_graph(struct object_directory *odb,
19751982
ctx->split_opts = split_opts;
19761983
ctx->changed_paths = flags & COMMIT_GRAPH_WRITE_BLOOM_FILTERS ? 1 : 0;
19771984
ctx->total_bloom_filter_data_size = 0;
1985+
ctx->no_input = flags & COMMIT_GRAPH_WRITE_NO_INPUT ? 1 : 0;
19781986

19791987
if (ctx->split) {
19801988
struct commit_graph *g;
@@ -2034,7 +2042,7 @@ int write_commit_graph(struct object_directory *odb,
20342042
goto cleanup;
20352043
}
20362044

2037-
if (!pack_indexes && !commit_hex) {
2045+
if (!ctx->no_input && !pack_indexes && !commit_hex) {
20382046
ctx->order_by_pack = 1;
20392047
fill_oids_from_all_packs(ctx);
20402048
}
@@ -2060,7 +2068,7 @@ int write_commit_graph(struct object_directory *odb,
20602068
goto cleanup;
20612069
}
20622070

2063-
if (!ctx->commits.nr)
2071+
if (!ctx->commits.nr && (!ctx->split_opts || ctx->split_opts->flags != COMMIT_GRAPH_SPLIT_MERGE_REQUIRED))
20642072
goto cleanup;
20652073

20662074
if (ctx->split) {

commit-graph.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,13 +86,21 @@ enum commit_graph_write_flags {
8686
COMMIT_GRAPH_WRITE_SPLIT = (1 << 2),
8787
/* Make sure that each OID in the input is a valid commit OID. */
8888
COMMIT_GRAPH_WRITE_CHECK_OIDS = (1 << 3),
89-
COMMIT_GRAPH_WRITE_BLOOM_FILTERS = (1 << 4),
89+
COMMIT_GRAPH_WRITE_NO_INPUT = (1 << 4),
90+
COMMIT_GRAPH_WRITE_BLOOM_FILTERS = (1 << 5),
91+
};
92+
93+
enum commit_graph_split_flags {
94+
COMMIT_GRAPH_SPLIT_MERGE_AUTO = 0,
95+
COMMIT_GRAPH_SPLIT_MERGE_REQUIRED = 1,
96+
COMMIT_GRAPH_SPLIT_MERGE_PROHIBITED = 2
9097
};
9198

9299
struct split_commit_graph_opts {
93100
int size_multiple;
94101
int max_commits;
95102
timestamp_t expire_time;
103+
enum commit_graph_split_flags flags;
96104
};
97105

98106
/*

t/t5318-commit-graph.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@ graph_git_behavior 'cleared graph, commit 8 vs merge 2' full commits/8 merge/2
229229

230230
test_expect_success 'build graph from latest pack with closure' '
231231
cd "$TRASH_DIRECTORY/full" &&
232-
cat new-idx | git commit-graph write --stdin-packs &&
232+
cat new-idx | git commit-graph write --input=stdin-packs &&
233233
test_path_is_file $objdir/info/commit-graph &&
234234
graph_read_expect "9" "extra_edges"
235235
'
@@ -242,7 +242,7 @@ test_expect_success 'build graph from commits with closure' '
242242
git tag -a -m "merge" tag/merge merge/2 &&
243243
git rev-parse tag/merge >commits-in &&
244244
git rev-parse merge/1 >>commits-in &&
245-
cat commits-in | git commit-graph write --stdin-commits &&
245+
cat commits-in | git commit-graph write --input=stdin-commits &&
246246
test_path_is_file $objdir/info/commit-graph &&
247247
graph_read_expect "6"
248248
'

0 commit comments

Comments
 (0)