Merge branch 'jn/fast-import-empty-tree-removal' into maint
authorJunio C Hamano <gitster@pobox.com>
Thu, 27 Jan 2011 18:23:53 +0000 (10:23 -0800)
committerJunio C Hamano <gitster@pobox.com>
Thu, 27 Jan 2011 18:23:53 +0000 (10:23 -0800)
* jn/fast-import-empty-tree-removal:
fast-import: treat filemodify with empty tree as delete

1  2 
fast-import.c
t/t9300-fast-import.sh
diff --combined fast-import.c
index 613623be14c4c647e11b20fefb382b3f7438fb3c,cd9310d1e5a5ac0cc6edf83c93c5f254fd579f64..7563e43a39c4d4573218fab52ffbf64a255f2562
@@@ -539,17 -539,22 +539,17 @@@ static struct object_entry *insert_obje
  {
        unsigned int h = sha1[0] << 8 | sha1[1];
        struct object_entry *e = object_table[h];
 -      struct object_entry *p = NULL;
  
        while (e) {
                if (!hashcmp(sha1, e->idx.sha1))
                        return e;
 -              p = e;
                e = e->next;
        }
  
        e = new_object(sha1);
 -      e->next = NULL;
 +      e->next = object_table[h];
        e->idx.offset = 0;
 -      if (p)
 -              p->next = e;
 -      else
 -              object_table[h] = e;
 +      object_table[h] = e;
        return e;
  }
  
@@@ -1523,14 -1528,6 +1523,14 @@@ static int tree_content_remove
        for (i = 0; i < t->entry_count; i++) {
                e = t->entries[i];
                if (e->name->str_len == n && !strncmp(p, e->name->str_dat, n)) {
 +                      if (slash1 && !S_ISDIR(e->versions[1].mode))
 +                              /*
 +                               * If p names a file in some subdirectory, and a
 +                               * file or symlink matching the name of the
 +                               * parent directory of p exists, then p cannot
 +                               * exist and need not be deleted.
 +                               */
 +                              return 1;
                        if (!slash1 || !S_ISDIR(e->versions[1].mode))
                                goto del_entry;
                        if (!e->tree)
@@@ -1669,7 -1666,7 +1669,7 @@@ static void dump_marks_helper(FILE *f
        if (m->shift) {
                for (k = 0; k < 1024; k++) {
                        if (m->data.sets[k])
 -                              dump_marks_helper(f, (base + k) << m->shift,
 +                              dump_marks_helper(f, base + (k << m->shift),
                                        m->data.sets[k]);
                }
        } else {
@@@ -2166,6 -2163,12 +2166,12 @@@ static void file_change_m(struct branc
                p = uq.buf;
        }
  
+       /* Git does not track empty, non-toplevel directories. */
+       if (S_ISDIR(mode) && !memcmp(sha1, EMPTY_TREE_SHA1_BIN, 20) && *p) {
+               tree_content_remove(&b->branch_tree, p, NULL);
+               return;
+       }
        if (S_ISGITLINK(mode)) {
                if (inline_data)
                        die("Git links cannot be specified 'inline': %s",
@@@ -2879,7 -2882,7 +2885,7 @@@ static int git_pack_config(const char *
  }
  
  static const char fast_import_usage[] =
 -"git fast-import [--date-format=f] [--max-pack-size=n] [--big-file-threshold=n] [--depth=n] [--active-branches=n] [--export-marks=marks.file]";
 +"git fast-import [--date-format=<f>] [--max-pack-size=<n>] [--big-file-threshold=<n>] [--depth=<n>] [--active-branches=<n>] [--export-marks=<marks.file>]";
  
  static void parse_argv(void)
  {
diff --combined t/t9300-fast-import.sh
index 7c059204e90722db20bae1d10a0988853f852262,8487734ada77b4667c89665d255886c59cff8b22..385e78c22c0e00b9e81117a5ed7378298460c47b
@@@ -166,63 -166,6 +166,63 @@@ test_expect_success 
         test `git rev-parse --verify master:file2` \
            = `git rev-parse --verify verify--import-marks:copy-of-file2`'
  
 +test_tick
 +mt=$(git hash-object --stdin < /dev/null)
 +: >input.blob
 +: >marks.exp
 +: >tree.exp
 +
 +cat >input.commit <<EOF
 +commit refs/heads/verify--dump-marks
 +committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
 +data <<COMMIT
 +test the sparse array dumping routines with exponentially growing marks
 +COMMIT
 +EOF
 +
 +i=0
 +l=4
 +m=6
 +n=7
 +while test "$i" -lt 27; do
 +    cat >>input.blob <<EOF
 +blob
 +mark :$l
 +data 0
 +blob
 +mark :$m
 +data 0
 +blob
 +mark :$n
 +data 0
 +EOF
 +    echo "M 100644 :$l l$i" >>input.commit
 +    echo "M 100644 :$m m$i" >>input.commit
 +    echo "M 100644 :$n n$i" >>input.commit
 +
 +    echo ":$l $mt" >>marks.exp
 +    echo ":$m $mt" >>marks.exp
 +    echo ":$n $mt" >>marks.exp
 +
 +    printf "100644 blob $mt\tl$i\n" >>tree.exp
 +    printf "100644 blob $mt\tm$i\n" >>tree.exp
 +    printf "100644 blob $mt\tn$i\n" >>tree.exp
 +
 +    l=$(($l + $l))
 +    m=$(($m + $m))
 +    n=$(($l + $n))
 +
 +    i=$((1 + $i))
 +done
 +
 +sort tree.exp > tree.exp_s
 +
 +test_expect_success 'A: export marks with large values' '
 +      cat input.blob input.commit | git fast-import --export-marks=marks.large &&
 +      git ls-tree refs/heads/verify--dump-marks >tree.out &&
 +      test_cmp tree.exp_s tree.out &&
 +      test_cmp marks.exp marks.large'
 +
  ###
  ### series B
  ###
@@@ -874,6 -817,48 +874,48 @@@ test_expect_success 
         git diff-tree -C --find-copies-harder -r N4^ N4 >actual &&
         compare_diff_raw expect actual'
  
+ test_expect_success \
+       'N: delete directory by copying' \
+       'cat >expect <<-\EOF &&
+       OBJID
+       :100644 000000 OBJID OBJID D    foo/bar/qux
+       OBJID
+       :000000 100644 OBJID OBJID A    foo/bar/baz
+       :000000 100644 OBJID OBJID A    foo/bar/qux
+       EOF
+        empty_tree=$(git mktree </dev/null) &&
+        cat >input <<-INPUT_END &&
+       commit refs/heads/N-delete
+       committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+       data <<COMMIT
+       collect data to be deleted
+       COMMIT
+       deleteall
+       M 100644 inline foo/bar/baz
+       data <<DATA_END
+       hello
+       DATA_END
+       C "foo/bar/baz" "foo/bar/qux"
+       C "foo/bar/baz" "foo/bar/quux/1"
+       C "foo/bar/baz" "foo/bar/quuux"
+       M 040000 $empty_tree foo/bar/quux
+       M 040000 $empty_tree foo/bar/quuux
+       commit refs/heads/N-delete
+       committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+       data <<COMMIT
+       delete subdirectory
+       COMMIT
+       M 040000 $empty_tree foo/bar/qux
+       INPUT_END
+        git fast-import <input &&
+        git rev-list N-delete |
+               git diff-tree -r --stdin --root --always |
+               sed -e "s/$_x40/OBJID/g" >actual &&
+        test_cmp expect actual'
  test_expect_success \
        'N: modify copied tree' \
        'cat >expect <<-\EOF &&
@@@ -1110,10 -1095,11 +1152,10 @@@ test_expect_success 
        'P: supermodule & submodule mix' \
        'git fast-import <input &&
         git checkout subuse1 &&
 -       rm -rf sub && mkdir sub && cd sub &&
 +       rm -rf sub && mkdir sub && (cd sub &&
         git init &&
         git fetch --update-head-ok .. refs/heads/sub:refs/heads/master &&
 -       git checkout master &&
 -       cd .. &&
 +       git checkout master) &&
         git submodule init &&
         git submodule update'