зеркало из https://github.com/microsoft/git.git
Merge branch 'mv/parseopt-ls-files'
* mv/parseopt-ls-files: ls-files: fix broken --no-empty-directory t3000: use test_cmp instead of diff parse-opt: migrate builtin-ls-files. Turn the flags in struct dir_struct into a single variable Conflicts: builtin-ls-files.c t/t3000-ls-files-others.sh
This commit is contained in:
Коммит
de2e3b04cd
|
@ -104,7 +104,7 @@ static void fill_directory(struct dir_struct *dir, const char **pathspec,
|
|||
/* Set up the default git porcelain excludes */
|
||||
memset(dir, 0, sizeof(*dir));
|
||||
if (!ignored_too) {
|
||||
dir->collect_ignored = 1;
|
||||
dir->flags |= DIR_COLLECT_IGNORED;
|
||||
setup_standard_excludes(dir);
|
||||
}
|
||||
|
||||
|
|
|
@ -407,7 +407,7 @@ static int merge_working_tree(struct checkout_opts *opts,
|
|||
topts.verbose_update = !opts->quiet;
|
||||
topts.fn = twoway_merge;
|
||||
topts.dir = xcalloc(1, sizeof(*topts.dir));
|
||||
topts.dir->show_ignored = 1;
|
||||
topts.dir->flags |= DIR_SHOW_IGNORED;
|
||||
topts.dir->exclude_per_dir = ".gitignore";
|
||||
tree = parse_tree_indirect(old->commit->object.sha1);
|
||||
init_tree_desc(&trees[0], tree->buffer, tree->size);
|
||||
|
|
|
@ -60,7 +60,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
|
|||
|
||||
memset(&dir, 0, sizeof(dir));
|
||||
if (ignored_only)
|
||||
dir.show_ignored = 1;
|
||||
dir.flags |= DIR_SHOW_IGNORED;
|
||||
|
||||
if (ignored && ignored_only)
|
||||
die("-x and -X cannot be used together");
|
||||
|
@ -69,7 +69,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
|
|||
die("clean.requireForce%s set and -n or -f not given; "
|
||||
"refusing to clean", config_set ? "" : " not");
|
||||
|
||||
dir.show_other_directories = 1;
|
||||
dir.flags |= DIR_SHOW_OTHER_DIRECTORIES;
|
||||
|
||||
if (!ignored)
|
||||
setup_standard_excludes(&dir);
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "dir.h"
|
||||
#include "builtin.h"
|
||||
#include "tree.h"
|
||||
#include "parse-options.h"
|
||||
|
||||
static int abbrev;
|
||||
static int show_deleted;
|
||||
|
@ -28,6 +29,7 @@ static const char **pathspec;
|
|||
static int error_unmatch;
|
||||
static char *ps_matched;
|
||||
static const char *with_tree;
|
||||
static int exc_given;
|
||||
|
||||
static const char *tag_cached = "";
|
||||
static const char *tag_unmerged = "";
|
||||
|
@ -174,7 +176,8 @@ static void show_files(struct dir_struct *dir, const char *prefix)
|
|||
for (i = 0; i < active_nr; i++) {
|
||||
struct cache_entry *ce = active_cache[i];
|
||||
int dtype = ce_to_dtype(ce);
|
||||
if (excluded(dir, ce->name, &dtype) != dir->show_ignored)
|
||||
if (excluded(dir, ce->name, &dtype) !=
|
||||
!!(dir->flags & DIR_SHOW_IGNORED))
|
||||
continue;
|
||||
if (show_unmerged && !ce_stage(ce))
|
||||
continue;
|
||||
|
@ -189,7 +192,8 @@ static void show_files(struct dir_struct *dir, const char *prefix)
|
|||
struct stat st;
|
||||
int err;
|
||||
int dtype = ce_to_dtype(ce);
|
||||
if (excluded(dir, ce->name, &dtype) != dir->show_ignored)
|
||||
if (excluded(dir, ce->name, &dtype) !=
|
||||
!!(dir->flags & DIR_SHOW_IGNORED))
|
||||
continue;
|
||||
if (ce->ce_flags & CE_UPDATE)
|
||||
continue;
|
||||
|
@ -374,157 +378,139 @@ int report_path_error(const char *ps_matched, const char **pathspec, int prefix_
|
|||
return errors;
|
||||
}
|
||||
|
||||
static const char ls_files_usage[] =
|
||||
"git ls-files [-z] [-t] [-v] (--[cached|deleted|others|stage|unmerged|killed|modified])* "
|
||||
"[ --ignored ] [--exclude=<pattern>] [--exclude-from=<file>] "
|
||||
"[ --exclude-per-directory=<filename> ] [--exclude-standard] "
|
||||
"[--full-name] [--abbrev] [--] [<file>]*";
|
||||
static const char * const ls_files_usage[] = {
|
||||
"git ls-files [options] [<file>]*",
|
||||
NULL
|
||||
};
|
||||
|
||||
static int option_parse_z(const struct option *opt,
|
||||
const char *arg, int unset)
|
||||
{
|
||||
line_terminator = unset ? '\n' : '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int option_parse_exclude(const struct option *opt,
|
||||
const char *arg, int unset)
|
||||
{
|
||||
struct exclude_list *list = opt->value;
|
||||
|
||||
exc_given = 1;
|
||||
add_exclude(arg, "", 0, list);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int option_parse_exclude_from(const struct option *opt,
|
||||
const char *arg, int unset)
|
||||
{
|
||||
struct dir_struct *dir = opt->value;
|
||||
|
||||
exc_given = 1;
|
||||
add_excludes_from_file(dir, arg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int option_parse_exclude_standard(const struct option *opt,
|
||||
const char *arg, int unset)
|
||||
{
|
||||
struct dir_struct *dir = opt->value;
|
||||
|
||||
exc_given = 1;
|
||||
setup_standard_excludes(dir);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cmd_ls_files(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int i;
|
||||
int exc_given = 0, require_work_tree = 0;
|
||||
int require_work_tree = 0, show_tag = 0;
|
||||
struct dir_struct dir;
|
||||
struct option builtin_ls_files_options[] = {
|
||||
{ OPTION_CALLBACK, 'z', NULL, NULL, NULL,
|
||||
"paths are separated with NUL character",
|
||||
PARSE_OPT_NOARG, option_parse_z },
|
||||
OPT_BOOLEAN('t', NULL, &show_tag,
|
||||
"identify the file status with tags"),
|
||||
OPT_BOOLEAN('v', NULL, &show_valid_bit,
|
||||
"use lowercase letters for 'assume unchanged' files"),
|
||||
OPT_BOOLEAN('c', "cached", &show_cached,
|
||||
"show cached files in the output (default)"),
|
||||
OPT_BOOLEAN('d', "deleted", &show_deleted,
|
||||
"show deleted files in the output"),
|
||||
OPT_BOOLEAN('m', "modified", &show_modified,
|
||||
"show modified files in the output"),
|
||||
OPT_BOOLEAN('o', "others", &show_others,
|
||||
"show other files in the output"),
|
||||
OPT_BIT('i', "ignored", &dir.flags,
|
||||
"show ignored files in the output",
|
||||
DIR_SHOW_IGNORED),
|
||||
OPT_BOOLEAN('s', "stage", &show_stage,
|
||||
"show staged contents' object name in the output"),
|
||||
OPT_BOOLEAN('k', "killed", &show_killed,
|
||||
"show files on the filesystem that need to be removed"),
|
||||
OPT_BIT(0, "directory", &dir.flags,
|
||||
"show 'other' directories' name only",
|
||||
DIR_SHOW_OTHER_DIRECTORIES),
|
||||
OPT_BIT(0, "no-empty-directory", &dir.flags,
|
||||
"don't show empty directories",
|
||||
DIR_HIDE_EMPTY_DIRECTORIES),
|
||||
OPT_BOOLEAN('u', "unmerged", &show_unmerged,
|
||||
"show unmerged files in the output"),
|
||||
{ OPTION_CALLBACK, 'x', "exclude", &dir.exclude_list[EXC_CMDL], "pattern",
|
||||
"skip files matching pattern",
|
||||
0, option_parse_exclude },
|
||||
{ OPTION_CALLBACK, 'X', "exclude-from", &dir, "file",
|
||||
"exclude patterns are read from <file>",
|
||||
0, option_parse_exclude_from },
|
||||
OPT_STRING(0, "exclude-per-directory", &dir.exclude_per_dir, "file",
|
||||
"read additional per-directory exclude patterns in <file>"),
|
||||
{ OPTION_CALLBACK, 0, "exclude-standard", &dir, NULL,
|
||||
"add the standard git exclusions",
|
||||
PARSE_OPT_NOARG, option_parse_exclude_standard },
|
||||
{ OPTION_SET_INT, 0, "full-name", &prefix_offset, NULL,
|
||||
"make the output relative to the project top directory",
|
||||
PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL },
|
||||
OPT_BOOLEAN(0, "error-unmatch", &error_unmatch,
|
||||
"if any <file> is not in the index, treat this as an error"),
|
||||
OPT_STRING(0, "with-tree", &with_tree, "tree-ish",
|
||||
"pretend that paths removed since <tree-ish> are still present"),
|
||||
OPT__ABBREV(&abbrev),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
memset(&dir, 0, sizeof(dir));
|
||||
if (prefix)
|
||||
prefix_offset = strlen(prefix);
|
||||
git_config(git_default_config, NULL);
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
const char *arg = argv[i];
|
||||
|
||||
if (!strcmp(arg, "--")) {
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
if (!strcmp(arg, "-z")) {
|
||||
line_terminator = 0;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "-t") || !strcmp(arg, "-v")) {
|
||||
tag_cached = "H ";
|
||||
tag_unmerged = "M ";
|
||||
tag_removed = "R ";
|
||||
tag_modified = "C ";
|
||||
tag_other = "? ";
|
||||
tag_killed = "K ";
|
||||
if (arg[1] == 'v')
|
||||
show_valid_bit = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "-c") || !strcmp(arg, "--cached")) {
|
||||
show_cached = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "-d") || !strcmp(arg, "--deleted")) {
|
||||
show_deleted = 1;
|
||||
require_work_tree = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "-m") || !strcmp(arg, "--modified")) {
|
||||
show_modified = 1;
|
||||
require_work_tree = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "-o") || !strcmp(arg, "--others")) {
|
||||
show_others = 1;
|
||||
require_work_tree = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "-i") || !strcmp(arg, "--ignored")) {
|
||||
dir.show_ignored = 1;
|
||||
require_work_tree = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "-s") || !strcmp(arg, "--stage")) {
|
||||
show_stage = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "-k") || !strcmp(arg, "--killed")) {
|
||||
show_killed = 1;
|
||||
require_work_tree = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "--directory")) {
|
||||
dir.show_other_directories = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "--no-empty-directory")) {
|
||||
dir.hide_empty_directories = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "-u") || !strcmp(arg, "--unmerged")) {
|
||||
/* There's no point in showing unmerged unless
|
||||
* you also show the stage information.
|
||||
*/
|
||||
show_stage = 1;
|
||||
show_unmerged = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "-x") && i+1 < argc) {
|
||||
exc_given = 1;
|
||||
add_exclude(argv[++i], "", 0, &dir.exclude_list[EXC_CMDL]);
|
||||
continue;
|
||||
}
|
||||
if (!prefixcmp(arg, "--exclude=")) {
|
||||
exc_given = 1;
|
||||
add_exclude(arg+10, "", 0, &dir.exclude_list[EXC_CMDL]);
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "-X") && i+1 < argc) {
|
||||
exc_given = 1;
|
||||
add_excludes_from_file(&dir, argv[++i]);
|
||||
continue;
|
||||
}
|
||||
if (!prefixcmp(arg, "--exclude-from=")) {
|
||||
exc_given = 1;
|
||||
add_excludes_from_file(&dir, arg+15);
|
||||
continue;
|
||||
}
|
||||
if (!prefixcmp(arg, "--exclude-per-directory=")) {
|
||||
exc_given = 1;
|
||||
dir.exclude_per_dir = arg + 24;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "--exclude-standard")) {
|
||||
exc_given = 1;
|
||||
setup_standard_excludes(&dir);
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "--full-name")) {
|
||||
prefix_offset = 0;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "--error-unmatch")) {
|
||||
error_unmatch = 1;
|
||||
continue;
|
||||
}
|
||||
if (!prefixcmp(arg, "--with-tree=")) {
|
||||
with_tree = arg + 12;
|
||||
continue;
|
||||
}
|
||||
if (!prefixcmp(arg, "--abbrev=")) {
|
||||
abbrev = strtoul(arg+9, NULL, 10);
|
||||
if (abbrev && abbrev < MINIMUM_ABBREV)
|
||||
abbrev = MINIMUM_ABBREV;
|
||||
else if (abbrev > 40)
|
||||
abbrev = 40;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "--abbrev")) {
|
||||
abbrev = DEFAULT_ABBREV;
|
||||
continue;
|
||||
}
|
||||
if (*arg == '-')
|
||||
usage(ls_files_usage);
|
||||
break;
|
||||
argc = parse_options(argc, argv, builtin_ls_files_options,
|
||||
ls_files_usage, 0);
|
||||
if (show_tag || show_valid_bit) {
|
||||
tag_cached = "H ";
|
||||
tag_unmerged = "M ";
|
||||
tag_removed = "R ";
|
||||
tag_modified = "C ";
|
||||
tag_other = "? ";
|
||||
tag_killed = "K ";
|
||||
}
|
||||
if (show_modified || show_others || show_deleted || (dir.flags & DIR_SHOW_IGNORED) || show_killed)
|
||||
require_work_tree = 1;
|
||||
if (show_unmerged)
|
||||
/*
|
||||
* There's no point in showing unmerged unless
|
||||
* you also show the stage information.
|
||||
*/
|
||||
show_stage = 1;
|
||||
if (dir.exclude_per_dir)
|
||||
exc_given = 1;
|
||||
|
||||
if (require_work_tree && !is_inside_work_tree())
|
||||
setup_work_tree();
|
||||
|
||||
pathspec = get_pathspec(prefix, argv + i);
|
||||
pathspec = get_pathspec(prefix, argv);
|
||||
|
||||
/* be nice with submodule patsh ending in a slash */
|
||||
read_cache();
|
||||
|
@ -543,7 +529,7 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)
|
|||
ps_matched = xcalloc(1, num);
|
||||
}
|
||||
|
||||
if (dir.show_ignored && !exc_given) {
|
||||
if ((dir.flags & DIR_SHOW_IGNORED) && !exc_given) {
|
||||
fprintf(stderr, "%s: --ignored needs some exclude pattern\n",
|
||||
argv[0]);
|
||||
exit(1);
|
||||
|
|
|
@ -636,7 +636,7 @@ static int checkout_fast_forward(unsigned char *head, unsigned char *remote)
|
|||
memset(&opts, 0, sizeof(opts));
|
||||
memset(&t, 0, sizeof(t));
|
||||
memset(&dir, 0, sizeof(dir));
|
||||
dir.show_ignored = 1;
|
||||
dir.flags |= DIR_SHOW_IGNORED;
|
||||
dir.exclude_per_dir = ".gitignore";
|
||||
opts.dir = &dir;
|
||||
|
||||
|
|
|
@ -170,7 +170,7 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)
|
|||
die("more than one --exclude-per-directory are given.");
|
||||
|
||||
dir = xcalloc(1, sizeof(*opts.dir));
|
||||
dir->show_ignored = 1;
|
||||
dir->flags |= DIR_SHOW_IGNORED;
|
||||
dir->exclude_per_dir = arg + 24;
|
||||
opts.dir = dir;
|
||||
/* We do not need to nor want to do read-directory
|
||||
|
|
17
dir.c
17
dir.c
|
@ -487,14 +487,14 @@ static enum directory_treatment treat_directory(struct dir_struct *dir,
|
|||
return recurse_into_directory;
|
||||
|
||||
case index_gitdir:
|
||||
if (dir->show_other_directories)
|
||||
if (dir->flags & DIR_SHOW_OTHER_DIRECTORIES)
|
||||
return ignore_directory;
|
||||
return show_directory;
|
||||
|
||||
case index_nonexistent:
|
||||
if (dir->show_other_directories)
|
||||
if (dir->flags & DIR_SHOW_OTHER_DIRECTORIES)
|
||||
break;
|
||||
if (!dir->no_gitlinks) {
|
||||
if (!(dir->flags & DIR_NO_GITLINKS)) {
|
||||
unsigned char sha1[20];
|
||||
if (resolve_gitlink_ref(dirname, "HEAD", sha1) == 0)
|
||||
return show_directory;
|
||||
|
@ -503,7 +503,7 @@ static enum directory_treatment treat_directory(struct dir_struct *dir,
|
|||
}
|
||||
|
||||
/* This is the "show_other_directories" case */
|
||||
if (!dir->hide_empty_directories)
|
||||
if (!(dir->flags & DIR_HIDE_EMPTY_DIRECTORIES))
|
||||
return show_directory;
|
||||
if (!read_directory_recursive(dir, dirname, dirname, len, 1, simplify))
|
||||
return ignore_directory;
|
||||
|
@ -601,7 +601,7 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co
|
|||
|
||||
dtype = DTYPE(de);
|
||||
exclude = excluded(dir, fullname, &dtype);
|
||||
if (exclude && dir->collect_ignored
|
||||
if (exclude && (dir->flags & DIR_COLLECT_IGNORED)
|
||||
&& in_pathspec(fullname, baselen + len, simplify))
|
||||
dir_add_ignored(dir, fullname, baselen + len);
|
||||
|
||||
|
@ -609,7 +609,7 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co
|
|||
* Excluded? If we don't explicitly want to show
|
||||
* ignored files, ignore it
|
||||
*/
|
||||
if (exclude && !dir->show_ignored)
|
||||
if (exclude && !(dir->flags & DIR_SHOW_IGNORED))
|
||||
continue;
|
||||
|
||||
if (dtype == DT_UNKNOWN)
|
||||
|
@ -621,7 +621,7 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co
|
|||
* even if we don't ignore them, since the
|
||||
* directory may contain files that we do..
|
||||
*/
|
||||
if (!exclude && dir->show_ignored) {
|
||||
if (!exclude && (dir->flags & DIR_SHOW_IGNORED)) {
|
||||
if (dtype != DT_DIR)
|
||||
continue;
|
||||
}
|
||||
|
@ -634,7 +634,8 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co
|
|||
len++;
|
||||
switch (treat_directory(dir, fullname, baselen + len, simplify)) {
|
||||
case show_directory:
|
||||
if (exclude != dir->show_ignored)
|
||||
if (exclude != !!(dir->flags
|
||||
& DIR_SHOW_IGNORED))
|
||||
continue;
|
||||
break;
|
||||
case recurse_into_directory:
|
||||
|
|
12
dir.h
12
dir.h
|
@ -34,11 +34,13 @@ struct exclude_stack {
|
|||
struct dir_struct {
|
||||
int nr, alloc;
|
||||
int ignored_nr, ignored_alloc;
|
||||
unsigned int show_ignored:1,
|
||||
show_other_directories:1,
|
||||
hide_empty_directories:1,
|
||||
no_gitlinks:1,
|
||||
collect_ignored:1;
|
||||
enum {
|
||||
DIR_SHOW_IGNORED = 1<<0,
|
||||
DIR_SHOW_OTHER_DIRECTORIES = 1<<1,
|
||||
DIR_HIDE_EMPTY_DIRECTORIES = 1<<2,
|
||||
DIR_NO_GITLINKS = 1<<3,
|
||||
DIR_COLLECT_IGNORED = 1<<4
|
||||
} flags;
|
||||
struct dir_entry **entries;
|
||||
struct dir_entry **ignored;
|
||||
|
||||
|
|
|
@ -13,12 +13,13 @@ filesystem.
|
|||
path2/file2 - a file in a directory
|
||||
path3-junk - a file to confuse things
|
||||
path3/file3 - a file in a directory
|
||||
path4 - an empty directory
|
||||
'
|
||||
. ./test-lib.sh
|
||||
|
||||
date >path0
|
||||
ln -s xyzzy path1
|
||||
mkdir path2 path3
|
||||
mkdir path2 path3 path4
|
||||
date >path2/file2
|
||||
date >path2-junk
|
||||
date >path3/file3
|
||||
|
@ -28,6 +29,7 @@ git update-index --add path3-junk path3/file3
|
|||
cat >expected1 <<EOF
|
||||
expected1
|
||||
expected2
|
||||
expected3
|
||||
output
|
||||
path0
|
||||
path1
|
||||
|
@ -35,6 +37,8 @@ path2-junk
|
|||
path2/file2
|
||||
EOF
|
||||
sed -e 's|path2/file2|path2/|' <expected1 >expected2
|
||||
cat <expected2 >expected3
|
||||
echo path4/ >>expected2
|
||||
|
||||
test_expect_success \
|
||||
'git ls-files --others to show output.' \
|
||||
|
@ -53,4 +57,12 @@ test_expect_success \
|
|||
'git ls-files --others --directory should not get confused.' \
|
||||
'test_cmp expected2 output'
|
||||
|
||||
test_expect_success \
|
||||
'git ls-files --others --directory --no-empty-directory to show output.' \
|
||||
'git ls-files --others --directory --no-empty-directory >output'
|
||||
|
||||
test_expect_success \
|
||||
'--no-empty-directory hides empty directory' \
|
||||
'test_cmp expected3 output'
|
||||
|
||||
test_done
|
||||
|
|
|
@ -250,10 +250,9 @@ static void wt_status_print_untracked(struct wt_status *s)
|
|||
|
||||
memset(&dir, 0, sizeof(dir));
|
||||
|
||||
if (!s->untracked) {
|
||||
dir.show_other_directories = 1;
|
||||
dir.hide_empty_directories = 1;
|
||||
}
|
||||
if (!s->untracked)
|
||||
dir.flags |=
|
||||
DIR_SHOW_OTHER_DIRECTORIES | DIR_HIDE_EMPTY_DIRECTORIES;
|
||||
setup_standard_excludes(&dir);
|
||||
|
||||
read_directory(&dir, ".", "", 0, NULL);
|
||||
|
|
Загрузка…
Ссылка в новой задаче