summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJunio C Hamano <gitster@pobox.com>2020-02-20 17:34:36 (GMT)
committerJunio C Hamano <gitster@pobox.com>2020-02-21 02:05:33 (GMT)
commitff165f00c1065d94c0bcab8708364e6dc5655f5d (patch)
tree7262fdc26d7f0416bffeafe8cfa97786b3179037
parentb6d4d82bd5a49197d5d2f4f81c08da0d461cfcf1 (diff)
downloadgit-ff165f00c1065d94c0bcab8708364e6dc5655f5d.zip
git-ff165f00c1065d94c0bcab8708364e6dc5655f5d.tar.gz
git-ff165f00c1065d94c0bcab8708364e6dc5655f5d.tar.bz2
describe: force long format for a name based on a mislocated tag
An annotated tag has two names: where it sits in the refs/tags hierarchy and the tagname recorded in the "tag" field in the object itself. They usually should match. Since 212945d4 ("Teach git-describe to verify annotated tag names before output", 2008-02-28), a commit described using an annotated tag bases its name on the tagname from the object. While this was a deliberate design decision to make it easier to converse about tags with others, even if the tags happen to be fetched to a different name than it was given by its creator, it had one downside. The output from "git describe", at least in the modern Git, should be usable as an object name to name the exact commit given to the "git describe" command. Using the tagname, when two names differ, breaks this property, when describing a commit that is directly pointed at by such a tag. An annotated tag Bob made as "v1.0" may sit at "refs/tags/v1.0-bob" in the ref hierarchy, and output from "git describe v1.0-bob^0" would say "v1.0", but there may not be any tag at "refs/tags/v1.0" locally or there may be another tag that points at a different object. Note that this won't be a problem if a commit being described is not directly pointed at by such a mislocated tag. In the example in the previous paragraph, describing a commit whose parent is v1.0-bob would result in "v1.0" (i.e. the tagname taken from the tag object) followed by "-1-gXXXXX" where XXXXX is the abbreviated object name, and a string that ends with "-g" followed by a hexadecimal string is an object name for the object whose name begins with hexadecimal string (as long as it is unique), so it does not matter if the leading part is "v1.0" or "v1.0-bob". Show the name in the long format, i.e. with "-0-gXXXXX" suffix, when the name we give is based on a mislocated annotated tag to ensure that the output can be used as the object name for the object originally given to the command to fix the issue. While at it, remove an overly cautious dead code to protect against an annotated tag object without the tagname. Such a tag is filtered out much earlier in the codeflow, and will not reach this part of the code. Helped-by: Matheus Tavares <matheus.bernardino@usp.br> Helped-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
-rw-r--r--builtin/describe.c15
-rwxr-xr-xt/t6120-describe.sh20
2 files changed, 28 insertions, 7 deletions
diff --git a/builtin/describe.c b/builtin/describe.c
index b6df81d..f71bddf 100644
--- a/builtin/describe.c
+++ b/builtin/describe.c
@@ -54,6 +54,7 @@ struct commit_name {
struct tag *tag;
unsigned prio:2; /* annotated tag = 2, tag = 1, head = 0 */
unsigned name_checked:1;
+ unsigned misnamed:1;
struct object_id oid;
char *path;
};
@@ -132,6 +133,7 @@ static void add_to_known_names(const char *path,
e->tag = tag;
e->prio = prio;
e->name_checked = 0;
+ e->misnamed = 0;
oidcpy(&e->oid, oid);
free(e->path);
e->path = xstrdup(path);
@@ -275,10 +277,11 @@ static void append_name(struct commit_name *n, struct strbuf *dst)
die(_("annotated tag %s not available"), n->path);
}
if (n->tag && !n->name_checked) {
- if (!n->tag->tag)
- die(_("annotated tag %s has no embedded name"), n->path);
- if (strcmp(n->tag->tag, all ? n->path + 5 : n->path))
- warning(_("tag '%s' is really '%s' here"), n->tag->tag, n->path);
+ if (strcmp(n->tag->tag, all ? n->path + 5 : n->path)) {
+ warning(_("tag '%s' is externally known as '%s'"),
+ n->path, n->tag->tag);
+ n->misnamed = 1;
+ }
n->name_checked = 1;
}
@@ -314,7 +317,7 @@ static void describe_commit(struct object_id *oid, struct strbuf *dst)
* Exact match to an existing ref.
*/
append_name(n, dst);
- if (longformat)
+ if (n->misnamed || longformat)
append_suffix(0, n->tag ? get_tagged_oid(n->tag) : oid, dst);
if (suffix)
strbuf_addstr(dst, suffix);
@@ -449,7 +452,7 @@ static void describe_commit(struct object_id *oid, struct strbuf *dst)
}
append_name(all_matches[0].name, dst);
- if (abbrev)
+ if (all_matches[0].name->misnamed || abbrev)
append_suffix(all_matches[0].depth, &cmit->object.oid, dst);
if (suffix)
strbuf_addstr(dst, suffix);
diff --git a/t/t6120-describe.sh b/t/t6120-describe.sh
index 45047d0..f22448b 100755
--- a/t/t6120-describe.sh
+++ b/t/t6120-describe.sh
@@ -130,12 +130,30 @@ test_expect_success 'rename tag A to Q locally' '
mv .git/refs/tags/A .git/refs/tags/Q
'
cat - >err.expect <<EOF
-warning: tag 'A' is really 'Q' here
+warning: tag 'Q' is externally known as 'A'
EOF
check_describe A-* HEAD
test_expect_success 'warning was displayed for Q' '
test_i18ncmp err.expect err.actual
'
+test_expect_success 'misnamed annotated tag forces long output' '
+ description=$(git describe --no-long Q^0) &&
+ expr "$description" : "A-0-g[0-9a-f]*$" &&
+ git rev-parse --verify "$description" >actual &&
+ git rev-parse --verify Q^0 >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'abbrev=0 will not break misplaced tag (1)' '
+ description=$(git describe --abbrev=0 Q^0) &&
+ expr "$description" : "A-0-g[0-9a-f]*$"
+'
+
+test_expect_success 'abbrev=0 will not break misplaced tag (2)' '
+ description=$(git describe --abbrev=0 c^0) &&
+ expr "$description" : "A-1-g[0-9a-f]*$"
+'
+
test_expect_success 'rename tag Q back to A' '
mv .git/refs/tags/Q .git/refs/tags/A
'