{"thread":{"id":"63607","subject":"Suggestion: error \"tag ... already exists\" should distinguish between tagging different or same commit:","startedAt":"2025-06-09T07:01:45Z","lastAt":"2025-07-11T21:40:47Z","messageCount":14,"participants":["M Hickford","Junio C Hamano","Hilco Wijbenga","Andreas Schwab","rsbecker@nexbridge.com","Justin Tobler"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"519951","messageId":"CAGJzqsnvTnp3k8Ab2exaBAw5pszQRz00UcucnK=ECtY5vhG+1A@mail.gmail.com","threadId":"63607","inReplyTo":null,"subject":"Suggestion: error \"tag ... already exists\" should distinguish between tagging different or same commit:","fromName":"M Hickford","fromEmail":"mirth.hickford@gmail.com","sentAt":"2025-06-09T07:00:00Z","receivedAt":"2025-06-09T07:01:45Z","isPatch":false,"sender":{"key":"mirth.hickford@gmail.com","avatar":"https://avatars.githubusercontent.com/u/105314?v=4"},"body":"Hi. Presently, the error \"tag ... already exists\" doesn't distinguish\nbetween tagging the same commit or a different commit:\n\n     >git tag hello v1.9.5\n\n     >git tag hello v1.9.5\n     fatal: tag 'hello' already exists\n\n     >git tag hello v2.0.0\n     fatal: tag 'hello' already exists\n\nTo inform the user, it would be nice to distinguish these cases, perhaps:\n\n     >git tag hello v1.9.5\n     fatal: tag 'hello' already exists pointing at\nd4e6038a068d0aecd5ec28c83afbfc6d4903092f\n\n     >git tag hello v2.0.0\n     fatal: tag 'hello' already exists but points at\n18a07354e33f86c8349ffdc300d9087876658264\n\nThe second error is typically more concerning than the first.\n\nWhat do you think?\n"},{"id":"519992","messageId":"xmqqcybcrc2u.fsf@gitster.g","threadId":"63607","inReplyTo":"CAGJzqsnvTnp3k8Ab2exaBAw5pszQRz00UcucnK=ECtY5vhG+1A@mail.gmail.com","subject":"Re: Suggestion: error \"tag ... already exists\" should distinguish between tagging different or same commit:","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2025-06-09T18:42:33Z","receivedAt":"2025-06-09T18:42:35Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"M Hickford <mirth.hickford@gmail.com> writes:\n\n> Hi. Presently, the error \"tag ... already exists\" doesn't distinguish\n> between tagging the same commit or a different commit:\n>\n>      >git tag hello v1.9.5\n>\n>      >git tag hello v1.9.5\n>      fatal: tag 'hello' already exists\n>\n>      >git tag hello v2.0.0\n>      fatal: tag 'hello' already exists\n>\n> To inform the user, it would be nice to distinguish these cases, perhaps:\n>\n>      >git tag hello v1.9.5\n>      fatal: tag 'hello' already exists pointing at\n> d4e6038a068d0aecd5ec28c83afbfc6d4903092f\n>\n>      >git tag hello v2.0.0\n>      fatal: tag 'hello' already exists but points at\n> 18a07354e33f86c8349ffdc300d9087876658264\n>\n> The second error is typically more concerning than the first.\n>\n> What do you think?\n\nNot interested.  When the user gets that \"fatal\" message, the\nexisting tag did not get modified, so they can just do whatever\ncheck they want (like \"git range-diff v1.9.5...hello\") themselves.\n\nBesides, in the above examples, is d4e6038a something the user\nimmediately recognises as the same as v1.9.5 or the object existing\nv1.9.5 tag points at?  I somehow doubt it.  So after getting the\nerror, there needs some digging to figure out how v1.9.5 and\nexisting hello are related to each other _anyway_, I would think.\n\n\n"},{"id":"520000","messageId":"CAE1pOi34+btHyV8GbjpFPcJ+2ixu59ce4eAE=Q7F4JEcuJyXnw@mail.gmail.com","threadId":"63607","inReplyTo":"xmqqcybcrc2u.fsf@gitster.g","subject":"Re: Suggestion: error \"tag ... already exists\" should distinguish between tagging different or same commit:","fromName":"Hilco Wijbenga","fromEmail":"hilco.wijbenga@gmail.com","sentAt":"2025-06-09T19:37:41Z","receivedAt":"2025-06-09T19:37:54Z","isPatch":false,"sender":{"key":"hilco.wijbenga@gmail.com","avatar":null},"body":"Does it really make sense for that first example to fail, though? \"git\ntag hello v1.9.5\" is an idempotent operation, isn't it? The second\nattempt is a no-op?\n\nIf \"git tag ...\" simply does nothing if the tag already exists (as\nrequested) then that would make the OP's issue go away: only the 2nd\nexample would fail.\n\nOn Mon, Jun 9, 2025 at 11:45 AM Junio C Hamano <gitster@pobox.com> wrote:\n>\n> M Hickford <mirth.hickford@gmail.com> writes:\n>\n> > Hi. Presently, the error \"tag ... already exists\" doesn't distinguish\n> > between tagging the same commit or a different commit:\n> >\n> >      >git tag hello v1.9.5\n> >\n> >      >git tag hello v1.9.5\n> >      fatal: tag 'hello' already exists\n> >\n> >      >git tag hello v2.0.0\n> >      fatal: tag 'hello' already exists\n> >\n> > To inform the user, it would be nice to distinguish these cases, perhaps:\n> >\n> >      >git tag hello v1.9.5\n> >      fatal: tag 'hello' already exists pointing at\n> > d4e6038a068d0aecd5ec28c83afbfc6d4903092f\n> >\n> >      >git tag hello v2.0.0\n> >      fatal: tag 'hello' already exists but points at\n> > 18a07354e33f86c8349ffdc300d9087876658264\n> >\n> > The second error is typically more concerning than the first.\n> >\n> > What do you think?\n>\n> Not interested.  When the user gets that \"fatal\" message, the\n> existing tag did not get modified, so they can just do whatever\n> check they want (like \"git range-diff v1.9.5...hello\") themselves.\n>\n> Besides, in the above examples, is d4e6038a something the user\n> immediately recognises as the same as v1.9.5 or the object existing\n> v1.9.5 tag points at?  I somehow doubt it.  So after getting the\n> error, there needs some digging to figure out how v1.9.5 and\n> existing hello are related to each other _anyway_, I would think.\n>\n>\n>\n"},{"id":"520002","messageId":"87qzzsisdp.fsf@igel.home","threadId":"63607","inReplyTo":"CAE1pOi34+btHyV8GbjpFPcJ+2ixu59ce4eAE=Q7F4JEcuJyXnw@mail.gmail.com","subject":"Re: Suggestion: error \"tag ... already exists\" should distinguish between tagging different or same commit:","fromName":"Andreas Schwab","fromEmail":"schwab@linux-m68k.org","sentAt":"2025-06-09T20:15:14Z","receivedAt":"2025-06-09T20:15:33Z","isPatch":false,"sender":{"key":"schwab@linux-m68k.org","avatar":"https://avatars.githubusercontent.com/u/2175493?v=4"},"body":"On Jun 09 2025, Hilco Wijbenga wrote:\n\n> Does it really make sense for that first example to fail, though? \"git\n> tag hello v1.9.5\" is an idempotent operation, isn't it? The second\n> attempt is a no-op?\n\nThat's not true if an annotated tag is replaced by a lightweight tag.\n\n-- \nAndreas Schwab, schwab@linux-m68k.org\nGPG Key fingerprint = 7578 EB47 D4E5 4D69 2510  2552 DF73 E780 A9DA AEC1\n\"And now for something completely different.\"\n"},{"id":"520003","messageId":"xmqqqzzspt0i.fsf@gitster.g","threadId":"63607","inReplyTo":"CAE1pOi34+btHyV8GbjpFPcJ+2ixu59ce4eAE=Q7F4JEcuJyXnw@mail.gmail.com","subject":"Re: Suggestion: error \"tag ... already exists\" should distinguish between tagging different or same commit:","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2025-06-09T20:19:41Z","receivedAt":"2025-06-09T20:19:44Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Hilco Wijbenga <hilco.wijbenga@gmail.com> writes:\n\n> Does it really make sense for that first example to fail, though? \"git\n> tag hello v1.9.5\" is an idempotent operation, isn't it? The second\n> attempt is a no-op?\n>\n> If \"git tag ...\" simply does nothing if the tag already exists (as\n> requested) then that would make the OP's issue go away: only the 2nd\n> example would fail.\n\nI do not think I personally mind that direction; when I responded, I\nthought that in the example, 'hello' is initially pointing at\nsomething entirely different (perhaps v2.0.0), though.\n\nBut it may be tricky to do, though.\n\nIt is easy for lightweight tags, but you'd have to fail an attempt\nto add an annotated and/or signed tag without -f anyway, so you have\nto be prepared to answer \"why does this behave differently with and\nwithout -a/-s?\".\n"},{"id":"520017","messageId":"CAE1pOi0bFpuGuFSEHDUgv3mcwwwgXAEn8q3QSwF33ucqFWJ_AQ@mail.gmail.com","threadId":"63607","inReplyTo":"xmqqqzzspt0i.fsf@gitster.g","subject":"Re: Suggestion: error \"tag ... already exists\" should distinguish between tagging different or same commit:","fromName":"Hilco Wijbenga","fromEmail":"hilco.wijbenga@gmail.com","sentAt":"2025-06-09T21:03:02Z","receivedAt":"2025-06-09T21:03:18Z","isPatch":false,"sender":{"key":"hilco.wijbenga@gmail.com","avatar":null},"body":"Clearly, I have not used everything that \"git tag\" offers. :-)\n\nSo, to clarify, I was thinking (naively?) that Git would check that\nthe tag as requested is _exactly_ the same as the existing tag. Only\n_that_ specific scenario would then not fail.\n\nOn Mon, Jun 9, 2025 at 1:19 PM Junio C Hamano <gitster@pobox.com> wrote:\n>\n> Hilco Wijbenga <hilco.wijbenga@gmail.com> writes:\n>\n> > Does it really make sense for that first example to fail, though? \"git\n> > tag hello v1.9.5\" is an idempotent operation, isn't it? The second\n> > attempt is a no-op?\n> >\n> > If \"git tag ...\" simply does nothing if the tag already exists (as\n> > requested) then that would make the OP's issue go away: only the 2nd\n> > example would fail.\n>\n> I do not think I personally mind that direction; when I responded, I\n> thought that in the example, 'hello' is initially pointing at\n> something entirely different (perhaps v2.0.0), though.\n>\n> But it may be tricky to do, though.\n>\n> It is easy for lightweight tags, but you'd have to fail an attempt\n> to add an annotated and/or signed tag without -f anyway, so you have\n> to be prepared to answer \"why does this behave differently with and\n> without -a/-s?\".\n"},{"id":"520026","messageId":"CAGJzqskj803dUcEuV+P-yuWdT0tiaidb7h3YxQSCgYHWgBfaWA@mail.gmail.com","threadId":"63607","inReplyTo":"xmqqcybcrc2u.fsf@gitster.g","subject":"Re: Suggestion: error \"tag ... already exists\" should distinguish between tagging different or same commit:","fromName":"M Hickford","fromEmail":"mirth.hickford@gmail.com","sentAt":"2025-06-10T07:00:00Z","receivedAt":"2025-06-10T07:01:10Z","isPatch":false,"sender":{"key":"mirth.hickford@gmail.com","avatar":"https://avatars.githubusercontent.com/u/105314?v=4"},"body":"On Mon, 9 Jun 2025 at 19:42, Junio C Hamano <gitster@pobox.com> wrote:\n>\n> M Hickford <mirth.hickford@gmail.com> writes:\n>\n> > Hi. Presently, the error \"tag ... already exists\" doesn't distinguish\n> > between tagging the same commit or a different commit:\n> >\n> >      >git tag hello v1.9.5\n> >\n> >      >git tag hello v1.9.5\n> >      fatal: tag 'hello' already exists\n> >\n> >      >git tag hello v2.0.0\n> >      fatal: tag 'hello' already exists\n> >\n> > To inform the user, it would be nice to distinguish these cases, perhaps:\n> >\n> >      >git tag hello v1.9.5\n> >      fatal: tag 'hello' already exists pointing at\n> > d4e6038a068d0aecd5ec28c83afbfc6d4903092f\n> >\n> >      >git tag hello v2.0.0\n> >      fatal: tag 'hello' already exists but points at\n> > 18a07354e33f86c8349ffdc300d9087876658264\n> >\n> > The second error is typically more concerning than the first.\n> >\n> > What do you think?\n>\n> Not interested.  When the user gets that \"fatal\" message, the\n> existing tag did not get modified, so they can just do whatever\n> check they want (like \"git range-diff v1.9.5...hello\") themselves.\n>\n> Besides, in the above examples, is d4e6038a something the user\n> immediately recognises as the same as v1.9.5 or the object existing\n> v1.9.5 tag points at?  I somehow doubt it.  So after getting the\n> error, there needs some digging to figure out how v1.9.5 and\n> existing hello are related to each other _anyway_, I would think.\n\nGood point. How about just changing the second error message?\n\n>git tag hello v1.9.5\n\n>git tag hello v1.9.5\nfatal: tag 'hello' already exists\n\n>git tag hello v2.0.0\nfatal: tag 'hello' already exists but points at a different commit\n"},{"id":"520042","messageId":"xmqqzfefodje.fsf@gitster.g","threadId":"63607","inReplyTo":"CAGJzqskj803dUcEuV+P-yuWdT0tiaidb7h3YxQSCgYHWgBfaWA@mail.gmail.com","subject":"Re: Suggestion: error \"tag ... already exists\" should distinguish between tagging different or same commit:","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2025-06-10T14:51:33Z","receivedAt":"2025-06-10T14:51:35Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"M Hickford <mirth.hickford@gmail.com> writes:\n\n>> Besides, in the above examples, is d4e6038a something the user\n>> immediately recognises as the same as v1.9.5 or the object existing\n>> v1.9.5 tag points at?  I somehow doubt it.  So after getting the\n>> error, there needs some digging to figure out how v1.9.5 and\n>> existing hello are related to each other _anyway_, I would think.\n>\n> Good point. How about just changing the second error message?\n>\n>>git tag hello v1.9.5\n>\n>>git tag hello v1.9.5\n> fatal: tag 'hello' already exists\n>\n>>git tag hello v2.0.0\n> fatal: tag 'hello' already exists but points at a different commit\n\nOr simply something like this.  I am not convinced (yet) that this\nis a good idea; I merely is showing that the implementation would\nlook like this.\n\n----- >8 -----\nSubject: tag: allow idempotent \"git tag\" without \"--force\"\n\nWhen \"git tag T O\" is told to create a tag pointing at an object O\nwithout the \"--force\" option, it refuses with \"tag T already exists\",\neven when T points at O (which makes it a no-op).\n\nLet's allow this \"idempotent\" case by special casing.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/tag.c  |  2 +-\n t/t7004-tag.sh | 12 +++++++++---\n 2 files changed, 10 insertions(+), 4 deletions(-)\n\ndiff --git c/builtin/tag.c w/builtin/tag.c\nindex 4742b27d16..5380a46494 100644\n--- c/builtin/tag.c\n+++ w/builtin/tag.c\n@@ -660,7 +660,7 @@ int cmd_tag(int argc,\n \n \tif (refs_read_ref(get_main_ref_store(the_repository), ref.buf, &prev))\n \t\toidclr(&prev, the_repository->hash_algo);\n-\telse if (!force)\n+\telse if (!force && (create_tag_object || !oideq(&object, &prev)))\n \t\tdie(_(\"tag '%s' already exists\"), tag);\n \n \topt.message_given = msg.given || msgfile;\ndiff --git c/t/t7004-tag.sh w/t/t7004-tag.sh\nindex 10835631ca..9a253a44a8 100755\n--- c/t/t7004-tag.sh\n+++ w/t/t7004-tag.sh\n@@ -126,7 +126,7 @@ test_expect_success 'annotated tag with --create-reflog has correct message' '\n '\n \n test_expect_success '--create-reflog does not create reflog on failure' '\n-\ttest_must_fail git tag --create-reflog mytag &&\n+\ttest_must_fail git tag --create-reflog mytag no-such-object &&\n \ttest_must_fail git reflog exists refs/tags/mytag\n '\n \n@@ -183,8 +183,14 @@ test_expect_success 'listing tags using a non-matching pattern should output not\n \n # special cases for creating tags:\n \n-test_expect_success 'trying to create a tag with the name of one existing should fail' '\n-\ttest_must_fail git tag mytag\n+test_expect_success 'recreating a tag without --force' '\n+\t# light-weight tag pointing at the same thing\n+\t# now succeeds\n+\tgit tag mytag HEAD &&\n+\t# light-weight tag pointing at a different thing\n+\ttest_must_fail git tag mytag HEAD: &&\n+\t# creating annotated tag, pointing at the same object.\n+\ttest_must_fail git tag -a -m anno mytag $taggedobject\n '\n \n test_expect_success 'trying to create a tag with a non-valid name should fail' '\n"},{"id":"521478","messageId":"xmqqfrf73ahu.fsf@gitster.g","threadId":"63607","inReplyTo":"xmqqzfefodje.fsf@gitster.g","subject":"Re: Suggestion: error \"tag ... already exists\" should distinguish between tagging different or same commit:","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2025-07-07T22:24:29Z","receivedAt":"2025-07-07T22:24:31Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Or simply something like this.  I am not convinced (yet) that this\n> is a good idea; I merely is showing that the implementation would\n> look like this.\n>\n> ----- >8 -----\n> Subject: tag: allow idempotent \"git tag\" without \"--force\"\n>\n> When \"git tag T O\" is told to create a tag pointing at an object O\n> without the \"--force\" option, it refuses with \"tag T already exists\",\n> even when T points at O (which makes it a no-op).\n>\n> Let's allow this \"idempotent\" case by special casing.\n>\n> Signed-off-by: Junio C Hamano <gitster@pobox.com>\n> ---\n>  builtin/tag.c  |  2 +-\n>  t/t7004-tag.sh | 12 +++++++++---\n>  2 files changed, 10 insertions(+), 4 deletions(-)\n\nAs I see nobody biting, I am inclined to say that this is not such a\nbrilliant idea.  Let's chuck it.\n\n>\n> diff --git c/builtin/tag.c w/builtin/tag.c\n> index 4742b27d16..5380a46494 100644\n> --- c/builtin/tag.c\n> +++ w/builtin/tag.c\n> @@ -660,7 +660,7 @@ int cmd_tag(int argc,\n>  \n>  \tif (refs_read_ref(get_main_ref_store(the_repository), ref.buf, &prev))\n>  \t\toidclr(&prev, the_repository->hash_algo);\n> -\telse if (!force)\n> +\telse if (!force && (create_tag_object || !oideq(&object, &prev)))\n>  \t\tdie(_(\"tag '%s' already exists\"), tag);\n>  \n>  \topt.message_given = msg.given || msgfile;\n> diff --git c/t/t7004-tag.sh w/t/t7004-tag.sh\n> index 10835631ca..9a253a44a8 100755\n> --- c/t/t7004-tag.sh\n> +++ w/t/t7004-tag.sh\n> @@ -126,7 +126,7 @@ test_expect_success 'annotated tag with --create-reflog has correct message' '\n>  '\n>  \n>  test_expect_success '--create-reflog does not create reflog on failure' '\n> -\ttest_must_fail git tag --create-reflog mytag &&\n> +\ttest_must_fail git tag --create-reflog mytag no-such-object &&\n>  \ttest_must_fail git reflog exists refs/tags/mytag\n>  '\n>  \n> @@ -183,8 +183,14 @@ test_expect_success 'listing tags using a non-matching pattern should output not\n>  \n>  # special cases for creating tags:\n>  \n> -test_expect_success 'trying to create a tag with the name of one existing should fail' '\n> -\ttest_must_fail git tag mytag\n> +test_expect_success 'recreating a tag without --force' '\n> +\t# light-weight tag pointing at the same thing\n> +\t# now succeeds\n> +\tgit tag mytag HEAD &&\n> +\t# light-weight tag pointing at a different thing\n> +\ttest_must_fail git tag mytag HEAD: &&\n> +\t# creating annotated tag, pointing at the same object.\n> +\ttest_must_fail git tag -a -m anno mytag $taggedobject\n>  '\n>  \n>  test_expect_success 'trying to create a tag with a non-valid name should fail' '\n"},{"id":"521485","messageId":"00ca01dbef94$b155f380$1401da80$@nexbridge.com","threadId":"63607","inReplyTo":"xmqqfrf73ahu.fsf@gitster.g","subject":"RE: Suggestion: error \"tag ... already exists\" should distinguish between tagging different or same commit:","fromName":"","fromEmail":"rsbecker@nexbridge.com","sentAt":"2025-07-07T23:12:58Z","receivedAt":"2025-07-07T23:13:55Z","isPatch":false,"sender":{"key":"randall.becker@nexbridge.ca","avatar":"https://avatars.githubusercontent.com/u/28956764?v=4"},"body":"On July 7, 2025 6:24 PM, Junio C Hamano wrote:\n>Junio C Hamano <gitster@pobox.com> writes:\n>\n>> Or simply something like this.  I am not convinced (yet) that this is\n>> a good idea; I merely is showing that the implementation would look\n>> like this.\n>>\n>> ----- >8 -----\n>> Subject: tag: allow idempotent \"git tag\" without \"--force\"\n>>\n>> When \"git tag T O\" is told to create a tag pointing at an object O\n>> without the \"--force\" option, it refuses with \"tag T already exists\",\n>> even when T points at O (which makes it a no-op).\n>>\n>> Let's allow this \"idempotent\" case by special casing.\n>>\n>> Signed-off-by: Junio C Hamano <gitster@pobox.com>\n>> ---\n>>  builtin/tag.c  |  2 +-\n>>  t/t7004-tag.sh | 12 +++++++++---\n>>  2 files changed, 10 insertions(+), 4 deletions(-)\n>\n>As I see nobody biting, I am inclined to say that this is not such a\nbrilliant idea.  Let's\n>chuck it.\n>\n>>\n>> diff --git c/builtin/tag.c w/builtin/tag.c index\n>> 4742b27d16..5380a46494 100644\n>> --- c/builtin/tag.c\n>> +++ w/builtin/tag.c\n>> @@ -660,7 +660,7 @@ int cmd_tag(int argc,\n>>\n>>  \tif (refs_read_ref(get_main_ref_store(the_repository), ref.buf,\n&prev))\n>>  \t\toidclr(&prev, the_repository->hash_algo);\n>> -\telse if (!force)\n>> +\telse if (!force && (create_tag_object || !oideq(&object, &prev)))\n>>  \t\tdie(_(\"tag '%s' already exists\"), tag);\n>>\n>>  \topt.message_given = msg.given || msgfile; diff --git\n>> c/t/t7004-tag.sh w/t/t7004-tag.sh index 10835631ca..9a253a44a8 100755\n>> --- c/t/t7004-tag.sh\n>> +++ w/t/t7004-tag.sh\n>> @@ -126,7 +126,7 @@ test_expect_success 'annotated tag with\n--create-reflog\n>has correct message' '\n>>  '\n>>\n>>  test_expect_success '--create-reflog does not create reflog on failure'\n'\n>> -\ttest_must_fail git tag --create-reflog mytag &&\n>> +\ttest_must_fail git tag --create-reflog mytag no-such-object &&\n>>  \ttest_must_fail git reflog exists refs/tags/mytag  '\n>>\n>> @@ -183,8 +183,14 @@ test_expect_success 'listing tags using a\n>> non-matching pattern should output not\n>>\n>>  # special cases for creating tags:\n>>\n>> -test_expect_success 'trying to create a tag with the name of one\nexisting should\n>fail' '\n>> -\ttest_must_fail git tag mytag\n>> +test_expect_success 'recreating a tag without --force' '\n>> +\t# light-weight tag pointing at the same thing\n>> +\t# now succeeds\n>> +\tgit tag mytag HEAD &&\n>> +\t# light-weight tag pointing at a different thing\n>> +\ttest_must_fail git tag mytag HEAD: &&\n>> +\t# creating annotated tag, pointing at the same object.\n>> +\ttest_must_fail git tag -a -m anno mytag $taggedobject\n>>  '\n>>\n>>  test_expect_success 'trying to create a tag with a non-valid name should\nfail' '\n\nConsidering that git tag T O will generally require a git push --force and\nalways a\ngit pull --force in order to update tags on the upstream and receiving an\nupdate\nto the tag locally, I think requiring git tag --force T O when O is\ndifferent from the\ncurrent tag is a reasonable idea from a consistency standpoint. I do support\nthe\nnotion of git tag T O not requiring a --force if O is already where the tag\nis\npointing. The only counter case I can really see in this is when -s is used\nto allow\nthe sign to be updated but even then, does --force really change anything\nwhen\nonly signing (I think not) because O does not change. If O changes when\nsigning,\nI think that --force is almost essential to avoid messing up the signatures.\n\n--Randall\n\n"},{"id":"521841","messageId":"xmqq34b21r6h.fsf@gitster.g","threadId":"63607","inReplyTo":"00ca01dbef94$b155f380$1401da80$@nexbridge.com","subject":"Re: Suggestion: error \"tag ... already exists\" should distinguish between tagging different or same commit:","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2025-07-11T19:08:22Z","receivedAt":"2025-07-11T19:08:24Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"<rsbecker@nexbridge.com> writes:\n\n> Considering that git tag T O will generally require a git push\n> --force and always a git pull --force in order to update tags on\n> the upstream and receiving an update to the tag locally, I think\n> requiring git tag --force T O when O is different from the current\n> tag is a reasonable idea from a consistency standpoint. I do\n> support the notion of git tag T O not requiring a --force if O is\n> already where the tag is pointing.\n\nYup, that is essentially the idea behind that patch.\n\n> The only counter case I can really see in this is when -s is used\n> to allow the sign to be updated but even then, does --force really\n> change anything when only signing (I think not) because O does not\n> change.\n\nIn \"git tag -s T O\" (or \"-a\" for that matter), O may not change, but\nthe resulting tag object would certainly be different from the\nobject that is pointed at by the existing tag reference T, due to\ntagger identity and the message in the tag being different from the\noriginal.  So even without O changing ...\n\n> If O changes when signing, I think that --force is almost\n> essential to avoid messing up the signatures.\n\n... we would require --force and that would be a good thing.\n"},{"id":"521842","messageId":"xmqqv7nyzgp7.fsf@gitster.g","threadId":"63607","inReplyTo":"xmqqzfefodje.fsf@gitster.g","subject":"[PATCH] tag: allow idempotent \"git tag\" without \"--force\"","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2025-07-11T19:10:44Z","receivedAt":"2025-07-11T19:10:46Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"When \"git tag T O\" is told to create a tag pointing at an object O\nwithout the \"--force\" option, it refuses with \"tag T already exists\",\neven when T points at O (which makes it a no-op).\n\nLet's allow this \"idempotent\" case by special casing and making it\ntruly a no-op.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n\n * In thread https://lore.kernel.org/git/xmqqzfefodje.fsf@gitster.g/\n   I had a slightly different version but I think the logic flow\n   reads better in this version, even though they essentially do the\n   same thing.\n\n builtin/tag.c  |  2 ++\n t/t7004-tag.sh | 12 +++++++++---\n 2 files changed, 11 insertions(+), 3 deletions(-)\n\ndiff --git a/builtin/tag.c b/builtin/tag.c\nindex c4bd145831..1dd69b3447 100644\n--- a/builtin/tag.c\n+++ b/builtin/tag.c\n@@ -647,6 +647,8 @@ int cmd_tag(int argc,\n \n \tif (refs_read_ref(get_main_ref_store(the_repository), ref.buf, &prev))\n \t\toidclr(&prev, the_repository->hash_algo);\n+\telse if (!create_tag_object && oideq(&object, &prev))\n+\t\texit(0);\n \telse if (!force)\n \t\tdie(_(\"tag '%s' already exists\"), tag);\n \ndiff --git a/t/t7004-tag.sh b/t/t7004-tag.sh\nindex 10835631ca..9a253a44a8 100755\n--- a/t/t7004-tag.sh\n+++ b/t/t7004-tag.sh\n@@ -126,7 +126,7 @@ test_expect_success 'annotated tag with --create-reflog has correct message' '\n '\n \n test_expect_success '--create-reflog does not create reflog on failure' '\n-\ttest_must_fail git tag --create-reflog mytag &&\n+\ttest_must_fail git tag --create-reflog mytag no-such-object &&\n \ttest_must_fail git reflog exists refs/tags/mytag\n '\n \n@@ -183,8 +183,14 @@ test_expect_success 'listing tags using a non-matching pattern should output not\n \n # special cases for creating tags:\n \n-test_expect_success 'trying to create a tag with the name of one existing should fail' '\n-\ttest_must_fail git tag mytag\n+test_expect_success 'recreating a tag without --force' '\n+\t# light-weight tag pointing at the same thing\n+\t# now succeeds\n+\tgit tag mytag HEAD &&\n+\t# light-weight tag pointing at a different thing\n+\ttest_must_fail git tag mytag HEAD: &&\n+\t# creating annotated tag, pointing at the same object.\n+\ttest_must_fail git tag -a -m anno mytag $taggedobject\n '\n \n test_expect_success 'trying to create a tag with a non-valid name should fail' '\n-- \n2.50.1-396-g5c2aadec13\n\n"},{"id":"521848","messageId":"dt5ruadvr7lmhsbypmb6yili5cookfx5btw4gzfeui7ehxxajv@ziael4udbbcy","threadId":"63607","inReplyTo":"xmqqv7nyzgp7.fsf@gitster.g","subject":"Re: [PATCH] tag: allow idempotent \"git tag\" without \"--force\"","fromName":"Justin Tobler","fromEmail":"jltobler@gmail.com","sentAt":"2025-07-11T20:57:00Z","receivedAt":"2025-07-11T21:02:39Z","isPatch":true,"sender":{"key":"jltobler@gmail.com","avatar":"https://avatars.githubusercontent.com/u/53454972?v=4"},"body":"On 25/07/11 12:10PM, Junio C Hamano wrote:\n> When \"git tag T O\" is told to create a tag pointing at an object O\n> without the \"--force\" option, it refuses with \"tag T already exists\",\n> even when T points at O (which makes it a no-op).\n> \n> Let's allow this \"idempotent\" case by special casing and making it\n> truly a no-op.\n\nNot necessarily a strong argument against, but I could maybe see a user\nonly wanting to perform some followup operation if a tag is _actually_\ncreated. For example push the newly created tag:\n\n  git tag T O && git push --tags\n\nTo me atleast, the feedback of knowing whether tag was created seems a bit more\ninteresting. I also don't feel super strongly though.\n\n-Justin\n"},{"id":"521851","messageId":"xmqqcya6z9r7.fsf@gitster.g","threadId":"63607","inReplyTo":"dt5ruadvr7lmhsbypmb6yili5cookfx5btw4gzfeui7ehxxajv@ziael4udbbcy","subject":"Re: [PATCH] tag: allow idempotent \"git tag\" without \"--force\"","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2025-07-11T21:40:44Z","receivedAt":"2025-07-11T21:40:47Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Justin Tobler <jltobler@gmail.com> writes:\n\n> For example push the newly created tag:\n>\n>   git tag T O && git push --tags\n\nThe above is not quite a scalable workflow and is not recommendable,\nthough.  What if you are publishing to more than one place, and/or\nsometimes some of them are not reachable?  You want to push out your\ntag not because you newly created it, but because you know some\nremotes may not have it for whatever reason.  \"I just created one\"\nis a crude approximate for the latter.  \"Last time I created one, it\nsomehow failed to push out\" (so I have to try again) needs to be\nconsidered.\n\nHaving said that, ever since I invented \"push --follow-tags\", I\nrarely push tags out just for the sake of pushing them out.  Only\nwhen the real contents that matter are pushed out, tags that point\nat them would follow.\n\n> To me atleast, the feedback of knowing whether tag was created seems a bit more\n> interesting. I also don't feel super strongly though.\n\nI do not fell strongly one way or anothre, either.  Discarding the\ntopic is easier than keeping it for me, so let me mark it for trash\nbin.\n\nThanks.\n"}]}