[PATCH v4] git-clean: Display more accurate delete messages
(1) Only print out the names of the files and directories that got actually deleted. (2) Show warning message for ignored untracked git repositories Consider the following repo layout: test.git/ |-- tracked_dir/ | |-- some_tracked_file | |-- some_untracked_file |-- tracked_file |-- untracked_file |-- untracked_foo/ | |-- bar/ | | |-- bar.txt | |-- emptydir/ | |-- frotz.git/ | |-- frotz.tx |-- untracked_some.git/ |-- some.txt Suppose the user issues 'git clean -fd' from the test.git directory. When -d option is used and untracked directory 'foo' contains a subdirectory 'frotz.git' that is managed by a different git repository therefore it will not be removed. $ git clean -fd Removing tracked_dir/some_untracked_file Removing untracked_file Removing untracked_foo/ Removing untracked_some.git/ The message displayed to the user is slightly misleading. The foo/ directory has not been removed because of foo/frotz.git still exists. On the other hand the subdirectories 'bar' and 'emptydir' have been deleted but they're not mentioned anywhere. Also, untracked_some.git has not been removed either. This behaviour is the result of the way the deletion of untracked directories are reported. In the current implementation they are deleted recursively but only the name of the top most directory is printed out. The calling function does not know about any subdirectories that could not be removed during the recursion. Improve the way the deleted directories are reported back to the user: (1) Create a recursive delete function 'remove_dirs' in builtin/clean.c to run in both dry_run and delete modes with the delete logic as follows: (a) Check if the current directory to be deleted is an untracked git repository. If it is and --force --force option is not set do not touch this directory, print ignore message, set dir_gone flag to false for the caller and return. (b) Otherwise for each item in current directory: (i) If current directory cannot be accessed, print warning, set dir_gone flag to false and return. (ii) If the item is a subdirectory recurse into it, check for the returned value of the dir_gone flag. If the subdirectory is gone, add the name of the deleted directory to a list of successfully removed items 'dels'. Else set the dir_gone flag as the current directory cannot be removed because we have at least one subdirectory hanging around. (iii) If it is a file try to remove it. If success add the file name to the 'dels' list, else print error and set dir_gone flag to false. (c) After we finished deleting all items in the current directory and the dir_gone flag is still true, remove the directory itself. If failed set the dir_gone flag to false. (d) If the current directory cannot be deleted because the dir_gone flag has been set to false, print out all the successfully deleted items for this directory from the 'dels' list. (e) We're done with the current directory, return. (2) Modify the cmd_clean() function to: (a) call the recursive delete function 'remove_dirs()' for each topmost directory it wants to remove (b) check for the returned value of dir_gone flag. If it's true print the name of the directory as being removed. Consider the output of the improved version: $ git clean -fd Removing tracked_dir/some_untracked_file Removing untracked_file warning: ignoring untracked git repository untracked_foo/frotz.git Removing untracked_foo/bar Removing untracked_foo/emptydir warning: ignoring untracked git repository untracked_some.git/ Now it displays only the file and directory names that got actually deleted and shows warnings about ignored untracked git repositories. Reported-by: Soren Brinkmann Signed-off-by: Zoltan Klinger --- builtin/clean.c | 158 +-- 1 file changed, 129 insertions(+), 29 deletions(-) diff --git a/builtin/clean.c b/builtin/clean.c index 69c1cda..1714546 100644 --- a/builtin/clean.c +++ b/builtin/clean.c @@ -10,6 +10,7 @@ #include "cache.h" #include "dir.h" #include "parse-options.h" +#include "refs.h" #include "string-list.h" #include "quote.h" @@ -20,6 +21,12 @@ static const char *const builtin_clean_usage[] = { NULL }; +static const char *msg_remove = N_("Removing %s\n"); +static const char *msg_would_remove = N_("Would remove %s\n"); +static const char *msg_would_ignore_git_dir = N_("Would ignore untracked git repository %s\n"); +static const char *msg_warn_ignore_git_dir = N_("ignoring
Re: [PATCH v4] git-clean: Display more accurate delete messages
Zoltan Klinger wrote: > $ git clean -fd > Removing tracked_dir/some_untracked_file > Removing untracked_file > Removing untracked_foo/ > Removing untracked_some.git/ > > The message displayed to the user is slightly misleading. The foo/ > directory has not been removed because of foo/frotz.git still exists. > On the other hand the subdirectories 'bar' and 'emptydir' have been > deleted but they're not mentioned anywhere. Also, untracked_some.git > has not been removed either. [...] > Consider the output of the improved version: > > $ git clean -fd > Removing tracked_dir/some_untracked_file > Removing untracked_file > warning: ignoring untracked git repository untracked_foo/frotz.git > Removing untracked_foo/bar > Removing untracked_foo/emptydir > warning: ignoring untracked git repository untracked_some.git/ Thanks, this looks like a nice improvement. I wonder whether it's possible to make the output more consistent, as in: Removing tracked_dir/some_untracked_file Removing untracked_file Skipping repository untracked_foo/frotz.git Removing untracked_foo/bar Removing untracked_foo/emptydir Skipping repository untracked_some.git or similar. What do you think? Thanks, Jonathan -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v4] git-clean: Display more accurate delete messages
> I wonder whether it's possible to make the output more consistent, > as in: > > Removing tracked_dir/some_untracked_file > Removing untracked_file > Skipping repository untracked_foo/frotz.git > Removing untracked_foo/bar > Removing untracked_foo/emptydir > Skipping repository untracked_some.git > > or similar. What do you think? Agree, the output looks much neater printed like that. I am going to update the patch unless someone feels strongly against the proposed output. -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v4] git-clean: Display more accurate delete messages
Zoltan Klinger writes: > Consider the output of the improved version: > > $ git clean -fd > Removing tracked_dir/some_untracked_file > Removing untracked_file > warning: ignoring untracked git repository untracked_foo/frotz.git > Removing untracked_foo/bar > Removing untracked_foo/emptydir > warning: ignoring untracked git repository untracked_some.git/ > > Now it displays only the file and directory names that got actually > deleted and shows warnings about ignored untracked git repositories. > > Reported-by: Soren Brinkmann > > Signed-off-by: Zoltan Klinger > --- I think the code before this patch used to say "Would not remove" and "Not removing" in certain cases to report the paths that the command decided not to remove, but after this patch these two messages no longer appear in the patch. Is it expected, are we losing information, or...? > builtin/clean.c | 158 > +-- > 1 file changed, 129 insertions(+), 29 deletions(-) > > diff --git a/builtin/clean.c b/builtin/clean.c > index 69c1cda..1714546 100644 > --- a/builtin/clean.c > +++ b/builtin/clean.c > @@ -10,6 +10,7 @@ > #include "cache.h" > #include "dir.h" > #include "parse-options.h" > +#include "refs.h" > #include "string-list.h" > #include "quote.h" > > @@ -20,6 +21,12 @@ static const char *const builtin_clean_usage[] = { > NULL > }; > > +static const char *msg_remove = N_("Removing %s\n"); > +static const char *msg_would_remove = N_("Would remove %s\n"); > +static const char *msg_would_ignore_git_dir = N_("Would ignore untracked git > repository %s\n"); > +static const char *msg_warn_ignore_git_dir = N_("ignoring untracked git > repository %s"); > +static const char *msg_warn_remove_failed = N_("failed to remove %s"); > + > static int git_clean_config(const char *var, const char *value, void *cb) > { > if (!strcmp(var, "clean.requireforce")) > @@ -34,11 +41,116 @@ static int exclude_cb(const struct option *opt, const > char *arg, int unset) > return 0; > } > > +static int remove_dirs(struct strbuf *path, const char *prefix, int > force_flag, > + int dry_run, int quiet, int *dir_gone) > +{ > + DIR *dir; > + struct strbuf quoted = STRBUF_INIT; > + struct dirent *e; > + int res = 0, ret = 0, gone = 1, original_len = path->len, len, i; > + unsigned char submodule_head[20]; > + struct string_list dels = STRING_LIST_INIT_DUP; > + > + *dir_gone = 1; > + > + if ((force_flag & REMOVE_DIR_KEEP_NESTED_GIT) && > + !resolve_gitlink_ref(path->buf, "HEAD", submodule_head)) { > + if (dry_run && !quiet) { > + quote_path_relative(path->buf, strlen(path->buf), > "ed, prefix); > + printf(_(msg_would_ignore_git_dir), quoted.buf); > + } else if (!dry_run) { > + quote_path_relative(path->buf, strlen(path->buf), > "ed, prefix); > + warning(_(msg_warn_ignore_git_dir), quoted.buf); > + } > + > + *dir_gone = 0; > + return 0; > + } > + > + dir = opendir(path->buf); > + if (!dir) { > + /* an empty dir could be removed even if it is unreadble */ > + res = dry_run ? 0 : rmdir(path->buf); > + if (res) { > + quote_path_relative(path->buf, strlen(path->buf), > "ed, prefix); > + warning(_(msg_warn_remove_failed), quoted.buf); > + *dir_gone = 0; > + } > + return res; > + } > + > + if (path->buf[original_len - 1] != '/') > + strbuf_addch(path, '/'); > + > + len = path->len; > + while ((e = readdir(dir)) != NULL) { > + struct stat st; > + if (is_dot_or_dotdot(e->d_name)) > + continue; > + > + strbuf_setlen(path, len); > + strbuf_addstr(path, e->d_name); > + if (lstat(path->buf, &st)) > + ; /* fall thru */ > + else if (S_ISDIR(st.st_mode)) { > + if (remove_dirs(path, prefix, force_flag, dry_run, > quiet, &gone)) > + ret = 1; > + if (gone) { > + quote_path_relative(path->buf, > strlen(path->buf), "ed, prefix); > + string_list_append(&dels, quoted.buf); > + } > + else > + *dir_gone = 0; > + continue; > + } else { > + res = dry_run ? 0 : unlink(path->buf); > + if (!res) { > + quote_path_relative(path->buf, > strlen(path->buf), "ed, prefix); > + string_list_append(&dels, quoted.buf); > + } > + else { > + quote_path_relative(path->buf,
Re: [PATCH v4] git-clean: Display more accurate delete messages
> I think the code before this patch used to say "Would not remove" > and "Not removing" in certain cases to report the paths that the > command decided not to remove, but after this patch these two > messages no longer appear in the patch. > > Is it expected, are we losing information, or...? > I do not think we are losing any information. Say, we have a repo like this: test.git |-- untracked_file |-- untracked_bar | |-- bar.txt |-- untracked_foo |-- foo.txt The original version prints out: $ git clean -fn Would remove untracked_file Would not remove untracked_bar/ Would not remove untracked_foo/ We never asked for any directories to be removed so IMHO the "Would not remove ..." messages are just noise. The new version prints out: $ git clean -fn Would remove untracked_file -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v4] git-clean: Display more accurate delete messages
Zoltan Klinger writes: >> I think the code before this patch used to say "Would not remove" >> and "Not removing" in certain cases to report the paths that the >> command decided not to remove, but after this patch these two >> messages no longer appear in the patch. >> >> Is it expected, are we losing information, or...? > > I do not think we are losing any information. > Say, we have a repo like this: > test.git > |-- untracked_file > |-- untracked_bar > | |-- bar.txt > |-- untracked_foo >|-- foo.txt > > The original version prints out: > $ git clean -fn > Would remove untracked_file > Would not remove untracked_bar/ > Would not remove untracked_foo/ > > We never asked for any directories to be removed so IMHO the "Would > not remove ..." messages are just noise. > > The new version prints out: > $ git clean -fn > Would remove untracked_file Oh. I was blinded by the primary reason of your patch being "be more careful and defer reporting a removal until we know everything in a directory did get removed and managed to remove the directory", and did not realize this "noise removal". Perhaps add Also do not mention that we are not removing directories when the user did not ask us to do so with '-d'. or something to the description? Thanks for a clarification. -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html