Skip to content

Commit 0e7c532

Browse files
committed
Merge branch 'jn/fast-import-fix' into pu
* jn/fast-import-fix: fast-import: do not clear notes in do_change_note_fanout() t9300 (fast-import): another test for the "replace root" feature fast-import: tighten M 040000 syntax fast-import: filemodify after M 040000 <tree> "" crashes
2 parents db540b9 + b212412 commit 0e7c532

File tree

2 files changed

+145
-12
lines changed

2 files changed

+145
-12
lines changed

fast-import.c

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1438,14 +1438,28 @@ static void store_tree(struct tree_entry *root)
14381438
t->entry_count -= del;
14391439
}
14401440

1441+
static void tree_content_replace(
1442+
struct tree_entry *root,
1443+
const unsigned char *sha1,
1444+
const uint16_t mode,
1445+
struct tree_content *newtree)
1446+
{
1447+
if (!S_ISDIR(mode))
1448+
die("Root cannot be a non-directory");
1449+
hashcpy(root->versions[1].sha1, sha1);
1450+
if (root->tree)
1451+
release_tree_content_recursive(root->tree);
1452+
root->tree = newtree;
1453+
}
1454+
14411455
static int tree_content_set(
14421456
struct tree_entry *root,
14431457
const char *p,
14441458
const unsigned char *sha1,
14451459
const uint16_t mode,
14461460
struct tree_content *subtree)
14471461
{
1448-
struct tree_content *t = root->tree;
1462+
struct tree_content *t;
14491463
const char *slash1;
14501464
unsigned int i, n;
14511465
struct tree_entry *e;
@@ -1455,20 +1469,14 @@ static int tree_content_set(
14551469
n = slash1 - p;
14561470
else
14571471
n = strlen(p);
1458-
if (!slash1 && !n) {
1459-
if (!S_ISDIR(mode))
1460-
die("Root cannot be a non-directory");
1461-
hashcpy(root->versions[1].sha1, sha1);
1462-
if (root->tree)
1463-
release_tree_content_recursive(root->tree);
1464-
root->tree = subtree;
1465-
return 1;
1466-
}
14671472
if (!n)
14681473
die("Empty path component found in input");
14691474
if (!slash1 && !S_ISDIR(mode) && subtree)
14701475
die("Non-directories cannot have subtrees");
14711476

1477+
if (!root->tree)
1478+
load_tree(root);
1479+
t = root->tree;
14721480
for (i = 0; i < t->entry_count; i++) {
14731481
e = t->entries[i];
14741482
if (e->name->str_len == n && !strncmp_icase(p, e->name->str_dat, n)) {
@@ -1524,7 +1532,7 @@ static int tree_content_remove(
15241532
const char *p,
15251533
struct tree_entry *backup_leaf)
15261534
{
1527-
struct tree_content *t = root->tree;
1535+
struct tree_content *t;
15281536
const char *slash1;
15291537
unsigned int i, n;
15301538
struct tree_entry *e;
@@ -1535,6 +1543,9 @@ static int tree_content_remove(
15351543
else
15361544
n = strlen(p);
15371545

1546+
if (!root->tree)
1547+
load_tree(root);
1548+
t = root->tree;
15381549
for (i = 0; i < t->entry_count; i++) {
15391550
e = t->entries[i];
15401551
if (e->name->str_len == n && !strncmp_icase(p, e->name->str_dat, n)) {
@@ -1582,7 +1593,7 @@ static int tree_content_get(
15821593
const char *p,
15831594
struct tree_entry *leaf)
15841595
{
1585-
struct tree_content *t = root->tree;
1596+
struct tree_content *t;
15861597
const char *slash1;
15871598
unsigned int i, n;
15881599
struct tree_entry *e;
@@ -1593,6 +1604,9 @@ static int tree_content_get(
15931604
else
15941605
n = strlen(p);
15951606

1607+
if (!root->tree)
1608+
load_tree(root);
1609+
t = root->tree;
15961610
for (i = 0; i < t->entry_count; i++) {
15971611
e = t->entries[i];
15981612
if (e->name->str_len == n && !strncmp_icase(p, e->name->str_dat, n)) {
@@ -2219,6 +2233,10 @@ static void file_change_m(struct branch *b)
22192233
command_buf.buf);
22202234
}
22212235

2236+
if (!*p) {
2237+
tree_content_replace(&b->branch_tree, sha1, mode, NULL);
2238+
return;
2239+
}
22222240
tree_content_set(&b->branch_tree, p, sha1, mode, NULL);
22232241
}
22242242

@@ -2277,6 +2295,13 @@ static void file_change_cr(struct branch *b, int rename)
22772295
tree_content_get(&b->branch_tree, s, &leaf);
22782296
if (!leaf.versions[1].mode)
22792297
die("Path %s not in branch", s);
2298+
if (!*d) { /* C "path/to/subdir" "" */
2299+
tree_content_replace(&b->branch_tree,
2300+
leaf.versions[1].sha1,
2301+
leaf.versions[1].mode,
2302+
leaf.tree);
2303+
return;
2304+
}
22802305
tree_content_set(&b->branch_tree, d,
22812306
leaf.versions[1].sha1,
22822307
leaf.versions[1].mode,

t/t9300-fast-import.sh

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -928,6 +928,114 @@ test_expect_success \
928928
git diff-tree -C --find-copies-harder -r N5^^ N5 >actual &&
929929
compare_diff_raw expect actual'
930930

931+
test_expect_success \
932+
'N: reject foo/ syntax' \
933+
'subdir=$(git rev-parse refs/heads/branch^0:file2) &&
934+
test_must_fail git fast-import <<-INPUT_END
935+
commit refs/heads/N5B
936+
committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
937+
data <<COMMIT
938+
copy with invalid syntax
939+
COMMIT
940+
941+
from refs/heads/branch^0
942+
M 040000 $subdir file3/
943+
INPUT_END'
944+
945+
test_expect_success \
946+
'N: copy to root by id and modify' \
947+
'echo "hello, world" >expect.foo &&
948+
echo hello >expect.bar &&
949+
git fast-import <<-SETUP_END &&
950+
commit refs/heads/N7
951+
committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
952+
data <<COMMIT
953+
hello, tree
954+
COMMIT
955+
956+
deleteall
957+
M 644 inline foo/bar
958+
data <<EOF
959+
hello
960+
EOF
961+
SETUP_END
962+
963+
tree=$(git rev-parse --verify N7:) &&
964+
git fast-import <<-INPUT_END &&
965+
commit refs/heads/N8
966+
committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
967+
data <<COMMIT
968+
copy to root by id and modify
969+
COMMIT
970+
971+
M 040000 $tree ""
972+
M 644 inline foo/foo
973+
data <<EOF
974+
hello, world
975+
EOF
976+
INPUT_END
977+
git show N8:foo/foo >actual.foo &&
978+
git show N8:foo/bar >actual.bar &&
979+
test_cmp expect.foo actual.foo &&
980+
test_cmp expect.bar actual.bar'
981+
982+
test_expect_success \
983+
'N: extract subtree' \
984+
'branch=$(git rev-parse --verify refs/heads/branch^{tree}) &&
985+
cat >input <<-INPUT_END &&
986+
commit refs/heads/N9
987+
committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
988+
data <<COMMIT
989+
extract subtree branch:newdir
990+
COMMIT
991+
992+
M 040000 $branch ""
993+
C "newdir" ""
994+
INPUT_END
995+
git fast-import <input &&
996+
git diff --exit-code branch:newdir N9'
997+
998+
test_expect_success \
999+
'N: modify subtree, extract it, and modify again' \
1000+
'echo hello >expect.baz &&
1001+
echo hello, world >expect.qux &&
1002+
git fast-import <<-SETUP_END &&
1003+
commit refs/heads/N10
1004+
committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1005+
data <<COMMIT
1006+
hello, tree
1007+
COMMIT
1008+
1009+
deleteall
1010+
M 644 inline foo/bar/baz
1011+
data <<EOF
1012+
hello
1013+
EOF
1014+
SETUP_END
1015+
1016+
tree=$(git rev-parse --verify N10:) &&
1017+
git fast-import <<-INPUT_END &&
1018+
commit refs/heads/N11
1019+
committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1020+
data <<COMMIT
1021+
copy to root by id and modify
1022+
COMMIT
1023+
1024+
M 040000 $tree ""
1025+
M 100644 inline foo/bar/qux
1026+
data <<EOF
1027+
hello, world
1028+
EOF
1029+
R "foo" ""
1030+
C "bar/qux" "bar/quux"
1031+
INPUT_END
1032+
git show N11:bar/baz >actual.baz &&
1033+
git show N11:bar/qux >actual.qux &&
1034+
git show N11:bar/quux >actual.quux &&
1035+
test_cmp expect.baz actual.baz &&
1036+
test_cmp expect.qux actual.qux &&
1037+
test_cmp expect.qux actual.quux'
1038+
9311039
###
9321040
### series O
9331041
###

0 commit comments

Comments
 (0)