builtin-ls-files.con commit Turn the flags in struct dir_struct into a single variable (7c4c97c)
   1/*
   2 * This merges the file listing in the directory cache index
   3 * with the actual working directory list, and shows different
   4 * combinations of the two.
   5 *
   6 * Copyright (C) Linus Torvalds, 2005
   7 */
   8#include "cache.h"
   9#include "quote.h"
  10#include "dir.h"
  11#include "builtin.h"
  12#include "tree.h"
  13
  14static int abbrev;
  15static int show_deleted;
  16static int show_cached;
  17static int show_others;
  18static int show_stage;
  19static int show_unmerged;
  20static int show_modified;
  21static int show_killed;
  22static int show_valid_bit;
  23static int line_terminator = '\n';
  24
  25static int prefix_len;
  26static int prefix_offset;
  27static const char **pathspec;
  28static int error_unmatch;
  29static char *ps_matched;
  30static const char *with_tree;
  31
  32static const char *tag_cached = "";
  33static const char *tag_unmerged = "";
  34static const char *tag_removed = "";
  35static const char *tag_other = "";
  36static const char *tag_killed = "";
  37static const char *tag_modified = "";
  38
  39static void show_dir_entry(const char *tag, struct dir_entry *ent)
  40{
  41        int len = prefix_len;
  42        int offset = prefix_offset;
  43
  44        if (len >= ent->len)
  45                die("git ls-files: internal error - directory entry not superset of prefix");
  46
  47        if (!match_pathspec(pathspec, ent->name, ent->len, len, ps_matched))
  48                return;
  49
  50        fputs(tag, stdout);
  51        write_name_quoted(ent->name + offset, stdout, line_terminator);
  52}
  53
  54static void show_other_files(struct dir_struct *dir)
  55{
  56        int i;
  57
  58        for (i = 0; i < dir->nr; i++) {
  59                struct dir_entry *ent = dir->entries[i];
  60                if (!cache_name_is_other(ent->name, ent->len))
  61                        continue;
  62                show_dir_entry(tag_other, ent);
  63        }
  64}
  65
  66static void show_killed_files(struct dir_struct *dir)
  67{
  68        int i;
  69        for (i = 0; i < dir->nr; i++) {
  70                struct dir_entry *ent = dir->entries[i];
  71                char *cp, *sp;
  72                int pos, len, killed = 0;
  73
  74                for (cp = ent->name; cp - ent->name < ent->len; cp = sp + 1) {
  75                        sp = strchr(cp, '/');
  76                        if (!sp) {
  77                                /* If ent->name is prefix of an entry in the
  78                                 * cache, it will be killed.
  79                                 */
  80                                pos = cache_name_pos(ent->name, ent->len);
  81                                if (0 <= pos)
  82                                        die("bug in show-killed-files");
  83                                pos = -pos - 1;
  84                                while (pos < active_nr &&
  85                                       ce_stage(active_cache[pos]))
  86                                        pos++; /* skip unmerged */
  87                                if (active_nr <= pos)
  88                                        break;
  89                                /* pos points at a name immediately after
  90                                 * ent->name in the cache.  Does it expect
  91                                 * ent->name to be a directory?
  92                                 */
  93                                len = ce_namelen(active_cache[pos]);
  94                                if ((ent->len < len) &&
  95                                    !strncmp(active_cache[pos]->name,
  96                                             ent->name, ent->len) &&
  97                                    active_cache[pos]->name[ent->len] == '/')
  98                                        killed = 1;
  99                                break;
 100                        }
 101                        if (0 <= cache_name_pos(ent->name, sp - ent->name)) {
 102                                /* If any of the leading directories in
 103                                 * ent->name is registered in the cache,
 104                                 * ent->name will be killed.
 105                                 */
 106                                killed = 1;
 107                                break;
 108                        }
 109                }
 110                if (killed)
 111                        show_dir_entry(tag_killed, dir->entries[i]);
 112        }
 113}
 114
 115static void show_ce_entry(const char *tag, struct cache_entry *ce)
 116{
 117        int len = prefix_len;
 118        int offset = prefix_offset;
 119
 120        if (len >= ce_namelen(ce))
 121                die("git ls-files: internal error - cache entry not superset of prefix");
 122
 123        if (!match_pathspec(pathspec, ce->name, ce_namelen(ce), len, ps_matched))
 124                return;
 125
 126        if (tag && *tag && show_valid_bit &&
 127            (ce->ce_flags & CE_VALID)) {
 128                static char alttag[4];
 129                memcpy(alttag, tag, 3);
 130                if (isalpha(tag[0]))
 131                        alttag[0] = tolower(tag[0]);
 132                else if (tag[0] == '?')
 133                        alttag[0] = '!';
 134                else {
 135                        alttag[0] = 'v';
 136                        alttag[1] = tag[0];
 137                        alttag[2] = ' ';
 138                        alttag[3] = 0;
 139                }
 140                tag = alttag;
 141        }
 142
 143        if (!show_stage) {
 144                fputs(tag, stdout);
 145        } else {
 146                printf("%s%06o %s %d\t",
 147                       tag,
 148                       ce->ce_mode,
 149                       abbrev ? find_unique_abbrev(ce->sha1,abbrev)
 150                                : sha1_to_hex(ce->sha1),
 151                       ce_stage(ce));
 152        }
 153        write_name_quoted(ce->name + offset, stdout, line_terminator);
 154}
 155
 156static void show_files(struct dir_struct *dir, const char *prefix)
 157{
 158        int i;
 159
 160        /* For cached/deleted files we don't need to even do the readdir */
 161        if (show_others || show_killed) {
 162                const char *path = ".", *base = "";
 163                int baselen = prefix_len;
 164
 165                if (baselen)
 166                        path = base = prefix;
 167                read_directory(dir, path, base, baselen, pathspec);
 168                if (show_others)
 169                        show_other_files(dir);
 170                if (show_killed)
 171                        show_killed_files(dir);
 172        }
 173        if (show_cached | show_stage) {
 174                for (i = 0; i < active_nr; i++) {
 175                        struct cache_entry *ce = active_cache[i];
 176                        int dtype = ce_to_dtype(ce);
 177                        if (excluded(dir, ce->name, &dtype) !=
 178                                        !!(dir->flags & DIR_SHOW_IGNORED))
 179                                continue;
 180                        if (show_unmerged && !ce_stage(ce))
 181                                continue;
 182                        if (ce->ce_flags & CE_UPDATE)
 183                                continue;
 184                        show_ce_entry(ce_stage(ce) ? tag_unmerged : tag_cached, ce);
 185                }
 186        }
 187        if (show_deleted | show_modified) {
 188                for (i = 0; i < active_nr; i++) {
 189                        struct cache_entry *ce = active_cache[i];
 190                        struct stat st;
 191                        int err;
 192                        int dtype = ce_to_dtype(ce);
 193                        if (excluded(dir, ce->name, &dtype) !=
 194                                        !!(dir->flags & DIR_SHOW_IGNORED))
 195                                continue;
 196                        if (ce->ce_flags & CE_UPDATE)
 197                                continue;
 198                        err = lstat(ce->name, &st);
 199                        if (show_deleted && err)
 200                                show_ce_entry(tag_removed, ce);
 201                        if (show_modified && ce_modified(ce, &st, 0))
 202                                show_ce_entry(tag_modified, ce);
 203                }
 204        }
 205}
 206
 207/*
 208 * Prune the index to only contain stuff starting with "prefix"
 209 */
 210static void prune_cache(const char *prefix)
 211{
 212        int pos = cache_name_pos(prefix, prefix_len);
 213        unsigned int first, last;
 214
 215        if (pos < 0)
 216                pos = -pos-1;
 217        memmove(active_cache, active_cache + pos,
 218                (active_nr - pos) * sizeof(struct cache_entry *));
 219        active_nr -= pos;
 220        first = 0;
 221        last = active_nr;
 222        while (last > first) {
 223                int next = (last + first) >> 1;
 224                struct cache_entry *ce = active_cache[next];
 225                if (!strncmp(ce->name, prefix, prefix_len)) {
 226                        first = next+1;
 227                        continue;
 228                }
 229                last = next;
 230        }
 231        active_nr = last;
 232}
 233
 234static const char *verify_pathspec(const char *prefix)
 235{
 236        const char **p, *n, *prev;
 237        unsigned long max;
 238
 239        prev = NULL;
 240        max = PATH_MAX;
 241        for (p = pathspec; (n = *p) != NULL; p++) {
 242                int i, len = 0;
 243                for (i = 0; i < max; i++) {
 244                        char c = n[i];
 245                        if (prev && prev[i] != c)
 246                                break;
 247                        if (!c || c == '*' || c == '?')
 248                                break;
 249                        if (c == '/')
 250                                len = i+1;
 251                }
 252                prev = n;
 253                if (len < max) {
 254                        max = len;
 255                        if (!max)
 256                                break;
 257                }
 258        }
 259
 260        if (prefix_offset > max || memcmp(prev, prefix, prefix_offset))
 261                die("git ls-files: cannot generate relative filenames containing '..'");
 262
 263        prefix_len = max;
 264        return max ? xmemdupz(prev, max) : NULL;
 265}
 266
 267static void strip_trailing_slash_from_submodules(void)
 268{
 269        const char **p;
 270
 271        for (p = pathspec; *p != NULL; p++) {
 272                int len = strlen(*p), pos;
 273
 274                if (len < 1 || (*p)[len - 1] != '/')
 275                        continue;
 276                pos = cache_name_pos(*p, len - 1);
 277                if (pos >= 0 && S_ISGITLINK(active_cache[pos]->ce_mode))
 278                        *p = xstrndup(*p, len - 1);
 279        }
 280}
 281
 282/*
 283 * Read the tree specified with --with-tree option
 284 * (typically, HEAD) into stage #1 and then
 285 * squash them down to stage #0.  This is used for
 286 * --error-unmatch to list and check the path patterns
 287 * that were given from the command line.  We are not
 288 * going to write this index out.
 289 */
 290void overlay_tree_on_cache(const char *tree_name, const char *prefix)
 291{
 292        struct tree *tree;
 293        unsigned char sha1[20];
 294        const char **match;
 295        struct cache_entry *last_stage0 = NULL;
 296        int i;
 297
 298        if (get_sha1(tree_name, sha1))
 299                die("tree-ish %s not found.", tree_name);
 300        tree = parse_tree_indirect(sha1);
 301        if (!tree)
 302                die("bad tree-ish %s", tree_name);
 303
 304        /* Hoist the unmerged entries up to stage #3 to make room */
 305        for (i = 0; i < active_nr; i++) {
 306                struct cache_entry *ce = active_cache[i];
 307                if (!ce_stage(ce))
 308                        continue;
 309                ce->ce_flags |= CE_STAGEMASK;
 310        }
 311
 312        if (prefix) {
 313                static const char *(matchbuf[2]);
 314                matchbuf[0] = prefix;
 315                matchbuf[1] = NULL;
 316                match = matchbuf;
 317        } else
 318                match = NULL;
 319        if (read_tree(tree, 1, match))
 320                die("unable to read tree entries %s", tree_name);
 321
 322        for (i = 0; i < active_nr; i++) {
 323                struct cache_entry *ce = active_cache[i];
 324                switch (ce_stage(ce)) {
 325                case 0:
 326                        last_stage0 = ce;
 327                        /* fallthru */
 328                default:
 329                        continue;
 330                case 1:
 331                        /*
 332                         * If there is stage #0 entry for this, we do not
 333                         * need to show it.  We use CE_UPDATE bit to mark
 334                         * such an entry.
 335                         */
 336                        if (last_stage0 &&
 337                            !strcmp(last_stage0->name, ce->name))
 338                                ce->ce_flags |= CE_UPDATE;
 339                }
 340        }
 341}
 342
 343int report_path_error(const char *ps_matched, const char **pathspec, int prefix_offset)
 344{
 345        /*
 346         * Make sure all pathspec matched; otherwise it is an error.
 347         */
 348        int num, errors = 0;
 349        for (num = 0; pathspec[num]; num++) {
 350                int other, found_dup;
 351
 352                if (ps_matched[num])
 353                        continue;
 354                /*
 355                 * The caller might have fed identical pathspec
 356                 * twice.  Do not barf on such a mistake.
 357                 */
 358                for (found_dup = other = 0;
 359                     !found_dup && pathspec[other];
 360                     other++) {
 361                        if (other == num || !ps_matched[other])
 362                                continue;
 363                        if (!strcmp(pathspec[other], pathspec[num]))
 364                                /*
 365                                 * Ok, we have a match already.
 366                                 */
 367                                found_dup = 1;
 368                }
 369                if (found_dup)
 370                        continue;
 371
 372                error("pathspec '%s' did not match any file(s) known to git.",
 373                      pathspec[num] + prefix_offset);
 374                errors++;
 375        }
 376        return errors;
 377}
 378
 379static const char ls_files_usage[] =
 380        "git ls-files [-z] [-t] [-v] (--[cached|deleted|others|stage|unmerged|killed|modified])* "
 381        "[ --ignored ] [--exclude=<pattern>] [--exclude-from=<file>] "
 382        "[ --exclude-per-directory=<filename> ] [--exclude-standard] "
 383        "[--full-name] [--abbrev] [--] [<file>]*";
 384
 385int cmd_ls_files(int argc, const char **argv, const char *prefix)
 386{
 387        int i;
 388        int exc_given = 0, require_work_tree = 0;
 389        struct dir_struct dir;
 390
 391        memset(&dir, 0, sizeof(dir));
 392        if (prefix)
 393                prefix_offset = strlen(prefix);
 394        git_config(git_default_config, NULL);
 395
 396        for (i = 1; i < argc; i++) {
 397                const char *arg = argv[i];
 398
 399                if (!strcmp(arg, "--")) {
 400                        i++;
 401                        break;
 402                }
 403                if (!strcmp(arg, "-z")) {
 404                        line_terminator = 0;
 405                        continue;
 406                }
 407                if (!strcmp(arg, "-t") || !strcmp(arg, "-v")) {
 408                        tag_cached = "H ";
 409                        tag_unmerged = "M ";
 410                        tag_removed = "R ";
 411                        tag_modified = "C ";
 412                        tag_other = "? ";
 413                        tag_killed = "K ";
 414                        if (arg[1] == 'v')
 415                                show_valid_bit = 1;
 416                        continue;
 417                }
 418                if (!strcmp(arg, "-c") || !strcmp(arg, "--cached")) {
 419                        show_cached = 1;
 420                        continue;
 421                }
 422                if (!strcmp(arg, "-d") || !strcmp(arg, "--deleted")) {
 423                        show_deleted = 1;
 424                        continue;
 425                }
 426                if (!strcmp(arg, "-m") || !strcmp(arg, "--modified")) {
 427                        show_modified = 1;
 428                        require_work_tree = 1;
 429                        continue;
 430                }
 431                if (!strcmp(arg, "-o") || !strcmp(arg, "--others")) {
 432                        show_others = 1;
 433                        require_work_tree = 1;
 434                        continue;
 435                }
 436                if (!strcmp(arg, "-i") || !strcmp(arg, "--ignored")) {
 437                        dir.flags |= DIR_SHOW_IGNORED;
 438                        require_work_tree = 1;
 439                        continue;
 440                }
 441                if (!strcmp(arg, "-s") || !strcmp(arg, "--stage")) {
 442                        show_stage = 1;
 443                        continue;
 444                }
 445                if (!strcmp(arg, "-k") || !strcmp(arg, "--killed")) {
 446                        show_killed = 1;
 447                        require_work_tree = 1;
 448                        continue;
 449                }
 450                if (!strcmp(arg, "--directory")) {
 451                        dir.flags |= DIR_SHOW_OTHER_DIRECTORIES;
 452                        continue;
 453                }
 454                if (!strcmp(arg, "--no-empty-directory")) {
 455                        dir.flags |= DIR_HIDE_EMPTY_DIRECTORIES;
 456                        continue;
 457                }
 458                if (!strcmp(arg, "-u") || !strcmp(arg, "--unmerged")) {
 459                        /* There's no point in showing unmerged unless
 460                         * you also show the stage information.
 461                         */
 462                        show_stage = 1;
 463                        show_unmerged = 1;
 464                        continue;
 465                }
 466                if (!strcmp(arg, "-x") && i+1 < argc) {
 467                        exc_given = 1;
 468                        add_exclude(argv[++i], "", 0, &dir.exclude_list[EXC_CMDL]);
 469                        continue;
 470                }
 471                if (!prefixcmp(arg, "--exclude=")) {
 472                        exc_given = 1;
 473                        add_exclude(arg+10, "", 0, &dir.exclude_list[EXC_CMDL]);
 474                        continue;
 475                }
 476                if (!strcmp(arg, "-X") && i+1 < argc) {
 477                        exc_given = 1;
 478                        add_excludes_from_file(&dir, argv[++i]);
 479                        continue;
 480                }
 481                if (!prefixcmp(arg, "--exclude-from=")) {
 482                        exc_given = 1;
 483                        add_excludes_from_file(&dir, arg+15);
 484                        continue;
 485                }
 486                if (!prefixcmp(arg, "--exclude-per-directory=")) {
 487                        exc_given = 1;
 488                        dir.exclude_per_dir = arg + 24;
 489                        continue;
 490                }
 491                if (!strcmp(arg, "--exclude-standard")) {
 492                        exc_given = 1;
 493                        setup_standard_excludes(&dir);
 494                        continue;
 495                }
 496                if (!strcmp(arg, "--full-name")) {
 497                        prefix_offset = 0;
 498                        continue;
 499                }
 500                if (!strcmp(arg, "--error-unmatch")) {
 501                        error_unmatch = 1;
 502                        continue;
 503                }
 504                if (!prefixcmp(arg, "--with-tree=")) {
 505                        with_tree = arg + 12;
 506                        continue;
 507                }
 508                if (!prefixcmp(arg, "--abbrev=")) {
 509                        abbrev = strtoul(arg+9, NULL, 10);
 510                        if (abbrev && abbrev < MINIMUM_ABBREV)
 511                                abbrev = MINIMUM_ABBREV;
 512                        else if (abbrev > 40)
 513                                abbrev = 40;
 514                        continue;
 515                }
 516                if (!strcmp(arg, "--abbrev")) {
 517                        abbrev = DEFAULT_ABBREV;
 518                        continue;
 519                }
 520                if (*arg == '-')
 521                        usage(ls_files_usage);
 522                break;
 523        }
 524
 525        if (require_work_tree && !is_inside_work_tree())
 526                setup_work_tree();
 527
 528        pathspec = get_pathspec(prefix, argv + i);
 529
 530        /* be nice with submodule patsh ending in a slash */
 531        read_cache();
 532        if (pathspec)
 533                strip_trailing_slash_from_submodules();
 534
 535        /* Verify that the pathspec matches the prefix */
 536        if (pathspec)
 537                prefix = verify_pathspec(prefix);
 538
 539        /* Treat unmatching pathspec elements as errors */
 540        if (pathspec && error_unmatch) {
 541                int num;
 542                for (num = 0; pathspec[num]; num++)
 543                        ;
 544                ps_matched = xcalloc(1, num);
 545        }
 546
 547        if ((dir.flags & DIR_SHOW_IGNORED) && !exc_given) {
 548                fprintf(stderr, "%s: --ignored needs some exclude pattern\n",
 549                        argv[0]);
 550                exit(1);
 551        }
 552
 553        /* With no flags, we default to showing the cached files */
 554        if (!(show_stage | show_deleted | show_others | show_unmerged |
 555              show_killed | show_modified))
 556                show_cached = 1;
 557
 558        if (prefix)
 559                prune_cache(prefix);
 560        if (with_tree) {
 561                /*
 562                 * Basic sanity check; show-stages and show-unmerged
 563                 * would not make any sense with this option.
 564                 */
 565                if (show_stage || show_unmerged)
 566                        die("ls-files --with-tree is incompatible with -s or -u");
 567                overlay_tree_on_cache(with_tree, prefix);
 568        }
 569        show_files(&dir, prefix);
 570
 571        if (ps_matched) {
 572                int bad;
 573                bad = report_path_error(ps_matched, pathspec, prefix_offset);
 574                if (bad)
 575                        fprintf(stderr, "Did you forget to 'git add'?\n");
 576
 577                return bad ? 1 : 0;
 578        }
 579
 580        return 0;
 581}