Skip to content

Commit cbc882e

Browse files
committed
Merge branch 'jc/pack-ref-exclude-include'
"git pack-refs" learns "--include" and "--exclude" to tweak the ref hierarchy to be packed using pattern matching. * jc/pack-ref-exclude-include: pack-refs: teach pack-refs --include option pack-refs: teach --exclude option to exclude refs from being packed docs: clarify git-pack-refs --all will pack all refs
2 parents ebd07c9 + 4fe42f3 commit cbc882e

File tree

11 files changed

+132
-26
lines changed

11 files changed

+132
-26
lines changed

Documentation/git-pack-refs.txt

Lines changed: 26 additions & 3 deletions
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] [--include <pattern>] [--exclude <pattern>]
1212

1313
DESCRIPTION
1414
-----------
@@ -51,14 +51,37 @@ The command by default packs all tags and refs that are already
5151
packed, and leaves other refs
5252
alone. This is because branches are expected to be actively
5353
developed and packing their tips does not help performance.
54-
This option causes branch tips to be packed as well. Useful for
55-
a repository with many branches of historical interests.
54+
This option causes all refs to be packed as well, with the exception
55+
of hidden refs, broken refs, and symbolic refs. Useful for a repository
56+
with many branches of historical interests.
5657

5758
--no-prune::
5859

5960
The command usually removes loose refs under `$GIT_DIR/refs`
6061
hierarchy after packing them. This option tells it not to.
6162

63+
--include <pattern>::
64+
65+
Pack refs based on a `glob(7)` pattern. Repetitions of this option
66+
accumulate inclusion patterns. If a ref is both included in `--include` and
67+
`--exclude`, `--exclude` takes precedence. Using `--include` will preclude all
68+
tags from being included by default. Symbolic refs and broken refs will never
69+
be packed. When used with `--all`, it will be a noop. Use `--no-include` to clear
70+
and reset the list of patterns.
71+
72+
--exclude <pattern>::
73+
74+
Do not pack refs matching the given `glob(7)` pattern. Repetitions of this option
75+
accumulate exclusion patterns. Use `--no-exclude` to clear and reset the list of
76+
patterns. If a ref is already packed, including it with `--exclude` will not
77+
unpack it.
78+
79+
When used with `--all`, pack only loose refs which do not match any of
80+
the provided `--exclude` patterns.
81+
82+
When used with `--include`, refs provided to `--include`, minus refs that are
83+
provided to `--exclude` will be packed.
84+
6285

6386
BUGS
6487
----

builtin/pack-refs.c

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,45 @@
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] [--include <pattern>] [--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+
static struct string_list included_refs = STRING_LIST_INIT_NODUP;
19+
struct pack_refs_opts pack_refs_opts = { .exclusions = &excludes,
20+
.includes = &included_refs,
21+
.flags = flags };
22+
static struct string_list option_excluded_refs = STRING_LIST_INIT_NODUP;
23+
struct string_list_item *item;
24+
1625
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),
26+
OPT_BIT(0, "all", &pack_refs_opts.flags, N_("pack everything"), PACK_REFS_ALL),
27+
OPT_BIT(0, "prune", &pack_refs_opts.flags, N_("prune loose refs (default)"), PACK_REFS_PRUNE),
28+
OPT_STRING_LIST(0, "include", pack_refs_opts.includes, N_("pattern"),
29+
N_("references to include")),
30+
OPT_STRING_LIST(0, "exclude", &option_excluded_refs, N_("pattern"),
31+
N_("references to exclude")),
1932
OPT_END(),
2033
};
2134
git_config(git_default_config, NULL);
2235
if (parse_options(argc, argv, prefix, opts, pack_refs_usage, 0))
2336
usage_with_options(pack_refs_usage, opts);
24-
return refs_pack_refs(get_main_ref_store(the_repository), flags);
37+
38+
for_each_string_list_item(item, &option_excluded_refs)
39+
add_ref_exclusion(pack_refs_opts.exclusions, item->string);
40+
41+
if (pack_refs_opts.flags & PACK_REFS_ALL)
42+
string_list_append(pack_refs_opts.includes, "*");
43+
44+
if (!pack_refs_opts.includes->nr)
45+
string_list_append(pack_refs_opts.includes, "refs/tags/*");
46+
47+
return refs_pack_refs(get_main_ref_store(the_repository), &pack_refs_opts);
2548
}

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: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,12 @@ 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+
struct string_list *includes;
70+
};
71+
6672
const char *refs_resolve_ref_unsafe(struct ref_store *refs,
6773
const char *refname,
6874
int resolve_flags,
@@ -405,7 +411,7 @@ void warn_dangling_symrefs(FILE *fp, const char *msg_fmt,
405411
* Write a packed-refs file for the current repository.
406412
* flags: Combination of the above PACK_REFS_* flags.
407413
*/
408-
int refs_pack_refs(struct ref_store *refs, unsigned int flags);
414+
int refs_pack_refs(struct ref_store *refs, struct pack_refs_opts *opts);
409415

410416
/*
411417
* 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
@@ -123,10 +123,10 @@ static int debug_initial_transaction_commit(struct ref_store *refs,
123123
return res;
124124
}
125125

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

refs/files-backend.c

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
#include "../worktree.h"
2222
#include "../wrapper.h"
2323
#include "../write-or-die.h"
24+
#include "../revision.h"
25+
#include <wildmatch.h>
2426

2527
/*
2628
* This backend uses the following flags in `ref_update::flags` for
@@ -1175,17 +1177,15 @@ static void prune_refs(struct files_ref_store *refs, struct ref_to_prune **refs_
11751177
*/
11761178
static int should_pack_ref(const char *refname,
11771179
const struct object_id *oid, unsigned int ref_flags,
1178-
unsigned int pack_flags)
1180+
struct pack_refs_opts *opts)
11791181
{
1182+
struct string_list_item *item;
1183+
11801184
/* Do not pack per-worktree refs: */
11811185
if (parse_worktree_ref(refname, NULL, NULL, NULL) !=
11821186
REF_WORKTREE_SHARED)
11831187
return 0;
11841188

1185-
/* Do not pack non-tags unless PACK_REFS_ALL is set: */
1186-
if (!(pack_flags & PACK_REFS_ALL) && !starts_with(refname, "refs/tags/"))
1187-
return 0;
1188-
11891189
/* Do not pack symbolic refs: */
11901190
if (ref_flags & REF_ISSYMREF)
11911191
return 0;
@@ -1194,10 +1194,18 @@ static int should_pack_ref(const char *refname,
11941194
if (!ref_resolves_to_object(refname, the_repository, oid, ref_flags))
11951195
return 0;
11961196

1197-
return 1;
1197+
if (ref_excluded(opts->exclusions, refname))
1198+
return 0;
1199+
1200+
for_each_string_list_item(item, opts->includes)
1201+
if (!wildmatch(item->string, refname, 0))
1202+
return 1;
1203+
1204+
return 0;
11981205
}
11991206

1200-
static int files_pack_refs(struct ref_store *ref_store, unsigned int flags)
1207+
static int files_pack_refs(struct ref_store *ref_store,
1208+
struct pack_refs_opts *opts)
12011209
{
12021210
struct files_ref_store *refs =
12031211
files_downcast(ref_store, REF_STORE_WRITE | REF_STORE_ODB,
@@ -1222,8 +1230,7 @@ static int files_pack_refs(struct ref_store *ref_store, unsigned int flags)
12221230
* in the packed ref cache. If the reference should be
12231231
* pruned, also add it to refs_to_prune.
12241232
*/
1225-
if (!should_pack_ref(iter->refname, iter->oid, iter->flags,
1226-
flags))
1233+
if (!should_pack_ref(iter->refname, iter->oid, iter->flags, opts))
12271234
continue;
12281235

12291236
/*
@@ -1237,7 +1244,7 @@ static int files_pack_refs(struct ref_store *ref_store, unsigned int flags)
12371244
iter->refname, err.buf);
12381245

12391246
/* Schedule the loose reference for pruning if requested. */
1240-
if ((flags & PACK_REFS_PRUNE)) {
1247+
if ((opts->flags & PACK_REFS_PRUNE)) {
12411248
struct ref_to_prune *n;
12421249
FLEX_ALLOC_STR(n, name, iter->refname);
12431250
oidcpy(&n->oid, iter->oid);

refs/packed-backend.c

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

15791579
static int packed_pack_refs(struct ref_store *ref_store UNUSED,
1580-
unsigned int flags UNUSED)
1580+
struct pack_refs_opts *pack_opts UNUSED)
15811581
{
15821582
/*
15831583
* 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
@@ -87,7 +87,7 @@ struct rev_cmdline_info {
8787
struct ref_exclusions {
8888
/*
8989
* Excluded refs is a list of wildmatch patterns. If any of the
90-
* patterns matches, the reference will be excluded.
90+
* patterns match, the reference will be excluded.
9191
*/
9292
struct string_list excluded_refs;
9393

t/helper/test-ref-store.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "worktree.h"
66
#include "object-store.h"
77
#include "repository.h"
8+
#include "revision.h"
89

910
struct flag_definition {
1011
const char *name;
@@ -116,8 +117,16 @@ static struct flag_definition pack_flags[] = { FLAG_DEF(PACK_REFS_PRUNE),
116117
static int cmd_pack_refs(struct ref_store *refs, const char **argv)
117118
{
118119
unsigned int flags = arg_flags(*argv++, "flags", pack_flags);
120+
static struct ref_exclusions exclusions = REF_EXCLUSIONS_INIT;
121+
static struct string_list included_refs = STRING_LIST_INIT_NODUP;
122+
struct pack_refs_opts pack_opts = { .flags = flags,
123+
.exclusions = &exclusions,
124+
.includes = &included_refs };
119125

120-
return refs_pack_refs(refs, flags);
126+
if (pack_opts.flags & PACK_REFS_ALL)
127+
string_list_append(pack_opts.includes, "*");
128+
129+
return refs_pack_refs(refs, &pack_opts);
121130
}
122131

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

t/t3210-pack-refs.sh

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,43 @@ 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+
127+
test_expect_success 'test only included refs are packed' '
128+
git branch pack_this1 &&
129+
git branch pack_this2 &&
130+
git tag dont_pack5 &&
131+
git pack-refs --include "refs/heads/pack_this*" &&
132+
test -f .git/refs/tags/dont_pack5 &&
133+
! test -f .git/refs/heads/pack_this1 &&
134+
! test -f .git/refs/heads/pack_this2'
135+
136+
test_expect_success 'test --no-include refs clears included refs' '
137+
git branch pack1 &&
138+
git branch pack2 &&
139+
git pack-refs --include "refs/heads/pack*" --no-include &&
140+
test -f .git/refs/heads/pack1 &&
141+
test -f .git/refs/heads/pack2'
142+
143+
test_expect_success 'test --exclude takes precedence over --include' '
144+
git branch dont_pack5 &&
145+
git pack-refs --include "refs/heads/pack*" --exclude "refs/heads/pack*" &&
146+
test -f .git/refs/heads/dont_pack5'
147+
111148
test_expect_success \
112149
'see if up-to-date packed refs are preserved' \
113150
'git branch q &&

0 commit comments

Comments
 (0)