Web lists-archives.com

Re: [RFC PATCH 1/4] Add alias option to git branch




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", &copy, N_("copy a branch and its reflog"), 1),
 		OPT_BIT('C', NULL, &copy, 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