diff --git a/branch.c b/branch.c
index 7a88a4861e..a577a3ddc1 100644
--- a/branch.c
+++ b/branch.c
@@ -185,6 +185,13 @@ int read_branch_desc(struct strbuf *buf, const char *branch_name)
*/
int validate_branchname(const char *name, struct strbuf *ref)
{
+ /*
+ * since 9ba89f484e (Add new @ shortcut for HEAD, 2013-09-02)
+ * "@" is no longer a valid reference.
+ */
+ if (!strcmp(name, "@"))
+ die(_("'@' is an ambiguous refname"));
+
if (strbuf_check_branch_ref(ref, name))
die(_("'%s' is not a valid branch name."), name);
diff --git a/builtin/branch.c b/builtin/branch.c
index b23b1d1752..7a5a10ad82 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -857,6 +857,9 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
if (track == BRANCH_TRACK_OVERRIDE)
die(_("the '--set-upstream' option is no longer supported. Please use '--track' or '--set-upstream-to' instead."));
+ if (!strcmp(argv[0], "@"))
+ die(_("'@' is ambiguous"));
+
create_branch(the_repository,
argv[0], (argc == 2) ? argv[1] : head,
force, 0, reflog, quiet, track);diff --git a/builtin/checkout.c b/builtin/checkout.c
index b5d477919a..bc92a2c723 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -1151,8 +1151,11 @@ static void setup_new_branch_info_and_source_tree(
setup_branch_path(new_branch_info);
if (!check_refname_format(new_branch_info->path, 0) &&
- !read_ref(new_branch_info->path, &branch_rev))
+ !read_ref(new_branch_info->path, &branch_rev)) {
oidcpy(rev, &branch_rev);
+ if (!strcmp(new_branch_info->name, "@"))
+ warning("ambiguous name, rename this branch ASAP");
+ }
else {
free((char *)new_branch_info->path);
new_branch_info->path = NULL; /* not an existing branch */diff --git a/builtin/tag.c b/builtin/tag.c
index 82fcfc0982..357efc37f8 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -608,6 +608,9 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
else
die(_("Invalid cleanup mode %s"), cleanup_arg);
+ if (!strcmp(tag, "@"))
+ die(_("'@' is ambiguous"));
+
create_reflog_msg(&object, &reflog_msg);
if (create_tag_object) {diff --git a/refs.c b/refs.c
index 8b9f7c3a80..6b5d869bf5 100644
--- a/refs.c
+++ b/refs.c
@@ -167,14 +167,6 @@ static int check_or_sanitize_refname(const char *refname, int flags,
{
int component_len, component_count = 0;
- if (!strcmp(refname, "@")) {
- /* Refname is a single character '@'. */
- if (sanitized)
- strbuf_addch(sanitized, '-');
- else
- return -1;
- }
-
while (1) {
if (sanitized && sanitized->len)
strbuf_complete(sanitized, '/');diff --git a/t/t3204-branch-name-interpretation.sh b/t/t3204-branch-name-interpretation.sh
index 993a6b5eff..862a5dff8e 100755
--- a/t/t3204-branch-name-interpretation.sh
+++ b/t/t3204-branch-name-interpretation.sh
@@ -110,11 +110,11 @@ test_expect_success 'disallow deleting remote branch via @{-1}' '
# The thing we are testing here is that "@" is the real branch refs/heads/@,
# and not refs/heads/HEAD. These tests should not imply that refs/heads/@ is a
-# sane thing, but it _is_ technically allowed for now. If we disallow it, these
-# can be switched to test_must_fail.
+# sane thing, and should go away once "@" is correctly marked as an invalid
+# refname
test_expect_success 'create branch named "@"' '
- git branch -f @ one &&
- expect_branch refs/heads/@ one
+ test_must_fail git branch -f @ one 2>err &&
+ grep "fatal: '\''@'\'' is ambiguous" err
'
test_expect_success 'delete branch named "@"' '--
2.33.0.911.gbe391d4e11