This can be useful e.g. in `filter-branch` when rewritting tags produced by
older versions of Git, such as v2.6.12-rc2..v2.6.13-rc3 in the Linux kernel
source tree:
$ git cat-file tag v2.6.12-rc2
object 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2
type commit
tag v2.6.12-rc2
Linux v2.6.12-rc2 release
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.4 (GNU/Linux)
iD8DBQBCbW8ZF3YsRnbiHLsRAgFRAKCq/TkuDaEombFABkPqYgGCgWN2lQCcC0qc
wznDbFU45A54dZC8RZ5JxyE=
=ESRP
-----END PGP SIGNATURE-----
$ git cat-file tag v2.6.12-rc2 | git mktag
error: char76: could not find "tagger "
fatal: invalid tag signature file
$ git cat-file tag v2.6.12-rc2 | git mktag --allow-missing-tagger
9e734775f7c22d2f89943ad6c745571f1930105f
To that end, pass the new option to `mktag` in `filter-branch`.
Signed-off-by: Ian Campbell <[email protected]>
---
Documentation/git-mktag.txt | 9 +++-
builtin/mktag.c | 100 +++++++++++++++++++++++++-------------------
git-filter-branch.sh | 2 +-
t/t3800-mktag.sh | 33 ++++++++++++++-
4 files changed, 98 insertions(+), 46 deletions(-)
diff --git a/Documentation/git-mktag.txt b/Documentation/git-mktag.txt
index fa6a75612..c720c7419 100644
--- a/Documentation/git-mktag.txt
+++ b/Documentation/git-mktag.txt
@@ -9,7 +9,7 @@ git-mktag - Creates a tag object
SYNOPSIS
--------
[verse]
-'git mktag'
+'git mktag' [--allow-missing-tagger]
DESCRIPTION
-----------
@@ -34,6 +34,13 @@ exists, is separated by a blank line from the header. The
message part may contain a signature that Git itself doesn't
care about, but that can be verified with gpg.
+OPTIONS
+-------
+--allow-missing-tagger::
+ Allow the `tagger` line in the header to be omitted. This is
+ rarely desirable but may be useful in recreating tags created
+ by older Git.
+
GIT
---
Part of the linkgit:git[1] suite
diff --git a/builtin/mktag.c b/builtin/mktag.c
index 031b750f0..0f5dae8d5 100644
--- a/builtin/mktag.c
+++ b/builtin/mktag.c
@@ -1,4 +1,5 @@
#include "builtin.h"
+#include "parse-options.h"
#include "tag.h"
/*
@@ -15,6 +16,8 @@
* the shortest possible tagger-line.
*/
+static int allow_missing_tagger;
+
/*
* We refuse to tag something we can't verify. Just because.
*/
@@ -41,8 +44,9 @@ static int verify_tag(char *buffer, unsigned long size)
unsigned char sha1[20];
const char *object, *type_line, *tag_line, *tagger_line, *lb, *rb;
size_t len;
+ const unsigned long min_size = allow_missing_tagger ? 71 : 84;
- if (size < 84)
+ if (size < min_size)
return error("wanna fool me ? you obviously got the size wrong
!");
buffer[size] = 0;
@@ -98,46 +102,46 @@ static int verify_tag(char *buffer, unsigned long size)
/* Verify the tagger line */
tagger_line = tag_line;
- if (memcmp(tagger_line, "tagger ", 7))
+ if (!memcmp(tagger_line, "tagger ", 7)) {
+ /*
+ * Check for correct form for name and email
+ * i.e. " <" followed by "> " on _this_ line
+ * No angle brackets within the name or email address fields.
+ * No spaces within the email address field.
+ */
+ tagger_line += 7;
+ if (!(lb = strstr(tagger_line, " <")) || !(rb = strstr(lb+2, ">
")) ||
+ strpbrk(tagger_line, "<>\n") != lb+1 ||
+ strpbrk(lb+2, "><\n ") != rb)
+ return error("char%"PRIuMAX": malformed tagger field",
+ (uintmax_t) (tagger_line - buffer));
+
+ /* Check for author name, at least one character, space is
acceptable */
+ if (lb == tagger_line)
+ return error("char%"PRIuMAX": missing tagger name",
+ (uintmax_t) (tagger_line - buffer));
+
+ /* timestamp, 1 or more digits followed by space */
+ tagger_line = rb + 2;
+ if (!(len = strspn(tagger_line, "0123456789")))
+ return error("char%"PRIuMAX": missing tag timestamp",
+ (uintmax_t) (tagger_line - buffer));
+ tagger_line += len;
+ if (*tagger_line != ' ')
+ return error("char%"PRIuMAX": malformed tag timestamp",
+ (uintmax_t) (tagger_line - buffer));
+ tagger_line++;
+
+ /* timezone, 5 digits [+-]hhmm, max. 1400 */
+ if (!((tagger_line[0] == '+' || tagger_line[0] == '-') &&
+ strspn(tagger_line+1, "0123456789") == 4 &&
+ tagger_line[5] == '\n' && atoi(tagger_line+1) <= 1400))
+ return error("char%"PRIuMAX": malformed tag timezone",
+ (uintmax_t) (tagger_line - buffer));
+ tagger_line += 6;
+ } else if (!allow_missing_tagger)
return error("char%"PRIuMAX": could not find \"tagger \"",
- (uintmax_t) (tagger_line - buffer));
-
- /*
- * Check for correct form for name and email
- * i.e. " <" followed by "> " on _this_ line
- * No angle brackets within the name or email address fields.
- * No spaces within the email address field.
- */
- tagger_line += 7;
- if (!(lb = strstr(tagger_line, " <")) || !(rb = strstr(lb+2, "> ")) ||
- strpbrk(tagger_line, "<>\n") != lb+1 ||
- strpbrk(lb+2, "><\n ") != rb)
- return error("char%"PRIuMAX": malformed tagger field",
- (uintmax_t) (tagger_line - buffer));
-
- /* Check for author name, at least one character, space is acceptable */
- if (lb == tagger_line)
- return error("char%"PRIuMAX": missing tagger name",
- (uintmax_t) (tagger_line - buffer));
-
- /* timestamp, 1 or more digits followed by space */
- tagger_line = rb + 2;
- if (!(len = strspn(tagger_line, "0123456789")))
- return error("char%"PRIuMAX": missing tag timestamp",
- (uintmax_t) (tagger_line - buffer));
- tagger_line += len;
- if (*tagger_line != ' ')
- return error("char%"PRIuMAX": malformed tag timestamp",
- (uintmax_t) (tagger_line - buffer));
- tagger_line++;
-
- /* timezone, 5 digits [+-]hhmm, max. 1400 */
- if (!((tagger_line[0] == '+' || tagger_line[0] == '-') &&
- strspn(tagger_line+1, "0123456789") == 4 &&
- tagger_line[5] == '\n' && atoi(tagger_line+1) <= 1400))
- return error("char%"PRIuMAX": malformed tag timezone",
- (uintmax_t) (tagger_line - buffer));
- tagger_line += 6;
+ (uintmax_t) (tagger_line - buffer));
/* Verify the blank line separating the header from the body */
if (*tagger_line != '\n')
@@ -148,13 +152,25 @@ static int verify_tag(char *buffer, unsigned long size)
return 0;
}
+static char const * const mktag_usage[] = {
+ N_("git mktag [<options>]"),
+ NULL
+};
+
+static struct option mktag_opts[] = {
+ OPT_BOOL(0, "allow-missing-tagger", &allow_missing_tagger, N_("allow
the tagger field to be omitted")),
+ OPT_END(),
+};
+
int cmd_mktag(int argc, const char **argv, const char *prefix)
{
struct strbuf buf = STRBUF_INIT;
unsigned char result_sha1[20];
- if (argc != 1)
- usage("git mktag");
+ argc = parse_options(argc, argv, prefix, mktag_opts, mktag_usage, 0);
+
+ if (argc != 0)
+ usage_with_options(mktag_usage, mktag_opts);
if (strbuf_read(&buf, 0, 4096) < 0) {
die_errno("could not read from stdin");
diff --git a/git-filter-branch.sh b/git-filter-branch.sh
index 3a74602ef..05645064a 100755
--- a/git-filter-branch.sh
+++ b/git-filter-branch.sh
@@ -530,7 +530,7 @@ if [ "$filter_tag_name" ]; then
}' \
-e '/^-----BEGIN PGP SIGNATURE-----/q' \
-e 'p' ) |
- git mktag) ||
+ git mktag --allow-missing-tagger) ||
die "Could not create new tag object for $ref"
if git cat-file tag "$ref" | \
sane_grep '^-----BEGIN PGP SIGNATURE-----'
>/dev/null 2>&1
diff --git a/t/t3800-mktag.sh b/t/t3800-mktag.sh
index 8eb47942e..3a77a26c8 100755
--- a/t/t3800-mktag.sh
+++ b/t/t3800-mktag.sh
@@ -340,7 +340,36 @@ check_verify_failure 'detect invalid header entry' \
'^error: char124: trailing garbage in tag header$'
############################################################
-# 24. create valid tag
+# 24. missing tagger ok with --allow-missing-tagger
+
+cat >tag.sig <<EOF
+object $head
+type commit
+tag mytag
+
+EOF
+
+test_expect_success \
+ 'missing tagger with --allow-missing-tagger' \
+ 'git mktag --allow-missing-tagger <tag.sig >.git/refs/tags/mytag 2>message'
+
+############################################################
+# 25. detect invalid header entry with --allow-missing-tagger
+
+cat >tag.sig <<EOF
+object $head
+type commit
+tag mytag
+this line should not be here
+EOF
+
+test_expect_success \
+ 'detect invalid header entry with --allow-missing-tagger' \
+ '( test_must_fail git mktag --allow-missing-tagger <tag.sig 2>message ) &&
+ grep "^error: char70: trailing garbage in tag header$" message'
+
+############################################################
+# 26. create valid tag
cat >tag.sig <<EOF
object $head
@@ -355,7 +384,7 @@ test_expect_success \
'git mktag <tag.sig >.git/refs/tags/mytag 2>message'
############################################################
-# 25. check mytag
+# 27. check mytag
test_expect_success \
'check mytag' \
--
2.11.0