From: Julia Evans Date: Mon, 02 Nov 2026 18:19:57 GMT Subject: Re: [PATCH v2 0/5] root refs vs pseudorefs Message-ID: <840bc117-75e9-4d63-882e-3831156871a3@app.fastmail.com> In-Reply-To: <20261101230326.3675597-1-andy.koppe@gmail.com> On Sun, Nov 1, 2026, at 6:03 PM, Andy Koppe wrote: > Changes in v2: > - Tweak pseudoref definition. > - Add prefix lists for per-worktree refs. > - Wrap lists in '--'. > - Add root refs and pseudorefs to ref types in gitdatamodel(7). > - Trim messages of commits 3 and 4. > > Andy Koppe (5): > doc: glossary: add root ref and clarify pseudorefs > doc: glossary: update per-worktree refs > doc: stop calling root refs pseudorefs > refs: stop calling root refs pseudorefs > t: stop calling root refs pseudorefs > > Documentation/config/core.adoc | 2 +- > Documentation/for-each-ref-options.adoc | 2 +- > Documentation/git-ls-remote.adoc | 4 +- > Documentation/git-update-ref.adoc | 13 ++- > Documentation/git-worktree.adoc | 13 ++- > Documentation/gitdatamodel.adoc | 18 +++- > Documentation/glossary-content.adoc | 98 ++++++++++++------- > Documentation/rev-list-options.adoc | 4 +- > builtin/for-each-ref.c | 2 +- > contrib/completion/git-completion.bash | 7 +- > refs.h | 13 ++- > revision.c | 2 +- > t/show-ref-exists-tests.sh | 4 +- > t/t0600-reffiles-backend.sh | 2 +- > t/t0610-reftable-basics.sh | 2 +- > t/t1400-update-ref.sh | 66 ++++++------- > t/t1403-show-ref.sh | 2 +- > t/t1460-refs-migrate.sh | 4 +- > t/t4013-diff-various.sh | 6 +- > ...iff.diff-tree_--cc_--summary_REVERSE_HEAD} | 2 +- > t/t6302-for-each-ref-filter.sh | 4 +- > t/t9902-completion.sh | 4 +- > 22 files changed, 158 insertions(+), 116 deletions(-) > rename t/t4013/{diff.diff-tree_--cc_--summary_REVERSE => > diff.diff-tree_--cc_--summary_REVERSE_HEAD} (73%) > > Range-diff against v1: > 1: 9979ad1589 ! 1: 4734fa2f2e doc: glossary: add root ref and clarify > pseudorefs > @@ Documentation/glossary-content.adoc: exclude;; > - A ref that has different semantics than normal refs. These refs > can be > - read via normal Git commands, but cannot be written to by > commands like > - linkgit:git-update-ref[1]. > -+ A name that can be used like a <> to refer to > -+ <>, but that is not stored in the same way > as refs. > -+ For example, pseudorefs cannot be written by > linkgit:git-update-ref[1] > -+ or listed by linkgit:git-for-each-ref[1]. > ++ A name that can be used like a <> to refer to an > ++ <>, but that is not stored in the same way as > refs. > ++ For example, pseudorefs can be passed to linkgit:git-log[1] or > ++ linkgit:git-diff[1], but they cannot be written by > ++ linkgit:git-update-ref[1] or listed by > linkgit:git-for-each-ref[1]. > + > The following pseudorefs are known to Git: > - > -@@ Documentation/glossary-content.adoc: The following pseudorefs > are known to Git: > +- > +++ > ++-- > + - `FETCH_HEAD` is written by linkgit:git-fetch[1] or > linkgit:git-pull[1]. It > + may refer to multiple object IDs. Each object ID is annotated > with metadata > + indicating where it was fetched from and its fetch status. > > - `MERGE_HEAD` is written by linkgit:git-merge[1] when resolving merge > conflicts. It contains all commit IDs which are being merged. > ++-- > ++ > +When a pseudoref contains more than one object ID, using it to refer to an > +object yields the first one. > 2: 8932691331 ! 2: 62f4ae009c doc: glossary: update per-worktree refs > @@ Documentation/glossary-content.adoc: exclude;; > - that start with `refs/bisect/`, but might later include other > - unusual refs. > + A <> that is specific to a <>, > -+ rather than shared between all worktrees. All > -+ <>, such as <>, are > -+ per-worktree, as are refs that start with `refs/bisect/`, > -+ `refs/worktree/` or `refs/rewritten/`. > ++ rather than shared between all worktrees. All <>, > ++ for example <> and `ORIG_HEAD`, are per-worktree, as are > ++ refs with the following prefixes: > +++ > ++-- > ++ - `refs/bisect/` > ++ > ++ - `refs/rewritten/` > ++ > ++ - `refs/worktree/` > ++-- > ++ > +<> are also specific to each worktree. > ++ > @@ Documentation/glossary-content.adoc: exclude;; > +per-worktree refs of other worktrees. > > [[def_pseudoref]]pseudoref:: > - A name that can be used like a <> to refer to > + A name that can be used like a <> to refer to an > @@ Documentation/glossary-content.adoc: and pseudorefs. > "working tree" and repository metadata, most of which are > shared among other worktrees of a single repository, and > some of which are maintained separately per worktree > - (e.g. the index, HEAD and pseudorefs like MERGE_HEAD, > - per-worktree refs and per-worktree configuration file). > -+ (e.g. the index, per-worktree refs such as HEAD, pseudorefs > -+ such as MERGE_HEAD, and the per-worktree configuration file). > ++ (e.g. the index, <>, and the > ++ per-worktree configuration file). > 3: 8cdd299c28 ! 3: 73dcb3d715 doc: stop calling root refs pseudorefs > @@ Commit message > there, correct "symbolics" to "symbolic refs". > > In git-update-ref(1), drop the incorrect mention of ORIG_HEAD. HEAD is > - the only root ref that gets a reflog by default. Also restructure the > - sentence to make it easier to parse. > + the only root ref that gets a reflog by default. In the description of > + core.logAllRefUpdates, correct the claim that "always" only applies to > + refs under "refs/". It applies to root refs too. > > - In the description of core.logAllRefUpdates, correct the claim that > - "always" only applies to refs under "refs/". It applies to root refs > - too. > + Distinguish root refs and pseudorefs in gitdatamodel(7). Lowercase the > + "other references" list entry there to match the others. > > Signed-off-by: Andy Koppe > > @@ Documentation/git-worktree.adoc: but others are specific to an > individual worktr > -however: refs inside `refs/bisect`, `refs/worktree` and > `refs/rewritten` are > -not shared. > +In general, all root refs and pseudorefs are per-worktree and all > refs > -+starting with `refs/` are shared. There are exceptions, however: > refs > -+inside `refs/bisect`, `refs/worktree` and `refs/rewritten` are not > -+shared. > ++starting with `refs/` are shared, except for refs with the > following prefixes: > ++ > ++ - `refs/bisect/` > ++ > ++ - `refs/rewritten/` > ++ > ++ - `refs/worktree/` > > Refs that are per-worktree can still be accessed from another worktree via > two special paths, `main-worktree` and `worktrees`. The former gives > > + ## Documentation/gitdatamodel.adoc ## > +@@ Documentation/gitdatamodel.adoc: remote-tracking branches: > `refs/remotes//`:: > + default branch. This is the branch that `git clone` checks out by > default. > + > + [[other-refs]] > +-Other references:: > ++other references:: > + Git tools may create references anywhere under `refs/`. > + For example, linkgit:git-stash[1], linkgit:git-bisect[1], > + and linkgit:git-notes[1] all create their own references > + in `refs/stash`, `refs/bisect`, etc. > + Third-party Git tools may also create their own references. > +-+ > +-Git may also create references other than `HEAD` at the base of > the > +-hierarchy, like `ORIG_HEAD`. > ++ > ++[[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?