{"thread":{"id":"57520","subject":"Keep reflogs for deleted (remote tracking) branches?","startedAt":"2022-03-08T11:27:54Z","lastAt":"2022-03-14T12:10:41Z","messageCount":8,"participants":["Tao Klerks","Han-Wen Nienhuys","Ævar Arnfjörð Bjarmason","Jeff Hostetler"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"450722","messageId":"CAPMMpog=qBwLrxss_ci6ZMM+AjbdrF8tszXLW7YH1Zqr+m7mPQ@mail.gmail.com","threadId":"57520","inReplyTo":null,"subject":"Keep reflogs for deleted (remote tracking) branches?","fromName":"Tao Klerks","fromEmail":"tao@klerks.biz","sentAt":"2022-03-08T11:27:38Z","receivedAt":"2022-03-08T11:27:54Z","isPatch":false,"sender":{"key":"tao@klerks.biz","avatar":"https://avatars.githubusercontent.com/u/531704?v=4"},"body":"Hi folks,\n\nI have a practical question in case I missed something.\n\nImagine a small team (10ppl) working on a single centralized repo, in\ngithub for example. They regularly create new branches, and typically\ndelete them eventually - after merging, or at other times when\nbranches were a dead end or whatever. The members of this team all\nhave a \"simple\" git remote configuration, the result of a \"git clone\"\nwith no special configuration. One exception is that they have set\n\"fetch.prune\" to \"true\", because otherwise remote branches that have\nbeen deleted (in the context of completed merges, or arbitrarily by\nother team members) accumulate locally and having to explicitly prune\nthem from time to time is a pain. Every time someone says \"why do I\nstill see these branches in my repo?\", someone else replies \"oh, just\nrun 'git config fetch.prune true'\".\n\nNow, one day someone deletes a branch accidentally from the server,\nand the sole author of that branch has gone on vacation (or has an IT\nfailure, or has left the company, or whatever). Other team members\nhave seen this branch go by, it's appeared in their \"fetch\" output,\nbut no-one remembers checking it out, so it's not in their main\n\"HEAD\" reflogs.\n\nEven though the ref was at one point on every team member's computer,\nand they still undoubtedly have a dangling commit in their repos,\nthey're going to have a hard time finding it - there are many dangling\ncommits in any given repo.\n\nNow my question: is there any way to (temporarily) keep a reflog for\nthat deleted/pruned branch, in those team members' repos?\n\nAs far as I can tell, even \"core.logAllRefUpdates=always\" does *not*\nkeep any reflog entries around, even temporarily (until reflog\nexpiry), once a ref  is deleted - do I understand that correctly? Is\nthis behavior intentional / reasoned, or just a consequence of the\nfact that it's *hard* to keep \"managing\" per-branch reflogs for\nbranches that don't exist?\n\nI am planning a workaround using server hooks to \"back up\" refs that\nare being deleted from specific namespaces, in my specific case, and I\nimagine that a system like github keeps track of deleted stuff itself\nfor a while, but I find this \"per-ref reflog disappearance\" behavior\npuzzling / out-of-character, so wanted to make sure I'm not missing\nsomething.\n\nThanks,\nTao\n"},{"id":"450724","messageId":"CAFQ2z_Oht=-QrzoH8FW_Jm-B7u9O0wXUaY-ifwZah6gkcgVVSA@mail.gmail.com","threadId":"57520","inReplyTo":"CAPMMpog=qBwLrxss_ci6ZMM+AjbdrF8tszXLW7YH1Zqr+m7mPQ@mail.gmail.com","subject":"Re: Keep reflogs for deleted (remote tracking) branches?","fromName":"Han-Wen Nienhuys","fromEmail":"hanwen@google.com","sentAt":"2022-03-08T11:54:39Z","receivedAt":"2022-03-08T11:54:54Z","isPatch":false,"sender":{"key":"hanwen@google.com","avatar":"https://avatars.githubusercontent.com/u/31547?v=4"},"body":"On Tue, Mar 8, 2022 at 12:28 PM Tao Klerks <tao@klerks.biz> wrote:\n> As far as I can tell, even \"core.logAllRefUpdates=always\" does *not*\n> keep any reflog entries around, even temporarily (until reflog\n> expiry), once a ref  is deleted - do I understand that correctly? Is\n> this behavior intentional / reasoned, or just a consequence of the\n> fact that it's *hard* to keep \"managing\" per-branch reflogs for\n> branches that don't exist?\n>\n> I am planning a workaround using server hooks to \"back up\" refs that\n> are being deleted from specific namespaces, in my specific case, and I\n> imagine that a system like github keeps track of deleted stuff itself\n> for a while, but I find this \"per-ref reflog disappearance\" behavior\n> puzzling / out-of-character, so wanted to make sure I'm not missing\n> something.\n\nI think this behavior is motivated by directory/file conflicts. If you\nhave a reflog file in refs/logs/foo, you can't create a reflog for\nrefs/foo/bar, because that would live in refs/logs/foo/bar\n\nAt Google, we keep reflogs in a completely different storage system\naltogether, which avoids this problem, and I wouldn't be surprised if\nother large hosting providers do something similar.\n\n-- \nHan-Wen Nienhuys - Google Munich\nI work 80%. Don't expect answers from me on Fridays.\n"},{"id":"450727","messageId":"220308.868rtky4q8.gmgdl@evledraar.gmail.com","threadId":"57520","inReplyTo":"CAFQ2z_Oht=-QrzoH8FW_Jm-B7u9O0wXUaY-ifwZah6gkcgVVSA@mail.gmail.com","subject":"Re: Keep reflogs for deleted (remote tracking) branches?","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-03-08T12:59:38Z","receivedAt":"2022-03-08T13:05:25Z","isPatch":false,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Tue, Mar 08 2022, Han-Wen Nienhuys wrote:\n\n> On Tue, Mar 8, 2022 at 12:28 PM Tao Klerks <tao@klerks.biz> wrote:\n>> As far as I can tell, even \"core.logAllRefUpdates=always\" does *not*\n>> keep any reflog entries around, even temporarily (until reflog\n>> expiry), once a ref  is deleted - do I understand that correctly? Is\n>> this behavior intentional / reasoned, or just a consequence of the\n>> fact that it's *hard* to keep \"managing\" per-branch reflogs for\n>> branches that don't exist?\n>>\n>> I am planning a workaround using server hooks to \"back up\" refs that\n>> are being deleted from specific namespaces, in my specific case, and I\n>> imagine that a system like github keeps track of deleted stuff itself\n>> for a while, but I find this \"per-ref reflog disappearance\" behavior\n>> puzzling / out-of-character, so wanted to make sure I'm not missing\n>> something.\n>\n> I think this behavior is motivated by directory/file conflicts. If you\n> have a reflog file in refs/logs/foo, you can't create a reflog for\n> refs/foo/bar, because that would live in refs/logs/foo/bar\n>\n> At Google, we keep reflogs in a completely different storage system\n> altogether, which avoids this problem, and I wouldn't be surprised if\n> other large hosting providers do something similar.\n\nI once worked on a system where:\n\n * References would be \"archived\", i.e. just a backup system that would\n   run \"git fetch\" without pruning.\n\n * You were only allowed to push to either existing branches like\n   \"master\", or names with exactly one slash in them, e.g. \"avar/topic\",\n   not \"avar/topic/nested\", for that you'd need \"avar/topic-nested\" or\n   whatever.\n\nThe second item neatly avoids D/F conflicts, at the cost of some\ngrumbling from people who can't use their preferred branch name.\n\nAnd you can easily implement backups without that constraint by fetching\nrefs/* to refs/YYYYMMDD-HHMMSS/* or whatever, and have some manual\npruning process in place for those \"secondly refs\".\n\nMore generally I have not really run into this as a practical\nproblem.\n\nI.e. if a co-worker created a branch, AND nobody else used it, AND\nnothing was based on it, AND someone (presumably they) thought it was OK\nto delete it, it was probably something nobody cared all that much about\nto begin with :)\n\nAnother way to solve a similar problem is to have\npre-receive/post-receive hooks log attempted/successful pushes, which\nalong with an appropriate \"gc\" policy will allow you to manually look up\nthese older branches (or even to fetch them, if you publish the log and\nset uploadpack.allowAnySHA1InWant=true).\n"},{"id":"450751","messageId":"2aa11123-5456-b0f1-6c33-302924164e98@jeffhostetler.com","threadId":"57520","inReplyTo":"CAPMMpog=qBwLrxss_ci6ZMM+AjbdrF8tszXLW7YH1Zqr+m7mPQ@mail.gmail.com","subject":"Re: Keep reflogs for deleted (remote tracking) branches?","fromName":"Jeff Hostetler","fromEmail":"git@jeffhostetler.com","sentAt":"2022-03-08T14:57:04Z","receivedAt":"2022-03-08T14:57:09Z","isPatch":false,"sender":{"key":"git@jeffhostetler.com","avatar":null},"body":"\n\nOn 3/8/22 6:27 AM, Tao Klerks wrote:\n> Hi folks,\n> \n> I have a practical question in case I missed something.\n> \n> Imagine a small team (10ppl) working on a single centralized repo, in\n> github for example. They regularly create new branches, and typically\n> delete them eventually - after merging, or at other times when\n> branches were a dead end or whatever. The members of this team all\n> have a \"simple\" git remote configuration, the result of a \"git clone\"\n> with no special configuration. One exception is that they have set\n> \"fetch.prune\" to \"true\", because otherwise remote branches that have\n> been deleted (in the context of completed merges, or arbitrarily by\n> other team members) accumulate locally and having to explicitly prune\n> them from time to time is a pain. Every time someone says \"why do I\n> still see these branches in my repo?\", someone else replies \"oh, just\n> run 'git config fetch.prune true'\".\n> \n> Now, one day someone deletes a branch accidentally from the server,\n> and the sole author of that branch has gone on vacation (or has an IT\n> failure, or has left the company, or whatever). Other team members\n> have seen this branch go by, it's appeared in their \"fetch\" output,\n> but no-one remembers checking it out, so it's not in their main\n> \"HEAD\" reflogs.\n> \n> Even though the ref was at one point on every team member's computer,\n> and they still undoubtedly have a dangling commit in their repos,\n> they're going to have a hard time finding it - there are many dangling\n> commits in any given repo.\n> \n> Now my question: is there any way to (temporarily) keep a reflog for\n> that deleted/pruned branch, in those team members' repos?\n> \n> As far as I can tell, even \"core.logAllRefUpdates=always\" does *not*\n> keep any reflog entries around, even temporarily (until reflog\n> expiry), once a ref  is deleted - do I understand that correctly? Is\n> this behavior intentional / reasoned, or just a consequence of the\n> fact that it's *hard* to keep \"managing\" per-branch reflogs for\n> branches that don't exist?\n> \n> I am planning a workaround using server hooks to \"back up\" refs that\n> are being deleted from specific namespaces, in my specific case, and I\n> imagine that a system like github keeps track of deleted stuff itself\n> for a while, but I find this \"per-ref reflog disappearance\" behavior\n> puzzling / out-of-character, so wanted to make sure I'm not missing\n> something.\n> \n> Thanks,\n> Tao\n> \n\nHave you considered having each team member have their own\nprivate fork of the repo?  Then their branches are theirs\nalone and no one else needs to see or collide with them.\n\nThen when their work is ready for review/publishing, do\ncross-fork PRs into the company's main fork.\n\nJeff\n"},{"id":"451297","messageId":"CAPMMpoiF_vH_wUNfH6QrhLJmq+5kVWe2h_W-QEcctfF=dMdFmg@mail.gmail.com","threadId":"57520","inReplyTo":"2aa11123-5456-b0f1-6c33-302924164e98@jeffhostetler.com","subject":"Re: Keep reflogs for deleted (remote tracking) branches?","fromName":"Tao Klerks","fromEmail":"tao@klerks.biz","sentAt":"2022-03-14T08:09:39Z","receivedAt":"2022-03-14T08:09:59Z","isPatch":false,"sender":{"key":"tao@klerks.biz","avatar":"https://avatars.githubusercontent.com/u/531704?v=4"},"body":"On Tue, Mar 8, 2022 at 3:57 PM Jeff Hostetler <git@jeffhostetler.com> wrote:\n>\n>\n> On 3/8/22 6:27 AM, Tao Klerks wrote:\n> >\n> > I have a practical question in case I missed something.\n> >\n>\n> Have you considered having each team member have their own\n> private fork of the repo?  Then their branches are theirs\n> alone and no one else needs to see or collide with them.\n\nYes, this is a scheme that I've certainly considered - it is the\npublic norm after all, at least in open-source development.\n\nIn the case I'm describing, however, teams often prefer to work in\ncommunal spaces, seeing work appear and disappear in their group\nenvironment.\n\nOf course most teams wish to be isolated from each other, and of\ncourse individuals want and have the option to work in isolation from\ntheir team for any given period of time - and by \"isolation\" I don't\nnecessarily mean secret, but rather \"not pushing refs into a space\nthat others will automatically fetch\".\n\nThe case I am describing is a specific subset of an ecosystem - the\ncase where a team normally works in a communal central refspace.\n\nAnyway, thanks - it looks like no-one considers git's behavior very\nsurprising here, I guess I'll just implement a server-hook-based\nworkaround.\n"},{"id":"451298","messageId":"CAPMMpoiDTprbf_9J3gY6WQwUVWfOTms6LVyJDYQUOcUp-42doA@mail.gmail.com","threadId":"57520","inReplyTo":"220308.868rtky4q8.gmgdl@evledraar.gmail.com","subject":"Re: Keep reflogs for deleted (remote tracking) branches?","fromName":"Tao Klerks","fromEmail":"tao@klerks.biz","sentAt":"2022-03-14T08:25:40Z","receivedAt":"2022-03-14T08:26:01Z","isPatch":false,"sender":{"key":"tao@klerks.biz","avatar":"https://avatars.githubusercontent.com/u/531704?v=4"},"body":"On Tue, Mar 8, 2022 at 2:05 PM Ævar Arnfjörð Bjarmason <avarab@gmail.com> wrote:\n>\n>\n> On Tue, Mar 08 2022, Han-Wen Nienhuys wrote:\n>\n> > On Tue, Mar 8, 2022 at 12:28 PM Tao Klerks <tao@klerks.biz> wrote:\n> >> As far as I can tell, even \"core.logAllRefUpdates=always\" does *not*\n> >> keep any reflog entries around, even temporarily (until reflog\n> >> expiry), once a ref  is deleted - do I understand that correctly? Is\n> >> this behavior intentional / reasoned, or just a consequence of the\n> >> fact that it's *hard* to keep \"managing\" per-branch reflogs for\n> >> branches that don't exist?\n> >>\n> >> I am planning a workaround using server hooks to \"back up\" refs that\n> >> are being deleted from specific namespaces, in my specific case, and I\n> >> imagine that a system like github keeps track of deleted stuff itself\n> >> for a while, but I find this \"per-ref reflog disappearance\" behavior\n> >> puzzling / out-of-character, so wanted to make sure I'm not missing\n> >> something.\n> >\n> > I think this behavior is motivated by directory/file conflicts. If you\n> > have a reflog file in refs/logs/foo, you can't create a reflog for\n> > refs/foo/bar, because that would live in refs/logs/foo/bar\n> >\n> > At Google, we keep reflogs in a completely different storage system\n> > altogether, which avoids this problem, and I wouldn't be surprised if\n> > other large hosting providers do something similar.\n\nThis is interesting - so at google is the assumption that the storage\nsystem, whatever it looks like, *does* keep reflogs for deleted\nbranches? Or at least backs up states that get force-pushed out of\nexistence?\n\n>\n> I once worked on a system where:\n>\n>  * References would be \"archived\", i.e. just a backup system that would\n>    run \"git fetch\" without pruning.\n>\n>  * You were only allowed to push to either existing branches like\n>    \"master\", or names with exactly one slash in them, e.g. \"avar/topic\",\n>    not \"avar/topic/nested\", for that you'd need \"avar/topic-nested\" or\n>    whatever.\n>\n> The second item neatly avoids D/F conflicts, at the cost of some\n> grumbling from people who can't use their preferred branch name.\n>\n> And you can easily implement backups without that constraint by fetching\n> refs/* to refs/YYYYMMDD-HHMMSS/* or whatever, and have some manual\n> pruning process in place for those \"secondly refs\".\n\nAh right, backing up into another system - I guess we could...\n\n>\n> More generally I have not really run into this as a practical\n> problem.\n\nThat's fair, nor have I - but I *have* come reasonably close: one\nperson accidentally deletes a branch that someone else had prepared\n*without even realizing*, and the initial author is not available, and\nI only find out about it a few hours later. Dangling commit hunt, here\nwe come. (the original author became available and re-pushed before it\ncame to that)\n\n>\n> Another way to solve a similar problem is to have\n> pre-receive/post-receive hooks log attempted/successful pushes, which\n> along with an appropriate \"gc\" policy will allow you to manually look up\n> these older branches (or even to fetch them, if you publish the log and\n> set uploadpack.allowAnySHA1InWant=true).\n\nYep, that's closer to my expected plan, thanks - my intent is to back\nup, on force-push and/or deletion, into a specific refspace with a\ncleanup policy, using a server hook. So after something is \"deleted\"\n(or force-pushed away), it can be easily recovered for a period of eg\n3 months in that refspace, eg\n\"refs/force-push-backups/YYYY-MM-DD-<BRANCHNAME>-<HASHPREFIX>\".\n\nMy question is specifically about the, in my opinion, very surprising\nbehavior of deleting reflogs along with deleted branches - I mainly\nprovided the example use-case for context.\n"},{"id":"451302","messageId":"220314.86y21cerhe.gmgdl@evledraar.gmail.com","threadId":"57520","inReplyTo":"CAPMMpoiDTprbf_9J3gY6WQwUVWfOTms6LVyJDYQUOcUp-42doA@mail.gmail.com","subject":"Re: Keep reflogs for deleted (remote tracking) branches?","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-03-14T10:44:43Z","receivedAt":"2022-03-14T10:52:19Z","isPatch":false,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Mon, Mar 14 2022, Tao Klerks wrote:\n\n> On Tue, Mar 8, 2022 at 2:05 PM Ævar Arnfjörð Bjarmason <avarab@gmail.com> wrote:\n>> More generally I have not really run into this as a practical\n>> problem.\n>\n> That's fair, nor have I - but I *have* come reasonably close: one\n> person accidentally deletes a branch that someone else had prepared\n> *without even realizing*, and the initial author is not available, and\n> I only find out about it a few hours later. Dangling commit hunt, here\n> we come. (the original author became available and re-pushed before it\n> came to that)\n\nI think you might find it interesting to have pre-receive hooks\ne.g. reject pushes if you're deleting a topic whose commits aren't\nentirely <your author> i.e. just something like:\n\n    git push -o ireallymeanit=1 --delete topic\n\nI.e. it's an easy to implement extra safety check that people can always\nopt-out of, print a scary message and most people will think twice :)\n\n>> Another way to solve a similar problem is to have\n>> pre-receive/post-receive hooks log attempted/successful pushes, which\n>> along with an appropriate \"gc\" policy will allow you to manually look up\n>> these older branches (or even to fetch them, if you publish the log and\n>> set uploadpack.allowAnySHA1InWant=true).\n>\n> Yep, that's closer to my expected plan, thanks - my intent is to back\n> up, on force-push and/or deletion, into a specific refspace with a\n> cleanup policy, using a server hook. So after something is \"deleted\"\n> (or force-pushed away), it can be easily recovered for a period of eg\n> 3 months in that refspace, eg\n> \"refs/force-push-backups/YYYY-MM-DD-<BRANCHNAME>-<HASHPREFIX>\".\n>\n> My question is specifically about the, in my opinion, very surprising\n> behavior of deleting reflogs along with deleted branches - I mainly\n> provided the example use-case for context.\n\nYes it's quite a mess, e.g. if you follow the rabit hole at the\nrecent[1].\n\nOne fundimental problem (discussed in various places around the reftable\nbackend) is that we carry N meanings for an empty reflog:\n\nA. \"This is an active branch, but we have expired the entries\".\n\nB. \"I manually created this, knowing that the various core.* configs\n   around reflog will say \"oh, a reflog exists, let's log to it\" (in\n   some cases).\n\nC. Another is: This is \"stale\" log, i.e. no branch exists, but the log\n   is there.\n\nWhich is one reason[2] we'd delete them on branch deletion, because\notherwise we'd start logging again when a branch is re-created, which\npossibly isn't what we wanted.\n\n1. https://lore.kernel.org/git/de5e2b0e290791d0a4f58a893d8571b5fc8c4f1a.1646952843.git.avarab@gmail.com\n2. I'm not saying this was intended, and haven't looked into this case,\n   just that's it it's an emergent effect of how these files are treated\n   now.\n"},{"id":"451308","messageId":"CAPMMpohNi4LhyQm+WYfmRRVZ_B2YfoqeRzWRusza6VUwkJUOWg@mail.gmail.com","threadId":"57520","inReplyTo":"220314.86y21cerhe.gmgdl@evledraar.gmail.com","subject":"Re: Keep reflogs for deleted (remote tracking) branches?","fromName":"Tao Klerks","fromEmail":"tao@klerks.biz","sentAt":"2022-03-14T12:10:01Z","receivedAt":"2022-03-14T12:10:41Z","isPatch":false,"sender":{"key":"tao@klerks.biz","avatar":"https://avatars.githubusercontent.com/u/531704?v=4"},"body":"On Mon, Mar 14, 2022 at 11:52 AM Ævar Arnfjörð Bjarmason\n<avarab@gmail.com> wrote:\n>\n> I think you might find it interesting to have pre-receive hooks\n> e.g. reject pushes if you're deleting a topic whose commits aren't\n> entirely <your author> i.e. just something like:\n>\n>     git push -o ireallymeanit=1 --delete topic\n>\n> I.e. it's an easy to implement extra safety check that people can always\n> opt-out of, print a scary message and most people will think twice :)\n\nThat is indeed very interesting, thanks! I need to think about exactly\nwhen this is the right thing to do, but it's a tool in the box that I\nwas not aware of!\n\n\n> > My question is specifically about the, in my opinion, very surprising\n> > behavior of deleting reflogs along with deleted branches - I mainly\n> > provided the example use-case for context.\n>\n> Yes it's quite a mess, e.g. if you follow the rabit hole at the\n> recent[1].\n>\n> One fundimental problem (discussed in various places around the reftable\n> backend) is that we carry N meanings for an empty reflog:\n>\n> A. \"This is an active branch, but we have expired the entries\".\n>\n> B. \"I manually created this, knowing that the various core.* configs\n>    around reflog will say \"oh, a reflog exists, let's log to it\" (in\n>    some cases).\n>\n> C. Another is: This is \"stale\" log, i.e. no branch exists, but the log\n>    is there.\n>\n> Which is one reason[2] we'd delete them on branch deletion, because\n> otherwise we'd start logging again when a branch is re-created, which\n> possibly isn't what we wanted.\n>\n> 1. https://lore.kernel.org/git/de5e2b0e290791d0a4f58a893d8571b5fc8c4f1a.1646952843.git.avarab@gmail.com\n> 2. I'm not saying this was intended, and haven't looked into this case,\n>    just that's it it's an emergent effect of how these files are treated\n>    now.\n\nVery interesting, thx. Fwiw I would argue that resuming full logging\nwhen a new branch appears with the same name (within the period of\ntime where the reflog is not empty yet) is a very reasonable thing to\nend up doing, but I guess Han-Wen's note about potential path\nconflicts on branches *after* a deletion make this a hard thing to\nchange, even if \"accidental logging resuming\" were accepted as a\nsensible outcome here.\n"}]}