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

Re: [PATCH] Add support for GIT_CEILING_DIRECTORIES

From
DRDavid Reiss <dreiss@facebook.com>
Date
May 15, 2008, 21:09 UTC
Message-ID
<482CA693.3060602@facebook.com>
In-Reply-To
<alpine.DEB.1.00.0805152055280.30431@racer>

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:
Show 217 quoted lines
> 
> 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@gmx.de>
> ---
> 
>         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
> 
Previous: Johannes SchindelinNext: Johannes Schindelin
Message 5 of 20 in “Add support for GIT_CEILING_DIRS”
  1. Add support for GIT_CEILING_DIRSDavid Reiss, May 15, 2008
  2. Johannes SchindelinMay 15, 2008
  3. David ReissMay 15, 2008
  4. Add support for GIT_CEILING_DIRECTORIESJohannes Schindelin, May 15, 2008
  5. David ReissMay 15, 2008
  6. Johannes SchindelinMay 15, 2008
  7. David ReissMay 15, 2008
  8. Add support for GIT_CEILING_DIRECTORIESJohannes Schindelin, May 15, 2008
  9. Johannes SixtMay 16, 2008
  10. Johannes SchindelinMay 16, 2008
  11. Johannes SixtMay 16, 2008
  12. David ReissMay 16, 2008
  13. Johannes SchindelinMay 17, 2008
  14. Add support for GIT_CEILING_DIRECTORIESJohannes Schindelin, May 17, 2008
  15. Johannes SixtMay 19, 2008
  16. Johannes SchindelinMay 19, 2008
  17. Junio C HamanoMay 15, 2008
  18. Johannes SchindelinMay 15, 2008
  19. Johannes SixtMay 16, 2008
  20. Johannes SchindelinMay 16, 2008

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.