Git mktag: Construct Tag Objects with Validation
Construct annotated-tag objects from their canonical contents, understand the validation performed by git mktag, and distinguish tag objects from tag references.
Advanced
A tag reference and a tag object are different things
A tag name such as `refs/tags/v1.0` is a reference. An annotated tag can point that reference at a separate tag object. The tag object stores the object being tagged, its object type, the tag name, tagger information, and the annotation message. `git mktag` works at the object layer: it reads the tag object's contents from standard input and writes the resulting tag object to the object database.
# In a repository with at least one commit:
COMMIT=$(git rev-parse HEAD)
TIMESTAMP=$(git show -s --format=%ct HEAD)
printf 'object %s\ntype commit\ntag v-test\ntagger Test <test@example.com> %s +0000\n\nA manually constructed tag object.\n' "$COMMIT" "$TIMESTAMP" > tag.txt
git mktag < tag.txtQuick check
What does `git mktag` create?
The input is the canonical tag-object content
The tag-object content identifies the target object with an `object` header, identifies its type with `type`, records the tag name with `tag`, and records the tagger with `tagger`. A blank line separates these headers from the annotation message. The exact bytes matter because Git hashes the complete object content when it creates the object ID.
COMMIT=$(git rev-parse HEAD)
TIMESTAMP=$(git show -s --format=%ct HEAD)
cat > tag.txt <<EOF
object $COMMIT
type commit
tag v-test
tagger Test <test@example.com> $TIMESTAMP +0000
A manually constructed tag object.
EOF
git mktag < tag.txtThe example uses the current repository's HEAD and commit timestamp so the command is directly runnable. A tag object can target Git objects other than commits too; the `type` header identifies the target's object type.
Quick check
Why can two otherwise similar tag contents produce different object IDs?
`mktag` validates instead of merely hashing
`git mktag` is intentionally a validating constructor. It checks that the input has the structure required for a tag object and that the referenced object can be resolved. This distinguishes it from `git hash-object -t tag -w`, which can write bytes as a tag-typed object without providing the same tag-specific validation.
# Valid tag object contents
git mktag < tag.txt
# A deliberately nonexistent target should be rejected.
printf '%s\n' \
'object 0000000000000000000000000000000000000000' \
'type commit' \
'tag invalid' \
"tagger Test <test@example.com> $TIMESTAMP +0000" \
'' \
'Bad target' | git mktagQuick check
What is the important distinction between `git mktag` and `git hash-object -t tag -w`?
Strict validation and extra headers
`git mktag` enables the equivalent of `git fsck --strict` by default. The current official documentation also exposes `--strict` explicitly and `--no-strict` to disable that strict mode. Extra headers are errors by default, even though ordinary `git fsck` may treat some of them as warnings or ignore them.
# Start from the valid tag.txt created above.
# Explicitly request the documented strict mode.
git mktag --strict < tag.txt
# Insert an extra header after the required tagger header.
{ head -n 4 tag.txt; printf '%s\n\n' 'extra-header value'; tail -n 1 tag.txt; } > tag-with-extra-header.txt
# Default strict validation rejects the extra header.
git mktag < tag-with-extra-header.txt
# Disable the strict mode for this deliberately nonstandard input.
git mktag --no-strict < tag-with-extra-header.txt
# The equivalent fsck configuration can also relax this particular check.
git -c fsck.extraHeaderEntry=ignore mktag < tag-with-extra-header.txtQuick check
Which option disables the strict validation that `git mktag` enables by default?
The resulting object is a normal Git object
The object ID printed by `git mktag` can be inspected with the normal object-inspection commands. `git cat-file -t` reports its type, and `git cat-file -p` displays the stored tag contents. This lets you verify that the bytes accepted by `mktag` became a tag object in the object database.
TAG_OBJECT=$(git mktag < tag.txt)
git cat-file -t "$TAG_OBJECT"
git cat-file -p "$TAG_OBJECT"Quick check
Does `git mktag` create a `refs/tags/...` name for the new object?
Do not use `mktag` as a replacement for `git tag`
For normal annotated-tag workflows, `git tag -a`, `git tag -m`, or related porcelain commands are the appropriate interface because they create and manage the tag reference as part of the workflow. `git mktag` is a plumbing command for constructing and validating the tag object itself. The existing Foxipa tag lessons own tag-reference workflows and signature verification; this lesson owns the lower-level object-construction boundary.
Practice what you learned
Use the dedicated Git code-completion exercise for this lesson.
Thanks for your feedback.
Mark this learning resource complete to track your learning progress.