filter-branch: always export GIT_DIR if it is set
[gitweb.git] / builtin-ls-files.c
index 79ffe8f42351f6ca5d01ce5601b6708bdfac7101..48a313516db12dbb74d1f0293d3a55edc0cb3f2c 100644 (file)
@@ -5,29 +5,27 @@
  *
  * 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 = "";
@@ -91,20 +89,38 @@ static void show_dir_entry(const char *tag, struct dir_entry *ent)
 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);
@@ -207,7 +223,7 @@ static void show_ce_entry(const char *tag, struct cache_entry *ce)
        }
 }
 
-static void show_files(struct dir_struct *dir)
+static void show_files(struct dir_struct *dir, const char *prefix)
 {
        int i;
 
@@ -218,7 +234,7 @@ static void show_files(struct dir_struct *dir)
 
                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)
@@ -253,7 +269,7 @@ static void show_files(struct dir_struct *dir)
 /*
  * 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;
@@ -276,7 +292,7 @@ static void prune_cache(void)
        active_nr = last;
 }
 
-static void verify_pathspec(void)
+static const char *verify_pathspec(const char *prefix)
 {
        const char **p, *n, *prev;
        char *real_prefix;
@@ -313,7 +329,7 @@ static void verify_pathspec(void)
                memcpy(real_prefix, prev, max);
                real_prefix[max] = 0;
        }
-       prefix = real_prefix;
+       return real_prefix;
 }
 
 static const char ls_files_usage[] =
@@ -325,7 +341,7 @@ static const char ls_files_usage[] =
 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));
@@ -365,14 +381,17 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)
                }
                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")) {
@@ -381,6 +400,7 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)
                }
                if (!strcmp(arg, "-k") || !strcmp(arg, "--killed")) {
                        show_killed = 1;
+                       require_work_tree = 1;
                        continue;
                }
                if (!strcmp(arg, "--directory")) {
@@ -404,7 +424,7 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)
                        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;
@@ -414,12 +434,12 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)
                        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;
@@ -432,7 +452,7 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)
                        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;
@@ -449,11 +469,15 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)
                break;
        }
 
+       if (require_work_tree &&
+                       (!is_inside_work_tree() || 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) {
@@ -476,8 +500,8 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)
 
        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
@@ -487,10 +511,14 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)
                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;
        }