fast-import: allow moving the root tree

Because fast-import.c::tree_content_remove does not check for the empty path, it is not possible to move the root tree to a subdirectory. Instead the error "Path not in branch" is produced (note the double space where the empty path has been inserted). Fix this by explicitly checking for the empty path and handling it. Signed-off-by: John Keeping <john@keeping.me.uk> Signed-off-by: Junio C Hamano <gitster@pobox.com>

John Keeping committed Jun 23, 2013 at 15:58 UTC 62bfa11cc9a8cb0aacbba0aed503e85cdc6ba0a4
2 files changed +15 -8
fast-import.c
+14 -7
@@ -1568,7 +1568,8 @@ static int tree_content_set(
1568 static int tree_content_remove(
1569 struct tree_entry *root,
1570 const char *p,
1571 - struct tree_entry *backup_leaf)
1571 + struct tree_entry *backup_leaf,
1572 + int allow_root)
1573 {
1574 struct tree_content *t;
1575 const char *slash1;
@@ -1583,6 +1584,12 @@ static int tree_content_remove(
1584
1585 if (!root->tree)
1586 load_tree(root);
1587 +
1588 + if (!*p && allow_root) {
1589 + e = root;
1590 + goto del_entry;
1591 + }
1592 +
1593 t = root->tree;
1594 for (i = 0; i < t->entry_count; i++) {
1595 e = t->entries[i];
@@ -1599,7 +1606,7 @@ static int tree_content_remove(
1606 goto del_entry;
1607 if (!e->tree)
1608 load_tree(e);
1602 - if (tree_content_remove(e, slash1 + 1, backup_leaf)) {
1609 + if (tree_content_remove(e, slash1 + 1, backup_leaf, 0)) {
1610 for (n = 0; n < e->tree->entry_count; n++) {
1611 if (e->tree->entries[n]->versions[1].mode) {
1612 hashclr(root->versions[1].sha1);
@@ -2188,7 +2195,7 @@ static uintmax_t do_change_note_fanout(
2195 }
2196
2197 /* Rename fullpath to realpath */
2191 - if (!tree_content_remove(orig_root, fullpath, &leaf))
2198 + if (!tree_content_remove(orig_root, fullpath, &leaf, 0))
2199 die("Failed to remove path %s", fullpath);
2200 tree_content_set(orig_root, realpath,
2201 leaf.versions[1].sha1,
@@ -2323,7 +2330,7 @@ static void file_change_m(struct branch *b)
2330
2331 /* Git does not track empty, non-toplevel directories. */
2332 if (S_ISDIR(mode) && !memcmp(sha1, EMPTY_TREE_SHA1_BIN, 20) && *p) {
2326 - tree_content_remove(&b->branch_tree, p, NULL);
2333 + tree_content_remove(&b->branch_tree, p, NULL, 0);
2334 return;
2335 }
2336
@@ -2384,7 +2391,7 @@ static void file_change_d(struct branch *b)
2391 die("Garbage after path in: %s", command_buf.buf);
2392 p = uq.buf;
2393 }
2387 - tree_content_remove(&b->branch_tree, p, NULL);
2394 + tree_content_remove(&b->branch_tree, p, NULL, 1);
2395 }
2396
2397 static void file_change_cr(struct branch *b, int rename)
@@ -2422,7 +2429,7 @@ static void file_change_cr(struct branch *b, int rename)
2429
2430 memset(&leaf, 0, sizeof(leaf));
2431 if (rename)
2425 - tree_content_remove(&b->branch_tree, s, &leaf);
2432 + tree_content_remove(&b->branch_tree, s, &leaf, 1);
2433 else
2434 tree_content_get(&b->branch_tree, s, &leaf, 1);
2435 if (!leaf.versions[1].mode)
@@ -2530,7 +2537,7 @@ static void note_change_n(struct branch *b, unsigned char *old_fanout)
2537 }
2538
2539 construct_path_with_fanout(sha1_to_hex(commit_sha1), *old_fanout, path);
2533 - if (tree_content_remove(&b->branch_tree, path, NULL))
2540 + if (tree_content_remove(&b->branch_tree, path, NULL, 0))
2541 b->num_notes--;
2542
2543 if (is_null_sha1(sha1))
t/t9300-fast-import.sh
+1 -1
@@ -1050,7 +1050,7 @@ cat >expect <<EOF
1050 :100755 100755 e74b7d465e52746be2b4bae983670711e6e66657 e74b7d465e52746be2b4bae983670711e6e66657 R100 newdir/exec.sh sub/newdir/exec.sh
1051 :100644 100644 fcf778cda181eaa1cbc9e9ce3a2e15ee9f9fe791 fcf778cda181eaa1cbc9e9ce3a2e15ee9f9fe791 R100 newdir/interesting sub/newdir/interesting
1052 EOF
1053 -test_expect_failure \
1053 +test_expect_success \
1054 'M: rename root to subdirectory' \
1055 'git fast-import <input &&
1056 git diff-tree -M -r M4^ M4 >actual &&