Coverage Report

Created: 2024-09-16 06:11

/src/git/builtin/ls-files.c
Line
Count
Source (jump to first uncovered line)
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 "builtin.h"
9
#include "repository.h"
10
#include "config.h"
11
#include "convert.h"
12
#include "quote.h"
13
#include "dir.h"
14
#include "gettext.h"
15
#include "object-name.h"
16
#include "strbuf.h"
17
#include "parse-options.h"
18
#include "resolve-undo.h"
19
#include "string-list.h"
20
#include "path.h"
21
#include "pathspec.h"
22
#include "read-cache.h"
23
#include "setup.h"
24
#include "sparse-index.h"
25
#include "submodule.h"
26
#include "object-store.h"
27
#include "hex.h"
28
29
30
static int abbrev;
31
static int show_deleted;
32
static int show_cached;
33
static int show_others;
34
static int show_stage;
35
static int show_unmerged;
36
static int show_resolve_undo;
37
static int show_modified;
38
static int show_killed;
39
static int show_valid_bit;
40
static int show_fsmonitor_bit;
41
static int line_terminator = '\n';
42
static int debug_mode;
43
static int show_eol;
44
static int recurse_submodules;
45
static int skipping_duplicates;
46
static int show_sparse_dirs;
47
48
static const char *prefix;
49
static int max_prefix_len;
50
static int prefix_len;
51
static struct pathspec pathspec;
52
static int error_unmatch;
53
static char *ps_matched;
54
static const char *with_tree;
55
static int exc_given;
56
static int exclude_args;
57
static const char *format;
58
59
static const char *tag_cached = "";
60
static const char *tag_unmerged = "";
61
static const char *tag_removed = "";
62
static const char *tag_other = "";
63
static const char *tag_killed = "";
64
static const char *tag_modified = "";
65
static const char *tag_skip_worktree = "";
66
static const char *tag_resolve_undo = "";
67
68
static void write_eolinfo(struct index_state *istate,
69
        const struct cache_entry *ce, const char *path)
70
0
{
71
0
  if (show_eol) {
72
0
    struct stat st;
73
0
    const char *i_txt = "";
74
0
    const char *w_txt = "";
75
0
    const char *a_txt = get_convert_attr_ascii(istate, path);
76
0
    if (ce && S_ISREG(ce->ce_mode))
77
0
      i_txt = get_cached_convert_stats_ascii(istate,
78
0
                     ce->name);
79
0
    if (!lstat(path, &st) && S_ISREG(st.st_mode))
80
0
      w_txt = get_wt_convert_stats_ascii(path);
81
0
    printf("i/%-5s w/%-5s attr/%-17s\t", i_txt, w_txt, a_txt);
82
0
  }
83
0
}
84
85
static void write_name(const char *name)
86
0
{
87
  /*
88
   * With "--full-name", prefix_len=0; this caller needs to pass
89
   * an empty string in that case (a NULL is good for "").
90
   */
91
0
  write_name_quoted_relative(name, prefix_len ? prefix : NULL,
92
0
           stdout, line_terminator);
93
0
}
94
95
static void write_name_to_buf(struct strbuf *sb, const char *name)
96
0
{
97
0
  struct strbuf buf = STRBUF_INIT;
98
0
  const char *rel = relative_path(name, prefix_len ? prefix : NULL, &buf);
99
100
0
  if (line_terminator)
101
0
    quote_c_style(rel, sb, NULL, 0);
102
0
  else
103
0
    strbuf_addstr(sb, rel);
104
105
0
  strbuf_release(&buf);
106
0
}
107
108
static const char *get_tag(const struct cache_entry *ce, const char *tag)
109
0
{
110
0
  static char alttag[4];
111
112
0
  if (tag && *tag && ((show_valid_bit && (ce->ce_flags & CE_VALID)) ||
113
0
    (show_fsmonitor_bit && (ce->ce_flags & CE_FSMONITOR_VALID)))) {
114
0
    memcpy(alttag, tag, 3);
115
116
0
    if (isalpha(tag[0])) {
117
0
      alttag[0] = tolower(tag[0]);
118
0
    } else if (tag[0] == '?') {
119
0
      alttag[0] = '!';
120
0
    } else {
121
0
      alttag[0] = 'v';
122
0
      alttag[1] = tag[0];
123
0
      alttag[2] = ' ';
124
0
      alttag[3] = 0;
125
0
    }
126
127
0
    tag = alttag;
128
0
  }
129
130
0
  return tag;
131
0
}
132
133
static void print_debug(const struct cache_entry *ce)
134
0
{
135
0
  if (debug_mode) {
136
0
    const struct stat_data *sd = &ce->ce_stat_data;
137
138
0
    printf("  ctime: %u:%u\n", sd->sd_ctime.sec, sd->sd_ctime.nsec);
139
0
    printf("  mtime: %u:%u\n", sd->sd_mtime.sec, sd->sd_mtime.nsec);
140
0
    printf("  dev: %u\tino: %u\n", sd->sd_dev, sd->sd_ino);
141
0
    printf("  uid: %u\tgid: %u\n", sd->sd_uid, sd->sd_gid);
142
0
    printf("  size: %u\tflags: %x\n", sd->sd_size, ce->ce_flags);
143
0
  }
144
0
}
145
146
static void show_dir_entry(struct index_state *istate,
147
         const char *tag, struct dir_entry *ent)
148
0
{
149
0
  int len = max_prefix_len;
150
151
0
  if (len > ent->len)
152
0
    die("git ls-files: internal error - directory entry not superset of prefix");
153
154
  /* If ps_matches is non-NULL, figure out which pathspec(s) match. */
155
0
  if (ps_matched)
156
0
    dir_path_match(istate, ent, &pathspec, len, ps_matched);
157
158
0
  fputs(tag, stdout);
159
0
  write_eolinfo(istate, NULL, ent->name);
160
0
  write_name(ent->name);
161
0
}
162
163
static void show_other_files(struct index_state *istate,
164
           const struct dir_struct *dir)
165
0
{
166
0
  int i;
167
168
0
  for (i = 0; i < dir->nr; i++) {
169
0
    struct dir_entry *ent = dir->entries[i];
170
0
    if (!index_name_is_other(istate, ent->name, ent->len))
171
0
      continue;
172
0
    show_dir_entry(istate, tag_other, ent);
173
0
  }
174
0
}
175
176
static void show_killed_files(struct index_state *istate,
177
            const struct dir_struct *dir)
178
0
{
179
0
  int i;
180
0
  for (i = 0; i < dir->nr; i++) {
181
0
    struct dir_entry *ent = dir->entries[i];
182
0
    char *cp, *sp;
183
0
    int pos, len, killed = 0;
184
185
0
    for (cp = ent->name; cp - ent->name < ent->len; cp = sp + 1) {
186
0
      sp = strchr(cp, '/');
187
0
      if (!sp) {
188
        /* If ent->name is prefix of an entry in the
189
         * cache, it will be killed.
190
         */
191
0
        pos = index_name_pos(istate, ent->name, ent->len);
192
0
        if (0 <= pos)
193
0
          BUG("killed-file %.*s not found",
194
0
            ent->len, ent->name);
195
0
        pos = -pos - 1;
196
0
        while (pos < istate->cache_nr &&
197
0
               ce_stage(istate->cache[pos]))
198
0
          pos++; /* skip unmerged */
199
0
        if (istate->cache_nr <= pos)
200
0
          break;
201
        /* pos points at a name immediately after
202
         * ent->name in the cache.  Does it expect
203
         * ent->name to be a directory?
204
         */
205
0
        len = ce_namelen(istate->cache[pos]);
206
0
        if ((ent->len < len) &&
207
0
            !strncmp(istate->cache[pos]->name,
208
0
               ent->name, ent->len) &&
209
0
            istate->cache[pos]->name[ent->len] == '/')
210
0
          killed = 1;
211
0
        break;
212
0
      }
213
0
      if (0 <= index_name_pos(istate, ent->name, sp - ent->name)) {
214
        /* If any of the leading directories in
215
         * ent->name is registered in the cache,
216
         * ent->name will be killed.
217
         */
218
0
        killed = 1;
219
0
        break;
220
0
      }
221
0
    }
222
0
    if (killed)
223
0
      show_dir_entry(istate, tag_killed, dir->entries[i]);
224
0
  }
225
0
}
226
227
static void show_files(struct repository *repo, struct dir_struct *dir);
228
229
static void show_submodule(struct repository *superproject,
230
         struct dir_struct *dir, const char *path)
231
0
{
232
0
  struct repository subrepo;
233
234
0
  if (repo_submodule_init(&subrepo, superproject, path, null_oid()))
235
0
    return;
236
237
0
  if (repo_read_index(&subrepo) < 0)
238
0
    die("index file corrupt");
239
240
0
  show_files(&subrepo, dir);
241
242
0
  repo_clear(&subrepo);
243
0
}
244
245
static void expand_objectsize(struct strbuf *line, const struct object_id *oid,
246
            const enum object_type type, unsigned int padded)
247
0
{
248
0
  if (type == OBJ_BLOB) {
249
0
    unsigned long size;
250
0
    if (oid_object_info(the_repository, oid, &size) < 0)
251
0
      die(_("could not get object info about '%s'"),
252
0
          oid_to_hex(oid));
253
0
    if (padded)
254
0
      strbuf_addf(line, "%7"PRIuMAX, (uintmax_t)size);
255
0
    else
256
0
      strbuf_addf(line, "%"PRIuMAX, (uintmax_t)size);
257
0
  } else if (padded) {
258
0
    strbuf_addf(line, "%7s", "-");
259
0
  } else {
260
0
    strbuf_addstr(line, "-");
261
0
  }
262
0
}
263
264
static void show_ce_fmt(struct repository *repo, const struct cache_entry *ce,
265
0
      const char *format, const char *fullname) {
266
0
  struct strbuf sb = STRBUF_INIT;
267
268
0
  while (strbuf_expand_step(&sb, &format)) {
269
0
    size_t len;
270
0
    struct stat st;
271
272
0
    if (skip_prefix(format, "%", &format))
273
0
      strbuf_addch(&sb, '%');
274
0
    else if ((len = strbuf_expand_literal(&sb, format)))
275
0
      format += len;
276
0
    else if (skip_prefix(format, "(objectmode)", &format))
277
0
      strbuf_addf(&sb, "%06o", ce->ce_mode);
278
0
    else if (skip_prefix(format, "(objectname)", &format))
279
0
      strbuf_add_unique_abbrev(&sb, &ce->oid, abbrev);
280
0
    else if (skip_prefix(format, "(objecttype)", &format))
281
0
      strbuf_addstr(&sb, type_name(object_type(ce->ce_mode)));
282
0
    else if (skip_prefix(format, "(objectsize:padded)", &format))
283
0
      expand_objectsize(&sb, &ce->oid,
284
0
            object_type(ce->ce_mode), 1);
285
0
    else if (skip_prefix(format, "(objectsize)", &format))
286
0
      expand_objectsize(&sb, &ce->oid,
287
0
            object_type(ce->ce_mode), 0);
288
0
    else if (skip_prefix(format, "(stage)", &format))
289
0
      strbuf_addf(&sb, "%d", ce_stage(ce));
290
0
    else if (skip_prefix(format, "(eolinfo:index)", &format))
291
0
      strbuf_addstr(&sb, S_ISREG(ce->ce_mode) ?
292
0
              get_cached_convert_stats_ascii(repo->index,
293
0
              ce->name) : "");
294
0
    else if (skip_prefix(format, "(eolinfo:worktree)", &format))
295
0
      strbuf_addstr(&sb, !lstat(fullname, &st) &&
296
0
              S_ISREG(st.st_mode) ?
297
0
              get_wt_convert_stats_ascii(fullname) : "");
298
0
    else if (skip_prefix(format, "(eolattr)", &format))
299
0
      strbuf_addstr(&sb, get_convert_attr_ascii(repo->index,
300
0
                 fullname));
301
0
    else if (skip_prefix(format, "(path)", &format))
302
0
      write_name_to_buf(&sb, fullname);
303
0
    else
304
0
      strbuf_expand_bad_format(format, "ls-files");
305
0
  }
306
0
  strbuf_addch(&sb, line_terminator);
307
0
  fwrite(sb.buf, sb.len, 1, stdout);
308
0
  strbuf_release(&sb);
309
0
}
310
311
static void show_ce(struct repository *repo, struct dir_struct *dir,
312
        const struct cache_entry *ce, const char *fullname,
313
        const char *tag)
314
0
{
315
0
  if (max_prefix_len > strlen(fullname))
316
0
    die("git ls-files: internal error - cache entry not superset of prefix");
317
318
0
  if (recurse_submodules && S_ISGITLINK(ce->ce_mode) &&
319
0
      is_submodule_active(repo, ce->name)) {
320
0
    show_submodule(repo, dir, ce->name);
321
0
  } else if (match_pathspec(repo->index, &pathspec, fullname, strlen(fullname),
322
0
          max_prefix_len, ps_matched,
323
0
          S_ISDIR(ce->ce_mode) ||
324
0
          S_ISGITLINK(ce->ce_mode))) {
325
0
    if (format) {
326
0
      show_ce_fmt(repo, ce, format, fullname);
327
0
      print_debug(ce);
328
0
      return;
329
0
    }
330
331
0
    tag = get_tag(ce, tag);
332
333
0
    if (!show_stage) {
334
0
      fputs(tag, stdout);
335
0
    } else {
336
0
      printf("%s%06o %s %d\t",
337
0
             tag,
338
0
             ce->ce_mode,
339
0
             repo_find_unique_abbrev(repo, &ce->oid, abbrev),
340
0
             ce_stage(ce));
341
0
    }
342
0
    write_eolinfo(repo->index, ce, fullname);
343
0
    write_name(fullname);
344
0
    print_debug(ce);
345
0
  }
346
0
}
347
348
static void show_ru_info(struct index_state *istate)
349
0
{
350
0
  struct string_list_item *item;
351
352
0
  if (!istate->resolve_undo)
353
0
    return;
354
355
0
  for_each_string_list_item(item, istate->resolve_undo) {
356
0
    const char *path = item->string;
357
0
    struct resolve_undo_info *ui = item->util;
358
0
    int i, len;
359
360
0
    len = strlen(path);
361
0
    if (len < max_prefix_len)
362
0
      continue; /* outside of the prefix */
363
0
    if (!match_pathspec(istate, &pathspec, path, len,
364
0
            max_prefix_len, ps_matched, 0))
365
0
      continue; /* uninterested */
366
0
    for (i = 0; i < 3; i++) {
367
0
      if (!ui->mode[i])
368
0
        continue;
369
0
      printf("%s%06o %s %d\t", tag_resolve_undo, ui->mode[i],
370
0
             repo_find_unique_abbrev(the_repository, &ui->oid[i], abbrev),
371
0
             i + 1);
372
0
      write_name(path);
373
0
    }
374
0
  }
375
0
}
376
377
static int ce_excluded(struct dir_struct *dir, struct index_state *istate,
378
           const char *fullname, const struct cache_entry *ce)
379
0
{
380
0
  int dtype = ce_to_dtype(ce);
381
0
  return is_excluded(dir, istate, fullname, &dtype);
382
0
}
383
384
static void construct_fullname(struct strbuf *out, const struct repository *repo,
385
             const struct cache_entry *ce)
386
0
{
387
0
  strbuf_reset(out);
388
0
  if (repo->submodule_prefix)
389
0
    strbuf_addstr(out, repo->submodule_prefix);
390
0
  strbuf_addstr(out, ce->name);
391
0
}
392
393
static void show_files(struct repository *repo, struct dir_struct *dir)
394
0
{
395
0
  int i;
396
0
  struct strbuf fullname = STRBUF_INIT;
397
398
  /* For cached/deleted files we don't need to even do the readdir */
399
0
  if (show_others || show_killed) {
400
0
    if (!show_others)
401
0
      dir->flags |= DIR_COLLECT_KILLED_ONLY;
402
0
    fill_directory(dir, repo->index, &pathspec);
403
0
    if (show_others)
404
0
      show_other_files(repo->index, dir);
405
0
    if (show_killed)
406
0
      show_killed_files(repo->index, dir);
407
0
  }
408
409
0
  if (!(show_cached || show_stage || show_deleted || show_modified))
410
0
    return;
411
412
0
  if (!show_sparse_dirs)
413
0
    ensure_full_index(repo->index);
414
415
0
  for (i = 0; i < repo->index->cache_nr; i++) {
416
0
    const struct cache_entry *ce = repo->index->cache[i];
417
0
    struct stat st;
418
0
    int stat_err;
419
420
0
    construct_fullname(&fullname, repo, ce);
421
422
0
    if ((dir->flags & DIR_SHOW_IGNORED) &&
423
0
      !ce_excluded(dir, repo->index, fullname.buf, ce))
424
0
      continue;
425
0
    if (ce->ce_flags & CE_UPDATE)
426
0
      continue;
427
0
    if ((show_cached || show_stage) &&
428
0
        (!show_unmerged || ce_stage(ce))) {
429
0
      show_ce(repo, dir, ce, fullname.buf,
430
0
        ce_stage(ce) ? tag_unmerged :
431
0
        (ce_skip_worktree(ce) ? tag_skip_worktree :
432
0
         tag_cached));
433
0
      if (skipping_duplicates)
434
0
        goto skip_to_next_name;
435
0
    }
436
437
0
    if (!(show_deleted || show_modified))
438
0
      continue;
439
0
    if (ce_skip_worktree(ce))
440
0
      continue;
441
0
    stat_err = lstat(fullname.buf, &st);
442
0
    if (stat_err && (errno != ENOENT && errno != ENOTDIR))
443
0
      error_errno("cannot lstat '%s'", fullname.buf);
444
0
    if (stat_err && show_deleted) {
445
0
      show_ce(repo, dir, ce, fullname.buf, tag_removed);
446
0
      if (skipping_duplicates)
447
0
        goto skip_to_next_name;
448
0
    }
449
0
    if (show_modified &&
450
0
        (stat_err || ie_modified(repo->index, ce, &st, 0))) {
451
0
      show_ce(repo, dir, ce, fullname.buf, tag_modified);
452
0
      if (skipping_duplicates)
453
0
        goto skip_to_next_name;
454
0
    }
455
0
    continue;
456
457
0
skip_to_next_name:
458
0
    {
459
0
      int j;
460
0
      struct cache_entry **cache = repo->index->cache;
461
0
      for (j = i + 1; j < repo->index->cache_nr; j++)
462
0
        if (strcmp(ce->name, cache[j]->name))
463
0
          break;
464
0
      i = j - 1; /* compensate for the for loop */
465
0
    }
466
0
  }
467
468
0
  strbuf_release(&fullname);
469
0
}
470
471
/*
472
 * Prune the index to only contain stuff starting with "prefix"
473
 */
474
static void prune_index(struct index_state *istate,
475
      const char *prefix, size_t prefixlen)
476
0
{
477
0
  int pos;
478
0
  unsigned int first, last;
479
480
0
  if (!prefix || !istate->cache_nr)
481
0
    return;
482
0
  pos = index_name_pos(istate, prefix, prefixlen);
483
0
  if (pos < 0)
484
0
    pos = -pos-1;
485
0
  first = pos;
486
0
  last = istate->cache_nr;
487
0
  while (last > first) {
488
0
    int next = first + ((last - first) >> 1);
489
0
    const struct cache_entry *ce = istate->cache[next];
490
0
    if (!strncmp(ce->name, prefix, prefixlen)) {
491
0
      first = next+1;
492
0
      continue;
493
0
    }
494
0
    last = next;
495
0
  }
496
0
  MOVE_ARRAY(istate->cache, istate->cache + pos, last - pos);
497
0
  istate->cache_nr = last - pos;
498
0
}
499
500
static int get_common_prefix_len(const char *common_prefix)
501
0
{
502
0
  int common_prefix_len;
503
504
0
  if (!common_prefix)
505
0
    return 0;
506
507
0
  common_prefix_len = strlen(common_prefix);
508
509
  /*
510
   * If the prefix has a trailing slash, strip it so that submodules wont
511
   * be pruned from the index.
512
   */
513
0
  if (common_prefix[common_prefix_len - 1] == '/')
514
0
    common_prefix_len--;
515
516
0
  return common_prefix_len;
517
0
}
518
519
static const char * const ls_files_usage[] = {
520
  N_("git ls-files [<options>] [<file>...]"),
521
  NULL
522
};
523
524
static int option_parse_exclude(const struct option *opt,
525
        const char *arg, int unset)
526
0
{
527
0
  struct string_list *exclude_list = opt->value;
528
529
0
  BUG_ON_OPT_NEG(unset);
530
531
0
  exc_given = 1;
532
0
  string_list_append(exclude_list, arg);
533
534
0
  return 0;
535
0
}
536
537
static int option_parse_exclude_from(const struct option *opt,
538
             const char *arg, int unset)
539
0
{
540
0
  struct dir_struct *dir = opt->value;
541
542
0
  BUG_ON_OPT_NEG(unset);
543
544
0
  exc_given = 1;
545
0
  add_patterns_from_file(dir, arg);
546
547
0
  return 0;
548
0
}
549
550
static int option_parse_exclude_standard(const struct option *opt,
551
           const char *arg, int unset)
552
0
{
553
0
  struct dir_struct *dir = opt->value;
554
555
0
  BUG_ON_OPT_NEG(unset);
556
0
  BUG_ON_OPT_ARG(arg);
557
558
0
  exc_given = 1;
559
0
  setup_standard_excludes(dir);
560
561
0
  return 0;
562
0
}
563
564
int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
565
0
{
566
0
  int require_work_tree = 0, show_tag = 0, i;
567
0
  char *max_prefix;
568
0
  struct dir_struct dir = DIR_INIT;
569
0
  struct pattern_list *pl;
570
0
  struct string_list exclude_list = STRING_LIST_INIT_NODUP;
571
0
  struct option builtin_ls_files_options[] = {
572
    /* Think twice before adding "--nul" synonym to this */
573
0
    OPT_SET_INT('z', NULL, &line_terminator,
574
0
      N_("separate paths with the NUL character"), '\0'),
575
0
    OPT_BOOL('t', NULL, &show_tag,
576
0
      N_("identify the file status with tags")),
577
0
    OPT_BOOL('v', NULL, &show_valid_bit,
578
0
      N_("use lowercase letters for 'assume unchanged' files")),
579
0
    OPT_BOOL('f', NULL, &show_fsmonitor_bit,
580
0
      N_("use lowercase letters for 'fsmonitor clean' files")),
581
0
    OPT_BOOL('c', "cached", &show_cached,
582
0
      N_("show cached files in the output (default)")),
583
0
    OPT_BOOL('d', "deleted", &show_deleted,
584
0
      N_("show deleted files in the output")),
585
0
    OPT_BOOL('m', "modified", &show_modified,
586
0
      N_("show modified files in the output")),
587
0
    OPT_BOOL('o', "others", &show_others,
588
0
      N_("show other files in the output")),
589
0
    OPT_BIT('i', "ignored", &dir.flags,
590
0
      N_("show ignored files in the output"),
591
0
      DIR_SHOW_IGNORED),
592
0
    OPT_BOOL('s', "stage", &show_stage,
593
0
      N_("show staged contents' object name in the output")),
594
0
    OPT_BOOL('k', "killed", &show_killed,
595
0
      N_("show files on the filesystem that need to be removed")),
596
0
    OPT_BIT(0, "directory", &dir.flags,
597
0
      N_("show 'other' directories' names only"),
598
0
      DIR_SHOW_OTHER_DIRECTORIES),
599
0
    OPT_BOOL(0, "eol", &show_eol, N_("show line endings of files")),
600
0
    OPT_NEGBIT(0, "empty-directory", &dir.flags,
601
0
      N_("don't show empty directories"),
602
0
      DIR_HIDE_EMPTY_DIRECTORIES),
603
0
    OPT_BOOL('u', "unmerged", &show_unmerged,
604
0
      N_("show unmerged files in the output")),
605
0
    OPT_BOOL(0, "resolve-undo", &show_resolve_undo,
606
0
          N_("show resolve-undo information")),
607
0
    OPT_CALLBACK_F('x', "exclude", &exclude_list, N_("pattern"),
608
0
      N_("skip files matching pattern"),
609
0
      PARSE_OPT_NONEG, option_parse_exclude),
610
0
    OPT_CALLBACK_F('X', "exclude-from", &dir, N_("file"),
611
0
      N_("read exclude patterns from <file>"),
612
0
      PARSE_OPT_NONEG, option_parse_exclude_from),
613
0
    OPT_STRING(0, "exclude-per-directory", &dir.exclude_per_dir, N_("file"),
614
0
      N_("read additional per-directory exclude patterns in <file>")),
615
0
    OPT_CALLBACK_F(0, "exclude-standard", &dir, NULL,
616
0
      N_("add the standard git exclusions"),
617
0
      PARSE_OPT_NOARG | PARSE_OPT_NONEG,
618
0
      option_parse_exclude_standard),
619
0
    OPT_SET_INT_F(0, "full-name", &prefix_len,
620
0
            N_("make the output relative to the project top directory"),
621
0
            0, PARSE_OPT_NONEG),
622
0
    OPT_BOOL(0, "recurse-submodules", &recurse_submodules,
623
0
      N_("recurse through submodules")),
624
0
    OPT_BOOL(0, "error-unmatch", &error_unmatch,
625
0
      N_("if any <file> is not in the index, treat this as an error")),
626
0
    OPT_STRING(0, "with-tree", &with_tree, N_("tree-ish"),
627
0
      N_("pretend that paths removed since <tree-ish> are still present")),
628
0
    OPT__ABBREV(&abbrev),
629
0
    OPT_BOOL(0, "debug", &debug_mode, N_("show debugging data")),
630
0
    OPT_BOOL(0, "deduplicate", &skipping_duplicates,
631
0
       N_("suppress duplicate entries")),
632
0
    OPT_BOOL(0, "sparse", &show_sparse_dirs,
633
0
       N_("show sparse directories in the presence of a sparse index")),
634
0
    OPT_STRING_F(0, "format", &format, N_("format"),
635
0
           N_("format to use for the output"),
636
0
           PARSE_OPT_NONEG),
637
0
    OPT_END()
638
0
  };
639
0
  int ret = 0;
640
641
0
  if (argc == 2 && !strcmp(argv[1], "-h"))
642
0
    usage_with_options(ls_files_usage, builtin_ls_files_options);
643
644
0
  prepare_repo_settings(the_repository);
645
0
  the_repository->settings.command_requires_full_index = 0;
646
647
0
  prefix = cmd_prefix;
648
0
  if (prefix)
649
0
    prefix_len = strlen(prefix);
650
0
  git_config(git_default_config, NULL);
651
652
0
  if (repo_read_index(the_repository) < 0)
653
0
    die("index file corrupt");
654
655
0
  argc = parse_options(argc, argv, prefix, builtin_ls_files_options,
656
0
      ls_files_usage, 0);
657
0
  pl = add_pattern_list(&dir, EXC_CMDL, "--exclude option");
658
0
  for (i = 0; i < exclude_list.nr; i++) {
659
0
    add_pattern(exclude_list.items[i].string, "", 0, pl, --exclude_args);
660
0
  }
661
662
0
  if (format && (show_stage || show_others || show_killed ||
663
0
    show_resolve_undo || skipping_duplicates || show_eol || show_tag))
664
0
      usage_msg_opt(_("--format cannot be used with -s, -o, -k, -t, "
665
0
              "--resolve-undo, --deduplicate, --eol"),
666
0
              ls_files_usage, builtin_ls_files_options);
667
668
0
  if (show_tag || show_valid_bit || show_fsmonitor_bit) {
669
0
    tag_cached = "H ";
670
0
    tag_unmerged = "M ";
671
0
    tag_removed = "R ";
672
0
    tag_modified = "C ";
673
0
    tag_other = "? ";
674
0
    tag_killed = "K ";
675
0
    tag_skip_worktree = "S ";
676
0
    tag_resolve_undo = "U ";
677
0
  }
678
0
  if (show_modified || show_others || show_deleted || (dir.flags & DIR_SHOW_IGNORED) || show_killed)
679
0
    require_work_tree = 1;
680
0
  if (show_unmerged)
681
    /*
682
     * There's no point in showing unmerged unless
683
     * you also show the stage information.
684
     */
685
0
    show_stage = 1;
686
0
  if (show_tag || show_stage)
687
0
    skipping_duplicates = 0;
688
0
  if (dir.exclude_per_dir)
689
0
    exc_given = 1;
690
691
0
  if (require_work_tree && !is_inside_work_tree())
692
0
    setup_work_tree();
693
694
0
  if (recurse_submodules &&
695
0
      (show_deleted || show_others || show_unmerged ||
696
0
       show_killed || show_modified || show_resolve_undo || with_tree))
697
0
    die("ls-files --recurse-submodules unsupported mode");
698
699
0
  if (recurse_submodules && error_unmatch)
700
0
    die("ls-files --recurse-submodules does not support "
701
0
        "--error-unmatch");
702
703
0
  parse_pathspec(&pathspec, 0,
704
0
           PATHSPEC_PREFER_CWD,
705
0
           prefix, argv);
706
707
  /*
708
   * Find common prefix for all pathspec's
709
   * This is used as a performance optimization which unfortunately cannot
710
   * be done when recursing into submodules because when a pathspec is
711
   * given which spans repository boundaries you can't simply remove the
712
   * submodule entry because the pathspec may match something inside the
713
   * submodule.
714
   */
715
0
  if (recurse_submodules)
716
0
    max_prefix = NULL;
717
0
  else
718
0
    max_prefix = common_prefix(&pathspec);
719
0
  max_prefix_len = get_common_prefix_len(max_prefix);
720
721
0
  prune_index(the_repository->index, max_prefix, max_prefix_len);
722
723
  /* Treat unmatching pathspec elements as errors */
724
0
  if (pathspec.nr && error_unmatch)
725
0
    ps_matched = xcalloc(pathspec.nr, 1);
726
727
0
  if ((dir.flags & DIR_SHOW_IGNORED) && !show_others && !show_cached)
728
0
    die("ls-files -i must be used with either -o or -c");
729
730
0
  if ((dir.flags & DIR_SHOW_IGNORED) && !exc_given)
731
0
    die("ls-files --ignored needs some exclude pattern");
732
733
  /* With no flags, we default to showing the cached files */
734
0
  if (!(show_stage || show_deleted || show_others || show_unmerged ||
735
0
        show_killed || show_modified || show_resolve_undo))
736
0
    show_cached = 1;
737
738
0
  if (with_tree) {
739
    /*
740
     * Basic sanity check; show-stages and show-unmerged
741
     * would not make any sense with this option.
742
     */
743
0
    if (show_stage || show_unmerged)
744
0
      die(_("options '%s' and '%s' cannot be used together"), "ls-files --with-tree", "-s/-u");
745
0
    overlay_tree_on_index(the_repository->index, with_tree, max_prefix);
746
0
  }
747
748
0
  show_files(the_repository, &dir);
749
750
0
  if (show_resolve_undo)
751
0
    show_ru_info(the_repository->index);
752
753
0
  if (ps_matched && report_path_error(ps_matched, &pathspec)) {
754
0
    fprintf(stderr, "Did you forget to 'git add'?\n");
755
0
    ret = 1;
756
0
  }
757
758
0
  string_list_clear(&exclude_list, 0);
759
0
  dir_clear(&dir);
760
0
  free(max_prefix);
761
0
  return ret;
762
0
}