{"thread":{"id":"3785","subject":"[PATCH] Add git-clean command","startedAt":"2006-04-03T22:18:41Z","lastAt":"2006-04-06T14:11:22Z","messageCount":11,"participants":["Pavel Roskin","Junio C Hamano","Martin Waitz","Alex Riesen","Sam Ravnborg","Jim Meyering"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"18304","messageId":"20060403221841.25097.18242.stgit@dv.roinet.com","threadId":"3785","inReplyTo":null,"subject":"[PATCH] Add git-clean command","fromName":"Pavel Roskin","fromEmail":"proski@gnu.org","sentAt":"2006-04-03T22:18:41Z","receivedAt":"2006-04-03T22:18:41Z","isPatch":true,"sender":{"key":"proski@gnu.org","avatar":null},"body":"This command removes untracked files from the working tree.  This\nimplementation is based on cg-clean with some simplifications.  The\ndocumentation is included.\n\nSigned-off-by: Pavel Roskin <proski@gnu.org>\n---\n\n .gitignore                  |    1 +\n Documentation/git-clean.txt |   50 +++++++++++++++++++++++++++++++\n Makefile                    |    2 +\n git-clean.sh                |   70 +++++++++++++++++++++++++++++++++++++++++++\n 4 files changed, 122 insertions(+), 1 deletions(-)\n\ndiff --git a/.gitignore b/.gitignore\nindex 75891c3..b5959d6 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -15,6 +15,7 @@ git-checkout\n git-checkout-index\n git-cherry\n git-cherry-pick\n+git-clean\n git-clone\n git-clone-pack\n git-commit\ndiff --git a/Documentation/git-clean.txt b/Documentation/git-clean.txt\nnew file mode 100644\nindex 0000000..0c671e1\n--- /dev/null\n+++ b/Documentation/git-clean.txt\n@@ -0,0 +1,50 @@\n+git-clean(1)\n+============\n+\n+NAME\n+----\n+git-clean - Remove untracked files from the working tree\n+\n+SYNOPSIS\n+--------\n+[verse]\n+'git-clean' [-d | -D] [-n] [-q] [-x]\n+\n+DESCRIPTION\n+-----------\n+Removes files unknown to git.  This allows to clean the working tree\n+from files that are not under version control.  If the '-x' option is\n+specified, ignored files are also removed, allowing to remove all\n+build products.\n+\n+OPTIONS\n+-------\n+-d::\n+\tRemove untracked directories in addition to untracked files.\n+\n+-D::\n+\tSame as above, but use chmod first.  This is useful for\n+\tread-only directories used in some testsuites.\n+\n+-n::\n+\tDon't actually remove anything, just show what would be done.\n+\n+-q::\n+\tBe quiet, only report errors, but not the files that are\n+\tsuccessfully removed.\n+\n+-x::\n+\tDon't use the ignore rules.  This allows removing all untracked\n+\tfiles, including build products.  This can be used (possibly in\n+\tconjunction with gitlink:git-reset[1]) to create a pristine\n+\tworking directory to test a clean build.\n+\n+\n+Author\n+------\n+Written by Pavel Roskin <proski@gnu.org>\n+\n+\n+GIT\n+---\n+Part of the gitlink:git[7] suite\ndiff --git a/Makefile b/Makefile\nindex c79d646..221e59a 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -114,7 +114,7 @@ ### --- END CONFIGURATION SECTION ---\n \n SCRIPT_SH = \\\n \tgit-add.sh git-bisect.sh git-branch.sh git-checkout.sh \\\n-\tgit-cherry.sh git-clone.sh git-commit.sh \\\n+\tgit-cherry.sh git-clean.sh git-clone.sh git-commit.sh \\\n \tgit-count-objects.sh git-diff.sh git-fetch.sh \\\n \tgit-format-patch.sh git-log.sh git-ls-remote.sh \\\n \tgit-merge-one-file.sh git-parse-remote.sh \\\ndiff --git a/git-clean.sh b/git-clean.sh\nnew file mode 100755\nindex 0000000..8470559\n--- /dev/null\n+++ b/git-clean.sh\n@@ -0,0 +1,70 @@\n+#!/bin/sh\n+#\n+# Copyright (c) 2005-2006 Pavel Roskin\n+#\n+\n+USAGE=\"[-d | -D] [-n] [-q] [-x]\"\n+LONG_USAGE='Clean untracked files from the working directory\n+\t-d\tremove directories as well\n+\t-D\tremove directories, try harder (chmod first)\n+\t-n \tdon'\\''t remove anything, just show what would be done\n+\t-q\tbe quiet, only report errors\n+\t-x\tremove ignored files as well'\n+SUBDIRECTORY_OK=Yes\n+. git-sh-setup\n+\n+noexclude=\n+cleandir=\n+cleandirhard=\n+quiet=\n+rmf=\"rm -f\"\n+rmrf=\"rm -rf\"\n+rm_refuse=\"echo Not removing\"\n+echo1=\"echo\"\n+\n+for arg in \"$@\"; do\n+\tif [ \"$arg\" = \"-d\" ]; then\n+\t\tcleandir=1\n+\telif [ \"$arg\" = \"-D\" ]; then\n+\t\tcleandir=1\n+\t\tcleandirhard=1\n+\telif [ \"$arg\" = \"-n\" ]; then\n+\t\tquiet=1\n+\t\trmf=\"echo Would remove\"\n+\t\trmrf=\"echo Would remove\"\n+\t\trm_refuse=\"echo Would not remove\"\n+\t\techo1=\":\"\n+\telif [ \"$arg\" = \"-q\" ]; then\n+\t\tquiet=1\n+\telif [ \"$arg\" = \"-x\" ]; then\n+\t\tnoexclude=1\n+\telse\n+\t\techo >&2 \"Unknown option: \\\"$arg\\\"\"\n+\t\texit 1\n+\tfi\n+done\n+\n+excl1=\n+excl2=\n+if [ -z \"$noexclude\" ]; then\n+\texcl1=\"--exclude-per-directory=.gitignore\"\n+\tif [ -f \"$GIT_DIR/info/exclude\" ]; then\n+\t\texcl2=\"--exclude-from=$GIT_DIR/info/exclude\"\n+\tfi\n+fi\n+\n+git-ls-files --others --directory \"$excl1\" \"$excl2\" |\n+while read -r file; do\n+\tif [ -d \"$file\" -a ! -L \"$file\" ]; then\n+\t\tif [ -z \"$cleandir\" ]; then\n+\t\t\t$rm_refuse \"$file\"\n+\t\t\tcontinue\n+\t\tfi\n+\t\t$echo1 \"Removing $file\"\n+\t\t[ \"$cleandirhard\" ] && chmod -R 700 \"$file\"\n+\t\t$rmrf \"$file\"\n+\telse\n+\t\t$echo1 \"Removing $file\"\n+\t\t$rmf \"$file\"\n+\tfi\n+done\n"},{"id":"18314","messageId":"7vzmj2b3w3.fsf@assigned-by-dhcp.cox.net","threadId":"3785","inReplyTo":"20060403221841.25097.18242.stgit@dv.roinet.com","subject":"Re: [PATCH] Add git-clean command","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-04-04T00:06:36Z","receivedAt":"2006-04-04T00:06:36Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Pavel Roskin <proski@gnu.org> writes:\n\n> This command removes untracked files from the working tree.  This\n> implementation is based on cg-clean with some simplifications.  The\n> documentation is included.\n\nI am not opposed to the command in the sense that I do not want\nto forbid people from doing what they want to do, but on the\nother hand I do not see why people (apparently many people) want\nto have something like this.  Are their \"make clean\" broken?\n\nHaving said that, just some nitpicks.\n\n> diff --git a/.gitignore b/.gitignore\n>...\n> +git-clean\n\nI appreciate the attention to the detail; very nice to have\na .gitignore entry along with addition of a command.\n\n> diff --git a/git-clean.sh b/git-clean.sh\n>...\n> +for arg in \"$@\"; do\n\n\tfor arg\n        do\n        \t...\n\n> +\tif [ \"$arg\" = \"-d\" ]; then\n\n\tcase \"$arg\" in -d)...\n\n> +excl1=\n> +excl2=\n> +if [ -z \"$noexclude\" ]; then\n> +\texcl1=\"--exclude-per-directory=.gitignore\"\n> +\tif [ -f \"$GIT_DIR/info/exclude\" ]; then\n> +\t\texcl2=\"--exclude-from=$GIT_DIR/info/exclude\"\n> +\tfi\n> +fi\n> +\n> +git-ls-files --others --directory \"$excl1\" \"$excl2\" |\n> +while read -r file; do\n> ...\n\nThe $noexclude case passes two empty strings to git-ls-files,\nwhich may happen to be harmless with the current implementation,\nbut does not feel quite right.\n\nMaybe better to read ls-files -z to be really pathname safe, I\ndunno.\n\n> +\t\t$echo1 \"Removing $file\"\n> +\t\t[ \"$cleandirhard\" ] && chmod -R 700 \"$file\"\n\nI am not quite sure this chmod -R is a good idea.  If we are\ntrying really hard would we need to also make sure we can rmdir\nthe \"$file\" by chmod'ing its parent directory?  But once we\nstart doing that where would we stop?\n"},{"id":"18328","messageId":"20060404082002.GJ4663@admingilde.org","threadId":"3785","inReplyTo":"20060403221841.25097.18242.stgit@dv.roinet.com","subject":"Re: [PATCH] Add git-clean command","fromName":"Martin Waitz","fromEmail":"tali@admingilde.org","sentAt":"2006-04-04T08:20:02Z","receivedAt":"2006-04-04T08:20:02Z","isPatch":true,"sender":{"key":"tali@admingilde.org","avatar":"https://gravatar.com/avatar/3f89b03eee362187effabe257898735b475673a12265c398ea9161259ae91553?d=mp&s=160"},"body":"hoi :)\n\n> +-x::\n> +\tDon't use the ignore rules.  This allows removing all untracked\n> +\tfiles, including build products.  This can be used (possibly in\n> +\tconjunction with gitlink:git-reset[1]) to create a pristine\n> +\tworking directory to test a clean build.\n\nas ignored files are generally generated files, doesn't it make sense\nto clean up the \"ignored\" files, and leave other untracked files\nalone?  That way you don't loose files which you forgot to add to git.\n\nWhat is the use case of cleaning up all untracked files without also\ncleaning ignored files?\n\n-- \nMartin Waitz\n"},{"id":"18330","messageId":"7vfykt908g.fsf@assigned-by-dhcp.cox.net","threadId":"3785","inReplyTo":"20060404082002.GJ4663@admingilde.org","subject":"Re: [PATCH] Add git-clean command","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-04-04T09:08:31Z","receivedAt":"2006-04-04T09:08:31Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Martin Waitz <tali@admingilde.org> writes:\n\n>> +-x::\n>> +\tDon't use the ignore rules.  This allows removing all untracked\n>> +\tfiles, including build products.  This can be used (possibly in\n>> +\tconjunction with gitlink:git-reset[1]) to create a pristine\n>> +\tworking directory to test a clean build.\n>\n> as ignored files are generally generated files, doesn't it make sense\n> to clean up the \"ignored\" files, and leave other untracked files\n> alone?  That way you don't loose files which you forgot to add to git.\n\nSounds like a sane suggestion, but my previous comment about\n\"make clean\" broken for people who want this \"git clean\" feature\napplies here as well.\n\nOne justification I can think of for \"git clean\" without -x flag\nis to make a clean tree that has only the source and build\nproducts, removing editor backup files, throwaway test output\nfiles and friends, but as you pointed out, this risks losing\nnewly created source files that you forgot to add, so I would\nneed a bit of convincing before I use such a command myself.\n\nCompared to that, removing only ignored files sounds like a much\nsafer operation -- they are explicitly listed as expendable, so\nit is a lot less likely to lose anything important.  But again,\nthat is what \"make clean\" is there for...\n"},{"id":"18331","messageId":"81b0412b0604040217s3b8863d3w1b79400c42ca2b90@mail.gmail.com","threadId":"3785","inReplyTo":"20060404082002.GJ4663@admingilde.org","subject":"Re: [PATCH] Add git-clean command","fromName":"Alex Riesen","fromEmail":"raa.lkml@gmail.com","sentAt":"2006-04-04T09:17:19Z","receivedAt":"2006-04-04T09:17:19Z","isPatch":true,"sender":{"key":"raa.lkml@gmail.com","avatar":"https://avatars.githubusercontent.com/u/324101?v=4"},"body":"On 4/4/06, Martin Waitz <tali@admingilde.org> wrote:\n> What is the use case of cleaning up all untracked files without also\n> cleaning ignored files?\n\nThinks of git's .gitignore: it has config.mak in it. Are you sure you want\n\"clean\" your build customizations?\n"},{"id":"18336","messageId":"20060404105818.GA17326@mars.ravnborg.org","threadId":"3785","inReplyTo":"7vzmj2b3w3.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH] Add git-clean command","fromName":"Sam Ravnborg","fromEmail":"sam@ravnborg.org","sentAt":"2006-04-04T10:58:18Z","receivedAt":"2006-04-04T10:58:18Z","isPatch":true,"sender":{"key":"sam@ravnborg.org","avatar":"https://gravatar.com/avatar/168a912606ed0742d840bb365e3cc21db390c36531a58341dc7a069cc1f15f62?d=mp&s=160"},"body":"On Mon, Apr 03, 2006 at 05:06:36PM -0700, Junio C Hamano wrote:\n> \n> I am not opposed to the command in the sense that I do not want\n> to forbid people from doing what they want to do, but on the\n> other hand I do not see why people (apparently many people) want\n> to have something like this.  Are their \"make clean\" broken?\n\nNo reason to waste time on make clean.\ngit ls-files -o | xargs rm\nDoes the same job nicely.\n\nOther typical usecases for me:\nRemove temporaries that I created while trying out stuff.\nOften I have a bunch of files named 'x', 'xx', 'fisk' etc.\naround for no use. An easy way to remove these without breaking\nmy 'allmodconfig' build is nice. It anyway > 1 hour to build and\nI like to get rid of the untracked stuff in an easy way.\n\nSo use cases goes like this:\n- Remove everything not tracked by git (including .gitignore files)\n- Remove everything except tracked by git or ignored\n- Remove ignored files (replacement of make clean) (seldom)\n\nAbove should work both from top-level dir and in subdirectories.\n\nThat is my minimal expectations to git clean.\nWhat Pavel came up with cover everything except the make clean\nreplacement part.\n\n\tSam\n"},{"id":"18344","messageId":"1144164749.30675.12.camel@dv","threadId":"3785","inReplyTo":"81b0412b0604040217s3b8863d3w1b79400c42ca2b90@mail.gmail.com","subject":"Re: [PATCH] Add git-clean command","fromName":"Pavel Roskin","fromEmail":"proski@gnu.org","sentAt":"2006-04-04T15:32:29Z","receivedAt":"2006-04-04T15:32:29Z","isPatch":true,"sender":{"key":"proski@gnu.org","avatar":null},"body":"On Tue, 2006-04-04 at 11:17 +0200, Alex Riesen wrote:\n> On 4/4/06, Martin Waitz <tali@admingilde.org> wrote:\n> > What is the use case of cleaning up all untracked files without also\n> > cleaning ignored files?\n> \n> Thinks of git's .gitignore: it has config.mak in it. Are you sure you want\n> \"clean\" your build customizations?\n\nIn may case, I normally want to remove copies of the sources.  For\nexample, I take foo.c, make a clean copy of it, then I change and test\nit.  If if doesn't work and I want to try another approach, I copy it to\nfoo.c-bad or foo.c-approach1.  I also make diffs between files to see\nwhat exactly I changed.  I may also create files for output, valgrind\nlogs and so on.\n\nAt some point, I'm satisfied with foo.c, so I commit it.  Then I want to\nremove copies, diffs and other stuff.  Yet I don't want to rebuild\neverything.\n\nIt's very rare that I add a new file, and I always remember to add it to\nthe version control.  But I'll consider adding an option to only remove\nignored files.\n\n-- \nRegards,\nPavel Roskin\n"},{"id":"18346","messageId":"1144165927.30675.32.camel@dv","threadId":"3785","inReplyTo":"20060404105818.GA17326@mars.ravnborg.org","subject":"Re: [PATCH] Add git-clean command","fromName":"Pavel Roskin","fromEmail":"proski@gnu.org","sentAt":"2006-04-04T15:52:07Z","receivedAt":"2006-04-04T15:52:07Z","isPatch":true,"sender":{"key":"proski@gnu.org","avatar":null},"body":"On Tue, 2006-04-04 at 12:58 +0200, Sam Ravnborg wrote:\n> On Mon, Apr 03, 2006 at 05:06:36PM -0700, Junio C Hamano wrote:\n> > \n> > I am not opposed to the command in the sense that I do not want\n> > to forbid people from doing what they want to do, but on the\n> > other hand I do not see why people (apparently many people) want\n> > to have something like this.  Are their \"make clean\" broken?\n\nNormally it is not, but if it is, they want to know it.  If git-clean\nremove something after \"make clean\" then maybe the later is incomplete.\n\nTo put it another way, if I make changes and share them with others, I\nwant to make sure that my changes will work for them.  If the mechanism\nfor sharing my changes is make-based, I rely on make to check them.  In\nprojects using Automake it's called \"make distcheck\".  If I'm sharing my\nchanges as a git patch, I want a git-based verification that the project\nstill builds from scratch.\n\nAlso, the files cleaned by \"make clean\" are normally build products.\nThings that you _really_ don't want to be in the source tree at the\nrelease time are other files, such as backup files with changes that you\ndecided to back out, sources that you may not share, firmware that cost\nyour company $50000 and so on.  \"make clean\" won't remove them.\n\n> No reason to waste time on make clean.\n> git ls-files -o | xargs rm\n> Does the same job nicely.\n\nThis would remove ignored files.  It's not always what I want.\n\n> Other typical usecases for me:\n> Remove temporaries that I created while trying out stuff.\n> Often I have a bunch of files named 'x', 'xx', 'fisk' etc.\n> around for no use. An easy way to remove these without breaking\n> my 'allmodconfig' build is nice. It anyway > 1 hour to build and\n> I like to get rid of the untracked stuff in an easy way.\n> \n> So use cases goes like this:\n> - Remove everything not tracked by git (including .gitignore files)\n> - Remove everything except tracked by git or ignored\n> - Remove ignored files (replacement of make clean) (seldom)\n\nI'll think about the later.\n\n> Above should work both from top-level dir and in subdirectories.\n> \n> That is my minimal expectations to git clean.\n> What Pavel came up with cover everything except the make clean\n> replacement part.\n\nExactly.  The \"make clean\" replacement is actually the one I didn't\nimplement.\n\n-- \nRegards,\nPavel Roskin\n"},{"id":"18365","messageId":"1144216844.3793.10.camel@dv","threadId":"3785","inReplyTo":"7vzmj2b3w3.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH] Add git-clean command","fromName":"Pavel Roskin","fromEmail":"proski@gnu.org","sentAt":"2006-04-05T06:00:44Z","receivedAt":"2006-04-05T06:00:44Z","isPatch":true,"sender":{"key":"proski@gnu.org","avatar":null},"body":"On Mon, 2006-04-03 at 17:06 -0700, Junio C Hamano wrote:\n> > diff --git a/git-clean.sh b/git-clean.sh\n> >...\n> > +for arg in \"$@\"; do\n> \n> \tfor arg\n>         do\n>         \t...\n\nI checked other git shell scripts and copied the \"while\" construct from\none of them - if it's good for other commands, it's good for git-clean.\n\n> > +\tif [ \"$arg\" = \"-d\" ]; then\n> \n> \tcase \"$arg\" in -d)...\n> \n> > +excl1=\n> > +excl2=\n> > +if [ -z \"$noexclude\" ]; then\n> > +\texcl1=\"--exclude-per-directory=.gitignore\"\n> > +\tif [ -f \"$GIT_DIR/info/exclude\" ]; then\n> > +\t\texcl2=\"--exclude-from=$GIT_DIR/info/exclude\"\n> > +\tfi\n> > +fi\n> > +\n> > +git-ls-files --others --directory \"$excl1\" \"$excl2\" |\n> > +while read -r file; do\n> > ...\n> \n> The $noexclude case passes two empty strings to git-ls-files,\n> which may happen to be harmless with the current implementation,\n> but does not feel quite right.\n\nGood catch.  This is needed since $GIT_DIR can contain spaces.  I\nbelieve ${excl2:+\"$excl2\"} would do the trick.\n\n> Maybe better to read ls-files -z to be really pathname safe, I\n> dunno.\n\nI think \"xargs -0\" has its own problems (argument length limitations),\nand the other solution is to use perl.  While at that, I'd rather\nrewrite the whole script in Perl, or maybe in even C.\n\nI think this should eventually happen to all git scripts, but I have no\nintention to do it right now unless you really want me to.\n\n> > +\t\t$echo1 \"Removing $file\"\n> > +\t\t[ \"$cleandirhard\" ] && chmod -R 700 \"$file\"\n> \n> I am not quite sure this chmod -R is a good idea.  If we are\n> trying really hard would we need to also make sure we can rmdir\n> the \"$file\" by chmod'ing its parent directory?  But once we\n> start doing that where would we stop?\n\nOK, I was undecided on that.  I'm dropping this option.\n\n-- \nRegards,\nPavel Roskin\n"},{"id":"18392","messageId":"87d5fwau3z.fsf_-_@rho.meyering.net","threadId":"3785","inReplyTo":"1144165927.30675.32.camel@dv","subject":"unchecked uses of strdup","fromName":"Jim Meyering","fromEmail":"jim@meyering.net","sentAt":"2006-04-05T16:02:24Z","receivedAt":"2006-04-05T16:02:24Z","isPatch":false,"sender":{"key":"jim@meyering.net","avatar":"https://avatars.githubusercontent.com/u/710630?v=4"},"body":"There are pretty many uses of strdup in git's sources.\nHere's one that can cause trouble if it ever returns NULL:\n\n    [from fsck-objects.c]\n    static int fsck_head_link(void)\n    {\n            unsigned char sha1[20];\n            const char *git_HEAD = strdup(git_path(\"HEAD\"));\n            const char *git_refs_heads_master = resolve_ref(git_HEAD, sha1, 1);\n\nThe problem is that resolve_ref does an unconditional `stat'\non the parameter corresponding to the maybe-NULL git_HEAD.\n\nOne solution is to change such uses of strdup to uses of xstrdup.\n"},{"id":"18421","messageId":"81b0412b0604060711o57fb110cm5fa559c0fd785a66@mail.gmail.com","threadId":"3785","inReplyTo":"87d5fwau3z.fsf_-_@rho.meyering.net","subject":"Re: unchecked uses of strdup","fromName":"Alex Riesen","fromEmail":"raa.lkml@gmail.com","sentAt":"2006-04-06T14:11:22Z","receivedAt":"2006-04-06T14:11:22Z","isPatch":false,"sender":{"key":"raa.lkml@gmail.com","avatar":"https://avatars.githubusercontent.com/u/324101?v=4"},"body":"On 4/5/06, Jim Meyering <jim@meyering.net> wrote:\n> There are pretty many uses of strdup in git's sources.\n> Here's one that can cause trouble if it ever returns NULL:\n>\n>     [from fsck-objects.c]\n>     static int fsck_head_link(void)\n>     {\n>             unsigned char sha1[20];\n>             const char *git_HEAD = strdup(git_path(\"HEAD\"));\n>             const char *git_refs_heads_master = resolve_ref(git_HEAD, sha1, 1);\n>\n> The problem is that resolve_ref does an unconditional `stat'\n> on the parameter corresponding to the maybe-NULL git_HEAD.\n\nThat's actually alright (aside a nice core file). Worse are the cases\nwhere a NULL would cause some \"normal\" behaviour, e.g. arguments,\nwhich have a meaning for NULL value.\n"}]}