{"thread":{"id":"59093","subject":"[PATCH] worktree add: introduce basic DWYM for --orphan","startedAt":"2023-01-14T22:50:41Z","lastAt":"2023-01-18T20:43:59Z","messageCount":4,"participants":["Jacob Abel","Phillip Wood"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"470367","messageId":"20230114224956.24801-1-jacobabel@nullpo.dev","threadId":"59093","inReplyTo":null,"subject":"[PATCH] worktree add: introduce basic DWYM for --orphan","fromName":"Jacob Abel","fromEmail":"jacobabel@nullpo.dev","sentAt":"2023-01-14T22:50:25Z","receivedAt":"2023-01-14T22:50:41Z","isPatch":true,"sender":{"key":"jacobabel@nullpo.dev","avatar":"https://avatars.githubusercontent.com/u/9424043?v=4"},"body":"Introduces a DWYM shorthand of --orphan for when the worktree directory\nand the to-be-created branch share the same name.\n\nCurrent Behavior:\n    % git worktree list\n    /path/to/git/repo        a38d39a4c5 [main]\n    % git worktree add --orphan new_branch ../new_branch/\n    Preparing worktree (new branch 'new_branch')\n    % git worktree add --orphan ../new_branch2/\n    usage: git worktree add [<options>] <path> [<commit-ish>]\n       or: git worktree list [<options>]\n    [...]\n    %\n\nNew Behavior:\n\n    % git worktree list\n    /path/to/git/repo        a38d39a4c5 [main]\n    % git worktree add --orphan new_branch ../new_branch/\n    Preparing worktree (new branch 'new_branch')\n    % git worktree list\n    /path/to/git/repo        a38d39a4c5 [main]\n    /path/to/git/new_branch  a38d39a4c5 [new_branch]\n    % git worktree add --orphan ../new_branch2/\n    Preparing worktree (new branch 'new_branch2')\n    % git worktree list\n    /path/to/git/repo        a38d39a4c5 [main]\n    /path/to/git/new_branch  a38d39a4c5 [new_branch]\n    /path/to/git/new_branch2 a38d39a4c5 [new_branch2]\n    %\n\nSigned-off-by: Jacob Abel <jacobabel@nullpo.dev>\n---\n Documentation/git-worktree.txt | 13 +++++++++----\n builtin/worktree.c             | 21 +++++++++++++++------\n t/t2400-worktree-add.sh        | 10 ++++++++++\n 3 files changed, 34 insertions(+), 10 deletions(-)\n\ndiff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt\nindex d78460c29c..a56ddb0185 100644\n--- a/Documentation/git-worktree.txt\n+++ b/Documentation/git-worktree.txt\n@@ -12,7 +12,7 @@ SYNOPSIS\n 'git worktree add' [-f] [--detach] [--checkout] [--lock [--reason <string>]]\n \t\t   [(-b | -B) <new-branch>] <path> [<commit-ish>]\n 'git worktree add' [-f] [--lock [--reason <string>]]\n-\t\t   --orphan <new-branch> <path>\n+\t\t   --orphan [<new-branch>] <path>\n 'git worktree list' [-v | --porcelain [-z]]\n 'git worktree lock' [--reason <string>] <worktree>\n 'git worktree move' <worktree> <new-path>\n@@ -99,13 +99,16 @@ in the new worktree, if it's not checked out anywhere else, otherwise the\n command will refuse to create the worktree (unless `--force` is used).\n +\n ------------\n-$ git worktree add --orphan <branch> <path>\n+$ git worktree add --orphan [<branch>] <path>\n ------------\n +\n Create a worktree containing no files, with an empty index, and associated\n with a new orphan branch named `<branch>`. The first commit made on this new\n branch will have no parents and will be the root of a new history disconnected\n from any other branches.\n++\n+If a branch name `<branch>` is not supplied, the name is derived from the\n+supplied path `<path>`.\n\n list::\n\n@@ -233,9 +236,11 @@ This can also be set up as the default behaviour by using the\n \tWith `prune`, do not remove anything; just report what it would\n \tremove.\n\n---orphan <new-branch>::\n+--orphan [<new-branch>]::\n \tWith `add`, make the new worktree and index empty, associating\n-\tthe worktree with a new orphan branch named `<new-branch>`.\n+\tthe worktree with a new orphan branch named `<new-branch>`. If\n+\t`<new-branch>` is not supplied, the new branch name is derived\n+\tfrom `<path>`.\n\n --porcelain::\n \tWith `list`, output in an easy-to-parse format for scripts.\ndiff --git a/builtin/worktree.c b/builtin/worktree.c\nindex d975628353..481f895075 100644\n--- a/builtin/worktree.c\n+++ b/builtin/worktree.c\n@@ -19,7 +19,7 @@\n \tN_(\"git worktree add [-f] [--detach] [--checkout] [--lock [--reason <string>]]\\n\" \\\n \t   \"                 [(-b | -B) <new-branch>] <path> [<commit-ish>]\"), \\\n \tN_(\"git worktree add [-f] [--lock [--reason <string>]]\\n\" \\\n-\t   \"                 --orphan <new-branch> <path>\")\n+\t   \"                 --orphan [<new-branch>] <path>\")\n\n #define BUILTIN_WORKTREE_LIST_USAGE \\\n \tN_(\"git worktree list [-v | --porcelain [-z]]\")\n@@ -681,10 +681,13 @@ static int add(int ac, const char **av, const char *prefix)\n \telse if (keep_locked)\n \t\topts.keep_locked = _(\"added with --lock\");\n\n-\tif (ac < 1 || ac > 2)\n+\tif (ac < 1 && opts.orphan) {\n+\t\tpath = prefix_filename(prefix, orphan_branch);\n+\t} else if (ac >= 1 && ac <= 2) {\n+\t\tpath = prefix_filename(prefix, av[0]);\n+\t} else {\n \t\tusage_with_options(git_worktree_add_usage, options);\n-\n-\tpath = prefix_filename(prefix, av[0]);\n+\t}\n \tbranch = ac < 2 ? \"HEAD\" : av[1];\n\n \tif (!strcmp(branch, \"-\"))\n@@ -702,14 +705,20 @@ static int add(int ac, const char **av, const char *prefix)\n \t\tstrbuf_release(&symref);\n \t}\n\n-\tif (opts.orphan) {\n-\t\tnew_branch = orphan_branch;\n+\tif (ac < 1 && opts.orphan) {\n+\t\tconst char *s = dwim_branch(path, &orphan_branch);\n+\t\tif (s)\n+\t\t\torphan_branch = s;\n \t} else if (ac < 2 && !new_branch && !opts.detach) {\n \t\tconst char *s = dwim_branch(path, &new_branch);\n \t\tif (s)\n \t\t\tbranch = s;\n \t}\n\n+\tif (opts.orphan) {\n+\t\tnew_branch = orphan_branch;\n+\t}\n+\n \tif (ac == 2 && !new_branch && !opts.detach) {\n \t\tstruct object_id oid;\n \t\tstruct commit *commit;\ndiff --git a/t/t2400-worktree-add.sh b/t/t2400-worktree-add.sh\nindex 1bf8d619e2..c3de277738 100755\n--- a/t/t2400-worktree-add.sh\n+++ b/t/t2400-worktree-add.sh\n@@ -354,6 +354,16 @@ test_expect_success '\"add --orphan\" fails if the branch already exists' '\n \ttest_path_is_missing orphandir2\n '\n\n+test_expect_success '\"add --orphan\" with basic DWYM' '\n+\ttest_when_finished \"rm -rf empty_repo\" &&\n+\techo refs/heads/worktreedir >expected &&\n+\tGIT_DIR=\"empty_repo\" git init --bare &&\n+\t# Use non-trivial path to verify it DWYMs properly.\n+\tgit -C empty_repo worktree add --orphan ../empty_repo/worktreedir &&\n+\tgit -C empty_repo/worktreedir symbolic-ref HEAD >actual &&\n+\ttest_cmp expected actual\n+'\n+\n test_expect_success '\"add --orphan\" with empty repository' '\n \ttest_when_finished \"rm -rf empty_repo\" &&\n \techo refs/heads/newbranch >expected &&\n--\n2.38.2\n\n\n"},{"id":"470368","messageId":"20230114225635.quyxb4vppvtv76dx@phi","threadId":"59093","inReplyTo":"20230114224956.24801-1-jacobabel@nullpo.dev","subject":"Re: [PATCH] worktree add: introduce basic DWYM for --orphan","fromName":"Jacob Abel","fromEmail":"jacobabel@nullpo.dev","sentAt":"2023-01-14T22:58:59Z","receivedAt":"2023-01-14T22:59:13Z","isPatch":true,"sender":{"key":"jacobabel@nullpo.dev","avatar":"https://avatars.githubusercontent.com/u/9424043?v=4"},"body":"On 23/01/14 10:50PM, Jacob Abel wrote:\n>\n> [...]\n\nOops for some reason this didn't show up as a reply on the lore. This is\nsupposed to be a reply to the following email chain:\n\nhttps://lore.kernel.org/git/20230114224715.ewec6sz5h3q3iijs@phi/\n\n"},{"id":"470427","messageId":"cddc6987-3b58-4688-65f8-3da0fbd1cc51@dunelm.org.uk","threadId":"59093","inReplyTo":"20230114224956.24801-1-jacobabel@nullpo.dev","subject":"Re: [PATCH] worktree add: introduce basic DWYM for --orphan","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2023-01-16T10:52:20Z","receivedAt":"2023-01-16T10:52:31Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Jacob\n\nOn 14/01/2023 22:50, Jacob Abel wrote:\n> Introduces a DWYM shorthand of --orphan for when the worktree directory\n> and the to-be-created branch share the same name.\n> \n> Current Behavior:\n>      % git worktree list\n>      /path/to/git/repo        a38d39a4c5 [main]\n>      % git worktree add --orphan new_branch ../new_branch/\n>      Preparing worktree (new branch 'new_branch')\n>      % git worktree add --orphan ../new_branch2/\n>      usage: git worktree add [<options>] <path> [<commit-ish>]\n>         or: git worktree list [<options>]\n>      [...]\n>      %\n> \n> New Behavior:\n> \n>      % git worktree list\n>      /path/to/git/repo        a38d39a4c5 [main]\n>      % git worktree add --orphan new_branch ../new_branch/\n>      Preparing worktree (new branch 'new_branch')\n>      % git worktree list\n>      /path/to/git/repo        a38d39a4c5 [main]\n>      /path/to/git/new_branch  a38d39a4c5 [new_branch]\n>      % git worktree add --orphan ../new_branch2/\n>      Preparing worktree (new branch 'new_branch2')\n>      % git worktree list\n>      /path/to/git/repo        a38d39a4c5 [main]\n>      /path/to/git/new_branch  a38d39a4c5 [new_branch]\n>      /path/to/git/new_branch2 a38d39a4c5 [new_branch2]\n>      %\n\nThanks for working on this. As I said in my previous mail I think it \nwould be easier to use OPT_BOOL() for --orphan from the start. By using \nOPT_STRING() you'll run into problems with \"git worktree add --orphan \n--lock <directory>\"\n\nBest Wishes\n\nPhillip\n\n> Signed-off-by: Jacob Abel <jacobabel@nullpo.dev>\n> ---\n>   Documentation/git-worktree.txt | 13 +++++++++----\n>   builtin/worktree.c             | 21 +++++++++++++++------\n>   t/t2400-worktree-add.sh        | 10 ++++++++++\n>   3 files changed, 34 insertions(+), 10 deletions(-)\n> \n> diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt\n> index d78460c29c..a56ddb0185 100644\n> --- a/Documentation/git-worktree.txt\n> +++ b/Documentation/git-worktree.txt\n> @@ -12,7 +12,7 @@ SYNOPSIS\n>   'git worktree add' [-f] [--detach] [--checkout] [--lock [--reason <string>]]\n>   \t\t   [(-b | -B) <new-branch>] <path> [<commit-ish>]\n>   'git worktree add' [-f] [--lock [--reason <string>]]\n> -\t\t   --orphan <new-branch> <path>\n> +\t\t   --orphan [<new-branch>] <path>\n>   'git worktree list' [-v | --porcelain [-z]]\n>   'git worktree lock' [--reason <string>] <worktree>\n>   'git worktree move' <worktree> <new-path>\n> @@ -99,13 +99,16 @@ in the new worktree, if it's not checked out anywhere else, otherwise the\n>   command will refuse to create the worktree (unless `--force` is used).\n>   +\n>   ------------\n> -$ git worktree add --orphan <branch> <path>\n> +$ git worktree add --orphan [<branch>] <path>\n>   ------------\n>   +\n>   Create a worktree containing no files, with an empty index, and associated\n>   with a new orphan branch named `<branch>`. The first commit made on this new\n>   branch will have no parents and will be the root of a new history disconnected\n>   from any other branches.\n> ++\n> +If a branch name `<branch>` is not supplied, the name is derived from the\n> +supplied path `<path>`.\n> \n>   list::\n> \n> @@ -233,9 +236,11 @@ This can also be set up as the default behaviour by using the\n>   \tWith `prune`, do not remove anything; just report what it would\n>   \tremove.\n> \n> ---orphan <new-branch>::\n> +--orphan [<new-branch>]::\n>   \tWith `add`, make the new worktree and index empty, associating\n> -\tthe worktree with a new orphan branch named `<new-branch>`.\n> +\tthe worktree with a new orphan branch named `<new-branch>`. If\n> +\t`<new-branch>` is not supplied, the new branch name is derived\n> +\tfrom `<path>`.\n> \n>   --porcelain::\n>   \tWith `list`, output in an easy-to-parse format for scripts.\n> diff --git a/builtin/worktree.c b/builtin/worktree.c\n> index d975628353..481f895075 100644\n> --- a/builtin/worktree.c\n> +++ b/builtin/worktree.c\n> @@ -19,7 +19,7 @@\n>   \tN_(\"git worktree add [-f] [--detach] [--checkout] [--lock [--reason <string>]]\\n\" \\\n>   \t   \"                 [(-b | -B) <new-branch>] <path> [<commit-ish>]\"), \\\n>   \tN_(\"git worktree add [-f] [--lock [--reason <string>]]\\n\" \\\n> -\t   \"                 --orphan <new-branch> <path>\")\n> +\t   \"                 --orphan [<new-branch>] <path>\")\n> \n>   #define BUILTIN_WORKTREE_LIST_USAGE \\\n>   \tN_(\"git worktree list [-v | --porcelain [-z]]\")\n> @@ -681,10 +681,13 @@ static int add(int ac, const char **av, const char *prefix)\n>   \telse if (keep_locked)\n>   \t\topts.keep_locked = _(\"added with --lock\");\n> \n> -\tif (ac < 1 || ac > 2)\n> +\tif (ac < 1 && opts.orphan) {\n> +\t\tpath = prefix_filename(prefix, orphan_branch);\n> +\t} else if (ac >= 1 && ac <= 2) {\n> +\t\tpath = prefix_filename(prefix, av[0]);\n> +\t} else {\n>   \t\tusage_with_options(git_worktree_add_usage, options);\n> -\n> -\tpath = prefix_filename(prefix, av[0]);\n> +\t}\n>   \tbranch = ac < 2 ? \"HEAD\" : av[1];\n> \n>   \tif (!strcmp(branch, \"-\"))\n> @@ -702,14 +705,20 @@ static int add(int ac, const char **av, const char *prefix)\n>   \t\tstrbuf_release(&symref);\n>   \t}\n> \n> -\tif (opts.orphan) {\n> -\t\tnew_branch = orphan_branch;\n> +\tif (ac < 1 && opts.orphan) {\n> +\t\tconst char *s = dwim_branch(path, &orphan_branch);\n> +\t\tif (s)\n> +\t\t\torphan_branch = s;\n>   \t} else if (ac < 2 && !new_branch && !opts.detach) {\n>   \t\tconst char *s = dwim_branch(path, &new_branch);\n>   \t\tif (s)\n>   \t\t\tbranch = s;\n>   \t}\n> \n> +\tif (opts.orphan) {\n> +\t\tnew_branch = orphan_branch;\n> +\t}\n> +\n>   \tif (ac == 2 && !new_branch && !opts.detach) {\n>   \t\tstruct object_id oid;\n>   \t\tstruct commit *commit;\n> diff --git a/t/t2400-worktree-add.sh b/t/t2400-worktree-add.sh\n> index 1bf8d619e2..c3de277738 100755\n> --- a/t/t2400-worktree-add.sh\n> +++ b/t/t2400-worktree-add.sh\n> @@ -354,6 +354,16 @@ test_expect_success '\"add --orphan\" fails if the branch already exists' '\n>   \ttest_path_is_missing orphandir2\n>   '\n> \n> +test_expect_success '\"add --orphan\" with basic DWYM' '\n> +\ttest_when_finished \"rm -rf empty_repo\" &&\n> +\techo refs/heads/worktreedir >expected &&\n> +\tGIT_DIR=\"empty_repo\" git init --bare &&\n> +\t# Use non-trivial path to verify it DWYMs properly.\n> +\tgit -C empty_repo worktree add --orphan ../empty_repo/worktreedir &&\n> +\tgit -C empty_repo/worktreedir symbolic-ref HEAD >actual &&\n> +\ttest_cmp expected actual\n> +'\n> +\n>   test_expect_success '\"add --orphan\" with empty repository' '\n>   \ttest_when_finished \"rm -rf empty_repo\" &&\n>   \techo refs/heads/newbranch >expected &&\n> --\n> 2.38.2\n> \n> \n"},{"id":"470663","messageId":"20230118204323.gn6rs3gydybsqt4g@phi","threadId":"59093","inReplyTo":"cddc6987-3b58-4688-65f8-3da0fbd1cc51@dunelm.org.uk","subject":"Re: [PATCH] worktree add: introduce basic DWYM for --orphan","fromName":"Jacob Abel","fromEmail":"jacobabel@nullpo.dev","sentAt":"2023-01-18T20:43:39Z","receivedAt":"2023-01-18T20:43:59Z","isPatch":true,"sender":{"key":"jacobabel@nullpo.dev","avatar":"https://avatars.githubusercontent.com/u/9424043?v=4"},"body":"On 23/01/16 10:52AM, Phillip Wood wrote:\n> Hi Jacob\n>\n> On 14/01/2023 22:50, Jacob Abel wrote:\n> > Introduces a DWYM shorthand of --orphan for when the worktree directory\n> > and the to-be-created branch share the same name.\n> >\n> > Current Behavior:\n> >      % git worktree list\n> >      /path/to/git/repo        a38d39a4c5 [main]\n> >      % git worktree add --orphan new_branch ../new_branch/\n> >      Preparing worktree (new branch 'new_branch')\n> >      % git worktree add --orphan ../new_branch2/\n> >      usage: git worktree add [<options>] <path> [<commit-ish>]\n> >         or: git worktree list [<options>]\n> >      [...]\n> >      %\n> >\n> > New Behavior:\n> >\n> >      % git worktree list\n> >      /path/to/git/repo        a38d39a4c5 [main]\n> >      % git worktree add --orphan new_branch ../new_branch/\n> >      Preparing worktree (new branch 'new_branch')\n> >      % git worktree list\n> >      /path/to/git/repo        a38d39a4c5 [main]\n> >      /path/to/git/new_branch  a38d39a4c5 [new_branch]\n> >      % git worktree add --orphan ../new_branch2/\n> >      Preparing worktree (new branch 'new_branch2')\n> >      % git worktree list\n> >      /path/to/git/repo        a38d39a4c5 [main]\n> >      /path/to/git/new_branch  a38d39a4c5 [new_branch]\n> >      /path/to/git/new_branch2 a38d39a4c5 [new_branch2]\n> >      %\n>\n> Thanks for working on this. As I said in my previous mail I think it\n> would be easier to use OPT_BOOL() for --orphan from the start. By using\n> OPT_STRING() you'll run into problems with \"git worktree add --orphan\n> --lock <directory>\"\n>\n> Best Wishes\n>\n> Phillip\n>\n> > [...]\n\nAh, good point. I missed that.\n\nAlso given the way the conversation is going, I'll drop this patch and integrate\nthe changes into the patches of the main series since I'll be re-rolling.\n\n"}]}