Merge branch 'jk/fast-import-empty-ls'

* 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
This commit is contained in:
Junio C Hamano 2013-09-04 12:23:35 -07:00
commit 7e39472020
2 changed files with 103 additions and 20 deletions

View 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 @@ del_entry:
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) {
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, 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;
}
if (!S_ISDIR(e->versions[1].mode))
return 0;
if (!e->tree)
load_tree(e);
return tree_content_get(e, slash1 + 1, leaf);
}
}
return 0;
}
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.

View File

@ -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