git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: How to create tags outside of refs/tags?

From
Jeff King <peff@peff.net>
Date
Feb 22, 2011, 08:03 UTC
Message-ID
<20110222080305.GA11177@sigill.intra.peff.net>
In-Reply-To
<AANLkTi=7yUh9J9S5LdpNY0SwCv008ih2LEd3KNvy46sL@mail.gmail.com>
On Tue, Feb 22, 2011 at 07:17:20AM +0100, Christian Halstrick wrote:
Show 15 quoted lines
> On Mon, Feb 21, 2011 at 18:21, Christian Halstrick
> <christian.halstrick@gmail.com> wrote:
> > I would like to create such tags to mark released states of my sources
> > which should never be garbage collected in case no branch is pointing
> > them anymore. On the other hand these tags should not pollute the
> > namespace of normal tags, means: don't want a 'git tag' command to
> > list those technical tags.
> 
> Is there any better way to achieve that certain commits are not
> garbage collected than to create such tags. I love my foot and don't
> want to "shoot if off" but I want to make sure the the
> "release-process-machinery" in our company can be sure that certain
> source states are never gc'ed. I can also live with creating normal
> tags 'refs/tags/release/1.20' but would prefer a solution where 'git
> tags' shows only developer created tags.

It sounds a lot saner to me to fix "git tag", then, to ignore certain uninteresting bits of the tag namespace. We already do allow pattern matching the tags shown, but:

  1. It's an fnmatch, so I don't think there is a way to do a negative
     match like "ignore everything that matches release/*".
  2. It can only be specified on the command-line, whereas obviously you
     would want this as the default for a repo when you type "git tag".
So I think we could do something like the patch below, which allows:
  # set up some boring and interesting tags
  for i in boring more-boring interesting; do
    for j in one two three; do
      git tag $i/$j
    done
  done
  # tell git to ignore boring stuff
  git config tag.ignore 'boring/*'
  git config --add tag.ignore 'more-boring/*'
  # only interesting tags are shown
  git tag
  # only interesting tags are checked for --contains
  git tag --contains HEAD
  # all tags are shown
  git tag --no-ignore

One alternative would be to allow specifying a default pattern in the config, and then some way of marking it as a regex instead of fnmatch. Then you could (in theory) construct a regex that negatively matches your boring refs. Although without perl-compatibile negative look-ahead, such regexes can get pretty hard to write.

Anyway, here's what the patch looks like. Obviously missing docs and tests.

---
diff --git a/builtin/tag.c b/builtin/tag.c
index 46f7138..629dfa3 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -12,6 +12,7 @@
 #include "tag.h"
 #include "run-command.h"
 #include "parse-options.h"
+#include "string-list.h"
 
 static const char * const git_tag_usage[] = {
 	"git tag [-a|-s|-u <key-id>] [-f] [-m <msg>|-F <file>] <tagname> [<head>]",
@@ -27,8 +28,11 @@ struct tag_filter {
 	const char *pattern;
 	int lines;
 	struct commit_list *with_commit;
+	const struct string_list *ignore;
 };
 
+static struct string_list ignore_tags = STRING_LIST_INIT_DUP;
+
 static int show_reference(const char *refname, const unsigned char *sha1,
 			  int flag, void *cb_data)
 {
@@ -41,6 +45,13 @@ static int show_reference(const char *refname, const unsigned char *sha1,
 		char *buf, *sp, *eol;
 		size_t len;
 
+		if (filter->ignore) {
+			for (i = 0; i < filter->ignore->nr; i++)
+				if (!fnmatch(filter->ignore->items[i].string,
+					     refname, 0))
+					return 0;
+		}
+
 		if (filter->with_commit) {
 			struct commit *commit;
 
@@ -89,7 +100,8 @@ static int show_reference(const char *refname, const unsigned char *sha1,
 }
 
 static int list_tags(const char *pattern, int lines,
-			struct commit_list *with_commit)
+			struct commit_list *with_commit,
+			const struct string_list *ignore)
 {
 	struct tag_filter filter;
 
@@ -99,6 +111,7 @@ static int list_tags(const char *pattern, int lines,
 	filter.pattern = pattern;
 	filter.lines = lines;
 	filter.with_commit = with_commit;
+	filter.ignore = ignore;
 
 	for_each_tag_ref(show_reference, (void *) &filter);
 
@@ -233,6 +246,13 @@ static int git_tag_config(const char *var, const char *value, void *cb)
 		return 0;
 	}
 
+	if (!strcmp(var, "tag.ignore")) {
+		if (!value)
+			return config_error_nonbool(var);
+		string_list_append(&ignore_tags, value);
+		return 0;
+	}
+
 	return git_default_config(var, value, cb);
 }
 
@@ -365,6 +385,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
 	const char *msgfile = NULL, *keyid = NULL;
 	struct msg_arg msg = { 0, STRBUF_INIT };
 	struct commit_list *with_commit = NULL;
+	int ignore = 1;
 	struct option options[] = {
 		OPT_BOOLEAN('l', NULL, &list, "list tag names"),
 		{ OPTION_INTEGER, 'n', NULL, &lines, "n",
@@ -391,6 +412,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
 			PARSE_OPT_LASTARG_DEFAULT,
 			parse_opt_with_commit, (intptr_t)"HEAD",
 		},
+		OPT_BOOLEAN(0, "ignore", &ignore, "respect tag.ignore config"),
 		OPT_END()
 	};
 
@@ -415,7 +437,8 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
 		usage_with_options(git_tag_usage, options);
 	if (list)
 		return list_tags(argv[0], lines == -1 ? 0 : lines,
-				 with_commit);
+				 with_commit,
+				 ignore ? &ignore_tags : NULL);
 	if (lines != -1)
 		die("-n option is only allowed with -l.");
 	if (with_commit)
Previous: Christian HalstrickNext: Junio C Hamano
Message 5 of 16 in “How to create tags outside of refs/tags?”
  1. Christian HalstrickFeb 21, 2011
  2. Jay SoffianFeb 21, 2011
  3. Junio C HamanoFeb 21, 2011
  4. Christian HalstrickFeb 22, 2011
  5. Jeff KingFeb 22, 2011
  6. Junio C HamanoFeb 22, 2011
  7. Jeff KingFeb 22, 2011
  8. Jakub NarebskiFeb 22, 2011
  9. Jeff KingFeb 22, 2011
  10. Christian HalstrickFeb 22, 2011
  11. Junio C HamanoFeb 22, 2011
  12. Christian HalstrickFeb 22, 2011
  13. Michael J GruberFeb 23, 2011
  14. Christian HalstrickFeb 23, 2011
  15. Enrico WeigeltFeb 23, 2011
  16. Jay SoffianFeb 22, 2011

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.