{"thread":{"id":"62692","subject":"[Possible Bug] --cruft option not work with git gc --prune=now","startedAt":"2024-12-24T12:07:31Z","lastAt":"2024-12-30T11:58:51Z","messageCount":5,"participants":["ZheNing Hu","Taylor Blau","Jeff King"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"509552","messageId":"CAOLTT8Q0cH3Q=yPnTYKAwn8bC+iDW7onibsLF=bzVr8tGw5J0Q@mail.gmail.com","threadId":"62692","inReplyTo":null,"subject":"[Possible Bug] --cruft option not work with git gc --prune=now","fromName":"ZheNing Hu","fromEmail":"adlternative@gmail.com","sentAt":"2024-12-24T12:07:16Z","receivedAt":"2024-12-24T12:07:31Z","isPatch":false,"sender":{"key":"adlternative@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58138461?v=4"},"body":"I am trying to use the --cruft feature of git gc, and everything works\nwell, but when I combine it with --prune=now, I notice that no cruft\npackage is generated, which is very strange. So I turned on trace and\nchecked: instead of executing `git repack --cruft`, it executed `git\nrepack -d -l -a`. Is this normal? If `git gc --cruft --prune=now`\ndoesn't work as expected, it won't be safe to further execute `git gc\n--cruft --expire-to=<dir> --prune=now`(in my another patch).\n\n\nI checked the code, and it appears that add_repack_all_option() first\nprocesses `--prune=now` before handling `--cruft` option.\n\nIf this is a bug, I am willing to propose a patch to fix it.\n\n```shell\nGIT_TRACE=1 git gc --prune=now --cruft\n19:56:54.132263 git.c:479               trace: built-in: git gc\n--prune=now --cruft\n19:56:54.137004 run-command.c:666       trace: run_command: git\npack-refs --all --prune\n19:56:54.137087 run-command.c:758       trace: start_command:\n/Users/adl/libexec/git-core/git pack-refs --all --prune\n19:56:54.152233 git.c:479               trace: built-in: git pack-refs\n--all --prune\n19:56:54.166598 run-command.c:666       trace: run_command: git reflog\nexpire --all\n19:56:54.166705 run-command.c:758       trace: start_command:\n/Users/adl/libexec/git-core/git reflog expire --all\n19:56:54.181965 git.c:479               trace: built-in: git reflog expire --all\n19:56:54.184495 run-command.c:666       trace: run_command: git repack -d -l -a\n19:56:54.184571 run-command.c:758       trace: start_command:\n/Users/adl/libexec/git-core/git repack -d -l -a\n19:56:54.196211 git.c:479               trace: built-in: git repack -d -l -a\n19:56:54.198260 run-command.c:666       trace: run_command: git\npack-objects --local --delta-base-offset objects/pack/.tmp-59391-pack\n--keep-true-parents --honor-pack-keep --non-empty --all --reflog\n--indexed-objects --write-bitmap-index-quiet\n19:56:54.198304 run-command.c:758       trace: start_command:\n/Users/adl/libexec/git-core/git pack-objects --local\n--delta-base-offset objects/pack/.tmp-59391-pack --keep-true-parents\n--honor-pack-keep --non-empty --all --reflog --indexed-objects\n--write-bitmap-index-quiet\n19:56:54.209384 git.c:479               trace: built-in: git\npack-objects --local --delta-base-offset objects/pack/.tmp-59391-pack\n--keep-true-parents --honor-pack-keep --non-empty --all --reflog\n--indexed-objects --write-bitmap-index-quiet\nEnumerating objects: 512819, done.\nCounting objects: 100% (512819/512819), done.\nDelta compression using up to 12 threads\nCompressing objects: 100% (237575/237575), done.\nWriting objects: 100% (512819/512819), done.\nSelecting bitmap commits: 23999, done.\nBuilding bitmaps: 100% (309/309), done.\nTotal 512819 (delta 116078), reused 512819 (delta 116078), pack-reused\n0 (from 0)\n19:57:12.783287 run-command.c:666       trace: run_command: git prune\n--expire now\n19:57:12.783887 run-command.c:758       trace: start_command:\n/Users/adl/libexec/git-core/git prune --expire now\n19:57:12.799337 git.c:479               trace: built-in: git prune --expire now\n19:57:12.802050 run-command.c:666       trace: run_command: git\nworktree prune --expire 3.months.ago\n19:57:12.802115 run-command.c:758       trace: start_command:\n/Users/adl/libexec/git-core/git worktree prune --expire 3.months.ago\n19:57:12.812977 git.c:479               trace: built-in: git worktree\nprune --expire 3.months.ago\n19:57:12.814412 run-command.c:666       trace: run_command: git rerere gc\n19:57:12.814476 run-command.c:758       trace: start_command:\n/Users/adl/libexec/git-core/git rerere gc\n19:57:12.825732 git.c:479               trace: built-in: git rerere gc\n```\n\n--\nZheNing Hu\n"},{"id":"509554","messageId":"CABvF+3Z5kWAAbLz_P=oL1o90-u5Mo=DCyi5sEv-a_bJABB=pKw@mail.gmail.com","threadId":"62692","inReplyTo":"CAOLTT8Q0cH3Q=yPnTYKAwn8bC+iDW7onibsLF=bzVr8tGw5J0Q@mail.gmail.com","subject":"Re: [Possible Bug] --cruft option not work with git gc --prune=now","fromName":"Taylor Blau","fromEmail":"me@ttaylorr.com","sentAt":"2024-12-24T15:43:50Z","receivedAt":"2024-12-24T15:44:02Z","isPatch":false,"sender":{"key":"me@ttaylorr.com","avatar":"https://avatars.githubusercontent.com/u/301000140?v=4"},"body":"On Tue, Dec 24, 2024 at 08:07:16PM +0800, ZheNing Hu wrote:\n> I am trying to use the --cruft feature of git gc, and everything works\n> well, but when I combine it with --prune=now, I notice that no cruft\n> package is generated, which is very strange. So I turned on trace and\n> checked: instead of executing `git repack --cruft`, it executed `git\n> repack -d -l -a`. Is this normal? If `git gc --cruft --prune=now`\n> doesn't work as expected, it won't be safe to further execute `git gc\n> --cruft --expire-to=<dir> --prune=now`(in my another patch).\n>\n> I checked the code, and it appears that add_repack_all_option() first\n> processes `--prune=now` before handling `--cruft` option.\n\nThat's right, since --prune=now will cause your repository to purge any\nunreachable objects immediately, regardless of their mtimes.\n\nSo after a 'git gc --prune=now', your repository will only consist of\nreachable objects, meaning that there will be nothing to put into a\ncruft pack.\n\nNote that 'git gc' does not support the '--expire-to' option, but you\ncan use it via 'git repack'.\n\nThanks,\nTaylor\n"},{"id":"509562","messageId":"CAOLTT8TraRjBObcLotNr7+a9Ap7Fy8VVy7HjHLLWwEB_LvBrUQ@mail.gmail.com","threadId":"62692","inReplyTo":"CABvF+3ZU=96jQBmGw3eWmAQ4DjCdcm1VT7fHMVz_MxvW2xxPng@mail.gmail.com","subject":"Re: [Possible Bug] --cruft option not work with git gc --prune=now","fromName":"ZheNing Hu","fromEmail":"adlternative@gmail.com","sentAt":"2024-12-26T06:19:56Z","receivedAt":"2024-12-26T06:20:09Z","isPatch":false,"sender":{"key":"adlternative@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58138461?v=4"},"body":"Taylor Blau <me@ttaylorr.com> 于2024年12月24日周二 23:39写道：\n\n>\n> On Tue, Dec 24, 2024 at 08:07:16PM +0800, ZheNing Hu wrote:\n> > I am trying to use the --cruft feature of git gc, and everything works\n> > well, but when I combine it with --prune=now, I notice that no cruft\n> > package is generated, which is very strange. So I turned on trace and\n> > checked: instead of executing `git repack --cruft`, it executed `git\n> > repack -d -l -a`. Is this normal? If `git gc --cruft --prune=now`\n> > doesn't work as expected, it won't be safe to further execute `git gc\n> > --cruft --expire-to=<dir> --prune=now`(in my another patch).\n> >\n> > I checked the code, and it appears that add_repack_all_option() first\n> > processes `--prune=now` before handling `--cruft` option.\n>\n> That's right, since --prune=now will cause your repository to purge any\n> unreachable objects immediately, regardless of their mtimes.\n>\n> So after a 'git gc --prune=now', your repository will only consist of\n> reachable objects, meaning that there will be nothing to put into a\n> cruft pack.\n>\n> Note that 'git gc' does not support the '--expire-to' option, but you\n> can use it via 'git repack'.\n>\n\nOkay, I know that gc doesn't have an --expire-to parameter,\nbut here I was hoping to use git gc --prune=now --expire-to=<dir>,\nwhere expired and unreachable objects would be stored in <dir> for\neasy recovery in case of repository corruption. Moreover, it's more\nconvenient compared to using git repack + git prune\n(isn't a single gc command much simpler? Plus, most users are\nlikely familiar with gc rather than repack and prune).\n\n> Thanks,\n> Taylor\n\nThanks,\nZheNing Hu\n"},{"id":"509564","messageId":"20241226152347.GA68791@coredump.intra.peff.net","threadId":"62692","inReplyTo":"CAOLTT8TraRjBObcLotNr7+a9Ap7Fy8VVy7HjHLLWwEB_LvBrUQ@mail.gmail.com","subject":"Re: [Possible Bug] --cruft option not work with git gc --prune=now","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2024-12-26T15:23:47Z","receivedAt":"2024-12-26T15:23:55Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Dec 26, 2024 at 02:19:56PM +0800, ZheNing Hu wrote:\n\n> Okay, I know that gc doesn't have an --expire-to parameter,\n> but here I was hoping to use git gc --prune=now --expire-to=<dir>,\n> where expired and unreachable objects would be stored in <dir> for\n> easy recovery in case of repository corruption. Moreover, it's more\n> convenient compared to using git repack + git prune\n> (isn't a single gc command much simpler? Plus, most users are\n> likely familiar with gc rather than repack and prune).\n\nI don't think there is any reason that gc _can't_ support --expire-to as\nyou want. But any patch to do so would have to adjust how it calls\ngit-repack.\n\nUp until now, \"--prune=now\" meant it was fine to run \"repack -ad\", since\nthat would just discard any unreachable packed objects without further\nconsideration.  If we're keeping any objects, then we have to tell\nrepack what to do with them (which traditionally was just passing\n--unpack-unreachable, but these days can include --cruft).\n\nWith --expire-to, that logic wouldn't be valid anymore; even if we are\nexpiring all objects, we still might want to tell repack where to put\nthe expired ones. So I think you'd want to adjust the if/else in\nadd_repack_all_option() to pass --cruft, etc, when you see --expire-to\n(but still continue to \"repack -ad\" otherwise to keep the traditional\n\"git gc --prune=now\" as cheap as possible).\n\n-Peff\n"},{"id":"509730","messageId":"CAOLTT8R3WRiTcNjYzHdiazK9F0ppC9RG5m+9gyX6KrcTEF6jyw@mail.gmail.com","threadId":"62692","inReplyTo":"20241226152347.GA68791@coredump.intra.peff.net","subject":"Re: [Possible Bug] --cruft option not work with git gc --prune=now","fromName":"ZheNing Hu","fromEmail":"adlternative@gmail.com","sentAt":"2024-12-30T11:58:38Z","receivedAt":"2024-12-30T11:58:51Z","isPatch":false,"sender":{"key":"adlternative@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58138461?v=4"},"body":"Jeff King <peff@peff.net> 于2024年12月26日周四 23:23写道：\n>\n> On Thu, Dec 26, 2024 at 02:19:56PM +0800, ZheNing Hu wrote:\n>\n> > Okay, I know that gc doesn't have an --expire-to parameter,\n> > but here I was hoping to use git gc --prune=now --expire-to=<dir>,\n> > where expired and unreachable objects would be stored in <dir> for\n> > easy recovery in case of repository corruption. Moreover, it's more\n> > convenient compared to using git repack + git prune\n> > (isn't a single gc command much simpler? Plus, most users are\n> > likely familiar with gc rather than repack and prune).\n>\n> I don't think there is any reason that gc _can't_ support --expire-to as\n> you want. But any patch to do so would have to adjust how it calls\n> git-repack.\n>\n> Up until now, \"--prune=now\" meant it was fine to run \"repack -ad\", since\n> that would just discard any unreachable packed objects without further\n> consideration.  If we're keeping any objects, then we have to tell\n> repack what to do with them (which traditionally was just passing\n> --unpack-unreachable, but these days can include --cruft).\n>\n> With --expire-to, that logic wouldn't be valid anymore; even if we are\n> expiring all objects, we still might want to tell repack where to put\n> the expired ones. So I think you'd want to adjust the if/else in\n> add_repack_all_option() to pass --cruft, etc, when you see --expire-to\n> (but still continue to \"repack -ad\" otherwise to keep the traditional\n> \"git gc --prune=now\" as cheap as possible).\n>\n\nYou're right. Only when using `--cruft` and `--expire-to=<dir>` in git-gc,\nthe behavior of `--prune=now` should change: it should pass\n`--cruft-expiration=now` to repack instead of passing `-a`.\n\nI will cc you in the patch for supporting --expired-to=<dir> in git\ngc. Thank you :)\n\n> -Peff\n\n--\nZheNing Hu\n"}]}