This is an emulation of what git provides, but now that I've written it I'm not totally convinced it's the right thing. There's a lot of behavior here that's keying off the value of a returned string. Would it make more sense to have this be an `Action<Tag, GitObject>` that receives the old tag and the new target? We could even call it in the right order for chained tags.