[RFC] Teach git-branch howto rename a branch

Subsystems: the rest

4 messages, 3 authors, 2016-08-11 · open the first message on its own page

[RFC] Teach git-branch howto rename a branch

From: Lars Hjemli <hidden>
Date: 2016-08-11 19:27:40

This adds a '--rename' option to git branch. If specified, branch
creation becomes branch renaming.

With a single branchname, the current branch is renamed and .git/HEAD is
updated.

With two branchnames, the second name is renamed to the first.

Signed-off-by: Lars Hjemli <redacted>
---
 builtin-branch.c |  117 +++++++++++++++++++++++++++++++++++------------------
 1 files changed, 77 insertions(+), 40 deletions(-)
diff --git a/builtin-branch.c b/builtin-branch.c
index f14d814..e714569 100644
--- a/builtin-branch.c
+++ b/builtin-branch.c
@@ -11,7 +11,7 @@
 #include "builtin.h"
 
 static const char builtin_branch_usage[] =
-"git-branch (-d | -D) <branchname> | [-l] [-f] <branchname> [<start-point>] | [-r | -a] [-v] [--abbrev=<length>] ";
+"git-branch (-d | -D) <branchname> | [-l] [-f] [--rename] <branchname> [<start-point>] | [-r | -a] [-v] [--abbrev=<length>] ";
 
 
 static const char *head;
@@ -36,47 +36,55 @@ static int in_merge_bases(const unsigned
 	return ret;
 }
 
-static void delete_branches(int argc, const char **argv, int force)
+static void delete_branch(const char *branch, int force, struct commit *head_rev)
 {
-	struct commit *rev, *head_rev;
-	unsigned char sha1[20];
+	struct commit *rev;
 	char *name;
-	int i;
+	unsigned char sha1[20];
 
-	head_rev = lookup_commit_reference(head_sha1);
-	for (i = 0; i < argc; i++) {
-		if (!strcmp(head, argv[i]))
-			die("Cannot delete the branch you are currently on.");
-
-		name = xstrdup(mkpath("refs/heads/%s", argv[i]));
-		if (!resolve_ref(name, sha1, 1, NULL))
-			die("Branch '%s' not found.", argv[i]);
-
-		rev = lookup_commit_reference(sha1);
-		if (!rev || !head_rev)
-			die("Couldn't look up commit objects.");
-
-		/* This checks whether the merge bases of branch and
-		 * HEAD contains branch -- which means that the HEAD
-		 * contains everything in both.
-		 */
-
-		if (!force &&
-		    !in_merge_bases(sha1, rev, head_rev)) {
-			fprintf(stderr,
-				"The branch '%s' is not a strict subset of your current HEAD.\n"
-				"If you are sure you want to delete it, run 'git branch -D %s'.\n",
-				argv[i], argv[i]);
-			exit(1);
-		}
+	if (!strcmp(head, branch))
+		die("Cannot delete the branch you are currently on.");
+
+	name = xstrdup(mkpath("refs/heads/%s", branch));
+	if (!resolve_ref(name, sha1, 1, NULL))
+		die("Branch '%s' not found.", branch);
+
+	rev = lookup_commit_reference(sha1);
+	if (!rev)
+		die("Couldn't look up commit objects for %s", branch);
+
+	/* This checks whether the merge bases of branch and
+	 * HEAD contains branch -- which means that the HEAD
+	 * contains everything in both.
+	 */
+
+	if (head_rev && !force &&
+	    !in_merge_bases(sha1, rev, head_rev)) {
+		fprintf(stderr,
+			"The branch '%s' is not a strict subset of your current HEAD.\n"
+			"If you are sure you want to delete it, run 'git branch -D %s'.\n",
+			branch, branch);
+		exit(1);
+	}
 
-		if (delete_ref(name, sha1))
-			printf("Error deleting branch '%s'\n", argv[i]);
-		else
-			printf("Deleted branch %s.\n", argv[i]);
+	if (delete_ref(name, sha1))
+		printf("Error deleting branch '%s'\n", branch);
+	else
+		printf("Deleted branch %s.\n", branch);
 
-		free(name);
-	}
+	free(name);
+}
+
+static void delete_branches(int argc, const char **argv, int force)
+{
+	struct commit *head_rev;
+	int i;
+	
+	head_rev = lookup_commit_reference(head_sha1);
+	if (!head_rev)
+		die("Couldn't look up commit object for current HEAD.");
+	for (i = 0; i < argc; i++) 
+		delete_branch(argv[i], force, head_rev);
 }
 
 #define REF_UNKNOWN_TYPE    0x00
@@ -200,15 +208,18 @@ static void print_ref_list(int kinds, in
 	free_ref_list(&ref_list);
 }
 
-static void create_branch(const char *name, const char *start,
+static char *create_branch(const char *name, const char *start,
 			  int force, int reflog)
 {
 	struct ref_lock *lock;
 	struct commit *commit;
 	unsigned char sha1[20];
-	char ref[PATH_MAX], msg[PATH_MAX + 20];
+	char *ref, msg[PATH_MAX + 20];
+	int reflen;
 
-	snprintf(ref, sizeof ref, "refs/heads/%s", name);
+	reflen = strlen(name) + 12;
+	ref = xmalloc(reflen+1);
+	snprintf(ref, reflen, "refs/heads/%s", name);
 	if (check_ref_format(ref))
 		die("'%s' is not a valid branch name.", name);
 
@@ -235,12 +246,30 @@ static void create_branch(const char *na
 
 	if (write_ref_sha1(lock, sha1, msg) < 0)
 		die("Failed to write ref: %s.", strerror(errno));
+	return ref;
+}
+
+static void rename_branch(const char *newname, const char *oldname, int force, int reflog)
+{
+	char ref[PATH_MAX];
+
+	snprintf(ref, sizeof ref, "refs/heads/%s", oldname);
+	if (check_ref_format(ref))
+		die("'%s' is not a valid branch name.", oldname);
+
+	newname = create_branch(newname, oldname, force, reflog);
+	if (!strcmp(oldname, head)) {
+		create_symref("HEAD", newname);
+		head = newname + 11;
+	}
+	delete_branch(oldname, force, NULL);
 }
 
 int cmd_branch(int argc, const char **argv, const char *prefix)
 {
 	int delete = 0, force_delete = 0, force_create = 0;
 	int verbose = 0, abbrev = DEFAULT_ABBREV;
+	int rename = 0;
 	int reflog = 0;
 	int kinds = REF_LOCAL_BRANCH;
 	int i;
@@ -269,6 +298,10 @@ int cmd_branch(int argc, const char **ar
 			force_create = 1;
 			continue;
 		}
+		if (!strcmp(arg, "--rename")) {
+			rename = 1;
+			continue;
+		}
 		if (!strcmp(arg, "-r")) {
 			kinds = REF_REMOTE_BRANCH;
 			continue;
@@ -303,6 +336,10 @@ int cmd_branch(int argc, const char **ar
 		delete_branches(argc - i, argv + i, force_delete);
 	else if (i == argc)
 		print_ref_list(kinds, verbose, abbrev);
+	else if (rename && (i == argc - 1))
+		rename_branch(argv[i], head, force_create, reflog);
+	else if (rename && (i == argc - 2))
+		rename_branch(argv[i], argv[i + 1], force_create, reflog);
 	else if (i == argc - 1)
 		create_branch(argv[i], head, force_create, reflog);
 	else if (i == argc - 2)
-- 
1.4.4

Re: [RFC] Teach git-branch howto rename a branch

From: Josef Weidendorfer <hidden>
Date: 2016-08-11 19:26:14

On Saturday 25 November 2006 00:03, Lars Hjemli wrote:
This adds a '--rename' option to git branch. If specified, branch
creation becomes branch renaming.
This probably also should rename all config keys
 branch.<oldname>.*
into
 branch.<newname>.*

Re: [RFC] Teach git-branch howto rename a branch

From: Lars Hjemli <hidden>
Date: 2016-08-11 19:49:14

On 11/25/06, Fredrik Kuivinen [off-list ref] wrote:
On 11/25/06, Lars Hjemli [off-list ref] wrote:
quoted
This adds a '--rename' option to git branch. If specified, branch
creation becomes branch renaming.

With a single branchname, the current branch is renamed and .git/HEAD is
updated.

With two branchnames, the second name is renamed to the first.
Nice idea. But wouldn't it be more sensible to rename the first branch to the
second instead of the other way around? That is, the syntax would be

    git branch --rename FROM TO

which is more similar to how "mv" works.
Possibly, but then we would have

  git branch newbranch [oldbranch]

when creating a new branch, and

  git branch --rename [oldbranch] newbranch

for rename/move.

I'd prefer to be "internally consistent", but it does look and feel a
little strange...

Another option would be:

  git branch [--rename] [--from <branch>] newbranch

and deprecate the usage of two unnamed argumens for create/rename

-- 

Re: [RFC] Teach git-branch howto rename a branch

From: Fredrik Kuivinen <hidden>
Date: 2016-08-11 20:12:02

On 11/25/06, Lars Hjemli [off-list ref] wrote:
This adds a '--rename' option to git branch. If specified, branch
creation becomes branch renaming.

With a single branchname, the current branch is renamed and .git/HEAD is
updated.

With two branchnames, the second name is renamed to the first.
Nice idea. But wouldn't it be more sensible to rename the first branch to the
second instead of the other way around? That is, the syntax would be

    git branch --rename FROM TO

which is more similar to how "mv" works.
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help