{"thread":{"id":"12641","subject":"[PATCH] gc: call \"prune --expire 2.weeks.ago\"","startedAt":"2008-03-11T20:58:20Z","lastAt":"2008-03-13T11:11:01Z","messageCount":41,"participants":["Johannes Schindelin","Junio C Hamano","Nicolas Pitre","Marko Kreen","Pieter de Bie","Geert Bosch","Jeff King","Brandon Casey","Jakub Narebski","Wincent Colaiuta","Johannes Sixt"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"71755","messageId":"alpine.LSU.1.00.0803112157560.3873@racer.site","threadId":"12641","inReplyTo":null,"subject":"[PATCH] gc: call \"prune --expire 2.weeks.ago\"","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-03-11T20:58:20Z","receivedAt":"2008-03-11T20:58:20Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"\nIf \"--prune\" is passed to gc, it still just calls \"git prune\".\nOtherwise, \"prune --expire 2.weeks.ago\" is called, where the grace\nperiod is overrideable by the config variable gc.pruneExpire.\n\nWhile adding a test to t5304-prune.sh (since it really tests the\nimplicit call to \"prune\"), the original test for \"prune --expire\"\nis moved there from t1410-reflog.sh, where it did not belong.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n\n\tI am really tempted to reduce the grace period further, but\n\tI'd like to hear opinions first.  Is 3.days.ago too short?\n\n Documentation/config.txt |    5 +++++\n Documentation/git-gc.txt |   16 +++++++++++-----\n builtin-gc.c             |   19 +++++++++++++++++--\n t/t1410-reflog.sh        |   18 ------------------\n t/t5304-prune.sh         |   36 ++++++++++++++++++++++++++++++++++++\n 5 files changed, 69 insertions(+), 25 deletions(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex 14df635..adde89a 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -590,6 +590,11 @@ gc.packrefs::\n \tat some stage, and setting this to `false` will continue to\n \tprevent `git pack-refs` from being run from `git gc`.\n \n+gc.pruneexpire::\n+\tWhen `git gc` is run without `--prune`, it will still call\n+\t`prune`, but with `--expire 2.weeks.ago`.  Override the value\n+\twith this config variable.\n+\n gc.reflogexpire::\n \t`git reflog expire` removes reflog entries older than\n \tthis time; defaults to 90 days.\ndiff --git a/Documentation/git-gc.txt b/Documentation/git-gc.txt\nindex 2e7be91..2042d9f 100644\n--- a/Documentation/git-gc.txt\n+++ b/Documentation/git-gc.txt\n@@ -28,13 +28,19 @@ OPTIONS\n --prune::\n \tUsually `git-gc` packs refs, expires old reflog entries,\n \tpacks loose objects,\n-\tand removes old 'rerere' records.  Removal\n+\tand removes old 'rerere' records.  Unilateral removal\n \tof unreferenced loose objects is an unsafe operation\n \twhile other git operations are in progress, so it is not\n-\tdone by default.  Pass this option if you want it, and only\n-\twhen you know nobody else is creating new objects in the\n-\trepository at the same time (e.g. never use this option\n-\tin a cron script).\n+\tdone by default.\n++\n+Instead, `git-prune` is called with an option telling it to expire\n+only unreferenced loose objects that are at least 2 weeks old.  Set\n+the config variable `gc.pruneexpire` to override this grace period.\n++\n+Pass `--prune` to expire all unreferenced loose objects, but only\n+when you know nobody else is creating new objects in the\n+repository at the same time (e.g. never use this option\n+in a cron script).\n \n --aggressive::\n \tUsually 'git-gc' runs very quickly while providing good disk\ndiff --git a/builtin-gc.c b/builtin-gc.c\nindex 7cad366..8d07350 100644\n--- a/builtin-gc.c\n+++ b/builtin-gc.c\n@@ -26,12 +26,13 @@ static int pack_refs = 1;\n static int aggressive_window = 250;\n static int gc_auto_threshold = 6700;\n static int gc_auto_pack_limit = 20;\n+static char *prune_expire = \"2.weeks.ago\";\n \n #define MAX_ADD 10\n static const char *argv_pack_refs[] = {\"pack-refs\", \"--all\", \"--prune\", NULL};\n static const char *argv_reflog[] = {\"reflog\", \"expire\", \"--all\", NULL};\n static const char *argv_repack[MAX_ADD] = {\"repack\", \"-d\", \"-l\", NULL};\n-static const char *argv_prune[] = {\"prune\", NULL};\n+static const char *argv_prune[] = {\"prune\", NULL, NULL, NULL};\n static const char *argv_rerere[] = {\"rerere\", \"gc\", NULL};\n \n static int gc_config(const char *var, const char *value)\n@@ -55,6 +56,14 @@ static int gc_config(const char *var, const char *value)\n \t\tgc_auto_pack_limit = git_config_int(var, value);\n \t\treturn 0;\n \t}\n+\tif (!strcmp(var, \"gc.pruneexpire\")) {\n+\t\tif (!value)\n+\t\t\treturn config_error_nonbool(var);\n+\t\tif (!approxidate(value))\n+\t\t\treturn error(\"Invalid gc.pruneExpire: '%s'\", value);\n+\t\tprune_expire = xstrdup(value);\n+\t\treturn 0;\n+\t}\n \treturn git_default_config(var, value);\n }\n \n@@ -235,7 +244,13 @@ int cmd_gc(int argc, const char **argv, const char *prefix)\n \tif (run_command_v_opt(argv_repack, RUN_GIT_CMD))\n \t\treturn error(FAILED_RUN, argv_repack[0]);\n \n-\tif (prune && run_command_v_opt(argv_prune, RUN_GIT_CMD))\n+\tif (!prune) {\n+\t\targv_prune[1] = \"--expire\";\n+\t\targv_prune[2] = prune_expire;\n+\t\targv_prune[3] = NULL;\n+\t}\n+\n+\tif (run_command_v_opt(argv_prune, RUN_GIT_CMD))\n \t\treturn error(FAILED_RUN, argv_prune[0]);\n \n \tif (run_command_v_opt(argv_rerere, RUN_GIT_CMD))\ndiff --git a/t/t1410-reflog.sh b/t/t1410-reflog.sh\nindex 24476be..73f830d 100755\n--- a/t/t1410-reflog.sh\n+++ b/t/t1410-reflog.sh\n@@ -202,22 +202,4 @@ test_expect_success 'delete' '\n \n '\n \n-test_expect_success 'prune --expire' '\n-\n-\tbefore=$(git count-objects | sed \"s/ .*//\") &&\n-\tBLOB=$(echo aleph | git hash-object -w --stdin) &&\n-\tBLOB_FILE=.git/objects/$(echo $BLOB | sed \"s/^../&\\//\") &&\n-\ttest $((1 + $before)) = $(git count-objects | sed \"s/ .*//\") &&\n-\ttest -f $BLOB_FILE &&\n-\tgit reset --hard &&\n-\tgit prune --expire=1.hour.ago &&\n-\ttest $((1 + $before)) = $(git count-objects | sed \"s/ .*//\") &&\n-\ttest -f $BLOB_FILE &&\n-\ttest-chmtime -86500 $BLOB_FILE &&\n-\tgit prune --expire 1.day &&\n-\ttest $before = $(git count-objects | sed \"s/ .*//\") &&\n-\t! test -f $BLOB_FILE\n-\n-'\n-\n test_done\ndiff --git a/t/t5304-prune.sh b/t/t5304-prune.sh\nindex 6560af7..2a88b3f 100644\n--- a/t/t5304-prune.sh\n+++ b/t/t5304-prune.sh\n@@ -29,4 +29,40 @@ test_expect_success 'prune stale packs' '\n \n '\n \n+test_expect_success 'prune --expire' '\n+\n+\tbefore=$(git count-objects | sed \"s/ .*//\") &&\n+\tBLOB=$(echo aleph | git hash-object -w --stdin) &&\n+\tBLOB_FILE=.git/objects/$(echo $BLOB | sed \"s/^../&\\//\") &&\n+\ttest $((1 + $before)) = $(git count-objects | sed \"s/ .*//\") &&\n+\ttest -f $BLOB_FILE &&\n+\tgit prune --expire=1.hour.ago &&\n+\ttest $((1 + $before)) = $(git count-objects | sed \"s/ .*//\") &&\n+\ttest -f $BLOB_FILE &&\n+\ttest-chmtime -86500 $BLOB_FILE &&\n+\tgit prune --expire 1.day &&\n+\ttest $before = $(git count-objects | sed \"s/ .*//\") &&\n+\t! test -f $BLOB_FILE\n+\n+'\n+\n+test_expect_success 'gc: implicit prune --expire' '\n+\n+\tbefore=$(git count-objects | sed \"s/ .*//\") &&\n+\tBLOB=$(echo aleph_0 | git hash-object -w --stdin) &&\n+echo blob: $BLOB &&\n+\tBLOB_FILE=.git/objects/$(echo $BLOB | sed \"s/^../&\\//\") &&\n+\ttest $((1 + $before)) = $(git count-objects | sed \"s/ .*//\") &&\n+\ttest -f $BLOB_FILE &&\n+\ttest-chmtime -$((86400*14-30)) $BLOB_FILE &&\n+\tgit gc &&\n+\ttest $((1 + $before)) = $(git count-objects | sed \"s/ .*//\") &&\n+\ttest -f $BLOB_FILE &&\n+\ttest-chmtime -$((86400*14+1)) $BLOB_FILE &&\n+\tgit gc &&\n+\ttest $before = $(git count-objects | sed \"s/ .*//\") &&\n+\t! test -f $BLOB_FILE\n+\n+'\n+\n test_done\n-- \n1.5.4.4.646.ge37ad\n"},{"id":"71764","messageId":"7vskywadum.fsf@gitster.siamese.dyndns.org","threadId":"12641","inReplyTo":"alpine.LSU.1.00.0803112157560.3873@racer.site","subject":"Re: [PATCH] gc: call \"prune --expire 2.weeks.ago\"","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-03-12T02:13:53Z","receivedAt":"2008-03-12T02:13:53Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> If \"--prune\" is passed to gc, it still just calls \"git prune\".\n> Otherwise, \"prune --expire 2.weeks.ago\" is called, where the grace\n> period is overrideable by the config variable gc.pruneExpire.\n\n\"What it does.\"\n\n> While adding a test to t5304-prune.sh (since it really tests the\n> implicit call to \"prune\"), the original test for \"prune --expire\"\n> is moved there from t1410-reflog.sh, where it did not belong.\n\n\"What the fallouts from this change were.\"\n\n> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nCan we also have \"why this is a good idea\", \"what problem this solves\"?\n"},{"id":"71770","messageId":"alpine.LFD.1.00.0803112234470.2947@xanadu.home","threadId":"12641","inReplyTo":"7vskywadum.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH] gc: call \"prune --expire 2.weeks.ago\"","fromName":"Nicolas Pitre","fromEmail":"nico@cam.org","sentAt":"2008-03-12T02:37:09Z","receivedAt":"2008-03-12T02:37:09Z","isPatch":true,"sender":{"key":"nico@fluxnic.net","avatar":"https://avatars.githubusercontent.com/u/702790?v=4"},"body":"On Tue, 11 Mar 2008, Junio C Hamano wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n> > If \"--prune\" is passed to gc, it still just calls \"git prune\".\n> > Otherwise, \"prune --expire 2.weeks.ago\" is called, where the grace\n> > period is overrideable by the config variable gc.pruneExpire.\n> \n> \"What it does.\"\n> \n> > While adding a test to t5304-prune.sh (since it really tests the\n> > implicit call to \"prune\"), the original test for \"prune --expire\"\n> > is moved there from t1410-reflog.sh, where it did not belong.\n> \n> \"What the fallouts from this change were.\"\n> \n> > Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> \n> Can we also have \"why this is a good idea\", \"what problem this solves\"?\n\nFWIW, my agreeing with the \"why this is a good idea\" can be translated \ninto:\n\nAcked-by: Nicolas Pitre <nico@cam.org>\n\n\nNicolas\n"},{"id":"71787","messageId":"7vbq5k77z0.fsf@gitster.siamese.dyndns.org","threadId":"12641","inReplyTo":"alpine.LFD.1.00.0803112234470.2947@xanadu.home","subject":"Re: [PATCH] gc: call \"prune --expire 2.weeks.ago\"","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-03-12T06:49:07Z","receivedAt":"2008-03-12T06:49:07Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Nicolas Pitre <nico@cam.org> writes:\n\n>> Can we also have \"why this is a good idea\", \"what problem this solves\"?\n>\n> FWIW, my agreeing with the \"why this is a good idea\" can be translated \n> into:\n>\n> Acked-by: Nicolas Pitre <nico@cam.org>\n\nHmmm.  Is it _that_ obvious?\n\nAt least it would be easier to readers if we had something like this in\nthe documentation (and/or the commit message):\n\n    \"git gc\" used to never prune unreachable objects without being\n    explicitly told to, with its --prune option.  This left cruft to\n    accumulate; the user eventually has to run \"git prune\" manually.\n\n    It is safe to prune old objects that are unreachable from refs nor\n    reflogs.  \"git gc\" is updated to run \"git prune --expire 2.weeks.ago\"\n    so that users has to run \"git prune\" by hand much less often.\n\nIs it too much to ask for regulars to set the example of justifying why\neach of the change is a good idea?\n"},{"id":"71799","messageId":"alpine.LSU.1.00.0803121153160.1656@racer.site","threadId":"12641","inReplyTo":"7vbq5k77z0.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH] gc: call \"prune --expire 2.weeks.ago\"","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-03-12T10:57:39Z","receivedAt":"2008-03-12T10:57:39Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Tue, 11 Mar 2008, Junio C Hamano wrote:\n\n> Nicolas Pitre <nico@cam.org> writes:\n> \n> >> Can we also have \"why this is a good idea\", \"what problem this \n> >> solves\"?\n> >\n> > FWIW, my agreeing with the \"why this is a good idea\" can be translated \n> > into:\n> >\n> > Acked-by: Nicolas Pitre <nico@cam.org>\n> \n> Hmmm.  Is it _that_ obvious?\n> \n> At least it would be easier to readers if we had something like this in \n> the documentation (and/or the commit message):\n> \n>     \"git gc\" used to never prune unreachable objects without being\n>     explicitly told to, with its --prune option.  This left cruft to\n>     accumulate; the user eventually has to run \"git prune\" manually.\n> \n>     It is safe to prune old objects that are unreachable from refs nor\n>     reflogs.  \"git gc\" is updated to run \"git prune --expire 2.weeks.ago\"\n>     so that users has to run \"git prune\" by hand much less often.\n> \n> Is it too much to ask for regulars to set the example of justifying why \n> each of the change is a good idea?\n\nI would have written something like\n\n\tEarlier, git-gc would not prune loose objects without being called \n\twith --prune.  However, users were actively warned that it is not \n\ta safe operation, so most users never called it.\n\n\tThis makes the operation reasonably safe (unless you have critical \n\tgit operations running for over two weeks), by pruning only those \n\tobjects that are old (in the sense of git operations, which \n\ttypically take no more than a few seconds).\n\nHowever, I think that it should have been obvious to those who know the \ninternals of git-gc, and it is completely uninteresting to those that are \njust users.  All they will realise (or not) is that \"git gc --auto\" now \nless often complains about too many loose objects (hopefully).\n\nThe real question I asked was: is 2 weeks a sensible default?  As I said, \nI was almost tempted to reduce it to 3 days.\n\nHmm?\n\nCiao,\nDscho\n"},{"id":"71810","messageId":"alpine.LFD.1.00.0803121105481.2947@xanadu.home","threadId":"12641","inReplyTo":"7vbq5k77z0.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH] gc: call \"prune --expire 2.weeks.ago\"","fromName":"Nicolas Pitre","fromEmail":"nico@cam.org","sentAt":"2008-03-12T15:07:35Z","receivedAt":"2008-03-12T15:07:35Z","isPatch":true,"sender":{"key":"nico@fluxnic.net","avatar":"https://avatars.githubusercontent.com/u/702790?v=4"},"body":"On Tue, 11 Mar 2008, Junio C Hamano wrote:\n\n> Nicolas Pitre <nico@cam.org> writes:\n> \n> >> Can we also have \"why this is a good idea\", \"what problem this solves\"?\n> >\n> > FWIW, my agreeing with the \"why this is a good idea\" can be translated \n> > into:\n> >\n> > Acked-by: Nicolas Pitre <nico@cam.org>\n> \n> Hmmm.  Is it _that_ obvious?\n\nTo the average user, maybe not.  But My ack is orthogonal to that issue.\n\n\nNicolas\n"},{"id":"71812","messageId":"e51f66da0803120832p579d49fdmc4801b004e8cdabb@mail.gmail.com","threadId":"12641","inReplyTo":"alpine.LFD.1.00.0803121105481.2947@xanadu.home","subject":"Re: [PATCH] gc: call \"prune --expire 2.weeks.ago\"","fromName":"Marko Kreen","fromEmail":"markokr@gmail.com","sentAt":"2008-03-12T15:32:47Z","receivedAt":"2008-03-12T15:32:47Z","isPatch":true,"sender":{"key":"markokr@gmail.com","avatar":null},"body":"On 3/12/08, Nicolas Pitre <nico@cam.org> wrote:\n> On Tue, 11 Mar 2008, Junio C Hamano wrote:\n> > Nicolas Pitre <nico@cam.org> writes:\n>  > >> Can we also have \"why this is a good idea\", \"what problem this solves\"?\n>  > >\n>  > > FWIW, my agreeing with the \"why this is a good idea\" can be translated\n>  > > into:\n>  > >\n>  > > Acked-by: Nicolas Pitre <nico@cam.org>\n>  >\n>  > Hmmm.  Is it _that_ obvious?\n>\n> To the average user, maybe not.  But My ack is orthogonal to that issue.\n\nWell, I'm a newbie user and now I'm trained to always do \"gc --prune\",\nbecause \"gc\" itself does not make tree \"really\" clean.\n\nBut this will quite likely bit me in the long run.\n\nSo from my newbie perspective, anything that decreases\nnumber of mandatory arguments to commands is good.\n*cough* commit -a *cough*\n\nBut the difference from 'commit -a' is that its not a style\nissue - \"gc\" without --prune will keep stuff around indefinitely,\nwhich makes occasional --prune usage mandatory.  As its annoying\nto memorize when it was last ran, its easier to use it always.\n\nSo from my newbie perpective, +1 for making plain \"gc\" work.\n\n-- \nmarko\n"},{"id":"71815","messageId":"alpine.LFD.1.00.0803121143170.2947@xanadu.home","threadId":"12641","inReplyTo":"alpine.LSU.1.00.0803121153160.1656@racer.site","subject":"Re: [PATCH] gc: call \"prune --expire 2.weeks.ago\"","fromName":"Nicolas Pitre","fromEmail":"nico@cam.org","sentAt":"2008-03-12T15:45:07Z","receivedAt":"2008-03-12T15:45:07Z","isPatch":true,"sender":{"key":"nico@fluxnic.net","avatar":"https://avatars.githubusercontent.com/u/702790?v=4"},"body":"On Wed, 12 Mar 2008, Johannes Schindelin wrote:\n\n> The real question I asked was: is 2 weeks a sensible default?  As I said, \n> I was almost tempted to reduce it to 3 days.\n\n3 days would make me nervous, even if it should be plenty safe.\n\n2 weeks is OTOH maybe a bit too conservative.\n\nWhat about one week instead?\n\n\nNicolas\n"},{"id":"71816","messageId":"FE263BF7-9948-463C-B9B2-833B068EB10B@ai.rug.nl","threadId":"12641","inReplyTo":"alpine.LFD.1.00.0803121143170.2947@xanadu.home","subject":"Re: [PATCH] gc: call \"prune --expire 2.weeks.ago\"","fromName":"Pieter de Bie","fromEmail":"pdebie@ai.rug.nl","sentAt":"2008-03-12T15:53:25Z","receivedAt":"2008-03-12T15:53:25Z","isPatch":true,"sender":{"key":"pdebie@ai.rug.nl","avatar":null},"body":"\nOn Mar 12, 2008, at 4:45 PM, Nicolas Pitre wrote:\n\n>\n> 2 weeks is OTOH maybe a bit too conservative.\n>\n> What about one week instead?\n\nI'd really like it to be at least 2 weeks\n\n- Pieter\n"},{"id":"71818","messageId":"alpine.LSU.1.00.0803121705330.1656@racer.site","threadId":"12641","inReplyTo":"FE263BF7-9948-463C-B9B2-833B068EB10B@ai.rug.nl","subject":"Re: [PATCH] gc: call \"prune --expire 2.weeks.ago\"","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-03-12T16:05:51Z","receivedAt":"2008-03-12T16:05:51Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Wed, 12 Mar 2008, Pieter de Bie wrote:\n\n> On Mar 12, 2008, at 4:45 PM, Nicolas Pitre wrote:\n> \n> > 2 weeks is OTOH maybe a bit too conservative.\n> >\n> > What about one week instead?\n> \n> I'd really like it to be at least 2 weeks\n\nCould you back that up with an explanation, as to why?\n\nThanks,\nDscho\n"},{"id":"71821","messageId":"F3B86403-2AB7-4F65-85FD-FF3243B69C77@adacore.com","threadId":"12641","inReplyTo":"alpine.LSU.1.00.0803121153160.1656@racer.site","subject":"Re: [PATCH] gc: call \"prune --expire 2.weeks.ago\"","fromName":"Geert Bosch","fromEmail":"bosch@adacore.com","sentAt":"2008-03-12T16:20:55Z","receivedAt":"2008-03-12T16:20:55Z","isPatch":true,"sender":{"key":"bosch@adacore.com","avatar":null},"body":"\nOn Mar 12, 2008, at 06:57, Johannes Schindelin wrote:\n> The real question I asked was: is 2 weeks a sensible default?  As I  \n> said,\n> I was almost tempted to reduce it to 3 days.\n>\n> Hmm?\n\nTwo weeks is a sensible default. Many people don't use their SCM every\nday (really!). Say you'd work on something friday, mess up and go home,\nit would be quite bad on monday morning to find that gc kicks in and\nremoves some objects you're trying to recover.\n\nThe only point is to reduce build-up over long periods,\nso two weeks seems a perfectly fine cut-off.\n"},{"id":"71823","messageId":"20080312170155.GB11236@coredump.intra.peff.net","threadId":"12641","inReplyTo":"alpine.LSU.1.00.0803121705330.1656@racer.site","subject":"Re: [PATCH] gc: call \"prune --expire 2.weeks.ago\"","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2008-03-12T17:01:55Z","receivedAt":"2008-03-12T17:01:55Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Wed, Mar 12, 2008 at 05:05:51PM +0100, Johannes Schindelin wrote:\n\n> > I'd really like it to be at least 2 weeks\n> \n> Could you back that up with an explanation, as to why?\n\nI assume it's \"because I wouldn't want to lose work I had done within\nthe last two weeks.\" Yes, I know that this expiration is actually after\nthe reflog has already expired, but there is a loophole there: branches\nthat have been deleted have their reflogs deleted (some have argued that\nthis doesn't matter, since the HEAD reflog will still mention the\ncommits. In most cases, this is true, though there are still a few\nexceptions).\n\nI think being conservative here is a good idea. The big reason for this\nis to fix the spurious \"gc --auto\" runs caused by needing to prune. So\nthere is no downside to increasing the time limit unless you think\npeople will generate enough objects in that limit to cause the problem\nagain. In which case they will continue to complain to the list, and we\ncan drop the time.\n\n-Peff\n"},{"id":"71824","messageId":"alpine.LSU.1.00.0803121833210.1656@racer.site","threadId":"12641","inReplyTo":"alpine.LFD.1.00.0803112234470.2947@xanadu.home","subject":"[PATCH v2] gc: call \"prune --expire 2.weeks.ago\" by default","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-03-12T17:35:02Z","receivedAt":"2008-03-12T17:35:02Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"\nThe only reason we did not call \"prune\" in git-gc was that it is an\ninherently dangerous operation: if there is a commit going on, you will\nprune loose objects that were just created, and are, in fact, needed by the\ncommit object just about to be created.\n\nSince it is dangerous, we told users so.  That led to many users not even\ndaring to run it when it was actually safe. Besides, they are users, and\nshould not have to remember such details as when to call git-gc with\n--prune, or to call git-prune directly.\n\nOf course, the consequence was that \"git gc --auto\" gets triggered much\nmore often than we would like, since unreferenced loose objects (such as\nleft-overs from a rebase or a reset --hard) were never pruned.\n\nAlas, git-prune recently learnt the option --expire <minimum-age>, which\nmakes it a much safer operation.  This allows us to call prune from git-gc,\nwith a grace period of 2 weeks for the unreferenced loose objects (this\nvalue was determined in a discussion on the git list as a safe one).\n\nIf you want to override this grace period, just set the config variable\ngc.pruneExpire to a different value; an example would be\n\n\t[gc]\n\t\tpruneExpire = 6.months.ago\n\nif you feel really paranoid.\n\nNote that this new behaviour does not affect git-gc when you pass the\noption --prune; in that case, prune will clean up the loose objects with no\ngrace period at all.\n\nWhile adding a test to t5304-prune.sh (since it really tests the implicit\ncall to \"prune\"), also the original test for \"prune --expire\" was moved\nthere from t1410-reflog.sh, where it did not belong.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\nAcked-by: Nicolas Pitre <nico@cam.org>\n\n---\n\n\tSince my original suggestion of 2 weeks was more or less agreed \n\tupon, I only reworked the commit message, and added the Ack of \n\tNico.\n\n\tJunio, is this message good enough?\n\n Documentation/config.txt |    5 +++++\n Documentation/git-gc.txt |   16 +++++++++++-----\n builtin-gc.c             |   19 +++++++++++++++++--\n t/t1410-reflog.sh        |   18 ------------------\n t/t5304-prune.sh         |   36 ++++++++++++++++++++++++++++++++++++\n 5 files changed, 69 insertions(+), 25 deletions(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex f64b269..db5b2dc 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -590,6 +590,11 @@ gc.packrefs::\n \tat some stage, and setting this to `false` will continue to\n \tprevent `git pack-refs` from being run from `git gc`.\n \n+gc.pruneexpire::\n+\tWhen `git gc` is run without `--prune`, it will still call\n+\t`prune`, but with `--expire 2.weeks.ago`.  Override the value\n+\twith this config variable.\n+\n gc.reflogexpire::\n \t`git reflog expire` removes reflog entries older than\n \tthis time; defaults to 90 days.\ndiff --git a/Documentation/git-gc.txt b/Documentation/git-gc.txt\nindex 2e7be91..2042d9f 100644\n--- a/Documentation/git-gc.txt\n+++ b/Documentation/git-gc.txt\n@@ -28,13 +28,19 @@ OPTIONS\n --prune::\n \tUsually `git-gc` packs refs, expires old reflog entries,\n \tpacks loose objects,\n-\tand removes old 'rerere' records.  Removal\n+\tand removes old 'rerere' records.  Unilateral removal\n \tof unreferenced loose objects is an unsafe operation\n \twhile other git operations are in progress, so it is not\n-\tdone by default.  Pass this option if you want it, and only\n-\twhen you know nobody else is creating new objects in the\n-\trepository at the same time (e.g. never use this option\n-\tin a cron script).\n+\tdone by default.\n++\n+Instead, `git-prune` is called with an option telling it to expire\n+only unreferenced loose objects that are at least 2 weeks old.  Set\n+the config variable `gc.pruneexpire` to override this grace period.\n++\n+Pass `--prune` to expire all unreferenced loose objects, but only\n+when you know nobody else is creating new objects in the\n+repository at the same time (e.g. never use this option\n+in a cron script).\n \n --aggressive::\n \tUsually 'git-gc' runs very quickly while providing good disk\ndiff --git a/builtin-gc.c b/builtin-gc.c\nindex 7cad366..8d07350 100644\n--- a/builtin-gc.c\n+++ b/builtin-gc.c\n@@ -26,12 +26,13 @@ static int pack_refs = 1;\n static int aggressive_window = 250;\n static int gc_auto_threshold = 6700;\n static int gc_auto_pack_limit = 20;\n+static char *prune_expire = \"2.weeks.ago\";\n \n #define MAX_ADD 10\n static const char *argv_pack_refs[] = {\"pack-refs\", \"--all\", \"--prune\", NULL};\n static const char *argv_reflog[] = {\"reflog\", \"expire\", \"--all\", NULL};\n static const char *argv_repack[MAX_ADD] = {\"repack\", \"-d\", \"-l\", NULL};\n-static const char *argv_prune[] = {\"prune\", NULL};\n+static const char *argv_prune[] = {\"prune\", NULL, NULL, NULL};\n static const char *argv_rerere[] = {\"rerere\", \"gc\", NULL};\n \n static int gc_config(const char *var, const char *value)\n@@ -55,6 +56,14 @@ static int gc_config(const char *var, const char *value)\n \t\tgc_auto_pack_limit = git_config_int(var, value);\n \t\treturn 0;\n \t}\n+\tif (!strcmp(var, \"gc.pruneexpire\")) {\n+\t\tif (!value)\n+\t\t\treturn config_error_nonbool(var);\n+\t\tif (!approxidate(value))\n+\t\t\treturn error(\"Invalid gc.pruneExpire: '%s'\", value);\n+\t\tprune_expire = xstrdup(value);\n+\t\treturn 0;\n+\t}\n \treturn git_default_config(var, value);\n }\n \n@@ -235,7 +244,13 @@ int cmd_gc(int argc, const char **argv, const char *prefix)\n \tif (run_command_v_opt(argv_repack, RUN_GIT_CMD))\n \t\treturn error(FAILED_RUN, argv_repack[0]);\n \n-\tif (prune && run_command_v_opt(argv_prune, RUN_GIT_CMD))\n+\tif (!prune) {\n+\t\targv_prune[1] = \"--expire\";\n+\t\targv_prune[2] = prune_expire;\n+\t\targv_prune[3] = NULL;\n+\t}\n+\n+\tif (run_command_v_opt(argv_prune, RUN_GIT_CMD))\n \t\treturn error(FAILED_RUN, argv_prune[0]);\n \n \tif (run_command_v_opt(argv_rerere, RUN_GIT_CMD))\ndiff --git a/t/t1410-reflog.sh b/t/t1410-reflog.sh\nindex 24476be..73f830d 100755\n--- a/t/t1410-reflog.sh\n+++ b/t/t1410-reflog.sh\n@@ -202,22 +202,4 @@ test_expect_success 'delete' '\n \n '\n \n-test_expect_success 'prune --expire' '\n-\n-\tbefore=$(git count-objects | sed \"s/ .*//\") &&\n-\tBLOB=$(echo aleph | git hash-object -w --stdin) &&\n-\tBLOB_FILE=.git/objects/$(echo $BLOB | sed \"s/^../&\\//\") &&\n-\ttest $((1 + $before)) = $(git count-objects | sed \"s/ .*//\") &&\n-\ttest -f $BLOB_FILE &&\n-\tgit reset --hard &&\n-\tgit prune --expire=1.hour.ago &&\n-\ttest $((1 + $before)) = $(git count-objects | sed \"s/ .*//\") &&\n-\ttest -f $BLOB_FILE &&\n-\ttest-chmtime -86500 $BLOB_FILE &&\n-\tgit prune --expire 1.day &&\n-\ttest $before = $(git count-objects | sed \"s/ .*//\") &&\n-\t! test -f $BLOB_FILE\n-\n-'\n-\n test_done\ndiff --git a/t/t5304-prune.sh b/t/t5304-prune.sh\nindex 6560af7..2a88b3f 100644\n--- a/t/t5304-prune.sh\n+++ b/t/t5304-prune.sh\n@@ -29,4 +29,40 @@ test_expect_success 'prune stale packs' '\n \n '\n \n+test_expect_success 'prune --expire' '\n+\n+\tbefore=$(git count-objects | sed \"s/ .*//\") &&\n+\tBLOB=$(echo aleph | git hash-object -w --stdin) &&\n+\tBLOB_FILE=.git/objects/$(echo $BLOB | sed \"s/^../&\\//\") &&\n+\ttest $((1 + $before)) = $(git count-objects | sed \"s/ .*//\") &&\n+\ttest -f $BLOB_FILE &&\n+\tgit prune --expire=1.hour.ago &&\n+\ttest $((1 + $before)) = $(git count-objects | sed \"s/ .*//\") &&\n+\ttest -f $BLOB_FILE &&\n+\ttest-chmtime -86500 $BLOB_FILE &&\n+\tgit prune --expire 1.day &&\n+\ttest $before = $(git count-objects | sed \"s/ .*//\") &&\n+\t! test -f $BLOB_FILE\n+\n+'\n+\n+test_expect_success 'gc: implicit prune --expire' '\n+\n+\tbefore=$(git count-objects | sed \"s/ .*//\") &&\n+\tBLOB=$(echo aleph_0 | git hash-object -w --stdin) &&\n+echo blob: $BLOB &&\n+\tBLOB_FILE=.git/objects/$(echo $BLOB | sed \"s/^../&\\//\") &&\n+\ttest $((1 + $before)) = $(git count-objects | sed \"s/ .*//\") &&\n+\ttest -f $BLOB_FILE &&\n+\ttest-chmtime -$((86400*14-30)) $BLOB_FILE &&\n+\tgit gc &&\n+\ttest $((1 + $before)) = $(git count-objects | sed \"s/ .*//\") &&\n+\ttest -f $BLOB_FILE &&\n+\ttest-chmtime -$((86400*14+1)) $BLOB_FILE &&\n+\tgit gc &&\n+\ttest $before = $(git count-objects | sed \"s/ .*//\") &&\n+\t! test -f $BLOB_FILE\n+\n+'\n+\n test_done\n-- \n1.5.4.4.694.g43223\n"},{"id":"71825","messageId":"47D8193B.901@nrlssc.navy.mil","threadId":"12641","inReplyTo":"alpine.LSU.1.00.0803121833210.1656@racer.site","subject":"Re: [PATCH v2] gc: call \"prune --expire 2.weeks.ago\" by default","fromName":"Brandon Casey","fromEmail":"casey@nrlssc.navy.mil","sentAt":"2008-03-12T17:56:11Z","receivedAt":"2008-03-12T17:56:11Z","isPatch":true,"sender":{"key":"drafnel@gmail.com","avatar":"https://avatars.githubusercontent.com/u/921167?v=4"},"body":"Johannes Schindelin wrote:\n> If you want to override this grace period, just set the config variable\n> gc.pruneExpire to a different value; an example would be\n> \n> \t[gc]\n> \t\tpruneExpire = 6.months.ago\n> \n> if you feel really paranoid.\n> \n> Note that this new behaviour does not affect git-gc when you pass the\n> option --prune; in that case, prune will clean up the loose objects with no\n> grace period at all.\n\nHmm. Perhaps 'git-gc' should always call 'prune' with the '--expire' argument\nfor simplicity of the 'git-gc' interface and --prune should become a noop?\n\nIs 'git-gc --prune' still useful to end users when those in-the-know can use\ngit-prune when they really want all loose unreferenced objects to be removed?\n\nAlso, what about clones created with --shared or --reference? Should there be\na way to disable this functionality? gc.pruneExpire never\n\n-brandon\n"},{"id":"71826","messageId":"m3prtzyens.fsf@localhost.localdomain","threadId":"12641","inReplyTo":"47D8193B.901@nrlssc.navy.mil","subject":"Re: [PATCH v2] gc: call \"prune --expire 2.weeks.ago\" by default","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2008-03-12T18:35:23Z","receivedAt":"2008-03-12T18:35:23Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Brandon Casey <casey@nrlssc.navy.mil> writes:\n\n> Is 'git-gc --prune' still useful to end users when those in-the-know can use\n> git-prune when they really want all loose unreferenced objects to be removed?\n\nIt is one command less to remember (just like with \"git tag --verify\"\nand \"git verify-tag\"), so I'm all for \"git gc --prune\" to remain.\n \n> Also, what about clones created with --shared or --reference? Should there be\n> a way to disable this functionality? gc.pruneExpire never\n\nThat would be nice.\n\n-- \nJakub Narebski\nPoland\nShadeHawk on #git\n"},{"id":"71828","messageId":"alpine.LSU.1.00.0803122005330.1656@racer.site","threadId":"12641","inReplyTo":"m3prtzyens.fsf@localhost.localdomain","subject":"Re: [PATCH v2] gc: call \"prune --expire 2.weeks.ago\" by default","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-03-12T19:07:23Z","receivedAt":"2008-03-12T19:07:23Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Wed, 12 Mar 2008, Jakub Narebski wrote:\n\n> Brandon Casey <casey@nrlssc.navy.mil> writes:\n> \n> > Is 'git-gc --prune' still useful to end users when those in-the-know \n> > can use git-prune when they really want all loose unreferenced objects \n> > to be removed?\n> \n> It is one command less to remember (just like with \"git tag --verify\" \n> and \"git verify-tag\"), so I'm all for \"git gc --prune\" to remain.\n\nI don't care one way or the other.\n\n> > Also, what about clones created with --shared or --reference? Should \n> > there be a way to disable this functionality? gc.pruneExpire never\n> \n> That would be nice.\n\nOkay, so I just remove the !approxidate() check.  Then, \"gc.pruneExpire = \nnever\" should work as you expect it to.\n\nCiao,\nDscho\n"},{"id":"71831","messageId":"7viqzr69ka.fsf@gitster.siamese.dyndns.org","threadId":"12641","inReplyTo":"alpine.LSU.1.00.0803122005330.1656@racer.site","subject":"Re: [PATCH v2] gc: call \"prune --expire 2.weeks.ago\" by default","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-03-12T19:12:21Z","receivedAt":"2008-03-12T19:12:21Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> Okay, so I just remove the !approxidate() check.  Then, \"gc.pruneExpire = \n> never\" should work as you expect it to.\n\nHuh?  date.c::special[] has \"never\" defined for this exact reason.\n"},{"id":"71833","messageId":"alpine.LSU.1.00.0803122035580.1656@racer.site","threadId":"12641","inReplyTo":"7viqzr69ka.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH v2] gc: call \"prune --expire 2.weeks.ago\" by default","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-03-12T19:38:14Z","receivedAt":"2008-03-12T19:38:14Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Wed, 12 Mar 2008, Junio C Hamano wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n> > Okay, so I just remove the !approxidate() check.  Then, \"gc.pruneExpire = \n> > never\" should work as you expect it to.\n> \n> Huh?  date.c::special[] has \"never\" defined for this exact reason.\n\nOops.  I thought that approxidate() returns 0 on error, but apparently \nthis is not so.  Instead, it returns \"now\"!\n\nSo first of all, my patch is incorrect, and second: invalid dates cannot \nbe caught reliably.\n\nDarn.\n\nCiao,\nDscho \"who'll think about a way around that\"\n"},{"id":"71834","messageId":"alpine.LSU.1.00.0803122051340.1656@racer.site","threadId":"12641","inReplyTo":"7viqzr69ka.fsf@gitster.siamese.dyndns.org","subject":"[PATCH v3] gc: call \"prune --expire 2.weeks.ago\" by default","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-03-12T19:53:25Z","receivedAt":"2008-03-12T19:53:25Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"\nThe only reason we did not call \"prune\" in git-gc was that it is an\ninherently dangerous operation: if there is a commit going on, you will\nprune loose objects that were just created, and are, in fact, needed by the\ncommit object just about to be created.\n\nSince it is dangerous, we told users so.  That led to many users not even\ndaring to run it when it was actually safe. Besides, they are users, and\nshould not have to remember such details as when to call git-gc with\n--prune, or to call git-prune directly.\n\nOf course, the consequence was that \"git gc --auto\" gets triggered much\nmore often than we would like, since unreferenced loose objects (such as\nleft-overs from a rebase or a reset --hard) were never pruned.\n\nAlas, git-prune recently learnt the option --expire <minimum-age>, which\nmakes it a much safer operation.  This allows us to call prune from git-gc,\nwith a grace period of 2 weeks for the unreferenced loose objects (this\nvalue was determined in a discussion on the git list as a safe one).\n\nIf you want to override this grace period, just set the config variable\ngc.pruneExpire to a different value; an example would be\n\n\t[gc]\n\t\tpruneExpire = 6.months.ago\n\nif you feel really paranoid.\n\nNote that this new behaviour does not affect git-gc when you pass the\noption --prune; in that case, prune will clean up the loose objects with no\ngrace period at all.\n\nWhile adding a test to t5304-prune.sh (since it really tests the implicit\ncall to \"prune\"), also the original test for \"prune --expire\" was moved\nthere from t1410-reflog.sh, where it did not belong.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n\n\tThis checks for an invalid gc.pruneExpire by assuming that an \n\tinvalid date string is not \"now\", but parses to the same value\n\t(or actually newer, since between the two calls to approxidate(), \n\tthere is a slight chance of a wrapover to the next second).\n\n\tSo yes, gc.pruneExpire = never should work now.\n\n Documentation/config.txt |    5 +++++\n Documentation/git-gc.txt |   16 +++++++++++-----\n builtin-gc.c             |   20 ++++++++++++++++++--\n t/t1410-reflog.sh        |   18 ------------------\n t/t5304-prune.sh         |   44 ++++++++++++++++++++++++++++++++++++++++++++\n 5 files changed, 78 insertions(+), 25 deletions(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex f64b269..db5b2dc 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -590,6 +590,11 @@ gc.packrefs::\n \tat some stage, and setting this to `false` will continue to\n \tprevent `git pack-refs` from being run from `git gc`.\n \n+gc.pruneexpire::\n+\tWhen `git gc` is run without `--prune`, it will still call\n+\t`prune`, but with `--expire 2.weeks.ago`.  Override the value\n+\twith this config variable.\n+\n gc.reflogexpire::\n \t`git reflog expire` removes reflog entries older than\n \tthis time; defaults to 90 days.\ndiff --git a/Documentation/git-gc.txt b/Documentation/git-gc.txt\nindex 2e7be91..2042d9f 100644\n--- a/Documentation/git-gc.txt\n+++ b/Documentation/git-gc.txt\n@@ -28,13 +28,19 @@ OPTIONS\n --prune::\n \tUsually `git-gc` packs refs, expires old reflog entries,\n \tpacks loose objects,\n-\tand removes old 'rerere' records.  Removal\n+\tand removes old 'rerere' records.  Unilateral removal\n \tof unreferenced loose objects is an unsafe operation\n \twhile other git operations are in progress, so it is not\n-\tdone by default.  Pass this option if you want it, and only\n-\twhen you know nobody else is creating new objects in the\n-\trepository at the same time (e.g. never use this option\n-\tin a cron script).\n+\tdone by default.\n++\n+Instead, `git-prune` is called with an option telling it to expire\n+only unreferenced loose objects that are at least 2 weeks old.  Set\n+the config variable `gc.pruneexpire` to override this grace period.\n++\n+Pass `--prune` to expire all unreferenced loose objects, but only\n+when you know nobody else is creating new objects in the\n+repository at the same time (e.g. never use this option\n+in a cron script).\n \n --aggressive::\n \tUsually 'git-gc' runs very quickly while providing good disk\ndiff --git a/builtin-gc.c b/builtin-gc.c\nindex 7cad366..9663fae 100644\n--- a/builtin-gc.c\n+++ b/builtin-gc.c\n@@ -26,12 +26,13 @@ static int pack_refs = 1;\n static int aggressive_window = 250;\n static int gc_auto_threshold = 6700;\n static int gc_auto_pack_limit = 20;\n+static char *prune_expire = \"2.weeks.ago\";\n \n #define MAX_ADD 10\n static const char *argv_pack_refs[] = {\"pack-refs\", \"--all\", \"--prune\", NULL};\n static const char *argv_reflog[] = {\"reflog\", \"expire\", \"--all\", NULL};\n static const char *argv_repack[MAX_ADD] = {\"repack\", \"-d\", \"-l\", NULL};\n-static const char *argv_prune[] = {\"prune\", NULL};\n+static const char *argv_prune[] = {\"prune\", NULL, NULL, NULL};\n static const char *argv_rerere[] = {\"rerere\", \"gc\", NULL};\n \n static int gc_config(const char *var, const char *value)\n@@ -55,6 +56,15 @@ static int gc_config(const char *var, const char *value)\n \t\tgc_auto_pack_limit = git_config_int(var, value);\n \t\treturn 0;\n \t}\n+\tif (!strcmp(var, \"gc.pruneexpire\")) {\n+\t\tif (!value)\n+\t\t\treturn config_error_nonbool(var);\n+\t\tif (strcmp(value, \"now\") &&\n+\t\t\t\tapproxidate(value) - approxidate(\"now\") >= 0)\n+\t\t\treturn error(\"Invalid gc.pruneExpire: '%s'\", value);\n+\t\tprune_expire = xstrdup(value);\n+\t\treturn 0;\n+\t}\n \treturn git_default_config(var, value);\n }\n \n@@ -235,7 +245,13 @@ int cmd_gc(int argc, const char **argv, const char *prefix)\n \tif (run_command_v_opt(argv_repack, RUN_GIT_CMD))\n \t\treturn error(FAILED_RUN, argv_repack[0]);\n \n-\tif (prune && run_command_v_opt(argv_prune, RUN_GIT_CMD))\n+\tif (!prune) {\n+\t\targv_prune[1] = \"--expire\";\n+\t\targv_prune[2] = prune_expire;\n+\t\targv_prune[3] = NULL;\n+\t}\n+\n+\tif (run_command_v_opt(argv_prune, RUN_GIT_CMD))\n \t\treturn error(FAILED_RUN, argv_prune[0]);\n \n \tif (run_command_v_opt(argv_rerere, RUN_GIT_CMD))\ndiff --git a/t/t1410-reflog.sh b/t/t1410-reflog.sh\nindex 24476be..73f830d 100755\n--- a/t/t1410-reflog.sh\n+++ b/t/t1410-reflog.sh\n@@ -202,22 +202,4 @@ test_expect_success 'delete' '\n \n '\n \n-test_expect_success 'prune --expire' '\n-\n-\tbefore=$(git count-objects | sed \"s/ .*//\") &&\n-\tBLOB=$(echo aleph | git hash-object -w --stdin) &&\n-\tBLOB_FILE=.git/objects/$(echo $BLOB | sed \"s/^../&\\//\") &&\n-\ttest $((1 + $before)) = $(git count-objects | sed \"s/ .*//\") &&\n-\ttest -f $BLOB_FILE &&\n-\tgit reset --hard &&\n-\tgit prune --expire=1.hour.ago &&\n-\ttest $((1 + $before)) = $(git count-objects | sed \"s/ .*//\") &&\n-\ttest -f $BLOB_FILE &&\n-\ttest-chmtime -86500 $BLOB_FILE &&\n-\tgit prune --expire 1.day &&\n-\ttest $before = $(git count-objects | sed \"s/ .*//\") &&\n-\t! test -f $BLOB_FILE\n-\n-'\n-\n test_done\ndiff --git a/t/t5304-prune.sh b/t/t5304-prune.sh\nindex 6560af7..3b6b01d 100644\n--- a/t/t5304-prune.sh\n+++ b/t/t5304-prune.sh\n@@ -29,4 +29,48 @@ test_expect_success 'prune stale packs' '\n \n '\n \n+test_expect_success 'prune --expire' '\n+\n+\tbefore=$(git count-objects | sed \"s/ .*//\") &&\n+\tBLOB=$(echo aleph | git hash-object -w --stdin) &&\n+\tBLOB_FILE=.git/objects/$(echo $BLOB | sed \"s/^../&\\//\") &&\n+\ttest $((1 + $before)) = $(git count-objects | sed \"s/ .*//\") &&\n+\ttest -f $BLOB_FILE &&\n+\tgit prune --expire=1.hour.ago &&\n+\ttest $((1 + $before)) = $(git count-objects | sed \"s/ .*//\") &&\n+\ttest -f $BLOB_FILE &&\n+\ttest-chmtime -86500 $BLOB_FILE &&\n+\tgit prune --expire 1.day &&\n+\ttest $before = $(git count-objects | sed \"s/ .*//\") &&\n+\t! test -f $BLOB_FILE\n+\n+'\n+\n+test_expect_success 'gc: implicit prune --expire' '\n+\n+\tbefore=$(git count-objects | sed \"s/ .*//\") &&\n+\tBLOB=$(echo aleph_0 | git hash-object -w --stdin) &&\n+\tBLOB_FILE=.git/objects/$(echo $BLOB | sed \"s/^../&\\//\") &&\n+\ttest $((1 + $before)) = $(git count-objects | sed \"s/ .*//\") &&\n+\ttest -f $BLOB_FILE &&\n+\ttest-chmtime -$((86400*14-30)) $BLOB_FILE &&\n+\tgit gc &&\n+\ttest $((1 + $before)) = $(git count-objects | sed \"s/ .*//\") &&\n+\ttest -f $BLOB_FILE &&\n+\ttest-chmtime -$((86400*14+1)) $BLOB_FILE &&\n+\tgit gc &&\n+\ttest $before = $(git count-objects | sed \"s/ .*//\") &&\n+\t! test -f $BLOB_FILE\n+\n+'\n+\n+test_expect_success 'gc: refuse to start with invalid gc.pruneExpire' '\n+\n+\tgit config gc.pruneExpire invalid &&\n+\ttest_must_fail git gc &&\n+\tgit config gc.pruneExpire now &&\n+\tgit gc\n+\n+'\n+\n test_done\n-- \n1.5.4.4.694.g43223\n"},{"id":"71836","messageId":"alpine.LSU.1.00.0803122054570.1656@racer.site","threadId":"12641","inReplyTo":"alpine.LSU.1.00.0803122051340.1656@racer.site","subject":"Re: [PATCH v3] gc: call \"prune --expire 2.weeks.ago\" by default","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-03-12T19:55:28Z","receivedAt":"2008-03-12T19:55:28Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"... and here is the interdiff:\n\n builtin-gc.c     |    3 ++-\n t/t5304-prune.sh |   10 +++++++++-\n 2 files changed, 11 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin-gc.c b/builtin-gc.c\nindex 8d07350..9663fae 100644\n--- a/builtin-gc.c\n+++ b/builtin-gc.c\n@@ -59,7 +59,8 @@ static int gc_config(const char *var, const char *value)\n \tif (!strcmp(var, \"gc.pruneexpire\")) {\n \t\tif (!value)\n \t\t\treturn config_error_nonbool(var);\n-\t\tif (!approxidate(value))\n+\t\tif (strcmp(value, \"now\") &&\n+\t\t\t\tapproxidate(value) - approxidate(\"now\") >= 0)\n \t\t\treturn error(\"Invalid gc.pruneExpire: '%s'\", value);\n \t\tprune_expire = xstrdup(value);\n \t\treturn 0;\ndiff --git a/t/t5304-prune.sh b/t/t5304-prune.sh\nindex 2a88b3f..3b6b01d 100644\n--- a/t/t5304-prune.sh\n+++ b/t/t5304-prune.sh\n@@ -50,7 +50,6 @@ test_expect_success 'gc: implicit prune --expire' '\n \n \tbefore=$(git count-objects | sed \"s/ .*//\") &&\n \tBLOB=$(echo aleph_0 | git hash-object -w --stdin) &&\n-echo blob: $BLOB &&\n \tBLOB_FILE=.git/objects/$(echo $BLOB | sed \"s/^../&\\//\") &&\n \ttest $((1 + $before)) = $(git count-objects | sed \"s/ .*//\") &&\n \ttest -f $BLOB_FILE &&\n@@ -65,4 +64,13 @@ echo blob: $BLOB &&\n \n '\n \n+test_expect_success 'gc: refuse to start with invalid gc.pruneExpire' '\n+\n+\tgit config gc.pruneExpire invalid &&\n+\ttest_must_fail git gc &&\n+\tgit config gc.pruneExpire now &&\n+\tgit gc\n+\n+'\n+\n test_done\n"},{"id":"71837","messageId":"47D83532.70103@nrlssc.navy.mil","threadId":"12641","inReplyTo":"m3prtzyens.fsf@localhost.localdomain","subject":"Re: [PATCH v2] gc: call \"prune --expire 2.weeks.ago\" by default","fromName":"Brandon Casey","fromEmail":"casey@nrlssc.navy.mil","sentAt":"2008-03-12T19:55:30Z","receivedAt":"2008-03-12T19:55:30Z","isPatch":true,"sender":{"key":"drafnel@gmail.com","avatar":"https://avatars.githubusercontent.com/u/921167?v=4"},"body":"Jakub Narebski wrote:\n> Brandon Casey <casey@nrlssc.navy.mil> writes:\n> \n>> Is 'git-gc --prune' still useful to end users when those in-the-know can use\n>> git-prune when they really want all loose unreferenced objects to be removed?\n> \n> It is one command less to remember (just like with \"git tag --verify\"\n> and \"git verify-tag\"), so I'm all for \"git gc --prune\" to remain.\n\nI think the issue here is that the prune behavior of git-gc is more complex when\nboth 'git-gc' does prune and 'git-gc --prune' does prune, but only one of them\nis controlled by gc.pruneExpire. From a high level perspective, this is\nnon-obvious and so has to be explicitly outlined in the help text _and_ users\nhave to remember it. The git-gc command and the documentation and suggested work\nflows can all be simplified by just always doing a safe prune.\n\nI think git-prune is seldomly used by normal users for the reasons Dscho\ndescribed, and I think once the behavior implemented by his patch becomes\nstandard it will never be used by normal users (except the ones who always use\n--prune for the reasons Geert Bosch described, and they'll probably want the\nnew behavior). So I think git-prune will sink a little lower into plumbing and\ncommon users won't need to know anything about pruning, and only sophisticated\nusers will need to know git-prune.\n\n-brandon\n"},{"id":"71838","messageId":"alpine.LSU.1.00.0803122058430.1656@racer.site","threadId":"12641","inReplyTo":"47D83532.70103@nrlssc.navy.mil","subject":"Re: [PATCH v2] gc: call \"prune --expire 2.weeks.ago\" by default","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-03-12T19:59:53Z","receivedAt":"2008-03-12T19:59:53Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Wed, 12 Mar 2008, Brandon Casey wrote:\n\n> I think git-prune is seldomly used by normal users for the reasons Dscho \n> described, and I think once the behavior implemented by his patch \n> becomes standard it will never be used by normal users (except the ones \n> who always use --prune for the reasons Geert Bosch described, and \n> they'll probably want the new behavior). So I think git-prune will sink \n> a little lower into plumbing and common users won't need to know \n> anything about pruning, and only sophisticated users will need to know \n> git-prune.\n\nBut because we are nice people, we will deprecate --prune before we remove \nit, should we go that route at all.\n\nCiao,\nDscho\n"},{"id":"71839","messageId":"47D83C53.7000602@nrlssc.navy.mil","threadId":"12641","inReplyTo":"alpine.LSU.1.00.0803122058430.1656@racer.site","subject":"Re: [PATCH v2] gc: call \"prune --expire 2.weeks.ago\" by default","fromName":"Brandon Casey","fromEmail":"casey@nrlssc.navy.mil","sentAt":"2008-03-12T20:25:55Z","receivedAt":"2008-03-12T20:25:55Z","isPatch":true,"sender":{"key":"drafnel@gmail.com","avatar":"https://avatars.githubusercontent.com/u/921167?v=4"},"body":"Johannes Schindelin wrote:\n> Hi,\n> \n> On Wed, 12 Mar 2008, Brandon Casey wrote:\n> \n>> I think git-prune is seldomly used by normal users for the reasons Dscho \n>> described, and I think once the behavior implemented by his patch \n>> becomes standard it will never be used by normal users (except the ones \n>> who always use --prune for the reasons Geert Bosch described, and \n>> they'll probably want the new behavior). So I think git-prune will sink \n>> a little lower into plumbing and common users won't need to know \n>> anything about pruning, and only sophisticated users will need to know \n>> git-prune.\n> \n> But because we are nice people, we will deprecate --prune before we remove \n> it, should we go that route at all.\n\nI am not suggesting that git-gc stop parsing --prune and instead start erroring\nout on it. If it is ok to change the behavior of git-gc, it seems like it\nis ok to change the behavior of 'git-gc --prune' in the same way, especially if\nthe change makes it less destructive.\n\nI would suggest not having the somewhat ambiguous state of 'git-gc' prunes one\nway and 'git-gc --prune' prunes in another more dangerous way. And only one is\ncontrolled by a config option named gc.pruneExpire (_and_ it's not the obvious\nusage of git-gc which actually has the word 'prune' on the command line).\n\nSo I hope making --prune a noop fits your definition of nice deprecation.\n\n-brandon\n"},{"id":"71840","messageId":"7vejaf65q0.fsf@gitster.siamese.dyndns.org","threadId":"12641","inReplyTo":"47D83C53.7000602@nrlssc.navy.mil","subject":"Re: [PATCH v2] gc: call \"prune --expire 2.weeks.ago\" by default","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-03-12T20:35:19Z","receivedAt":"2008-03-12T20:35:19Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Brandon Casey <casey@nrlssc.navy.mil> writes:\n\n> I am not suggesting that git-gc stop parsing --prune and instead start\n> erroring out on it. If it is ok to change the behavior of git-gc, it\n> seems like it is ok to change the behavior of 'git-gc --prune' in the\n> same way, especially if the change makes it less destructive.\n\nYeah, gc.pruneexpire does sound like it applies to both implicit ones and\nexplicit ones, doesn't it?  I think your suggestion makes sense.\n"},{"id":"71842","messageId":"alpine.LSU.1.00.0803122153440.1656@racer.site","threadId":"12641","inReplyTo":"7vejaf65q0.fsf@gitster.siamese.dyndns.org","subject":"[PATCH v4] gc: call \"prune --expire 2.weeks.ago\" by default","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-03-12T20:55:47Z","receivedAt":"2008-03-12T20:55:47Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"\nThe only reason we did not call \"prune\" in git-gc was that it is an\ninherently dangerous operation: if there is a commit going on, you will\nprune loose objects that were just created, and are, in fact, needed by the\ncommit object just about to be created.\n\nSince it is dangerous, we told users so.  That led to many users not even\ndaring to run it when it was actually safe. Besides, they are users, and\nshould not have to remember such details as when to call git-gc with\n--prune, or to call git-prune directly.\n\nOf course, the consequence was that \"git gc --auto\" gets triggered much\nmore often than we would like, since unreferenced loose objects (such as\nleft-overs from a rebase or a reset --hard) were never pruned.\n\nAlas, git-prune recently learnt the option --expire <minimum-age>, which\nmakes it a much safer operation.  This allows us to call prune from git-gc,\nwith a grace period of 2 weeks for the unreferenced loose objects (this\nvalue was determined in a discussion on the git list as a safe one).\n\nIf you want to override this grace period, just set the config variable\ngc.pruneExpire to a different value; an example would be\n\n\t[gc]\n\t\tpruneExpire = 6.months.ago\n\nor even \"never\", if you feel really paranoid.\n\nNote that this new behaviour makes \"--prune\" be a no-op.\n\nWhile adding a test to t5304-prune.sh (since it really tests the implicit\ncall to \"prune\"), also the original test for \"prune --expire\" was moved\nthere from t1410-reflog.sh, where it did not belong.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n\n\tOn Wed, 12 Mar 2008, Junio C Hamano wrote:\n\n\t> Brandon Casey <casey@nrlssc.navy.mil> writes:\n\t> \n\t> > I am not suggesting that git-gc stop parsing --prune and \n\t> > instead start erroring out on it. If it is ok to change the behavior \n\t> > of git-gc, it seems like it is ok to change the behavior of 'git-gc \n\t> > --prune' in the same way, especially if the change makes it less \n\t> > destructive.\n\t> \n\t> Yeah, gc.pruneexpire does sound like it applies to both implicit \n\t> ones and explicit ones, doesn't it?  I think your suggestion makes \n\t> sense.\n\n\tOkay, I give up my resistance.\n\n\tChanges since v3: --prune is not even described in the man page \n\tanymore, since it now is a no-op.\n\n\tInterdiff will follow in its own mail...\n\n Documentation/config.txt |    4 ++++\n Documentation/git-gc.txt |   17 +++++------------\n builtin-gc.c             |   15 +++++++++++++--\n t/t1410-reflog.sh        |   18 ------------------\n t/t5304-prune.sh         |   44 ++++++++++++++++++++++++++++++++++++++++++++\n 5 files changed, 66 insertions(+), 32 deletions(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex f64b269..a2f1df2 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -590,6 +590,10 @@ gc.packrefs::\n \tat some stage, and setting this to `false` will continue to\n \tprevent `git pack-refs` from being run from `git gc`.\n \n+gc.pruneexpire::\n+\tWhen `git gc` is run, it will call `prune --expire 2.weeks.ago`.\n+\tOverride the grace period with this config variable.\n+\n gc.reflogexpire::\n \t`git reflog expire` removes reflog entries older than\n \tthis time; defaults to 90 days.\ndiff --git a/Documentation/git-gc.txt b/Documentation/git-gc.txt\nindex 2e7be91..229a7c9 100644\n--- a/Documentation/git-gc.txt\n+++ b/Documentation/git-gc.txt\n@@ -8,7 +8,7 @@ git-gc - Cleanup unnecessary files and optimize the local repository\n \n SYNOPSIS\n --------\n-'git-gc' [--prune] [--aggressive] [--auto] [--quiet]\n+'git-gc' [--aggressive] [--auto] [--quiet]\n \n DESCRIPTION\n -----------\n@@ -25,17 +25,6 @@ operating performance. Some git commands may automatically run\n OPTIONS\n -------\n \n---prune::\n-\tUsually `git-gc` packs refs, expires old reflog entries,\n-\tpacks loose objects,\n-\tand removes old 'rerere' records.  Removal\n-\tof unreferenced loose objects is an unsafe operation\n-\twhile other git operations are in progress, so it is not\n-\tdone by default.  Pass this option if you want it, and only\n-\twhen you know nobody else is creating new objects in the\n-\trepository at the same time (e.g. never use this option\n-\tin a cron script).\n-\n --aggressive::\n \tUsually 'git-gc' runs very quickly while providing good disk\n \tspace utilization and performance.  This option will cause\n@@ -104,6 +93,10 @@ the value, the more time is spent optimizing the delta compression.  See\n the documentation for the --window' option in linkgit:git-repack[1] for\n more details.  This defaults to 10.\n \n+The optional configuration variable 'gc.pruneExpire' controls how old\n+the unreferenced loose objects have to be before they are pruned.  The\n+default is \"2 weeks ago\".\n+\n See Also\n --------\n linkgit:git-prune[1]\ndiff --git a/builtin-gc.c b/builtin-gc.c\nindex 7cad366..8bd54d8 100644\n--- a/builtin-gc.c\n+++ b/builtin-gc.c\n@@ -26,12 +26,13 @@ static int pack_refs = 1;\n static int aggressive_window = 250;\n static int gc_auto_threshold = 6700;\n static int gc_auto_pack_limit = 20;\n+static char *prune_expire = \"2.weeks.ago\";\n \n #define MAX_ADD 10\n static const char *argv_pack_refs[] = {\"pack-refs\", \"--all\", \"--prune\", NULL};\n static const char *argv_reflog[] = {\"reflog\", \"expire\", \"--all\", NULL};\n static const char *argv_repack[MAX_ADD] = {\"repack\", \"-d\", \"-l\", NULL};\n-static const char *argv_prune[] = {\"prune\", NULL};\n+static const char *argv_prune[] = {\"prune\", \"--expire\", NULL, NULL};\n static const char *argv_rerere[] = {\"rerere\", \"gc\", NULL};\n \n static int gc_config(const char *var, const char *value)\n@@ -55,6 +56,15 @@ static int gc_config(const char *var, const char *value)\n \t\tgc_auto_pack_limit = git_config_int(var, value);\n \t\treturn 0;\n \t}\n+\tif (!strcmp(var, \"gc.pruneexpire\")) {\n+\t\tif (!value)\n+\t\t\treturn config_error_nonbool(var);\n+\t\tif (strcmp(value, \"now\") &&\n+\t\t\t\tapproxidate(value) - approxidate(\"now\") >= 0)\n+\t\t\treturn error(\"Invalid gc.pruneExpire: '%s'\", value);\n+\t\tprune_expire = xstrdup(value);\n+\t\treturn 0;\n+\t}\n \treturn git_default_config(var, value);\n }\n \n@@ -235,7 +245,8 @@ int cmd_gc(int argc, const char **argv, const char *prefix)\n \tif (run_command_v_opt(argv_repack, RUN_GIT_CMD))\n \t\treturn error(FAILED_RUN, argv_repack[0]);\n \n-\tif (prune && run_command_v_opt(argv_prune, RUN_GIT_CMD))\n+\targv_prune[2] = prune_expire;\n+\tif (run_command_v_opt(argv_prune, RUN_GIT_CMD))\n \t\treturn error(FAILED_RUN, argv_prune[0]);\n \n \tif (run_command_v_opt(argv_rerere, RUN_GIT_CMD))\ndiff --git a/t/t1410-reflog.sh b/t/t1410-reflog.sh\nindex 24476be..73f830d 100755\n--- a/t/t1410-reflog.sh\n+++ b/t/t1410-reflog.sh\n@@ -202,22 +202,4 @@ test_expect_success 'delete' '\n \n '\n \n-test_expect_success 'prune --expire' '\n-\n-\tbefore=$(git count-objects | sed \"s/ .*//\") &&\n-\tBLOB=$(echo aleph | git hash-object -w --stdin) &&\n-\tBLOB_FILE=.git/objects/$(echo $BLOB | sed \"s/^../&\\//\") &&\n-\ttest $((1 + $before)) = $(git count-objects | sed \"s/ .*//\") &&\n-\ttest -f $BLOB_FILE &&\n-\tgit reset --hard &&\n-\tgit prune --expire=1.hour.ago &&\n-\ttest $((1 + $before)) = $(git count-objects | sed \"s/ .*//\") &&\n-\ttest -f $BLOB_FILE &&\n-\ttest-chmtime -86500 $BLOB_FILE &&\n-\tgit prune --expire 1.day &&\n-\ttest $before = $(git count-objects | sed \"s/ .*//\") &&\n-\t! test -f $BLOB_FILE\n-\n-'\n-\n test_done\ndiff --git a/t/t5304-prune.sh b/t/t5304-prune.sh\nindex 6560af7..3b6b01d 100644\n--- a/t/t5304-prune.sh\n+++ b/t/t5304-prune.sh\n@@ -29,4 +29,48 @@ test_expect_success 'prune stale packs' '\n \n '\n \n+test_expect_success 'prune --expire' '\n+\n+\tbefore=$(git count-objects | sed \"s/ .*//\") &&\n+\tBLOB=$(echo aleph | git hash-object -w --stdin) &&\n+\tBLOB_FILE=.git/objects/$(echo $BLOB | sed \"s/^../&\\//\") &&\n+\ttest $((1 + $before)) = $(git count-objects | sed \"s/ .*//\") &&\n+\ttest -f $BLOB_FILE &&\n+\tgit prune --expire=1.hour.ago &&\n+\ttest $((1 + $before)) = $(git count-objects | sed \"s/ .*//\") &&\n+\ttest -f $BLOB_FILE &&\n+\ttest-chmtime -86500 $BLOB_FILE &&\n+\tgit prune --expire 1.day &&\n+\ttest $before = $(git count-objects | sed \"s/ .*//\") &&\n+\t! test -f $BLOB_FILE\n+\n+'\n+\n+test_expect_success 'gc: implicit prune --expire' '\n+\n+\tbefore=$(git count-objects | sed \"s/ .*//\") &&\n+\tBLOB=$(echo aleph_0 | git hash-object -w --stdin) &&\n+\tBLOB_FILE=.git/objects/$(echo $BLOB | sed \"s/^../&\\//\") &&\n+\ttest $((1 + $before)) = $(git count-objects | sed \"s/ .*//\") &&\n+\ttest -f $BLOB_FILE &&\n+\ttest-chmtime -$((86400*14-30)) $BLOB_FILE &&\n+\tgit gc &&\n+\ttest $((1 + $before)) = $(git count-objects | sed \"s/ .*//\") &&\n+\ttest -f $BLOB_FILE &&\n+\ttest-chmtime -$((86400*14+1)) $BLOB_FILE &&\n+\tgit gc &&\n+\ttest $before = $(git count-objects | sed \"s/ .*//\") &&\n+\t! test -f $BLOB_FILE\n+\n+'\n+\n+test_expect_success 'gc: refuse to start with invalid gc.pruneExpire' '\n+\n+\tgit config gc.pruneExpire invalid &&\n+\ttest_must_fail git gc &&\n+\tgit config gc.pruneExpire now &&\n+\tgit gc\n+\n+'\n+\n test_done\n-- \n1.5.4.4.694.g43223\n"},{"id":"71844","messageId":"alpine.LSU.1.00.0803122156080.1656@racer.site","threadId":"12641","inReplyTo":"alpine.LSU.1.00.0803122153440.1656@racer.site","subject":"Re: [PATCH v4] gc: call \"prune --expire 2.weeks.ago\" by default","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-03-12T20:56:31Z","receivedAt":"2008-03-12T20:56:31Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"And here is the interdiff:\n\n Documentation/config.txt |    5 ++---\n Documentation/git-gc.txt |   23 +++++------------------\n builtin-gc.c             |    9 ++-------\n 3 files changed, 9 insertions(+), 28 deletions(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex db5b2dc..a2f1df2 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -591,9 +591,8 @@ gc.packrefs::\n \tprevent `git pack-refs` from being run from `git gc`.\n \n gc.pruneexpire::\n-\tWhen `git gc` is run without `--prune`, it will still call\n-\t`prune`, but with `--expire 2.weeks.ago`.  Override the value\n-\twith this config variable.\n+\tWhen `git gc` is run, it will call `prune --expire 2.weeks.ago`.\n+\tOverride the grace period with this config variable.\n \n gc.reflogexpire::\n \t`git reflog expire` removes reflog entries older than\ndiff --git a/Documentation/git-gc.txt b/Documentation/git-gc.txt\nindex 2042d9f..229a7c9 100644\n--- a/Documentation/git-gc.txt\n+++ b/Documentation/git-gc.txt\n@@ -8,7 +8,7 @@ git-gc - Cleanup unnecessary files and optimize the local repository\n \n SYNOPSIS\n --------\n-'git-gc' [--prune] [--aggressive] [--auto] [--quiet]\n+'git-gc' [--aggressive] [--auto] [--quiet]\n \n DESCRIPTION\n -----------\n@@ -25,23 +25,6 @@ operating performance. Some git commands may automatically run\n OPTIONS\n -------\n \n---prune::\n-\tUsually `git-gc` packs refs, expires old reflog entries,\n-\tpacks loose objects,\n-\tand removes old 'rerere' records.  Unilateral removal\n-\tof unreferenced loose objects is an unsafe operation\n-\twhile other git operations are in progress, so it is not\n-\tdone by default.\n-+\n-Instead, `git-prune` is called with an option telling it to expire\n-only unreferenced loose objects that are at least 2 weeks old.  Set\n-the config variable `gc.pruneexpire` to override this grace period.\n-+\n-Pass `--prune` to expire all unreferenced loose objects, but only\n-when you know nobody else is creating new objects in the\n-repository at the same time (e.g. never use this option\n-in a cron script).\n-\n --aggressive::\n \tUsually 'git-gc' runs very quickly while providing good disk\n \tspace utilization and performance.  This option will cause\n@@ -110,6 +93,10 @@ the value, the more time is spent optimizing the delta compression.  See\n the documentation for the --window' option in linkgit:git-repack[1] for\n more details.  This defaults to 10.\n \n+The optional configuration variable 'gc.pruneExpire' controls how old\n+the unreferenced loose objects have to be before they are pruned.  The\n+default is \"2 weeks ago\".\n+\n See Also\n --------\n linkgit:git-prune[1]\ndiff --git a/builtin-gc.c b/builtin-gc.c\nindex 9663fae..8bd54d8 100644\n--- a/builtin-gc.c\n+++ b/builtin-gc.c\n@@ -32,7 +32,7 @@ static char *prune_expire = \"2.weeks.ago\";\n static const char *argv_pack_refs[] = {\"pack-refs\", \"--all\", \"--prune\", NULL};\n static const char *argv_reflog[] = {\"reflog\", \"expire\", \"--all\", NULL};\n static const char *argv_repack[MAX_ADD] = {\"repack\", \"-d\", \"-l\", NULL};\n-static const char *argv_prune[] = {\"prune\", NULL, NULL, NULL};\n+static const char *argv_prune[] = {\"prune\", \"--expire\", NULL, NULL};\n static const char *argv_rerere[] = {\"rerere\", \"gc\", NULL};\n \n static int gc_config(const char *var, const char *value)\n@@ -245,12 +245,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)\n \tif (run_command_v_opt(argv_repack, RUN_GIT_CMD))\n \t\treturn error(FAILED_RUN, argv_repack[0]);\n \n-\tif (!prune) {\n-\t\targv_prune[1] = \"--expire\";\n-\t\targv_prune[2] = prune_expire;\n-\t\targv_prune[3] = NULL;\n-\t}\n-\n+\targv_prune[2] = prune_expire;\n \tif (run_command_v_opt(argv_prune, RUN_GIT_CMD))\n \t\treturn error(FAILED_RUN, argv_prune[0]);\n \n"},{"id":"71845","messageId":"7vwso74p33.fsf@gitster.siamese.dyndns.org","threadId":"12641","inReplyTo":"alpine.LSU.1.00.0803122153440.1656@racer.site","subject":"Re: [PATCH v4] gc: call \"prune --expire 2.weeks.ago\" by default","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-03-12T21:20:00Z","receivedAt":"2008-03-12T21:20:00Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> ---prune::\n\nI am fairly paranoid about end users wondering about what is described in\nancient documentation and complaining that we do not talk about it\nanymore.  I am tempted to suggest:\n\n\tThis is a no-op but you may see it mentioned in older docs and\n\tscripts.  Older git-gc never ran 'prune' without being told, and\n\tthis option was a way to tell it to.\n\nbut this would lead to littering the documentation with too much\nhistorical information in the long run.  I dunno.  I am inclined to favor\nthe removal as your patch did, but somebody else may have clever ideas.\n\n> +\tif (!strcmp(var, \"gc.pruneexpire\")) {\n> +\t\tif (!value)\n> +\t\t\treturn config_error_nonbool(var);\n> +\t\tif (strcmp(value, \"now\") &&\n> +\t\t\t\tapproxidate(value) - approxidate(\"now\") >= 0)\n> +\t\t\treturn error(\"Invalid gc.pruneExpire: '%s'\", value);\n\nYuck; approxidate() returns ulong.  Can subtracting a ulong from another\never go negative?\n\nBesides, because there is no guarantee of the order of evaluation between\nthese two approxidate() calls, you may get +1 or -1 on the second boundary.\n\nI think the reason why you did not catch it in your test is because your\ntests are half complete; they test only what you wanted to catch\n(misconfigured case) and do not test the other half (properly working\ncase).\n"},{"id":"71871","messageId":"alpine.LFD.1.00.0803121838560.2947@xanadu.home","threadId":"12641","inReplyTo":"7vwso74p33.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH v4] gc: call \"prune --expire 2.weeks.ago\" by default","fromName":"Nicolas Pitre","fromEmail":"nico@cam.org","sentAt":"2008-03-12T22:40:00Z","receivedAt":"2008-03-12T22:40:00Z","isPatch":true,"sender":{"key":"nico@fluxnic.net","avatar":"https://avatars.githubusercontent.com/u/702790?v=4"},"body":"On Wed, 12 Mar 2008, Junio C Hamano wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n> > ---prune::\n> \n> I am fairly paranoid about end users wondering about what is described in\n> ancient documentation and complaining that we do not talk about it\n> anymore.  I am tempted to suggest:\n> \n> \tThis is a no-op but you may see it mentioned in older docs and\n> \tscripts.  Older git-gc never ran 'prune' without being told, and\n> \tthis option was a way to tell it to.\n> \n> but this would lead to littering the documentation with too much\n> historical information in the long run.  I dunno.  I am inclined to favor\n> the removal as your patch did, but somebody else may have clever ideas.\n\nHistorical notes of that sort belong in RelNotes.\n\n\nNicolas\n"},{"id":"71874","messageId":"B27EC8CF-482D-499B-B4E0-019049926C93@ai.rug.nl","threadId":"12641","inReplyTo":"20080312170155.GB11236@coredump.intra.peff.net","subject":"Re: [PATCH] gc: call \"prune --expire 2.weeks.ago\"","fromName":"Pieter de Bie","fromEmail":"pdebie@ai.rug.nl","sentAt":"2008-03-12T22:50:04Z","receivedAt":"2008-03-12T22:50:04Z","isPatch":true,"sender":{"key":"pdebie@ai.rug.nl","avatar":null},"body":"\nOn Mar 12, 2008, at 6:01 PM, Jeff King wrote:\n\n> On Wed, Mar 12, 2008 at 05:05:51PM +0100, Johannes Schindelin wrote:\n>\n>>> I'd really like it to be at least 2 weeks\n>>\n>> Could you back that up with an explanation, as to why?\n>\n> I assume it's \"because I wouldn't want to lose work I had done within\n> the last two weeks.\" Yes, I know that this expiration is actually  \n> after\n> the reflog has already expired\n\nAh, I hadn't realised that. Then I don't really care, one week sounds  \nfine too. 2 weeks just seemed a bit short, as the default reflog is 30  \ndays. But if it's 2 weeks after the 30 days, that should be more than  \nenough\n\n- Pieter\n"},{"id":"71875","messageId":"alpine.LSU.1.00.0803122348210.1656@racer.site","threadId":"12641","inReplyTo":"7vwso74p33.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH v4] gc: call \"prune --expire 2.weeks.ago\" by default","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-03-12T22:50:39Z","receivedAt":"2008-03-12T22:50:39Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Wed, 12 Mar 2008, Junio C Hamano wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n> > ---prune::\n> \n> I am fairly paranoid about end users wondering about what is described in\n> ancient documentation and complaining that we do not talk about it\n> anymore.  I am tempted to suggest:\n> \n> \tThis is a no-op but you may see it mentioned in older docs and\n> \tscripts.  Older git-gc never ran 'prune' without being told, and\n> \tthis option was a way to tell it to.\n> \n> but this would lead to littering the documentation with too much \n> historical information in the long run.  I dunno.  I am inclined to \n> favor the removal as your patch did, but somebody else may have clever \n> ideas.\n\nWell, if you want to, I am quite willing to adapt the patch.  (I care \nenough about the real issue, namely that \"prune\" should be called \nautomatically.)\n\n> > +\tif (!strcmp(var, \"gc.pruneexpire\")) {\n> > +\t\tif (!value)\n> > +\t\t\treturn config_error_nonbool(var);\n> > +\t\tif (strcmp(value, \"now\") &&\n> > +\t\t\t\tapproxidate(value) - approxidate(\"now\") >= 0)\n> > +\t\t\treturn error(\"Invalid gc.pruneExpire: '%s'\", value);\n> \n> Yuck; approxidate() returns ulong.  Can subtracting a ulong from another\n> ever go negative?\n> \n> Besides, because there is no guarantee of the order of evaluation between\n> these two approxidate() calls, you may get +1 or -1 on the second boundary.\n> \n> I think the reason why you did not catch it in your test is because your\n> tests are half complete; they test only what you wanted to catch\n> (misconfigured case) and do not test the other half (properly working\n> case).\n\nYes, probably.  Of course, comparing a difference to 0 is absolutely \nmoronic.\n\nI should have written\n\n\t\t\t\tapproxidate(value) >= approxidate(\"now\"))\n\nin the first place.\n\nSo, could you tell me, please, if I should resend the patch with your \n--prune documentation, or without?\n\nCiao,\nDscho\n"},{"id":"71878","messageId":"7vzlt335a5.fsf@gitster.siamese.dyndns.org","threadId":"12641","inReplyTo":"alpine.LSU.1.00.0803122348210.1656@racer.site","subject":"Re: [PATCH v4] gc: call \"prune --expire 2.weeks.ago\" by default","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-03-12T23:13:06Z","receivedAt":"2008-03-12T23:13:06Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n>> Yuck; approxidate() returns ulong.  Can subtracting a ulong from another\n>> ever go negative?\n>> \n>> Besides, because there is no guarantee of the order of evaluation between\n>> these two approxidate() calls, you may get +1 or -1 on the second boundary.\n>> \n>> I think the reason why you did not catch it in your test is because your\n>> tests are half complete; they test only what you wanted to catch\n>> (misconfigured case) and do not test the other half (properly working\n>> case).\n>\n> Yes, probably.  Of course, comparing a difference to 0 is absolutely \n> moronic.\n>\n> I should have written\n>\n> \t\t\t\tapproxidate(value) >= approxidate(\"now\"))\n>\n> in the first place.\n\nEh, sorry, but why?\n\n> So, could you tell me, please, if I should resend the patch with your \n> --prune documentation, or without?\n\nI like Nico's suggestion to put that \"historical notes\" in RelNotes, so\nthe documentation part is fine as is.\n"},{"id":"71879","messageId":"7vtzjb34y0.fsf@gitster.siamese.dyndns.org","threadId":"12641","inReplyTo":"B27EC8CF-482D-499B-B4E0-019049926C93@ai.rug.nl","subject":"Re: [PATCH] gc: call \"prune --expire 2.weeks.ago\"","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-03-12T23:20:23Z","receivedAt":"2008-03-12T23:20:23Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Pieter de Bie <pdebie@ai.rug.nl> writes:\n\n> On Mar 12, 2008, at 6:01 PM, Jeff King wrote:\n>\n>> On Wed, Mar 12, 2008 at 05:05:51PM +0100, Johannes Schindelin wrote:\n>>\n>>>> I'd really like it to be at least 2 weeks\n>>>\n>>> Could you back that up with an explanation, as to why?\n>>\n>> I assume it's \"because I wouldn't want to lose work I had done within\n>> the last two weeks.\" Yes, I know that this expiration is actually\n>> after\n>> the reflog has already expired\n>\n> Ah, I hadn't realised that. Then I don't really care, one week sounds\n> fine too. 2 weeks just seemed a bit short, as the default reflog is 30\n> days. But if it's 2 weeks after the 30 days, that should be more than\n> enough\n\nWasn't the default 90 days?\n\nIn any case, after 90 days, my reading of the code is that these loose\nones become unreachable, and when we look at their timestamps, we notice\nthat they are already more than 2 weeks old, and they will immediately be\nremoved.\n\nSo it won't be \"2 weeks after X\", either.\n"},{"id":"71880","messageId":"alpine.LSU.1.00.0803130021520.1656@racer.site","threadId":"12641","inReplyTo":"7vzlt335a5.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH v4] gc: call \"prune --expire 2.weeks.ago\" by default","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-03-12T23:28:08Z","receivedAt":"2008-03-12T23:28:08Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Wed, 12 Mar 2008, Junio C Hamano wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n> >> Yuck; approxidate() returns ulong.  Can subtracting a ulong from \n> >> another ever go negative?\n> >> \n> >> Besides, because there is no guarantee of the order of evaluation \n> >> between these two approxidate() calls, you may get +1 or -1 on the \n> >> second boundary.\n> >> \n> >> I think the reason why you did not catch it in your test is because \n> >> your tests are half complete; they test only what you wanted to catch \n> >> (misconfigured case) and do not test the other half (properly working \n> >> case).\n> >\n> > Yes, probably.  Of course, comparing a difference to 0 is absolutely \n> > moronic.\n> >\n> > I should have written\n> >\n> > \t\t\t\tapproxidate(value) >= approxidate(\"now\"))\n> >\n> > in the first place.\n> \n> Eh, sorry, but why?\n\nThe thing is: I want to prevent invalid dates in gc.pruneExpire from going \nunnoticed, _especially_ since they would default to \"now\".  IOW if you \nsaid something like \"one.weak.ago\", it would actually have the same effect \nas \"now\" and offer _no_ grace period.\n\nBut like you said, comparing the difference of two unsigned longs to >= 0 \nmight be quite stupid.  Instead, I compare them _directly_.\n\nSince I compare the value to \"now\" first, and only if it is not, compare \nthe approxidate() of the value to the current time stamp, I can verify \nthat no invalid date was specified.\n\nUnfortunately, this check includes future dates.  Fortunately, they do not \nmake sense at all.\n\nTo make my reasoning clear, how about this comment above that if() clause?\n\n\t\t/*\n\t\t * In case of an invalid date, approxidate() returns the\n\t\t * same as approxidate(\"now\").  Since the millisecond\n\t\t * boundary could have been crossed between the two calls\n\t\t * to approxidate(), we compare not only for equality,\n\t\t * but also if the former is greater than the latter.\n\t\t *\n\t\t * Note: this assumes that future dates are invalid, which\n\t\t * makes sense, really.\n\t\t */\n\nHmm?\n\nCiao,\nDscho\n"},{"id":"71881","messageId":"alpine.LSU.1.00.0803130028550.1656@racer.site","threadId":"12641","inReplyTo":"7vtzjb34y0.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH] gc: call \"prune --expire 2.weeks.ago\"","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-03-12T23:30:53Z","receivedAt":"2008-03-12T23:30:53Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Wed, 12 Mar 2008, Junio C Hamano wrote:\n\n> In any case, after 90 days, my reading of the code is that these loose \n> ones become unreachable, and when we look at their timestamps, we notice \n> that they are already more than 2 weeks old, and they will immediately \n> be removed.\n\nYes.\n\nIn any case, most likely these objects would have been packed anyway \nduring that period, so they would have been pruned by the repack called by \ngit-gc.\n\nMy patch really, really is about _unreferenced_ loose objects, i.e. \nsomething you get by multiple \"git add\"s without commits.  And by merge \nconflicts.\n\nIOW by objects that were never referenced by commit objects.\n\nCiao,\nDscho\n"},{"id":"71882","messageId":"7vod9j342h.fsf@gitster.siamese.dyndns.org","threadId":"12641","inReplyTo":"alpine.LSU.1.00.0803130021520.1656@racer.site","subject":"Re: [PATCH v4] gc: call \"prune --expire 2.weeks.ago\" by default","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-03-12T23:39:18Z","receivedAt":"2008-03-12T23:39:18Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n>> Eh, sorry, but why?\n>\n> The thing is: I want to prevent invalid dates in gc.pruneExpire from going \n> unnoticed, _especially_ since they would default to \"now\".  IOW if you \n> said something like \"one.weak.ago\", it would actually have the same effect \n> as \"now\" and offer _no_ grace period.\n>\n> But like you said, comparing the difference of two unsigned longs to >= 0 \n> might be quite stupid.  Instead, I compare them _directly_.\n>\n> Since I compare the value to \"now\" first, and only if it is not, compare \n> the approxidate() of the value to the current time stamp, I can verify \n> that no invalid date was specified.\n>\n> Unfortunately, this check includes future dates.  Fortunately, they do not \n> make sense at all.\n>\n> To make my reasoning clear, how about this comment above that if() clause?\n>\n> \t\t/*\n> \t\t * In case of an invalid date, approxidate() returns the\n> \t\t * same as approxidate(\"now\").  Since the millisecond\n> \t\t * boundary could have been crossed between the two calls\n> \t\t * to approxidate(), we compare not only for equality,\n> \t\t * but also if the former is greater than the latter.\n> \t\t *\n> \t\t * Note: this assumes that future dates are invalid, which\n> \t\t * makes sense, really.\n> \t\t */\n>\n> Hmm?\n\nAh,...\n\nBut C language rules haven't changed in such a way that it guarantees B to\nbe evaluated before A when you write \"A >= B\", have it?\n\nSo at least I think you would need something like this if you go that\nroute:\n\n  \t\tif (strcmp(value, \"now\")) {\n                \tunsigned long now = approxidate(\"now\");\n                \tif (approxidate(value) >= now)\n\t\t\t\treturn error(\"Invalid %s: '%s'\", var, value);\n\t\t\t...\n\t\t}\n\nAlso the resolution of approxidate() is in seconds so millisecond boundary\ndoes not matter, but that issue is, eh, secondary ;-).\n\nI have to wonder if approxidate_with_error() function that takes a pointer\nto receive an error condition may be a better way to solve this cleanly.\n"},{"id":"71883","messageId":"7vk5k733y5.fsf@gitster.siamese.dyndns.org","threadId":"12641","inReplyTo":"alpine.LSU.1.00.0803130028550.1656@racer.site","subject":"Re: [PATCH] gc: call \"prune --expire 2.weeks.ago\"","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-03-12T23:41:54Z","receivedAt":"2008-03-12T23:41:54Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> Yes.\n>\n> In any case, most likely these objects would have been packed anyway \n> during that period, so they would have been pruned by the repack called by \n> git-gc.\n\nYes, that is the most probable way for these unused cruft to get removed.\n\n> My patch really, really is about _unreferenced_ loose objects, i.e. \n> something you get by multiple \"git add\"s without commits.  And by merge \n> conflicts.\n>\n> IOW by objects that were never referenced by commit objects.\n"},{"id":"71884","messageId":"alpine.LSU.1.00.0803130042520.1656@racer.site","threadId":"12641","inReplyTo":"7vod9j342h.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH v4] gc: call \"prune --expire 2.weeks.ago\" by default","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-03-12T23:43:17Z","receivedAt":"2008-03-12T23:43:17Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Wed, 12 Mar 2008, Junio C Hamano wrote:\n\n> I have to wonder if approxidate_with_error() function that takes a \n> pointer to receive an error condition may be a better way to solve this \n> cleanly.\n\nRight.  But that will have to wait for at least tomorrow, if it waits for \nme.\n\nCiao,\nDscho\n"},{"id":"71911","messageId":"4F997D24-1853-4B53-9865-F456ECA43FD7@wincent.com","threadId":"12641","inReplyTo":"alpine.LSU.1.00.0803122153440.1656@racer.site","subject":"Re: [PATCH v4] gc: call \"prune --expire 2.weeks.ago\" by default","fromName":"Wincent Colaiuta","fromEmail":"win@wincent.com","sentAt":"2008-03-13T09:21:21Z","receivedAt":"2008-03-13T09:21:21Z","isPatch":true,"sender":{"key":"greg@hurrell.net","avatar":"https://avatars.githubusercontent.com/u/7074?v=4"},"body":"El 12/3/2008, a las 21:55, Johannes Schindelin escribió:\n\n> Alas, git-prune recently learnt the option --expire <minimum-age>,  \n> which\n> makes it a much safer operation.  This allows us to call prune from  \n> git-gc,\n> with a grace period of 2 weeks for the unreferenced loose objects  \n> (this\n> value was determined in a discussion on the git list as a safe one).\n\nJust a really minor quibble: I don't think you mean \"alas\" here;  \n\"alas\" basically means \"unfortunately\" or \"regrettably\".\n\nCheers,\nWincent\n"},{"id":"71912","messageId":"7FB80115-C1E4-4F83-9374-41AB1BDA0579@wincent.com","threadId":"12641","inReplyTo":"7vod9j342h.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH v4] gc: call \"prune --expire 2.weeks.ago\" by default","fromName":"Wincent Colaiuta","fromEmail":"win@wincent.com","sentAt":"2008-03-13T09:48:50Z","receivedAt":"2008-03-13T09:48:50Z","isPatch":true,"sender":{"key":"greg@hurrell.net","avatar":"https://avatars.githubusercontent.com/u/7074?v=4"},"body":"El 13/3/2008, a las 0:39, Junio C Hamano escribió:\n\n> Ah,...\n>\n> But C language rules haven't changed in such a way that it  \n> guarantees B to\n> be evaluated before A when you write \"A >= B\", have it?\n>\n> So at least I think you would need something like this if you go that\n> route:\n>\n>  \t\tif (strcmp(value, \"now\")) {\n>                \tunsigned long now = approxidate(\"now\");\n>                \tif (approxidate(value) >= now)\n> \t\t\t\treturn error(\"Invalid %s: '%s'\", var, value);\n> \t\t\t...\n> \t\t}\n\n\nAre you sure that that alternative provides any guarantees about  \nevaluation order either? (I'm not a compiler expert, nor am I  \nconsulting a copy of the standard; but I don't think it does.)\n\nIn order to enforce evaluation in the required order I think it might  \nhave to be something like this:\n\n\tif (strcmp(value, \"now\")) {\n\t\tunsigned long now;\n\t\tif ((now = approxidate(\"now\")) &&\n\t\t    approxidate(value) >= now)\n\t\t\treturn error(\"Invalid %s: '%s'\", var, value);\n\t\t...\n\t}\n\nie. the && operator guarantees left to right evaluation order, and  \nsince approxidate always returns a non-zero ulong the second  \nexpression (after the &&) will always be evaluated.\n\nCheers,\nWincent\n"},{"id":"71913","messageId":"47D8FF3B.9050304@viscovery.net","threadId":"12641","inReplyTo":"7FB80115-C1E4-4F83-9374-41AB1BDA0579@wincent.com","subject":"Re: [PATCH v4] gc: call \"prune --expire 2.weeks.ago\" by default","fromName":"Johannes Sixt","fromEmail":"j.sixt@viscovery.net","sentAt":"2008-03-13T10:17:31Z","receivedAt":"2008-03-13T10:17:31Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Wincent Colaiuta schrieb:\n> El 13/3/2008, a las 0:39, Junio C Hamano escribió:\n>>          if (strcmp(value, \"now\")) {\n>>                    unsigned long now = approxidate(\"now\");\n>>                    if (approxidate(value) >= now)\n>>                 return error(\"Invalid %s: '%s'\", var, value);\n>>             ...\n>>         }\n> \n> \n> Are you sure that that alternative provides any guarantees about\n> evaluation order either? (I'm not a compiler expert, nor am I consulting\n> a copy of the standard; but I don't think it does.)\n\nThere is a sequence point at the semicolon. This means that all observable\nside effects of approxidate(\"now\") are visible when approxidate(value) is\nevaluated (and no observable side effect of the latter is visible when the\nformer is evaluated), which doesn't leave much choice for the compiler.\nSo, yes, this does guarantee the intended evaluation order.\n\n-- Hannes\n"},{"id":"71915","messageId":"alpine.LSU.1.00.0803131210110.1656@racer.site","threadId":"12641","inReplyTo":"4F997D24-1853-4B53-9865-F456ECA43FD7@wincent.com","subject":"Re: [PATCH v4] gc: call \"prune --expire 2.weeks.ago\" by default","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-03-13T11:11:01Z","receivedAt":"2008-03-13T11:11:01Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Thu, 13 Mar 2008, Wincent Colaiuta wrote:\n\n> El 12/3/2008, a las 21:55, Johannes Schindelin escribió:\n> \n> >Alas, git-prune recently learnt the option --expire <minimum-age>, \n> >which makes it a much safer operation.  This allows us to call prune \n> >from git-gc, with a grace period of 2 weeks for the unreferenced loose \n> >objects (this value was determined in a discussion on the git list as a \n> >safe one).\n> \n> Just a really minor quibble: I don't think you mean \"alas\" here; \"alas\" \n> basically means \"unfortunately\" or \"regrettably\".\n\nNo, I really meant \"alas\" here, since it is more of a sigh.  The sigh is \nbecause I had expected somebody else to care more than me about it, and I \nhad done the --expire patch already.\n\nCiao,\nDscho\n"}]}