Skip to content

Commit 7e61ed2

Browse files
committed
Merge branch 'ak/refs-files-root-refs-cache' into seen
The loose refs cache in the files backend has been updated to avoid caching root refs (like 'HEAD'), preventing them from being omitted from subsequent iterators that explicitly request them when a previous iterator populated the cache without them. * ak/refs-files-root-refs-cache: refs/files: keep root refs out of loose ref cache
2 parents 24a5986 + 93be798 commit 7e61ed2

5 files changed

Lines changed: 46 additions & 12 deletions

File tree

‎Documentation/for-each-ref-options.adoc‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,8 @@ TAB %(refname)`.
7373
using the same rules as _<pattern>_ above.
7474

7575
`--include-root-refs`::
76-
List root refs (`HEAD` and pseudorefs) apart from regular refs.
76+
List root refs such as `HEAD` and `ORIG_HEAD` in addition to regular
77+
refs. (The pseudorefs `FETCH_HEAD` and `MERGE_HEAD` are not included.)
7778

7879
`--start-after=<marker>`::
7980
Allows paginating the output by skipping references up to and including the

‎builtin/for-each-ref.c‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ int for_each_ref_core(int argc, const char **argv, const char *prefix, struct re
4848
OPT_NO_CONTAINS(&filter.no_commit, N_("print only refs which don't contain the commit")),
4949
OPT_BOOL(0, "ignore-case", &icase, N_("sorting and filtering are case insensitive")),
5050
OPT_BOOL(0, "stdin", &from_stdin, N_("read reference patterns from stdin")),
51-
OPT_BOOL(0, "include-root-refs", &include_root_refs, N_("also include HEAD ref and pseudorefs")),
51+
OPT_BOOL(0, "include-root-refs", &include_root_refs, N_("also include root refs like HEAD")),
5252
OPT_END(),
5353
};
5454

‎refs.h‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -448,8 +448,8 @@ enum refs_for_each_flag {
448448
REFS_FOR_EACH_OMIT_DANGLING_SYMREFS = (1 << 2),
449449

450450
/*
451-
* Include root refs i.e. HEAD and pseudorefs along with the regular
452-
* refs.
451+
* Include root refs such as HEAD and ORIG_HEAD in addition to the
452+
* regular refs. Pseudorefs are not root refs and thus not included.
453453
*/
454454
REFS_FOR_EACH_INCLUDE_ROOT_REFS = (1 << 3),
455455
};

‎refs/files-backend.c‎

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -481,8 +481,7 @@ static void add_root_refs(struct files_ref_store *refs,
481481
for_each_root_ref(refs, fill_root_ref, &data);
482482
}
483483

484-
static struct ref_cache *get_loose_ref_cache(struct files_ref_store *refs,
485-
unsigned int flags)
484+
static struct ref_cache *get_loose_ref_cache(struct files_ref_store *refs)
486485
{
487486
if (!refs->loose) {
488487
struct ref_dir *dir;
@@ -499,9 +498,6 @@ static struct ref_cache *get_loose_ref_cache(struct files_ref_store *refs,
499498

500499
dir = get_ref_dir(refs->loose->root);
501500

502-
if (flags & REFS_FOR_EACH_INCLUDE_ROOT_REFS)
503-
add_root_refs(refs, dir);
504-
505501
/*
506502
* Add an incomplete entry for "refs/" (to be filled
507503
* lazily):
@@ -511,6 +507,19 @@ static struct ref_cache *get_loose_ref_cache(struct files_ref_store *refs,
511507
return refs->loose;
512508
}
513509

510+
/*
511+
* Root refs are kept out of the loose ref cache because ref iterators must
512+
* only include them when requested with REFS_FOR_EACH_INCLUDE_ROOT_REFS.
513+
*/
514+
static struct ref_cache *create_root_ref_cache(struct files_ref_store *refs)
515+
{
516+
struct ref_cache *cache = create_ref_cache(&refs->base, NULL);
517+
518+
cache->root->flag &= ~REF_INCOMPLETE;
519+
add_root_refs(refs, get_ref_dir(cache->root));
520+
return cache;
521+
}
522+
514523
static int read_ref_internal(struct ref_store *ref_store, const char *refname,
515524
struct object_id *oid, struct strbuf *referent,
516525
unsigned int *type, int *failure_errno, int skip_packed_refs)
@@ -1004,6 +1013,7 @@ struct files_ref_iterator {
10041013
struct ref_iterator base;
10051014

10061015
struct ref_iterator *iter0;
1016+
struct ref_cache *root_refs;
10071017
struct repository *repo;
10081018
unsigned int flags;
10091019
};
@@ -1053,6 +1063,7 @@ static void files_ref_iterator_release(struct ref_iterator *ref_iterator)
10531063
struct files_ref_iterator *iter =
10541064
(struct files_ref_iterator *)ref_iterator;
10551065
ref_iterator_free(iter->iter0);
1066+
free_ref_cache(iter->root_refs);
10561067
}
10571068

10581069
static struct ref_iterator_vtable files_ref_iterator_vtable = {
@@ -1068,6 +1079,7 @@ static struct ref_iterator *files_ref_iterator_begin(
10681079
{
10691080
struct files_ref_store *refs;
10701081
struct ref_iterator *loose_iter, *packed_iter, *overlay_iter;
1082+
struct ref_cache *root_refs = NULL;
10711083
struct files_ref_iterator *iter;
10721084
struct ref_iterator *ref_iterator;
10731085
unsigned int required_flags = REF_STORE_READ;
@@ -1094,9 +1106,17 @@ static struct ref_iterator *files_ref_iterator_begin(
10941106
* disk, and re-reads it if not.
10951107
*/
10961108

1097-
loose_iter = cache_ref_iterator_begin(get_loose_ref_cache(refs, flags),
1109+
loose_iter = cache_ref_iterator_begin(get_loose_ref_cache(refs),
10981110
prefix, ref_store->repo, 1);
10991111

1112+
if (flags & REFS_FOR_EACH_INCLUDE_ROOT_REFS) {
1113+
root_refs = create_root_ref_cache(refs);
1114+
loose_iter = overlay_ref_iterator_begin(
1115+
cache_ref_iterator_begin(root_refs, prefix,
1116+
ref_store->repo, 0),
1117+
loose_iter);
1118+
}
1119+
11001120
/*
11011121
* The packed-refs file might contain broken references, for
11021122
* example an old version of a reference that points at an
@@ -1118,6 +1138,7 @@ static struct ref_iterator *files_ref_iterator_begin(
11181138
ref_iterator = &iter->base;
11191139
base_ref_iterator_init(ref_iterator, &files_ref_iterator_vtable);
11201140
iter->iter0 = overlay_iter;
1141+
iter->root_refs = root_refs;
11211142
iter->repo = ref_store->repo;
11221143
iter->flags = flags;
11231144

@@ -1490,7 +1511,7 @@ static int should_pack_refs(struct files_ref_store *refs,
14901511
if (limit < 16)
14911512
limit = 16;
14921513

1493-
iter = cache_ref_iterator_begin(get_loose_ref_cache(refs, 0), NULL,
1514+
iter = cache_ref_iterator_begin(get_loose_ref_cache(refs), NULL,
14941515
refs->base.repo, 0);
14951516
while ((ret = ref_iterator_advance(iter)) == ITER_OK) {
14961517
if (should_pack_ref(refs, &iter->ref, opts))
@@ -1530,7 +1551,7 @@ static int files_optimize(struct ref_store *ref_store,
15301551

15311552
packed_refs_lock(refs->packed_ref_store, LOCK_DIE_ON_ERROR, &err);
15321553

1533-
iter = cache_ref_iterator_begin(get_loose_ref_cache(refs, 0), NULL,
1554+
iter = cache_ref_iterator_begin(get_loose_ref_cache(refs), NULL,
15341555
refs->base.repo, 0);
15351556
while ((ok = ref_iterator_advance(iter)) == ITER_OK) {
15361557
/*

‎t/t6302-for-each-ref-filter.sh‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,18 @@ test_expect_success '--include-root-refs omits dangling symrefs' '
9696
)
9797
'
9898

99+
test_expect_success '--include-root-refs with --merged' '
100+
cat >expect <<-\EOF &&
101+
HEAD
102+
ORIG_HEAD
103+
EOF
104+
test_when_finished "git update-ref -d ORIG_HEAD" &&
105+
git update-ref ORIG_HEAD main &&
106+
git for-each-ref --format="%(refname)" --include-root-refs \
107+
--merged=main "*HEAD" >actual &&
108+
test_cmp expect actual
109+
'
110+
99111
test_expect_success 'filtering with --points-at' '
100112
cat >expect <<-\EOF &&
101113
refs/heads/main

0 commit comments

Comments
 (0)