# Suggestion: error "tag ... already exists" should distinguish between tagging different or same commit:

14 messages from 2025-06-09 to 2025-07-11. Participants: M Hickford, Junio C Hamano, Hilco Wijbenga, Andreas Schwab, rsbecker@nexbridge.com, Justin Tobler.
Thread: https://gitlist.dev/t/63607

## M Hickford, 2025-06-09 07:00

Subject: Suggestion: error "tag ... already exists" should distinguish between tagging different or same commit:
Message-ID: <CAGJzqsnvTnp3k8Ab2exaBAw5pszQRz00UcucnK=ECtY5vhG+1A@mail.gmail.com>
URL: https://gitlist.dev/e/CAGJzqsnvTnp3k8Ab2exaBAw5pszQRz00UcucnK%3DECtY5vhG%2B1A%40mail.gmail.com

```
Hi. Presently, the error "tag ... already exists" doesn't distinguish
between tagging the same commit or a different commit:

     >git tag hello v1.9.5

     >git tag hello v1.9.5
     fatal: tag 'hello' already exists

     >git tag hello v2.0.0
     fatal: tag 'hello' already exists

To inform the user, it would be nice to distinguish these cases, perhaps:

     >git tag hello v1.9.5
     fatal: tag 'hello' already exists pointing at
d4e6038a068d0aecd5ec28c83afbfc6d4903092f

     >git tag hello v2.0.0
     fatal: tag 'hello' already exists but points at
18a07354e33f86c8349ffdc300d9087876658264

The second error is typically more concerning than the first.

What do you think?

```

## Junio C Hamano, 2025-06-09 18:42

Subject: Re: Suggestion: error "tag ... already exists" should distinguish between tagging different or same commit:
Message-ID: <xmqqcybcrc2u.fsf@gitster.g>
URL: https://gitlist.dev/e/xmqqcybcrc2u.fsf%40gitster.g
In-Reply-To: <CAGJzqsnvTnp3k8Ab2exaBAw5pszQRz00UcucnK=ECtY5vhG+1A@mail.gmail.com>

```
M Hickford <mirth.hickford@gmail.com> writes:

> Hi. Presently, the error "tag ... already exists" doesn't distinguish
> between tagging the same commit or a different commit:
>
>      >git tag hello v1.9.5
>
>      >git tag hello v1.9.5
>      fatal: tag 'hello' already exists
>
>      >git tag hello v2.0.0
>      fatal: tag 'hello' already exists
>
> To inform the user, it would be nice to distinguish these cases, perhaps:
>
>      >git tag hello v1.9.5
>      fatal: tag 'hello' already exists pointing at
> d4e6038a068d0aecd5ec28c83afbfc6d4903092f
>
>      >git tag hello v2.0.0
>      fatal: tag 'hello' already exists but points at
> 18a07354e33f86c8349ffdc300d9087876658264
>
> The second error is typically more concerning than the first.
>
> What do you think?

Not interested.  When the user gets that "fatal" message, the
existing tag did not get modified, so they can just do whatever
check they want (like "git range-diff v1.9.5...hello") themselves.

Besides, in the above examples, is d4e6038a something the user
immediately recognises as the same as v1.9.5 or the object existing
v1.9.5 tag points at?  I somehow doubt it.  So after getting the
error, there needs some digging to figure out how v1.9.5 and
existing hello are related to each other _anyway_, I would think.



```

## Hilco Wijbenga, 2025-06-09 19:37

Subject: Re: Suggestion: error "tag ... already exists" should distinguish between tagging different or same commit:
Message-ID: <CAE1pOi34+btHyV8GbjpFPcJ+2ixu59ce4eAE=Q7F4JEcuJyXnw@mail.gmail.com>
URL: https://gitlist.dev/e/CAE1pOi34%2BbtHyV8GbjpFPcJ%2B2ixu59ce4eAE%3DQ7F4JEcuJyXnw%40mail.gmail.com
In-Reply-To: <xmqqcybcrc2u.fsf@gitster.g>

```
Does it really make sense for that first example to fail, though? "git
tag hello v1.9.5" is an idempotent operation, isn't it? The second
attempt is a no-op?

If "git tag ..." simply does nothing if the tag already exists (as
requested) then that would make the OP's issue go away: only the 2nd
example would fail.

On Mon, Jun 9, 2025 at 11:45 AM Junio C Hamano <gitster@pobox.com> wrote:
>
> M Hickford <mirth.hickford@gmail.com> writes:
>
> > Hi. Presently, the error "tag ... already exists" doesn't distinguish
> > between tagging the same commit or a different commit:
> >
> >      >git tag hello v1.9.5
> >
> >      >git tag hello v1.9.5
> >      fatal: tag 'hello' already exists
> >
> >      >git tag hello v2.0.0
> >      fatal: tag 'hello' already exists
> >
> > To inform the user, it would be nice to distinguish these cases, perhaps:
> >
> >      >git tag hello v1.9.5
> >      fatal: tag 'hello' already exists pointing at
> > d4e6038a068d0aecd5ec28c83afbfc6d4903092f
> >
> >      >git tag hello v2.0.0
> >      fatal: tag 'hello' already exists but points at
> > 18a07354e33f86c8349ffdc300d9087876658264
> >
> > The second error is typically more concerning than the first.
> >
> > What do you think?
>
> Not interested.  When the user gets that "fatal" message, the
> existing tag did not get modified, so they can just do whatever
> check they want (like "git range-diff v1.9.5...hello") themselves.
>
> Besides, in the above examples, is d4e6038a something the user
> immediately recognises as the same as v1.9.5 or the object existing
> v1.9.5 tag points at?  I somehow doubt it.  So after getting the
> error, there needs some digging to figure out how v1.9.5 and
> existing hello are related to each other _anyway_, I would think.
>
>
>

```

## Andreas Schwab, 2025-06-09 20:15

Subject: Re: Suggestion: error "tag ... already exists" should distinguish between tagging different or same commit:
Message-ID: <87qzzsisdp.fsf@igel.home>
URL: https://gitlist.dev/e/87qzzsisdp.fsf%40igel.home
In-Reply-To: <CAE1pOi34+btHyV8GbjpFPcJ+2ixu59ce4eAE=Q7F4JEcuJyXnw@mail.gmail.com>

```
On Jun 09 2025, Hilco Wijbenga wrote:

> Does it really make sense for that first example to fail, though? "git
> tag hello v1.9.5" is an idempotent operation, isn't it? The second
> attempt is a no-op?

That's not true if an annotated tag is replaced by a lightweight tag.

-- 
Andreas Schwab, schwab@linux-m68k.org
GPG Key fingerprint = 7578 EB47 D4E5 4D69 2510  2552 DF73 E780 A9DA AEC1
"And now for something completely different."

```

## Junio C Hamano, 2025-06-09 20:19

Subject: Re: Suggestion: error "tag ... already exists" should distinguish between tagging different or same commit:
Message-ID: <xmqqqzzspt0i.fsf@gitster.g>
URL: https://gitlist.dev/e/xmqqqzzspt0i.fsf%40gitster.g
In-Reply-To: <CAE1pOi34+btHyV8GbjpFPcJ+2ixu59ce4eAE=Q7F4JEcuJyXnw@mail.gmail.com>

```
Hilco Wijbenga <hilco.wijbenga@gmail.com> writes:

> Does it really make sense for that first example to fail, though? "git
> tag hello v1.9.5" is an idempotent operation, isn't it? The second
> attempt is a no-op?
>
> If "git tag ..." simply does nothing if the tag already exists (as
> requested) then that would make the OP's issue go away: only the 2nd
> example would fail.

I do not think I personally mind that direction; when I responded, I
thought that in the example, 'hello' is initially pointing at
something entirely different (perhaps v2.0.0), though.

But it may be tricky to do, though.

It is easy for lightweight tags, but you'd have to fail an attempt
to add an annotated and/or signed tag without -f anyway, so you have
to be prepared to answer "why does this behave differently with and
without -a/-s?".

```

## Hilco Wijbenga, 2025-06-09 21:03

Subject: Re: Suggestion: error "tag ... already exists" should distinguish between tagging different or same commit:
Message-ID: <CAE1pOi0bFpuGuFSEHDUgv3mcwwwgXAEn8q3QSwF33ucqFWJ_AQ@mail.gmail.com>
URL: https://gitlist.dev/e/CAE1pOi0bFpuGuFSEHDUgv3mcwwwgXAEn8q3QSwF33ucqFWJ_AQ%40mail.gmail.com
In-Reply-To: <xmqqqzzspt0i.fsf@gitster.g>

```
Clearly, I have not used everything that "git tag" offers. :-)

So, to clarify, I was thinking (naively?) that Git would check that
the tag as requested is _exactly_ the same as the existing tag. Only
_that_ specific scenario would then not fail.

On Mon, Jun 9, 2025 at 1:19 PM Junio C Hamano <gitster@pobox.com> wrote:
>
> Hilco Wijbenga <hilco.wijbenga@gmail.com> writes:
>
> > Does it really make sense for that first example to fail, though? "git
> > tag hello v1.9.5" is an idempotent operation, isn't it? The second
> > attempt is a no-op?
> >
> > If "git tag ..." simply does nothing if the tag already exists (as
> > requested) then that would make the OP's issue go away: only the 2nd
> > example would fail.
>
> I do not think I personally mind that direction; when I responded, I
> thought that in the example, 'hello' is initially pointing at
> something entirely different (perhaps v2.0.0), though.
>
> But it may be tricky to do, though.
>
> It is easy for lightweight tags, but you'd have to fail an attempt
> to add an annotated and/or signed tag without -f anyway, so you have
> to be prepared to answer "why does this behave differently with and
> without -a/-s?".

```

## M Hickford, 2025-06-10 07:00

Subject: Re: Suggestion: error "tag ... already exists" should distinguish between tagging different or same commit:
Message-ID: <CAGJzqskj803dUcEuV+P-yuWdT0tiaidb7h3YxQSCgYHWgBfaWA@mail.gmail.com>
URL: https://gitlist.dev/e/CAGJzqskj803dUcEuV%2BP-yuWdT0tiaidb7h3YxQSCgYHWgBfaWA%40mail.gmail.com
In-Reply-To: <xmqqcybcrc2u.fsf@gitster.g>

```
On Mon, 9 Jun 2025 at 19:42, Junio C Hamano <gitster@pobox.com> wrote:
>
> M Hickford <mirth.hickford@gmail.com> writes:
>
> > Hi. Presently, the error "tag ... already exists" doesn't distinguish
> > between tagging the same commit or a different commit:
> >
> >      >git tag hello v1.9.5
> >
> >      >git tag hello v1.9.5
> >      fatal: tag 'hello' already exists
> >
> >      >git tag hello v2.0.0
> >      fatal: tag 'hello' already exists
> >
> > To inform the user, it would be nice to distinguish these cases, perhaps:
> >
> >      >git tag hello v1.9.5
> >      fatal: tag 'hello' already exists pointing at
> > d4e6038a068d0aecd5ec28c83afbfc6d4903092f
> >
> >      >git tag hello v2.0.0
> >      fatal: tag 'hello' already exists but points at
> > 18a07354e33f86c8349ffdc300d9087876658264
> >
> > The second error is typically more concerning than the first.
> >
> > What do you think?
>
> Not interested.  When the user gets that "fatal" message, the
> existing tag did not get modified, so they can just do whatever
> check they want (like "git range-diff v1.9.5...hello") themselves.
>
> Besides, in the above examples, is d4e6038a something the user
> immediately recognises as the same as v1.9.5 or the object existing
> v1.9.5 tag points at?  I somehow doubt it.  So after getting the
> error, there needs some digging to figure out how v1.9.5 and
> existing hello are related to each other _anyway_, I would think.

Good point. How about just changing the second error message?

>git tag hello v1.9.5

>git tag hello v1.9.5
fatal: tag 'hello' already exists

>git tag hello v2.0.0
fatal: tag 'hello' already exists but points at a different commit

```

## Junio C Hamano, 2025-06-10 14:51

Subject: Re: Suggestion: error "tag ... already exists" should distinguish between tagging different or same commit:
Message-ID: <xmqqzfefodje.fsf@gitster.g>
URL: https://gitlist.dev/e/xmqqzfefodje.fsf%40gitster.g
In-Reply-To: <CAGJzqskj803dUcEuV+P-yuWdT0tiaidb7h3YxQSCgYHWgBfaWA@mail.gmail.com>

```
M Hickford <mirth.hickford@gmail.com> writes:

>> Besides, in the above examples, is d4e6038a something the user
>> immediately recognises as the same as v1.9.5 or the object existing
>> v1.9.5 tag points at?  I somehow doubt it.  So after getting the
>> error, there needs some digging to figure out how v1.9.5 and
>> existing hello are related to each other _anyway_, I would think.
>
> Good point. How about just changing the second error message?
>
>>git tag hello v1.9.5
>
>>git tag hello v1.9.5
> fatal: tag 'hello' already exists
>
>>git tag hello v2.0.0
> fatal: tag 'hello' already exists but points at a different commit

Or simply something like this.  I am not convinced (yet) that this
is a good idea; I merely is showing that the implementation would
look like this.

----- >8 -----
Subject: tag: allow idempotent "git tag" without "--force"

When "git tag T O" is told to create a tag pointing at an object O
without the "--force" option, it refuses with "tag T already exists",
even when T points at O (which makes it a no-op).

Let's allow this "idempotent" case by special casing.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 builtin/tag.c  |  2 +-
 t/t7004-tag.sh | 12 +++++++++---
 2 files changed, 10 insertions(+), 4 deletions(-)

diff --git c/builtin/tag.c w/builtin/tag.c
index 4742b27d16..5380a46494 100644
--- c/builtin/tag.c
+++ w/builtin/tag.c
@@ -660,7 +660,7 @@ int cmd_tag(int argc,
 
 	if (refs_read_ref(get_main_ref_store(the_repository), ref.buf, &prev))
 		oidclr(&prev, the_repository->hash_algo);
-	else if (!force)
+	else if (!force && (create_tag_object || !oideq(&object, &prev)))
 		die(_("tag '%s' already exists"), tag);
 
 	opt.message_given = msg.given || msgfile;
diff --git c/t/t7004-tag.sh w/t/t7004-tag.sh
index 10835631ca..9a253a44a8 100755
--- c/t/t7004-tag.sh
+++ w/t/t7004-tag.sh
@@ -126,7 +126,7 @@ test_expect_success 'annotated tag with --create-reflog has correct message' '
 '
 
 test_expect_success '--create-reflog does not create reflog on failure' '
-	test_must_fail git tag --create-reflog mytag &&
+	test_must_fail git tag --create-reflog mytag no-such-object &&
 	test_must_fail git reflog exists refs/tags/mytag
 '
 
@@ -183,8 +183,14 @@ test_expect_success 'listing tags using a non-matching pattern should output not
 
 # special cases for creating tags:
 
-test_expect_success 'trying to create a tag with the name of one existing should fail' '
-	test_must_fail git tag mytag
+test_expect_success 'recreating a tag without --force' '
+	# light-weight tag pointing at the same thing
+	# now succeeds
+	git tag mytag HEAD &&
+	# light-weight tag pointing at a different thing
+	test_must_fail git tag mytag HEAD: &&
+	# creating annotated tag, pointing at the same object.
+	test_must_fail git tag -a -m anno mytag $taggedobject
 '
 
 test_expect_success 'trying to create a tag with a non-valid name should fail' '

```

## Junio C Hamano, 2025-07-07 22:24

Subject: Re: Suggestion: error "tag ... already exists" should distinguish between tagging different or same commit:
Message-ID: <xmqqfrf73ahu.fsf@gitster.g>
URL: https://gitlist.dev/e/xmqqfrf73ahu.fsf%40gitster.g
In-Reply-To: <xmqqzfefodje.fsf@gitster.g>

```
Junio C Hamano <gitster@pobox.com> writes:

> Or simply something like this.  I am not convinced (yet) that this
> is a good idea; I merely is showing that the implementation would
> look like this.
>
> ----- >8 -----
> Subject: tag: allow idempotent "git tag" without "--force"
>
> When "git tag T O" is told to create a tag pointing at an object O
> without the "--force" option, it refuses with "tag T already exists",
> even when T points at O (which makes it a no-op).
>
> Let's allow this "idempotent" case by special casing.
>
> Signed-off-by: Junio C Hamano <gitster@pobox.com>
> ---
>  builtin/tag.c  |  2 +-
>  t/t7004-tag.sh | 12 +++++++++---
>  2 files changed, 10 insertions(+), 4 deletions(-)

As I see nobody biting, I am inclined to say that this is not such a
brilliant idea.  Let's chuck it.

>
> diff --git c/builtin/tag.c w/builtin/tag.c
> index 4742b27d16..5380a46494 100644
> --- c/builtin/tag.c
> +++ w/builtin/tag.c
> @@ -660,7 +660,7 @@ int cmd_tag(int argc,
>  
>  	if (refs_read_ref(get_main_ref_store(the_repository), ref.buf, &prev))
>  		oidclr(&prev, the_repository->hash_algo);
> -	else if (!force)
> +	else if (!force && (create_tag_object || !oideq(&object, &prev)))
>  		die(_("tag '%s' already exists"), tag);
>  
>  	opt.message_given = msg.given || msgfile;
> diff --git c/t/t7004-tag.sh w/t/t7004-tag.sh
> index 10835631ca..9a253a44a8 100755
> --- c/t/t7004-tag.sh
> +++ w/t/t7004-tag.sh
> @@ -126,7 +126,7 @@ test_expect_success 'annotated tag with --create-reflog has correct message' '
>  '
>  
>  test_expect_success '--create-reflog does not create reflog on failure' '
> -	test_must_fail git tag --create-reflog mytag &&
> +	test_must_fail git tag --create-reflog mytag no-such-object &&
>  	test_must_fail git reflog exists refs/tags/mytag
>  '
>  
> @@ -183,8 +183,14 @@ test_expect_success 'listing tags using a non-matching pattern should output not
>  
>  # special cases for creating tags:
>  
> -test_expect_success 'trying to create a tag with the name of one existing should fail' '
> -	test_must_fail git tag mytag
> +test_expect_success 'recreating a tag without --force' '
> +	# light-weight tag pointing at the same thing
> +	# now succeeds
> +	git tag mytag HEAD &&
> +	# light-weight tag pointing at a different thing
> +	test_must_fail git tag mytag HEAD: &&
> +	# creating annotated tag, pointing at the same object.
> +	test_must_fail git tag -a -m anno mytag $taggedobject
>  '
>  
>  test_expect_success 'trying to create a tag with a non-valid name should fail' '

```

## rsbecker@nexbridge.com, 2025-07-07 23:12

Subject: RE: Suggestion: error "tag ... already exists" should distinguish between tagging different or same commit:
Message-ID: <00ca01dbef94$b155f380$1401da80$@nexbridge.com>
URL: https://gitlist.dev/e/00ca01dbef94%24b155f380%241401da80%24%40nexbridge.com
In-Reply-To: <xmqqfrf73ahu.fsf@gitster.g>

```
On July 7, 2025 6:24 PM, Junio C Hamano wrote:
>Junio C Hamano <gitster@pobox.com> writes:
>
>> Or simply something like this.  I am not convinced (yet) that this is
>> a good idea; I merely is showing that the implementation would look
>> like this.
>>
>> ----- >8 -----
>> Subject: tag: allow idempotent "git tag" without "--force"
>>
>> When "git tag T O" is told to create a tag pointing at an object O
>> without the "--force" option, it refuses with "tag T already exists",
>> even when T points at O (which makes it a no-op).
>>
>> Let's allow this "idempotent" case by special casing.
>>
>> Signed-off-by: Junio C Hamano <gitster@pobox.com>
>> ---
>>  builtin/tag.c  |  2 +-
>>  t/t7004-tag.sh | 12 +++++++++---
>>  2 files changed, 10 insertions(+), 4 deletions(-)
>
>As I see nobody biting, I am inclined to say that this is not such a
brilliant idea.  Let's
>chuck it.
>
>>
>> diff --git c/builtin/tag.c w/builtin/tag.c index
>> 4742b27d16..5380a46494 100644
>> --- c/builtin/tag.c
>> +++ w/builtin/tag.c
>> @@ -660,7 +660,7 @@ int cmd_tag(int argc,
>>
>>  	if (refs_read_ref(get_main_ref_store(the_repository), ref.buf,
&prev))
>>  		oidclr(&prev, the_repository->hash_algo);
>> -	else if (!force)
>> +	else if (!force && (create_tag_object || !oideq(&object, &prev)))
>>  		die(_("tag '%s' already exists"), tag);
>>
>>  	opt.message_given = msg.given || msgfile; diff --git
>> c/t/t7004-tag.sh w/t/t7004-tag.sh index 10835631ca..9a253a44a8 100755
>> --- c/t/t7004-tag.sh
>> +++ w/t/t7004-tag.sh
>> @@ -126,7 +126,7 @@ test_expect_success 'annotated tag with
--create-reflog
>has correct message' '
>>  '
>>
>>  test_expect_success '--create-reflog does not create reflog on failure'
'
>> -	test_must_fail git tag --create-reflog mytag &&
>> +	test_must_fail git tag --create-reflog mytag no-such-object &&
>>  	test_must_fail git reflog exists refs/tags/mytag  '
>>
>> @@ -183,8 +183,14 @@ test_expect_success 'listing tags using a
>> non-matching pattern should output not
>>
>>  # special cases for creating tags:
>>
>> -test_expect_success 'trying to create a tag with the name of one
existing should
>fail' '
>> -	test_must_fail git tag mytag
>> +test_expect_success 'recreating a tag without --force' '
>> +	# light-weight tag pointing at the same thing
>> +	# now succeeds
>> +	git tag mytag HEAD &&
>> +	# light-weight tag pointing at a different thing
>> +	test_must_fail git tag mytag HEAD: &&
>> +	# creating annotated tag, pointing at the same object.
>> +	test_must_fail git tag -a -m anno mytag $taggedobject
>>  '
>>
>>  test_expect_success 'trying to create a tag with a non-valid name should
fail' '

Considering that git tag T O will generally require a git push --force and
always a
git pull --force in order to update tags on the upstream and receiving an
update
to the tag locally, I think requiring git tag --force T O when O is
different from the
current tag is a reasonable idea from a consistency standpoint. I do support
the
notion of git tag T O not requiring a --force if O is already where the tag
is
pointing. The only counter case I can really see in this is when -s is used
to allow
the sign to be updated but even then, does --force really change anything
when
only signing (I think not) because O does not change. If O changes when
signing,
I think that --force is almost essential to avoid messing up the signatures.

--Randall


```

## Junio C Hamano, 2025-07-11 19:08

Subject: Re: Suggestion: error "tag ... already exists" should distinguish between tagging different or same commit:
Message-ID: <xmqq34b21r6h.fsf@gitster.g>
URL: https://gitlist.dev/e/xmqq34b21r6h.fsf%40gitster.g
In-Reply-To: <00ca01dbef94$b155f380$1401da80$@nexbridge.com>

```
<rsbecker@nexbridge.com> writes:

> Considering that git tag T O will generally require a git push
> --force and always a git pull --force in order to update tags on
> the upstream and receiving an update to the tag locally, I think
> requiring git tag --force T O when O is different from the current
> tag is a reasonable idea from a consistency standpoint. I do
> support the notion of git tag T O not requiring a --force if O is
> already where the tag is pointing.

Yup, that is essentially the idea behind that patch.

> The only counter case I can really see in this is when -s is used
> to allow the sign to be updated but even then, does --force really
> change anything when only signing (I think not) because O does not
> change.

In "git tag -s T O" (or "-a" for that matter), O may not change, but
the resulting tag object would certainly be different from the
object that is pointed at by the existing tag reference T, due to
tagger identity and the message in the tag being different from the
original.  So even without O changing ...

> If O changes when signing, I think that --force is almost
> essential to avoid messing up the signatures.

... we would require --force and that would be a good thing.

```

## Junio C Hamano, 2025-07-11 19:10

Subject: [PATCH] tag: allow idempotent "git tag" without "--force"
Message-ID: <xmqqv7nyzgp7.fsf@gitster.g>
URL: https://gitlist.dev/e/xmqqv7nyzgp7.fsf%40gitster.g
In-Reply-To: <xmqqzfefodje.fsf@gitster.g>

```
When "git tag T O" is told to create a tag pointing at an object O
without the "--force" option, it refuses with "tag T already exists",
even when T points at O (which makes it a no-op).

Let's allow this "idempotent" case by special casing and making it
truly a no-op.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
---

 * In thread https://lore.kernel.org/git/xmqqzfefodje.fsf@gitster.g/
   I had a slightly different version but I think the logic flow
   reads better in this version, even though they essentially do the
   same thing.

 builtin/tag.c  |  2 ++
 t/t7004-tag.sh | 12 +++++++++---
 2 files changed, 11 insertions(+), 3 deletions(-)

diff --git a/builtin/tag.c b/builtin/tag.c
index c4bd145831..1dd69b3447 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -647,6 +647,8 @@ int cmd_tag(int argc,
 
 	if (refs_read_ref(get_main_ref_store(the_repository), ref.buf, &prev))
 		oidclr(&prev, the_repository->hash_algo);
+	else if (!create_tag_object && oideq(&object, &prev))
+		exit(0);
 	else if (!force)
 		die(_("tag '%s' already exists"), tag);
 
diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh
index 10835631ca..9a253a44a8 100755
--- a/t/t7004-tag.sh
+++ b/t/t7004-tag.sh
@@ -126,7 +126,7 @@ test_expect_success 'annotated tag with --create-reflog has correct message' '
 '
 
 test_expect_success '--create-reflog does not create reflog on failure' '
-	test_must_fail git tag --create-reflog mytag &&
+	test_must_fail git tag --create-reflog mytag no-such-object &&
 	test_must_fail git reflog exists refs/tags/mytag
 '
 
@@ -183,8 +183,14 @@ test_expect_success 'listing tags using a non-matching pattern should output not
 
 # special cases for creating tags:
 
-test_expect_success 'trying to create a tag with the name of one existing should fail' '
-	test_must_fail git tag mytag
+test_expect_success 'recreating a tag without --force' '
+	# light-weight tag pointing at the same thing
+	# now succeeds
+	git tag mytag HEAD &&
+	# light-weight tag pointing at a different thing
+	test_must_fail git tag mytag HEAD: &&
+	# creating annotated tag, pointing at the same object.
+	test_must_fail git tag -a -m anno mytag $taggedobject
 '
 
 test_expect_success 'trying to create a tag with a non-valid name should fail' '
-- 
2.50.1-396-g5c2aadec13


```

## Justin Tobler, 2025-07-11 20:57

Subject: Re: [PATCH] tag: allow idempotent "git tag" without "--force"
Message-ID: <dt5ruadvr7lmhsbypmb6yili5cookfx5btw4gzfeui7ehxxajv@ziael4udbbcy>
URL: https://gitlist.dev/e/dt5ruadvr7lmhsbypmb6yili5cookfx5btw4gzfeui7ehxxajv%40ziael4udbbcy
In-Reply-To: <xmqqv7nyzgp7.fsf@gitster.g>

```
On 25/07/11 12:10PM, Junio C Hamano wrote:
> When "git tag T O" is told to create a tag pointing at an object O
> without the "--force" option, it refuses with "tag T already exists",
> even when T points at O (which makes it a no-op).
> 
> Let's allow this "idempotent" case by special casing and making it
> truly a no-op.

Not necessarily a strong argument against, but I could maybe see a user
only wanting to perform some followup operation if a tag is _actually_
created. For example push the newly created tag:

  git tag T O && git push --tags

To me atleast, the feedback of knowing whether tag was created seems a bit more
interesting. I also don't feel super strongly though.

-Justin

```

## Junio C Hamano, 2025-07-11 21:40

Subject: Re: [PATCH] tag: allow idempotent "git tag" without "--force"
Message-ID: <xmqqcya6z9r7.fsf@gitster.g>
URL: https://gitlist.dev/e/xmqqcya6z9r7.fsf%40gitster.g
In-Reply-To: <dt5ruadvr7lmhsbypmb6yili5cookfx5btw4gzfeui7ehxxajv@ziael4udbbcy>

```
Justin Tobler <jltobler@gmail.com> writes:

> For example push the newly created tag:
>
>   git tag T O && git push --tags

The above is not quite a scalable workflow and is not recommendable,
though.  What if you are publishing to more than one place, and/or
sometimes some of them are not reachable?  You want to push out your
tag not because you newly created it, but because you know some
remotes may not have it for whatever reason.  "I just created one"
is a crude approximate for the latter.  "Last time I created one, it
somehow failed to push out" (so I have to try again) needs to be
considered.

Having said that, ever since I invented "push --follow-tags", I
rarely push tags out just for the sake of pushing them out.  Only
when the real contents that matter are pushed out, tags that point
at them would follow.

> To me atleast, the feedback of knowing whether tag was created seems a bit more
> interesting. I also don't feel super strongly though.

I do not fell strongly one way or anothre, either.  Discarding the
topic is easier than keeping it for me, so let me mark it for trash
bin.

Thanks.

```
