mirror of
https://github.com/git/git.git
synced 2024-10-30 13:57:54 +01:00
Merge branch 'jc/maint-clean-nested-worktree-in-subdir'
"git clean -d -f" (not "-d -f -f") is supposed to protect nested working trees of independent git repositories that exist in the current project working tree from getting removed, but the protection applied only to such working trees that are at the top-level of the current project by mistake. * jc/maint-clean-nested-worktree-in-subdir: clean: preserve nested git worktree in subdirectories
This commit is contained in:
commit
a2caeb2e26
2 changed files with 43 additions and 11 deletions
27
dir.c
27
dir.c
|
@ -1172,23 +1172,27 @@ int is_empty_dir(const char *path)
|
|||
return ret;
|
||||
}
|
||||
|
||||
int remove_dir_recursively(struct strbuf *path, int flag)
|
||||
static int remove_dir_recurse(struct strbuf *path, int flag, int *kept_up)
|
||||
{
|
||||
DIR *dir;
|
||||
struct dirent *e;
|
||||
int ret = 0, original_len = path->len, len;
|
||||
int ret = 0, original_len = path->len, len, kept_down = 0;
|
||||
int only_empty = (flag & REMOVE_DIR_EMPTY_ONLY);
|
||||
int keep_toplevel = (flag & REMOVE_DIR_KEEP_TOPLEVEL);
|
||||
unsigned char submodule_head[20];
|
||||
|
||||
if ((flag & REMOVE_DIR_KEEP_NESTED_GIT) &&
|
||||
!resolve_gitlink_ref(path->buf, "HEAD", submodule_head))
|
||||
!resolve_gitlink_ref(path->buf, "HEAD", submodule_head)) {
|
||||
/* Do not descend and nuke a nested git work tree. */
|
||||
if (kept_up)
|
||||
*kept_up = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
flag &= ~(REMOVE_DIR_KEEP_TOPLEVEL|REMOVE_DIR_KEEP_NESTED_GIT);
|
||||
flag &= ~REMOVE_DIR_KEEP_TOPLEVEL;
|
||||
dir = opendir(path->buf);
|
||||
if (!dir) {
|
||||
/* an empty dir could be removed even if it is unreadble */
|
||||
if (!keep_toplevel)
|
||||
return rmdir(path->buf);
|
||||
else
|
||||
|
@ -1208,7 +1212,7 @@ int remove_dir_recursively(struct strbuf *path, int flag)
|
|||
if (lstat(path->buf, &st))
|
||||
; /* fall thru */
|
||||
else if (S_ISDIR(st.st_mode)) {
|
||||
if (!remove_dir_recursively(path, flag))
|
||||
if (!remove_dir_recurse(path, flag, &kept_down))
|
||||
continue; /* happy */
|
||||
} else if (!only_empty && !unlink(path->buf))
|
||||
continue; /* happy, too */
|
||||
|
@ -1220,11 +1224,22 @@ int remove_dir_recursively(struct strbuf *path, int flag)
|
|||
closedir(dir);
|
||||
|
||||
strbuf_setlen(path, original_len);
|
||||
if (!ret && !keep_toplevel)
|
||||
if (!ret && !keep_toplevel && !kept_down)
|
||||
ret = rmdir(path->buf);
|
||||
else if (kept_up)
|
||||
/*
|
||||
* report the uplevel that it is not an error that we
|
||||
* did not rmdir() our directory.
|
||||
*/
|
||||
*kept_up = !ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int remove_dir_recursively(struct strbuf *path, int flag)
|
||||
{
|
||||
return remove_dir_recurse(path, flag, NULL);
|
||||
}
|
||||
|
||||
void setup_standard_excludes(struct dir_struct *dir)
|
||||
{
|
||||
const char *path;
|
||||
|
|
|
@ -399,8 +399,8 @@ test_expect_success SANITY 'removal failure' '
|
|||
'
|
||||
|
||||
test_expect_success 'nested git work tree' '
|
||||
rm -fr foo bar &&
|
||||
mkdir foo bar &&
|
||||
rm -fr foo bar baz &&
|
||||
mkdir -p foo bar baz/boo &&
|
||||
(
|
||||
cd foo &&
|
||||
git init &&
|
||||
|
@ -412,15 +412,24 @@ test_expect_success 'nested git work tree' '
|
|||
cd bar &&
|
||||
>goodbye.people
|
||||
) &&
|
||||
(
|
||||
cd baz/boo &&
|
||||
git init &&
|
||||
>deeper.world
|
||||
git add . &&
|
||||
git commit -a -m deeply.nested
|
||||
) &&
|
||||
git clean -f -d &&
|
||||
test -f foo/.git/index &&
|
||||
test -f foo/hello.world &&
|
||||
test -f baz/boo/.git/index &&
|
||||
test -f baz/boo/deeper.world &&
|
||||
! test -d bar
|
||||
'
|
||||
|
||||
test_expect_success 'force removal of nested git work tree' '
|
||||
rm -fr foo bar &&
|
||||
mkdir foo bar &&
|
||||
rm -fr foo bar baz &&
|
||||
mkdir -p foo bar baz/boo &&
|
||||
(
|
||||
cd foo &&
|
||||
git init &&
|
||||
|
@ -432,9 +441,17 @@ test_expect_success 'force removal of nested git work tree' '
|
|||
cd bar &&
|
||||
>goodbye.people
|
||||
) &&
|
||||
(
|
||||
cd baz/boo &&
|
||||
git init &&
|
||||
>deeper.world
|
||||
git add . &&
|
||||
git commit -a -m deeply.nested
|
||||
) &&
|
||||
git clean -f -f -d &&
|
||||
! test -d foo &&
|
||||
! test -d bar
|
||||
! test -d bar &&
|
||||
! test -d baz
|
||||
'
|
||||
|
||||
test_expect_success 'git clean -e' '
|
||||
|
|
Loading…
Reference in a new issue