From 0ef37164c2e453e8348fee05e50d3a4ed6d69f6b Mon Sep 17 00:00:00 2001 From: "Lars R. Damerow" Date: Wed, 17 Mar 2010 12:55:51 -0700 Subject: [PATCH 1/5] config.c: remove static keyword from git_env_bool() Since this function is the preferred way to handle boolean environment variables it's useful to have it available to other files. Signed-off-by: Lars R. Damerow Signed-off-by: Junio C Hamano --- cache.h | 1 + config.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/cache.h b/cache.h index 2928107bb1..535153e1b3 100644 --- a/cache.h +++ b/cache.h @@ -949,6 +949,7 @@ extern int git_config_set_multivar(const char *, const char *, const char *, int extern int git_config_rename_section(const char *, const char *); extern const char *git_etc_gitconfig(void); extern int check_repository_format_version(const char *var, const char *value, void *cb); +extern int git_env_bool(const char *, int); extern int git_config_system(void); extern int git_config_global(void); extern int config_error_nonbool(const char *); diff --git a/config.c b/config.c index 6963fbea43..70e460016e 100644 --- a/config.c +++ b/config.c @@ -683,7 +683,7 @@ const char *git_etc_gitconfig(void) return system_wide; } -static int git_env_bool(const char *k, int def) +int git_env_bool(const char *k, int def) { const char *v = getenv(k); return v ? git_config_bool(k, v) : def; From 502ffe3491bb6a3aff3f93e7eea19c01cf30c337 Mon Sep 17 00:00:00 2001 From: "Lars R. Damerow" Date: Wed, 17 Mar 2010 12:55:52 -0700 Subject: [PATCH 2/5] truncate cwd string before printing error message Without this truncation the error message printed only shows the cwd from the start of the search, not where it failed. Signed-off-by: Lars R. Damerow Signed-off-by: Junio C Hamano --- setup.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/setup.c b/setup.c index 5716d90b57..f0b56b9f54 100644 --- a/setup.c +++ b/setup.c @@ -422,8 +422,10 @@ const char *setup_git_directory_gently(int *nongit_ok) } die("Not a git repository (or any of the parent directories): %s", DEFAULT_GIT_DIR_ENVIRONMENT); } - if (chdir("..")) + if (chdir("..")) { + cwd[offset] = '\0'; die_errno("Cannot change to '%s/..'", cwd); + } } inside_git_dir = 0; From 8030e44215fe8f34edd57d711a35f2f0f97a0423 Mon Sep 17 00:00:00 2001 From: "Lars R. Damerow" Date: Wed, 17 Mar 2010 12:55:53 -0700 Subject: [PATCH 3/5] Add support for GIT_ONE_FILESYSTEM This patch makes git pay attention to the GIT_ONE_FILESYSTEM environment variable. When that variable is set, git will stop searching for a GIT_DIR when it attempts to cross a filesystem boundary. When working in an environment with too many automount points to make maintaining a GIT_CEILING_DIRECTORIES list enjoyable, GIT_ONE_FILESYSTEM gives the option of turning all such attempts off with one setting. Signed-off-by: Lars R. Damerow Signed-off-by: Junio C Hamano --- Documentation/git.txt | 6 ++++++ setup.c | 25 +++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/Documentation/git.txt b/Documentation/git.txt index 4e00b315ff..bf1b45eef1 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -530,6 +530,12 @@ git so take care if using Cogito etc. a GIT_DIR set on the command line or in the environment. (Useful for excluding slow-loading network directories.) +'GIT_ONE_FILESYSTEM':: + If set to a true value ("true" or a non-zero integer), stop at + filesystem boundaries when looking for a repository directory. + Like 'GIT_CEILING_DIRECTORIES', it will not affect an explicit + respository directory set via 'GIT_DIR' or on the command line. + git Commits ~~~~~~~~~~~ 'GIT_AUTHOR_NAME':: diff --git a/setup.c b/setup.c index f0b56b9f54..8b911b1a38 100644 --- a/setup.c +++ b/setup.c @@ -323,6 +323,8 @@ const char *setup_git_directory_gently(int *nongit_ok) const char *gitdirenv; const char *gitfile_dir; int len, offset, ceil_offset, root_len; + int current_device = 0, one_filesystem = 0; + struct stat buf; /* * Let's assume that we are in a git repository. @@ -390,6 +392,12 @@ const char *setup_git_directory_gently(int *nongit_ok) * etc. */ offset = len = strlen(cwd); + one_filesystem = git_env_bool("GIT_ONE_FILESYSTEM", 0); + if (one_filesystem) { + if (stat(".", &buf)) + die_errno("failed to stat '.'"); + current_device = buf.st_dev; + } for (;;) { gitfile_dir = read_gitfile_gently(DEFAULT_GIT_DIR_ENVIRONMENT); if (gitfile_dir) { @@ -422,6 +430,23 @@ const char *setup_git_directory_gently(int *nongit_ok) } die("Not a git repository (or any of the parent directories): %s", DEFAULT_GIT_DIR_ENVIRONMENT); } + if (one_filesystem) { + if (stat("..", &buf)) { + cwd[offset] = '\0'; + die_errno("failed to stat '%s/..'", cwd); + } + if (buf.st_dev != current_device) { + if (nongit_ok) { + if (chdir(cwd)) + die_errno("Cannot come back to cwd"); + *nongit_ok = 1; + return NULL; + } + cwd[offset] = '\0'; + die("Not a git repository (or any parent up to mount parent %s)\n" + "Stopping at filesystem boundary since GIT_ONE_FILESYSTEM is set.", cwd); + } + } if (chdir("..")) { cwd[offset] = '\0'; die_errno("Cannot change to '%s/..'", cwd); From e640551773c9730a47779dfc93155feb092c8e3c Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sun, 4 Apr 2010 10:33:53 -0700 Subject: [PATCH 4/5] GIT_ONE_FILESYSTEM: flip the default to stop at filesystem boundaries Regarding the new environment variable, Linus Torvalds writes on Tue, 30 Mar 2010 in : I suspect that it is _very_ unusual to have a source repo that crosses multiple filesystems, and the original reason for this patch-series seems to me to be likely to be more common than that multi-fs case. So having the logic go the other way would seem to match the common case, no? The "crossing filesystem boundary" condition is checked by comparing st_dev field in the result from stat(2). This is slightly worrysome if non-POSIX ports return different values in the field even for directories in the same work tree extracted to the same "filesystem". Erik Faye-Lund confirms that in the msysgit port st_dev is 0, so this should be safe, as "even Windows is safe" ;-) This will affect those who use /.git to cram /etc and /home/me in the same repostiory, /home is mounted from non-root filesystem, and a git operation is done from inside /home/me/src. But that is such a corner case we don't want to give preference over helping people who will benefit from having this default so that they do not have to suffer from slow automounters. Signed-off-by: Junio C Hamano --- Documentation/git.txt | 12 ++++++++---- setup.c | 4 ++-- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/Documentation/git.txt b/Documentation/git.txt index bf1b45eef1..aa62083209 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -531,10 +531,14 @@ git so take care if using Cogito etc. (Useful for excluding slow-loading network directories.) 'GIT_ONE_FILESYSTEM':: - If set to a true value ("true" or a non-zero integer), stop at - filesystem boundaries when looking for a repository directory. - Like 'GIT_CEILING_DIRECTORIES', it will not affect an explicit - respository directory set via 'GIT_DIR' or on the command line. + When run in a directory that does not have ".git" repository + directory, git tries to find such a directory in the parent + directories to find the top of the working tree, but by default it + does not cross filesystem boundaries. This environment variable + can be set to false value ("false" or zero) to tell git not to + stop at filesystem boundaries. Like 'GIT_CEILING_DIRECTORIES', + this will not affect an explicit respository directory set via + 'GIT_DIR' or on the command line. git Commits ~~~~~~~~~~~ diff --git a/setup.c b/setup.c index 8b911b1a38..d290633490 100644 --- a/setup.c +++ b/setup.c @@ -323,7 +323,7 @@ const char *setup_git_directory_gently(int *nongit_ok) const char *gitdirenv; const char *gitfile_dir; int len, offset, ceil_offset, root_len; - int current_device = 0, one_filesystem = 0; + int current_device = 0, one_filesystem = 1; struct stat buf; /* @@ -444,7 +444,7 @@ const char *setup_git_directory_gently(int *nongit_ok) } cwd[offset] = '\0'; die("Not a git repository (or any parent up to mount parent %s)\n" - "Stopping at filesystem boundary since GIT_ONE_FILESYSTEM is set.", cwd); + "Stopping at filesystem boundary since GIT_ONE_FILESYSTEM is true.", cwd); } } if (chdir("..")) { From cf87463e79a3018f666bfc9af113d3eea58a3d82 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sun, 4 Apr 2010 14:49:31 -0700 Subject: [PATCH 5/5] Rename ONE_FILESYSTEM to DISCOVERY_ACROSS_FILESYSTEM If a missing ONE_FILESYSTEM defaults to true, the only users who set this variable set it to false to tell git not to limit the discovery to one filesystem; there are too many negations in one sentence to make a simple panda brain dizzy. Use the variable GIT_DISCOVERY_ACROSS_FILESYSTEM that changes the behaviour from the default "limit to one filesystem" to "cross the boundary as I ask you to"; makes the semantics much more straight forward. Signed-off-by: Junio C Hamano --- Documentation/git.txt | 10 +++++----- setup.c | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Documentation/git.txt b/Documentation/git.txt index aa62083209..991aaec599 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -530,15 +530,15 @@ git so take care if using Cogito etc. a GIT_DIR set on the command line or in the environment. (Useful for excluding slow-loading network directories.) -'GIT_ONE_FILESYSTEM':: +'GIT_DISCOVERY_ACROSS_FILESYSTEM':: When run in a directory that does not have ".git" repository directory, git tries to find such a directory in the parent directories to find the top of the working tree, but by default it does not cross filesystem boundaries. This environment variable - can be set to false value ("false" or zero) to tell git not to - stop at filesystem boundaries. Like 'GIT_CEILING_DIRECTORIES', - this will not affect an explicit respository directory set via - 'GIT_DIR' or on the command line. + can be set to true to tell git not to stop at filesystem + boundaries. Like 'GIT_CEILING_DIRECTORIES', this will not affect + an explicit repository directory set via 'GIT_DIR' or on the + command line. git Commits ~~~~~~~~~~~ diff --git a/setup.c b/setup.c index d290633490..5a083fa77d 100644 --- a/setup.c +++ b/setup.c @@ -392,7 +392,7 @@ const char *setup_git_directory_gently(int *nongit_ok) * etc. */ offset = len = strlen(cwd); - one_filesystem = git_env_bool("GIT_ONE_FILESYSTEM", 0); + one_filesystem = !git_env_bool("GIT_DISCOVERY_ACROSS_FILESYSTEM", 0); if (one_filesystem) { if (stat(".", &buf)) die_errno("failed to stat '.'"); @@ -444,7 +444,7 @@ const char *setup_git_directory_gently(int *nongit_ok) } cwd[offset] = '\0'; die("Not a git repository (or any parent up to mount parent %s)\n" - "Stopping at filesystem boundary since GIT_ONE_FILESYSTEM is true.", cwd); + "Stopping at filesystem boundary (GIT_DISCOVERY_ACROSS_FILESYSTEM not set).", cwd); } } if (chdir("..")) {