longest_prefix is just a textual check. It doesn't verify that the prefix is actually a full directory component of the cwd. For example... dreiss@dreiss-vmware:/tmp$ mkdir test dreiss@dreiss-vmware:/tmp$ cd test dreiss@dreiss-vmware:/tmp/test$ git init Initialized empty Git repository in .git/ dreiss@dreiss-vmware:master:test$ mkdir abcd dreiss@dreiss-vmware:master:test$ cd abcd dreiss@dreiss-vmware:master:test/abcd$ git rev-parse --show-prefix abcd/ dreiss@dreiss-vmware:master:test/abcd$ ~/git-ceil/git rev-parse --show-prefix abcd/ dreiss@dreiss-vmware:master:test/abcd$ GIT_CEILING_DIRECTORIES=/tmp/test/ab ~/git-ceil/git rev-parse --show-prefix fatal: Not a git repository dreiss@dreiss-vmware:master:test/abcd:128$ "/tmp/test/ab" is a textual prefix of the cwd, but it should not prevent "/tmp/test/.git" from being discovered. For what it's worth, my test cases check this behavior. Ironically, I think this could be fixed by requiring the ceiling directories to have trailing slashes. Also, I think it is better to move the 'chdir("..")' after the do loop, so that git won't even chdir up into the ceiling directory. This actually doesn't matter to me, but I figured that it might be nice for someone. Finally, just a small thing. The documentation still says "GIT_CEILING_DIRS". --David Johannes Schindelin wrote: > > In certain setups, trying to access a non-existing .git/ can take quite > some time, for example when the directory is an automount directory. > > Allow the user to specify directories where Git should stop looking for > a .git/ directory: GIT_CEILING_DIRECTORIES, if set, is expected to be > a colon delimited list of such barrier directories. > > Note: if GIT_CEILING_DIRECTORIES=/a/b and your current working directory > is /a, Git will _not_ stop looking. > > Note2: you must not specify the directories with trailing slashes. > > Initial implementation by David Reiss. > > Signed-off-by: Johannes Schindelin <johannes.schindelin@xxxxxx> > --- > > Show me the bugs! > > I just checked: the "/" issue you were referring to is most likely > the fact that "git rev-parse --git-dir" would return "//.git" > instead of "/.git" (if that is the appropriate GIT_DIR). > > This is the original behavior (without this patch), and IMO a > separate issue, which might not even need fixing. > > Documentation/git.txt | 6 +++++ > cache.h | 2 + > path.c | 19 ++++++++++++++++ > setup.c | 11 +++++++- > t/t1504-ceiling-directories.sh | 46 > ++++++++++++++++++++++++++++++++++++++++ > t/test-lib.sh | 1 + > 6 files changed, 83 insertions(+), 2 deletions(-) > create mode 100644 t/t1504-ceiling-directories.sh > > diff --git a/Documentation/git.txt b/Documentation/git.txt > index adcd3e0..a12d1f8 100644 > --- a/Documentation/git.txt > +++ b/Documentation/git.txt > @@ -415,6 +415,12 @@ git so take care if using Cogito etc. > This can also be controlled by the '--work-tree' command line > option and the core.worktree configuration variable. > > +'GIT_CEILING_DIRS':: > + If set (to a colon delimited list of absolute directories), Git > + will refuse to look for the .git/ directory further when hitting > + one of those directories (otherwise it would traverse the parent > + directories until hitting the root directory). > + > git Commits > ~~~~~~~~~~~ > 'GIT_AUTHOR_NAME':: > diff --git a/cache.h b/cache.h > index a8638b1..c31b4c7 100644 > --- a/cache.h > +++ b/cache.h > @@ -300,6 +300,7 @@ static inline enum object_type object_type(unsigned > int mode) > #define CONFIG_ENVIRONMENT "GIT_CONFIG" > #define CONFIG_LOCAL_ENVIRONMENT "GIT_CONFIG_LOCAL" > #define EXEC_PATH_ENVIRONMENT "GIT_EXEC_PATH" > +#define CEILING_DIRECTORIES_ENVIRONMENT "GIT_CEILING_DIRECTORIES" > #define GITATTRIBUTES_FILE ".gitattributes" > #define INFOATTRIBUTES_FILE "info/attributes" > #define ATTRIBUTE_MACRO_PREFIX "[attr]" > @@ -522,6 +523,7 @@ static inline int is_absolute_path(const char *path) > return path[0] == '/'; > } > const char *make_absolute_path(const char *path); > +int longest_prefix(const char *path, const char *prefix_list); > > /* Read and unpack a sha1 file into memory, write memory to a sha1 file */ > extern int sha1_object_info(const unsigned char *, unsigned long *); > diff --git a/path.c b/path.c > index b7c24a2..c0d7364 100644 > --- a/path.c > +++ b/path.c > @@ -357,3 +357,22 @@ const char *make_absolute_path(const char *path) > > return buf; > } > + > +int longest_prefix(const char *path, const char *prefix_list) > +{ > + int max_length = 0, length = 0, i; > + > + for (i = 0; prefix_list[i]; i++) > + if (prefix_list[i] == ':') { > + if (length > max_length) > + max_length = length; > + length = 0; > + } > + else if (length >= 0) { > + if (prefix_list[i] == path[length]) > + length++; > + else > + length = -1; > + } > + return max_length > length ? max_length : length; > +} > diff --git a/setup.c b/setup.c > index 9e9a2b1..cece3e4 100644 > --- a/setup.c > +++ b/setup.c > @@ -365,10 +365,13 @@ const char *read_gitfile_gently(const char *path) > const char *setup_git_directory_gently(int *nongit_ok) > { > const char *work_tree_env = getenv(GIT_WORK_TREE_ENVIRONMENT); > + const char *ceiling_directories = > + getenv(CEILING_DIRECTORIES_ENVIRONMENT); > static char cwd[PATH_MAX+1]; > const char *gitdirenv; > const char *gitfile_dir; > int len, offset; > + int min_offset = 0; > > /* > * Let's assume that we are in a git repository. > @@ -422,6 +425,9 @@ const char *setup_git_directory_gently(int *nongit_ok) > if (!getcwd(cwd, sizeof(cwd)-1)) > die("Unable to read current working directory"); > > + if (ceiling_directories) > + min_offset = longest_prefix(cwd, ceiling_directories); > + > /* > * Test in the following order (relative to the cwd): > * - .git (file containing "gitdir: <path>") > @@ -453,7 +459,7 @@ const char *setup_git_directory_gently(int *nongit_ok) > } > chdir(".."); > do { > - if (!offset) { > + if (offset <= min_offset) { > if (nongit_ok) { > if (chdir(cwd)) > die("Cannot come back to > cwd"); > @@ -462,7 +468,8 @@ const char *setup_git_directory_gently(int *nongit_ok) > } > die("Not a git repository"); > } > - } while (cwd[--offset] != '/'); > + } while (offset > min_offset && > + --offset >=0 && cwd[offset] != '/'); > } > > inside_git_dir = 0; > diff --git a/t/t1504-ceiling-directories.sh b/t/t1504-ceiling-directories.sh > new file mode 100644 > index 0000000..1d8ef0b > --- /dev/null > +++ b/t/t1504-ceiling-directories.sh > @@ -0,0 +1,46 @@ > +#!/bin/sh > +# > +# Copyright (c) 2007 Johannes E. Schindelin > +# > + > +test_description='test limiting with GIT_CEILING_DIRECTORIES' > + > +. ./test-lib.sh > + > +test_expect_success 'setup' ' > + > + CWD="$(pwd -P)" && > + mkdir subdir > + > +' > + > +test_expect_success 'without GIT_CEILING_DIRECTORIES' ' > + > + test .git = "$(git rev-parse --git-dir)" && > + (cd subdir && git rev-parse --git-dir) && > + echo "$CWD" && > + test "$CWD/.git" = "$(cd subdir && git rev-parse --git-dir)" > + > +' > + > +test_expect_success 'with non-matching ceiling directory' ' > + > + test "$(GIT_CEILING_DIRECTORIES="$CWD/X" \ > + git rev-parse --git-dir)" = .git > + > +' > + > +test_expect_success 'with matching ceiling directories' ' > + > + GIT_CEILING_DIRECTORIES="$CWD/X:$CWD/subdir" && > + export GIT_CEILING_DIRECTORIES && > + (cd subdir && test_must_fail git rev-parse --git-dir) && > + git rev-parse --git-dir && > + GIT_CEILING_DIRECTORIES="$CWD/subdir:$CWD/X" && > + export GIT_CEILING_DIRECTORIES && > + (cd subdir && test_must_fail git rev-parse --git-dir) && > + git rev-parse --git-dir > + > +' > + > +test_done > diff --git a/t/test-lib.sh b/t/test-lib.sh > index 5002fb0..c3a3167 100644 > --- a/t/test-lib.sh > +++ b/t/test-lib.sh > @@ -35,6 +35,7 @@ unset GIT_WORK_TREE > unset GIT_EXTERNAL_DIFF > unset GIT_INDEX_FILE > unset GIT_OBJECT_DIRECTORY > +unset GIT_CEILING_DIRECTORIES > unset SHA1_FILE_DIRECTORIES > unset SHA1_FILE_DIRECTORY > GIT_MERGE_VERBOSITY=5 > -- > 1.5.5.1.425.g5f464 > -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html