Changes since 'pu' version: - refresh_index() in 09/21 is set not to show "XXX: needs merge" messages, cluttering "list-files -u" output - new patch 10/21 to add a default alias 'ls' to 'list-files', of course overridable by the user - fix "list-files -u" not showing anything because show_files_compact in 16/21 ignores show_unmerged flag - directory listing in 17/21 is rewritten to work filtering (e.g. -m, -M...) - new patch 21/21 adds tests for the series Nguyễn Thái Ngọc Duy (21): ls_colors.c: add $LS_COLORS parsing code ls_colors.c: parse color.ls.* from config file ls_colors.c: add a function to color a file name ls_colors.c: highlight submodules like directories ls-files: buffer full item in strbuf before printing ls-files: add --color to highlight file names ls-files: add --column ls-files: support --max-depth list-files: a user friendly version of ls-files and more list-files: make alias 'ls' default to 'list-files' list-files: -u does not imply showing stages list-files: add -R/--recursive short for --max-depth=-1 list-files: add -1 short for --no-column list-files: add -t back list-files: sort output and remove duplicates list-files: do not show duplicate cached entries list-files: show directories as well as files list-files: add -F/--classify list-files -F: show submodules with the new indicator '&' list-files: -M aka diff-cached t3080: tests for git-list-files Total diff against 'pu' is something like this -- 8< -- diff --git a/Documentation/git-list-files.txt b/Documentation/git-list-files.txt index c57129b..223f6fd 100644 --- a/Documentation/git-list-files.txt +++ b/Documentation/git-list-files.txt @@ -14,7 +14,8 @@ DESCRIPTION ----------- List files (by default in current working directory) that are in the index. Depending on the chosen options, maybe only modified files in -working tree are shown, or untracked files... +working tree are shown, or untracked files... The builtin alias "ls" +is set to "list-files". OPTIONS ------- diff --git a/builtin/ls-files.c b/builtin/ls-files.c index 02a9ac1..b04c712 100644 --- a/builtin/ls-files.c +++ b/builtin/ls-files.c @@ -213,6 +213,37 @@ static void show_killed_files(struct dir_struct *dir) } } +static int show_as_directory(const struct cache_entry *ce) +{ + struct strbuf sb = STRBUF_INIT; + const char *p; + + strbuf_add(&sb, ce->name, ce_namelen(ce)); + while (sb.len && (p = strrchr(sb.buf, '/')) != NULL) { + struct strbuf sb2 = STRBUF_INIT; + strbuf_setlen(&sb, p - sb.buf); + if (!match_pathspec(&pathspec, sb.buf, sb.len, + max_prefix_len, NULL, 1)) + continue; + write_name(&sb2, sb.buf); + if (want_color(use_color)) { + struct strbuf sb3 = STRBUF_INIT; + color_filename(&sb3, ce->name, sb2.buf, S_IFDIR, 1); + strbuf_release(&sb2); + sb2 = sb3; + } + if (show_tag) + strbuf_insert(&sb2, 0, tag_cached, strlen(tag_cached)); + if (show_indicator) + append_indicator(&sb2, S_IFDIR); + strbuf_fputs(&sb2, strbuf_detach(&sb, NULL), NULL); + strbuf_release(&sb2); + return 1; + } + strbuf_release(&sb); + return 0; +} + static void write_ce_name(struct strbuf *sb, const struct cache_entry *ce) { struct strbuf quoted = STRBUF_INIT; @@ -230,16 +261,31 @@ static void write_ce_name(struct strbuf *sb, const struct cache_entry *ce) static void show_ce_entry(const char *tag, const struct cache_entry *ce) { static struct strbuf sb = STRBUF_INIT; - int len = max_prefix_len; + int len = max_prefix_len, saved_max_depth; if (len >= ce_namelen(ce)) die("git ls-files: internal error - cache entry not superset of prefix"); + if (show_dirs) { + /* ignore depth to catch dirs that contain matched entries */ + saved_max_depth = pathspec.max_depth; + pathspec.max_depth = -1; + } + if (!match_pathspec(&pathspec, ce->name, ce_namelen(ce), len, ps_matched, S_ISDIR(ce->ce_mode) || S_ISGITLINK(ce->ce_mode))) return; + if (show_dirs) { + pathspec.max_depth = saved_max_depth; + if (strchr(ce->name, '/') && + !match_pathspec(&pathspec, ce->name, ce_namelen(ce), + prefix_len, NULL, 1) && + show_as_directory(ce)) + return; + } + if (tag && *tag && show_valid_bit && (ce->ce_flags & CE_VALID)) { static char alttag[4]; @@ -348,7 +394,7 @@ static void show_files(struct dir_struct *dir) (ce_skip_worktree(ce) ? tag_skip_worktree : tag_cached), ce); } } - if (show_deleted || show_modified || show_diff_cached) { + if (show_deleted || show_modified) { for (i = 0; i < active_nr; i++) { const struct cache_entry *ce = active_cache[i]; struct stat st; @@ -377,45 +423,6 @@ static void show_files(struct dir_struct *dir) } } -static void show_directories(const struct cache_entry *ce) -{ - static const char *last_directory; - struct strbuf sb = STRBUF_INIT; - const char *p = ce->name + prefix_len; - const char *sep; - - if (last_directory) { - int len = strlen(last_directory); - if (!strncmp(ce->name, last_directory, len) && - ce->name[len] == '/') - p += len + 1; - } - - while (*p && (sep = strchr(p, '/'))) { - struct strbuf sb2 = STRBUF_INIT; - strbuf_reset(&sb); - strbuf_add(&sb, ce->name, sep - ce->name); - p = sep + 1; - if (!match_pathspec(&pathspec, sb.buf, sb.len, - prefix_len, NULL, 1)) - continue; - write_name(&sb2, sb.buf); - if (want_color(use_color)) { - struct strbuf sb3 = STRBUF_INIT; - color_filename(&sb3, ce->name, sb2.buf, S_IFDIR, 1); - strbuf_release(&sb2); - sb2 = sb3; - } - if (show_tag) - strbuf_insert(&sb2, 0, tag_cached, strlen(tag_cached)); - if (show_indicator) - append_indicator(&sb2, S_IFDIR); - last_directory = strbuf_detach(&sb, NULL); - strbuf_fputs(&sb2, last_directory, NULL); - strbuf_release(&sb2); - } -} - static void show_files_compact(struct dir_struct *dir) { int i; @@ -430,14 +437,13 @@ static void show_files_compact(struct dir_struct *dir) if (show_killed) show_killed_files(dir); } - if (!(show_cached || show_stage || show_deleted || show_modified)) + if (!(show_cached || show_unmerged || show_deleted || + show_modified || show_diff_cached)) return; for (i = 0; i < active_nr; i++) { const struct cache_entry *ce = active_cache[i]; struct stat st; int err, shown = 0; - if (show_dirs) - show_directories(ce); if ((dir->flags & DIR_SHOW_IGNORED) && !ce_excluded(dir, ce)) continue; @@ -452,6 +458,15 @@ static void show_files_compact(struct dir_struct *dir) show_ce_entry(tag_removed, ce); shown = 1; } + if (show_diff_cached && (ce->ce_flags & CE_MATCHED)) { + show_ce_entry(tag_diff_cached, ce); + shown = 1; + /* + * if we don't clear, it'll confuse write_ce_name() + * when show_ce_entry(tag_modified, ce) is called + */ + active_cache[i]->ce_flags &= ~CE_MATCHED; + } if (show_modified && (err || ce_modified(ce, &st, 0))) { show_ce_entry(tag_modified, ce); shown = 1; @@ -817,7 +832,6 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix) use_color = -1; max_depth = 0; show_tag = -1; - show_dirs = 1; git_config(git_ls_config, NULL); } else git_config(git_default_config, NULL); @@ -866,6 +880,8 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix) prefix, argv); pathspec.max_depth = max_depth; pathspec.recursive = 1; + show_dirs = porcelain && max_depth != -1; + /* Find common prefix for all pathspec's */ max_prefix = common_prefix(&pathspec); @@ -911,7 +927,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix) overlay_tree_on_cache(with_tree, max_prefix); } if (porcelain) { - refresh_index(&the_index, REFRESH_QUIET, &pathspec, NULL, NULL); + refresh_index(&the_index, REFRESH_QUIET | REFRESH_UNMERGED, &pathspec, NULL, NULL); setup_pager(); } if (show_diff_cached) diff --git a/config.c b/config.c index 15a2983..16209c6 100644 --- a/config.c +++ b/config.c @@ -40,6 +40,10 @@ static struct config_source *cf; static int zlib_compression_seen; +static const char *builtin_config = + "[alias]\n" + " ls = list-files\n"; + /* * Default config_set that contains key-value pairs from the usual set of config * config files (i.e repo specific .git/config, user wide ~/.gitconfig, XDG @@ -1175,6 +1179,10 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config) home_config_paths(&user_config, &xdg_config, "config"); + if (git_config_system()) + git_config_from_buf(fn, "<builtin>", builtin_config, + strlen(builtin_config), data); + if (git_config_system() && !access_or_die(git_etc_gitconfig(), R_OK, 0)) { ret += git_config_from_file(fn, git_etc_gitconfig(), data); diff --git a/t/t3080-list-files.sh b/t/t3080-list-files.sh new file mode 100755 index 0000000..6313dd9 --- /dev/null +++ b/t/t3080-list-files.sh @@ -0,0 +1,122 @@ +#!/bin/sh + +test_description='git list-files test' + +. ./test-lib.sh + +test_expect_success 'setup' ' + mkdir dir && + touch file dir/file && + git init gitlink && + ( cd gitlink && test_commit foo ) && + git add file dir/file gitlink && + git commit -qm1 +' + +test_expect_success 'LS_COLORS env variable' ' + LS_COLORS="rs=0:fi=31:di=32" \ + git list-files --color=always | grep -v gitlink >actual && + test_cmp "$TEST_DIRECTORY"/t3080/ls_colors actual +' + +test_expect_success 'color.ls.*' ' + test_config color.ls.file red && + test_config color.ls.directory green && + test_config color.ls.submodule yellow && + git list-files --color=always >actual && + test_cmp "$TEST_DIRECTORY"/t3080/color_ls actual +' + +test_expect_success 'column output' ' + COLUMNS=20 git list-files --column=always >actual && + cat >expected <<-\EOF && + dir gitlink + file + EOF + test_cmp expected actual && + git list-files -1 >actual && + cat >expected <<-\EOF && + dir + file + gitlink + EOF + test_cmp expected actual +' + +test_expect_success '--max-depth' ' + git list-files --max-depth=1 >actual && + cat >expected <<-\EOF && + dir/file + file + gitlink + EOF + test_cmp expected actual +' + +test_expect_success 'recursive' ' + git list-files -R >actual && + cat >expected <<-\EOF && + dir/file + file + gitlink + EOF + test_cmp expected actual +' + +test_expect_success 'globbing' ' + git list-files "f*" >actual && + cat >expected <<-\EOF && + file + EOF + test_cmp expected actual && + git list-files "**/f*" >actual && + cat >expected <<-\EOF && + dir/file + file + EOF + test_cmp expected actual +' + +test_expect_success 'no dups' ' + echo dirty >>file && + git list-files -m file >actual && + echo "file" >expected && + test_cmp expected actual && + git list-files -cm file >actual && + echo "C file" >expected && + test_cmp expected actual && + git list-files -tcm file >actual && + test_cmp expected actual +' + +test_expect_success '--classify' ' + git list-files -F >actual && + cat >expected <<-\EOF && + dir/ + file + gitlink& + EOF + test_cmp expected actual +' + +test_expect_success 'diff-cached' ' + echo dirty >>file && + git add file && + git list-files -M >actual && + echo "file" >expected && + test_cmp expected actual +' + +test_expect_success 'unmerged files' ' + git ls-files --stage file >index-info && + sed "s/ 0/ 2/;s/file/unmerged/" index-info | git update-index --index-info && + sed "s/ 0/ 3/;s,file,dir/unmerged," index-info | git update-index --index-info && + git list-files -u >actual && + cat >expected <<-\EOF && + dir + unmerged + EOF + test_cmp expected actual +' + +test_done diff --git a/t/t3080/color_ls b/t/t3080/color_ls new file mode 100644 index 0000000..47f77ad --- /dev/null +++ b/t/t3080/color_ls @@ -0,0 +1,3 @@ +[32mdir[m +[31mfile[m +[33mgitlink[m diff --git a/t/t3080/ls_colors b/t/t3080/ls_colors new file mode 100644 index 0000000..423c016 --- /dev/null +++ b/t/t3080/ls_colors @@ -0,0 +1,2 @@ +[32mdir[m +[31mfile[m -- 8< -- -- 2.2.0.84.ge9c7a8a -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html