Long story short I'm writing a script to migrate a very large project from (gasp) Microsoft SourceSafe to Git and I'm trying to retain the authors of the SourceSafe project's labels(which are essentially tags in Git). I know you can modify the author and committer name/date of a Git Commit but can you do the same to a Git Tag?
How to change the Tagger name and email of a Git Tag
2.9k Views Asked by molinab297 At
3
There are 3 best solutions below
1
On
unlike commits you can easily delete tags from remote, recreate them with the author name you want
git tag -d <tag-name>
git push origin :refs/tags/<tag-name>
git config --global user.name "John Doe"
git config --global user.email [email protected]
git tag <tag-name> [commit]
git push origin <tag-name>
0
On
One additional detail: When creating annotated/signed tags, git tag will use GIT_COMMITTER_NAME and GIT_COMMITTER_EMAIL (not GIT_AUTHOR_NAME/GIT_AUTHOR_EMAIL) for the
"Tagger" field.
To create a tag with a different name/email without changing the global Git config:
GIT_COMMITTER_NAME="name" GIT_COMMITTER_EMAIL="email" git tag -am"1.0.0" v1.0.0 <commit>
Note1: To create a signed tag (-s), a private key for the specified identity is required (that's the point of signing).
Note2: It is also possible to recreate older tags with a specific timestamp. For example: GIT_COMMITTER_DATE="Wed Dec 16 22:33:44 UTC 2020" ...
TL;DR
Re-create the tags with the new desired data. But if anyone else had them before, they may not accept your new ones. Or they may! It's up to them, though.
Description
Actually, you can't, and the fact that you can't (and what you can do instead) plays an important part in the rest of the answer.
All Git objects have a hash ID as their "true name". The hash is formed by computing a cryptographic checksum of the object's contents. This means you can never change any Git object at all.1 What you can do is construct a new object, then convince everyone who had the old object to stop using it, and use instead the new object.
This is what
git commit --amenddoes (and what various interactive rebase options likeeditandrewordcan do as well). First we extract the original Git object into ordinary data, where we can manipulate it; then we do the manipulation and ask Git to construct a new object; and finally we stop using the old object and start using the new one instead.For a commit that is the tip commit (see the definition of head in the gitglossary), this all goes pretty easily and smoothly, as long as we haven't pushed that commit yet. There are no additional commits referring back to this tip commit, so we make a new commit that is "just as good", re-direct the branch name (the head) to the new commit, and forget about the original we just replaced. It looks like we changed a commit, but we got a new hash ID instead.
How this applies to tags
Git has two kinds of tags, a lightweight tag and an annotated tag. The difference between these is that an annotated tag consists of a lightweight tag pointing to a tag object. It's the tag object that has the tagger information. (A lightweight tag has no such information of its own, it just points directly to the commit object.)
Hence, to "change" a tag object, we must do the same thing we do to "change" a commit object: copy it to a new tag object.
There is no built in command to do this, but it is easy to build one out of
git cat-file -p—this lets you extract the original tag into ordinary data—andgit mktag, which lets you turn ordinary data into a new tag object. For instance, thev2.2.1tag in the Git repository for Git begins with:The
objectline is the commit to which the tag points:so we can copy this tag to a new one with a different
tagger:where the
seddoes whatever is necessary (see below) and$nameis the name of the tag. Then we would make the lightweight tagv2.2.1point to this new tag object in$new_hash_id. But there are two problems (only one of which is likely to apply to your case).Tags may be PGP-signed
The above tag goes on to say:
and then has a PGP signature in it. This signature covers all the data except for the signature itself. If you copy-and-modify this tag, you should discard the original signature entirely (it will be invalid and will fail any testing applied); whether you can and should replace it with a new signature, and if so, whose, is up to you.
Tags are not supposed to change their target objects
The existing lightweight tag
v2.2.1currently points to the existing tag object:This is the data we have been viewing up to this point.
The new tag object will have some other, different hash ID. When we amended an unpublished commit, that was no big deal, because no one else had any idea that some branch name mapped to some particular hash ID.
Tags, however, are pretty commonly "well known". In fact, the point of tags—particularly PGP-signed annotated tags, where the PGP signature lets you verify that no one has monkeyed with the tag data—is to guarantee that you can be sure that this tag is the right tag, and that the commit object to which it points is the original commit and not some Trojan Horse. If you change an existing tag, you're subverting this intent. Moreover, some people who know the previous tag's value will simply refuse to take a new value: you won't be able to get them to update an existing tag. As long as you're doing this before anyone else has the tag, though, they will never know, and you will be fine.
1Or rather, you cannot change a Git object's contents unless you can break the hash. See also How does the newly found sha1 collision affect git?