From: "Harald Nordgren via GitGitGadget" <gitgitgadget@gmail.com>
To: git@vger.kernel.org
Cc: Harald Nordgren <haraldnordgren@gmail.com>,
Harald Nordgren <haraldnordgren@gmail.com>
Subject: [PATCH] revisions: add @{default} shorthand for default branch
Date: Thu, 29 Jan 2026 15:25:52 +0000 [thread overview]
Message-ID: <pull.2183.git.git.1769700352081.gitgitgadget@gmail.com> (raw)
From: Harald Nordgren <haraldnordgren@gmail.com>
Git already has shorthands like @{upstream} and @{push} to refer to
tracking branches, but there is no convenient way to refer to the
default branch of a repository (typically "main" or "master").
Users often want to switch to the default branch regardless of its
name, especially when working across repositories with different
default branch names. Currently they must either hardcode the branch
name or query it via configuration, which is cumbersome.
Add a new @{default} shorthand that resolves to the default branch
as determined by init.defaultBranch (or falls back to "main" or
"master" depending on Git version). This allows users to write:
git checkout @{default}
instead of having to know or look up the default branch name.
The implementation follows the same pattern as @{upstream} and @{push},
using a new branch_get_default() function that queries the default
branch name and verifies it exists in the repository.
Signed-off-by: Harald Nordgren <haraldnordgren@gmail.com>
---
revisions: add @{default} shorthand for default branch
Git already has shorthands like @{upstream} and @{push} to refer to
tracking branches, but there is no convenient way to refer to the
default branch of a repository (typically "main" or "master").
Users often want to switch to the default branch regardless of its name,
especially when working across repositories with different default
branch names. Currently they must either hardcode the branch name or
query it via configuration, which is cumbersome.
Add a new @{default} shorthand that resolves to the default branch as
determined by init.defaultBranch (or falls back to "main" or "master"
depending on Git version). This allows users to write:
git checkout @{default}
instead of having to know or look up the default branch name.
The implementation follows the same pattern as @{upstream} and @{push},
using a new branch_get_default() function that queries the default
branch name and verifies it exists in the repository.
Signed-off-by: Harald Nordgren haraldnordgren@gmail.com
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-2183%2FHaraldNordgren%2Fdefault_shorthand-v1
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-2183/HaraldNordgren/default_shorthand-v1
Pull-Request: https://github.com/git/git/pull/2183
Documentation/revisions.adoc | 17 +++++++++++++++++
object-name.c | 21 ++++++++++++++++++++-
remote.c | 12 ++++++++++++
remote.h | 6 ++++++
t/t1508-at-combinations.sh | 1 +
t/t2012-checkout-last.sh | 6 ++++++
6 files changed, 62 insertions(+), 1 deletion(-)
diff --git a/Documentation/revisions.adoc b/Documentation/revisions.adoc
index 6ea6c7cead..17bf42765f 100644
--- a/Documentation/revisions.adoc
+++ b/Documentation/revisions.adoc
@@ -149,6 +149,23 @@ from one location and push to another. In a non-triangular workflow,
This suffix is also accepted when spelled in uppercase, and means the same
thing no matter the case.
+'@\{default\}'::
+ The suffix '@\{default}' refers to the default branch of the repository,
+ typically `main` or `master`. This is determined by the `init.defaultBranch`
+ configuration option, or falls back to `main` (or `master` in older Git
+ versions) if not configured. The default branch must exist in the repository
+ for this syntax to work.
++
+Here's an example:
++
+------------------------------
+$ git checkout @{default}
+Switched to branch 'main'
+
+$ git rev-parse --symbolic-full-name @{default}
+refs/heads/main
+------------------------------
+
'<rev>{caret}[<n>]', e.g. 'HEAD{caret}, v1.5.1{caret}0'::
A suffix '{caret}' to a revision parameter means the first parent of
that commit object. '{caret}<n>' means the <n>th parent (i.e.
diff --git a/object-name.c b/object-name.c
index 8b862c124e..34172f9f80 100644
--- a/object-name.c
+++ b/object-name.c
@@ -947,6 +947,12 @@ static inline int push_mark(const char *string, int len)
return at_mark(string, len, suffix, ARRAY_SIZE(suffix));
}
+static inline int default_mark(const char *string, int len)
+{
+ const char *suffix[] = { "@{default}" };
+ return at_mark(string, len, suffix, ARRAY_SIZE(suffix));
+}
+
static enum get_oid_result get_oid_1(struct repository *r, const char *name, int len, struct object_id *oid, unsigned lookup_flags);
static int interpret_nth_prior_checkout(struct repository *r, const char *name, int namelen, struct strbuf *buf);
@@ -998,7 +1004,8 @@ static int get_oid_basic(struct repository *r, const char *str, int len,
continue;
}
if (!upstream_mark(str + at, len - at) &&
- !push_mark(str + at, len - at)) {
+ !push_mark(str + at, len - at) &&
+ !default_mark(str + at, len - at)) {
reflog_len = (len-1) - (at+2);
len = at;
}
@@ -1707,6 +1714,12 @@ static int branch_interpret_allowed(const char *refname, unsigned allowed)
return 0;
}
+static const char *branch_get_default_mark(struct branch *branch UNUSED,
+ struct strbuf *err UNUSED)
+{
+ return branch_get_default_ref();
+}
+
static int interpret_branch_mark(struct repository *r,
const char *name, int namelen,
int at, struct strbuf *buf,
@@ -1798,6 +1811,12 @@ int repo_interpret_branch_name(struct repository *r,
options);
if (len > 0)
return len;
+
+ len = interpret_branch_mark(r, name, namelen, at - name, buf,
+ default_mark, branch_get_default_mark,
+ options);
+ if (len > 0)
+ return len;
}
return -1;
diff --git a/remote.c b/remote.c
index b756ff6f15..2c829c8c34 100644
--- a/remote.c
+++ b/remote.c
@@ -1961,6 +1961,18 @@ const char *branch_get_push(struct branch *branch, struct strbuf *err)
return branch->push_tracking_ref;
}
+const char *branch_get_default_ref(void)
+{
+ static struct strbuf default_ref = STRBUF_INIT;
+ char *default_branch_name;
+
+ strbuf_reset(&default_ref);
+ default_branch_name = repo_default_branch_name(the_repository, 1);
+ strbuf_addf(&default_ref, "refs/heads/%s", default_branch_name);
+ free(default_branch_name);
+ return default_ref.buf;
+}
+
static int ignore_symref_update(const char *refname, struct strbuf *scratch)
{
return !refs_read_symbolic_ref(get_main_ref_store(the_repository), refname, scratch);
diff --git a/remote.h b/remote.h
index 0ca399e183..5ebb27e173 100644
--- a/remote.h
+++ b/remote.h
@@ -366,6 +366,12 @@ const char *branch_get_upstream(struct branch *branch, struct strbuf *err);
*/
const char *branch_get_push(struct branch *branch, struct strbuf *err);
+/**
+ * Return the fully-qualified refname of the default branch.
+ * I.e., what "@{default}" would give you.
+ */
+const char *branch_get_default_ref(void);
+
/* Flags to match_refs. */
enum match_refs_flags {
MATCH_REFS_NONE = 0,
diff --git a/t/t1508-at-combinations.sh b/t/t1508-at-combinations.sh
index 87a4286414..09d888df53 100755
--- a/t/t1508-at-combinations.sh
+++ b/t/t1508-at-combinations.sh
@@ -69,6 +69,7 @@ check "@{-1}@{u}" ref refs/heads/main
check "@{-1}@{u}@{1}" commit main-one
check "@" commit new-two
check "@@{u}" ref refs/heads/upstream-branch
+check "@{default}" ref refs/heads/main
check "@@/at-test" ref refs/heads/@@/at-test
test_have_prereq MINGW ||
check "@/at-test" ref refs/heads/@/at-test
diff --git a/t/t2012-checkout-last.sh b/t/t2012-checkout-last.sh
index 1f6c4ed042..59999f0852 100755
--- a/t/t2012-checkout-last.sh
+++ b/t/t2012-checkout-last.sh
@@ -27,6 +27,12 @@ test_cmp_symbolic_HEAD_ref () {
test_cmp expect actual
}
+test_expect_success '"checkout @{default}" switches to default branch' '
+ git checkout @{default} &&
+ test_cmp_symbolic_HEAD_ref main &&
+ git checkout other
+'
+
test_expect_success '"checkout -" switches back' '
git checkout - &&
test_cmp_symbolic_HEAD_ref main
base-commit: ea717645d199f6f1b66058886475db3e8c9330e9
--
gitgitgadget
next reply other threads:[~2026-01-29 15:25 UTC|newest]
Thread overview: 32+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-01-29 15:25 Harald Nordgren via GitGitGadget [this message]
2026-01-29 20:23 ` [PATCH] revisions: add @{default} shorthand for default branch Junio C Hamano
2026-01-30 10:59 ` Harald Nordgren
2026-01-30 11:12 ` Harald Nordgren
2026-01-30 16:42 ` Junio C Hamano
2026-01-30 20:58 ` Harald Nordgren
2026-01-30 21:56 ` Junio C Hamano
2026-01-31 0:09 ` Harald Nordgren
2026-01-31 19:16 ` Junio C Hamano
2026-01-31 20:22 ` Harald Nordgren
2026-01-31 20:55 ` Harald Nordgren
2026-02-02 12:32 ` Junio C Hamano
2026-02-02 15:30 ` Harald Nordgren
2026-02-02 9:37 ` Phillip Wood
2026-02-02 10:14 ` Harald Nordgren
2026-02-02 19:40 ` D. Ben Knoble
2026-02-02 21:19 ` Harald Nordgren
2026-02-02 21:53 ` Kristoffer Haugsbakk
2026-02-02 22:17 ` Ben Knoble
2026-02-02 22:54 ` Harald Nordgren
2026-02-02 21:33 ` Junio C Hamano
2026-02-02 22:16 ` Ben Knoble
2026-02-02 23:03 ` Harald Nordgren
2026-02-02 21:44 ` Junio C Hamano
2026-02-02 22:56 ` Harald Nordgren
2026-02-03 11:18 ` Harald Nordgren
2026-02-03 14:38 ` Phillip Wood
2026-02-02 22:28 ` Junio C Hamano
2026-01-30 13:26 ` [PATCH v2] " Harald Nordgren via GitGitGadget
2026-01-30 16:54 ` Kristoffer Haugsbakk
2026-01-30 20:45 ` [PATCH v3] revisions: add @{primary} shorthand for primary branch Harald Nordgren via GitGitGadget
2026-01-31 0:06 ` [PATCH v4] " Harald Nordgren via GitGitGadget
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=pull.2183.git.git.1769700352081.gitgitgadget@gmail.com \
--to=gitgitgadget@gmail.com \
--cc=git@vger.kernel.org \
--cc=haraldnordgren@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox