From: Andy Koppe Date: Mon, 02 Nov 2026 19:47:48 GMT Subject: Re: [PATCH v2 0/5] root refs vs pseudorefs Message-ID: In-Reply-To: <840bc117-75e9-4d63-882e-3831156871a3@app.fastmail.com> 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/.