fast-import: allow unquoted empty path for root
Ever since filerename was added inf39a946a1f
(Support wholesale directory renames in fast-import, 2007-07-09) and filecopy inb6f3481bb4
(Teach fast-import to recursively copy files/directories, 2007-07-15), both have produced an error when the destination path is empty. Later, when support for targeting the root directory with an empty string was added in2794ad5244
(fast-import: Allow filemodify to set the root, 2010-10-10), this had the effect of allowing the quoted empty string (`""`), but forbidding its unquoted variant (``). This seems to have been intended as simple data validation for parsing two paths, rather than a syntax restriction, because it was not extended to the other operations. All other occurrences of paths (in filemodify, filedelete, the source of filecopy and filerename, and ls) allow both. For most of this feature's lifetime, the documentation has not prescribed the use of quoted empty strings. Ine5959106d6
(Documentation/fast-import: put explanation of M 040000 <dataref> "" in context, 2011-01-15), its documentation was changed from “`<path>` may also be an empty string (`""`) to specify the root of the tree” to “The root of the tree can be represented by an empty string as `<path>`”. Thus, we should assume that some front-ends have depended on this behavior. Remove this restriction for the destination paths of filecopy and filerename and change tests targeting the root to test `""` and ``. Signed-off-by: Thalia Archibald <thalia@archibald.dev> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:

committed by
Junio C Hamano

parent
5733f894d7
commit
b5062f752e
@ -2423,9 +2423,6 @@ static void file_change_cr(const char *p, struct branch *b, int rename)
|
||||
|
||||
strbuf_reset(&source);
|
||||
parse_path_space(&source, p, &p, "source");
|
||||
|
||||
if (!*p)
|
||||
die("Missing dest: %s", command_buf.buf);
|
||||
strbuf_reset(&dest);
|
||||
parse_path_eol(&dest, p, "dest");
|
||||
|
||||
|
@ -1059,7 +1059,9 @@ test_expect_success 'M: rename subdirectory to new subdirectory' '
|
||||
compare_diff_raw expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'M: rename root to subdirectory' '
|
||||
for root in '""' ''
|
||||
do
|
||||
test_expect_success "M: rename root ($root) to subdirectory" '
|
||||
cat >input <<-INPUT_END &&
|
||||
commit refs/heads/M4
|
||||
committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
|
||||
@ -1068,7 +1070,7 @@ test_expect_success 'M: rename root to subdirectory' '
|
||||
COMMIT
|
||||
|
||||
from refs/heads/M2^0
|
||||
R "" sub
|
||||
R $root sub
|
||||
|
||||
INPUT_END
|
||||
|
||||
@ -1082,7 +1084,8 @@ test_expect_success 'M: rename root to subdirectory' '
|
||||
git fast-import <input &&
|
||||
git diff-tree -M -r M4^ M4 >actual &&
|
||||
compare_diff_raw expect actual
|
||||
'
|
||||
'
|
||||
done
|
||||
|
||||
###
|
||||
### series N
|
||||
@ -1259,12 +1262,14 @@ test_expect_success PIPE 'N: empty directory reads as missing' '
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'N: copy root directory by tree hash' '
|
||||
for root in '""' ''
|
||||
do
|
||||
test_expect_success "N: copy root ($root) by tree hash" '
|
||||
cat >expect <<-EOF &&
|
||||
:100755 000000 $newf $zero D file3/newf
|
||||
:100644 000000 $oldf $zero D file3/oldf
|
||||
EOF
|
||||
root=$(git rev-parse refs/heads/branch^0^{tree}) &&
|
||||
root_tree=$(git rev-parse refs/heads/branch^0^{tree}) &&
|
||||
cat >input <<-INPUT_END &&
|
||||
commit refs/heads/N6
|
||||
committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
|
||||
@ -1273,14 +1278,14 @@ test_expect_success 'N: copy root directory by tree hash' '
|
||||
COMMIT
|
||||
|
||||
from refs/heads/branch^0
|
||||
M 040000 $root ""
|
||||
M 040000 $root_tree $root
|
||||
INPUT_END
|
||||
git fast-import <input &&
|
||||
git diff-tree -C --find-copies-harder -r N4 N6 >actual &&
|
||||
compare_diff_raw expect actual
|
||||
'
|
||||
'
|
||||
|
||||
test_expect_success 'N: copy root by path' '
|
||||
test_expect_success "N: copy root ($root) by path" '
|
||||
cat >expect <<-EOF &&
|
||||
:100755 100755 $newf $newf C100 file2/newf oldroot/file2/newf
|
||||
:100644 100644 $oldf $oldf C100 file2/oldf oldroot/file2/oldf
|
||||
@ -1296,12 +1301,13 @@ test_expect_success 'N: copy root by path' '
|
||||
COMMIT
|
||||
|
||||
from refs/heads/branch^0
|
||||
C "" oldroot
|
||||
C $root 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
|
||||
'
|
||||
'
|
||||
done
|
||||
|
||||
test_expect_success 'N: delete directory by copying' '
|
||||
cat >expect <<-\EOF &&
|
||||
@ -1431,7 +1437,9 @@ test_expect_success 'N: reject foo/ syntax in ls argument' '
|
||||
INPUT_END
|
||||
'
|
||||
|
||||
test_expect_success 'N: copy to root by id and modify' '
|
||||
for root in '""' ''
|
||||
do
|
||||
test_expect_success "N: copy to root ($root) by id and modify" '
|
||||
echo "hello, world" >expect.foo &&
|
||||
echo hello >expect.bar &&
|
||||
git fast-import <<-SETUP_END &&
|
||||
@ -1456,7 +1464,7 @@ test_expect_success 'N: copy to root by id and modify' '
|
||||
copy to root by id and modify
|
||||
COMMIT
|
||||
|
||||
M 040000 $tree ""
|
||||
M 040000 $tree $root
|
||||
M 644 inline foo/foo
|
||||
data <<EOF
|
||||
hello, world
|
||||
@ -1466,9 +1474,9 @@ test_expect_success 'N: copy to root by id and modify' '
|
||||
git show N8:foo/bar >actual.bar &&
|
||||
test_cmp expect.foo actual.foo &&
|
||||
test_cmp expect.bar actual.bar
|
||||
'
|
||||
'
|
||||
|
||||
test_expect_success 'N: extract subtree' '
|
||||
test_expect_success "N: extract subtree to the root ($root)" '
|
||||
branch=$(git rev-parse --verify refs/heads/branch^{tree}) &&
|
||||
cat >input <<-INPUT_END &&
|
||||
commit refs/heads/N9
|
||||
@ -1477,14 +1485,14 @@ test_expect_success 'N: extract subtree' '
|
||||
extract subtree branch:newdir
|
||||
COMMIT
|
||||
|
||||
M 040000 $branch ""
|
||||
C "newdir" ""
|
||||
M 040000 $branch $root
|
||||
C "newdir" $root
|
||||
INPUT_END
|
||||
git fast-import <input &&
|
||||
git diff --exit-code branch:newdir N9
|
||||
'
|
||||
'
|
||||
|
||||
test_expect_success 'N: modify subtree, extract it, and modify again' '
|
||||
test_expect_success "N: modify subtree, extract it to the root ($root), and modify again" '
|
||||
echo hello >expect.baz &&
|
||||
echo hello, world >expect.qux &&
|
||||
git fast-import <<-SETUP_END &&
|
||||
@ -1509,12 +1517,12 @@ test_expect_success 'N: modify subtree, extract it, and modify again' '
|
||||
copy to root by id and modify
|
||||
COMMIT
|
||||
|
||||
M 040000 $tree ""
|
||||
M 040000 $tree $root
|
||||
M 100644 inline foo/bar/qux
|
||||
data <<EOF
|
||||
hello, world
|
||||
EOF
|
||||
R "foo" ""
|
||||
R "foo" $root
|
||||
C "bar/qux" "bar/quux"
|
||||
INPUT_END
|
||||
git show N11:bar/baz >actual.baz &&
|
||||
@ -1522,7 +1530,9 @@ test_expect_success 'N: modify subtree, extract it, and modify again' '
|
||||
git show N11:bar/quux >actual.quux &&
|
||||
test_cmp expect.baz actual.baz &&
|
||||
test_cmp expect.qux actual.qux &&
|
||||
test_cmp expect.qux actual.quux'
|
||||
test_cmp expect.qux actual.quux
|
||||
'
|
||||
done
|
||||
|
||||
###
|
||||
### series O
|
||||
@ -3067,6 +3077,7 @@ test_expect_success 'S: ls with garbage after sha1 must fail' '
|
||||
# There are two sorts of ways a path can be parsed, depending on whether it is
|
||||
# the last field on the line. Additionally, ls without a <dataref> has a special
|
||||
# case. Test every occurrence of <path> in the grammar against every error case.
|
||||
# Paths for the root (empty strings) are tested elsewhere.
|
||||
#
|
||||
|
||||
#
|
||||
@ -3321,16 +3332,19 @@ test_path_eol_quoted_fail 'ls (without dataref in commit)' 'ls ' path
|
||||
###
|
||||
# Setup is carried over from series S.
|
||||
|
||||
test_expect_success 'T: ls root tree' '
|
||||
for root in '""' ''
|
||||
do
|
||||
test_expect_success "T: ls root ($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 ""
|
||||
ls $sha1 $root
|
||||
EOF
|
||||
test_cmp expect actual
|
||||
'
|
||||
'
|
||||
done
|
||||
|
||||
test_expect_success 'T: delete branch' '
|
||||
git branch to-delete &&
|
||||
@ -3432,30 +3446,33 @@ test_expect_success 'U: validate directory delete result' '
|
||||
compare_diff_raw expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'U: filedelete root succeeds' '
|
||||
for root in '""' ''
|
||||
do
|
||||
test_expect_success "U: filedelete root ($root) succeeds" '
|
||||
cat >input <<-INPUT_END &&
|
||||
commit refs/heads/U
|
||||
commit refs/heads/U-delete-root
|
||||
committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
|
||||
data <<COMMIT
|
||||
must succeed
|
||||
COMMIT
|
||||
from refs/heads/U^0
|
||||
D ""
|
||||
D $root
|
||||
|
||||
INPUT_END
|
||||
|
||||
git fast-import <input
|
||||
'
|
||||
'
|
||||
|
||||
test_expect_success 'U: validate root delete result' '
|
||||
test_expect_success "U: validate root ($root) delete result" '
|
||||
cat >expect <<-EOF &&
|
||||
:100644 000000 $f7id $ZERO_OID D hello.c
|
||||
EOF
|
||||
|
||||
git diff-tree -M -r U^1 U >actual &&
|
||||
git diff-tree -M -r U U-delete-root >actual &&
|
||||
|
||||
compare_diff_raw expect actual
|
||||
'
|
||||
'
|
||||
done
|
||||
|
||||
###
|
||||
### series V (checkpoint)
|
||||
|
Reference in New Issue
Block a user