Merge branch 'tb/commit-graph-no-check-oids'

Clean-up the commit-graph codepath.

* tb/commit-graph-no-check-oids:
  commit-graph: drop COMMIT_GRAPH_WRITE_CHECK_OIDS flag
  t5318: reorder test below 'graph_read_expect'
  commit-graph.c: simplify 'fill_oids_from_commits'
  builtin/commit-graph.c: dereference tags in builtin
  builtin/commit-graph.c: extract 'read_one_commit()'
  commit-graph.c: peel refs in 'add_ref_to_set'
  commit-graph.c: show progress of finding reachable commits
  commit-graph.c: extract 'refs_cb_data'
This commit is contained in:
Junio C Hamano 2020-06-08 18:06:27 -07:00
commit dc57a9be5e
5 changed files with 94 additions and 76 deletions

View File

@ -47,8 +47,10 @@ with `--stdin-commits` or `--reachable`.)
+
With the `--stdin-commits` option, generate the new commit graph by
walking commits starting at the commits specified in stdin as a list
of OIDs in hex, one OID per line. (Cannot be combined with
`--stdin-packs` or `--reachable`.)
of OIDs in hex, one OID per line. OIDs that resolve to non-commits
(either directly, or by peeling tags) are silently ignored. OIDs that
are malformed, or do not exist generate an error. (Cannot be combined
with `--stdin-packs` or `--reachable`.)
+
With the `--reachable` option, generate the new commit graph by walking
commits starting at all refs. (Cannot be combined with `--stdin-commits`

View File

@ -6,6 +6,8 @@
#include "repository.h"
#include "commit-graph.h"
#include "object-store.h"
#include "progress.h"
#include "tag.h"
static char const * const builtin_commit_graph_usage[] = {
N_("git commit-graph verify [--object-dir <objdir>] [--shallow] [--[no-]progress]"),
@ -138,14 +140,37 @@ static int write_option_parse_split(const struct option *opt, const char *arg,
return 0;
}
static int read_one_commit(struct oidset *commits, struct progress *progress,
const char *hash)
{
struct object *result;
struct object_id oid;
const char *end;
if (parse_oid_hex(hash, &oid, &end))
return error(_("unexpected non-hex object ID: %s"), hash);
result = deref_tag(the_repository, parse_object(the_repository, &oid),
NULL, 0);
if (!result)
return error(_("invalid object: %s"), hash);
else if (object_as_type(the_repository, result, OBJ_COMMIT, 1))
oidset_insert(commits, &result->oid);
display_progress(progress, oidset_size(commits));
return 0;
}
static int graph_write(int argc, const char **argv)
{
struct string_list *pack_indexes = NULL;
struct string_list pack_indexes = STRING_LIST_INIT_NODUP;
struct strbuf buf = STRBUF_INIT;
struct oidset commits = OIDSET_INIT;
struct object_directory *odb = NULL;
struct string_list lines;
int result = 0;
enum commit_graph_write_flags flags = 0;
struct progress *progress = NULL;
static struct option builtin_commit_graph_write_options[] = {
OPT_STRING(0, "object-dir", &opts.obj_dir,
@ -209,44 +234,38 @@ static int graph_write(int argc, const char **argv)
return 0;
}
string_list_init(&lines, 0);
if (opts.stdin_packs || opts.stdin_commits) {
struct strbuf buf = STRBUF_INIT;
if (opts.stdin_packs) {
while (strbuf_getline(&buf, stdin) != EOF)
string_list_append(&lines, strbuf_detach(&buf, NULL));
string_list_append(&pack_indexes,
strbuf_detach(&buf, NULL));
} else if (opts.stdin_commits) {
oidset_init(&commits, 0);
if (opts.progress)
progress = start_delayed_progress(
_("Collecting commits from input"), 0);
if (opts.stdin_packs)
pack_indexes = &lines;
if (opts.stdin_commits) {
struct string_list_item *item;
oidset_init(&commits, lines.nr);
for_each_string_list_item(item, &lines) {
struct object_id oid;
const char *end;
if (parse_oid_hex(item->string, &oid, &end)) {
error(_("unexpected non-hex object ID: "
"%s"), item->string);
return 1;
}
oidset_insert(&commits, &oid);
while (strbuf_getline(&buf, stdin) != EOF) {
if (read_one_commit(&commits, progress, buf.buf)) {
result = 1;
goto cleanup;
}
flags |= COMMIT_GRAPH_WRITE_CHECK_OIDS;
}
UNLEAK(buf);
}
if (write_commit_graph(odb,
pack_indexes,
opts.stdin_packs ? &pack_indexes : NULL,
opts.stdin_commits ? &commits : NULL,
flags,
&split_opts))
result = 1;
UNLEAK(lines);
cleanup:
string_list_clear(&pack_indexes, 0);
strbuf_release(&buf);
if (progress)
stop_progress(&progress);
return result;
}

View File

@ -881,7 +881,6 @@ struct write_commit_graph_context {
unsigned append:1,
report_progress:1,
split:1,
check_oids:1,
changed_paths:1,
order_by_pack:1;
@ -1319,13 +1318,25 @@ static void compute_bloom_filters(struct write_commit_graph_context *ctx)
stop_progress(&progress);
}
struct refs_cb_data {
struct oidset *commits;
struct progress *progress;
};
static int add_ref_to_set(const char *refname,
const struct object_id *oid,
int flags, void *cb_data)
{
struct oidset *commits = (struct oidset *)cb_data;
struct object_id peeled;
struct refs_cb_data *data = (struct refs_cb_data *)cb_data;
if (!peel_ref(refname, &peeled))
oid = &peeled;
if (oid_object_info(the_repository, oid, NULL) == OBJ_COMMIT)
oidset_insert(data->commits, oid);
display_progress(data->progress, oidset_size(data->commits));
oidset_insert(commits, oid);
return 0;
}
@ -1334,13 +1345,22 @@ int write_commit_graph_reachable(struct object_directory *odb,
const struct split_commit_graph_opts *split_opts)
{
struct oidset commits = OIDSET_INIT;
struct refs_cb_data data;
int result;
for_each_ref(add_ref_to_set, &commits);
memset(&data, 0, sizeof(data));
data.commits = &commits;
if (flags & COMMIT_GRAPH_WRITE_PROGRESS)
data.progress = start_delayed_progress(
_("Collecting referenced commits"), 0);
for_each_ref(add_ref_to_set, &data);
result = write_commit_graph(odb, NULL, &commits,
flags, split_opts);
oidset_clear(&commits);
if (data.progress)
stop_progress(&data.progress);
return result;
}
@ -1392,46 +1412,19 @@ static int fill_oids_from_packs(struct write_commit_graph_context *ctx,
static int fill_oids_from_commits(struct write_commit_graph_context *ctx,
struct oidset *commits)
{
uint32_t i = 0;
struct strbuf progress_title = STRBUF_INIT;
struct oidset_iter iter;
struct object_id *oid;
if (!oidset_size(commits))
return 0;
if (ctx->report_progress) {
strbuf_addf(&progress_title,
Q_("Finding commits for commit graph from %d ref",
"Finding commits for commit graph from %d refs",
oidset_size(commits)),
oidset_size(commits));
ctx->progress = start_delayed_progress(
progress_title.buf,
oidset_size(commits));
}
oidset_iter_init(commits, &iter);
while ((oid = oidset_iter_next(&iter))) {
struct commit *result;
display_progress(ctx->progress, ++i);
result = lookup_commit_reference_gently(ctx->r, oid, 1);
if (result) {
ALLOC_GROW(ctx->oids.list, ctx->oids.nr + 1, ctx->oids.alloc);
oidcpy(&ctx->oids.list[ctx->oids.nr], &(result->object.oid));
ctx->oids.nr++;
} else if (ctx->check_oids) {
error(_("invalid commit object id: %s"),
oid_to_hex(oid));
return -1;
}
ALLOC_GROW(ctx->oids.list, ctx->oids.nr + 1, ctx->oids.alloc);
oidcpy(&ctx->oids.list[ctx->oids.nr], oid);
ctx->oids.nr++;
}
stop_progress(&ctx->progress);
strbuf_release(&progress_title);
return 0;
}
@ -2017,7 +2010,6 @@ int write_commit_graph(struct object_directory *odb,
ctx->append = flags & COMMIT_GRAPH_WRITE_APPEND ? 1 : 0;
ctx->report_progress = flags & COMMIT_GRAPH_WRITE_PROGRESS ? 1 : 0;
ctx->split = flags & COMMIT_GRAPH_WRITE_SPLIT ? 1 : 0;
ctx->check_oids = flags & COMMIT_GRAPH_WRITE_CHECK_OIDS ? 1 : 0;
ctx->split_opts = split_opts;
ctx->changed_paths = flags & COMMIT_GRAPH_WRITE_BLOOM_FILTERS ? 1 : 0;
ctx->total_bloom_filter_data_size = 0;

View File

@ -91,9 +91,7 @@ enum commit_graph_write_flags {
COMMIT_GRAPH_WRITE_APPEND = (1 << 0),
COMMIT_GRAPH_WRITE_PROGRESS = (1 << 1),
COMMIT_GRAPH_WRITE_SPLIT = (1 << 2),
/* Make sure that each OID in the input is a valid commit OID. */
COMMIT_GRAPH_WRITE_CHECK_OIDS = (1 << 3),
COMMIT_GRAPH_WRITE_BLOOM_FILTERS = (1 << 4),
COMMIT_GRAPH_WRITE_BLOOM_FILTERS = (1 << 3),
};
enum commit_graph_split_flags {

View File

@ -46,15 +46,6 @@ test_expect_success 'create commits and repack' '
git repack
'
test_expect_success 'exit with correct error on bad input to --stdin-commits' '
cd "$TRASH_DIRECTORY/full" &&
echo HEAD | test_expect_code 1 git commit-graph write --stdin-commits 2>stderr &&
test_i18ngrep "unexpected non-hex object ID: HEAD" stderr &&
# valid tree OID, but not a commit OID
git rev-parse HEAD^{tree} | test_expect_code 1 git commit-graph write --stdin-commits 2>stderr &&
test_i18ngrep "invalid commit object id" stderr
'
graph_git_two_modes() {
git -c core.commitGraph=true $1 >output
git -c core.commitGraph=false $1 >expect
@ -95,6 +86,22 @@ graph_read_expect() {
test_cmp expect output
}
test_expect_success 'exit with correct error on bad input to --stdin-commits' '
cd "$TRASH_DIRECTORY/full" &&
# invalid, non-hex OID
echo HEAD >in &&
test_expect_code 1 git commit-graph write --stdin-commits <in 2>stderr &&
test_i18ngrep "unexpected non-hex object ID: HEAD" stderr &&
# non-existent OID
echo $ZERO_OID >in &&
test_expect_code 1 git commit-graph write --stdin-commits <in 2>stderr &&
test_i18ngrep "invalid object" stderr &&
# valid commit and tree OID
git rev-parse HEAD HEAD^{tree} >in &&
git commit-graph write --stdin-commits <in &&
graph_read_expect 3
'
test_expect_success 'write graph' '
cd "$TRASH_DIRECTORY/full" &&
git commit-graph write &&