1
0
Fork 0
mirror of https://github.com/git/git.git synced 2024-04-25 12:35:11 +02:00

Merge branch 'jc/pack-ref-exclude-include' into next

"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
This commit is contained in:
Junio C Hamano 2023-05-23 17:26:30 +09:00
commit 37333a2d00
11 changed files with 132 additions and 26 deletions

View File

@ -8,7 +8,7 @@ git-pack-refs - Pack heads and tags for efficient repository access
SYNOPSIS
--------
[verse]
'git pack-refs' [--all] [--no-prune]
'git pack-refs' [--all] [--no-prune] [--include <pattern>] [--exclude <pattern>]
DESCRIPTION
-----------
@ -51,14 +51,37 @@ The command by default packs all tags and refs that are already
packed, and leaves other refs
alone. This is because branches are expected to be actively
developed and packing their tips does not help performance.
This option causes branch tips to be packed as well. Useful for
a repository with many branches of historical interests.
This option causes all refs to be packed as well, with the exception
of hidden refs, broken refs, and symbolic refs. Useful for a repository
with many branches of historical interests.
--no-prune::
The command usually removes loose refs under `$GIT_DIR/refs`
hierarchy after packing them. This option tells it not to.
--include <pattern>::
Pack refs based on a `glob(7)` pattern. Repetitions of this option
accumulate inclusion patterns. If a ref is both included in `--include` and
`--exclude`, `--exclude` takes precedence. Using `--include` will preclude all
tags from being included by default. Symbolic refs and broken refs will never
be packed. When used with `--all`, it will be a noop. Use `--no-include` to clear
and reset the list of patterns.
--exclude <pattern>::
Do not pack refs matching the given `glob(7)` pattern. Repetitions of this option
accumulate exclusion patterns. Use `--no-exclude` to clear and reset the list of
patterns. If a ref is already packed, including it with `--exclude` will not
unpack it.
When used with `--all`, pack only loose refs which do not match any of
the provided `--exclude` patterns.
When used with `--include`, refs provided to `--include`, minus refs that are
provided to `--exclude` will be packed.
BUGS
----

View File

@ -4,22 +4,45 @@
#include "parse-options.h"
#include "refs.h"
#include "repository.h"
#include "revision.h"
static char const * const pack_refs_usage[] = {
N_("git pack-refs [--all] [--no-prune]"),
N_("git pack-refs [--all] [--no-prune] [--include <pattern>] [--exclude <pattern>]"),
NULL
};
int cmd_pack_refs(int argc, const char **argv, const char *prefix)
{
unsigned int flags = PACK_REFS_PRUNE;
static struct ref_exclusions excludes = REF_EXCLUSIONS_INIT;
static struct string_list included_refs = STRING_LIST_INIT_NODUP;
struct pack_refs_opts pack_refs_opts = { .exclusions = &excludes,
.includes = &included_refs,
.flags = flags };
static struct string_list option_excluded_refs = STRING_LIST_INIT_NODUP;
struct string_list_item *item;
struct option opts[] = {
OPT_BIT(0, "all", &flags, N_("pack everything"), PACK_REFS_ALL),
OPT_BIT(0, "prune", &flags, N_("prune loose refs (default)"), PACK_REFS_PRUNE),
OPT_BIT(0, "all", &pack_refs_opts.flags, N_("pack everything"), PACK_REFS_ALL),
OPT_BIT(0, "prune", &pack_refs_opts.flags, N_("prune loose refs (default)"), PACK_REFS_PRUNE),
OPT_STRING_LIST(0, "include", pack_refs_opts.includes, N_("pattern"),
N_("references to include")),
OPT_STRING_LIST(0, "exclude", &option_excluded_refs, N_("pattern"),
N_("references to exclude")),
OPT_END(),
};
git_config(git_default_config, NULL);
if (parse_options(argc, argv, prefix, opts, pack_refs_usage, 0))
usage_with_options(pack_refs_usage, opts);
return refs_pack_refs(get_main_ref_store(the_repository), flags);
for_each_string_list_item(item, &option_excluded_refs)
add_ref_exclusion(pack_refs_opts.exclusions, item->string);
if (pack_refs_opts.flags & PACK_REFS_ALL)
string_list_append(pack_refs_opts.includes, "*");
if (!pack_refs_opts.includes->nr)
string_list_append(pack_refs_opts.includes, "refs/tags/*");
return refs_pack_refs(get_main_ref_store(the_repository), &pack_refs_opts);
}

4
refs.c
View File

@ -2132,9 +2132,9 @@ void base_ref_store_init(struct ref_store *refs, struct repository *repo,
}
/* backend functions */
int refs_pack_refs(struct ref_store *refs, unsigned int flags)
int refs_pack_refs(struct ref_store *refs, struct pack_refs_opts *opts)
{
return refs->be->pack_refs(refs, flags);
return refs->be->pack_refs(refs, opts);
}
int peel_iterated_oid(const struct object_id *base, struct object_id *peeled)

8
refs.h
View File

@ -63,6 +63,12 @@ struct worktree;
#define RESOLVE_REF_NO_RECURSE 0x02
#define RESOLVE_REF_ALLOW_BAD_NAME 0x04
struct pack_refs_opts {
unsigned int flags;
struct ref_exclusions *exclusions;
struct string_list *includes;
};
const char *refs_resolve_ref_unsafe(struct ref_store *refs,
const char *refname,
int resolve_flags,
@ -405,7 +411,7 @@ void warn_dangling_symrefs(FILE *fp, const char *msg_fmt,
* Write a packed-refs file for the current repository.
* flags: Combination of the above PACK_REFS_* flags.
*/
int refs_pack_refs(struct ref_store *refs, unsigned int flags);
int refs_pack_refs(struct ref_store *refs, struct pack_refs_opts *opts);
/*
* Setup reflog before using. Fill in err and return -1 on failure.

View File

@ -123,10 +123,10 @@ static int debug_initial_transaction_commit(struct ref_store *refs,
return res;
}
static int debug_pack_refs(struct ref_store *ref_store, unsigned int flags)
static int debug_pack_refs(struct ref_store *ref_store, struct pack_refs_opts *opts)
{
struct debug_ref_store *drefs = (struct debug_ref_store *)ref_store;
int res = drefs->refs->be->pack_refs(drefs->refs, flags);
int res = drefs->refs->be->pack_refs(drefs->refs, opts);
trace_printf_key(&trace_refs, "pack_refs: %d\n", res);
return res;
}

View File

@ -21,6 +21,8 @@
#include "../worktree.h"
#include "../wrapper.h"
#include "../write-or-die.h"
#include "../revision.h"
#include <wildmatch.h>
/*
* 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_
*/
static int should_pack_ref(const char *refname,
const struct object_id *oid, unsigned int ref_flags,
unsigned int pack_flags)
struct pack_refs_opts *opts)
{
struct string_list_item *item;
/* Do not pack per-worktree refs: */
if (parse_worktree_ref(refname, NULL, NULL, NULL) !=
REF_WORKTREE_SHARED)
return 0;
/* Do not pack non-tags unless PACK_REFS_ALL is set: */
if (!(pack_flags & PACK_REFS_ALL) && !starts_with(refname, "refs/tags/"))
return 0;
/* Do not pack symbolic refs: */
if (ref_flags & REF_ISSYMREF)
return 0;
@ -1194,10 +1194,18 @@ static int should_pack_ref(const char *refname,
if (!ref_resolves_to_object(refname, the_repository, oid, ref_flags))
return 0;
return 1;
if (ref_excluded(opts->exclusions, refname))
return 0;
for_each_string_list_item(item, opts->includes)
if (!wildmatch(item->string, refname, 0))
return 1;
return 0;
}
static int files_pack_refs(struct ref_store *ref_store, unsigned int flags)
static int files_pack_refs(struct ref_store *ref_store,
struct pack_refs_opts *opts)
{
struct files_ref_store *refs =
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)
* in the packed ref cache. If the reference should be
* pruned, also add it to refs_to_prune.
*/
if (!should_pack_ref(iter->refname, iter->oid, iter->flags,
flags))
if (!should_pack_ref(iter->refname, iter->oid, iter->flags, opts))
continue;
/*
@ -1237,7 +1244,7 @@ static int files_pack_refs(struct ref_store *ref_store, unsigned int flags)
iter->refname, err.buf);
/* Schedule the loose reference for pruning if requested. */
if ((flags & PACK_REFS_PRUNE)) {
if ((opts->flags & PACK_REFS_PRUNE)) {
struct ref_to_prune *n;
FLEX_ALLOC_STR(n, name, iter->refname);
oidcpy(&n->oid, iter->oid);

View File

@ -1577,7 +1577,7 @@ static int packed_delete_refs(struct ref_store *ref_store, const char *msg,
}
static int packed_pack_refs(struct ref_store *ref_store UNUSED,
unsigned int flags UNUSED)
struct pack_refs_opts *pack_opts UNUSED)
{
/*
* Packed refs are already packed. It might be that loose refs

View File

@ -547,7 +547,8 @@ typedef int ref_transaction_commit_fn(struct ref_store *refs,
struct ref_transaction *transaction,
struct strbuf *err);
typedef int pack_refs_fn(struct ref_store *ref_store, unsigned int flags);
typedef int pack_refs_fn(struct ref_store *ref_store,
struct pack_refs_opts *opts);
typedef int create_symref_fn(struct ref_store *ref_store,
const char *ref_target,
const char *refs_heads_master,

View File

@ -87,7 +87,7 @@ struct rev_cmdline_info {
struct ref_exclusions {
/*
* Excluded refs is a list of wildmatch patterns. If any of the
* patterns matches, the reference will be excluded.
* patterns match, the reference will be excluded.
*/
struct string_list excluded_refs;

View File

@ -5,6 +5,7 @@
#include "worktree.h"
#include "object-store.h"
#include "repository.h"
#include "revision.h"
struct flag_definition {
const char *name;
@ -116,8 +117,16 @@ static struct flag_definition pack_flags[] = { FLAG_DEF(PACK_REFS_PRUNE),
static int cmd_pack_refs(struct ref_store *refs, const char **argv)
{
unsigned int flags = arg_flags(*argv++, "flags", pack_flags);
static struct ref_exclusions exclusions = REF_EXCLUSIONS_INIT;
static struct string_list included_refs = STRING_LIST_INIT_NODUP;
struct pack_refs_opts pack_opts = { .flags = flags,
.exclusions = &exclusions,
.includes = &included_refs };
return refs_pack_refs(refs, flags);
if (pack_opts.flags & PACK_REFS_ALL)
string_list_append(pack_opts.includes, "*");
return refs_pack_refs(refs, &pack_opts);
}
static int cmd_create_symref(struct ref_store *refs, const char **argv)

View File

@ -108,6 +108,43 @@ test_expect_success \
git branch -d n/o/p &&
git branch n'
test_expect_success 'test excluded refs are not packed' '
git branch dont_pack1 &&
git branch dont_pack2 &&
git branch pack_this &&
git pack-refs --all --exclude "refs/heads/dont_pack*" &&
test -f .git/refs/heads/dont_pack1 &&
test -f .git/refs/heads/dont_pack2 &&
! test -f .git/refs/heads/pack_this'
test_expect_success 'test --no-exclude refs clears excluded refs' '
git branch dont_pack3 &&
git branch dont_pack4 &&
git pack-refs --all --exclude "refs/heads/dont_pack*" --no-exclude &&
! test -f .git/refs/heads/dont_pack3 &&
! test -f .git/refs/heads/dont_pack4'
test_expect_success 'test only included refs are packed' '
git branch pack_this1 &&
git branch pack_this2 &&
git tag dont_pack5 &&
git pack-refs --include "refs/heads/pack_this*" &&
test -f .git/refs/tags/dont_pack5 &&
! test -f .git/refs/heads/pack_this1 &&
! test -f .git/refs/heads/pack_this2'
test_expect_success 'test --no-include refs clears included refs' '
git branch pack1 &&
git branch pack2 &&
git pack-refs --include "refs/heads/pack*" --no-include &&
test -f .git/refs/heads/pack1 &&
test -f .git/refs/heads/pack2'
test_expect_success 'test --exclude takes precedence over --include' '
git branch dont_pack5 &&
git pack-refs --include "refs/heads/pack*" --exclude "refs/heads/pack*" &&
test -f .git/refs/heads/dont_pack5'
test_expect_success \
'see if up-to-date packed refs are preserved' \
'git branch q &&