Merge branch 'jc/ls-files-killed-optim'
authorJunio C Hamano <gitster@pobox.com>
Wed, 11 Sep 2013 22:03:28 +0000 (11 15:03 -0700)
committerJunio C Hamano <gitster@pobox.com>
Wed, 11 Sep 2013 22:03:28 +0000 (11 15:03 -0700)
"git ls-files -k" needs to crawl only the part of the working tree
that may overlap the paths in the index to find killed files, but
shared code with the logic to find all the untracked files, which
made it unnecessarily inefficient.

* jc/ls-files-killed-optim:
  dir.c::test_one_path(): work around directory_exists_in_index_icase() breakage
  t3010: update to demonstrate "ls-files -k" optimization pitfalls
  ls-files -k: a directory only can be killed if the index has a non-directory
  dir.c: use the cache_* macro to access the current index

1  2 
builtin/ls-files.c
dir.c
dir.h
t/t3010-ls-files-killed-modified.sh

@@@ -220,7 -213,9 +220,9 @@@ static void show_files(struct dir_struc
  
        /* For cached/deleted files we don't need to even do the readdir */
        if (show_others || show_killed) {
 -              fill_directory(dir, pathspec);
+               if (!show_others)
+                       dir->flags |= DIR_COLLECT_KILLED_ONLY;
 +              fill_directory(dir, &pathspec);
                if (show_others)
                        show_other_files(dir);
                if (show_killed)
diff --cc dir.c
--- 1/dir.c
--- 2/dir.c
+++ b/dir.c
@@@ -890,7 -929,7 +889,7 @@@ enum exist_status 
   */
  static enum exist_status directory_exists_in_index_icase(const char *dirname, int len)
  {
-       const struct cache_entry *ce = index_name_exists(&the_index, dirname, len + 1, ignore_case);
 -      struct cache_entry *ce = cache_name_exists(dirname, len + 1, ignore_case);
++      const struct cache_entry *ce = cache_name_exists(dirname, len + 1, ignore_case);
        unsigned char endchar;
  
        if (!ce)
diff --cc dir.h
Simple merge
@@@ -11,8 -11,7 +11,9 @@@ This test prepares the following in th
      path1       - a symlink
      path2/file2 - a file in a directory
      path3/file3 - a file in a directory
+     pathx/ju    - a file in a directory
 +    submod1/  - a submodule
 +    submod2/  - another submodule
  
  and the following on the filesystem:
  
      path4     - a file
      path5     - a symlink
      path6/file6 - a file in a directory
+     pathx/ju/nk - a file in a directory to be killed
 +    submod1/  - a submodule (modified from the cache)
 +    submod2/  - a submodule (matches the cache)
  
 -git ls-files -k should report that existing filesystem
 -objects except path4, path5 and path6/file6 to be killed.
 +git ls-files -k should report that existing filesystem objects
 +path0/*, path1/*, path2 and path3 to be killed.
  
  Also for modification test, the cache and working tree have:
  
@@@ -41,78 -39,78 +43,87 @@@ modified without reporting path9 and pa
  '
  . ./test-lib.sh
  
 -date >path0
 -if test_have_prereq SYMLINKS
 -then
 -      ln -s xyzzy path1
 -else
 -      date > path1
 -fi
 -mkdir path2 path3 pathx
 -date >path2/file2
 -date >path3/file3
 ->pathx/ju
 -: >path7
 -date >path8
 -: >path9
 -date >path10
 -test_expect_success \
 -    'git update-index --add to add various paths.' \
 -    "git update-index --add -- path0 path1 path?/file? pathx/ju path7 path8 path9 path10"
 -
 -rm -fr path? ;# leave path10 alone
 -date >path2
 -if test_have_prereq SYMLINKS
 -then
 -      ln -s frotz path3
 -      ln -s nitfol path5
 -else
 -      date > path3
 -      date > path5
 -fi
 -mkdir -p path0 path1 path6 pathx/ju
 -date >path0/file0
 -date >path1/file1
 -date >path6/file6
 -date >path7
 -: >path8
 -: >path9
 -touch path10
 ->pathx/ju/nk
 -
 -cat >.expected <<EOF
 -path0/file0
 -path1/file1
 -path2
 -path3
 -pathx/ju/nk
 -EOF
 -
 -test_expect_success 'git ls-files -k to show killed files (w/o icase)' '
 -    git ls-files -k >.output &&
 -    test_cmp .expected .output
 +test_expect_success 'git update-index --add to add various paths.' '
 +      date >path0 &&
 +      test_ln_s_add xyzzy path1 &&
-       mkdir path2 path3 &&
++      mkdir path2 path3 pathx &&
 +      date >path2/file2 &&
 +      date >path3/file3 &&
++      >pathx/ju &&
 +      : >path7 &&
 +      date >path8 &&
 +      : >path9 &&
 +      date >path10 &&
-       git update-index --add -- path0 path?/file? path7 path8 path9 path10 &&
++      git update-index --add -- path0 path?/file? pathx/ju path7 path8 path9 path10 &&
 +      for i in 1 2
 +      do
 +              git init submod$i &&
 +              (
 +                      cd submod$i && git commit --allow-empty -m "empty $i"
 +              ) || break
 +      done &&
 +      git update-index --add submod[12]
 +      (
 +              cd submod1 &&
 +              git commit --allow-empty -m "empty 1 (updated)"
 +      ) &&
 +      rm -fr path?    # leave path10 alone
  '
  
 -test_expect_success 'git ls-files -k to show killed files (w/ icase)' '
 -    git -c core.ignorecase=true ls-files -k >.output &&
 -    test_cmp .expected .output
 +test_expect_success 'git ls-files -k to show killed files.' '
 +      date >path2 &&
 +      if test_have_prereq SYMLINKS
 +      then
 +              ln -s frotz path3 &&
 +              ln -s nitfol path5
 +      else
 +              date >path3 &&
 +              date >path5
 +      fi &&
-       mkdir path0 path1 path6 &&
++      mkdir -p path0 path1 path6 pathx/ju &&
 +      date >path0/file0 &&
 +      date >path1/file1 &&
 +      date >path6/file6 &&
 +      date >path7 &&
 +      : >path8 &&
 +      : >path9 &&
 +      touch path10 &&
-       git ls-files -k >.output
- '
- test_expect_success 'validate git ls-files -k output.' '
-       cat >.expected <<-\EOF &&
++      >pathx/ju/nk &&
++      cat >.expected <<-\EOF
 +      path0/file0
 +      path1/file1
 +      path2
 +      path3
++      pathx/ju/nk
 +      EOF
+ '
 -test_expect_success \
 -    'git ls-files -m to show modified files.' \
 -    'git ls-files -m >.output'
 -cat >.expected <<EOF
 -path0
 -path1
 -path2/file2
 -path3/file3
 -path7
 -path8
 -pathx/ju
 -EOF
 -
 -test_expect_success \
 -    'validate git ls-files -m output.' \
 -    'test_cmp .expected .output'
++test_expect_success 'git ls-files -k output (w/o icase)' '
++      git ls-files -k >.output
++      test_cmp .expected .output
++'
++
++test_expect_success 'git ls-files -k output (w/ icase)' '
++      git -c core.ignorecase=true ls-files -k >.output
 +      test_cmp .expected .output
 +'
 +
 +test_expect_success 'git ls-files -m to show modified files.' '
 +      git ls-files -m >.output
 +'
 +
 +test_expect_success 'validate git ls-files -m output.' '
 +      cat >.expected <<-\EOF &&
 +      path0
 +      path1
 +      path2/file2
 +      path3/file3
 +      path7
 +      path8
++      pathx/ju
 +      submod1
 +      EOF
 +      test_cmp .expected .output
 +'
  
  test_done