Skip to content

Commit b9947e4

Browse files
committed
Merge branch 'tb/commit-graph-split-merge' into pu
* 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 1bb6b90 + 2309b5b commit b9947e4

File tree

6 files changed

+239
-95
lines changed

6 files changed

+239
-95
lines changed

Documentation/git-commit-graph.txt

Lines changed: 34 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -39,29 +39,42 @@ 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 commits specified:
43+
* With the `--input=stdin-packs` option, generate the new commit graph
44+
by walking objects only in the specified pack-indexes. (Cannot be
45+
combined with `--input=stdin-commits` or `--input=reachable`.)
4346
+
44-
With the `--stdin-packs` option, generate the new commit graph by
45-
walking objects only in the specified pack-indexes. (Cannot be combined
46-
with `--stdin-commits` or `--reachable`.)
47-
+
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
47+
* With the `--input=stdin-commits` option, generate the new commit graph
48+
by walking commits starting at the commits specified in stdin as a list
5049
of OIDs in hex, one OID per line. (Cannot be combined with
51-
`--stdin-packs` or `--reachable`.)
50+
`--input=stdin-packs` or `--input=reachable`.)
51+
+
52+
* With the `--input=reachable` option, generate the new commit graph by
53+
walking commits starting at all refs. (Cannot be combined with
54+
`--input=stdin-commits` or `--input=stdin-packs`.)
5255
+
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`.)
56+
* With the `--input=append` option, include all commits that are present
57+
in the existing commit-graph file.
5658
+
57-
With the `--append` option, include all commits that are present in the
58-
existing commit-graph file.
59+
* With the `--input=none` option, behave as if `input=append` were
60+
given, but do not walk other packs to find additional commits.
61+
62+
If none of the above options are given, then commits found in
63+
packfiles are specified.
5964
+
60-
With the `--split` option, write the commit-graph as a chain of multiple
61-
commit-graph files stored in `<dir>/info/commit-graphs`. The new commits
62-
not already in the commit-graph are added in a new "tip" file. This file
63-
is merged with the existing file if the following merge conditions are
64-
met:
65+
With the `--split[=<strategy>]` option, write the commit-graph as a
66+
chain of multiple commit-graph files stored in
67+
`<dir>/info/commit-graphs`. Commit-graph layers are merged based on the
68+
strategy and other splitting options. The new commits not already in the
69+
commit-graph are added in a new "tip" file. This file is merged with the
70+
existing file if the following merge conditions are met:
71+
* If `--split=merge-always` is specified, then a merge is always
72+
conducted, and the remaining options are ignored. Conversely, if
73+
`--split=no-merge` is specified, a merge is never performed, and the
74+
remaining options are ignored. A bare `--split` defers to the remaining
75+
options. (Note that merging a chain of commit graphs replaces the
76+
existing chain with a length-1 chain where the first and only
77+
incremental holds the entire graph).
6578
+
6679
* If `--size-multiple=<X>` is not specified, let `X` equal 2. If the new
6780
tip file would have `N` commits and the previous tip has `M` commits and
@@ -99,20 +112,20 @@ $ git commit-graph write
99112
using commits in `<pack-index>`.
100113
+
101114
------------------------------------------------
102-
$ echo <pack-index> | git commit-graph write --stdin-packs
115+
$ echo <pack-index> | git commit-graph write --input=stdin-packs
103116
------------------------------------------------
104117

105118
* Write a commit-graph file containing all reachable commits.
106119
+
107120
------------------------------------------------
108-
$ git show-ref -s | git commit-graph write --stdin-commits
121+
$ git show-ref -s | git commit-graph write --input=stdin-commits
109122
------------------------------------------------
110123

111124
* Write a commit-graph file containing all commits in the current
112125
commit-graph file along with those reachable from `HEAD`.
113126
+
114127
------------------------------------------------
115-
$ git rev-parse HEAD | git commit-graph write --stdin-commits --append
128+
$ git rev-parse HEAD | git commit-graph write --input=stdin-commits --input=append
116129
------------------------------------------------
117130

118131

builtin/commit-graph.c

Lines changed: 90 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@
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] [--[no-]progress] <split options>"),
12+
N_("git commit-graph write [--object-dir <objdir>] [--append] "
13+
"[--split[=<strategy>]] "
14+
"[--input=<reachable|stdin-packs|stdin-commits|none>] "
15+
"[--[no-]progress] <split options>"),
1316
NULL
1417
};
1518

@@ -19,21 +22,53 @@ static const char * const builtin_commit_graph_verify_usage[] = {
1922
};
2023

2124
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] [--[no-]progress] <split options>"),
25+
N_("git commit-graph write [--object-dir <objdir>] [--append] "
26+
"[--split[=<strategy>]] "
27+
"[--input=<reachable|stdin-packs|stdin-commits|none>] "
28+
"[--[no-]progress] <split options>"),
2329
NULL
2430
};
2531

32+
enum commit_graph_input {
33+
COMMIT_GRAPH_INPUT_REACHABLE = (1 << 1),
34+
COMMIT_GRAPH_INPUT_STDIN_PACKS = (1 << 2),
35+
COMMIT_GRAPH_INPUT_STDIN_COMMITS = (1 << 3),
36+
COMMIT_GRAPH_INPUT_APPEND = (1 << 4),
37+
COMMIT_GRAPH_INPUT_NONE = (1 << 5)
38+
};
39+
2640
static struct opts_commit_graph {
2741
const char *obj_dir;
28-
int reachable;
29-
int stdin_packs;
30-
int stdin_commits;
31-
int append;
42+
enum commit_graph_input input;
3243
int split;
3344
int shallow;
3445
int progress;
3546
} opts;
3647

48+
static int option_parse_input(const struct option *opt, const char *arg,
49+
int unset)
50+
{
51+
enum commit_graph_input *to = opt->value;
52+
if (unset || !strcmp(arg, "packs")) {
53+
*to = 0;
54+
return 0;
55+
}
56+
57+
if (!strcmp(arg, "reachable"))
58+
*to |= COMMIT_GRAPH_INPUT_REACHABLE;
59+
else if (!strcmp(arg, "stdin-packs"))
60+
*to |= COMMIT_GRAPH_INPUT_STDIN_PACKS;
61+
else if (!strcmp(arg, "stdin-commits"))
62+
*to |= COMMIT_GRAPH_INPUT_STDIN_COMMITS;
63+
else if (!strcmp(arg, "append"))
64+
*to |= COMMIT_GRAPH_INPUT_APPEND;
65+
else if (!strcmp(arg, "none"))
66+
*to |= (COMMIT_GRAPH_INPUT_APPEND | COMMIT_GRAPH_INPUT_NONE);
67+
else
68+
die(_("unrecognized --input source, %s"), arg);
69+
return 0;
70+
}
71+
3772
static struct object_directory *find_odb_or_die(struct repository *r,
3873
const char *obj_dir)
3974
{
@@ -101,6 +136,25 @@ static int graph_verify(int argc, const char **argv)
101136
extern int read_replace_refs;
102137
static struct split_commit_graph_opts split_opts;
103138

139+
static int write_option_parse_split(const struct option *opt, const char *arg,
140+
int unset)
141+
{
142+
enum commit_graph_split_flags *flags = opt->value;
143+
144+
opts.split = 1;
145+
if (!arg)
146+
return 0;
147+
148+
if (!strcmp(arg, "merge-all"))
149+
*flags = COMMIT_GRAPH_SPLIT_MERGE_REQUIRED;
150+
else if (!strcmp(arg, "no-merge"))
151+
*flags = COMMIT_GRAPH_SPLIT_MERGE_PROHIBITED;
152+
else
153+
die(_("unrecognized --split argument, %s"), arg);
154+
155+
return 0;
156+
}
157+
104158
static int graph_write(int argc, const char **argv)
105159
{
106160
struct string_list *pack_indexes = NULL;
@@ -114,17 +168,26 @@ static int graph_write(int argc, const char **argv)
114168
OPT_STRING(0, "object-dir", &opts.obj_dir,
115169
N_("dir"),
116170
N_("The object directory to store the graph")),
117-
OPT_BOOL(0, "reachable", &opts.reachable,
118-
N_("start walk at all refs")),
119-
OPT_BOOL(0, "stdin-packs", &opts.stdin_packs,
120-
N_("scan pack-indexes listed by stdin for commits")),
121-
OPT_BOOL(0, "stdin-commits", &opts.stdin_commits,
122-
N_("start walk at commits listed by stdin")),
123-
OPT_BOOL(0, "append", &opts.append,
124-
N_("include all commits already in the commit-graph file")),
171+
OPT_CALLBACK(0, "input", &opts.input, NULL,
172+
N_("include commits from this source in the graph"),
173+
option_parse_input),
174+
OPT_BIT(0, "reachable", &opts.input,
175+
N_("start walk at all refs"),
176+
COMMIT_GRAPH_INPUT_REACHABLE),
177+
OPT_BIT(0, "stdin-packs", &opts.input,
178+
N_("scan pack-indexes listed by stdin for commits"),
179+
COMMIT_GRAPH_INPUT_STDIN_PACKS),
180+
OPT_BIT(0, "stdin-commits", &opts.input,
181+
N_("start walk at commits listed by stdin"),
182+
COMMIT_GRAPH_INPUT_STDIN_COMMITS),
183+
OPT_BIT(0, "append", &opts.input,
184+
N_("include all commits already in the commit-graph file"),
185+
COMMIT_GRAPH_INPUT_APPEND),
125186
OPT_BOOL(0, "progress", &opts.progress, N_("force progress reporting")),
126-
OPT_BOOL(0, "split", &opts.split,
127-
N_("allow writing an incremental commit-graph file")),
187+
OPT_CALLBACK_F(0, "split", &split_opts.flags, NULL,
188+
N_("allow writing an incremental commit-graph file"),
189+
PARSE_OPT_OPTARG | PARSE_OPT_NONEG,
190+
write_option_parse_split),
128191
OPT_INTEGER(0, "max-commits", &split_opts.max_commits,
129192
N_("maximum number of commits in a non-base split commit-graph")),
130193
OPT_INTEGER(0, "size-multiple", &split_opts.size_multiple,
@@ -145,12 +208,16 @@ static int graph_write(int argc, const char **argv)
145208
builtin_commit_graph_write_options,
146209
builtin_commit_graph_write_usage, 0);
147210

148-
if (opts.reachable + opts.stdin_packs + opts.stdin_commits > 1)
149-
die(_("use at most one of --reachable, --stdin-commits, or --stdin-packs"));
211+
if ((!!(opts.input & COMMIT_GRAPH_INPUT_REACHABLE) +
212+
!!(opts.input & COMMIT_GRAPH_INPUT_STDIN_PACKS) +
213+
!!(opts.input & COMMIT_GRAPH_INPUT_STDIN_COMMITS)) > 1)
214+
die(_("use at most one of --input=reachable, --input=stdin-commits, or --input=stdin-packs"));
150215
if (!opts.obj_dir)
151216
opts.obj_dir = get_object_directory();
152-
if (opts.append)
217+
if (opts.input & COMMIT_GRAPH_INPUT_APPEND)
153218
flags |= COMMIT_GRAPH_WRITE_APPEND;
219+
if (opts.input & COMMIT_GRAPH_INPUT_NONE)
220+
flags |= COMMIT_GRAPH_WRITE_NO_INPUT;
154221
if (opts.split)
155222
flags |= COMMIT_GRAPH_WRITE_SPLIT;
156223
if (opts.progress)
@@ -159,22 +226,22 @@ static int graph_write(int argc, const char **argv)
159226
read_replace_refs = 0;
160227
odb = find_odb_or_die(the_repository, opts.obj_dir);
161228

162-
if (opts.reachable) {
229+
if (opts.input & COMMIT_GRAPH_INPUT_REACHABLE) {
163230
if (write_commit_graph_reachable(odb, flags, &split_opts))
164231
return 1;
165232
return 0;
166233
}
167234

168235
string_list_init(&lines, 0);
169-
if (opts.stdin_packs || opts.stdin_commits) {
236+
if (opts.input & (COMMIT_GRAPH_INPUT_STDIN_PACKS | COMMIT_GRAPH_INPUT_STDIN_COMMITS)) {
170237
struct strbuf buf = STRBUF_INIT;
171238

172239
while (strbuf_getline(&buf, stdin) != EOF)
173240
string_list_append(&lines, strbuf_detach(&buf, NULL));
174241

175-
if (opts.stdin_packs)
242+
if (opts.input & COMMIT_GRAPH_INPUT_STDIN_PACKS)
176243
pack_indexes = &lines;
177-
if (opts.stdin_commits) {
244+
if (opts.input & COMMIT_GRAPH_INPUT_STDIN_COMMITS) {
178245
commit_hex = &lines;
179246
flags |= COMMIT_GRAPH_WRITE_CHECK_OIDS;
180247
}

commit-graph.c

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -808,7 +808,8 @@ struct write_commit_graph_context {
808808
unsigned append:1,
809809
report_progress:1,
810810
split:1,
811-
check_oids:1;
811+
check_oids:1,
812+
no_input:1;
812813

813814
const struct split_commit_graph_opts *split_opts;
814815
};
@@ -1565,15 +1566,18 @@ static void split_graph_merge_strategy(struct write_commit_graph_context *ctx)
15651566
num_commits = ctx->commits.nr;
15661567
ctx->num_commit_graphs_after = ctx->num_commit_graphs_before + 1;
15671568

1568-
while (g && (g->num_commits <= size_mult * num_commits ||
1569-
(max_commits && num_commits > max_commits))) {
1570-
if (g->odb != ctx->odb)
1571-
break;
1569+
if (ctx->split_opts->flags != COMMIT_GRAPH_SPLIT_MERGE_PROHIBITED) {
1570+
while (g && (g->num_commits <= size_mult * num_commits ||
1571+
(max_commits && num_commits > max_commits) ||
1572+
(ctx->split_opts->flags == COMMIT_GRAPH_SPLIT_MERGE_REQUIRED))) {
1573+
if (g->odb != ctx->odb)
1574+
break;
15721575

1573-
num_commits += g->num_commits;
1574-
g = g->base_graph;
1576+
num_commits += g->num_commits;
1577+
g = g->base_graph;
15751578

1576-
ctx->num_commit_graphs_after--;
1579+
ctx->num_commit_graphs_after--;
1580+
}
15771581
}
15781582

15791583
ctx->new_base_graph = g;
@@ -1799,6 +1803,7 @@ int write_commit_graph(struct object_directory *odb,
17991803
ctx->split = flags & COMMIT_GRAPH_WRITE_SPLIT ? 1 : 0;
18001804
ctx->check_oids = flags & COMMIT_GRAPH_WRITE_CHECK_OIDS ? 1 : 0;
18011805
ctx->split_opts = split_opts;
1806+
ctx->no_input = flags & COMMIT_GRAPH_WRITE_NO_INPUT ? 1 : 0;
18021807

18031808
if (ctx->split) {
18041809
struct commit_graph *g;
@@ -1857,7 +1862,7 @@ int write_commit_graph(struct object_directory *odb,
18571862
goto cleanup;
18581863
}
18591864

1860-
if (!pack_indexes && !commit_hex)
1865+
if (!ctx->no_input && !pack_indexes && !commit_hex)
18611866
fill_oids_from_all_packs(ctx);
18621867

18631868
close_reachable(ctx);
@@ -1881,7 +1886,7 @@ int write_commit_graph(struct object_directory *odb,
18811886
goto cleanup;
18821887
}
18831888

1884-
if (!ctx->commits.nr)
1889+
if (!ctx->commits.nr && (!ctx->split || ctx->split_opts->flags != COMMIT_GRAPH_SPLIT_MERGE_REQUIRED))
18851890
goto cleanup;
18861891

18871892
if (ctx->split) {

commit-graph.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,13 +81,21 @@ enum commit_graph_write_flags {
8181
COMMIT_GRAPH_WRITE_PROGRESS = (1 << 1),
8282
COMMIT_GRAPH_WRITE_SPLIT = (1 << 2),
8383
/* Make sure that each OID in the input is a valid commit OID. */
84-
COMMIT_GRAPH_WRITE_CHECK_OIDS = (1 << 3)
84+
COMMIT_GRAPH_WRITE_CHECK_OIDS = (1 << 3),
85+
COMMIT_GRAPH_WRITE_NO_INPUT = (1 << 4)
86+
};
87+
88+
enum commit_graph_split_flags {
89+
COMMIT_GRAPH_SPLIT_UNSPECIFIED = 0,
90+
COMMIT_GRAPH_SPLIT_MERGE_REQUIRED = 1,
91+
COMMIT_GRAPH_SPLIT_MERGE_PROHIBITED = 2
8592
};
8693

8794
struct split_commit_graph_opts {
8895
int size_multiple;
8996
int max_commits;
9097
timestamp_t expire_time;
98+
enum commit_graph_split_flags flags;
9199
};
92100

93101
/*

0 commit comments

Comments
 (0)