{"thread":{"id":"62932","subject":"[PATCH 0/3] clean: add `config.exclude` and `--remove-excluded`","startedAt":"2025-02-10T19:15:39Z","lastAt":"2025-02-11T23:00:14Z","messageCount":9,"participants":["Ivan Shapovalov","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":3},"messages":[{"id":"512191","messageId":"20250210191504.309661-1-intelfx@intelfx.name","threadId":"62932","inReplyTo":null,"subject":"[PATCH 0/3] clean: add `config.exclude` and `--remove-excluded`","fromName":"Ivan Shapovalov","fromEmail":"intelfx@intelfx.name","sentAt":"2025-02-10T19:14:36Z","receivedAt":"2025-02-10T19:15:39Z","isPatch":true,"sender":{"key":"intelfx@intelfx.name","avatar":"https://gravatar.com/avatar/fb0d6e45051c5d8cda450fd6d02ecba0216f5f3aae1ebcf5de522939ff18eef3?d=mp&s=160"},"body":"This series extends the concept of \"excluded files\" in `git clean` to\nmake it useful to protect \"precious files\" that might be present in a\nspecific developer's working tree (see below).\n\nSpecifically, this series adds a `config.exclude` knob to configure\n\"always excluded\" files (same as `-e` on the command line), and a\n`--remove-excluded` flag (intentionally without a short form) to\n\"REALLY remove everything, dammit!\"\n\nThis might seem like euphemism treadmill, but there is a specific\nuse-case for all of the exclusion methods and options:\n\n.gitignore:     files that _the project_ does not want to track or touch\n                (build artifacts)\nclean.exclude:  files that _the user_ does not want to track or touch\n                (IDE configuration)\ngit clean -x:   remove build artifacts, but keep precious files\n                (when a pristine build is desired)\ngit clean -x --remove-excluded:\n                remove everything, including precious files\n                (e.g. for redistribution)\n\nFor instance, if I use Sublime Text or JetBrains IDEs to work on\nprojects, I might want to add this to my ~/.gitconfig:\n\n[clean]\n  exclude = /*.sublime-*\n  exclude = /.idea\n\nOr, if I make use of the Bear compiler wrapper to generate the\ncompilation database in those projects that do not use any of the\nmodern build-systems to automate such generation, I might write:\n\n[clean]\n  exclude = /compile_commands.json\n\nThis way, even if I run `git clean -fxd` to test a clean build, I do\nnot need to worry about accidentally removing the compilation database\nthat would take a bunch of CPU-time to regenerate.\n\nIvan Shapovalov (3):\n  clean, dir: add and use new helper `add_patterns_from_string_list()`\n  clean: rename `ignored` -> `remove_ignored`\n  clean: add `config.exclude` and `--remove-excluded`\n\n Documentation/config/clean.txt | 11 +++++++++++\n Documentation/git-clean.txt    | 22 +++++++++++++++-------\n builtin/clean.c                | 32 +++++++++++++++++++++-----------\n dir.c                          | 15 +++++++++++++++\n dir.h                          |  4 ++++\n 5 files changed, 66 insertions(+), 18 deletions(-)\n\n-- \n2.48.1.5.g9188e14f140\n\n"},{"id":"512192","messageId":"20250210191504.309661-2-intelfx@intelfx.name","threadId":"62932","inReplyTo":"20250210191504.309661-1-intelfx@intelfx.name","subject":"[PATCH 1/3] clean, dir: add and use new helper `add_patterns_from_string_list()`","fromName":"Ivan Shapovalov","fromEmail":"intelfx@intelfx.name","sentAt":"2025-02-10T19:14:37Z","receivedAt":"2025-02-10T19:15:42Z","isPatch":true,"sender":{"key":"intelfx@intelfx.name","avatar":"https://gravatar.com/avatar/fb0d6e45051c5d8cda450fd6d02ecba0216f5f3aae1ebcf5de522939ff18eef3?d=mp&s=160"},"body":"Signed-off-by: Ivan Shapovalov <intelfx@intelfx.name>\n---\n builtin/clean.c |  5 +----\n dir.c           | 15 +++++++++++++++\n dir.h           |  4 ++++\n 3 files changed, 20 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/clean.c b/builtin/clean.c\nindex 053c94fc6b..eaddf6a06e 100644\n--- a/builtin/clean.c\n+++ b/builtin/clean.c\n@@ -931,7 +931,6 @@ int cmd_clean(int argc,\n \tstruct pathspec pathspec;\n \tstruct strbuf buf = STRBUF_INIT;\n \tstruct string_list exclude_list = STRING_LIST_INIT_NODUP;\n-\tstruct pattern_list *pl;\n \tstruct string_list_item *item;\n \tconst char *qname;\n \tstruct option options[] = {\n@@ -1017,9 +1016,7 @@ int cmd_clean(int argc,\n \tif (repo_read_index(the_repository) < 0)\n \t\tdie(_(\"index file corrupt\"));\n \n-\tpl = add_pattern_list(&dir, EXC_CMDL, \"--exclude option\");\n-\tfor (i = 0; i < exclude_list.nr; i++)\n-\t\tadd_pattern(exclude_list.items[i].string, \"\", 0, pl, -(i+1));\n+\tadd_patterns_from_string_list(&dir, EXC_CMDL, \"--exclude option\", &exclude_list);\n \n \tparse_pathspec(&pathspec, 0,\n \t\t       PATHSPEC_PREFER_CWD,\ndiff --git a/dir.c b/dir.c\nindex 5b2181e589..fa3fd53649 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -1263,6 +1263,21 @@ struct pattern_list *add_pattern_list(struct dir_struct *dir,\n \treturn pl;\n }\n \n+/*\n+ * Convenience function to convert a string_list into pattern_list.\n+ */\n+struct pattern_list *add_patterns_from_string_list(struct dir_struct *dir,\n+\t\t\t\t\t\t   int group_type,\n+\t\t\t\t\t\t   const char *src,\n+\t\t\t\t\t\t   struct string_list *sl)\n+{\n+\tstruct pattern_list *pl;\n+\tpl = add_pattern_list(dir, group_type, src);\n+\tfor (int i = 0; i < sl->nr; i++)\n+\t\tadd_pattern(sl->items[i].string, \"\", 0, pl, -(i+1));\n+\treturn pl;\n+}\n+\n /*\n  * Used to set up core.excludesfile and .git/info/exclude lists.\n  */\ndiff --git a/dir.h b/dir.h\nindex a3a2f00f5d..eb843c9bb6 100644\n--- a/dir.h\n+++ b/dir.h\n@@ -460,6 +460,10 @@ int hashmap_contains_parent(struct hashmap *map,\n \t\t\t    struct strbuf *buffer);\n struct pattern_list *add_pattern_list(struct dir_struct *dir,\n \t\t\t\t      int group_type, const char *src);\n+struct pattern_list *add_patterns_from_string_list(struct dir_struct *dir,\n+\t\t\t\t\t\t   int group_type,\n+\t\t\t\t\t\t   const char *src,\n+\t\t\t\t\t\t   struct string_list *lst);\n int add_patterns_from_file_to_list(const char *fname, const char *base, int baselen,\n \t\t\t\t   struct pattern_list *pl, struct index_state *istate,\n \t\t\t\t   unsigned flags);\n-- \n2.48.1.5.g9188e14f140\n\n"},{"id":"512193","messageId":"20250210191504.309661-3-intelfx@intelfx.name","threadId":"62932","inReplyTo":"20250210191504.309661-1-intelfx@intelfx.name","subject":"[PATCH 2/3] clean: rename `ignored` -> `remove_ignored`","fromName":"Ivan Shapovalov","fromEmail":"intelfx@intelfx.name","sentAt":"2025-02-10T19:14:38Z","receivedAt":"2025-02-10T19:15:46Z","isPatch":true,"sender":{"key":"intelfx@intelfx.name","avatar":"https://gravatar.com/avatar/fb0d6e45051c5d8cda450fd6d02ecba0216f5f3aae1ebcf5de522939ff18eef3?d=mp&s=160"},"body":"No behavior change.\n\nSigned-off-by: Ivan Shapovalov <intelfx@intelfx.name>\n---\n builtin/clean.c | 10 +++++-----\n 1 file changed, 5 insertions(+), 5 deletions(-)\n\ndiff --git a/builtin/clean.c b/builtin/clean.c\nindex eaddf6a06e..ec58338049 100644\n--- a/builtin/clean.c\n+++ b/builtin/clean.c\n@@ -923,7 +923,7 @@ int cmd_clean(int argc,\n \t      struct repository *repo UNUSED)\n {\n \tint i, res;\n-\tint dry_run = 0, remove_directories = 0, quiet = 0, ignored = 0;\n+\tint dry_run = 0, remove_directories = 0, quiet = 0, remove_ignored = 0;\n \tint ignored_only = 0, force = 0, errors = 0, gone = 1;\n \tint rm_flags = REMOVE_DIR_KEEP_NESTED_GIT;\n \tstruct strbuf abs_path = STRBUF_INIT;\n@@ -942,7 +942,7 @@ int cmd_clean(int argc,\n \t\t\t\tN_(\"remove whole directories\")),\n \t\tOPT_CALLBACK_F('e', \"exclude\", &exclude_list, N_(\"pattern\"),\n \t\t  N_(\"add <pattern> to ignore rules\"), PARSE_OPT_NONEG, exclude_cb),\n-\t\tOPT_BOOL('x', NULL, &ignored, N_(\"remove ignored files, too\")),\n+\t\tOPT_BOOL('x', NULL, &remove_ignored, N_(\"remove ignored files, too\")),\n \t\tOPT_BOOL('X', NULL, &ignored_only,\n \t\t\t\tN_(\"remove only ignored files\")),\n \t\tOPT_END()\n@@ -963,9 +963,9 @@ int cmd_clean(int argc,\n \n \tdir.flags |= DIR_SHOW_OTHER_DIRECTORIES;\n \n-\tif (ignored && ignored_only)\n+\tif (remove_ignored && ignored_only)\n \t\tdie(_(\"options '%s' and '%s' cannot be used together\"), \"-x\", \"-X\");\n-\tif (!ignored)\n+\tif (!remove_ignored)\n \t\tsetup_standard_excludes(&dir);\n \tif (ignored_only)\n \t\tdir.flags |= DIR_SHOW_IGNORED;\n@@ -995,7 +995,7 @@ int cmd_clean(int argc,\n \t\t * recursing into a directory which is itself ignored.\n \t\t */\n \t\tdir.flags |= DIR_SHOW_IGNORED_TOO;\n-\t\tif (!ignored)\n+\t\tif (!remove_ignored)\n \t\t\tdir.flags |= DIR_SHOW_IGNORED_TOO_MODE_MATCHING;\n \n \t\t/*\n-- \n2.48.1.5.g9188e14f140\n\n"},{"id":"512194","messageId":"20250210191504.309661-4-intelfx@intelfx.name","threadId":"62932","inReplyTo":"20250210191504.309661-1-intelfx@intelfx.name","subject":"[PATCH 3/3] clean: add `config.exclude` and `--remove-excluded`","fromName":"Ivan Shapovalov","fromEmail":"intelfx@intelfx.name","sentAt":"2025-02-10T19:14:39Z","receivedAt":"2025-02-10T19:15:50Z","isPatch":true,"sender":{"key":"intelfx@intelfx.name","avatar":"https://gravatar.com/avatar/fb0d6e45051c5d8cda450fd6d02ecba0216f5f3aae1ebcf5de522939ff18eef3?d=mp&s=160"},"body":"Add `config.exclude` to configure \"always excluded\" files (same as `-e`\non the command line), and `--remove-excluded` (intentionally without a\nshort form) to \"REALLY remove everything, dammit!\"\n\nThis might seem like euphemism treadmill, but there is a specific\nuse-case for all of the exclusion methods and options:\n\n.gitignore:     files that _the project_ does not want to track or touch\n                (build artifacts)\nclean.exclude:  files that _the user_ does not want to track or touch\n                (IDE configuration)\ngit clean -x:   remove build artifacts, but keep precious files\n                (when a pristine build is desired)\ngit clean -x --remove-excluded:\n                remove everything, including precious files\n                (e.g. for redistribution)\n\nSigned-off-by: Ivan Shapovalov <intelfx@intelfx.name>\n---\n Documentation/config/clean.txt | 11 +++++++++++\n Documentation/git-clean.txt    | 22 +++++++++++++++-------\n builtin/clean.c                | 19 ++++++++++++++++---\n 3 files changed, 42 insertions(+), 10 deletions(-)\n\ndiff --git a/Documentation/config/clean.txt b/Documentation/config/clean.txt\nindex c0188ead4e..eb64ad26fa 100644\n--- a/Documentation/config/clean.txt\n+++ b/Documentation/config/clean.txt\n@@ -1,3 +1,14 @@\n clean.requireForce::\n \tA boolean to make git-clean refuse to delete files unless -f\n \tis given. Defaults to true.\n+\n+clean.exclude::\n+\tAdditional exclude patterns that have higher priority than the standard\n+\tlinkgit:gitignore[5] rules and will be honored in (almost) all cases,\n+\teven if the `-x` or `-X` options are given. These patterns are intended\n+\tto be used for user-specific \"precious\" files such as IDE configuration\n+\tthat must not be removed even if a pristine build is desired. This list\n+\thas the same priority and semantics as the `-e` command line option.\n+\n+\tThe `--remove-excluded` command line option can be used to disregard\n+\tthese exclude patterns (intentionally no short form).\ndiff --git a/Documentation/git-clean.txt b/Documentation/git-clean.txt\nindex fd17165416..33d6fb7228 100644\n--- a/Documentation/git-clean.txt\n+++ b/Documentation/git-clean.txt\n@@ -59,15 +59,10 @@ OPTIONS\n \tBe quiet, only report errors, but not the files that are\n \tsuccessfully removed.\n \n--e <pattern>::\n---exclude=<pattern>::\n-\tUse the given exclude pattern in addition to the standard ignore rules\n-\t(see linkgit:gitignore[5]).\n-\n -x::\n \tDon't use the standard ignore rules (see linkgit:gitignore[5]), but\n-\tstill use the ignore rules given with `-e` options from the command\n-\tline.  This allows removing all untracked\n+\tstill use the ignore rules given with the `-e` command line option or the\n+\t`clean.exclude` configuration variable.  This allows removing all untracked\n \tfiles, including build products.  This can be used (possibly in\n \tconjunction with 'git restore' or 'git reset') to create a pristine\n \tworking directory to test a clean build.\n@@ -76,6 +71,19 @@ OPTIONS\n \tRemove only files ignored by Git.  This may be useful to rebuild\n \teverything from scratch, but keep manually created files.\n \n+-e <pattern>::\n+--exclude=<pattern>::\n+\tUse the given exclude pattern in addition to the standard ignore rules\n+\t(see linkgit:gitignore[5]). Exclude patterns can also be configured\n+\tusing the `clean.exclude` configuration variable. These patterns have\n+\thigher priority than the `-x` or `-X` options and will be honored\n+\teven in their presence.\n+\n+--remove-excluded::\n+\tDisregard the additional exclude patterns provided by `-e` or the\n+\tconfiguration variable `clean.exclude`. This flag has the highest\n+\tpriority and intentionally does not have a short form.\n+\n Interactive mode\n ----------------\n When the command enters the interactive mode, it shows the\ndiff --git a/builtin/clean.c b/builtin/clean.c\nindex ec58338049..eae22a1ec7 100644\n--- a/builtin/clean.c\n+++ b/builtin/clean.c\n@@ -29,6 +29,7 @@\n static int require_force = -1; /* unset */\n static int interactive;\n static struct string_list del_list = STRING_LIST_INIT_DUP;\n+static struct string_list config_exclude_list = STRING_LIST_INIT_DUP;\n static unsigned int colopts;\n \n static const char *const builtin_clean_usage[] = {\n@@ -133,6 +134,11 @@ static int git_clean_config(const char *var, const char *value,\n \t\treturn 0;\n \t}\n \n+\tif (!strcmp(var, \"clean.exclude\")) {\n+\t\tstring_list_append(&config_exclude_list, value);\n+\t\treturn 0;\n+\t}\n+\n \tif (git_color_config(var, value, cb) < 0)\n \t\treturn -1;\n \n@@ -925,6 +931,7 @@ int cmd_clean(int argc,\n \tint i, res;\n \tint dry_run = 0, remove_directories = 0, quiet = 0, remove_ignored = 0;\n \tint ignored_only = 0, force = 0, errors = 0, gone = 1;\n+\tint remove_excluded = 0;\n \tint rm_flags = REMOVE_DIR_KEEP_NESTED_GIT;\n \tstruct strbuf abs_path = STRBUF_INIT;\n \tstruct dir_struct dir = DIR_INIT;\n@@ -940,11 +947,13 @@ int cmd_clean(int argc,\n \t\tOPT_BOOL('i', \"interactive\", &interactive, N_(\"interactive cleaning\")),\n \t\tOPT_BOOL('d', NULL, &remove_directories,\n \t\t\t\tN_(\"remove whole directories\")),\n-\t\tOPT_CALLBACK_F('e', \"exclude\", &exclude_list, N_(\"pattern\"),\n-\t\t  N_(\"add <pattern> to ignore rules\"), PARSE_OPT_NONEG, exclude_cb),\n \t\tOPT_BOOL('x', NULL, &remove_ignored, N_(\"remove ignored files, too\")),\n \t\tOPT_BOOL('X', NULL, &ignored_only,\n \t\t\t\tN_(\"remove only ignored files\")),\n+\t\tOPT_CALLBACK_F('e', \"exclude\", &exclude_list, N_(\"pattern\"),\n+\t\t\t\tN_(\"always exclude <pattern> from cleaning (overrides -x)\"), PARSE_OPT_NONEG, exclude_cb),\n+\t\tOPT_BOOL(0, \"remove-excluded\", &remove_excluded,\n+\t\t\t\tN_(\"remove excluded files, too (overrides -e and clean.exclude)\")),\n \t\tOPT_END()\n \t};\n \n@@ -1016,7 +1025,10 @@ int cmd_clean(int argc,\n \tif (repo_read_index(the_repository) < 0)\n \t\tdie(_(\"index file corrupt\"));\n \n-\tadd_patterns_from_string_list(&dir, EXC_CMDL, \"--exclude option\", &exclude_list);\n+\tif (!remove_excluded) {\n+\t\tadd_patterns_from_string_list(&dir, EXC_CMDL, \"--exclude option\", &exclude_list);\n+\t\tadd_patterns_from_string_list(&dir, EXC_CMDL, \"clean.exclude\", &config_exclude_list);\n+\t}\n \n \tparse_pathspec(&pathspec, 0,\n \t\t       PATHSPEC_PREFER_CWD,\n@@ -1091,6 +1103,7 @@ int cmd_clean(int argc,\n \tstrbuf_release(&buf);\n \tstring_list_clear(&del_list, 0);\n \tstring_list_clear(&exclude_list, 0);\n+\tstring_list_clear(&config_exclude_list, 0);\n \tclear_pathspec(&pathspec);\n \treturn (errors != 0);\n }\n-- \n2.48.1.5.g9188e14f140\n\n"},{"id":"512250","messageId":"xmqqcyfoxr7o.fsf@gitster.g","threadId":"62932","inReplyTo":"20250210191504.309661-1-intelfx@intelfx.name","subject":"Re: [PATCH 0/3] clean: add `config.exclude` and `--remove-excluded`","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2025-02-11T18:37:47Z","receivedAt":"2025-02-11T18:37:50Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ivan Shapovalov <intelfx@intelfx.name> writes:\n\n> This series extends the concept of \"excluded files\" in `git clean` to\n> make it useful to protect \"precious files\" that might be present in a\n> specific developer's working tree (see below).\n\nHow does it interact with \"git status\"?\n\n> Specifically, this series adds a `config.exclude` knob to configure\n> \"always excluded\" files (same as `-e` on the command line), and a\n> `--remove-excluded` flag (intentionally without a short form) to\n> \"REALLY remove everything, dammit!\"\n\nI am not sure if this uses the adjective `precious` to mean the same\nthing as we historically talked about `precious`, in the context of\n\"Git does not have `precious files`.  What we call `ignored` are\nsynoymous to `expendables`, and we'd eventually want to add the\n`precious` class of files that are separate from `ignored` files\".\n\nIf the feature is about _turning_ the existing `ignored/excluded`\ninto precious and require a new option to clean those files that\nhave always been treated as expendables, then that is a grave\nusability regression.  I am hoping that it is not the case.\n\nLet's read on.\n\n> This might seem like euphemism treadmill, but there is a specific\n> use-case for all of the exclusion methods and options:\n>\n> .gitignore:     files that _the project_ does not want to track or touch\n>                 (build artifacts)\n> clean.exclude:  files that _the user_ does not want to track or touch\n>                 (IDE configuration)\n\nThe above two share the same \"does not want to track or touch\"\nexplanation and readers do not know if you want them to have\ndistinct meaning, or just two different places the user has to store\nthe same information, one project-wide, given by and shared with\nothers, the other personal.\n\nYou need to say something like \"`clean.exclude` introduces a new\n`precious` class, the user does nto want to track or touch but\nunlike those that match the patterns in .gitignore, they are not\nexpendables\" here, if that is what you are trying to say (I am just\nguessing).\n\nWithout that ...\n\n> git clean -x:   remove build artifacts, but keep precious files\n>                 (when a pristine build is desired)\n\n... this would merely be a wishful thinking, but once the reader\nunderstands that you are introducing a new class, yes, it does make\nsense.  And it is backward compatible enhancement, which is very\ngood.\n\n> git clean -x --remove-excluded:\n>                 remove everything, including precious files\n>                 (e.g. for redistribution)\n\nDitto.\n\nAnother common theme around `precious` is not IDE configuration but\nthings like config.mak file we have.  Or perhaps deploy key files?\n\nIt is a clever UI hack to notice that the `precious` things are not\nsomething you'd share with the project, and to take advantage of the\ndistinction between the project-wide vs personal preference in the\nconfiguration system to introduce the `precious` class.  For that,\nit might even make sense to call the variable \"clean.precious\", as\nits semantics is VASTLY different from what we called `exclude` or\n`ignore` (they are synonyms---and they mean expendable files that\nare not to be tracked).\n\nAnd when people want non-project-wide but personal paths that are\nexcluded and expendable, they can use $GIT_DIR/info/exclude file.\nSo a possible alternative is to have the dir.[ch] infrastructure to\nstart paying attention to a new file $GIT_DIR/info/precious instead\nof the configuration variables.  I am not making an assessment on\nthe relative merit between clean.precious vs $GIT_DIR/info/precious\nyet---just throwing an alternative for others to discuss.\n\nBy the way, I notice Ævar is CC'ed, but I haven't seen him for quite\na while around here, and am wondering how you decided to do so.  Did\nyou have private conversations with and got suggestions from him or\nsomething?  Just being curious, but at the same time, if somebody's\ninfluence in the resulting design is big enough, crediting them with\n\"Helped-by:\" or some other trailer might be worth considering.\n\n\n"},{"id":"512251","messageId":"e7e0c581b4caab142989df174ee51e454e97dee1.camel@intelfx.name","threadId":"62932","inReplyTo":"xmqqcyfoxr7o.fsf@gitster.g","subject":"Re: [PATCH 0/3] clean: add `config.exclude` and `--remove-excluded`","fromName":"Ivan Shapovalov","fromEmail":"intelfx@intelfx.name","sentAt":"2025-02-11T18:47:09Z","receivedAt":"2025-02-11T18:47:13Z","isPatch":true,"sender":{"key":"intelfx@intelfx.name","avatar":"https://gravatar.com/avatar/fb0d6e45051c5d8cda450fd6d02ecba0216f5f3aae1ebcf5de522939ff18eef3?d=mp&s=160"},"body":"On 2025-02-11 at 10:37 -0800, Junio C Hamano wrote:\n> Ivan Shapovalov <intelfx@intelfx.name> writes:\n> \n> > This series extends the concept of \"excluded files\" in `git clean` to\n> > make it useful to protect \"precious files\" that might be present in a\n> > specific developer's working tree (see below).\n> \n> How does it interact with \"git status\"?\n\nIn the same way as `git clean -e`, i.e., there is no interaction.\n\n> \n> > Specifically, this series adds a `config.exclude` knob to configure\n> > \"always excluded\" files (same as `-e` on the command line), and a\n> > `--remove-excluded` flag (intentionally without a short form) to\n> > \"REALLY remove everything, dammit!\"\n> \n> I am not sure if this uses the adjective `precious` to mean the same\n> thing as we historically talked about `precious`, in the context of\n> \"Git does not have `precious files`.  What we call `ignored` are\n> synoymous to `expendables`, and we'd eventually want to add the\n> `precious` class of files that are separate from `ignored` files\".\n\nThere were no implications behind my usage of the word \"precious\".\n\n> \n> If the feature is about _turning_ the existing `ignored/excluded`\n> into precious and require a new option to clean those files that\n> have always been treated as expendables, then that is a grave\n> usability regression.  I am hoping that it is not the case.\n> \n> Let's read on.\n> \n> > This might seem like euphemism treadmill, but there is a specific\n> > use-case for all of the exclusion methods and options:\n> > \n> > .gitignore:     files that _the project_ does not want to track or touch\n> >                 (build artifacts)\n> > clean.exclude:  files that _the user_ does not want to track or touch\n> >                 (IDE configuration)\n> \n> The above two share the same \"does not want to track or touch\"\n> explanation and readers do not know if you want them to have\n> distinct meaning, or just two different places the user has to store\n> the same information, one project-wide, given by and shared with\n> others, the other personal.\n> \n> You need to say something like \"`clean.exclude` introduces a new\n> `precious` class, the user does nto want to track or touch but\n> unlike those that match the patterns in .gitignore, they are not\n> expendables\" here, if that is what you are trying to say (I am just\n> guessing).\n\nI don't think I'm trying to introduce any new fundamental concepts to\nGit. This patch is merely extending an existing command line option\ninto a configuration knob, because I noticed myself passing the same\narguments over and over and eventually creating an alias that does\nnothing but `git clean -e ...`, with the `-e` flag repeated a good 20\nor so times.\n\n> \n> Without that ...\n> \n> > git clean -x:   remove build artifacts, but keep precious files\n> >                 (when a pristine build is desired)\n> \n> ... this would merely be a wishful thinking, but once the reader\n> understands that you are introducing a new class, yes, it does make\n> sense.  And it is backward compatible enhancement, which is very\n> good.\n> \n> > git clean -x --remove-excluded:\n> >                 remove everything, including precious files\n> >                 (e.g. for redistribution)\n> \n> Ditto.\n\nThe above descriptions are just that, free-form descriptions to help\nunderstand the intended use-case. I'm not sure I understand the reasons\nbehind the \"wishful thinking\" label applied here.\n\n> \n> Another common theme around `precious` is not IDE configuration but\n> things like config.mak file we have.  Or perhaps deploy key files?\n\nconfig.mak is precisely one of such files that I now have in my own\n`clean.exclude`.\n\n> \n> It is a clever UI hack to notice that the `precious` things are not\n> something you'd share with the project, and to take advantage of the\n> distinction between the project-wide vs personal preference in the\n> configuration system to introduce the `precious` class.  For that,\n> it might even make sense to call the variable \"clean.precious\", as\n> its semantics is VASTLY different from what we called `exclude` or\n> `ignore` (they are synonyms---and they mean expendable files that\n> are not to be tracked).\n> \n> And when people want non-project-wide but personal paths that are\n> excluded and expendable, they can use $GIT_DIR/info/exclude file.\n> So a possible alternative is to have the dir.[ch] infrastructure to\n> start paying attention to a new file $GIT_DIR/info/precious instead\n> of the configuration variables.  I am not making an assessment on\n> the relative merit between clean.precious vs $GIT_DIR/info/precious\n> yet---just throwing an alternative for others to discuss.\n> \n> By the way, I notice Ævar is CC'ed, but I haven't seen him for quite\n> a while around here, and am wondering how you decided to do so.  Did\n> you have private conversations with and got suggestions from him or\n> something?  Just being curious, but at the same time, if somebody's\n> influence in the resulting design is big enough, crediting them with\n> \"Helped-by:\" or some other trailer might be worth considering.\n\nThis email was part of the `perl contrib/contacts/git-contacts` output\nfor this patchset, as documented in Documentation/SubmittingPatches\nand Documentation/MyFirstContribution.txt. Should I have not done that?\n\n\n-- \nIvan Shapovalov / intelfx /\n"},{"id":"512260","messageId":"xmqq7c5wxjin.fsf@gitster.g","threadId":"62932","inReplyTo":"e7e0c581b4caab142989df174ee51e454e97dee1.camel@intelfx.name","subject":"Re: [PATCH 0/3] clean: add `config.exclude` and `--remove-excluded`","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2025-02-11T21:24:00Z","receivedAt":"2025-02-11T21:24:03Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ivan Shapovalov <intelfx@intelfx.name> writes:\n\n> On 2025-02-11 at 10:37 -0800, Junio C Hamano wrote:\n>> Ivan Shapovalov <intelfx@intelfx.name> writes:\n>> \n>> > This series extends the concept of \"excluded files\" in `git clean` to\n>> > make it useful to protect \"precious files\" that might be present in a\n>> > specific developer's working tree (see below).\n>> \n>> How does it interact with \"git status\"?\n>\n> In the same way as `git clean -e`, i.e., there is no interaction.\n\nThat is dissapointing.  I was hoping that \"git status -u\" would list\nprecious and ignored ones in two separate sections.\n\n> There were no implications behind my usage of the word \"precious\".\n\nThen you should ;-)  We'd like to see us use the same language to\nrefer to the same concept within this same project (and more\nimportantly, avoid misleading people by calling two different things\nwith the same phrase).\n\n> This email was part of the `perl contrib/contacts/git-contacts` output\n> for this patchset, as documented in Documentation/SubmittingPatches\n> and Documentation/MyFirstContribution.txt. Should I have not done that?\n\nNo, as I said, I was curious if he is getting involved with the\nproject back again behind the curtain.\n\nThanks.\n"},{"id":"512263","messageId":"c0e31c9b8da723f4a7bbcc6099ce7e3c00a92fb4.camel@intelfx.name","threadId":"62932","inReplyTo":"xmqq7c5wxjin.fsf@gitster.g","subject":"Re: [PATCH 0/3] clean: add `config.exclude` and `--remove-excluded`","fromName":"Ivan Shapovalov","fromEmail":"intelfx@intelfx.name","sentAt":"2025-02-11T21:42:15Z","receivedAt":"2025-02-11T21:42:20Z","isPatch":true,"sender":{"key":"intelfx@intelfx.name","avatar":"https://gravatar.com/avatar/fb0d6e45051c5d8cda450fd6d02ecba0216f5f3aae1ebcf5de522939ff18eef3?d=mp&s=160"},"body":"On 2025-02-11 at 13:24 -0800, Junio C Hamano wrote:\n> Ivan Shapovalov <intelfx@intelfx.name> writes:\n> \n> > On 2025-02-11 at 10:37 -0800, Junio C Hamano wrote:\n> > > Ivan Shapovalov <intelfx@intelfx.name> writes:\n> > > \n> > > > This series extends the concept of \"excluded files\" in `git clean` to\n> > > > make it useful to protect \"precious files\" that might be present in a\n> > > > specific developer's working tree (see below).\n> > > \n> > > How does it interact with \"git status\"?\n> > \n> > In the same way as `git clean -e`, i.e., there is no interaction.\n> \n> That is dissapointing.  I was hoping that \"git status -u\" would list\n> precious and ignored ones in two separate sections.\n\nDo I need to implement those interactions in order for this patch set\nto be considered viable?\n\n> \n> > There were no implications behind my usage of the word \"precious\".\n> \n> Then you should ;-)  We'd like to see us use the same language to\n> refer to the same concept within this same project (and more\n> importantly, avoid misleading people by calling two different things\n> with the same phrase).\n\nI did not intend to mislead anyone (as evident by the fact that I was\nsimply not aware of any preexisting connotations). I'd appreciate\nsuggestions for a replacement term.\n\n-- \nIvan Shapovalov / intelfx /\n\n> \n> > This email was part of the `perl contrib/contacts/git-contacts` output\n> > for this patchset, as documented in Documentation/SubmittingPatches\n> > and Documentation/MyFirstContribution.txt. Should I have not done that?\n> \n> No, as I said, I was curious if he is getting involved with the\n> project back again behind the curtain.\n"},{"id":"512266","messageId":"xmqqseokw0hw.fsf@gitster.g","threadId":"62932","inReplyTo":"20250210191504.309661-4-intelfx@intelfx.name","subject":"Re: [PATCH 3/3] clean: add `config.exclude` and `--remove-excluded`","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2025-02-11T23:00:11Z","receivedAt":"2025-02-11T23:00:14Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ivan Shapovalov <intelfx@intelfx.name> writes:\n\n> Add `config.exclude` to configure \"always excluded\" files (same as `-e`\n> on the command line), and `--remove-excluded` (intentionally without a\n> short form) to \"REALLY remove everything, dammit!\"\n>\n> This might seem like euphemism treadmill, but there is a specific\n> use-case for all of the exclusion methods and options:\n>\n> .gitignore:     files that _the project_ does not want to track or touch\n>                 (build artifacts)\n> clean.exclude:  files that _the user_ does not want to track or touch\n>                 (IDE configuration)\n> git clean -x:   remove build artifacts, but keep precious files\n>                 (when a pristine build is desired)\n> git clean -x --remove-excluded:\n>                 remove everything, including precious files\n>                 (e.g. for redistribution)\n>\n> Signed-off-by: Ivan Shapovalov <intelfx@intelfx.name>\n> ---\n>  Documentation/config/clean.txt | 11 +++++++++++\n>  Documentation/git-clean.txt    | 22 +++++++++++++++-------\n>  builtin/clean.c                | 19 ++++++++++++++++---\n>  3 files changed, 42 insertions(+), 10 deletions(-)\n\nA few comments on the proposed semantics.\n\n - It is questionable to throw paths that match command line \"-e\"\n   patterns into the 'precious' class.  It breaks backward\n   compatibility and established end-user expectations, doesn't it?\n\n - It is nice to see that an effort is made to sift \"excluded\" into\n   two classes.  The traditional \"ignored/excluded are expendable,\n   so \"git clean\" will remove them, \"git switch\", when path F is\n   excluded and there is a file F, would remove it when it needs to\n   check out a tree that has paths under directory F.  \"git add F\"\n   and \"git add .\" would not add it unless forced.  We would want\n   another class of files `precious` that are ignored in the same\n   sense by \"git add\", but yet excempt from removal by \"git clean\"\n   and things like \"git switch\".\n\n - On the other hand, it is a good idea to use a new source of\n   patterns that the command never paid attention to, like a new\n   configuration variable.  Since nobody has ever used it for\n   \"excluded and expendable\", there is no risk of breaking end-user\n   expectations.\n\n - This particular implementation falls far short of the ideal of\n   \"precious files\" class, though.  Since \"git clean\" is the only\n   thing that pays attention to clean.exclude, \"git add .\" would\n   happily add those paths that match the pattern, and \"git switch\"\n   to check out a directory whose pathname matches the pattern would\n   happily nuke a precious file that is in the working tree at that\n   path.\n\nEarlier discussions proposed extended syntax added to .gitignore\nmechanism and relevant codepaths, not just \"git clean\", all pay\nattention to the new \"precious\" paths, but one idea proposed by\nthis series that is much better than the previous designs is the\nuse of separate sources of patterns---we do not have to worry about\nbackward compatibility issues at all with that design.\n\nIn my earlier review, I said it was clever to recognize that\nprecious would be of personal nature, but I now realize that there\nare valid reasons why projects may _know_ what paths are precious\nand would want to distribute that knowledge to its participants.\nFor example, our project would benefit from having config.mak marked\nas precious for everybody, so that nobody commits such a file by\nmistake and then ask us to pull from them.\n\nAs a configuration variable does not propagate across repositories\nby design, it would not work as a way for the project to share its\nidea of what paths are in the \"precious\" class, so in addition to\nthe clean.exclude (which probably is a bad name, as (1) we want not\njust clean but things like add and switch also pay attention to it,\nand (2) the class it defines is distinct from \"exclude\", and would\nwant to have the word \"precious\" in it) variable, we'd probably need\nto have a way to record them in tracked files, either in .gitignore\nfiles using some extended syntax, or separate .gitprecious files.\n\nThanks.\n"}]}