*
* Copyright (C) Linus Torvalds, 2005
*/
-#include <fnmatch.h>
-
#include "cache.h"
#include "quote.h"
#include "dir.h"
#include "builtin.h"
-static int abbrev = 0;
-static int show_deleted = 0;
-static int show_cached = 0;
-static int show_others = 0;
-static int show_stage = 0;
-static int show_unmerged = 0;
-static int show_modified = 0;
-static int show_killed = 0;
-static int show_valid_bit = 0;
+static int abbrev;
+static int show_deleted;
+static int show_cached;
+static int show_others;
+static int show_stage;
+static int show_unmerged;
+static int show_modified;
+static int show_killed;
+static int show_valid_bit;
static int line_terminator = '\n';
-static int prefix_len = 0, prefix_offset = 0;
-static const char *prefix = NULL;
-static const char **pathspec = NULL;
-static int error_unmatch = 0;
-static char *ps_matched = NULL;
+static int prefix_len;
+static int prefix_offset;
+static const char **pathspec;
+static int error_unmatch;
+static char *ps_matched;
static const char *tag_cached = "";
static const char *tag_unmerged = "";
static void show_other_files(struct dir_struct *dir)
{
int i;
+
+
+ /*
+ * Skip matching and unmerged entries for the paths,
+ * since we want just "others".
+ *
+ * (Matching entries are normally pruned during
+ * the directory tree walk, but will show up for
+ * gitlinks because we don't necessarily have
+ * dir->show_other_directories set to suppress
+ * them).
+ */
for (i = 0; i < dir->nr; i++) {
- /* We should not have a matching entry, but we
- * may have an unmerged entry for this path.
- */
struct dir_entry *ent = dir->entries[i];
- int pos = cache_name_pos(ent->name, ent->len);
+ int len, pos;
struct cache_entry *ce;
+
+ /*
+ * Remove the '/' at the end that directory
+ * walking adds for directory entries.
+ */
+ len = ent->len;
+ if (len && ent->name[len-1] == '/')
+ len--;
+ pos = cache_name_pos(ent->name, len);
if (0 <= pos)
- die("bug in show-other-files");
+ continue; /* exact match */
pos = -pos - 1;
if (pos < active_nr) {
ce = active_cache[pos];
- if (ce_namelen(ce) == ent->len &&
- !memcmp(ce->name, ent->name, ent->len))
+ if (ce_namelen(ce) == len &&
+ !memcmp(ce->name, ent->name, len))
continue; /* Yup, this one exists unmerged */
}
show_dir_entry(tag_other, ent);
}
}
-static void show_files(struct dir_struct *dir)
+static void show_files(struct dir_struct *dir, const char *prefix)
{
int i;
if (baselen)
path = base = prefix;
- read_directory(dir, path, base, baselen);
+ read_directory(dir, path, base, baselen, pathspec);
if (show_others)
show_other_files(dir);
if (show_killed)
/*
* Prune the index to only contain stuff starting with "prefix"
*/
-static void prune_cache(void)
+static void prune_cache(const char *prefix)
{
int pos = cache_name_pos(prefix, prefix_len);
unsigned int first, last;
active_nr = last;
}
-static void verify_pathspec(void)
+static const char *verify_pathspec(const char *prefix)
{
const char **p, *n, *prev;
char *real_prefix;
memcpy(real_prefix, prev, max);
real_prefix[max] = 0;
}
- prefix = real_prefix;
+ return real_prefix;
}
static const char ls_files_usage[] =
"[ --exclude-per-directory=<filename> ] [--full-name] [--abbrev] "
"[--] [<file>]*";
-int cmd_ls_files(int argc, const char **argv, char** envp)
+int cmd_ls_files(int argc, const char **argv, const char *prefix)
{
int i;
- int exc_given = 0;
+ int exc_given = 0, require_work_tree = 0;
struct dir_struct dir;
memset(&dir, 0, sizeof(dir));
- prefix = setup_git_directory();
if (prefix)
prefix_offset = strlen(prefix);
git_config(git_default_config);
}
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")) {
}
if (!strcmp(arg, "-k") || !strcmp(arg, "--killed")) {
show_killed = 1;
+ require_work_tree = 1;
continue;
}
if (!strcmp(arg, "--directory")) {
add_exclude(argv[++i], "", 0, &dir.exclude_list[EXC_CMDL]);
continue;
}
- if (!strncmp(arg, "--exclude=", 10)) {
+ if (!prefixcmp(arg, "--exclude=")) {
exc_given = 1;
add_exclude(arg+10, "", 0, &dir.exclude_list[EXC_CMDL]);
continue;
add_excludes_from_file(&dir, argv[++i]);
continue;
}
- if (!strncmp(arg, "--exclude-from=", 15)) {
+ if (!prefixcmp(arg, "--exclude-from=")) {
exc_given = 1;
add_excludes_from_file(&dir, arg+15);
continue;
}
- if (!strncmp(arg, "--exclude-per-directory=", 24)) {
+ if (!prefixcmp(arg, "--exclude-per-directory=")) {
exc_given = 1;
dir.exclude_per_dir = arg + 24;
continue;
error_unmatch = 1;
continue;
}
- if (!strncmp(arg, "--abbrev=", 9)) {
+ if (!prefixcmp(arg, "--abbrev=")) {
abbrev = strtoul(arg+9, NULL, 10);
if (abbrev && abbrev < MINIMUM_ABBREV)
abbrev = MINIMUM_ABBREV;
break;
}
+ if (require_work_tree &&
+ (is_bare_repository() || is_inside_git_dir()))
+ die("This operation must be run in a work tree");
+
pathspec = get_pathspec(prefix, argv + i);
/* Verify that the pathspec matches the prefix */
if (pathspec)
- verify_pathspec();
+ prefix = verify_pathspec(prefix);
/* Treat unmatching pathspec elements as errors */
if (pathspec && error_unmatch) {
read_cache();
if (prefix)
- prune_cache();
- show_files(&dir);
+ prune_cache(prefix);
+ show_files(&dir, prefix);
if (ps_matched) {
/* We need to make sure all pathspec matched otherwise
for (num = 0; pathspec[num]; num++) {
if (ps_matched[num])
continue;
- error("pathspec '%s' did not match any.",
+ error("pathspec '%s' did not match any file(s) known to git.",
pathspec[num] + prefix_offset);
errors++;
}
+
+ if (errors)
+ fprintf(stderr, "Did you forget to 'git add'?\n");
+
return errors ? 1 : 0;
}