Merge branch 'jc/maint-clean-nested-dir-safety'

* jc/maint-clean-nested-dir-safety:
  clean: require double -f options to nuke nested git repository and work tree
This commit is contained in:
Junio C Hamano 2009-08-16 04:13:13 -07:00
commit 14683af812
6 changed files with 63 additions and 5 deletions

View File

@ -27,6 +27,9 @@ OPTIONS
------- -------
-d:: -d::
Remove untracked directories in addition to untracked files. Remove untracked directories in addition to untracked files.
If an untracked directory is managed by a different git
repository, it is not removed by default. Use -f option twice
if you really want to remove such a directory.
-f:: -f::
If the git configuration specifies clean.requireForce as true, If the git configuration specifies clean.requireForce as true,

View File

@ -31,6 +31,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
int i; int i;
int show_only = 0, remove_directories = 0, quiet = 0, ignored = 0; int show_only = 0, remove_directories = 0, quiet = 0, ignored = 0;
int ignored_only = 0, baselen = 0, config_set = 0, errors = 0; int ignored_only = 0, baselen = 0, config_set = 0, errors = 0;
int rm_flags = REMOVE_DIR_KEEP_NESTED_GIT;
struct strbuf directory = STRBUF_INIT; struct strbuf directory = STRBUF_INIT;
struct dir_struct dir; struct dir_struct dir;
static const char **pathspec; static const char **pathspec;
@ -69,6 +70,9 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
die("clean.requireForce%s set and -n or -f not given; " die("clean.requireForce%s set and -n or -f not given; "
"refusing to clean", config_set ? "" : " not"); "refusing to clean", config_set ? "" : " not");
if (force > 1)
rm_flags = 0;
dir.flags |= DIR_SHOW_OTHER_DIRECTORIES; dir.flags |= DIR_SHOW_OTHER_DIRECTORIES;
if (!ignored) if (!ignored)
@ -131,7 +135,8 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
(matches == MATCHED_EXACTLY)) { (matches == MATCHED_EXACTLY)) {
if (!quiet) if (!quiet)
printf("Removing %s\n", qname); printf("Removing %s\n", qname);
if (remove_dir_recursively(&directory, 0) != 0) { if (remove_dir_recursively(&directory,
rm_flags) != 0) {
warning("failed to remove '%s'", qname); warning("failed to remove '%s'", qname);
errors++; errors++;
} }

12
dir.c
View File

@ -861,12 +861,20 @@ int is_empty_dir(const char *path)
return ret; return ret;
} }
int remove_dir_recursively(struct strbuf *path, int only_empty) int remove_dir_recursively(struct strbuf *path, int flag)
{ {
DIR *dir = opendir(path->buf); DIR *dir;
struct dirent *e; struct dirent *e;
int ret = 0, original_len = path->len, len; int ret = 0, original_len = path->len, len;
int only_empty = (flag & REMOVE_DIR_EMPTY_ONLY);
unsigned char submodule_head[20];
if ((flag & REMOVE_DIR_KEEP_NESTED_GIT) &&
!resolve_gitlink_ref(path->buf, "HEAD", submodule_head))
/* Do not descend and nuke a nested git work tree. */
return 0;
dir = opendir(path->buf);
if (!dir) if (!dir)
return -1; return -1;
if (path->buf[original_len - 1] != '/') if (path->buf[original_len - 1] != '/')

5
dir.h
View File

@ -88,7 +88,10 @@ static inline int is_dot_or_dotdot(const char *name)
extern int is_empty_dir(const char *dir); extern int is_empty_dir(const char *dir);
extern void setup_standard_excludes(struct dir_struct *dir); extern void setup_standard_excludes(struct dir_struct *dir);
extern int remove_dir_recursively(struct strbuf *path, int only_empty);
#define REMOVE_DIR_EMPTY_ONLY 01
#define REMOVE_DIR_KEEP_NESTED_GIT 02
extern int remove_dir_recursively(struct strbuf *path, int flag);
/* tries to remove the path with empty directories along it, ignores ENOENT */ /* tries to remove the path with empty directories along it, ignores ENOENT */
extern int remove_path(const char *path); extern int remove_path(const char *path);

2
refs.c
View File

@ -821,7 +821,7 @@ static int remove_empty_directories(const char *file)
strbuf_init(&path, 20); strbuf_init(&path, 20);
strbuf_addstr(&path, file); strbuf_addstr(&path, file);
result = remove_dir_recursively(&path, 1); result = remove_dir_recursively(&path, REMOVE_DIR_EMPTY_ONLY);
strbuf_release(&path); strbuf_release(&path);

View File

@ -380,4 +380,43 @@ test_expect_success 'removal failure' '
' '
chmod 755 foo chmod 755 foo
test_expect_success 'nested git work tree' '
rm -fr foo bar &&
mkdir foo bar &&
(
cd foo &&
git init &&
>hello.world
git add . &&
git commit -a -m nested
) &&
(
cd bar &&
>goodbye.people
) &&
git clean -f -d &&
test -f foo/.git/index &&
test -f foo/hello.world &&
! test -d bar
'
test_expect_success 'force removal of nested git work tree' '
rm -fr foo bar &&
mkdir foo bar &&
(
cd foo &&
git init &&
>hello.world
git add . &&
git commit -a -m nested
) &&
(
cd bar &&
>goodbye.people
) &&
git clean -f -f -d &&
! test -d foo &&
! test -d bar
'
test_done test_done