Merge branch 'jk/fast-import-empty-ls'
authorJunio C Hamano <gitster@pobox.com>
Wed, 4 Sep 2013 19:23:35 +0000 (12:23 -0700)
committerJunio C Hamano <gitster@pobox.com>
Wed, 4 Sep 2013 19:23:35 +0000 (12:23 -0700)
* jk/fast-import-empty-ls:
fast-import: allow moving the root tree
fast-import: allow ls or filecopy of the root tree
fast-import: set valid mode on root tree in "ls"
t9300: document fast-import empty path issues

fast-import.c
t/t9300-fast-import.sh
index 23f625f561dfd664a460827d507e7c0b720e9849..21db3fc46d58231fd1345d65ae6cf1104901e55e 100644 (file)
@@ -1568,7 +1568,8 @@ static int tree_content_set(
 static int tree_content_remove(
        struct tree_entry *root,
        const char *p,
-       struct tree_entry *backup_leaf)
+       struct tree_entry *backup_leaf,
+       int allow_root)
 {
        struct tree_content *t;
        const char *slash1;
@@ -1583,6 +1584,12 @@ static int tree_content_remove(
 
        if (!root->tree)
                load_tree(root);
+
+       if (!*p && allow_root) {
+               e = root;
+               goto del_entry;
+       }
+
        t = root->tree;
        for (i = 0; i < t->entry_count; i++) {
                e = t->entries[i];
@@ -1599,7 +1606,7 @@ static int tree_content_remove(
                                goto del_entry;
                        if (!e->tree)
                                load_tree(e);
-                       if (tree_content_remove(e, slash1 + 1, backup_leaf)) {
+                       if (tree_content_remove(e, slash1 + 1, backup_leaf, 0)) {
                                for (n = 0; n < e->tree->entry_count; n++) {
                                        if (e->tree->entries[n]->versions[1].mode) {
                                                hashclr(root->versions[1].sha1);
@@ -1629,7 +1636,8 @@ static int tree_content_remove(
 static int tree_content_get(
        struct tree_entry *root,
        const char *p,
-       struct tree_entry *leaf)
+       struct tree_entry *leaf,
+       int allow_root)
 {
        struct tree_content *t;
        const char *slash1;
@@ -1641,31 +1649,39 @@ static int tree_content_get(
                n = slash1 - p;
        else
                n = strlen(p);
-       if (!n)
+       if (!n && !allow_root)
                die("Empty path component found in input");
 
        if (!root->tree)
                load_tree(root);
+
+       if (!n) {
+               e = root;
+               goto found_entry;
+       }
+
        t = root->tree;
        for (i = 0; i < t->entry_count; i++) {
                e = t->entries[i];
                if (e->name->str_len == n && !strncmp_icase(p, e->name->str_dat, n)) {
-                       if (!slash1) {
-                               memcpy(leaf, e, sizeof(*leaf));
-                               if (e->tree && is_null_sha1(e->versions[1].sha1))
-                                       leaf->tree = dup_tree_content(e->tree);
-                               else
-                                       leaf->tree = NULL;
-                               return 1;
-                       }
+                       if (!slash1)
+                               goto found_entry;
                        if (!S_ISDIR(e->versions[1].mode))
                                return 0;
                        if (!e->tree)
                                load_tree(e);
-                       return tree_content_get(e, slash1 + 1, leaf);
+                       return tree_content_get(e, slash1 + 1, leaf, 0);
                }
        }
        return 0;
+
+found_entry:
+       memcpy(leaf, e, sizeof(*leaf));
+       if (e->tree && is_null_sha1(e->versions[1].sha1))
+               leaf->tree = dup_tree_content(e->tree);
+       else
+               leaf->tree = NULL;
+       return 1;
 }
 
 static int update_branch(struct branch *b)
@@ -2179,7 +2195,7 @@ static uintmax_t do_change_note_fanout(
                        }
 
                        /* Rename fullpath to realpath */
-                       if (!tree_content_remove(orig_root, fullpath, &leaf))
+                       if (!tree_content_remove(orig_root, fullpath, &leaf, 0))
                                die("Failed to remove path %s", fullpath);
                        tree_content_set(orig_root, realpath,
                                leaf.versions[1].sha1,
@@ -2314,7 +2330,7 @@ static void file_change_m(struct branch *b)
 
        /* 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);
+               tree_content_remove(&b->branch_tree, p, NULL, 0);
                return;
        }
 
@@ -2375,7 +2391,7 @@ static void file_change_d(struct branch *b)
                        die("Garbage after path in: %s", command_buf.buf);
                p = uq.buf;
        }
-       tree_content_remove(&b->branch_tree, p, NULL);
+       tree_content_remove(&b->branch_tree, p, NULL, 1);
 }
 
 static void file_change_cr(struct branch *b, int rename)
@@ -2413,9 +2429,9 @@ static void file_change_cr(struct branch *b, int rename)
 
        memset(&leaf, 0, sizeof(leaf));
        if (rename)
-               tree_content_remove(&b->branch_tree, s, &leaf);
+               tree_content_remove(&b->branch_tree, s, &leaf, 1);
        else
-               tree_content_get(&b->branch_tree, s, &leaf);
+               tree_content_get(&b->branch_tree, s, &leaf, 1);
        if (!leaf.versions[1].mode)
                die("Path %s not in branch", s);
        if (!*d) {      /* C "path/to/subdir" "" */
@@ -2521,7 +2537,7 @@ static void note_change_n(struct branch *b, unsigned char *old_fanout)
        }
 
        construct_path_with_fanout(sha1_to_hex(commit_sha1), *old_fanout, path);
-       if (tree_content_remove(&b->branch_tree, path, NULL))
+       if (tree_content_remove(&b->branch_tree, path, NULL, 0))
                b->num_notes--;
 
        if (is_null_sha1(sha1))
@@ -3051,6 +3067,8 @@ static void parse_ls(struct branch *b)
                struct object_entry *e = parse_treeish_dataref(&p);
                root = new_tree_entry();
                hashcpy(root->versions[1].sha1, e->idx.sha1);
+               if (!is_null_sha1(root->versions[1].sha1))
+                       root->versions[1].mode = S_IFDIR;
                load_tree(root);
                if (*p++ != ' ')
                        die("Missing space after tree-ish: %s", command_buf.buf);
@@ -3065,7 +3083,7 @@ static void parse_ls(struct branch *b)
                        die("Garbage after path in: %s", command_buf.buf);
                p = uq.buf;
        }
-       tree_content_get(root, p, &leaf);
+       tree_content_get(root, p, &leaf, 1);
        /*
         * A directory in preparation would have a sha1 of zero
         * until it is saved.  Save, for simplicity.
index ac6f3b6af25c67ae3a2c0748c34f99b4cd0d4b32..31a770d9bc58d7c01d69f7817fcbc06622859662 100755 (executable)
@@ -1031,6 +1031,32 @@ test_expect_success \
         git diff-tree -M -r M3^ M3 >actual &&
         compare_diff_raw expect actual'
 
+cat >input <<INPUT_END
+commit refs/heads/M4
+committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+data <<COMMIT
+rename root
+COMMIT
+
+from refs/heads/M2^0
+R "" sub
+
+INPUT_END
+
+cat >expect <<EOF
+:100644 100644 7123f7f44e39be127c5eb701e5968176ee9d78b1 7123f7f44e39be127c5eb701e5968176ee9d78b1 R100  file2/oldf      sub/file2/oldf
+:100755 100755 85df50785d62d3b05ab03d9cbf7e4a0b49449730 85df50785d62d3b05ab03d9cbf7e4a0b49449730 R100  file4   sub/file4
+:100755 100755 f1fb5da718392694d0076d677d6d0e364c79b0bc f1fb5da718392694d0076d677d6d0e364c79b0bc R100  i/am/new/to/you sub/i/am/new/to/you
+:100755 100755 e74b7d465e52746be2b4bae983670711e6e66657 e74b7d465e52746be2b4bae983670711e6e66657 R100  newdir/exec.sh  sub/newdir/exec.sh
+:100644 100644 fcf778cda181eaa1cbc9e9ce3a2e15ee9f9fe791 fcf778cda181eaa1cbc9e9ce3a2e15ee9f9fe791 R100  newdir/interesting      sub/newdir/interesting
+EOF
+test_expect_success \
+       'M: rename root to subdirectory' \
+       'git fast-import <input &&
+        git diff-tree -M -r M4^ M4 >actual &&
+        cat actual &&
+        compare_diff_raw expect actual'
+
 ###
 ### series N
 ###
@@ -1227,6 +1253,29 @@ test_expect_success \
         git diff-tree -C --find-copies-harder -r N4 N6 >actual &&
         compare_diff_raw expect actual'
 
+test_expect_success \
+       'N: copy root by path' \
+       'cat >expect <<-\EOF &&
+       :100755 100755 f1fb5da718392694d0076d677d6d0e364c79b0bc f1fb5da718392694d0076d677d6d0e364c79b0bc C100   file2/newf      oldroot/file2/newf
+       :100644 100644 7123f7f44e39be127c5eb701e5968176ee9d78b1 7123f7f44e39be127c5eb701e5968176ee9d78b1 C100   file2/oldf      oldroot/file2/oldf
+       :100755 100755 85df50785d62d3b05ab03d9cbf7e4a0b49449730 85df50785d62d3b05ab03d9cbf7e4a0b49449730 C100   file4   oldroot/file4
+       :100755 100755 e74b7d465e52746be2b4bae983670711e6e66657 e74b7d465e52746be2b4bae983670711e6e66657 C100   newdir/exec.sh  oldroot/newdir/exec.sh
+       :100644 100644 fcf778cda181eaa1cbc9e9ce3a2e15ee9f9fe791 fcf778cda181eaa1cbc9e9ce3a2e15ee9f9fe791 C100   newdir/interesting      oldroot/newdir/interesting
+       EOF
+        cat >input <<-INPUT_END &&
+       commit refs/heads/N-copy-root-path
+       committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+       data <<COMMIT
+       copy root directory by (empty) path
+       COMMIT
+
+       from refs/heads/branch^0
+       C "" oldroot
+       INPUT_END
+        git fast-import <input &&
+        git diff-tree -C --find-copies-harder -r branch N-copy-root-path >actual &&
+        compare_diff_raw expect actual'
+
 test_expect_success \
        'N: delete directory by copying' \
        'cat >expect <<-\EOF &&
@@ -2934,4 +2983,20 @@ test_expect_success 'S: ls with garbage after sha1 must fail' '
        test_i18ngrep "space after tree-ish" err
 '
 
+###
+### series T (ls)
+###
+# Setup is carried over from series S.
+
+test_expect_success 'T: ls root tree' '
+       sed -e "s/Z\$//" >expect <<-EOF &&
+       040000 tree $(git rev-parse S^{tree})   Z
+       EOF
+       sha1=$(git rev-parse --verify S) &&
+       git fast-import --import-marks=marks <<-EOF >actual &&
+       ls $sha1 ""
+       EOF
+       test_cmp expect actual
+'
+
 test_done