On a number of parts of the Internet (such as here), it is implied that git commits must be signed when being done or never.
However, technically a signature on a commit is nothing more than a signature on the commit object (as shown here), that consists of a hash of the "tree" file (that is a list of hashes of the git objects), the hash of the parent and some metadata.
As a consequence, there seems to be nothing that prevents a commit to be signed a posteriori, without rewriting the entire history.
Is it really possible? Is there a recommended way of doing so? Would such an after-the-fact signature work nicely with pushes and pulls?
I don't believe you can do this without rewriting history. I just cloned the same repository twice to conduct a test. I made the same change in both repositories, then committed with the same log message ("foobar"), the only difference being that one was signed and one was not.
As you can see, starting from the same parent (50c6dd65), the result is a two different commit hashes. So for un-pushed commits, it's not any different than any other history rewriting (and therefore it carries the same liabilities).
In response to your comment asking if the hash changed merely because of a difference in timestamps, I don't believe so. If you inspect using
cat-file
:As I understand it, this metadata is all part of the input to the hash algorithm resulting in the commit ID. If that is the case, the presence of the
gpgsig
data here means it will always give you a different hash than the unsigned version of the commit.