Merge branch 'jk/ref-paranoia'
The ref iteration code used to optionally allow dangling refs to be shown, which has been tightened up. * jk/ref-paranoia: refs: drop "broken" flag from for_each_fullref_in() ref-filter: drop broken-ref code entirely ref-filter: stop setting FILTER_REFS_INCLUDE_BROKEN repack, prune: drop GIT_REF_PARANOIA settings refs: turn on GIT_REF_PARANOIA by default refs: omit dangling symrefs when using GIT_REF_PARANOIA refs: add DO_FOR_EACH_OMIT_DANGLING_SYMREFS flag refs-internal.h: reorganize DO_FOR_EACH_* flag documentation refs-internal.h: move DO_FOR_EACH_* flags next to each other t5312: be more assertive about command failure t5312: test non-destructive repack t5312: create bogus ref as necessary t5312: drop "verbose" helper t5600: provide detached HEAD for corruption failures t5516: don't use HEAD ref for invalid ref-deletion tests t7900: clean up some more broken refs
This commit is contained in:
commit
f6c075ad71
@ -867,15 +867,16 @@ for full details.
|
||||
end user, to be recorded in the body of the reflog.
|
||||
|
||||
`GIT_REF_PARANOIA`::
|
||||
If set to `1`, include broken or badly named refs when iterating
|
||||
over lists of refs. In a normal, non-corrupted repository, this
|
||||
does nothing. However, enabling it may help git to detect and
|
||||
abort some operations in the presence of broken refs. Git sets
|
||||
this variable automatically when performing destructive
|
||||
operations like linkgit:git-prune[1]. You should not need to set
|
||||
it yourself unless you want to be paranoid about making sure
|
||||
an operation has touched every ref (e.g., because you are
|
||||
cloning a repository to make a backup).
|
||||
If set to `0`, ignore broken or badly named refs when iterating
|
||||
over lists of refs. Normally Git will try to include any such
|
||||
refs, which may cause some operations to fail. This is usually
|
||||
preferable, as potentially destructive operations (e.g.,
|
||||
linkgit:git-prune[1]) are better off aborting rather than
|
||||
ignoring broken refs (and thus considering the history they
|
||||
point to as not worth saving). The default value is `1` (i.e.,
|
||||
be paranoid about detecting and aborting all operations). You
|
||||
should not normally need to set this to `0`, but it may be
|
||||
useful when trying to salvage data from a corrupted repository.
|
||||
|
||||
`GIT_ALLOW_PROTOCOL`::
|
||||
If set to a colon-separated list of protocols, behave as if
|
||||
|
@ -427,7 +427,7 @@ static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sortin
|
||||
|
||||
memset(&array, 0, sizeof(array));
|
||||
|
||||
filter_refs(&array, filter, filter->kind | FILTER_REFS_INCLUDE_BROKEN);
|
||||
filter_refs(&array, filter, filter->kind);
|
||||
|
||||
if (filter->verbose)
|
||||
maxwidth = calc_maxwidth(&array, strlen(remote_prefix));
|
||||
|
@ -77,7 +77,7 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
|
||||
|
||||
filter.name_patterns = argv;
|
||||
filter.match_as_path = 1;
|
||||
filter_refs(&array, &filter, FILTER_REFS_ALL | FILTER_REFS_INCLUDE_BROKEN);
|
||||
filter_refs(&array, &filter, FILTER_REFS_ALL);
|
||||
ref_array_sort(sorting, &array);
|
||||
|
||||
if (!maxcount || array.nr < maxcount)
|
||||
|
@ -143,7 +143,6 @@ int cmd_prune(int argc, const char **argv, const char *prefix)
|
||||
expire = TIME_MAX;
|
||||
save_commit_buffer = 0;
|
||||
read_replace_refs = 0;
|
||||
ref_paranoia = 1;
|
||||
repo_init_revisions(the_repository, &revs, prefix);
|
||||
|
||||
argc = parse_options(argc, argv, prefix, options, prune_usage, 0);
|
||||
|
@ -586,15 +586,12 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
|
||||
strvec_pushf(&cmd.args,
|
||||
"--unpack-unreachable=%s",
|
||||
unpack_unreachable);
|
||||
strvec_push(&cmd.env_array, "GIT_REF_PARANOIA=1");
|
||||
} else if (pack_everything & LOOSEN_UNREACHABLE) {
|
||||
strvec_push(&cmd.args,
|
||||
"--unpack-unreachable");
|
||||
} else if (keep_unreachable) {
|
||||
strvec_push(&cmd.args, "--keep-unreachable");
|
||||
strvec_push(&cmd.args, "--pack-loose-unreachable");
|
||||
} else {
|
||||
strvec_push(&cmd.env_array, "GIT_REF_PARANOIA=1");
|
||||
}
|
||||
}
|
||||
} else if (geometry) {
|
||||
|
@ -863,8 +863,8 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "--bisect")) {
|
||||
for_each_fullref_in("refs/bisect/bad", show_reference, NULL, 0);
|
||||
for_each_fullref_in("refs/bisect/good", anti_reference, NULL, 0);
|
||||
for_each_fullref_in("refs/bisect/bad", show_reference, NULL);
|
||||
for_each_fullref_in("refs/bisect/good", anti_reference, NULL);
|
||||
continue;
|
||||
}
|
||||
if (opt_with_value(arg, "--branches", &arg)) {
|
||||
|
8
cache.h
8
cache.h
@ -994,14 +994,6 @@ extern const char *core_fsmonitor;
|
||||
extern int core_apply_sparse_checkout;
|
||||
extern int core_sparse_checkout_cone;
|
||||
|
||||
/*
|
||||
* Include broken refs in all ref iterations, which will
|
||||
* generally choke dangerous operations rather than letting
|
||||
* them silently proceed without taking the broken ref into
|
||||
* account.
|
||||
*/
|
||||
extern int ref_paranoia;
|
||||
|
||||
/*
|
||||
* Returns the boolean value of $GIT_OPTIONAL_LOCKS (or the default value).
|
||||
*/
|
||||
|
@ -31,7 +31,6 @@ int prefer_symlink_refs;
|
||||
int is_bare_repository_cfg = -1; /* unspecified */
|
||||
int warn_ambiguous_refs = 1;
|
||||
int warn_on_object_refname_ambiguity = 1;
|
||||
int ref_paranoia = -1;
|
||||
int repository_format_precious_objects;
|
||||
int repository_format_worktree_config;
|
||||
const char *git_commit_encoding;
|
||||
|
@ -189,7 +189,7 @@ int ls_refs(struct repository *r, struct packet_reader *request)
|
||||
if (!data.prefixes.nr)
|
||||
strvec_push(&data.prefixes, "");
|
||||
for_each_fullref_in_prefixes(get_git_namespace(), data.prefixes.v,
|
||||
send_ref, &data, 0);
|
||||
send_ref, &data);
|
||||
packet_fflush(stdout);
|
||||
strvec_clear(&data.prefixes);
|
||||
strbuf_release(&data.buf);
|
||||
|
22
ref-filter.c
22
ref-filter.c
@ -2100,8 +2100,7 @@ static int filter_pattern_match(struct ref_filter *filter, const char *refname)
|
||||
*/
|
||||
static int for_each_fullref_in_pattern(struct ref_filter *filter,
|
||||
each_ref_fn cb,
|
||||
void *cb_data,
|
||||
int broken)
|
||||
void *cb_data)
|
||||
{
|
||||
if (!filter->match_as_path) {
|
||||
/*
|
||||
@ -2109,7 +2108,7 @@ static int for_each_fullref_in_pattern(struct ref_filter *filter,
|
||||
* prefixes like "refs/heads/" etc. are stripped off,
|
||||
* so we have to look at everything:
|
||||
*/
|
||||
return for_each_fullref_in("", cb, cb_data, broken);
|
||||
return for_each_fullref_in("", cb, cb_data);
|
||||
}
|
||||
|
||||
if (filter->ignore_case) {
|
||||
@ -2118,16 +2117,16 @@ static int for_each_fullref_in_pattern(struct ref_filter *filter,
|
||||
* so just return everything and let the caller
|
||||
* sort it out.
|
||||
*/
|
||||
return for_each_fullref_in("", cb, cb_data, broken);
|
||||
return for_each_fullref_in("", cb, cb_data);
|
||||
}
|
||||
|
||||
if (!filter->name_patterns[0]) {
|
||||
/* no patterns; we have to look at everything */
|
||||
return for_each_fullref_in("", cb, cb_data, broken);
|
||||
return for_each_fullref_in("", cb, cb_data);
|
||||
}
|
||||
|
||||
return for_each_fullref_in_prefixes(NULL, filter->name_patterns,
|
||||
cb, cb_data, broken);
|
||||
cb, cb_data);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2405,13 +2404,10 @@ int filter_refs(struct ref_array *array, struct ref_filter *filter, unsigned int
|
||||
{
|
||||
struct ref_filter_cbdata ref_cbdata;
|
||||
int ret = 0;
|
||||
unsigned int broken = 0;
|
||||
|
||||
ref_cbdata.array = array;
|
||||
ref_cbdata.filter = filter;
|
||||
|
||||
if (type & FILTER_REFS_INCLUDE_BROKEN)
|
||||
broken = 1;
|
||||
filter->kind = type & FILTER_REFS_KIND_MASK;
|
||||
|
||||
init_contains_cache(&ref_cbdata.contains_cache);
|
||||
@ -2428,13 +2424,13 @@ int filter_refs(struct ref_array *array, struct ref_filter *filter, unsigned int
|
||||
* of filter_ref_kind().
|
||||
*/
|
||||
if (filter->kind == FILTER_REFS_BRANCHES)
|
||||
ret = for_each_fullref_in("refs/heads/", ref_filter_handler, &ref_cbdata, broken);
|
||||
ret = for_each_fullref_in("refs/heads/", ref_filter_handler, &ref_cbdata);
|
||||
else if (filter->kind == FILTER_REFS_REMOTES)
|
||||
ret = for_each_fullref_in("refs/remotes/", ref_filter_handler, &ref_cbdata, broken);
|
||||
ret = for_each_fullref_in("refs/remotes/", ref_filter_handler, &ref_cbdata);
|
||||
else if (filter->kind == FILTER_REFS_TAGS)
|
||||
ret = for_each_fullref_in("refs/tags/", ref_filter_handler, &ref_cbdata, broken);
|
||||
ret = for_each_fullref_in("refs/tags/", ref_filter_handler, &ref_cbdata);
|
||||
else if (filter->kind & FILTER_REFS_ALL)
|
||||
ret = for_each_fullref_in_pattern(filter, ref_filter_handler, &ref_cbdata, broken);
|
||||
ret = for_each_fullref_in_pattern(filter, ref_filter_handler, &ref_cbdata);
|
||||
if (!ret && (filter->kind & FILTER_REFS_DETACHED_HEAD))
|
||||
head_ref(ref_filter_handler, &ref_cbdata);
|
||||
}
|
||||
|
@ -13,7 +13,6 @@
|
||||
#define QUOTE_PYTHON 4
|
||||
#define QUOTE_TCL 8
|
||||
|
||||
#define FILTER_REFS_INCLUDE_BROKEN 0x0001
|
||||
#define FILTER_REFS_TAGS 0x0002
|
||||
#define FILTER_REFS_BRANCHES 0x0004
|
||||
#define FILTER_REFS_REMOTES 0x0008
|
||||
|
42
refs.c
42
refs.c
@ -1409,14 +1409,21 @@ int head_ref(each_ref_fn fn, void *cb_data)
|
||||
|
||||
struct ref_iterator *refs_ref_iterator_begin(
|
||||
struct ref_store *refs,
|
||||
const char *prefix, int trim, int flags)
|
||||
const char *prefix, int trim,
|
||||
enum do_for_each_ref_flags flags)
|
||||
{
|
||||
struct ref_iterator *iter;
|
||||
|
||||
if (ref_paranoia < 0)
|
||||
ref_paranoia = git_env_bool("GIT_REF_PARANOIA", 0);
|
||||
if (ref_paranoia)
|
||||
flags |= DO_FOR_EACH_INCLUDE_BROKEN;
|
||||
if (!(flags & DO_FOR_EACH_INCLUDE_BROKEN)) {
|
||||
static int ref_paranoia = -1;
|
||||
|
||||
if (ref_paranoia < 0)
|
||||
ref_paranoia = git_env_bool("GIT_REF_PARANOIA", 1);
|
||||
if (ref_paranoia) {
|
||||
flags |= DO_FOR_EACH_INCLUDE_BROKEN;
|
||||
flags |= DO_FOR_EACH_OMIT_DANGLING_SYMREFS;
|
||||
}
|
||||
}
|
||||
|
||||
iter = refs->be->iterator_begin(refs, prefix, flags);
|
||||
|
||||
@ -1475,7 +1482,8 @@ static int do_for_each_ref_helper(struct repository *r,
|
||||
}
|
||||
|
||||
static int do_for_each_ref(struct ref_store *refs, const char *prefix,
|
||||
each_ref_fn fn, int trim, int flags, void *cb_data)
|
||||
each_ref_fn fn, int trim,
|
||||
enum do_for_each_ref_flags flags, void *cb_data)
|
||||
{
|
||||
struct ref_iterator *iter;
|
||||
struct do_for_each_ref_help hp = { fn, cb_data };
|
||||
@ -1510,25 +1518,16 @@ int for_each_ref_in(const char *prefix, each_ref_fn fn, void *cb_data)
|
||||
return refs_for_each_ref_in(get_main_ref_store(the_repository), prefix, fn, cb_data);
|
||||
}
|
||||
|
||||
int for_each_fullref_in(const char *prefix, each_ref_fn fn, void *cb_data, unsigned int broken)
|
||||
int for_each_fullref_in(const char *prefix, each_ref_fn fn, void *cb_data)
|
||||
{
|
||||
unsigned int flag = 0;
|
||||
|
||||
if (broken)
|
||||
flag = DO_FOR_EACH_INCLUDE_BROKEN;
|
||||
return do_for_each_ref(get_main_ref_store(the_repository),
|
||||
prefix, fn, 0, flag, cb_data);
|
||||
prefix, fn, 0, 0, cb_data);
|
||||
}
|
||||
|
||||
int refs_for_each_fullref_in(struct ref_store *refs, const char *prefix,
|
||||
each_ref_fn fn, void *cb_data,
|
||||
unsigned int broken)
|
||||
each_ref_fn fn, void *cb_data)
|
||||
{
|
||||
unsigned int flag = 0;
|
||||
|
||||
if (broken)
|
||||
flag = DO_FOR_EACH_INCLUDE_BROKEN;
|
||||
return do_for_each_ref(refs, prefix, fn, 0, flag, cb_data);
|
||||
return do_for_each_ref(refs, prefix, fn, 0, 0, cb_data);
|
||||
}
|
||||
|
||||
int for_each_replace_ref(struct repository *r, each_repo_ref_fn fn, void *cb_data)
|
||||
@ -1620,8 +1619,7 @@ static void find_longest_prefixes(struct string_list *out,
|
||||
|
||||
int for_each_fullref_in_prefixes(const char *namespace,
|
||||
const char **patterns,
|
||||
each_ref_fn fn, void *cb_data,
|
||||
unsigned int broken)
|
||||
each_ref_fn fn, void *cb_data)
|
||||
{
|
||||
struct string_list prefixes = STRING_LIST_INIT_DUP;
|
||||
struct string_list_item *prefix;
|
||||
@ -1636,7 +1634,7 @@ int for_each_fullref_in_prefixes(const char *namespace,
|
||||
|
||||
for_each_string_list_item(prefix, &prefixes) {
|
||||
strbuf_addstr(&buf, prefix->string);
|
||||
ret = for_each_fullref_in(buf.buf, fn, cb_data, broken);
|
||||
ret = for_each_fullref_in(buf.buf, fn, cb_data);
|
||||
if (ret)
|
||||
break;
|
||||
strbuf_setlen(&buf, namespace_len);
|
||||
|
9
refs.h
9
refs.h
@ -342,10 +342,8 @@ int for_each_ref(each_ref_fn fn, void *cb_data);
|
||||
int for_each_ref_in(const char *prefix, each_ref_fn fn, void *cb_data);
|
||||
|
||||
int refs_for_each_fullref_in(struct ref_store *refs, const char *prefix,
|
||||
each_ref_fn fn, void *cb_data,
|
||||
unsigned int broken);
|
||||
int for_each_fullref_in(const char *prefix, each_ref_fn fn, void *cb_data,
|
||||
unsigned int broken);
|
||||
each_ref_fn fn, void *cb_data);
|
||||
int for_each_fullref_in(const char *prefix, each_ref_fn fn, void *cb_data);
|
||||
|
||||
/**
|
||||
* iterate all refs in "patterns" by partitioning patterns into disjoint sets
|
||||
@ -354,8 +352,7 @@ int for_each_fullref_in(const char *prefix, each_ref_fn fn, void *cb_data,
|
||||
* callers should be prepared to ignore references that they did not ask for.
|
||||
*/
|
||||
int for_each_fullref_in_prefixes(const char *namespace, const char **patterns,
|
||||
each_ref_fn fn, void *cb_data,
|
||||
unsigned int broken);
|
||||
each_ref_fn fn, void *cb_data);
|
||||
/**
|
||||
* iterate refs from the respective area.
|
||||
*/
|
||||
|
@ -744,6 +744,11 @@ static int files_ref_iterator_advance(struct ref_iterator *ref_iterator)
|
||||
ref_type(iter->iter0->refname) != REF_TYPE_PER_WORKTREE)
|
||||
continue;
|
||||
|
||||
if ((iter->flags & DO_FOR_EACH_OMIT_DANGLING_SYMREFS) &&
|
||||
(iter->iter0->flags & REF_ISSYMREF) &&
|
||||
(iter->iter0->flags & REF_ISBROKEN))
|
||||
continue;
|
||||
|
||||
if (!(iter->flags & DO_FOR_EACH_INCLUDE_BROKEN) &&
|
||||
!ref_resolves_to_object(iter->iter0->refname,
|
||||
iter->iter0->oid,
|
||||
|
@ -245,8 +245,36 @@ int refs_rename_ref_available(struct ref_store *refs,
|
||||
/* We allow "recursive" symbolic refs. Only within reason, though */
|
||||
#define SYMREF_MAXDEPTH 5
|
||||
|
||||
/* Include broken references in a do_for_each_ref*() iteration: */
|
||||
#define DO_FOR_EACH_INCLUDE_BROKEN 0x01
|
||||
/*
|
||||
* These flags are passed to refs_ref_iterator_begin() (and do_for_each_ref(),
|
||||
* which feeds it).
|
||||
*/
|
||||
enum do_for_each_ref_flags {
|
||||
/*
|
||||
* Include broken references in a do_for_each_ref*() iteration, which
|
||||
* would normally be omitted. This includes both refs that point to
|
||||
* missing objects (a true repository corruption), ones with illegal
|
||||
* names (which we prefer not to expose to callers), as well as
|
||||
* dangling symbolic refs (i.e., those that point to a non-existent
|
||||
* ref; this is not a corruption, but as they have no valid oid, we
|
||||
* omit them from normal iteration results).
|
||||
*/
|
||||
DO_FOR_EACH_INCLUDE_BROKEN = (1 << 0),
|
||||
|
||||
/*
|
||||
* Only include per-worktree refs in a do_for_each_ref*() iteration.
|
||||
* Normally this will be used with a files ref_store, since that's
|
||||
* where all reference backends will presumably store their
|
||||
* per-worktree refs.
|
||||
*/
|
||||
DO_FOR_EACH_PER_WORKTREE_ONLY = (1 << 1),
|
||||
|
||||
/*
|
||||
* Omit dangling symrefs from output; this only has an effect with
|
||||
* INCLUDE_BROKEN, since they are otherwise not included at all.
|
||||
*/
|
||||
DO_FOR_EACH_OMIT_DANGLING_SYMREFS = (1 << 2),
|
||||
};
|
||||
|
||||
/*
|
||||
* Reference iterators
|
||||
@ -349,16 +377,12 @@ int is_empty_ref_iterator(struct ref_iterator *ref_iterator);
|
||||
* Return an iterator that goes over each reference in `refs` for
|
||||
* which the refname begins with prefix. If trim is non-zero, then
|
||||
* trim that many characters off the beginning of each refname.
|
||||
* The output is ordered by refname. The following flags are supported:
|
||||
*
|
||||
* DO_FOR_EACH_INCLUDE_BROKEN: include broken references in
|
||||
* the iteration.
|
||||
*
|
||||
* DO_FOR_EACH_PER_WORKTREE_ONLY: only produce REF_TYPE_PER_WORKTREE refs.
|
||||
* The output is ordered by refname.
|
||||
*/
|
||||
struct ref_iterator *refs_ref_iterator_begin(
|
||||
struct ref_store *refs,
|
||||
const char *prefix, int trim, int flags);
|
||||
const char *prefix, int trim,
|
||||
enum do_for_each_ref_flags flags);
|
||||
|
||||
/*
|
||||
* A callback function used to instruct merge_ref_iterator how to
|
||||
@ -446,10 +470,8 @@ void base_ref_iterator_free(struct ref_iterator *iter);
|
||||
/*
|
||||
* backend-specific implementation of ref_iterator_advance. For symrefs, the
|
||||
* function should set REF_ISSYMREF, and it should also dereference the symref
|
||||
* to provide the OID referent. If DO_FOR_EACH_INCLUDE_BROKEN is set, symrefs
|
||||
* with non-existent referents and refs pointing to non-existent object names
|
||||
* should also be returned. If DO_FOR_EACH_PER_WORKTREE_ONLY, only
|
||||
* REF_TYPE_PER_WORKTREE refs should be returned.
|
||||
* to provide the OID referent. It should respect do_for_each_ref_flags
|
||||
* that were passed to refs_ref_iterator_begin().
|
||||
*/
|
||||
typedef int ref_iterator_advance_fn(struct ref_iterator *ref_iterator);
|
||||
|
||||
@ -498,14 +520,6 @@ int do_for_each_repo_ref_iterator(struct repository *r,
|
||||
struct ref_iterator *iter,
|
||||
each_repo_ref_fn fn, void *cb_data);
|
||||
|
||||
/*
|
||||
* Only include per-worktree refs in a do_for_each_ref*() iteration.
|
||||
* Normally this will be used with a files ref_store, since that's
|
||||
* where all reference backends will presumably store their
|
||||
* per-worktree refs.
|
||||
*/
|
||||
#define DO_FOR_EACH_PER_WORKTREE_ONLY 0x02
|
||||
|
||||
struct ref_store;
|
||||
|
||||
/* refs backends */
|
||||
|
@ -2548,7 +2548,7 @@ static int for_each_bisect_ref(struct ref_store *refs, each_ref_fn fn,
|
||||
struct strbuf bisect_refs = STRBUF_INIT;
|
||||
int status;
|
||||
strbuf_addf(&bisect_refs, "refs/bisect/%s", term);
|
||||
status = refs_for_each_fullref_in(refs, bisect_refs.buf, fn, cb_data, 0);
|
||||
status = refs_for_each_fullref_in(refs, bisect_refs.buf, fn, cb_data);
|
||||
strbuf_release(&bisect_refs);
|
||||
return status;
|
||||
}
|
||||
|
@ -170,7 +170,7 @@ test_expect_success 'for-each-ref emits warnings for broken names' '
|
||||
! grep -e "badname" output &&
|
||||
! grep -e "broken\.\.\.symref" output &&
|
||||
test_i18ngrep "ignoring ref with broken name refs/heads/broken\.\.\.ref" error &&
|
||||
test_i18ngrep "ignoring broken ref refs/heads/badname" error &&
|
||||
test_i18ngrep ! "ignoring broken ref refs/heads/badname" error &&
|
||||
test_i18ngrep "ignoring ref with broken name refs/heads/broken\.\.\.symref" error
|
||||
'
|
||||
|
||||
|
@ -7,6 +7,9 @@ if we see, for example, a ref with a bogus name, it is OK either to
|
||||
bail out or to proceed using it as a reachable tip, but it is _not_
|
||||
OK to proceed as if it did not exist. Otherwise we might silently
|
||||
delete objects that cannot be recovered.
|
||||
|
||||
Note that we do assert command failure in these cases, because that is
|
||||
what currently happens. If that changes, these tests should be revisited.
|
||||
'
|
||||
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
|
||||
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
|
||||
@ -18,39 +21,58 @@ test_expect_success 'disable reflogs' '
|
||||
git reflog expire --expire=all --all
|
||||
'
|
||||
|
||||
create_bogus_ref () {
|
||||
test_when_finished 'rm -f .git/refs/heads/bogus..name' &&
|
||||
echo $bogus >.git/refs/heads/bogus..name
|
||||
}
|
||||
|
||||
test_expect_success 'create history reachable only from a bogus-named ref' '
|
||||
test_tick && git commit --allow-empty -m main &&
|
||||
base=$(git rev-parse HEAD) &&
|
||||
test_tick && git commit --allow-empty -m bogus &&
|
||||
bogus=$(git rev-parse HEAD) &&
|
||||
git cat-file commit $bogus >saved &&
|
||||
echo $bogus >.git/refs/heads/bogus..name &&
|
||||
git reset --hard HEAD^
|
||||
'
|
||||
|
||||
test_expect_success 'pruning does not drop bogus object' '
|
||||
test_when_finished "git hash-object -w -t commit saved" &&
|
||||
test_might_fail git prune --expire=now &&
|
||||
verbose git cat-file -e $bogus
|
||||
create_bogus_ref &&
|
||||
test_must_fail git prune --expire=now &&
|
||||
git cat-file -e $bogus
|
||||
'
|
||||
|
||||
test_expect_success 'put bogus object into pack' '
|
||||
git tag reachable $bogus &&
|
||||
git repack -ad &&
|
||||
git tag -d reachable &&
|
||||
verbose git cat-file -e $bogus
|
||||
git cat-file -e $bogus
|
||||
'
|
||||
|
||||
test_expect_success 'non-destructive repack bails on bogus ref' '
|
||||
create_bogus_ref &&
|
||||
test_must_fail git repack -adk
|
||||
'
|
||||
|
||||
test_expect_success 'GIT_REF_PARANOIA=0 overrides safety' '
|
||||
create_bogus_ref &&
|
||||
GIT_REF_PARANOIA=0 git repack -adk
|
||||
'
|
||||
|
||||
|
||||
test_expect_success 'destructive repack keeps packed object' '
|
||||
test_might_fail git repack -Ad --unpack-unreachable=now &&
|
||||
verbose git cat-file -e $bogus &&
|
||||
test_might_fail git repack -ad &&
|
||||
verbose git cat-file -e $bogus
|
||||
create_bogus_ref &&
|
||||
test_must_fail git repack -Ad --unpack-unreachable=now &&
|
||||
git cat-file -e $bogus &&
|
||||
test_must_fail git repack -ad &&
|
||||
git cat-file -e $bogus
|
||||
'
|
||||
|
||||
# subsequent tests will have different corruptions
|
||||
test_expect_success 'clean up bogus ref' '
|
||||
rm .git/refs/heads/bogus..name
|
||||
test_expect_success 'destructive repack not confused by dangling symref' '
|
||||
test_when_finished "git symbolic-ref -d refs/heads/dangling" &&
|
||||
git symbolic-ref refs/heads/dangling refs/heads/does-not-exist &&
|
||||
git repack -ad &&
|
||||
test_must_fail git cat-file -e $bogus
|
||||
'
|
||||
|
||||
# We create two new objects here, "one" and "two". Our
|
||||
@ -77,8 +99,8 @@ test_expect_success 'create history with missing tip commit' '
|
||||
|
||||
test_expect_success 'pruning with a corrupted tip does not drop history' '
|
||||
test_when_finished "git hash-object -w -t commit saved" &&
|
||||
test_might_fail git prune --expire=now &&
|
||||
verbose git cat-file -e $recoverable
|
||||
test_must_fail git prune --expire=now &&
|
||||
git cat-file -e $recoverable
|
||||
'
|
||||
|
||||
test_expect_success 'pack-refs does not silently delete broken loose ref' '
|
||||
|
@ -662,10 +662,10 @@ test_expect_success 'push does not update local refs on failure' '
|
||||
|
||||
test_expect_success 'allow deleting an invalid remote ref' '
|
||||
|
||||
mk_test testrepo heads/main &&
|
||||
mk_test testrepo heads/branch &&
|
||||
rm -f testrepo/.git/objects/??/* &&
|
||||
git push testrepo :refs/heads/main &&
|
||||
(cd testrepo && test_must_fail git rev-parse --verify refs/heads/main)
|
||||
git push testrepo :refs/heads/branch &&
|
||||
(cd testrepo && test_must_fail git rev-parse --verify refs/heads/branch)
|
||||
|
||||
'
|
||||
|
||||
@ -706,25 +706,26 @@ test_expect_success 'pushing valid refs triggers post-receive and post-update ho
|
||||
'
|
||||
|
||||
test_expect_success 'deleting dangling ref triggers hooks with correct args' '
|
||||
mk_test_with_hooks testrepo heads/main &&
|
||||
mk_test_with_hooks testrepo heads/branch &&
|
||||
orig=$(git -C testrepo rev-parse refs/heads/branch) &&
|
||||
rm -f testrepo/.git/objects/??/* &&
|
||||
git push testrepo :refs/heads/main &&
|
||||
git push testrepo :refs/heads/branch &&
|
||||
(
|
||||
cd testrepo/.git &&
|
||||
cat >pre-receive.expect <<-EOF &&
|
||||
$ZERO_OID $ZERO_OID refs/heads/main
|
||||
$orig $ZERO_OID refs/heads/branch
|
||||
EOF
|
||||
|
||||
cat >update.expect <<-EOF &&
|
||||
refs/heads/main $ZERO_OID $ZERO_OID
|
||||
refs/heads/branch $orig $ZERO_OID
|
||||
EOF
|
||||
|
||||
cat >post-receive.expect <<-EOF &&
|
||||
$ZERO_OID $ZERO_OID refs/heads/main
|
||||
$orig $ZERO_OID refs/heads/branch
|
||||
EOF
|
||||
|
||||
cat >post-update.expect <<-EOF &&
|
||||
refs/heads/main
|
||||
refs/heads/branch
|
||||
EOF
|
||||
|
||||
test_cmp pre-receive.expect pre-receive.actual &&
|
||||
|
@ -35,7 +35,9 @@ test_expect_success 'create a repo to clone' '
|
||||
'
|
||||
|
||||
test_expect_success 'create objects in repo for later corruption' '
|
||||
test_commit -C foo file
|
||||
test_commit -C foo file &&
|
||||
git -C foo checkout --detach &&
|
||||
test_commit -C foo detached
|
||||
'
|
||||
|
||||
# source repository given to git clone should be relative to the
|
||||
|
@ -276,7 +276,7 @@ test_expect_success 'incremental-repack task' '
|
||||
|
||||
# Delete refs that have not been repacked in these packs.
|
||||
git for-each-ref --format="delete %(refname)" \
|
||||
refs/prefetch refs/tags >refs &&
|
||||
refs/prefetch refs/tags refs/remotes >refs &&
|
||||
git update-ref --stdin <refs &&
|
||||
|
||||
# Replace the object directory with this pack layout.
|
||||
@ -285,6 +285,10 @@ test_expect_success 'incremental-repack task' '
|
||||
ls $packDir/*.pack >packs-before &&
|
||||
test_line_count = 3 packs-before &&
|
||||
|
||||
# make sure we do not have any broken refs that were
|
||||
# missed in the deletion above
|
||||
git for-each-ref &&
|
||||
|
||||
# the job repacks the two into a new pack, but does not
|
||||
# delete the old ones.
|
||||
git maintenance run --task=incremental-repack &&
|
||||
|
Loading…
Reference in New Issue
Block a user