Skip to content

Commit 993d57e

Browse files
pks-tgitster
authored andcommitted
refs: pseudorefs are no refs
The `is_root_ref()` function will happily clarify a pseudoref as a root ref, even though pseudorefs are no refs. Next to being wrong, it also leads to inconsistent behaviour across ref backends: while the "files" backend accidentally knows to parse those pseudorefs and thus yields them to the caller, the "reftable" backend won't ever see the pseudoref at all because they are never stored in the "reftable" backend. Fix this issue by filtering out pseudorefs in `is_root_ref()`. Signed-off-by: Patrick Steinhardt <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 31951c2 commit 993d57e

File tree

2 files changed

+50
-32
lines changed

2 files changed

+50
-32
lines changed

refs.c

Lines changed: 33 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -844,6 +844,37 @@ int is_per_worktree_ref(const char *refname)
844844
starts_with(refname, "refs/rewritten/");
845845
}
846846

847+
static int is_pseudo_ref(const char *refname)
848+
{
849+
/*
850+
* Pseudorefs are refs that have different semantics compared to
851+
* "normal" refs. These refs can thus not be stored in the ref backend,
852+
* but must always be accessed via the filesystem. The following refs
853+
* are pseudorefs:
854+
*
855+
* - FETCH_HEAD may contain multiple object IDs, and each one of them
856+
* carries additional metadata like where it came from.
857+
*
858+
* - MERGE_HEAD may contain multiple object IDs when merging multiple
859+
* heads.
860+
*
861+
* Reading, writing or deleting references must consistently go either
862+
* through the filesystem (pseudorefs) or through the reference
863+
* backend (normal ones).
864+
*/
865+
static const char * const pseudo_refs[] = {
866+
"FETCH_HEAD",
867+
"MERGE_HEAD",
868+
};
869+
size_t i;
870+
871+
for (i = 0; i < ARRAY_SIZE(pseudo_refs); i++)
872+
if (!strcmp(refname, pseudo_refs[i]))
873+
return 1;
874+
875+
return 0;
876+
}
877+
847878
static int is_root_ref_syntax(const char *refname)
848879
{
849880
const char *c;
@@ -868,7 +899,8 @@ int is_root_ref(const char *refname)
868899
};
869900
size_t i;
870901

871-
if (!is_root_ref_syntax(refname))
902+
if (!is_root_ref_syntax(refname) ||
903+
is_pseudo_ref(refname))
872904
return 0;
873905

874906
if (ends_with(refname, "_HEAD"))
@@ -1856,37 +1888,6 @@ static int refs_read_special_head(struct ref_store *ref_store,
18561888
return result;
18571889
}
18581890

1859-
static int is_pseudo_ref(const char *refname)
1860-
{
1861-
/*
1862-
* Pseudorefs are refs that have different semantics compared to
1863-
* "normal" refs. These refs can thus not be stored in the ref backend,
1864-
* but must always be accessed via the filesystem. The following refs
1865-
* are pseudorefs:
1866-
*
1867-
* - FETCH_HEAD may contain multiple object IDs, and each one of them
1868-
* carries additional metadata like where it came from.
1869-
*
1870-
* - MERGE_HEAD may contain multiple object IDs when merging multiple
1871-
* heads.
1872-
*
1873-
* Reading, writing or deleting references must consistently go either
1874-
* through the filesystem (pseudorefs) or through the reference
1875-
* backend (normal ones).
1876-
*/
1877-
static const char * const pseudo_refs[] = {
1878-
"FETCH_HEAD",
1879-
"MERGE_HEAD",
1880-
};
1881-
size_t i;
1882-
1883-
for (i = 0; i < ARRAY_SIZE(pseudo_refs); i++)
1884-
if (!strcmp(refname, pseudo_refs[i]))
1885-
return 1;
1886-
1887-
return 0;
1888-
}
1889-
18901891
int refs_read_raw_ref(struct ref_store *ref_store, const char *refname,
18911892
struct object_id *oid, struct strbuf *referent,
18921893
unsigned int *type, int *failure_errno)

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,23 @@ test_expect_success '--include-root-refs pattern prints pseudorefs' '
5252
test_cmp expect actual
5353
'
5454

55+
test_expect_success '--include-root-refs pattern does not print special refs' '
56+
test_when_finished "rm -rf repo" &&
57+
git init repo &&
58+
(
59+
cd repo &&
60+
test_commit initial &&
61+
git rev-parse HEAD >.git/MERGE_HEAD &&
62+
git for-each-ref --format="%(refname)" --include-root-refs >actual &&
63+
cat >expect <<-EOF &&
64+
HEAD
65+
$(git symbolic-ref HEAD)
66+
refs/tags/initial
67+
EOF
68+
test_cmp expect actual
69+
)
70+
'
71+
5572
test_expect_success '--include-root-refs with other patterns' '
5673
cat >expect <<-\EOF &&
5774
HEAD

0 commit comments

Comments
 (0)