{"thread":{"id":"59710","subject":"[PATCH v10 7/8] worktree add: extend DWIM to infer --orphan","startedAt":"2023-05-07T12:07:28Z","lastAt":"2023-05-07T12:07:28Z","messageCount":1,"participants":["Jacob Abel"],"isPatch":true,"patchVersion":10,"patchTotal":8},"messages":[{"id":"476724","messageId":"20230507120530.14669-8-jacobabel@nullpo.dev","threadId":"59710","inReplyTo":null,"subject":"[PATCH v10 7/8] worktree add: extend DWIM to infer --orphan","fromName":"Jacob Abel","fromEmail":"jacobabel@nullpo.dev","sentAt":"2023-05-07T12:07:03Z","receivedAt":"2023-05-07T12:07:28Z","isPatch":true,"sender":{"key":"jacobabel@nullpo.dev","avatar":"https://avatars.githubusercontent.com/u/9424043?v=4"},"body":"Extend DWIM to try to infer `--orphan` when in an empty repository. i.e.\na repository with an invalid/unborn HEAD, no local branches, and if\n`--guess-remote` is used then no remote branches.\n\nThis behavior is equivalent to `git switch -c` or `git checkout -b` in\nan empty repository.\n\nAlso warn the user (overriden with `-f`/`--force`) when they likely\nintend to checkout a remote branch to the worktree but have not yet\nfetched from the remote. i.e. when using `--guess-remote` and there is a\nremote but no local or remote refs.\n\nCurrent Behavior:\n% git --no-pager branch --list --remotes\n% git remote\norigin\n% git workree add ../main\nhint: If you meant to create a worktree containing a new orphan branch\n[...]\nhint: Disable this message with \"git config advice.worktreeAddOrphan false\"\nfatal: invalid reference: HEAD\n% git workree add --guess-remote ../main\nhint: If you meant to create a worktree containing a new orphan branch\n[...]\nhint: Disable this message with \"git config advice.worktreeAddOrphan false\"\nfatal: invalid reference: HEAD\n% git fetch --quiet\n% git --no-pager branch --list --remotes\norigin/HEAD -> origin/main\norigin/main\n% git workree add --guess-remote ../main\nPreparing worktree (new branch 'main')\nbranch 'main' set up to track 'origin/main'.\nHEAD is now at dadc8e6dac commit message\n%\n\nNew Behavior:\n% git --no-pager branch --list --remotes\n% git remote\norigin\n% git workree add ../main\nNo possible source branch, inferring '--orphan'\nPreparing worktree (new branch 'main')\n% git worktree remove ../main\n% git workree add --guess-remote ../main\nfatal: No local or remote refs exist despite at least one remote\npresent, stopping; use 'add -f' to overide or fetch a remote first\n% git workree add --guess-remote -f ../main\nNo possible source branch, inferring '--orphan'\nPreparing worktree (new branch 'main')\n% git worktree remove ../main\n% git fetch --quiet\n% git --no-pager branch --list --remotes\norigin/HEAD -> origin/main\norigin/main\n% git workree add --guess-remote ../main\nPreparing worktree (new branch 'main')\nbranch 'main' set up to track 'origin/main'.\nHEAD is now at dadc8e6dac commit message\n%\n\nSigned-off-by: Jacob Abel <jacobabel@nullpo.dev>\n---\n Documentation/git-worktree.txt |  10 +\n builtin/worktree.c             | 114 +++++++++++-\n t/t2400-worktree-add.sh        | 326 +++++++++++++++++++++++++++++++++\n 3 files changed, 449 insertions(+), 1 deletion(-)\n\ndiff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt\nindex 485d865eb2..a4fbf5e838 100644\n--- a/Documentation/git-worktree.txt\n+++ b/Documentation/git-worktree.txt\n@@ -95,6 +95,16 @@ exist, a new branch based on `HEAD` is automatically created as if\n `-b <branch>` was given.  If `<branch>` does exist, it will be checked out\n 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+If `<commit-ish>` is omitted, neither `--detach`, or `--orphan` is\n+used, and there are no valid local branches (or remote branches if\n+`--guess-remote` is specified) then, as a convenience, the new worktree is\n+associated with a new orphan branch named `<branch>` (after\n+`$(basename <path>)` if neither `-b` or `-B` is used) as if `--orphan` was\n+passed to the command. In the event the repository has a remote and\n+`--guess-remote` is used, but no remote or local branches exist, then the\n+command fails with a warning reminding the user to fetch from their remote\n+first (or override by using `-f/--force`).\n\n list::\n\ndiff --git a/builtin/worktree.c b/builtin/worktree.c\nindex 15bdb380c7..093b2cb032 100644\n--- a/builtin/worktree.c\n+++ b/builtin/worktree.c\n@@ -12,6 +12,7 @@\n #include \"strvec.h\"\n #include \"branch.h\"\n #include \"refs.h\"\n+#include \"remote.h\"\n #include \"run-command.h\"\n #include \"hook.h\"\n #include \"sigchain.h\"\n@@ -40,6 +41,9 @@\n #define BUILTIN_WORKTREE_UNLOCK_USAGE \\\n \tN_(\"git worktree unlock <worktree>\")\n\n+#define WORKTREE_ADD_DWIM_ORPHAN_INFER_TEXT \\\n+\t_(\"No possible source branch, inferring '--orphan'\")\n+\n #define WORKTREE_ADD_ORPHAN_WITH_DASH_B_HINT_TEXT \\\n \t_(\"If you meant to create a worktree containing a new orphan branch\\n\" \\\n \t\"(branch with no commits) for this repository, you can do so\\n\" \\\n@@ -613,6 +617,107 @@ static void print_preparing_worktree_line(int detach,\n \t}\n }\n\n+/**\n+ * Callback to short circuit iteration over refs on the first reference\n+ * corresponding to a valid oid.\n+ *\n+ * Returns 0 on failure and non-zero on success.\n+ */\n+static int first_valid_ref(const char *refname,\n+\t\t\t   const struct object_id *oid,\n+\t\t\t   int flags,\n+\t\t\t   void *cb_data)\n+{\n+\treturn 1;\n+}\n+\n+/**\n+ * Verifies HEAD and determines whether there exist any valid local references.\n+ *\n+ * - Checks whether HEAD points to a valid reference.\n+ *\n+ * - Checks whether any valid local branches exist.\n+ *\n+ * Returns 1 if any of the previous checks are true, otherwise returns 0.\n+ */\n+static int can_use_local_refs(const struct add_opts *opts)\n+{\n+\tif (head_ref(first_valid_ref, NULL)) {\n+\t\treturn 1;\n+\t} else if (for_each_branch_ref(first_valid_ref, NULL)) {\n+\t\treturn 1;\n+\t}\n+\treturn 0;\n+}\n+\n+/**\n+ * Reports whether the necessary flags were set and whether the repository has\n+ * remote references to attempt DWIM tracking of upstream branches.\n+ *\n+ * 1. Checks that `--guess-remote` was used or `worktree.guessRemote = true`.\n+ *\n+ * 2. Checks whether any valid remote branches exist.\n+ *\n+ * 3. Checks that there exists at least one remote and emits a warning/error\n+ *    if both checks 1. and 2. are false (can be bypassed with `--force`).\n+ *\n+ * Returns 1 if checks 1. and 2. are true, otherwise 0.\n+ */\n+static int can_use_remote_refs(const struct add_opts *opts)\n+{\n+\tif (!guess_remote) {\n+\t\tif (!opts->quiet)\n+\t\t\tfprintf_ln(stderr, WORKTREE_ADD_DWIM_ORPHAN_INFER_TEXT);\n+\t\treturn 0;\n+\t} else if (for_each_remote_ref(first_valid_ref, NULL)) {\n+\t\treturn 1;\n+\t} else if (!opts->force && remote_get(NULL)) {\n+\t\tdie(_(\"No local or remote refs exist despite at least one remote\\n\"\n+\t\t      \"present, stopping; use 'add -f' to overide or fetch a remote first\"));\n+\t} else if (!opts->quiet) {\n+\t\tfprintf_ln(stderr, WORKTREE_ADD_DWIM_ORPHAN_INFER_TEXT);\n+\t}\n+\treturn 0;\n+}\n+\n+/**\n+ * Determines whether `--orphan` should be inferred in the evaluation of\n+ * `worktree add path/` or `worktree add -b branch path/` and emits an error\n+ * if the supplied arguments would produce an illegal combination when the\n+ * `--orphan` flag is included.\n+ *\n+ * `opts` and `opt_track` contain the other options & flags supplied to the\n+ * command.\n+ *\n+ * remote determines whether to check `can_use_remote_refs()` or not. This\n+ * is primarily to differentiate between the basic `add` DWIM and `add -b`.\n+ *\n+ * Returns 1 when inferring `--orphan`, 0 otherwise, and emits an error when\n+ * `--orphan` is inferred but doing so produces an illegal combination of\n+ * options and flags. Additionally produces an error when remote refs are\n+ * checked and the repo is in a state that looks like the user added a remote\n+ * but forgot to fetch (and did not override the warning with -f).\n+ */\n+static int dwim_orphan(const struct add_opts *opts, int opt_track, int remote)\n+{\n+\tif (can_use_local_refs(opts)) {\n+\t\treturn 0;\n+\t} else if (remote && can_use_remote_refs(opts)) {\n+\t\treturn 0;\n+\t} else if (!opts->quiet) {\n+\t\tfprintf_ln(stderr, WORKTREE_ADD_DWIM_ORPHAN_INFER_TEXT);\n+\t}\n+\n+\tif (opt_track) {\n+\t\tdie(_(\"'%s' and '%s' cannot be used together\"), \"--orphan\",\n+\t\t    \"--track\");\n+\t} else if (!opts->checkout) {\n+\t\tdie(_(\"'%s' and '%s' cannot be used together\"), \"--orphan\",\n+\t\t    \"--no-checkout\");\n+\t}\n+\treturn 1;\n+}\n+\n static const char *dwim_branch(const char *path, const char **new_branch)\n {\n \tint n;\n@@ -723,12 +828,19 @@ static int add(int ac, const char **av, const char *prefix)\n \t\tint n;\n \t\tconst char *s = worktree_basename(path, &n);\n \t\tnew_branch = xstrndup(s, n);\n-\t} else if (new_branch || opts.detach || opts.orphan) {\n+\t} else if (opts.orphan || opts.detach) {\n \t\t// No-op\n+\t} else if (ac < 2 && new_branch) {\n+\t\t// DWIM: Infer --orphan when repo has no refs.\n+\t\topts.orphan = dwim_orphan(&opts, !!opt_track, 0);\n \t} else if (ac < 2) {\n+\t\t// DWIM: Guess branch name from path.\n \t\tconst char *s = dwim_branch(path, &new_branch);\n \t\tif (s)\n \t\t\tbranch = s;\n+\n+\t\t// DWIM: Infer --orphan when repo has no refs.\n+\t\topts.orphan = (!s) && dwim_orphan(&opts, !!opt_track, 1);\n \t} else if (ac == 2) {\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 46eef26179..c7ca8df586 100755\n--- a/t/t2400-worktree-add.sh\n+++ b/t/t2400-worktree-add.sh\n@@ -705,6 +705,332 @@ test_expect_success 'git worktree --no-guess-remote option overrides config' '\n \t)\n '\n\n+test_dwim_orphan () {\n+\tlocal info_text=\"No possible source branch, inferring '--orphan'\" &&\n+\tlocal fetch_error_text=\"fatal: No local or remote refs exist despite at least one remote\" &&\n+\tlocal orphan_hint=\"hint: If you meant to create a worktree containing a new orphan branch\" &&\n+\tlocal invalid_ref_regex=\"^fatal: invalid reference:\\s\\+.*\" &&\n+\tlocal bad_combo_regex=\"^fatal: '[a-z-]\\+' and '[a-z-]\\+' cannot be used together\" &&\n+\n+\tlocal git_ns=\"repo\" &&\n+\tlocal dashc_args=\"-C $git_ns\" &&\n+\tlocal use_cd=0 &&\n+\n+\tlocal bad_head=0 &&\n+\tlocal empty_repo=1 &&\n+\tlocal local_ref=0 &&\n+\tlocal use_quiet=0 &&\n+\tlocal remote=0 &&\n+\tlocal remote_ref=0 &&\n+\tlocal use_new_branch=0 &&\n+\n+\tlocal outcome=\"$1\" &&\n+\tlocal outcome_text &&\n+\tlocal success &&\n+\tshift &&\n+\tlocal args=\"\" &&\n+\tlocal context=\"\" &&\n+\tcase \"$outcome\" in\n+\t\"infer\")\n+\t\tsuccess=1 &&\n+\t\toutcome_text='\"add\" DWIM infer --orphan'\n+\t\t;;\n+\t\"no_infer\")\n+\t\tsuccess=1 &&\n+\t\toutcome_text='\"add\" DWIM doesnt infer --orphan'\n+\t\t;;\n+\t\"fetch_error\")\n+\t\tsuccess=0 &&\n+\t\toutcome_text='\"add\" error need fetch'\n+\t\t;;\n+\t\"fatal_orphan_bad_combo\")\n+\t\tsuccess=0 &&\n+\t\toutcome_text='\"add\" error inferred \"--orphan\" gives illegal opts combo'\n+\t\t;;\n+\t*)\n+\t\techo \"test_dwim_orphan(): invalid outcome: '$outcome'\" >&2 &&\n+\t\treturn 1\n+\t\t;;\n+\tesac &&\n+\twhile [ $# -gt 0 ]\n+\tdo\n+\t\tcase \"$1\" in\n+\t\t# How and from where to create the worktree\n+\t\t\"-C_repo\")\n+\t\t\tuse_cd=0 &&\n+\t\t\tgit_ns=\"repo\" &&\n+\t\t\tdashc_args=\"-C $git_ns\" &&\n+\t\t\tcontext=\"$context, 'git -C repo'\"\n+\t\t\t;;\n+\t\t\"-C_wt\")\n+\t\t\tuse_cd=0 &&\n+\t\t\tgit_ns=\"wt\" &&\n+\t\t\tdashc_args=\"-C $git_ns\" &&\n+\t\t\tcontext=\"$context, 'git -C wt'\"\n+\t\t\t;;\n+\t\t\"cd_repo\")\n+\t\t\tuse_cd=1 &&\n+\t\t\tgit_ns=\"repo\" &&\n+\t\t\tdashc_args=\"\" &&\n+\t\t\tcontext=\"$context, 'cd repo && git'\"\n+\t\t\t;;\n+\t\t\"cd_wt\")\n+\t\t\tuse_cd=1 &&\n+\t\t\tgit_ns=\"wt\" &&\n+\t\t\tdashc_args=\"\" &&\n+\t\t\tcontext=\"$context, 'cd wt && git'\"\n+\t\t\t;;\n+\n+\t\t# Bypass the \"pull first\" warning\n+\t\t\"force\")\n+\t\t\targs=\"$args --force\" &&\n+\t\t\tcontext=\"$context, --force\"\n+\t\t\t;;\n+\n+\t\t# Try to use remote refs when DWIM\n+\t\t\"guess_remote\")\n+\t\t\targs=\"$args --guess-remote\" &&\n+\t\t\tcontext=\"$context, --guess-remote\"\n+\t\t\t;;\n+\t\t\"no_guess_remote\")\n+\t\t\targs=\"$args --no-guess-remote\" &&\n+\t\t\tcontext=\"$context, --no-guess-remote\"\n+\t\t\t;;\n+\n+\t\t# Whether there is at least one local branch present\n+\t\t\"local_ref\")\n+\t\t\tempty_repo=0 &&\n+\t\t\tlocal_ref=1 &&\n+\t\t\tcontext=\"$context, >=1 local branches\"\n+\t\t\t;;\n+\t\t\"no_local_ref\")\n+\t\t\tempty_repo=0 &&\n+\t\t\tcontext=\"$context, 0 local branches\"\n+\t\t\t;;\n+\n+\t\t# Whether the HEAD points at a valid ref (skip this opt when no refs)\n+\t\t\"good_head\")\n+\t\t\t# requires: local_ref\n+\t\t\tcontext=\"$context, valid HEAD\"\n+\t\t\t;;\n+\t\t\"bad_head\")\n+\t\t\tbad_head=1 &&\n+\t\t\tcontext=\"$context, invalid (or orphan) HEAD\"\n+\t\t\t;;\n+\n+\t\t# Whether the code path is tested with the base add command or -b\n+\t\t\"no_-b\")\n+\t\t\tuse_new_branch=0 &&\n+\t\t\tcontext=\"$context, no --branch\"\n+\t\t\t;;\n+\t\t\"-b\")\n+\t\t\tuse_new_branch=1 &&\n+\t\t\tcontext=\"$context, --branch\"\n+\t\t\t;;\n+\n+\t\t# Whether to check that all output is suppressed (except errors)\n+\t\t# or that the output is as expected\n+\t\t\"quiet\")\n+\t\t\tuse_quiet=1 &&\n+\t\t\targs=\"$args --quiet\" &&\n+\t\t\tcontext=\"$context, --quiet\"\n+\t\t\t;;\n+\t\t\"no_quiet\")\n+\t\t\tuse_quiet=0 &&\n+\t\t\tcontext=\"$context, no --quiet (expect output)\"\n+\t\t\t;;\n+\n+\t\t# Whether there is at least one remote attached to the repo\n+\t\t\"remote\")\n+\t\t\tempty_repo=0 &&\n+\t\t\tremote=1 &&\n+\t\t\tcontext=\"$context, >=1 remotes\"\n+\t\t\t;;\n+\t\t\"no_remote\")\n+\t\t\tempty_repo=0 &&\n+\t\t\tremote=0 &&\n+\t\t\tcontext=\"$context, 0 remotes\"\n+\t\t\t;;\n+\n+\t\t# Whether there is at least one valid remote ref\n+\t\t\"remote_ref\")\n+\t\t\t# requires: remote\n+\t\t\tempty_repo=0 &&\n+\t\t\tremote_ref=1 &&\n+\t\t\tcontext=\"$context, >=1 fetched remote branches\"\n+\t\t\t;;\n+\t\t\"no_remote_ref\")\n+\t\t\tempty_repo=0 &&\n+\t\t\tremote_ref=0 &&\n+\t\t\tcontext=\"$context, 0 fetched remote branches\"\n+\t\t\t;;\n+\n+\t\t# Options or flags that become illegal when --orphan is inferred\n+\t\t\"no_checkout\")\n+\t\t\targs=\"$args --no-checkout\" &&\n+\t\t\tcontext=\"$context, --no-checkout\"\n+\t\t\t;;\n+\t\t\"track\")\n+\t\t\targs=\"$args --track\" &&\n+\t\t\tcontext=\"$context, --track\"\n+\t\t\t;;\n+\n+\t\t# All other options are illegal\n+\t\t*)\n+\t\t\techo \"test_dwim_orphan(): invalid arg: '$1'\" >&2 &&\n+\t\t\treturn 1\n+\t\t\t;;\n+\t\tesac &&\n+\t\tshift\n+\tdone &&\n+\tcontext=\"${context#', '}\" &&\n+\tif [ $use_new_branch -eq 1 ]\n+\tthen\n+\t\targs=\"$args -b foo\"\n+\telse\n+\t\tcontext=\"DWIM (no --branch), $context\"\n+\tfi &&\n+\tif [ $empty_repo -eq 1 ]\n+\tthen\n+\t\tcontext=\"empty repo, $context\"\n+\tfi &&\n+\targs=\"$args ../foo\" &&\n+\tcontext=\"${context%', '}\" &&\n+\ttest_expect_success \"$outcome_text w/ $context\" '\n+\t\ttest_when_finished \"rm -rf repo\" &&\n+\t\tgit init repo &&\n+\t\tif [ $local_ref -eq 1 ] && [ \"$git_ns\" = \"repo\" ]\n+\t\tthen\n+\t\t\t(cd repo && test_commit commit) &&\n+\t\t\tif [ $bad_head -eq 1 ]\n+\t\t\tthen\n+\t\t\t\tgit -C repo symbolic-ref HEAD refs/heads/badbranch\n+\t\t\tfi\n+\t\telif [ $local_ref -eq 1 ] && [ \"$git_ns\" = \"wt\" ]\n+\t\tthen\n+\t\t\ttest_when_finished \"git -C repo worktree remove -f ../wt\" &&\n+\t\t\tgit -C repo worktree add --orphan -b main ../wt &&\n+\t\t\t(cd wt && test_commit commit) &&\n+\t\t\tif [ $bad_head -eq 1 ]\n+\t\t\tthen\n+\t\t\t\tgit -C wt symbolic-ref HEAD refs/heads/badbranch\n+\t\t\tfi\n+\t\telif [ $local_ref -eq 0 ] && [ \"$git_ns\" = \"wt\" ]\n+\t\tthen\n+\t\t\ttest_when_finished \"git -C repo worktree remove -f ../wt\" &&\n+\t\t\tgit -C repo worktree add --orphan -b orphanbranch ../wt\n+\t\tfi &&\n+\n+\t\tif [ $remote -eq 1 ]\n+\t\tthen\n+\t\t\ttest_when_finished \"rm -rf upstream\" &&\n+\t\t\tgit init upstream &&\n+\t\t\t(cd upstream && test_commit commit) &&\n+\t\t\tgit -C upstream switch -c foo &&\n+\t\t\tgit -C repo remote add upstream ../upstream\n+\t\tfi &&\n+\n+\t\tif [ $remote_ref -eq 1 ]\n+\t\tthen\n+\t\t\tgit -C repo fetch\n+\t\tfi &&\n+\t\tif [ $success -eq 1 ]\n+\t\tthen\n+\t\t\ttest_when_finished git -C repo worktree remove ../foo\n+\t\tfi &&\n+\t\t(\n+\t\t\tif [ $use_cd -eq 1 ]\n+\t\t\tthen\n+\t\t\t\tcd $git_ns\n+\t\t\tfi &&\n+\t\t\tif [ \"$outcome\" = \"infer\" ]\n+\t\t\tthen\n+\t\t\t\tgit $dashc_args worktree add $args 2>actual &&\n+\t\t\t\tif [ $use_quiet -eq 1 ]\n+\t\t\t\tthen\n+\t\t\t\t\ttest_must_be_empty actual\n+\t\t\t\telse\n+\t\t\t\t\tgrep \"$info_text\" actual\n+\t\t\t\tfi\n+\t\t\telif [ \"$outcome\" = \"no_infer\" ]\n+\t\t\tthen\n+\t\t\t\tgit $dashc_args worktree add $args 2>actual &&\n+\t\t\t\tif [ $use_quiet -eq 1 ]\n+\t\t\t\tthen\n+\t\t\t\t\ttest_must_be_empty actual\n+\t\t\t\telse\n+\t\t\t\t\t! grep \"$info_text\" actual\n+\t\t\t\tfi\n+\t\t\telif [ \"$outcome\" = \"fetch_error\" ]\n+\t\t\tthen\n+\t\t\t\ttest_must_fail git $dashc_args worktree add $args 2>actual &&\n+\t\t\t\tgrep \"$fetch_error_text\" actual\n+\t\t\telif [ \"$outcome\" = \"fatal_orphan_bad_combo\" ]\n+\t\t\tthen\n+\t\t\t\ttest_must_fail git $dashc_args worktree add $args 2>actual &&\n+\t\t\t\tif [ $use_quiet -eq 1 ]\n+\t\t\t\tthen\n+\t\t\t\t\t! grep \"$info_text\" actual\n+\t\t\t\telse\n+\t\t\t\t\tgrep \"$info_text\" actual\n+\t\t\t\tfi &&\n+\t\t\t\tgrep \"$bad_combo_regex\" actual\n+\t\t\telif [ \"$outcome\" = \"warn_bad_head\" ]\n+\t\t\tthen\n+\t\t\t\ttest_must_fail git $dashc_args worktree add $args 2>actual &&\n+\t\t\t\tif [ $use_quiet -eq 1 ]\n+\t\t\t\tthen\n+\t\t\t\t\tgrep \"$invalid_ref_regex\" actual &&\n+\t\t\t\t\t! grep \"$orphan_hint\" actual\n+\t\t\t\telse\n+\t\t\t\t\theadpath=$(git $dashc_args rev-parse --sq --path-format=absolute --git-path HEAD) &&\n+\t\t\t\t\theadcontents=$(cat \"$headpath\") &&\n+\t\t\t\t\tgrep \"HEAD points to an invalid (or orphaned) reference\" actual &&\n+\t\t\t\t\tgrep \"HEAD path:\\s*.$headpath.\" actual &&\n+\t\t\t\t\tgrep \"HEAD contents:\\s*.$headcontents.\" actual &&\n+\t\t\t\t\tgrep \"$orphan_hint\" actual &&\n+\t\t\t\t\t! grep \"$info_text\" actual\n+\t\t\t\tfi &&\n+\t\t\t\tgrep \"$invalid_ref_regex\" actual\n+\t\t\telse\n+\t\t\t\t# Unreachable\n+\t\t\t\tfalse\n+\t\t\tfi\n+\t\t) &&\n+\t\tif [ $success -ne 1 ]\n+\t\tthen\n+\t\t\ttest_path_is_missing foo\n+\t\tfi\n+\t'\n+}\n+\n+for quiet_mode in \"no_quiet\" \"quiet\"\n+do\n+\tfor changedir_type in \"cd_repo\" \"cd_wt\" \"-C_repo\" \"-C_wt\"\n+\tdo\n+\t\tdwim_test_args=\"$quiet_mode $changedir_type\"\n+\t\ttest_dwim_orphan 'infer' $dwim_test_args no_-b\n+\t\ttest_dwim_orphan 'no_infer' $dwim_test_args no_-b local_ref good_head\n+\t\ttest_dwim_orphan 'infer' $dwim_test_args no_-b no_local_ref no_remote no_remote_ref no_guess_remote\n+\t\ttest_dwim_orphan 'infer' $dwim_test_args no_-b no_local_ref remote no_remote_ref no_guess_remote\n+\t\ttest_dwim_orphan 'fetch_error' $dwim_test_args no_-b no_local_ref remote no_remote_ref guess_remote\n+\t\ttest_dwim_orphan 'infer' $dwim_test_args no_-b no_local_ref remote no_remote_ref guess_remote force\n+\t\ttest_dwim_orphan 'no_infer' $dwim_test_args no_-b no_local_ref remote remote_ref guess_remote\n+\n+\t\ttest_dwim_orphan 'infer' $dwim_test_args -b\n+\t\ttest_dwim_orphan 'no_infer' $dwim_test_args -b local_ref good_head\n+\t\ttest_dwim_orphan 'infer' $dwim_test_args -b no_local_ref no_remote no_remote_ref no_guess_remote\n+\t\ttest_dwim_orphan 'infer' $dwim_test_args -b no_local_ref remote no_remote_ref no_guess_remote\n+\t\ttest_dwim_orphan 'infer' $dwim_test_args -b no_local_ref remote no_remote_ref guess_remote\n+\t\ttest_dwim_orphan 'infer' $dwim_test_args -b no_local_ref remote remote_ref guess_remote\n+\tdone\n+\n+\ttest_dwim_orphan 'fatal_orphan_bad_combo' $quiet_mode no_-b no_checkout\n+\ttest_dwim_orphan 'fatal_orphan_bad_combo' $quiet_mode no_-b track\n+\ttest_dwim_orphan 'fatal_orphan_bad_combo' $quiet_mode -b no_checkout\n+\ttest_dwim_orphan 'fatal_orphan_bad_combo' $quiet_mode -b track\n+done\n+\n post_checkout_hook () {\n \ttest_when_finished \"rm -rf .git/hooks\" &&\n \tmkdir .git/hooks &&\n--\n2.39.3\n\n\n"}]}