mv: let 'git mv file no-such-dir/' error out
Git used to trim the trailing slash, and make the command equivalent to 'git mv file no-such-dir', which created the file no-such-dir (while the trailing slash explicitly stated that it could only be a directory). This patch skips the trailing slash removal for the destination path. The path with its trailing slash is passed to rename(2), which errors out with the appropriate message: $ git mv file no-such-dir/ fatal: renaming 'file' failed: Not a directory Original-patch-by: Duy Nguyen <pclouds@gmail.com> Signed-off-by: Matthieu Moy <Matthieu.Moy@imag.fr> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:

committed by
Junio C Hamano

parent
a155a5f075
commit
c57f6281ff
23
builtin/mv.c
23
builtin/mv.c
@ -16,9 +16,12 @@ static const char * const builtin_mv_usage[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
#define DUP_BASENAME 1
|
||||
#define KEEP_TRAILING_SLASH 2
|
||||
|
||||
static const char **internal_copy_pathspec(const char *prefix,
|
||||
const char **pathspec,
|
||||
int count, int base_name)
|
||||
int count, unsigned flags)
|
||||
{
|
||||
int i;
|
||||
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++) {
|
||||
int length = strlen(result[i]);
|
||||
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--;
|
||||
if (to_copy != length || base_name) {
|
||||
if (to_copy != length || flags & DUP_BASENAME) {
|
||||
char *it = xmemdupz(result[i], to_copy);
|
||||
if (base_name) {
|
||||
if (flags & DUP_BASENAME) {
|
||||
result[i] = xstrdup(basename(it));
|
||||
free(it);
|
||||
} else
|
||||
@ -87,16 +91,21 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
|
||||
|
||||
source = internal_copy_pathspec(prefix, argv, argc, 0);
|
||||
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 *));
|
||||
|
||||
if (dest_path[0][0] == '\0')
|
||||
/* 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) &&
|
||||
S_ISDIR(st.st_mode)) {
|
||||
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 {
|
||||
if (argc != 1)
|
||||
die("destination '%s' is not a directory", dest_path[0]);
|
||||
|
Reference in New Issue
Block a user