[2nd SQUASHED PATCH] Add support for GIT_CEILING_DIRECTORIES | |
| [Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] | |
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 would 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>
---
Documentation/git.txt | 6 ++++
cache.h | 2 +
path.c | 25 ++++++++++++++++
setup.c | 14 +++++++-
t/t1504-ceiling-directories.sh | 63 ++++++++++++++++++++++++++++++++++++++++
t/test-lib.sh | 1 +
6 files changed, 109 insertions(+), 2 deletions(-)
create mode 100644 t/t1504-ceiling-directories.sh
diff --git a/Documentation/git.txt b/Documentation/git.txt
index adcd3e0..e4413bf 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_DIRECTORIES'::
+ 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..a097ecc 100644
--- a/path.c
+++ b/path.c
@@ -357,3 +357,28 @@ const char *make_absolute_path(const char *path)
return buf;
}
+
+static int is_separator(char c)
+{
+ return !c || c == '/';
+}
+
+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 && is_separator(path[length]))
+ max_length = length;
+ length = 0;
+ }
+ else if (length >= 0) {
+ if (prefix_list[i] == path[length])
+ length++;
+ else
+ length = -1;
+ }
+ return max_length > length || !is_separator(path[length]) ?
+ max_length : length;
+}
diff --git a/setup.c b/setup.c
index 9e9a2b1..2f7a17a 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>")
@@ -435,6 +441,8 @@ const char *setup_git_directory_gently(int *nongit_ok)
*/
offset = len = strlen(cwd);
for (;;) {
+ if (offset <= min_offset)
+ goto non_git;
gitfile_dir = read_gitfile_gently(DEFAULT_GIT_DIR_ENVIRONMENT);
if (gitfile_dir) {
if (set_git_dir(gitfile_dir))
@@ -453,7 +461,8 @@ const char *setup_git_directory_gently(int *nongit_ok)
}
chdir("..");
do {
- if (!offset) {
+ if (offset <= min_offset) {
+non_git:
if (nongit_ok) {
if (chdir(cwd))
die("Cannot come back to cwd");
@@ -462,7 +471,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..edc00be
--- /dev/null
+++ b/t/t1504-ceiling-directories.sh
@@ -0,0 +1,63 @@
+#!/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 directory' '
+
+ GIT_CEILING_DIRECTORIES="$CWD" &&
+ export GIT_CEILING_DIRECTORIES &&
+ (cd subdir && test_must_fail git rev-parse --git-dir) &&
+ test_must_fail git rev-parse --git-dir
+
+'
+
+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_expect_success 'with non-directory prefix' '
+
+ GIT_CEILING_DIRECTORIES="$CWD/sub" &&
+ export GIT_CEILING_DIRECTORIES &&
+ (cd subdir && 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.490.g1644c11
--
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
[Newbies FAQ] [Kernel List] [Site Home] [Free Online Dating] [Gcc Help] [IETF Annouce] [DCCP] [Netdev] [Networking] [Security] [V4L] [Bugtraq] [Free Online Dating] [Rubini] [Photo] [Yosemite] [MIPS Linux] [ARM Linux] [Linux Security] [Linux RAID] [Linux SCSI] [DDR & Rambus] [Linux Resources]