refs: complete list of special refs

We have some references that are more special than others. The reason for them being special is that they either do not follow the usual format of references, or that they are written to the filesystem directly by the respective owning subsystem and thus circumvent the reference backend. This works perfectly fine right now because the reffiles backend will know how to read those refs just fine. But with the prospect of gaining a new reference backend implementation we need to be a lot more careful here: - We need to make sure that we are consistent about how those refs are written. They must either always be written via the filesystem, or they must always be written via the reference backend. Any mixture will lead to inconsistent state. - We need to make sure that such special refs are always handled specially when reading them. We're already mostly good with regard to the first item, except for `BISECT_EXPECTED_REV` which will be addressed in a subsequent commit. But the current list of special refs is missing some refs that really should be treated specially. Right now, we only treat `FETCH_HEAD` and `MERGE_HEAD` specially here. Introduce a new function `is_special_ref()` that contains all current instances of special refs to fix the reading path. Note that this is only a temporary measure where we record and rectify the current state. Ideally, the list of special refs should in the end only contain `FETCH_HEAD` and `MERGE_HEAD` again because they both may reference multiple objects and can contain annotations, so they indeed are special. Based-on-patch-by: Han-Wen Nienhuys <hanwenn@gmail.com> Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Patrick Steinhardt committed Dec 14, 2023 at 14:37 UTC 70c70de616c306cd4bb7c70426e394d08f929dff
1 file changed +52 -2
refs.c
+52 -2
@@ -1820,15 +1820,65 @@ done:
1820 return result;
1821 }
1822
1823 +static int is_special_ref(const char *refname)
1824 +{
1825 + /*
1826 + * Special references get written and read directly via the filesystem
1827 + * by the subsystems that create them. Thus, they must not go through
1828 + * the reference backend but must instead be read directly. It is
1829 + * arguable whether this behaviour is sensible, or whether it's simply
1830 + * a leaky abstraction enabled by us only having a single reference
1831 + * backend implementation. But at least for a subset of references it
1832 + * indeed does make sense to treat them specially:
1833 + *
1834 + * - FETCH_HEAD may contain multiple object IDs, and each one of them
1835 + * carries additional metadata like where it came from.
1836 + *
1837 + * - MERGE_HEAD may contain multiple object IDs when merging multiple
1838 + * heads.
1839 + *
1840 + * There are some exceptions that you might expect to see on this list
1841 + * but which are handled exclusively via the reference backend:
1842 + *
1843 + * - CHERRY_PICK_HEAD
1844 + *
1845 + * - HEAD
1846 + *
1847 + * - ORIG_HEAD
1848 + *
1849 + * - "rebase-apply/" and "rebase-merge/" contain all of the state for
1850 + * rebases, including some reference-like files. These are
1851 + * exclusively read and written via the filesystem and never go
1852 + * through the refdb.
1853 + *
1854 + * Writing or deleting references must consistently go either through
1855 + * the filesystem (special refs) or through the reference backend
1856 + * (normal ones).
1857 + */
1858 + static const char * const special_refs[] = {
1859 + "AUTO_MERGE",
1860 + "BISECT_EXPECTED_REV",
1861 + "FETCH_HEAD",
1862 + "MERGE_AUTOSTASH",
1863 + "MERGE_HEAD",
1864 + };
1865 + size_t i;
1866 +
1867 + for (i = 0; i < ARRAY_SIZE(special_refs); i++)
1868 + if (!strcmp(refname, special_refs[i]))
1869 + return 1;
1870 +
1871 + return 0;
1872 +}
1873 +
1874 int refs_read_raw_ref(struct ref_store *ref_store, const char *refname,
1875 struct object_id *oid, struct strbuf *referent,
1876 unsigned int *type, int *failure_errno)
1877 {
1878 assert(failure_errno);
1828 - if (!strcmp(refname, "FETCH_HEAD") || !strcmp(refname, "MERGE_HEAD")) {
1879 + if (is_special_ref(refname))
1880 return refs_read_special_head(ref_store, refname, oid, referent,
1881 type, failure_errno);
1831 - }
1882
1883 return ref_store->be->read_raw_ref(ref_store, refname, oid, referent,
1884 type, failure_errno);