5 #include "parse-options.h"
6 #include "commit-graph.h"
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>] [--file=<hash>]"),
11 N_("git commit-graph write [--object-dir <objdir>] [--set-latest] [--delete-expired]"),
15 static const char * const builtin_commit_graph_read_usage[] = {
16 N_("git commit-graph read [--object-dir <objdir>] [--file=<hash>]"),
20 static const char * const builtin_commit_graph_write_usage[] = {
21 N_("git commit-graph write [--object-dir <objdir>] [--set-latest] [--delete-expired]"),
25 static struct opts_commit_graph {
27 const char *graph_file;
32 static int graph_read(int argc, const char **argv)
34 struct commit_graph *graph = 0;
35 struct strbuf full_path = STRBUF_INIT;
37 static struct option builtin_commit_graph_read_options[] = {
38 { OPTION_STRING, 'o', "object-dir", &opts.obj_dir,
40 N_("The object directory to store the graph") },
41 { OPTION_STRING, 'H', "file", &opts.graph_file,
43 N_("The filename for a specific commit graph file in the object directory."),
44 PARSE_OPT_OPTARG, NULL, (intptr_t) "" },
48 argc = parse_options(argc, argv, NULL,
49 builtin_commit_graph_read_options,
50 builtin_commit_graph_read_usage, 0);
53 opts.obj_dir = get_object_directory();
56 die("no graph hash specified");
58 strbuf_addf(&full_path, "%s/info/%s", opts.obj_dir, opts.graph_file);
59 graph = load_commit_graph_one(full_path.buf);
62 die("graph file %s does not exist", full_path.buf);
64 printf("header: %08x %d %d %d %d\n",
65 ntohl(*(uint32_t*)graph->data),
66 *(unsigned char*)(graph->data + 4),
67 *(unsigned char*)(graph->data + 5),
68 *(unsigned char*)(graph->data + 6),
69 *(unsigned char*)(graph->data + 7));
70 printf("num_commits: %u\n", graph->num_commits);
73 if (graph->chunk_oid_fanout)
74 printf(" oid_fanout");
75 if (graph->chunk_oid_lookup)
76 printf(" oid_lookup");
77 if (graph->chunk_commit_data)
78 printf(" commit_metadata");
79 if (graph->chunk_large_edges)
80 printf(" large_edges");
86 static void set_latest_file(const char *obj_dir, const char *graph_file)
89 struct lock_file lk = LOCK_INIT;
90 char *latest_fname = get_graph_latest_filename(obj_dir);
92 fd = hold_lock_file_for_update(&lk, latest_fname, LOCK_DIE_ON_ERROR);
93 FREE_AND_NULL(latest_fname);
96 die_errno("unable to open graph-head");
98 write_in_full(fd, graph_file, strlen(graph_file));
99 commit_lock_file(&lk);
103 * To avoid race conditions and deleting graph files that are being
104 * used by other processes, look inside a pack directory for all files
105 * of the form "graph-<hash>.graph" that do not match the old or new
106 * graph hashes and delete them.
108 static void do_delete_expired(const char *obj_dir,
109 const char *old_graph_name,
110 const char *new_graph_name)
115 struct strbuf path = STRBUF_INIT;
117 strbuf_addf(&path, "%s/info", obj_dir);
118 dir = opendir(path.buf);
121 error_errno("unable to open object pack directory: %s",
126 strbuf_addch(&path, '/');
127 dirnamelen = path.len;
128 while ((de = readdir(dir)) != NULL) {
131 if (is_dot_or_dotdot(de->d_name))
134 strbuf_setlen(&path, dirnamelen);
135 strbuf_addstr(&path, de->d_name);
138 if (strip_suffix_mem(path.buf, &base_len, ".graph") &&
139 strcmp(new_graph_name, de->d_name) &&
140 (!old_graph_name || strcmp(old_graph_name, de->d_name)) &&
141 remove_path(path.buf))
142 die("failed to remove path %s", path.buf);
145 strbuf_release(&path);
148 static int graph_write(int argc, const char **argv)
151 char *old_graph_name;
153 static struct option builtin_commit_graph_write_options[] = {
154 { OPTION_STRING, 'o', "object-dir", &opts.obj_dir,
156 N_("The object directory to store the graph") },
157 OPT_BOOL('u', "set-latest", &opts.set_latest,
158 N_("update graph-head to written graph file")),
159 OPT_BOOL('d', "delete-expired", &opts.delete_expired,
160 N_("delete expired head graph file")),
164 argc = parse_options(argc, argv, NULL,
165 builtin_commit_graph_write_options,
166 builtin_commit_graph_write_usage, 0);
169 opts.obj_dir = get_object_directory();
171 old_graph_name = get_graph_latest_contents(opts.obj_dir);
173 graph_name = write_commit_graph(opts.obj_dir);
177 set_latest_file(opts.obj_dir, graph_name);
179 if (opts.delete_expired)
180 do_delete_expired(opts.obj_dir,
184 printf("%s\n", graph_name);
185 FREE_AND_NULL(graph_name);
191 int cmd_commit_graph(int argc, const char **argv, const char *prefix)
193 static struct option builtin_commit_graph_options[] = {
194 { OPTION_STRING, 'o', "object-dir", &opts.obj_dir,
196 N_("The object directory to store the graph") },
200 if (argc == 2 && !strcmp(argv[1], "-h"))
201 usage_with_options(builtin_commit_graph_usage,
202 builtin_commit_graph_options);
204 git_config(git_default_config, NULL);
205 argc = parse_options(argc, argv, prefix,
206 builtin_commit_graph_options,
207 builtin_commit_graph_usage,
208 PARSE_OPT_STOP_AT_NON_OPTION);
211 if (!strcmp(argv[0], "read"))
212 return graph_read(argc, argv);
213 if (!strcmp(argv[0], "write"))
214 return graph_write(argc, argv);
217 usage_with_options(builtin_commit_graph_usage,
218 builtin_commit_graph_options);