* [PATCH 0/5] root refs vs pseudorefs
@ 2026-10-22 21:28 Andy Koppe
2026-10-22 21:28 ` [PATCH 1/5] doc: glossary: add root ref and clarify pseudorefs Andy Koppe
` (6 more replies)
0 siblings, 7 replies; 13+ messages in thread
From: Andy Koppe @ 2026-10-22 21:28 UTC (permalink / raw)
To: git; +Cc: Andy Koppe, Patrick Steinhardt, Karthik Nayak, Julia Evans
Since 993d57eded (refs: pseudorefs are no refs, 2024-05-15), the term
"pseudoref" has been restricted to FETCH_HEAD and MERGE_HEAD, which are
not stored in the ref backends, while other refs outside of "refs/",
such as HEAD and ORIG_HEAD, are called root refs. However, a fair number
of docs, comments, messages and tests still use "pseudoref" in its old
sense. And while the glossary describes the rules for refs in the root
of the hierarchy, it does not explicitly define the term, even though
"git for-each-ref --include-root-refs" uses it.
This series adds a "root ref" entry to the glossary and clarifies the
"pseudoref" entry, and then replaces the outdated uses of "pseudoref" in
docs, code and tests. While at it, it also updates the long outdated
glossary entry for per-worktree refs, and fixes a few inaccuracies
found along the way, for example about which refs get a reflog in
git-update-ref(1) and core.logAllRefUpdates.
I've left __git_pseudoref_exists() in the completion script alone apart
from its comment, even though it's used for both pseudorefs and root
refs. It could be renamed, keeping the old name as a deprecated wrapper
like elsewhere in the script, but it's not obvious what to, because
there is no term covering both.
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 | 9 +-
Documentation/glossary-content.adoc | 86 ++++++++++++-------
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 +-
21 files changed, 129 insertions(+), 111 deletions(-)
rename t/t4013/{diff.diff-tree_--cc_--summary_REVERSE => diff.diff-tree_--cc_--summary_REVERSE_HEAD} (73%)
base-commit: 7e34d8174dcda3435d1404c9a30bef46afe6c13e
--
2.56.0
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH 1/5] doc: glossary: add root ref and clarify pseudorefs
2026-10-22 21:28 [PATCH 0/5] root refs vs pseudorefs Andy Koppe
@ 2026-10-22 21:28 ` Andy Koppe
2026-10-22 22:07 ` Junio C Hamano
2026-10-23 7:41 ` Patrick Steinhardt
2026-10-22 21:28 ` [PATCH 2/5] doc: glossary: update per-worktree refs Andy Koppe
` (5 subsequent siblings)
6 siblings, 2 replies; 13+ messages in thread
From: Andy Koppe @ 2026-10-22 21:28 UTC (permalink / raw)
To: git; +Cc: Andy Koppe, Patrick Steinhardt, Karthik Nayak, Julia Evans
The glossary describes refs in the root of the ref hierarchy, but does
not actually name them "root refs", even though the term is used
elsewhere, for example by "git for-each-ref --include-root-refs". It
also defines pseudorefs as refs, yet is_root_ref() deliberately excludes
them, as they are not stored or handled by the ref backends.
Add a "root ref" entry, moving the naming rules and the list of
irregular root refs there from the "ref" entry. State that pseudorefs
are not root refs, and refer to gitrevisions(7) for descriptions of
commonly used root refs and pseudorefs.
Reword the "pseudoref" entry so that it no longer calls them refs, add
git-for-each-ref(1) as another example of how they are not proper refs,
and explain that using a pseudoref containing multiple object IDs yields
the first one.
Signed-off-by: Andy Koppe <andy.koppe@gmail.com>
---
Documentation/glossary-content.adoc | 68 +++++++++++++++++------------
1 file changed, 41 insertions(+), 27 deletions(-)
diff --git a/Documentation/glossary-content.adoc b/Documentation/glossary-content.adoc
index 52301a56dd..b2c582254b 100644
--- a/Documentation/glossary-content.adoc
+++ b/Documentation/glossary-content.adoc
@@ -500,9 +500,10 @@ exclude;;
unusual refs.
[[def_pseudoref]]pseudoref::
- 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 <<def_ref,ref>> to refer to
+ <<def_object,objects>>, 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].
+
The following pseudorefs are known to Git:
@@ -512,6 +513,9 @@ The following pseudorefs are known to Git:
- `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.
[[def_pull]]pull::
Pulling a <<def_branch,branch>> means to <<def_fetch,fetch>> it and
@@ -562,33 +566,12 @@ The following pseudorefs are known to Git:
+
The ref namespace is hierarchical.
Ref names must either start with `refs/` or be located in the root of
-the hierarchy. For the latter, their name must follow these rules:
-+
---
- - The name consists of only upper-case characters or underscores.
-
- - The name ends with "`_HEAD`" or is equal to "`HEAD`".
---
-+
-There are some irregular refs in the root of the hierarchy that do not
-match these rules. The following list is exhaustive and shall not be
-extended in the future:
-+
---
- - `AUTO_MERGE`
-
- - `BISECT_EXPECTED_REV`
-
- - `NOTES_MERGE_PARTIAL`
-
- - `NOTES_MERGE_REF`
-
- - `MERGE_AUTOSTASH`
---
+the hierarchy, in which case they must follow the naming rules for
+<<def_root_ref,root refs>>.
+
Different subhierarchies are used for different purposes. For example,
the `refs/heads/` hierarchy is used to represent local branches whereas
-the `refs/tags/` hierarchy is used to represent local tags..
+the `refs/tags/` hierarchy is used to represent local tags.
+
See also "REFERENCES" in linkgit:gitdatamodel[7].
@@ -640,6 +623,37 @@ format. See linkgit:git-reflog[1] for details.
To throw away part of the development, i.e. to assign the
<<def_head,head>> to an earlier <<def_revision,revision>>.
+[[def_root_ref]]root ref::
+ A <<def_ref,ref>> located in the root of the ref hierarchy, outside
+ `refs/`. Root ref names must follow these rules:
++
+--
+ - The name consists of only upper-case characters or underscores.
+
+ - The name ends with "`_HEAD`" or is equal to "`HEAD`".
+--
++
+The following irregular root refs are exceptions to these rules. This
+list is exhaustive and shall not be extended in future:
++
+--
+ - `AUTO_MERGE`
+
+ - `BISECT_EXPECTED_REV`
+
+ - `NOTES_MERGE_PARTIAL`
+
+ - `NOTES_MERGE_REF`
+
+ - `MERGE_AUTOSTASH`
+--
++
+<<def_pseudoref,Pseudorefs>> are not considered root refs, even though
+they follow the naming rules.
++
+See linkgit:gitrevisions[7] for descriptions of commonly used root refs
+and pseudorefs.
+
[[def_SCM]]SCM::
Source code management (tool).
--
2.56.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 2/5] doc: glossary: update per-worktree refs
2026-10-22 21:28 [PATCH 0/5] root refs vs pseudorefs Andy Koppe
2026-10-22 21:28 ` [PATCH 1/5] doc: glossary: add root ref and clarify pseudorefs Andy Koppe
@ 2026-10-22 21:28 ` Andy Koppe
2026-10-23 7:41 ` Patrick Steinhardt
2026-10-22 21:28 ` [PATCH 3/5] doc: stop calling root refs pseudorefs Andy Koppe
` (4 subsequent siblings)
6 siblings, 1 reply; 13+ messages in thread
From: Andy Koppe @ 2026-10-22 21:28 UTC (permalink / raw)
To: git; +Cc: Andy Koppe, Patrick Steinhardt, Karthik Nayak, Julia Evans
The "per-worktree ref" entry says that these are only HEAD and refs
under "refs/bisect/", but that has been out of date since a9be29c981
(sequencer: make refs generated by the `label` command worktree-local,
2018-04-25). All root refs are per-worktree, as are refs under
"refs/worktree/" and "refs/rewritten/". Pseudorefs are specific to each
worktree too.
Bring the list up to date, and refer to git-worktree(1) for how to
access per-worktree refs of other worktrees. In the "worktree" entry,
describe HEAD as a per-worktree ref and MERGE_HEAD as a pseudoref,
rather than listing them separately from per-worktree refs.
Signed-off-by: Andy Koppe <andy.koppe@gmail.com>
---
Documentation/glossary-content.adoc | 18 ++++++++++++------
1 file changed, 12 insertions(+), 6 deletions(-)
diff --git a/Documentation/glossary-content.adoc b/Documentation/glossary-content.adoc
index b2c582254b..eff6d23215 100644
--- a/Documentation/glossary-content.adoc
+++ b/Documentation/glossary-content.adoc
@@ -494,10 +494,16 @@ exclude;;
interface than the <<def_plumbing,plumbing>>.
[[def_per_worktree_ref]]per-worktree ref::
- Refs that are per-<<def_worktree,worktree>>, rather than
- global. This is presently only <<def_HEAD,HEAD>> and any refs
- that start with `refs/bisect/`, but might later include other
- unusual refs.
+ A <<def_ref,ref>> that is specific to a <<def_worktree,worktree>>,
+ rather than shared between all worktrees. All
+ <<def_root_ref,root refs>>, such as <<def_HEAD,HEAD>>, are
+ per-worktree, as are refs that start with `refs/bisect/`,
+ `refs/worktree/` or `refs/rewritten/`.
++
+<<def_pseudoref,Pseudorefs>> are also specific to each worktree.
++
+See "REFS" in linkgit:git-worktree[1] for how to access the
+per-worktree refs of other worktrees.
[[def_pseudoref]]pseudoref::
A name that can be used like a <<def_ref,ref>> to refer to
@@ -788,5 +794,5 @@ 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).
--
2.56.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 3/5] doc: stop calling root refs pseudorefs
2026-10-22 21:28 [PATCH 0/5] root refs vs pseudorefs Andy Koppe
2026-10-22 21:28 ` [PATCH 1/5] doc: glossary: add root ref and clarify pseudorefs Andy Koppe
2026-10-22 21:28 ` [PATCH 2/5] doc: glossary: update per-worktree refs Andy Koppe
@ 2026-10-22 21:28 ` Andy Koppe
2026-10-23 7:41 ` Patrick Steinhardt
2026-10-22 21:28 ` [PATCH 4/5] refs: " Andy Koppe
` (3 subsequent siblings)
6 siblings, 1 reply; 13+ messages in thread
From: Andy Koppe @ 2026-10-22 21:28 UTC (permalink / raw)
To: git; +Cc: Andy Koppe, Patrick Steinhardt, Karthik Nayak, Julia Evans
Several manual pages still use "pseudoref" in its old sense of any ref
outside of "refs/", which the glossary now calls a root ref. Pseudorefs
have since been restricted to FETCH_HEAD and MERGE_HEAD, which are not
considered root refs.
Replace "pseudoref" with "root ref" in those pages, giving HEAD and
ORIG_HEAD as examples. In git-worktree(1), say that both root refs and
pseudorefs are per-worktree, and drop the description of them as being
directly under $GIT_DIR, because that does not apply to the reftable
backend.
In git-ls-remote(1), describe --refs as omitting refs outside "refs/",
since that is what it actually checks. In the example, refer to HEAD,
which is the only root ref that git-upload-pack(1) advertises. While
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.
In the description of core.logAllRefUpdates, correct the claim that
"always" only applies to refs under "refs/". It applies to root refs
too.
Signed-off-by: Andy Koppe <andy.koppe@gmail.com>
---
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 | 9 ++++-----
Documentation/rev-list-options.adoc | 4 ++--
6 files changed, 16 insertions(+), 18 deletions(-)
diff --git a/Documentation/config/core.adoc b/Documentation/config/core.adoc
index bdc74d291c..8f8fe36a58 100644
--- a/Documentation/config/core.adoc
+++ b/Documentation/config/core.adoc
@@ -376,7 +376,7 @@ core.logAllRefUpdates::
`refs/heads/`), remote refs (i.e. under `refs/remotes/`),
note refs (i.e. under `refs/notes/`), and the symbolic ref `HEAD`.
If it is set to `always`, then a missing reflog is automatically
- created for any ref under `refs/`.
+ created for any ref, including root refs such as `ORIG_HEAD`.
+
This information can be used to determine what commit
was the tip of a branch "2 days ago".
diff --git a/Documentation/for-each-ref-options.adoc b/Documentation/for-each-ref-options.adoc
index 54e2fa95c2..2b6d4ede0b 100644
--- a/Documentation/for-each-ref-options.adoc
+++ b/Documentation/for-each-ref-options.adoc
@@ -73,7 +73,7 @@ TAB %(refname)`.
using the same rules as _<pattern>_ above.
`--include-root-refs`::
- List root refs (`HEAD` and pseudorefs) apart from regular refs.
+ Also list root refs, such as `HEAD` or `ORIG_HEAD`.
`--start-after=<marker>`::
Allows paginating the output by skipping references up to and including the
diff --git a/Documentation/git-ls-remote.adoc b/Documentation/git-ls-remote.adoc
index d71c4ab3e2..7ce7df3149 100644
--- a/Documentation/git-ls-remote.adoc
+++ b/Documentation/git-ls-remote.adoc
@@ -35,7 +35,7 @@ OPTIONS
with other git subcommands.
--refs::
- Do not show peeled tags or pseudorefs like `HEAD` in the output.
+ Do not show peeled tags or refs outside `refs/`.
-q::
--quiet::
@@ -118,7 +118,7 @@ line shows the name of the object the tag points at.
EXAMPLES
--------
-* List all references (including symbolics and pseudorefs), peeling
+* List all references (including `HEAD` and symbolic refs), peeling
tags:
+
----
diff --git a/Documentation/git-update-ref.adoc b/Documentation/git-update-ref.adoc
index 37a5019a8b..c775334230 100644
--- a/Documentation/git-update-ref.adoc
+++ b/Documentation/git-update-ref.adoc
@@ -163,13 +163,12 @@ still see a subset of the modifications.
LOGGING UPDATES
---------------
-If config parameter "core.logAllRefUpdates" is true and the ref is one
-under "refs/heads/", "refs/remotes/", "refs/notes/", or a pseudoref
-like HEAD or ORIG_HEAD; or the file "$GIT_DIR/logs/<ref>" exists then
-`git update-ref` will append a line to the log file
-"$GIT_DIR/logs/<ref>" (dereferencing all symbolic refs before creating
-the log name) describing the change in ref value. Log lines are
-formatted as:
+If config parameter "core.logAllRefUpdates" is true and the ref is
+HEAD or one under "refs/heads/", "refs/remotes/" or "refs/notes/", or
+if the file "$GIT_DIR/logs/<ref>" exists, then `git update-ref` will
+append a line to the log file "$GIT_DIR/logs/<ref>" (dereferencing all
+symbolic refs before creating the log name) describing the change in
+ref value. Log lines are formatted as:
oldsha1 SP newsha1 SP committer LF
diff --git a/Documentation/git-worktree.adoc b/Documentation/git-worktree.adoc
index e6e77252ab..f0eb6d4137 100644
--- a/Documentation/git-worktree.adoc
+++ b/Documentation/git-worktree.adoc
@@ -303,11 +303,10 @@ but others are specific to an individual worktree. One example is `HEAD`,
which is different for each worktree. This section is about the sharing
rules and how to access refs of one worktree from another.
-In general, all pseudo refs are per-worktree and all refs starting with
-`refs/` are shared. Pseudo refs are ones like `HEAD` which are directly
-under `$GIT_DIR` instead of inside `$GIT_DIR/refs`. There are exceptions,
-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.
Refs that are per-worktree can still be accessed from another worktree via
two special paths, `main-worktree` and `worktrees`. The former gives
diff --git a/Documentation/rev-list-options.adoc b/Documentation/rev-list-options.adoc
index bd9f345690..822604278a 100644
--- a/Documentation/rev-list-options.adoc
+++ b/Documentation/rev-list-options.adoc
@@ -350,8 +350,8 @@ Under `--pretty=reference`, this information will not be shown at all.
`--merge`::
Show commits touching conflicted paths in the range `HEAD...<other>`,
- where `<other>` is the first existing pseudoref in `MERGE_HEAD`,
- `CHERRY_PICK_HEAD`, `REVERT_HEAD` or `REBASE_HEAD`. Only works
+ where `<other>` is the first of `MERGE_HEAD`, `CHERRY_PICK_HEAD`,
+ `REVERT_HEAD` or `REBASE_HEAD` that exists. Only works
when the index has unmerged entries. This option can be used to show
relevant commits when resolving conflicts from a 3-way merge.
--
2.56.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 4/5] refs: stop calling root refs pseudorefs
2026-10-22 21:28 [PATCH 0/5] root refs vs pseudorefs Andy Koppe
` (2 preceding siblings ...)
2026-10-22 21:28 ` [PATCH 3/5] doc: stop calling root refs pseudorefs Andy Koppe
@ 2026-10-22 21:28 ` Andy Koppe
2026-10-23 7:41 ` Patrick Steinhardt
2026-10-22 21:28 ` [PATCH 5/5] t: " Andy Koppe
` (2 subsequent siblings)
6 siblings, 1 reply; 13+ messages in thread
From: Andy Koppe @ 2026-10-22 21:28 UTC (permalink / raw)
To: git; +Cc: Andy Koppe, Patrick Steinhardt, Karthik Nayak, Julia Evans
Some messages and comments in the code still use "pseudoref" in its old
sense of any ref outside of "refs/", whereas the glossary now calls
those root refs and restricts pseudorefs to FETCH_HEAD and MERGE_HEAD.
Replace "pseudoref" with "root ref" in the help text for
"git for-each-ref --include-root-refs", in comments in refs.h, and in
comments in the bash completion script, including the one for
__git_pseudoref_exists(), which is also used for root refs. The function
itself is not renamed. There is no obvious term covering both root refs
and pseudorefs, and the old name might need to be kept for third-party
completion scripts.
Update the description of pseudorefs in refs.h to match the glossary.
Signed-off-by: Andy Koppe <andy.koppe@gmail.com>
---
builtin/for-each-ref.c | 2 +-
contrib/completion/git-completion.bash | 7 ++++---
refs.h | 13 ++++++-------
revision.c | 2 +-
4 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c
index 4a2fc421db..6ff32e919c 100644
--- a/builtin/for-each-ref.c
+++ b/builtin/for-each-ref.c
@@ -48,7 +48,7 @@ int for_each_ref_core(int argc, const char **argv, const char *prefix, struct re
OPT_NO_CONTAINS(&filter.no_commit, N_("print only refs which don't contain the commit")),
OPT_BOOL(0, "ignore-case", &icase, N_("sorting and filtering are case insensitive")),
OPT_BOOL(0, "stdin", &from_stdin, N_("read reference patterns from stdin")),
- OPT_BOOL(0, "include-root-refs", &include_root_refs, N_("also include HEAD ref and pseudorefs")),
+ OPT_BOOL(0, "include-root-refs", &include_root_refs, N_("also include root refs")),
OPT_END(),
};
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index c3a49e2e22..e12ac0359c 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -147,8 +147,9 @@ __git_eread ()
test -r "$1" && IFS=$'\r\n' read -r "$2" <"$1"
}
-# Runs git in $__git_repo_path to determine whether a pseudoref exists.
-# 1: The pseudo-ref to search
+# Runs git in $__git_repo_path to determine whether a root ref or
+# pseudoref exists.
+# 1: The ref to check
__git_pseudoref_exists ()
{
local ref=$1
@@ -954,7 +955,7 @@ __git_refs ()
esac
}
-# Completes refs, short and long, local and remote, symbolic and pseudo.
+# Completes refs, short and long, local and remote, symbolic, root and pseudo.
#
# Usage: __git_complete_refs [<option>]...
# --remote=<remote>: The remote to list refs from, can be the name of a
diff --git a/refs.h b/refs.h
index ee3b8a62ef..3be7ef3b0e 100644
--- a/refs.h
+++ b/refs.h
@@ -85,7 +85,7 @@ enum ref_transaction_error {
* Even with RESOLVE_REF_ALLOW_BAD_NAME, names that escape the refs/
* directory and do not consist of all caps and underscores cannot be
* resolved. The function returns NULL for such ref names.
- * Caps and underscores refers to the pseudorefs, such as HEAD,
+ * Caps and underscores refers to root refs and pseudorefs, such as HEAD,
* FETCH_HEAD and friends, that all live outside of the refs/ directory.
*/
#define RESOLVE_REF_READING 0x01
@@ -448,8 +448,8 @@ enum refs_for_each_flag {
REFS_FOR_EACH_OMIT_DANGLING_SYMREFS = (1 << 2),
/*
- * Include root refs i.e. HEAD and pseudorefs along with the regular
- * refs.
+ * Include root refs, such as HEAD and ORIG_HEAD, along with the
+ * regular refs.
*/
REFS_FOR_EACH_INCLUDE_ROOT_REFS = (1 << 3),
};
@@ -1306,10 +1306,9 @@ void update_ref_namespace(enum ref_namespace namespace, char *ref);
int is_root_ref(const char *refname);
/*
- * Pseudorefs are refs that have different semantics compared to
- * "normal" refs. These refs can thus not be stored in the ref backend,
- * but must always be accessed via the filesystem. The following refs
- * are pseudorefs:
+ * Pseudorefs are names that can be used like refs, but have different
+ * semantics. They cannot be stored in the ref backend, but must always
+ * be accessed via the filesystem. The following are pseudorefs:
*
* - FETCH_HEAD may contain multiple object IDs, and each one of them
* carries additional metadata like where it came from.
diff --git a/revision.c b/revision.c
index a83e499047..d6dd56faf1 100644
--- a/revision.c
+++ b/revision.c
@@ -2000,7 +2000,7 @@ static const char *lookup_other_head(struct object_id *oid)
return other_head[i];
}
- die(_("--merge requires one of the pseudorefs MERGE_HEAD, CHERRY_PICK_HEAD, REVERT_HEAD or REBASE_HEAD"));
+ die(_("--merge requires one of MERGE_HEAD, CHERRY_PICK_HEAD, REVERT_HEAD or REBASE_HEAD"));
}
static void prepare_show_merge(struct rev_info *revs)
--
2.56.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 5/5] t: stop calling root refs pseudorefs
2026-10-22 21:28 [PATCH 0/5] root refs vs pseudorefs Andy Koppe
` (3 preceding siblings ...)
2026-10-22 21:28 ` [PATCH 4/5] refs: " Andy Koppe
@ 2026-10-22 21:28 ` Andy Koppe
2026-10-22 22:18 ` [PATCH 0/5] root refs vs pseudorefs Junio C Hamano
2026-10-23 13:21 ` Julia Evans
6 siblings, 0 replies; 13+ messages in thread
From: Andy Koppe @ 2026-10-22 21:28 UTC (permalink / raw)
To: git; +Cc: Andy Koppe, Patrick Steinhardt, Karthik Nayak, Julia Evans
Several test titles and comments still use "pseudoref" in its old sense
of any ref outside of "refs/", which the glossary now calls root refs.
Replace "pseudoref" with "root ref" there. In t1400 and t4013, rename
the root refs that the tests create from PSEUDOREF to ROOT_REF_HEAD and
from REVERSE to REVERSE_HEAD, so that they follow the naming rules for
root refs. This includes renaming the expected output file in t4013.
Some tests also still refer to FETCH_HEAD and MERGE_HEAD as "special
refs", which was the previous term for "pseudorefs". Correct them.
Signed-off-by: Andy Koppe <andy.koppe@gmail.com>
---
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 +-
10 files changed, 48 insertions(+), 48 deletions(-)
rename t/t4013/{diff.diff-tree_--cc_--summary_REVERSE => diff.diff-tree_--cc_--summary_REVERSE_HEAD} (73%)
diff --git a/t/show-ref-exists-tests.sh b/t/show-ref-exists-tests.sh
index 1351f690eb..d4a021a0c6 100644
--- a/t/show-ref-exists-tests.sh
+++ b/t/show-ref-exists-tests.sh
@@ -64,11 +64,11 @@ test_expect_success '--exists with directory fails with generic error' '
test_cmp expect err
'
-test_expect_success '--exists with non-existent special ref' '
+test_expect_success '--exists with non-existent pseudoref' '
test_expect_code 2 ${git_show_ref_exists} FETCH_HEAD
'
-test_expect_success '--exists with existing special ref' '
+test_expect_success '--exists with existing pseudoref' '
test_when_finished "rm .git/FETCH_HEAD" &&
git rev-parse HEAD >.git/FETCH_HEAD &&
${git_show_ref_exists} FETCH_HEAD
diff --git a/t/t0600-reffiles-backend.sh b/t/t0600-reffiles-backend.sh
index 62b0851852..26385aab7d 100755
--- a/t/t0600-reffiles-backend.sh
+++ b/t/t0600-reffiles-backend.sh
@@ -267,7 +267,7 @@ test_expect_success 'setup worktree' '
)
'
-# Some refs (refs/bisect/*, pseudorefs) are kept per worktree, so they should
+# Some refs (refs/bisect/*, root refs) are kept per worktree, so they should
# only appear in the for-each-reflog output if it is called from the correct
# worktree, which is exercised in this test. This test is poorly written for
# multiple reasons: 1) it creates invalidly formatted log entries. 2) it uses
diff --git a/t/t0610-reftable-basics.sh b/t/t0610-reftable-basics.sh
index a702745839..01a0310762 100755
--- a/t/t0610-reftable-basics.sh
+++ b/t/t0610-reftable-basics.sh
@@ -1156,7 +1156,7 @@ test_expect_success 'worktree: adds worktree with detached HEAD' '
test_cmp expect actual
'
-test_expect_success 'fetch: accessing FETCH_HEAD special ref works' '
+test_expect_success 'fetch: accessing FETCH_HEAD pseudoref works' '
test_when_finished "rm -rf repo sub" &&
git init sub &&
diff --git a/t/t1400-update-ref.sh b/t/t1400-update-ref.sh
index 1a164c96f9..95a617254b 100755
--- a/t/t1400-update-ref.sh
+++ b/t/t1400-update-ref.sh
@@ -503,61 +503,61 @@ test_expect_success 'git cat-file blob main@{2005-05-26 23:42}:F (expect OTHER)'
test OTHER = $(git cat-file blob "main@{2005-05-26 23:42}:F")
'
-# Test adding and deleting pseudorefs
+# Test adding and deleting root refs
-test_expect_success 'given old value for missing pseudoref, do not create' '
- test_must_fail git update-ref PSEUDOREF $A $B 2>err &&
- test_must_fail git rev-parse PSEUDOREF &&
+test_expect_success 'given old value for missing root ref, do not create' '
+ test_must_fail git update-ref ROOT_REF_HEAD $A $B 2>err &&
+ test_must_fail git rev-parse ROOT_REF_HEAD &&
test_grep "unable to resolve reference" err
'
-test_expect_success 'create pseudoref' '
- git update-ref PSEUDOREF $A &&
- test $A = $(git show-ref -s --verify PSEUDOREF)
+test_expect_success 'create root ref' '
+ git update-ref ROOT_REF_HEAD $A &&
+ test $A = $(git show-ref -s --verify ROOT_REF_HEAD)
'
-test_expect_success 'overwrite pseudoref with no old value given' '
- git update-ref PSEUDOREF $B &&
- test $B = $(git show-ref -s --verify PSEUDOREF)
+test_expect_success 'overwrite root ref with no old value given' '
+ git update-ref ROOT_REF_HEAD $B &&
+ test $B = $(git show-ref -s --verify ROOT_REF_HEAD)
'
-test_expect_success 'overwrite pseudoref with correct old value' '
- git update-ref PSEUDOREF $C $B &&
- test $C = $(git show-ref -s --verify PSEUDOREF)
+test_expect_success 'overwrite root ref with correct old value' '
+ git update-ref ROOT_REF_HEAD $C $B &&
+ test $C = $(git show-ref -s --verify ROOT_REF_HEAD)
'
-test_expect_success 'do not overwrite pseudoref with wrong old value' '
- test_must_fail git update-ref PSEUDOREF $D $E 2>err &&
- test $C = $(git show-ref -s --verify PSEUDOREF) &&
+test_expect_success 'do not overwrite root ref with wrong old value' '
+ test_must_fail git update-ref ROOT_REF_HEAD $D $E 2>err &&
+ test $C = $(git show-ref -s --verify ROOT_REF_HEAD) &&
test_grep "cannot lock ref.*expected" err
'
-test_expect_success 'delete pseudoref' '
- git update-ref -d PSEUDOREF &&
- test_must_fail git show-ref -s --verify PSEUDOREF
+test_expect_success 'delete root ref' '
+ git update-ref -d ROOT_REF_HEAD &&
+ test_must_fail git show-ref -s --verify ROOT_REF_HEAD
'
-test_expect_success 'do not delete pseudoref with wrong old value' '
- git update-ref PSEUDOREF $A &&
- test_must_fail git update-ref -d PSEUDOREF $B 2>err &&
- test $A = $(git show-ref -s --verify PSEUDOREF) &&
+test_expect_success 'do not delete root ref with wrong old value' '
+ git update-ref ROOT_REF_HEAD $A &&
+ test_must_fail git update-ref -d ROOT_REF_HEAD $B 2>err &&
+ test $A = $(git show-ref -s --verify ROOT_REF_HEAD) &&
test_grep "cannot lock ref.*expected" err
'
-test_expect_success 'delete pseudoref with correct old value' '
- git update-ref -d PSEUDOREF $A &&
- test_must_fail git show-ref -s --verify PSEUDOREF
+test_expect_success 'delete root ref with correct old value' '
+ git update-ref -d ROOT_REF_HEAD $A &&
+ test_must_fail git show-ref -s --verify ROOT_REF_HEAD
'
-test_expect_success 'create pseudoref with old OID zero' '
- git update-ref PSEUDOREF $A $Z &&
- test $A = $(git show-ref -s --verify PSEUDOREF)
+test_expect_success 'create root ref with old OID zero' '
+ git update-ref ROOT_REF_HEAD $A $Z &&
+ test $A = $(git show-ref -s --verify ROOT_REF_HEAD)
'
-test_expect_success 'do not overwrite pseudoref with old OID zero' '
- test_when_finished git update-ref -d PSEUDOREF &&
- test_must_fail git update-ref PSEUDOREF $B $Z 2>err &&
- test $A = $(git show-ref -s --verify PSEUDOREF) &&
+test_expect_success 'do not overwrite root ref with old OID zero' '
+ test_when_finished git update-ref -d ROOT_REF_HEAD &&
+ test_must_fail git update-ref ROOT_REF_HEAD $B $Z 2>err &&
+ test $A = $(git show-ref -s --verify ROOT_REF_HEAD) &&
test_grep "already exists" err
'
diff --git a/t/t1403-show-ref.sh b/t/t1403-show-ref.sh
index 226b3ec0e8..38648fd560 100755
--- a/t/t1403-show-ref.sh
+++ b/t/t1403-show-ref.sh
@@ -181,7 +181,7 @@ test_expect_success 'show-ref --verify HEAD' '
test_must_be_empty actual
'
-test_expect_success 'show-ref --verify pseudorefs' '
+test_expect_success 'show-ref --verify root refs' '
git update-ref CHERRY_PICK_HEAD HEAD $ZERO_OID &&
test_when_finished "git update-ref -d CHERRY_PICK_HEAD" &&
git show-ref -s --verify HEAD >actual &&
diff --git a/t/t1460-refs-migrate.sh b/t/t1460-refs-migrate.sh
index ecf6411288..1f59d820a0 100755
--- a/t/t1460-refs-migrate.sh
+++ b/t/t1460-refs-migrate.sh
@@ -170,7 +170,7 @@ do
test_cmp expect actual
'
- test_expect_success "$from_format -> $to_format: pseudo-refs" '
+ test_expect_success "$from_format -> $to_format: root refs" '
test_when_finished "rm -rf repo" &&
git init --ref-storage-format=$from_format repo &&
test_commit -C repo initial &&
@@ -178,7 +178,7 @@ do
test_migration repo "$to_format"
'
- test_expect_success "$from_format -> $to_format: special refs are left alone" '
+ test_expect_success "$from_format -> $to_format: pseudorefs are left alone" '
test_when_finished "rm -rf repo" &&
git init --ref-storage-format=$from_format repo &&
test_commit -C repo initial &&
diff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh
index 21c9ad7c5d..43a9bf6d7c 100755
--- a/t/t4013-diff-various.sh
+++ b/t/t4013-diff-various.sh
@@ -115,10 +115,10 @@ test_expect_success setup '
git checkout -f main &&
# Same merge as main, but with parents reversed. Hide it in a
- # pseudo-ref to avoid impacting tests with --all.
+ # root ref to avoid impacting tests with --all.
commit=$(echo reverse |
git commit-tree -p main^2 -p main^1 main^{tree}) &&
- git update-ref REVERSE $commit &&
+ git update-ref REVERSE_HEAD $commit &&
git config diff.renames false &&
@@ -328,7 +328,7 @@ diff-tree --cc --stat --summary main
diff-tree -c --stat --summary side
diff-tree --cc --stat --summary side
diff-tree --cc --shortstat main
-diff-tree --cc --summary REVERSE
+diff-tree --cc --summary REVERSE_HEAD
# improved by Timo's patch
diff-tree --cc --patch-with-stat main
# improved by Timo's patch
diff --git a/t/t4013/diff.diff-tree_--cc_--summary_REVERSE b/t/t4013/diff.diff-tree_--cc_--summary_REVERSE_HEAD
similarity index 73%
rename from t/t4013/diff.diff-tree_--cc_--summary_REVERSE
rename to t/t4013/diff.diff-tree_--cc_--summary_REVERSE_HEAD
index e208dd5682..0f86ae60db 100644
--- a/t/t4013/diff.diff-tree_--cc_--summary_REVERSE
+++ b/t/t4013/diff.diff-tree_--cc_--summary_REVERSE_HEAD
@@ -1,4 +1,4 @@
-$ git diff-tree --cc --summary REVERSE
+$ git diff-tree --cc --summary REVERSE_HEAD
2562325a7ee916efb2481da93073b82cec801cbc
create mode 100644 file1
delete mode 100644 file2
diff --git a/t/t6302-for-each-ref-filter.sh b/t/t6302-for-each-ref-filter.sh
index 7f060d97bf..14f6d7e597 100755
--- a/t/t6302-for-each-ref-filter.sh
+++ b/t/t6302-for-each-ref-filter.sh
@@ -31,7 +31,7 @@ test_expect_success 'setup some history and refs' '
git update-ref refs/odd/spot main
'
-test_expect_success '--include-root-refs pattern prints pseudorefs' '
+test_expect_success '--include-root-refs pattern prints root refs' '
cat >expect <<-\EOF &&
HEAD
ORIG_HEAD
@@ -52,7 +52,7 @@ test_expect_success '--include-root-refs pattern prints pseudorefs' '
test_cmp expect actual
'
-test_expect_success '--include-root-refs pattern does not print special refs' '
+test_expect_success '--include-root-refs pattern does not print pseudorefs' '
test_when_finished "rm -rf repo" &&
git init repo &&
(
diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh
index f6de74054a..1cb55f9301 100755
--- a/t/t9902-completion.sh
+++ b/t/t9902-completion.sh
@@ -2693,13 +2693,13 @@ test_expect_success 'checkout matches case insensitively with GIT_COMPLETION_IGN
)
'
-test_expect_success 'checkout completes pseudo refs' '
+test_expect_success 'checkout completes root refs' '
test_completion "git checkout H" <<-\EOF
HEAD Z
EOF
'
-test_expect_success 'checkout completes pseudo refs case insensitively with GIT_COMPLETION_IGNORE_CASE' '
+test_expect_success 'checkout completes root refs case insensitively with GIT_COMPLETION_IGNORE_CASE' '
(
GIT_COMPLETION_IGNORE_CASE=1 &&
test_completion "git checkout h" <<-\EOF
--
2.56.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH 1/5] doc: glossary: add root ref and clarify pseudorefs
2026-10-22 21:28 ` [PATCH 1/5] doc: glossary: add root ref and clarify pseudorefs Andy Koppe
@ 2026-10-22 22:07 ` Junio C Hamano
2026-10-23 7:41 ` Patrick Steinhardt
1 sibling, 0 replies; 13+ messages in thread
From: Junio C Hamano @ 2026-10-22 22:07 UTC (permalink / raw)
To: Andy Koppe; +Cc: git, Patrick Steinhardt, Karthik Nayak, Julia Evans
Andy Koppe <andy.koppe@gmail.com> writes:
> The glossary describes refs in the root of the ref hierarchy, but does
> not actually name them "root refs", even though the term is used
> elsewhere, for example by "git for-each-ref --include-root-refs". It
> also defines pseudorefs as refs, yet is_root_ref() deliberately excludes
> them, as they are not stored or handled by the ref backends.
>
> Add a "root ref" entry, moving the naming rules and the list of
> irregular root refs there from the "ref" entry. State that pseudorefs
> are not root refs, and refer to gitrevisions(7) for descriptions of
> commonly used root refs and pseudorefs.
>
> Reword the "pseudoref" entry so that it no longer calls them refs, add
> git-for-each-ref(1) as another example of how they are not proper refs,
> and explain that using a pseudoref containing multiple object IDs yields
> the first one.
>
> Signed-off-by: Andy Koppe <andy.koppe@gmail.com>
> ---
> Documentation/glossary-content.adoc | 68 +++++++++++++++++------------
> 1 file changed, 41 insertions(+), 27 deletions(-)
>
> diff --git a/Documentation/glossary-content.adoc b/Documentation/glossary-content.adoc
> index 52301a56dd..b2c582254b 100644
> --- a/Documentation/glossary-content.adoc
> +++ b/Documentation/glossary-content.adoc
> @@ -500,9 +500,10 @@ exclude;;
> unusual refs.
>
> [[def_pseudoref]]pseudoref::
> - 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 <<def_ref,ref>> to refer to
> + <<def_object,objects>>, 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].
I would love to get input from Patrick who wrote 993d57eded (refs:
pseudorefs are no refs, 2024-05-15), as I consider that the loss of
"different semantics" from this description is a rather serious one.
FETCH_HEAD and MERGE_HEAD cannot be written with update-ref simply
because it is normal for them to record multiple object names, so it
is not just "how" they are stored, but also "what" they can store,
that makes them "strange", "pseudo", "different", and "special".
> The following pseudorefs are known to Git:
>
> @@ -512,6 +513,9 @@ The following pseudorefs are known to Git:
>
> - `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.
This is an important addition.
> @@ -562,33 +566,12 @@ The following pseudorefs are known to Git:
> +
> The ref namespace is hierarchical.
> Ref names must either start with `refs/` or be located in the root of
> +the hierarchy, in which case they must follow the naming rules for
> +<<def_root_ref,root refs>>.
> +
> Different subhierarchies are used for different purposes. For example,
> the `refs/heads/` hierarchy is used to represent local branches whereas
> -the `refs/tags/` hierarchy is used to represent local tags..
> +the `refs/tags/` hierarchy is used to represent local tags.
> +
> See also "REFERENCES" in linkgit:gitdatamodel[7].
>
> @@ -640,6 +623,37 @@ format. See linkgit:git-reflog[1] for details.
> To throw away part of the development, i.e. to assign the
> <<def_head,head>> to an earlier <<def_revision,revision>>.
>
> +[[def_root_ref]]root ref::
> + A <<def_ref,ref>> located in the root of the ref hierarchy, outside
> + `refs/`. Root ref names must follow these rules:
> ++
> +--
> + - The name consists of only upper-case characters or underscores.
> +
> + - The name ends with "`_HEAD`" or is equal to "`HEAD`".
> +--
> ++
> +The following irregular root refs are exceptions to these rules. This
> +list is exhaustive and shall not be extended in future:
> ++
> +--
> + - `AUTO_MERGE`
> +
> + - `BISECT_EXPECTED_REV`
> +
> + - `NOTES_MERGE_PARTIAL`
> +
> + - `NOTES_MERGE_REF`
> +
> + - `MERGE_AUTOSTASH`
> +--
> ++
> +<<def_pseudoref,Pseudorefs>> are not considered root refs, even though
> +they follow the naming rules.
> ++
> +See linkgit:gitrevisions[7] for descriptions of commonly used root refs
> +and pseudorefs.
I think this is a great reorganization to split out the "these are
exceptions" into its own section.
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 0/5] root refs vs pseudorefs
2026-10-22 21:28 [PATCH 0/5] root refs vs pseudorefs Andy Koppe
` (4 preceding siblings ...)
2026-10-22 21:28 ` [PATCH 5/5] t: " Andy Koppe
@ 2026-10-22 22:18 ` Junio C Hamano
2026-10-23 13:21 ` Julia Evans
6 siblings, 0 replies; 13+ messages in thread
From: Junio C Hamano @ 2026-10-22 22:18 UTC (permalink / raw)
To: Andy Koppe; +Cc: git, Patrick Steinhardt, Karthik Nayak, Julia Evans
Andy Koppe <andy.koppe@gmail.com> writes:
> Since 993d57eded (refs: pseudorefs are no refs, 2024-05-15), the term
> "pseudoref" has been restricted to FETCH_HEAD and MERGE_HEAD, which are
> not stored in the ref backends, while other refs outside of "refs/",
> such as HEAD and ORIG_HEAD, are called root refs. However, a fair number
> of docs, comments, messages and tests still use "pseudoref" in its old
> sense. And while the glossary describes the rules for refs in the root
> of the hierarchy, it does not explicitly define the term, even though
> "git for-each-ref --include-root-refs" uses it.
Thanks. Overall this was a pleasant read.
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 1/5] doc: glossary: add root ref and clarify pseudorefs
2026-10-22 21:28 ` [PATCH 1/5] doc: glossary: add root ref and clarify pseudorefs Andy Koppe
2026-10-22 22:07 ` Junio C Hamano
@ 2026-10-23 7:41 ` Patrick Steinhardt
1 sibling, 0 replies; 13+ messages in thread
From: Patrick Steinhardt @ 2026-10-23 7:41 UTC (permalink / raw)
To: Andy Koppe; +Cc: git, Karthik Nayak, Julia Evans
On Thu, Oct 22, 2026 at 10:28:49PM +0100, Andy Koppe wrote:
> diff --git a/Documentation/glossary-content.adoc b/Documentation/glossary-content.adoc
> index 52301a56dd..b2c582254b 100644
> --- a/Documentation/glossary-content.adoc
> +++ b/Documentation/glossary-content.adoc
> @@ -500,9 +500,10 @@ exclude;;
> unusual refs.
>
> [[def_pseudoref]]pseudoref::
> - 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 <<def_ref,ref>> to refer to
> + <<def_object,objects>>, 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].
As Junio already mentioned, I think we should retain the information
about different semantics.
I also think that the previous guidance around how pseudorefs can be
used is weakened, because now you only list examples of how they cannot
be used. Previously though we explicitly specified that the only
supported operation is reading the refs directly. So instead of giving
examples of how they cannot be used, I think we should continue to list
the few operations that _are_ possible.
> @@ -512,6 +513,9 @@ The following pseudorefs are known to Git:
>
> - `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.
This is indeed a good addition.
> @@ -640,6 +623,37 @@ format. See linkgit:git-reflog[1] for details.
> To throw away part of the development, i.e. to assign the
> <<def_head,head>> to an earlier <<def_revision,revision>>.
>
> +[[def_root_ref]]root ref::
And splitting this out makes sense, as well.
> + A <<def_ref,ref>> located in the root of the ref hierarchy, outside
> + `refs/`. Root ref names must follow these rules:
> ++
> +--
> + - The name consists of only upper-case characters or underscores.
> +
> + - The name ends with "`_HEAD`" or is equal to "`HEAD`".
> +--
> ++
> +The following irregular root refs are exceptions to these rules. This
> +list is exhaustive and shall not be extended in future:
Okay, this paragraph has been shortened a bit, which I think is a good
change.
Thanks!
Patrick
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 2/5] doc: glossary: update per-worktree refs
2026-10-22 21:28 ` [PATCH 2/5] doc: glossary: update per-worktree refs Andy Koppe
@ 2026-10-23 7:41 ` Patrick Steinhardt
0 siblings, 0 replies; 13+ messages in thread
From: Patrick Steinhardt @ 2026-10-23 7:41 UTC (permalink / raw)
To: Andy Koppe; +Cc: git, Karthik Nayak, Julia Evans
On Thu, Oct 22, 2026 at 10:28:50PM +0100, Andy Koppe wrote:
> diff --git a/Documentation/glossary-content.adoc b/Documentation/glossary-content.adoc
> index b2c582254b..eff6d23215 100644
> --- a/Documentation/glossary-content.adoc
> +++ b/Documentation/glossary-content.adoc
> @@ -494,10 +494,16 @@ exclude;;
> interface than the <<def_plumbing,plumbing>>.
>
> [[def_per_worktree_ref]]per-worktree ref::
> - Refs that are per-<<def_worktree,worktree>>, rather than
> - global. This is presently only <<def_HEAD,HEAD>> and any refs
> - that start with `refs/bisect/`, but might later include other
> - unusual refs.
> + A <<def_ref,ref>> that is specific to a <<def_worktree,worktree>>,
> + rather than shared between all worktrees. All
> + <<def_root_ref,root refs>>, such as <<def_HEAD,HEAD>>, are
> + per-worktree, as are refs that start with `refs/bisect/`,
> + `refs/worktree/` or `refs/rewritten/`.
> ++
> +<<def_pseudoref,Pseudorefs>> are also specific to each worktree.
Should we maybe also turn this into an itemized list? Makes it easier to
see at a glance which rrefs are per-worktree, and it becomes easier to
extend going forward.
> +See "REFS" in linkgit:git-worktree[1] for how to access the
> +per-worktree refs of other worktrees.
>
> [[def_pseudoref]]pseudoref::
> A name that can be used like a <<def_ref,ref>> to refer to
> @@ -788,5 +794,5 @@ 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).
This is a bit curious as you distinguish between per-worktree refs and
pseudorefs, even though you mention both of them as part of the
per-worktree ref section. I wonder whether we should simply refer to
that section without naming any examples.
Patrick
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 3/5] doc: stop calling root refs pseudorefs
2026-10-22 21:28 ` [PATCH 3/5] doc: stop calling root refs pseudorefs Andy Koppe
@ 2026-10-23 7:41 ` Patrick Steinhardt
0 siblings, 0 replies; 13+ messages in thread
From: Patrick Steinhardt @ 2026-10-23 7:41 UTC (permalink / raw)
To: Andy Koppe; +Cc: git, Karthik Nayak, Julia Evans
On Thu, Oct 22, 2026 at 10:28:51PM +0100, Andy Koppe wrote:
> diff --git a/Documentation/git-update-ref.adoc b/Documentation/git-update-ref.adoc
> index 37a5019a8b..c775334230 100644
> --- a/Documentation/git-update-ref.adoc
> +++ b/Documentation/git-update-ref.adoc
> @@ -163,13 +163,12 @@ still see a subset of the modifications.
>
> LOGGING UPDATES
> ---------------
> -If config parameter "core.logAllRefUpdates" is true and the ref is one
> -under "refs/heads/", "refs/remotes/", "refs/notes/", or a pseudoref
> -like HEAD or ORIG_HEAD; or the file "$GIT_DIR/logs/<ref>" exists then
> -`git update-ref` will append a line to the log file
> -"$GIT_DIR/logs/<ref>" (dereferencing all symbolic refs before creating
> -the log name) describing the change in ref value. Log lines are
> -formatted as:
> +If config parameter "core.logAllRefUpdates" is true and the ref is
> +HEAD or one under "refs/heads/", "refs/remotes/" or "refs/notes/", or
> +if the file "$GIT_DIR/logs/<ref>" exists, then `git update-ref` will
It's kind of hard to understand how the ANDs and ORs play together.
Like, does the config parameter extend to all subsequent ORs? That's not
really a new issue though.
> +append a line to the log file "$GIT_DIR/logs/<ref>" (dereferencing all
Also, this infomation about "$GIT_DIR/logs/<ref>" is out-of-date, as the
reftable backend doesn't store its reflogs in there.
I wonder whether we should maybe just stop explaining how
"core.logAllRefUpdates" works and instead refer to git-config(1).
> diff --git a/Documentation/git-worktree.adoc b/Documentation/git-worktree.adoc
> index e6e77252ab..f0eb6d4137 100644
> --- a/Documentation/git-worktree.adoc
> +++ b/Documentation/git-worktree.adoc
> @@ -303,11 +303,10 @@ but others are specific to an individual worktree. One example is `HEAD`,
> which is different for each worktree. This section is about the sharing
> rules and how to access refs of one worktree from another.
>
> -In general, all pseudo refs are per-worktree and all refs starting with
> -`refs/` are shared. Pseudo refs are ones like `HEAD` which are directly
> -under `$GIT_DIR` instead of inside `$GIT_DIR/refs`. There are exceptions,
> -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.
It might make sense to have a bulleted list here, same as I proposed in
a preceding patch.
Patrick
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 4/5] refs: stop calling root refs pseudorefs
2026-10-22 21:28 ` [PATCH 4/5] refs: " Andy Koppe
@ 2026-10-23 7:41 ` Patrick Steinhardt
0 siblings, 0 replies; 13+ messages in thread
From: Patrick Steinhardt @ 2026-10-23 7:41 UTC (permalink / raw)
To: Andy Koppe; +Cc: git, Karthik Nayak, Julia Evans
On Thu, Oct 22, 2026 at 10:28:52PM +0100, Andy Koppe wrote:
> Some messages and comments in the code still use "pseudoref" in its old
> sense of any ref outside of "refs/", whereas the glossary now calls
> those root refs and restricts pseudorefs to FETCH_HEAD and MERGE_HEAD.
>
> Replace "pseudoref" with "root ref" in the help text for
> "git for-each-ref --include-root-refs", in comments in refs.h, and in
> comments in the bash completion script, including the one for
> __git_pseudoref_exists(), which is also used for root refs.
I feel like this sentence is somewhat pointless, as you basically
just explain the diff.
> The function
> itself is not renamed. There is no obvious term covering both root refs
> and pseudorefs, and the old name might need to be kept for third-party
> completion scripts.
This is useful though.
> Update the description of pseudorefs in refs.h to match the glossary.
And this is again info that can simply be dropped.
Patrick
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 0/5] root refs vs pseudorefs
2026-10-22 21:28 [PATCH 0/5] root refs vs pseudorefs Andy Koppe
` (5 preceding siblings ...)
2026-10-22 22:18 ` [PATCH 0/5] root refs vs pseudorefs Junio C Hamano
@ 2026-10-23 13:21 ` Julia Evans
6 siblings, 0 replies; 13+ messages in thread
From: Julia Evans @ 2026-10-23 13:21 UTC (permalink / raw)
To: Andy Koppe; +Cc: git, Patrick Steinhardt, Karthik Nayak
> On Oct 22, 2026, at 5:28 PM, Andy Koppe <andy.koppe@gmail.com> wrote:
>
> Since 993d57eded (refs: pseudorefs are no refs, 2024-05-15), the term
> "pseudoref" has been restricted to FETCH_HEAD and MERGE_HEAD, which are
> not stored in the ref backends, while other refs outside of "refs/",
> such as HEAD and ORIG_HEAD, are called root refs. However, a fair number
> of docs, comments, messages and tests still use "pseudoref" in its old
> sense. And while the glossary describes the rules for refs in the root
> of the hierarchy, it does not explicitly define the term, even though
> "git for-each-ref --include-root-refs" uses it.
>
> This series adds a "root ref" entry to the glossary and clarifies the
> "pseudoref" entry, and then replaces the outdated uses of "pseudoref" in
> docs, code and tests. While at it, it also updates the long outdated
> glossary entry for per-worktree refs, and fixes a few inaccuracies
> found along the way, for example about which refs get a reflog in
> git-update-ref(1) and core.logAllRefUpdates.
>
> I've left __git_pseudoref_exists() in the completion script alone apart
> from its comment, even though it's used for both pseudorefs and root
> refs. It could be renamed, keeping the old name as a deprecated wrapper
> like elsewhere in the script, but it's not obvious what to, because
> there is no term covering both.
> 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 | 9 +-
> Documentation/glossary-content.adoc | 86 ++++++++++++-------
> Documentation/rev-list-options.adoc | 4 +-
I wonder if gitdatamodel.adoc should also cover pseudorefs and root refs
in the “References” section. Right now it only says something extremely
short on the topic:
Git may also create references other than HEAD at the base of
the hierarchy, like ORIG_HEAD.
> 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 +-
> 21 files changed, 129 insertions(+), 111 deletions(-)
> rename t/t4013/{diff.diff-tree_--cc_--summary_REVERSE => diff.diff-tree_--cc_--summary_REVERSE_HEAD} (73%)
>
>
> base-commit: 7e34d8174dcda3435d1404c9a30bef46afe6c13e
> --
> 2.56.0
>
>
^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2026-10-23 13:21 UTC | newest]
Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-22 21:28 [PATCH 0/5] root refs vs pseudorefs Andy Koppe
2026-10-22 21:28 ` [PATCH 1/5] doc: glossary: add root ref and clarify pseudorefs Andy Koppe
2026-10-22 22:07 ` Junio C Hamano
2026-10-23 7:41 ` Patrick Steinhardt
2026-10-22 21:28 ` [PATCH 2/5] doc: glossary: update per-worktree refs Andy Koppe
2026-10-23 7:41 ` Patrick Steinhardt
2026-10-22 21:28 ` [PATCH 3/5] doc: stop calling root refs pseudorefs Andy Koppe
2026-10-23 7:41 ` Patrick Steinhardt
2026-10-22 21:28 ` [PATCH 4/5] refs: " Andy Koppe
2026-10-23 7:41 ` Patrick Steinhardt
2026-10-22 21:28 ` [PATCH 5/5] t: " Andy Koppe
2026-10-22 22:18 ` [PATCH 0/5] root refs vs pseudorefs Junio C Hamano
2026-10-23 13:21 ` Julia Evans
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox