]> git.ipfire.org Git - thirdparty/git.git/commitdiff
refs: add array of ref namespaces
authorDerrick Stolee <derrickstolee@github.com>
Fri, 5 Aug 2022 17:58:36 +0000 (17:58 +0000)
committerJunio C Hamano <gitster@pobox.com>
Fri, 5 Aug 2022 21:13:12 +0000 (14:13 -0700)
Git interprets different meanings to different refs based on their
names. Some meanings are cosmetic, like how refs in  'refs/remotes/*'
are colored differently from refs in 'refs/heads/*'. Others are more
critical, such as how replace refs are interpreted.

Before making behavior changes based on ref namespaces, collect all
known ref namespaces into a array of ref_namespace_info structs. This
array is indexed by the new ref_namespace enum for quick access.

As of this change, this array is purely documentation. Future changes
will add dependencies on this array.

Signed-off-by: Derrick Stolee <derrickstolee@github.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
environment.c
notes.c
refs.c
refs.h

index b3296ce7d15140bff12299b25d1450f69f8508ee..9eb22f975c715443b5a1a763c31ef1d351d1d483 100644 (file)
@@ -185,6 +185,8 @@ void setup_git_env(const char *git_dir)
        free(git_replace_ref_base);
        git_replace_ref_base = xstrdup(replace_ref_base ? replace_ref_base
                                                          : "refs/replace/");
+       update_ref_namespace(NAMESPACE_REPLACE, git_replace_ref_base);
+
        free(git_namespace);
        git_namespace = expand_namespace(getenv(GIT_NAMESPACE_ENVIRONMENT));
        shallow_file = getenv(GIT_SHALLOW_FILE_ENVIRONMENT);
diff --git a/notes.c b/notes.c
index 7452e71cc8dd289c7ace9361a6c6e090b8b113f9..7bade6d8f69ca256a51436ec9a04d55d93528c7b 100644 (file)
--- a/notes.c
+++ b/notes.c
@@ -1005,6 +1005,7 @@ void init_notes(struct notes_tree *t, const char *notes_ref,
 
        if (!notes_ref)
                notes_ref = default_notes_ref();
+       update_ref_namespace(NAMESPACE_NOTES, xstrdup(notes_ref));
 
        if (!combine_notes)
                combine_notes = combine_notes_concatenate;
diff --git a/refs.c b/refs.c
index 3fdfa86a5b9025f4bff9a26f7eecb7ad3a007e92..65decf25d09635033bc353e9d4c8cb113dde9586 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -20,6 +20,7 @@
 #include "repository.h"
 #include "sigchain.h"
 #include "date.h"
+#include "commit.h"
 
 /*
  * List of all available backends
@@ -56,6 +57,88 @@ static unsigned char refname_disposition[256] = {
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 4, 4
 };
 
+struct ref_namespace_info ref_namespace[] = {
+       [NAMESPACE_HEAD] = {
+               .ref = "HEAD",
+               .decoration = DECORATION_REF_HEAD,
+               .exact = 1,
+       },
+       [NAMESPACE_BRANCHES] = {
+               .ref = "refs/heads/",
+               .decoration = DECORATION_REF_LOCAL,
+       },
+       [NAMESPACE_TAGS] = {
+               .ref = "refs/tags/",
+               .decoration = DECORATION_REF_TAG,
+       },
+       [NAMESPACE_REMOTE_REFS] = {
+               /*
+                * The default refspec for new remotes copies refs from
+                * refs/heads/ on the remote into refs/remotes/<remote>/.
+                * As such, "refs/remotes/" has special handling.
+                */
+               .ref = "refs/remotes/",
+               .decoration = DECORATION_REF_REMOTE,
+       },
+       [NAMESPACE_STASH] = {
+               /*
+                * The single ref "refs/stash" stores the latest stash.
+                * Older stashes can be found in the reflog.
+                */
+               .ref = "refs/stash",
+               .exact = 1,
+               .decoration = DECORATION_REF_STASH,
+       },
+       [NAMESPACE_REPLACE] = {
+               /*
+                * This namespace allows Git to act as if one object ID
+                * points to the content of another. Unlike the other
+                * ref namespaces, this one can be changed by the
+                * GIT_REPLACE_REF_BASE environment variable. This
+                * .namespace value will be overwritten in setup_git_env().
+                */
+               .ref = "refs/replace/",
+               .decoration = DECORATION_GRAFTED,
+       },
+       [NAMESPACE_NOTES] = {
+               /*
+                * The refs/notes/commit ref points to the tip of a
+                * parallel commit history that adds metadata to commits
+                * in the normal history. This ref can be overwritten
+                * by the core.notesRef config variable or the
+                * GIT_NOTES_REFS environment variable.
+                */
+               .ref = "refs/notes/commit",
+               .exact = 1,
+       },
+       [NAMESPACE_PREFETCH] = {
+               /*
+                * Prefetch refs are written by the background 'fetch'
+                * maintenance task. It allows faster foreground fetches
+                * by advertising these previously-downloaded tips without
+                * updating refs/remotes/ without user intervention.
+                */
+               .ref = "refs/prefetch/",
+       },
+       [NAMESPACE_REWRITTEN] = {
+               /*
+                * Rewritten refs are used by the 'label' command in the
+                * sequencer. These are particularly useful during an
+                * interactive rebase that uses the 'merge' command.
+                */
+               .ref = "refs/rewritten/",
+       },
+};
+
+void update_ref_namespace(enum ref_namespace namespace, char *ref)
+{
+       struct ref_namespace_info *info = &ref_namespace[namespace];
+       if (info->ref_updated)
+               free(info->ref);
+       info->ref = ref;
+       info->ref_updated = 1;
+}
+
 /*
  * Try to read one refname component from the front of refname.
  * Return the length of the component found, or -1 if the component is
diff --git a/refs.h b/refs.h
index 47cb9edbaa8913c3af721d347744beefacb1e754..d6575b8c2bdf0d3e9021f7000b42308ff33203af 100644 (file)
--- a/refs.h
+++ b/refs.h
@@ -2,6 +2,7 @@
 #define REFS_H
 
 #include "cache.h"
+#include "commit.h"
 
 struct object_id;
 struct ref_store;
@@ -930,4 +931,49 @@ struct ref_store *get_main_ref_store(struct repository *r);
 struct ref_store *get_submodule_ref_store(const char *submodule);
 struct ref_store *get_worktree_ref_store(const struct worktree *wt);
 
+/*
+ * Some of the names specified by refs have special meaning to Git.
+ * Organize these namespaces in a comon 'ref_namespace' array for
+ * reference from multiple places in the codebase.
+ */
+
+struct ref_namespace_info {
+       char *ref;
+       enum decoration_type decoration;
+
+       /*
+        * If 'exact' is true, then we must match the 'ref' exactly.
+        * Otherwise, use a prefix match.
+        *
+        * 'ref_updated' is for internal use. It represents whether the
+        * 'ref' value was replaced from its original literal version.
+        */
+       unsigned exact:1,
+                ref_updated:1;
+};
+
+enum ref_namespace {
+       NAMESPACE_HEAD,
+       NAMESPACE_BRANCHES,
+       NAMESPACE_TAGS,
+       NAMESPACE_REMOTE_REFS,
+       NAMESPACE_STASH,
+       NAMESPACE_REPLACE,
+       NAMESPACE_NOTES,
+       NAMESPACE_PREFETCH,
+       NAMESPACE_REWRITTEN,
+
+       /* Must be last */
+       NAMESPACE__COUNT
+};
+
+/* See refs.c for the contents of this array. */
+extern struct ref_namespace_info ref_namespace[NAMESPACE__COUNT];
+
+/*
+ * Some ref namespaces can be modified by config values or environment
+ * variables. Modify a namespace as specified by its ref_namespace key.
+ */
+void update_ref_namespace(enum ref_namespace namespace, char *ref);
+
 #endif /* REFS_H */