2018-04-02 22:34:18 +02:00
|
|
|
#include "builtin.h"
|
|
|
|
#include "config.h"
|
2018-04-02 22:34:20 +02:00
|
|
|
#include "dir.h"
|
|
|
|
#include "lockfile.h"
|
2018-04-02 22:34:18 +02:00
|
|
|
#include "parse-options.h"
|
2018-06-27 15:24:32 +02:00
|
|
|
#include "repository.h"
|
2018-04-02 22:34:20 +02:00
|
|
|
#include "commit-graph.h"
|
2019-06-18 20:14:32 +02:00
|
|
|
#include "object-store.h"
|
2020-05-13 23:59:44 +02:00
|
|
|
#include "progress.h"
|
commit-graph: drop COMMIT_GRAPH_WRITE_CHECK_OIDS flag
Since 7c5c9b9c57 (commit-graph: error out on invalid commit oids in
'write --stdin-commits', 2019-08-05), the commit-graph builtin dies on
receiving non-commit OIDs as input to '--stdin-commits'.
This behavior can be cumbersome to work around in, say, the case of
piping 'git for-each-ref' to 'git commit-graph write --stdin-commits' if
the caller does not want to cull out non-commits themselves. In this
situation, it would be ideal if 'git commit-graph write' wrote the graph
containing the inputs that did pertain to commits, and silently ignored
the remainder of the input.
Some options have been proposed to the effect of '--[no-]check-oids'
which would allow callers to have the commit-graph builtin do just that.
After some discussion, it is difficult to imagine a caller who wouldn't
want to pass '--no-check-oids', suggesting that we should get rid of the
behavior of complaining about non-commit inputs altogether.
If callers do wish to retain this behavior, they can easily work around
this change by doing the following:
git for-each-ref --format='%(objectname) %(objecttype) %(*objecttype)' |
awk '
!/commit/ { print "not-a-commit:"$1 }
/commit/ { print $1 }
' |
git commit-graph write --stdin-commits
To make it so that valid OIDs that refer to non-existent objects are
indeed an error after loosening the error handling, perform an extra
lookup to make sure that object indeed exists before sending it to the
commit-graph internals.
Helped-by: Jeff King <peff@peff.net>
Signed-off-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-05-13 23:59:55 +02:00
|
|
|
#include "tag.h"
|
2018-04-02 22:34:18 +02:00
|
|
|
|
|
|
|
static char const * const builtin_commit_graph_usage[] = {
|
2019-08-26 18:29:58 +02:00
|
|
|
N_("git commit-graph verify [--object-dir <objdir>] [--shallow] [--[no-]progress]"),
|
2020-04-14 06:04:08 +02:00
|
|
|
N_("git commit-graph write [--object-dir <objdir>] [--append] "
|
|
|
|
"[--split[=<strategy>]] [--reachable|--stdin-packs|--stdin-commits] "
|
2020-09-18 15:27:27 +02:00
|
|
|
"[--changed-paths] [--[no-]max-new-filters <n>] [--[no-]progress] "
|
|
|
|
"<split options>"),
|
2018-04-02 22:34:20 +02:00
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
2018-06-27 15:24:32 +02:00
|
|
|
static const char * const builtin_commit_graph_verify_usage[] = {
|
2019-08-26 18:29:58 +02:00
|
|
|
N_("git commit-graph verify [--object-dir <objdir>] [--shallow] [--[no-]progress]"),
|
2018-06-27 15:24:32 +02:00
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
2018-04-02 22:34:20 +02:00
|
|
|
static const char * const builtin_commit_graph_write_usage[] = {
|
2020-04-14 06:04:08 +02:00
|
|
|
N_("git commit-graph write [--object-dir <objdir>] [--append] "
|
|
|
|
"[--split[=<strategy>]] [--reachable|--stdin-packs|--stdin-commits] "
|
2020-09-18 15:27:27 +02:00
|
|
|
"[--changed-paths] [--[no-]max-new-filters <n>] [--[no-]progress] "
|
|
|
|
"<split options>"),
|
2018-04-02 22:34:18 +02:00
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct opts_commit_graph {
|
|
|
|
const char *obj_dir;
|
2018-06-27 15:24:45 +02:00
|
|
|
int reachable;
|
2018-04-10 14:56:06 +02:00
|
|
|
int stdin_packs;
|
2018-04-10 14:56:07 +02:00
|
|
|
int stdin_commits;
|
2018-04-10 14:56:08 +02:00
|
|
|
int append;
|
2019-06-18 20:14:28 +02:00
|
|
|
int split;
|
2019-06-18 20:14:32 +02:00
|
|
|
int shallow;
|
2019-08-26 18:29:58 +02:00
|
|
|
int progress;
|
2020-04-06 18:59:51 +02:00
|
|
|
int enable_changed_paths;
|
2018-04-02 22:34:18 +02:00
|
|
|
} opts;
|
|
|
|
|
2020-02-04 06:51:50 +01:00
|
|
|
static struct object_directory *find_odb(struct repository *r,
|
|
|
|
const char *obj_dir)
|
|
|
|
{
|
|
|
|
struct object_directory *odb;
|
|
|
|
char *obj_dir_real = real_pathdup(obj_dir, 1);
|
2020-03-10 14:11:22 +01:00
|
|
|
struct strbuf odb_path_real = STRBUF_INIT;
|
2020-02-04 06:51:50 +01:00
|
|
|
|
|
|
|
prepare_alt_odb(r);
|
|
|
|
for (odb = r->objects->odb; odb; odb = odb->next) {
|
2020-03-10 14:11:22 +01:00
|
|
|
strbuf_realpath(&odb_path_real, odb->path, 1);
|
|
|
|
if (!strcmp(obj_dir_real, odb_path_real.buf))
|
2020-02-04 06:51:50 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
free(obj_dir_real);
|
2020-03-10 14:11:22 +01:00
|
|
|
strbuf_release(&odb_path_real);
|
2020-02-04 06:51:50 +01:00
|
|
|
|
|
|
|
if (!odb)
|
|
|
|
die(_("could not find object directory matching %s"), obj_dir);
|
|
|
|
return odb;
|
|
|
|
}
|
|
|
|
|
2018-06-27 15:24:32 +02:00
|
|
|
static int graph_verify(int argc, const char **argv)
|
|
|
|
{
|
|
|
|
struct commit_graph *graph = NULL;
|
2020-02-04 06:51:50 +01:00
|
|
|
struct object_directory *odb = NULL;
|
2018-06-27 15:24:32 +02:00
|
|
|
char *graph_name;
|
2019-03-25 13:08:30 +01:00
|
|
|
int open_ok;
|
|
|
|
int fd;
|
|
|
|
struct stat st;
|
2019-06-18 20:14:32 +02:00
|
|
|
int flags = 0;
|
2018-06-27 15:24:32 +02:00
|
|
|
|
|
|
|
static struct option builtin_commit_graph_verify_options[] = {
|
|
|
|
OPT_STRING(0, "object-dir", &opts.obj_dir,
|
|
|
|
N_("dir"),
|
2021-01-06 15:44:03 +01:00
|
|
|
N_("the object directory to store the graph")),
|
2019-06-18 20:14:32 +02:00
|
|
|
OPT_BOOL(0, "shallow", &opts.shallow,
|
|
|
|
N_("if the commit-graph is split, only verify the tip file")),
|
2019-08-26 18:29:58 +02:00
|
|
|
OPT_BOOL(0, "progress", &opts.progress, N_("force progress reporting")),
|
2018-06-27 15:24:32 +02:00
|
|
|
OPT_END(),
|
|
|
|
};
|
|
|
|
|
2019-08-27 18:56:34 +02:00
|
|
|
trace2_cmd_mode("verify");
|
|
|
|
|
2019-08-26 18:29:58 +02:00
|
|
|
opts.progress = isatty(2);
|
2018-06-27 15:24:32 +02: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 20:14:32 +02:00
|
|
|
if (opts.shallow)
|
|
|
|
flags |= COMMIT_GRAPH_VERIFY_SHALLOW;
|
2019-08-26 18:29:58 +02:00
|
|
|
if (opts.progress)
|
|
|
|
flags |= COMMIT_GRAPH_WRITE_PROGRESS;
|
2018-06-27 15:24:32 +02:00
|
|
|
|
2020-02-04 06:51:50 +01:00
|
|
|
odb = find_odb(the_repository, opts.obj_dir);
|
commit-graph.c: remove path normalization, comparison
As of the previous patch, all calls to 'commit-graph.c' functions which
perform path normalization (for e.g., 'get_commit_graph_filename()') are
of the form 'ctx->odb->path', which is always in normalized form.
Now that there are no callers passing non-normalized paths to these
functions, ensure that future callers are bound by the same restrictions
by making these functions take a 'struct object_directory *' instead of
a 'const char *'. To match, replace all calls with arguments of the form
'ctx->odb->path' with 'ctx->odb' To recover the path, functions that
perform path manipulation simply use 'odb->path'.
Further, avoid string comparisons with arguments of the form
'odb->path', and instead prefer raw pointer comparisons, which
accomplish the same effect, but are far less brittle.
This has a pleasant side-effect of making these functions much more
robust to paths that cannot be normalized by 'normalize_path_copy()',
i.e., because they are outside of the current working directory.
For example, prior to this patch, Valgrind reports that the following
uninitialized memory read [1]:
$ ( cd t && GIT_DIR=../.git valgrind git rev-parse HEAD^ )
because 'normalize_path_copy()' can't normalize '../.git' (since it's
relative to but above of the current working directory) [2].
By using a 'struct object_directory *' directly,
'get_commit_graph_filename()' does not need to normalize, because all
paths are relative to the current working directory since they are
always read from the '->path' of an object directory.
[1]: https://lore.kernel.org/git/20191027042116.GA5801@sigill.intra.peff.net.
[2]: The bug here is that 'get_commit_graph_filename()' returns the
result of 'normalize_path_copy()' without checking the return
value.
Signed-off-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-02-03 22:18:02 +01:00
|
|
|
graph_name = get_commit_graph_filename(odb);
|
2019-03-25 13:08:30 +01:00
|
|
|
open_ok = open_commit_graph(graph_name, &fd, &st);
|
2019-06-18 20:14:32 +02:00
|
|
|
if (!open_ok && errno != ENOENT)
|
2019-03-25 13:08:32 +01:00
|
|
|
die_errno(_("Could not open commit-graph '%s'"), graph_name);
|
2019-06-18 20:14:32 +02:00
|
|
|
|
2018-06-27 15:24:32 +02:00
|
|
|
FREE_AND_NULL(graph_name);
|
|
|
|
|
2019-06-18 20:14:32 +02:00
|
|
|
if (open_ok)
|
2020-09-09 17:22:56 +02:00
|
|
|
graph = load_commit_graph_one_fd_st(the_repository, fd, &st, odb);
|
2020-02-04 06:51:50 +01:00
|
|
|
else
|
2020-02-03 22:18:00 +01:00
|
|
|
graph = read_commit_graph_one(the_repository, odb);
|
2019-06-18 20:14:32 +02:00
|
|
|
|
|
|
|
/* Return failure if open_ok predicted success */
|
2018-06-27 15:24:32 +02:00
|
|
|
if (!graph)
|
2019-06-18 20:14:32 +02:00
|
|
|
return !!open_ok;
|
2018-06-27 15:24:32 +02:00
|
|
|
|
2018-10-03 19:12:17 +02:00
|
|
|
UNLEAK(graph);
|
2019-06-18 20:14:32 +02:00
|
|
|
return verify_commit_graph(the_repository, graph, flags);
|
2018-06-27 15:24:32 +02:00
|
|
|
}
|
|
|
|
|
2018-08-20 20:24:27 +02:00
|
|
|
extern int read_replace_refs;
|
2020-09-18 04:59:49 +02:00
|
|
|
static struct commit_graph_opts write_opts;
|
2018-08-20 20:24:27 +02:00
|
|
|
|
2020-04-14 06:04:08 +02:00
|
|
|
static int write_option_parse_split(const struct option *opt, const char *arg,
|
|
|
|
int unset)
|
|
|
|
{
|
builtin/commit-graph.c: introduce split strategy 'no-merge'
In the previous commit, we laid the groundwork for supporting different
splitting strategies. In this commit, we introduce the first splitting
strategy: 'no-merge'.
Passing '--split=no-merge' is useful for callers which wish to write a
new incremental commit-graph, but do not want to spend effort condensing
the incremental chain [1]. Previously, this was possible by passing
'--size-multiple=0', but this no longer the case following 63020f175f
(commit-graph: prefer default size_mult when given zero, 2020-01-02).
When '--split=no-merge' is given, the commit-graph machinery will never
condense an existing chain, and it will always write a new incremental.
[1]: This might occur when, for example, a server administrator running
some program after each push may want to ensure that each job runs
proportional in time to the size of the push, and does not "jump" when
the commit-graph machinery decides to trigger a merge.
Signed-off-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-04-14 06:04:12 +02:00
|
|
|
enum commit_graph_split_flags *flags = opt->value;
|
|
|
|
|
2020-09-30 14:29:02 +02:00
|
|
|
BUG_ON_OPT_NEG(unset);
|
|
|
|
|
2020-04-14 06:04:08 +02:00
|
|
|
opts.split = 1;
|
|
|
|
if (!arg)
|
|
|
|
return 0;
|
|
|
|
|
builtin/commit-graph.c: introduce split strategy 'no-merge'
In the previous commit, we laid the groundwork for supporting different
splitting strategies. In this commit, we introduce the first splitting
strategy: 'no-merge'.
Passing '--split=no-merge' is useful for callers which wish to write a
new incremental commit-graph, but do not want to spend effort condensing
the incremental chain [1]. Previously, this was possible by passing
'--size-multiple=0', but this no longer the case following 63020f175f
(commit-graph: prefer default size_mult when given zero, 2020-01-02).
When '--split=no-merge' is given, the commit-graph machinery will never
condense an existing chain, and it will always write a new incremental.
[1]: This might occur when, for example, a server administrator running
some program after each push may want to ensure that each job runs
proportional in time to the size of the push, and does not "jump" when
the commit-graph machinery decides to trigger a merge.
Signed-off-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-04-14 06:04:12 +02:00
|
|
|
if (!strcmp(arg, "no-merge"))
|
|
|
|
*flags = COMMIT_GRAPH_SPLIT_MERGE_PROHIBITED;
|
builtin/commit-graph.c: introduce split strategy 'replace'
When using split commit-graphs, it is sometimes useful to completely
replace the commit-graph chain with a new base.
For example, consider a scenario in which a repository builds a new
commit-graph incremental for each push. Occasionally (say, after some
fixed number of pushes), they may wish to rebuild the commit-graph chain
with all reachable commits.
They can do so with
$ git commit-graph write --reachable
but this removes the chain entirely and replaces it with a single
commit-graph in 'objects/info/commit-graph'. Unfortunately, this means
that the next push will have to move this commit-graph into the first
layer of a new chain, and then write its new commits on top.
Avoid such copying entirely by allowing the caller to specify that they
wish to replace the entirety of their commit-graph chain, while also
specifying that the new commit-graph should become the basis of a fresh,
length-one chain.
This addresses the above situation by making it possible for the caller
to instead write:
$ git commit-graph write --reachable --split=replace
which writes a new length-one chain to 'objects/info/commit-graphs',
making the commit-graph incremental generated by the subsequent push
relatively cheap by avoiding the aforementioned copy.
In order to do this, remove an assumption in 'write_commit_graph_file'
that chains are always at least two incrementals long.
Signed-off-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-04-14 06:04:17 +02:00
|
|
|
else if (!strcmp(arg, "replace"))
|
|
|
|
*flags = COMMIT_GRAPH_SPLIT_REPLACE;
|
builtin/commit-graph.c: introduce split strategy 'no-merge'
In the previous commit, we laid the groundwork for supporting different
splitting strategies. In this commit, we introduce the first splitting
strategy: 'no-merge'.
Passing '--split=no-merge' is useful for callers which wish to write a
new incremental commit-graph, but do not want to spend effort condensing
the incremental chain [1]. Previously, this was possible by passing
'--size-multiple=0', but this no longer the case following 63020f175f
(commit-graph: prefer default size_mult when given zero, 2020-01-02).
When '--split=no-merge' is given, the commit-graph machinery will never
condense an existing chain, and it will always write a new incremental.
[1]: This might occur when, for example, a server administrator running
some program after each push may want to ensure that each job runs
proportional in time to the size of the push, and does not "jump" when
the commit-graph machinery decides to trigger a merge.
Signed-off-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-04-14 06:04:12 +02:00
|
|
|
else
|
|
|
|
die(_("unrecognized --split argument, %s"), arg);
|
2020-04-14 06:04:08 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-05-13 23:59:44 +02:00
|
|
|
static int read_one_commit(struct oidset *commits, struct progress *progress,
|
|
|
|
const char *hash)
|
2020-05-18 21:27:09 +02:00
|
|
|
{
|
commit-graph: drop COMMIT_GRAPH_WRITE_CHECK_OIDS flag
Since 7c5c9b9c57 (commit-graph: error out on invalid commit oids in
'write --stdin-commits', 2019-08-05), the commit-graph builtin dies on
receiving non-commit OIDs as input to '--stdin-commits'.
This behavior can be cumbersome to work around in, say, the case of
piping 'git for-each-ref' to 'git commit-graph write --stdin-commits' if
the caller does not want to cull out non-commits themselves. In this
situation, it would be ideal if 'git commit-graph write' wrote the graph
containing the inputs that did pertain to commits, and silently ignored
the remainder of the input.
Some options have been proposed to the effect of '--[no-]check-oids'
which would allow callers to have the commit-graph builtin do just that.
After some discussion, it is difficult to imagine a caller who wouldn't
want to pass '--no-check-oids', suggesting that we should get rid of the
behavior of complaining about non-commit inputs altogether.
If callers do wish to retain this behavior, they can easily work around
this change by doing the following:
git for-each-ref --format='%(objectname) %(objecttype) %(*objecttype)' |
awk '
!/commit/ { print "not-a-commit:"$1 }
/commit/ { print $1 }
' |
git commit-graph write --stdin-commits
To make it so that valid OIDs that refer to non-existent objects are
indeed an error after loosening the error handling, perform an extra
lookup to make sure that object indeed exists before sending it to the
commit-graph internals.
Helped-by: Jeff King <peff@peff.net>
Signed-off-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-05-13 23:59:55 +02:00
|
|
|
struct object *result;
|
2020-05-18 21:27:09 +02:00
|
|
|
struct object_id oid;
|
|
|
|
const char *end;
|
|
|
|
|
|
|
|
if (parse_oid_hex(hash, &oid, &end))
|
|
|
|
return error(_("unexpected non-hex object ID: %s"), hash);
|
|
|
|
|
commit-graph: drop COMMIT_GRAPH_WRITE_CHECK_OIDS flag
Since 7c5c9b9c57 (commit-graph: error out on invalid commit oids in
'write --stdin-commits', 2019-08-05), the commit-graph builtin dies on
receiving non-commit OIDs as input to '--stdin-commits'.
This behavior can be cumbersome to work around in, say, the case of
piping 'git for-each-ref' to 'git commit-graph write --stdin-commits' if
the caller does not want to cull out non-commits themselves. In this
situation, it would be ideal if 'git commit-graph write' wrote the graph
containing the inputs that did pertain to commits, and silently ignored
the remainder of the input.
Some options have been proposed to the effect of '--[no-]check-oids'
which would allow callers to have the commit-graph builtin do just that.
After some discussion, it is difficult to imagine a caller who wouldn't
want to pass '--no-check-oids', suggesting that we should get rid of the
behavior of complaining about non-commit inputs altogether.
If callers do wish to retain this behavior, they can easily work around
this change by doing the following:
git for-each-ref --format='%(objectname) %(objecttype) %(*objecttype)' |
awk '
!/commit/ { print "not-a-commit:"$1 }
/commit/ { print $1 }
' |
git commit-graph write --stdin-commits
To make it so that valid OIDs that refer to non-existent objects are
indeed an error after loosening the error handling, perform an extra
lookup to make sure that object indeed exists before sending it to the
commit-graph internals.
Helped-by: Jeff King <peff@peff.net>
Signed-off-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-05-13 23:59:55 +02:00
|
|
|
result = deref_tag(the_repository, parse_object(the_repository, &oid),
|
|
|
|
NULL, 0);
|
|
|
|
if (!result)
|
|
|
|
return error(_("invalid object: %s"), hash);
|
2020-06-17 11:14:08 +02:00
|
|
|
else if (object_as_type(result, OBJ_COMMIT, 1))
|
commit-graph: drop COMMIT_GRAPH_WRITE_CHECK_OIDS flag
Since 7c5c9b9c57 (commit-graph: error out on invalid commit oids in
'write --stdin-commits', 2019-08-05), the commit-graph builtin dies on
receiving non-commit OIDs as input to '--stdin-commits'.
This behavior can be cumbersome to work around in, say, the case of
piping 'git for-each-ref' to 'git commit-graph write --stdin-commits' if
the caller does not want to cull out non-commits themselves. In this
situation, it would be ideal if 'git commit-graph write' wrote the graph
containing the inputs that did pertain to commits, and silently ignored
the remainder of the input.
Some options have been proposed to the effect of '--[no-]check-oids'
which would allow callers to have the commit-graph builtin do just that.
After some discussion, it is difficult to imagine a caller who wouldn't
want to pass '--no-check-oids', suggesting that we should get rid of the
behavior of complaining about non-commit inputs altogether.
If callers do wish to retain this behavior, they can easily work around
this change by doing the following:
git for-each-ref --format='%(objectname) %(objecttype) %(*objecttype)' |
awk '
!/commit/ { print "not-a-commit:"$1 }
/commit/ { print $1 }
' |
git commit-graph write --stdin-commits
To make it so that valid OIDs that refer to non-existent objects are
indeed an error after loosening the error handling, perform an extra
lookup to make sure that object indeed exists before sending it to the
commit-graph internals.
Helped-by: Jeff King <peff@peff.net>
Signed-off-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-05-13 23:59:55 +02:00
|
|
|
oidset_insert(commits, &result->oid);
|
2020-05-13 23:59:44 +02:00
|
|
|
|
|
|
|
display_progress(progress, oidset_size(commits));
|
|
|
|
|
2020-05-18 21:27:09 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-09-18 15:27:27 +02:00
|
|
|
static int write_option_max_new_filters(const struct option *opt,
|
|
|
|
const char *arg,
|
|
|
|
int unset)
|
|
|
|
{
|
|
|
|
int *to = opt->value;
|
|
|
|
if (unset)
|
|
|
|
*to = -1;
|
|
|
|
else {
|
|
|
|
const char *s;
|
|
|
|
*to = strtol(arg, (char **)&s, 10);
|
|
|
|
if (*s)
|
|
|
|
return error(_("%s expects a numerical value"),
|
|
|
|
optname(opt, opt->flags));
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-09-18 04:59:57 +02:00
|
|
|
static int git_commit_graph_write_config(const char *var, const char *value,
|
|
|
|
void *cb)
|
|
|
|
{
|
|
|
|
if (!strcmp(var, "commitgraph.maxnewfilters"))
|
|
|
|
write_opts.max_new_filters = git_config_int(var, value);
|
|
|
|
/*
|
|
|
|
* No need to fall-back to 'git_default_config', since this was already
|
|
|
|
* called in 'cmd_commit_graph()'.
|
|
|
|
*/
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-04-02 22:34:20 +02:00
|
|
|
static int graph_write(int argc, const char **argv)
|
|
|
|
{
|
2020-05-18 21:27:09 +02:00
|
|
|
struct string_list pack_indexes = STRING_LIST_INIT_NODUP;
|
|
|
|
struct strbuf buf = STRBUF_INIT;
|
2020-04-14 06:04:25 +02:00
|
|
|
struct oidset commits = OIDSET_INIT;
|
2020-02-04 06:51:50 +01:00
|
|
|
struct object_directory *odb = NULL;
|
2019-06-12 15:29:37 +02:00
|
|
|
int result = 0;
|
2019-08-26 18:29:58 +02:00
|
|
|
enum commit_graph_write_flags flags = 0;
|
2020-05-13 23:59:44 +02:00
|
|
|
struct progress *progress = NULL;
|
2018-04-10 14:56:06 +02:00
|
|
|
|
2018-04-02 22:34:20 +02:00
|
|
|
static struct option builtin_commit_graph_write_options[] = {
|
|
|
|
OPT_STRING(0, "object-dir", &opts.obj_dir,
|
|
|
|
N_("dir"),
|
2021-01-06 15:44:03 +01:00
|
|
|
N_("the object directory to store the graph")),
|
2018-06-27 15:24:45 +02:00
|
|
|
OPT_BOOL(0, "reachable", &opts.reachable,
|
|
|
|
N_("start walk at all refs")),
|
2018-04-10 14:56:06 +02:00
|
|
|
OPT_BOOL(0, "stdin-packs", &opts.stdin_packs,
|
|
|
|
N_("scan pack-indexes listed by stdin for commits")),
|
2018-04-10 14:56:07 +02:00
|
|
|
OPT_BOOL(0, "stdin-commits", &opts.stdin_commits,
|
|
|
|
N_("start walk at commits listed by stdin")),
|
2018-04-10 14:56:08 +02:00
|
|
|
OPT_BOOL(0, "append", &opts.append,
|
|
|
|
N_("include all commits already in the commit-graph file")),
|
2020-04-06 18:59:51 +02:00
|
|
|
OPT_BOOL(0, "changed-paths", &opts.enable_changed_paths,
|
|
|
|
N_("enable computation for changed paths")),
|
2019-08-26 18:29:58 +02:00
|
|
|
OPT_BOOL(0, "progress", &opts.progress, N_("force progress reporting")),
|
2020-09-18 04:59:49 +02:00
|
|
|
OPT_CALLBACK_F(0, "split", &write_opts.split_flags, NULL,
|
2020-04-14 06:04:08 +02:00
|
|
|
N_("allow writing an incremental commit-graph file"),
|
|
|
|
PARSE_OPT_OPTARG | PARSE_OPT_NONEG,
|
|
|
|
write_option_parse_split),
|
2020-09-18 04:59:49 +02:00
|
|
|
OPT_INTEGER(0, "max-commits", &write_opts.max_commits,
|
2019-06-18 20:14:32 +02:00
|
|
|
N_("maximum number of commits in a non-base split commit-graph")),
|
2020-09-18 04:59:49 +02:00
|
|
|
OPT_INTEGER(0, "size-multiple", &write_opts.size_multiple,
|
2019-06-18 20:14:32 +02:00
|
|
|
N_("maximum ratio between two levels of a split commit-graph")),
|
2020-09-18 04:59:49 +02:00
|
|
|
OPT_EXPIRY_DATE(0, "expire-time", &write_opts.expire_time,
|
2020-04-01 23:00:44 +02:00
|
|
|
N_("only expire files older than a given date-time")),
|
2020-09-18 15:27:27 +02:00
|
|
|
OPT_CALLBACK_F(0, "max-new-filters", &write_opts.max_new_filters,
|
|
|
|
NULL, N_("maximum number of changed-path Bloom filters to compute"),
|
|
|
|
0, write_option_max_new_filters),
|
2018-04-02 22:34:20 +02:00
|
|
|
OPT_END(),
|
|
|
|
};
|
|
|
|
|
2019-08-26 18:29:58 +02:00
|
|
|
opts.progress = isatty(2);
|
2020-07-01 15:27:24 +02:00
|
|
|
opts.enable_changed_paths = -1;
|
2020-09-18 04:59:49 +02:00
|
|
|
write_opts.size_multiple = 2;
|
|
|
|
write_opts.max_commits = 0;
|
|
|
|
write_opts.expire_time = 0;
|
2020-09-18 15:27:27 +02:00
|
|
|
write_opts.max_new_filters = -1;
|
2019-06-18 20:14:32 +02:00
|
|
|
|
2019-08-27 18:56:34 +02:00
|
|
|
trace2_cmd_mode("write");
|
|
|
|
|
2020-09-18 04:59:57 +02:00
|
|
|
git_config(git_commit_graph_write_config, &opts);
|
|
|
|
|
2018-04-02 22:34:20 +02:00
|
|
|
argc = parse_options(argc, argv, NULL,
|
|
|
|
builtin_commit_graph_write_options,
|
|
|
|
builtin_commit_graph_write_usage, 0);
|
|
|
|
|
2018-06-27 15:24:45 +02: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 22:34:20 +02:00
|
|
|
if (!opts.obj_dir)
|
|
|
|
opts.obj_dir = get_object_directory();
|
2019-06-12 15:29:38 +02:00
|
|
|
if (opts.append)
|
2019-08-05 10:02:39 +02:00
|
|
|
flags |= COMMIT_GRAPH_WRITE_APPEND;
|
2019-06-18 20:14:28 +02:00
|
|
|
if (opts.split)
|
2019-08-05 10:02:39 +02:00
|
|
|
flags |= COMMIT_GRAPH_WRITE_SPLIT;
|
2019-08-26 18:29:58 +02:00
|
|
|
if (opts.progress)
|
|
|
|
flags |= COMMIT_GRAPH_WRITE_PROGRESS;
|
2020-07-01 15:27:24 +02:00
|
|
|
if (!opts.enable_changed_paths)
|
|
|
|
flags |= COMMIT_GRAPH_NO_WRITE_BLOOM_FILTERS;
|
|
|
|
if (opts.enable_changed_paths == 1 ||
|
2020-04-06 18:59:55 +02:00
|
|
|
git_env_bool(GIT_TEST_COMMIT_GRAPH_CHANGED_PATHS, 0))
|
2020-04-06 18:59:51 +02:00
|
|
|
flags |= COMMIT_GRAPH_WRITE_BLOOM_FILTERS;
|
2018-04-02 22:34:20 +02:00
|
|
|
|
2018-08-20 20:24:27 +02:00
|
|
|
read_replace_refs = 0;
|
2020-02-04 06:51:50 +01:00
|
|
|
odb = find_odb(the_repository, opts.obj_dir);
|
2018-08-20 20:24:27 +02:00
|
|
|
|
2019-06-18 20:14:32 +02:00
|
|
|
if (opts.reachable) {
|
2020-09-18 04:59:49 +02:00
|
|
|
if (write_commit_graph_reachable(odb, flags, &write_opts))
|
2019-06-18 20:14:32 +02:00
|
|
|
return 1;
|
|
|
|
return 0;
|
|
|
|
}
|
2018-06-27 15:24:45 +02:00
|
|
|
|
2020-05-18 21:27:09 +02:00
|
|
|
if (opts.stdin_packs) {
|
2018-06-27 15:24:44 +02:00
|
|
|
while (strbuf_getline(&buf, stdin) != EOF)
|
2020-05-18 21:27:09 +02:00
|
|
|
string_list_append(&pack_indexes,
|
|
|
|
strbuf_detach(&buf, NULL));
|
|
|
|
} else if (opts.stdin_commits) {
|
|
|
|
oidset_init(&commits, 0);
|
2020-05-13 23:59:44 +02:00
|
|
|
if (opts.progress)
|
|
|
|
progress = start_delayed_progress(
|
|
|
|
_("Collecting commits from input"), 0);
|
2020-05-18 21:27:09 +02:00
|
|
|
|
|
|
|
while (strbuf_getline(&buf, stdin) != EOF) {
|
2020-05-13 23:59:44 +02:00
|
|
|
if (read_one_commit(&commits, progress, buf.buf)) {
|
2020-05-18 21:27:09 +02:00
|
|
|
result = 1;
|
|
|
|
goto cleanup;
|
2020-04-14 06:04:25 +02:00
|
|
|
}
|
2019-08-05 10:02:40 +02:00
|
|
|
}
|
2020-05-13 23:59:44 +02:00
|
|
|
|
commit-graph: fix "Collecting commits from input" progress line
To display a progress line while reading commits from standard input
and looking them up, 5b6653e523 (builtin/commit-graph.c: dereference
tags in builtin, 2020-05-13) should have added a pair of
start_delayed_progress() and stop_progress() calls around the loop
reading stdin. Alas, the stop_progress() call ended up at the wrong
place, after write_commit_graph(), which does all the commit-graph
computation and writing, and has several progress lines of its own.
Consequently, that new
Collecting commits from input: 1234
progress line is overwritten by the first progress line shown by
write_commit_graph(), and its final "done" line is shown last, after
everything is finished:
$ { sleep 3 ; git rev-list -3 HEAD ; sleep 1 ; } | ~/src/git/git commit-graph write --stdin-commits
Expanding reachable commits in commit graph: 873402, done.
Writing out commit graph in 4 passes: 100% (3493608/3493608), done.
Collecting commits from input: 3, done.
Furthermore, that stop_progress() call was added after the 'cleanup'
label, where that loop reading stdin jumps in case of an error. In
case of invalid input this then results in the "done" line shown after
the error message:
$ { sleep 3 ; git rev-list -3 HEAD ; echo junk ; } | ~/src/git/git commit-graph write --stdin-commits
error: unexpected non-hex object ID: junk
Collecting commits from input: 3, done.
Move that stop_progress() call to the right place.
While at it, drop the unnecessary 'if (progress)' condition protecting
the stop_progress() call, because that function is prepared to handle
a NULL progress struct.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Reviewed-by: Derrick Stolee <stolee@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-07-10 21:02:38 +02:00
|
|
|
stop_progress(&progress);
|
2018-04-10 14:56:06 +02:00
|
|
|
}
|
|
|
|
|
2020-02-04 06:51:50 +01:00
|
|
|
if (write_commit_graph(odb,
|
2020-05-18 21:27:09 +02:00
|
|
|
opts.stdin_packs ? &pack_indexes : NULL,
|
2020-04-14 06:04:25 +02:00
|
|
|
opts.stdin_commits ? &commits : NULL,
|
2019-06-18 20:14:32 +02:00
|
|
|
flags,
|
2020-09-18 04:59:49 +02:00
|
|
|
&write_opts))
|
2019-06-12 15:29:37 +02:00
|
|
|
result = 1;
|
2018-04-10 14:56:06 +02:00
|
|
|
|
2020-05-18 21:27:09 +02:00
|
|
|
cleanup:
|
|
|
|
string_list_clear(&pack_indexes, 0);
|
|
|
|
strbuf_release(&buf);
|
2019-06-12 15:29:37 +02:00
|
|
|
return result;
|
2018-04-02 22:34:20 +02:00
|
|
|
}
|
2018-04-02 22:34:18 +02: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"),
|
2021-01-06 15:44:03 +01:00
|
|
|
N_("the object directory to store the graph")),
|
2018-04-02 22:34:18 +02:00
|
|
|
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 07:04:40 +02:00
|
|
|
save_commit_buffer = 0;
|
|
|
|
|
2018-04-02 22:34:20 +02:00
|
|
|
if (argc > 0) {
|
2018-06-27 15:24:32 +02:00
|
|
|
if (!strcmp(argv[0], "verify"))
|
|
|
|
return graph_verify(argc, argv);
|
2018-04-02 22:34:20 +02:00
|
|
|
if (!strcmp(argv[0], "write"))
|
|
|
|
return graph_write(argc, argv);
|
|
|
|
}
|
|
|
|
|
2018-04-02 22:34:18 +02:00
|
|
|
usage_with_options(builtin_commit_graph_usage,
|
|
|
|
builtin_commit_graph_options);
|
|
|
|
}
|