commit-graph: build graph from starting commits
Teach git-commit-graph to read commits from stdin when the --stdin-commits flag is specified. Commits reachable from these commits are added to the graph. This is a much faster way to construct the graph than inspecting all packed objects, but is restricted to known tips. For the Linux repository, 700,000+ commits were added to the graph file starting from 'master' in 7-9 seconds, depending on the number of packfiles in the repo (1, 24, or 120). Signed-off-by: Derrick Stolee <dstolee@microsoft.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Derrick Stolee committed
Apr 10, 2018 at 08:56 UTC
3d5df01b5e42416a59e857135e932bbdd8cc3ba0
5 files changed
+75
-10
Documentation/git-commit-graph.txt
+13
-1
@@ -36,7 +36,13 @@ COMMANDS
36
Write a commit graph file based on the commits found in packfiles.
37
+
38
With the `--stdin-packs` option, generate the new commit graph by
39
-walking objects only in the specified pack-indexes.
39
+walking objects only in the specified pack-indexes. (Cannot be combined
40
+with --stdin-commits.)
41
++
42
+With the `--stdin-commits` option, generate the new commit graph by
43
+walking commits starting at the commits specified in stdin as a list
44
+of OIDs in hex, one OID per line. (Cannot be combined with
45
+--stdin-packs.)
46
47
'read'::
48
@@ -60,6 +66,12 @@ $ git commit-graph write
66
$ echo <pack-index> | git commit-graph write --stdin-packs
67
------------------------------------------------
68
69
+* Write a graph file containing all reachable commits.
70
++
71
+------------------------------------------------
72
+$ git show-ref -s | git commit-graph write --stdin-commits
73
+------------------------------------------------
74
+
75
* Read basic information from the commit-graph file.
76
+
77
------------------------------------------------
builtin/commit-graph.c
+21
-6
@@ -8,7 +8,7 @@
8
static char const * const builtin_commit_graph_usage[] = {
9
N_("git commit-graph [--object-dir <objdir>]"),
10
N_("git commit-graph read [--object-dir <objdir>]"),
11
- N_("git commit-graph write [--object-dir <objdir>] [--stdin-packs]"),
11
+ N_("git commit-graph write [--object-dir <objdir>] [--stdin-packs|--stdin-commits]"),
12
NULL
13
};
14
@@ -18,13 +18,14 @@ static const char * const builtin_commit_graph_read_usage[] = {
18
};
19
20
static const char * const builtin_commit_graph_write_usage[] = {
21
- N_("git commit-graph write [--object-dir <objdir>] [--stdin-packs]"),
21
+ N_("git commit-graph write [--object-dir <objdir>] [--stdin-packs|--stdin-commits]"),
22
NULL
23
};
24
25
static struct opts_commit_graph {
26
const char *obj_dir;
27
int stdin_packs;
28
+ int stdin_commits;
29
} opts;
30
31
static int graph_read(int argc, const char **argv)
@@ -79,6 +80,8 @@ static int graph_write(int argc, const char **argv)
80
{
81
const char **pack_indexes = NULL;
82
int packs_nr = 0;
83
+ const char **commit_hex = NULL;
84
+ int commits_nr = 0;
85
const char **lines = NULL;
86
int lines_nr = 0;
87
int lines_alloc = 0;
@@ -89,6 +92,8 @@ static int graph_write(int argc, const char **argv)
92
N_("The object directory to store the graph")),
93
OPT_BOOL(0, "stdin-packs", &opts.stdin_packs,
94
N_("scan pack-indexes listed by stdin for commits")),
95
+ OPT_BOOL(0, "stdin-commits", &opts.stdin_commits,
96
+ N_("start walk at commits listed by stdin")),
97
OPT_END(),
98
};
99
@@ -96,10 +101,12 @@ static int graph_write(int argc, const char **argv)
101
builtin_commit_graph_write_options,
102
builtin_commit_graph_write_usage, 0);
103
104
+ if (opts.stdin_packs && opts.stdin_commits)
105
+ die(_("cannot use both --stdin-commits and --stdin-packs"));
106
if (!opts.obj_dir)
107
opts.obj_dir = get_object_directory();
108
102
- if (opts.stdin_packs) {
109
+ if (opts.stdin_packs || opts.stdin_commits) {
110
struct strbuf buf = STRBUF_INIT;
111
lines_nr = 0;
112
lines_alloc = 128;
@@ -110,13 +117,21 @@ static int graph_write(int argc, const char **argv)
117
lines[lines_nr++] = strbuf_detach(&buf, NULL);
118
}
119
113
- pack_indexes = lines;
114
- packs_nr = lines_nr;
120
+ if (opts.stdin_packs) {
121
+ pack_indexes = lines;
122
+ packs_nr = lines_nr;
123
+ }
124
+ if (opts.stdin_commits) {
125
+ commit_hex = lines;
126
+ commits_nr = lines_nr;
127
+ }
128
}
129
130
write_commit_graph(opts.obj_dir,
131
pack_indexes,
119
- packs_nr);
132
+ packs_nr,
133
+ commit_hex,
134
+ commits_nr);
135
136
return 0;
137
}
commit-graph.c
+25
-2
@@ -551,7 +551,9 @@ static void close_reachable(struct packed_oid_list *oids)
551
552
void write_commit_graph(const char *obj_dir,
553
const char **pack_indexes,
554
- int nr_packs)
554
+ int nr_packs,
555
+ const char **commit_hex,
556
+ int nr_commits)
557
{
558
struct packed_oid_list oids;
559
struct packed_commit_list commits;
@@ -591,7 +593,28 @@ void write_commit_graph(const char *obj_dir,
593
close_pack(p);
594
}
595
strbuf_release(&packname);
594
- } else
596
+ }
597
+
598
+ if (commit_hex) {
599
+ for (i = 0; i < nr_commits; i++) {
600
+ const char *end;
601
+ struct object_id oid;
602
+ struct commit *result;
603
+
604
+ if (commit_hex[i] && parse_oid_hex(commit_hex[i], &oid, &end))
605
+ continue;
606
+
607
+ result = lookup_commit_reference_gently(&oid, 1);
608
+
609
+ if (result) {
610
+ ALLOC_GROW(oids.list, oids.nr + 1, oids.alloc);
611
+ oidcpy(&oids.list[oids.nr], &(result->object.oid));
612
+ oids.nr++;
613
+ }
614
+ }
615
+ }
616
+
617
+ if (!pack_indexes && !commit_hex)
618
for_each_packed_object(add_packed_commits, &oids, 0);
619
620
close_reachable(&oids);
commit-graph.h
+3
-1
@@ -38,6 +38,8 @@ struct commit_graph *load_commit_graph_one(const char *graph_file);
38
39
void write_commit_graph(const char *obj_dir,
40
const char **pack_indexes,
41
- int nr_packs);
41
+ int nr_packs,
42
+ const char **commit_hex,
43
+ int nr_commits);
44
45
#endif
t/t5318-commit-graph.sh
+13
@@ -177,6 +177,19 @@ test_expect_success 'build graph from latest pack with closure' '
177
graph_git_behavior 'graph from pack, commit 8 vs merge 1' full commits/8 merge/1
178
graph_git_behavior 'graph from pack, commit 8 vs merge 2' full commits/8 merge/2
179
180
+test_expect_success 'build graph from commits with closure' '
181
+ cd "$TRASH_DIRECTORY/full" &&
182
+ git tag -a -m "merge" tag/merge merge/2 &&
183
+ git rev-parse tag/merge >commits-in &&
184
+ git rev-parse merge/1 >>commits-in &&
185
+ cat commits-in | git commit-graph write --stdin-commits &&
186
+ test_path_is_file $objdir/info/commit-graph &&
187
+ graph_read_expect "6"
188
+'
189
+
190
+graph_git_behavior 'graph from commits, commit 8 vs merge 1' full commits/8 merge/1
191
+graph_git_behavior 'graph from commits, commit 8 vs merge 2' full commits/8 merge/2
192
+
193
test_expect_success 'setup bare repo' '
194
cd "$TRASH_DIRECTORY" &&
195
git clone --bare --no-local full bare &&