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 <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Patrick Steinhardt committed
May 15, 2024 at 08:51 UTC
993d57ededa2238e7526ccdb05b39b0265053f37
2 files changed
+50
-32
refs.c
+33
-32
@@ -844,6 +844,37 @@ int is_per_worktree_ref(const char *refname)
844
starts_with(refname, "refs/rewritten/");
845
}
846
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
+
878
static int is_root_ref_syntax(const char *refname)
879
{
880
const char *c;
@@ -868,7 +899,8 @@ int is_root_ref(const char *refname)
899
};
900
size_t i;
901
871
- if (!is_root_ref_syntax(refname))
902
+ if (!is_root_ref_syntax(refname) ||
903
+ is_pseudo_ref(refname))
904
return 0;
905
906
if (ends_with(refname, "_HEAD"))
@@ -1856,37 +1888,6 @@ done:
1888
return result;
1889
}
1890
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
-
1891
int refs_read_raw_ref(struct ref_store *ref_store, const char *refname,
1892
struct object_id *oid, struct strbuf *referent,
1893
unsigned int *type, int *failure_errno)
t/t6302-for-each-ref-filter.sh
+17
@@ -52,6 +52,23 @@ test_expect_success '--include-root-refs pattern prints pseudorefs' '
52
test_cmp expect actual
53
'
54
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
+
72
test_expect_success '--include-root-refs with other patterns' '
73
cat >expect <<-\EOF &&
74
HEAD