Subject: Re: [PATCH 3/3] clean: add `config.exclude` and `--remove-excluded`

From: Junio C Hamano <[email-masked]>
Date: Tue, 11 Feb 2025 15:00:11 -0800

Ivan Shapovalov <[email-masked]> writes:

> Add `config.exclude` to configure "always excluded" files (same as `-e`
> on the command line), and `--remove-excluded` (intentionally without a
> short form) to "REALLY remove everything, dammit!"
>
> This might seem like euphemism treadmill, but there is a specific
> use-case for all of the exclusion methods and options:
>
> .gitignore:     files that _the project_ does not want to track or touch
>                 (build artifacts)
> clean.exclude:  files that _the user_ does not want to track or touch
>                 (IDE configuration)
> git clean -x:   remove build artifacts, but keep precious files
>                 (when a pristine build is desired)
> git clean -x --remove-excluded:
>                 remove everything, including precious files
>                 (e.g. for redistribution)
>
> Signed-off-by: Ivan Shapovalov <[email-masked]>
> ---
>  Documentation/config/clean.txt | 11 +++++++++++
>  Documentation/git-clean.txt    | 22 +++++++++++++++-------
>  builtin/clean.c                | 19 ++++++++++++++++---
>  3 files changed, 42 insertions(+), 10 deletions(-)

A few comments on the proposed semantics.

 - It is questionable to throw paths that match command line "-e"
   patterns into the 'precious' class.  It breaks backward
   compatibility and established end-user expectations, doesn't it?

 - It is nice to see that an effort is made to sift "excluded" into
   two classes.  The traditional "ignored/excluded are expendable,
   so "git clean" will remove them, "git switch", when path F is
   excluded and there is a file F, would remove it when it needs to
   check out a tree that has paths under directory F.  "git add F"
   and "git add ." would not add it unless forced.  We would want
   another class of files `precious` that are ignored in the same
   sense by "git add", but yet excempt from removal by "git clean"
   and things like "git switch".

 - On the other hand, it is a good idea to use a new source of
   patterns that the command never paid attention to, like a new
   configuration variable.  Since nobody has ever used it for
   "excluded and expendable", there is no risk of breaking end-user
   expectations.

 - This particular implementation falls far short of the ideal of
   "precious files" class, though.  Since "git clean" is the only
   thing that pays attention to clean.exclude, "git add ." would
   happily add those paths that match the pattern, and "git switch"
   to check out a directory whose pathname matches the pattern would
   happily nuke a precious file that is in the working tree at that
   path.

Earlier discussions proposed extended syntax added to .gitignore
mechanism and relevant codepaths, not just "git clean", all pay
attention to the new "precious" paths, but one idea proposed by
this series that is much better than the previous designs is the
use of separate sources of patterns---we do not have to worry about
backward compatibility issues at all with that design.

In my earlier review, I said it was clever to recognize that
precious would be of personal nature, but I now realize that there
are valid reasons why projects may _know_ what paths are precious
and would want to distribute that knowledge to its participants.
For example, our project would benefit from having config.mak marked
as precious for everybody, so that nobody commits such a file by
mistake and then ask us to pull from them.

As a configuration variable does not propagate across repositories
by design, it would not work as a way for the project to share its
idea of what paths are in the "precious" class, so in addition to
the clean.exclude (which probably is a bad name, as (1) we want not
just clean but things like add and switch also pay attention to it,
and (2) the class it defines is distinct from "exclude", and would
want to have the word "precious" in it) variable, we'd probably need
to have a way to record them in tracked files, either in .gitignore
files using some extended syntax, or separate .gitprecious files.

Thanks.