Skip to content

Commit 7e39472

Browse files
committed
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
2 parents 0f7483e + 62bfa11 commit 7e39472

File tree

2 files changed

+103
-20
lines changed

2 files changed

+103
-20
lines changed

fast-import.c

Lines changed: 38 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1568,7 +1568,8 @@ static int tree_content_set(
15681568
static int tree_content_remove(
15691569
struct tree_entry *root,
15701570
const char *p,
1571-
struct tree_entry *backup_leaf)
1571+
struct tree_entry *backup_leaf,
1572+
int allow_root)
15721573
{
15731574
struct tree_content *t;
15741575
const char *slash1;
@@ -1583,6 +1584,12 @@ static int tree_content_remove(
15831584

15841585
if (!root->tree)
15851586
load_tree(root);
1587+
1588+
if (!*p && allow_root) {
1589+
e = root;
1590+
goto del_entry;
1591+
}
1592+
15861593
t = root->tree;
15871594
for (i = 0; i < t->entry_count; i++) {
15881595
e = t->entries[i];
@@ -1599,7 +1606,7 @@ static int tree_content_remove(
15991606
goto del_entry;
16001607
if (!e->tree)
16011608
load_tree(e);
1602-
if (tree_content_remove(e, slash1 + 1, backup_leaf)) {
1609+
if (tree_content_remove(e, slash1 + 1, backup_leaf, 0)) {
16031610
for (n = 0; n < e->tree->entry_count; n++) {
16041611
if (e->tree->entries[n]->versions[1].mode) {
16051612
hashclr(root->versions[1].sha1);
@@ -1629,7 +1636,8 @@ static int tree_content_remove(
16291636
static int tree_content_get(
16301637
struct tree_entry *root,
16311638
const char *p,
1632-
struct tree_entry *leaf)
1639+
struct tree_entry *leaf,
1640+
int allow_root)
16331641
{
16341642
struct tree_content *t;
16351643
const char *slash1;
@@ -1641,31 +1649,39 @@ static int tree_content_get(
16411649
n = slash1 - p;
16421650
else
16431651
n = strlen(p);
1644-
if (!n)
1652+
if (!n && !allow_root)
16451653
die("Empty path component found in input");
16461654

16471655
if (!root->tree)
16481656
load_tree(root);
1657+
1658+
if (!n) {
1659+
e = root;
1660+
goto found_entry;
1661+
}
1662+
16491663
t = root->tree;
16501664
for (i = 0; i < t->entry_count; i++) {
16511665
e = t->entries[i];
16521666
if (e->name->str_len == n && !strncmp_icase(p, e->name->str_dat, n)) {
1653-
if (!slash1) {
1654-
memcpy(leaf, e, sizeof(*leaf));
1655-
if (e->tree && is_null_sha1(e->versions[1].sha1))
1656-
leaf->tree = dup_tree_content(e->tree);
1657-
else
1658-
leaf->tree = NULL;
1659-
return 1;
1660-
}
1667+
if (!slash1)
1668+
goto found_entry;
16611669
if (!S_ISDIR(e->versions[1].mode))
16621670
return 0;
16631671
if (!e->tree)
16641672
load_tree(e);
1665-
return tree_content_get(e, slash1 + 1, leaf);
1673+
return tree_content_get(e, slash1 + 1, leaf, 0);
16661674
}
16671675
}
16681676
return 0;
1677+
1678+
found_entry:
1679+
memcpy(leaf, e, sizeof(*leaf));
1680+
if (e->tree && is_null_sha1(e->versions[1].sha1))
1681+
leaf->tree = dup_tree_content(e->tree);
1682+
else
1683+
leaf->tree = NULL;
1684+
return 1;
16691685
}
16701686

16711687
static int update_branch(struct branch *b)
@@ -2179,7 +2195,7 @@ static uintmax_t do_change_note_fanout(
21792195
}
21802196

21812197
/* Rename fullpath to realpath */
2182-
if (!tree_content_remove(orig_root, fullpath, &leaf))
2198+
if (!tree_content_remove(orig_root, fullpath, &leaf, 0))
21832199
die("Failed to remove path %s", fullpath);
21842200
tree_content_set(orig_root, realpath,
21852201
leaf.versions[1].sha1,
@@ -2314,7 +2330,7 @@ static void file_change_m(struct branch *b)
23142330

23152331
/* Git does not track empty, non-toplevel directories. */
23162332
if (S_ISDIR(mode) && !memcmp(sha1, EMPTY_TREE_SHA1_BIN, 20) && *p) {
2317-
tree_content_remove(&b->branch_tree, p, NULL);
2333+
tree_content_remove(&b->branch_tree, p, NULL, 0);
23182334
return;
23192335
}
23202336

@@ -2375,7 +2391,7 @@ static void file_change_d(struct branch *b)
23752391
die("Garbage after path in: %s", command_buf.buf);
23762392
p = uq.buf;
23772393
}
2378-
tree_content_remove(&b->branch_tree, p, NULL);
2394+
tree_content_remove(&b->branch_tree, p, NULL, 1);
23792395
}
23802396

23812397
static void file_change_cr(struct branch *b, int rename)
@@ -2413,9 +2429,9 @@ static void file_change_cr(struct branch *b, int rename)
24132429

24142430
memset(&leaf, 0, sizeof(leaf));
24152431
if (rename)
2416-
tree_content_remove(&b->branch_tree, s, &leaf);
2432+
tree_content_remove(&b->branch_tree, s, &leaf, 1);
24172433
else
2418-
tree_content_get(&b->branch_tree, s, &leaf);
2434+
tree_content_get(&b->branch_tree, s, &leaf, 1);
24192435
if (!leaf.versions[1].mode)
24202436
die("Path %s not in branch", s);
24212437
if (!*d) { /* C "path/to/subdir" "" */
@@ -2521,7 +2537,7 @@ static void note_change_n(struct branch *b, unsigned char *old_fanout)
25212537
}
25222538

25232539
construct_path_with_fanout(sha1_to_hex(commit_sha1), *old_fanout, path);
2524-
if (tree_content_remove(&b->branch_tree, path, NULL))
2540+
if (tree_content_remove(&b->branch_tree, path, NULL, 0))
25252541
b->num_notes--;
25262542

25272543
if (is_null_sha1(sha1))
@@ -3051,6 +3067,8 @@ static void parse_ls(struct branch *b)
30513067
struct object_entry *e = parse_treeish_dataref(&p);
30523068
root = new_tree_entry();
30533069
hashcpy(root->versions[1].sha1, e->idx.sha1);
3070+
if (!is_null_sha1(root->versions[1].sha1))
3071+
root->versions[1].mode = S_IFDIR;
30543072
load_tree(root);
30553073
if (*p++ != ' ')
30563074
die("Missing space after tree-ish: %s", command_buf.buf);
@@ -3065,7 +3083,7 @@ static void parse_ls(struct branch *b)
30653083
die("Garbage after path in: %s", command_buf.buf);
30663084
p = uq.buf;
30673085
}
3068-
tree_content_get(root, p, &leaf);
3086+
tree_content_get(root, p, &leaf, 1);
30693087
/*
30703088
* A directory in preparation would have a sha1 of zero
30713089
* until it is saved. Save, for simplicity.

t/t9300-fast-import.sh

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1031,6 +1031,32 @@ test_expect_success \
10311031
git diff-tree -M -r M3^ M3 >actual &&
10321032
compare_diff_raw expect actual'
10331033

1034+
cat >input <<INPUT_END
1035+
commit refs/heads/M4
1036+
committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1037+
data <<COMMIT
1038+
rename root
1039+
COMMIT
1040+
1041+
from refs/heads/M2^0
1042+
R "" sub
1043+
1044+
INPUT_END
1045+
1046+
cat >expect <<EOF
1047+
:100644 100644 7123f7f44e39be127c5eb701e5968176ee9d78b1 7123f7f44e39be127c5eb701e5968176ee9d78b1 R100 file2/oldf sub/file2/oldf
1048+
:100755 100755 85df50785d62d3b05ab03d9cbf7e4a0b49449730 85df50785d62d3b05ab03d9cbf7e4a0b49449730 R100 file4 sub/file4
1049+
:100755 100755 f1fb5da718392694d0076d677d6d0e364c79b0bc f1fb5da718392694d0076d677d6d0e364c79b0bc R100 i/am/new/to/you sub/i/am/new/to/you
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_success \
1054+
'M: rename root to subdirectory' \
1055+
'git fast-import <input &&
1056+
git diff-tree -M -r M4^ M4 >actual &&
1057+
cat actual &&
1058+
compare_diff_raw expect actual'
1059+
10341060
###
10351061
### series N
10361062
###
@@ -1227,6 +1253,29 @@ test_expect_success \
12271253
git diff-tree -C --find-copies-harder -r N4 N6 >actual &&
12281254
compare_diff_raw expect actual'
12291255

1256+
test_expect_success \
1257+
'N: copy root by path' \
1258+
'cat >expect <<-\EOF &&
1259+
:100755 100755 f1fb5da718392694d0076d677d6d0e364c79b0bc f1fb5da718392694d0076d677d6d0e364c79b0bc C100 file2/newf oldroot/file2/newf
1260+
:100644 100644 7123f7f44e39be127c5eb701e5968176ee9d78b1 7123f7f44e39be127c5eb701e5968176ee9d78b1 C100 file2/oldf oldroot/file2/oldf
1261+
:100755 100755 85df50785d62d3b05ab03d9cbf7e4a0b49449730 85df50785d62d3b05ab03d9cbf7e4a0b49449730 C100 file4 oldroot/file4
1262+
:100755 100755 e74b7d465e52746be2b4bae983670711e6e66657 e74b7d465e52746be2b4bae983670711e6e66657 C100 newdir/exec.sh oldroot/newdir/exec.sh
1263+
:100644 100644 fcf778cda181eaa1cbc9e9ce3a2e15ee9f9fe791 fcf778cda181eaa1cbc9e9ce3a2e15ee9f9fe791 C100 newdir/interesting oldroot/newdir/interesting
1264+
EOF
1265+
cat >input <<-INPUT_END &&
1266+
commit refs/heads/N-copy-root-path
1267+
committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1268+
data <<COMMIT
1269+
copy root directory by (empty) path
1270+
COMMIT
1271+
1272+
from refs/heads/branch^0
1273+
C "" oldroot
1274+
INPUT_END
1275+
git fast-import <input &&
1276+
git diff-tree -C --find-copies-harder -r branch N-copy-root-path >actual &&
1277+
compare_diff_raw expect actual'
1278+
12301279
test_expect_success \
12311280
'N: delete directory by copying' \
12321281
'cat >expect <<-\EOF &&
@@ -2934,4 +2983,20 @@ test_expect_success 'S: ls with garbage after sha1 must fail' '
29342983
test_i18ngrep "space after tree-ish" err
29352984
'
29362985

2986+
###
2987+
### series T (ls)
2988+
###
2989+
# Setup is carried over from series S.
2990+
2991+
test_expect_success 'T: ls root tree' '
2992+
sed -e "s/Z\$//" >expect <<-EOF &&
2993+
040000 tree $(git rev-parse S^{tree}) Z
2994+
EOF
2995+
sha1=$(git rev-parse --verify S) &&
2996+
git fast-import --import-marks=marks <<-EOF >actual &&
2997+
ls $sha1 ""
2998+
EOF
2999+
test_cmp expect actual
3000+
'
3001+
29373002
test_done

0 commit comments

Comments
 (0)