From: Julia Evans Date: Mon, 02 Nov 2026 21:00:48 GMT Subject: Re: [PATCH v2 0/5] root refs vs pseudorefs Message-ID: In-Reply-To: On Mon, Nov 2, 2026, at 2:47 PM, Andy Koppe wrote: > 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?