Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions Documentation/git-pack-objects.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ SYNOPSIS
[--no-reuse-delta] [--delta-base-offset] [--non-empty]
[--local] [--incremental] [--window=<n>] [--depth=<n>]
[--revs [--unpacked | --all]] [--keep-pack=<pack-name>]
[--ignore-pack-keep-from=<file>]
[--cruft] [--cruft-expiration=<time>]
[--stdout [--filter=<filter-spec>] | <base-name>]
[--shallow] [--keep-true-parents] [--[no-]sparse]
Expand Down Expand Up @@ -193,6 +194,17 @@ depth is 4095.
leading directory (e.g. `pack-123.pack`). The option could be
specified multiple times to keep multiple packs.

--ignore-pack-keep-from=<file>::
Read names of local packs from `<file>`, one per line in the
same form as for `--keep-pack`, and treat them as if they had
no .keep file, both for `--honor-pack-keep` and when deciding
which objects to loosen or keep with `--unpack-unreachable`,
`--keep-unreachable` and `--cruft`.
This is for callers like linkgit:git-repack[1] that are about
to delete those packs: a .keep file that appears on one of them
after the caller decided to delete it must not cause its objects
to be left out.

--incremental::
This flag causes an object already in a pack to be ignored
even if it would have otherwise been packed.
Expand Down
55 changes: 54 additions & 1 deletion builtin/pack-objects.c
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ static const char *const pack_usage[] = {
" [--no-reuse-delta] [--delta-base-offset] [--non-empty]\n"
" [--local] [--incremental] [--window=<n>] [--depth=<n>]\n"
" [--revs [--unpacked | --all]] [--keep-pack=<pack-name>]\n"
" [--ignore-pack-keep-from=<file>]\n"
" [--cruft] [--cruft-expiration=<time>]\n"
" [--stdout [--filter=<filter-spec>] | <base-name>]\n"
" [--shallow] [--keep-true-parents] [--[no-]sparse]\n"
Expand Down Expand Up @@ -4294,10 +4295,18 @@ static void enumerate_and_traverse_cruft_objects(struct string_list *fresh_packs
/*
* Re-mark only the fresh packs as kept so that objects in
* unknown packs do not halt the reachability traversal early.
* A pack given with --keep-pack must not halt it either, but as an
* "open" kept pack its objects are still left out. The kept-pack
* cache was built while the packs were still marked, so drop it
* too.
*/
repo_for_each_pack(the_repository, p)
repo_for_each_pack(the_repository, p) {
p->pack_keep_in_core = 0;
if (p->pack_keep_in_core_open)
ignore_packed_keep_in_core_open = 1;
}
mark_pack_kept_in_core(fresh_packs, 1);
repo_invalidate_kept_pack_caches(the_repository);

if (prepare_revision_walk(&revs))
die(_("revision walk setup failed"));
Expand Down Expand Up @@ -4343,6 +4352,14 @@ static void read_cruft_objects(void)

if (item) {
item->util = p;
} else if (p->pack_keep_in_core) {
/*
* Only --keep-pack marks a pack as kept this early.
* Make it an "open" kept pack as well, so that its
* objects are still left out once it is unmarked
* before the traversal; until then this has no effect.
*/
p->pack_keep_in_core_open = 1;
} else {
/*
* This pack wasn't mentioned in either the "fresh" or
Expand Down Expand Up @@ -4989,6 +5006,36 @@ static void get_object_list(struct rev_info *revs, struct strvec *argv)
oid_array_clear(&recent_objects);
}

/*
* Treat the local packs named in "path" as if they had no ".keep" file.
* The names are matched like those given with --keep-pack. This has to
* happen before anything looks at p->pack_keep, which is read from the
* disk only once, when the pack is first seen.
*/
static void ignore_pack_keep_from_file(const char *path)
{
struct string_list names = STRING_LIST_INIT_DUP;
struct strbuf buf = STRBUF_INIT;
struct packed_git *p;
FILE *fp = xfopen(path, "r");

names.cmp = fspathcmp;
while (strbuf_getline(&buf, fp) != EOF)
string_list_append(&names, buf.buf);
if (ferror(fp))
die_errno(_("could not read '%s'"), path);
fclose(fp);
string_list_sort(&names);

repo_for_each_pack(the_repository, p)
if (p->pack_local &&
string_list_has_string(&names, pack_basename(p)))
p->pack_keep = 0;

string_list_clear(&names, 0);
strbuf_release(&buf);
}

static void add_extra_kept_packs(const struct string_list *names)
{
struct packed_git *p;
Expand Down Expand Up @@ -5122,6 +5169,7 @@ int cmd_pack_objects(int argc,
int rev_list_index = 0;
enum stdin_packs_mode stdin_packs = STDIN_PACKS_MODE_NONE;
struct string_list keep_pack_list = STRING_LIST_INIT_NODUP;
char *ignore_pack_keep_from = NULL;
struct list_objects_filter_options filter_options =
LIST_OBJECTS_FILTER_INIT;
struct repo_config_values *cfg = repo_config_values(the_repository);
Expand Down Expand Up @@ -5206,6 +5254,8 @@ int cmd_pack_objects(int argc,
N_("ignore packs that have companion .keep file")),
OPT_STRING_LIST(0, "keep-pack", &keep_pack_list, N_("name"),
N_("ignore this pack")),
OPT_FILENAME(0, "ignore-pack-keep-from", &ignore_pack_keep_from,
N_("ignore .keep files of the packs named in <file>")),
OPT_INTEGER(0, "compression", &cfg->pack_compression_level,
N_("pack compression level")),
OPT_BOOL(0, "keep-true-parents", &grafts_keep_true_parents,
Expand Down Expand Up @@ -5433,6 +5483,8 @@ int cmd_pack_objects(int argc,
if (progress && all_progress_implied)
progress = 2;

if (ignore_pack_keep_from)
ignore_pack_keep_from_file(ignore_pack_keep_from);
add_extra_kept_packs(&keep_pack_list);
if (ignore_packed_keep_on_disk) {
struct packed_git *p;
Expand Down Expand Up @@ -5527,6 +5579,7 @@ int cmd_pack_objects(int argc,
clear_packing_data(&to_pack);
list_objects_filter_release(&filter_options);
string_list_clear(&keep_pack_list, 0);
free(ignore_pack_keep_from);
strvec_clear(&rp);

return 0;
Expand Down
23 changes: 23 additions & 0 deletions builtin/repack.c
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,28 @@ int cmd_repack(int argc,
existing.repo = repo;
existing_packs_collect(&existing, &keep_pack_list);

/*
* Tell pack-objects which packs we may delete. pack-objects looks
* for ".keep" files on its own, and one that appears on such a
* pack from now on must not make it leave out objects that would
* then be deleted with the pack.
*/
if (delete_redundant &&
((pack_everything & ALL_INTO_ONE) || geometry.split_factor) &&
existing_packs_has_non_kept(&existing)) {
struct strbuf path = STRBUF_INIT;
struct tempfile *non_kept_packs;

strbuf_addf(&path, "%s/tmp_non_kept_packs_XXXXXX",
repo_get_object_directory(repo));

non_kept_packs = xmks_tempfile(path.buf);
existing_packs_write_non_kept(&existing, non_kept_packs);
po_args.ignore_pack_keep_from = get_tempfile_path(non_kept_packs);

strbuf_release(&path);
}

if (geometry.split_factor) {
if (pack_everything)
die(_("options '%s' and '%s' cannot be used together"), "--geometric", "-A/-a");
Expand Down Expand Up @@ -644,6 +666,7 @@ int cmd_repack(int argc,
cruft_po_args.quiet = po_args.quiet;
cruft_po_args.delta_base_offset = po_args.delta_base_offset;
cruft_po_args.pack_kept_objects = 0;
cruft_po_args.ignore_pack_keep_from = po_args.ignore_pack_keep_from;

ret = write_cruft_pack(&opts, cruft_expiration,
combine_cruft_below_size, &names,
Expand Down
3 changes: 2 additions & 1 deletion odb/source-packed.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ struct odb_source_packed {
* Should not be accessed directly, but via
* `packfile_store_get_kept_pack_cache()`. The list of packs gets
* invalidated when the stored flags and the flags passed to
* `packfile_store_get_kept_pack_cache()` mismatch.
* `packfile_store_get_kept_pack_cache()` mismatch, or explicitly via
* `repo_invalidate_kept_pack_caches()`.
*/
struct {
struct packed_git **packs;
Expand Down
18 changes: 16 additions & 2 deletions packfile.c
Original file line number Diff line number Diff line change
Expand Up @@ -1881,15 +1881,29 @@ int packfile_fill_entry(struct packed_git *p,
return 1;
}

static void invalidate_kept_pack_cache(struct odb_source_packed *store)
{
FREE_AND_NULL(store->kept_cache.packs);
store->kept_cache.flags = 0;
}

void repo_invalidate_kept_pack_caches(struct repository *r)
{
struct odb_source_files *files =
odb_source_files_downcast(r->objects->source);

for (struct odb_files_dir *dir = files->dirs; dir; dir = dir->next)
invalidate_kept_pack_cache(dir->packed);
}

static void maybe_invalidate_kept_pack_cache(struct odb_source_packed *store,
unsigned flags)
{
if (!store->kept_cache.packs)
return;
if (store->kept_cache.flags == flags)
return;
FREE_AND_NULL(store->kept_cache.packs);
store->kept_cache.flags = 0;
invalidate_kept_pack_cache(store);
}

struct packed_git **packfile_store_get_kept_pack_cache(struct odb_source_packed *store,
Expand Down
7 changes: 7 additions & 0 deletions packfile.h
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,13 @@ enum kept_pack_type {
struct packed_git **packfile_store_get_kept_pack_cache(struct odb_source_packed *store,
unsigned flags);

/*
* Drop every packfile store's cache of kept packs, so that the next call
* to `packfile_store_get_kept_pack_cache()` rebuilds it, e.g. after
* changing which packs are kept in core.
*/
void repo_invalidate_kept_pack_caches(struct repository *r);

struct pack_window {
struct pack_window *next;
unsigned char *base;
Expand Down
26 changes: 26 additions & 0 deletions repack.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ void prepare_pack_objects(struct child_process *cmd,
strvec_push(&cmd->args, "--delta-base-offset");
if (!args->pack_kept_objects)
strvec_push(&cmd->args, "--honor-pack-keep");
if (args->ignore_pack_keep_from)
strvec_pushf(&cmd->args, "--ignore-pack-keep-from=%s",
args->ignore_pack_keep_from);
strvec_push(&cmd->args, out);
cmd->git_cmd = 1;
cmd->out = -1;
Expand Down Expand Up @@ -172,6 +175,29 @@ int existing_packs_has_non_kept(const struct existing_packs *existing)
return existing->non_kept_packs.nr || existing->cruft_packs.nr;
}

void existing_packs_write_non_kept(const struct existing_packs *existing,
struct tempfile *f)
{
struct string_list_item *item;
FILE *out = fdopen_tempfile(f, "w");

if (!out)
die(_("could not open tempfile %s for writing"),
get_tempfile_path(f));

for_each_string_list_item(item, &existing->non_kept_packs)
fprintf(out, "%s.pack\n", item->string);
for_each_string_list_item(item, &existing->cruft_packs)
fprintf(out, "%s.pack\n", item->string);

if (close_tempfile_gently(f)) {
int save_errno = errno;
delete_tempfile(&f);
errno = save_errno;
die_errno(_("could not close non-kept packs tempfile"));
}
}

static void existing_pack_mark_for_deletion(struct string_list_item *item)
{
item->util = (void*)((uintptr_t)item->util | DELETE_PACK);
Expand Down
14 changes: 12 additions & 2 deletions repack.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ struct pack_objects_args {
int path_walk;
int delta_base_offset;
int pack_kept_objects;
/*
* A file naming the packs this repack may delete, for
* pack-objects' "--ignore-pack-keep-from"; the path is borrowed.
*/
const char *ignore_pack_keep_from;
struct list_objects_filter_options filter_options;
};

Expand All @@ -28,6 +33,7 @@ struct pack_objects_args {
}

struct child_process;
struct tempfile;

void prepare_pack_objects(struct child_process *cmd,
const struct pack_objects_args *args,
Expand Down Expand Up @@ -80,6 +86,12 @@ struct existing_packs {
void existing_packs_collect(struct existing_packs *existing,
const struct string_list *extra_keep);
int existing_packs_has_non_kept(const struct existing_packs *existing);
/*
* Write the names of the non-kept and cruft packs, the ones a repack may
* delete, to "f", one per line, for pack-objects' "--ignore-pack-keep-from".
*/
void existing_packs_write_non_kept(const struct existing_packs *existing,
struct tempfile *f);
int existing_pack_is_marked_for_deletion(struct string_list_item *item);
void existing_packs_retain_cruft(struct existing_packs *existing,
struct packed_git *cruft);
Expand Down Expand Up @@ -138,8 +150,6 @@ void pack_geometry_remove_redundant(struct pack_geometry *geometry,
bool wrote_incremental_midx);
void pack_geometry_release(struct pack_geometry *geometry);

struct tempfile;

enum repack_write_midx_mode {
REPACK_WRITE_MIDX_NONE,
REPACK_WRITE_MIDX_DEFAULT,
Expand Down
Loading
Loading