git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[RFC] Teach git-branch howto rename a branch

From
LHLars Hjemli <hjemli@gmail.com>
Date
Nov 24, 2006, 23:03 UTC
Message-ID
<1164409429445-git-send-email-hjemli@gmail.com>

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 <hjemli@gmail.com>
---
 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
Next: Junio C Hamano
Message 1 of 13 in “[RFC] Teach git-branch howto rename a branch”
  1. Lars HjemliNov 24, 2006
  2. Junio C HamanoNov 25, 2006
  3. Shawn PearceNov 25, 2006
  4. Jakub NarebskiNov 25, 2006
  5. Shawn PearceNov 25, 2006
  6. Lars HjemliNov 25, 2006
  7. Junio C HamanoNov 25, 2006
  8. Lars HjemliNov 25, 2006
  9. git-branch -D: make it work even when on a yet-to-be-born branchJunio C Hamano, Nov 25, 2006
  10. Lars HjemliNov 25, 2006
  11. Fredrik KuivinenNov 25, 2006
  12. Lars HjemliNov 25, 2006
  13. Josef WeidendorferNov 26, 2006

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.