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

[PATCH 3/4] Automatically detect a bare git repository.

From
Shawn O. Pearce <spearce@spearce.org>
Date
Dec 31, 2006, 04:30 UTC
Message-ID
<20061231043019.GC5823@spearce.org>
In-Reply-To
<3ffc8ddd9b500c2a34d2bd6ba147dc750d951bcd.1167539318.git.spearce@spearce.org>

Many users find it unfriendly that they can create a bare git repository easily with `git clone --bare` but are then unable to run simple commands like `git log` once they cd into that newly created bare repository. This occurs because we do not check to see if the current working directory is a git repository.

Instead of failing out with "fatal: Not a git repository" we should try to automatically detect if the current working directory is a bare repository and use that for GIT_DIR, and fail out only if that doesn't appear to be true.

We test the current working directory only after we have tried searching up the directory tree. This is to retain backwards compatibility with our previous behavior on the off chance that a user has a 'refs' and 'objects' subdirectories and a 'HEAD' file that looks like a symref, all stored within a repository's associated working directory.

This change also consolidates the validation logic between the case of GIT_DIR being supplied and GIT_DIR not being supplied, cleaning up the code.

Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
---
 This is in response to Theodore Tso's email asking why 'git log'
 doesn't work in a bare repository.  Now it does.  :-)
 setup.c |   73 +++++++++++++++++++++++++++++++++-----------------------------
 1 files changed, 39 insertions(+), 34 deletions(-)
diff --git a/setup.c b/setup.c
index 2afdba4..2ae57f7 100644
--- a/setup.c
+++ b/setup.c
@@ -131,28 +131,46 @@ const char **get_pathspec(const char *prefix, const char **pathspec)
 }
 
 /*
- * Test if it looks like we're at the top level git directory.
+ * Test if it looks like we're at a git directory.
  * We want to see:
  *
- *  - either a .git/objects/ directory _or_ the proper
+ *  - either a objects/ directory _or_ the proper
  *    GIT_OBJECT_DIRECTORY environment variable
- *  - a refs/ directory under ".git"
+ *  - a refs/ directory
  *  - either a HEAD symlink or a HEAD file that is formatted as
  *    a proper "ref:".
  */
-static int is_toplevel_directory(void)
+static int is_git_directory(const char *suspect)
 {
-	if (access(".git/refs/", X_OK) ||
-	    access(getenv(DB_ENVIRONMENT) ?
-		   getenv(DB_ENVIRONMENT) : ".git/objects/", X_OK) ||
-	    validate_symref(".git/HEAD"))
+	char path[PATH_MAX];
+	size_t len = strlen(suspect);
+
+	strcpy(path, suspect);
+	if (getenv(DB_ENVIRONMENT)) {
+		if (access(getenv(DB_ENVIRONMENT), X_OK))
+			return 0;
+	}
+	else {
+		strcpy(path + len, "/objects");
+		if (access(path, X_OK))
+			return 0;
+	}
+
+	strcpy(path + len, "/refs");
+	if (access(path, X_OK))
 		return 0;
+
+	strcpy(path + len, "/HEAD");
+	if (validate_symref(path))
+		return 0;
+
 	return 1;
 }
 
 const char *setup_git_directory_gently(int *nongit_ok)
 {
 	static char cwd[PATH_MAX+1];
+	const char *gitdirenv;
 	int len, offset;
 
 	/*
@@ -160,36 +178,17 @@ const char *setup_git_directory_gently(int *nongit_ok)
 	 * to do any discovery, but we still do repository
 	 * validation.
 	 */
-	if (getenv(GIT_DIR_ENVIRONMENT)) {
-		char path[PATH_MAX];
-		int len = strlen(getenv(GIT_DIR_ENVIRONMENT));
-		if (sizeof(path) - 40 < len)
+	gitdirenv = getenv(GIT_DIR_ENVIRONMENT);
+	if (gitdirenv) {
+		if (PATH_MAX - 40 < strlen(gitdirenv))
 			die("'$%s' too big", GIT_DIR_ENVIRONMENT);
-		memcpy(path, getenv(GIT_DIR_ENVIRONMENT), len);
-		
-		strcpy(path + len, "/refs");
-		if (access(path, X_OK))
-			goto bad_dir_environ;
-		strcpy(path + len, "/HEAD");
-		if (validate_symref(path))
-			goto bad_dir_environ;
-		if (getenv(DB_ENVIRONMENT)) {
-			if (access(getenv(DB_ENVIRONMENT), X_OK))
-				goto bad_dir_environ;
-		}
-		else {
-			strcpy(path + len, "/objects");
-			if (access(path, X_OK))
-				goto bad_dir_environ;
-		}
-		return NULL;
-	bad_dir_environ:
+		if (is_git_directory(gitdirenv))
+			return NULL;
 		if (nongit_ok) {
 			*nongit_ok = 1;
 			return NULL;
 		}
-		path[len] = 0;
-		die("Not a git repository: '%s'", path);
+		die("Not a git repository: '%s'", gitdirenv);
 	}
 
 	if (!getcwd(cwd, sizeof(cwd)) || cwd[0] != '/')
@@ -197,11 +196,17 @@ const char *setup_git_directory_gently(int *nongit_ok)
 
 	offset = len = strlen(cwd);
 	for (;;) {
-		if (is_toplevel_directory())
+		if (is_git_directory(".git"))
 			break;
 		chdir("..");
 		do {
 			if (!offset) {
+				if (is_git_directory(cwd)) {
+					if (chdir(cwd))
+						die("Cannot come back to cwd");
+					setenv(GIT_DIR_ENVIRONMENT, cwd, 1);
+					return NULL;
+				}
 				if (nongit_ok) {
 					if (chdir(cwd))
 						die("Cannot come back to cwd");
-- 
1.5.0.rc0.g6bb1
Previous: Shawn O. PearceNext: Junio C Hamano
Message 2 of 17 in “Replace "GIT_DIR" with GIT_DIR_ENVIRONMENT.”
  1. 2/4 Replace "GIT_DIR" with GIT_DIR_ENVIRONMENT.Shawn O. Pearce, Dec 31, 2006
  2. 3/4 Automatically detect a bare git repository.Shawn O. Pearce, Dec 31, 2006
  3. Junio C HamanoDec 31, 2006
  4. Shawn PearceDec 31, 2006
  5. Junio C HamanoDec 31, 2006
  6. Theodore TsoDec 31, 2006
  7. Shawn O. PearceJan 1, 2007
  8. Martin WaitzDec 31, 2006
  9. Shawn O. PearceJan 1, 2007
  10. 4/4 Disallow working directory commands in a bare repository.Shawn O. Pearce, Dec 31, 2006
  11. Junio C HamanoDec 31, 2006
  12. Shawn O. PearceDec 31, 2006
  13. Junio C HamanoDec 31, 2006
  14. Theodore TsoDec 31, 2006
  15. Johannes SchindelinDec 31, 2006
  16. Junio C HamanoDec 31, 2006
  17. Johannes SchindelinJan 2, 2007

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.