mv: add check_dir_in_index() and solve general dir check issue
Originally, moving a <source> directory which is not on-disk due to its existence outside of sparse-checkout cone, "giv mv" command errors out with "bad source". Add a helper check_dir_in_index() function to see if a directory name exists in the index. Also add a SKIP_WORKTREE_DIR bit to mark such directories. Change the checking logic, so that such <source> directory makes "giv mv" command warns with "advise_on_updating_sparse_paths()" instead of "bad source"; also user now can supply a "--sparse" flag so this operation can be carried out successfully. Helped-by: Victoria Dye <vdye@github.com> Helped-by: Derrick Stolee <derrickstolee@github.com> Signed-off-by: Shaoxuan Yuan <shaoxuan.yuan02@gmail.com> Acked-by: Derrick Stolee <derrickstolee@github.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
parent
24ea81d9ac
commit
b91a2b6594
50
builtin/mv.c
50
builtin/mv.c
@ -25,6 +25,7 @@ enum update_mode {
|
||||
WORKING_DIRECTORY = (1 << 1),
|
||||
INDEX = (1 << 2),
|
||||
SPARSE = (1 << 3),
|
||||
SKIP_WORKTREE_DIR = (1 << 4),
|
||||
};
|
||||
|
||||
#define DUP_BASENAME 1
|
||||
@ -123,6 +124,36 @@ static int index_range_of_same_dir(const char *src, int length,
|
||||
return last - first;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if an out-of-cone directory should be in the index. Imagine this case
|
||||
* that all the files under a directory are marked with 'CE_SKIP_WORKTREE' bit
|
||||
* and thus the directory is sparsified.
|
||||
*
|
||||
* Return 0 if such directory exist (i.e. with any of its contained files not
|
||||
* marked with CE_SKIP_WORKTREE, the directory would be present in working tree).
|
||||
* Return 1 otherwise.
|
||||
*/
|
||||
static int check_dir_in_index(const char *name)
|
||||
{
|
||||
const char *with_slash = add_slash(name);
|
||||
int length = strlen(with_slash);
|
||||
|
||||
int pos = cache_name_pos(with_slash, length);
|
||||
const struct cache_entry *ce;
|
||||
|
||||
if (pos < 0) {
|
||||
pos = -pos - 1;
|
||||
if (pos >= the_index.cache_nr)
|
||||
return 1;
|
||||
ce = active_cache[pos];
|
||||
if (strncmp(with_slash, ce->name, length))
|
||||
return 1;
|
||||
if (ce_skip_worktree(ce))
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int cmd_mv(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int i, flags, gitmodules_modified = 0;
|
||||
@ -184,7 +215,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
|
||||
/* Checking */
|
||||
for (i = 0; i < argc; i++) {
|
||||
const char *src = source[i], *dst = destination[i];
|
||||
int length, src_is_dir;
|
||||
int length;
|
||||
const char *bad = NULL;
|
||||
int skip_sparse = 0;
|
||||
|
||||
@ -198,12 +229,17 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
|
||||
|
||||
pos = cache_name_pos(src, length);
|
||||
if (pos < 0) {
|
||||
const char *src_w_slash = add_slash(src);
|
||||
if (!path_in_sparse_checkout(src_w_slash, &the_index) &&
|
||||
!check_dir_in_index(src)) {
|
||||
modes[i] |= SKIP_WORKTREE_DIR;
|
||||
goto dir_check;
|
||||
}
|
||||
/* only error if existence is expected. */
|
||||
if (!(modes[i] & SPARSE))
|
||||
bad = _("bad source");
|
||||
goto act_on_entry;
|
||||
}
|
||||
|
||||
ce = active_cache[pos];
|
||||
if (!ce_skip_worktree(ce)) {
|
||||
bad = _("bad source");
|
||||
@ -230,12 +266,14 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
|
||||
bad = _("can not move directory into itself");
|
||||
goto act_on_entry;
|
||||
}
|
||||
if ((src_is_dir = S_ISDIR(st.st_mode))
|
||||
if (S_ISDIR(st.st_mode)
|
||||
&& lstat(dst, &st) == 0) {
|
||||
bad = _("cannot move directory over file");
|
||||
goto act_on_entry;
|
||||
}
|
||||
if (src_is_dir) {
|
||||
|
||||
dir_check:
|
||||
if (S_ISDIR(st.st_mode)) {
|
||||
int j, dst_len, n;
|
||||
int first = cache_name_pos(src, length), last;
|
||||
|
||||
@ -369,7 +407,7 @@ remove_entry:
|
||||
printf(_("Renaming %s to %s\n"), src, dst);
|
||||
if (show_only)
|
||||
continue;
|
||||
if (!(mode & (INDEX | SPARSE)) &&
|
||||
if (!(mode & (INDEX | SPARSE | SKIP_WORKTREE_DIR)) &&
|
||||
rename(src, dst) < 0) {
|
||||
if (ignore_errors)
|
||||
continue;
|
||||
@ -384,7 +422,7 @@ remove_entry:
|
||||
1);
|
||||
}
|
||||
|
||||
if (mode & (WORKING_DIRECTORY))
|
||||
if (mode & (WORKING_DIRECTORY | SKIP_WORKTREE_DIR))
|
||||
continue;
|
||||
|
||||
pos = cache_name_pos(src, strlen(src));
|
||||
|
@ -1828,7 +1828,7 @@ test_expect_success 'checkout behaves oddly with df-conflict-2' '
|
||||
test_cmp full-checkout-err sparse-index-err
|
||||
'
|
||||
|
||||
test_expect_failure 'mv directory from out-of-cone to in-cone' '
|
||||
test_expect_success 'mv directory from out-of-cone to in-cone' '
|
||||
init_repos &&
|
||||
|
||||
# <source> as a sparse directory (or SKIP_WORKTREE_DIR without enabling
|
||||
|
@ -219,7 +219,7 @@ test_expect_success 'refuse to move file to non-skip-worktree sparse path' '
|
||||
test_cmp expect stderr
|
||||
'
|
||||
|
||||
test_expect_failure 'refuse to move out-of-cone directory without --sparse' '
|
||||
test_expect_success 'refuse to move out-of-cone directory without --sparse' '
|
||||
test_when_finished "cleanup_sparse_checkout" &&
|
||||
setup_sparse_checkout &&
|
||||
|
||||
@ -230,7 +230,7 @@ test_expect_failure 'refuse to move out-of-cone directory without --sparse' '
|
||||
test_cmp expect stderr
|
||||
'
|
||||
|
||||
test_expect_failure 'can move out-of-cone directory with --sparse' '
|
||||
test_expect_success 'can move out-of-cone directory with --sparse' '
|
||||
test_when_finished "cleanup_sparse_checkout" &&
|
||||
setup_sparse_checkout &&
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user