Merge branch 'mm/mv-file-to-no-such-dir-with-slash' into maint
"git mv A B/", when B does not exist as a directory, should error out, but it didn't. * mm/mv-file-to-no-such-dir-with-slash: mv: let 'git mv file no-such-dir/' error out on Windows, too mv: let 'git mv file no-such-dir/' error out
This commit is contained in:
commit
ada6ebb6e9
25
builtin/mv.c
25
builtin/mv.c
@ -16,9 +16,12 @@ static const char * const builtin_mv_usage[] = {
|
|||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define DUP_BASENAME 1
|
||||||
|
#define KEEP_TRAILING_SLASH 2
|
||||||
|
|
||||||
static const char **internal_copy_pathspec(const char *prefix,
|
static const char **internal_copy_pathspec(const char *prefix,
|
||||||
const char **pathspec,
|
const char **pathspec,
|
||||||
int count, int base_name)
|
int count, unsigned flags)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
const char **result = xmalloc((count + 1) * sizeof(const char *));
|
const char **result = xmalloc((count + 1) * sizeof(const char *));
|
||||||
@ -27,11 +30,12 @@ static const char **internal_copy_pathspec(const char *prefix,
|
|||||||
for (i = 0; i < count; i++) {
|
for (i = 0; i < count; i++) {
|
||||||
int length = strlen(result[i]);
|
int length = strlen(result[i]);
|
||||||
int to_copy = length;
|
int to_copy = length;
|
||||||
while (to_copy > 0 && is_dir_sep(result[i][to_copy - 1]))
|
while (!(flags & KEEP_TRAILING_SLASH) &&
|
||||||
|
to_copy > 0 && is_dir_sep(result[i][to_copy - 1]))
|
||||||
to_copy--;
|
to_copy--;
|
||||||
if (to_copy != length || base_name) {
|
if (to_copy != length || flags & DUP_BASENAME) {
|
||||||
char *it = xmemdupz(result[i], to_copy);
|
char *it = xmemdupz(result[i], to_copy);
|
||||||
if (base_name) {
|
if (flags & DUP_BASENAME) {
|
||||||
result[i] = xstrdup(basename(it));
|
result[i] = xstrdup(basename(it));
|
||||||
free(it);
|
free(it);
|
||||||
} else
|
} else
|
||||||
@ -87,16 +91,21 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
|
|||||||
|
|
||||||
source = internal_copy_pathspec(prefix, argv, argc, 0);
|
source = internal_copy_pathspec(prefix, argv, argc, 0);
|
||||||
modes = xcalloc(argc, sizeof(enum update_mode));
|
modes = xcalloc(argc, sizeof(enum update_mode));
|
||||||
dest_path = internal_copy_pathspec(prefix, argv + argc, 1, 0);
|
/*
|
||||||
|
* Keep trailing slash, needed to let
|
||||||
|
* "git mv file no-such-dir/" error out.
|
||||||
|
*/
|
||||||
|
dest_path = internal_copy_pathspec(prefix, argv + argc, 1,
|
||||||
|
KEEP_TRAILING_SLASH);
|
||||||
submodule_gitfile = xcalloc(argc, sizeof(char *));
|
submodule_gitfile = xcalloc(argc, sizeof(char *));
|
||||||
|
|
||||||
if (dest_path[0][0] == '\0')
|
if (dest_path[0][0] == '\0')
|
||||||
/* special case: "." was normalized to "" */
|
/* special case: "." was normalized to "" */
|
||||||
destination = internal_copy_pathspec(dest_path[0], argv, argc, 1);
|
destination = internal_copy_pathspec(dest_path[0], argv, argc, DUP_BASENAME);
|
||||||
else if (!lstat(dest_path[0], &st) &&
|
else if (!lstat(dest_path[0], &st) &&
|
||||||
S_ISDIR(st.st_mode)) {
|
S_ISDIR(st.st_mode)) {
|
||||||
dest_path[0] = add_slash(dest_path[0]);
|
dest_path[0] = add_slash(dest_path[0]);
|
||||||
destination = internal_copy_pathspec(dest_path[0], argv, argc, 1);
|
destination = internal_copy_pathspec(dest_path[0], argv, argc, DUP_BASENAME);
|
||||||
} else {
|
} else {
|
||||||
if (argc != 1)
|
if (argc != 1)
|
||||||
die("destination '%s' is not a directory", dest_path[0]);
|
die("destination '%s' is not a directory", dest_path[0]);
|
||||||
@ -205,6 +214,8 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
|
|||||||
}
|
}
|
||||||
} else if (string_list_has_string(&src_for_dst, dst))
|
} else if (string_list_has_string(&src_for_dst, dst))
|
||||||
bad = _("multiple sources for the same target");
|
bad = _("multiple sources for the same target");
|
||||||
|
else if (is_dir_sep(dst[strlen(dst) - 1]))
|
||||||
|
bad = _("destination directory does not exist");
|
||||||
else
|
else
|
||||||
string_list_insert(&src_for_dst, dst);
|
string_list_insert(&src_for_dst, dst);
|
||||||
|
|
||||||
|
@ -70,6 +70,35 @@ test_expect_success \
|
|||||||
rm -f idontexist untracked1 untracked2 \
|
rm -f idontexist untracked1 untracked2 \
|
||||||
path0/idontexist path0/untracked1 path0/untracked2 \
|
path0/idontexist path0/untracked1 path0/untracked2 \
|
||||||
.git/index.lock
|
.git/index.lock
|
||||||
|
rmdir path1
|
||||||
|
|
||||||
|
test_expect_success \
|
||||||
|
'moving to absent target with trailing slash' \
|
||||||
|
'test_must_fail git mv path0/COPYING no-such-dir/ &&
|
||||||
|
test_must_fail git mv path0/COPYING no-such-dir// &&
|
||||||
|
git mv path0/ no-such-dir/ &&
|
||||||
|
test_path_is_dir no-such-dir'
|
||||||
|
|
||||||
|
test_expect_success \
|
||||||
|
'clean up' \
|
||||||
|
'git reset --hard'
|
||||||
|
|
||||||
|
test_expect_success \
|
||||||
|
'moving to existing untracked target with trailing slash' \
|
||||||
|
'mkdir path1 &&
|
||||||
|
git mv path0/ path1/ &&
|
||||||
|
test_path_is_dir path1/path0/'
|
||||||
|
|
||||||
|
test_expect_success \
|
||||||
|
'moving to existing tracked target with trailing slash' \
|
||||||
|
'mkdir path2 &&
|
||||||
|
>path2/file && git add path2/file &&
|
||||||
|
git mv path1/path0/ path2/ &&
|
||||||
|
test_path_is_dir path2/path0/'
|
||||||
|
|
||||||
|
test_expect_success \
|
||||||
|
'clean up' \
|
||||||
|
'git reset --hard'
|
||||||
|
|
||||||
test_expect_success \
|
test_expect_success \
|
||||||
'adding another file' \
|
'adding another file' \
|
||||||
|
Loading…
Reference in New Issue
Block a user