{"thread":{"id":"51023","subject":"\"git branch -f\" corrupt other worktree","startedAt":"2019-05-02T11:58:34Z","lastAt":"2019-05-02T17:16:21Z","messageCount":6,"participants":["frank kulow","Duy Nguyen","Ævar Arnfjörð Bjarmason"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"374812","messageId":"CAA2qrhBmbSe5R0xQPBZiRcz0MGG=JcF4BjxHqmyeTFNR19FKbg@mail.gmail.com","threadId":"51023","inReplyTo":null,"subject":"\"git branch -f\" corrupt other worktree","fromName":"frank kulow","fromEmail":"kulow.f@googlemail.com","sentAt":"2019-05-02T11:58:31Z","receivedAt":"2019-05-02T11:58:34Z","isPatch":false,"sender":{"key":"kulow.f@googlemail.com","avatar":null},"body":"git version 2.21.0.windows.1\n\n> /c/tmp/gt (Branch_702091a0)\n$ git worktree add ../wt master\nPreparing worktree (checking out 'master')\nHEAD is now at f534c32 4\n\n> /c/tmp/gt (Branch_702091a0)\n$ git branch -D master\nerror: Cannot delete branch 'master' checked out at 'C:/tmp/wt'\n\n#but this is possible:\n\n> /c/tmp/gt (Branch_702091a0)\n$ git branch -f master HEAD\n\n#and the other worktree is now corrupted:\n\n> /c/tmp/wt (master)\n$ git status\nOn branch master\nChanges to be committed:\n  (use \"git reset HEAD <file>...\" to unstage)\n\n        modified:   txt.txt\n        deleted:    txtb.txt\n\n\n\ngreetings f.kulow\n"},{"id":"374813","messageId":"CACsJy8CJ_PB+QKp-T-yTHNPYgjEEVN39QbnAu4kKzGGcEQ0ezA@mail.gmail.com","threadId":"51023","inReplyTo":"CAA2qrhBmbSe5R0xQPBZiRcz0MGG=JcF4BjxHqmyeTFNR19FKbg@mail.gmail.com","subject":"Re: \"git branch -f\" corrupt other worktree","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2019-05-02T12:29:50Z","receivedAt":"2019-05-02T12:30:18Z","isPatch":false,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Thu, May 2, 2019 at 6:59 PM frank kulow <kulow.f@googlemail.com> wrote:\n>\n> git version 2.21.0.windows.1\n>\n> > /c/tmp/gt (Branch_702091a0)\n> $ git worktree add ../wt master\n> Preparing worktree (checking out 'master')\n> HEAD is now at f534c32 4\n>\n> > /c/tmp/gt (Branch_702091a0)\n> $ git branch -D master\n> error: Cannot delete branch 'master' checked out at 'C:/tmp/wt'\n>\n> #but this is possible:\n>\n> > /c/tmp/gt (Branch_702091a0)\n> $ git branch -f master HEAD\n\nI admit I didn't see this. But I don't know how far we would go\nprotecting other worktrees. You give --force and that usually means\n\"Yes I know what I'm doing, don't stop me\". If --force rejects in this\ncase, what would be the real force, --force --force maybe, or fall\nback to \"git update-ref\"?\n\n>\n> #and the other worktree is now corrupted:\n>\n> > /c/tmp/wt (master)\n> $ git status\n> On branch master\n> Changes to be committed:\n>   (use \"git reset HEAD <file>...\" to unstage)\n>\n>         modified:   txt.txt\n>         deleted:    txtb.txt\n>\n>\n>\n> greetings f.kulow\n\n\n\n-- \nDuy\n"},{"id":"374814","messageId":"87d0l1qat5.fsf@evledraar.gmail.com","threadId":"51023","inReplyTo":"CACsJy8CJ_PB+QKp-T-yTHNPYgjEEVN39QbnAu4kKzGGcEQ0ezA@mail.gmail.com","subject":"Re: \"git branch -f\" corrupt other worktree","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2019-05-02T12:51:18Z","receivedAt":"2019-05-02T12:51:23Z","isPatch":false,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Thu, May 02 2019, Duy Nguyen wrote:\n\n> On Thu, May 2, 2019 at 6:59 PM frank kulow <kulow.f@googlemail.com> wrote:\n>>\n>> git version 2.21.0.windows.1\n>>\n>> > /c/tmp/gt (Branch_702091a0)\n>> $ git worktree add ../wt master\n>> Preparing worktree (checking out 'master')\n>> HEAD is now at f534c32 4\n>>\n>> > /c/tmp/gt (Branch_702091a0)\n>> $ git branch -D master\n>> error: Cannot delete branch 'master' checked out at 'C:/tmp/wt'\n>>\n>> #but this is possible:\n>>\n>> > /c/tmp/gt (Branch_702091a0)\n>> $ git branch -f master HEAD\n>\n> I admit I didn't see this. But I don't know how far we would go\n> protecting other worktrees. You give --force and that usually means\n> \"Yes I know what I'm doing, don't stop me\". If --force rejects in this\n> case, what would be the real force, --force --force maybe, or fall\n> back to \"git update-ref\"?\n>\n>>\n>> #and the other worktree is now corrupted:\n>>\n>> > /c/tmp/wt (master)\n>> $ git status\n>> On branch master\n>> Changes to be committed:\n>>   (use \"git reset HEAD <file>...\" to unstage)\n>>\n>>         modified:   txt.txt\n>>         deleted:    txtb.txt\n>>\n>>\n>>\n>> greetings f.kulow\n\nPart of this is \"doctor, it hurts when I stab my eye\" :) but I wonder in\ngeneral whether users are more likely to expect different worktrees to\nhave different views of the refstore, since they way they're created is\n\"I want just this branch over there\".\n\nI.e. whether they want something closer to another directory with\n\"alternates\" pointing to the \"main\" repo, and whether that should be\npromoted to UI that's easier to set up than it is now.\n\nOr maybe something in-between, where they'd expect remote tracking refs\nto update for everything, but a worktree's \"master\" branch not to be\ntouchable by a worktree on \"topic\".\n\n"},{"id":"374815","messageId":"CACsJy8A67x5wtbTe9Zk6URLZOqMNUFaLuNyZSVdYkZ1Z3y=6+A@mail.gmail.com","threadId":"51023","inReplyTo":"87d0l1qat5.fsf@evledraar.gmail.com","subject":"Re: \"git branch -f\" corrupt other worktree","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2019-05-02T13:05:57Z","receivedAt":"2019-05-02T13:06:26Z","isPatch":false,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Thu, May 2, 2019 at 7:51 PM Ævar Arnfjörð Bjarmason <avarab@gmail.com> wrote:\n>\n>\n> On Thu, May 02 2019, Duy Nguyen wrote:\n>\n> > On Thu, May 2, 2019 at 6:59 PM frank kulow <kulow.f@googlemail.com> wrote:\n> >>\n> >> git version 2.21.0.windows.1\n> >>\n> >> > /c/tmp/gt (Branch_702091a0)\n> >> $ git worktree add ../wt master\n> >> Preparing worktree (checking out 'master')\n> >> HEAD is now at f534c32 4\n> >>\n> >> > /c/tmp/gt (Branch_702091a0)\n> >> $ git branch -D master\n> >> error: Cannot delete branch 'master' checked out at 'C:/tmp/wt'\n> >>\n> >> #but this is possible:\n> >>\n> >> > /c/tmp/gt (Branch_702091a0)\n> >> $ git branch -f master HEAD\n> >\n> > I admit I didn't see this. But I don't know how far we would go\n> > protecting other worktrees. You give --force and that usually means\n> > \"Yes I know what I'm doing, don't stop me\". If --force rejects in this\n> > case, what would be the real force, --force --force maybe, or fall\n> > back to \"git update-ref\"?\n> >\n> >>\n> >> #and the other worktree is now corrupted:\n> >>\n> >> > /c/tmp/wt (master)\n> >> $ git status\n> >> On branch master\n> >> Changes to be committed:\n> >>   (use \"git reset HEAD <file>...\" to unstage)\n> >>\n> >>         modified:   txt.txt\n> >>         deleted:    txtb.txt\n> >>\n> >>\n> >>\n> >> greetings f.kulow\n>\n> Part of this is \"doctor, it hurts when I stab my eye\" :) but I wonder in\n> general whether users are more likely to expect different worktrees to\n> have different views of the refstore, since they way they're created is\n> \"I want just this branch over there\".\n>\n> I.e. whether they want something closer to another directory with\n> \"alternates\" pointing to the \"main\" repo, and whether that should be\n> promoted to UI that's easier to set up than it is now.\n>\n> Or maybe something in-between, where they'd expect remote tracking refs\n> to update for everything, but a worktree's \"master\" branch not to be\n> touchable by a worktree on \"topic\".\n\nI think it's a minefield to go with different views on refs. They can\nalready have per-worktree refs now. Granted it's long to type (e.g.\nworktrees/foo/something) but it does help remind it's per-worktree.\nAnd we can probably improve the ref resolution rules to resolve\n\"foo/something\" (or \"something\" even) to worktrees/foo/something for\nexample. But going totally custom, I think it's hard to even manage as\na user.\n\nWith that said, I think we can technically support per-worktree refs\neven outside worktrees/, or the whole refeference space per-worktree,\nnow. The difficulty will be coming up with some sane UI that can\nhandle that and not leave too many traps behind. I can't see that UI.\n-- \nDuy\n"},{"id":"374818","messageId":"CACsJy8CzakrDS8qW5DTbkG_SNaVQ7Y6Ps-vT91zRPKGgvUUQeA@mail.gmail.com","threadId":"51023","inReplyTo":"CACsJy8A67x5wtbTe9Zk6URLZOqMNUFaLuNyZSVdYkZ1Z3y=6+A@mail.gmail.com","subject":"Re: \"git branch -f\" corrupt other worktree","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2019-05-02T13:49:08Z","receivedAt":"2019-05-02T13:49:37Z","isPatch":false,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Thu, May 2, 2019 at 8:05 PM Duy Nguyen <pclouds@gmail.com> wrote:\n> > Part of this is \"doctor, it hurts when I stab my eye\" :) but I wonder in\n> > general whether users are more likely to expect different worktrees to\n> > have different views of the refstore, since they way they're created is\n> > \"I want just this branch over there\".\n> >\n> > I.e. whether they want something closer to another directory with\n> > \"alternates\" pointing to the \"main\" repo, and whether that should be\n> > promoted to UI that's easier to set up than it is now.\n> >\n> > Or maybe something in-between, where they'd expect remote tracking refs\n> > to update for everything, but a worktree's \"master\" branch not to be\n> > touchable by a worktree on \"topic\".\n>\n> I think it's a minefield to go with different views on refs. They can\n> already have per-worktree refs now. Granted it's long to type (e.g.\n> worktrees/foo/something) but it does help remind it's per-worktree.\n\nCorrection (apparently I'm not using per-worktree refs enough to remember).\n\ns,worktrees/foo/something,worktree/something,\n\nworktrees/<name>/<ref> is to access per-worktree refs of other\nworktrees. worktree/<ref> is about the current one.\n\n> And we can probably improve the ref resolution rules to resolve\n> \"foo/something\" (or \"something\" even) to worktrees/foo/something for\n> example. But going totally custom, I think it's hard to even manage as\n> a user.\n>\n> With that said, I think we can technically support per-worktree refs\n> even outside worktrees/, or the whole refeference space per-worktree,\n> now. The difficulty will be coming up with some sane UI that can\n> handle that and not leave too many traps behind. I can't see that UI.\n> --\n> Duy\n\n\n\n-- \nDuy\n"},{"id":"374838","messageId":"20190502171612.GA13673@ash","threadId":"51023","inReplyTo":"CACsJy8A67x5wtbTe9Zk6URLZOqMNUFaLuNyZSVdYkZ1Z3y=6+A@mail.gmail.com","subject":"Re: \"git branch -f\" corrupt other worktree","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2019-05-02T17:16:13Z","receivedAt":"2019-05-02T17:16:21Z","isPatch":false,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Thu, May 02, 2019 at 08:05:57PM +0700, Duy Nguyen wrote:\n> The difficulty will be coming up with some sane UI that can\n> handle that and not leave too many traps behind. I can't see that UI.\n\nWell, I'm still thinking about it. And perhaps a good UI is not that\nfar away. The following hacky patch does three things:\n\n1. it resolves \"foo\" to \"refs/worktree/foo\" if neither refs/heads/foo\n   or refs/tags/foo exists.\n\n2. it pretty prints refs/worktree/foo as worktree/foo\n\n3. \"git branch\" has a new option --per-worktree that creates\n   refs/worktree/foo instead of refs/heads/foo.\n\nThe idea here is we manage/decide per-worktree or shared refs at\nbranch/tag creation time. After that we use it like a normal\nbranch/tag. Point #1 helps the \"normal\" part.\n\nPoint #2 could even pretty print it to \"foo\" to make it even more\nnormal, but I feel that the distinction between per-worktree and\nshared should still be more visible, hence \"worktree/foo\".\n\n--per-worktree is pretty much a placeholder name. If we could find a\ngood name (and --worktre is already taken), then it could be added in\nmore places where a branch may be created.\n\nIt's far from complete. For example, refs/worktree/foo is not\nconsidered a branch by any command, Only those inside refs/heads are\nat the moment.\n\nWhen I added refs/worktree/ namespace I didn't think that far ahead,\nwhat kind of refs should be in there. But maybe we can still have\nbranches in refs/worktree/heads/ and tags in refs/worktree/tags/. Or\nperhaps all refs/worktree/ should only contain branches, tags are\nalways shared (it's shared with remotes now even, at least in common\ncase)...\n\nWith more details worked out, perhaps we can make it work.\n\n-- 8< --\ndiff --git a/branch.c b/branch.c\nindex 28b81a7e02..e5d738efa7 100644\n--- a/branch.c\n+++ b/branch.c\n@@ -242,6 +242,8 @@ N_(\"\\n\"\n \"will track its remote counterpart, you may want to use\\n\"\n \"\\\"git push -u\\\" to set the upstream config as you push.\");\n \n+int create_branch_per_worktree;\n+\n void create_branch(struct repository *r,\n \t\t   const char *name, const char *start_name,\n \t\t   int force, int clobber_head_ok, int reflog,\n@@ -308,6 +310,9 @@ void create_branch(struct repository *r,\n \tif (reflog)\n \t\tlog_all_ref_updates = LOG_REFS_NORMAL;\n \n+\tif (create_branch_per_worktree)\n+\t\tstrbuf_splice(&ref, 0, 11, \"refs/worktree/\", 14);\n+\n \tif (!dont_change_ref) {\n \t\tstruct ref_transaction *transaction;\n \t\tstruct strbuf err = STRBUF_INIT;\ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex d4359b33ac..8839c6f33f 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -605,6 +605,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)\n \tint icase = 0;\n \tstatic struct ref_sorting *sorting = NULL, **sorting_tail = &sorting;\n \tstruct ref_format format = REF_FORMAT_INIT;\n+\tint per_worktree = 0;\n \n \tstruct option options[] = {\n \t\tOPT_GROUP(N_(\"Generic options\")),\n@@ -613,6 +614,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)\n \t\tOPT__QUIET(&quiet, N_(\"suppress informational messages\")),\n \t\tOPT_SET_INT('t', \"track\",  &track, N_(\"set up tracking mode (see git-pull(1))\"),\n \t\t\tBRANCH_TRACK_EXPLICIT),\n+\t\tOPT_BOOL(0, \"per-worktree\",  &per_worktree, N_(\"create per-worktree branch\")),\n \t\tOPT_SET_INT_F(0, \"set-upstream\", &track, N_(\"do not use\"),\n \t\t\tBRANCH_TRACK_OVERRIDE, PARSE_OPT_HIDDEN),\n \t\tOPT_STRING('u', \"set-upstream-to\", &new_upstream, N_(\"upstream\"), N_(\"change the upstream info\")),\n@@ -829,12 +831,15 @@ int cmd_branch(int argc, const char **argv, const char *prefix)\n \t\tgit_config_set_multivar(buf.buf, NULL, NULL, 1);\n \t\tstrbuf_release(&buf);\n \t} else if (argc > 0 && argc <= 2) {\n+\t\textern int create_branch_per_worktree;\n+\n \t\tif (filter.kind != FILTER_REFS_BRANCHES)\n \t\t\tdie(_(\"-a and -r options to 'git branch' do not make sense with a branch name\"));\n \n \t\tif (track == BRANCH_TRACK_OVERRIDE)\n \t\t\tdie(_(\"the '--set-upstream' option is no longer supported. Please use '--track' or '--set-upstream-to' instead.\"));\n \n+\t\tcreate_branch_per_worktree = per_worktree;\n \t\tcreate_branch(the_repository,\n \t\t\t      argv[0], (argc == 2) ? argv[1] : head,\n \t\t\t      force, 0, reflog, quiet, track);\ndiff --git a/refs.c b/refs.c\nindex 142888a40a..8d01a80e07 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -479,7 +479,9 @@ const char *prettify_refname(const char *name)\n {\n \tif (skip_prefix(name, \"refs/heads/\", &name) ||\n \t    skip_prefix(name, \"refs/tags/\", &name) ||\n-\t    skip_prefix(name, \"refs/remotes/\", &name))\n+\t    skip_prefix(name, \"refs/remotes/\", &name) ||\n+\t    (starts_with(name, \"refs/worktree/\") &&\n+\t     skip_prefix(name, \"refs/\", &name)))\n \t\t; /* nothing */\n \treturn name;\n }\n@@ -491,6 +493,7 @@ static const char *ref_rev_parse_rules[] = {\n \t\"refs/heads/%.*s\",\n \t\"refs/remotes/%.*s\",\n \t\"refs/remotes/%.*s/HEAD\",\n+\t\"refs/worktree/%.*s\",\n \tNULL\n };\n \n-- 8< --\n"}]}