mirror of
https://github.com/git/git.git
synced 2025-01-21 15:04:02 +08:00
Merge branch 'cc/repack-sift-filtered-objects-to-separate-pack'
"git repack" machinery learns to pay attention to the "--filter=" option. * cc/repack-sift-filtered-objects-to-separate-pack: gc: add `gc.repackFilterTo` config option repack: implement `--filter-to` for storing filtered out objects gc: add `gc.repackFilter` config option repack: add `--filter=<filter-spec>` option pack-bitmap-write: rebuild using new bitmap when remapping repack: refactor finding pack prefix repack: refactor finishing pack-objects command t/helper: add 'find-pack' test-tool pack-objects: allow `--filter` without `--stdout`
This commit is contained in:
commit
1fdedb7c7d
@ -145,6 +145,22 @@ Multiple hooks are supported, but all must exit successfully, else the
|
||||
operation (either generating a cruft pack or unpacking unreachable
|
||||
objects) will be halted.
|
||||
|
||||
gc.repackFilter::
|
||||
When repacking, use the specified filter to move certain
|
||||
objects into a separate packfile. See the
|
||||
`--filter=<filter-spec>` option of linkgit:git-repack[1].
|
||||
|
||||
gc.repackFilterTo::
|
||||
When repacking and using a filter, see `gc.repackFilter`, the
|
||||
specified location will be used to create the packfile
|
||||
containing the filtered out objects. **WARNING:** The
|
||||
specified location should be accessible, using for example the
|
||||
Git alternates mechanism, otherwise the repo could be
|
||||
considered corrupt by Git as it migh not be able to access the
|
||||
objects in that packfile. See the `--filter-to=<dir>` option
|
||||
of linkgit:git-repack[1] and the `objects/info/alternates`
|
||||
section of linkgit:gitrepository-layout[5].
|
||||
|
||||
gc.rerereResolved::
|
||||
Records of conflicted merge you resolved earlier are
|
||||
kept for this many days when 'git rerere gc' is run.
|
||||
|
@ -296,8 +296,8 @@ So does `git bundle` (see linkgit:git-bundle[1]) when it creates a bundle.
|
||||
nevertheless.
|
||||
|
||||
--filter=<filter-spec>::
|
||||
Requires `--stdout`. Omits certain objects (usually blobs) from
|
||||
the resulting packfile. See linkgit:git-rev-list[1] for valid
|
||||
Omits certain objects (usually blobs) from the resulting
|
||||
packfile. See linkgit:git-rev-list[1] for valid
|
||||
`<filter-spec>` forms.
|
||||
|
||||
--no-filter::
|
||||
|
@ -143,6 +143,29 @@ depth is 4095.
|
||||
a larger and slower repository; see the discussion in
|
||||
`pack.packSizeLimit`.
|
||||
|
||||
--filter=<filter-spec>::
|
||||
Remove objects matching the filter specification from the
|
||||
resulting packfile and put them into a separate packfile. Note
|
||||
that objects used in the working directory are not filtered
|
||||
out. So for the split to fully work, it's best to perform it
|
||||
in a bare repo and to use the `-a` and `-d` options along with
|
||||
this option. Also `--no-write-bitmap-index` (or the
|
||||
`repack.writebitmaps` config option set to `false`) should be
|
||||
used otherwise writing bitmap index will fail, as it supposes
|
||||
a single packfile containing all the objects. See
|
||||
linkgit:git-rev-list[1] for valid `<filter-spec>` forms.
|
||||
|
||||
--filter-to=<dir>::
|
||||
Write the pack containing filtered out objects to the
|
||||
directory `<dir>`. Only useful with `--filter`. This can be
|
||||
used for putting the pack on a separate object directory that
|
||||
is accessed through the Git alternates mechanism. **WARNING:**
|
||||
If the packfile containing the filtered out objects is not
|
||||
accessible, the repo can become corrupt as it might not be
|
||||
possible to access the objects in that packfile. See the
|
||||
`objects` and `objects/info/alternates` sections of
|
||||
linkgit:gitrepository-layout[5].
|
||||
|
||||
-b::
|
||||
--write-bitmap-index::
|
||||
Write a reachability bitmap index as part of the repack. This
|
||||
|
1
Makefile
1
Makefile
@ -800,6 +800,7 @@ TEST_BUILTINS_OBJS += test-dump-untracked-cache.o
|
||||
TEST_BUILTINS_OBJS += test-env-helper.o
|
||||
TEST_BUILTINS_OBJS += test-example-decorate.o
|
||||
TEST_BUILTINS_OBJS += test-fast-rebase.o
|
||||
TEST_BUILTINS_OBJS += test-find-pack.o
|
||||
TEST_BUILTINS_OBJS += test-fsmonitor-client.o
|
||||
TEST_BUILTINS_OBJS += test-genrandom.o
|
||||
TEST_BUILTINS_OBJS += test-genzeros.o
|
||||
|
10
builtin/gc.c
10
builtin/gc.c
@ -61,6 +61,8 @@ static timestamp_t gc_log_expire_time;
|
||||
static const char *gc_log_expire = "1.day.ago";
|
||||
static const char *prune_expire = "2.weeks.ago";
|
||||
static const char *prune_worktrees_expire = "3.months.ago";
|
||||
static char *repack_filter;
|
||||
static char *repack_filter_to;
|
||||
static unsigned long big_pack_threshold;
|
||||
static unsigned long max_delta_cache_size = DEFAULT_DELTA_CACHE_SIZE;
|
||||
|
||||
@ -170,6 +172,9 @@ static void gc_config(void)
|
||||
git_config_get_ulong("gc.bigpackthreshold", &big_pack_threshold);
|
||||
git_config_get_ulong("pack.deltacachesize", &max_delta_cache_size);
|
||||
|
||||
git_config_get_string("gc.repackfilter", &repack_filter);
|
||||
git_config_get_string("gc.repackfilterto", &repack_filter_to);
|
||||
|
||||
git_config(git_default_config, NULL);
|
||||
}
|
||||
|
||||
@ -355,6 +360,11 @@ static void add_repack_all_option(struct string_list *keep_pack)
|
||||
|
||||
if (keep_pack)
|
||||
for_each_string_list(keep_pack, keep_one_pack, NULL);
|
||||
|
||||
if (repack_filter && *repack_filter)
|
||||
strvec_pushf(&repack, "--filter=%s", repack_filter);
|
||||
if (repack_filter_to && *repack_filter_to)
|
||||
strvec_pushf(&repack, "--filter-to=%s", repack_filter_to);
|
||||
}
|
||||
|
||||
static void add_repack_incremental_option(void)
|
||||
|
@ -4402,12 +4402,8 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
|
||||
if (!rev_list_all || !rev_list_reflog || !rev_list_index)
|
||||
unpack_unreachable_expiration = 0;
|
||||
|
||||
if (filter_options.choice) {
|
||||
if (!pack_to_stdout)
|
||||
die(_("cannot use --filter without --stdout"));
|
||||
if (stdin_packs)
|
||||
die(_("cannot use --filter with --stdin-packs"));
|
||||
}
|
||||
if (stdin_packs && filter_options.choice)
|
||||
die(_("cannot use --filter with --stdin-packs"));
|
||||
|
||||
if (stdin_packs && use_internal_rev_list)
|
||||
die(_("cannot use internal rev list with --stdin-packs"));
|
||||
|
164
builtin/repack.c
164
builtin/repack.c
@ -21,6 +21,7 @@
|
||||
#include "pack.h"
|
||||
#include "pack-bitmap.h"
|
||||
#include "refs.h"
|
||||
#include "list-objects-filter-options.h"
|
||||
|
||||
#define ALL_INTO_ONE 1
|
||||
#define LOOSEN_UNREACHABLE 2
|
||||
@ -56,6 +57,7 @@ struct pack_objects_args {
|
||||
int no_reuse_object;
|
||||
int quiet;
|
||||
int local;
|
||||
struct list_objects_filter_options filter_options;
|
||||
};
|
||||
|
||||
static int repack_config(const char *var, const char *value,
|
||||
@ -806,6 +808,86 @@ static void remove_redundant_bitmaps(struct string_list *include,
|
||||
strbuf_release(&path);
|
||||
}
|
||||
|
||||
static int finish_pack_objects_cmd(struct child_process *cmd,
|
||||
struct string_list *names,
|
||||
int local)
|
||||
{
|
||||
FILE *out;
|
||||
struct strbuf line = STRBUF_INIT;
|
||||
|
||||
out = xfdopen(cmd->out, "r");
|
||||
while (strbuf_getline_lf(&line, out) != EOF) {
|
||||
struct string_list_item *item;
|
||||
|
||||
if (line.len != the_hash_algo->hexsz)
|
||||
die(_("repack: Expecting full hex object ID lines only "
|
||||
"from pack-objects."));
|
||||
/*
|
||||
* 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);
|
||||
|
||||
strbuf_release(&line);
|
||||
|
||||
return finish_command(cmd);
|
||||
}
|
||||
|
||||
static int write_filtered_pack(const struct pack_objects_args *args,
|
||||
const char *destination,
|
||||
const char *pack_prefix,
|
||||
struct existing_packs *existing,
|
||||
struct string_list *names)
|
||||
{
|
||||
struct child_process cmd = CHILD_PROCESS_INIT;
|
||||
struct string_list_item *item;
|
||||
FILE *in;
|
||||
int ret;
|
||||
const char *caret;
|
||||
const char *scratch;
|
||||
int local = skip_prefix(destination, packdir, &scratch);
|
||||
|
||||
prepare_pack_objects(&cmd, args, destination);
|
||||
|
||||
strvec_push(&cmd.args, "--stdin-packs");
|
||||
|
||||
if (!pack_kept_objects)
|
||||
strvec_push(&cmd.args, "--honor-pack-keep");
|
||||
for_each_string_list_item(item, &existing->kept_packs)
|
||||
strvec_pushf(&cmd.args, "--keep-pack=%s", item->string);
|
||||
|
||||
cmd.in = -1;
|
||||
|
||||
ret = start_command(&cmd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Here 'names' contains only the pack(s) that were just
|
||||
* written, which is exactly the packs we want to keep. Also
|
||||
* 'existing_kept_packs' already contains the packs in
|
||||
* 'keep_pack_list'.
|
||||
*/
|
||||
in = xfdopen(cmd.in, "w");
|
||||
for_each_string_list_item(item, names)
|
||||
fprintf(in, "^%s-%s.pack\n", pack_prefix, item->string);
|
||||
for_each_string_list_item(item, &existing->non_kept_packs)
|
||||
fprintf(in, "%s.pack\n", item->string);
|
||||
for_each_string_list_item(item, &existing->cruft_packs)
|
||||
fprintf(in, "%s.pack\n", item->string);
|
||||
caret = pack_kept_objects ? "" : "^";
|
||||
for_each_string_list_item(item, &existing->kept_packs)
|
||||
fprintf(in, "%s%s.pack\n", caret, item->string);
|
||||
fclose(in);
|
||||
|
||||
return finish_pack_objects_cmd(&cmd, names, local);
|
||||
}
|
||||
|
||||
static int write_cruft_pack(const struct pack_objects_args *args,
|
||||
const char *destination,
|
||||
const char *pack_prefix,
|
||||
@ -814,9 +896,8 @@ static int write_cruft_pack(const struct pack_objects_args *args,
|
||||
struct existing_packs *existing)
|
||||
{
|
||||
struct child_process cmd = CHILD_PROCESS_INIT;
|
||||
struct strbuf line = STRBUF_INIT;
|
||||
struct string_list_item *item;
|
||||
FILE *in, *out;
|
||||
FILE *in;
|
||||
int ret;
|
||||
const char *scratch;
|
||||
int local = skip_prefix(destination, packdir, &scratch);
|
||||
@ -861,27 +942,18 @@ static int write_cruft_pack(const struct pack_objects_args *args,
|
||||
fprintf(in, "%s.pack\n", item->string);
|
||||
fclose(in);
|
||||
|
||||
out = xfdopen(cmd.out, "r");
|
||||
while (strbuf_getline_lf(&line, out) != EOF) {
|
||||
struct string_list_item *item;
|
||||
return finish_pack_objects_cmd(&cmd, names, local);
|
||||
}
|
||||
|
||||
if (line.len != the_hash_algo->hexsz)
|
||||
die(_("repack: Expecting full hex object ID lines only "
|
||||
"from pack-objects."));
|
||||
/*
|
||||
* 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);
|
||||
|
||||
strbuf_release(&line);
|
||||
|
||||
return finish_command(&cmd);
|
||||
static const char *find_pack_prefix(const char *packdir, const char *packtmp)
|
||||
{
|
||||
const char *pack_prefix;
|
||||
if (!skip_prefix(packtmp, packdir, &pack_prefix))
|
||||
die(_("pack prefix %s does not begin with objdir %s"),
|
||||
packtmp, packdir);
|
||||
if (*pack_prefix == '/')
|
||||
pack_prefix++;
|
||||
return pack_prefix;
|
||||
}
|
||||
|
||||
int cmd_repack(int argc, const char **argv, const char *prefix)
|
||||
@ -891,10 +963,8 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
|
||||
struct string_list names = STRING_LIST_INIT_DUP;
|
||||
struct existing_packs existing = EXISTING_PACKS_INIT;
|
||||
struct pack_geometry geometry = { 0 };
|
||||
struct strbuf line = STRBUF_INIT;
|
||||
struct tempfile *refs_snapshot = NULL;
|
||||
int i, ext, ret;
|
||||
FILE *out;
|
||||
int show_progress;
|
||||
|
||||
/* variables to be filled by option parsing */
|
||||
@ -907,6 +977,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
|
||||
int write_midx = 0;
|
||||
const char *cruft_expiration = NULL;
|
||||
const char *expire_to = NULL;
|
||||
const char *filter_to = NULL;
|
||||
|
||||
struct option builtin_repack_options[] = {
|
||||
OPT_BIT('a', NULL, &pack_everything,
|
||||
@ -948,6 +1019,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
|
||||
N_("limits the maximum number of threads")),
|
||||
OPT_STRING(0, "max-pack-size", &po_args.max_pack_size, N_("bytes"),
|
||||
N_("maximum size of each packfile")),
|
||||
OPT_PARSE_LIST_OBJECTS_FILTER(&po_args.filter_options),
|
||||
OPT_BOOL(0, "pack-kept-objects", &pack_kept_objects,
|
||||
N_("repack objects in packs marked with .keep")),
|
||||
OPT_STRING_LIST(0, "keep-pack", &keep_pack_list, N_("name"),
|
||||
@ -958,9 +1030,13 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
|
||||
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_STRING(0, "filter-to", &filter_to, N_("dir"),
|
||||
N_("pack prefix to store a pack containing filtered out objects")),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
list_objects_filter_init(&po_args.filter_options);
|
||||
|
||||
git_config(repack_config, &cruft_po_args);
|
||||
|
||||
argc = parse_options(argc, argv, prefix, builtin_repack_options,
|
||||
@ -1101,6 +1177,12 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
|
||||
strvec_push(&cmd.args, "--incremental");
|
||||
}
|
||||
|
||||
if (po_args.filter_options.choice)
|
||||
strvec_pushf(&cmd.args, "--filter=%s",
|
||||
expand_list_objects_filter_spec(&po_args.filter_options));
|
||||
else if (filter_to)
|
||||
die(_("option '%s' can only be used along with '%s'"), "--filter-to", "--filter");
|
||||
|
||||
if (geometry.split_factor)
|
||||
cmd.in = -1;
|
||||
else
|
||||
@ -1124,18 +1206,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
|
||||
fclose(in);
|
||||
}
|
||||
|
||||
out = xfdopen(cmd.out, "r");
|
||||
while (strbuf_getline_lf(&line, out) != EOF) {
|
||||
struct string_list_item *item;
|
||||
|
||||
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(item->string);
|
||||
}
|
||||
strbuf_release(&line);
|
||||
fclose(out);
|
||||
ret = finish_command(&cmd);
|
||||
ret = finish_pack_objects_cmd(&cmd, &names, 1);
|
||||
if (ret)
|
||||
goto cleanup;
|
||||
|
||||
@ -1143,12 +1214,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
|
||||
printf_ln(_("Nothing new to pack."));
|
||||
|
||||
if (pack_everything & PACK_CRUFT) {
|
||||
const char *pack_prefix;
|
||||
if (!skip_prefix(packtmp, packdir, &pack_prefix))
|
||||
die(_("pack prefix %s does not begin with objdir %s"),
|
||||
packtmp, packdir);
|
||||
if (*pack_prefix == '/')
|
||||
pack_prefix++;
|
||||
const char *pack_prefix = find_pack_prefix(packdir, packtmp);
|
||||
|
||||
if (!cruft_po_args.window)
|
||||
cruft_po_args.window = po_args.window;
|
||||
@ -1203,6 +1269,19 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
|
||||
}
|
||||
}
|
||||
|
||||
if (po_args.filter_options.choice) {
|
||||
if (!filter_to)
|
||||
filter_to = packtmp;
|
||||
|
||||
ret = write_filtered_pack(&po_args,
|
||||
filter_to,
|
||||
find_pack_prefix(packdir, packtmp),
|
||||
&existing,
|
||||
&names);
|
||||
if (ret)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
string_list_sort(&names);
|
||||
|
||||
close_object_store(the_repository->objects);
|
||||
@ -1295,6 +1374,7 @@ cleanup:
|
||||
string_list_clear(&names, 1);
|
||||
existing_packs_release(&existing);
|
||||
free_pack_geometry(&geometry);
|
||||
list_objects_filter_release(&po_args.filter_options);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -413,15 +413,19 @@ static int fill_bitmap_commit(struct bb_commit *ent,
|
||||
|
||||
if (old_bitmap && mapping) {
|
||||
struct ewah_bitmap *old = bitmap_for_commit(old_bitmap, c);
|
||||
struct bitmap *remapped = bitmap_new();
|
||||
/*
|
||||
* If this commit has an old bitmap, then translate that
|
||||
* bitmap and add its bits to this one. No need to walk
|
||||
* parents or the tree for this commit.
|
||||
*/
|
||||
if (old && !rebuild_bitmap(mapping, old, ent->bitmap)) {
|
||||
if (old && !rebuild_bitmap(mapping, old, remapped)) {
|
||||
bitmap_or(ent->bitmap, remapped);
|
||||
bitmap_free(remapped);
|
||||
reused_bitmaps_nr++;
|
||||
continue;
|
||||
}
|
||||
bitmap_free(remapped);
|
||||
}
|
||||
|
||||
/*
|
||||
|
50
t/helper/test-find-pack.c
Normal file
50
t/helper/test-find-pack.c
Normal file
@ -0,0 +1,50 @@
|
||||
#include "test-tool.h"
|
||||
#include "object-name.h"
|
||||
#include "object-store.h"
|
||||
#include "packfile.h"
|
||||
#include "parse-options.h"
|
||||
#include "setup.h"
|
||||
|
||||
/*
|
||||
* Display the path(s), one per line, of the packfile(s) containing
|
||||
* the given object.
|
||||
*
|
||||
* If '--check-count <n>' is passed, then error out if the number of
|
||||
* packfiles containing the object is not <n>.
|
||||
*/
|
||||
|
||||
static const char *find_pack_usage[] = {
|
||||
"test-tool find-pack [--check-count <n>] <object>",
|
||||
NULL
|
||||
};
|
||||
|
||||
int cmd__find_pack(int argc, const char **argv)
|
||||
{
|
||||
struct object_id oid;
|
||||
struct packed_git *p;
|
||||
int count = -1, actual_count = 0;
|
||||
const char *prefix = setup_git_directory();
|
||||
|
||||
struct option options[] = {
|
||||
OPT_INTEGER('c', "check-count", &count, "expected number of packs"),
|
||||
OPT_END(),
|
||||
};
|
||||
|
||||
argc = parse_options(argc, argv, prefix, options, find_pack_usage, 0);
|
||||
if (argc != 1)
|
||||
usage(find_pack_usage[0]);
|
||||
|
||||
if (repo_get_oid(the_repository, argv[0], &oid))
|
||||
die("cannot parse %s as an object name", argv[0]);
|
||||
|
||||
for (p = get_all_packs(the_repository); p; p = p->next)
|
||||
if (find_pack_entry_one(oid.hash, p)) {
|
||||
printf("%s\n", p->pack_name);
|
||||
actual_count++;
|
||||
}
|
||||
|
||||
if (count > -1 && count != actual_count)
|
||||
die("bad packfile count %d instead of %d", actual_count, count);
|
||||
|
||||
return 0;
|
||||
}
|
@ -31,6 +31,7 @@ static struct test_cmd cmds[] = {
|
||||
{ "env-helper", cmd__env_helper },
|
||||
{ "example-decorate", cmd__example_decorate },
|
||||
{ "fast-rebase", cmd__fast_rebase },
|
||||
{ "find-pack", cmd__find_pack },
|
||||
{ "fsmonitor-client", cmd__fsmonitor_client },
|
||||
{ "genrandom", cmd__genrandom },
|
||||
{ "genzeros", cmd__genzeros },
|
||||
|
@ -25,6 +25,7 @@ int cmd__dump_reftable(int argc, const char **argv);
|
||||
int cmd__env_helper(int argc, const char **argv);
|
||||
int cmd__example_decorate(int argc, const char **argv);
|
||||
int cmd__fast_rebase(int argc, const char **argv);
|
||||
int cmd__find_pack(int argc, const char **argv);
|
||||
int cmd__fsmonitor_client(int argc, const char **argv);
|
||||
int cmd__genrandom(int argc, const char **argv);
|
||||
int cmd__genzeros(int argc, const char **argv);
|
||||
|
82
t/t0081-find-pack.sh
Executable file
82
t/t0081-find-pack.sh
Executable file
@ -0,0 +1,82 @@
|
||||
#!/bin/sh
|
||||
|
||||
test_description='test `test-tool find-pack`'
|
||||
|
||||
TEST_PASSES_SANITIZE_LEAK=true
|
||||
. ./test-lib.sh
|
||||
|
||||
test_expect_success 'setup' '
|
||||
test_commit one &&
|
||||
test_commit two &&
|
||||
test_commit three &&
|
||||
test_commit four &&
|
||||
test_commit five
|
||||
'
|
||||
|
||||
test_expect_success 'repack everything into a single packfile' '
|
||||
git repack -a -d --no-write-bitmap-index &&
|
||||
|
||||
head_commit_pack=$(test-tool find-pack HEAD) &&
|
||||
head_tree_pack=$(test-tool find-pack HEAD^{tree}) &&
|
||||
one_pack=$(test-tool find-pack HEAD:one.t) &&
|
||||
three_pack=$(test-tool find-pack HEAD:three.t) &&
|
||||
old_commit_pack=$(test-tool find-pack HEAD~4) &&
|
||||
|
||||
test-tool find-pack --check-count 1 HEAD &&
|
||||
test-tool find-pack --check-count=1 HEAD^{tree} &&
|
||||
! test-tool find-pack --check-count=0 HEAD:one.t &&
|
||||
! test-tool find-pack -c 2 HEAD:one.t &&
|
||||
test-tool find-pack -c 1 HEAD:three.t &&
|
||||
|
||||
# Packfile exists at the right path
|
||||
case "$head_commit_pack" in
|
||||
".git/objects/pack/pack-"*".pack") true ;;
|
||||
*) false ;;
|
||||
esac &&
|
||||
test -f "$head_commit_pack" &&
|
||||
|
||||
# Everything is in the same pack
|
||||
test "$head_commit_pack" = "$head_tree_pack" &&
|
||||
test "$head_commit_pack" = "$one_pack" &&
|
||||
test "$head_commit_pack" = "$three_pack" &&
|
||||
test "$head_commit_pack" = "$old_commit_pack"
|
||||
'
|
||||
|
||||
test_expect_success 'add more packfiles' '
|
||||
git rev-parse HEAD^{tree} HEAD:two.t HEAD:four.t >objects &&
|
||||
git pack-objects .git/objects/pack/mypackname1 >packhash1 <objects &&
|
||||
|
||||
git rev-parse HEAD~ HEAD~^{tree} HEAD:five.t >objects &&
|
||||
git pack-objects .git/objects/pack/mypackname2 >packhash2 <objects &&
|
||||
|
||||
head_commit_pack=$(test-tool find-pack HEAD) &&
|
||||
|
||||
# HEAD^{tree} is in 2 packfiles
|
||||
test-tool find-pack HEAD^{tree} >head_tree_packs &&
|
||||
grep "$head_commit_pack" head_tree_packs &&
|
||||
grep mypackname1 head_tree_packs &&
|
||||
! grep mypackname2 head_tree_packs &&
|
||||
test-tool find-pack --check-count 2 HEAD^{tree} &&
|
||||
! test-tool find-pack --check-count 1 HEAD^{tree} &&
|
||||
|
||||
# HEAD:five.t is also in 2 packfiles
|
||||
test-tool find-pack HEAD:five.t >five_packs &&
|
||||
grep "$head_commit_pack" five_packs &&
|
||||
! grep mypackname1 five_packs &&
|
||||
grep mypackname2 five_packs &&
|
||||
test-tool find-pack -c 2 HEAD:five.t &&
|
||||
! test-tool find-pack --check-count=0 HEAD:five.t
|
||||
'
|
||||
|
||||
test_expect_success 'add more commits (as loose objects)' '
|
||||
test_commit six &&
|
||||
test_commit seven &&
|
||||
|
||||
test -z "$(test-tool find-pack HEAD)" &&
|
||||
test -z "$(test-tool find-pack HEAD:six.t)" &&
|
||||
test-tool find-pack --check-count 0 HEAD &&
|
||||
test-tool find-pack -c 0 HEAD:six.t &&
|
||||
! test-tool find-pack -c 1 HEAD:seven.t
|
||||
'
|
||||
|
||||
test_done
|
@ -53,6 +53,14 @@ test_expect_success 'verify blob:none packfile has no blobs' '
|
||||
! grep blob verify_result
|
||||
'
|
||||
|
||||
test_expect_success 'verify blob:none packfile without --stdout' '
|
||||
git -C r1 pack-objects --revs --filter=blob:none mypackname >packhash <<-EOF &&
|
||||
HEAD
|
||||
EOF
|
||||
git -C r1 verify-pack -v "mypackname-$(cat packhash).pack" >verify_result &&
|
||||
! grep blob verify_result
|
||||
'
|
||||
|
||||
test_expect_success 'verify normal and blob:none packfiles have same commits/trees' '
|
||||
git -C r1 verify-pack -v ../all.pack >verify_result &&
|
||||
grep -E "commit|tree" verify_result |
|
||||
|
@ -202,6 +202,30 @@ test_expect_success 'one of gc.reflogExpire{Unreachable,}=never does not skip "e
|
||||
grep -E "^trace: (built-in|exec|run_command): git reflog expire --" trace.out
|
||||
'
|
||||
|
||||
test_expect_success 'gc.repackFilter launches repack with a filter' '
|
||||
git clone --no-local --bare . bare.git &&
|
||||
|
||||
git -C bare.git -c gc.cruftPacks=false gc &&
|
||||
test_stdout_line_count = 1 ls bare.git/objects/pack/*.pack &&
|
||||
|
||||
GIT_TRACE=$(pwd)/trace.out git -C bare.git -c gc.repackFilter=blob:none \
|
||||
-c repack.writeBitmaps=false -c gc.cruftPacks=false gc &&
|
||||
test_stdout_line_count = 2 ls bare.git/objects/pack/*.pack &&
|
||||
grep -E "^trace: (built-in|exec|run_command): git repack .* --filter=blob:none ?.*" trace.out
|
||||
'
|
||||
|
||||
test_expect_success 'gc.repackFilterTo store filtered out objects' '
|
||||
test_when_finished "rm -rf bare.git filtered.git" &&
|
||||
|
||||
git init --bare filtered.git &&
|
||||
git -C bare.git -c gc.repackFilter=blob:none \
|
||||
-c gc.repackFilterTo=../filtered.git/objects/pack/pack \
|
||||
-c repack.writeBitmaps=false -c gc.cruftPacks=false gc &&
|
||||
|
||||
test_stdout_line_count = 1 ls bare.git/objects/pack/*.pack &&
|
||||
test_stdout_line_count = 1 ls filtered.git/objects/pack/*.pack
|
||||
'
|
||||
|
||||
prepare_cruft_history () {
|
||||
test_commit base &&
|
||||
|
||||
|
@ -327,6 +327,203 @@ test_expect_success 'auto-bitmaps do not complain if unavailable' '
|
||||
test_must_be_empty actual
|
||||
'
|
||||
|
||||
test_expect_success 'repacking with a filter works' '
|
||||
git -C bare.git repack -a -d &&
|
||||
test_stdout_line_count = 1 ls bare.git/objects/pack/*.pack &&
|
||||
git -C bare.git -c repack.writebitmaps=false repack -a -d --filter=blob:none &&
|
||||
test_stdout_line_count = 2 ls bare.git/objects/pack/*.pack &&
|
||||
commit_pack=$(test-tool -C bare.git find-pack -c 1 HEAD) &&
|
||||
blob_pack=$(test-tool -C bare.git find-pack -c 1 HEAD:file1) &&
|
||||
test "$commit_pack" != "$blob_pack" &&
|
||||
tree_pack=$(test-tool -C bare.git find-pack -c 1 HEAD^{tree}) &&
|
||||
test "$tree_pack" = "$commit_pack" &&
|
||||
blob_pack2=$(test-tool -C bare.git find-pack -c 1 HEAD:file2) &&
|
||||
test "$blob_pack2" = "$blob_pack"
|
||||
'
|
||||
|
||||
test_expect_success '--filter fails with --write-bitmap-index' '
|
||||
test_must_fail \
|
||||
env GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0 \
|
||||
git -C bare.git repack -a -d --write-bitmap-index --filter=blob:none
|
||||
'
|
||||
|
||||
test_expect_success 'repacking with two filters works' '
|
||||
git init two-filters &&
|
||||
(
|
||||
cd two-filters &&
|
||||
mkdir subdir &&
|
||||
test_commit foo &&
|
||||
test_commit subdir_bar subdir/bar &&
|
||||
test_commit subdir_baz subdir/baz
|
||||
) &&
|
||||
git clone --no-local --bare two-filters two-filters.git &&
|
||||
(
|
||||
cd two-filters.git &&
|
||||
test_stdout_line_count = 1 ls objects/pack/*.pack &&
|
||||
git -c repack.writebitmaps=false repack -a -d \
|
||||
--filter=blob:none --filter=tree:1 &&
|
||||
test_stdout_line_count = 2 ls objects/pack/*.pack &&
|
||||
commit_pack=$(test-tool find-pack -c 1 HEAD) &&
|
||||
blob_pack=$(test-tool find-pack -c 1 HEAD:foo.t) &&
|
||||
root_tree_pack=$(test-tool find-pack -c 1 HEAD^{tree}) &&
|
||||
subdir_tree_hash=$(git ls-tree --object-only HEAD -- subdir) &&
|
||||
subdir_tree_pack=$(test-tool find-pack -c 1 "$subdir_tree_hash") &&
|
||||
|
||||
# Root tree and subdir tree are not in the same packfiles
|
||||
test "$commit_pack" != "$blob_pack" &&
|
||||
test "$commit_pack" = "$root_tree_pack" &&
|
||||
test "$blob_pack" = "$subdir_tree_pack"
|
||||
)
|
||||
'
|
||||
|
||||
prepare_for_keep_packs () {
|
||||
git init keep-packs &&
|
||||
(
|
||||
cd keep-packs &&
|
||||
test_commit foo &&
|
||||
test_commit bar
|
||||
) &&
|
||||
git clone --no-local --bare keep-packs keep-packs.git &&
|
||||
(
|
||||
cd keep-packs.git &&
|
||||
|
||||
# Create two packs
|
||||
# The first pack will contain all of the objects except one blob
|
||||
git rev-list --objects --all >objs &&
|
||||
grep -v "bar.t" objs | git pack-objects pack &&
|
||||
# The second pack will contain the excluded object and be kept
|
||||
packid=$(grep "bar.t" objs | git pack-objects pack) &&
|
||||
>pack-$packid.keep &&
|
||||
|
||||
# Replace the existing pack with the 2 new ones
|
||||
rm -f objects/pack/pack* &&
|
||||
mv pack-* objects/pack/
|
||||
)
|
||||
}
|
||||
|
||||
test_expect_success '--filter works with .keep packs' '
|
||||
prepare_for_keep_packs &&
|
||||
(
|
||||
cd keep-packs.git &&
|
||||
|
||||
foo_pack=$(test-tool find-pack -c 1 HEAD:foo.t) &&
|
||||
bar_pack=$(test-tool find-pack -c 1 HEAD:bar.t) &&
|
||||
head_pack=$(test-tool find-pack -c 1 HEAD) &&
|
||||
|
||||
test "$foo_pack" != "$bar_pack" &&
|
||||
test "$foo_pack" = "$head_pack" &&
|
||||
|
||||
git -c repack.writebitmaps=false repack -a -d --filter=blob:none &&
|
||||
|
||||
foo_pack_1=$(test-tool find-pack -c 1 HEAD:foo.t) &&
|
||||
bar_pack_1=$(test-tool find-pack -c 1 HEAD:bar.t) &&
|
||||
head_pack_1=$(test-tool find-pack -c 1 HEAD) &&
|
||||
|
||||
# Object bar is still only in the old .keep pack
|
||||
test "$foo_pack_1" != "$foo_pack" &&
|
||||
test "$bar_pack_1" = "$bar_pack" &&
|
||||
test "$head_pack_1" != "$head_pack" &&
|
||||
|
||||
test "$foo_pack_1" != "$bar_pack_1" &&
|
||||
test "$foo_pack_1" != "$head_pack_1" &&
|
||||
test "$bar_pack_1" != "$head_pack_1"
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success '--filter works with --pack-kept-objects and .keep packs' '
|
||||
rm -rf keep-packs keep-packs.git &&
|
||||
prepare_for_keep_packs &&
|
||||
(
|
||||
cd keep-packs.git &&
|
||||
|
||||
foo_pack=$(test-tool find-pack -c 1 HEAD:foo.t) &&
|
||||
bar_pack=$(test-tool find-pack -c 1 HEAD:bar.t) &&
|
||||
head_pack=$(test-tool find-pack -c 1 HEAD) &&
|
||||
|
||||
test "$foo_pack" != "$bar_pack" &&
|
||||
test "$foo_pack" = "$head_pack" &&
|
||||
|
||||
git -c repack.writebitmaps=false repack -a -d --filter=blob:none \
|
||||
--pack-kept-objects &&
|
||||
|
||||
foo_pack_1=$(test-tool find-pack -c 1 HEAD:foo.t) &&
|
||||
test-tool find-pack -c 2 HEAD:bar.t >bar_pack_1 &&
|
||||
head_pack_1=$(test-tool find-pack -c 1 HEAD) &&
|
||||
|
||||
test "$foo_pack_1" != "$foo_pack" &&
|
||||
test "$foo_pack_1" != "$bar_pack" &&
|
||||
test "$head_pack_1" != "$head_pack" &&
|
||||
|
||||
# Object bar is in both the old .keep pack and the new
|
||||
# pack that contained the filtered out objects
|
||||
grep "$bar_pack" bar_pack_1 &&
|
||||
grep "$foo_pack_1" bar_pack_1 &&
|
||||
test "$foo_pack_1" != "$head_pack_1"
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success '--filter-to stores filtered out objects' '
|
||||
git -C bare.git repack -a -d &&
|
||||
test_stdout_line_count = 1 ls bare.git/objects/pack/*.pack &&
|
||||
|
||||
git init --bare filtered.git &&
|
||||
git -C bare.git -c repack.writebitmaps=false repack -a -d \
|
||||
--filter=blob:none \
|
||||
--filter-to=../filtered.git/objects/pack/pack &&
|
||||
test_stdout_line_count = 1 ls bare.git/objects/pack/pack-*.pack &&
|
||||
test_stdout_line_count = 1 ls filtered.git/objects/pack/pack-*.pack &&
|
||||
|
||||
commit_pack=$(test-tool -C bare.git find-pack -c 1 HEAD) &&
|
||||
blob_pack=$(test-tool -C bare.git find-pack -c 0 HEAD:file1) &&
|
||||
blob_hash=$(git -C bare.git rev-parse HEAD:file1) &&
|
||||
test -n "$blob_hash" &&
|
||||
blob_pack=$(test-tool -C filtered.git find-pack -c 1 $blob_hash) &&
|
||||
|
||||
echo $(pwd)/filtered.git/objects >bare.git/objects/info/alternates &&
|
||||
blob_pack=$(test-tool -C bare.git find-pack -c 1 HEAD:file1) &&
|
||||
blob_content=$(git -C bare.git show $blob_hash) &&
|
||||
test "$blob_content" = "content1"
|
||||
'
|
||||
|
||||
test_expect_success '--filter works with --max-pack-size' '
|
||||
rm -rf filtered.git &&
|
||||
git init --bare filtered.git &&
|
||||
git init max-pack-size &&
|
||||
(
|
||||
cd max-pack-size &&
|
||||
test_commit base &&
|
||||
# two blobs which exceed the maximum pack size
|
||||
test-tool genrandom foo 1048576 >foo &&
|
||||
git hash-object -w foo &&
|
||||
test-tool genrandom bar 1048576 >bar &&
|
||||
git hash-object -w bar &&
|
||||
git add foo bar &&
|
||||
git commit -m "adding foo and bar"
|
||||
) &&
|
||||
git clone --no-local --bare max-pack-size max-pack-size.git &&
|
||||
(
|
||||
cd max-pack-size.git &&
|
||||
git -c repack.writebitmaps=false repack -a -d --filter=blob:none \
|
||||
--max-pack-size=1M \
|
||||
--filter-to=../filtered.git/objects/pack/pack &&
|
||||
echo $(cd .. && pwd)/filtered.git/objects >objects/info/alternates &&
|
||||
|
||||
# Check that the 3 blobs are in different packfiles in filtered.git
|
||||
test_stdout_line_count = 3 ls ../filtered.git/objects/pack/pack-*.pack &&
|
||||
test_stdout_line_count = 1 ls objects/pack/pack-*.pack &&
|
||||
foo_pack=$(test-tool find-pack -c 1 HEAD:foo) &&
|
||||
bar_pack=$(test-tool find-pack -c 1 HEAD:bar) &&
|
||||
base_pack=$(test-tool find-pack -c 1 HEAD:base.t) &&
|
||||
test "$foo_pack" != "$bar_pack" &&
|
||||
test "$foo_pack" != "$base_pack" &&
|
||||
test "$bar_pack" != "$base_pack" &&
|
||||
for pack in "$foo_pack" "$bar_pack" "$base_pack"
|
||||
do
|
||||
case "$foo_pack" in */filtered.git/objects/pack/*) true ;; *) return 1 ;; esac
|
||||
done
|
||||
)
|
||||
'
|
||||
|
||||
objdir=.git/objects
|
||||
midx=$objdir/pack/multi-pack-index
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user