Skip to content

Commit e385ef2

Browse files
author
hufei.005
committed
Fix slow tig status when given a subdirectory path
1 parent 70435f8 commit e385ef2

3 files changed

Lines changed: 106 additions & 16 deletions

File tree

include/tig/git.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,10 @@
3838
/* Don't show staged unmerged entries. */
3939
#define GIT_DIFF_STAGED_FILES(output_arg) \
4040
"git", "diff-index", (output_arg), "%(cmdlineargs)", "--diff-filter=ACDMRTXB", \
41-
"-C", "--cached", "HEAD", "--", NULL
41+
"-C", "--cached", "HEAD", "--", "%(fileargs)", NULL
4242

4343
#define GIT_DIFF_UNSTAGED_FILES(output_arg) \
44-
"git", "diff-files", (output_arg), "%(cmdlineargs)", NULL
44+
"git", "diff-files", (output_arg), "%(cmdlineargs)", "--", "%(fileargs)", NULL
4545

4646
#define GIT_DIFF_BLAME(encoding_arg, context_arg, prefix_arg, space_arg, word_diff_arg, new_name) \
4747
"git", "diff-files", (encoding_arg), "--textconv", "--patch-with-stat", "-C", \

src/status.c

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
* GNU General Public License for more details.
1212
*/
1313

14+
#include "tig/argv.h"
1415
#include "tig/io.h"
1516
#include "tig/refdb.h"
1617
#include "tig/repo.h"
@@ -92,8 +93,14 @@ status_run(struct view *view, const char *argv[], char status, enum line_type ty
9293
struct buffer buf;
9394
struct io io;
9495
const char **status_argv = NULL;
95-
bool ok = argv_format(view->env, &status_argv, argv, 0) &&
96-
io_run(&io, IO_RD, repo.exec_dir, NULL, status_argv);
96+
int format_flags = 0;
97+
bool ok;
98+
99+
if (!view_has_flags(view, VIEW_FILE_FILTER) || opt_file_filter)
100+
format_flags |= argv_flag_file_filter;
101+
102+
ok = argv_format(view->env, &status_argv, argv, format_flags) &&
103+
io_run(&io, IO_RD, repo.exec_dir, NULL, status_argv);
97104

98105
argv_free(status_argv);
99106
free(status_argv);
@@ -188,12 +195,8 @@ status_run(struct view *view, const char *argv[], char status, enum line_type ty
188195
static const char *status_diff_index_argv[] = { GIT_DIFF_STAGED_FILES("-z") };
189196
static const char *status_diff_files_argv[] = { GIT_DIFF_UNSTAGED_FILES("-z") };
190197

191-
static const char *status_list_other_argv[] = {
192-
"git", "ls-files", "-z", "--others", "--exclude-standard", NULL, NULL, NULL
193-
};
194-
195198
static const char *status_list_no_head_argv[] = {
196-
"git", "ls-files", "-z", "--cached", "--exclude-standard", NULL
199+
"git", "ls-files", "-z", "--cached", "--exclude-standard", "%(fileargs)", NULL
197200
};
198201

199202
/* Restore the previous line number to stay in the context or select a
@@ -361,16 +364,26 @@ status_update_onbranch(void)
361364
static bool
362365
status_read_untracked(struct view *view)
363366
{
367+
const char *argv[16];
368+
int argc = 0;
369+
364370
if (!opt_status_show_untracked_files)
365371
return add_line_nodata(view, LINE_STAT_UNTRACKED)
366372
&& add_line_nodata(view, LINE_STAT_NONE);
367373

368-
status_list_other_argv[ARRAY_SIZE(status_list_other_argv) - 3] =
369-
opt_status_show_untracked_dirs ? NULL : "--directory";
370-
status_list_other_argv[ARRAY_SIZE(status_list_other_argv) - 2] =
371-
opt_status_show_untracked_dirs ? NULL : "--no-empty-directory";
374+
argv[argc++] = "git";
375+
argv[argc++] = "ls-files";
376+
argv[argc++] = "-z";
377+
argv[argc++] = "--others";
378+
argv[argc++] = "--exclude-standard";
379+
if (!opt_status_show_untracked_dirs) {
380+
argv[argc++] = "--directory";
381+
argv[argc++] = "--no-empty-directory";
382+
}
383+
argv[argc++] = "%(fileargs)";
384+
argv[argc] = NULL;
372385

373-
return status_run(view, status_list_other_argv, '?', LINE_STAT_UNTRACKED);
386+
return status_run(view, argv, '?', LINE_STAT_UNTRACKED);
374387
}
375388

376389
/* First parse staged info using git-diff-index(1), then parse unstaged
@@ -394,7 +407,8 @@ status_open(struct view *view, enum open_flags flags)
394407
add_line_nodata(view, LINE_HEADER);
395408
status_update_onbranch();
396409

397-
update_index();
410+
if (!opt_file_args || !opt_file_filter)
411+
update_index();
398412

399413
if ((!show_untracked_only && !status_run(view, staged_argv, staged_status, LINE_STAT_STAGED)) ||
400414
(!show_untracked_only && !status_run(view, status_diff_files_argv, 0, LINE_STAT_UNSTAGED)) ||
@@ -865,7 +879,7 @@ status_select(struct view *view, struct line *line)
865879
static struct view_ops status_ops = {
866880
"file",
867881
"",
868-
VIEW_CUSTOM_STATUS | VIEW_SEND_CHILD_ENTER | VIEW_STATUS_LIKE | VIEW_REFRESH,
882+
VIEW_CUSTOM_STATUS | VIEW_SEND_CHILD_ENTER | VIEW_STATUS_LIKE | VIEW_FILE_FILTER | VIEW_REFRESH,
869883
0,
870884
status_open,
871885
NULL,

test/status/file-filter-test

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
#!/bin/sh
2+
3+
. libtest.sh
4+
. libgit.sh
5+
6+
export LINES=15
7+
export COLUMNS=120
8+
9+
# This test uses the trace output so do not show trace for this test.
10+
trace=
11+
export TIG_TRACE="$HOME/trace"
12+
13+
test_setup_work_dir()
14+
{
15+
git_init .
16+
17+
git_add subdir/staged <<EOF
18+
staged in subdir
19+
EOF
20+
21+
git_add other/staged <<EOF
22+
staged in other
23+
EOF
24+
25+
git_commit -m "Initial commit"
26+
git branch -M master
27+
28+
printf 'unstaged in subdir\n' >> subdir/staged
29+
printf 'unstaged in other\n' >> other/staged
30+
touch -- subdir/untracked other/untracked
31+
}
32+
33+
test_case 'status-path-filter' \
34+
--args='status subdir' \
35+
<<EXPECTED_SCREEN
36+
On branch master
37+
Changes to be committed:
38+
(no files)
39+
Changes not staged for commit:
40+
M subdir/staged
41+
Untracked files:
42+
? subdir/untracked
43+
44+
45+
[status] Press u to stage 'subdir/staged' for commit 100%
46+
EXPECTED_SCREEN
47+
48+
run_test_cases
49+
50+
grep 'git rev-parse' < "$TIG_TRACE" > rev-parse.trace
51+
grep 'git diff-index' < "$TIG_TRACE" > diff-index.trace
52+
grep 'git diff-files' < "$TIG_TRACE" > diff-files.trace
53+
grep 'git ls-files' < "$TIG_TRACE" > ls-files.trace
54+
55+
if grep -q 'update-index' < "$TIG_TRACE"; then
56+
die "update-index should not run when status is path-filtered"
57+
fi
58+
59+
assert_equals 'rev-parse.trace' <<EOF
60+
git rev-parse --no-revs --no-flags subdir
61+
git rev-parse --flags --no-revs subdir
62+
git rev-parse --symbolic --revs-only subdir
63+
git rev-parse --git-dir --is-inside-work-tree --show-cdup --show-prefix HEAD --symbolic-full-name HEAD
64+
EOF
65+
66+
assert_equals 'diff-index.trace' <<EOF
67+
git diff-index -z --diff-filter=ACDMRTXB -C --cached HEAD -- subdir
68+
EOF
69+
70+
assert_equals 'diff-files.trace' <<EOF
71+
git diff-files -z -- subdir
72+
EOF
73+
74+
assert_equals 'ls-files.trace' <<EOF
75+
git ls-files -z --others --exclude-standard subdir
76+
EOF

0 commit comments

Comments
 (0)