{"thread":{"id":"65026","subject":"[PATCH] branch: add 'branch.addCurrentBranchAsPrefix' config param","startedAt":"2026-02-20T08:07:16Z","lastAt":"2026-04-09T20:02:34Z","messageCount":23,"participants":["Yoann Valeri via GitGitGadget","Junio C Hamano","VALERI Yoann via GitGitGadget","Eric Sunshine"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"536466","messageId":"pull.2202.git.git.1771574833967.gitgitgadget@gmail.com","threadId":"65026","inReplyTo":null,"subject":"[PATCH] branch: add 'branch.addCurrentBranchAsPrefix' config param","fromName":"Yoann Valeri via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-02-20T08:07:13Z","receivedAt":"2026-02-20T08:07:16Z","isPatch":true,"body":"From: VALERI Yoann <yoann.valeri@cea.fr>\n\nThis patch adds a new configuration parameter for the branch creation\nfeature: 'branch.addCurrentBranchAsPrefix'. When set to true, if one\ncreates a new branch with either `git branch`, `git checkout -[bB]` or\n`git switch -[cC]`, we will now retrieve the current branch's name, and\nuse it as prefix for the name of the newly created branch, alongside a\nhyphen separating the two.\n\nFor instance, using this parameter, and attempting to create a branch\n'test' while on the 'main' branch will instead create a branch\n'main-test'.\n\nThis parameters is useful for projects handling many branches, with\nfeatures often needing backport on different branches, so as to reduce\nthe time taken to create branches without having to come up with clever\nnames.\n\nSigned-off-by: VALERI Yoann <yoann.valeri@cea.fr>\n---\n    branch: add 'branch.addCurrentBranchAsPrefix' config param\n\nPublished-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-2202%2Fvaleriyoann%2Fbranch-with-prefix-v1\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-2202/valeriyoann/branch-with-prefix-v1\nPull-Request: https://github.com/git/git/pull/2202\n\n Documentation/config/branch.adoc |  7 +++++\n branch.c                         | 14 +++++++++\n branch.h                         |  8 +++++\n builtin/branch.c                 | 17 ++++++-----\n builtin/checkout.c               | 52 +++++++++++++++++++++++---------\n t/t2018-checkout-branch.sh       | 26 ++++++++++++++++\n t/t2060-switch.sh                | 26 ++++++++++++++++\n t/t3200-branch.sh                | 14 +++++++++\n 8 files changed, 142 insertions(+), 22 deletions(-)\n\ndiff --git a/Documentation/config/branch.adoc b/Documentation/config/branch.adoc\nindex a4db9fa5c8..bd153ea406 100644\n--- a/Documentation/config/branch.adoc\n+++ b/Documentation/config/branch.adoc\n@@ -35,6 +35,13 @@ This option defaults to `never`.\n \tvalue of this variable will be used as the default.\n \tSee linkgit:git-for-each-ref[1] field names for valid values.\n \n+`branch.addCurrentBranchAsPrefix`::\n+\tWhen a new branch is created with `git branch`, `git switch` or `git\n+\tcheckout` use the name of the current branch as a prefix for the new\n+\tbranch's name, alongside the one provided by the user, with a hyphen in the\n+\tmiddle. For instance, using this configuration variable, creating the branch\n+\t`test` while on `main` will create the branch `main-test`. False by default.\n+\n `branch.<name>.remote`::\n \tWhen on branch _<name>_, it tells `git fetch` and `git push`\n \twhich remote to fetch from or push to.  The remote to push to\ndiff --git a/branch.c b/branch.c\nindex 243db7d0fc..f2d348b046 100644\n--- a/branch.c\n+++ b/branch.c\n@@ -365,6 +365,20 @@ int read_branch_desc(struct strbuf *buf, const char *branch_name)\n \treturn 0;\n }\n \n+void add_branch_prefix(const char *current_branch,\n+\t\t\t\t\t   const char *target_branch, struct strbuf *buf)\n+{\n+\tint value = 0;\n+\n+\trepo_config_get_bool(the_repository,\n+\t\t\t\t\t\t \"branch.addCurrentBranchAsPrefix\", &value);\n+\n+\tif (value)\n+\t\tstrbuf_addf(buf, \"%s-%s\", current_branch, target_branch);\n+\telse\n+\t\tstrbuf_addstr(buf, target_branch);\n+}\n+\n /*\n  * Check if 'name' can be a valid name for a branch; die otherwise.\n  * Return 1 if the named branch already exists; return 0 otherwise.\ndiff --git a/branch.h b/branch.h\nindex ec2f35fda4..060de1b72c 100644\n--- a/branch.h\n+++ b/branch.h\n@@ -148,6 +148,14 @@ int install_branch_config(int flag, const char *local, const char *origin, const\n  */\n int read_branch_desc(struct strbuf *, const char *branch_name);\n \n+/*\n+ * Fetch the configuration parameter 'branch.addCurrentBranchAsPrefix' and\n+ * fill the buffer 'buf' with '<current_branch>-<target_branch>' if true,\n+ * otherwise just '<current_branch>'.\n+ */\n+void add_branch_prefix(const char *current_branch,\n+\t\t\t\t\t   const char *target_branch, struct strbuf *buf);\n+\n /*\n  * Check if a branch is checked out in the main worktree or any linked\n  * worktree and die (with a message describing its checkout location) if\ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex c577b5d20f..2fbf2d9722 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -995,6 +995,7 @@ int cmd_branch(int argc,\n \t} else if (!noncreate_actions && argc > 0 && argc <= 2) {\n \t\tconst char *branch_name = argv[0];\n \t\tconst char *start_name = argc == 2 ? argv[1] : head;\n+\t\tstruct strbuf new_branch_name = STRBUF_INIT;\n \n \t\tif (filter.kind != FILTER_REFS_BRANCHES)\n \t\t\tdie(_(\"the -a, and -r, options to 'git branch' do not take a branch name.\\n\"\n@@ -1003,15 +1004,17 @@ int cmd_branch(int argc,\n \t\tif (track == BRANCH_TRACK_OVERRIDE)\n \t\t\tdie(_(\"the '--set-upstream' option is no longer supported. Please use '--track' or '--set-upstream-to' instead\"));\n \n-\t\tif (recurse_submodules) {\n-\t\t\tcreate_branches_recursively(the_repository, branch_name,\n+\t\tadd_branch_prefix(start_name, branch_name, &new_branch_name);\n+\n+\t\tif (recurse_submodules)\n+\t\t\tcreate_branches_recursively(the_repository, new_branch_name.buf,\n \t\t\t\t\t\t    start_name, NULL, force,\n \t\t\t\t\t\t    reflog, quiet, track, 0);\n-\t\t\tret = 0;\n-\t\t\tgoto out;\n-\t\t}\n-\t\tcreate_branch(the_repository, branch_name, start_name, force, 0,\n-\t\t\t      reflog, quiet, track, 0);\n+\t\telse\n+\t\t\tcreate_branch(the_repository, new_branch_name.buf, start_name,\n+\t\t\t\t\t\t  force, 0, reflog, quiet, track, 0);\n+\n+\t\tstrbuf_release(&new_branch_name);\n \t} else\n \t\tusage_with_options(builtin_branch_usage, options);\n \ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex 0ba4f03f2e..950198d8f3 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -1170,31 +1170,42 @@ static void orphaned_commit_warning(struct commit *old_commit, struct commit *ne\n \trelease_revisions(&revs);\n }\n \n+static void get_current_branch_info(struct branch_info *branch_info)\n+{\n+\tstruct object_id rev;\n+\tint flag;\n+\n+\tbranch_info->path = refs_resolve_refdup(get_main_ref_store(the_repository),\n+\t\t\t\t\t\t\t\t\t\t\t\"HEAD\", 0, &rev, &flag);\n+\n+\tif (branch_info->path)\n+\t\tbranch_info->commit = lookup_commit_reference_gently(the_repository,\n+\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t &rev, 1);\n+\n+\tif (!(flag & REF_ISSYMREF))\n+\t\tFREE_AND_NULL(branch_info->path);\n+\n+\tif (branch_info->path) {\n+\t\tconst char *const prefix = \"refs/heads/\";\n+\t\tconst char *p;\n+\n+\t\tif (skip_prefix(branch_info->path, prefix, &p))\n+\t\t\tbranch_info->name = xstrdup(p);\n+\t}\n+}\n+\n static int switch_branches(const struct checkout_opts *opts,\n \t\t\t   struct branch_info *new_branch_info)\n {\n \tint ret = 0;\n \tstruct branch_info old_branch_info = { 0 };\n-\tstruct object_id rev;\n-\tint flag, writeout_error = 0;\n+\tint writeout_error = 0;\n \tint do_merge = 1;\n \n \ttrace2_cmd_mode(\"branch\");\n \n \tmemset(&old_branch_info, 0, sizeof(old_branch_info));\n-\told_branch_info.path = refs_resolve_refdup(get_main_ref_store(the_repository),\n-\t\t\t\t\t\t   \"HEAD\", 0, &rev, &flag);\n-\tif (old_branch_info.path)\n-\t\told_branch_info.commit = lookup_commit_reference_gently(the_repository, &rev, 1);\n-\tif (!(flag & REF_ISSYMREF))\n-\t\tFREE_AND_NULL(old_branch_info.path);\n-\n-\tif (old_branch_info.path) {\n-\t\tconst char *const prefix = \"refs/heads/\";\n-\t\tconst char *p;\n-\t\tif (skip_prefix(old_branch_info.path, prefix, &p))\n-\t\t\told_branch_info.name = xstrdup(p);\n-\t}\n+\tget_current_branch_info(&old_branch_info);\n \n \tif (opts->new_orphan_branch && opts->orphan_from_empty_tree) {\n \t\tif (new_branch_info->name)\n@@ -1772,6 +1783,7 @@ static int checkout_main(int argc, const char **argv, const char *prefix,\n \tint parseopt_flags = 0;\n \tstruct branch_info new_branch_info = { 0 };\n \tint ret;\n+\tstruct strbuf full_branch_name = { 0 };\n \n \topts->overwrite_ignore = 1;\n \topts->prefix = prefix;\n@@ -1962,7 +1974,15 @@ static int checkout_main(int argc, const char **argv, const char *prefix,\n \t}\n \n \tif (opts->new_branch) {\n+\t\tstruct branch_info current_branch = { 0 };\n \t\tstruct strbuf buf = STRBUF_INIT;\n+\t\tstrbuf_init(&full_branch_name, 0);\n+\n+\t\tget_current_branch_info(&current_branch);\n+\t\tadd_branch_prefix(current_branch.name, opts->new_branch,\n+\t\t\t\t\t\t  &full_branch_name);\n+\t\tbranch_info_release(&current_branch);\n+\t\topts->new_branch = full_branch_name.buf;\n \n \t\tif (opts->new_branch_force)\n \t\t\topts->branch_exists = validate_branchname(opts->new_branch, &buf);\n@@ -1981,6 +2001,8 @@ static int checkout_main(int argc, const char **argv, const char *prefix,\n \tclear_pathspec(&opts->pathspec);\n \tfree(opts->pathspec_from_file);\n \tfree(options);\n+\tif (full_branch_name.buf)\n+\t\tstrbuf_release(&full_branch_name);\n \n \treturn ret;\n }\ndiff --git a/t/t2018-checkout-branch.sh b/t/t2018-checkout-branch.sh\nindex a48ebdbf4d..8345a509dc 100755\n--- a/t/t2018-checkout-branch.sh\n+++ b/t/t2018-checkout-branch.sh\n@@ -285,4 +285,30 @@ test_expect_success 'checkout -b rejects an extra path argument' '\n \ttest_grep \"Cannot update paths and switch to branch\" err\n '\n \n+test_expect_success 'checkout -b with prefix is valid' '\n+\tgit checkout -b main &&\n+\tgit checkout -b checkoutb-with-prefix &&\n+\tgit checkout main &&\n+\ttest_config branch.addCurrentBranchAsPrefix false &&\n+\ttest_must_fail git checkout -b checkoutb-with-prefix &&\n+\ttest_config branch.addCurrentBranchAsPrefix true &&\n+\tgit checkout -b checkoutb-with-prefix &&\n+\tgit checkout -b checkoutb-with-prefix &&\n+\ttest_ref_exists refs/heads/checkoutb-with-prefix &&\n+\ttest_ref_exists refs/heads/main-checkoutb-with-prefix &&\n+\ttest_ref_exists refs/heads/main-checkoutb-with-prefix-checkoutb-with-prefix\n+'\n+\n+test_expect_success 'checkout -B with prefix is valid' '\n+\tgit checkout main &&\n+\tgit checkout -B checkoutB-with-prefix &&\n+\tgit checkout main &&\n+\ttest_config branch.addCurrentBranchAsPrefix false &&\n+\tgit checkout -B checkoutB-with-prefix &&\n+\ttest_config branch.addCurrentBranchAsPrefix true &&\n+\tgit checkout -B checkoutB-with-prefix &&\n+\ttest_ref_exists refs/heads/checkoutB-with-prefix &&\n+\ttest_ref_exists refs/heads/checkoutB-with-prefix-checkoutB-with-prefix\n+'\n+\n test_done\ndiff --git a/t/t2060-switch.sh b/t/t2060-switch.sh\nindex c91c4db936..458f8b9f3f 100755\n--- a/t/t2060-switch.sh\n+++ b/t/t2060-switch.sh\n@@ -177,4 +177,30 @@ test_expect_success 'switch back when temporarily detached and checked out elsew\n \tgit -C wt2 switch --ignore-other-worktrees shared\n '\n \n+test_expect_success 'switch -c with prefix is valid' '\n+\tgit switch main &&\n+\tgit switch -c switchc-with-prefix &&\n+\tgit checkout main &&\n+\ttest_config branch.addCurrentBranchAsPrefix false &&\n+\ttest_must_fail git switch -c switchc-with-prefix &&\n+\ttest_config branch.addCurrentBranchAsPrefix true &&\n+\tgit switch -c switchc-with-prefix &&\n+\tgit switch -c switchc-with-prefix &&\n+\ttest_ref_exists refs/heads/switchc-with-prefix &&\n+\ttest_ref_exists refs/heads/main-switchc-with-prefix &&\n+\ttest_ref_exists refs/heads/main-switchc-with-prefix-switchc-with-prefix\n+'\n+\n+test_expect_success 'switch -C with prefix is valid' '\n+\tgit switch main &&\n+\tgit switch -C switchC-with-prefix &&\n+\tgit checkout main &&\n+\ttest_config branch.addCurrentBranchAsPrefix false &&\n+\tgit switch -C switchC-with-prefix &&\n+\ttest_config branch.addCurrentBranchAsPrefix true &&\n+\tgit switch -C switchC-with-prefix &&\n+\ttest_ref_exists refs/heads/switchC-with-prefix &&\n+\ttest_ref_exists refs/heads/switchC-with-prefix-switchC-with-prefix\n+'\n+\n test_done\ndiff --git a/t/t3200-branch.sh b/t/t3200-branch.sh\nindex c58e505c43..496b034d0b 100755\n--- a/t/t3200-branch.sh\n+++ b/t/t3200-branch.sh\n@@ -1716,4 +1716,18 @@ test_expect_success 'errors if given a bad branch name' '\n \ttest_cmp expect actual\n '\n \n+test_expect_success 'create branch with prefix' '\n+\tgit config branch.autosetupmerge false &&\n+\tgit branch branch-with-prefix &&\n+\ttest_config branch.addCurrentBranchAsPrefix false &&\n+\ttest_must_fail git branch branch-with-prefix &&\n+\ttest_config branch.addCurrentBranchAsPrefix true &&\n+\tgit branch branch-with-prefix &&\n+\tgit checkout branch-with-prefix &&\n+\tgit branch branch-with-prefix &&\n+\ttest_ref_exists refs/heads/branch-with-prefix &&\n+\ttest_ref_exists refs/heads/main-branch-with-prefix &&\n+\ttest_ref_exists refs/heads/branch-with-prefix-branch-with-prefix\n+'\n+\n test_done\n\nbase-commit: 852829b3dd2fe4e7c7fc4d8badde644cf1b66c74\n-- \ngitgitgadget\n"},{"id":"536528","messageId":"xmqq5x7r1k45.fsf@gitster.g","threadId":"65026","inReplyTo":"pull.2202.git.git.1771574833967.gitgitgadget@gmail.com","subject":"Re: [PATCH] branch: add 'branch.addCurrentBranchAsPrefix' config param","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-02-20T15:59:38Z","receivedAt":"2026-02-20T15:59:41Z","isPatch":true,"body":"\"Yoann Valeri via GitGitGadget\" <gitgitgadget@gmail.com> writes:\n\n> From: VALERI Yoann <yoann.valeri@cea.fr>\n>\n> This patch adds a new configuration parameter for the branch creation\n> feature: 'branch.addCurrentBranchAsPrefix'. When set to true, if one\n\nWe generally do not add a configuration variable before the concept\nproves useful by being available as a command line option for some\ntime.  Have we had a command line option that corresponds to this\nfeature for a year or two?  Such a command line option will be\nnecessary even after we decide to add a configuration variable to\nallow users to override the configured value per-invocation basis,\ne.g., \"git branch --no-current-branch-prefix maint-2.54 v2.54.0\",\nwhen you want to use the feature for most of your branches but want\nto deviate from that convention in selected cases.\n\nThanks.\n"},{"id":"536529","messageId":"xmqqy0knz9ct.fsf@gitster.g","threadId":"65026","inReplyTo":"pull.2202.git.git.1771574833967.gitgitgadget@gmail.com","subject":"Re: [PATCH] branch: add 'branch.addCurrentBranchAsPrefix' config param","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-02-20T16:08:02Z","receivedAt":"2026-02-20T16:08:04Z","isPatch":true,"body":"By the way, the address at @cea.fr used as the author ident and for\nsign-off seems to be bouncing, due to \"550 mailbox unavailable\".\n\nTwo requests:\n\n * To the author of the patch.  Could you make sure to sign-off with\n   reachable e-mail address?  It cannot be helped that years after a\n   patch is written, the author may become unreachable, but we do\n   not want to see it happen even before we accept the patch.\n\n * To GitGitGadget maintainers.  Could you think about ways to catch\n   an incident like this, perhaps by sending a ping e-mail to first\n   time contributors to request response before allowing /submit or\n   something?\n\n\n\n"},{"id":"537294","messageId":"pull.2202.v2.git.git.1772207333.gitgitgadget@gmail.com","threadId":"65026","inReplyTo":"pull.2202.git.git.1771574833967.gitgitgadget@gmail.com","subject":"[PATCH v2 0/2] branch: add 'branch.addCurrentBranchAsPrefix' config param","fromName":"Yoann Valeri via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-02-27T15:48:51Z","receivedAt":"2026-02-27T15:48:56Z","isPatch":true,"body":"Changes since v1:\n\n * Added a '--no-prefix' option to git branch\n\nVALERI Yoann (2):\n  branch: add 'branch.addCurrentBranchAsPrefix' config param\n  branch: add a no-prefix option\n\n Documentation/config/branch.adoc |  7 +++++\n branch.c                         | 14 +++++++++\n branch.h                         |  8 +++++\n builtin/branch.c                 | 24 ++++++++++-----\n builtin/checkout.c               | 52 +++++++++++++++++++++++---------\n t/t2018-checkout-branch.sh       | 26 ++++++++++++++++\n t/t2060-switch.sh                | 26 ++++++++++++++++\n t/t3200-branch.sh                | 16 ++++++++++\n 8 files changed, 150 insertions(+), 23 deletions(-)\n\n\nbase-commit: 7b2bccb0d58d4f24705bf985de1f4612e4cf06e5\nPublished-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-2202%2Fvaleriyoann%2Fbranch-with-prefix-v2\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-2202/valeriyoann/branch-with-prefix-v2\nPull-Request: https://github.com/git/git/pull/2202\n\nRange-diff vs v1:\n\n 1:  30a6d8e195 = 1:  49641fb34c branch: add 'branch.addCurrentBranchAsPrefix' config param\n -:  ---------- > 2:  0fbdf031cb branch: add a no-prefix option\n\n-- \ngitgitgadget\n"},{"id":"537296","messageId":"49641fb34c2ad5ab987082085d96b04196951c3f.1772207333.git.gitgitgadget@gmail.com","threadId":"65026","inReplyTo":"pull.2202.v2.git.git.1772207333.gitgitgadget@gmail.com","subject":"[PATCH v2 1/2] branch: add 'branch.addCurrentBranchAsPrefix' config param","fromName":"VALERI Yoann via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-02-27T15:48:52Z","receivedAt":"2026-02-27T15:48:58Z","isPatch":true,"body":"From: VALERI Yoann <yoann.valeri@cea.fr>\n\nThis patch adds a new configuration parameter for the branch creation\nfeature: 'branch.addCurrentBranchAsPrefix'. When set to true, if one\ncreates a new branch with either `git branch`, `git checkout -[bB]` or\n`git switch -[cC]`, we will now retrieve the current branch's name, and\nuse it as prefix for the name of the newly created branch, alongside a\nhyphen separating the two.\n\nFor instance, using this parameter, and attempting to create a branch\n'test' while on the 'main' branch will instead create a branch\n'main-test'.\n\nThis parameters is useful for projects handling many branches, with\nfeatures often needing backport on different branches, so as to reduce\nthe time taken to create branches without having to come up with clever\nnames.\n\nSigned-off-by: VALERI Yoann <yoann.valeri@cea.fr>\n---\n Documentation/config/branch.adoc |  7 +++++\n branch.c                         | 14 +++++++++\n branch.h                         |  8 +++++\n builtin/branch.c                 | 17 ++++++-----\n builtin/checkout.c               | 52 +++++++++++++++++++++++---------\n t/t2018-checkout-branch.sh       | 26 ++++++++++++++++\n t/t2060-switch.sh                | 26 ++++++++++++++++\n t/t3200-branch.sh                | 14 +++++++++\n 8 files changed, 142 insertions(+), 22 deletions(-)\n\ndiff --git a/Documentation/config/branch.adoc b/Documentation/config/branch.adoc\nindex a4db9fa5c8..bd153ea406 100644\n--- a/Documentation/config/branch.adoc\n+++ b/Documentation/config/branch.adoc\n@@ -35,6 +35,13 @@ This option defaults to `never`.\n \tvalue of this variable will be used as the default.\n \tSee linkgit:git-for-each-ref[1] field names for valid values.\n \n+`branch.addCurrentBranchAsPrefix`::\n+\tWhen a new branch is created with `git branch`, `git switch` or `git\n+\tcheckout` use the name of the current branch as a prefix for the new\n+\tbranch's name, alongside the one provided by the user, with a hyphen in the\n+\tmiddle. For instance, using this configuration variable, creating the branch\n+\t`test` while on `main` will create the branch `main-test`. False by default.\n+\n `branch.<name>.remote`::\n \tWhen on branch _<name>_, it tells `git fetch` and `git push`\n \twhich remote to fetch from or push to.  The remote to push to\ndiff --git a/branch.c b/branch.c\nindex 243db7d0fc..f2d348b046 100644\n--- a/branch.c\n+++ b/branch.c\n@@ -365,6 +365,20 @@ int read_branch_desc(struct strbuf *buf, const char *branch_name)\n \treturn 0;\n }\n \n+void add_branch_prefix(const char *current_branch,\n+\t\t\t\t\t   const char *target_branch, struct strbuf *buf)\n+{\n+\tint value = 0;\n+\n+\trepo_config_get_bool(the_repository,\n+\t\t\t\t\t\t \"branch.addCurrentBranchAsPrefix\", &value);\n+\n+\tif (value)\n+\t\tstrbuf_addf(buf, \"%s-%s\", current_branch, target_branch);\n+\telse\n+\t\tstrbuf_addstr(buf, target_branch);\n+}\n+\n /*\n  * Check if 'name' can be a valid name for a branch; die otherwise.\n  * Return 1 if the named branch already exists; return 0 otherwise.\ndiff --git a/branch.h b/branch.h\nindex ec2f35fda4..060de1b72c 100644\n--- a/branch.h\n+++ b/branch.h\n@@ -148,6 +148,14 @@ int install_branch_config(int flag, const char *local, const char *origin, const\n  */\n int read_branch_desc(struct strbuf *, const char *branch_name);\n \n+/*\n+ * Fetch the configuration parameter 'branch.addCurrentBranchAsPrefix' and\n+ * fill the buffer 'buf' with '<current_branch>-<target_branch>' if true,\n+ * otherwise just '<current_branch>'.\n+ */\n+void add_branch_prefix(const char *current_branch,\n+\t\t\t\t\t   const char *target_branch, struct strbuf *buf);\n+\n /*\n  * Check if a branch is checked out in the main worktree or any linked\n  * worktree and die (with a message describing its checkout location) if\ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex c577b5d20f..2fbf2d9722 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -995,6 +995,7 @@ int cmd_branch(int argc,\n \t} else if (!noncreate_actions && argc > 0 && argc <= 2) {\n \t\tconst char *branch_name = argv[0];\n \t\tconst char *start_name = argc == 2 ? argv[1] : head;\n+\t\tstruct strbuf new_branch_name = STRBUF_INIT;\n \n \t\tif (filter.kind != FILTER_REFS_BRANCHES)\n \t\t\tdie(_(\"the -a, and -r, options to 'git branch' do not take a branch name.\\n\"\n@@ -1003,15 +1004,17 @@ int cmd_branch(int argc,\n \t\tif (track == BRANCH_TRACK_OVERRIDE)\n \t\t\tdie(_(\"the '--set-upstream' option is no longer supported. Please use '--track' or '--set-upstream-to' instead\"));\n \n-\t\tif (recurse_submodules) {\n-\t\t\tcreate_branches_recursively(the_repository, branch_name,\n+\t\tadd_branch_prefix(start_name, branch_name, &new_branch_name);\n+\n+\t\tif (recurse_submodules)\n+\t\t\tcreate_branches_recursively(the_repository, new_branch_name.buf,\n \t\t\t\t\t\t    start_name, NULL, force,\n \t\t\t\t\t\t    reflog, quiet, track, 0);\n-\t\t\tret = 0;\n-\t\t\tgoto out;\n-\t\t}\n-\t\tcreate_branch(the_repository, branch_name, start_name, force, 0,\n-\t\t\t      reflog, quiet, track, 0);\n+\t\telse\n+\t\t\tcreate_branch(the_repository, new_branch_name.buf, start_name,\n+\t\t\t\t\t\t  force, 0, reflog, quiet, track, 0);\n+\n+\t\tstrbuf_release(&new_branch_name);\n \t} else\n \t\tusage_with_options(builtin_branch_usage, options);\n \ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex f7b313816e..9dc1d00ed2 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -1170,31 +1170,42 @@ static void orphaned_commit_warning(struct commit *old_commit, struct commit *ne\n \trelease_revisions(&revs);\n }\n \n+static void get_current_branch_info(struct branch_info *branch_info)\n+{\n+\tstruct object_id rev;\n+\tint flag;\n+\n+\tbranch_info->path = refs_resolve_refdup(get_main_ref_store(the_repository),\n+\t\t\t\t\t\t\t\t\t\t\t\"HEAD\", 0, &rev, &flag);\n+\n+\tif (branch_info->path)\n+\t\tbranch_info->commit = lookup_commit_reference_gently(the_repository,\n+\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t &rev, 1);\n+\n+\tif (!(flag & REF_ISSYMREF))\n+\t\tFREE_AND_NULL(branch_info->path);\n+\n+\tif (branch_info->path) {\n+\t\tconst char *const prefix = \"refs/heads/\";\n+\t\tconst char *p;\n+\n+\t\tif (skip_prefix(branch_info->path, prefix, &p))\n+\t\t\tbranch_info->name = xstrdup(p);\n+\t}\n+}\n+\n static int switch_branches(const struct checkout_opts *opts,\n \t\t\t   struct branch_info *new_branch_info)\n {\n \tint ret = 0;\n \tstruct branch_info old_branch_info = { 0 };\n-\tstruct object_id rev;\n-\tint flag, writeout_error = 0;\n+\tint writeout_error = 0;\n \tint do_merge = 1;\n \n \ttrace2_cmd_mode(\"branch\");\n \n \tmemset(&old_branch_info, 0, sizeof(old_branch_info));\n-\told_branch_info.path = refs_resolve_refdup(get_main_ref_store(the_repository),\n-\t\t\t\t\t\t   \"HEAD\", 0, &rev, &flag);\n-\tif (old_branch_info.path)\n-\t\told_branch_info.commit = lookup_commit_reference_gently(the_repository, &rev, 1);\n-\tif (!(flag & REF_ISSYMREF))\n-\t\tFREE_AND_NULL(old_branch_info.path);\n-\n-\tif (old_branch_info.path) {\n-\t\tconst char *const prefix = \"refs/heads/\";\n-\t\tconst char *p;\n-\t\tif (skip_prefix(old_branch_info.path, prefix, &p))\n-\t\t\told_branch_info.name = xstrdup(p);\n-\t}\n+\tget_current_branch_info(&old_branch_info);\n \n \tif (opts->new_orphan_branch && opts->orphan_from_empty_tree) {\n \t\tif (new_branch_info->name)\n@@ -1772,6 +1783,7 @@ static int checkout_main(int argc, const char **argv, const char *prefix,\n \tint parseopt_flags = 0;\n \tstruct branch_info new_branch_info = { 0 };\n \tint ret;\n+\tstruct strbuf full_branch_name = { 0 };\n \n \topts->overwrite_ignore = 1;\n \topts->prefix = prefix;\n@@ -1962,7 +1974,15 @@ static int checkout_main(int argc, const char **argv, const char *prefix,\n \t}\n \n \tif (opts->new_branch) {\n+\t\tstruct branch_info current_branch = { 0 };\n \t\tstruct strbuf buf = STRBUF_INIT;\n+\t\tstrbuf_init(&full_branch_name, 0);\n+\n+\t\tget_current_branch_info(&current_branch);\n+\t\tadd_branch_prefix(current_branch.name, opts->new_branch,\n+\t\t\t\t\t\t  &full_branch_name);\n+\t\tbranch_info_release(&current_branch);\n+\t\topts->new_branch = full_branch_name.buf;\n \n \t\tif (opts->new_branch_force)\n \t\t\topts->branch_exists = validate_branchname(opts->new_branch, &buf);\n@@ -1981,6 +2001,8 @@ static int checkout_main(int argc, const char **argv, const char *prefix,\n \tclear_pathspec(&opts->pathspec);\n \tfree(opts->pathspec_from_file);\n \tfree(options);\n+\tif (full_branch_name.buf)\n+\t\tstrbuf_release(&full_branch_name);\n \n \treturn ret;\n }\ndiff --git a/t/t2018-checkout-branch.sh b/t/t2018-checkout-branch.sh\nindex a48ebdbf4d..8345a509dc 100755\n--- a/t/t2018-checkout-branch.sh\n+++ b/t/t2018-checkout-branch.sh\n@@ -285,4 +285,30 @@ test_expect_success 'checkout -b rejects an extra path argument' '\n \ttest_grep \"Cannot update paths and switch to branch\" err\n '\n \n+test_expect_success 'checkout -b with prefix is valid' '\n+\tgit checkout -b main &&\n+\tgit checkout -b checkoutb-with-prefix &&\n+\tgit checkout main &&\n+\ttest_config branch.addCurrentBranchAsPrefix false &&\n+\ttest_must_fail git checkout -b checkoutb-with-prefix &&\n+\ttest_config branch.addCurrentBranchAsPrefix true &&\n+\tgit checkout -b checkoutb-with-prefix &&\n+\tgit checkout -b checkoutb-with-prefix &&\n+\ttest_ref_exists refs/heads/checkoutb-with-prefix &&\n+\ttest_ref_exists refs/heads/main-checkoutb-with-prefix &&\n+\ttest_ref_exists refs/heads/main-checkoutb-with-prefix-checkoutb-with-prefix\n+'\n+\n+test_expect_success 'checkout -B with prefix is valid' '\n+\tgit checkout main &&\n+\tgit checkout -B checkoutB-with-prefix &&\n+\tgit checkout main &&\n+\ttest_config branch.addCurrentBranchAsPrefix false &&\n+\tgit checkout -B checkoutB-with-prefix &&\n+\ttest_config branch.addCurrentBranchAsPrefix true &&\n+\tgit checkout -B checkoutB-with-prefix &&\n+\ttest_ref_exists refs/heads/checkoutB-with-prefix &&\n+\ttest_ref_exists refs/heads/checkoutB-with-prefix-checkoutB-with-prefix\n+'\n+\n test_done\ndiff --git a/t/t2060-switch.sh b/t/t2060-switch.sh\nindex c91c4db936..458f8b9f3f 100755\n--- a/t/t2060-switch.sh\n+++ b/t/t2060-switch.sh\n@@ -177,4 +177,30 @@ test_expect_success 'switch back when temporarily detached and checked out elsew\n \tgit -C wt2 switch --ignore-other-worktrees shared\n '\n \n+test_expect_success 'switch -c with prefix is valid' '\n+\tgit switch main &&\n+\tgit switch -c switchc-with-prefix &&\n+\tgit checkout main &&\n+\ttest_config branch.addCurrentBranchAsPrefix false &&\n+\ttest_must_fail git switch -c switchc-with-prefix &&\n+\ttest_config branch.addCurrentBranchAsPrefix true &&\n+\tgit switch -c switchc-with-prefix &&\n+\tgit switch -c switchc-with-prefix &&\n+\ttest_ref_exists refs/heads/switchc-with-prefix &&\n+\ttest_ref_exists refs/heads/main-switchc-with-prefix &&\n+\ttest_ref_exists refs/heads/main-switchc-with-prefix-switchc-with-prefix\n+'\n+\n+test_expect_success 'switch -C with prefix is valid' '\n+\tgit switch main &&\n+\tgit switch -C switchC-with-prefix &&\n+\tgit checkout main &&\n+\ttest_config branch.addCurrentBranchAsPrefix false &&\n+\tgit switch -C switchC-with-prefix &&\n+\ttest_config branch.addCurrentBranchAsPrefix true &&\n+\tgit switch -C switchC-with-prefix &&\n+\ttest_ref_exists refs/heads/switchC-with-prefix &&\n+\ttest_ref_exists refs/heads/switchC-with-prefix-switchC-with-prefix\n+'\n+\n test_done\ndiff --git a/t/t3200-branch.sh b/t/t3200-branch.sh\nindex c58e505c43..496b034d0b 100755\n--- a/t/t3200-branch.sh\n+++ b/t/t3200-branch.sh\n@@ -1716,4 +1716,18 @@ test_expect_success 'errors if given a bad branch name' '\n \ttest_cmp expect actual\n '\n \n+test_expect_success 'create branch with prefix' '\n+\tgit config branch.autosetupmerge false &&\n+\tgit branch branch-with-prefix &&\n+\ttest_config branch.addCurrentBranchAsPrefix false &&\n+\ttest_must_fail git branch branch-with-prefix &&\n+\ttest_config branch.addCurrentBranchAsPrefix true &&\n+\tgit branch branch-with-prefix &&\n+\tgit checkout branch-with-prefix &&\n+\tgit branch branch-with-prefix &&\n+\ttest_ref_exists refs/heads/branch-with-prefix &&\n+\ttest_ref_exists refs/heads/main-branch-with-prefix &&\n+\ttest_ref_exists refs/heads/branch-with-prefix-branch-with-prefix\n+'\n+\n test_done\n-- \ngitgitgadget\n\n"},{"id":"537295","messageId":"0fbdf031cb9f054e023d44fd3eb3315732d527c0.1772207333.git.gitgitgadget@gmail.com","threadId":"65026","inReplyTo":"pull.2202.v2.git.git.1772207333.gitgitgadget@gmail.com","subject":"[PATCH v2 2/2] branch: add a no-prefix option","fromName":"VALERI Yoann via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-02-27T15:48:53Z","receivedAt":"2026-02-27T15:48:59Z","isPatch":true,"body":"From: VALERI Yoann <yoann.valeri@cea.fr>\n\nThis patch adds a '--no-prefix' option to 'git branch' to selectively\noverride the 'branch.addCurrentBranchAsPrefix' configuration parameter.\nSigned-off-by: VALERI Yoann <yoann.valeri@cea.fr>\n---\n builtin/branch.c  | 9 +++++++--\n t/t3200-branch.sh | 4 +++-\n 2 files changed, 10 insertions(+), 3 deletions(-)\n\ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex 2fbf2d9722..701c2a3180 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -713,7 +713,8 @@ int cmd_branch(int argc,\n {\n \t/* possible actions */\n \tint delete = 0, rename = 0, copy = 0, list = 0,\n-\t    unset_upstream = 0, show_current = 0, edit_description = 0;\n+\t    unset_upstream = 0, show_current = 0, edit_description = 0,\n+\t    no_prefix = 0;\n \tconst char *new_upstream = NULL;\n \tint noncreate_actions = 0;\n \t/* possible options */\n@@ -776,6 +777,7 @@ int cmd_branch(int argc,\n \t\tOPT_BOOL('i', \"ignore-case\", &icase, N_(\"sorting and filtering are case insensitive\")),\n \t\tOPT_BOOL(0, \"recurse-submodules\", &recurse_submodules_explicit, N_(\"recurse through submodules\")),\n \t\tOPT_STRING(  0 , \"format\", &format.format, N_(\"format\"), N_(\"format to use for the output\")),\n+\t\tOPT_BOOL(0, \"no-prefix\", &no_prefix, N_(\"do not add a prefix to the branch being created\")),\n \t\tOPT_END(),\n \t};\n \n@@ -1004,7 +1006,10 @@ int cmd_branch(int argc,\n \t\tif (track == BRANCH_TRACK_OVERRIDE)\n \t\t\tdie(_(\"the '--set-upstream' option is no longer supported. Please use '--track' or '--set-upstream-to' instead\"));\n \n-\t\tadd_branch_prefix(start_name, branch_name, &new_branch_name);\n+\t\tif (!no_prefix)\n+\t\t\tadd_branch_prefix(start_name, branch_name, &new_branch_name);\n+\t\telse\n+\t\t\tstrbuf_addstr(&new_branch_name, branch_name);\n \n \t\tif (recurse_submodules)\n \t\t\tcreate_branches_recursively(the_repository, new_branch_name.buf,\ndiff --git a/t/t3200-branch.sh b/t/t3200-branch.sh\nindex 496b034d0b..bc09abf725 100755\n--- a/t/t3200-branch.sh\n+++ b/t/t3200-branch.sh\n@@ -1725,9 +1725,11 @@ test_expect_success 'create branch with prefix' '\n \tgit branch branch-with-prefix &&\n \tgit checkout branch-with-prefix &&\n \tgit branch branch-with-prefix &&\n+\tgit branch branch-with-no-prefix --no-prefix &&\n \ttest_ref_exists refs/heads/branch-with-prefix &&\n \ttest_ref_exists refs/heads/main-branch-with-prefix &&\n-\ttest_ref_exists refs/heads/branch-with-prefix-branch-with-prefix\n+\ttest_ref_exists refs/heads/branch-with-prefix-branch-with-prefix &&\n+\ttest_ref_exists refs/heads/branch-with-no-prefix\n '\n \n test_done\n-- \ngitgitgadget\n"},{"id":"537306","messageId":"xmqqtsv2ru72.fsf@gitster.g","threadId":"65026","inReplyTo":"0fbdf031cb9f054e023d44fd3eb3315732d527c0.1772207333.git.gitgitgadget@gmail.com","subject":"Re: [PATCH v2 2/2] branch: add a no-prefix option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-02-27T17:07:45Z","receivedAt":"2026-02-27T17:07:48Z","isPatch":true,"body":"\"VALERI Yoann via GitGitGadget\" <gitgitgadget@gmail.com> writes:\n\n> From: VALERI Yoann <yoann.valeri@cea.fr>\n>\n> This patch adds a '--no-prefix' option to 'git branch' to selectively\n> override the 'branch.addCurrentBranchAsPrefix' configuration parameter.\n> Signed-off-by: VALERI Yoann <yoann.valeri@cea.fr>\n> ---\n\nThat is unusual in multiple ways.\n\nThe usual way to do so is to give a command line option that is\nusable without needing any configuration.  This happens first in\nearly patches in a series.\n\nAnd then, assuming that the command line option is widely supported\nas useful (but cumbersome to specify every time), help the users by\nadding a configuration variable, that can be overridden via the\ncommand line option.  That happens next in later patches in a\nseries.\n\nAnd in order to help users discover these two features more easily,\nit is customery to give them very similar names.  In other words,\nadding \"--[no-]prefix-current-branch-name\" may be more\nunderstandable if it is added in patch [1/2], if we want to make the\nmatching configuration \"branch.addCurrentBranchAsPrefix\" in patch\n[2/2].\n\nEven better, have you considered leaving the door open for _others_\nto come up with better ideas _later_ by making it extensible, e.g.,\n\n    --no-name-prefix\n    --name-prefix=<token>\n\nwhere the initial implementation the only supported <token> is\n\"current\" (to signal \"current branch name\")?  That would mean that\nthe corresponding configuration variable would also be a string, not\na boolean, e.g., \"branch.namePrefix = current\".\n\nPerhaps those who work with more than one remotes want to give their\nbranches meant to be pushed to remote A with prefix A- while naming\nthe branches meant to be pushed to remote B with prefix B-, or\nsomething, that is not based on the current branch but something\nelse (e.g., @{push} in this hypothetical example).  I am not saying\nthat you should add such a support to the feature in this series\n(quite honestly, I am not convinced at all if prefixing with the\ncurrent branch name is even something worth adding myself), but we\ndo not want to end up with millions of branch.add${Foo}AsPrefix with\ndifferent values of ${Foo} when we discover that such prefixing\nscheme is useful in the future.\n\nThanks.\n\n"},{"id":"538073","messageId":"pull.2202.v3.git.git.1772802872.gitgitgadget@gmail.com","threadId":"65026","inReplyTo":"pull.2202.v2.git.git.1772207333.gitgitgadget@gmail.com","subject":"[PATCH v3 0/3] branch: add prefixes to new branch names","fromName":"Yoann Valeri via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-03-06T13:14:29Z","receivedAt":"2026-03-06T13:14:35Z","isPatch":true,"body":"This PR adds a way to add prefixes to a new branch being created. The goal\nis mostly to ease the developer process of creating new branches by adding\nshortcuts that can be set either with a command-line option or with\nconfiguration parameter. This is useful especially when you have to do\nsimilar backports on multiple branches, removing a bit of the need for\nfinding names or typing the names over and over again.\n\nChanges since v1:\n\n * Added a '--no-prefix' option to git branch\n\nChanges since v2:\n\n * Changed the PR structure, with 3 patches:\n   * first patch adds the '--name-prefix' option\n   * second adds the 'branch.namePrefix' configuration parameter\n   * third adds the '--no-name-prefix' option\n * Those patches only target 'git branch' now\n\nVALERI Yoann (3):\n  branch: add '--name-prefix' option\n  branch: add 'branch.namePrefix' config param\n  branch: add '--no-name-prefix' option\n\n Documentation/config/branch.adoc |  5 +++++\n Documentation/git-branch.adoc    | 11 ++++++++++-\n branch.c                         | 21 ++++++++++++++++++++\n branch.h                         | 12 +++++++++++\n builtin/branch.c                 | 25 +++++++++++++++--------\n t/t3200-branch.sh                | 34 ++++++++++++++++++++++++++++++++\n 6 files changed, 99 insertions(+), 9 deletions(-)\n\n\nbase-commit: 2cc71917514657b93014134350864f4849edfc83\nPublished-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-2202%2Fvaleriyoann%2Fbranch-with-prefix-v3\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-2202/valeriyoann/branch-with-prefix-v3\nPull-Request: https://github.com/git/git/pull/2202\n\nRange-diff vs v2:\n\n 1:  49641fb34c ! 1:  6cbb950d8b branch: add 'branch.addCurrentBranchAsPrefix' config param\n     @@ Metadata\n      Author: VALERI Yoann <yoann.valeri@cea.fr>\n      \n       ## Commit message ##\n     -    branch: add 'branch.addCurrentBranchAsPrefix' config param\n     +    branch: add '--name-prefix' option\n      \n     -    This patch adds a new configuration parameter for the branch creation\n     -    feature: 'branch.addCurrentBranchAsPrefix'. When set to true, if one\n     -    creates a new branch with either `git branch`, `git checkout -[bB]` or\n     -    `git switch -[cC]`, we will now retrieve the current branch's name, and\n     -    use it as prefix for the name of the newly created branch, alongside a\n     -    hyphen separating the two.\n     -\n     -    For instance, using this parameter, and attempting to create a branch\n     -    'test' while on the 'main' branch will instead create a branch\n     -    'main-test'.\n     -\n     -    This parameters is useful for projects handling many branches, with\n     -    features often needing backport on different branches, so as to reduce\n     -    the time taken to create branches without having to come up with clever\n     -    names.\n     +    This patch adds a '--name-prefix' option to add a prefix to a newly\n     +    created branch. It can use a regular string or a token as prefix. The\n     +    only token currently handled is '@{current}', which is substituted for\n     +    the current branch's name.\n      \n          Signed-off-by: VALERI Yoann <yoann.valeri@cea.fr>\n      \n     - ## Documentation/config/branch.adoc ##\n     -@@ Documentation/config/branch.adoc: This option defaults to `never`.\n     - \tvalue of this variable will be used as the default.\n     - \tSee linkgit:git-for-each-ref[1] field names for valid values.\n     - \n     -+`branch.addCurrentBranchAsPrefix`::\n     -+\tWhen a new branch is created with `git branch`, `git switch` or `git\n     -+\tcheckout` use the name of the current branch as a prefix for the new\n     -+\tbranch's name, alongside the one provided by the user, with a hyphen in the\n     -+\tmiddle. For instance, using this configuration variable, creating the branch\n     -+\t`test` while on `main` will create the branch `main-test`. False by default.\n     -+\n     - `branch.<name>.remote`::\n     - \tWhen on branch _<name>_, it tells `git fetch` and `git push`\n     - \twhich remote to fetch from or push to.  The remote to push to\n     + ## Documentation/git-branch.adoc ##\n     +@@ Documentation/git-branch.adoc: git branch [--color[=<when>] | --no-color] [--show-current]\n     + \t   [(-r|--remotes) | (-a|--all)]\n     + \t   [--list] [<pattern>...]\n     + git branch [--track[=(direct|inherit)] | --no-track] [-f]\n     +-\t   [--recurse-submodules] <branch-name> [<start-point>]\n     ++\t   [--recurse-submodules] [--name-prefix=<token>]\n     ++           <branch-name> [<start-point>]\n     + git branch (--set-upstream-to=<upstream>|-u <upstream>) [<branch-name>]\n     + git branch --unset-upstream [<branch-name>]\n     + git branch (-m|-M) [<old-branch>] <new-branch>\n     +@@ Documentation/git-branch.adoc: Note that this will create the new branch, but it will not switch the\n     + working tree to it; use `git switch <new-branch>` to switch to the\n     + new branch.\n     + \n     ++With a `--name-prefix` option, you can add a prefix to the branch to create.\n     ++This can either a simple name, or a token. Currently, only '@{current}' is\n     ++managed as token, and will use the current branch name as prefix.\n     ++\n     + When a local branch is started off a remote-tracking branch, Git sets up the\n     + branch (specifically the `branch.<name>.remote` and `branch.<name>.merge`\n     + configuration entries) so that `git pull` will appropriately merge from\n     +@@ Documentation/git-branch.adoc: superproject's \"origin/main\", but tracks the submodule's \"origin/main\".\n     + \tand the object it points at.  _<format>_ is the same as\n     + \tthat of linkgit:git-for-each-ref[1].\n     + \n     ++`--name-prefix <token>`::\n     ++\tA string that will be used as prefix to the name of the new branch to\n     ++        create. Can be '@{current}' to use the current branch's name.\n     ++\n     + _<branch-name>_::\n     + \tThe name of the branch to create or delete.\n     + \tThe new branch name must pass all checks defined by\n      \n       ## branch.c ##\n      @@ branch.c: int read_branch_desc(struct strbuf *buf, const char *branch_name)\n       \treturn 0;\n       }\n       \n     -+void add_branch_prefix(const char *current_branch,\n     -+\t\t\t\t\t   const char *target_branch, struct strbuf *buf)\n     ++void add_branch_prefix(const char *name_prefix,\n     ++\t\t\t\t\t   const char *current_branch, struct strbuf *buf)\n      +{\n      +\tint value = 0;\n      +\n     -+\trepo_config_get_bool(the_repository,\n     -+\t\t\t\t\t\t \"branch.addCurrentBranchAsPrefix\", &value);\n     ++\tif (!name_prefix)\n     ++\t\treturn;\n      +\n     -+\tif (value)\n     -+\t\tstrbuf_addf(buf, \"%s-%s\", current_branch, target_branch);\n     -+\telse\n     -+\t\tstrbuf_addstr(buf, target_branch);\n     ++\tif (name_prefix[0] != '@') {\n     ++\t\tstrbuf_addstr(buf, name_prefix);\n     ++\t\treturn;\n     ++\t}\n     ++\n     ++\tif (strcmp(name_prefix, \"@{current}\") == 0)\n     ++\t\tstrbuf_addstr(buf, current_branch);\n      +}\n      +\n       /*\n     @@ branch.h: int install_branch_config(int flag, const char *local, const char *ori\n       int read_branch_desc(struct strbuf *, const char *branch_name);\n       \n      +/*\n     -+ * Fetch the configuration parameter 'branch.addCurrentBranchAsPrefix' and\n     -+ * fill the buffer 'buf' with '<current_branch>-<target_branch>' if true,\n     -+ * otherwise just '<current_branch>'.\n     ++ * Store in 'buf' a prefix to the name of a branch to create by using the given\n     ++ * string 'name_prefix'. It can either be a simple string to a shorthand\n     ++ * starting with '@'.\n     ++ *\n     ++ * Currently, only '@{current}' is managed, and will use 'current_branch' as\n     ++ * prefix.\n      + */\n     -+void add_branch_prefix(const char *current_branch,\n     -+\t\t\t\t\t   const char *target_branch, struct strbuf *buf);\n     ++void add_branch_prefix(const char *name_prefix, const char *current_branch,\n     ++\t\t\t\t\t   struct strbuf *buf);\n     ++\n      +\n       /*\n        * Check if a branch is checked out in the main worktree or any linked\n        * worktree and die (with a message describing its checkout location) if\n      \n       ## builtin/branch.c ##\n     +@@ builtin/branch.c: int cmd_branch(int argc,\n     + \tstruct string_list sorting_options = STRING_LIST_INIT_DUP;\n     + \tstruct ref_format format = REF_FORMAT_INIT;\n     + \tint ret;\n     ++\tconst char *name_prefix = NULL;\n     + \n     + \tstruct option options[] = {\n     + \t\tOPT_GROUP(N_(\"Generic options\")),\n     +@@ builtin/branch.c: int cmd_branch(int argc,\n     + \t\tOPT_BOOL('i', \"ignore-case\", &icase, N_(\"sorting and filtering are case insensitive\")),\n     + \t\tOPT_BOOL(0, \"recurse-submodules\", &recurse_submodules_explicit, N_(\"recurse through submodules\")),\n     + \t\tOPT_STRING(  0 , \"format\", &format.format, N_(\"format\"), N_(\"format to use for the output\")),\n     ++\t\tOPT_STRING(0, \"name-prefix\", &name_prefix, N_(\"name\"), N_(\"prefix for the branch to create\")),\n     + \t\tOPT_END(),\n     + \t};\n     + \n      @@ builtin/branch.c: int cmd_branch(int argc,\n       \t} else if (!noncreate_actions && argc > 0 && argc <= 2) {\n       \t\tconst char *branch_name = argv[0];\n     @@ builtin/branch.c: int cmd_branch(int argc,\n       \n      -\t\tif (recurse_submodules) {\n      -\t\t\tcreate_branches_recursively(the_repository, branch_name,\n     -+\t\tadd_branch_prefix(start_name, branch_name, &new_branch_name);\n     ++\t\tadd_branch_prefix(name_prefix, start_name, &new_branch_name);\n     ++\t\tstrbuf_addstr(&new_branch_name, branch_name);\n      +\n      +\t\tif (recurse_submodules)\n      +\t\t\tcreate_branches_recursively(the_repository, new_branch_name.buf,\n     @@ builtin/branch.c: int cmd_branch(int argc,\n       \t\tusage_with_options(builtin_branch_usage, options);\n       \n      \n     - ## builtin/checkout.c ##\n     -@@ builtin/checkout.c: static void orphaned_commit_warning(struct commit *old_commit, struct commit *ne\n     - \trelease_revisions(&revs);\n     - }\n     - \n     -+static void get_current_branch_info(struct branch_info *branch_info)\n     -+{\n     -+\tstruct object_id rev;\n     -+\tint flag;\n     -+\n     -+\tbranch_info->path = refs_resolve_refdup(get_main_ref_store(the_repository),\n     -+\t\t\t\t\t\t\t\t\t\t\t\"HEAD\", 0, &rev, &flag);\n     -+\n     -+\tif (branch_info->path)\n     -+\t\tbranch_info->commit = lookup_commit_reference_gently(the_repository,\n     -+\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t &rev, 1);\n     -+\n     -+\tif (!(flag & REF_ISSYMREF))\n     -+\t\tFREE_AND_NULL(branch_info->path);\n     -+\n     -+\tif (branch_info->path) {\n     -+\t\tconst char *const prefix = \"refs/heads/\";\n     -+\t\tconst char *p;\n     -+\n     -+\t\tif (skip_prefix(branch_info->path, prefix, &p))\n     -+\t\t\tbranch_info->name = xstrdup(p);\n     -+\t}\n     -+}\n     -+\n     - static int switch_branches(const struct checkout_opts *opts,\n     - \t\t\t   struct branch_info *new_branch_info)\n     - {\n     - \tint ret = 0;\n     - \tstruct branch_info old_branch_info = { 0 };\n     --\tstruct object_id rev;\n     --\tint flag, writeout_error = 0;\n     -+\tint writeout_error = 0;\n     - \tint do_merge = 1;\n     - \n     - \ttrace2_cmd_mode(\"branch\");\n     - \n     - \tmemset(&old_branch_info, 0, sizeof(old_branch_info));\n     --\told_branch_info.path = refs_resolve_refdup(get_main_ref_store(the_repository),\n     --\t\t\t\t\t\t   \"HEAD\", 0, &rev, &flag);\n     --\tif (old_branch_info.path)\n     --\t\told_branch_info.commit = lookup_commit_reference_gently(the_repository, &rev, 1);\n     --\tif (!(flag & REF_ISSYMREF))\n     --\t\tFREE_AND_NULL(old_branch_info.path);\n     --\n     --\tif (old_branch_info.path) {\n     --\t\tconst char *const prefix = \"refs/heads/\";\n     --\t\tconst char *p;\n     --\t\tif (skip_prefix(old_branch_info.path, prefix, &p))\n     --\t\t\told_branch_info.name = xstrdup(p);\n     --\t}\n     -+\tget_current_branch_info(&old_branch_info);\n     - \n     - \tif (opts->new_orphan_branch && opts->orphan_from_empty_tree) {\n     - \t\tif (new_branch_info->name)\n     -@@ builtin/checkout.c: static int checkout_main(int argc, const char **argv, const char *prefix,\n     - \tint parseopt_flags = 0;\n     - \tstruct branch_info new_branch_info = { 0 };\n     - \tint ret;\n     -+\tstruct strbuf full_branch_name = { 0 };\n     - \n     - \topts->overwrite_ignore = 1;\n     - \topts->prefix = prefix;\n     -@@ builtin/checkout.c: static int checkout_main(int argc, const char **argv, const char *prefix,\n     - \t}\n     - \n     - \tif (opts->new_branch) {\n     -+\t\tstruct branch_info current_branch = { 0 };\n     - \t\tstruct strbuf buf = STRBUF_INIT;\n     -+\t\tstrbuf_init(&full_branch_name, 0);\n     -+\n     -+\t\tget_current_branch_info(&current_branch);\n     -+\t\tadd_branch_prefix(current_branch.name, opts->new_branch,\n     -+\t\t\t\t\t\t  &full_branch_name);\n     -+\t\tbranch_info_release(&current_branch);\n     -+\t\topts->new_branch = full_branch_name.buf;\n     - \n     - \t\tif (opts->new_branch_force)\n     - \t\t\topts->branch_exists = validate_branchname(opts->new_branch, &buf);\n     -@@ builtin/checkout.c: static int checkout_main(int argc, const char **argv, const char *prefix,\n     - \tclear_pathspec(&opts->pathspec);\n     - \tfree(opts->pathspec_from_file);\n     - \tfree(options);\n     -+\tif (full_branch_name.buf)\n     -+\t\tstrbuf_release(&full_branch_name);\n     - \n     - \treturn ret;\n     - }\n     -\n     - ## t/t2018-checkout-branch.sh ##\n     -@@ t/t2018-checkout-branch.sh: test_expect_success 'checkout -b rejects an extra path argument' '\n     - \ttest_grep \"Cannot update paths and switch to branch\" err\n     - '\n     - \n     -+test_expect_success 'checkout -b with prefix is valid' '\n     -+\tgit checkout -b main &&\n     -+\tgit checkout -b checkoutb-with-prefix &&\n     -+\tgit checkout main &&\n     -+\ttest_config branch.addCurrentBranchAsPrefix false &&\n     -+\ttest_must_fail git checkout -b checkoutb-with-prefix &&\n     -+\ttest_config branch.addCurrentBranchAsPrefix true &&\n     -+\tgit checkout -b checkoutb-with-prefix &&\n     -+\tgit checkout -b checkoutb-with-prefix &&\n     -+\ttest_ref_exists refs/heads/checkoutb-with-prefix &&\n     -+\ttest_ref_exists refs/heads/main-checkoutb-with-prefix &&\n     -+\ttest_ref_exists refs/heads/main-checkoutb-with-prefix-checkoutb-with-prefix\n     -+'\n     -+\n     -+test_expect_success 'checkout -B with prefix is valid' '\n     -+\tgit checkout main &&\n     -+\tgit checkout -B checkoutB-with-prefix &&\n     -+\tgit checkout main &&\n     -+\ttest_config branch.addCurrentBranchAsPrefix false &&\n     -+\tgit checkout -B checkoutB-with-prefix &&\n     -+\ttest_config branch.addCurrentBranchAsPrefix true &&\n     -+\tgit checkout -B checkoutB-with-prefix &&\n     -+\ttest_ref_exists refs/heads/checkoutB-with-prefix &&\n     -+\ttest_ref_exists refs/heads/checkoutB-with-prefix-checkoutB-with-prefix\n     -+'\n     -+\n     - test_done\n     -\n     - ## t/t2060-switch.sh ##\n     -@@ t/t2060-switch.sh: test_expect_success 'switch back when temporarily detached and checked out elsew\n     - \tgit -C wt2 switch --ignore-other-worktrees shared\n     - '\n     - \n     -+test_expect_success 'switch -c with prefix is valid' '\n     -+\tgit switch main &&\n     -+\tgit switch -c switchc-with-prefix &&\n     -+\tgit checkout main &&\n     -+\ttest_config branch.addCurrentBranchAsPrefix false &&\n     -+\ttest_must_fail git switch -c switchc-with-prefix &&\n     -+\ttest_config branch.addCurrentBranchAsPrefix true &&\n     -+\tgit switch -c switchc-with-prefix &&\n     -+\tgit switch -c switchc-with-prefix &&\n     -+\ttest_ref_exists refs/heads/switchc-with-prefix &&\n     -+\ttest_ref_exists refs/heads/main-switchc-with-prefix &&\n     -+\ttest_ref_exists refs/heads/main-switchc-with-prefix-switchc-with-prefix\n     -+'\n     -+\n     -+test_expect_success 'switch -C with prefix is valid' '\n     -+\tgit switch main &&\n     -+\tgit switch -C switchC-with-prefix &&\n     -+\tgit checkout main &&\n     -+\ttest_config branch.addCurrentBranchAsPrefix false &&\n     -+\tgit switch -C switchC-with-prefix &&\n     -+\ttest_config branch.addCurrentBranchAsPrefix true &&\n     -+\tgit switch -C switchC-with-prefix &&\n     -+\ttest_ref_exists refs/heads/switchC-with-prefix &&\n     -+\ttest_ref_exists refs/heads/switchC-with-prefix-switchC-with-prefix\n     -+'\n     -+\n     - test_done\n     -\n       ## t/t3200-branch.sh ##\n      @@ t/t3200-branch.sh: test_expect_success 'errors if given a bad branch name' '\n       \ttest_cmp expect actual\n       '\n       \n     -+test_expect_success 'create branch with prefix' '\n     ++test_expect_success 'create branch with --name-prefix' '\n      +\tgit config branch.autosetupmerge false &&\n      +\tgit branch branch-with-prefix &&\n     -+\ttest_config branch.addCurrentBranchAsPrefix false &&\n     -+\ttest_must_fail git branch branch-with-prefix &&\n     -+\ttest_config branch.addCurrentBranchAsPrefix true &&\n     -+\tgit branch branch-with-prefix &&\n     -+\tgit checkout branch-with-prefix &&\n     -+\tgit branch branch-with-prefix &&\n     ++\tgit branch --name-prefix \"blob\" -- -with-prefix &&\n     ++\ttest_must_fail git branch --name-prefix \"blob\" -- -with-prefix &&\n     ++\tgit branch --name-prefix \"@{current}\" -- -with-prefix &&\n     ++\tgit switch blob-with-prefix &&\n     ++\tgit branch --name-prefix \"@{current}\" -- -with-prefix &&\n     ++\ttest_must_fail git branch --name-prefix \"@{current}\" -- -with-prefix &&\n      +\ttest_ref_exists refs/heads/branch-with-prefix &&\n     -+\ttest_ref_exists refs/heads/main-branch-with-prefix &&\n     -+\ttest_ref_exists refs/heads/branch-with-prefix-branch-with-prefix\n     ++\ttest_ref_exists refs/heads/main-with-prefix &&\n     ++\ttest_ref_exists refs/heads/blob-with-prefix &&\n     ++\ttest_ref_exists refs/heads/blob-with-prefix-with-prefix &&\n     ++\tgit checkout main &&\n     ++\tgit branch -D branch-with-prefix main-with-prefix blob-with-prefix &&\n     ++\tgit branch -D blob-with-prefix-with-prefix\n      +'\n      +\n       test_done\n -:  ---------- > 2:  d51f71708c branch: add 'branch.namePrefix' config param\n 2:  0fbdf031cb ! 3:  8f45374007 branch: add a no-prefix option\n     @@ Metadata\n      Author: VALERI Yoann <yoann.valeri@cea.fr>\n      \n       ## Commit message ##\n     -    branch: add a no-prefix option\n     +    branch: add '--no-name-prefix' option\n      \n     -    This patch adds a '--no-prefix' option to 'git branch' to selectively\n     -    override the 'branch.addCurrentBranchAsPrefix' configuration parameter.\n     +    This patch adds the '--no-name-prefix' option to prevent adding any\n     +    prefix to the branch being created, whether through the '--name-prefix'\n     +    option or the 'branch.namePrefix' configuration parameter.\n          Signed-off-by: VALERI Yoann <yoann.valeri@cea.fr>\n      \n       ## builtin/branch.c ##\n     @@ builtin/branch.c: int cmd_branch(int argc,\n       \tint delete = 0, rename = 0, copy = 0, list = 0,\n      -\t    unset_upstream = 0, show_current = 0, edit_description = 0;\n      +\t    unset_upstream = 0, show_current = 0, edit_description = 0,\n     -+\t    no_prefix = 0;\n     ++\t\tno_name_prefix = 0;\n       \tconst char *new_upstream = NULL;\n       \tint noncreate_actions = 0;\n       \t/* possible options */\n     @@ builtin/branch.c: int cmd_branch(int argc,\n       \t\tOPT_BOOL('i', \"ignore-case\", &icase, N_(\"sorting and filtering are case insensitive\")),\n       \t\tOPT_BOOL(0, \"recurse-submodules\", &recurse_submodules_explicit, N_(\"recurse through submodules\")),\n       \t\tOPT_STRING(  0 , \"format\", &format.format, N_(\"format\"), N_(\"format to use for the output\")),\n     -+\t\tOPT_BOOL(0, \"no-prefix\", &no_prefix, N_(\"do not add a prefix to the branch being created\")),\n     +-\t\tOPT_STRING(0, \"name-prefix\", &name_prefix, N_(\"name\"), N_(\"prefix for the branch to create\")),\n     ++\t\tOPT_STRING_F(0, \"name-prefix\", &name_prefix, N_(\"name\"), N_(\"prefix for the branch to create\"), PARSE_OPT_NONEG),\n     ++\t\tOPT_BOOL(0, \"no-name-prefix\", &no_name_prefix, N_(\"do not use any prefix for the branch to create\")),\n       \t\tOPT_END(),\n       \t};\n       \n     @@ builtin/branch.c: int cmd_branch(int argc,\n       \t\tif (track == BRANCH_TRACK_OVERRIDE)\n       \t\t\tdie(_(\"the '--set-upstream' option is no longer supported. Please use '--track' or '--set-upstream-to' instead\"));\n       \n     --\t\tadd_branch_prefix(start_name, branch_name, &new_branch_name);\n     -+\t\tif (!no_prefix)\n     -+\t\t\tadd_branch_prefix(start_name, branch_name, &new_branch_name);\n     -+\t\telse\n     -+\t\t\tstrbuf_addstr(&new_branch_name, branch_name);\n     +-\t\tadd_branch_prefix(name_prefix, start_name, &new_branch_name);\n     ++\t\tif (!no_name_prefix)\n     ++\t\t\tadd_branch_prefix(name_prefix, start_name, &new_branch_name);\n     + \t\tstrbuf_addstr(&new_branch_name, branch_name);\n       \n       \t\tif (recurse_submodules)\n     - \t\t\tcreate_branches_recursively(the_repository, new_branch_name.buf,\n      \n       ## t/t3200-branch.sh ##\n     -@@ t/t3200-branch.sh: test_expect_success 'create branch with prefix' '\n     - \tgit branch branch-with-prefix &&\n     - \tgit checkout branch-with-prefix &&\n     - \tgit branch branch-with-prefix &&\n     -+\tgit branch branch-with-no-prefix --no-prefix &&\n     +@@ t/t3200-branch.sh: test_expect_success 'create branch with --name-prefix' '\n     + \tgit switch blob-with-prefix &&\n     + \tgit branch --name-prefix \"@{current}\" -- -with-prefix &&\n     + \ttest_must_fail git branch --name-prefix \"@{current}\" -- -with-prefix &&\n     ++\tgit branch --name-prefix \"blob\" --no-name-prefix branch-with-no-prefix &&\n       \ttest_ref_exists refs/heads/branch-with-prefix &&\n     - \ttest_ref_exists refs/heads/main-branch-with-prefix &&\n     --\ttest_ref_exists refs/heads/branch-with-prefix-branch-with-prefix\n     -+\ttest_ref_exists refs/heads/branch-with-prefix-branch-with-prefix &&\n     -+\ttest_ref_exists refs/heads/branch-with-no-prefix\n     + \ttest_ref_exists refs/heads/main-with-prefix &&\n     + \ttest_ref_exists refs/heads/blob-with-prefix &&\n     + \ttest_ref_exists refs/heads/blob-with-prefix-with-prefix &&\n     ++\ttest_ref_exists refs/heads/branch-with-no-prefix &&\n     + \tgit checkout main &&\n     + \tgit branch -D branch-with-prefix main-with-prefix blob-with-prefix &&\n     +-\tgit branch -D blob-with-prefix-with-prefix\n     ++\tgit branch -D blob-with-prefix-with-prefix branch-with-no-prefix\n     + '\n     + \n     + test_expect_success 'create branch with config prefix' '\n     +@@ t/t3200-branch.sh: test_expect_success 'create branch with config prefix' '\n     + \ttest_config branch.namePrefix \"@{current}\" &&\n     + \tgit checkout main &&\n     + \tgit branch -- -with-prefix &&\n     ++\tgit branch --no-name-prefix branch-with-no-prefix &&\n     + \ttest_ref_exists refs/heads/blob-with-prefix &&\n     + \ttest_ref_exists refs/heads/main-with-prefix &&\n     +-\tgit branch -D blob-with-prefix main-with-prefix\n     ++\ttest_ref_exists refs/heads/branch-with-no-prefix &&\n     ++\tgit branch -D blob-with-prefix main-with-prefix branch-with-no-prefix\n       '\n       \n       test_done\n\n-- \ngitgitgadget\n"},{"id":"538074","messageId":"6cbb950d8bc3b647d7fff72a72f938ee369b552c.1772802872.git.gitgitgadget@gmail.com","threadId":"65026","inReplyTo":"pull.2202.v3.git.git.1772802872.gitgitgadget@gmail.com","subject":"[PATCH v3 1/3] branch: add '--name-prefix' option","fromName":"VALERI Yoann via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-03-06T13:14:30Z","receivedAt":"2026-03-06T13:14:36Z","isPatch":true,"body":"From: VALERI Yoann <yoann.valeri@cea.fr>\n\nThis patch adds a '--name-prefix' option to add a prefix to a newly\ncreated branch. It can use a regular string or a token as prefix. The\nonly token currently handled is '@{current}', which is substituted for\nthe current branch's name.\n\nSigned-off-by: VALERI Yoann <yoann.valeri@cea.fr>\n---\n Documentation/git-branch.adoc | 11 ++++++++++-\n branch.c                      | 17 +++++++++++++++++\n branch.h                      | 12 ++++++++++++\n builtin/branch.c              | 20 +++++++++++++-------\n t/t3200-branch.sh             | 18 ++++++++++++++++++\n 5 files changed, 70 insertions(+), 8 deletions(-)\n\ndiff --git a/Documentation/git-branch.adoc b/Documentation/git-branch.adoc\nindex c0afddc424..00967fa758 100644\n--- a/Documentation/git-branch.adoc\n+++ b/Documentation/git-branch.adoc\n@@ -17,7 +17,8 @@ git branch [--color[=<when>] | --no-color] [--show-current]\n \t   [(-r|--remotes) | (-a|--all)]\n \t   [--list] [<pattern>...]\n git branch [--track[=(direct|inherit)] | --no-track] [-f]\n-\t   [--recurse-submodules] <branch-name> [<start-point>]\n+\t   [--recurse-submodules] [--name-prefix=<token>]\n+           <branch-name> [<start-point>]\n git branch (--set-upstream-to=<upstream>|-u <upstream>) [<branch-name>]\n git branch --unset-upstream [<branch-name>]\n git branch (-m|-M) [<old-branch>] <new-branch>\n@@ -64,6 +65,10 @@ Note that this will create the new branch, but it will not switch the\n working tree to it; use `git switch <new-branch>` to switch to the\n new branch.\n \n+With a `--name-prefix` option, you can add a prefix to the branch to create.\n+This can either a simple name, or a token. Currently, only '@{current}' is\n+managed as token, and will use the current branch name as prefix.\n+\n When a local branch is started off a remote-tracking branch, Git sets up the\n branch (specifically the `branch.<name>.remote` and `branch.<name>.merge`\n configuration entries) so that `git pull` will appropriately merge from\n@@ -319,6 +324,10 @@ superproject's \"origin/main\", but tracks the submodule's \"origin/main\".\n \tand the object it points at.  _<format>_ is the same as\n \tthat of linkgit:git-for-each-ref[1].\n \n+`--name-prefix <token>`::\n+\tA string that will be used as prefix to the name of the new branch to\n+        create. Can be '@{current}' to use the current branch's name.\n+\n _<branch-name>_::\n \tThe name of the branch to create or delete.\n \tThe new branch name must pass all checks defined by\ndiff --git a/branch.c b/branch.c\nindex 243db7d0fc..c24d7ce823 100644\n--- a/branch.c\n+++ b/branch.c\n@@ -365,6 +365,23 @@ int read_branch_desc(struct strbuf *buf, const char *branch_name)\n \treturn 0;\n }\n \n+void add_branch_prefix(const char *name_prefix,\n+\t\t\t\t\t   const char *current_branch, struct strbuf *buf)\n+{\n+\tint value = 0;\n+\n+\tif (!name_prefix)\n+\t\treturn;\n+\n+\tif (name_prefix[0] != '@') {\n+\t\tstrbuf_addstr(buf, name_prefix);\n+\t\treturn;\n+\t}\n+\n+\tif (strcmp(name_prefix, \"@{current}\") == 0)\n+\t\tstrbuf_addstr(buf, current_branch);\n+}\n+\n /*\n  * Check if 'name' can be a valid name for a branch; die otherwise.\n  * Return 1 if the named branch already exists; return 0 otherwise.\ndiff --git a/branch.h b/branch.h\nindex ec2f35fda4..f4ac1e9bbd 100644\n--- a/branch.h\n+++ b/branch.h\n@@ -148,6 +148,18 @@ int install_branch_config(int flag, const char *local, const char *origin, const\n  */\n int read_branch_desc(struct strbuf *, const char *branch_name);\n \n+/*\n+ * Store in 'buf' a prefix to the name of a branch to create by using the given\n+ * string 'name_prefix'. It can either be a simple string to a shorthand\n+ * starting with '@'.\n+ *\n+ * Currently, only '@{current}' is managed, and will use 'current_branch' as\n+ * prefix.\n+ */\n+void add_branch_prefix(const char *name_prefix, const char *current_branch,\n+\t\t\t\t\t   struct strbuf *buf);\n+\n+\n /*\n  * Check if a branch is checked out in the main worktree or any linked\n  * worktree and die (with a message describing its checkout location) if\ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex c577b5d20f..58631913c7 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -725,6 +725,7 @@ int cmd_branch(int argc,\n \tstruct string_list sorting_options = STRING_LIST_INIT_DUP;\n \tstruct ref_format format = REF_FORMAT_INIT;\n \tint ret;\n+\tconst char *name_prefix = NULL;\n \n \tstruct option options[] = {\n \t\tOPT_GROUP(N_(\"Generic options\")),\n@@ -776,6 +777,7 @@ int cmd_branch(int argc,\n \t\tOPT_BOOL('i', \"ignore-case\", &icase, N_(\"sorting and filtering are case insensitive\")),\n \t\tOPT_BOOL(0, \"recurse-submodules\", &recurse_submodules_explicit, N_(\"recurse through submodules\")),\n \t\tOPT_STRING(  0 , \"format\", &format.format, N_(\"format\"), N_(\"format to use for the output\")),\n+\t\tOPT_STRING(0, \"name-prefix\", &name_prefix, N_(\"name\"), N_(\"prefix for the branch to create\")),\n \t\tOPT_END(),\n \t};\n \n@@ -995,6 +997,7 @@ int cmd_branch(int argc,\n \t} else if (!noncreate_actions && argc > 0 && argc <= 2) {\n \t\tconst char *branch_name = argv[0];\n \t\tconst char *start_name = argc == 2 ? argv[1] : head;\n+\t\tstruct strbuf new_branch_name = STRBUF_INIT;\n \n \t\tif (filter.kind != FILTER_REFS_BRANCHES)\n \t\t\tdie(_(\"the -a, and -r, options to 'git branch' do not take a branch name.\\n\"\n@@ -1003,15 +1006,18 @@ int cmd_branch(int argc,\n \t\tif (track == BRANCH_TRACK_OVERRIDE)\n \t\t\tdie(_(\"the '--set-upstream' option is no longer supported. Please use '--track' or '--set-upstream-to' instead\"));\n \n-\t\tif (recurse_submodules) {\n-\t\t\tcreate_branches_recursively(the_repository, branch_name,\n+\t\tadd_branch_prefix(name_prefix, start_name, &new_branch_name);\n+\t\tstrbuf_addstr(&new_branch_name, branch_name);\n+\n+\t\tif (recurse_submodules)\n+\t\t\tcreate_branches_recursively(the_repository, new_branch_name.buf,\n \t\t\t\t\t\t    start_name, NULL, force,\n \t\t\t\t\t\t    reflog, quiet, track, 0);\n-\t\t\tret = 0;\n-\t\t\tgoto out;\n-\t\t}\n-\t\tcreate_branch(the_repository, branch_name, start_name, force, 0,\n-\t\t\t      reflog, quiet, track, 0);\n+\t\telse\n+\t\t\tcreate_branch(the_repository, new_branch_name.buf, start_name,\n+\t\t\t\t\t\t  force, 0, reflog, quiet, track, 0);\n+\n+\t\tstrbuf_release(&new_branch_name);\n \t} else\n \t\tusage_with_options(builtin_branch_usage, options);\n \ndiff --git a/t/t3200-branch.sh b/t/t3200-branch.sh\nindex c58e505c43..550989a2bb 100755\n--- a/t/t3200-branch.sh\n+++ b/t/t3200-branch.sh\n@@ -1716,4 +1716,22 @@ test_expect_success 'errors if given a bad branch name' '\n \ttest_cmp expect actual\n '\n \n+test_expect_success 'create branch with --name-prefix' '\n+\tgit config branch.autosetupmerge false &&\n+\tgit branch branch-with-prefix &&\n+\tgit branch --name-prefix \"blob\" -- -with-prefix &&\n+\ttest_must_fail git branch --name-prefix \"blob\" -- -with-prefix &&\n+\tgit branch --name-prefix \"@{current}\" -- -with-prefix &&\n+\tgit switch blob-with-prefix &&\n+\tgit branch --name-prefix \"@{current}\" -- -with-prefix &&\n+\ttest_must_fail git branch --name-prefix \"@{current}\" -- -with-prefix &&\n+\ttest_ref_exists refs/heads/branch-with-prefix &&\n+\ttest_ref_exists refs/heads/main-with-prefix &&\n+\ttest_ref_exists refs/heads/blob-with-prefix &&\n+\ttest_ref_exists refs/heads/blob-with-prefix-with-prefix &&\n+\tgit checkout main &&\n+\tgit branch -D branch-with-prefix main-with-prefix blob-with-prefix &&\n+\tgit branch -D blob-with-prefix-with-prefix\n+'\n+\n test_done\n-- \ngitgitgadget\n\n"},{"id":"538075","messageId":"d51f71708ceb0263c8e10b6d7915f7a426c88f2e.1772802872.git.gitgitgadget@gmail.com","threadId":"65026","inReplyTo":"pull.2202.v3.git.git.1772802872.gitgitgadget@gmail.com","subject":"[PATCH v3 2/3] branch: add 'branch.namePrefix' config param","fromName":"VALERI Yoann via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-03-06T13:14:31Z","receivedAt":"2026-03-06T13:14:38Z","isPatch":true,"body":"From: VALERI Yoann <yoann.valeri@cea.fr>\n\nThis patch adds a new configuration parameter for the branch creation\nfeature: 'branch.namePrefix'. It corresponds to the '--name-prefix'\noption of 'git branch' made as configuration parameter, and behaves\nexactly like it.\n\nSigned-off-by: VALERI Yoann <yoann.valeri@cea.fr>\n---\n Documentation/config/branch.adoc |  5 +++++\n branch.c                         | 18 +++++++++++-------\n t/t3200-branch.sh                | 12 ++++++++++++\n 3 files changed, 28 insertions(+), 7 deletions(-)\n\ndiff --git a/Documentation/config/branch.adoc b/Documentation/config/branch.adoc\nindex a4db9fa5c8..202c9048b4 100644\n--- a/Documentation/config/branch.adoc\n+++ b/Documentation/config/branch.adoc\n@@ -35,6 +35,11 @@ This option defaults to `never`.\n \tvalue of this variable will be used as the default.\n \tSee linkgit:git-for-each-ref[1] field names for valid values.\n \n+`branch.namePrefix`::\n+\tWhen a new branch is created with `git branch`, use the provided value as\n+\tprefix for its name. Can be '@{current}' to use the current branch's name\n+\tas prefix.\n+\n `branch.<name>.remote`::\n \tWhen on branch _<name>_, it tells `git fetch` and `git push`\n \twhich remote to fetch from or push to.  The remote to push to\ndiff --git a/branch.c b/branch.c\nindex c24d7ce823..5fb7280d47 100644\n--- a/branch.c\n+++ b/branch.c\n@@ -368,18 +368,22 @@ int read_branch_desc(struct strbuf *buf, const char *branch_name)\n void add_branch_prefix(const char *name_prefix,\n \t\t\t\t\t   const char *current_branch, struct strbuf *buf)\n {\n-\tint value = 0;\n+\tchar *config_prefix = NULL;\n \n-\tif (!name_prefix)\n-\t\treturn;\n+\tif (!name_prefix) {\n+\t\tif (repo_config_get_string(the_repository, \"branch.namePrefix\",\n+\t\t\t\t\t\t\t\t   &config_prefix))\n+\t\t\treturn;\n \n-\tif (name_prefix[0] != '@') {\n-\t\tstrbuf_addstr(buf, name_prefix);\n-\t\treturn;\n+\t\tname_prefix = config_prefix;\n \t}\n \n-\tif (strcmp(name_prefix, \"@{current}\") == 0)\n+\tif (name_prefix[0] != '@')\n+\t\tstrbuf_addstr(buf, name_prefix);\n+\telse if (strcmp(name_prefix, \"@{current}\") == 0)\n \t\tstrbuf_addstr(buf, current_branch);\n+\n+    free(config_prefix);\n }\n \n /*\ndiff --git a/t/t3200-branch.sh b/t/t3200-branch.sh\nindex 550989a2bb..847a8355cf 100755\n--- a/t/t3200-branch.sh\n+++ b/t/t3200-branch.sh\n@@ -1734,4 +1734,16 @@ test_expect_success 'create branch with --name-prefix' '\n \tgit branch -D blob-with-prefix-with-prefix\n '\n \n+test_expect_success 'create branch with config prefix' '\n+\ttest_config branch.namePrefix blob &&\n+\tgit branch -- -with-prefix &&\n+\ttest_must_fail git branch -- -with-prefix &&\n+\ttest_config branch.namePrefix \"@{current}\" &&\n+\tgit checkout main &&\n+\tgit branch -- -with-prefix &&\n+\ttest_ref_exists refs/heads/blob-with-prefix &&\n+\ttest_ref_exists refs/heads/main-with-prefix &&\n+\tgit branch -D blob-with-prefix main-with-prefix\n+'\n+\n test_done\n-- \ngitgitgadget\n\n"},{"id":"538076","messageId":"8f45374007fddfa4cc81e536ae6e095b0d67d5e6.1772802872.git.gitgitgadget@gmail.com","threadId":"65026","inReplyTo":"pull.2202.v3.git.git.1772802872.gitgitgadget@gmail.com","subject":"[PATCH v3 3/3] branch: add '--no-name-prefix' option","fromName":"VALERI Yoann via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-03-06T13:14:32Z","receivedAt":"2026-03-06T13:14:39Z","isPatch":true,"body":"From: VALERI Yoann <yoann.valeri@cea.fr>\n\nThis patch adds the '--no-name-prefix' option to prevent adding any\nprefix to the branch being created, whether through the '--name-prefix'\noption or the 'branch.namePrefix' configuration parameter.\nSigned-off-by: VALERI Yoann <yoann.valeri@cea.fr>\n---\n builtin/branch.c  | 9 ++++++---\n t/t3200-branch.sh | 8 ++++++--\n 2 files changed, 12 insertions(+), 5 deletions(-)\n\ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex 58631913c7..204d7865d1 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -713,7 +713,8 @@ int cmd_branch(int argc,\n {\n \t/* possible actions */\n \tint delete = 0, rename = 0, copy = 0, list = 0,\n-\t    unset_upstream = 0, show_current = 0, edit_description = 0;\n+\t    unset_upstream = 0, show_current = 0, edit_description = 0,\n+\t\tno_name_prefix = 0;\n \tconst char *new_upstream = NULL;\n \tint noncreate_actions = 0;\n \t/* possible options */\n@@ -777,7 +778,8 @@ int cmd_branch(int argc,\n \t\tOPT_BOOL('i', \"ignore-case\", &icase, N_(\"sorting and filtering are case insensitive\")),\n \t\tOPT_BOOL(0, \"recurse-submodules\", &recurse_submodules_explicit, N_(\"recurse through submodules\")),\n \t\tOPT_STRING(  0 , \"format\", &format.format, N_(\"format\"), N_(\"format to use for the output\")),\n-\t\tOPT_STRING(0, \"name-prefix\", &name_prefix, N_(\"name\"), N_(\"prefix for the branch to create\")),\n+\t\tOPT_STRING_F(0, \"name-prefix\", &name_prefix, N_(\"name\"), N_(\"prefix for the branch to create\"), PARSE_OPT_NONEG),\n+\t\tOPT_BOOL(0, \"no-name-prefix\", &no_name_prefix, N_(\"do not use any prefix for the branch to create\")),\n \t\tOPT_END(),\n \t};\n \n@@ -1006,7 +1008,8 @@ int cmd_branch(int argc,\n \t\tif (track == BRANCH_TRACK_OVERRIDE)\n \t\t\tdie(_(\"the '--set-upstream' option is no longer supported. Please use '--track' or '--set-upstream-to' instead\"));\n \n-\t\tadd_branch_prefix(name_prefix, start_name, &new_branch_name);\n+\t\tif (!no_name_prefix)\n+\t\t\tadd_branch_prefix(name_prefix, start_name, &new_branch_name);\n \t\tstrbuf_addstr(&new_branch_name, branch_name);\n \n \t\tif (recurse_submodules)\ndiff --git a/t/t3200-branch.sh b/t/t3200-branch.sh\nindex 847a8355cf..cbaa45330f 100755\n--- a/t/t3200-branch.sh\n+++ b/t/t3200-branch.sh\n@@ -1725,13 +1725,15 @@ test_expect_success 'create branch with --name-prefix' '\n \tgit switch blob-with-prefix &&\n \tgit branch --name-prefix \"@{current}\" -- -with-prefix &&\n \ttest_must_fail git branch --name-prefix \"@{current}\" -- -with-prefix &&\n+\tgit branch --name-prefix \"blob\" --no-name-prefix branch-with-no-prefix &&\n \ttest_ref_exists refs/heads/branch-with-prefix &&\n \ttest_ref_exists refs/heads/main-with-prefix &&\n \ttest_ref_exists refs/heads/blob-with-prefix &&\n \ttest_ref_exists refs/heads/blob-with-prefix-with-prefix &&\n+\ttest_ref_exists refs/heads/branch-with-no-prefix &&\n \tgit checkout main &&\n \tgit branch -D branch-with-prefix main-with-prefix blob-with-prefix &&\n-\tgit branch -D blob-with-prefix-with-prefix\n+\tgit branch -D blob-with-prefix-with-prefix branch-with-no-prefix\n '\n \n test_expect_success 'create branch with config prefix' '\n@@ -1741,9 +1743,11 @@ test_expect_success 'create branch with config prefix' '\n \ttest_config branch.namePrefix \"@{current}\" &&\n \tgit checkout main &&\n \tgit branch -- -with-prefix &&\n+\tgit branch --no-name-prefix branch-with-no-prefix &&\n \ttest_ref_exists refs/heads/blob-with-prefix &&\n \ttest_ref_exists refs/heads/main-with-prefix &&\n-\tgit branch -D blob-with-prefix main-with-prefix\n+\ttest_ref_exists refs/heads/branch-with-no-prefix &&\n+\tgit branch -D blob-with-prefix main-with-prefix branch-with-no-prefix\n '\n \n test_done\n-- \ngitgitgadget\n"},{"id":"538111","messageId":"xmqqseaczn87.fsf@gitster.g","threadId":"65026","inReplyTo":"pull.2202.v3.git.git.1772802872.gitgitgadget@gmail.com","subject":"Re: [PATCH v3 0/3] branch: add prefixes to new branch names","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-03-06T21:01:28Z","receivedAt":"2026-03-06T21:01:31Z","isPatch":true,"body":"\"Yoann Valeri via GitGitGadget\" <gitgitgadget@gmail.com> writes:\n\n> This PR adds a way to add prefixes to a new branch being created. The goal\n> is mostly to ease the developer process of creating new branches by adding\n> shortcuts that can be set either with a command-line option or with\n> configuration parameter. This is useful especially when you have to do\n> similar backports on multiple branches, removing a bit of the need for\n> finding names or typing the names over and over again.\n>\n> Changes since v1:\n>\n>  * Added a '--no-prefix' option to git branch\n>\n> Changes since v2:\n>\n>  * Changed the PR structure, with 3 patches:\n>    * first patch adds the '--name-prefix' option\n>    * second adds the 'branch.namePrefix' configuration parameter\n>    * third adds the '--no-name-prefix' option\n>  * Those patches only target 'git branch' now\n\nI haven't read the actual patches, but the first step that adds\n\"--name-prefix\" should also support \"--no-name-prefix\" at the same\ntime, with or without patches 2 and 3.  Doing so would allow users\nwith an alias\n\n    [alias] bn = branch --name-prefix=blah\n\n, who want to almost always add \"blah\" to their branches, to defeat\nthe prefix in rare occasions with\n\n    $ git bn --no-name-prefix foo\n\n"},{"id":"538116","messageId":"xmqqzf4ky6xb.fsf@gitster.g","threadId":"65026","inReplyTo":"8f45374007fddfa4cc81e536ae6e095b0d67d5e6.1772802872.git.gitgitgadget@gmail.com","subject":"Re: [PATCH v3 3/3] branch: add '--no-name-prefix' option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-03-06T21:38:56Z","receivedAt":"2026-03-06T21:38:59Z","isPatch":true,"body":"\"VALERI Yoann via GitGitGadget\" <gitgitgadget@gmail.com> writes:\n\n> -\t\tOPT_STRING(0, \"name-prefix\", &name_prefix, N_(\"name\"), N_(\"prefix for the branch to create\")),\n> +\t\tOPT_STRING_F(0, \"name-prefix\", &name_prefix, N_(\"name\"), N_(\"prefix for the branch to create\"), PARSE_OPT_NONEG),\n> +\t\tOPT_BOOL(0, \"no-name-prefix\", &no_name_prefix, N_(\"do not use any prefix for the branch to create\")),\n\nYou do not want a separate \"no-*\" entry in the options[] table.\nIf we look at parse-options.c to see how OPTION_STRING is handled,\nwe find:\n\n\tcase OPTION_STRING:\n\t\tif (unset)\n\t\t\t*(const char **)opt->value = NULL;\n\t\telse if (opt->flags & PARSE_OPT_OPTARG && !p->opt)\n\t\t\t*(const char **)opt->value = (const char *)opt->defval;\n\t\telse\n\t\t\treturn get_arg(p, opt, flags, (const char **)opt->value);\n\t\treturn 0;\n\nwhich tells us\n\n * \"--no-name-prefix\" is caught by \"if (unset)\" and causes the\n   name_prefix variable set to NULL.\n\n * if we give OPT_OPTARG, we can allow \"--name-prefix\" (with no\n   parameter) to default to opt->defval value; this feature is not\n   very useful in our application.\n\n * Otherwise we get the string after \"--name-prefix=\".\n\nSo you do not need to do anything strange.  To correctly implement\nthe order of handling configuration and command line, you would do:\n\n * initialize name_prefix to NULL.  By default no name_prefix is\n   used.\n\n * early in the cmd_branch() before you call parse_options(),\n   consult the configuration and pick up branch.nameprefix\n   and set it to name_prefix variable.\n\n * then you call parse_options().  If the command line has\n   \"--no-name-prefix\", \"if (unset)\" kicks in and clears the\n   name_prefix variable pointed at by the opt->value.  If the\n   command line has \"--name-prefix=blah\", the name_prefix variable,\n   which may have obtained a value from the configuration, is\n   overwritten with \"blah\".  If the command line does not do\n   anything, then the name_prefix variable will retain whatever\n   value it got from the configuration.\n\n\n\n\n"},{"id":"538167","messageId":"CAPig+cQu92SNS9mamfEwfdZMgqHeDh4Qn7HExgB9OzFiTZTHtA@mail.gmail.com","threadId":"65026","inReplyTo":"pull.2202.v3.git.git.1772802872.gitgitgadget@gmail.com","subject":"Re: [PATCH v3 0/3] branch: add prefixes to new branch names","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2026-03-07T07:05:06Z","receivedAt":"2026-03-07T07:05:22Z","isPatch":true,"body":"On Fri, Mar 6, 2026 at 8:14 AM Yoann Valeri via GitGitGadget\n<gitgitgadget@gmail.com> wrote:\n> This PR adds a way to add prefixes to a new branch being created. The goal\n> is mostly to ease the developer process of creating new branches by adding\n> shortcuts that can be set either with a command-line option or with\n> configuration parameter. This is useful especially when you have to do\n> similar backports on multiple branches, removing a bit of the need for\n> finding names or typing the names over and over again.\n\nSorry, but I'm having trouble understanding the value of this patch\nseries. Neither the cover letter nor the patches themselves provide\nenough context to really understand how this feature would be helpful.\nAdding some real-world examples of how this simplifies your workflow\n*might* help sell the idea. Without such examples, it's difficult to\nimagine that you can't achieve the same with some simple aliases or\ntooling/scripting on your side.\n\nMy other concern is that this implementation is too special-case by\nassuming that users will only want to apply the \"special value\" as a\nprefix. It is easy to imagine some users instead wanting the special\nvalue added as a suffix or embedded. As such, a (possibly) more\npalatable implementation (assuming this feature is even desirable at\nall) might be to instead allow the user to specify some sort of format\nstring into which the special value (or values) is interpolated.\n"},{"id":"538168","messageId":"CAPig+cRQcA+0yWqbYMfjFXxhTsQ-tjJEqsVFudu1thuYi3AXUw@mail.gmail.com","threadId":"65026","inReplyTo":"6cbb950d8bc3b647d7fff72a72f938ee369b552c.1772802872.git.gitgitgadget@gmail.com","subject":"Re: [PATCH v3 1/3] branch: add '--name-prefix' option","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2026-03-07T07:06:01Z","receivedAt":"2026-03-07T07:06:17Z","isPatch":true,"body":"On Fri, Mar 6, 2026 at 8:15 AM VALERI Yoann via GitGitGadget\n<gitgitgadget@gmail.com> wrote:\n> This patch adds a '--name-prefix' option to add a prefix to a newly\n> created branch. It can use a regular string or a token as prefix. The\n> only token currently handled is '@{current}', which is substituted for\n> the current branch's name.\n>\n> Signed-off-by: VALERI Yoann <yoann.valeri@cea.fr>\n> ---\n> diff --git a/Documentation/git-branch.adoc b/Documentation/git-branch.adoc\n> @@ -64,6 +65,10 @@ Note that this will create the new branch, but it will not switch the\n> +With a `--name-prefix` option, you can add a prefix to the branch to create.\n> +This can either a simple name, or a token. Currently, only '@{current}' is\n> +managed as token, and will use the current branch name as prefix.\n\ns/This can/& be/\n\n> diff --git a/branch.c b/branch.c\n> @@ -365,6 +365,23 @@ int read_branch_desc(struct strbuf *buf, const char *branch_name)\n> +void add_branch_prefix(const char *name_prefix,\n> +                                          const char *current_branch, struct strbuf *buf)\n> +{\n> +       int value = 0;\n\nWhat is `value`? It doesn't seem to be used at all in this function.\n\n> +       if (!name_prefix)\n> +               return;\n> +\n> +       if (name_prefix[0] != '@') {\n> +               strbuf_addstr(buf, name_prefix);\n> +               return;\n> +       }\n> +\n> +       if (strcmp(name_prefix, \"@{current}\") == 0)\n> +               strbuf_addstr(buf, current_branch);\n> +}\n\nI would expect this function to produce some sort of diagnostic\nwarning when the user has given it a \"@{token}\" it doesn't recognize.\n\n> diff --git a/branch.h b/branch.h\n> @@ -148,6 +148,18 @@ int install_branch_config(int flag, const char *local, const char *origin, const\n> +/*\n> + * Store in 'buf' a prefix to the name of a branch to create by using the given\n> + * string 'name_prefix'. It can either be a simple string to a shorthand\n> + * starting with '@'.\n> + *\n> + * Currently, only '@{current}' is managed, and will use 'current_branch' as\n> + * prefix.\n> + */\n> +void add_branch_prefix(const char *name_prefix, const char *current_branch,\n> +                                          struct strbuf *buf);\n\nIt feels unnecessarily burdensome to force the caller to compute and\npass in `current_branch`. Intuitively, one would expect\nadd_branch_prefix() to compute the current branch itself if it\ndiscovers that \"@{current}\" has been requested.\n\nMoveover, this approach will not scale well when support for\nadditional \"@{tokens}\" is added down the road since it burdens *all*\ncallers with providing the values for *all* possible tokens.\n\n> diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh\n> @@ -1716,4 +1716,22 @@ test_expect_success 'errors if given a bad branch name' '\n> +test_expect_success 'create branch with --name-prefix' '\n> +       git config branch.autosetupmerge false &&\n\nLet's use `test_config` which will ensure that this setting is\nreverted at the end of the test.\n\n\n> +       git branch branch-with-prefix &&\n> +       git branch --name-prefix \"blob\" -- -with-prefix &&\n> +       test_must_fail git branch --name-prefix \"blob\" -- -with-prefix &&\n> +       git branch --name-prefix \"@{current}\" -- -with-prefix &&\n> +       git switch blob-with-prefix &&\n> +       git branch --name-prefix \"@{current}\" -- -with-prefix &&\n> +       test_must_fail git branch --name-prefix \"@{current}\" -- -with-prefix &&\n> +       test_ref_exists refs/heads/branch-with-prefix &&\n> +       test_ref_exists refs/heads/main-with-prefix &&\n> +       test_ref_exists refs/heads/blob-with-prefix &&\n> +       test_ref_exists refs/heads/blob-with-prefix-with-prefix &&\n> +       git checkout main &&\n> +       git branch -D branch-with-prefix main-with-prefix blob-with-prefix &&\n> +       git branch -D blob-with-prefix-with-prefix\n> +'\n"},{"id":"538169","messageId":"CAPig+cQ_jY8ofigbbtcdakaijS0XhzJFvEkOCPdZpdkt=qMTow@mail.gmail.com","threadId":"65026","inReplyTo":"d51f71708ceb0263c8e10b6d7915f7a426c88f2e.1772802872.git.gitgitgadget@gmail.com","subject":"Re: [PATCH v3 2/3] branch: add 'branch.namePrefix' config param","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2026-03-07T07:07:30Z","receivedAt":"2026-03-07T07:07:46Z","isPatch":true,"body":"On Fri, Mar 6, 2026 at 8:15 AM VALERI Yoann via GitGitGadget\n<gitgitgadget@gmail.com> wrote:\n> This patch adds a new configuration parameter for the branch creation\n> feature: 'branch.namePrefix'. It corresponds to the '--name-prefix'\n> option of 'git branch' made as configuration parameter, and behaves\n> exactly like it.\n>\n> Signed-off-by: VALERI Yoann <yoann.valeri@cea.fr>\n> ---\n> diff --git a/Documentation/config/branch.adoc b/Documentation/config/branch.adoc\n> @@ -35,6 +35,11 @@ This option defaults to `never`.\n> +`branch.namePrefix`::\n> +       When a new branch is created with `git branch`, use the provided value as\n> +       prefix for its name. Can be '@{current}' to use the current branch's name\n> +       as prefix.\n\nThis probably ought to mention --[no]-name-prefix to let the user know\nthat the configuration value can be overridden.\n\n> diff --git a/branch.c b/branch.c\n> @@ -368,18 +368,22 @@ int read_branch_desc(struct strbuf *buf, const char *branch_name)\n>  void add_branch_prefix(const char *name_prefix,\n>                                            const char *current_branch, struct strbuf *buf)\n>  {\n> -       int value = 0;\n> +       char *config_prefix = NULL;\n>\n> -       if (!name_prefix)\n> -               return;\n> +       if (!name_prefix) {\n> +               if (repo_config_get_string(the_repository, \"branch.namePrefix\",\n> +                                                                  &config_prefix))\n> +                       return;\n>\n> -       if (name_prefix[0] != '@') {\n> -               strbuf_addstr(buf, name_prefix);\n> -               return;\n> +               name_prefix = config_prefix;\n>         }\n>\n> -       if (strcmp(name_prefix, \"@{current}\") == 0)\n> +       if (name_prefix[0] != '@')\n> +               strbuf_addstr(buf, name_prefix);\n> +       else if (strcmp(name_prefix, \"@{current}\") == 0)\n>                 strbuf_addstr(buf, current_branch);\n> +\n> +    free(config_prefix);\n>  }\n\nThis \"diff\" is very difficult to read because it's rewriting much of\nthe logic which was first introduced in patch [1/3]. When you reroll,\nit would be a good idea to get the overall logic straight in patch\n[1/3] so that subsequent patches only make small changes to it to\nimprove it (if necessary).\n"},{"id":"538192","messageId":"xmqqfr6alsuz.fsf@gitster.g","threadId":"65026","inReplyTo":"CAPig+cQu92SNS9mamfEwfdZMgqHeDh4Qn7HExgB9OzFiTZTHtA@mail.gmail.com","subject":"Re: [PATCH v3 0/3] branch: add prefixes to new branch names","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-03-08T06:48:04Z","receivedAt":"2026-03-08T06:48:07Z","isPatch":true,"body":"Eric Sunshine <sunshine@sunshineco.com> writes:\n\n> Sorry, but I'm having trouble understanding the value of this patch\n> series. Neither the cover letter nor the patches themselves provide\n> enough context to really understand how this feature would be helpful.\n> Adding some real-world examples of how this simplifies your workflow\n> *might* help sell the idea. Without such examples, it's difficult to\n> imagine that you can't achieve the same with some simple aliases or\n> tooling/scripting on your side.\n\nVery reasonable suggestion.  Thanks.\n"},{"id":"538193","messageId":"xmqq4imqls0l.fsf@gitster.g","threadId":"65026","inReplyTo":"6cbb950d8bc3b647d7fff72a72f938ee369b552c.1772802872.git.gitgitgadget@gmail.com","subject":"Re: [PATCH v3 1/3] branch: add '--name-prefix' option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-03-08T07:06:18Z","receivedAt":"2026-03-08T07:06:21Z","isPatch":true,"body":"\"VALERI Yoann via GitGitGadget\" <gitgitgadget@gmail.com> writes:\n\n> diff --git a/Documentation/git-branch.adoc b/Documentation/git-branch.adoc\n> index c0afddc424..00967fa758 100644\n> --- a/Documentation/git-branch.adoc\n> +++ b/Documentation/git-branch.adoc\n> @@ -17,7 +17,8 @@ git branch [--color[=<when>] | --no-color] [--show-current]\n>  \t   [(-r|--remotes) | (-a|--all)]\n>  \t   [--list] [<pattern>...]\n>  git branch [--track[=(direct|inherit)] | --no-track] [-f]\n> -\t   [--recurse-submodules] <branch-name> [<start-point>]\n> +\t   [--recurse-submodules] [--name-prefix=<token>]\n> +           <branch-name> [<start-point>]\n\nThe indentation of the last line seems a bit off; the previous line\nuses leading HT both in the original and in the updated version, but\nthe last line uses SP indent.\n\n> @@ -64,6 +65,10 @@ Note that this will create the new branch, but it will not switch the\n>  working tree to it; use `git switch <new-branch>` to switch to the\n>  new branch.\n>  \n> +With a `--name-prefix` option, you can add a prefix to the branch to create.\n> +This can either a simple name, or a token. Currently, only '@{current}' is\n> +managed as token, and will use the current branch name as prefix.\n\n\"can either\" -> \"can either be\".\n\"managed\" -> \"supported\".\n\n> @@ -319,6 +324,10 @@ superproject's \"origin/main\", but tracks the submodule's \"origin/main\".\n>  \tand the object it points at.  _<format>_ is the same as\n>  \tthat of linkgit:git-for-each-ref[1].\n>  \n> +`--name-prefix <token>`::\n> +\tA string that will be used as prefix to the name of the new branch to\n> +        create. Can be '@{current}' to use the current branch's name.\n> +\n>  _<branch-name>_::\n>  \tThe name of the branch to create or delete.\n>  \tThe new branch name must pass all checks defined by\n> diff --git a/branch.c b/branch.c\n> index 243db7d0fc..c24d7ce823 100644\n> --- a/branch.c\n> +++ b/branch.c\n> @@ -365,6 +365,23 @@ int read_branch_desc(struct strbuf *buf, const char *branch_name)\n>  \treturn 0;\n>  }\n>  \n> +void add_branch_prefix(const char *name_prefix,\n> +\t\t\t\t\t   const char *current_branch, struct strbuf *buf)\n\nOverly deep indentation here.  Our tab-width is always 8, and you\nwould align the first \"const char\" on these two lines.\n\n> +{\n> +\tint value = 0;\n\nUnused variable?\n\n> +\tif (!name_prefix)\n> +\t\treturn;\n> +\n> +\tif (name_prefix[0] != '@') {\n> +\t\tstrbuf_addstr(buf, name_prefix);\n> +\t\treturn;\n> +\t}\n> +\n> +\tif (strcmp(name_prefix, \"@{current}\") == 0)\n> +\t\tstrbuf_addstr(buf, current_branch);\n> +}\n\nWhat happens when we need to support more than the @{current}?  Will\nthis function grow more parameters and the callers need to prepare\nmore parameters, even if only one of them may be picked by this\nfunction?  That does not smell like a sound way to make things\nmaintainable.\n\n> diff --git a/builtin/branch.c b/builtin/branch.c\n> index c577b5d20f..58631913c7 100644\n> --- a/builtin/branch.c\n> +++ b/builtin/branch.c\n> ...\n> +\t\tadd_branch_prefix(name_prefix, start_name, &new_branch_name);\n\n\nHere, `start_name` is passed as `current_branch` to `add_branch_prefix`.\nHowever, `start_name` is the `<start-point>` (e.g., another branch,\na tag, or a commit). If the user runs:\n\n    $ git branch --name-prefix=@{current} new-branch other-branch\n\nthe prefix will be `other-branch` instead of the *current* branch\nname as advertised in the documentation.  It _may_ be how the\nfeature was intended to work, but then the name \"current\" and the\nway the documentation describes the token are both misleading.\n\n> +\t\t\tcreate_branch(the_repository, new_branch_name.buf, start_name,\n> +\t\t\t\t\t\t  force, 0, reflog, quiet, track, 0);\n\nOverly deep indentation.\n"},{"id":"541245","messageId":"pull.2202.v4.git.git.1775731390.gitgitgadget@gmail.com","threadId":"65026","inReplyTo":"pull.2202.v3.git.git.1772802872.gitgitgadget@gmail.com","subject":"[PATCH v4 0/2] branch: add prefixes to new branch names","fromName":"Yoann Valeri via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-04-09T10:43:08Z","receivedAt":"2026-04-09T10:43:12Z","isPatch":true,"body":"This PR adds a way to add prefixes to a new branch being created. The goal\nis mostly to ease the developer process of creating new branches by adding\nshortcuts that can be set either with a command-line option or with\nconfiguration parameter. This is useful especially when you have to do\nsimilar backports on multiple branches, removing a bit of the need for\nfinding names or typing the names over and over again.\n\nOne instance of where this feature would be useful is for software stacks\nbased on distribution versions (for instance the Ocean software stack for\nHPC centers https://ocean.eupex.eu/). Here, stacks for the different\nversions are organized in git branches, one per versions. Since multiple\nsoftwares will go on multiple version branches, we have to create the same\npackage for each of those version branches, which result one work branch per\nversion branch. For instance, if we want to update a package for AlmaLinux\n8.10, we have to create another branch specifically for that package and\nthat version. Therefore, if we have a lot of version branches to update,\nthat means double the work branches, and specifying each time the version\nbranch the work branch is based on becomes annoying and can be error prone.\nThat is especially true if many people (around 40 for the Ocean stack) work\non this stack.\n\nSo I propose this new feature to simplify this process. While it could be\ndone with a script or an alias, both of those require either the developer\nto share the script or to create it, or to define an alias they may forget.\nHence, an even easier way to ease the process is with this configuration\nparameter which is a one and done deal.\n\nChanges since v1:\n\n * Added a '--no-prefix' option to git branch\n\nChanges since v2:\n\n * Changed the PR structure, with 3 patches:\n   * first patch adds the '--name-prefix' option\n   * second adds the 'branch.namePrefix' configuration parameter\n   * third adds the '--no-name-prefix' option\n * Those patches only target 'git branch' now\n\nChanges since v3:\n\n * Changed the PR structure, with 2 patches:\n   * first patch adds the '--[no-]name-prefix' option\n   * second adds the 'branch.namePrefix' configuration parameter\n * Fixed the different issues pointed out by reviewers, especially regarding\n   option/configuration management\n\nVALERI Yoann (2):\n  branch: add '--name-prefix' option\n  branch: add 'branch.namePrefix' config param\n\n Documentation/config/branch.adoc |  6 ++++\n Documentation/git-branch.adoc    | 11 +++++-\n branch.c                         | 57 ++++++++++++++++++++++++++++++++\n branch.h                         | 12 +++++++\n builtin/branch.c                 | 29 ++++++++++++----\n t/t3200-branch.sh                | 39 ++++++++++++++++++++++\n 6 files changed, 146 insertions(+), 8 deletions(-)\n\n\nbase-commit: 256554692df0685b45e60778b08802b720880c50\nPublished-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-2202%2Fvaleriyoann%2Fbranch-with-prefix-v4\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-2202/valeriyoann/branch-with-prefix-v4\nPull-Request: https://github.com/git/git/pull/2202\n\nRange-diff vs v3:\n\n 1:  6cbb950d8b ! 1:  322f94d121 branch: add '--name-prefix' option\n     @@ Documentation/git-branch.adoc: git branch [--color[=<when>] | --no-color] [--sho\n       git branch [--track[=(direct|inherit)] | --no-track] [-f]\n      -\t   [--recurse-submodules] <branch-name> [<start-point>]\n      +\t   [--recurse-submodules] [--name-prefix=<token>]\n     -+           <branch-name> [<start-point>]\n     ++\t   <branch-name> [<start-point>]\n       git branch (--set-upstream-to=<upstream>|-u <upstream>) [<branch-name>]\n       git branch --unset-upstream [<branch-name>]\n       git branch (-m|-M) [<old-branch>] <new-branch>\n     @@ Documentation/git-branch.adoc: Note that this will create the new branch, but it\n       new branch.\n       \n      +With a `--name-prefix` option, you can add a prefix to the branch to create.\n     -+This can either a simple name, or a token. Currently, only '@{current}' is\n     -+managed as token, and will use the current branch name as prefix.\n     ++This can either be a simple name, or a token. Currently, only '@{current}' is\n     ++supported as token, and will use the current branch name as prefix.\n      +\n       When a local branch is started off a remote-tracking branch, Git sets up the\n       branch (specifically the `branch.<name>.remote` and `branch.<name>.merge`\n     @@ branch.c: int read_branch_desc(struct strbuf *buf, const char *branch_name)\n       \treturn 0;\n       }\n       \n     -+void add_branch_prefix(const char *name_prefix,\n     -+\t\t\t\t\t   const char *current_branch, struct strbuf *buf)\n     ++static char *get_current_branch_name(void)\n      +{\n     -+\tint value = 0;\n     ++\tconst char *const prefix = \"refs/heads/\";\n     ++\tstruct object_id rev;\n     ++\tconst char *p;\n     ++\tchar *output;\n     ++\tchar *path;\n     ++\tint flag;\n      +\n     ++\tpath = refs_resolve_refdup(get_main_ref_store(the_repository),\n     ++\t\t\t\t\t\t\t   \"HEAD\", 0, &rev, &flag);\n     ++\tif (!path) {\n     ++\t\twarning(_(\"Failed to get the current branch's path\"));\n     ++\t\treturn NULL;\n     ++\t} else if (!(flag & REF_ISSYMREF)) {\n     ++\t\tFREE_AND_NULL(path);\n     ++\t\twarning(_(\"Failed to get the current branch's name\"));\n     ++\t\treturn NULL;\n     ++\t}\n     ++\n     ++\tif (skip_prefix(path, prefix, &p)) {\n     ++\t\toutput = xstrdup(p);\n     ++\t\tfree(path);\n     ++\t\treturn output;\n     ++\t}\n     ++\n     ++\twarning(_(\"Failed to get the current branch's name\"));\n     ++\treturn NULL;\n     ++}\n     ++\n     ++int add_branch_prefix(const char *name_prefix, struct strbuf *buf)\n     ++{\n      +\tif (!name_prefix)\n     -+\t\treturn;\n     ++\t\treturn 0;\n      +\n      +\tif (name_prefix[0] != '@') {\n      +\t\tstrbuf_addstr(buf, name_prefix);\n     -+\t\treturn;\n     ++\t\treturn 0;\n     ++\t}\n     ++\n     ++\tif (strcmp(name_prefix, \"@{current}\") == 0) {\n     ++\t\tchar *current_branch_name = get_current_branch_name();\n     ++\n     ++\t\tif (!current_branch_name)\n     ++\t\t\treturn 1;\n     ++\n     ++\t\tstrbuf_addstr(buf, current_branch_name);\n     ++\t\tfree(current_branch_name);\n     ++\t} else {\n     ++\t\tadvise(_(\"Token '%s' unrecognized, only '@{current}' is managed currently\"),\n     ++\t\t\t   name_prefix);\n     ++\t\treturn 1;\n      +\t}\n      +\n     -+\tif (strcmp(name_prefix, \"@{current}\") == 0)\n     -+\t\tstrbuf_addstr(buf, current_branch);\n     ++\treturn 0;\n      +}\n      +\n       /*\n     @@ branch.h: int install_branch_config(int flag, const char *local, const char *ori\n      + * string 'name_prefix'. It can either be a simple string to a shorthand\n      + * starting with '@'.\n      + *\n     -+ * Currently, only '@{current}' is managed, and will use 'current_branch' as\n     -+ * prefix.\n     ++ * Currently, only '@{current}' is managed, and will retrieve the current branch\n     ++ * to use as prefix.\n     ++ *\n     ++ * Return 1 if the function failed to set the branch prefix, 0 otherwise.\n      + */\n     -+void add_branch_prefix(const char *name_prefix, const char *current_branch,\n     -+\t\t\t\t\t   struct strbuf *buf);\n     -+\n     ++int add_branch_prefix(const char *name_prefix, struct strbuf *buf);\n      +\n       /*\n        * Check if a branch is checked out in the main worktree or any linked\n     @@ builtin/branch.c\n      @@ builtin/branch.c: int cmd_branch(int argc,\n       \tstruct string_list sorting_options = STRING_LIST_INIT_DUP;\n       \tstruct ref_format format = REF_FORMAT_INIT;\n     + \tstruct repo_config_values *cfg = repo_config_values(the_repository);\n     ++\tchar *name_prefix = NULL;\n       \tint ret;\n     -+\tconst char *name_prefix = NULL;\n       \n       \tstruct option options[] = {\n     - \t\tOPT_GROUP(N_(\"Generic options\")),\n      @@ builtin/branch.c: int cmd_branch(int argc,\n       \t\tOPT_BOOL('i', \"ignore-case\", &icase, N_(\"sorting and filtering are case insensitive\")),\n       \t\tOPT_BOOL(0, \"recurse-submodules\", &recurse_submodules_explicit, N_(\"recurse through submodules\")),\n     @@ builtin/branch.c: int cmd_branch(int argc,\n       \t\tconst char *branch_name = argv[0];\n       \t\tconst char *start_name = argc == 2 ? argv[1] : head;\n      +\t\tstruct strbuf new_branch_name = STRBUF_INIT;\n     ++\t\tint rc;\n       \n       \t\tif (filter.kind != FILTER_REFS_BRANCHES)\n       \t\t\tdie(_(\"the -a, and -r, options to 'git branch' do not take a branch name.\\n\"\n     @@ builtin/branch.c: int cmd_branch(int argc,\n       \n      -\t\tif (recurse_submodules) {\n      -\t\t\tcreate_branches_recursively(the_repository, branch_name,\n     -+\t\tadd_branch_prefix(name_prefix, start_name, &new_branch_name);\n     ++\t\trc = add_branch_prefix(name_prefix, &new_branch_name);\n     ++\t\tif (rc)\n     ++\t\t\tdie(_(\"Failed to add a branch prefix to '%s'\"), branch_name);\n     ++\n      +\t\tstrbuf_addstr(&new_branch_name, branch_name);\n      +\n      +\t\tif (recurse_submodules)\n     @@ t/t3200-branch.sh: test_expect_success 'errors if given a bad branch name' '\n       '\n       \n      +test_expect_success 'create branch with --name-prefix' '\n     -+\tgit config branch.autosetupmerge false &&\n     ++\ttest_config branch.autosetupmerge false &&\n      +\tgit branch branch-with-prefix &&\n     ++\ttest_ref_exists refs/heads/branch-with-prefix &&\n      +\tgit branch --name-prefix \"blob\" -- -with-prefix &&\n     ++\ttest_ref_exists refs/heads/blob-with-prefix &&\n      +\ttest_must_fail git branch --name-prefix \"blob\" -- -with-prefix &&\n      +\tgit branch --name-prefix \"@{current}\" -- -with-prefix &&\n     ++\ttest_ref_exists refs/heads/main-with-prefix &&\n      +\tgit switch blob-with-prefix &&\n      +\tgit branch --name-prefix \"@{current}\" -- -with-prefix &&\n     -+\ttest_must_fail git branch --name-prefix \"@{current}\" -- -with-prefix &&\n     -+\ttest_ref_exists refs/heads/branch-with-prefix &&\n     -+\ttest_ref_exists refs/heads/main-with-prefix &&\n     -+\ttest_ref_exists refs/heads/blob-with-prefix &&\n      +\ttest_ref_exists refs/heads/blob-with-prefix-with-prefix &&\n     ++\ttest_must_fail git branch --name-prefix \"@{current}\" -- -with-prefix &&\n     ++\tgit branch --name-prefix \"blob\" --no-name-prefix branch-with-no-prefix &&\n     ++\ttest_ref_exists refs/heads/branch-with-no-prefix &&\n      +\tgit checkout main &&\n     ++\ttest_config alias.bn \"branch --name-prefix=blob\" &&\n     ++\tgit bn --no-name-prefix bn-with-no-prefix &&\n     ++\ttest_ref_exists refs/heads/bn-with-no-prefix &&\n      +\tgit branch -D branch-with-prefix main-with-prefix blob-with-prefix &&\n     -+\tgit branch -D blob-with-prefix-with-prefix\n     ++\tgit branch -D blob-with-prefix-with-prefix branch-with-no-prefix &&\n     ++\tgit branch -D bn-with-no-prefix\n      +'\n      +\n       test_done\n 2:  d51f71708c ! 2:  80d1ffde9d branch: add 'branch.namePrefix' config param\n     @@ Documentation/config/branch.adoc: This option defaults to `never`.\n      +`branch.namePrefix`::\n      +\tWhen a new branch is created with `git branch`, use the provided value as\n      +\tprefix for its name. Can be '@{current}' to use the current branch's name\n     -+\tas prefix.\n     ++\tas prefix. This value can be overriden by using the '--[no-]name-prefix'\n     ++\toption of `git branch`.\n      +\n       `branch.<name>.remote`::\n       \tWhen on branch _<name>_, it tells `git fetch` and `git push`\n       \twhich remote to fetch from or push to.  The remote to push to\n      \n     - ## branch.c ##\n     -@@ branch.c: int read_branch_desc(struct strbuf *buf, const char *branch_name)\n     - void add_branch_prefix(const char *name_prefix,\n     - \t\t\t\t\t   const char *current_branch, struct strbuf *buf)\n     - {\n     --\tint value = 0;\n     -+\tchar *config_prefix = NULL;\n     + ## builtin/branch.c ##\n     +@@ builtin/branch.c: int cmd_branch(int argc,\n     + \tstruct ref_format format = REF_FORMAT_INIT;\n     + \tstruct repo_config_values *cfg = repo_config_values(the_repository);\n     + \tchar *name_prefix = NULL;\n     ++\tchar *safekeep_name_prefix;\n     + \tint ret;\n       \n     --\tif (!name_prefix)\n     --\t\treturn;\n     -+\tif (!name_prefix) {\n     -+\t\tif (repo_config_get_string(the_repository, \"branch.namePrefix\",\n     -+\t\t\t\t\t\t\t\t   &config_prefix))\n     -+\t\t\treturn;\n     + \tstruct option options[] = {\n     +@@ builtin/branch.c: int cmd_branch(int argc,\n     + \telse if (!skip_prefix(head, \"refs/heads/\", &head))\n     + \t\tdie(_(\"HEAD not found below refs/heads!\"));\n       \n     --\tif (name_prefix[0] != '@') {\n     --\t\tstrbuf_addstr(buf, name_prefix);\n     --\t\treturn;\n     -+\t\tname_prefix = config_prefix;\n     - \t}\n     - \n     --\tif (strcmp(name_prefix, \"@{current}\") == 0)\n     -+\tif (name_prefix[0] != '@')\n     -+\t\tstrbuf_addstr(buf, name_prefix);\n     -+\telse if (strcmp(name_prefix, \"@{current}\") == 0)\n     - \t\tstrbuf_addstr(buf, current_branch);\n     ++\trepo_config_get_string(the_repository, \"branch.namePrefix\", &name_prefix);\n     ++\tsafekeep_name_prefix = name_prefix;\n      +\n     -+    free(config_prefix);\n     - }\n     + \targc = parse_options(argc, argv, prefix, options, builtin_branch_usage,\n     + \t\t\t     0);\n     + \n     +@@ builtin/branch.c: int cmd_branch(int argc,\n     + \tret = 0;\n       \n     - /*\n     + out:\n     ++\tfree(safekeep_name_prefix);\n     + \tstring_list_clear(&sorting_options, 0);\n     + \treturn ret;\n     + }\n      \n       ## t/t3200-branch.sh ##\n      @@ t/t3200-branch.sh: test_expect_success 'create branch with --name-prefix' '\n     - \tgit branch -D blob-with-prefix-with-prefix\n     + \tgit branch -D bn-with-no-prefix\n       '\n       \n      +test_expect_success 'create branch with config prefix' '\n     ++\ttest_config branch.autosetupmerge false &&\n      +\ttest_config branch.namePrefix blob &&\n      +\tgit branch -- -with-prefix &&\n     ++\ttest_ref_exists refs/heads/blob-with-prefix &&\n      +\ttest_must_fail git branch -- -with-prefix &&\n      +\ttest_config branch.namePrefix \"@{current}\" &&\n      +\tgit checkout main &&\n      +\tgit branch -- -with-prefix &&\n     -+\ttest_ref_exists refs/heads/blob-with-prefix &&\n      +\ttest_ref_exists refs/heads/main-with-prefix &&\n     -+\tgit branch -D blob-with-prefix main-with-prefix\n     ++\tgit branch --no-name-prefix branch-with-no-prefix &&\n     ++\ttest_ref_exists refs/heads/branch-with-no-prefix &&\n     ++\tgit branch -D blob-with-prefix main-with-prefix branch-with-no-prefix\n      +'\n      +\n       test_done\n 3:  8f45374007 < -:  ---------- branch: add '--no-name-prefix' option\n\n-- \ngitgitgadget\n"},{"id":"541246","messageId":"322f94d12173e55e03baf187a37a3870192bc1d2.1775731390.git.gitgitgadget@gmail.com","threadId":"65026","inReplyTo":"pull.2202.v4.git.git.1775731390.gitgitgadget@gmail.com","subject":"[PATCH v4 1/2] branch: add '--name-prefix' option","fromName":"VALERI Yoann via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-04-09T10:43:09Z","receivedAt":"2026-04-09T10:43:13Z","isPatch":true,"body":"From: VALERI Yoann <yoann.valeri@cea.fr>\n\nThis patch adds a '--name-prefix' option to add a prefix to a newly\ncreated branch. It can use a regular string or a token as prefix. The\nonly token currently handled is '@{current}', which is substituted for\nthe current branch's name.\n\nSigned-off-by: VALERI Yoann <yoann.valeri@cea.fr>\n---\n Documentation/git-branch.adoc | 11 ++++++-\n branch.c                      | 57 +++++++++++++++++++++++++++++++++++\n branch.h                      | 12 ++++++++\n builtin/branch.c              | 24 ++++++++++-----\n t/t3200-branch.sh             | 24 +++++++++++++++\n 5 files changed, 120 insertions(+), 8 deletions(-)\n\ndiff --git a/Documentation/git-branch.adoc b/Documentation/git-branch.adoc\nindex c0afddc424..631b912119 100644\n--- a/Documentation/git-branch.adoc\n+++ b/Documentation/git-branch.adoc\n@@ -17,7 +17,8 @@ git branch [--color[=<when>] | --no-color] [--show-current]\n \t   [(-r|--remotes) | (-a|--all)]\n \t   [--list] [<pattern>...]\n git branch [--track[=(direct|inherit)] | --no-track] [-f]\n-\t   [--recurse-submodules] <branch-name> [<start-point>]\n+\t   [--recurse-submodules] [--name-prefix=<token>]\n+\t   <branch-name> [<start-point>]\n git branch (--set-upstream-to=<upstream>|-u <upstream>) [<branch-name>]\n git branch --unset-upstream [<branch-name>]\n git branch (-m|-M) [<old-branch>] <new-branch>\n@@ -64,6 +65,10 @@ Note that this will create the new branch, but it will not switch the\n working tree to it; use `git switch <new-branch>` to switch to the\n new branch.\n \n+With a `--name-prefix` option, you can add a prefix to the branch to create.\n+This can either be a simple name, or a token. Currently, only '@{current}' is\n+supported as token, and will use the current branch name as prefix.\n+\n When a local branch is started off a remote-tracking branch, Git sets up the\n branch (specifically the `branch.<name>.remote` and `branch.<name>.merge`\n configuration entries) so that `git pull` will appropriately merge from\n@@ -319,6 +324,10 @@ superproject's \"origin/main\", but tracks the submodule's \"origin/main\".\n \tand the object it points at.  _<format>_ is the same as\n \tthat of linkgit:git-for-each-ref[1].\n \n+`--name-prefix <token>`::\n+\tA string that will be used as prefix to the name of the new branch to\n+        create. Can be '@{current}' to use the current branch's name.\n+\n _<branch-name>_::\n \tThe name of the branch to create or delete.\n \tThe new branch name must pass all checks defined by\ndiff --git a/branch.c b/branch.c\nindex 243db7d0fc..42e7c799ad 100644\n--- a/branch.c\n+++ b/branch.c\n@@ -365,6 +365,63 @@ int read_branch_desc(struct strbuf *buf, const char *branch_name)\n \treturn 0;\n }\n \n+static char *get_current_branch_name(void)\n+{\n+\tconst char *const prefix = \"refs/heads/\";\n+\tstruct object_id rev;\n+\tconst char *p;\n+\tchar *output;\n+\tchar *path;\n+\tint flag;\n+\n+\tpath = refs_resolve_refdup(get_main_ref_store(the_repository),\n+\t\t\t\t\t\t\t   \"HEAD\", 0, &rev, &flag);\n+\tif (!path) {\n+\t\twarning(_(\"Failed to get the current branch's path\"));\n+\t\treturn NULL;\n+\t} else if (!(flag & REF_ISSYMREF)) {\n+\t\tFREE_AND_NULL(path);\n+\t\twarning(_(\"Failed to get the current branch's name\"));\n+\t\treturn NULL;\n+\t}\n+\n+\tif (skip_prefix(path, prefix, &p)) {\n+\t\toutput = xstrdup(p);\n+\t\tfree(path);\n+\t\treturn output;\n+\t}\n+\n+\twarning(_(\"Failed to get the current branch's name\"));\n+\treturn NULL;\n+}\n+\n+int add_branch_prefix(const char *name_prefix, struct strbuf *buf)\n+{\n+\tif (!name_prefix)\n+\t\treturn 0;\n+\n+\tif (name_prefix[0] != '@') {\n+\t\tstrbuf_addstr(buf, name_prefix);\n+\t\treturn 0;\n+\t}\n+\n+\tif (strcmp(name_prefix, \"@{current}\") == 0) {\n+\t\tchar *current_branch_name = get_current_branch_name();\n+\n+\t\tif (!current_branch_name)\n+\t\t\treturn 1;\n+\n+\t\tstrbuf_addstr(buf, current_branch_name);\n+\t\tfree(current_branch_name);\n+\t} else {\n+\t\tadvise(_(\"Token '%s' unrecognized, only '@{current}' is managed currently\"),\n+\t\t\t   name_prefix);\n+\t\treturn 1;\n+\t}\n+\n+\treturn 0;\n+}\n+\n /*\n  * Check if 'name' can be a valid name for a branch; die otherwise.\n  * Return 1 if the named branch already exists; return 0 otherwise.\ndiff --git a/branch.h b/branch.h\nindex 3dc6e2a0ff..97371444ff 100644\n--- a/branch.h\n+++ b/branch.h\n@@ -146,6 +146,18 @@ int install_branch_config(int flag, const char *local, const char *origin, const\n  */\n int read_branch_desc(struct strbuf *, const char *branch_name);\n \n+/*\n+ * Store in 'buf' a prefix to the name of a branch to create by using the given\n+ * string 'name_prefix'. It can either be a simple string to a shorthand\n+ * starting with '@'.\n+ *\n+ * Currently, only '@{current}' is managed, and will retrieve the current branch\n+ * to use as prefix.\n+ *\n+ * Return 1 if the function failed to set the branch prefix, 0 otherwise.\n+ */\n+int add_branch_prefix(const char *name_prefix, struct strbuf *buf);\n+\n /*\n  * Check if a branch is checked out in the main worktree or any linked\n  * worktree and die (with a message describing its checkout location) if\ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex 1572a4f9ef..cf7d095f22 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -725,6 +725,7 @@ int cmd_branch(int argc,\n \tstruct string_list sorting_options = STRING_LIST_INIT_DUP;\n \tstruct ref_format format = REF_FORMAT_INIT;\n \tstruct repo_config_values *cfg = repo_config_values(the_repository);\n+\tchar *name_prefix = NULL;\n \tint ret;\n \n \tstruct option options[] = {\n@@ -777,6 +778,7 @@ int cmd_branch(int argc,\n \t\tOPT_BOOL('i', \"ignore-case\", &icase, N_(\"sorting and filtering are case insensitive\")),\n \t\tOPT_BOOL(0, \"recurse-submodules\", &recurse_submodules_explicit, N_(\"recurse through submodules\")),\n \t\tOPT_STRING(  0 , \"format\", &format.format, N_(\"format\"), N_(\"format to use for the output\")),\n+\t\tOPT_STRING(0, \"name-prefix\", &name_prefix, N_(\"name\"), N_(\"prefix for the branch to create\")),\n \t\tOPT_END(),\n \t};\n \n@@ -996,6 +998,8 @@ int cmd_branch(int argc,\n \t} else if (!noncreate_actions && argc > 0 && argc <= 2) {\n \t\tconst char *branch_name = argv[0];\n \t\tconst char *start_name = argc == 2 ? argv[1] : head;\n+\t\tstruct strbuf new_branch_name = STRBUF_INIT;\n+\t\tint rc;\n \n \t\tif (filter.kind != FILTER_REFS_BRANCHES)\n \t\t\tdie(_(\"the -a, and -r, options to 'git branch' do not take a branch name.\\n\"\n@@ -1004,15 +1008,21 @@ int cmd_branch(int argc,\n \t\tif (track == BRANCH_TRACK_OVERRIDE)\n \t\t\tdie(_(\"the '--set-upstream' option is no longer supported. Please use '--track' or '--set-upstream-to' instead\"));\n \n-\t\tif (recurse_submodules) {\n-\t\t\tcreate_branches_recursively(the_repository, branch_name,\n+\t\trc = add_branch_prefix(name_prefix, &new_branch_name);\n+\t\tif (rc)\n+\t\t\tdie(_(\"Failed to add a branch prefix to '%s'\"), branch_name);\n+\n+\t\tstrbuf_addstr(&new_branch_name, branch_name);\n+\n+\t\tif (recurse_submodules)\n+\t\t\tcreate_branches_recursively(the_repository, new_branch_name.buf,\n \t\t\t\t\t\t    start_name, NULL, force,\n \t\t\t\t\t\t    reflog, quiet, track, 0);\n-\t\t\tret = 0;\n-\t\t\tgoto out;\n-\t\t}\n-\t\tcreate_branch(the_repository, branch_name, start_name, force, 0,\n-\t\t\t      reflog, quiet, track, 0);\n+\t\telse\n+\t\t\tcreate_branch(the_repository, new_branch_name.buf, start_name,\n+\t\t\t\t\t\t  force, 0, reflog, quiet, track, 0);\n+\n+\t\tstrbuf_release(&new_branch_name);\n \t} else\n \t\tusage_with_options(builtin_branch_usage, options);\n \ndiff --git a/t/t3200-branch.sh b/t/t3200-branch.sh\nindex e7829c2c4b..f81d4380a9 100755\n--- a/t/t3200-branch.sh\n+++ b/t/t3200-branch.sh\n@@ -1717,4 +1717,28 @@ test_expect_success 'errors if given a bad branch name' '\n \ttest_cmp expect actual\n '\n \n+test_expect_success 'create branch with --name-prefix' '\n+\ttest_config branch.autosetupmerge false &&\n+\tgit branch branch-with-prefix &&\n+\ttest_ref_exists refs/heads/branch-with-prefix &&\n+\tgit branch --name-prefix \"blob\" -- -with-prefix &&\n+\ttest_ref_exists refs/heads/blob-with-prefix &&\n+\ttest_must_fail git branch --name-prefix \"blob\" -- -with-prefix &&\n+\tgit branch --name-prefix \"@{current}\" -- -with-prefix &&\n+\ttest_ref_exists refs/heads/main-with-prefix &&\n+\tgit switch blob-with-prefix &&\n+\tgit branch --name-prefix \"@{current}\" -- -with-prefix &&\n+\ttest_ref_exists refs/heads/blob-with-prefix-with-prefix &&\n+\ttest_must_fail git branch --name-prefix \"@{current}\" -- -with-prefix &&\n+\tgit branch --name-prefix \"blob\" --no-name-prefix branch-with-no-prefix &&\n+\ttest_ref_exists refs/heads/branch-with-no-prefix &&\n+\tgit checkout main &&\n+\ttest_config alias.bn \"branch --name-prefix=blob\" &&\n+\tgit bn --no-name-prefix bn-with-no-prefix &&\n+\ttest_ref_exists refs/heads/bn-with-no-prefix &&\n+\tgit branch -D branch-with-prefix main-with-prefix blob-with-prefix &&\n+\tgit branch -D blob-with-prefix-with-prefix branch-with-no-prefix &&\n+\tgit branch -D bn-with-no-prefix\n+'\n+\n test_done\n-- \ngitgitgadget\n\n"},{"id":"541247","messageId":"80d1ffde9d3d55d0ff2b28219e2484fb12d543d9.1775731390.git.gitgitgadget@gmail.com","threadId":"65026","inReplyTo":"pull.2202.v4.git.git.1775731390.gitgitgadget@gmail.com","subject":"[PATCH v4 2/2] branch: add 'branch.namePrefix' config param","fromName":"VALERI Yoann via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-04-09T10:43:10Z","receivedAt":"2026-04-09T10:43:15Z","isPatch":true,"body":"From: VALERI Yoann <yoann.valeri@cea.fr>\n\nThis patch adds a new configuration parameter for the branch creation\nfeature: 'branch.namePrefix'. It corresponds to the '--name-prefix'\noption of 'git branch' made as configuration parameter, and behaves\nexactly like it.\n\nSigned-off-by: VALERI Yoann <yoann.valeri@cea.fr>\n---\n Documentation/config/branch.adoc |  6 ++++++\n builtin/branch.c                 |  5 +++++\n t/t3200-branch.sh                | 15 +++++++++++++++\n 3 files changed, 26 insertions(+)\n\ndiff --git a/Documentation/config/branch.adoc b/Documentation/config/branch.adoc\nindex a4db9fa5c8..392228c300 100644\n--- a/Documentation/config/branch.adoc\n+++ b/Documentation/config/branch.adoc\n@@ -35,6 +35,12 @@ This option defaults to `never`.\n \tvalue of this variable will be used as the default.\n \tSee linkgit:git-for-each-ref[1] field names for valid values.\n \n+`branch.namePrefix`::\n+\tWhen a new branch is created with `git branch`, use the provided value as\n+\tprefix for its name. Can be '@{current}' to use the current branch's name\n+\tas prefix. This value can be overriden by using the '--[no-]name-prefix'\n+\toption of `git branch`.\n+\n `branch.<name>.remote`::\n \tWhen on branch _<name>_, it tells `git fetch` and `git push`\n \twhich remote to fetch from or push to.  The remote to push to\ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex cf7d095f22..2987ac4122 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -726,6 +726,7 @@ int cmd_branch(int argc,\n \tstruct ref_format format = REF_FORMAT_INIT;\n \tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \tchar *name_prefix = NULL;\n+\tchar *safekeep_name_prefix;\n \tint ret;\n \n \tstruct option options[] = {\n@@ -809,6 +810,9 @@ int cmd_branch(int argc,\n \telse if (!skip_prefix(head, \"refs/heads/\", &head))\n \t\tdie(_(\"HEAD not found below refs/heads!\"));\n \n+\trepo_config_get_string(the_repository, \"branch.namePrefix\", &name_prefix);\n+\tsafekeep_name_prefix = name_prefix;\n+\n \targc = parse_options(argc, argv, prefix, options, builtin_branch_usage,\n \t\t\t     0);\n \n@@ -1029,6 +1033,7 @@ int cmd_branch(int argc,\n \tret = 0;\n \n out:\n+\tfree(safekeep_name_prefix);\n \tstring_list_clear(&sorting_options, 0);\n \treturn ret;\n }\ndiff --git a/t/t3200-branch.sh b/t/t3200-branch.sh\nindex f81d4380a9..e75f886842 100755\n--- a/t/t3200-branch.sh\n+++ b/t/t3200-branch.sh\n@@ -1741,4 +1741,19 @@ test_expect_success 'create branch with --name-prefix' '\n \tgit branch -D bn-with-no-prefix\n '\n \n+test_expect_success 'create branch with config prefix' '\n+\ttest_config branch.autosetupmerge false &&\n+\ttest_config branch.namePrefix blob &&\n+\tgit branch -- -with-prefix &&\n+\ttest_ref_exists refs/heads/blob-with-prefix &&\n+\ttest_must_fail git branch -- -with-prefix &&\n+\ttest_config branch.namePrefix \"@{current}\" &&\n+\tgit checkout main &&\n+\tgit branch -- -with-prefix &&\n+\ttest_ref_exists refs/heads/main-with-prefix &&\n+\tgit branch --no-name-prefix branch-with-no-prefix &&\n+\ttest_ref_exists refs/heads/branch-with-no-prefix &&\n+\tgit branch -D blob-with-prefix main-with-prefix branch-with-no-prefix\n+'\n+\n test_done\n-- \ngitgitgadget\n"},{"id":"541293","messageId":"xmqqv7dzsyhd.fsf@gitster.g","threadId":"65026","inReplyTo":"80d1ffde9d3d55d0ff2b28219e2484fb12d543d9.1775731390.git.gitgitgadget@gmail.com","subject":"Re: [PATCH v4 2/2] branch: add 'branch.namePrefix' config param","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-04-09T19:52:14Z","receivedAt":"2026-04-09T19:52:16Z","isPatch":true,"body":"\"VALERI Yoann via GitGitGadget\" <gitgitgadget@gmail.com> writes:\n\n> +`branch.namePrefix`::\n> +\tWhen a new branch is created with `git branch`, use the provided value as\n> +\tprefix for its name. Can be '@{current}' to use the current branch's name\n> +\tas prefix. This value can be overriden by using the '--[no-]name-prefix'\n> +\toption of `git branch`.\n\nEven after reading the cover letter, I am not convinced why this is\na good idea in the first place.\n\nAlso, I am not sure if \"current branch\" really captures what you are\ntrying to achieve.  When \"git branch foo\" creates a new branch \"foo\"\nout of _the_ _current_ branch, i.e.\n\n    $ git checkout base\n    $ git branch foo\n\nwith the nameprefix configuration, it may appear that it is doing\nwhat you want by deriving the name of the new branch taking both\n\"base\" and \"foo\" into account, but what would you want to happen if\nyou did this instead:\n\n    $ git checkout base\n    $ git branch foo\n\nor while you may be on an unrelated \"master\" branch, create and\nswitch to the new branch:\n\n    $ git checkout -b foo base\n\nwhose name takes both \"base\" and \"foo\" into account.\n\nWhat I am getting at is that \"the current branch\" is missing the\npoint and it may be \"the branch the new branch was forked off of\"\nthat is what you really are trying to find that \"base\" in.\n\nHaving said all that, I am fairly negative on this new feature,\nsimply because it is too much magic and will be confusing,\nespecially when invoked with a configuration variable.\n\n"},{"id":"541295","messageId":"xmqqqzonsy08.fsf@gitster.g","threadId":"65026","inReplyTo":"80d1ffde9d3d55d0ff2b28219e2484fb12d543d9.1775731390.git.gitgitgadget@gmail.com","subject":"Re: [PATCH v4 2/2] branch: add 'branch.namePrefix' config param","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-04-09T20:02:31Z","receivedAt":"2026-04-09T20:02:34Z","isPatch":true,"body":"\"VALERI Yoann via GitGitGadget\" <gitgitgadget@gmail.com> writes:\n\n> +test_expect_success 'create branch with config prefix' '\n> +\ttest_config branch.autosetupmerge false &&\n> +\ttest_config branch.namePrefix blob &&\n> +\tgit branch -- -with-prefix &&\n> +\ttest_ref_exists refs/heads/blob-with-prefix &&\n\nAnother thing I noticed.\n\nWouldn't you rather want to have a mechanism where the user does not\nhave to prefix the end-user supplied value (\"with-prefix\" in this\ncase) without leading dash?  From the look of what you are trying to\nconfigure with the variable, the desire seems to be to allow the\nuser to make many branches that share the same prefix, so\nconceptually, among blob-master, blob-maint, blob-feature branches\nthat would result in \"git branch $name\" where name is taken from the\nvocabulary (master, maint, feature), the responsibility to supply\nthe word-separating hyphen belongs to either the prefix side (i.e.,\n\"blob-\") or the mechanism that does prefising (i.e., the prefix\nconfiguration @{current} comes up with a prefix string \"blob\", and\nwith the end-user supplied value of \"with-prefix\", the mechanism\nthat pastes these two strings makes the result \"blob-with-prefix\",\nsupplying the hyphen between \"blob\" and \"with-prefix\".\n\nI said that I am negative in my previous message, simply because I\ndidn't get the intended use case at all, but even if there were a\ngood use case explained in future messages to make me change my\nmind, I doubt that a design that requires the hyphen in front of\n\"with-prefix\" the end-user is supposed to supply is a good thing to\nhave.\n\nThanks.\n"}]}