{"thread":{"id":"21543","subject":"[PATCH RFC] builtin-push: add --delete as syntactic sugar for :foo","startedAt":"2009-11-09T12:09:35Z","lastAt":"2009-12-30T19:57:42Z","messageCount":11,"participants":["Jan Krüger","Junio C Hamano","Sverre Rabbelier","Nanako Shiraishi"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"127136","messageId":"20091109130935.2bea7771@perceptron","threadId":"21543","inReplyTo":null,"subject":"[PATCH RFC] builtin-push: add --delete as syntactic sugar for :foo","fromName":"Jan Krüger","fromEmail":"jk@jk.gs","sentAt":"2009-11-09T12:09:35Z","receivedAt":"2009-11-09T12:09:35Z","isPatch":true,"sender":{"key":"jk@jk.gs","avatar":"https://avatars.githubusercontent.com/u/1774?v=4"},"body":"Refspecs without a source side have been reported as confusing by many.\nAs an alternative, this adds support for commands like:\n\n    git push origin --delete somebranch\n\nSpecifically, --delete will prepend a colon to all colon-less refspecs\ngiven on the command line.\n\nSigned-off-by: Jan Krüger <jk@jk.gs>\n---\nSince I consider this extension pure syntactic sugar, it doesn't change\nthe underlying transport code. As such it's a relatively non-invasive\nchange.\n\nOne might imagine a different implementation that supports combining\n--delete with --all and/or --tags, but perhaps it's better if people\nare forced to do that kind of thing manually.\n\n builtin-push.c        |   15 +++++++++++++++\n t/t5516-fetch-push.sh |    6 ++++++\n 2 files changed, 21 insertions(+), 0 deletions(-)\n\ndiff --git a/builtin-push.c b/builtin-push.c\nindex 8631c06..4ae9166 100644\n--- a/builtin-push.c\n+++ b/builtin-push.c\n@@ -15,6 +15,7 @@ static const char * const push_usage[] = {\n };\n \n static int thin;\n+static int deleterefs;\n static const char *receivepack;\n \n static const char **refspec;\n@@ -44,6 +45,14 @@ static void set_refspecs(const char **refs, int nr)\n \t\t\tstrcat(tag, refs[i]);\n \t\t\tref = tag;\n \t\t}\n+\t\tif (deleterefs && !strchr(ref, ':')) {\n+\t\t\tchar *delref;\n+\t\t\tint len = strlen(refs[i] + 1);\n+\t\t\tdelref = xmalloc(len);\n+\t\t\tstrcpy(delref, \":\");\n+\t\t\tstrcat(delref, refs[i]);\n+\t\t\tref = delref;\n+\t\t}\n \t\tadd_refspec(ref);\n \t}\n }\n@@ -181,6 +190,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)\n \t\tOPT_BIT( 0 , \"all\", &flags, \"push all refs\", TRANSPORT_PUSH_ALL),\n \t\tOPT_BIT( 0 , \"mirror\", &flags, \"mirror all refs\",\n \t\t\t    (TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE)),\n+\t\tOPT_BOOLEAN( 0, \"delete\", &deleterefs, \"delete refs\"),\n \t\tOPT_BOOLEAN( 0 , \"tags\", &tags, \"push tags (can't be used with --all or --mirror)\"),\n \t\tOPT_BIT('n' , \"dry-run\", &flags, \"dry run\", TRANSPORT_PUSH_DRY_RUN),\n \t\tOPT_BIT( 0,  \"porcelain\", &flags, \"machine-readable output\", TRANSPORT_PUSH_PORCELAIN),\n@@ -193,6 +203,11 @@ int cmd_push(int argc, const char **argv, const char *prefix)\n \n \targc = parse_options(argc, argv, prefix, options, push_usage, 0);\n \n+\tif (deleterefs && (tags || (flags & (TRANSPORT_PUSH_ALL | TRANSPORT_PUSH_MIRROR))))\n+\t\tdie(\"--delete is incompatible with --all, --mirror and --tags\");\n+\tif (deleterefs && argc < 2)\n+\t\tdie(\"--delete doesn't make sense without any refs\");\n+\n \tif (tags)\n \t\tadd_refspec(\"refs/tags/*\");\n \ndiff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh\nindex 6889a53..aa1450a 100755\n--- a/t/t5516-fetch-push.sh\n+++ b/t/t5516-fetch-push.sh\n@@ -546,6 +546,12 @@ test_expect_success 'allow deleting an invalid remote ref' '\n \n '\n \n+test_expect_success 'allow deleting a ref using --delete' '\n+\tmk_test heads/master &&\n+\tgit push testrepo --delete master &&\n+\t(cd testrepo && test_must_fail git rev-parse --verify refs/heads/master)\n+'\n+\n test_expect_success 'warn on push to HEAD of non-bare repository' '\n \tmk_test heads/master\n \t(cd testrepo &&\n-- \n1.6.5.2.155.gbb47.dirty\n"},{"id":"127173","messageId":"7v8wefy6pi.fsf@alter.siamese.dyndns.org","threadId":"21543","inReplyTo":"20091109130935.2bea7771@perceptron","subject":"Re: [PATCH RFC] builtin-push: add --delete as syntactic sugar for :foo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-11-09T16:59:53Z","receivedAt":"2009-11-09T16:59:53Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jan Krüger <jk@jk.gs> writes:\n\n> Refspecs without a source side have been reported as confusing by many.\n> As an alternative, this adds support for commands like:\n>\n>     git push origin --delete somebranch\n>\n> Specifically, --delete will prepend a colon to all colon-less refspecs\n> given on the command line.\n\nWill it barf and error out if there is any colon-ful one?  I think it\nshould.  I was about to write \"I guess it could be argued both ways\", but\nafter thinking about it for 5 seconds I do not see a sane way to explain a\ncommand line \"push origin --delete one two:three\".\n\nI agree with you that it wouldn't make sense to mix this with --all and\nfriends.\n"},{"id":"127174","messageId":"7vr5s7wrpw.fsf@alter.siamese.dyndns.org","threadId":"21543","inReplyTo":"7v8wefy6pi.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH RFC] builtin-push: add --delete as syntactic sugar for :foo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-11-09T17:08:59Z","receivedAt":"2009-11-09T17:08:59Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Will it barf and error out if there is any colon-ful one?  I think it\n> should.  I was about to write \"I guess it could be argued both ways\", but\n> after thinking about it for 5 seconds I do not see a sane way to explain a\n> command line \"push origin --delete one two:three\".\n\nActually the one I had in mind was\n\n\tgit push origin --delete one two:three four\n\nIf it were\n\n\tgit push origin --tags --delete=one --delete=four two:three\n\nit would be perfectly understandable, though.\n\nNo, I am not saying that we should make --delete take a parameter, allow\nmultiple of them, and make them compatible with --tags.  At least not yet.\n"},{"id":"127176","messageId":"fabb9a1e0911090920y70ca37a6h85cb38e97976bb59@mail.gmail.com","threadId":"21543","inReplyTo":"7v8wefy6pi.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH RFC] builtin-push: add --delete as syntactic sugar for :foo","fromName":"Sverre Rabbelier","fromEmail":"srabbelier@gmail.com","sentAt":"2009-11-09T17:20:09Z","receivedAt":"2009-11-09T17:20:09Z","isPatch":true,"sender":{"key":"srabbelier@gmail.com","avatar":"https://avatars.githubusercontent.com/u/3098?v=4"},"body":"Heya,\n\nOn Mon, Nov 9, 2009 at 17:59, Junio C Hamano <gitster@pobox.com> wrote:\n> Jan Krüger <jk@jk.gs> writes:\n>> Specifically, --delete will prepend a colon to all colon-less refspecs\n>> given on the command line.\n>\n> Will it barf and error out if there is any colon-ful one?  I think it\n> should.  I was about to write \"I guess it could be argued both ways\", but\n> after thinking about it for 5 seconds I do not see a sane way to explain a\n> command line \"push origin --delete one two:three\".\n\nDid we not have this discussion not 3 months ago and decided it was a bad idea?\n\n  http://thread.gmane.org/gmane.comp.version-control.git/125894\n\n-- \nCheers,\n\nSverre Rabbelier\n"},{"id":"127180","messageId":"20091109192044.605e50ba@perceptron","threadId":"21543","inReplyTo":"7v8wefy6pi.fsf@alter.siamese.dyndns.org","subject":"[PATCH RFC v2] builtin-push: add --delete as syntactic sugar for :foo","fromName":"Jan Krüger","fromEmail":"jk@jk.gs","sentAt":"2009-11-09T18:20:44Z","receivedAt":"2009-11-09T18:20:44Z","isPatch":true,"sender":{"key":"jk@jk.gs","avatar":"https://avatars.githubusercontent.com/u/1774?v=4"},"body":"Refspecs without a source side have been reported as confusing by many.\nAs an alternative, this adds support for commands like:\n\n    git push origin --delete somebranch\n\nSpecifically, --delete will prepend a colon to all colon-less refspecs\ngiven on the command line, and will refuse to accept refspecs with\ncolons to prevent undue confusion.\n\nSigned-off-by: Jan Krüger <jk@jk.gs>\n---\nAll good points, and I actually remembered to catch the colon-refspec\ncase a few minutes after sending the patch, but didn't have time to fix\nit up. (Sorry for not considering the old thread; I had gotten\nunsubscribed from the list back then).\n\nI think with this change it becomes much saner. And no, I'm not\nproposing to add --rename and --copy, too. ;)\n\nThe new error message is not completely technically correct since it's\nstill a refspec we're taking, we just force it to be without a colon.\nOn the other hand, this error message will hopefully make much more\nsense to people who don't know all the background, and it's not too\nhorribly wrong either.\n\n(Sverre added to Cc list from subthread)\n\n builtin-push.c        |   16 ++++++++++++++++\n t/t5516-fetch-push.sh |    6 ++++++\n 2 files changed, 22 insertions(+), 0 deletions(-)\n\ndiff --git a/builtin-push.c b/builtin-push.c\nindex 8631c06..e40bfe8 100644\n--- a/builtin-push.c\n+++ b/builtin-push.c\n@@ -15,6 +15,7 @@ static const char * const push_usage[] = {\n };\n \n static int thin;\n+static int deleterefs;\n static const char *receivepack;\n \n static const char **refspec;\n@@ -44,6 +45,15 @@ static void set_refspecs(const char **refs, int nr)\n \t\t\tstrcat(tag, refs[i]);\n \t\t\tref = tag;\n \t\t}\n+\t\tif (deleterefs && !strchr(ref, ':')) {\n+\t\t\tchar *delref;\n+\t\t\tint len = strlen(refs[i] + 1);\n+\t\t\tdelref = xmalloc(len);\n+\t\t\tstrcpy(delref, \":\");\n+\t\t\tstrcat(delref, refs[i]);\n+\t\t\tref = delref;\n+\t\t} else if (deleterefs)\n+\t\t\tdie(\"--delete only accepts plain target ref names\");\n \t\tadd_refspec(ref);\n \t}\n }\n@@ -181,6 +191,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)\n \t\tOPT_BIT( 0 , \"all\", &flags, \"push all refs\", TRANSPORT_PUSH_ALL),\n \t\tOPT_BIT( 0 , \"mirror\", &flags, \"mirror all refs\",\n \t\t\t    (TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE)),\n+\t\tOPT_BOOLEAN( 0, \"delete\", &deleterefs, \"delete refs\"),\n \t\tOPT_BOOLEAN( 0 , \"tags\", &tags, \"push tags (can't be used with --all or --mirror)\"),\n \t\tOPT_BIT('n' , \"dry-run\", &flags, \"dry run\", TRANSPORT_PUSH_DRY_RUN),\n \t\tOPT_BIT( 0,  \"porcelain\", &flags, \"machine-readable output\", TRANSPORT_PUSH_PORCELAIN),\n@@ -193,6 +204,11 @@ int cmd_push(int argc, const char **argv, const char *prefix)\n \n \targc = parse_options(argc, argv, prefix, options, push_usage, 0);\n \n+\tif (deleterefs && (tags || (flags & (TRANSPORT_PUSH_ALL | TRANSPORT_PUSH_MIRROR))))\n+\t\tdie(\"--delete is incompatible with --all, --mirror and --tags\");\n+\tif (deleterefs && argc < 2)\n+\t\tdie(\"--delete doesn't make sense without any refs\");\n+\n \tif (tags)\n \t\tadd_refspec(\"refs/tags/*\");\n \ndiff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh\nindex 6889a53..aa1450a 100755\n--- a/t/t5516-fetch-push.sh\n+++ b/t/t5516-fetch-push.sh\n@@ -546,6 +546,12 @@ test_expect_success 'allow deleting an invalid remote ref' '\n \n '\n \n+test_expect_success 'allow deleting a ref using --delete' '\n+\tmk_test heads/master &&\n+\tgit push testrepo --delete master &&\n+\t(cd testrepo && test_must_fail git rev-parse --verify refs/heads/master)\n+'\n+\n test_expect_success 'warn on push to HEAD of non-bare repository' '\n \tmk_test heads/master\n \t(cd testrepo &&\n-- \n1.6.5.2.155.gbb47.dirty\n"},{"id":"130446","messageId":"20091229200523.6117@nanako3.lavabit.com","threadId":"21543","inReplyTo":"20091109192044.605e50ba@perceptron","subject":"Re: [PATCH RFC v2] builtin-push: add --delete as syntactic sugar for :foo","fromName":"Nanako Shiraishi","fromEmail":"nanako3@lavabit.com","sentAt":"2009-12-29T11:05:23Z","receivedAt":"2009-12-29T11:05:23Z","isPatch":true,"sender":{"key":"nanako3@lavabit.com","avatar":"https://gravatar.com/avatar/3777b9e201c5883a62b1a6fdf7c53f2d712d1d80989146063ea861e33aad72a8?d=mp&s=160"},"body":"Junio, could you tell us what happened to this thread?\n\nThe patch implements \"git push repo --delete branch\" and rejects\n--delete used with other options like --all and --tags, as\nsuggested in the initial review.  I think it makes sense, but\nnothing happens after that.\n"},{"id":"130469","messageId":"7vvdfpg1je.fsf@alter.siamese.dyndns.org","threadId":"21543","inReplyTo":"20091229200523.6117@nanako3.lavabit.com","subject":"Re: [PATCH RFC v2] builtin-push: add --delete as syntactic sugar for :foo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-12-29T16:58:29Z","receivedAt":"2009-12-29T16:58:29Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Nanako Shiraishi <nanako3@lavabit.com> writes:\n\n> Junio, could you tell us what happened to this thread?\n>\n> The patch implements \"git push repo --delete branch\" and rejects\n> --delete used with other options like --all and --tags, as suggested in\n> the initial review.  I think it makes sense, but nothing happens after\n> that.\n\nSverre cited an old discussion and the discussion stalled.  I just re-read\nthe thread, and think the \"this is a wrong idea\" objection was primarily\nabout allowing --delete with non-delete kinds of refspecs, so in that\nsense Jan's patch is a perfected form of the Sverre's patch from that old\ndiscussion.\n\nAs a summary of the lesson learned and concensus from the old discussion,\nI agree with this from Sverre:\n\n  http://article.gmane.org/gmane.comp.version-control.git/125901\n\nnamely, (1) barf and abort if src:dst is given; (2) touch only refs given\nfrom the command line, \"push there --delete\" without any refspec is an\nerror; (3) be careful about \"git push there tag v1.0.0\" form.\n\nSo if Jan or Sverre want to resurrect the topic, I am all for it.\n"},{"id":"130532","messageId":"20091230105244.67f5969e@perceptron","threadId":"21543","inReplyTo":"7vvdfpg1je.fsf@alter.siamese.dyndns.org","subject":"[PATCH v3] builtin-push: add --delete as syntactic sugar for :foo","fromName":"Jan Krüger","fromEmail":"jk@jk.gs","sentAt":"2009-12-30T09:52:44Z","receivedAt":"2009-12-30T09:52:44Z","isPatch":true,"sender":{"key":"jk@jk.gs","avatar":"https://avatars.githubusercontent.com/u/1774?v=4"},"body":"Refspecs without a source side have been reported as confusing by many.\nAs an alternative, this adds support for commands like:\n\n    git push origin --delete somebranch\n    git push origin --delete tag sometag\n\nSpecifically, --delete will prepend a colon to all colon-less refspecs\ngiven on the command line, and will refuse to accept refspecs with\ncolons to prevent undue confusion.\n\nSigned-off-by: Jan Krüger <jk@jk.gs>\n---\n\nJunio C Hamano <gitster@pobox.com> wrote:\n\n> namely, (1) barf and abort if src:dst is given; (2) touch only refs\n> given from the command line, \"push there --delete\" without any\n> refspec is an error; (3) be careful about \"git push there tag v1.0.0\"\n> form.\n> \n> So if Jan or Sverre want to resurrect the topic, I am all for it.\n\nAlrighty. I assume by (3) you meant that it should be possible to use\nsomething like \"push there --delete tag v1.0.0\". Version 3 of the patch\nadds this, and it also includes updated tests and (brief) documentation.\n\n Documentation/git-push.txt |    4 ++++\n builtin-push.c             |   26 +++++++++++++++++++++++---\n t/t5516-fetch-push.sh      |   16 ++++++++++++++++\n 3 files changed, 43 insertions(+), 3 deletions(-)\n\ndiff --git a/Documentation/git-push.txt b/Documentation/git-push.txt\nindex 52c0538..e3eb1e8 100644\n--- a/Documentation/git-push.txt\n+++ b/Documentation/git-push.txt\n@@ -91,6 +91,10 @@ nor in any Push line of the corresponding remotes file---see below).\n \twill be tab-separated and sent to stdout instead of stderr.  The full\n \tsymbolic names of the refs will be given.\n \n+--delete::\n+\tAll listed refs are deleted from the remote repository. This is\n+\tthe same as prefixing all refs with a colon.\n+\n --tags::\n \tAll refs under `$GIT_DIR/refs/tags` are pushed, in\n \taddition to refspecs explicitly listed on the command\ndiff --git a/builtin-push.c b/builtin-push.c\nindex dcfb53f..f7661d2 100644\n--- a/builtin-push.c\n+++ b/builtin-push.c\n@@ -15,6 +15,7 @@ static const char * const push_usage[] = {\n };\n \n static int thin;\n+static int deleterefs;\n static const char *receivepack;\n \n static const char **refspec;\n@@ -39,11 +40,24 @@ static void set_refspecs(const char **refs, int nr)\n \t\t\tif (nr <= ++i)\n \t\t\t\tdie(\"tag shorthand without <tag>\");\n \t\t\tlen = strlen(refs[i]) + 11;\n-\t\t\ttag = xmalloc(len);\n-\t\t\tstrcpy(tag, \"refs/tags/\");\n+\t\t\tif (deleterefs) {\n+\t\t\t\ttag = xmalloc(len+1);\n+\t\t\t\tstrcpy(tag, \":refs/tags/\");\n+\t\t\t} else {\n+\t\t\t\ttag = xmalloc(len);\n+\t\t\t\tstrcpy(tag, \"refs/tags/\");\n+\t\t\t}\n \t\t\tstrcat(tag, refs[i]);\n \t\t\tref = tag;\n-\t\t}\n+\t\t} else if (deleterefs && !strchr(ref, ':')) {\n+\t\t\tchar *delref;\n+\t\t\tint len = strlen(ref)+1;\n+\t\t\tdelref = xmalloc(len);\n+\t\t\tstrcpy(delref, \":\");\n+\t\t\tstrcat(delref, ref);\n+\t\t\tref = delref;\n+\t\t} else if (deleterefs)\n+\t\t\tdie(\"--delete only accepts plain target ref names\");\n \t\tadd_refspec(ref);\n \t}\n }\n@@ -196,6 +210,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)\n \t\tOPT_BIT( 0 , \"all\", &flags, \"push all refs\", TRANSPORT_PUSH_ALL),\n \t\tOPT_BIT( 0 , \"mirror\", &flags, \"mirror all refs\",\n \t\t\t    (TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE)),\n+\t\tOPT_BOOLEAN( 0, \"delete\", &deleterefs, \"delete refs\"),\n \t\tOPT_BOOLEAN( 0 , \"tags\", &tags, \"push tags (can't be used with --all or --mirror)\"),\n \t\tOPT_BIT('n' , \"dry-run\", &flags, \"dry run\", TRANSPORT_PUSH_DRY_RUN),\n \t\tOPT_BIT( 0,  \"porcelain\", &flags, \"machine-readable output\", TRANSPORT_PUSH_PORCELAIN),\n@@ -209,6 +224,11 @@ int cmd_push(int argc, const char **argv, const char *prefix)\n \tgit_config(git_default_config, NULL);\n \targc = parse_options(argc, argv, prefix, options, push_usage, 0);\n \n+\tif (deleterefs && (tags || (flags & (TRANSPORT_PUSH_ALL | TRANSPORT_PUSH_MIRROR))))\n+\t\tdie(\"--delete is incompatible with --all, --mirror and --tags\");\n+\tif (deleterefs && argc < 2)\n+\t\tdie(\"--delete doesn't make sense without any refs\");\n+\n \tif (tags)\n \t\tadd_refspec(\"refs/tags/*\");\n \ndiff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh\nindex 516127b..a17666c 100755\n--- a/t/t5516-fetch-push.sh\n+++ b/t/t5516-fetch-push.sh\n@@ -547,6 +547,22 @@ test_expect_success 'allow deleting an invalid remote ref' '\n \n '\n \n+test_expect_success 'allow deleting a ref using --delete' '\n+\tmk_test heads/master &&\n+\t(cd testrepo && git config receive.denyDeleteCurrent warn) &&\n+\tgit push testrepo --delete master &&\n+\t(cd testrepo && test_must_fail git rev-parse --verify refs/heads/master)\n+'\n+\n+test_expect_success 'allow deleting a tag using --delete' '\n+\tmk_test heads/master &&\n+\tgit tag -a -m dummy_message deltag heads/master &&\n+\tgit push testrepo --tags &&\n+\t(cd testrepo && git rev-parse --verify -q refs/tags/deltag) &&\n+\tgit push testrepo --delete tag deltag &&\n+\t(cd testrepo && test_must_fail git rev-parse --verify refs/tags/deltag)\n+'\n+\n test_expect_success 'warn on push to HEAD of non-bare repository' '\n \tmk_test heads/master\n \t(cd testrepo &&\n-- \n1.6.6.60.gc2ff1\n"},{"id":"130547","messageId":"fabb9a1e0912300414q329bff5fy95ace5a5ad44db08@mail.gmail.com","threadId":"21543","inReplyTo":"20091230105244.67f5969e@perceptron","subject":"Re: [PATCH v3] builtin-push: add --delete as syntactic sugar for :foo","fromName":"Sverre Rabbelier","fromEmail":"srabbelier@gmail.com","sentAt":"2009-12-30T12:14:53Z","receivedAt":"2009-12-30T12:14:53Z","isPatch":true,"sender":{"key":"srabbelier@gmail.com","avatar":"https://avatars.githubusercontent.com/u/3098?v=4"},"body":"Heya,\n\nOn Wed, Dec 30, 2009 at 03:52, Jan Krüger <jk@jk.gs> wrote:\n>> So if Jan or Sverre want to resurrect the topic, I am all for it.\n>\n> Alrighty. I assume by (3) you meant that it should be possible to use\n> something like \"push there --delete tag v1.0.0\". Version 3 of the patch\n> adds this, and it also includes updated tests and (brief) documentation.\n\nThanks for picking this up.\n\n-- \nCheers,\n\nSverre Rabbelier\n"},{"id":"130576","messageId":"7vvdfoz1hi.fsf@alter.siamese.dyndns.org","threadId":"21543","inReplyTo":"20091230105244.67f5969e@perceptron","subject":"Re: [PATCH v3] builtin-push: add --delete as syntactic sugar for :foo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-12-30T19:49:13Z","receivedAt":"2009-12-30T19:49:13Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jan Krüger <jk@jk.gs> writes:\n\n> Refspecs without a source side have been reported as confusing by many.\n> As an alternative, this adds support for commands like:\n>\n>     git push origin --delete somebranch\n>     git push origin --delete tag sometag\n>\n> Specifically, --delete will prepend a colon to all colon-less refspecs\n> given on the command line, and will refuse to accept refspecs with\n> colons to prevent undue confusion.\n>\n> Signed-off-by: Jan Krüger <jk@jk.gs>\n> ---\n\nThanks.  From a cursory read, the patch looks good.  We would however want\nto have a test that has test_must_fail to protect the error codepath from\ngetting broken in the future.\n"},{"id":"130579","messageId":"20091230205742.23d73eb6@perceptron","threadId":"21543","inReplyTo":"7vvdfoz1hi.fsf@alter.siamese.dyndns.org","subject":"[PATCH v4] builtin-push: add --delete as syntactic sugar for :foo","fromName":"Jan Krüger","fromEmail":"jk@jk.gs","sentAt":"2009-12-30T19:57:42Z","receivedAt":"2009-12-30T19:57:42Z","isPatch":true,"sender":{"key":"jk@jk.gs","avatar":"https://avatars.githubusercontent.com/u/1774?v=4"},"body":"Refspecs without a source side have been reported as confusing by many.\nAs an alternative, this adds support for commands like:\n\n    git push origin --delete somebranch\n    git push origin --delete tag sometag\n\nSpecifically, --delete will prepend a colon to all colon-less refspecs\ngiven on the command line, and will refuse to accept refspecs with\ncolons to prevent undue confusion.\n\nSigned-off-by: Jan Krüger <jk@jk.gs>\n---\n Documentation/git-push.txt |    4 ++++\n builtin-push.c             |   26 +++++++++++++++++++++++---\n t/t5516-fetch-push.sh      |   26 ++++++++++++++++++++++++++\n 3 files changed, 53 insertions(+), 3 deletions(-)\n\nJunio C Hamano <gitster@pobox.com> wrote:\n\n> Thanks.  From a cursory read, the patch looks good.  We would however\n> want to have a test that has test_must_fail to protect the error\n> codepath from getting broken in the future.\n\nHere you are.\n\ndiff --git a/Documentation/git-push.txt b/Documentation/git-push.txt\nindex 52c0538..e3eb1e8 100644\n--- a/Documentation/git-push.txt\n+++ b/Documentation/git-push.txt\n@@ -91,6 +91,10 @@ nor in any Push line of the corresponding remotes file---see below).\n \twill be tab-separated and sent to stdout instead of stderr.  The full\n \tsymbolic names of the refs will be given.\n \n+--delete::\n+\tAll listed refs are deleted from the remote repository. This is\n+\tthe same as prefixing all refs with a colon.\n+\n --tags::\n \tAll refs under `$GIT_DIR/refs/tags` are pushed, in\n \taddition to refspecs explicitly listed on the command\ndiff --git a/builtin-push.c b/builtin-push.c\nindex dcfb53f..f7661d2 100644\n--- a/builtin-push.c\n+++ b/builtin-push.c\n@@ -15,6 +15,7 @@ static const char * const push_usage[] = {\n };\n \n static int thin;\n+static int deleterefs;\n static const char *receivepack;\n \n static const char **refspec;\n@@ -39,11 +40,24 @@ static void set_refspecs(const char **refs, int nr)\n \t\t\tif (nr <= ++i)\n \t\t\t\tdie(\"tag shorthand without <tag>\");\n \t\t\tlen = strlen(refs[i]) + 11;\n-\t\t\ttag = xmalloc(len);\n-\t\t\tstrcpy(tag, \"refs/tags/\");\n+\t\t\tif (deleterefs) {\n+\t\t\t\ttag = xmalloc(len+1);\n+\t\t\t\tstrcpy(tag, \":refs/tags/\");\n+\t\t\t} else {\n+\t\t\t\ttag = xmalloc(len);\n+\t\t\t\tstrcpy(tag, \"refs/tags/\");\n+\t\t\t}\n \t\t\tstrcat(tag, refs[i]);\n \t\t\tref = tag;\n-\t\t}\n+\t\t} else if (deleterefs && !strchr(ref, ':')) {\n+\t\t\tchar *delref;\n+\t\t\tint len = strlen(ref)+1;\n+\t\t\tdelref = xmalloc(len);\n+\t\t\tstrcpy(delref, \":\");\n+\t\t\tstrcat(delref, ref);\n+\t\t\tref = delref;\n+\t\t} else if (deleterefs)\n+\t\t\tdie(\"--delete only accepts plain target ref names\");\n \t\tadd_refspec(ref);\n \t}\n }\n@@ -196,6 +210,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)\n \t\tOPT_BIT( 0 , \"all\", &flags, \"push all refs\", TRANSPORT_PUSH_ALL),\n \t\tOPT_BIT( 0 , \"mirror\", &flags, \"mirror all refs\",\n \t\t\t    (TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE)),\n+\t\tOPT_BOOLEAN( 0, \"delete\", &deleterefs, \"delete refs\"),\n \t\tOPT_BOOLEAN( 0 , \"tags\", &tags, \"push tags (can't be used with --all or --mirror)\"),\n \t\tOPT_BIT('n' , \"dry-run\", &flags, \"dry run\", TRANSPORT_PUSH_DRY_RUN),\n \t\tOPT_BIT( 0,  \"porcelain\", &flags, \"machine-readable output\", TRANSPORT_PUSH_PORCELAIN),\n@@ -209,6 +224,11 @@ int cmd_push(int argc, const char **argv, const char *prefix)\n \tgit_config(git_default_config, NULL);\n \targc = parse_options(argc, argv, prefix, options, push_usage, 0);\n \n+\tif (deleterefs && (tags || (flags & (TRANSPORT_PUSH_ALL | TRANSPORT_PUSH_MIRROR))))\n+\t\tdie(\"--delete is incompatible with --all, --mirror and --tags\");\n+\tif (deleterefs && argc < 2)\n+\t\tdie(\"--delete doesn't make sense without any refs\");\n+\n \tif (tags)\n \t\tadd_refspec(\"refs/tags/*\");\n \ndiff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh\nindex 516127b..0f04b2e 100755\n--- a/t/t5516-fetch-push.sh\n+++ b/t/t5516-fetch-push.sh\n@@ -547,6 +547,32 @@ test_expect_success 'allow deleting an invalid remote ref' '\n \n '\n \n+test_expect_success 'allow deleting a ref using --delete' '\n+\tmk_test heads/master &&\n+\t(cd testrepo && git config receive.denyDeleteCurrent warn) &&\n+\tgit push testrepo --delete master &&\n+\t(cd testrepo && test_must_fail git rev-parse --verify refs/heads/master)\n+'\n+\n+test_expect_success 'allow deleting a tag using --delete' '\n+\tmk_test heads/master &&\n+\tgit tag -a -m dummy_message deltag heads/master &&\n+\tgit push testrepo --tags &&\n+\t(cd testrepo && git rev-parse --verify -q refs/tags/deltag) &&\n+\tgit push testrepo --delete tag deltag &&\n+\t(cd testrepo && test_must_fail git rev-parse --verify refs/tags/deltag)\n+'\n+\n+test_expect_success 'push --delete without args aborts' '\n+\tmk_test heads/master &&\n+\ttest_must_fail git push testrepo --delete\n+'\n+\n+test_expect_success 'push --delete refuses src:dest refspecs' '\n+\tmk_test heads/master &&\n+\ttest_must_fail git push testrepo --delete master:foo\n+'\n+\n test_expect_success 'warn on push to HEAD of non-bare repository' '\n \tmk_test heads/master\n \t(cd testrepo &&\n-- \n1.6.6.60.gc2ff1\n"}]}