2018-04-02 20:34:18 +00:00
|
|
|
#include "builtin.h"
|
|
|
|
#include "config.h"
|
2018-04-02 20:34:20 +00:00
|
|
|
#include "dir.h"
|
|
|
|
#include "lockfile.h"
|
2018-04-02 20:34:18 +00:00
|
|
|
#include "parse-options.h"
|
2018-06-27 13:24:32 +00:00
|
|
|
#include "repository.h"
|
2018-04-02 20:34:20 +00:00
|
|
|
#include "commit-graph.h"
|
2019-06-18 18:14:32 +00:00
|
|
|
#include "object-store.h"
|
2018-04-02 20:34:18 +00:00
|
|
|
|
|
|
|
static char const * const builtin_commit_graph_usage[] = {
|
2018-04-10 12:56:02 +00:00
|
|
|
N_("git commit-graph read [--object-dir <objdir>]"),
|
2019-08-26 16:29:58 +00:00
|
|
|
N_("git commit-graph verify [--object-dir <objdir>] [--shallow] [--[no-]progress]"),
|
|
|
|
N_("git commit-graph write [--object-dir <objdir>] [--append|--split] [--reachable|--stdin-packs|--stdin-commits] [--[no-]progress] <split options>"),
|
2018-04-02 20:34:20 +00:00
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
2018-06-27 13:24:32 +00:00
|
|
|
static const char * const builtin_commit_graph_verify_usage[] = {
|
2019-08-26 16:29:58 +00:00
|
|
|
N_("git commit-graph verify [--object-dir <objdir>] [--shallow] [--[no-]progress]"),
|
2018-06-27 13:24:32 +00:00
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
2018-04-10 12:56:02 +00:00
|
|
|
static const char * const builtin_commit_graph_read_usage[] = {
|
|
|
|
N_("git commit-graph read [--object-dir <objdir>]"),
|
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
2018-04-02 20:34:20 +00:00
|
|
|
static const char * const builtin_commit_graph_write_usage[] = {
|
2019-08-26 16:29:58 +00:00
|
|
|
N_("git commit-graph write [--object-dir <objdir>] [--append|--split] [--reachable|--stdin-packs|--stdin-commits] [--[no-]progress] <split options>"),
|
2018-04-02 20:34:18 +00:00
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct opts_commit_graph {
|
|
|
|
const char *obj_dir;
|
2018-06-27 13:24:45 +00:00
|
|
|
int reachable;
|
2018-04-10 12:56:06 +00:00
|
|
|
int stdin_packs;
|
2018-04-10 12:56:07 +00:00
|
|
|
int stdin_commits;
|
2018-04-10 12:56:08 +00:00
|
|
|
int append;
|
2019-06-18 18:14:28 +00:00
|
|
|
int split;
|
2019-06-18 18:14:32 +00:00
|
|
|
int shallow;
|
2019-08-26 16:29:58 +00:00
|
|
|
int progress;
|
2018-04-02 20:34:18 +00:00
|
|
|
} opts;
|
|
|
|
|
2018-06-27 13:24:32 +00:00
|
|
|
static int graph_verify(int argc, const char **argv)
|
|
|
|
{
|
|
|
|
struct commit_graph *graph = NULL;
|
|
|
|
char *graph_name;
|
2019-03-25 12:08:30 +00:00
|
|
|
int open_ok;
|
|
|
|
int fd;
|
|
|
|
struct stat st;
|
2019-06-18 18:14:32 +00:00
|
|
|
int flags = 0;
|
2018-06-27 13:24:32 +00:00
|
|
|
|
|
|
|
static struct option builtin_commit_graph_verify_options[] = {
|
|
|
|
OPT_STRING(0, "object-dir", &opts.obj_dir,
|
|
|
|
N_("dir"),
|
|
|
|
N_("The object directory to store the graph")),
|
2019-06-18 18:14:32 +00:00
|
|
|
OPT_BOOL(0, "shallow", &opts.shallow,
|
|
|
|
N_("if the commit-graph is split, only verify the tip file")),
|
2019-08-26 16:29:58 +00:00
|
|
|
OPT_BOOL(0, "progress", &opts.progress, N_("force progress reporting")),
|
2018-06-27 13:24:32 +00:00
|
|
|
OPT_END(),
|
|
|
|
};
|
|
|
|
|
2019-08-27 16:56:34 +00:00
|
|
|
trace2_cmd_mode("verify");
|
|
|
|
|
2019-08-26 16:29:58 +00:00
|
|
|
opts.progress = isatty(2);
|
2018-06-27 13:24:32 +00:00
|
|
|
argc = parse_options(argc, argv, NULL,
|
|
|
|
builtin_commit_graph_verify_options,
|
|
|
|
builtin_commit_graph_verify_usage, 0);
|
|
|
|
|
|
|
|
if (!opts.obj_dir)
|
|
|
|
opts.obj_dir = get_object_directory();
|
2019-06-18 18:14:32 +00:00
|
|
|
if (opts.shallow)
|
|
|
|
flags |= COMMIT_GRAPH_VERIFY_SHALLOW;
|
2019-08-26 16:29:58 +00:00
|
|
|
if (opts.progress)
|
|
|
|
flags |= COMMIT_GRAPH_WRITE_PROGRESS;
|
2018-06-27 13:24:32 +00:00
|
|
|
|
|
|
|
graph_name = get_commit_graph_filename(opts.obj_dir);
|
2019-03-25 12:08:30 +00:00
|
|
|
open_ok = open_commit_graph(graph_name, &fd, &st);
|
2019-06-18 18:14:32 +00:00
|
|
|
if (!open_ok && errno != ENOENT)
|
2019-03-25 12:08:32 +00:00
|
|
|
die_errno(_("Could not open commit-graph '%s'"), graph_name);
|
2019-06-18 18:14:32 +00:00
|
|
|
|
2018-06-27 13:24:32 +00:00
|
|
|
FREE_AND_NULL(graph_name);
|
|
|
|
|
2019-06-18 18:14:32 +00:00
|
|
|
if (open_ok)
|
|
|
|
graph = load_commit_graph_one_fd_st(fd, &st);
|
|
|
|
else
|
|
|
|
graph = read_commit_graph_one(the_repository, opts.obj_dir);
|
|
|
|
|
|
|
|
/* Return failure if open_ok predicted success */
|
2018-06-27 13:24:32 +00:00
|
|
|
if (!graph)
|
2019-06-18 18:14:32 +00:00
|
|
|
return !!open_ok;
|
2018-06-27 13:24:32 +00:00
|
|
|
|
2018-10-03 17:12:17 +00:00
|
|
|
UNLEAK(graph);
|
2019-06-18 18:14:32 +00:00
|
|
|
return verify_commit_graph(the_repository, graph, flags);
|
2018-06-27 13:24:32 +00:00
|
|
|
}
|
|
|
|
|
2018-04-10 12:56:02 +00:00
|
|
|
static int graph_read(int argc, const char **argv)
|
|
|
|
{
|
|
|
|
struct commit_graph *graph = NULL;
|
|
|
|
char *graph_name;
|
2019-03-25 12:08:30 +00:00
|
|
|
int open_ok;
|
|
|
|
int fd;
|
|
|
|
struct stat st;
|
2018-04-10 12:56:02 +00:00
|
|
|
|
|
|
|
static struct option builtin_commit_graph_read_options[] = {
|
|
|
|
OPT_STRING(0, "object-dir", &opts.obj_dir,
|
|
|
|
N_("dir"),
|
|
|
|
N_("The object directory to store the graph")),
|
|
|
|
OPT_END(),
|
|
|
|
};
|
|
|
|
|
2019-08-27 16:56:34 +00:00
|
|
|
trace2_cmd_mode("read");
|
|
|
|
|
2018-04-10 12:56:02 +00:00
|
|
|
argc = parse_options(argc, argv, NULL,
|
|
|
|
builtin_commit_graph_read_options,
|
|
|
|
builtin_commit_graph_read_usage, 0);
|
|
|
|
|
|
|
|
if (!opts.obj_dir)
|
|
|
|
opts.obj_dir = get_object_directory();
|
|
|
|
|
|
|
|
graph_name = get_commit_graph_filename(opts.obj_dir);
|
|
|
|
|
2019-03-25 12:08:30 +00:00
|
|
|
open_ok = open_commit_graph(graph_name, &fd, &st);
|
|
|
|
if (!open_ok)
|
|
|
|
die_errno(_("Could not open commit-graph '%s'"), graph_name);
|
|
|
|
|
2019-03-25 12:08:31 +00:00
|
|
|
graph = load_commit_graph_one_fd_st(fd, &st);
|
2018-10-03 17:12:17 +00:00
|
|
|
if (!graph)
|
2019-03-25 12:08:30 +00:00
|
|
|
return 1;
|
2018-06-27 13:24:27 +00:00
|
|
|
|
2018-04-10 12:56:02 +00:00
|
|
|
FREE_AND_NULL(graph_name);
|
|
|
|
|
|
|
|
printf("header: %08x %d %d %d %d\n",
|
|
|
|
ntohl(*(uint32_t*)graph->data),
|
|
|
|
*(unsigned char*)(graph->data + 4),
|
|
|
|
*(unsigned char*)(graph->data + 5),
|
|
|
|
*(unsigned char*)(graph->data + 6),
|
|
|
|
*(unsigned char*)(graph->data + 7));
|
|
|
|
printf("num_commits: %u\n", graph->num_commits);
|
|
|
|
printf("chunks:");
|
|
|
|
|
|
|
|
if (graph->chunk_oid_fanout)
|
|
|
|
printf(" oid_fanout");
|
|
|
|
if (graph->chunk_oid_lookup)
|
|
|
|
printf(" oid_lookup");
|
|
|
|
if (graph->chunk_commit_data)
|
|
|
|
printf(" commit_metadata");
|
commit-graph: rename "large edges" to "extra edges"
The optional 'Large Edge List' chunk of the commit graph file stores
parent information for commits with more than two parents, and the
names of most of the macros, variables, struct fields, and functions
related to this chunk contain the term "large edges", e.g.
write_graph_chunk_large_edges(). However, it's not a really great
term, as the edges to the second and subsequent parents stored in this
chunk are not any larger than the edges to the first and second
parents stored in the "main" 'Commit Data' chunk. It's the number of
edges, IOW number of parents, that is larger compared to non-merge and
"regular" two-parent merge commits. And indeed, two functions in
'commit-graph.c' have a local variable called 'num_extra_edges' that
refer to the same thing, and this "extra edges" term is much better at
describing these edges.
So let's rename all these references to "large edges" in macro,
variable, function, etc. names to "extra edges". There is a
GRAPH_OCTOPUS_EDGES_NEEDED macro as well; for the sake of consistency
rename it to GRAPH_EXTRA_EDGES_NEEDED.
We can do so safely without causing any incompatibility issues,
because the term "large edges" doesn't come up in the file format
itself in any form (the chunk's magic is {'E', 'D', 'G', 'E'}, there
is no 'L' in there), but only in the specification text. The string
"large edges", however, does come up in the output of 'git
commit-graph read' and in tests looking at its input, but that command
is explicitly documented as debugging aid, so we can change its output
and the affected tests safely.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-01-19 20:21:13 +00:00
|
|
|
if (graph->chunk_extra_edges)
|
|
|
|
printf(" extra_edges");
|
2018-04-10 12:56:02 +00:00
|
|
|
printf("\n");
|
|
|
|
|
2018-10-03 17:12:17 +00:00
|
|
|
UNLEAK(graph);
|
2018-07-11 22:42:40 +00:00
|
|
|
|
2018-04-10 12:56:02 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-08-20 18:24:27 +00:00
|
|
|
extern int read_replace_refs;
|
2019-06-18 18:14:32 +00:00
|
|
|
static struct split_commit_graph_opts split_opts;
|
2018-08-20 18:24:27 +00:00
|
|
|
|
2018-04-02 20:34:20 +00:00
|
|
|
static int graph_write(int argc, const char **argv)
|
|
|
|
{
|
2018-06-27 13:24:44 +00:00
|
|
|
struct string_list *pack_indexes = NULL;
|
|
|
|
struct string_list *commit_hex = NULL;
|
|
|
|
struct string_list lines;
|
2019-06-12 13:29:37 +00:00
|
|
|
int result = 0;
|
2019-08-26 16:29:58 +00:00
|
|
|
enum commit_graph_write_flags flags = 0;
|
2018-04-10 12:56:06 +00:00
|
|
|
|
2018-04-02 20:34:20 +00:00
|
|
|
static struct option builtin_commit_graph_write_options[] = {
|
|
|
|
OPT_STRING(0, "object-dir", &opts.obj_dir,
|
|
|
|
N_("dir"),
|
|
|
|
N_("The object directory to store the graph")),
|
2018-06-27 13:24:45 +00:00
|
|
|
OPT_BOOL(0, "reachable", &opts.reachable,
|
|
|
|
N_("start walk at all refs")),
|
2018-04-10 12:56:06 +00:00
|
|
|
OPT_BOOL(0, "stdin-packs", &opts.stdin_packs,
|
|
|
|
N_("scan pack-indexes listed by stdin for commits")),
|
2018-04-10 12:56:07 +00:00
|
|
|
OPT_BOOL(0, "stdin-commits", &opts.stdin_commits,
|
|
|
|
N_("start walk at commits listed by stdin")),
|
2018-04-10 12:56:08 +00:00
|
|
|
OPT_BOOL(0, "append", &opts.append,
|
|
|
|
N_("include all commits already in the commit-graph file")),
|
2019-08-26 16:29:58 +00:00
|
|
|
OPT_BOOL(0, "progress", &opts.progress, N_("force progress reporting")),
|
2019-06-18 18:14:28 +00:00
|
|
|
OPT_BOOL(0, "split", &opts.split,
|
|
|
|
N_("allow writing an incremental commit-graph file")),
|
2019-06-18 18:14:32 +00:00
|
|
|
OPT_INTEGER(0, "max-commits", &split_opts.max_commits,
|
|
|
|
N_("maximum number of commits in a non-base split commit-graph")),
|
|
|
|
OPT_INTEGER(0, "size-multiple", &split_opts.size_multiple,
|
|
|
|
N_("maximum ratio between two levels of a split commit-graph")),
|
|
|
|
OPT_EXPIRY_DATE(0, "expire-time", &split_opts.expire_time,
|
|
|
|
N_("maximum number of commits in a non-base split commit-graph")),
|
2018-04-02 20:34:20 +00:00
|
|
|
OPT_END(),
|
|
|
|
};
|
|
|
|
|
2019-08-26 16:29:58 +00:00
|
|
|
opts.progress = isatty(2);
|
2019-06-18 18:14:32 +00:00
|
|
|
split_opts.size_multiple = 2;
|
|
|
|
split_opts.max_commits = 0;
|
|
|
|
split_opts.expire_time = 0;
|
|
|
|
|
2019-08-27 16:56:34 +00:00
|
|
|
trace2_cmd_mode("write");
|
|
|
|
|
2018-04-02 20:34:20 +00:00
|
|
|
argc = parse_options(argc, argv, NULL,
|
|
|
|
builtin_commit_graph_write_options,
|
|
|
|
builtin_commit_graph_write_usage, 0);
|
|
|
|
|
2018-06-27 13:24:45 +00:00
|
|
|
if (opts.reachable + opts.stdin_packs + opts.stdin_commits > 1)
|
|
|
|
die(_("use at most one of --reachable, --stdin-commits, or --stdin-packs"));
|
2018-04-02 20:34:20 +00:00
|
|
|
if (!opts.obj_dir)
|
|
|
|
opts.obj_dir = get_object_directory();
|
2019-06-12 13:29:38 +00:00
|
|
|
if (opts.append)
|
2019-08-05 08:02:39 +00:00
|
|
|
flags |= COMMIT_GRAPH_WRITE_APPEND;
|
2019-06-18 18:14:28 +00:00
|
|
|
if (opts.split)
|
2019-08-05 08:02:39 +00:00
|
|
|
flags |= COMMIT_GRAPH_WRITE_SPLIT;
|
2019-08-26 16:29:58 +00:00
|
|
|
if (opts.progress)
|
|
|
|
flags |= COMMIT_GRAPH_WRITE_PROGRESS;
|
2018-04-02 20:34:20 +00:00
|
|
|
|
2018-08-20 18:24:27 +00:00
|
|
|
read_replace_refs = 0;
|
|
|
|
|
2019-06-18 18:14:32 +00:00
|
|
|
if (opts.reachable) {
|
|
|
|
if (write_commit_graph_reachable(opts.obj_dir, flags, &split_opts))
|
|
|
|
return 1;
|
|
|
|
return 0;
|
|
|
|
}
|
2018-06-27 13:24:45 +00:00
|
|
|
|
2018-06-27 13:24:44 +00:00
|
|
|
string_list_init(&lines, 0);
|
2018-04-10 12:56:07 +00:00
|
|
|
if (opts.stdin_packs || opts.stdin_commits) {
|
2018-04-10 12:56:06 +00:00
|
|
|
struct strbuf buf = STRBUF_INIT;
|
2018-06-27 13:24:44 +00:00
|
|
|
|
|
|
|
while (strbuf_getline(&buf, stdin) != EOF)
|
|
|
|
string_list_append(&lines, strbuf_detach(&buf, NULL));
|
|
|
|
|
|
|
|
if (opts.stdin_packs)
|
|
|
|
pack_indexes = &lines;
|
2019-08-05 08:02:40 +00:00
|
|
|
if (opts.stdin_commits) {
|
2018-06-27 13:24:44 +00:00
|
|
|
commit_hex = &lines;
|
2019-08-05 08:02:40 +00:00
|
|
|
flags |= COMMIT_GRAPH_WRITE_CHECK_OIDS;
|
|
|
|
}
|
2018-10-03 17:12:17 +00:00
|
|
|
|
|
|
|
UNLEAK(buf);
|
2018-04-10 12:56:06 +00:00
|
|
|
}
|
|
|
|
|
2019-06-12 13:29:37 +00:00
|
|
|
if (write_commit_graph(opts.obj_dir,
|
|
|
|
pack_indexes,
|
|
|
|
commit_hex,
|
2019-06-18 18:14:32 +00:00
|
|
|
flags,
|
|
|
|
&split_opts))
|
2019-06-12 13:29:37 +00:00
|
|
|
result = 1;
|
2018-04-10 12:56:06 +00:00
|
|
|
|
2018-10-03 17:12:17 +00:00
|
|
|
UNLEAK(lines);
|
2019-06-12 13:29:37 +00:00
|
|
|
return result;
|
2018-04-02 20:34:20 +00:00
|
|
|
}
|
2018-04-02 20:34:18 +00:00
|
|
|
|
|
|
|
int cmd_commit_graph(int argc, const char **argv, const char *prefix)
|
|
|
|
{
|
|
|
|
static struct option builtin_commit_graph_options[] = {
|
|
|
|
OPT_STRING(0, "object-dir", &opts.obj_dir,
|
|
|
|
N_("dir"),
|
|
|
|
N_("The object directory to store the graph")),
|
|
|
|
OPT_END(),
|
|
|
|
};
|
|
|
|
|
|
|
|
if (argc == 2 && !strcmp(argv[1], "-h"))
|
|
|
|
usage_with_options(builtin_commit_graph_usage,
|
|
|
|
builtin_commit_graph_options);
|
|
|
|
|
|
|
|
git_config(git_default_config, NULL);
|
|
|
|
argc = parse_options(argc, argv, prefix,
|
|
|
|
builtin_commit_graph_options,
|
|
|
|
builtin_commit_graph_usage,
|
|
|
|
PARSE_OPT_STOP_AT_NON_OPTION);
|
|
|
|
|
commit-graph: turn off save_commit_buffer
The commit-graph tool may read a lot of commits, but it only cares about
parsing their metadata (parents, trees, etc) and doesn't ever show the
messages to the user. And so it should not need save_commit_buffer,
which is meant for holding onto the object data of parsed commits so
that we can show them later. In fact, it's quite harmful to do so.
According to massif, the max heap of "git commit-graph write
--reachable" in linux.git before/after this patch (removing the commit
graph file in between) goes from ~1.1GB to ~270MB.
Which isn't surprising, since the difference is about the sum of the
uncompressed sizes of all commits in the repository, and this was
equivalent to leaking them.
This obviously helps if you're under memory pressure, but even without
it, things go faster. My before/after times for that command (without
massif) went from 12.521s to 11.874s, a speedup of ~5%.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-09-07 05:04:40 +00:00
|
|
|
save_commit_buffer = 0;
|
|
|
|
|
2018-04-02 20:34:20 +00:00
|
|
|
if (argc > 0) {
|
2018-04-10 12:56:02 +00:00
|
|
|
if (!strcmp(argv[0], "read"))
|
|
|
|
return graph_read(argc, argv);
|
2018-06-27 13:24:32 +00:00
|
|
|
if (!strcmp(argv[0], "verify"))
|
|
|
|
return graph_verify(argc, argv);
|
2018-04-02 20:34:20 +00:00
|
|
|
if (!strcmp(argv[0], "write"))
|
|
|
|
return graph_write(argc, argv);
|
|
|
|
}
|
|
|
|
|
2018-04-02 20:34:18 +00:00
|
|
|
usage_with_options(builtin_commit_graph_usage,
|
|
|
|
builtin_commit_graph_options);
|
|
|
|
}
|