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