fast-import: tighten M 040000 syntax
authorJonathan Nieder <jrnieder@gmail.com>
Mon, 18 Oct 2010 01:08:53 +0000 (20:08 -0500)
committerJunio C Hamano <gitster@pobox.com>
Mon, 18 Oct 2010 23:42:26 +0000 (16:42 -0700)
When tree_content_set() is asked to modify the path "foo/bar/",
it first recurses like so:

tree_content_set(root, "foo/bar/", sha1, S_IFDIR) ->
tree_content_set(root:foo, "bar/", ...) ->
tree_content_set(root:foo/bar, "", ...)

And as a side-effect of 2794ad5 (fast-import: Allow filemodify to set
the root, 2010-10-10), this last call is accepted and changes
the tree entry for root:foo/bar to refer to the specified tree.

That seems safe enough but let's reject the new syntax (we never meant
to support it) and make it harder for frontends to introduce pointless
incompatibilities with git fast-import 1.7.3.

Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
fast-import.c
t/t9300-fast-import.sh
index aaf47c5745f8923fe4787f11cef8abaf6cf8a794..cb947c10d7a6531f3f0de9a0afed013bb1809839 100644 (file)
@@ -1437,6 +1437,20 @@ static void store_tree(struct tree_entry *root)
        t->entry_count -= del;
 }
 
        t->entry_count -= del;
 }
 
+static void tree_content_replace(
+       struct tree_entry *root,
+       const unsigned char *sha1,
+       const uint16_t mode,
+       struct tree_content *newtree)
+{
+       if (!S_ISDIR(mode))
+               die("Root cannot be a non-directory");
+       hashcpy(root->versions[1].sha1, sha1);
+       if (root->tree)
+               release_tree_content_recursive(root->tree);
+       root->tree = newtree;
+}
+
 static int tree_content_set(
        struct tree_entry *root,
        const char *p,
 static int tree_content_set(
        struct tree_entry *root,
        const char *p,
@@ -1454,15 +1468,6 @@ static int tree_content_set(
                n = slash1 - p;
        else
                n = strlen(p);
                n = slash1 - p;
        else
                n = strlen(p);
-       if (!slash1 && !n) {
-               if (!S_ISDIR(mode))
-                       die("Root cannot be a non-directory");
-               hashcpy(root->versions[1].sha1, sha1);
-               if (root->tree)
-                       release_tree_content_recursive(root->tree);
-               root->tree = subtree;
-               return 1;
-       }
        if (!n)
                die("Empty path component found in input");
        if (!slash1 && !S_ISDIR(mode) && subtree)
        if (!n)
                die("Empty path component found in input");
        if (!slash1 && !S_ISDIR(mode) && subtree)
@@ -2230,6 +2235,10 @@ static void file_change_m(struct branch *b)
                                command_buf.buf);
        }
 
                                command_buf.buf);
        }
 
+       if (!*p) {
+               tree_content_replace(&b->branch_tree, sha1, mode, NULL);
+               return;
+       }
        tree_content_set(&b->branch_tree, p, sha1, mode, NULL);
 }
 
        tree_content_set(&b->branch_tree, p, sha1, mode, NULL);
 }
 
@@ -2288,6 +2297,13 @@ static void file_change_cr(struct branch *b, int rename)
                tree_content_get(&b->branch_tree, s, &leaf);
        if (!leaf.versions[1].mode)
                die("Path %s not in branch", s);
                tree_content_get(&b->branch_tree, s, &leaf);
        if (!leaf.versions[1].mode)
                die("Path %s not in branch", s);
+       if (!*d) {      /* C "path/to/subdir" "" */
+               tree_content_replace(&b->branch_tree,
+                       leaf.versions[1].sha1,
+                       leaf.versions[1].mode,
+                       leaf.tree);
+               return;
+       }
        tree_content_set(&b->branch_tree, d,
                leaf.versions[1].sha1,
                leaf.versions[1].mode,
        tree_content_set(&b->branch_tree, d,
                leaf.versions[1].sha1,
                leaf.versions[1].mode,
index 1df11adc907aac13b33c3f0e5dbf60467f597e3f..ce094577e03bcd921543c527a542cbc96d389cf4 100755 (executable)
@@ -928,6 +928,20 @@ test_expect_success \
         git diff-tree -C --find-copies-harder -r N5^^ N5 >actual &&
         compare_diff_raw expect actual'
 
         git diff-tree -C --find-copies-harder -r N5^^ N5 >actual &&
         compare_diff_raw expect actual'
 
+test_expect_success \
+       'N: reject foo/ syntax' \
+       'subdir=$(git rev-parse refs/heads/branch^0:file2) &&
+        test_must_fail git fast-import <<-INPUT_END
+       commit refs/heads/N5B
+       committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+       data <<COMMIT
+       copy with invalid syntax
+       COMMIT
+
+       from refs/heads/branch^0
+       M 040000 $subdir file3/
+       INPUT_END'
+
 test_expect_success \
        'N: copy to root by id and modify' \
        'echo "hello, world" >expect.foo &&
 test_expect_success \
        'N: copy to root by id and modify' \
        'echo "hello, world" >expect.foo &&
@@ -965,6 +979,22 @@ test_expect_success \
         test_cmp expect.foo actual.foo &&
         test_cmp expect.bar actual.bar'
 
         test_cmp expect.foo actual.foo &&
         test_cmp expect.bar actual.bar'
 
+test_expect_success \
+       'N: extract subtree' \
+       'branch=$(git rev-parse --verify refs/heads/branch^{tree}) &&
+        cat >input <<-INPUT_END &&
+       commit refs/heads/N9
+       committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+       data <<COMMIT
+       extract subtree branch:newdir
+       COMMIT
+
+       M 040000 $branch ""
+       R "newdir" ""
+       INPUT_END
+        git fast-import <input &&
+        git diff --exit-code branch:newdir N9'
+
 ###
 ### series O
 ###
 ###
 ### series O
 ###