{"thread":{"id":"50644","subject":"[RFC PATCH 0/4] Add alias option to git branch","startedAt":"2019-03-04T15:47:23Z","lastAt":"2019-03-06T10:13:53Z","messageCount":11,"participants":["Kenneth Cochran","Phil Sainty","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":4},"messages":[{"id":"370613","messageId":"47CA9077-E8C1-4093-8B36-2D5D3DE2D886@gmail.com","threadId":"50644","inReplyTo":null,"subject":"[RFC PATCH 0/4] Add alias option to git branch","fromName":"Kenneth Cochran","fromEmail":"kenneth.cochran101@gmail.com","sentAt":"2019-03-04T15:45:45Z","receivedAt":"2019-03-04T15:47:23Z","isPatch":true,"sender":{"key":"kenneth.cochran101@gmail.com","avatar":null},"body":"From c1bad54b29ae1c1d8548d248f6ecaa5959e55f7b Mon Sep 17 00:00:00 2001\nFrom: Kenneth Cochran <kenneth.cochran101@gmail.com>\nDate: Mon, 4 Mar 2019 09:40:22 -0600\nSubject: [RFC PATCH 0/4] Add alias option to git branch\nCc: Sahil Dua <sahildua2305@gmail.com>,\n    Duy Nguyen <pclouds@gmail.com>,\n    Jeff King <peff@peff.net>\n\nI find myself often using git symbolic-ref to get around work requirements to use branch names that are not very human friendly.\nThere are a few problems with this:\n\t- There’s a lot of text to type\n\t- Mistyping certain parts (heads/refs) will do things other than create a branch alias\n\t- It will happily overwrite an existing branch\n\t- Deleting one that is checked out will put HEAD in an invalid state.\n\nI think this solution is much better; however, I’m not super familiar with the codebase, so I’m sure it can be improved.\nI’d appreciate any feedback.\n\nKenneth Cochran (4):\n  branch: add \"--alias\" option to create an alias\n  refs: add function to iteratively dereference symref chain\n  worktree: symref should be found anywhere in chain\n  branch: disallow accidentally breaking symrefs\n\n Documentation/git-branch.txt |  8 ++++\n builtin/branch.c             | 49 ++++++++++++++++++++-\n refs.c                       | 28 ++++++++++++\n refs.h                       | 13 ++++++\n t/t3207-branch-alias.sh      | 83 ++++++++++++++++++++++++++++++++++++\n worktree.c                   | 18 +++++---\n 6 files changed, 191 insertions(+), 8 deletions(-)\n create mode 100755 t/t3207-branch-alias.sh\n\n-- \n2.17.1\n\n\n"},{"id":"370614","messageId":"7D21A788-5E38-466F-B3CC-F6A5CBEB2E2E@gmail.com","threadId":"50644","inReplyTo":"47CA9077-E8C1-4093-8B36-2D5D3DE2D886@gmail.com","subject":"Re: [RFC PATCH 1/4] Add alias option to git branch","fromName":"Kenneth Cochran","fromEmail":"kenneth.cochran101@gmail.com","sentAt":"2019-03-04T15:47:22Z","receivedAt":"2019-03-04T15:47:27Z","isPatch":true,"sender":{"key":"kenneth.cochran101@gmail.com","avatar":null},"body":"From 2f6409a39b24db826a22d2813ec8d5de46723500 Mon Sep 17 00:00:00 2001\nFrom: Kenneth Cochran <kenneth.cochran101@gmail.com>\nDate: Tue, 26 Feb 2019 04:41:22 -0600\nSubject: [RFC PATCH 1/4] branch: add \"--alias\" option to create an alias\nCc: Sahil Dua <sahildua2305@gmail.com>,\n    Duy Nguyen <pclouds@gmail.com>,\n    Jeff King <peff@peff.net>\n\nOften, people have to use long or unweildly branch names\ne.g. `feature/<bug_number>`. When working locally, it's nice to be\nable to refer to that by something more friendly. It's already possible\nto do this, with `git symbolic-ref refs/heads/alias_name refs/heads/branch_name`\nI see three problems with this current approach:\n  1. Typing out \"refs/heads/\" is tedious and error prone\n  2. git will willingly overwrite existing branch names\n  3. Deleting a checked out symref leaves head in an invalid state.\n\nThis commit solves the first two of the above issues.\nI've implemented this as a new option for git branch, since this seemed like the\nbest place for it. We'll still need additional work to improve how git handles\ndeleting checked out symrefs.\n\nThese changes were originally proposed by Phil Sainty, but it doesn't seem\nlike there was ever any discussion about it:\nhttps://www.mail-archive.com/git@vger.kernel.org/msg161274.html\n\nReported-by: Phil Sainty <psainty@orcon.net.nz>\nSigned-off-by: Kenneth Cochran <kenneth.cochran101@gmail.com>\n---\n Documentation/git-branch.txt |  8 +++++\n builtin/branch.c             | 29 ++++++++++++++++--\n t/t3207-branch-alias.sh      | 58 ++++++++++++++++++++++++++++++++++++\n 3 files changed, 93 insertions(+), 2 deletions(-)\n create mode 100755 t/t3207-branch-alias.sh\n\ndiff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt\nindex 3bd83a7cbd..0476c8567b 100644\n--- a/Documentation/git-branch.txt\n+++ b/Documentation/git-branch.txt\n@@ -19,6 +19,7 @@ SYNOPSIS\n 'git branch' --unset-upstream [<branchname>]\n 'git branch' (-m | -M) [<oldbranch>] <newbranch>\n 'git branch' (-c | -C) [<oldbranch>] <newbranch>\n+'git branch' --alias <aliasname> [<branchname>]\n 'git branch' (-d | -D) [-r] <branchname>...\n 'git branch' --edit-description [<branchname>]\n \n@@ -69,6 +70,10 @@ The `-c` and `-C` options have the exact same semantics as `-m` and\n `-M`, except instead of the branch being renamed it along with its\n config and reflog will be copied to a new name.\n \n+With a `--alias` option, a symbolic ref with `<aliasname>` will be\n+created. You may specify a branch to create the alias for. If one is\n+not specified, the currently checked out branch is assumed.\n+\n With a `-d` or `-D` option, `<branchname>` will be deleted.  You may\n specify more than one branch for deletion.  If the branch currently\n has a reflog then the reflog will also be deleted.\n@@ -124,6 +129,9 @@ OPTIONS\n -C::\n \tShortcut for `--copy --force`.\n \n+--alias::\n+\tCreate an alias for a branch.\n+\n --color[=<when>]::\n \tColor branches to highlight current, local, and\n \tremote-tracking branches.\ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex 1be727209b..4b8b8fc08f 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -547,6 +547,20 @@ static void copy_or_rename_branch(const char *oldname, const char *newname, int\n \tstrbuf_release(&newsection);\n }\n \n+static void create_branch_alias(const char* branch_name, const char* alias_name) {\n+\tstruct strbuf branch_ref = STRBUF_INIT;\n+\tstruct strbuf alias_ref = STRBUF_INIT;\n+\n+\tif(!validate_branchname(branch_name, &branch_ref))\n+\t\tdie(_(\"%s is not a valid branch\"), branch_name);\n+\tvalidate_new_branchname(alias_name, &alias_ref, 0);\n+\tcreate_symref(alias_ref.buf, branch_ref.buf, \"\");\n+\n+\tstrbuf_release(&branch_ref);\n+\tstrbuf_release(&alias_ref);\n+\tprintf(_(\"%s created as an alias for %s\\n\"), alias_name, branch_name);\n+}\n+\n static GIT_PATH_FUNC(edit_description, \"EDIT_DESCRIPTION\")\n \n static int edit_branch_description(const char *branch_name)\n@@ -580,7 +594,7 @@ static int edit_branch_description(const char *branch_name)\n \n int cmd_branch(int argc, const char **argv, const char *prefix)\n {\n-\tint delete = 0, rename = 0, copy = 0, force = 0, list = 0;\n+\tint delete = 0, rename = 0, copy = 0, force = 0, list = 0, alias = 0;\n \tint reflog = 0, edit_description = 0;\n \tint quiet = 0, unset_upstream = 0;\n \tconst char *new_upstream = NULL;\n@@ -617,6 +631,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)\n \t\tOPT_BIT('D', NULL, &delete, N_(\"delete branch (even if not merged)\"), 2),\n \t\tOPT_BIT('m', \"move\", &rename, N_(\"move/rename a branch and its reflog\"), 1),\n \t\tOPT_BIT('M', NULL, &rename, N_(\"move/rename a branch, even if target exists\"), 2),\n+\t\tOPT_BOOL(0, \"alias\", &alias, N_(\"create an alias for a branch\")),\n \t\tOPT_BIT('c', \"copy\", &copy, N_(\"copy a branch and its reflog\"), 1),\n \t\tOPT_BIT('C', NULL, &copy, N_(\"copy a branch, even if target exists\"), 2),\n \t\tOPT_BOOL('l', \"list\", &list, N_(\"list branch names\")),\n@@ -662,7 +677,8 @@ int cmd_branch(int argc, const char **argv, const char *prefix)\n \targc = parse_options(argc, argv, prefix, options, builtin_branch_usage,\n \t\t\t     0);\n \n-\tif (!delete && !rename && !copy && !edit_description && !new_upstream && !unset_upstream && argc == 0)\n+\tif (!delete && !rename && !copy && !edit_description && !new_upstream && !unset_upstream &&\n+\t    !alias && argc == 0)\n \t\tlist = 1;\n \n \tif (filter.with_commit || filter.merge != REF_FILTER_MERGED_NONE || filter.points_at.nr ||\n@@ -762,6 +778,15 @@ int cmd_branch(int argc, const char **argv, const char *prefix)\n \t\t\tcopy_or_rename_branch(argv[0], argv[1], 0, rename > 1);\n \t\telse\n \t\t\tdie(_(\"too many arguments for a rename operation\"));\n+\t} else if (alias) {\n+\t\tif (!argc)\n+\t\t\tdie(_(\"alias name required\"));\n+\t\telse if (argc == 1)\n+\t\t\tcreate_branch_alias(head, argv[0]);\n+\t\telse if (argc == 2)\n+\t\t\tcreate_branch_alias(argv[1], argv[0]);\n+\t\telse\n+\t\t\tdie(_(\"too many arguments for an alias operation\"));\n \t} else if (new_upstream) {\n \t\tstruct branch *branch = branch_get(argv[0]);\n \ndiff --git a/t/t3207-branch-alias.sh b/t/t3207-branch-alias.sh\nnew file mode 100755\nindex 0000000000..9d4c8c2914\n--- /dev/null\n+++ b/t/t3207-branch-alias.sh\n@@ -0,0 +1,58 @@\n+#!/bin/sh\n+#\n+# Copyright (c) 2005 Amos Waterland\n+#\n+\n+test_description='git branch assorted tests'\n+\n+. ./test-lib.sh\n+. \"$TEST_DIRECTORY\"/lib-rebase.sh\n+\n+test_expect_success 'prepare a trivial repository' '\n+\techo Hello >A &&\n+\tgit update-index --add A &&\n+\tgit commit -m \"Initial commit.\" &&\n+\techo World >>A &&\n+\tgit update-index --add A &&\n+\tgit commit -m \"Second commit.\" &&\n+\tHEAD=$(git rev-parse --verify HEAD)\n+'\n+\n+test_expect_success 'git branch --alias' '\n+\ttest_must_fail git branch --alias\n+'\n+\n+test_expect_success 'git branch --alias sym' '\n+\techo \"sym created as an alias for master\" >expect &&\n+\tgit branch --alias sym >actual &&\n+\ttest_i18ncmp expect actual &&\n+\techo $HEAD >expect &&\n+\tgit rev-parse --verify sym >actual &&\n+\ttest_i18ncmp expect actual\n+'\n+\n+test_expect_success 'git branch --alias sym1 brnch' '\n+\tgit branch brnch &&\n+\techo \"sym1 created as an alias for brnch\" >expect &&\n+\tgit branch --alias sym1 brnch >actual &&\n+\ttest_i18ncmp expect actual &&\n+\tgit rev-parse --verify brnch >expect &&\n+\tgit rev-parse --verify sym1 >actual &&\n+\ttest_i18ncmp expect actual\n+'\n+\n+test_expect_success 'git branch --alias sym2 brnch2 third_arg' '\n+\ttest_must_fail git branch --alias sym2 brnch2 third_arg\n+'\n+\n+test_expect_success 'git branch --alias refuses to overwrite existing branch' '\n+\tgit branch bre &&\n+\ttest_must_fail git branch --alias bre\n+'\n+\n+test_expect_success 'git branch --alias refuses to overwrite existing symref' '\n+\tgit branch --alias syme &&\n+\ttest_must_fail git branch --alias syme\n+'\n+\n+test_done\n-- \n2.17.1\n\n\n"},{"id":"370615","messageId":"D9CFD250-26D4-4D1F-B0CD-01E24E8606D9@gmail.com","threadId":"50644","inReplyTo":"7D21A788-5E38-466F-B3CC-F6A5CBEB2E2E@gmail.com","subject":"Re: [RFC PATCH 2/4] Add alias option to git branch","fromName":"Kenneth Cochran","fromEmail":"kenneth.cochran101@gmail.com","sentAt":"2019-03-04T15:48:25Z","receivedAt":"2019-03-04T15:50:01Z","isPatch":true,"sender":{"key":"kenneth.cochran101@gmail.com","avatar":null},"body":"From 5aa6f037642df3b358ab659d17b5fb5bc7936f0f Mon Sep 17 00:00:00 2001\nFrom: Kenneth Cochran <kenneth.cochran101@gmail.com>\nDate: Sun, 3 Mar 2019 15:05:11 -0600\nSubject: [RFC PATCH 2/4] refs: add function to iteratively dereference symref\n chain\nCc: Sahil Dua <sahildua2305@gmail.com>,\n    Duy Nguyen <pclouds@gmail.com>,\n    Jeff King <peff@peff.net>\n\nAs far as I can tell, currently, there's not really any way\nto run something once per symref in a symref chain. This adds that\nability.\n\nThis will be useful for instance to improve how `git branch -d`\nhandles a checked out symref.\n\nSigned-off-by: Kenneth Cochran <kenneth.cochran101@gmail.com>\n---\n refs.c | 28 ++++++++++++++++++++++++++++\n refs.h | 13 +++++++++++++\n 2 files changed, 41 insertions(+)\n\ndiff --git a/refs.c b/refs.c\nindex 142888a40a..18a222d76a 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -1466,6 +1466,34 @@ static int do_for_each_ref(struct ref_store *refs, const char *prefix,\n \t\t\t\t\tdo_for_each_ref_helper, &hp);\n }\n \n+int refs_for_each_ref_in_chain(struct ref_store *refs, each_ref_fn fn,\n+\t\t\t       void *cb_data, const char *starting_ref)\n+{\n+\tint symref_count;\n+\tstruct object_id oid;\n+\tint flags;\n+\tconst char *ref_name = xstrdup(starting_ref);\n+\tint res;\n+\n+\tfor (symref_count = 0; symref_count < SYMREF_MAXDEPTH; symref_count++) {\n+\t\tres = fn(ref_name, &oid, flags, cb_data);\n+\t\tref_name = refs_resolve_ref_unsafe(refs, ref_name, RESOLVE_REF_NO_RECURSE,\n+\t\t\t\t\t\t   &oid, &flags);\n+\n+\t\tif (res)\n+\t\t\treturn res;\n+\t\tif (!(flags & REF_ISSYMREF))\n+\t\t\tbreak;\n+\t}\n+\treturn 0;\n+}\n+\n+int for_each_ref_in_chain(each_ref_fn fn, void *cb_data, const char *starting_ref)\n+{\n+\treturn refs_for_each_ref_in_chain(get_main_ref_store(the_repository), fn,\n+\t\t\t\t\t  cb_data, starting_ref);\n+}\n+\n int refs_for_each_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data)\n {\n \treturn do_for_each_ref(refs, \"\", fn, 0, 0, cb_data);\ndiff --git a/refs.h b/refs.h\nindex 308fa1f03b..66ccb85e8d 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -327,6 +327,19 @@ int for_each_glob_ref_in(each_ref_fn fn, const char *pattern,\n int head_ref_namespaced(each_ref_fn fn, void *cb_data);\n int for_each_namespaced_ref(each_ref_fn fn, void *cb_data);\n \n+/*\n+ * Iteratively calls fn with each reference in a symref chain.\n+ * Iteration will continue until one of the following occurs:\n+ * - SYMREF_MAXDEPTH is reached\n+ * - A non-symbolic ref is reached (fn will be called with this before returning)\n+ * - fn returns a non 0 value\n+ *\n+ * Will always return 0 unless fn returns a non-zero value.\n+ */\n+int refs_for_each_ref_in_chain(struct ref_store *refs, each_ref_fn fn,\n+\t\t\t       void *cb_data, const char *starting_ref);\n+int for_each_ref_in_chain(each_ref_fn fn, void *cb_data, const char *starting_ref);\n+\n /* can be used to learn about broken ref and symref */\n int refs_for_each_rawref(struct ref_store *refs, each_ref_fn fn, void *cb_data);\n int for_each_rawref(each_ref_fn fn, void *cb_data);\n-- \n2.17.1\n\n\n"},{"id":"370616","messageId":"D4829D84-9192-4C7A-8487-0374DAFC324A@gmail.com","threadId":"50644","inReplyTo":"D9CFD250-26D4-4D1F-B0CD-01E24E8606D9@gmail.com","subject":"Re: [RFC PATCH 3/4] Add alias option to git branch","fromName":"Kenneth Cochran","fromEmail":"kenneth.cochran101@gmail.com","sentAt":"2019-03-04T15:49:12Z","receivedAt":"2019-03-04T15:50:03Z","isPatch":true,"sender":{"key":"kenneth.cochran101@gmail.com","avatar":null},"body":"From 9f9b9010cb0b8c2874428d2f4bd21f06f747bfee Mon Sep 17 00:00:00 2001\nFrom: Kenneth Cochran <kenneth.cochran101@gmail.com>\nDate: Sun, 3 Mar 2019 15:34:20 -0600\nSubject: [RFC PATCH 3/4] worktree: symref should be found anywhere in chain\nCc: Sahil Dua <sahildua2305@gmail.com>,\n    Duy Nguyen <pclouds@gmail.com>,\n    Jeff King <peff@peff.net>\n\nCurrently, when searching for a shared symref, a symref chain is\nfully dereferenced before checking the name. This poses problems for\n`git branch -d` which will happily delete a checked out symref.\n\nThe existing behaviour (recognizing a non-symbolic ref by the same name)\nstill exists, but it will now also find any symref that is in between the\nstarting symref and the first non-symbolic ref.\n\nConcretely, for the following chain\nHEAD -> symref1 -> symref2 -> master\npreviously the function was only able to find master.\nWith these changes applied, it will be able to find any of the above references.\n\nSigned-off-by: Kenneth Cochran <kenneth.cochran101@gmail.com>\n---\n t/t3207-branch-alias.sh | 13 +++++++++++++\n worktree.c              | 18 ++++++++++++------\n 2 files changed, 25 insertions(+), 6 deletions(-)\n\ndiff --git a/t/t3207-branch-alias.sh b/t/t3207-branch-alias.sh\nindex 9d4c8c2914..c1edeed4eb 100755\n--- a/t/t3207-branch-alias.sh\n+++ b/t/t3207-branch-alias.sh\n@@ -55,4 +55,17 @@ test_expect_success 'git branch --alias refuses to overwrite existing symref' '\n \ttest_must_fail git branch --alias syme\n '\n \n+test_expect_success 'git branch -d refuses to delete a checked out symref' '\n+\tgit branch --alias symd &&\n+\tgit checkout symd &&\n+\ttest_must_fail git branch -d symd\n+'\n+\n+test_expect_success 'git branch -d refuses to delete an indirectly checked out symref' '\n+\tgit symbolic-ref refs/heads/symd2 refs/heads/symd &&\n+\tgit checkout symd2 &&\n+\ttest_must_fail git branch -d symd2 &&\n+\ttest_must_fail git branch -d symd\n+'\n+\n test_done\ndiff --git a/worktree.c b/worktree.c\nindex d6a0ee7f73..b58325c6c1 100644\n--- a/worktree.c\n+++ b/worktree.c\n@@ -387,6 +387,17 @@ int is_worktree_being_bisected(const struct worktree *wt,\n \treturn found_rebase;\n }\n \n+static int find_symref_by_name(const char *ref_name, const struct object_id *oid,\n+\t\t\t       int flags, void *cb_data)\n+{\n+\tconst char *target = (const char *)cb_data;\n+\n+\tif ((flags & REF_ISSYMREF) && !strcmp(target, ref_name))\n+\t\treturn 1;\n+\telse\n+\t\treturn 0;\n+}\n+\n /*\n  * note: this function should be able to detect shared symref even if\n  * HEAD is temporarily detached (e.g. in the middle of rebase or\n@@ -406,9 +417,7 @@ const struct worktree *find_shared_symref(const char *symref,\n \n \tfor (i = 0; worktrees[i]; i++) {\n \t\tstruct worktree *wt = worktrees[i];\n-\t\tconst char *symref_target;\n \t\tstruct ref_store *refs;\n-\t\tint flags;\n \n \t\tif (wt->is_bare)\n \t\t\tcontinue;\n@@ -425,10 +434,7 @@ const struct worktree *find_shared_symref(const char *symref,\n \t\t}\n \n \t\trefs = get_worktree_ref_store(wt);\n-\t\tsymref_target = refs_resolve_ref_unsafe(refs, symref, 0,\n-\t\t\t\t\t\t\tNULL, &flags);\n-\t\tif ((flags & REF_ISSYMREF) &&\n-\t\t    symref_target && !strcmp(symref_target, target)) {\n+\t\tif(refs_for_each_ref_in_chain(refs, find_symref_by_name, (void *)target, symref)) {\n \t\t\texisting = wt;\n \t\t\tbreak;\n \t\t}\n-- \n2.17.1\n\n\n"},{"id":"370617","messageId":"C678086A-93E9-4F0B-AAAA-FBBBC27F2BFC@gmail.com","threadId":"50644","inReplyTo":"D4829D84-9192-4C7A-8487-0374DAFC324A@gmail.com","subject":"Re: [RFC PATCH 4/4] Add alias option to git branch","fromName":"Kenneth Cochran","fromEmail":"kenneth.cochran101@gmail.com","sentAt":"2019-03-04T15:49:56Z","receivedAt":"2019-03-04T15:50:05Z","isPatch":true,"sender":{"key":"kenneth.cochran101@gmail.com","avatar":null},"body":"From c1bad54b29ae1c1d8548d248f6ecaa5959e55f7b Mon Sep 17 00:00:00 2001\nFrom: Kenneth Cochran <kenneth.cochran101@gmail.com>\nDate: Mon, 4 Mar 2019 01:08:46 -0600\nSubject: [RFC PATCH 4/4] branch: disallow accidentally breaking symrefs\nCc: Sahil Dua <sahildua2305@gmail.com>,\n    Duy Nguyen <pclouds@gmail.com>,\n    Jeff King <peff@peff.net>\n\nCurrently, symrefs are ignored when deleting a branch, making\nit possible to accidentally create dangling symrefs without any\nwarning.\n\nThese changes give an error if a branch deletion operation would\ncreate a dangling symref, unless the user specifies to force the\ndelete anyways.\n\nSigned-off-by: Kenneth Cochran <kenneth.cochran101@gmail.com>\n---\n builtin/branch.c        | 20 ++++++++++++++++++++\n t/t3207-branch-alias.sh | 12 ++++++++++++\n 2 files changed, 32 insertions(+)\n\ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex 4b8b8fc08f..5c05ccd5e9 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -233,6 +233,11 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,\n \t\tif (kinds == FILTER_REFS_BRANCHES) {\n \t\t\tconst struct worktree *wt =\n \t\t\t\tfind_shared_symref(\"HEAD\", name);\n+\t\t\tchar *buf;\n+\t\t\tsize_t len;\n+\t\t\tFILE *memstream;\n+\t\t\tint cont = 0;\n+\n \t\t\tif (wt) {\n \t\t\t\terror(_(\"Cannot delete branch '%s' \"\n \t\t\t\t\t\"checked out at '%s'\"),\n@@ -240,6 +245,21 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,\n \t\t\t\tret = 1;\n \t\t\t\tcontinue;\n \t\t\t}\n+\n+\t\t\tmemstream = open_memstream(&buf, &len);\n+\t\t\twarn_dangling_symref(memstream, \"%s\", name);\n+\t\t\tfclose(memstream);\n+\t\t\tbuf[strcspn(buf, \"\\n\")] = '\\0';\n+\t\t\tif (len > 0 && !force) {\n+\t\t\t\tcont = 1;\n+\t\t\t\terror(_(\"Deleting branch '%s' would leave dangling symrefs.\\n\"\n+\t\t\t\t\t\"If you're sure you want to delete it, run 'git branch -D %s'\\n\"\n+\t\t\t\t\t\"The following symrefs would be left dangling:\\n%s\"),\n+\t\t\t\t      bname.buf, bname.buf, buf);\n+\t\t\t}\n+\t\t\tfree(buf);\n+\t\t\tif (cont)\n+\t\t\t\tcontinue;\n \t\t}\n \n \t\ttarget = resolve_refdup(name,\ndiff --git a/t/t3207-branch-alias.sh b/t/t3207-branch-alias.sh\nindex c1edeed4eb..2f3a7b398b 100755\n--- a/t/t3207-branch-alias.sh\n+++ b/t/t3207-branch-alias.sh\n@@ -68,4 +68,16 @@ test_expect_success 'git branch -d refuses to delete an indirectly checked out s\n \ttest_must_fail git branch -d symd\n '\n \n+test_expect_success 'git branch -d refuses to create a dangling symref' '\n+\tgit branch dangling_parent &&\n+\tgit branch --alias dangling dangling_parent &&\n+\tgit branch -d dangling_parent &&\n+\ttest_path_is_file .git/refs/heads/dangling_parent\n+'\n+\n+test_expect_success 'git branch -D forces creation of dangling symref' '\n+\tgit branch -D dangling_parent &&\n+\ttest_must_fail test_path_is_file .git/refs/heads/dangling_parent\n+'\n+\n test_done\n-- \n2.17.1\n\n\n"},{"id":"370618","messageId":"CAJ145vVvFowZXFGZE=MB+DiC0n_dnqm3vU_YC-80aA0_7kUcbA@mail.gmail.com","threadId":"50644","inReplyTo":"C678086A-93E9-4F0B-AAAA-FBBBC27F2BFC@gmail.com","subject":"Re: [RFC PATCH 4/4] Add alias option to git branch","fromName":"Kenneth Cochran","fromEmail":"kenneth.cochran101@gmail.com","sentAt":"2019-03-04T16:38:35Z","receivedAt":"2019-03-04T16:38:50Z","isPatch":true,"sender":{"key":"kenneth.cochran101@gmail.com","avatar":null},"body":"Adding Phil for comments\n"},{"id":"370629","messageId":"CAJ145vUOYcMvozYtWx2QJOWCSGw__-Cs3w_sxKhwwtHFQt-qHA@mail.gmail.com","threadId":"50644","inReplyTo":"95defc95-c558-3487-d418-e65f7db5dda5@orcon.net.nz","subject":"Re: [RFC PATCH 4/4] Add alias option to git branch","fromName":"Kenneth Cochran","fromEmail":"kenneth.cochran101@gmail.com","sentAt":"2019-03-04T19:52:10Z","receivedAt":"2019-03-04T19:52:25Z","isPatch":true,"sender":{"key":"kenneth.cochran101@gmail.com","avatar":null},"body":"On Mon, Mar 4, 2019 at 1:34 PM Phil Sainty <psainty@orcon.net.nz> wrote:\n>\n> 5/03/19 5:23 AM, Kenneth Cochran wrote:\n> > Adding Phil for comments\n>\n> Thank you for following this up, Kenneth.  I'll do some testing with\n> your patch sometime soon.\n\nThanks! Any feedback is appreciated.\n\n>\n> I've realised that the last version of my script that I posted to the\n> mailing list was buggy, and that in wanting to hold off sending another\n> version for a little while in case I found more bugs, I in fact failed\n> to send a fixed version at all.\n>\n> This is probably not relevant to your patches; but just in case,\n> the up to date code for that script is here:\n>\n> https://stackoverflow.com/a/23532744/324105\n\nThis stack overflow post was actually what led me to the git mailing\nlist in the first place :)\n\n>\n> and the fixes since v1.11 were:\n>\n> * Change incorrect uses of git show-ref, introduced by v1.10 (including\n>   effective regression of v1.08), to use git symbolic-ref instead.\n>\n> * Fix the option handling for '--', and added it to the help text.\n>\n>\n> -Phil\n\nOn Mon, Mar 4, 2019 at 1:34 PM Phil Sainty <psainty@orcon.net.nz> wrote:\n>\n> 5/03/19 5:23 AM, Kenneth Cochran wrote:\n> > Adding Phil for comments\n>\n> Thank you for following this up, Kenneth.  I'll do some testing with\n> your patch sometime soon.\n>\n> I've realised that the last version of my script that I posted to the\n> mailing list was buggy, and that in wanting to hold off sending another\n> version for a little while in case I found more bugs, I in fact failed\n> to send a fixed version at all.\n>\n> This is probably not relevant to your patches; but just in case,\n> the up to date code for that script is here:\n>\n> https://stackoverflow.com/a/23532744/324105\n>\n> and the fixes since v1.11 were:\n>\n> * Change incorrect uses of git show-ref, introduced by v1.10 (including\n>   effective regression of v1.08), to use git symbolic-ref instead.\n>\n> * Fix the option handling for '--', and added it to the help text.\n>\n>\n> -Phil\n"},{"id":"370632","messageId":"95defc95-c558-3487-d418-e65f7db5dda5@orcon.net.nz","threadId":"50644","inReplyTo":"CAJ145vUChd7+5QkmJsOK3bzZsudWfzZYp5wHZDzoq8SKSv0g0A@mail.gmail.com","subject":"Re: [RFC PATCH 4/4] Add alias option to git branch","fromName":"Phil Sainty","fromEmail":"psainty@orcon.net.nz","sentAt":"2019-03-04T19:33:58Z","receivedAt":"2019-03-04T20:15:31Z","isPatch":true,"sender":{"key":"psainty@orcon.net.nz","avatar":null},"body":"5/03/19 5:23 AM, Kenneth Cochran wrote:\n> Adding Phil for comments\n\nThank you for following this up, Kenneth.  I'll do some testing with\nyour patch sometime soon.\n\nI've realised that the last version of my script that I posted to the\nmailing list was buggy, and that in wanting to hold off sending another\nversion for a little while in case I found more bugs, I in fact failed\nto send a fixed version at all.\n\nThis is probably not relevant to your patches; but just in case,\nthe up to date code for that script is here:\n\nhttps://stackoverflow.com/a/23532744/324105\n\nand the fixes since v1.11 were:\n\n* Change incorrect uses of git show-ref, introduced by v1.10 (including\n  effective regression of v1.08), to use git symbolic-ref instead.\n\n* Fix the option handling for '--', and added it to the help text.\n\n\n-Phil\n"},{"id":"370710","messageId":"xmqqa7i9v4mv.fsf@gitster-ct.c.googlers.com","threadId":"50644","inReplyTo":"47CA9077-E8C1-4093-8B36-2D5D3DE2D886@gmail.com","subject":"Re: [RFC PATCH 0/4] Add alias option to git branch","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-03-05T13:21:12Z","receivedAt":"2019-03-05T13:21:17Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Kenneth Cochran <kenneth.cochran101@gmail.com> writes:\n\n> From c1bad54b29ae1c1d8548d248f6ecaa5959e55f7b Mon Sep 17 00:00:00 2001\n> From: Kenneth Cochran <kenneth.cochran101@gmail.com>\n> Date: Mon, 4 Mar 2019 09:40:22 -0600\n> Subject: [RFC PATCH 0/4] Add alias option to git branch\n> Cc: Sahil Dua <sahildua2305@gmail.com>,\n>     Duy Nguyen <pclouds@gmail.com>,\n>     Jeff King <peff@peff.net>\n\nAvoid using these in-body headers.\n\nReader's MUA won't show this \"Subject:\", but instead show the same\n\"Add alias option to gir branch\", among hundreds of mailing list\nmessages, making it very tempting to ignore these four messages.\n\n\n> I find myself often using git symbolic-ref to get around work requirements to use branch names that are not very human friendly.\n> There are a few problems with this:\n> \t- There’s a lot of text to type\n> \t- Mistyping certain parts (heads/refs) will do things other than create a branch alias\n> \t- It will happily overwrite an existing branch\n> \t- Deleting one that is checked out will put HEAD in an invalid state.\n\nMeh.\n\nAll of the above are problems _you_ create by trying to use symbolic\nrefs.  If the project wants to use an overlong branch name, using it\nwith \"git branch\" or \"git checkout\" or whatever would be a much\nbetter solution.  Command-line completion will complete long branch\nnames, and \"git branch overly-long-name-of-an-existing-branch\" will\nnot overwrite an existing branch (without --force).  \"git branch -d\noverly-long-name-of-an-existing-branch\" would not delete an\nchecked-out branch, either.\n\n"},{"id":"370725","messageId":"CAJ145vW3HPaP2GeSL65q5C1XhYpiE+7=apU1ia=17eNWPfRj_g@mail.gmail.com","threadId":"50644","inReplyTo":"xmqqa7i9v4mv.fsf@gitster-ct.c.googlers.com","subject":"Re: [RFC PATCH 0/4] Add alias option to git branch","fromName":"Kenneth Cochran","fromEmail":"kenneth.cochran101@gmail.com","sentAt":"2019-03-05T17:36:35Z","receivedAt":"2019-03-05T17:36:51Z","isPatch":true,"sender":{"key":"kenneth.cochran101@gmail.com","avatar":null},"body":"On Tue, Mar 5, 2019 at 7:21 AM Junio C Hamano <gitster@pobox.com> wrote:\n>\n> Kenneth Cochran <kenneth.cochran101@gmail.com> writes:\n>\n> > From c1bad54b29ae1c1d8548d248f6ecaa5959e55f7b Mon Sep 17 00:00:00 2001\n> > From: Kenneth Cochran <kenneth.cochran101@gmail.com>\n> > Date: Mon, 4 Mar 2019 09:40:22 -0600\n> > Subject: [RFC PATCH 0/4] Add alias option to git branch\n> > Cc: Sahil Dua <sahildua2305@gmail.com>,\n> >     Duy Nguyen <pclouds@gmail.com>,\n> >     Jeff King <peff@peff.net>\n>\n> Avoid using these in-body headers.\n>\n> Reader's MUA won't show this \"Subject:\", but instead show the same\n> \"Add alias option to gir branch\", among hundreds of mailing list\n> messages, making it very tempting to ignore these four messages.\n>\n\nThanks, I'll be sure to fix that in the future.\n\n>\n> > I find myself often using git symbolic-ref to get around work requirements to use branch names that are not very human friendly.\n> > There are a few problems with this:\n> >       - There’s a lot of text to type\n> >       - Mistyping certain parts (heads/refs) will do things other than create a branch alias\n> >       - It will happily overwrite an existing branch\n> >       - Deleting one that is checked out will put HEAD in an invalid state.\n>\n> Meh.\n>\n> All of the above are problems _you_ create by trying to use symbolic\n> refs.  If the project wants to use an overlong branch name, using it\n> with \"git branch\" or \"git checkout\" or whatever would be a much\n> better solution.  Command-line completion will complete long branch\n> names, and \"git branch overly-long-name-of-an-existing-branch\" will\n> not overwrite an existing branch (without --force).  \"git branch -d\n> overly-long-name-of-an-existing-branch\" would not delete an\n> checked-out branch, either.\n>\n\nI definitely agree, I had only meant that these were problems with my\ncurrent solution of using git symbolic-ref directly - problems that these\npatches are meant to fix. I probably should have included more\ninformation about why I use that solution in the first place.\n\nCommand line completion definitely helps in some cases, but not all - for\nexample, let's say I have two branches, feature/PRODUCT-13032 and\nfeature/PRODUCT-13023. These branches are generally short lived, so\nthey're not around long enough that the numbers have much meaning to\nme - even with tab completion, I need to have the bug tracking software\nopen alongside the terminal in order to keep them separated. This can be\neven more pronounced when working on several branches that are\nnumbered in sequence.\n\n`git checkout foo` is much easier than `git checkout feature/PRODUCT-13032`,\neven with tab completion. There's a significant number of stack overflow\nquestions about this functionality, and for almost all of them,\n`git symbolic-ref refs/heads/newname refs/heads/branchname` is the accepted\nanswer. There's definitely interest in having this ability besides just me.\n"},{"id":"370799","messageId":"b490c79b-37e0-7c6d-8643-3ec2343411ac@orcon.net.nz","threadId":"50644","inReplyTo":"CAJ145vW3HPaP2GeSL65q5C1XhYpiE+7=apU1ia=17eNWPfRj_g@mail.gmail.com","subject":"Re: [RFC PATCH 0/4] Add alias option to git branch","fromName":"Phil Sainty","fromEmail":"psainty@orcon.net.nz","sentAt":"2019-03-06T10:13:48Z","receivedAt":"2019-03-06T10:13:53Z","isPatch":true,"sender":{"key":"psainty@orcon.net.nz","avatar":null},"body":"I can only concur about the genuine usefulness of symbolic refs as\nbranch aliases.  I wrote my shell script for this 5 years ago, and\nI've made use of the facility almost every working day since.\n\nI jump around branches frequently, and my feature branch names always\nstart with an issue/bug number followed by a short description -- which\nis perfect for listings and seeing at a glance what a branch is about,\nand terrible for tab-completion.\n\nThose long branch names are useful and informative for the developers\non the project, but being able to also have a 2-3 letter alias in my\nworking copy for the lifetime of a branch -- something which is trivial\nfor me to remember and type -- gives me the best of both worlds, and\nI find it to be a tremendous convenience.\n\nIt's really not dissimilar to why so many people find shell aliases\nto be so handy.\n\nThe nice thing is that all the plumbing is already there and working.\nI've used it happily for 5 years, and other people use it similarly.\nThis feature just adds some protective porcelain over it, so that\npeople can more easily make use of the existing benefits without any\nof the potential dangers.\n\n\n-Phil\n"}]}