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

Make .git directory validation code test HEAD

From
Linus Torvalds <torvalds@osdl.org>
Date
Aug 27, 2005, 20:54 UTC
Message-ID
<Pine.LNX.4.58.0508271334320.3317@g5.osdl.org>
In-Reply-To
<87zmr39svy.fsf@litku.valo.iki.fi>

Inspired by a report by Kalle Valo, this changes git-sh-setup-script and the "setup_git_directory()" function to test that $GIT_DIR/HEAD is a symlink, since a number of core git features depend on that these days.

We used to allow a regular file there, but git-fsck-cache has been complaining about that for a while, and anything that uses branches depends on the HEAD file being a symlink, so let's just encode that as a fundamental requirement.

Before, a non-symlink HEAD file would appear to work, but have subtle bugs like not having the HEAD show up as a valid reference (because it wasn't under "refs"). Now, we will complain loudly, and the user can fix it up trivially instead of getting strange behaviour.

This also removes the tests for "$GIT_DIR" and "$GIT_OBJECT_DIRECTORY" being directories, since the other tests will implicitly test for that anyway (ie the tests for HEAD, refs and 00 would fail).

Signed-off-by: Linus Torvalds <torvalds@osdl.org>
---
On Sat, 27 Aug 2005, Kalle Valo wrote:
Show 6 quoted lines
> 
> I investigated it and realized that this was my mistake. I had copied
> the imported git repository from my laptop to my desktop using 'scp
> -r' and it changed .git/HEAD to a file, not a link as it should have
> been. I copied it again, this time with tar to preserve symbolic
> links, and cvsimport started to work again. So this was just a PEBCAK.
diff --git a/git-sh-setup-script b/git-sh-setup-script
--- a/git-sh-setup-script
+++ b/git-sh-setup-script
@@ -11,7 +11,6 @@ die() {
 	exit 1
 }
 
-[ -d "$GIT_DIR" ] &&
+[ -h "$GIT_DIR/HEAD" ] &&
 [ -d "$GIT_DIR/refs" ] &&
-[ -d "$GIT_OBJECT_DIRECTORY" ] &&
 [ -d "$GIT_OBJECT_DIRECTORY/00" ]
diff --git a/setup.c b/setup.c
--- a/setup.c
+++ b/setup.c
@@ -72,6 +72,24 @@ const char **get_pathspec(const char *pr
 	return (const char **) pathspec;
 }
 
+/*
+ * Test it it looks like we're at the top
+ * level git directory. We want to see a
+ *
+ *  - a HEAD symlink and a refs/ directory under ".git"
+ *  - either a .git/objects/ directory _or_ the proper
+ *    GIT_OBJECT_DIRECTORY environment variable
+ */
+static int is_toplevel_directory(void)
+{
+	struct stat st;
+
+	return	!lstat(".git/HEAD", &st) &&
+		S_ISLNK(st.st_mode) &&
+		!access(".git/refs/", X_OK) &&
+		(gitenv(DB_ENVIRONMENT) || !access(".git/objects/", X_OK));
+}
+
 const char *setup_git_directory(void)
 {
 	static char cwd[PATH_MAX+1];
@@ -89,17 +107,8 @@ const char *setup_git_directory(void)
 
 	offset = len = strlen(cwd);
 	for (;;) {
-		/*
-		 * We always want to see a .git/refs/ subdirectory
-		 */
-		if (!access(".git/refs/", X_OK)) {
-			/*
-			 * Then we need either a GIT_OBJECT_DIRECTORY define
-			 * or a .git/objects/ directory
-			 */
-			if (gitenv(DB_ENVIRONMENT) || !access(".git/objects/", X_OK))
-				break;
-		}
+		if (is_toplevel_directory())
+			break;
 		chdir("..");
 		do {
 			if (!offset)
Previous: Kalle ValoNext: Junio C Hamano
Message 4 of 5 in “cvsimport error: need a valid pathname”
  1. Kalle ValoAug 27, 2005
  2. Martin LanghoffAug 27, 2005
  3. Kalle ValoAug 27, 2005
  4. Make .git directory validation code test HEADLinus Torvalds, Aug 27, 2005
  5. Junio C HamanoAug 28, 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.