Subject: [PATCH v3 1/3] branch: add '--name-prefix' option

From: "VALERI Yoann via GitGitGadget" <[email-masked]>
Date: Fri, 06 Mar 2026 13:14:30 +0000

From: VALERI Yoann <[email-masked]>

This patch adds a '--name-prefix' option to add a prefix to a newly
created branch. It can use a regular string or a token as prefix. The
only token currently handled is '@{current}', which is substituted for
the current branch's name.

Signed-off-by: VALERI Yoann <[email-masked]>
---
 Documentation/git-branch.adoc | 11 ++++++++++-
 branch.c                      | 17 +++++++++++++++++
 branch.h                      | 12 ++++++++++++
 builtin/branch.c              | 20 +++++++++++++-------
 t/t3200-branch.sh             | 18 ++++++++++++++++++
 5 files changed, 70 insertions(+), 8 deletions(-)

diff --git a/Documentation/git-branch.adoc b/Documentation/git-branch.adoc
index c0afddc424..00967fa758 100644
--- a/Documentation/git-branch.adoc
+++ b/Documentation/git-branch.adoc
@@ -17,7 +17,8 @@ git branch [--color[=<when>] | --no-color] [--show-current]
 	   [(-r|--remotes) | (-a|--all)]
 	   [--list] [<pattern>...]
 git branch [--track[=(direct|inherit)] | --no-track] [-f]
-	   [--recurse-submodules] <branch-name> [<start-point>]
+	   [--recurse-submodules] [--name-prefix=<token>]
+           <branch-name> [<start-point>]
 git branch (--set-upstream-to=<upstream>|-u <upstream>) [<branch-name>]
 git branch --unset-upstream [<branch-name>]
 git branch (-m|-M) [<old-branch>] <new-branch>
@@ -64,6 +65,10 @@ Note that this will create the new branch, but it will not switch the
 working tree to it; use `git switch <new-branch>` to switch to the
 new branch.
 
+With a `--name-prefix` option, you can add a prefix to the branch to create.
+This can either a simple name, or a token. Currently, only '@{current}' is
+managed as token, and will use the current branch name as prefix.
+
 When a local branch is started off a remote-tracking branch, Git sets up the
 branch (specifically the `branch.<name>.remote` and `branch.<name>.merge`
 configuration entries) so that `git pull` will appropriately merge from
@@ -319,6 +324,10 @@ superproject's "origin/main", but tracks the submodule's "origin/main".
 	and the object it points at.  _<format>_ is the same as
 	that of linkgit:git-for-each-ref[1].
 
+`--name-prefix <token>`::
+	A string that will be used as prefix to the name of the new branch to
+        create. Can be '@{current}' to use the current branch's name.
+
 _<branch-name>_::
 	The name of the branch to create or delete.
 	The new branch name must pass all checks defined by
diff --git a/branch.c b/branch.c
index 243db7d0fc..c24d7ce823 100644
--- a/branch.c
+++ b/branch.c
@@ -365,6 +365,23 @@ int read_branch_desc(struct strbuf *buf, const char *branch_name)
 	return 0;
 }
 
+void add_branch_prefix(const char *name_prefix,
+					   const char *current_branch, struct strbuf *buf)
+{
+	int value = 0;
+
+	if (!name_prefix)
+		return;
+
+	if (name_prefix[0] != '@') {
+		strbuf_addstr(buf, name_prefix);
+		return;
+	}
+
+	if (strcmp(name_prefix, "@{current}") == 0)
+		strbuf_addstr(buf, current_branch);
+}
+
 /*
  * Check if 'name' can be a valid name for a branch; die otherwise.
  * Return 1 if the named branch already exists; return 0 otherwise.
diff --git a/branch.h b/branch.h
index ec2f35fda4..f4ac1e9bbd 100644
--- a/branch.h
+++ b/branch.h
@@ -148,6 +148,18 @@ int install_branch_config(int flag, const char *local, const char *origin, const
  */
 int read_branch_desc(struct strbuf *, const char *branch_name);
 
+/*
+ * Store in 'buf' a prefix to the name of a branch to create by using the given
+ * string 'name_prefix'. It can either be a simple string to a shorthand
+ * starting with '@'.
+ *
+ * Currently, only '@{current}' is managed, and will use 'current_branch' as
+ * prefix.
+ */
+void add_branch_prefix(const char *name_prefix, const char *current_branch,
+					   struct strbuf *buf);
+
+
 /*
  * Check if a branch is checked out in the main worktree or any linked
  * worktree and die (with a message describing its checkout location) if
diff --git a/builtin/branch.c b/builtin/branch.c
index c577b5d20f..58631913c7 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -725,6 +725,7 @@ int cmd_branch(int argc,
 	struct string_list sorting_options = STRING_LIST_INIT_DUP;
 	struct ref_format format = REF_FORMAT_INIT;
 	int ret;
+	const char *name_prefix = NULL;
 
 	struct option options[] = {
 		OPT_GROUP(N_("Generic options")),
@@ -776,6 +777,7 @@ int cmd_branch(int argc,
 		OPT_BOOL('i', "ignore-case", &icase, N_("sorting and filtering are case insensitive")),
 		OPT_BOOL(0, "recurse-submodules", &recurse_submodules_explicit, N_("recurse through submodules")),
 		OPT_STRING(  0 , "format", &format.format, N_("format"), N_("format to use for the output")),
+		OPT_STRING(0, "name-prefix", &name_prefix, N_("name"), N_("prefix for the branch to create")),
 		OPT_END(),
 	};
 
@@ -995,6 +997,7 @@ int cmd_branch(int argc,
 	} else if (!noncreate_actions && argc > 0 && argc <= 2) {
 		const char *branch_name = argv[0];
 		const char *start_name = argc == 2 ? argv[1] : head;
+		struct strbuf new_branch_name = STRBUF_INIT;
 
 		if (filter.kind != FILTER_REFS_BRANCHES)
 			die(_("the -a, and -r, options to 'git branch' do not take a branch name.\n"
@@ -1003,15 +1006,18 @@ int cmd_branch(int argc,
 		if (track == BRANCH_TRACK_OVERRIDE)
 			die(_("the '--set-upstream' option is no longer supported. Please use '--track' or '--set-upstream-to' instead"));
 
-		if (recurse_submodules) {
-			create_branches_recursively(the_repository, branch_name,
+		add_branch_prefix(name_prefix, start_name, &new_branch_name);
+		strbuf_addstr(&new_branch_name, branch_name);
+
+		if (recurse_submodules)
+			create_branches_recursively(the_repository, new_branch_name.buf,
 						    start_name, NULL, force,
 						    reflog, quiet, track, 0);
-			ret = 0;
-			goto out;
-		}
-		create_branch(the_repository, branch_name, start_name, force, 0,
-			      reflog, quiet, track, 0);
+		else
+			create_branch(the_repository, new_branch_name.buf, start_name,
+						  force, 0, reflog, quiet, track, 0);
+
+		strbuf_release(&new_branch_name);
 	} else
 		usage_with_options(builtin_branch_usage, options);
 
diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh
index c58e505c43..550989a2bb 100755
--- a/t/t3200-branch.sh
+++ b/t/t3200-branch.sh
@@ -1716,4 +1716,22 @@ test_expect_success 'errors if given a bad branch name' '
 	test_cmp expect actual
 '
 
+test_expect_success 'create branch with --name-prefix' '
+	git config branch.autosetupmerge false &&
+	git branch branch-with-prefix &&
+	git branch --name-prefix "blob" -- -with-prefix &&
+	test_must_fail git branch --name-prefix "blob" -- -with-prefix &&
+	git branch --name-prefix "@{current}" -- -with-prefix &&
+	git switch blob-with-prefix &&
+	git branch --name-prefix "@{current}" -- -with-prefix &&
+	test_must_fail git branch --name-prefix "@{current}" -- -with-prefix &&
+	test_ref_exists refs/heads/branch-with-prefix &&
+	test_ref_exists refs/heads/main-with-prefix &&
+	test_ref_exists refs/heads/blob-with-prefix &&
+	test_ref_exists refs/heads/blob-with-prefix-with-prefix &&
+	git checkout main &&
+	git branch -D branch-with-prefix main-with-prefix blob-with-prefix &&
+	git branch -D blob-with-prefix-with-prefix
+'
+
 test_done
-- 
gitgitgadget