{"thread":{"id":"38507","subject":"Git gc removes all packs","startedAt":"2015-02-05T15:13:03Z","lastAt":"2015-02-27T13:14:26Z","messageCount":10,"participants":["Dmitry Neverov","Jeff King","Michael Haggerty","Junio C Hamano"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"255626","messageId":"CAC+L6n1M7LtGaJy94fnhXm94zJ32HXLNVGMguWSqHm=qqLLDxA@mail.gmail.com","threadId":"38507","inReplyTo":null,"subject":"Git gc removes all packs","fromName":"Dmitry Neverov","fromEmail":"dmitry.neverov@gmail.com","sentAt":"2015-02-05T15:13:03Z","receivedAt":"2015-02-05T15:13:03Z","isPatch":false,"sender":{"key":"dmitry.neverov@gmail.com","avatar":null},"body":"Hi,\n\nI'm experiencing a strange behavior of automatic git gc which corrupts a\nlocal repository. Git version 2.2.2 on Mac OS X 10.10.1.\n\nI'm using git p4 for synchronization with perforce. Sometimes after 'git\np4 rebase' git starts a garbage collection. When gc finishes a local\nrepository contains no pack files only loose objects, so I have to\nre-import repository from perforce. It also doesn't contain a temporary\npack git gc was creating.\n\nCommand line history looks like this:\n\n> git p4 rebase\nPerforming incremental import into refs/remotes/p4/master git branch\nDepot paths: //XXX/YYY/\nImport destination: refs/remotes/p4/master\nImporting revision 352157 (100%)\nRebasing the current branch onto remotes/p4/master\nFirst, rewinding head to replay your work on top of it...\nFast-forwarded master to remotes/p4/master.\nAuto packing the repository in background for optimum performance.\nSee \"git help gc\" for manual housekeeping.\n\n> ps aux | grep git\nnd              14335  95.0  1.4  4643292 114788   ??  R     8:52PM\n0:05.79 git pack-objects --keep-true-parents --honor-pack-keep\n--non-empty --all --reflog --indexed-objects\n--unpack-unreachable=2.weeks.ago --local --delta-base-offset\n/path/to/repo/.git/objects/pack/.tmp-14333-pack\nnd              14333   0.0  0.0  2452420    920   ??  S     8:52PM\n0:00.00 git repack -d -l -A --unpack-unreachable=2.weeks.ago\nnd              14331   0.0  0.0  2436036    744   ??  Ss    8:52PM\n0:00.00 git gc --auto\n\nAfter the 14331 process termination all packs are gone.\n\nOne more thing about my setup: since git p4 promotes a use of a linear\nhistory I use a separate repository for another branch in perforce. In\norder to be able to cherry-pick between repositories I added this\nanother repo objects dir as an alternate and also added a ref which is a\nsymbolic link to a branch in another repo (so I don't have to do any\nfetches).\n\nHow do I troubleshoot the problem? Is there any way to enable a some\nkind of logging for automatic git gc? Can use of alternates or symbolic\nlinks in refs cause such a behavior?\n\n--\nDmitry\n"},{"id":"255649","messageId":"20150205200332.GD15326@peff.net","threadId":"38507","inReplyTo":"CAC+L6n1M7LtGaJy94fnhXm94zJ32HXLNVGMguWSqHm=qqLLDxA@mail.gmail.com","subject":"Re: Git gc removes all packs","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2015-02-05T20:03:32Z","receivedAt":"2015-02-05T20:03:32Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Feb 05, 2015 at 04:13:03PM +0100, Dmitry Neverov wrote:\n\n> I'm using git p4 for synchronization with perforce. Sometimes after 'git\n> p4 rebase' git starts a garbage collection. When gc finishes a local\n> repository contains no pack files only loose objects, so I have to\n> re-import repository from perforce. It also doesn't contain a temporary\n> pack git gc was creating.\n\nIt sounds like git didn't find any refs; it will pack only objects which\nare reachable. Unreachable objects are either:\n\n  1. Exploded into loose objects if the mtime on the pack they contain\n     is less than 2 weeks old (and will eventually expire when they\n     become 2 weeks old).\n\n  2. Dropped completely if older than 2 weeks.\n\n> One more thing about my setup: since git p4 promotes a use of a linear\n> history I use a separate repository for another branch in perforce. In\n> order to be able to cherry-pick between repositories I added this\n> another repo objects dir as an alternate and also added a ref which is a\n> symbolic link to a branch in another repo (so I don't have to do any\n> fetches).\n\nYou can't symlink refs like this. The loose refs in the filesystem may\nbe migrated into the \"packed-refs\" file, at which point your symlink\nwill be broken. That is a likely reason why git would not find any refs.\n\nSo your setup will not ever work reliably.  But IMHO, it is a bug that\ngit does not notice the broken symlink and abort an operation which is\ncomputing reachability in order to drop objects. As you noticed, it\nmeans a misconfiguration or filesystem error results in data loss.\n\n-Peff\n"},{"id":"256203","messageId":"54E36EBF.2070600@alum.mit.edu","threadId":"38507","inReplyTo":"20150205200332.GD15326@peff.net","subject":"Re: Git gc removes all packs","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2015-02-17T16:39:27Z","receivedAt":"2015-02-17T16:39:27Z","isPatch":false,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"On 02/05/2015 09:03 PM, Jeff King wrote:\n> On Thu, Feb 05, 2015 at 04:13:03PM +0100, Dmitry Neverov wrote:\n>> [...]\n>> One more thing about my setup: since git p4 promotes a use of a linear\n>> history I use a separate repository for another branch in perforce. In\n>> order to be able to cherry-pick between repositories I added this\n>> another repo objects dir as an alternate and also added a ref which is a\n>> symbolic link to a branch in another repo (so I don't have to do any\n>> fetches).\n> \n> You can't symlink refs like this. The loose refs in the filesystem may\n> be migrated into the \"packed-refs\" file, at which point your symlink\n> will be broken. That is a likely reason why git would not find any refs.\n> \n> So your setup will not ever work reliably.  But IMHO, it is a bug that\n> git does not notice the broken symlink and abort an operation which is\n> computing reachability in order to drop objects. As you noticed, it\n> means a misconfiguration or filesystem error results in data loss.\n\nThere's a bunch of code in refs.c that is there explicitly for reading\nloose references that are symlinks. If the link contents literally start\nwith \"refs/\", then they are read and treated as a symbolic ref.\nOtherwise, the symlink is just followed.\n\nIt is still possible to write symbolic refs that are represented as\nsymlinks (see core.preferSymlinkRefs), but that backwards-compatibility\ncode was added in 2006(!) Maybe it's time to deprecate it. And maybe we\nshould start working towards a future where any symlinks under \"refs\"\ncause git to complain.\n\nMichael\n\n-- \nMichael Haggerty\nmhagger@alum.mit.edu\n"},{"id":"256204","messageId":"20150217165514.GA12176@peff.net","threadId":"38507","inReplyTo":"54E36EBF.2070600@alum.mit.edu","subject":"Re: Git gc removes all packs","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2015-02-17T16:55:15Z","receivedAt":"2015-02-17T16:55:15Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Tue, Feb 17, 2015 at 05:39:27PM +0100, Michael Haggerty wrote:\n\n> > You can't symlink refs like this. The loose refs in the filesystem may\n> > be migrated into the \"packed-refs\" file, at which point your symlink\n> > will be broken. That is a likely reason why git would not find any refs.\n> > \n> > So your setup will not ever work reliably.  But IMHO, it is a bug that\n> > git does not notice the broken symlink and abort an operation which is\n> > computing reachability in order to drop objects. As you noticed, it\n> > means a misconfiguration or filesystem error results in data loss.\n> \n> There's a bunch of code in refs.c that is there explicitly for reading\n> loose references that are symlinks. If the link contents literally start\n> with \"refs/\", then they are read and treated as a symbolic ref.\n> Otherwise, the symlink is just followed.\n\nRight, but we should be able to notice that:\n\n  1. We found a symlink.\n\n  2. We couldn't read it its ref value (because it's a broken link).\n\nI think we _do_ notice that at the lowest level, and set REF_ISBROKEN.\nBut the problem is that the reachability code in prune and in\npack-objects (triggered by \"repack -ad\") uses for_each_ref, and not\nfor_each_rawref. So they ignore \"broken\" refs rather than complaining,\neven though failing to read a ref may mean we could drop objects which\nwere only mentioned by that ref.\n\n> It is still possible to write symbolic refs that are represented as\n> symlinks (see core.preferSymlinkRefs), but that backwards-compatibility\n> code was added in 2006(!) Maybe it's time to deprecate it. And maybe we\n> should start working towards a future where any symlinks under \"refs\"\n> cause git to complain.\n\nI wouldn't mind seeing all of the symlink code go away, but I think it\nis orthogonal to the problem I mentioned.\n\n-Peff\n"},{"id":"256232","messageId":"54E3A695.1050708@alum.mit.edu","threadId":"38507","inReplyTo":"20150217165514.GA12176@peff.net","subject":"Re: Git gc removes all packs","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2015-02-17T20:37:41Z","receivedAt":"2015-02-17T20:37:41Z","isPatch":false,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"On 02/17/2015 05:55 PM, Jeff King wrote:\n> On Tue, Feb 17, 2015 at 05:39:27PM +0100, Michael Haggerty wrote:\n> \n>>> You can't symlink refs like this. The loose refs in the filesystem may\n>>> be migrated into the \"packed-refs\" file, at which point your symlink\n>>> will be broken. That is a likely reason why git would not find any refs.\n>>>\n>>> So your setup will not ever work reliably.  But IMHO, it is a bug that\n>>> git does not notice the broken symlink and abort an operation which is\n>>> computing reachability in order to drop objects. As you noticed, it\n>>> means a misconfiguration or filesystem error results in data loss.\n>>\n>> There's a bunch of code in refs.c that is there explicitly for reading\n>> loose references that are symlinks. If the link contents literally start\n>> with \"refs/\", then they are read and treated as a symbolic ref.\n>> Otherwise, the symlink is just followed.\n> \n> Right, but we should be able to notice that:\n> \n>   1. We found a symlink.\n> \n>   2. We couldn't read it its ref value (because it's a broken link).\n> \n> I think we _do_ notice that at the lowest level, and set REF_ISBROKEN.\n> But the problem is that the reachability code in prune and in\n> pack-objects (triggered by \"repack -ad\") uses for_each_ref, and not\n> for_each_rawref. So they ignore \"broken\" refs rather than complaining,\n> even though failing to read a ref may mean we could drop objects which\n> were only mentioned by that ref.\n\nYes, this makes sense too. But my point was that sticking symlinks to\nrandom files in your refs hierarchy is pretty questionable even *before*\nthe symlink gets broken. If we would warn the user as soon as we saw\nsuch a thing, then the user's problem would never have advanced as far\nas it did. Do you think that emitting warnings on *intact* symlinks is\ntoo draconian?\n\n> [...]\n\nMichael\n\n-- \nMichael Haggerty\nmhagger@alum.mit.edu\n"},{"id":"256240","messageId":"xmqq7fvg19se.fsf@gitster.dls.corp.google.com","threadId":"38507","inReplyTo":"54E3A695.1050708@alum.mit.edu","subject":"Re: Git gc removes all packs","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-02-17T21:57:05Z","receivedAt":"2015-02-17T21:57:05Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Michael Haggerty <mhagger@alum.mit.edu> writes:\n\n> On 02/17/2015 05:55 PM, Jeff King wrote:\n>> On Tue, Feb 17, 2015 at 05:39:27PM +0100, Michael Haggerty wrote:\n>> \n>>> There's a bunch of code in refs.c that is there explicitly for reading\n>>> loose references that are symlinks. If the link contents literally start\n>>> with \"refs/\", then they are read and treated as a symbolic ref.\n>>> Otherwise, the symlink is just followed.\n>> ...\n> Yes, this makes sense too. But my point was that sticking symlinks to\n> random files in your refs hierarchy is pretty questionable even *before*\n> the symlink gets broken. If we would warn the user as soon as we saw\n> such a thing, then the user's problem would never have advanced as far\n> as it did. Do you think that emitting warnings on *intact* symlinks is\n> too draconian?\n\nDo you mean that we would end up reading refs/heads/hold if the user\ndid this:\n\n    git rev-parse --verify HEAD -- >precious\n    ln -s ../../../precious .git/refs/heads/hold\n\nbecause that symbolic link does not begin with \"refs/\", and is an\naccident waiting to happen so we should forbid it in the longer\nterm and warning when we see it would be the first step?\n"},{"id":"256243","messageId":"54E3BE8B.2040403@alum.mit.edu","threadId":"38507","inReplyTo":"xmqq7fvg19se.fsf@gitster.dls.corp.google.com","subject":"Re: Git gc removes all packs","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2015-02-17T22:19:55Z","receivedAt":"2015-02-17T22:19:55Z","isPatch":false,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"On 02/17/2015 10:57 PM, Junio C Hamano wrote:\n> Michael Haggerty <mhagger@alum.mit.edu> writes:\n> \n>> On 02/17/2015 05:55 PM, Jeff King wrote:\n>>> On Tue, Feb 17, 2015 at 05:39:27PM +0100, Michael Haggerty wrote:\n>>>\n>>>> There's a bunch of code in refs.c that is there explicitly for reading\n>>>> loose references that are symlinks. If the link contents literally start\n>>>> with \"refs/\", then they are read and treated as a symbolic ref.\n>>>> Otherwise, the symlink is just followed.\n>>> ...\n>> Yes, this makes sense too. But my point was that sticking symlinks to\n>> random files in your refs hierarchy is pretty questionable even *before*\n>> the symlink gets broken. If we would warn the user as soon as we saw\n>> such a thing, then the user's problem would never have advanced as far\n>> as it did. Do you think that emitting warnings on *intact* symlinks is\n>> too draconian?\n> \n> Do you mean that we would end up reading refs/heads/hold if the user\n> did this:\n> \n>     git rev-parse --verify HEAD -- >precious\n>     ln -s ../../../precious .git/refs/heads/hold\n> \n> because that symbolic link does not begin with \"refs/\",\n\nCorrect, you can do exactly that. The \"hold\" reference is resolvable and\nlistable using \"for-each-ref\". But if I try to update it, the contents\nof the \"precious\" file are overwritten. On the other hand, if I run\n\"pack-refs\", then the current value of the \"hold\" reference is moved to\n\"packed-refs\" and the symlink is removed. This behavior is not sane.\n\n> and is an\n> accident waiting to happen so we should forbid it in the longer\n> term and warning when we see it would be the first step?\n\nYes, I am proposing that approach, though if somebody can suggest a use\ncase I'm willing to be convinced otherwise. The only thing I can imagine\nsymlinks being useful for might be to temporarily create a fake repo,\nrun one or two specific known-safe commands, then delete the repo again.\n\nMichael\n\n-- \nMichael Haggerty\nmhagger@alum.mit.edu\n"},{"id":"256256","messageId":"xmqqoaor4rr2.fsf@gitster.dls.corp.google.com","threadId":"38507","inReplyTo":"54E3BE8B.2040403@alum.mit.edu","subject":"Re: Git gc removes all packs","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-02-18T07:13:05Z","receivedAt":"2015-02-18T07:13:05Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Michael Haggerty <mhagger@alum.mit.edu> writes:\n\n> On 02/17/2015 10:57 PM, Junio C Hamano wrote:\n> ...\n>> Do you mean that we would end up reading refs/heads/hold if the user\n>> did this:\n>> \n>>     git rev-parse --verify HEAD -- >precious\n>>     ln -s ../../../precious .git/refs/heads/hold\n>> \n>> because that symbolic link does not begin with \"refs/\",\n>\n> Correct, you can do exactly that. The \"hold\" reference is resolvable and\n> listable using \"for-each-ref\". But if I try to update it, the contents\n> of the \"precious\" file are overwritten. On the other hand, if I run\n> \"pack-refs\", then the current value of the \"hold\" reference is moved to\n> \"packed-refs\" and the symlink is removed. This behavior is not sane.\n>\n>> and is an\n>> accident waiting to happen so we should forbid it in the longer\n>> term and warning when we see it would be the first step?\n>\n> Yes, I am proposing that approach, though if somebody can suggest a use\n> case I'm willing to be convinced otherwise.\n\nThanks.  I agree the proposed tightening is probably harmless, but I\ntoo would want to see if somebody comes up with a valid use case.  I\ndo not think of anything offhand.\n"},{"id":"256738","messageId":"CAC+L6n3OFYsjm+5PMW3DBzJo7LnUsxRq1TRE4PMvFvWVG6DQ+A@mail.gmail.com","threadId":"38507","inReplyTo":"20150205200332.GD15326@peff.net","subject":"Re: Git gc removes all packs","fromName":"Dmitry Neverov","fromEmail":"dmitry.neverov@gmail.com","sentAt":"2015-02-27T10:16:09Z","receivedAt":"2015-02-27T10:16:09Z","isPatch":false,"sender":{"key":"dmitry.neverov@gmail.com","avatar":null},"body":"I followed your advice and removed a symlink ref from my repository.\nBut didn't help.. automatic GC has just removed all packs again. May\nalternates cause such a behavior? Are any ways to make gc log\nsomewhere why it removes packs?\n\nOn Thu, Feb 5, 2015 at 9:03 PM, Jeff King <peff@peff.net> wrote:\n> On Thu, Feb 05, 2015 at 04:13:03PM +0100, Dmitry Neverov wrote:\n>\n>> I'm using git p4 for synchronization with perforce. Sometimes after 'git\n>> p4 rebase' git starts a garbage collection. When gc finishes a local\n>> repository contains no pack files only loose objects, so I have to\n>> re-import repository from perforce. It also doesn't contain a temporary\n>> pack git gc was creating.\n>\n> It sounds like git didn't find any refs; it will pack only objects which\n> are reachable. Unreachable objects are either:\n>\n>   1. Exploded into loose objects if the mtime on the pack they contain\n>      is less than 2 weeks old (and will eventually expire when they\n>      become 2 weeks old).\n>\n>   2. Dropped completely if older than 2 weeks.\n>\n>> One more thing about my setup: since git p4 promotes a use of a linear\n>> history I use a separate repository for another branch in perforce. In\n>> order to be able to cherry-pick between repositories I added this\n>> another repo objects dir as an alternate and also added a ref which is a\n>> symbolic link to a branch in another repo (so I don't have to do any\n>> fetches).\n>\n> You can't symlink refs like this. The loose refs in the filesystem may\n> be migrated into the \"packed-refs\" file, at which point your symlink\n> will be broken. That is a likely reason why git would not find any refs.\n>\n> So your setup will not ever work reliably.  But IMHO, it is a bug that\n> git does not notice the broken symlink and abort an operation which is\n> computing reachability in order to drop objects. As you noticed, it\n> means a misconfiguration or filesystem error results in data loss.\n>\n> -Peff\n"},{"id":"256741","messageId":"20150227131425.GA13005@peff.net","threadId":"38507","inReplyTo":"CAC+L6n3OFYsjm+5PMW3DBzJo7LnUsxRq1TRE4PMvFvWVG6DQ+A@mail.gmail.com","subject":"Re: Git gc removes all packs","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2015-02-27T13:14:26Z","receivedAt":"2015-02-27T13:14:26Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Fri, Feb 27, 2015 at 11:16:09AM +0100, Dmitry Neverov wrote:\n\n> I followed your advice and removed a symlink ref from my repository.\n> But didn't help.. automatic GC has just removed all packs again. May\n> alternates cause such a behavior? Are any ways to make gc log\n> somewhere why it removes packs?\n\nIf you have two repositories, A and B, and A points to B via alternates,\nthen you cannot safely run \"git gc\" in B unless it knows about all of\nthe refs in A. As we discussed before, symlinking the refs is not\nenough, because those symlinks get stale. But nor is removing the\nsymlinks and just not knowing about the refs. :)\n\nThe only safe thing to do is to fetch all of the refs from A into B just\nbefore running the gc (and consequently, you probably want to disable\ngc.auto in B).\n\n-Peff\n"}]}