{"thread":{"id":"59606","subject":"Should --update-refs exclude refs pointing to the current HEAD?","startedAt":"2023-04-17T08:21:31Z","lastAt":"2024-03-24T10:42:50Z","messageCount":18,"participants":["Stefan Haller","Kristoffer Haugsbakk","Phillip Wood","Felipe Contreras","Junio C Hamano","Elijah Newren"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"475502","messageId":"adb7f680-5bfa-6fa5-6d8a-61323fee7f53@haller-berlin.de","threadId":"59606","inReplyTo":null,"subject":"Should --update-refs exclude refs pointing to the current HEAD?","fromName":"Stefan Haller","fromEmail":"lists@haller-berlin.de","sentAt":"2023-04-17T08:21:14Z","receivedAt":"2023-04-17T08:21:31Z","isPatch":false,"sender":{"key":"lists@haller-berlin.de","avatar":null},"body":"The --update-refs option of git rebase is so useful that I have it on by\ndefault in my config. For stacked branches I find it hard to think of\nscenarios where I wouldn't want it.\n\nHowever, there are cases for non-stacked branches (i.e. other branches\npointing at the current HEAD) where updating them is undesirable. In\nfact, pretty much always, for me. Two examples, both very similar:\n\n1. I have a topic branch which is based off of master; I want to make a\ncopy of that branch and rebase it onto devel, just to try if that would\nwork. I don't want the original branch to be moved along in this case.\n\n2. I have a topic branch, and I want to make a copy of it to make some\nheavy history rewriting experiments. Again, my interactive rebases would\nalways rebase both branches in the same way, not what I want. In this\ncase I could work around it by doing the experiments on the original\nbranch, creating a tag beforehand that I could reset back to if the\nexperiments fail. But maybe I do want to keep both branches around for a\nwhile for some reason.\n\nBoth of these cases could be fixed by --update-refs not touching any\nrefs that point to the current HEAD. I'm having a hard time coming up\nwith cases where you would ever want those to be updated, in fact.\n\nAny opinions?\n\n-Stefan\n\n"},{"id":"475503","messageId":"3e278b6d-70f8-7ee4-3ff4-0212f6838ef5@haller-berlin.de","threadId":"59606","inReplyTo":"adb7f680-5bfa-6fa5-6d8a-61323fee7f53@haller-berlin.de","subject":"Re: Should --update-refs exclude refs pointing to the current HEAD?","fromName":"Stefan Haller","fromEmail":"lists@haller-berlin.de","sentAt":"2023-04-17T08:30:23Z","receivedAt":"2023-04-17T08:30:34Z","isPatch":false,"sender":{"key":"lists@haller-berlin.de","avatar":null},"body":"On 17.04.23 10:21, Stefan Haller wrote:\n> The --update-refs option of git rebase is so useful that I have it on by\n> default in my config. For stacked branches I find it hard to think of\n> scenarios where I wouldn't want it.\n> \n> However, there are cases for non-stacked branches (i.e. other branches\n> pointing at the current HEAD) where updating them is undesirable. In\n> fact, pretty much always, for me. Two examples, both very similar:\n> \n> 1. I have a topic branch which is based off of master; I want to make a\n> copy of that branch and rebase it onto devel, just to try if that would\n> work. I don't want the original branch to be moved along in this case.\n> \n> 2. I have a topic branch, and I want to make a copy of it to make some\n> heavy history rewriting experiments. Again, my interactive rebases would\n> always rebase both branches in the same way, not what I want. In this\n> case I could work around it by doing the experiments on the original\n> branch, creating a tag beforehand that I could reset back to if the\n> experiments fail. But maybe I do want to keep both branches around for a\n> while for some reason.\n> \n> Both of these cases could be fixed by --update-refs not touching any\n> refs that point to the current HEAD. I'm having a hard time coming up\n> with cases where you would ever want those to be updated, in fact.\n\nOne question then is whether the behavior makes sense for the case where\nyou have a stack of branches, and you make a copy of the topmost one and\nthen do either of the two above scenarios with that copy. With my\nproposal it would leave the old top of the stack alone, but it *would*\nupdate all the inner branches of the stack. Whether that's desired or\nnot is very unclear to me, and I would leave it up to user to add\n--no-update-refs in this case if they don't want it.\n\n-Stefan\n"},{"id":"475504","messageId":"d3895d9b-b45a-449d-a5e6-b8b8c5e6c4b8@app.fastmail.com","threadId":"59606","inReplyTo":"adb7f680-5bfa-6fa5-6d8a-61323fee7f53@haller-berlin.de","subject":"Re: Should --update-refs exclude refs pointing to the current HEAD?","fromName":"Kristoffer Haugsbakk","fromEmail":"code@khaugsbakk.name","sentAt":"2023-04-17T08:34:22Z","receivedAt":"2023-04-17T08:35:24Z","isPatch":false,"sender":{"key":"code@khaugsbakk.name","avatar":"https://avatars.githubusercontent.com/u/2229597?v=4"},"body":"Hi\n\nOn Mon, Apr 17, 2023, at 10:21, Stefan Haller wrote:\n> 2. I have a topic branch, and I want to make a copy of it to make some\n> heavy history rewriting experiments. Again, my interactive rebases would\n> always rebase both branches in the same way, not what I want. In this\n> case I could work around it by doing the experiments on the original\n> branch, creating a tag beforehand that I could reset back to if the\n> experiments fail. But maybe I do want to keep both branches around for a\n> while for some reason.\n\nI would use a lightweight tag, too, since this option doesn’t touch tags.[1]\n\nWhy do you want to keep both branches around? I would keep the tag\naround and then branch off of that if I want to make another divergent\nhistory in the future.\n\nThis is interesting to me since copying branches indeed does not seem to\n*gel* with this git-rebase(1) option. But I never really understood the\nuse-case for copying branches rather than using lightweight tags.\n\n† 1: I wonder why it wasn’t called `--update-branches`. On the one hand,\n    the option ignores refs other than branches. On the other hand, the\n    command in the todo list *will* update tags if you tell it to, and\n    even refs like `/refs/notes/*`. But `--update-branches` seems like a\n    better name, at least outside the todo editor.\n\n-- \nKristoffer Haugsbakk\n"},{"id":"475505","messageId":"6a8b92d8-5b86-9cf3-3619-4c8bedfa2d47@haller-berlin.de","threadId":"59606","inReplyTo":"d3895d9b-b45a-449d-a5e6-b8b8c5e6c4b8@app.fastmail.com","subject":"Re: Should --update-refs exclude refs pointing to the current HEAD?","fromName":"Stefan Haller","fromEmail":"lists@haller-berlin.de","sentAt":"2023-04-17T09:22:54Z","receivedAt":"2023-04-17T09:23:57Z","isPatch":false,"sender":{"key":"lists@haller-berlin.de","avatar":null},"body":"On 17.04.23 10:34, Kristoffer Haugsbakk wrote:\n> Hi\n> \n> On Mon, Apr 17, 2023, at 10:21, Stefan Haller wrote:\n>> 2. I have a topic branch, and I want to make a copy of it to make some\n>> heavy history rewriting experiments. Again, my interactive rebases would\n>> always rebase both branches in the same way, not what I want. In this\n>> case I could work around it by doing the experiments on the original\n>> branch, creating a tag beforehand that I could reset back to if the\n>> experiments fail. But maybe I do want to keep both branches around for a\n>> while for some reason.\n> \n> I would use a lightweight tag, too, since this option doesn’t touch tags.[1]\n> \n> Why do you want to keep both branches around? \n\nSeveral reasons:\n\nMaybe the original branch was pushed already, and I'm collaborating on\nit with a coworker. At the same time, I want to run my rebase experiment\nin parallel on a copy.\n\nMaybe I want to create github PRs for both of them, in order to run CI\non them, or get feedback for both of them from my coworkers.\n\nAlso, it just seems to be the most natural workflow for many people. I\nhave seen my coworkers do this a lot without thinking much whether there\nwould be a better way.\n\nMy question is not so much whether copying branches is a good idea, it's\nmore about how --update-refs should deal with copied branches *if* you\ndecide to use them.\n\n-Stefan\n"},{"id":"475521","messageId":"98548a5b-7d30-543b-b943-fd48d8926a33@gmail.com","threadId":"59606","inReplyTo":"adb7f680-5bfa-6fa5-6d8a-61323fee7f53@haller-berlin.de","subject":"Re: Should --update-refs exclude refs pointing to the current HEAD?","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2023-04-17T12:14:27Z","receivedAt":"2023-04-17T12:15:08Z","isPatch":false,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Stefan\n\nOn 17/04/2023 09:21, Stefan Haller wrote:\n> The --update-refs option of git rebase is so useful that I have it on by\n> default in my config. For stacked branches I find it hard to think of\n> scenarios where I wouldn't want it.\n> \n> However, there are cases for non-stacked branches (i.e. other branches\n> pointing at the current HEAD) where updating them is undesirable. In\n> fact, pretty much always, for me. Two examples, both very similar:\n> \n> 1. I have a topic branch which is based off of master; I want to make a\n> copy of that branch and rebase it onto devel, just to try if that would\n> work. I don't want the original branch to be moved along in this case.\n> \n> 2. I have a topic branch, and I want to make a copy of it to make some\n> heavy history rewriting experiments. Again, my interactive rebases would\n> always rebase both branches in the same way, not what I want. In this\n> case I could work around it by doing the experiments on the original\n> branch, creating a tag beforehand that I could reset back to if the\n> experiments fail. But maybe I do want to keep both branches around for a\n> while for some reason.\n> \n> Both of these cases could be fixed by --update-refs not touching any\n> refs that point to the current HEAD.\n\nI'd use a detached HEAD for the \"experimental\" rebase and then update \nthe branch if the rebase was successful. If you really want to use \nanother branch you could try running \"git commit --amend --only\" before \nrebasing to update the commit date so the two branches don't point to \nthe same commit.\n\nWe could add a command line option to restrict the branches that are \nupdated by --update-refs but I'm not that enthusiastic about it.\n\n> I'm having a hard time coming up\n> with cases where you would ever want those to be updated, in fact.\n\nIf a user using stacked branches creates a new branch and then realizes \nthey need to fix something on the parent before creating any commits on \nthe new branch they would want both to be updated. e.g.\t\n\t$ git symbolic-ref HEAD\n\trefs/heads/topic\n\t$ git checkout -b another-topic\n\t# fix a bug in topic - want topic and another-topic to be\n\t# updated\n\t$ git rebase -i --update-refs HEAD~2\n\nBest Wishes\n\nPhillip\n\n> Any opinions?\n> \n> -Stefan\n> \n\n"},{"id":"475574","messageId":"643df9c257293_19bb0294b7@chronos.notmuch","threadId":"59606","inReplyTo":"6a8b92d8-5b86-9cf3-3619-4c8bedfa2d47@haller-berlin.de","subject":"Re: Should --update-refs exclude refs pointing to the current HEAD?","fromName":"Felipe Contreras","fromEmail":"felipe.contreras@gmail.com","sentAt":"2023-04-18T02:00:34Z","receivedAt":"2023-04-18T02:00:44Z","isPatch":false,"sender":{"key":"felipe.contreras@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8358?v=4"},"body":"Stefan Haller wrote:\n> On 17.04.23 10:34, Kristoffer Haugsbakk wrote:\n> > On Mon, Apr 17, 2023, at 10:21, Stefan Haller wrote:\n> >> 2. I have a topic branch, and I want to make a copy of it to make some\n> >> heavy history rewriting experiments. Again, my interactive rebases would\n> >> always rebase both branches in the same way, not what I want. In this\n> >> case I could work around it by doing the experiments on the original\n> >> branch, creating a tag beforehand that I could reset back to if the\n> >> experiments fail. But maybe I do want to keep both branches around for a\n> >> while for some reason.\n> > \n> > I would use a lightweight tag, too, since this option doesn’t touch tags.[1]\n> > \n> > Why do you want to keep both branches around? \n> \n> Several reasons:\n> \n> Maybe the original branch was pushed already, and I'm collaborating on\n> it with a coworker. At the same time, I want to run my rebase experiment\n> in parallel on a copy.\n> \n> Maybe I want to create github PRs for both of them, in order to run CI\n> on them, or get feedback for both of them from my coworkers.\n> \n> Also, it just seems to be the most natural workflow for many people. I\n> have seen my coworkers do this a lot without thinking much whether there\n> would be a better way.\n\nI also do this, however, I often create a new branch to point to the previous\none (`git branch foo-1`). I know I can refer to it with `foo@{1}`, but then I\nhave to keep track if I rebase more than once, or do any other reflog\noperation.\n\nIf I've sent the series for review with my tool `git send-series`, then I don't\nhave to worry about that because I have refs for every version I sent.\n\nA notion of branch versions really comes in handy.\n\nCheers.\n\n-- \nFelipe Contreras"},{"id":"475736","messageId":"2db5c4a5-533a-f004-cf26-7ef938d1f94d@haller-berlin.de","threadId":"59606","inReplyTo":"98548a5b-7d30-543b-b943-fd48d8926a33@gmail.com","subject":"Re: Should --update-refs exclude refs pointing to the current HEAD?","fromName":"Stefan Haller","fromEmail":"lists@haller-berlin.de","sentAt":"2023-04-20T15:27:14Z","receivedAt":"2023-04-20T15:27:26Z","isPatch":false,"sender":{"key":"lists@haller-berlin.de","avatar":null},"body":"On 17.04.23 14:14, Phillip Wood wrote:\n> On 17/04/2023 09:21, Stefan Haller wrote:\n>> Both of these cases could be fixed by --update-refs not touching any\n>> refs that point to the current HEAD.\n> \n>> I'm having a hard time coming up\n>> with cases where you would ever want those to be updated, in fact.\n> \n> If a user using stacked branches creates a new branch and then realizes\n> they need to fix something on the parent before creating any commits on\n> the new branch they would want both to be updated. e.g.   \n>     $ git symbolic-ref HEAD\n>     refs/heads/topic\n>     $ git checkout -b another-topic\n>     # fix a bug in topic - want topic and another-topic to be\n>     # updated\n>     $ git rebase -i --update-refs HEAD~2\n\nOK, this is indeed one situation where my proposed change would do the\nwrong thing.\n\nIt is of course impossible for git to tell whether you were meaning to\ncreate a stack of branches here, or whether this is one of the cases\nwhere I'm creating a copy of a branch and want to \"detach\" it from its\nsource branch, as in the examples I posted earlier in this thread.\n\nIn my personal experience the latter is much more common than the\nformer, and it's also easier to correct the mistake manually in your\nexample by hard-resetting one branch to the other again, so I still\nthink it would be a useful change.\n\nAny other opinions about this?\n\n-Stefan\n"},{"id":"489942","messageId":"354f9fed-567f-42c8-9da9-148a5e223022@haller-berlin.de","threadId":"59606","inReplyTo":"adb7f680-5bfa-6fa5-6d8a-61323fee7f53@haller-berlin.de","subject":"Re: Should --update-refs exclude refs pointing to the current HEAD?","fromName":"Stefan Haller","fromEmail":"lists@haller-berlin.de","sentAt":"2024-03-05T07:40:13Z","receivedAt":"2024-03-05T07:49:17Z","isPatch":false,"sender":{"key":"lists@haller-berlin.de","avatar":null},"body":"On 17.04.23 10:21, Stefan Haller wrote:\n> The --update-refs option of git rebase is so useful that I have it on by\n> default in my config. For stacked branches I find it hard to think of\n> scenarios where I wouldn't want it.\n> \n> However, there are cases for non-stacked branches (i.e. other branches\n> pointing at the current HEAD) where updating them is undesirable. In\n> fact, pretty much always, for me. Two examples, both very similar:\n> \n> 1. I have a topic branch which is based off of master; I want to make a\n> copy of that branch and rebase it onto devel, just to try if that would\n> work. I don't want the original branch to be moved along in this case.\n> \n> 2. I have a topic branch, and I want to make a copy of it to make some\n> heavy history rewriting experiments. Again, my interactive rebases would\n> always rebase both branches in the same way, not what I want. In this\n> case I could work around it by doing the experiments on the original\n> branch, creating a tag beforehand that I could reset back to if the\n> experiments fail. But maybe I do want to keep both branches around for a\n> while for some reason.\n> \n> Both of these cases could be fixed by --update-refs not touching any\n> refs that point to the current HEAD. I'm having a hard time coming up\n> with cases where you would ever want those to be updated, in fact.\n\nComing back to this after almost a year, I can say that I'm still\nrunning into this problem relatively frequently, and it is annoying\nevery single time. Excluding refs pointing at the current head from\nbeing updated, as proposed above, would be a big usability improvement\nfor me.\n\nAnd I now see that \"git replay --contained --onto\" has the same problem,\nwhich I find very unfortunate. In my opinion, \"contained\" should only\ninclude refs that form a stack, but not copies of the current branch.\n\nOf course, since branch stacks are only a heuristic and not a built-in\nconcept, it's impossible for git to distinguish between a pair of copied\nbranches and a degenerate stack whose top-most branch is (still) empty,\nas in the example in [1]. In my personal experience though, degenerate\nstacks like that are very rare, but copied branches are not, so for me\nit would make a lot of sense to change the behavior of both \"rebase\n--update-refs\" and \"replay --contained\".\n\n-Stefan\n\n[1] <https://public-inbox.org/git/\n     98548a5b-7d30-543b-b943-fd48d8926a33@gmail.com/>\n"},{"id":"489965","messageId":"xmqqsf144pi7.fsf@gitster.g","threadId":"59606","inReplyTo":"354f9fed-567f-42c8-9da9-148a5e223022@haller-berlin.de","subject":"Re: Should --update-refs exclude refs pointing to the current HEAD?","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2024-03-05T16:22:56Z","receivedAt":"2024-03-05T16:23:00Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Stefan Haller <lists@haller-berlin.de> writes:\n\n>> Both of these cases could be fixed by --update-refs not touching any\n>> refs that point to the current HEAD. I'm having a hard time coming up\n>> with cases where you would ever want those to be updated, in fact.\n\nThe point of \"update-refs\", as I understand it, is that in addition\nto the end point of the history (E in \"git rebase --onto N O E\"),\nany branch tips that are between O..E can be migrated to point at\ntheir rewritten counterparts.  So I am not sure how it fundamentally\nsolves much by protecting only refs that point at a single commit\n(\"the current HEAD\" in your statement).\n\nWhen I want to see how the rebased history would look like without\ntouching the original, I often rebase a detached HEAD (i.e. instead\nof the earlier one, use \"git rebase --onto N O E^0\", or when\nrebasing the current branch, \"git rebase [--onto N] O HEAD^0\") and\nthat would protect the current branch well, but --update-refs of\ncourse would not work well.  There is no handy place like detached\nHEAD that can be used to save rewritten version of these extra\nbranch tips.\n\nIf branch tips A, B, and C are involved in the range of commits\nbeing rewritten, one way to help us in such a situation may be to\nteach \"git rebase\" to (1) somehow create a new set of proposed-A,\nproposed-B, and proposed-C refs (they do not have to be branches),\nwhile keeping the original A, B, and C intact, (2) allow us to\ninspect the resulting refs, compare the corresponding ones from\nthese two sets, and (3) allow us to promote (possibly a subset of)\nproposed- ones to their counterpart real branches after we inspect\nthem.  The latter two do not have to be subcommands of \"git rebase\"\nbut can be separate and new commands.\n"},{"id":"490058","messageId":"CABPp-BGO2ftEMHJDrf6yg3J4AfpKn=rpf_5Wt_WAS+Hi70KqPQ@mail.gmail.com","threadId":"59606","inReplyTo":"xmqqsf144pi7.fsf@gitster.g","subject":"Re: Should --update-refs exclude refs pointing to the current HEAD?","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2024-03-06T02:57:26Z","receivedAt":"2024-03-06T02:57:40Z","isPatch":false,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"[Restoring part of Stefan's earlier message so I can respond to both\nthat piece, as well as add to the ideas Junio presents.]\n\nHi,\n\nOn Tue, Mar 5, 2024 at 8:22 AM Junio C Hamano <gitster@pobox.com> wrote:\n>\n> Stefan Haller <lists@haller-berlin.de> writes:\n>\n> >> And I now see that \"git replay --contained --onto\" has the same problem,\n> >> which I find very unfortunate. In my opinion, \"contained\" should only\n> >> include refs that form a stack, but not copies of the current branch.\n\nI wouldn't want to change the default.  Even if we were to add an\noption, I'm not entirely sure what it should even implement.  In\naddition to Phillip's previous response in the thread, and part of\nJunio's response below (which I'll add to):\n\n1) What if there is a branch that is \"just a copy\" of one of the\nbranches earlier in the \"stack\"?  Since it's \"just a copy\", shouldn't\nit be excluded for similar reasons to what you are arguing?  And, if\nso, which branch is the copy?\n\n2) Further, a \"stack\", to me at least, suggests a linear history\nwithout branching (i.e. each commit has at most one parent _and_ at\nmost one child among the commits in the stack).  I designed `git\nreplay` to handle diverging histories (i.e. rebasing multiple branches\nthat _might_ share a subset of common history but none necessarily\nneed to fully contain the others, though perhaps the branches do share\nsome other contained branches), and I want it to handle replaying\nmerges as well.  While `git rebase --update-refs` is absolutely\nlimited to \"stacks\", and thus your argument might make sense in the\ncontext of `git rebase`, since you are bringing `git replay` into the\nmix, it needs to apply beyond a stack of commits.  It's not clear to\nme how to genericize your suggestions to handle cases other than a\nsimple stack of commits, though.\n\n3) This is mostly covered in (1) and (2), but to be explicit: `git\nreplay` is completely against the HEAD-is-special assumptions that are\npervasive within `git rebase`, and your problem is entirely phrased as\nHEAD-is-special due to your call out of \"the current branch\".  Is your\nargument limited to such special cases?  (If so, it might still be\nvalid for `git rebase`, of course.)\n\n4) Aren't there easier ways to handle this -- for both rebase and\nreplay?  I'll suggest some alternatives below...\n\n> >> Both of these cases could be fixed by --update-refs not touching any\n> >> refs that point to the current HEAD. I'm having a hard time coming up\n> >> with cases where you would ever want those to be updated, in fact.\n>\n> The point of \"update-refs\", as I understand it, is that in addition\n> to the end point of the history (E in \"git rebase --onto N O E\"),\n> any branch tips that are between O..E can be migrated to point at\n> their rewritten counterparts.  So I am not sure how it fundamentally\n> solves much by protecting only refs that point at a single commit\n> (\"the current HEAD\" in your statement).\n>\n> When I want to see how the rebased history would look like without\n> touching the original, I often rebase a detached HEAD (i.e. instead\n> of the earlier one, use \"git rebase --onto N O E^0\", or when\n> rebasing the current branch, \"git rebase [--onto N] O HEAD^0\") and\n> that would protect the current branch well, but --update-refs of\n> course would not work well.  There is no handy place like detached\n> HEAD that can be used to save rewritten version of these extra\n> branch tips.\n>\n> If branch tips A, B, and C are involved in the range of commits\n> being rewritten, one way to help us in such a situation may be to\n> teach \"git rebase\" to (1) somehow create a new set of proposed-A,\n> proposed-B, and proposed-C refs (they do not have to be branches),\n> while keeping the original A, B, and C intact, (2) allow us to\n> inspect the resulting refs, compare the corresponding ones from\n> these two sets, and (3) allow us to promote (possibly a subset of)\n> proposed- ones to their counterpart real branches after we inspect\n> them.  The latter two do not have to be subcommands of \"git rebase\"\n> but can be separate and new commands.\n\nHere, Junio is suggesting one alternative, and it's already\nimplemented in `git replay`.  Let me extend upon it and add two other\nalternatives as well:\n\n4a) `git replay` does what Junio suggests naturally, since it doesn't\nupdate the refs but instead gives commands which can be fed to `git\nupdate-ref --stdin`.  Thus, users can inspect the output of `git\nreplay` and only perform the updates they want (by feeding a subset of\nthe lines to update-ref --stdin).\n\n4b) For `git replay`, --contained is just syntactic sugar -- it isn't\nnecessary.  git replay will allow you to list multiple branches that\nyou want replayed, so you can specify which branches are relevant to\nyou.  (This doesn't help with `git rebase`, because `--update-refs` is\nthe only way to get additional branches replayed.)\n\n4c) For `git rebase --update-refs`, you can add `--interactive` and\nthen delete the `update-ref` line(s) corresponding to the refs you\ndon't want updated.\n"},{"id":"490112","messageId":"845ced9a-1f35-4100-a1ff-4243db2ba34f@haller-berlin.de","threadId":"59606","inReplyTo":"CABPp-BGO2ftEMHJDrf6yg3J4AfpKn=rpf_5Wt_WAS+Hi70KqPQ@mail.gmail.com","subject":"Re: Should --update-refs exclude refs pointing to the current HEAD?","fromName":"Stefan Haller","fromEmail":"lists@haller-berlin.de","sentAt":"2024-03-06T21:00:29Z","receivedAt":"2024-03-06T21:00:37Z","isPatch":false,"sender":{"key":"lists@haller-berlin.de","avatar":null},"body":"On 06.03.24 03:57, Elijah Newren wrote:\n\n> 1) What if there is a branch that is \"just a copy\" of one of the\n> branches earlier in the \"stack\"?  Since it's \"just a copy\", shouldn't\n> it be excluded for similar reasons to what you are arguing?  And, if\n> so, which branch is the copy?\n\nThis is a good point, but in my experience it's a lot more rare. Maybe\nI'm looking at all this just from my own experience, and there might be\nother usecases that are very different from mine, but as far as I am\nconcerned, copies of branches are not long-lived. There is no point in\nhaving two branches point at the same commit. When I create a copy of a\nbranch, I do that only to rebase the copy somewhere else _immediately_,\nleaving the original branch where it was. Which means that I encounter\ncopied branches only at the top of the stack, not in the middle. Which\nmeans that I'm fine with keeping the current behavior of \"rebase\n--update-ref\" to update both copies of that middle-of-the-stack branch,\nbecause it never happens in practice for me.\n\n> 2) Further, a \"stack\", to me at least, suggests a linear history\n> without branching (i.e. each commit has at most one parent _and_ at\n> most one child among the commits in the stack).  I designed `git\n> replay` to handle diverging histories (i.e. rebasing multiple branches\n> that _might_ share a subset of common history but none necessarily\n> need to fully contain the others, though perhaps the branches do share\n> some other contained branches), and I want it to handle replaying\n> merges as well.  While `git rebase --update-refs` is absolutely\n> limited to \"stacks\", and thus your argument might make sense in the\n> context of `git rebase`, since you are bringing `git replay` into the\n> mix, it needs to apply beyond a stack of commits.  It's not clear to\n> me how to genericize your suggestions to handle cases other than a\n> simple stack of commits, though.\n\nI don't see a contradiction here. I don't tend to do this in practice,\nbut I can totally imagine a tree of stacked branches that share some\ncommon base branches in the beginning and then diverge into different\nbranches from there. It's true that \"rebase --update-refs\", when told to\nrebase one of the leaf branches, will destroy this tree because it pulls\nthe base branches away from under the other leaf branches, but this is\nunrelated to my proposal, it has this problem today already. And it's\nawesome that git replay has a way to avoid this by rebasing the whole\ntree at once, keeping everything intact. Still, I don't see what's bad\nabout excluding branches that point at the same commits as the leaf\nbranches it is told to rebase when using \"replay --contains\". (I suppose\nwhat I'm suggesting is to treat \"--contains\" to mean \"is included in the\nhalf-open interval from base to tip\" of the revision range you are\nrebasing, rather than the closed interval.)\n\nMaybe I should make this more explicit again: I'm not trying to solve\nthe problem of making a copy of a stack of branches, and rebasing that\ncopy somewhere else. I think this can't be solved except by making\nbranch stacks a new concept in git, which I'm not sure we want to do.\n\n> 3) This is mostly covered in (1) and (2), but to be explicit: `git\n> replay` is completely against the HEAD-is-special assumptions that are\n> pervasive within `git rebase`, and your problem is entirely phrased as\n> HEAD-is-special due to your call out of \"the current branch\".  Is your\n> argument limited to such special cases?  (If so, it might still be\n> valid for `git rebase`, of course.)\n\nNo, I don't think I need HEAD to be special. \"The thing that I'm\nrebasing\" is special, and it is always HEAD for git rebase, but it can\nbe something else for replay.\n\n> 4a) `git replay` does what Junio suggests naturally, since it doesn't\n> update the refs but instead gives commands which can be fed to `git\n> update-ref --stdin`.  Thus, users can inspect the output of `git\n> replay` and only perform the updates they want (by feeding a subset of\n> the lines to update-ref --stdin).\n\nAt this point I probably need to explain that I'm rarely using the\ncommand line. I'm a user and co-maintainer of lazygit, and I want to\nmake lazygit work in such a way that \"it does the right thing\" in as\nmany cases as possible.\n\n> 4b) For `git replay`, --contained is just syntactic sugar -- it isn't\n> necessary.  git replay will allow you to list multiple branches that\n> you want replayed, so you can specify which branches are relevant to\n> you.\n\nThat's great, even if it means that I have to redo some of the work that\n--contains would already do for me, just because I want a slightly\ndifferent behavior.\n\n> 4c) For `git rebase --update-refs`, you can add `--interactive` and\n> then delete the `update-ref` line(s) corresponding to the refs you\n> don't want updated.\n\nYes, that's what I always do today to work around the problem. It's just\neasy to forget, and I find it annoying that I have to take this extra\nstep every time.\n\nOne last remark: whenever I describe my use case involving copies of\nbranches, people tell me not to do that, use detached heads instead, or\nother ways to achieve what I want. But then I don't understand why my\nproposal would make a difference for them. If you don't use copied\nbranches, then why do you care whether \"rebase --update-refs\" or \"replay\n--contained\" moves those copies or not? I still haven't heard a good\nargument for why the current behavior is desirable, except for the one\nexample of a degenerate stack that Phillip Wood described in [1].\n\n-Stefan\n\n\n[1] <https://public-inbox.org/git/\n     98548a5b-7d30-543b-b943-fd48d8926a33@gmail.com/>\n"},{"id":"490133","messageId":"CABPp-BE36Zhacdumd1JSc+7NXYpxZ=CQ1=ieebze=mDewpEUGA@mail.gmail.com","threadId":"59606","inReplyTo":"845ced9a-1f35-4100-a1ff-4243db2ba34f@haller-berlin.de","subject":"Re: Should --update-refs exclude refs pointing to the current HEAD?","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2024-03-07T05:36:47Z","receivedAt":"2024-03-07T05:37:03Z","isPatch":false,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Wed, Mar 6, 2024 at 1:00 PM Stefan Haller <lists@haller-berlin.de> wrote:\n>\n> On 06.03.24 03:57, Elijah Newren wrote:\n>\n> > 1) What if there is a branch that is \"just a copy\" of one of the\n> > branches earlier in the \"stack\"?  Since it's \"just a copy\", shouldn't\n> > it be excluded for similar reasons to what you are arguing?  And, if\n> > so, which branch is the copy?\n>\n> This is a good point, but in my experience it's a lot more rare. Maybe\n> I'm looking at all this just from my own experience, and there might be\n> other usecases that are very different from mine, but as far as I am\n> concerned, copies of branches are not long-lived.\n\n> There is no point in having two branches point at the same commit.\n\nBut isn't that what you're doing?\n\n> When I create a copy of a\n> branch, I do that only to rebase the copy somewhere else _immediately_,\n> leaving the original branch where it was.\n\nIf it is inherently tied like this, why not create the new branch\nimmediately after the rebase (with active_branch@{1} as the start\npoint), instead of creating it immediately before?\n\n> Which means that I encounter\n> copied branches only at the top of the stack, not in the middle. Which\n> means that I'm fine with keeping the current behavior of \"rebase\n> --update-ref\" to update both copies of that middle-of-the-stack branch,\n> because it never happens in practice for me.\n\nYou've really lost me here; are you saying you're fine changing the\ndesign to add inherent edgecase bugs to the code because those edge\ncases \"never happen in practice for me\"?  I've spent a lot of time\ndealing with built up cruft in git from partial solutions and fixes\nthat overlooked subsets of relevant testcases, so I'm not a fan of\nthat statement and in particular the last two words of it.  Perhaps\nI'm reading it wrong, and if so I apologize, but it triggered unhappy\nmemories of mine from merge-recursive.c and dir.c and elsewhere.\n\n> > 2) Further, a \"stack\", to me at least, suggests a linear history\n> > without branching (i.e. each commit has at most one parent _and_ at\n> > most one child among the commits in the stack).  I designed `git\n> > replay` to handle diverging histories (i.e. rebasing multiple branches\n> > that _might_ share a subset of common history but none necessarily\n> > need to fully contain the others, though perhaps the branches do share\n> > some other contained branches), and I want it to handle replaying\n> > merges as well.  While `git rebase --update-refs` is absolutely\n> > limited to \"stacks\", and thus your argument might make sense in the\n> > context of `git rebase`, since you are bringing `git replay` into the\n> > mix, it needs to apply beyond a stack of commits.  It's not clear to\n> > me how to genericize your suggestions to handle cases other than a\n> > simple stack of commits, though.\n>\n> I don't see a contradiction here. I don't tend to do this in practice,\n> but I can totally imagine a tree of stacked branches that share some\n> common base branches in the beginning and then diverge into different\n> branches from there. It's true that \"rebase --update-refs\", when told to\n> rebase one of the leaf branches, will destroy this tree because it pulls\n> the base branches away from under the other leaf branches, but this is\n> unrelated to my proposal, it has this problem today already. And it's\n> awesome that git replay has a way to avoid this by rebasing the whole\n> tree at once, keeping everything intact. Still, I don't see what's bad\n> about excluding branches that point at the same commits as the leaf\n> branches it is told to rebase when using \"replay --contains\".\n\nBy \"leaf branches\", do you mean (a) those commits explicitly mentioned\non the command line for being replayed, (b) only the subset of the\nbranches mentioned on the command line which aren't an ancestor of\nanother commit being replayed, or (c) something else?\n\n> (I suppose\n> what I'm suggesting is to treat \"--contains\" to mean \"is included in the\n> half-open interval from base to tip\" of the revision range you are\n> rebasing, rather than the closed interval.)\n\n\"half-open interval\"?  That to me again implies a simple stack, which\nsince we're trying to address the more general case, makes me more\nconfused rather than less.\n\nLet me re-ask my question another way.  If someone runs\n    git replay --onto A --contained ^B ^C D E F\nwhen branches G, H, & I are in the revision range of \"^B ^C D E F\",\nwith G in particular pointing where D does and H pointing where E\ndoes, and E contains D in its history, and F contains commits that are\nin neither D nor E, how do I figure out which of D-I should be\nupdated?\n\n> Maybe I should make this more explicit again: I'm not trying to solve\n> the problem of making a copy of a stack of branches, and rebasing that\n> copy somewhere else. I think this can't be solved except by making\n> branch stacks a new concept in git, which I'm not sure we want to do.\n\nOh, I hadn't even thought of that.  Yeah, that'd be even more complex.\n\n> > 3) This is mostly covered in (1) and (2), but to be explicit: `git\n> > replay` is completely against the HEAD-is-special assumptions that are\n> > pervasive within `git rebase`, and your problem is entirely phrased as\n> > HEAD-is-special due to your call out of \"the current branch\".  Is your\n> > argument limited to such special cases?  (If so, it might still be\n> > valid for `git rebase`, of course.)\n>\n> No, I don't think I need HEAD to be special. \"The thing that I'm\n> rebasing\" is special, and it is always HEAD for git rebase, but it can\n> be something else for replay.\n\nBut what exactly should that something else be?  I still don't\nunderstand what that is from your explanation so far.\n\n> > 4a) `git replay` does what Junio suggests naturally, since it doesn't\n> > update the refs but instead gives commands which can be fed to `git\n> > update-ref --stdin`.  Thus, users can inspect the output of `git\n> > replay` and only perform the updates they want (by feeding a subset of\n> > the lines to update-ref --stdin).\n>\n> At this point I probably need to explain that I'm rarely using the\n> command line. I'm a user and co-maintainer of lazygit, and I want to\n> make lazygit work in such a way that \"it does the right thing\" in as\n> many cases as possible.\n\n...and I'm pointing out that `git replay` has the necessary tools to\nenable you to do so.  Unlike `git rebase --update-refs` it doesn't\nautomatically update the branches, but just creates the new commits\nand tells you what it could update each branch to, in a format that\nyou can pass along to another tool to actually do the updates of the\nbranches.  As such, you can write your tool to take that output, pick\nout the bits you like, and only pass those bits along so that only\nsome of the branches are updated.\n\n> > 4b) For `git replay`, --contained is just syntactic sugar -- it isn't\n> > necessary.  git replay will allow you to list multiple branches that\n> > you want replayed, so you can specify which branches are relevant to\n> > you.\n>\n> That's great, even if it means that I have to redo some of the work that\n> --contains would already do for me, just because I want a slightly\n> different behavior.\n\nRight, but I thought you were maintaining lazygit, meaning that\nprogramming it to select the branches you want is a one time cost?\n\nSomething like `git log --format=%D --decorate-refs=refs/heads/\n${base}..HEAD^1 | grep -v ^$`, plus adding in the current branch,\nright?\n\nOr is the concern with this suggestion the performance hit you'd take\n(which admittedly might be a problem with this solution, since you\nwalk the commits an extra time)?\n\n> > 4c) For `git rebase --update-refs`, you can add `--interactive` and\n> > then delete the `update-ref` line(s) corresponding to the refs you\n> > don't want updated.\n>\n> Yes, that's what I always do today to work around the problem. It's just\n> easy to forget, and I find it annoying that I have to take this extra\n> step every time.\n\nAnd if you forget, then after the rebase it's trivial to move the\nupdated branch back to where you want it, right?\n\n   git branch -f ${copy_branch_name} ${current_branch_name}@{1}\n\nIn fact, that's probably easier than making the rebase interactive,\nand should be easier to remember since you only ever create these\nbranches precisely when you want to do a rebase.\n\n> One last remark: whenever I describe my use case involving copies of\n> branches, people tell me not to do that, use detached heads instead, or\n> other ways to achieve what I want. But then I don't understand why my\n> proposal would make a difference for them. If you don't use copied\n> branches, then why do you care whether \"rebase --update-refs\" or \"replay\n> --contained\" moves those copies or not? I still haven't heard a good\n> argument for why the current behavior is desirable, except for the one\n> example of a degenerate stack that Phillip Wood described in [1].\n\nThe current behavior is easy to describe and explain to users, and\ngeneralizes nicely to cases of replaying multiple diverging and\nconverging branches.\n\nTo me, the behavior you're proposing doesn't seem to share either of\nthose qualities, at least not as you've explained it so far.\n\nBut, perhaps that's because I still don't really understand your\nusecase.  I'm trying to, and it's possible I could be convinced there\nis a proposal here that is easy to explain to users and generalizes\nnicely.  My way of attempting to get that out is to make\ncounter-proposals and ask questions as a way of teasing out what your\nusecase is and what a refined proposal might be.  Currently, it seems\nthere are two trivial alternative solutions that would solve this\nproblem more cleanly (namely, either creating the branch after the\nfact instead of beforehand, or simply updating the branch after the\nfact)...but maybe I'm still just missing something?\n"},{"id":"490143","messageId":"25aa1b8d-79f6-4b33-be22-735a867367c0@app.fastmail.com","threadId":"59606","inReplyTo":"354f9fed-567f-42c8-9da9-148a5e223022@haller-berlin.de","subject":"Re: Should --update-refs exclude refs pointing to the current HEAD?","fromName":"Kristoffer Haugsbakk","fromEmail":"code@khaugsbakk.name","sentAt":"2024-03-07T07:59:27Z","receivedAt":"2024-03-07T07:59:49Z","isPatch":false,"sender":{"key":"code@khaugsbakk.name","avatar":"https://avatars.githubusercontent.com/u/2229597?v=4"},"body":"On Tue, Mar 5, 2024, at 08:40, Stefan Haller wrote:\n> Coming back to this after almost a year, I can say that I'm still\n> running into this problem relatively frequently, and it is annoying\n> every single time. Excluding refs pointing at the current head from\n> being updated, as proposed above, would be a big usability improvement\n> for me.\n\nSounds like a ref-stash command is in order…\n\n    # I want a new branch\n    git checkout -b new\n    # But I don’t want it to be affected by the next rebase\n    git ref-stash push\n    git rebase [...]\n    # Now I’m done: put the ref back where it was\n    git ref-stash pop\n\n-- \nKristoffer Haugsbakk\n"},{"id":"490144","messageId":"CABPp-BG6FZkiiFAT1YC_POqeWrKESmh5a1Sf1vUUQ2QvBYL8xg@mail.gmail.com","threadId":"59606","inReplyTo":"25aa1b8d-79f6-4b33-be22-735a867367c0@app.fastmail.com","subject":"Re: Should --update-refs exclude refs pointing to the current HEAD?","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2024-03-07T08:22:31Z","receivedAt":"2024-03-07T08:22:46Z","isPatch":false,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"Hi,\n\nOn Wed, Mar 6, 2024 at 11:59 PM Kristoffer Haugsbakk\n<code@khaugsbakk.name> wrote:\n>\n> On Tue, Mar 5, 2024, at 08:40, Stefan Haller wrote:\n> > Coming back to this after almost a year, I can say that I'm still\n> > running into this problem relatively frequently, and it is annoying\n> > every single time. Excluding refs pointing at the current head from\n> > being updated, as proposed above, would be a big usability improvement\n> > for me.\n>\n> Sounds like a ref-stash command is in order…\n\nA what?\n\n>     # I want a new branch\n>     git checkout -b new\n>     # But I don’t want it to be affected by the next rebase\n\nThis doesn't make any sense; rebase always operates on the current\nbranch, and Stefan wasn't asking for anything otherwise.  He was just\nconcerned that with --update-refs, one of the other branches it also\noperated on was one he didn't want it to operate on.\n\nPerhaps you meant\n    git branch new\nfor your first command?\n\n>     git ref-stash push\n>     git rebase [...]\n>     # Now I’m done: put the ref back where it was\n>     git ref-stash pop\n\nLeaving aside questions about how ref-stash is supposed to interact\nwith each and every other command out there, and how it's supposed to\nknow which branches it's operating on when you do pushes and pops...\n\nWhy do we need to invent a new command, when we already have the\nreflog?  You could drop both ref-stash commands, and instead just have\na\n   git branch -f new new@{1}\nat the end (assuming of course \"git branch new\" was used instead of\nyour \"git checkout -b new\", as I suggested earlier) to put \"new\" back\nto where it was before the rebase.  That's fewer commands.\n\nOr, even simpler, drop the initial branch creation and both ref-stash\ncommands by just not creating the branch until after the rebase.\nThat'd make the entire set of commands just be:\n   git rebase --update-refs [...]\n   git branch new current_branch@{1}\n\nPlus, either solution works today and needs no new changes.\n"},{"id":"490210","messageId":"42426c93-84fe-47d2-a41c-16284a86f003@haller-berlin.de","threadId":"59606","inReplyTo":"CABPp-BE36Zhacdumd1JSc+7NXYpxZ=CQ1=ieebze=mDewpEUGA@mail.gmail.com","subject":"Re: Should --update-refs exclude refs pointing to the current HEAD?","fromName":"Stefan Haller","fromEmail":"lists@haller-berlin.de","sentAt":"2024-03-07T20:16:42Z","receivedAt":"2024-03-07T20:16:46Z","isPatch":false,"sender":{"key":"lists@haller-berlin.de","avatar":null},"body":"Elijah, thanks for your patience with this. I appreciate the time and\nenergy you put into understanding what I want to achieve. The questions\nyou are asking help me understand my proposal better myself.\n\nIt seems that I didn't do a very good job at getting my point across so\nfar, so I'll try again in a more structured way.\n\nLet's begin by describing two very different user scenarios:\n\n1) Stacked branches. Git supports these reasonably well for simple cases\nthrough the \"rebase --update-refs\" command (and the \"rebase.updateRefs\"\nconfig), but since they are not a first-class concept, git needs to rely\non heuristics to determine which branches are part of a stack. For\nsimple cases this works very well, but more esoteric cases can have\nproblems (e.g. a non-linear topology of multiple stacks that may share\ncommon base branches and then diverge, in which case rebasing one of\nthem destroys the others; or degenerate stacks involving \"empty\"\nbranches either in the middle or at the top, in which case there's no\nway to tell what the order of the branches is supposed to be).\n\n2) Copying a branch, and rebasing it away from the original one (for\nnon-stacked branches, see below). The use case is that you have a branch\ncalled topic-1 (branched off main), which is pushed and in review\nalready, with CI running on it, and you want to test whether it works on\ndevel, so you make a new branch called topic-1-on-devel off of topic-1,\nand rebase it onto devel. You want to make a draft PR of that new branch\nto have CI run on it, too, and of course you want to keep the original\nbranch untouched. For me and most of my co-worker that I have observed\nin pairing sessions, the natural way to achieve this is as described\nabove: checkout a new branch, and rebase it where you want it to go.\n\nNext I'll describe my goals, and my non-goals. I know I can easily\nachieve 2) by simply not using --update-refs, but I like to have\n\"rebase.updateRefs\" set to true by default because it is so useful, and\nhaving to remember to use --no-update-refs whenever I do 2) is annoying.\n\nSo my goal is to make 2) work well (in the simple, non-stacked case)\neven when \"rebase.updateRefs\" is true, while not making 1) work any\nworse in the \"normal\", non-degenerate case.\n\nI'm _not_ trying to fix the problems that --update-refs has today (I\nbriefly mentioned some of them above, but there are more), and I'm not\ntrying to make 2) work well with stacked branches. It would certainly be\nnice if that would work too, but I don't think it can without\nintroducing branch stacks as a first-class feature in git, so I'll have\nto live with not supporting that case well. It would still be a big\nimprovement for me without that.\n\nI'll now go on to respond to some of your questions inline below, but\nI'll skip some of them in order to not make this too long. Do let me\nknow if there are still open questions that I didn't address.\n\nOn 07.03.24 06:36, Elijah Newren wrote:\n> On Wed, Mar 6, 2024 at 1:00 PM Stefan Haller <lists@haller-berlin.de> wrote:\n>>\n>> On 06.03.24 03:57, Elijah Newren wrote:\n>>\n>>> 1) What if there is a branch that is \"just a copy\" of one of the\n>>> branches earlier in the \"stack\"?  Since it's \"just a copy\", shouldn't\n>>> it be excluded for similar reasons to what you are arguing?  And, if\n>>> so, which branch is the copy?\n>>\n>> This is a good point, but in my experience it's a lot more rare. Maybe\n>> I'm looking at all this just from my own experience, and there might be\n>> other usecases that are very different from mine, but as far as I am\n>> concerned, copies of branches are not long-lived.\n> \n>> There is no point in having two branches point at the same commit.\n> \n> But isn't that what you're doing?\n\nOnly briefly, not permanently. I only described this to illustrate why\nit never happens to encounter branch copies in the middle of a stack.\n\n>> When I create a copy of a\n>> branch, I do that only to rebase the copy somewhere else _immediately_,\n>> leaving the original branch where it was.\n> \n> If it is inherently tied like this, why not create the new branch\n> immediately after the rebase (with active_branch@{1} as the start\n> point), instead of creating it immediately before?\n\nThat would be the wrong way round. I want to leave the original branch\nuntouched, make a new branch and rebase that away from the original.\n\n>> Which means that I encounter\n>> copied branches only at the top of the stack, not in the middle. Which\n>> means that I'm fine with keeping the current behavior of \"rebase\n>> --update-ref\" to update both copies of that middle-of-the-stack branch,\n>> because it never happens in practice for me.\n> \n> You've really lost me here; are you saying you're fine changing the\n> design to add inherent edgecase bugs to the code because those edge\n> cases \"never happen in practice for me\"?\n\nWait, now you are really turning things around. You make it sound like\nmy proposal is responsible for what you call a \"bug\" here. It's not, git\nalready behaves like this (and you may or may not consider that a\nproblem), and my proposal doesn't change anything about it. It doesn't\n\"fix\" it, that's right (and this is what I referred to when I said \"I'm\nfine with it\"), but it doesn't make it any worse either.\n\n>> I don't see a contradiction here. I don't tend to do this in practice,\n>> but I can totally imagine a tree of stacked branches that share some\n>> common base branches in the beginning and then diverge into different\n>> branches from there. It's true that \"rebase --update-refs\", when told to\n>> rebase one of the leaf branches, will destroy this tree because it pulls\n>> the base branches away from under the other leaf branches, but this is\n>> unrelated to my proposal, it has this problem today already. And it's\n>> awesome that git replay has a way to avoid this by rebasing the whole\n>> tree at once, keeping everything intact. Still, I don't see what's bad\n>> about excluding branches that point at the same commits as the leaf\n>> branches it is told to rebase when using \"replay --contains\".\n> \n> By \"leaf branches\", do you mean (a) those commits explicitly mentioned\n> on the command line for being replayed, (b) only the subset of the\n> branches mentioned on the command line which aren't an ancestor of\n> another commit being replayed, or (c) something else?\n\nIf I understand you right (and if I understand the user interface of\ngit-replay right), then what I mean is the combination of all single\ncommits that are mentioned on the command line, plus the right side of\nall A..B ranges that are mentioned on the command line. In my mental\nmodel those are \"the things that are being rebased\" (please let me know\nif that mental model is wrong), and I am proposing to exclude all\nbranches from updating that point to any of those and are not mentioned\non the command line, because they can be considered copies.\n\n> Let me re-ask my question another way.  If someone runs\n>     git replay --onto A --contained ^B ^C D E F\n> when branches G, H, & I are in the revision range of \"^B ^C D E F\",\n> with G in particular pointing where D does and H pointing where E\n> does, and E contains D in its history, and F contains commits that are\n> in neither D nor E, how do I figure out which of D-I should be\n> updated?\n\nD, E, F, and I are updated, G and H are not; this seems very obvious to\nme. D, E, and F because they are all mentioned explicitly; G and H are\nnot updated because they point to one of the \"things-to-be-rebased\", so\nthey are copies; I is updated because it is contained in E but does not\npoint at one of the \"things-to-be-rebased\", so it's part of a \"stack\"\n(or whatever you want to call this topology).\n\nIt's a heuristic; we need a way to distinguish things that are part of a\nstack from things that are copies. My heuristic for this relies on the\nassumption that the stack is not degenerate in the sense that it doesn't\ncontain any \"empty\" branches in the middle or at the top of the stack,\notherwise it wouldn't be possible to distinguish the two.\n\n>> No, I don't think I need HEAD to be special. \"The thing that I'm\n>> rebasing\" is special, and it is always HEAD for git rebase, but it can\n>> be something else for replay.\n> \n> But what exactly should that something else be?  I still don't\n> understand what that is from your explanation so far.\n\nAll the refs that are mentioned on the command line, either as a single\ncommit or as the second half of an A..B expression. It may well be that\nI have some misconception of how exactly git replay works, this sounds\nlike the most likely explanation for why we don't understand each other.\n\n> Something like `git log --format=%D --decorate-refs=refs/heads/\n> ${base}..HEAD^1 | grep -v ^$`, plus adding in the current branch,\n> right?\n> \n> Or is the concern with this suggestion the performance hit you'd take\n> (which admittedly might be a problem with this solution, since you\n> walk the commits an extra time)?\n\nYes, I can do that, and no, I'm not concerned about performance. We\nalready have all that data cached in memory anyway, so that's not a\nproblem. But this would only work for git replay, there's no way to do\nthe same thing for --update-ref. My goal is to offer the same features\nboth for the checked out branch (using rebase) and other branches (using\nreplay), and have them behave the same.\n\nSo my proposal is more about changing --update-ref, since I can solve it\nmanually for replay, as you described. However, _if_ we decide to change\n\"rebase --update-ref\", then I think it would make sense to change\n\"replay --contains\" in the same way, so that they behave more consistently.\n\n>> One last remark: whenever I describe my use case involving copies of\n>> branches, people tell me not to do that, use detached heads instead, or\n>> other ways to achieve what I want. But then I don't understand why my\n>> proposal would make a difference for them. If you don't use copied\n>> branches, then why do you care whether \"rebase --update-refs\" or \"replay\n>> --contained\" moves those copies or not? I still haven't heard a good\n>> argument for why the current behavior is desirable, except for the one\n>> example of a degenerate stack that Phillip Wood described in [1].\n> \n> The current behavior is easy to describe and explain to users, and\n> generalizes nicely to cases of replaying multiple diverging and\n> converging branches.\n\nIt sounds like you value the property of being easy to describe higher\nthan doing the expected thing in as many cases as possible.\n\n-Stefan\n"},{"id":"490285","messageId":"CABPp-BF_hWGynLm8FwjWWVYc=7wc6iBr_f79=h==thkzJVoRzw@mail.gmail.com","threadId":"59606","inReplyTo":"42426c93-84fe-47d2-a41c-16284a86f003@haller-berlin.de","subject":"Re: Should --update-refs exclude refs pointing to the current HEAD?","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2024-03-09T03:28:33Z","receivedAt":"2024-03-09T03:28:48Z","isPatch":false,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Thu, Mar 7, 2024 at 12:16 PM Stefan Haller <lists@haller-berlin.de> wrote:\n>\n> Elijah, thanks for your patience with this. I appreciate the time and\n> energy you put into understanding what I want to achieve. The questions\n> you are asking help me understand my proposal better myself.\n>\n> It seems that I didn't do a very good job at getting my point across so\n> far, so I'll try again in a more structured way.\n\nI think I fell short on communication on a few points as well; sorry about that.\n\n> Let's begin by describing two very different user scenarios:\n>\n> 1) Stacked branches. Git supports these reasonably well for simple cases\n> through the \"rebase --update-refs\" command (and the \"rebase.updateRefs\"\n> config), but since they are not a first-class concept, git needs to rely\n> on heuristics to determine which branches are part of a stack. For\n> simple cases this works very well, but more esoteric cases can have\n> problems (e.g. a non-linear topology of multiple stacks that may share\n> common base branches and then diverge, in which case rebasing one of\n> them destroys the others; or degenerate stacks involving \"empty\"\n> branches either in the middle or at the top, in which case there's no\n> way to tell what the order of the branches is supposed to be).\n>\n> 2) Copying a branch, and rebasing it away from the original one (for\n> non-stacked branches, see below). The use case is that you have a branch\n> called topic-1 (branched off main), which is pushed and in review\n> already, with CI running on it, and you want to test whether it works on\n> devel, so you make a new branch called topic-1-on-devel off of topic-1,\n> and rebase it onto devel. You want to make a draft PR of that new branch\n> to have CI run on it, too, and of course you want to keep the original\n> branch untouched. For me and most of my co-worker that I have observed\n> in pairing sessions, the natural way to achieve this is as described\n> above: checkout a new branch, and rebase it where you want it to go.\n>\n> Next I'll describe my goals, and my non-goals. I know I can easily\n> achieve 2) by simply not using --update-refs, but I like to have\n> \"rebase.updateRefs\" set to true by default because it is so useful, and\n> having to remember to use --no-update-refs whenever I do 2) is annoying.\n>\n> So my goal is to make 2) work well (in the simple, non-stacked case)\n> even when \"rebase.updateRefs\" is true, while not making 1) work any\n> worse in the \"normal\", non-degenerate case.\n\nThanks, this is helpful background.\n\n> I'm _not_ trying to fix the problems that --update-refs has today (I\n> briefly mentioned some of them above, but there are more), and I'm not\n> trying to make 2) work well with stacked branches. It would certainly be\n> nice if that would work too, but I don't think it can without\n> introducing branch stacks as a first-class feature in git, so I'll have\n> to live with not supporting that case well. It would still be a big\n> improvement for me without that.\n\n> >> When I create a copy of a\n> >> branch, I do that only to rebase the copy somewhere else _immediately_,\n> >> leaving the original branch where it was.\n> >\n> > If it is inherently tied like this, why not create the new branch\n> > immediately after the rebase (with active_branch@{1} as the start\n> > point), instead of creating it immediately before?\n>\n> That would be the wrong way round. I want to leave the original branch\n> untouched, make a new branch and rebase that away from the original.\n\nAh, sorry for misunderstanding.  Still, though, what's wrong with running\n    git branch -f original_branch original_branch@{1}\nafter the operation?  That'll make the original branch point to where\nit was before the rebase operation.  Since there's no separation in\ntime between when you create the new copy branch and do this rebase\noperation, it's not a matter of forgetting that there was this\noriginal branch that you wanted to reflect its own pre-rebase state,\nright?\n\nAlso, since you're not using the git cli directly but going through\nlazygit, isn't this something you can just include in lazygit as part\nof whatever overall operation is creating the new copy branch and\nrebasing it?\n\n> >> Which means that I encounter\n> >> copied branches only at the top of the stack, not in the middle. Which\n> >> means that I'm fine with keeping the current behavior of \"rebase\n> >> --update-ref\" to update both copies of that middle-of-the-stack branch,\n> >> because it never happens in practice for me.\n> >\n> > You've really lost me here; are you saying you're fine changing the\n> > design to add inherent edgecase bugs to the code because those edge\n> > cases \"never happen in practice for me\"?\n>\n> Wait, now you are really turning things around. You make it sound like\n> my proposal is responsible for what you call a \"bug\" here. It's not, git\n> already behaves like this (and you may or may not consider that a\n> problem), and my proposal doesn't change anything about it. It doesn't\n> \"fix\" it, that's right (and this is what I referred to when I said \"I'm\n> fine with it\"), but it doesn't make it any worse either.\n\nAh, I see where I was unclear as well, and my lack of clarity stemmed\nfrom not understanding your proposal.  To try to close the loop, allow\nme to re-translate your \"This is a good point, but..it never happens\nin practice for me.\" paragraph, the way I _erroneously_ read it at the\ntime:\n\n\"\"\"\nFor my new proposal, the case you bring up is a good point.  But it\ndoesn't happen for me, so I propose to leave it as undefined behavior.\n[As undefined behavior, anyone that triggers it is likely to get\nbehavior they deem buggy and not like it, but that won't affect me.]\n\"\"\"\n\nNow, obviously, that doesn't sound quite right.  I knew it at the\ntime, but reading and re-reading your paragraph, it kept coming out\nthat way for me.  Thus I tried to ask if that's what you really meant,\nand apologizing in advance if I was mis-reading.\n\nAnyway, with the extra explanation in your latest email, I now see\nthat you weren't leaving it undefined, but your proposal wasn't clear\nto me either in that paragraph or in combination with the rest of your\nprevious email.  Sorry for my misunderstanding.\n\n> > By \"leaf branches\", do you mean (a) those commits explicitly mentioned\n> > on the command line for being replayed, (b) only the subset of the\n> > branches mentioned on the command line which aren't an ancestor of\n> > another commit being replayed, or (c) something else?\n>\n> If I understand you right (and if I understand the user interface of\n> git-replay right), then what I mean is the combination of all single\n> commits that are mentioned on the command line, plus the right side of\n> all A..B ranges that are mentioned on the command line. In my mental\n> model those are \"the things that are being rebased\" (please let me know\n> if that mental model is wrong), and I am proposing to exclude all\n> branches from updating that point to any of those and are not mentioned\n> on the command line, because they can be considered copies.\n>\n> > Let me re-ask my question another way.  If someone runs\n> >     git replay --onto A --contained ^B ^C D E F\n> > when branches G, H, & I are in the revision range of \"^B ^C D E F\",\n> > with G in particular pointing where D does and H pointing where E\n> > does, and E contains D in its history, and F contains commits that are\n> > in neither D nor E, how do I figure out which of D-I should be\n> > updated?\n>\n> D, E, F, and I are updated, G and H are not; this seems very obvious to\n> me. D, E, and F because they are all mentioned explicitly; G and H are\n> not updated because they point to one of the \"things-to-be-rebased\", so\n> they are copies; I is updated because it is contained in E but does not\n> point at one of the \"things-to-be-rebased\", so it's part of a \"stack\"\n> (or whatever you want to call this topology).\n>\n> It's a heuristic; we need a way to distinguish things that are part of a\n> stack from things that are copies. My heuristic for this relies on the\n> assumption that the stack is not degenerate in the sense that it doesn't\n> contain any \"empty\" branches in the middle or at the top of the stack,\n> otherwise it wouldn't be possible to distinguish the two.\n\nAh, okay, now I understand the concrete proposal; thanks.\n\n> However, _if_ we decide to change\n> \"rebase --update-ref\", then I think it would make sense to change\n> \"replay --contains\" in the same way, so that they behave more consistently.\n\nYep, makes sense.\n\n> >> One last remark: whenever I describe my use case involving copies of\n> >> branches, people tell me not to do that, use detached heads instead, or\n> >> other ways to achieve what I want. But then I don't understand why my\n> >> proposal would make a difference for them. If you don't use copied\n> >> branches, then why do you care whether \"rebase --update-refs\" or \"replay\n> >> --contained\" moves those copies or not? I still haven't heard a good\n> >> argument for why the current behavior is desirable, except for the one\n> >> example of a degenerate stack that Phillip Wood described in [1].\n> >\n> > The current behavior is easy to describe and explain to users, and\n> > generalizes nicely to cases of replaying multiple diverging and\n> > converging branches.\n>\n> It sounds like you value the property of being easy to describe higher\n> than doing the expected thing in as many cases as possible.\n\nThere's certainly some truth to that.  For example, \"three-way merges\"\nare unsophisticated, and folks have suggested various ways of \"making\nthem smarter\" over the years (though there was more of this years\nago).  To quote someone else on that:\n\"\"\"\nMe _personally_, I want to have something that is very repeatable and\nnon-clever. Something I understand _or_ tells me that it can't do it.\n\"\"\"\nand\n\"\"\"\nI just don't like your notion that you should support the 5% problem with\nugly hacks, and then you dismiss the 95% problem with \"nothing else does\nit either\".\n\nIn other words, we're already merging manually for the 95%. Why do you\nthink the 5% is so important?\n\"\"\"\n\nThree-way merging and rebase --update-refs are obviously quite\ndifferent, so this might not be a good analogy.  I'm just saying you\nare right that I do sometimes tend to have the same biases as the\nauthor of the above quotes.\n\nBut, to be more direct about this particular issue, I've actually had\nthe usecase Phillip described, and never run into yours.  Yes, it's\nrare that I've run into Phillip's described case, but rare is still\nmore often than never.  That said, I totally accept that I might be an\noddball.  So, I think it's important to look at the alternatives:\n\n* If we make no modifications to --update-refs:\n  * the --update-refs behavior is very simple to describe\n  * folks with your usecase immediately understand why the copied\nbranch was updated, even though you didn't want it to be\n  * you have a trivial workaround you can run, as mentioned above (git\nbranch -f original_branch original_branch@{1})\n\n* If we modify --update-refs as you suggest:\n  * the --update-refs behavior is more complicated to describe to users\n  * folks with Phillip's usecase probably assume a bug and report it\nsince it isn't going to make any sense to them (and, my guess is, many\nwould report a bug even if the behavior is documented)\n\nThe downsides for the latter option seem worse to me, so unless the\nfirst usecase is predominant, I'd rather not make a change.  Granted,\nyou did claim the first usecase would be far more common, and you may\nbe right, but it's not so clear cut to me; I don't know how to\nvalidate that.  I'd at least first like to hear why the workaround for\nyour usecase that looks trivial to me is too onerous for you.\n"},{"id":"490474","messageId":"042bfc26-0dcd-4c0d-aa02-f4ccf9f4e66e@haller-berlin.de","threadId":"59606","inReplyTo":"CABPp-BF_hWGynLm8FwjWWVYc=7wc6iBr_f79=h==thkzJVoRzw@mail.gmail.com","subject":"Re: Should --update-refs exclude refs pointing to the current HEAD?","fromName":"Stefan Haller","fromEmail":"lists@haller-berlin.de","sentAt":"2024-03-12T09:28:48Z","receivedAt":"2024-03-12T09:29:23Z","isPatch":false,"sender":{"key":"lists@haller-berlin.de","avatar":null},"body":"On 09.03.24 04:28, Elijah Newren wrote:\n>> That would be the wrong way round. I want to leave the original branch\n>> untouched, make a new branch and rebase that away from the original.\n> \n> Ah, sorry for misunderstanding.  Still, though, what's wrong with running\n>     git branch -f original_branch original_branch@{1}\n> after the operation?\n\nIt's unintuitive. Users don't think this way, at least as far as I have\nobserved them (and I don't think this way myself). Also, for many users\nthe branch{n} syntax to access previous reflog entries is an advanced\nconcept that they are not familiar with.\n\n> Also, since you're not using the git cli directly but going through\n> lazygit, isn't this something you can just include in lazygit as part\n> of whatever overall operation is creating the new copy branch and\n> rebasing it?\n\nYes, there are various workarounds that I could build into lazygit.\nRight now I'm planning to have lazygit check whether any branch heads\npoint at any of the commits in the range of commits that is being\nrebased except for the head, and if not, add --no-update-refs. This will\nsolve it well enough for most cases, and it doesn't bother me too much\nthat I have to add this additional complexity to our code. I was just\nhoping that cli users typing\n\n  git checkout -b original-branch copy\n  git rebase --onto devel main\n\nwould get the same improvement. It bothers me a bit that we have to\nbuild clients around the git cli that make it perform better than the\ngit cli does.\n\n>> Wait, now you are really turning things around. You make it sound like\n>> my proposal is responsible for what you call a \"bug\" here. It's not, git\n>> already behaves like this (and you may or may not consider that a\n>> problem), and my proposal doesn't change anything about it. It doesn't\n>> \"fix\" it, that's right (and this is what I referred to when I said \"I'm\n>> fine with it\"), but it doesn't make it any worse either.\n> \n> Ah, I see where I was unclear as well, and my lack of clarity stemmed\n> from not understanding your proposal.  To try to close the loop, allow\n> me to re-translate your \"This is a good point, but..it never happens\n> in practice for me.\" paragraph, the way I _erroneously_ read it at the\n> time:\n> \n> \"\"\"\n> For my new proposal, the case you bring up is a good point.  But it\n> doesn't happen for me, so I propose to leave it as undefined behavior.\n> [As undefined behavior, anyone that triggers it is likely to get\n> behavior they deem buggy and not like it, but that won't affect me.]\n> \"\"\"\n> \n> Now, obviously, that doesn't sound quite right.  I knew it at the\n> time, but reading and re-reading your paragraph, it kept coming out\n> that way for me.  Thus I tried to ask if that's what you really meant,\n> and apologizing in advance if I was mis-reading.\n> \n> Anyway, with the extra explanation in your latest email, I now see\n> that you weren't leaving it undefined, but your proposal wasn't clear\n> to me either in that paragraph or in combination with the rest of your\n> previous email.  Sorry for my misunderstanding.\n\nI think it's worth clarifying this again, and see whether \"undefined\nbehavior\" is the right term to use here. Again, this discussion has\nimproved my own understanding of the matter, so let me try to spell it\nout again:\n\nThe fundamental underlying problem is that when we encounter two\nbranches pointing at the same commit in a rebase, git has no way to\ndistinguish whether this is because there's an \"empty\" branch in a stack\n(either at the top or in the middle), or whether one branch is a copy of\nthe other. In the first case, both branches should be updated by \"rebase\n--update-ref\", in the second case only one of them should, since the\nother is not part of the stack. Since there's no way for git to tell for\nsure, it can only guess which of the two was meant by the user, with a\nheuristic that hopefully guesses right in the majority of cases. I think\nit would be wrong to call it a \"bug\" (or an \"edge case bug\" like you did\nearlier) if it guesses wrong in a particular scenario.\n\nRight now, it _always_ guesses in favor of the stack, so it never\nconsiders a branch to be a copy. For my own use of git, and of my\nco-workers as I have observed them in pairing sessions, this is almost\nalways wrong. I have never encountered an empty branch in a stack, as\nfar as I remember, but I am encountering copies of branches fairly\noften, so I'd like to improve the heuristic to make git guess right in\nthese cases. Note that this is definitely not a 5% thing as in your\nthree-way merging example; I can't provide any hard numbers of course,\nbut it feels much more like the classical 80/20 rule to me (where my\nproposal would improve it for 80% of the cases, to be clear).\n\nSo, I concluded that copies are much more frequent than empty branches\nin a stack, so it would make sense for me to turn the heuristic around\nand always guess in favor of a copied branch. The problem is that we can\nonly do this for the tip of the branch, because only in that case can we\ntell which branch is the copy (the one being rebased) and which one is\nthe original that should be left alone. For branches in the middle of\nthe stack we just can't tell, so we have to guess in favor of an empty\nbranch in a stack and update both refs, since otherwise we'd have to\nrandomly pick one of them to update and leave the other one alone,\nrisking to break the stack this way.\n\nSo that's really where my proposal comes from: guess in favor of a\ncopied branch only at the tip but not in the middle; not because we only\nwant it at the tip, but just because we only can at the tip.\n\nBut fortunately, it is in fact true that I almost never create a copy of\na branch in the middle of a stack, but then I almost never have empty\nbranches in the middle of a stack either, so it doesn't really matter to\nme which way the heuristic guesses in this case.\n\nI hope this clarifies it a bit more.\n\n\nHaving written all this, I do realize that it's probably too complex to\nexplain to users (not the behavior itself, which is fairly simple, but\nthe rationale behind it).\n\n-Stefan\n"},{"id":"491347","messageId":"3a197bc5-de6d-4623-9141-b227cf454450@haller-berlin.de","threadId":"59606","inReplyTo":"adb7f680-5bfa-6fa5-6d8a-61323fee7f53@haller-berlin.de","subject":"Re: Should --update-refs exclude refs pointing to the current HEAD?","fromName":"Stefan Haller","fromEmail":"lists@haller-berlin.de","sentAt":"2024-03-24T10:42:47Z","receivedAt":"2024-03-24T10:42:50Z","isPatch":false,"sender":{"key":"lists@haller-berlin.de","avatar":null},"body":"On 17.04.23 10:21, Stefan Haller wrote:\n> The --update-refs option of git rebase is so useful that I have it on by\n> default in my config. For stacked branches I find it hard to think of\n> scenarios where I wouldn't want it.\n> \n> However, there are cases for non-stacked branches (i.e. other branches\n> pointing at the current HEAD) where updating them is undesirable. In\n> fact, pretty much always, for me. Two examples, both very similar:\n> \n> 1. I have a topic branch which is based off of master; I want to make a\n> copy of that branch and rebase it onto devel, just to try if that would\n> work. I don't want the original branch to be moved along in this case.\n> \n> 2. I have a topic branch, and I want to make a copy of it to make some\n> heavy history rewriting experiments. Again, my interactive rebases would\n> always rebase both branches in the same way, not what I want. In this\n> case I could work around it by doing the experiments on the original\n> branch, creating a tag beforehand that I could reset back to if the\n> experiments fail. But maybe I do want to keep both branches around for a\n> while for some reason.\n> \n> Both of these cases could be fixed by --update-refs not touching any\n> refs that point to the current HEAD. I'm having a hard time coming up\n> with cases where you would ever want those to be updated, in fact.\n\nSorry for continuing to beat this dead horse, but I just can't help\nadding this other use case that I just ran into yesterday and that\nsupports my point as well.\n\nSuppose I have a branch b, and I realize that it has commits for two\nseparate features, so I want to split it up into two independent\nbranches. The most natural way to do this is to create a branch b2 off\nof b, do an interactive rebase on b and drop half of its commits, then\ncheckout b2, do an interactive rebase on it too and drop the other half\nof the commits. With rebase.updateRefs set to true, the first\ninteractive rebase changes both b and b2, which is not what I want.\n\nOf course you can argue that since I'm doing an interactive rebase in\nthis case, it's easy to see the update-ref todo and delete it if I don't\nwant it. That's true, but it's an extra thing that I have to pay\nattention to.\n\nAlso, there's a twist as I'm writing this from the perspective of\nlazygit again. Lazygit has a feature to drop commits from a branch\nwithout doing an interactive rebase; it runs an interactive rebase\nbehind the scenes, sets the marked commits to \"drop\", and continues the\nrebase. I don't get a chance to delete the update-ref todo in this case.\n\nNow you can argue that this is really lazygit's problem then, and I can\nadd code to it to delete the update-ref todo in this scenario if that's\nwhat I want. That's true again, and I will, but it bugs me that we have\nto add clients around stock git to get the desired behavior. I would\nprefer to change git so that it behaves in the desired way in the first\nplace.\n\nAnd finally you can argue again that there's Phillip Wood's\ncounter-example, where you create b2 off of b with the intention to\ncreate a stack, but before you make the first commit on b2 you realize\nthere's this unwanted commit in b that you want to drop first. In this\ncase you do want to update both b and b2. My take on this is that 1)\nit's a much more rare case in my experience, and 2) it's much easier to\nrecover from. Once you realize that b2 wasn't updated by the rebase, you\njust reset --hard it to b again. This is a straight-forward operation\nthat even novice git users know how to do. Compare this to having to\nreset b2 back to where it was when you realize that it was updated by\nthe rebase and you didn't want it to; you need to get it back from the\nreflog in that case, which is a more advanced operation for many users.\n\n-Stefan\n"}]}