Change date of git tag (or GitHub Release based on it)
Here's a one-liner based on some of the comments in the other answer:
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 -f $tag -m"$tag" $COMMIT_HASH ; done && git push --tags --force
WARNING: this will nuke your upstream tags and will not preserve messages for annotated tags! Be sure that you know what you're doing and DEFINITELY don't do this for a public repository!!!
To break it down...
# Loop over tags
git tag -l | while read -r tag
do
# get the commit hash of the current tag
COMMIT_HASH=$(git rev-list -1 $tag)
# get the commit date of the tag and create a new tag using
# the tag's name and message. By specifying the environment
# environment variable GIT_COMMITTER_DATE before this is
# run, we override the default tag date. Note that if you
# specify the variable on a different line, it will apply to
# the current environment. This isn't desired as probably
# don't want your future tags to also have that past date.
# Of course, when you close your shell, the variable will no
# longer persist.
GIT_COMMITTER_DATE="$(git show $COMMIT_HASH --format=%aD | head -1)" git tag -a -f $tag -m"$tag" $COMMIT_HASH
done
# Force push tags and overwrite ones on the server with the same name
git push --tags --force
Thanks to @Mr_and_Mrs_D for the suggestion to use a single push.
Building on the other answers, here's a way that will preserve the first line of the tag message
git tag -l | while read -r tag ; do COMMIT_HASH=$(git rev-list -1 $tag) COMMIT_MSG=$(git tag -l --format='%(contents)' $tag | head -n1) && GIT_COMMITTER_DATE="$(git show $COMMIT_HASH --format=%aD | head -1)" git tag -a -f $tag -m"$COMMIT_MSG" $COMMIT_HASH ; done
git tag -l -n1 #check by listing all tags with first line of message
git push --tags --force #push edited tags up to remote
The bit responsible for preserving the messages is:
COMMIT_MSG=$(git tag -l --format='%(contents)' $tag | head -n1)
head -n1
will take the first line of the old commit message. You can modify it to -n2
or -n3
etc to get two or three lines instead.
If you want to change the date/time for just one tag, this is how you can break down the one-liner to do it in your bash shell:
tag=v0.1.0
COMMIT_HASH=$(git rev-list -1 $tag)
COMMIT_MSG=$(git tag -l --format='%(contents)' $tag | head -n1)
COMMIT_DATE=$(git show $COMMIT_HASH --format=%aD | head -1)
GIT_COMMITTER_DATE=$COMMIT_DATE git tag -s -a -f $tag -m"$COMMIT_MSG" $COMMIT_HASH
References:
- Print the message of a git tag
- Get first line of a shell command's output
WARNING: This will not preserve tag messages for annotated tags.
Summary
For each tag that needs to be changed:
- Go back in time to the commit representing the tag
- Delete the tag (locally and remotely)
- This will turn your "Release" on GitHub into a Draft that you can later delete.
- Re-add the same-named tag using a magic invocation that sets its date to the date of the commit.
- Push the new tags with fixed dates back up to GitHub.
- Go to GitHub, delete any now-draft releases, and re-create new releases from the new tags
In code:
# Fixing tag named '1.0.1'
git checkout 1.0.1 # Go to the associated commit
git tag -d 1.0.1 # Locally delete the tag
git push origin :refs/tags/1.0.1 # Push this deletion up to GitHub
# Create the tag, with a date derived from the current head
GIT_COMMITTER_DATE="$(git show --format=%aD | head -1)" git tag -a 1.0.1 -m"v1.0.1"
git push --tags # Send the fixed tags to GitHub
Details
According to How to Tag in Git:
If you forget to tag a release or version bump, you can always tag it retroactively like so:
git checkout SHA1_OF_PAST_COMMIT git tag -m"Retroactively tagging version 1.5" v1.5
And while that's perfectly usable, it has the effect of putting your tags out of chronological order which can screw with build systems that look for the "latest" tag. But have no fear. Linus thought of everything:
# This moves you to the point in history where the commit exists git checkout SHA1_OF_PAST_COMMIT # This command gives you the datetime of the commit you're standing on git show --format=%aD | head -1 # And this temporarily sets git tag's clock back to the date you copy/pasted in from above GIT_COMMITTER_DATE="Thu Nov 11 12:21:57 2010 -0800" git tag -a 0.9.33 -m"Retroactively tagging version 0.9.33" # Combining the two... GIT_COMMITTER_DATE="$(git show --format=%aD | head -1)" git tag -a 0.9.33 -m"Retroactively tagging version 0.9.33"
However, if you have already added the tag, you cannot use the above with git tag -f existingtag
or else git will complain when you try to merge:
Rammy:docubot phrogz$ git push --tags
To [email protected]:Phrogz/docubot.git
! [rejected] 1.0.1 -> 1.0.1 (already exists)
error: failed to push some refs to '[email protected]:Phrogz/docubot.git'
hint: Updates were rejected because the tag already exists in the remote.
Instead, you must remove the tag locally:
git tag -d 1.0.1
Push that deletion remotely:
git push origin :refs/tags/1.0.1
On GitHub, reload Releases—the release has now been marked as a "Draft"—and remove the draft.
Now, add the backdated tag based on the instructions above, and finally push the resulting tag to GitHub:
git push --tags
and then go and re-add the GitHub Release information again.