Skip to content

Commit 9e234af

Browse files
committed
Merge branch 'jk/repack-no-explode-objects-from-old-pack'
Avoid writing out unreachable objects as loose objects when repacking, if such loose objects will immediately pruned due to its age anyway. By Jeff King * jk/repack-no-explode-objects-from-old-pack: gc: use argv-array for sub-commands argv-array: add a new "pushl" method argv-array: refactor empty_argv initialization gc: do not explode objects which will be immediately pruned
2 parents 4b2a0f8 + 234587f commit 9e234af

File tree

7 files changed

+107
-53
lines changed

7 files changed

+107
-53
lines changed

Documentation/technical/api-argv-array.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,11 @@ Functions
3737
`argv_array_push`::
3838
Push a copy of a string onto the end of the array.
3939

40+
`argv_array_pushl`::
41+
Push a list of strings onto the end of the array. The arguments
42+
should be a list of `const char *` strings, terminated by a NULL
43+
argument.
44+
4045
`argv_array_pushf`::
4146
Format a string and push it onto the end of the array. This is a
4247
convenience wrapper combining `strbuf_addf` and `argv_array_push`.

argv-array.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@
22
#include "argv-array.h"
33
#include "strbuf.h"
44

5-
static const char *empty_argv_storage = NULL;
6-
const char **empty_argv = &empty_argv_storage;
5+
const char *empty_argv[] = { NULL };
76

87
void argv_array_init(struct argv_array *array)
98
{
@@ -39,6 +38,17 @@ void argv_array_pushf(struct argv_array *array, const char *fmt, ...)
3938
argv_array_push_nodup(array, strbuf_detach(&v, NULL));
4039
}
4140

41+
void argv_array_pushl(struct argv_array *array, ...)
42+
{
43+
va_list ap;
44+
const char *arg;
45+
46+
va_start(ap, array);
47+
while((arg = va_arg(ap, const char *)))
48+
argv_array_push(array, arg);
49+
va_end(ap);
50+
}
51+
4252
void argv_array_clear(struct argv_array *array)
4353
{
4454
if (array->argv != empty_argv) {

argv-array.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#ifndef ARGV_ARRAY_H
22
#define ARGV_ARRAY_H
33

4-
extern const char **empty_argv;
4+
extern const char *empty_argv[];
55

66
struct argv_array {
77
const char **argv;
@@ -15,6 +15,7 @@ void argv_array_init(struct argv_array *);
1515
void argv_array_push(struct argv_array *, const char *);
1616
__attribute__((format (printf,2,3)))
1717
void argv_array_pushf(struct argv_array *, const char *fmt, ...);
18+
void argv_array_pushl(struct argv_array *, ...);
1819
void argv_array_clear(struct argv_array *);
1920

2021
#endif /* ARGV_ARRAY_H */

builtin/gc.c

Lines changed: 42 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "cache.h"
1515
#include "parse-options.h"
1616
#include "run-command.h"
17+
#include "argv-array.h"
1718

1819
#define FAILED_RUN "failed to run %s"
1920

@@ -28,12 +29,11 @@ static int gc_auto_threshold = 6700;
2829
static int gc_auto_pack_limit = 50;
2930
static const char *prune_expire = "2.weeks.ago";
3031

31-
#define MAX_ADD 10
32-
static const char *argv_pack_refs[] = {"pack-refs", "--all", "--prune", NULL};
33-
static const char *argv_reflog[] = {"reflog", "expire", "--all", NULL};
34-
static const char *argv_repack[MAX_ADD] = {"repack", "-d", "-l", NULL};
35-
static const char *argv_prune[] = {"prune", "--expire", NULL, NULL, NULL};
36-
static const char *argv_rerere[] = {"rerere", "gc", NULL};
32+
static struct argv_array pack_refs_cmd = ARGV_ARRAY_INIT;
33+
static struct argv_array reflog = ARGV_ARRAY_INIT;
34+
static struct argv_array repack = ARGV_ARRAY_INIT;
35+
static struct argv_array prune = ARGV_ARRAY_INIT;
36+
static struct argv_array rerere = ARGV_ARRAY_INIT;
3737

3838
static int gc_config(const char *var, const char *value, void *cb)
3939
{
@@ -67,19 +67,6 @@ static int gc_config(const char *var, const char *value, void *cb)
6767
return git_default_config(var, value, cb);
6868
}
6969

70-
static void append_option(const char **cmd, const char *opt, int max_length)
71-
{
72-
int i;
73-
74-
for (i = 0; cmd[i]; i++)
75-
;
76-
77-
if (i + 2 >= max_length)
78-
die(_("Too many options specified"));
79-
cmd[i++] = opt;
80-
cmd[i] = NULL;
81-
}
82-
8370
static int too_many_loose_objects(void)
8471
{
8572
/*
@@ -144,6 +131,17 @@ static int too_many_packs(void)
144131
return gc_auto_pack_limit <= cnt;
145132
}
146133

134+
static void add_repack_all_option(void)
135+
{
136+
if (prune_expire && !strcmp(prune_expire, "now"))
137+
argv_array_push(&repack, "-a");
138+
else {
139+
argv_array_push(&repack, "-A");
140+
if (prune_expire)
141+
argv_array_pushf(&repack, "--unpack-unreachable=%s", prune_expire);
142+
}
143+
}
144+
147145
static int need_to_gc(void)
148146
{
149147
/*
@@ -160,10 +158,7 @@ static int need_to_gc(void)
160158
* there is no need.
161159
*/
162160
if (too_many_packs())
163-
append_option(argv_repack,
164-
prune_expire && !strcmp(prune_expire, "now") ?
165-
"-a" : "-A",
166-
MAX_ADD);
161+
add_repack_all_option();
167162
else if (!too_many_loose_objects())
168163
return 0;
169164

@@ -177,7 +172,6 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
177172
int aggressive = 0;
178173
int auto_gc = 0;
179174
int quiet = 0;
180-
char buf[80];
181175

182176
struct option builtin_gc_options[] = {
183177
OPT__QUIET(&quiet, "suppress progress reporting"),
@@ -192,6 +186,12 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
192186
if (argc == 2 && !strcmp(argv[1], "-h"))
193187
usage_with_options(builtin_gc_usage, builtin_gc_options);
194188

189+
argv_array_pushl(&pack_refs_cmd, "pack-refs", "--all", "--prune", NULL);
190+
argv_array_pushl(&reflog, "reflog", "expire", "--all", NULL);
191+
argv_array_pushl(&repack, "repack", "-d", "-l", NULL);
192+
argv_array_pushl(&prune, "prune", "--expire", NULL );
193+
argv_array_pushl(&rerere, "rerere", "gc", NULL);
194+
195195
git_config(gc_config, NULL);
196196

197197
if (pack_refs < 0)
@@ -203,15 +203,13 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
203203
usage_with_options(builtin_gc_usage, builtin_gc_options);
204204

205205
if (aggressive) {
206-
append_option(argv_repack, "-f", MAX_ADD);
207-
append_option(argv_repack, "--depth=250", MAX_ADD);
208-
if (aggressive_window > 0) {
209-
sprintf(buf, "--window=%d", aggressive_window);
210-
append_option(argv_repack, buf, MAX_ADD);
211-
}
206+
argv_array_push(&repack, "-f");
207+
argv_array_push(&repack, "--depth=250");
208+
if (aggressive_window > 0)
209+
argv_array_pushf(&repack, "--window=%d", aggressive_window);
212210
}
213211
if (quiet)
214-
append_option(argv_repack, "-q", MAX_ADD);
212+
argv_array_push(&repack, "-q");
215213

216214
if (auto_gc) {
217215
/*
@@ -227,30 +225,27 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
227225
"run \"git gc\" manually. See "
228226
"\"git help gc\" for more information.\n"));
229227
} else
230-
append_option(argv_repack,
231-
prune_expire && !strcmp(prune_expire, "now")
232-
? "-a" : "-A",
233-
MAX_ADD);
228+
add_repack_all_option();
234229

235-
if (pack_refs && run_command_v_opt(argv_pack_refs, RUN_GIT_CMD))
236-
return error(FAILED_RUN, argv_pack_refs[0]);
230+
if (pack_refs && run_command_v_opt(pack_refs_cmd.argv, RUN_GIT_CMD))
231+
return error(FAILED_RUN, pack_refs_cmd.argv[0]);
237232

238-
if (run_command_v_opt(argv_reflog, RUN_GIT_CMD))
239-
return error(FAILED_RUN, argv_reflog[0]);
233+
if (run_command_v_opt(reflog.argv, RUN_GIT_CMD))
234+
return error(FAILED_RUN, reflog.argv[0]);
240235

241-
if (run_command_v_opt(argv_repack, RUN_GIT_CMD))
242-
return error(FAILED_RUN, argv_repack[0]);
236+
if (run_command_v_opt(repack.argv, RUN_GIT_CMD))
237+
return error(FAILED_RUN, repack.argv[0]);
243238

244239
if (prune_expire) {
245-
argv_prune[2] = prune_expire;
240+
argv_array_push(&prune, prune_expire);
246241
if (quiet)
247-
argv_prune[3] = "--no-progress";
248-
if (run_command_v_opt(argv_prune, RUN_GIT_CMD))
249-
return error(FAILED_RUN, argv_prune[0]);
242+
argv_array_push(&prune, "--no-progress");
243+
if (run_command_v_opt(prune.argv, RUN_GIT_CMD))
244+
return error(FAILED_RUN, prune.argv[0]);
250245
}
251246

252-
if (run_command_v_opt(argv_rerere, RUN_GIT_CMD))
253-
return error(FAILED_RUN, argv_rerere[0]);
247+
if (run_command_v_opt(rerere.argv, RUN_GIT_CMD))
248+
return error(FAILED_RUN, rerere.argv[0]);
254249

255250
if (auto_gc && too_many_loose_objects())
256251
warning(_("There are too many unreachable loose objects; "

builtin/pack-objects.c

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ static uint32_t nr_objects, nr_alloc, nr_result, nr_written;
6363
static int non_empty;
6464
static int reuse_delta = 1, reuse_object = 1;
6565
static int keep_unreachable, unpack_unreachable, include_tag;
66+
static unsigned long unpack_unreachable_expiration;
6667
static int local;
6768
static int incremental;
6869
static int ignore_packed_keep;
@@ -2249,6 +2250,10 @@ static void loosen_unused_packed_objects(struct rev_info *revs)
22492250
if (!p->pack_local || p->pack_keep)
22502251
continue;
22512252

2253+
if (unpack_unreachable_expiration &&
2254+
p->mtime < unpack_unreachable_expiration)
2255+
continue;
2256+
22522257
if (open_pack_index(p))
22532258
die("cannot open pack index");
22542259

@@ -2315,6 +2320,21 @@ static int option_parse_index_version(const struct option *opt,
23152320
return 0;
23162321
}
23172322

2323+
static int option_parse_unpack_unreachable(const struct option *opt,
2324+
const char *arg, int unset)
2325+
{
2326+
if (unset) {
2327+
unpack_unreachable = 0;
2328+
unpack_unreachable_expiration = 0;
2329+
}
2330+
else {
2331+
unpack_unreachable = 1;
2332+
if (arg)
2333+
unpack_unreachable_expiration = approxidate(arg);
2334+
}
2335+
return 0;
2336+
}
2337+
23182338
static int option_parse_ulong(const struct option *opt,
23192339
const char *arg, int unset)
23202340
{
@@ -2392,8 +2412,9 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
23922412
"include tag objects that refer to objects to be packed"),
23932413
OPT_BOOL(0, "keep-unreachable", &keep_unreachable,
23942414
"keep unreachable objects"),
2395-
OPT_BOOL(0, "unpack-unreachable", &unpack_unreachable,
2396-
"unpack unreachable objects"),
2415+
{ OPTION_CALLBACK, 0, "unpack-unreachable", NULL, "time",
2416+
"unpack unreachable objects newer than <time>",
2417+
PARSE_OPT_OPTARG, option_parse_unpack_unreachable },
23972418
OPT_BOOL(0, "thin", &thin,
23982419
"create thin packs"),
23992420
OPT_BOOL(0, "honor-pack-keep", &ignore_packed_keep,

git-repack.sh

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ F pass --no-reuse-object to git-pack-objects
1515
n do not run git-update-server-info
1616
q,quiet be quiet
1717
l pass --local to git-pack-objects
18+
unpack-unreachable= with -A, do not loosen objects older than this
1819
Packing constraints
1920
window= size of the window used for delta compression
2021
window-memory= same as the above, but limit memory size instead of entries count
@@ -33,6 +34,8 @@ do
3334
-a) all_into_one=t ;;
3435
-A) all_into_one=t
3536
unpack_unreachable=--unpack-unreachable ;;
37+
--unpack-unreachable)
38+
unpack_unreachable="--unpack-unreachable=$2"; shift ;;
3639
-d) remove_redundant=t ;;
3740
-q) GIT_QUIET=t ;;
3841
-f) no_reuse=--no-reuse-delta ;;
@@ -76,7 +79,12 @@ case ",$all_into_one," in
7679
if test -n "$existing" -a -n "$unpack_unreachable" -a \
7780
-n "$remove_redundant"
7881
then
79-
args="$args $unpack_unreachable"
82+
# This may have arbitrary user arguments, so we
83+
# have to protect it against whitespace splitting
84+
# when it gets run as "pack-objects $args" later.
85+
# Fortunately, we know it's an approxidate, so we
86+
# can just use dots instead.
87+
args="$args $(echo "$unpack_unreachable" | tr ' ' .)"
8088
fi
8189
fi
8290
;;

t/t7701-repack-unpack-unreachable.sh

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,4 +95,18 @@ test_expect_success 'unpacked objects receive timestamp of pack file' '
9595
compare_mtimes < mtimes
9696
'
9797

98+
test_expect_success 'do not bother loosening old objects' '
99+
obj1=$(echo one | git hash-object -w --stdin) &&
100+
obj2=$(echo two | git hash-object -w --stdin) &&
101+
pack1=$(echo $obj1 | git pack-objects .git/objects/pack/pack) &&
102+
pack2=$(echo $obj2 | git pack-objects .git/objects/pack/pack) &&
103+
git prune-packed &&
104+
git cat-file -p $obj1 &&
105+
git cat-file -p $obj2 &&
106+
test-chmtime =-86400 .git/objects/pack/pack-$pack2.pack &&
107+
git repack -A -d --unpack-unreachable=1.hour.ago &&
108+
git cat-file -p $obj1 &&
109+
test_must_fail git cat-file -p $obj2
110+
'
111+
98112
test_done

0 commit comments

Comments
 (0)