Re: [PATCH v2 0/5] root refs vs pseudorefs
- From
Julia Evans <julia@jvns.ca>
- Date
- Nov 2, 2026, 21:00 UTC
- Message-ID
- <f194e2af-cffc-4867-9069-7070c86785da@app.fastmail.com>
- In-Reply-To
- <CAHWeT-ZdZ0o=_rPWFPcXqCyc-WV=fzmKVRVx2LetfQzgYkKO0w@mail.gmail.com>
On Mon, Nov 2, 2026, at 2:47 PM, Andy Koppe wrote:
Show 53 quoted lines
> On Mon, 2 Nov 2026 at 18:20, Julia Evans wrote: >> On Sun, Nov 1, 2026, at 6:03 PM, Andy Koppe wrote: > >> > ++[[root-refs]] >> > ++root refs:: >> > ++ Git may also create references other than `HEAD` at the root >> > of the >> > ++ hierarchy, for example `ORIG_HEAD` or `REBASE_HEAD`. >> > ++ >> > ++[[pseudorefs]] >> > ++pseudorefs:: >> > ++ linkgit:git-fetch[1] and linkgit:git-merge[1] create the >> > so-called >> > ++ pseudorefs `FETCH_HEAD` and `MERGE_HEAD`. They are not >> > references as >> > ++ such, as they are not stored in the same way, but they can >> > nevertheless >> >> When I look at my .git directory during a merge conflict, I see these >> files: >> >> $ ls .git | grep HEAD >> FETCH_HEAD >> HEAD >> MERGE_HEAD >> ORIG_HEAD >> >> From the above, it sounds like ORIG_HEAD is a "root ref" and >> MERGE_HEAD is a "pseudoref", but naively it does look like >> they're stored in the same way. What's the difference? > > Good question. The differences certainly aren't obvious, and they > barely matter to users. > > Root refs: > - Can be stored in reftables instead of files in .git. > - Contain either a single hash or a single symbolic ref such as 'ref: > refs/heads/main'. > - Can be modified with 'git update-ref' (generally a bad idea for > built-in root refs) and listed with 'git for-each-ref' and similar > commands. > > Pseudorefs: > - Are always stored as files in .git. > - May contain multiple hashes, and in the case of FETCH_HEAD, carry > additional information about where each hash came from. > - Are only modified by the commands they serve (i.e. fetch, merge and > pull) and can't be listed. > > The big thing they have in common, apart from the *_HEAD names, is > that you can pass both types to commands such as 'git log', 'git diff' > or 'git checkout' to refer to a commit or tree, just like any ref > under refs/.
That’s very helpful. I think it would make sense to include “may contain multiple hashes” at least, that on its own makes it very clear what the difference is.
My impression is that FETCH_HEAD specifically is a relatively popular pseudoref and folks would be interested to know that it can contain multiple hashes.
If a pseudoref contains multiple hashes and you pass it to a command, will the command use the first hash?
Also are FETCH_HEAD and MERGE_HEAD the only pseudorefs?