>From 2f6409a39b24db826a22d2813ec8d5de46723500 Mon Sep 17 00:00:00 2001 From: Kenneth Cochran <kenneth.cochran101@xxxxxxxxx> Date: Tue, 26 Feb 2019 04:41:22 -0600 Subject: [RFC PATCH 1/4] branch: add "--alias" option to create an alias Cc: Sahil Dua <sahildua2305@xxxxxxxxx>, Duy Nguyen <pclouds@xxxxxxxxx>, Jeff King <peff@xxxxxxxx> Often, people have to use long or unweildly branch names e.g. `feature/<bug_number>`. When working locally, it's nice to be able to refer to that by something more friendly. It's already possible to do this, with `git symbolic-ref refs/heads/alias_name refs/heads/branch_name` I see three problems with this current approach: 1. Typing out "refs/heads/" is tedious and error prone 2. git will willingly overwrite existing branch names 3. Deleting a checked out symref leaves head in an invalid state. This commit solves the first two of the above issues. I've implemented this as a new option for git branch, since this seemed like the best place for it. We'll still need additional work to improve how git handles deleting checked out symrefs. These changes were originally proposed by Phil Sainty, but it doesn't seem like there was ever any discussion about it: https://www.mail-archive.com/git@xxxxxxxxxxxxxxx/msg161274.html Reported-by: Phil Sainty <psainty@xxxxxxxxxxxx> Signed-off-by: Kenneth Cochran <kenneth.cochran101@xxxxxxxxx> --- Documentation/git-branch.txt | 8 +++++ builtin/branch.c | 29 ++++++++++++++++-- t/t3207-branch-alias.sh | 58 ++++++++++++++++++++++++++++++++++++ 3 files changed, 93 insertions(+), 2 deletions(-) create mode 100755 t/t3207-branch-alias.sh diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt index 3bd83a7cbd..0476c8567b 100644 --- a/Documentation/git-branch.txt +++ b/Documentation/git-branch.txt @@ -19,6 +19,7 @@ SYNOPSIS 'git branch' --unset-upstream [<branchname>] 'git branch' (-m | -M) [<oldbranch>] <newbranch> 'git branch' (-c | -C) [<oldbranch>] <newbranch> +'git branch' --alias <aliasname> [<branchname>] 'git branch' (-d | -D) [-r] <branchname>... 'git branch' --edit-description [<branchname>] @@ -69,6 +70,10 @@ The `-c` and `-C` options have the exact same semantics as `-m` and `-M`, except instead of the branch being renamed it along with its config and reflog will be copied to a new name. +With a `--alias` option, a symbolic ref with `<aliasname>` will be +created. You may specify a branch to create the alias for. If one is +not specified, the currently checked out branch is assumed. + With a `-d` or `-D` option, `<branchname>` will be deleted. You may specify more than one branch for deletion. If the branch currently has a reflog then the reflog will also be deleted. @@ -124,6 +129,9 @@ OPTIONS -C:: Shortcut for `--copy --force`. +--alias:: + Create an alias for a branch. + --color[=<when>]:: Color branches to highlight current, local, and remote-tracking branches. diff --git a/builtin/branch.c b/builtin/branch.c index 1be727209b..4b8b8fc08f 100644 --- a/builtin/branch.c +++ b/builtin/branch.c @@ -547,6 +547,20 @@ static void copy_or_rename_branch(const char *oldname, const char *newname, int strbuf_release(&newsection); } +static void create_branch_alias(const char* branch_name, const char* alias_name) { + struct strbuf branch_ref = STRBUF_INIT; + struct strbuf alias_ref = STRBUF_INIT; + + if(!validate_branchname(branch_name, &branch_ref)) + die(_("%s is not a valid branch"), branch_name); + validate_new_branchname(alias_name, &alias_ref, 0); + create_symref(alias_ref.buf, branch_ref.buf, ""); + + strbuf_release(&branch_ref); + strbuf_release(&alias_ref); + printf(_("%s created as an alias for %s\n"), alias_name, branch_name); +} + static GIT_PATH_FUNC(edit_description, "EDIT_DESCRIPTION") static int edit_branch_description(const char *branch_name) @@ -580,7 +594,7 @@ static int edit_branch_description(const char *branch_name) int cmd_branch(int argc, const char **argv, const char *prefix) { - int delete = 0, rename = 0, copy = 0, force = 0, list = 0; + int delete = 0, rename = 0, copy = 0, force = 0, list = 0, alias = 0; int reflog = 0, edit_description = 0; int quiet = 0, unset_upstream = 0; const char *new_upstream = NULL; @@ -617,6 +631,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix) OPT_BIT('D', NULL, &delete, N_("delete branch (even if not merged)"), 2), OPT_BIT('m', "move", &rename, N_("move/rename a branch and its reflog"), 1), OPT_BIT('M', NULL, &rename, N_("move/rename a branch, even if target exists"), 2), + OPT_BOOL(0, "alias", &alias, N_("create an alias for a branch")), OPT_BIT('c', "copy", ©, N_("copy a branch and its reflog"), 1), OPT_BIT('C', NULL, ©, N_("copy a branch, even if target exists"), 2), OPT_BOOL('l', "list", &list, N_("list branch names")), @@ -662,7 +677,8 @@ int cmd_branch(int argc, const char **argv, const char *prefix) argc = parse_options(argc, argv, prefix, options, builtin_branch_usage, 0); - if (!delete && !rename && !copy && !edit_description && !new_upstream && !unset_upstream && argc == 0) + if (!delete && !rename && !copy && !edit_description && !new_upstream && !unset_upstream && + !alias && argc == 0) list = 1; if (filter.with_commit || filter.merge != REF_FILTER_MERGED_NONE || filter.points_at.nr || @@ -762,6 +778,15 @@ int cmd_branch(int argc, const char **argv, const char *prefix) copy_or_rename_branch(argv[0], argv[1], 0, rename > 1); else die(_("too many arguments for a rename operation")); + } else if (alias) { + if (!argc) + die(_("alias name required")); + else if (argc == 1) + create_branch_alias(head, argv[0]); + else if (argc == 2) + create_branch_alias(argv[1], argv[0]); + else + die(_("too many arguments for an alias operation")); } else if (new_upstream) { struct branch *branch = branch_get(argv[0]); diff --git a/t/t3207-branch-alias.sh b/t/t3207-branch-alias.sh new file mode 100755 index 0000000000..9d4c8c2914 --- /dev/null +++ b/t/t3207-branch-alias.sh @@ -0,0 +1,58 @@ +#!/bin/sh +# +# Copyright (c) 2005 Amos Waterland +# + +test_description='git branch assorted tests' + +. ./test-lib.sh +. "$TEST_DIRECTORY"/lib-rebase.sh + +test_expect_success 'prepare a trivial repository' ' + echo Hello >A && + git update-index --add A && + git commit -m "Initial commit." && + echo World >>A && + git update-index --add A && + git commit -m "Second commit." && + HEAD=$(git rev-parse --verify HEAD) +' + +test_expect_success 'git branch --alias' ' + test_must_fail git branch --alias +' + +test_expect_success 'git branch --alias sym' ' + echo "sym created as an alias for master" >expect && + git branch --alias sym >actual && + test_i18ncmp expect actual && + echo $HEAD >expect && + git rev-parse --verify sym >actual && + test_i18ncmp expect actual +' + +test_expect_success 'git branch --alias sym1 brnch' ' + git branch brnch && + echo "sym1 created as an alias for brnch" >expect && + git branch --alias sym1 brnch >actual && + test_i18ncmp expect actual && + git rev-parse --verify brnch >expect && + git rev-parse --verify sym1 >actual && + test_i18ncmp expect actual +' + +test_expect_success 'git branch --alias sym2 brnch2 third_arg' ' + test_must_fail git branch --alias sym2 brnch2 third_arg +' + +test_expect_success 'git branch --alias refuses to overwrite existing branch' ' + git branch bre && + test_must_fail git branch --alias bre +' + +test_expect_success 'git branch --alias refuses to overwrite existing symref' ' + git branch --alias syme && + test_must_fail git branch --alias syme +' + +test_done -- 2.17.1