refs: add array of ref namespaces

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>

Derrick Stolee committed Aug 5, 2022 at 17:58 UTC b9342b3fd6308c351f53075c9c4339913b73451f
4 files changed +132
environment.c
+2
@@ -185,6 +185,8 @@ void setup_git_env(const char *git_dir)
185 free(git_replace_ref_base);
186 git_replace_ref_base = xstrdup(replace_ref_base ? replace_ref_base
187 : "refs/replace/");
188 + update_ref_namespace(NAMESPACE_REPLACE, git_replace_ref_base);
189 +
190 free(git_namespace);
191 git_namespace = expand_namespace(getenv(GIT_NAMESPACE_ENVIRONMENT));
192 shallow_file = getenv(GIT_SHALLOW_FILE_ENVIRONMENT);
notes.c
+1
@@ -1005,6 +1005,7 @@ void init_notes(struct notes_tree *t, const char *notes_ref,
1005
1006 if (!notes_ref)
1007 notes_ref = default_notes_ref();
1008 + update_ref_namespace(NAMESPACE_NOTES, xstrdup(notes_ref));
1009
1010 if (!combine_notes)
1011 combine_notes = combine_notes_concatenate;
refs.c
+83
@@ -20,6 +20,7 @@
20 #include "repository.h"
21 #include "sigchain.h"
22 #include "date.h"
23 +#include "commit.h"
24
25 /*
26 * List of all available backends
@@ -56,6 +57,88 @@ static unsigned char refname_disposition[256] = {
57 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 4, 4
58 };
59
60 +struct ref_namespace_info ref_namespace[] = {
61 + [NAMESPACE_HEAD] = {
62 + .ref = "HEAD",
63 + .decoration = DECORATION_REF_HEAD,
64 + .exact = 1,
65 + },
66 + [NAMESPACE_BRANCHES] = {
67 + .ref = "refs/heads/",
68 + .decoration = DECORATION_REF_LOCAL,
69 + },
70 + [NAMESPACE_TAGS] = {
71 + .ref = "refs/tags/",
72 + .decoration = DECORATION_REF_TAG,
73 + },
74 + [NAMESPACE_REMOTE_REFS] = {
75 + /*
76 + * The default refspec for new remotes copies refs from
77 + * refs/heads/ on the remote into refs/remotes/<remote>/.
78 + * As such, "refs/remotes/" has special handling.
79 + */
80 + .ref = "refs/remotes/",
81 + .decoration = DECORATION_REF_REMOTE,
82 + },
83 + [NAMESPACE_STASH] = {
84 + /*
85 + * The single ref "refs/stash" stores the latest stash.
86 + * Older stashes can be found in the reflog.
87 + */
88 + .ref = "refs/stash",
89 + .exact = 1,
90 + .decoration = DECORATION_REF_STASH,
91 + },
92 + [NAMESPACE_REPLACE] = {
93 + /*
94 + * This namespace allows Git to act as if one object ID
95 + * points to the content of another. Unlike the other
96 + * ref namespaces, this one can be changed by the
97 + * GIT_REPLACE_REF_BASE environment variable. This
98 + * .namespace value will be overwritten in setup_git_env().
99 + */
100 + .ref = "refs/replace/",
101 + .decoration = DECORATION_GRAFTED,
102 + },
103 + [NAMESPACE_NOTES] = {
104 + /*
105 + * The refs/notes/commit ref points to the tip of a
106 + * parallel commit history that adds metadata to commits
107 + * in the normal history. This ref can be overwritten
108 + * by the core.notesRef config variable or the
109 + * GIT_NOTES_REFS environment variable.
110 + */
111 + .ref = "refs/notes/commit",
112 + .exact = 1,
113 + },
114 + [NAMESPACE_PREFETCH] = {
115 + /*
116 + * Prefetch refs are written by the background 'fetch'
117 + * maintenance task. It allows faster foreground fetches
118 + * by advertising these previously-downloaded tips without
119 + * updating refs/remotes/ without user intervention.
120 + */
121 + .ref = "refs/prefetch/",
122 + },
123 + [NAMESPACE_REWRITTEN] = {
124 + /*
125 + * Rewritten refs are used by the 'label' command in the
126 + * sequencer. These are particularly useful during an
127 + * interactive rebase that uses the 'merge' command.
128 + */
129 + .ref = "refs/rewritten/",
130 + },
131 +};
132 +
133 +void update_ref_namespace(enum ref_namespace namespace, char *ref)
134 +{
135 + struct ref_namespace_info *info = &ref_namespace[namespace];
136 + if (info->ref_updated)
137 + free(info->ref);
138 + info->ref = ref;
139 + info->ref_updated = 1;
140 +}
141 +
142 /*
143 * Try to read one refname component from the front of refname.
144 * Return the length of the component found, or -1 if the component is
refs.h
+46
@@ -2,6 +2,7 @@
2 #define REFS_H
3
4 #include "cache.h"
5 +#include "commit.h"
6
7 struct object_id;
8 struct ref_store;
@@ -930,4 +931,49 @@ struct ref_store *get_main_ref_store(struct repository *r);
931 struct ref_store *get_submodule_ref_store(const char *submodule);
932 struct ref_store *get_worktree_ref_store(const struct worktree *wt);
933
934 +/*
935 + * Some of the names specified by refs have special meaning to Git.
936 + * Organize these namespaces in a comon 'ref_namespace' array for
937 + * reference from multiple places in the codebase.
938 + */
939 +
940 +struct ref_namespace_info {
941 + char *ref;
942 + enum decoration_type decoration;
943 +
944 + /*
945 + * If 'exact' is true, then we must match the 'ref' exactly.
946 + * Otherwise, use a prefix match.
947 + *
948 + * 'ref_updated' is for internal use. It represents whether the
949 + * 'ref' value was replaced from its original literal version.
950 + */
951 + unsigned exact:1,
952 + ref_updated:1;
953 +};
954 +
955 +enum ref_namespace {
956 + NAMESPACE_HEAD,
957 + NAMESPACE_BRANCHES,
958 + NAMESPACE_TAGS,
959 + NAMESPACE_REMOTE_REFS,
960 + NAMESPACE_STASH,
961 + NAMESPACE_REPLACE,
962 + NAMESPACE_NOTES,
963 + NAMESPACE_PREFETCH,
964 + NAMESPACE_REWRITTEN,
965 +
966 + /* Must be last */
967 + NAMESPACE__COUNT
968 +};
969 +
970 +/* See refs.c for the contents of this array. */
971 +extern struct ref_namespace_info ref_namespace[NAMESPACE__COUNT];
972 +
973 +/*
974 + * Some ref namespaces can be modified by config values or environment
975 + * variables. Modify a namespace as specified by its ref_namespace key.
976 + */
977 +void update_ref_namespace(enum ref_namespace namespace, char *ref);
978 +
979 #endif /* REFS_H */