commit-graph: add 'verify' subcommand

If the commit-graph file becomes corrupt, we need a way to verify that its contents match the object database. In the manner of 'git fsck' we will implement a 'git commit-graph verify' subcommand to report all issues with the file. Add the 'verify' subcommand to the 'commit-graph' builtin and its documentation. The subcommand is currently a no-op except for loading the commit-graph into memory, which may trigger run-time errors that would be caught by normal use. Add a simple test that ensures the command returns a zero error code. If no commit-graph file exists, this is an acceptable state. Do not report any errors. Helped-by: Ramsay Jones <ramsay@ramsayjones.plus.com> Signed-off-by: Derrick Stolee <dstolee@microsoft.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Derrick Stolee committed Jun 27, 2018 at 09:24 UTC 283e68c72f49e6cfbae53cb5547d5b399ed25d1a
5 files changed +81
Documentation/git-commit-graph.txt
+6
@@ -10,6 +10,7 @@ SYNOPSIS
10 --------
11 [verse]
12 'git commit-graph read' [--object-dir <dir>]
13 +'git commit-graph verify' [--object-dir <dir>]
14 'git commit-graph write' <options> [--object-dir <dir>]
15
16
@@ -52,6 +53,11 @@ existing commit-graph file.
53 Read a graph file given by the commit-graph file and output basic
54 details about the graph file. Used for debugging purposes.
55
56 +'verify'::
57 +
58 +Read the commit-graph file and verify its contents against the object
59 +database. Used to check for corrupted data.
60 +
61
62 EXAMPLES
63 --------
builtin/commit-graph.c
+39
@@ -3,15 +3,22 @@
3 #include "dir.h"
4 #include "lockfile.h"
5 #include "parse-options.h"
6 +#include "repository.h"
7 #include "commit-graph.h"
8
9 static char const * const builtin_commit_graph_usage[] = {
10 N_("git commit-graph [--object-dir <objdir>]"),
11 N_("git commit-graph read [--object-dir <objdir>]"),
12 + N_("git commit-graph verify [--object-dir <objdir>]"),
13 N_("git commit-graph write [--object-dir <objdir>] [--append] [--stdin-packs|--stdin-commits]"),
14 NULL
15 };
16
17 +static const char * const builtin_commit_graph_verify_usage[] = {
18 + N_("git commit-graph verify [--object-dir <objdir>]"),
19 + NULL
20 +};
21 +
22 static const char * const builtin_commit_graph_read_usage[] = {
23 N_("git commit-graph read [--object-dir <objdir>]"),
24 NULL
@@ -29,6 +36,36 @@ static struct opts_commit_graph {
36 int append;
37 } opts;
38
39 +
40 +static int graph_verify(int argc, const char **argv)
41 +{
42 + struct commit_graph *graph = NULL;
43 + char *graph_name;
44 +
45 + static struct option builtin_commit_graph_verify_options[] = {
46 + OPT_STRING(0, "object-dir", &opts.obj_dir,
47 + N_("dir"),
48 + N_("The object directory to store the graph")),
49 + OPT_END(),
50 + };
51 +
52 + argc = parse_options(argc, argv, NULL,
53 + builtin_commit_graph_verify_options,
54 + builtin_commit_graph_verify_usage, 0);
55 +
56 + if (!opts.obj_dir)
57 + opts.obj_dir = get_object_directory();
58 +
59 + graph_name = get_commit_graph_filename(opts.obj_dir);
60 + graph = load_commit_graph_one(graph_name);
61 + FREE_AND_NULL(graph_name);
62 +
63 + if (!graph)
64 + return 0;
65 +
66 + return verify_commit_graph(the_repository, graph);
67 +}
68 +
69 static int graph_read(int argc, const char **argv)
70 {
71 struct commit_graph *graph = NULL;
@@ -165,6 +202,8 @@ int cmd_commit_graph(int argc, const char **argv, const char *prefix)
202 if (argc > 0) {
203 if (!strcmp(argv[0], "read"))
204 return graph_read(argc, argv);
205 + if (!strcmp(argv[0], "verify"))
206 + return graph_verify(argc, argv);
207 if (!strcmp(argv[0], "write"))
208 return graph_write(argc, argv);
209 }
commit-graph.c
+23
@@ -827,3 +827,26 @@ void write_commit_graph(const char *obj_dir,
827 oids.alloc = 0;
828 oids.nr = 0;
829 }
830 +
831 +static int verify_commit_graph_error;
832 +
833 +static void graph_report(const char *fmt, ...)
834 +{
835 + va_list ap;
836 +
837 + verify_commit_graph_error = 1;
838 + va_start(ap, fmt);
839 + vfprintf(stderr, fmt, ap);
840 + fprintf(stderr, "\n");
841 + va_end(ap);
842 +}
843 +
844 +int verify_commit_graph(struct repository *r, struct commit_graph *g)
845 +{
846 + if (!g) {
847 + graph_report("no commit-graph file loaded");
848 + return 1;
849 + }
850 +
851 + return verify_commit_graph_error;
852 +}
commit-graph.h
+3
@@ -2,6 +2,7 @@
2 #define COMMIT_GRAPH_H
3
4 #include "git-compat-util.h"
5 +#include "repository.h"
6
7 char *get_commit_graph_filename(const char *obj_dir);
8
@@ -53,4 +54,6 @@ void write_commit_graph(const char *obj_dir,
54 int nr_commits,
55 int append);
56
57 +int verify_commit_graph(struct repository *r, struct commit_graph *g);
58 +
59 #endif
t/t5318-commit-graph.sh
+10
@@ -11,6 +11,11 @@ test_expect_success 'setup full repo' '
11 objdir=".git/objects"
12 '
13
14 +test_expect_success 'verify graph with no graph file' '
15 + cd "$TRASH_DIRECTORY/full" &&
16 + git commit-graph verify
17 +'
18 +
19 test_expect_success 'write graph with no packs' '
20 cd "$TRASH_DIRECTORY/full" &&
21 git commit-graph write --object-dir . &&
@@ -230,4 +235,9 @@ test_expect_success 'perform fast-forward merge in full repo' '
235 test_cmp expect output
236 '
237
238 +test_expect_success 'git commit-graph verify' '
239 + cd "$TRASH_DIRECTORY/full" &&
240 + git commit-graph verify >output
241 +'
242 +
243 test_done