The text that GPG signs on a git tag is:

object $sha1
type commit
tag $name
tagger $user $timestamp $tz

$text

If you wanted to attack a signed git commit through the gpg signature's hash, you would have to do a second preimage attack on that text with a different commit sha1.

OTOH, if you wanted to attack a signed git commit through the git commit sha1, you would have to do a second preimage attack on that commit text, which is of the form:

commit $length\0
tree $sha1
parent $parent_sha1
author $author $author_timestamp $author_tz
committer $committer $committer_timestamp $committer_tz

$text

See where I'm going? it's the same kind of attack.

Another way to attack it would be to do a second pre-image attack on the pointed tree, which is harder because there is not really free-form text available in a tree object.

Yet another way to attack it would be to do a second pre-image attack on one of the blobs pointed to by a tree, where the format is of the form:

blob $length\0$content

I don't think this is significantly easier than any of the second pre-image attacks mentioned above.

So, in fact, in any case, to attack a gpg signed git tag, you need a second pre-image attack on the hash. If git uses something better than SHA-1, but GPG still uses SHA-1, the weakest link becomes, ironically, GPG.

That being said, second pre-image attacks are pretty much impractical for most hashes at the moment, even older ones that have been deemed broken for many years (like MD5 or even MD4 (TTBOMK)).

That is, even if git were using MD4, you couldn't replace an existing commit, tree or blob with something that has the same MD4.

Edit:

In fact, here's a challenge:

Let's assume that git can use any kind of hash instead of SHA1. Let's assume I have a repository with a single commit with a single tree that contains a single source file.

The source file is:

$ cat hackme.c
#include <stdio.h>

int main() {
printf("Hack me, world!\n");
return 0;
}

So that we all talk about the same thing, here is the raw sha1 for this source:

$ sha1sum hackme.c
cffc02c09faf2e9a83ecbb976e1304759868cf1c hackme.c

And its git SHA1:

$ git hash-object hackme.c
36134c8c8e9fdf705441dcc1f71736064afc7c44

Here is how you can create this SHA1 without git:

$ (echo -e -n blob $(stat -c %s hackme.c)\\x0; cat hackme.c) | sha1sum
36134c8c8e9fdf705441dcc1f71736064afc7c44 -

or

$ (echo -e -n blob $(stat -c %s hackme.c)\\x0; cat hackme.c) | openssl sha1
(stdin)= 36134c8c8e9fdf705441dcc1f71736064afc7c44

And for git variants that would be using MD5:

$ (echo -e -n blob $(stat -c %s hackme.c)\\x0; cat hackme.c) | openssl md5
(stdin)= 1b56dbc6613ff340b324ca973aec67f9

Or MD4:

$ (echo -e -n blob $(stat -c %s hackme.c)\\x0; cat hackme.c) | openssl md4
(stdin)= 0eaabfc1a32629dce98c476f591c3f60

The challenge is this: attack the hypothetical repository using the hash of your choosing[1] ; replace that source with something that is valid C because people using the content of the repository will be compiling the source. Obviously, you'll need the hash to match for "blob $length\0$content" where $length is the length of $content, in bytes, and $content is your replacement C source code.

1. let's say, pick any from the list on http://valerieaurora.org/hash.html

I posit you'll spend a lot of time and resources (and money) on the problem, (exponentially more so than Google did with SHAttered) except for Snefru.