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

[PATCH(amend)] introduce GIT_WORK_DIR environment variable

From
MLMatthias Lederhofer <matled@gmx.net>
Date
Mar 11, 2007, 15:56 UTC
Message-ID
<20070311155649.GA29663@moooo.ath.cx>
In-Reply-To
<fcaeb9bf0703110542t49bb3e77kb164ba7bfee1a6ed@mail.gmail.com>

This environment variable can be used with GIT_DIR to specify the toplevel working directory. When GIT_DIR is not set this variable is ignored. As for GIT_DIR there is also the option git --work-dir which overrides the environment variable.

Signed-off-by: Matthias Lederhofer <matled@gmx.net>
---
New patch, this should go with the 'rev-parse --is-bare-repository
option' patch.

Documentation added, is_bare_repository check fixed, relative GIT_DIR fix. Becaus GIT_DIR is expanded to a full path setup_git_env should be called after setup_git_directory_gently. I searched for the callers of setup_git_directory_gently and think this is fulfilled.

Nguyen Thai Ngoc Duy <pclouds@gmail.com> wrote:
Show 6 quoted lines
> I propose the following instead of the last two lines:
> 
>                if (!gitwd)
>                        return NULL;
>                if (stat(gitwd, &st_work))
>                        die("Unable to stat git working directory %s",gitwd);
It's in this new patch.
> If cwd changed and GIT_DIR is a relative path, git can no longer
> access GIT_DIR properly.
This too.
---
 Documentation/git.txt |   16 ++++++++-
 cache.h               |    2 +
 environment.c         |   11 +++++-
 git.c                 |   12 ++++++-
 setup.c               |   92 +++++++++++++++++++++++++++++++++++++++++++-----
 5 files changed, 119 insertions(+), 14 deletions(-)
diff --git a/Documentation/git.txt b/Documentation/git.txt
index e875e83..d2f5d27 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -10,7 +10,8 @@ SYNOPSIS
 --------
 [verse]
 'git' [--version] [--exec-path[=GIT_EXEC_PATH]] [-p|--paginate]
-    [--bare] [--git-dir=GIT_DIR] [--help] COMMAND [ARGS]
+    [--bare] [--git-dir=GIT_DIR] [--work-dir=GIT_WORK_DIR]
+    [--help] COMMAND [ARGS]
 
 DESCRIPTION
 -----------
@@ -81,6 +82,13 @@ OPTIONS
 	Set the path to the repository. This can also be controlled by
 	setting the GIT_DIR environment variable.
 
+--work-dir=<path>::
+	Set the path to the toplevel working directory.  The value will
+	be used only in combination with $GIT_DIR or '--git-dir'.
+	Without this option git will assume that the current directory
+	is also the toplevel directory.  This can also be controlled by
+	setting the GIT_WORK_DIR environment variable.
+
 --bare::
 	Same as --git-dir=`pwd`.
 
@@ -325,6 +333,12 @@ git so take care if using Cogito etc.
 	specifies a path to use instead of the default `.git`
 	for the base of the repository.
 
+'GIT_WORK_DIR'::
+	Set the path to the toplevel working directory.  The value will
+	be used only in combination with $GIT_DIR or '--git-dir'.
+	Without this environment variable git will assume that the
+	current directory is also the toplevel directory.
+
 git Commits
 ~~~~~~~~~~~
 'GIT_AUTHOR_NAME'::
diff --git a/cache.h b/cache.h
index f172d02..e3ca087 100644
--- a/cache.h
+++ b/cache.h
@@ -144,6 +144,7 @@ enum object_type {
 };
 
 #define GIT_DIR_ENVIRONMENT "GIT_DIR"
+#define GIT_WORKING_DIR_ENVIRONMENT "GIT_WORK_DIR"
 #define DEFAULT_GIT_DIR_ENVIRONMENT ".git"
 #define DB_ENVIRONMENT "GIT_OBJECT_DIRECTORY"
 #define INDEX_ENVIRONMENT "GIT_INDEX_FILE"
@@ -164,6 +165,7 @@ extern char *get_graft_file(void);
 
 #define ALTERNATE_DB_ENVIRONMENT "GIT_ALTERNATE_OBJECT_DIRECTORIES"
 
+extern int has_working_directory;
 extern const char **get_pathspec(const char *prefix, const char **pathspec);
 extern const char *setup_git_directory_gently(int *);
 extern const char *setup_git_directory(void);
diff --git a/environment.c b/environment.c
index 0151ad0..7bf6a87 100644
--- a/environment.c
+++ b/environment.c
@@ -59,8 +59,15 @@ static void setup_git_env(void)
 int is_bare_repository(void)
 {
 	const char *dir, *s;
-	if (0 <= is_bare_repository_cfg)
-		return is_bare_repository_cfg;
+	/* definitely bare */
+	if (is_bare_repository_cfg == 1)
+		return 1;
+	/* GIT_WORK_DIR is set, bare if cwd is outside */
+	if (has_working_directory >= 0)
+		return !has_working_directory;
+	/* configuration says it is not bare */
+	if (is_bare_repository_cfg == 0)
+		return 0;
 
 	dir = get_git_dir();
 	if (!strcmp(dir, DEFAULT_GIT_DIR_ENVIRONMENT))
diff --git a/git.c b/git.c
index fe2b74a..8a73648 100644
--- a/git.c
+++ b/git.c
@@ -4,7 +4,7 @@
 #include "quote.h"
 
 const char git_usage_string[] =
-	"git [--version] [--exec-path[=GIT_EXEC_PATH]] [-p|--paginate] [--bare] [--git-dir=GIT_DIR] [--help] COMMAND [ARGS]";
+	"git [--version] [--exec-path[=GIT_EXEC_PATH]] [-p|--paginate] [--bare] [--git-dir=GIT_DIR] [--work-dir=GIT_WORK_DIR] [--help] COMMAND [ARGS]";
 
 static void prepend_to_path(const char *dir, int len)
 {
@@ -68,6 +68,16 @@ static int handle_options(const char*** argv, int* argc)
 			(*argc)--;
 		} else if (!prefixcmp(cmd, "--git-dir=")) {
 			setenv(GIT_DIR_ENVIRONMENT, cmd + 10, 1);
+		} else if (!strcmp(cmd, "--work-dir")) {
+			if (*argc < 2) {
+				fprintf(stderr, "No directory given for --work-dir.\n" );
+				usage(git_usage_string);
+			}
+			setenv(GIT_WORKING_DIR_ENVIRONMENT, (*argv)[1], 1);
+			(*argv)++;
+			(*argc)--;
+		} else if (!prefixcmp(cmd, "--work-dir=")) {
+			setenv(GIT_WORKING_DIR_ENVIRONMENT, cmd + 11, 1);
 		} else if (!strcmp(cmd, "--bare")) {
 			static char git_dir[PATH_MAX+1];
 			setenv(GIT_DIR_ENVIRONMENT, getcwd(git_dir, sizeof(git_dir)), 1);
diff --git a/setup.c b/setup.c
index a45ea83..ebf628e 100644
--- a/setup.c
+++ b/setup.c
@@ -192,28 +192,100 @@ int is_inside_git_dir(void)
 	return inside_git_dir;
 }
 
+int has_working_directory = -1;
+
 const char *setup_git_directory_gently(int *nongit_ok)
 {
 	static char cwd[PATH_MAX+1];
 	const char *gitdirenv;
 	int len, offset;
 
-	/*
-	 * If GIT_DIR is set explicitly, we're not going
-	 * to do any discovery, but we still do repository
-	 * validation.
-	 */
 	gitdirenv = getenv(GIT_DIR_ENVIRONMENT);
 	if (gitdirenv) {
+		struct stat st, st_work, st_git;
+		const char *gitwd;
+		char *prefix;
+		char c;
+		int len;
+
 		if (PATH_MAX - 40 < strlen(gitdirenv))
 			die("'$%s' too big", GIT_DIR_ENVIRONMENT);
-		if (is_git_directory(gitdirenv))
-			return NULL;
-		if (nongit_ok) {
-			*nongit_ok = 1;
+		if (!is_git_directory(gitdirenv)) {
+			if (nongit_ok) {
+				*nongit_ok = 1;
+				return NULL;
+			}
+			die("Not a git repository: '%s'", gitdirenv);
+		}
+
+		/* check for working directory */
+		gitwd = getenv(GIT_WORKING_DIR_ENVIRONMENT);
+		if (!gitwd)
 			return NULL;
+		if (stat(gitwd, &st_work))
+			die("Unable to stat git working directory '%s'", gitwd);
+		if (inside_git_dir == -1 && stat(gitdirenv, &st_git))
+			die("Unable to stat git directory");
+		if (!getcwd(cwd, sizeof(cwd)-1) || cwd[0] != '/')
+			die("Unable to read current working directory");
+		len = strlen(cwd);
+
+		prefix = cwd+len;
+		for (;;) {
+			c = *prefix;
+			*prefix = '\0';
+			if (stat(cwd, &st))
+				die("Unable to stat '%s'", cwd);
+			if (st_work.st_dev == st.st_dev &&
+			    st_work.st_ino == st.st_ino)
+				break;
+			if (inside_git_dir == -1 &&
+			    st_git.st_dev == st.st_dev &&
+			    st_git.st_ino == st.st_ino)
+				inside_git_dir = 1;
+			*prefix = c;
+
+			if (prefix == cwd+1) {
+				has_working_directory = 0;
+				return NULL;
+			}
+			while (*(--prefix) != '/')
+				; /* do nothing */
+			if (prefix == cwd)
+				prefix++;
+		}
+
+		/*
+		 * if GIT_DIR is no absolute path it wont work anymore after
+		 * changing the directory, therefore expand it to an absolute
+		 * path
+		 */
+		if (gitdirenv[0] != '/') {
+			char buf[PATH_MAX];
+			if (chdir(gitdirenv))
+				die("Cannot change directory to '%s'",
+				    gitdirenv);
+			if (!getcwd(buf, sizeof(buf)) || buf[0] != '/')
+				die("Unable to read current working directory");
+			setenv(GIT_DIR_ENVIRONMENT, buf, 1);
+		}
+		if (chdir(cwd))
+			die("Cannot change directory to '%s'", cwd);
+
+		if (c) {
+			*prefix = c;
+			prefix++;
+			cwd[len] = '/';
+			cwd[len+1] = '\0';
+		} else {
+			prefix = NULL;
 		}
-		die("Not a git repository: '%s'", gitdirenv);
+
+		has_working_directory = 1;
+		if (inside_git_dir == -1)
+			inside_git_dir = 0;
+
+		return prefix;
 	}
 
 	if (!getcwd(cwd, sizeof(cwd)-1) || cwd[0] != '/')
-- 
1.5.0.3.356.gafc9e-dirty
Previous: Nguyen Thai Ngoc DuyNext: Nguyen Thai Ngoc Duy
Message 17 of 39 in “[RFC] introduce GIT_WORK_DIR environment variable”
  1. Matthias LederhoferMar 11, 2007
  2. Junio C HamanoMar 11, 2007
  3. Andy ParkinsMar 11, 2007
  4. Matthias LederhoferMar 11, 2007
  5. Junio C HamanoMar 11, 2007
  6. Johannes SchindelinMar 11, 2007
  7. Linus TorvaldsMar 11, 2007
  8. Junio C HamanoMar 11, 2007
  9. Linus TorvaldsMar 11, 2007
  10. A.J. RossiniMar 12, 2007
  11. Andy ParkinsApr 1, 2007
  12. Nguyen Thai Ngoc DuyMar 11, 2007
  13. Matthias LederhoferMar 11, 2007
  14. Nguyen Thai Ngoc DuyMar 11, 2007
  15. Matthias LederhoferMar 11, 2007
  16. Nguyen Thai Ngoc DuyMar 11, 2007
  17. introduce GIT_WORK_DIR environment variableMatthias Lederhofer, Mar 11, 2007
  18. Nguyen Thai Ngoc DuyMar 11, 2007
  19. use $GIT_DIR/workdir as working directory with $GIT_DIRMatthias Lederhofer, Mar 11, 2007
  20. core.workdir config variableMatthias Lederhofer, Mar 13, 2007
  21. core.workdir config variableMatthias Lederhofer, Mar 13, 2007
  22. Shawn O. PearceMar 14, 2007
  23. Junio C HamanoMar 14, 2007
  24. Shawn O. PearceMar 14, 2007
  25. Nguyen Thai Ngoc DuyMar 11, 2007
  26. rev-parse: --is-bare-repository optionMatthias Lederhofer, Mar 11, 2007
  27. git-init: set up GIT_DIR/workdir if GIT_WORK_DIR is setMatthias Lederhofer, Mar 12, 2007
  28. Joshua N PritikinMar 12, 2007
  29. Matthias LederhoferMar 12, 2007
  30. Matthias LederhoferMar 12, 2007
  31. Nguyen Thai Ngoc DuyMar 12, 2007
  32. Matthias LederhoferMar 12, 2007
  33. Junio C HamanoMar 12, 2007
  34. Matthias LederhoferMar 12, 2007
  35. always interpret GIT_WORK_DIR relative to $GIT_DIRMatthias Lederhofer, Mar 12, 2007
  36. GIT_WORK_DIR: documentation for relative pathMatthias Lederhofer, Mar 12, 2007
  37. Junio C HamanoMar 12, 2007
  38. Matthias LederhoferMar 12, 2007
  39. git-init: set up GIT_DIR/workdir if GIT_WORK_DIR is setMatthias Lederhofer, Mar 12, 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.