Skip to content

Commit 3e07d26

Browse files
committed
Merge branch 'mh/maint-ceil-absolute'
An earlier workaround designed to help people who list logical directories that will not match what getcwd(3) returns in the GIT_CEILING_DIRECTORIES had an adverse effect when it is slow to stat and readlink a directory component of an element listed on it. * mh/maint-ceil-absolute: Provide a mechanism to turn off symlink resolution in ceiling paths
2 parents 27db5a0 + 7ec30aa commit 3e07d26

File tree

3 files changed

+52
-16
lines changed

3 files changed

+52
-16
lines changed

Documentation/git.txt

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -678,12 +678,19 @@ Git so take care if using Cogito etc.
678678
The '--namespace' command-line option also sets this value.
679679

680680
'GIT_CEILING_DIRECTORIES'::
681-
This should be a colon-separated list of absolute paths.
682-
If set, it is a list of directories that Git should not chdir
683-
up into while looking for a repository directory.
684-
It will not exclude the current working directory or
685-
a GIT_DIR set on the command line or in the environment.
686-
(Useful for excluding slow-loading network directories.)
681+
This should be a colon-separated list of absolute paths. If
682+
set, it is a list of directories that Git should not chdir up
683+
into while looking for a repository directory (useful for
684+
excluding slow-loading network directories). It will not
685+
exclude the current working directory or a GIT_DIR set on the
686+
command line or in the environment. Normally, Git has to read
687+
the entries in this list and resolve any symlink that
688+
might be present in order to compare them with the current
689+
directory. However, if even this access is slow, you
690+
can add an empty entry to the list to tell Git that the
691+
subsequent entries are not symlinks and needn't be resolved;
692+
e.g.,
693+
'GIT_CEILING_DIRECTORIES=/maybe/symlink::/very/slow/non/symlink'.
687694

688695
'GIT_DISCOVERY_ACROSS_FILESYSTEM'::
689696
When run in a directory that does not have ".git" repository

setup.c

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -650,22 +650,32 @@ static dev_t get_device_or_die(const char *path, const char *prefix, int prefix_
650650
/*
651651
* A "string_list_each_func_t" function that canonicalizes an entry
652652
* from GIT_CEILING_DIRECTORIES using real_path_if_valid(), or
653-
* discards it if unusable.
653+
* discards it if unusable. The presence of an empty entry in
654+
* GIT_CEILING_DIRECTORIES turns off canonicalization for all
655+
* subsequent entries.
654656
*/
655657
static int canonicalize_ceiling_entry(struct string_list_item *item,
656-
void *unused)
658+
void *cb_data)
657659
{
660+
int *empty_entry_found = cb_data;
658661
char *ceil = item->string;
659-
const char *real_path;
660662

661-
if (!*ceil || !is_absolute_path(ceil))
663+
if (!*ceil) {
664+
*empty_entry_found = 1;
662665
return 0;
663-
real_path = real_path_if_valid(ceil);
664-
if (!real_path)
666+
} else if (!is_absolute_path(ceil)) {
665667
return 0;
666-
free(item->string);
667-
item->string = xstrdup(real_path);
668-
return 1;
668+
} else if (*empty_entry_found) {
669+
/* Keep entry but do not canonicalize it */
670+
return 1;
671+
} else {
672+
const char *real_path = real_path_if_valid(ceil);
673+
if (!real_path)
674+
return 0;
675+
free(item->string);
676+
item->string = xstrdup(real_path);
677+
return 1;
678+
}
669679
}
670680

671681
/*
@@ -705,9 +715,11 @@ static const char *setup_git_directory_gently_1(int *nongit_ok)
705715
return setup_explicit_git_dir(gitdirenv, cwd, len, nongit_ok);
706716

707717
if (env_ceiling_dirs) {
718+
int empty_entry_found = 0;
719+
708720
string_list_split(&ceiling_dirs, env_ceiling_dirs, PATH_SEP, -1);
709721
filter_string_list(&ceiling_dirs, 0,
710-
canonicalize_ceiling_entry, NULL);
722+
canonicalize_ceiling_entry, &empty_entry_found);
711723
ceil_offset = longest_ancestor_length(cwd, &ceiling_dirs);
712724
string_list_clear(&ceiling_dirs, 0);
713725
}

t/t1504-ceiling-dirs.sh

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ test_prefix ceil_at_sub ""
4444
GIT_CEILING_DIRECTORIES="$TRASH_ROOT/sub/"
4545
test_prefix ceil_at_sub_slash ""
4646

47+
if test_have_prereq SYMLINKS
48+
then
49+
ln -s sub top
50+
fi
4751

4852
mkdir -p sub/dir || exit 1
4953
cd sub/dir || exit 1
@@ -68,6 +72,19 @@ test_fail subdir_ceil_at_sub
6872
GIT_CEILING_DIRECTORIES="$TRASH_ROOT/sub/"
6973
test_fail subdir_ceil_at_sub_slash
7074

75+
if test_have_prereq SYMLINKS
76+
then
77+
GIT_CEILING_DIRECTORIES="$TRASH_ROOT/top"
78+
test_fail subdir_ceil_at_top
79+
GIT_CEILING_DIRECTORIES="$TRASH_ROOT/top/"
80+
test_fail subdir_ceil_at_top_slash
81+
82+
GIT_CEILING_DIRECTORIES=":$TRASH_ROOT/top"
83+
test_prefix subdir_ceil_at_top_no_resolve "sub/dir/"
84+
GIT_CEILING_DIRECTORIES=":$TRASH_ROOT/top/"
85+
test_prefix subdir_ceil_at_top_slash_no_resolve "sub/dir/"
86+
fi
87+
7188
GIT_CEILING_DIRECTORIES="$TRASH_ROOT/sub/dir"
7289
test_prefix subdir_ceil_at_subdir "sub/dir/"
7390

0 commit comments

Comments
 (0)