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

[PATCH] git-branch: a detached HEAD and branch called HEAD are different

From
Junio C Hamano <gitster@pobox.com>
Date
Feb 27, 2009, 06:10 UTC
Message-ID
<7vvdqwo1fe.fsf_-_@gitster.siamese.dyndns.org>
In-Reply-To
<7veixkpi4a.fsf@gitster.siamese.dyndns.org>

While on a detached HEAD, builtin-branch.c passed string "HEAD" around in the varilable "head" that held the current branch name. This did not allow you to distinguish between a local branch whose name is "HEAD" and a detached HEAD.

Allow the variable to contain NULL when the HEAD is detached. The change is primarily to protect !strcmp(head, name) to see if we are try to manipulate the current branch with "head &&"; we won't be futzing with the current branch when the HEAD is detached by definition.

Creating a local branch "HEAD" is not useful at all, but if you managed to create one by mistake, "git branch -d HEAD" couldn't delete it while your HEAD is detached, due to this bug.

One of the functions, rename_branch(), even expected NULL to signal this situation, to prevent "git branch -m othername" while on detached HEAD, and this change incidentally fixes this unrelated bug.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 * I wasn't personally very much interested in these "C-rewrites" of
   Porcelains, and I have never looked at the implementation very
   carefully, but some parts of them are disgustingly crappy, and I am
   finding these inconsistencies after looking at them only for 5
   minutes.  Oh well...
   Anyway, this is a preparatory clean-up.
 branch.c         |    2 +-
 builtin-branch.c |    8 +++++---
 2 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/branch.c b/branch.c
index 1f00e44..e287eab 100644
--- a/branch.c
+++ b/branch.c
@@ -121,7 +121,7 @@ void create_branch(const char *head,
 	if (resolve_ref(ref.buf, sha1, 1, NULL)) {
 		if (!force)
 			die("A branch named '%s' already exists.", name);
-		else if (!is_bare_repository() && !strcmp(head, name))
+		else if (!is_bare_repository() && head && !strcmp(head, name))
 			die("Cannot force update the current branch.");
 		forcing = 1;
 	}
diff --git a/builtin-branch.c b/builtin-branch.c
index 504a981..c34af27 100644
--- a/builtin-branch.c
+++ b/builtin-branch.c
@@ -126,7 +126,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds)
 		if (interpret_nth_last_branch(argv[i], &bname) != len)
 			strbuf_add(&bname, argv[i], len);
 
-		if (kinds == REF_LOCAL_BRANCH && !strcmp(head, bname.buf)) {
+		if (kinds == REF_LOCAL_BRANCH && head && !strcmp(head, bname.buf)) {
 			error("Cannot delete the branch '%s' "
 			      "which you are currently on.", bname.buf);
 			ret = 1;
@@ -408,7 +408,7 @@ static void print_ref_list(int kinds, int detached, int verbose, int abbrev, str
 	for (i = 0; i < ref_list.index; i++) {
 		int current = !detached &&
 			(ref_list.list[i].kind == REF_LOCAL_BRANCH) &&
-			!strcmp(ref_list.list[i].name, head);
+			head && !strcmp(ref_list.list[i].name, head);
 		print_ref_item(&ref_list.list[i], ref_list.maxwidth, verbose,
 			       abbrev, current);
 	}
@@ -541,6 +541,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
 	head = xstrdup(head);
 	if (!strcmp(head, "HEAD")) {
 		detached = 1;
+		head = NULL;
 	} else {
 		if (prefixcmp(head, "refs/heads/"))
 			die("HEAD not found below refs/heads!");
@@ -561,7 +562,8 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
 	else if (rename && (argc == 2))
 		rename_branch(argv[0], argv[1], rename > 1);
 	else if (argc <= 2)
-		create_branch(head, argv[0], (argc == 2) ? argv[1] : head,
+		create_branch(head, argv[0],
+			      (argc == 2) ? argv[1] : head ? head : "HEAD",
 			      force_create, reflog, track);
 	else
 		usage_with_options(builtin_branch_usage, options);
Previous: Junio C HamanoNext: Junio C Hamano
Message 19 of 21 in “teach the new "@{-1} syntax to "git branch"”
  1. teach the new "@{-1} syntax to "git branch"Junio C Hamano, Feb 14, 2009
  2. Jay SoffianFeb 14, 2009
  3. Junio C HamanoFeb 14, 2009
  4. 1/2 Teach the "@{-1} syntax to "git branch"Junio C Hamano, Feb 14, 2009
  5. 2/2 Teach @{-1} to git mergeJunio C Hamano, Feb 14, 2009
  6. Johannes SchindelinFeb 14, 2009
  7. Junio C HamanoFeb 15, 2009
  8. Junio C HamanoFeb 15, 2009
  9. Nanako ShiraishiFeb 15, 2009
  10. Junio C HamanoFeb 15, 2009
  11. Johannes SchindelinFeb 15, 2009
  12. Junio C HamanoFeb 16, 2009
  13. Johannes SchindelinFeb 16, 2009
  14. Jay SoffianFeb 16, 2009
  15. Junio C HamanoFeb 26, 2009
  16. Johannes SchindelinFeb 26, 2009
  17. Deskin MillerFeb 27, 2009
  18. Junio C HamanoFeb 27, 2009
  19. git-branch: a detached HEAD and branch called HEAD are differentJunio C Hamano, Feb 27, 2009
  20. "git branch -M @{-1}"Junio C Hamano, Feb 27, 2009
  21. Junio C HamanoFeb 27, 2009

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

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