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

Re: git 0.99.7b doesn't build on Cygwin

From
Linus Torvalds <torvalds@osdl.org>
Date
Sep 25, 2005, 16:59 UTC
Message-ID
<Pine.LNX.4.58.0509250941520.3308@g5.osdl.org>
In-Reply-To
<Pine.LNX.4.58.0509241526180.3308@g5.osdl.org>
On Sat, 24 Sep 2005, Linus Torvalds wrote:
Show 7 quoted lines
>
> Anyway, regardless, we could certainly make HEAD be a regular file 
> containing the name of the head instead.
> 
> It probably wouldn't even require a whole lot of changes. HEAD already 
> ends up getting some special attention, since most of the things that look 
> for refs only look inside the .git/refs directory.

This patch does some of it. I decided not to special-case HEAD, but to just improve "read_ref()" a bit.

Changing "read_ref()" was the trivial part - the bigger part that we had three different implementations of it, and this patch is thus bigger just because it collapses them all into "read_ref()" and makes the calling conventions acceptable to all.

NOTE! This makes "symbolic refs" usable in general, ie you can do
	echo "ref: refs/tags/v0.99.7" > .git/refs/tags/LATEST

and that essentially makes "LATEST" a symbolic ref that points to the v0.99.7 tag without using a filesystem symlink. But it does NOT mean that you can replace the HEAD symlink with a file containing "refs/tags/master" yet: there are _other_ parts of git that depend on it being a symlink.

(For the most core example, the "write new head" logic depends on just writing to HEAD, and that symlink will automatically change that write to the thing the HEAD _points_ to. That's the biggest one).

I'll change those too to accept a regular file, if people agree this is worthwhile. In theory there are even UNIXes out there that don't support symlinks, so maybe it's worth it. But maybe people dislike this.

In the meantime, you can test this out with
	echo "ref: HEAD" > .git/TEST_HEAD
	git-rev-parse HEAD TEST_HEAD master

which - if your HEAD points to master - should print out the same SHA1 three times ;)

		Linus
---
Subject: Allow reading "symbolic refs" that point to other refs

This extends the ref reading to understand a "symbolic ref": a ref file that starts with "ref: " and points to another ref file, and thus introduces the notion of ref aliases.

This is in preparation of allowing HEAD to eventually not be a symlink, but one of these symbolic refs instead.

Signed-off-by: Linus Torvalds <torvalds@osdl.org>
---
diff --git a/cache.h b/cache.h
--- a/cache.h
+++ b/cache.h
@@ -227,6 +227,7 @@ extern int has_pack_index(const unsigned
 extern int get_sha1(const char *str, unsigned char *sha1);
 extern int get_sha1_hex(const char *hex, unsigned char *sha1);
 extern char *sha1_to_hex(const unsigned char *sha1);	/* static buffer result! */
+extern int read_ref(const char *filename, unsigned char *sha1);
 
 /* General helper functions */
 extern void usage(const char *err) NORETURN;
diff --git a/refs.c b/refs.c
--- a/refs.c
+++ b/refs.c
@@ -2,17 +2,38 @@
 #include "cache.h"
 
 #include <errno.h>
+#include <ctype.h>
 
-static int read_ref(const char *refname, unsigned char *sha1)
+/* We allow "recursive" symbolic refs. Only within reason, though */
+#define MAXDEPTH 5
+
+int read_ref(const char *filename, unsigned char *sha1)
 {
-	int ret = -1;
-	int fd = open(git_path("%s", refname), O_RDONLY);
+	int depth = 0;
+	int ret = -1, fd;
+
+	while ((fd = open(filename, O_RDONLY)) >= 0) {
+		char buffer[256];
+		int len = read(fd, buffer, sizeof(buffer)-1);
 
-	if (fd >= 0) {
-		char buffer[60];
-		if (read(fd, buffer, sizeof(buffer)) >= 40)
-			ret = get_sha1_hex(buffer, sha1);
 		close(fd);
+		if (len < 0)
+			break;
+
+		buffer[len] = 0;
+		while (len && isspace(buffer[len-1]))
+			buffer[--len] = 0;
+
+		if (!strncmp(buffer, "ref: ", 5)) {
+			if (depth > MAXDEPTH)
+				break;
+			depth++;
+			filename = git_path("%s", buffer+5);
+			continue;
+		}
+		if (len >= 40)
+			ret = get_sha1_hex(buffer, sha1);
+		break;
 	}
 	return ret;
 }
@@ -54,7 +75,7 @@ static int do_for_each_ref(const char *b
 					break;
 				continue;
 			}
-			if (read_ref(path, sha1) < 0)
+			if (read_ref(git_path("%s", path), sha1) < 0)
 				continue;
 			if (!has_sha1_file(sha1))
 				continue;
@@ -71,7 +92,7 @@ static int do_for_each_ref(const char *b
 int head_ref(int (*fn)(const char *path, const unsigned char *sha1))
 {
 	unsigned char sha1[20];
-	if (!read_ref("HEAD", sha1))
+	if (!read_ref(git_path("HEAD"), sha1))
 		return fn("HEAD", sha1);
 	return 0;
 }
@@ -101,33 +122,14 @@ static char *ref_lock_file_name(const ch
 	return ret;
 }
 
-static int read_ref_file(const char *filename, unsigned char *sha1) {
-	int fd = open(filename, O_RDONLY);
-	char hex[41];
-	if (fd < 0) {
-		return error("Couldn't open %s\n", filename);
-	}
-	if ((read(fd, hex, 41) < 41) ||
-	    (hex[40] != '\n') ||
-	    get_sha1_hex(hex, sha1)) {
-		error("Couldn't read a hash from %s\n", filename);
-		close(fd);
-		return -1;
-	}
-	close(fd);
-	return 0;
-}
-
 int get_ref_sha1(const char *ref, unsigned char *sha1)
 {
-	char *filename;
-	int retval;
+	const char *filename;
+
 	if (check_ref_format(ref))
 		return -1;
-	filename = ref_file_name(ref);
-	retval = read_ref_file(filename, sha1);
-	free(filename);
-	return retval;
+	filename = git_path("refs/%s", ref);
+	return read_ref(filename, sha1);
 }
 
 static int lock_ref_file(const char *filename, const char *lock_filename,
@@ -140,7 +142,7 @@ static int lock_ref_file(const char *fil
 		return error("Couldn't open lock file for %s: %s",
 			     filename, strerror(errno));
 	}
-	retval = read_ref_file(filename, current_sha1);
+	retval = read_ref(filename, current_sha1);
 	if (old_sha1) {
 		if (retval) {
 			close(fd);
diff --git a/sha1_name.c b/sha1_name.c
--- a/sha1_name.c
+++ b/sha1_name.c
@@ -119,21 +119,6 @@ static int get_short_sha1(const char *na
 	return -1;
 }
 
-static int get_sha1_file(const char *path, unsigned char *result)
-{
-	char buffer[60];
-	int fd = open(path, O_RDONLY);
-	int len;
-
-	if (fd < 0)
-		return -1;
-	len = read(fd, buffer, sizeof(buffer));
-	close(fd);
-	if (len < 40)
-		return -1;
-	return get_sha1_hex(buffer, result);
-}
-
 static int get_sha1_basic(const char *str, int len, unsigned char *sha1)
 {
 	static const char *prefix[] = {
@@ -150,7 +135,7 @@ static int get_sha1_basic(const char *st
 
 	for (p = prefix; *p; p++) {
 		char *pathname = git_path("%s/%.*s", *p, len, str);
-		if (!get_sha1_file(pathname, sha1))
+		if (!read_ref(pathname, sha1))
 			return 0;
 	}
 
Previous: Linus TorvaldsNext: Jon Loeliger
Message 26 of 38 in “git 0.99.7b doesn't build on Cygwin”
  1. Peter TB BrettSep 23, 2005
  2. Johannes SchindelinSep 23, 2005
  3. Peter TB BrettSep 23, 2005
  4. Martin LanghoffSep 23, 2005
  5. Petr BaudisSep 23, 2005
  6. Linus TorvaldsSep 24, 2005
  7. Linus TorvaldsSep 24, 2005
  8. Junio C HamanoSep 25, 2005
  9. Implementing diff, was Re: git 0.99.7b doesn't build on CygwinJohannes Schindelin, Sep 25, 2005
  10. Davide LibenziSep 25, 2005
  11. Linus TorvaldsSep 25, 2005
  12. Davide LibenziSep 25, 2005
  13. Johannes SchindelinSep 24, 2005
  14. Linus TorvaldsSep 24, 2005
  15. Junio C HamanoSep 24, 2005
  16. Davide LibenziSep 24, 2005
  17. Linus TorvaldsSep 24, 2005
  18. Davide LibenziSep 24, 2005
  19. Junio C HamanoSep 24, 2005
  20. Davide LibenziSep 24, 2005
  21. Junio C HamanoSep 24, 2005
  22. Junio C HamanoSep 24, 2005
  23. Davide LibenziSep 24, 2005
  24. Linus TorvaldsSep 24, 2005
  25. Linus TorvaldsSep 24, 2005
  26. Linus TorvaldsSep 25, 2005
  27. Jon LoeligerSep 26, 2005
  28. Junio C HamanoSep 26, 2005
  29. Davide LibenziSep 24, 2005
  30. Giuseppe BilottaSep 25, 2005
  31. Junio C HamanoSep 26, 2005
  32. Davide LibenziSep 26, 2005
  33. Giuseppe BilottaSep 26, 2005
  34. H. Peter AnvinSep 26, 2005
  35. Davide LibenziSep 26, 2005
  36. H. Peter AnvinSep 26, 2005
  37. Daniel BarkalowSep 25, 2005
  38. Davide LibenziSep 24, 2005

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.