Reputation: 13378
I created a tag and forgot to sign it, then pushed the tag to GitHub. Is it possible to just sign that tag retroactively, or do I have to create a new tag?
I have read the man page for git tag
and googled a bit, but have come up with no clues that adding a signature to an already existing tag is possible.
Upvotes: 24
Views: 2452
Reputation: 848
This one-liner will sign all your local tags and force push them. At the same time, it will set the date of the tag to the commit it is attached to:
git tag -l | while read -r tag ; do COMMIT_HASH=$(git rev-list -1 $tag) && GIT_COMMITTER_DATE="$(git show $COMMIT_HASH --format=%aD | head -1)" git tag -a -s -f $tag -m"$tag" $COMMIT_HASH ; done && git push --tags --force
Source: This is a modified version of this other answer by vmrob adjusted to the current question.
Upvotes: 1
Reputation: 1326994
No you would need to::
replace it with a tag using the same name:
git tag <tag name> <tag name> -f -s
but first set the committer date, in order to not change the date
set GIT_COMMITTER_DATE="$(git log -1 --format=%aD <tag_name>)"
As mrts adds in the comments, since the tag was already pushed:
You also need to force push the updated tag with
git push origin <tag_name> -f
Starting with Git 2.42 (Q3 2023), you can sign only the tags which need it, using:
git for-each-ref --format='%(refname) %(signature)' refs/tags | python re-sign-tags.py
^^^^^^^^^^^^
(new with Git 2.42)
And re-sign-tags.py
import sys
import subprocess
def verify_tag(refname, signature):
grade = signature.split(":")[1]
if grade == "good":
print("Tag '%s' is signed with a good signature." % refname)
else:
print("Tag '%s' is signed with a bad signature." % refname)
def re_sign_tag(refname, signature):
signer = signature.split(":")[1]
print("Re-signing tag '%s' with key '%s'." % (refname, signer))
subprocess.run(["git", "tag", "-f", refname, refname, "-s"], check=True)
if __name__ == "__main__":
for refname, signature in sys.stdin:
if refname.startswith("refs/tags/"):
if verify_tag(refname, signature):
re_sign_tag(refname, signature)
With Git 2.42 (Q3 2023), the "git for-each-ref
"(man) family of commands learned placeholders related to GPG signature verification.
See commit 26c9c03, commit 2f36339 (04 Jun 2023) by Kousik Sanagavarapu (five-sh
).
(Merged by Junio C Hamano -- gitster
-- in commit 81ebc54, 14 Jul 2023)
ref-filter
: add new "signature" atomCo-authored-by: Hariom Verma
Co-authored-by: Jaydeep Das
Co-authored-by: Nsengiyumva Wilberforce
Mentored-by: Christian Couder
Mentored-by: Hariom Verma
Signed-off-by: Kousik Sanagavarapu
Duplicate the code for outputting the signature and its other parameters for commits and tags in ref-filter from pretty.
In the future, this will help in getting rid of the current duplicate implementations of such logic everywhere, when ref-filter can do everything that pretty is doing.The new atom "signature" and its friends are equivalent to the existing pretty formats as follows:
%(signature) = %GG %(signature:grade) = %G? %(siganture:signer) = %GS %(signature:key) = %GK %(signature:fingerprint) = %GF %(signature:primarykeyfingerprint) = %GP %(signature:trustlevel) = %GT
git for-each-ref
now includes in its man page:
signature
The GPG signature of a commit.
signature:grade
Show "G" for a good (valid) signature, "B" for a bad signature, "U" for a good signature with unknown validity, "X" for a good signature that has expired, "Y" for a good signature made by an expired key, "R" for a good signature made by a revoked key, "E" if the signature cannot be checked (e.g. missing key) and "N" for no signature.
signature:signer
The signer of the GPG signature of a commit.
signature:key
The key of the GPG signature of a commit.
signature:fingerprint
The fingerprint of the GPG signature of a commit.
signature:primarykeyfingerprint
The primary key fingerprint of the GPG signature of a commit.
signature:trustlevel
The trust level of the GPG signature of a commit. Possible outputs are
ultimate
,fully
,marginal
,never
andundefined
.
Upvotes: 21
Reputation: 871
I know this is an old question but going off of what VonC said. I created a one-line bash script that can go through all of your tags in your repository and sign them automatically. All you have to do is either accept or change the message set in the old tag. Here is the command I came up with
git for-each-ref refs/tags | awk '{print $3}' | cut -c11- | xargs -I % sh -c 'git tag % % -f -s'
Upvotes: 4