All of lore.kernel.org
 help / color / mirror / Atom feed
From: Luke Shumaker <lukeshu@lukeshu.com>
To: git@vger.kernel.org
Cc: "Elijah Newren" <newren@gmail.com>,
	"Junio C Hamano" <gitster@pobox.com>, "Jeff King" <peff@peff.net>,
	"brian m . carlson " <sandals@crustytoothpaste.net>,
	"Ævar Arnfjörð Bjarmason" <avarab@gmail.com>,
	"Luke Shumaker" <lukeshu@datawire.io>
Subject: [PATCH 3/3] fast-export, fast-import: let tags specify a different refname
Date: Wed, 21 Apr 2021 19:06:59 -0600	[thread overview]
Message-ID: <20210422010659.2498280-4-lukeshu@lukeshu.com> (raw)
In-Reply-To: <20210422010659.2498280-1-lukeshu@lukeshu.com>

From: Luke Shumaker <lukeshu@datawire.io>

A tag object contains the tag-name in the object, and is also pointed
to by a ref named 'refs/tags/{tag-name}'.  It's possible to end up
with a tag for which the internal name and the refname disagree.

This "shouldn't" happen, but sometimes it can:

 - In the "the coolest merge ever"[1], if Linus had wanted to import
   existing tags from Paul's gitk repo, he'd likely have wanted to give
   them a `gitk/` or `gitk-` prefix; you don't want gitk v0.0.1 to
   appear to be git v0.0.1, so when importing it, you'd rename the tag
   to `gitk/v0.0.1`.  (Less hypothetically, in-the-wild, my employer's
   repo has _several_ such merges/imports, where the tags from each repo
   were given a prefix.)
 - Sometimes tags are "archived" to something like
   "refs/archived-tags/foo".

That'd work fine if they're lightweight tags, but if they're annotated
tags, then after the rename the internal name in the tag object
(`v0.0.1`) is now different than the refname (`gitk/v0.0.1`).  Which
is still mostly fine, since not too many tools care if the internal
name and the refname disagree.

But, fast-export/fast-import are tools that do care: it's currently
impossible to represent these tags in a fast-import stream.

This patch adds an optional "refname" sub-command to fast-import's "tag"
top-level-command, the stream

    tag foo
    refname refs/tags/bar
    ...

will create a tag at "refs/tags/bar" that says "tag foo" internally.

[1]: https://lore.kernel.org/git/Pine.LNX.4.58.0506221433540.2353@ppc970.osdl.org/

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
 Documentation/git-fast-import.txt | 22 +++++++++++++---------
 builtin/fast-export.c             |  6 ++++++
 builtin/fast-import.c             | 10 ++++++++--
 t/t9350-fast-export.sh            | 11 ++++++++---
 4 files changed, 35 insertions(+), 14 deletions(-)

diff --git a/Documentation/git-fast-import.txt b/Documentation/git-fast-import.txt
index 39cfa05b28..8c1756bdad 100644
--- a/Documentation/git-fast-import.txt
+++ b/Documentation/git-fast-import.txt
@@ -822,24 +822,28 @@ Creates an annotated tag referring to a specific commit.  To create
 lightweight (non-annotated) tags see the `reset` command below.
 
 ....
-	'tag' SP <name> LF
+	'tag' SP <tagname> LF
 	mark?
+	('refname' SP <refname> LF)?
 	'from' SP <commit-ish> LF
 	original-oid?
 	'tagger' (SP <name>)? SP LT <email> GT SP <when> LF
 	data
 ....
 
-where `<name>` is the name of the tag to create.
+where `<tagname>` is the name of the tag that is stored in the tag
+object itself.  The value of `<tagname>` must be a valid for inclusion
+as part of a refname in Git and therefore may contain forward slashes.
+As `LF` is not valid in a Git refname, no quoting or escaping syntax
+is supported here.
 
-Tag names are automatically prefixed with `refs/tags/` when stored
-in Git, so importing the CVS branch symbol `RELENG-1_0-FINAL` would
-use just `RELENG-1_0-FINAL` for `<name>`, and fast-import will write the
-corresponding ref as `refs/tags/RELENG-1_0-FINAL`.
+The `refname` command controls where in the ref hierarchy to put the
+reference that points to the resulting tag object.  If `refname` is
+not given, then `refs/tags/<tagname>` is used.
 
-The value of `<name>` must be a valid refname in Git and therefore
-may contain forward slashes.  As `LF` is not valid in a Git refname,
-no quoting or escaping syntax is supported here.
+So, for example, importing the CVS branch symbol `RELENG-1_0-FINAL`
+would use just `RELENG-1_0-FINAL` for `<tagname>`, and fast-import
+will write the corresponding ref as `refs/tags/RELENG-1_0-FINAL`.
 
 The `from` command is the same as in the `commit` command; see
 above for details.
diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index 2bf83fe52e..de04aaf241 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -784,6 +784,7 @@ static void handle_tail(struct object_array *commits, struct rev_info *revs,
 
 static void handle_tag(const char *refname, struct tag *tag)
 {
+	static struct strbuf autorefname = STRBUF_INIT;
 	unsigned long size;
 	enum object_type type;
 	char *buf;
@@ -910,6 +911,9 @@ static void handle_tag(const char *refname, struct tag *tag)
 		}
 	}
 
+	strbuf_reset(&autorefname);
+	strbuf_addf(&autorefname, "refs/tags/%.*s", (int)tagname_len, tagname);
+
 	if (tagged->type == OBJ_TAG) {
 		printf("reset %s\nfrom %s\n\n",
 		       refname, oid_to_hex(&null_oid));
@@ -919,6 +923,8 @@ static void handle_tag(const char *refname, struct tag *tag)
 		mark_next_object(&tag->object);
 		printf("mark :%"PRIu32"\n", last_idnum);
 	}
+	if (strcmp(refname, autorefname.buf))
+		printf("refname %s\n", refname);
 	if (tagged_mark)
 		printf("from :%d\n", tagged_mark);
 	else
diff --git a/builtin/fast-import.c b/builtin/fast-import.c
index 43287f929f..49e5a0c159 100644
--- a/builtin/fast-import.c
+++ b/builtin/fast-import.c
@@ -2794,9 +2794,15 @@ static void parse_new_tag(const char *arg)
 	read_next_command();
 	parse_mark();
 
+	/* refname ... */
 	strbuf_reset(&refname);
-	strbuf_addstr(&refname, "refs/tags/");
-	strbuf_addstr(&refname, tagname);
+	if (skip_prefix(command_buf.buf, "refname ", &v)) {
+		strbuf_addstr(&refname, v);
+		read_next_command();
+	} else {
+		strbuf_addstr(&refname, "refs/tags/");
+		strbuf_addstr(&refname, tagname);
+	}
 
 	/* from ... */
 	if (!skip_prefix(command_buf.buf, "from ", &from))
diff --git a/t/t9350-fast-export.sh b/t/t9350-fast-export.sh
index 0bcc1bd54e..089c0c0a24 100755
--- a/t/t9350-fast-export.sh
+++ b/t/t9350-fast-export.sh
@@ -34,6 +34,9 @@ test_expect_success 'setup' '
 	git commit -m sitzt file2 &&
 	test_tick &&
 	git tag -a -m valentin muss &&
+	git tag -a -m joseph pure &&
+	git update-ref refs/english-tags/rein refs/tags/pure &&
+	git update-ref -d refs/tags/pure &&
 	git merge -s ours main
 
 '
@@ -42,6 +45,7 @@ test_expect_success 'fast-export | fast-import' '
 
 	MAIN=$(git rev-parse --verify main) &&
 	REIN=$(git rev-parse --verify rein) &&
+	PURE=$(git rev-parse --verify refs/english-tags/rein) &&
 	WER=$(git rev-parse --verify wer) &&
 	MUSS=$(git rev-parse --verify muss) &&
 	mkdir new &&
@@ -51,6 +55,7 @@ test_expect_success 'fast-export | fast-import' '
 	 git fast-import &&
 	 test $MAIN = $(git rev-parse --verify refs/heads/main) &&
 	 test $REIN = $(git rev-parse --verify refs/tags/rein) &&
+	 test $PURE = $(git rev-parse --verify refs/english-tags/rein) &&
 	 test $WER = $(git rev-parse --verify refs/heads/wer) &&
 	 test $MUSS = $(git rev-parse --verify refs/tags/muss)) <actual
 
@@ -359,7 +364,7 @@ test_expect_success 'fast-export | fast-import when main is tagged' '
 
 	git tag -m msg last &&
 	git fast-export -C -C --signed-tags=strip --all > output &&
-	test $(grep -c "^tag " output) = 3
+	test $(grep -c "^tag " output) = 4
 
 '
 
@@ -374,11 +379,11 @@ test_expect_success 'cope with tagger-less tags' '
 	TAG=$(git hash-object -t tag -w tag-content) &&
 	git update-ref refs/tags/sonnenschein $TAG &&
 	git fast-export -C -C --signed-tags=strip --all > output &&
-	test $(grep -c "^tag " output) = 4 &&
+	test $(grep -c "^tag " output) = 5 &&
 	! grep "Unspecified Tagger" output &&
 	git fast-export -C -C --signed-tags=strip --all \
 		--fake-missing-tagger > output &&
-	test $(grep -c "^tag " output) = 4 &&
+	test $(grep -c "^tag " output) = 5 &&
 	grep "Unspecified Tagger" output
 
 '
-- 
2.31.1


      parent reply	other threads:[~2021-04-22  1:07 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-04-22  1:06 [PATCH 0/3] fast-export, fast-import: let tags specify a different refname Luke Shumaker
2021-04-22  1:06 ` [PATCH 1/3] fast-export, fast-import: make stylistic changes Luke Shumaker
2021-04-22  1:06 ` [PATCH 2/3] fast-export: fix bug with nested tags Luke Shumaker
2021-04-22  1:06 ` Luke Shumaker [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210422010659.2498280-4-lukeshu@lukeshu.com \
    --to=lukeshu@lukeshu.com \
    --cc=avarab@gmail.com \
    --cc=git@vger.kernel.org \
    --cc=gitster@pobox.com \
    --cc=lukeshu@datawire.io \
    --cc=newren@gmail.com \
    --cc=peff@peff.net \
    --cc=sandals@crustytoothpaste.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.