| /* We need this macro to access core_apply_sparse_checkout */ |
| #define USE_THE_REPOSITORY_VARIABLE |
| |
| #include "builtin.h" |
| #include "git-compat-util.h" |
| #include "config.h" |
| #include "parse-options.h" |
| #include "repository.h" |
| #include "commit.h" |
| #include "dir.h" |
| #include "environment.h" |
| #include "hex.h" |
| #include "tree.h" |
| #include "tree-walk.h" |
| #include "object.h" |
| #include "object-store.h" |
| #include "oid-array.h" |
| #include "oidset.h" |
| #include "promisor-remote.h" |
| #include "strmap.h" |
| #include "string-list.h" |
| #include "revision.h" |
| #include "trace2.h" |
| #include "progress.h" |
| #include "packfile.h" |
| #include "path-walk.h" |
| |
| static const char * const builtin_backfill_usage[] = { |
| N_("git backfill [--min-batch-size=<n>] [--[no-]sparse]"), |
| NULL |
| }; |
| |
| struct backfill_context { |
| struct repository *repo; |
| struct oid_array current_batch; |
| size_t min_batch_size; |
| int sparse; |
| }; |
| |
| static void backfill_context_clear(struct backfill_context *ctx) |
| { |
| oid_array_clear(&ctx->current_batch); |
| } |
| |
| static void download_batch(struct backfill_context *ctx) |
| { |
| promisor_remote_get_direct(ctx->repo, |
| ctx->current_batch.oid, |
| ctx->current_batch.nr); |
| oid_array_clear(&ctx->current_batch); |
| |
| /* |
| * We likely have a new packfile. Add it to the packed list to |
| * avoid possible duplicate downloads of the same objects. |
| */ |
| reprepare_packed_git(ctx->repo); |
| } |
| |
| static int fill_missing_blobs(const char *path UNUSED, |
| struct oid_array *list, |
| enum object_type type, |
| void *data) |
| { |
| struct backfill_context *ctx = data; |
| |
| if (type != OBJ_BLOB) |
| return 0; |
| |
| for (size_t i = 0; i < list->nr; i++) { |
| if (!has_object(ctx->repo, &list->oid[i], |
| OBJECT_INFO_FOR_PREFETCH)) |
| oid_array_append(&ctx->current_batch, &list->oid[i]); |
| } |
| |
| if (ctx->current_batch.nr >= ctx->min_batch_size) |
| download_batch(ctx); |
| |
| return 0; |
| } |
| |
| static int do_backfill(struct backfill_context *ctx) |
| { |
| struct rev_info revs; |
| struct path_walk_info info = PATH_WALK_INFO_INIT; |
| int ret; |
| |
| if (ctx->sparse) { |
| CALLOC_ARRAY(info.pl, 1); |
| if (get_sparse_checkout_patterns(info.pl)) { |
| path_walk_info_clear(&info); |
| return error(_("problem loading sparse-checkout")); |
| } |
| } |
| |
| repo_init_revisions(ctx->repo, &revs, ""); |
| handle_revision_arg("HEAD", &revs, 0, 0); |
| |
| info.blobs = 1; |
| info.tags = info.commits = info.trees = 0; |
| |
| info.revs = &revs; |
| info.path_fn = fill_missing_blobs; |
| info.path_fn_data = ctx; |
| |
| ret = walk_objects_by_path(&info); |
| |
| /* Download the objects that did not fill a batch. */ |
| if (!ret) |
| download_batch(ctx); |
| |
| path_walk_info_clear(&info); |
| release_revisions(&revs); |
| return ret; |
| } |
| |
| int cmd_backfill(int argc, const char **argv, const char *prefix, struct repository *repo) |
| { |
| int result; |
| struct backfill_context ctx = { |
| .repo = repo, |
| .current_batch = OID_ARRAY_INIT, |
| .min_batch_size = 50000, |
| .sparse = 0, |
| }; |
| struct option options[] = { |
| OPT_UNSIGNED(0, "min-batch-size", &ctx.min_batch_size, |
| N_("Minimum number of objects to request at a time")), |
| OPT_BOOL(0, "sparse", &ctx.sparse, |
| N_("Restrict the missing objects to the current sparse-checkout")), |
| OPT_END(), |
| }; |
| |
| show_usage_with_options_if_asked(argc, argv, |
| builtin_backfill_usage, options); |
| |
| argc = parse_options(argc, argv, prefix, options, builtin_backfill_usage, |
| 0); |
| |
| repo_config(repo, git_default_config, NULL); |
| |
| if (ctx.sparse < 0) |
| ctx.sparse = core_apply_sparse_checkout; |
| |
| result = do_backfill(&ctx); |
| backfill_context_clear(&ctx); |
| return result; |
| } |