I try to avoid a few things when using Git.
Using knowledge of the internals, e.g. refs/tags. I try to use solely the documented Git commands and avoid using things which require knowledge of the internal contents of the .git directory. (That is to say, I treat Git as a Git user and not a Git developer.)
The use of force when not required.
Overdoing things. (Pushing a branch and/or lots of tags, to get one tag where I want it.)
So here is my non-violent solution for changing a tag, both locally and remotely, without knowledge of the Git internals.
I use it when a software fix ultimately has a problem and needs to be updated/re-released.
git tag -d fix123 # delete the old local tag
git push github :fix123 # delete the old remote tag (use for each affected remote)
git tag fix123 790a621265 # create a new local tag
git push github fix123 # push new tag to remote (use for each affected remote)
github
is a sample remote name, fix123
is a sample tag name, and 790a621265
a sample commit.