aboutsummaryrefslogtreecommitdiffstats
path: root/builtin/repack.c
diff options
context:
space:
mode:
Diffstat (limited to 'builtin/repack.c')
-rw-r--r--builtin/repack.c161
1 files changed, 133 insertions, 28 deletions
diff --git a/builtin/repack.c b/builtin/repack.c
index 10e23f9ee1..0541c3ce15 100644
--- a/builtin/repack.c
+++ b/builtin/repack.c
@@ -1,9 +1,13 @@
#include "builtin.h"
-#include "cache.h"
+#include "alloc.h"
#include "config.h"
#include "dir.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
#include "parse-options.h"
#include "run-command.h"
+#include "server-info.h"
#include "sigchain.h"
#include "strbuf.h"
#include "string-list.h"
@@ -32,7 +36,6 @@ static int write_bitmaps = -1;
static int use_delta_islands;
static int run_update_server_info = 1;
static char *packdir, *packtmp_name, *packtmp;
-static char *cruft_expiration;
static const char *const git_repack_usage[] = {
N_("git repack [<options>]"),
@@ -150,7 +153,8 @@ static void remove_redundant_pack(const char *dir_name, const char *base_name)
}
static void prepare_pack_objects(struct child_process *cmd,
- const struct pack_objects_args *args)
+ const struct pack_objects_args *args,
+ const char *out)
{
strvec_push(&cmd->args, "pack-objects");
if (args->window)
@@ -173,7 +177,7 @@ static void prepare_pack_objects(struct child_process *cmd,
strvec_push(&cmd->args, "--quiet");
if (delta_base_offset)
strvec_push(&cmd->args, "--delta-base-offset");
- strvec_push(&cmd->args, packtmp);
+ strvec_push(&cmd->args, out);
cmd->git_cmd = 1;
cmd->out = -1;
}
@@ -182,8 +186,9 @@ static void prepare_pack_objects(struct child_process *cmd,
* Write oid to the given struct child_process's stdin, starting it first if
* necessary.
*/
-static int write_oid(const struct object_id *oid, struct packed_git *pack,
- uint32_t pos, void *data)
+static int write_oid(const struct object_id *oid,
+ struct packed_git *pack UNUSED,
+ uint32_t pos UNUSED, void *data)
{
struct child_process *cmd = data;
@@ -241,7 +246,7 @@ static void repack_promisor_objects(const struct pack_objects_args *args,
FILE *out;
struct strbuf line = STRBUF_INIT;
- prepare_pack_objects(&cmd, args);
+ prepare_pack_objects(&cmd, args, packtmp);
cmd.in = -1;
/*
@@ -321,7 +326,8 @@ static int geometry_cmp(const void *va, const void *vb)
}
static void init_pack_geometry(struct pack_geometry **geometry_p,
- struct string_list *existing_kept_packs)
+ struct string_list *existing_kept_packs,
+ const struct pack_objects_args *args)
{
struct packed_git *p;
struct pack_geometry *geometry;
@@ -331,6 +337,14 @@ static void init_pack_geometry(struct pack_geometry **geometry_p,
geometry = *geometry_p;
for (p = get_all_packs(the_repository); p; p = p->next) {
+ if (args->local && !p->pack_local)
+ /*
+ * When asked to only repack local packfiles we skip
+ * over any packfiles that are borrowed from alternate
+ * object directories.
+ */
+ continue;
+
if (!pack_kept_objects) {
/*
* Any pack that has its pack_keep bit set will appear
@@ -444,8 +458,10 @@ static void split_pack_geometry(struct pack_geometry *geometry, int factor)
geometry->split = split;
}
-static struct packed_git *get_largest_active_pack(struct pack_geometry *geometry)
+static struct packed_git *get_preferred_pack(struct pack_geometry *geometry)
{
+ uint32_t i;
+
if (!geometry) {
/*
* No geometry means either an all-into-one repack (in which
@@ -460,7 +476,21 @@ static struct packed_git *get_largest_active_pack(struct pack_geometry *geometry
}
if (geometry->split == geometry->pack_nr)
return NULL;
- return geometry->pack[geometry->pack_nr - 1];
+
+ /*
+ * The preferred pack is the largest pack above the split line. In
+ * other words, it is the largest pack that does not get rolled up in
+ * the geometric repack.
+ */
+ for (i = geometry->pack_nr; i > geometry->split; i--)
+ /*
+ * A pack that is not local would never be included in a
+ * multi-pack index. We thus skip over any non-local packs.
+ */
+ if (geometry->pack[i - 1]->pack_local)
+ return geometry->pack[i - 1];
+
+ return NULL;
}
static void clear_pack_geometry(struct pack_geometry *geometry)
@@ -554,6 +584,17 @@ static void midx_included_packs(struct string_list *include,
for (i = geometry->split; i < geometry->pack_nr; i++) {
struct packed_git *p = geometry->pack[i];
+ /*
+ * The multi-pack index never refers to packfiles part
+ * of an alternate object database, so we skip these.
+ * While git-multi-pack-index(1) would silently ignore
+ * them anyway, this allows us to skip executing the
+ * command completely when we have only non-local
+ * packfiles.
+ */
+ if (!p->pack_local)
+ continue;
+
strbuf_addstr(&buf, pack_basename(p));
strbuf_strip_suffix(&buf, ".pack");
strbuf_addstr(&buf, ".idx");
@@ -587,7 +628,7 @@ static int write_midx_included_packs(struct string_list *include,
{
struct child_process cmd = CHILD_PROCESS_INIT;
struct string_list_item *item;
- struct packed_git *largest = get_largest_active_pack(geometry);
+ struct packed_git *preferred = get_preferred_pack(geometry);
FILE *in;
int ret;
@@ -608,9 +649,9 @@ static int write_midx_included_packs(struct string_list *include,
if (write_bitmaps)
strvec_push(&cmd.args, "--bitmap");
- if (largest)
+ if (preferred)
strvec_pushf(&cmd.args, "--preferred-pack=%s",
- pack_basename(largest));
+ pack_basename(preferred));
if (refs_snapshot)
strvec_pushf(&cmd.args, "--refs-snapshot=%s", refs_snapshot);
@@ -657,7 +698,9 @@ static void remove_redundant_bitmaps(struct string_list *include,
}
static int write_cruft_pack(const struct pack_objects_args *args,
+ const char *destination,
const char *pack_prefix,
+ const char *cruft_expiration,
struct string_list *names,
struct string_list *existing_packs,
struct string_list *existing_kept_packs)
@@ -667,8 +710,10 @@ static int write_cruft_pack(const struct pack_objects_args *args,
struct string_list_item *item;
FILE *in, *out;
int ret;
+ const char *scratch;
+ int local = skip_prefix(destination, packdir, &scratch);
- prepare_pack_objects(&cmd, args);
+ prepare_pack_objects(&cmd, args, destination);
strvec_push(&cmd.args, "--cruft");
if (cruft_expiration)
@@ -693,6 +738,10 @@ static int write_cruft_pack(const struct pack_objects_args *args,
* By the time it is read here, it contains only the pack(s)
* that were just written, which is exactly the set of packs we
* want to consider kept.
+ *
+ * If `--expire-to` is given, the double-use served by `names`
+ * ensures that the pack written to `--expire-to` excludes any
+ * objects contained in the cruft pack.
*/
in = xfdopen(cmd.in, "w");
for_each_string_list_item(item, names)
@@ -710,9 +759,14 @@ static int write_cruft_pack(const struct pack_objects_args *args,
if (line.len != the_hash_algo->hexsz)
die(_("repack: Expecting full hex object ID lines only "
"from pack-objects."));
-
- item = string_list_append(names, line.buf);
- item->util = populate_pack_exts(line.buf);
+ /*
+ * avoid putting packs written outside of the repository in the
+ * list of names
+ */
+ if (local) {
+ item = string_list_append(names, line.buf);
+ item->util = populate_pack_exts(line.buf);
+ }
}
fclose(out);
@@ -744,6 +798,8 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
struct pack_objects_args cruft_po_args = {NULL};
int geometric_factor = 0;
int write_midx = 0;
+ const char *cruft_expiration = NULL;
+ const char *expire_to = NULL;
struct option builtin_repack_options[] = {
OPT_BIT('a', NULL, &pack_everything,
@@ -755,7 +811,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
N_("same as -a, pack unreachable cruft objects separately"),
PACK_CRUFT),
OPT_STRING(0, "cruft-expiration", &cruft_expiration, N_("approxidate"),
- N_("with -C, expire objects older than this")),
+ N_("with --cruft, expire objects older than this")),
OPT_BOOL('d', NULL, &delete_redundant,
N_("remove redundant packs, and run git-prune-packed")),
OPT_BOOL('f', NULL, &po_args.no_reuse_delta,
@@ -793,6 +849,8 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
N_("find a geometric progression with factor <N>")),
OPT_BOOL('m', "write-midx", &write_midx,
N_("write a multi-pack index of the resulting packs")),
+ OPT_STRING(0, "expire-to", &expire_to, N_("dir"),
+ N_("pack prefix to store a pack containing pruned objects")),
OPT_END()
};
@@ -832,6 +890,18 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
if (write_bitmaps && !(pack_everything & ALL_INTO_ONE) && !write_midx)
die(_(incremental_bitmap_conflict_error));
+ if (write_bitmaps && po_args.local && has_alt_odb(the_repository)) {
+ /*
+ * When asked to do a local repack, but we have
+ * packfiles that are inherited from an alternate, then
+ * we cannot guarantee that the multi-pack-index would
+ * have full coverage of all objects. We thus disable
+ * writing bitmaps in that case.
+ */
+ warning(_("disabling bitmap writing, as some objects are not being packed"));
+ write_bitmaps = 0;
+ }
+
if (write_midx && write_bitmaps) {
struct strbuf path = STRBUF_INIT;
@@ -854,11 +924,11 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
if (geometric_factor) {
if (pack_everything)
die(_("options '%s' and '%s' cannot be used together"), "--geometric", "-A/-a");
- init_pack_geometry(&geometry, &existing_kept_packs);
+ init_pack_geometry(&geometry, &existing_kept_packs, &po_args);
split_pack_geometry(geometry, geometric_factor);
}
- prepare_pack_objects(&cmd, &po_args);
+ prepare_pack_objects(&cmd, &po_args, packtmp);
show_progress = !po_args.quiet && isatty(2);
@@ -884,7 +954,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
strvec_push(&cmd.args, "--reflog");
strvec_push(&cmd.args, "--indexed-objects");
}
- if (has_promisor_remote())
+ if (repo_has_promisor_remote(the_repository))
strvec_push(&cmd.args, "--exclude-promisor-objects");
if (!write_midx) {
if (write_bitmaps > 0)
@@ -931,7 +1001,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
ret = start_command(&cmd);
if (ret)
- return ret;
+ goto cleanup;
if (geometry) {
FILE *in = xfdopen(cmd.in, "w");
@@ -956,10 +1026,11 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
item = string_list_append(&names, line.buf);
item->util = populate_pack_exts(item->string);
}
+ strbuf_release(&line);
fclose(out);
ret = finish_command(&cmd);
if (ret)
- return ret;
+ goto cleanup;
if (!names.nr && !po_args.quiet)
printf_ln(_("Nothing new to pack."));
@@ -984,11 +1055,45 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
cruft_po_args.local = po_args.local;
cruft_po_args.quiet = po_args.quiet;
- ret = write_cruft_pack(&cruft_po_args, pack_prefix, &names,
+ ret = write_cruft_pack(&cruft_po_args, packtmp, pack_prefix,
+ cruft_expiration, &names,
&existing_nonkept_packs,
&existing_kept_packs);
if (ret)
- return ret;
+ goto cleanup;
+
+ if (delete_redundant && expire_to) {
+ /*
+ * If `--expire-to` is given with `-d`, it's possible
+ * that we're about to prune some objects. With cruft
+ * packs, pruning is implicit: any objects from existing
+ * packs that weren't picked up by new packs are removed
+ * when their packs are deleted.
+ *
+ * Generate an additional cruft pack, with one twist:
+ * `names` now includes the name of the cruft pack
+ * written in the previous step. So the contents of
+ * _this_ cruft pack exclude everything contained in the
+ * existing cruft pack (that is, all of the unreachable
+ * objects which are no older than
+ * `--cruft-expiration`).
+ *
+ * To make this work, cruft_expiration must become NULL
+ * so that this cruft pack doesn't actually prune any
+ * objects. If it were non-NULL, this call would always
+ * generate an empty pack (since every object not in the
+ * cruft pack generated above will have an mtime older
+ * than the expiration).
+ */
+ ret = write_cruft_pack(&cruft_po_args, expire_to,
+ pack_prefix,
+ NULL,
+ &names,
+ &existing_nonkept_packs,
+ &existing_kept_packs);
+ if (ret)
+ goto cleanup;
+ }
}
string_list_sort(&names);
@@ -1063,7 +1168,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
string_list_clear(&include, 0);
if (ret)
- return ret;
+ goto cleanup;
}
reprepare_packed_git(the_repository);
@@ -1120,11 +1225,11 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
write_midx_file(get_object_directory(), NULL, NULL, flags);
}
+cleanup:
string_list_clear(&names, 1);
string_list_clear(&existing_nonkept_packs, 0);
string_list_clear(&existing_kept_packs, 0);
clear_pack_geometry(geometry);
- strbuf_release(&line);
- return 0;
+ return ret;
}