{"thread":{"id":"14037","subject":"[PATCH] git-push: add a --delete flag to allow branch deletion","startedAt":"2008-06-19T14:13:07Z","lastAt":"2008-06-20T00:51:13Z","messageCount":5,"participants":["Pieter de Bie","Andreas Ericsson","Sverre Rabbelier","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"80318","messageId":"1213884787-24692-1-git-send-email-pdebie@ai.rug.nl","threadId":"14037","inReplyTo":null,"subject":"[PATCH] git-push: add a --delete flag to allow branch deletion","fromName":"Pieter de Bie","fromEmail":"pdebie@ai.rug.nl","sentAt":"2008-06-19T14:13:07Z","receivedAt":"2008-06-19T14:13:07Z","isPatch":true,"sender":{"key":"pdebie@ai.rug.nl","avatar":null},"body":"While this is already possible with the :<dst> refspec syntax,\na flag specifically for this action is more userfriendly.\n\nSigned-off-by: Pieter de Bie <pdebie@ai.rug.nl>\n---\n\nThe question on how to delete remote branches appears frequently in the\nirc channel. If we add an explicit option to do this to git push, hopefully\nit will be more clear.\n\n Documentation/git-push.txt |   13 ++++++++++++-\n builtin-push.c             |   37 +++++++++++++++++++++++++++++++++++--\n t/t5516-fetch-push.sh      |   13 +++++++++++++\n 3 files changed, 60 insertions(+), 3 deletions(-)\n\ndiff --git a/Documentation/git-push.txt b/Documentation/git-push.txt\nindex 89e0049..6a772a5 100644\n--- a/Documentation/git-push.txt\n+++ b/Documentation/git-push.txt\n@@ -11,6 +11,8 @@ SYNOPSIS\n [verse]\n 'git-push' [--all] [--dry-run] [--tags] [--receive-pack=<git-receive-pack>]\n            [--repo=all] [-f | --force] [-v | --verbose] [<repository> <refspec>...]\n+'git push' --delete <repository> <branchname> [<branch2> ...]\n+\n \n DESCRIPTION\n -----------\n@@ -18,6 +20,8 @@ DESCRIPTION\n Updates remote refs using local refs, while sending objects\n necessary to complete the given refs.\n \n+In the second form, deletes one or more branches on a given repository.\n+\n You can make interesting things happen to a repository\n every time you push into it, by setting up 'hooks' there.  See\n documentation for linkgit:git-receive-pack[1].\n@@ -52,7 +56,7 @@ A parameter <ref> without a colon pushes the <ref> from the source\n repository to the destination repository under the same name.\n +\n Pushing an empty <src> allows you to delete the <dst> ref from\n-the remote repository.\n+the remote repository. The same can be done by using the --delete flag.\n +\n The special refspec `:` (or `+:` to allow non-fast forward updates)\n directs git to push \"matching\" heads: for every head that exists on\n@@ -75,6 +79,10 @@ nor in any Push line of the corresponding remotes file---see below).\n \tif the configuration option `remote.<remote>.mirror` is\n \tset.\n \n+--delete::\n+\tDoes not push anything, but instead deletes <branchname> on the\n+\tremote repository.\n+\n --dry-run::\n \tDo everything except actually send the updates.\n \n@@ -179,6 +187,9 @@ git push origin :experimental::\n \tFind a ref that matches `experimental` in the `origin` repository\n \t(e.g. `refs/heads/experimental`), and delete it.\n \n+git push --delete origin experimental::\n+\tDoes the same as the above, but is more friendly.\n+\n git push origin master:satellite/master::\n \tFind a ref that matches `master` in the source repository\n \t(most likely, it would find `refs/heads/master`), and update\ndiff --git a/builtin-push.c b/builtin-push.c\nindex b35aad6..81f9a58 100644\n--- a/builtin-push.c\n+++ b/builtin-push.c\n@@ -10,7 +10,8 @@\n #include \"parse-options.h\"\n \n static const char * const push_usage[] = {\n-\t\"git-push [--all | --mirror] [--dry-run] [--tags] [--receive-pack=<git-receive-pack>] [--repo=all] [-f | --force] [-v] [<repository> <refspec>...]\",\n+\t\"git push [--all | --mirror] [--dry-run] [--tags] [--receive-pack=<git-receive-pack>] [--repo=all] [-f | --force] [-v] [<repository> <refspec>...]\",\n+\t\"git push --delete <repository> <branchname> [<branch2> ...]\",\n \tNULL,\n };\n \n@@ -48,6 +49,24 @@ static void set_refspecs(const char **refs, int nr)\n \t}\n }\n \n+static void set_delete_refspecs(const char **branches, int nr)\n+{\n+\tint i;\n+\tfor (i = 0; i < nr; i++) {\n+\t\tconst char *branch = branches[i];\n+\t\tint len;\n+\t\tchar *delete_refspec;\n+\n+\t\tif (strchr(branch, ':'))\n+\t\t\tdie(\"%s is not a valid branchname\", branch);\n+\t\tlen = strlen(branch) + 1;\n+\t\tdelete_refspec = xmalloc(len);\n+\t\t*delete_refspec = ':';\n+\t\tstrcpy(delete_refspec + 1, branch);\n+\t\tadd_refspec(delete_refspec);\n+\t}\n+}\n+\n static int do_push(const char *repo, int flags)\n {\n \tint i, errs;\n@@ -108,6 +127,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)\n \tint tags = 0;\n \tint rc;\n \tconst char *repo = NULL;\t/* default repository */\n+\tint delete = 0;\n \n \tstruct option options[] = {\n \t\tOPT__VERBOSE(&verbose),\n@@ -118,6 +138,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)\n \t\tOPT_BOOLEAN( 0 , \"dry-run\", &dry_run, \"dry run\"),\n \t\tOPT_BOOLEAN('f', \"force\", &force, \"force updates\"),\n \t\tOPT_BOOLEAN( 0 , \"thin\", &thin, \"use thin pack\"),\n+\t\tOPT_BOOLEAN('d', \"delete\", &delete, \"delete remote branch\"),\n \t\tOPT_STRING( 0 , \"receive-pack\", &receivepack, \"receive-pack\", \"receive pack program\"),\n \t\tOPT_STRING( 0 , \"exec\", &receivepack, \"receive-pack\", \"receive pack program\"),\n \t\tOPT_END()\n@@ -125,6 +146,18 @@ int cmd_push(int argc, const char **argv, const char *prefix)\n \n \targc = parse_options(argc, argv, options, push_usage, 0);\n \n+\tif (delete) {\n+\t\tif (all || mirror || tags || force || repo)\n+\t\t\tdie(\"--delete cannot be used with --all, --mirror, --tags, --farce or --repo\");\n+\n+\t\tif (argc == 0)\n+\t\t\tdie(\"Need a remote on which to delete a branch\");\n+\t\tif (argc == 1)\n+\t\t\tdie(\"Need a branch on the remote to delete\");\n+\t\trepo = argv[0];\n+\t\tset_delete_refspecs(argv + 1, argc - 1);\n+\t}\n+\n \tif (force)\n \t\tflags |= TRANSPORT_PUSH_FORCE;\n \tif (dry_run)\n@@ -138,7 +171,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)\n \tif (mirror)\n \t\tflags |= (TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE);\n \n-\tif (argc > 0) {\n+\tif (!delete && argc > 0) {\n \t\trepo = argv[0];\n \t\tset_refspecs(argv + 1, argc - 1);\n \t}\ndiff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh\nindex 6805032..42fe89c 100755\n--- a/t/t5516-fetch-push.sh\n+++ b/t/t5516-fetch-push.sh\n@@ -361,6 +361,19 @@ test_expect_success 'push with HEAD nonexisting at remote' '\n \tgit push testrepo HEAD &&\n \tcheck_push_result $the_commit heads/local\n '\n+test_expect_success 'delete with --delete syntax' '\n+\n+\tgit push testrepo master:test1 &&\n+\tgit push --delete testrepo test1 &&\n+\tgit push testrepo master:test1 master:test2 &&\n+\tcheck_push_result $the_commit heads/test1 &&\n+\tcheck_push_result $the_commit heads/test2 &&\n+\tgit push --delete testrepo test1 test2 &&\n+\t!(check_push_result $the_commit heads/test1) &&\n+\t!(check_push_result $the_commit heads/test2) &&\n+\ttest_must_fail git push --delete testrepo test1\n+\n+'\n \n test_expect_success 'push with +HEAD' '\n \n-- \n1.5.6.rc1.153.gc1d96\n"},{"id":"80390","messageId":"485ADE10.7070404@op5.se","threadId":"14037","inReplyTo":"1213884787-24692-1-git-send-email-pdebie@ai.rug.nl","subject":"Re: [PATCH] git-push: add a --delete flag to allow branch deletion","fromName":"Andreas Ericsson","fromEmail":"ae@op5.se","sentAt":"2008-06-19T22:30:40Z","receivedAt":"2008-06-19T22:30:40Z","isPatch":true,"sender":{"key":"ae@op5.se","avatar":"https://gravatar.com/avatar/426e89595c75a8f5252dd0c989e5fabe5bcac616e68557427ad9aef6b0ca342a?d=mp&s=160"},"body":"Pieter de Bie wrote:\n> While this is already possible with the :<dst> refspec syntax,\n> a flag specifically for this action is more userfriendly.\n> \n\nI like it. I always have to tell my co-workers which side of\nthe colon the branch-name to delete should be on. Since they\nwant the remote to lose the branch, it seems logical to some\nof them to make that side empty. This would make one (very\nsmall) headache of mine go away.\n\nQuestion though; does it delete the currently checked out\nbranch if no branch-name is given? I'd prefer if one has\nto explicitly name the branch to delete.\n\n-- \nAndreas Ericsson                   andreas.ericsson@op5.se\nOP5 AB                             www.op5.se\nTel: +46 8-230225                  Fax: +46 8-230231\n"},{"id":"80395","messageId":"4BED18CA-BFFE-4F35-A484-6CF0908D3FC1@ai.rug.nl","threadId":"14037","inReplyTo":"485ADE10.7070404@op5.se","subject":"Re: [PATCH] git-push: add a --delete flag to allow branch deletion","fromName":"Pieter de Bie","fromEmail":"pdebie@ai.rug.nl","sentAt":"2008-06-19T22:55:22Z","receivedAt":"2008-06-19T22:55:22Z","isPatch":true,"sender":{"key":"pdebie@ai.rug.nl","avatar":null},"body":"\nOn 20 jun 2008, at 00:30, Andreas Ericsson wrote:\n\n> Question though; does it delete the currently checked out\n> branch if no branch-name is given? I'd prefer if one has\n> to explicitly name the branch to delete.\n\nYou have to explicitly give it a remote and one or more branches\nto delete. I thought it would be best to be unambiguous in cases\nwhere deletion is concerned :)\n\n- Pieter\n"},{"id":"80401","messageId":"bd6139dc0806191620y3f821c15h91454ddef2173590@mail.gmail.com","threadId":"14037","inReplyTo":"4BED18CA-BFFE-4F35-A484-6CF0908D3FC1@ai.rug.nl","subject":"Re: [PATCH] git-push: add a --delete flag to allow branch deletion","fromName":"Sverre Rabbelier","fromEmail":"alturin@gmail.com","sentAt":"2008-06-19T23:20:43Z","receivedAt":"2008-06-19T23:20:43Z","isPatch":true,"sender":{"key":"alturin@gmail.com","avatar":null},"body":"On Fri, Jun 20, 2008 at 12:55 AM, Pieter de Bie <pdebie@ai.rug.nl> wrote:\n> On 20 jun 2008, at 00:30, Andreas Ericsson wrote:\n>\n>> Question though; does it delete the currently checked out\n>> branch if no branch-name is given? I'd prefer if one has\n>> to explicitly name the branch to delete.\n>\n> You have to explicitly give it a remote and one or more branches\n> to delete. I thought it would be best to be unambiguous in cases\n> where deletion is concerned :)\n\nI like it too, it's one of the most unintuitive parts of the git\ninterface imo. I am guessing there is no \"-d\" switch because deletion\nis involved? Then again, there is a \"git branch -d/D\"?\n\n-- \nCheers,\n\nSverre Rabbelier\n"},{"id":"80424","messageId":"7vej6tq67y.fsf@gitster.siamese.dyndns.org","threadId":"14037","inReplyTo":"1213884787-24692-1-git-send-email-pdebie@ai.rug.nl","subject":"Re: [PATCH] git-push: add a --delete flag to allow branch deletion","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-06-20T00:51:13Z","receivedAt":"2008-06-20T00:51:13Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Pieter de Bie <pdebie@ai.rug.nl> writes:\n\n> diff --git a/Documentation/git-push.txt b/Documentation/git-push.txt\n> index 89e0049..6a772a5 100644\n> --- a/Documentation/git-push.txt\n> +++ b/Documentation/git-push.txt\n> @@ -11,6 +11,8 @@ SYNOPSIS\n>  [verse]\n>  'git-push' [--all] [--dry-run] [--tags] [--receive-pack=<git-receive-pack>]\n>             [--repo=all] [-f | --force] [-v | --verbose] [<repository> <refspec>...]\n> +'git push' --delete <repository> <branchname> [<branch2> ...]\n> +\n>  \n>  DESCRIPTION\n>  -----------\n> @@ -18,6 +20,8 @@ DESCRIPTION\n>  Updates remote refs using local refs, while sending objects\n>  necessary to complete the given refs.\n>  \n> +In the second form, deletes one or more branches on a given repository.\n> +\n\nIs this really about branches?  Is it usable to somehow delete tags, and\nif so how?\n\nWhat happens if you have a branch 'foo' and a tag 'foo' in the remote\nrepository and you say \"git push --delete $there foo\"?\n\n> @@ -125,6 +146,18 @@ int cmd_push(int argc, const char **argv, const char *prefix)\n>  \n>  \targc = parse_options(argc, argv, options, push_usage, 0);\n>  \n> +\tif (delete) {\n> +\t\tif (all || mirror || tags || force || repo)\n> +\t\t\tdie(\"--delete cannot be used with --all, --mirror, --tags, --farce or --repo\");\n\nNice try, but it is not so amusing.\n"}]}