{"thread":{"id":"31883","subject":"[RFC/PATCH] git symbolic-ref --delete $symref","startedAt":"2012-10-21T11:32:33Z","lastAt":"2012-10-21T19:16:39Z","messageCount":2,"participants":["Johan Herland","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"201626","messageId":"1350819153-23491-1-git-send-email-johan@herland.net","threadId":"31883","inReplyTo":null,"subject":"[RFC/PATCH] git symbolic-ref --delete $symref","fromName":"Johan Herland","fromEmail":"johan@herland.net","sentAt":"2012-10-21T11:32:33Z","receivedAt":"2012-10-21T11:32:33Z","isPatch":true,"sender":{"key":"johan@herland.net","avatar":"https://avatars.githubusercontent.com/u/547031?v=4"},"body":"Teach symbolic-ref to delete symrefs by adding the -d/--delete option to\ngit-symbolic-ref. Both proper and dangling symrefs are deleted by this\noption, but other refs - or anything else that is not a symref - is not.\n\nThe symref deletion is performed by first verifying that we are given a\nproper symref, and then invoking delete_ref() on it with the REF_NODEREF\nflag.\n\nSigned-off-by: Johan Herland <johan@herland.net>\n---\n\nHere is a quick first attempt at implementing the 'git symbolic-ref -d'\nyou've been mentioning in the symref deletion thread.\n\n Documentation/git-symbolic-ref.txt | 10 +++++++++-\n builtin/symbolic-ref.c             | 33 +++++++++++++++++++++++----------\n t/t1401-symbolic-ref.sh            | 30 ++++++++++++++++++++++++++++++\n 3 files changed, 62 insertions(+), 11 deletions(-)\n\ndiff --git a/Documentation/git-symbolic-ref.txt b/Documentation/git-symbolic-ref.txt\nindex 981d3a8..ef68ad2 100644\n--- a/Documentation/git-symbolic-ref.txt\n+++ b/Documentation/git-symbolic-ref.txt\n@@ -3,13 +3,14 @@ git-symbolic-ref(1)\n\n NAME\n ----\n-git-symbolic-ref - Read and modify symbolic refs\n+git-symbolic-ref - Read, modify and delete symbolic refs\n\n SYNOPSIS\n --------\n [verse]\n 'git symbolic-ref' [-m <reason>] <name> <ref>\n 'git symbolic-ref' [-q] [--short] <name>\n+'git symbolic-ref' --delete [-q] <name>\n\n DESCRIPTION\n -----------\n@@ -21,6 +22,9 @@ argument to see which branch your working tree is on.\n Given two arguments, creates or updates a symbolic ref <name> to\n point at the given branch <ref>.\n\n+Given `--delete` and an additional argument, deletes the given\n+symbolic ref.\n+\n A symbolic ref is a regular file that stores a string that\n begins with `ref: refs/`.  For example, your `.git/HEAD` is\n a regular file whose contents is `ref: refs/heads/master`.\n@@ -28,6 +32,10 @@ a regular file whose contents is `ref: refs/heads/master`.\n OPTIONS\n -------\n\n+-d::\n+--delete::\n+\tDelete the symbolic ref <name>.\n+\n -q::\n --quiet::\n \tDo not issue an error message if the <name> is not a\ndiff --git a/builtin/symbolic-ref.c b/builtin/symbolic-ref.c\nindex 9e92828..f481959 100644\n--- a/builtin/symbolic-ref.c\n+++ b/builtin/symbolic-ref.c\n@@ -5,12 +5,11 @@\n\n static const char * const git_symbolic_ref_usage[] = {\n \tN_(\"git symbolic-ref [options] name [ref]\"),\n+\tN_(\"git symbolic-ref -d [-q] name\"),\n \tNULL\n };\n\n-static int shorten;\n-\n-static void check_symref(const char *HEAD, int quiet)\n+static int check_symref(const char *HEAD, int quiet, int shorten, int print)\n {\n \tunsigned char sha1[20];\n \tint flag;\n@@ -22,20 +21,24 @@ static void check_symref(const char *HEAD, int quiet)\n \t\tif (!quiet)\n \t\t\tdie(\"ref %s is not a symbolic ref\", HEAD);\n \t\telse\n-\t\t\texit(1);\n+\t\t\treturn 1;\n+\t}\n+\tif (print) {\n+\t\tif (shorten)\n+\t\t\trefname = shorten_unambiguous_ref(refname, 0);\n+\t\tputs(refname);\n \t}\n-\tif (shorten)\n-\t\trefname = shorten_unambiguous_ref(refname, 0);\n-\tputs(refname);\n+\treturn 0;\n }\n\n int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)\n {\n-\tint quiet = 0;\n+\tint quiet = 0, delete = 0, shorten = 0, ret = 0;\n \tconst char *msg = NULL;\n \tstruct option options[] = {\n \t\tOPT__QUIET(&quiet,\n \t\t\tN_(\"suppress error message for non-symbolic (detached) refs\")),\n+\t\tOPT_BOOL('d', \"delete\", &delete, N_(\"delete symbolic ref\")),\n \t\tOPT_BOOL(0, \"short\", &shorten, N_(\"shorten ref output\")),\n \t\tOPT_STRING('m', NULL, &msg, N_(\"reason\"), N_(\"reason of the update\")),\n \t\tOPT_END(),\n@@ -46,9 +49,19 @@ int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)\n \t\t\t     git_symbolic_ref_usage, 0);\n \tif (msg &&!*msg)\n \t\tdie(\"Refusing to perform update with empty message\");\n+\n+\tif (delete) {\n+\t\tif (argc != 1)\n+\t\t\tusage_with_options(git_symbolic_ref_usage, options);\n+\t\tret = check_symref(argv[0], 1, 0, 0);\n+\t\tif (ret)\n+\t\t\tdie(\"Cannot delete %s, not a symbolic ref\", argv[0]);\n+\t\treturn delete_ref(argv[0], NULL, REF_NODEREF);\n+\t}\n+\n \tswitch (argc) {\n \tcase 1:\n-\t\tcheck_symref(argv[0], quiet);\n+\t\tret = check_symref(argv[0], quiet, shorten, 1);\n \t\tbreak;\n \tcase 2:\n \t\tif (!strcmp(argv[0], \"HEAD\") &&\n@@ -59,5 +72,5 @@ int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)\n \tdefault:\n \t\tusage_with_options(git_symbolic_ref_usage, options);\n \t}\n-\treturn 0;\n+\treturn ret;\n }\ndiff --git a/t/t1401-symbolic-ref.sh b/t/t1401-symbolic-ref.sh\nindex 2c96551..36378b0 100755\n--- a/t/t1401-symbolic-ref.sh\n+++ b/t/t1401-symbolic-ref.sh\n@@ -33,4 +33,34 @@ test_expect_success 'symbolic-ref refuses bare sha1' '\n '\n reset_to_sane\n\n+test_expect_success 'symbolic-ref deletes HEAD' '\n+\tgit symbolic-ref -d HEAD &&\n+\ttest_path_is_file .git/refs/heads/foo &&\n+\ttest_path_is_missing .git/HEAD\n+'\n+reset_to_sane\n+\n+test_expect_success 'symbolic-ref deletes dangling HEAD' '\n+\tgit symbolic-ref HEAD refs/heads/missing &&\n+\tgit symbolic-ref -d HEAD &&\n+\ttest_path_is_missing .git/refs/heads/missing &&\n+\ttest_path_is_missing .git/HEAD\n+'\n+reset_to_sane\n+\n+test_expect_success 'symbolic-ref fails to delete missing FOO' '\n+\techo \"fatal: Cannot delete FOO, not a symbolic ref\" >expect &&\n+\ttest_must_fail git symbolic-ref -d FOO >actual 2>&1 &&\n+\ttest_cmp expect actual\n+'\n+reset_to_sane\n+\n+test_expect_success 'symbolic-ref fails to delete real ref' '\n+\techo \"fatal: Cannot delete refs/heads/foo, not a symbolic ref\" >expect &&\n+\ttest_must_fail git symbolic-ref -d refs/heads/foo >actual 2>&1 &&\n+\ttest_path_is_file .git/refs/heads/foo &&\n+\ttest_cmp expect actual\n+'\n+reset_to_sane\n+\n test_done\n--\n1.7.12.1.609.g5cd6968\n"},{"id":"201644","messageId":"7vobjvfxew.fsf@alter.siamese.dyndns.org","threadId":"31883","inReplyTo":"1350819153-23491-1-git-send-email-johan@herland.net","subject":"Re: [RFC/PATCH] git symbolic-ref --delete $symref","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-10-21T19:16:39Z","receivedAt":"2012-10-21T19:16:39Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johan Herland <johan@herland.net> writes:\n\n> Teach symbolic-ref to delete symrefs by adding the -d/--delete option to\n> git-symbolic-ref. Both proper and dangling symrefs are deleted by this\n> option, but other refs - or anything else that is not a symref - is not.\n>\n> The symref deletion is performed by first verifying that we are given a\n> proper symref, and then invoking delete_ref() on it with the REF_NODEREF\n> flag.\n>\n> Signed-off-by: Johan Herland <johan@herland.net>\n> ---\n>\n> Here is a quick first attempt at implementing the 'git symbolic-ref -d'\n> you've been mentioning in the symref deletion thread.\n\nExisting users are used to 'update-ref -d --no-deref SYM' being the\nway to delete a symref (even though 'symbolic-ref SYM' being the way\nto create one), I think, and the lack of this option in symbolic-ref\nwould not have hurt them, and addition of this option wouldn't help\nthem very much, either.\n\nBut addition of this option would help new people who wonder, after\ncreating a symref with 'symbolic-ref' (perhaps with a wrong name),\nwhat command is to be used to remove it, finding no removal option\nin the same command.\n\nThanks.\n\n>  Documentation/git-symbolic-ref.txt | 10 +++++++++-\n>  builtin/symbolic-ref.c             | 33 +++++++++++++++++++++++----------\n>  t/t1401-symbolic-ref.sh            | 30 ++++++++++++++++++++++++++++++\n>  3 files changed, 62 insertions(+), 11 deletions(-)\n>\n> diff --git a/Documentation/git-symbolic-ref.txt b/Documentation/git-symbolic-ref.txt\n> index 981d3a8..ef68ad2 100644\n> --- a/Documentation/git-symbolic-ref.txt\n> +++ b/Documentation/git-symbolic-ref.txt\n> @@ -3,13 +3,14 @@ git-symbolic-ref(1)\n>\n>  NAME\n>  ----\n> -git-symbolic-ref - Read and modify symbolic refs\n> +git-symbolic-ref - Read, modify and delete symbolic refs\n>\n>  SYNOPSIS\n>  --------\n>  [verse]\n>  'git symbolic-ref' [-m <reason>] <name> <ref>\n>  'git symbolic-ref' [-q] [--short] <name>\n> +'git symbolic-ref' --delete [-q] <name>\n>\n>  DESCRIPTION\n>  -----------\n> @@ -21,6 +22,9 @@ argument to see which branch your working tree is on.\n>  Given two arguments, creates or updates a symbolic ref <name> to\n>  point at the given branch <ref>.\n>\n> +Given `--delete` and an additional argument, deletes the given\n> +symbolic ref.\n> +\n>  A symbolic ref is a regular file that stores a string that\n>  begins with `ref: refs/`.  For example, your `.git/HEAD` is\n>  a regular file whose contents is `ref: refs/heads/master`.\n> @@ -28,6 +32,10 @@ a regular file whose contents is `ref: refs/heads/master`.\n>  OPTIONS\n>  -------\n>\n> +-d::\n> +--delete::\n> +\tDelete the symbolic ref <name>.\n> +\n>  -q::\n>  --quiet::\n>  \tDo not issue an error message if the <name> is not a\n> diff --git a/builtin/symbolic-ref.c b/builtin/symbolic-ref.c\n> index 9e92828..f481959 100644\n> --- a/builtin/symbolic-ref.c\n> +++ b/builtin/symbolic-ref.c\n> @@ -5,12 +5,11 @@\n>\n>  static const char * const git_symbolic_ref_usage[] = {\n>  \tN_(\"git symbolic-ref [options] name [ref]\"),\n> +\tN_(\"git symbolic-ref -d [-q] name\"),\n>  \tNULL\n>  };\n>\n> -static int shorten;\n> -\n> -static void check_symref(const char *HEAD, int quiet)\n> +static int check_symref(const char *HEAD, int quiet, int shorten, int print)\n>  {\n>  \tunsigned char sha1[20];\n>  \tint flag;\n> @@ -22,20 +21,24 @@ static void check_symref(const char *HEAD, int quiet)\n>  \t\tif (!quiet)\n>  \t\t\tdie(\"ref %s is not a symbolic ref\", HEAD);\n>  \t\telse\n> -\t\t\texit(1);\n> +\t\t\treturn 1;\n> +\t}\n> +\tif (print) {\n> +\t\tif (shorten)\n> +\t\t\trefname = shorten_unambiguous_ref(refname, 0);\n> +\t\tputs(refname);\n>  \t}\n> -\tif (shorten)\n> -\t\trefname = shorten_unambiguous_ref(refname, 0);\n> -\tputs(refname);\n> +\treturn 0;\n>  }\n>\n>  int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)\n>  {\n> -\tint quiet = 0;\n> +\tint quiet = 0, delete = 0, shorten = 0, ret = 0;\n>  \tconst char *msg = NULL;\n>  \tstruct option options[] = {\n>  \t\tOPT__QUIET(&quiet,\n>  \t\t\tN_(\"suppress error message for non-symbolic (detached) refs\")),\n> +\t\tOPT_BOOL('d', \"delete\", &delete, N_(\"delete symbolic ref\")),\n>  \t\tOPT_BOOL(0, \"short\", &shorten, N_(\"shorten ref output\")),\n>  \t\tOPT_STRING('m', NULL, &msg, N_(\"reason\"), N_(\"reason of the update\")),\n>  \t\tOPT_END(),\n> @@ -46,9 +49,19 @@ int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)\n>  \t\t\t     git_symbolic_ref_usage, 0);\n>  \tif (msg &&!*msg)\n>  \t\tdie(\"Refusing to perform update with empty message\");\n> +\n> +\tif (delete) {\n> +\t\tif (argc != 1)\n> +\t\t\tusage_with_options(git_symbolic_ref_usage, options);\n> +\t\tret = check_symref(argv[0], 1, 0, 0);\n> +\t\tif (ret)\n> +\t\t\tdie(\"Cannot delete %s, not a symbolic ref\", argv[0]);\n> +\t\treturn delete_ref(argv[0], NULL, REF_NODEREF);\n> +\t}\n> +\n>  \tswitch (argc) {\n>  \tcase 1:\n> -\t\tcheck_symref(argv[0], quiet);\n> +\t\tret = check_symref(argv[0], quiet, shorten, 1);\n>  \t\tbreak;\n>  \tcase 2:\n>  \t\tif (!strcmp(argv[0], \"HEAD\") &&\n> @@ -59,5 +72,5 @@ int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)\n>  \tdefault:\n>  \t\tusage_with_options(git_symbolic_ref_usage, options);\n>  \t}\n> -\treturn 0;\n> +\treturn ret;\n>  }\n> diff --git a/t/t1401-symbolic-ref.sh b/t/t1401-symbolic-ref.sh\n> index 2c96551..36378b0 100755\n> --- a/t/t1401-symbolic-ref.sh\n> +++ b/t/t1401-symbolic-ref.sh\n> @@ -33,4 +33,34 @@ test_expect_success 'symbolic-ref refuses bare sha1' '\n>  '\n>  reset_to_sane\n>\n> +test_expect_success 'symbolic-ref deletes HEAD' '\n> +\tgit symbolic-ref -d HEAD &&\n> +\ttest_path_is_file .git/refs/heads/foo &&\n> +\ttest_path_is_missing .git/HEAD\n> +'\n> +reset_to_sane\n> +\n> +test_expect_success 'symbolic-ref deletes dangling HEAD' '\n> +\tgit symbolic-ref HEAD refs/heads/missing &&\n> +\tgit symbolic-ref -d HEAD &&\n> +\ttest_path_is_missing .git/refs/heads/missing &&\n> +\ttest_path_is_missing .git/HEAD\n> +'\n> +reset_to_sane\n> +\n> +test_expect_success 'symbolic-ref fails to delete missing FOO' '\n> +\techo \"fatal: Cannot delete FOO, not a symbolic ref\" >expect &&\n> +\ttest_must_fail git symbolic-ref -d FOO >actual 2>&1 &&\n> +\ttest_cmp expect actual\n> +'\n> +reset_to_sane\n> +\n> +test_expect_success 'symbolic-ref fails to delete real ref' '\n> +\techo \"fatal: Cannot delete refs/heads/foo, not a symbolic ref\" >expect &&\n> +\ttest_must_fail git symbolic-ref -d refs/heads/foo >actual 2>&1 &&\n> +\ttest_path_is_file .git/refs/heads/foo &&\n> +\ttest_cmp expect actual\n> +'\n> +reset_to_sane\n> +\n>  test_done\n> --\n> 1.7.12.1.609.g5cd6968\n"}]}