зеркало из https://github.com/microsoft/git.git
Merge branch 'en/fill-directory-fixes'
Assorted fixes to the directory traversal API. * en/fill-directory-fixes: dir.c: use st_add3() for allocation size dir: consolidate similar code in treat_directory() dir: synchronize treat_leading_path() and read_directory_recursive() dir: fix checks on common prefix directory dir: break part of read_directory_recursive() out for reuse dir: exit before wildcard fall-through if there is no wildcard dir: remove stray quote character in comment Revert "dir.c: make 'git-status --ignored' work within leading directories" t3011: demonstrate directory traversal failures
This commit is contained in:
Коммит
d2189a721c
189
dir.c
189
dir.c
|
@ -371,12 +371,19 @@ static int match_pathspec_item(const struct index_state *istate,
|
||||||
!ps_strncmp(item, match, name, namelen))
|
!ps_strncmp(item, match, name, namelen))
|
||||||
return MATCHED_RECURSIVELY_LEADING_PATHSPEC;
|
return MATCHED_RECURSIVELY_LEADING_PATHSPEC;
|
||||||
|
|
||||||
/* name" doesn't match up to the first wild character */
|
/* name doesn't match up to the first wild character */
|
||||||
if (item->nowildcard_len < item->len &&
|
if (item->nowildcard_len < item->len &&
|
||||||
ps_strncmp(item, match, name,
|
ps_strncmp(item, match, name,
|
||||||
item->nowildcard_len - prefix))
|
item->nowildcard_len - prefix))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* name has no wildcard, and it didn't match as a leading
|
||||||
|
* pathspec so return.
|
||||||
|
*/
|
||||||
|
if (item->nowildcard_len == item->len)
|
||||||
|
return 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Here is where we would perform a wildmatch to check if
|
* Here is where we would perform a wildmatch to check if
|
||||||
* "name" can be matched as a directory (or a prefix) against
|
* "name" can be matched as a directory (or a prefix) against
|
||||||
|
@ -1652,6 +1659,8 @@ static enum path_treatment treat_directory(struct dir_struct *dir,
|
||||||
const char *dirname, int len, int baselen, int exclude,
|
const char *dirname, int len, int baselen, int exclude,
|
||||||
const struct pathspec *pathspec)
|
const struct pathspec *pathspec)
|
||||||
{
|
{
|
||||||
|
int nested_repo = 0;
|
||||||
|
|
||||||
/* The "len-1" is to strip the final '/' */
|
/* The "len-1" is to strip the final '/' */
|
||||||
switch (directory_exists_in_index(istate, dirname, len-1)) {
|
switch (directory_exists_in_index(istate, dirname, len-1)) {
|
||||||
case index_directory:
|
case index_directory:
|
||||||
|
@ -1661,15 +1670,16 @@ static enum path_treatment treat_directory(struct dir_struct *dir,
|
||||||
return path_none;
|
return path_none;
|
||||||
|
|
||||||
case index_nonexistent:
|
case index_nonexistent:
|
||||||
if (dir->flags & DIR_SKIP_NESTED_GIT) {
|
if ((dir->flags & DIR_SKIP_NESTED_GIT) ||
|
||||||
int nested_repo;
|
!(dir->flags & DIR_NO_GITLINKS)) {
|
||||||
struct strbuf sb = STRBUF_INIT;
|
struct strbuf sb = STRBUF_INIT;
|
||||||
strbuf_addstr(&sb, dirname);
|
strbuf_addstr(&sb, dirname);
|
||||||
nested_repo = is_nonbare_repository_dir(&sb);
|
nested_repo = is_nonbare_repository_dir(&sb);
|
||||||
strbuf_release(&sb);
|
strbuf_release(&sb);
|
||||||
if (nested_repo)
|
|
||||||
return path_none;
|
|
||||||
}
|
}
|
||||||
|
if (nested_repo)
|
||||||
|
return ((dir->flags & DIR_SKIP_NESTED_GIT) ? path_none :
|
||||||
|
(exclude ? path_excluded : path_untracked));
|
||||||
|
|
||||||
if (dir->flags & DIR_SHOW_OTHER_DIRECTORIES)
|
if (dir->flags & DIR_SHOW_OTHER_DIRECTORIES)
|
||||||
break;
|
break;
|
||||||
|
@ -1697,13 +1707,6 @@ static enum path_treatment treat_directory(struct dir_struct *dir,
|
||||||
|
|
||||||
return path_none;
|
return path_none;
|
||||||
}
|
}
|
||||||
if (!(dir->flags & DIR_NO_GITLINKS)) {
|
|
||||||
struct strbuf sb = STRBUF_INIT;
|
|
||||||
strbuf_addstr(&sb, dirname);
|
|
||||||
if (is_nonbare_repository_dir(&sb))
|
|
||||||
return exclude ? path_excluded : path_untracked;
|
|
||||||
strbuf_release(&sb);
|
|
||||||
}
|
|
||||||
return path_recurse;
|
return path_recurse;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2123,6 +2126,40 @@ static void close_cached_dir(struct cached_dir *cdir)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void add_path_to_appropriate_result_list(struct dir_struct *dir,
|
||||||
|
struct untracked_cache_dir *untracked,
|
||||||
|
struct cached_dir *cdir,
|
||||||
|
struct index_state *istate,
|
||||||
|
struct strbuf *path,
|
||||||
|
int baselen,
|
||||||
|
const struct pathspec *pathspec,
|
||||||
|
enum path_treatment state)
|
||||||
|
{
|
||||||
|
/* add the path to the appropriate result list */
|
||||||
|
switch (state) {
|
||||||
|
case path_excluded:
|
||||||
|
if (dir->flags & DIR_SHOW_IGNORED)
|
||||||
|
dir_add_name(dir, istate, path->buf, path->len);
|
||||||
|
else if ((dir->flags & DIR_SHOW_IGNORED_TOO) ||
|
||||||
|
((dir->flags & DIR_COLLECT_IGNORED) &&
|
||||||
|
exclude_matches_pathspec(path->buf, path->len,
|
||||||
|
pathspec)))
|
||||||
|
dir_add_ignored(dir, istate, path->buf, path->len);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case path_untracked:
|
||||||
|
if (dir->flags & DIR_SHOW_IGNORED)
|
||||||
|
break;
|
||||||
|
dir_add_name(dir, istate, path->buf, path->len);
|
||||||
|
if (cdir->fdir)
|
||||||
|
add_untracked(untracked, path->buf + baselen);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Read a directory tree. We currently ignore anything but
|
* Read a directory tree. We currently ignore anything but
|
||||||
* directories, regular files and symlinks. That's because git
|
* directories, regular files and symlinks. That's because git
|
||||||
|
@ -2147,6 +2184,15 @@ static enum path_treatment read_directory_recursive(struct dir_struct *dir,
|
||||||
struct untracked_cache_dir *untracked, int check_only,
|
struct untracked_cache_dir *untracked, int check_only,
|
||||||
int stop_at_first_file, const struct pathspec *pathspec)
|
int stop_at_first_file, const struct pathspec *pathspec)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
* WARNING WARNING WARNING:
|
||||||
|
*
|
||||||
|
* Any updates to the traversal logic here may need corresponding
|
||||||
|
* updates in treat_leading_path(). See the commit message for the
|
||||||
|
* commit adding this warning as well as the commit preceding it
|
||||||
|
* for details.
|
||||||
|
*/
|
||||||
|
|
||||||
struct cached_dir cdir;
|
struct cached_dir cdir;
|
||||||
enum path_treatment state, subdir_state, dir_state = path_none;
|
enum path_treatment state, subdir_state, dir_state = path_none;
|
||||||
struct strbuf path = STRBUF_INIT;
|
struct strbuf path = STRBUF_INIT;
|
||||||
|
@ -2226,29 +2272,9 @@ static enum path_treatment read_directory_recursive(struct dir_struct *dir,
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* add the path to the appropriate result list */
|
add_path_to_appropriate_result_list(dir, untracked, &cdir,
|
||||||
switch (state) {
|
istate, &path, baselen,
|
||||||
case path_excluded:
|
pathspec, state);
|
||||||
if (dir->flags & DIR_SHOW_IGNORED)
|
|
||||||
dir_add_name(dir, istate, path.buf, path.len);
|
|
||||||
else if ((dir->flags & DIR_SHOW_IGNORED_TOO) ||
|
|
||||||
((dir->flags & DIR_COLLECT_IGNORED) &&
|
|
||||||
exclude_matches_pathspec(path.buf, path.len,
|
|
||||||
pathspec)))
|
|
||||||
dir_add_ignored(dir, istate, path.buf, path.len);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case path_untracked:
|
|
||||||
if (dir->flags & DIR_SHOW_IGNORED)
|
|
||||||
break;
|
|
||||||
dir_add_name(dir, istate, path.buf, path.len);
|
|
||||||
if (cdir.fdir)
|
|
||||||
add_untracked(untracked, path.buf + baselen);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
close_cached_dir(&cdir);
|
close_cached_dir(&cdir);
|
||||||
out:
|
out:
|
||||||
|
@ -2278,41 +2304,104 @@ static int treat_leading_path(struct dir_struct *dir,
|
||||||
const char *path, int len,
|
const char *path, int len,
|
||||||
const struct pathspec *pathspec)
|
const struct pathspec *pathspec)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
* WARNING WARNING WARNING:
|
||||||
|
*
|
||||||
|
* Any updates to the traversal logic here may need corresponding
|
||||||
|
* updates in treat_leading_path(). See the commit message for the
|
||||||
|
* commit adding this warning as well as the commit preceding it
|
||||||
|
* for details.
|
||||||
|
*/
|
||||||
|
|
||||||
struct strbuf sb = STRBUF_INIT;
|
struct strbuf sb = STRBUF_INIT;
|
||||||
int baselen, rc = 0;
|
int prevlen, baselen;
|
||||||
const char *cp;
|
const char *cp;
|
||||||
int old_flags = dir->flags;
|
struct cached_dir cdir;
|
||||||
|
struct dirent *de;
|
||||||
|
enum path_treatment state = path_none;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For each directory component of path, we are going to check whether
|
||||||
|
* that path is relevant given the pathspec. For example, if path is
|
||||||
|
* foo/bar/baz/
|
||||||
|
* then we will ask treat_path() whether we should go into foo, then
|
||||||
|
* whether we should go into bar, then whether baz is relevant.
|
||||||
|
* Checking each is important because e.g. if path is
|
||||||
|
* .git/info/
|
||||||
|
* then we need to check .git to know we shouldn't traverse it.
|
||||||
|
* If the return from treat_path() is:
|
||||||
|
* * path_none, for any path, we return false.
|
||||||
|
* * path_recurse, for all path components, we return true
|
||||||
|
* * <anything else> for some intermediate component, we make sure
|
||||||
|
* to add that path to the relevant list but return false
|
||||||
|
* signifying that we shouldn't recurse into it.
|
||||||
|
*/
|
||||||
|
|
||||||
while (len && path[len - 1] == '/')
|
while (len && path[len - 1] == '/')
|
||||||
len--;
|
len--;
|
||||||
if (!len)
|
if (!len)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We need a manufactured dirent with sufficient space to store a
|
||||||
|
* leading directory component of path in its d_name. Here, we
|
||||||
|
* assume that the dirent's d_name is either declared as
|
||||||
|
* char d_name[BIG_ENOUGH]
|
||||||
|
* or that it is declared at the end of the struct as
|
||||||
|
* char d_name[]
|
||||||
|
* For either case, padding with len+1 bytes at the end will ensure
|
||||||
|
* sufficient storage space.
|
||||||
|
*/
|
||||||
|
de = xcalloc(1, st_add3(sizeof(struct dirent), len, 1));
|
||||||
|
memset(&cdir, 0, sizeof(cdir));
|
||||||
|
cdir.de = de;
|
||||||
|
#if defined(DT_UNKNOWN) && !defined(NO_D_TYPE_IN_DIRENT)
|
||||||
|
de->d_type = DT_DIR;
|
||||||
|
#endif
|
||||||
baselen = 0;
|
baselen = 0;
|
||||||
dir->flags &= ~DIR_SHOW_OTHER_DIRECTORIES;
|
prevlen = 0;
|
||||||
while (1) {
|
while (1) {
|
||||||
cp = path + baselen + !!baselen;
|
prevlen = baselen + !!baselen;
|
||||||
|
cp = path + prevlen;
|
||||||
cp = memchr(cp, '/', path + len - cp);
|
cp = memchr(cp, '/', path + len - cp);
|
||||||
if (!cp)
|
if (!cp)
|
||||||
baselen = len;
|
baselen = len;
|
||||||
else
|
else
|
||||||
baselen = cp - path;
|
baselen = cp - path;
|
||||||
strbuf_setlen(&sb, 0);
|
strbuf_reset(&sb);
|
||||||
strbuf_add(&sb, path, baselen);
|
strbuf_add(&sb, path, baselen);
|
||||||
if (!is_directory(sb.buf))
|
if (!is_directory(sb.buf))
|
||||||
break;
|
break;
|
||||||
if (simplify_away(sb.buf, sb.len, pathspec))
|
strbuf_reset(&sb);
|
||||||
break;
|
strbuf_add(&sb, path, prevlen);
|
||||||
if (treat_one_path(dir, NULL, istate, &sb, baselen, pathspec,
|
memcpy(de->d_name, path+prevlen, baselen-prevlen);
|
||||||
DT_DIR, NULL) == path_none)
|
de->d_name[baselen-prevlen] = '\0';
|
||||||
break; /* do not recurse into it */
|
state = treat_path(dir, NULL, &cdir, istate, &sb, prevlen,
|
||||||
if (len <= baselen) {
|
pathspec);
|
||||||
rc = 1;
|
if (state == path_untracked &&
|
||||||
break; /* finished checking */
|
get_dtype(cdir.de, istate, sb.buf, sb.len) == DT_DIR &&
|
||||||
|
(dir->flags & DIR_SHOW_IGNORED_TOO ||
|
||||||
|
do_match_pathspec(istate, pathspec, sb.buf, sb.len,
|
||||||
|
baselen, NULL, DO_MATCH_LEADING_PATHSPEC) == MATCHED_RECURSIVELY_LEADING_PATHSPEC)) {
|
||||||
|
add_path_to_appropriate_result_list(dir, NULL, &cdir,
|
||||||
|
istate,
|
||||||
|
&sb, baselen,
|
||||||
|
pathspec, state);
|
||||||
|
state = path_recurse;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (state != path_recurse)
|
||||||
|
break; /* do not recurse into it */
|
||||||
|
if (len <= baselen)
|
||||||
|
break; /* finished checking */
|
||||||
}
|
}
|
||||||
|
add_path_to_appropriate_result_list(dir, NULL, &cdir, istate,
|
||||||
|
&sb, baselen, pathspec,
|
||||||
|
state);
|
||||||
|
|
||||||
|
free(de);
|
||||||
strbuf_release(&sb);
|
strbuf_release(&sb);
|
||||||
dir->flags = old_flags;
|
return state == path_recurse;
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *get_ident_string(void)
|
static const char *get_ident_string(void)
|
||||||
|
|
|
@ -0,0 +1,209 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
test_description='directory traversal handling, especially with common prefixes'
|
||||||
|
|
||||||
|
. ./test-lib.sh
|
||||||
|
|
||||||
|
test_expect_success 'setup' '
|
||||||
|
test_commit hello &&
|
||||||
|
|
||||||
|
>empty &&
|
||||||
|
mkdir untracked_dir &&
|
||||||
|
>untracked_dir/empty &&
|
||||||
|
git init untracked_repo &&
|
||||||
|
>untracked_repo/empty &&
|
||||||
|
|
||||||
|
cat <<-EOF >.gitignore &&
|
||||||
|
ignored
|
||||||
|
an_ignored_dir/
|
||||||
|
EOF
|
||||||
|
mkdir an_ignored_dir &&
|
||||||
|
mkdir an_untracked_dir &&
|
||||||
|
>an_ignored_dir/ignored &&
|
||||||
|
>an_ignored_dir/untracked &&
|
||||||
|
>an_untracked_dir/ignored &&
|
||||||
|
>an_untracked_dir/untracked
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'git ls-files -o shows the right entries' '
|
||||||
|
cat <<-EOF >expect &&
|
||||||
|
.gitignore
|
||||||
|
actual
|
||||||
|
an_ignored_dir/ignored
|
||||||
|
an_ignored_dir/untracked
|
||||||
|
an_untracked_dir/ignored
|
||||||
|
an_untracked_dir/untracked
|
||||||
|
empty
|
||||||
|
expect
|
||||||
|
untracked_dir/empty
|
||||||
|
untracked_repo/
|
||||||
|
EOF
|
||||||
|
git ls-files -o >actual &&
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'git ls-files -o --exclude-standard shows the right entries' '
|
||||||
|
cat <<-EOF >expect &&
|
||||||
|
.gitignore
|
||||||
|
actual
|
||||||
|
an_untracked_dir/untracked
|
||||||
|
empty
|
||||||
|
expect
|
||||||
|
untracked_dir/empty
|
||||||
|
untracked_repo/
|
||||||
|
EOF
|
||||||
|
git ls-files -o --exclude-standard >actual &&
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'git ls-files -o untracked_dir recurses' '
|
||||||
|
echo untracked_dir/empty >expect &&
|
||||||
|
git ls-files -o untracked_dir >actual &&
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'git ls-files -o untracked_dir/ recurses' '
|
||||||
|
echo untracked_dir/empty >expect &&
|
||||||
|
git ls-files -o untracked_dir/ >actual &&
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'git ls-files -o --directory untracked_dir does not recurse' '
|
||||||
|
echo untracked_dir/ >expect &&
|
||||||
|
git ls-files -o --directory untracked_dir >actual &&
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'git ls-files -o --directory untracked_dir/ does not recurse' '
|
||||||
|
echo untracked_dir/ >expect &&
|
||||||
|
git ls-files -o --directory untracked_dir/ >actual &&
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'git ls-files -o untracked_repo does not recurse' '
|
||||||
|
echo untracked_repo/ >expect &&
|
||||||
|
git ls-files -o untracked_repo >actual &&
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'git ls-files -o untracked_repo/ does not recurse' '
|
||||||
|
echo untracked_repo/ >expect &&
|
||||||
|
git ls-files -o untracked_repo/ >actual &&
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'git ls-files -o untracked_dir untracked_repo recurses into untracked_dir only' '
|
||||||
|
cat <<-EOF >expect &&
|
||||||
|
untracked_dir/empty
|
||||||
|
untracked_repo/
|
||||||
|
EOF
|
||||||
|
git ls-files -o untracked_dir untracked_repo >actual &&
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'git ls-files -o untracked_dir/ untracked_repo/ recurses into untracked_dir only' '
|
||||||
|
cat <<-EOF >expect &&
|
||||||
|
untracked_dir/empty
|
||||||
|
untracked_repo/
|
||||||
|
EOF
|
||||||
|
git ls-files -o untracked_dir/ untracked_repo/ >actual &&
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'git ls-files -o --directory untracked_dir untracked_repo does not recurse' '
|
||||||
|
cat <<-EOF >expect &&
|
||||||
|
untracked_dir/
|
||||||
|
untracked_repo/
|
||||||
|
EOF
|
||||||
|
git ls-files -o --directory untracked_dir untracked_repo >actual &&
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'git ls-files -o --directory untracked_dir/ untracked_repo/ does not recurse' '
|
||||||
|
cat <<-EOF >expect &&
|
||||||
|
untracked_dir/
|
||||||
|
untracked_repo/
|
||||||
|
EOF
|
||||||
|
git ls-files -o --directory untracked_dir/ untracked_repo/ >actual &&
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'git ls-files -o .git shows nothing' '
|
||||||
|
git ls-files -o .git >actual &&
|
||||||
|
test_must_be_empty actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'git ls-files -o .git/ shows nothing' '
|
||||||
|
git ls-files -o .git/ >actual &&
|
||||||
|
test_must_be_empty actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success FUNNYNAMES 'git ls-files -o untracked_* recurses appropriately' '
|
||||||
|
mkdir "untracked_*" &&
|
||||||
|
>"untracked_*/empty" &&
|
||||||
|
|
||||||
|
cat <<-EOF >expect &&
|
||||||
|
untracked_*/empty
|
||||||
|
untracked_dir/empty
|
||||||
|
untracked_repo/
|
||||||
|
EOF
|
||||||
|
git ls-files -o "untracked_*" >actual &&
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
|
# It turns out fill_directory returns the right paths, but ls-files' post-call
|
||||||
|
# filtering in show_dir_entry() via calling dir_path_match() which ends up
|
||||||
|
# in git_fnmatch() has logic for PATHSPEC_ONESTAR that assumes the pathspec
|
||||||
|
# must match the full path; it doesn't check it for matching a leading
|
||||||
|
# directory.
|
||||||
|
test_expect_failure FUNNYNAMES 'git ls-files -o untracked_*/ recurses appropriately' '
|
||||||
|
cat <<-EOF >expect &&
|
||||||
|
untracked_*/empty
|
||||||
|
untracked_dir/empty
|
||||||
|
untracked_repo/
|
||||||
|
EOF
|
||||||
|
git ls-files -o "untracked_*/" >actual &&
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success FUNNYNAMES 'git ls-files -o --directory untracked_* does not recurse' '
|
||||||
|
cat <<-EOF >expect &&
|
||||||
|
untracked_*/
|
||||||
|
untracked_dir/
|
||||||
|
untracked_repo/
|
||||||
|
EOF
|
||||||
|
git ls-files -o --directory "untracked_*" >actual &&
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success FUNNYNAMES 'git ls-files -o --directory untracked_*/ does not recurse' '
|
||||||
|
cat <<-EOF >expect &&
|
||||||
|
untracked_*/
|
||||||
|
untracked_dir/
|
||||||
|
untracked_repo/
|
||||||
|
EOF
|
||||||
|
git ls-files -o --directory "untracked_*/" >actual &&
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'git ls-files -o consistent between one or two dirs' '
|
||||||
|
git ls-files -o --exclude-standard an_ignored_dir/ an_untracked_dir/ >tmp &&
|
||||||
|
! grep ^an_ignored_dir/ tmp >expect &&
|
||||||
|
git ls-files -o --exclude-standard an_ignored_dir/ >actual &&
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
|
# ls-files doesn't have a way to request showing both untracked and ignored
|
||||||
|
# files at the same time, so use `git status --ignored`
|
||||||
|
test_expect_success 'git status --ignored shows same files under dir with or without pathspec' '
|
||||||
|
cat <<-EOF >expect &&
|
||||||
|
?? an_untracked_dir/
|
||||||
|
!! an_untracked_dir/ignored
|
||||||
|
EOF
|
||||||
|
git status --porcelain --ignored >output &&
|
||||||
|
grep an_untracked_dir output >expect &&
|
||||||
|
git status --porcelain --ignored an_untracked_dir/ >actual &&
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_done
|
|
@ -43,11 +43,16 @@ test_expect_success 'status untracked directory with --ignored -u' '
|
||||||
test_cmp expected actual
|
test_cmp expected actual
|
||||||
'
|
'
|
||||||
cat >expected <<\EOF
|
cat >expected <<\EOF
|
||||||
?? untracked/uncommitted
|
?? untracked/
|
||||||
!! untracked/ignored
|
!! untracked/ignored
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
test_expect_success 'status prefixed untracked directory with --ignored' '
|
test_expect_success 'status of untracked directory with --ignored works with or without prefix' '
|
||||||
|
git status --porcelain --ignored >tmp &&
|
||||||
|
grep untracked/ tmp >actual &&
|
||||||
|
rm tmp &&
|
||||||
|
test_cmp expected actual &&
|
||||||
|
|
||||||
git status --porcelain --ignored untracked/ >actual &&
|
git status --porcelain --ignored untracked/ >actual &&
|
||||||
test_cmp expected actual
|
test_cmp expected actual
|
||||||
'
|
'
|
||||||
|
|
Загрузка…
Ссылка в новой задаче