Skip to content

Commit 826ae79

Browse files
john-caigitster
authored andcommitted
pack-refs: teach --exclude option to exclude refs from being packed
At GitLab, we have a system that creates ephemeral internal refs that don't live long before getting deleted. Having an option to exclude certain refs from a packed-refs file allows these internal references to be deleted much more efficiently. Add an --exclude option to the pack-refs builtin, and use the ref exclusions API to exclude certain refs from being packed into the final packed-refs file Signed-off-by: John Cai <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 283174b commit 826ae79

File tree

11 files changed

+69
-20
lines changed

11 files changed

+69
-20
lines changed

Documentation/git-pack-refs.txt

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ git-pack-refs - Pack heads and tags for efficient repository access
88
SYNOPSIS
99
--------
1010
[verse]
11-
'git pack-refs' [--all] [--no-prune]
11+
'git pack-refs' [--all] [--no-prune] [--exclude <pattern>]
1212

1313
DESCRIPTION
1414
-----------
@@ -60,6 +60,16 @@ with many branches of historical interests.
6060
The command usually removes loose refs under `$GIT_DIR/refs`
6161
hierarchy after packing them. This option tells it not to.
6262

63+
--exclude <pattern>::
64+
65+
Do not pack refs matching the given `glob(7)` pattern. Repetitions of this option
66+
accumulate exclusion patterns. Use `--no-exclude` to clear and reset the list of
67+
patterns. If a ref is already packed, including it with `--exclude` will not
68+
unpack it.
69+
70+
When used with `--all`, pack only loose refs which do not match any of
71+
the provided `--exclude` patterns.
72+
6373

6474
BUGS
6575
----

builtin/pack-refs.c

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,34 @@
44
#include "parse-options.h"
55
#include "refs.h"
66
#include "repository.h"
7+
#include "revision.h"
78

89
static char const * const pack_refs_usage[] = {
9-
N_("git pack-refs [--all] [--no-prune]"),
10+
N_("git pack-refs [--all] [--no-prune] [--exclude <pattern>]"),
1011
NULL
1112
};
1213

1314
int cmd_pack_refs(int argc, const char **argv, const char *prefix)
1415
{
1516
unsigned int flags = PACK_REFS_PRUNE;
17+
static struct ref_exclusions excludes = REF_EXCLUSIONS_INIT;
18+
struct pack_refs_opts pack_refs_opts = {.exclusions = &excludes, .flags = flags};
19+
static struct string_list option_excluded_refs = STRING_LIST_INIT_NODUP;
20+
struct string_list_item *item;
21+
1622
struct option opts[] = {
17-
OPT_BIT(0, "all", &flags, N_("pack everything"), PACK_REFS_ALL),
18-
OPT_BIT(0, "prune", &flags, N_("prune loose refs (default)"), PACK_REFS_PRUNE),
23+
OPT_BIT(0, "all", &pack_refs_opts.flags, N_("pack everything"), PACK_REFS_ALL),
24+
OPT_BIT(0, "prune", &pack_refs_opts.flags, N_("prune loose refs (default)"), PACK_REFS_PRUNE),
25+
OPT_STRING_LIST(0, "exclude", &option_excluded_refs, N_("pattern"),
26+
N_("references to exclude")),
1927
OPT_END(),
2028
};
2129
git_config(git_default_config, NULL);
2230
if (parse_options(argc, argv, prefix, opts, pack_refs_usage, 0))
2331
usage_with_options(pack_refs_usage, opts);
24-
return refs_pack_refs(get_main_ref_store(the_repository), flags);
32+
33+
for_each_string_list_item(item, &option_excluded_refs)
34+
add_ref_exclusion(pack_refs_opts.exclusions, item->string);
35+
36+
return refs_pack_refs(get_main_ref_store(the_repository), &pack_refs_opts);
2537
}

refs.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2132,9 +2132,9 @@ void base_ref_store_init(struct ref_store *refs, struct repository *repo,
21322132
}
21332133

21342134
/* backend functions */
2135-
int refs_pack_refs(struct ref_store *refs, unsigned int flags)
2135+
int refs_pack_refs(struct ref_store *refs, struct pack_refs_opts *opts)
21362136
{
2137-
return refs->be->pack_refs(refs, flags);
2137+
return refs->be->pack_refs(refs, opts);
21382138
}
21392139

21402140
int peel_iterated_oid(const struct object_id *base, struct object_id *peeled)

refs.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,11 @@ struct worktree;
6363
#define RESOLVE_REF_NO_RECURSE 0x02
6464
#define RESOLVE_REF_ALLOW_BAD_NAME 0x04
6565

66+
struct pack_refs_opts {
67+
unsigned int flags;
68+
struct ref_exclusions *exclusions;
69+
};
70+
6671
const char *refs_resolve_ref_unsafe(struct ref_store *refs,
6772
const char *refname,
6873
int resolve_flags,
@@ -405,7 +410,7 @@ void warn_dangling_symrefs(FILE *fp, const char *msg_fmt,
405410
* Write a packed-refs file for the current repository.
406411
* flags: Combination of the above PACK_REFS_* flags.
407412
*/
408-
int refs_pack_refs(struct ref_store *refs, unsigned int flags);
413+
int refs_pack_refs(struct ref_store *refs, struct pack_refs_opts *opts);
409414

410415
/*
411416
* Setup reflog before using. Fill in err and return -1 on failure.

refs/debug.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,10 +122,10 @@ static int debug_initial_transaction_commit(struct ref_store *refs,
122122
return res;
123123
}
124124

125-
static int debug_pack_refs(struct ref_store *ref_store, unsigned int flags)
125+
static int debug_pack_refs(struct ref_store *ref_store, struct pack_refs_opts *opts)
126126
{
127127
struct debug_ref_store *drefs = (struct debug_ref_store *)ref_store;
128-
int res = drefs->refs->be->pack_refs(drefs->refs, flags);
128+
int res = drefs->refs->be->pack_refs(drefs->refs, opts);
129129
trace_printf_key(&trace_refs, "pack_refs: %d\n", res);
130130
return res;
131131
}

refs/files-backend.c

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "../worktree.h"
2020
#include "../wrapper.h"
2121
#include "../write-or-die.h"
22+
#include "../revision.h"
2223

2324
/*
2425
* This backend uses the following flags in `ref_update::flags` for
@@ -1173,15 +1174,18 @@ static void prune_refs(struct files_ref_store *refs, struct ref_to_prune **refs_
11731174
*/
11741175
static int should_pack_ref(const char *refname,
11751176
const struct object_id *oid, unsigned int ref_flags,
1176-
unsigned int pack_flags)
1177+
struct pack_refs_opts *opts)
11771178
{
11781179
/* Do not pack per-worktree refs: */
11791180
if (parse_worktree_ref(refname, NULL, NULL, NULL) !=
11801181
REF_WORKTREE_SHARED)
11811182
return 0;
11821183

1184+
if (ref_excluded(opts->exclusions, refname))
1185+
return 0;
1186+
11831187
/* Do not pack non-tags unless PACK_REFS_ALL is set: */
1184-
if (!(pack_flags & PACK_REFS_ALL) && !starts_with(refname, "refs/tags/"))
1188+
if (!(opts->flags & PACK_REFS_ALL) && !starts_with(refname, "refs/tags/"))
11851189
return 0;
11861190

11871191
/* Do not pack symbolic refs: */
@@ -1195,7 +1199,8 @@ static int should_pack_ref(const char *refname,
11951199
return 1;
11961200
}
11971201

1198-
static int files_pack_refs(struct ref_store *ref_store, unsigned int flags)
1202+
static int files_pack_refs(struct ref_store *ref_store,
1203+
struct pack_refs_opts *opts)
11991204
{
12001205
struct files_ref_store *refs =
12011206
files_downcast(ref_store, REF_STORE_WRITE | REF_STORE_ODB,
@@ -1220,8 +1225,7 @@ static int files_pack_refs(struct ref_store *ref_store, unsigned int flags)
12201225
* in the packed ref cache. If the reference should be
12211226
* pruned, also add it to refs_to_prune.
12221227
*/
1223-
if (!should_pack_ref(iter->refname, iter->oid, iter->flags,
1224-
flags))
1228+
if (!should_pack_ref(iter->refname, iter->oid, iter->flags, opts))
12251229
continue;
12261230

12271231
/*
@@ -1235,7 +1239,7 @@ static int files_pack_refs(struct ref_store *ref_store, unsigned int flags)
12351239
iter->refname, err.buf);
12361240

12371241
/* Schedule the loose reference for pruning if requested. */
1238-
if ((flags & PACK_REFS_PRUNE)) {
1242+
if ((opts->flags & PACK_REFS_PRUNE)) {
12391243
struct ref_to_prune *n;
12401244
FLEX_ALLOC_STR(n, name, iter->refname);
12411245
oidcpy(&n->oid, iter->oid);

refs/packed-backend.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1576,7 +1576,7 @@ static int packed_delete_refs(struct ref_store *ref_store, const char *msg,
15761576
}
15771577

15781578
static int packed_pack_refs(struct ref_store *ref_store UNUSED,
1579-
unsigned int flags UNUSED)
1579+
struct pack_refs_opts *pack_opts UNUSED)
15801580
{
15811581
/*
15821582
* Packed refs are already packed. It might be that loose refs

refs/refs-internal.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -547,7 +547,8 @@ typedef int ref_transaction_commit_fn(struct ref_store *refs,
547547
struct ref_transaction *transaction,
548548
struct strbuf *err);
549549

550-
typedef int pack_refs_fn(struct ref_store *ref_store, unsigned int flags);
550+
typedef int pack_refs_fn(struct ref_store *ref_store,
551+
struct pack_refs_opts *opts);
551552
typedef int create_symref_fn(struct ref_store *ref_store,
552553
const char *ref_target,
553554
const char *refs_heads_master,

revision.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ struct rev_cmdline_info {
8686
struct ref_exclusions {
8787
/*
8888
* Excluded refs is a list of wildmatch patterns. If any of the
89-
* patterns matches, the reference will be excluded.
89+
* patterns match, the reference will be excluded.
9090
*/
9191
struct string_list excluded_refs;
9292

t/helper/test-ref-store.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,9 @@ static struct flag_definition pack_flags[] = { FLAG_DEF(PACK_REFS_PRUNE),
116116
static int cmd_pack_refs(struct ref_store *refs, const char **argv)
117117
{
118118
unsigned int flags = arg_flags(*argv++, "flags", pack_flags);
119+
struct pack_refs_opts pack_opts = { .flags = flags };
119120

120-
return refs_pack_refs(refs, flags);
121+
return refs_pack_refs(refs, &pack_opts);
121122
}
122123

123124
static int cmd_create_symref(struct ref_store *refs, const char **argv)

t/t3210-pack-refs.sh

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,22 @@ test_expect_success \
108108
git branch -d n/o/p &&
109109
git branch n'
110110

111+
test_expect_success 'test excluded refs are not packed' '
112+
git branch dont_pack1 &&
113+
git branch dont_pack2 &&
114+
git branch pack_this &&
115+
git pack-refs --all --exclude "refs/heads/dont_pack*" &&
116+
test -f .git/refs/heads/dont_pack1 &&
117+
test -f .git/refs/heads/dont_pack2 &&
118+
! test -f .git/refs/heads/pack_this'
119+
120+
test_expect_success 'test --no-exclude refs clears excluded refs' '
121+
git branch dont_pack3 &&
122+
git branch dont_pack4 &&
123+
git pack-refs --all --exclude "refs/heads/dont_pack*" --no-exclude &&
124+
! test -f .git/refs/heads/dont_pack3 &&
125+
! test -f .git/refs/heads/dont_pack4'
126+
111127
test_expect_success \
112128
'see if up-to-date packed refs are preserved' \
113129
'git branch q &&

0 commit comments

Comments
 (0)