Merge branch 'dl/complete-rebase-onto'
[git] / builtin / commit-graph.c
1 #include "builtin.h"
2 #include "config.h"
3 #include "dir.h"
4 #include "lockfile.h"
5 #include "parse-options.h"
6 #include "repository.h"
7 #include "commit-graph.h"
8 #include "object-store.h"
9
10 static char const * const builtin_commit_graph_usage[] = {
11         N_("git commit-graph read [--object-dir <objdir>]"),
12         N_("git commit-graph verify [--object-dir <objdir>] [--shallow] [--[no-]progress]"),
13         N_("git commit-graph write [--object-dir <objdir>] [--append|--split] [--reachable|--stdin-packs|--stdin-commits] [--[no-]progress] <split options>"),
14         NULL
15 };
16
17 static const char * const builtin_commit_graph_verify_usage[] = {
18         N_("git commit-graph verify [--object-dir <objdir>] [--shallow] [--[no-]progress]"),
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
25 };
26
27 static const char * const builtin_commit_graph_write_usage[] = {
28         N_("git commit-graph write [--object-dir <objdir>] [--append|--split] [--reachable|--stdin-packs|--stdin-commits] [--[no-]progress] <split options>"),
29         NULL
30 };
31
32 static struct opts_commit_graph {
33         const char *obj_dir;
34         int reachable;
35         int stdin_packs;
36         int stdin_commits;
37         int append;
38         int split;
39         int shallow;
40         int progress;
41 } opts;
42
43 static int graph_verify(int argc, const char **argv)
44 {
45         struct commit_graph *graph = NULL;
46         char *graph_name;
47         int open_ok;
48         int fd;
49         struct stat st;
50         int flags = 0;
51
52         static struct option builtin_commit_graph_verify_options[] = {
53                 OPT_STRING(0, "object-dir", &opts.obj_dir,
54                            N_("dir"),
55                            N_("The object directory to store the graph")),
56                 OPT_BOOL(0, "shallow", &opts.shallow,
57                          N_("if the commit-graph is split, only verify the tip file")),
58                 OPT_BOOL(0, "progress", &opts.progress, N_("force progress reporting")),
59                 OPT_END(),
60         };
61
62         trace2_cmd_mode("verify");
63
64         opts.progress = isatty(2);
65         argc = parse_options(argc, argv, NULL,
66                              builtin_commit_graph_verify_options,
67                              builtin_commit_graph_verify_usage, 0);
68
69         if (!opts.obj_dir)
70                 opts.obj_dir = get_object_directory();
71         if (opts.shallow)
72                 flags |= COMMIT_GRAPH_VERIFY_SHALLOW;
73         if (opts.progress)
74                 flags |= COMMIT_GRAPH_WRITE_PROGRESS;
75
76         graph_name = get_commit_graph_filename(opts.obj_dir);
77         open_ok = open_commit_graph(graph_name, &fd, &st);
78         if (!open_ok && errno != ENOENT)
79                 die_errno(_("Could not open commit-graph '%s'"), graph_name);
80
81         FREE_AND_NULL(graph_name);
82
83         if (open_ok)
84                 graph = load_commit_graph_one_fd_st(fd, &st);
85          else
86                 graph = read_commit_graph_one(the_repository, opts.obj_dir);
87
88         /* Return failure if open_ok predicted success */
89         if (!graph)
90                 return !!open_ok;
91
92         UNLEAK(graph);
93         return verify_commit_graph(the_repository, graph, flags);
94 }
95
96 static int graph_read(int argc, const char **argv)
97 {
98         struct commit_graph *graph = NULL;
99         char *graph_name;
100         int open_ok;
101         int fd;
102         struct stat st;
103
104         static struct option builtin_commit_graph_read_options[] = {
105                 OPT_STRING(0, "object-dir", &opts.obj_dir,
106                         N_("dir"),
107                         N_("The object directory to store the graph")),
108                 OPT_END(),
109         };
110
111         trace2_cmd_mode("read");
112
113         argc = parse_options(argc, argv, NULL,
114                              builtin_commit_graph_read_options,
115                              builtin_commit_graph_read_usage, 0);
116
117         if (!opts.obj_dir)
118                 opts.obj_dir = get_object_directory();
119
120         graph_name = get_commit_graph_filename(opts.obj_dir);
121
122         open_ok = open_commit_graph(graph_name, &fd, &st);
123         if (!open_ok)
124                 die_errno(_("Could not open commit-graph '%s'"), graph_name);
125
126         graph = load_commit_graph_one_fd_st(fd, &st);
127         if (!graph)
128                 return 1;
129
130         FREE_AND_NULL(graph_name);
131
132         printf("header: %08x %d %d %d %d\n",
133                 ntohl(*(uint32_t*)graph->data),
134                 *(unsigned char*)(graph->data + 4),
135                 *(unsigned char*)(graph->data + 5),
136                 *(unsigned char*)(graph->data + 6),
137                 *(unsigned char*)(graph->data + 7));
138         printf("num_commits: %u\n", graph->num_commits);
139         printf("chunks:");
140
141         if (graph->chunk_oid_fanout)
142                 printf(" oid_fanout");
143         if (graph->chunk_oid_lookup)
144                 printf(" oid_lookup");
145         if (graph->chunk_commit_data)
146                 printf(" commit_metadata");
147         if (graph->chunk_extra_edges)
148                 printf(" extra_edges");
149         printf("\n");
150
151         UNLEAK(graph);
152
153         return 0;
154 }
155
156 extern int read_replace_refs;
157 static struct split_commit_graph_opts split_opts;
158
159 static int graph_write(int argc, const char **argv)
160 {
161         struct string_list *pack_indexes = NULL;
162         struct string_list *commit_hex = NULL;
163         struct string_list lines;
164         int result = 0;
165         enum commit_graph_write_flags flags = 0;
166
167         static struct option builtin_commit_graph_write_options[] = {
168                 OPT_STRING(0, "object-dir", &opts.obj_dir,
169                         N_("dir"),
170                         N_("The object directory to store the graph")),
171                 OPT_BOOL(0, "reachable", &opts.reachable,
172                         N_("start walk at all refs")),
173                 OPT_BOOL(0, "stdin-packs", &opts.stdin_packs,
174                         N_("scan pack-indexes listed by stdin for commits")),
175                 OPT_BOOL(0, "stdin-commits", &opts.stdin_commits,
176                         N_("start walk at commits listed by stdin")),
177                 OPT_BOOL(0, "append", &opts.append,
178                         N_("include all commits already in the commit-graph file")),
179                 OPT_BOOL(0, "progress", &opts.progress, N_("force progress reporting")),
180                 OPT_BOOL(0, "split", &opts.split,
181                         N_("allow writing an incremental commit-graph file")),
182                 OPT_INTEGER(0, "max-commits", &split_opts.max_commits,
183                         N_("maximum number of commits in a non-base split commit-graph")),
184                 OPT_INTEGER(0, "size-multiple", &split_opts.size_multiple,
185                         N_("maximum ratio between two levels of a split commit-graph")),
186                 OPT_EXPIRY_DATE(0, "expire-time", &split_opts.expire_time,
187                         N_("maximum number of commits in a non-base split commit-graph")),
188                 OPT_END(),
189         };
190
191         opts.progress = isatty(2);
192         split_opts.size_multiple = 2;
193         split_opts.max_commits = 0;
194         split_opts.expire_time = 0;
195
196         trace2_cmd_mode("write");
197
198         argc = parse_options(argc, argv, NULL,
199                              builtin_commit_graph_write_options,
200                              builtin_commit_graph_write_usage, 0);
201
202         if (opts.reachable + opts.stdin_packs + opts.stdin_commits > 1)
203                 die(_("use at most one of --reachable, --stdin-commits, or --stdin-packs"));
204         if (!opts.obj_dir)
205                 opts.obj_dir = get_object_directory();
206         if (opts.append)
207                 flags |= COMMIT_GRAPH_WRITE_APPEND;
208         if (opts.split)
209                 flags |= COMMIT_GRAPH_WRITE_SPLIT;
210         if (opts.progress)
211                 flags |= COMMIT_GRAPH_WRITE_PROGRESS;
212
213         read_replace_refs = 0;
214
215         if (opts.reachable) {
216                 if (write_commit_graph_reachable(opts.obj_dir, flags, &split_opts))
217                         return 1;
218                 return 0;
219         }
220
221         string_list_init(&lines, 0);
222         if (opts.stdin_packs || opts.stdin_commits) {
223                 struct strbuf buf = STRBUF_INIT;
224
225                 while (strbuf_getline(&buf, stdin) != EOF)
226                         string_list_append(&lines, strbuf_detach(&buf, NULL));
227
228                 if (opts.stdin_packs)
229                         pack_indexes = &lines;
230                 if (opts.stdin_commits) {
231                         commit_hex = &lines;
232                         flags |= COMMIT_GRAPH_WRITE_CHECK_OIDS;
233                 }
234
235                 UNLEAK(buf);
236         }
237
238         if (write_commit_graph(opts.obj_dir,
239                                pack_indexes,
240                                commit_hex,
241                                flags,
242                                &split_opts))
243                 result = 1;
244
245         UNLEAK(lines);
246         return result;
247 }
248
249 int cmd_commit_graph(int argc, const char **argv, const char *prefix)
250 {
251         static struct option builtin_commit_graph_options[] = {
252                 OPT_STRING(0, "object-dir", &opts.obj_dir,
253                         N_("dir"),
254                         N_("The object directory to store the graph")),
255                 OPT_END(),
256         };
257
258         if (argc == 2 && !strcmp(argv[1], "-h"))
259                 usage_with_options(builtin_commit_graph_usage,
260                                    builtin_commit_graph_options);
261
262         git_config(git_default_config, NULL);
263         argc = parse_options(argc, argv, prefix,
264                              builtin_commit_graph_options,
265                              builtin_commit_graph_usage,
266                              PARSE_OPT_STOP_AT_NON_OPTION);
267
268         save_commit_buffer = 0;
269
270         if (argc > 0) {
271                 if (!strcmp(argv[0], "read"))
272                         return graph_read(argc, argv);
273                 if (!strcmp(argv[0], "verify"))
274                         return graph_verify(argc, argv);
275                 if (!strcmp(argv[0], "write"))
276                         return graph_write(argc, argv);
277         }
278
279         usage_with_options(builtin_commit_graph_usage,
280                            builtin_commit_graph_options);
281 }