Skip to content

Commit d70e331

Browse files
committed
Merge branch 'jk/prune-mtime'
Tighten the logic to decide that an unreachable cruft is sufficiently old by covering corner cases such as an ancient object becoming reachable and then going unreachable again, in which case its retention period should be prolonged. * jk/prune-mtime: (28 commits) drop add_object_array_with_mode revision: remove definition of unused 'add_object' function pack-objects: double-check options before discarding objects repack: pack objects mentioned by the index pack-objects: use argv_array reachable: use revision machinery's --indexed-objects code rev-list: add --indexed-objects option rev-list: document --reflog option t5516: test pushing a tag of an otherwise unreferenced blob traverse_commit_list: support pending blobs/trees with paths make add_object_array_with_context interface more sane write_sha1_file: freshen existing objects pack-objects: match prune logic for discarding objects pack-objects: refactor unpack-unreachable expiration check prune: keep objects reachable from recent objects sha1_file: add for_each iterators for loose and packed objects count-objects: use for_each_loose_file_in_objdir count-objects: do not use xsize_t when counting object size prune-packed: use for_each_loose_file_in_objdir reachable: mark index blobs as SEEN ...
2 parents 853878d + 189a122 commit d70e331

23 files changed

+836
-436
lines changed

Documentation/rev-list-options.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,15 @@ respectively, and they must begin with `refs/` when applied to `--glob`
168168
or `--all`. If a trailing '/{asterisk}' is intended, it must be given
169169
explicitly.
170170

171+
--reflog::
172+
Pretend as if all objects mentioned by reflogs are listed on the
173+
command line as `<commit>`.
174+
175+
--indexed-objects::
176+
Pretend as if all trees and blobs used by the index are listed
177+
on the command line. Note that you probably want to use
178+
`--objects`, too.
179+
171180
--ignore-missing::
172181
Upon seeing an invalid object name in the input, pretend as if
173182
the bad input was not given.

builtin/count-objects.c

Lines changed: 30 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111

1212
static unsigned long garbage;
1313
static off_t size_garbage;
14+
static int verbose;
15+
static unsigned long loose, packed, packed_loose;
16+
static off_t loose_size;
1417

1518
static void real_report_garbage(const char *desc, const char *path)
1619
{
@@ -21,61 +24,31 @@ static void real_report_garbage(const char *desc, const char *path)
2124
garbage++;
2225
}
2326

24-
static void count_objects(DIR *d, char *path, int len, int verbose,
25-
unsigned long *loose,
26-
off_t *loose_size,
27-
unsigned long *packed_loose)
27+
static void loose_garbage(const char *path)
2828
{
29-
struct dirent *ent;
30-
while ((ent = readdir(d)) != NULL) {
31-
char hex[41];
32-
unsigned char sha1[20];
33-
const char *cp;
34-
int bad = 0;
29+
if (verbose)
30+
report_garbage("garbage found", path);
31+
}
3532

36-
if (is_dot_or_dotdot(ent->d_name))
37-
continue;
38-
for (cp = ent->d_name; *cp; cp++) {
39-
int ch = *cp;
40-
if (('0' <= ch && ch <= '9') ||
41-
('a' <= ch && ch <= 'f'))
42-
continue;
43-
bad = 1;
44-
break;
45-
}
46-
if (cp - ent->d_name != 38)
47-
bad = 1;
48-
else {
49-
struct stat st;
50-
memcpy(path + len + 3, ent->d_name, 38);
51-
path[len + 2] = '/';
52-
path[len + 41] = 0;
53-
if (lstat(path, &st) || !S_ISREG(st.st_mode))
54-
bad = 1;
55-
else
56-
(*loose_size) += xsize_t(on_disk_bytes(st));
57-
}
58-
if (bad) {
59-
if (verbose) {
60-
struct strbuf sb = STRBUF_INIT;
61-
strbuf_addf(&sb, "%.*s/%s",
62-
len + 2, path, ent->d_name);
63-
report_garbage("garbage found", sb.buf);
64-
strbuf_release(&sb);
65-
}
66-
continue;
67-
}
68-
(*loose)++;
69-
if (!verbose)
70-
continue;
71-
memcpy(hex, path+len, 2);
72-
memcpy(hex+2, ent->d_name, 38);
73-
hex[40] = 0;
74-
if (get_sha1_hex(hex, sha1))
75-
die("internal error");
76-
if (has_sha1_pack(sha1))
77-
(*packed_loose)++;
33+
static int count_loose(const unsigned char *sha1, const char *path, void *data)
34+
{
35+
struct stat st;
36+
37+
if (lstat(path, &st) || !S_ISREG(st.st_mode))
38+
loose_garbage(path);
39+
else {
40+
loose_size += on_disk_bytes(st);
41+
loose++;
42+
if (verbose && has_sha1_pack(sha1))
43+
packed_loose++;
7844
}
45+
return 0;
46+
}
47+
48+
static int count_cruft(const char *basename, const char *path, void *data)
49+
{
50+
loose_garbage(path);
51+
return 0;
7952
}
8053

8154
static char const * const count_objects_usage[] = {
@@ -85,12 +58,7 @@ static char const * const count_objects_usage[] = {
8558

8659
int cmd_count_objects(int argc, const char **argv, const char *prefix)
8760
{
88-
int i, verbose = 0, human_readable = 0;
89-
const char *objdir = get_object_directory();
90-
int len = strlen(objdir);
91-
char *path = xmalloc(len + 50);
92-
unsigned long loose = 0, packed = 0, packed_loose = 0;
93-
off_t loose_size = 0;
61+
int human_readable = 0;
9462
struct option opts[] = {
9563
OPT__VERBOSE(&verbose, N_("be verbose")),
9664
OPT_BOOL('H', "human-readable", &human_readable,
@@ -104,19 +72,10 @@ int cmd_count_objects(int argc, const char **argv, const char *prefix)
10472
usage_with_options(count_objects_usage, opts);
10573
if (verbose)
10674
report_garbage = real_report_garbage;
107-
memcpy(path, objdir, len);
108-
if (len && objdir[len-1] != '/')
109-
path[len++] = '/';
110-
for (i = 0; i < 256; i++) {
111-
DIR *d;
112-
sprintf(path + len, "%02x", i);
113-
d = opendir(path);
114-
if (!d)
115-
continue;
116-
count_objects(d, path, len, verbose,
117-
&loose, &loose_size, &packed_loose);
118-
closedir(d);
119-
}
75+
76+
for_each_loose_file_in_objdir(get_object_directory(),
77+
count_loose, count_cruft, NULL, NULL);
78+
12079
if (verbose) {
12180
struct packed_git *p;
12281
unsigned long num_pack = 0;

builtin/grep.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -456,10 +456,10 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
456456
}
457457

458458
static int grep_object(struct grep_opt *opt, const struct pathspec *pathspec,
459-
struct object *obj, const char *name, struct object_context *oc)
459+
struct object *obj, const char *name, const char *path)
460460
{
461461
if (obj->type == OBJ_BLOB)
462-
return grep_sha1(opt, obj->sha1, name, 0, oc ? oc->path : NULL);
462+
return grep_sha1(opt, obj->sha1, name, 0, path);
463463
if (obj->type == OBJ_COMMIT || obj->type == OBJ_TREE) {
464464
struct tree_desc tree;
465465
void *data;
@@ -501,7 +501,7 @@ static int grep_objects(struct grep_opt *opt, const struct pathspec *pathspec,
501501
for (i = 0; i < nr; i++) {
502502
struct object *real_obj;
503503
real_obj = deref_tag(list->objects[i].item, NULL, 0);
504-
if (grep_object(opt, pathspec, real_obj, list->objects[i].name, list->objects[i].context)) {
504+
if (grep_object(opt, pathspec, real_obj, list->objects[i].name, list->objects[i].path)) {
505505
hit = 1;
506506
if (opt->status_only)
507507
break;
@@ -821,7 +821,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
821821
struct object *object = parse_object_or_die(sha1, arg);
822822
if (!seen_dashdash)
823823
verify_non_filename(prefix, arg);
824-
add_object_array_with_context(object, arg, &list, xmemdupz(&oc, sizeof(struct object_context)));
824+
add_object_array_with_path(object, arg, &list, oc.mode, oc.path);
825825
continue;
826826
}
827827
if (!strcmp(arg, "--")) {

builtin/pack-objects.c

Lines changed: 71 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@
2020
#include "streaming.h"
2121
#include "thread-utils.h"
2222
#include "pack-bitmap.h"
23+
#include "reachable.h"
24+
#include "sha1-array.h"
25+
#include "argv-array.h"
2326

2427
static const char *pack_usage[] = {
2528
N_("git pack-objects --stdout [options...] [< ref-list | < object-list]"),
@@ -2406,6 +2409,27 @@ static int has_sha1_pack_kept_or_nonlocal(const unsigned char *sha1)
24062409
return 0;
24072410
}
24082411

2412+
/*
2413+
* Store a list of sha1s that are should not be discarded
2414+
* because they are either written too recently, or are
2415+
* reachable from another object that was.
2416+
*
2417+
* This is filled by get_object_list.
2418+
*/
2419+
static struct sha1_array recent_objects;
2420+
2421+
static int loosened_object_can_be_discarded(const unsigned char *sha1,
2422+
unsigned long mtime)
2423+
{
2424+
if (!unpack_unreachable_expiration)
2425+
return 0;
2426+
if (mtime > unpack_unreachable_expiration)
2427+
return 0;
2428+
if (sha1_array_lookup(&recent_objects, sha1) >= 0)
2429+
return 0;
2430+
return 1;
2431+
}
2432+
24092433
static void loosen_unused_packed_objects(struct rev_info *revs)
24102434
{
24112435
struct packed_git *p;
@@ -2416,17 +2440,14 @@ static void loosen_unused_packed_objects(struct rev_info *revs)
24162440
if (!p->pack_local || p->pack_keep)
24172441
continue;
24182442

2419-
if (unpack_unreachable_expiration &&
2420-
p->mtime < unpack_unreachable_expiration)
2421-
continue;
2422-
24232443
if (open_pack_index(p))
24242444
die("cannot open pack index");
24252445

24262446
for (i = 0; i < p->num_objects; i++) {
24272447
sha1 = nth_packed_object_sha1(p, i);
24282448
if (!packlist_find(&to_pack, sha1, NULL) &&
2429-
!has_sha1_pack_kept_or_nonlocal(sha1))
2449+
!has_sha1_pack_kept_or_nonlocal(sha1) &&
2450+
!loosened_object_can_be_discarded(sha1, p->mtime))
24302451
if (force_object_loose(sha1, p->mtime))
24312452
die("unable to force loose object");
24322453
}
@@ -2462,6 +2483,19 @@ static int get_object_list_from_bitmap(struct rev_info *revs)
24622483
return 0;
24632484
}
24642485

2486+
static void record_recent_object(struct object *obj,
2487+
const struct name_path *path,
2488+
const char *last,
2489+
void *data)
2490+
{
2491+
sha1_array_append(&recent_objects, obj->sha1);
2492+
}
2493+
2494+
static void record_recent_commit(struct commit *commit, void *data)
2495+
{
2496+
sha1_array_append(&recent_objects, commit->object.sha1);
2497+
}
2498+
24652499
static void get_object_list(int ac, const char **av)
24662500
{
24672501
struct rev_info revs;
@@ -2509,10 +2543,23 @@ static void get_object_list(int ac, const char **av)
25092543
mark_edges_uninteresting(&revs, show_edge);
25102544
traverse_commit_list(&revs, show_commit, show_object, NULL);
25112545

2546+
if (unpack_unreachable_expiration) {
2547+
revs.ignore_missing_links = 1;
2548+
if (add_unseen_recent_objects_to_traversal(&revs,
2549+
unpack_unreachable_expiration))
2550+
die("unable to add recent objects");
2551+
if (prepare_revision_walk(&revs))
2552+
die("revision walk setup failed");
2553+
traverse_commit_list(&revs, record_recent_commit,
2554+
record_recent_object, NULL);
2555+
}
2556+
25122557
if (keep_unreachable)
25132558
add_objects_in_unpacked_packs(&revs);
25142559
if (unpack_unreachable)
25152560
loosen_unused_packed_objects(&revs);
2561+
2562+
sha1_array_clear(&recent_objects);
25162563
}
25172564

25182565
static int option_parse_index_version(const struct option *opt,
@@ -2567,9 +2614,9 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
25672614
int use_internal_rev_list = 0;
25682615
int thin = 0;
25692616
int all_progress_implied = 0;
2570-
const char *rp_av[6];
2571-
int rp_ac = 0;
2617+
struct argv_array rp = ARGV_ARRAY_INIT;
25722618
int rev_list_unpacked = 0, rev_list_all = 0, rev_list_reflog = 0;
2619+
int rev_list_index = 0;
25732620
struct option pack_objects_options[] = {
25742621
OPT_SET_INT('q', "quiet", &progress,
25752622
N_("do not show progress meter"), 0),
@@ -2616,6 +2663,9 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
26162663
{ OPTION_SET_INT, 0, "reflog", &rev_list_reflog, NULL,
26172664
N_("include objects referred by reflog entries"),
26182665
PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 1 },
2666+
{ OPTION_SET_INT, 0, "indexed-objects", &rev_list_index, NULL,
2667+
N_("include objects referred to by the index"),
2668+
PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 1 },
26192669
OPT_BOOL(0, "stdout", &pack_to_stdout,
26202670
N_("output pack to stdout")),
26212671
OPT_BOOL(0, "include-tag", &include_tag,
@@ -2658,24 +2708,28 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
26582708
if (pack_to_stdout != !base_name || argc)
26592709
usage_with_options(pack_usage, pack_objects_options);
26602710

2661-
rp_av[rp_ac++] = "pack-objects";
2711+
argv_array_push(&rp, "pack-objects");
26622712
if (thin) {
26632713
use_internal_rev_list = 1;
2664-
rp_av[rp_ac++] = "--objects-edge";
2714+
argv_array_push(&rp, "--objects-edge");
26652715
} else
2666-
rp_av[rp_ac++] = "--objects";
2716+
argv_array_push(&rp, "--objects");
26672717

26682718
if (rev_list_all) {
26692719
use_internal_rev_list = 1;
2670-
rp_av[rp_ac++] = "--all";
2720+
argv_array_push(&rp, "--all");
26712721
}
26722722
if (rev_list_reflog) {
26732723
use_internal_rev_list = 1;
2674-
rp_av[rp_ac++] = "--reflog";
2724+
argv_array_push(&rp, "--reflog");
2725+
}
2726+
if (rev_list_index) {
2727+
use_internal_rev_list = 1;
2728+
argv_array_push(&rp, "--indexed-objects");
26752729
}
26762730
if (rev_list_unpacked) {
26772731
use_internal_rev_list = 1;
2678-
rp_av[rp_ac++] = "--unpacked";
2732+
argv_array_push(&rp, "--unpacked");
26792733
}
26802734

26812735
if (!reuse_object)
@@ -2706,6 +2760,8 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
27062760

27072761
if (keep_unreachable && unpack_unreachable)
27082762
die("--keep-unreachable and --unpack-unreachable are incompatible.");
2763+
if (!rev_list_all || !rev_list_reflog || !rev_list_index)
2764+
unpack_unreachable_expiration = 0;
27092765

27102766
if (!use_internal_rev_list || !pack_to_stdout || is_repository_shallow())
27112767
use_bitmap_index = 0;
@@ -2723,8 +2779,8 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
27232779
if (!use_internal_rev_list)
27242780
read_object_list_from_stdin();
27252781
else {
2726-
rp_av[rp_ac] = NULL;
2727-
get_object_list(rp_ac, rp_av);
2782+
get_object_list(rp.argc, rp.argv);
2783+
argv_array_clear(&rp);
27282784
}
27292785
cleanup_preferred_base();
27302786
if (include_tag && nr_result)

0 commit comments

Comments
 (0)