Subject: [RESEND PATCH v10 0/8] worktree: Support `--orphan` when creating new worktrees

From: Jacob Abel <[email-masked]>
Date: Wed, 17 May 2023 21:47:30 +0000

This patchset introduces the ability to create new worktrees from orphan/unborn
branches and introduces DWIM behavior to create worktrees from an orphan branch
when no valid refs exists locally in the repository (as is typical in newly
initialized repositories) or on a remote (when `--guess-remote` is used). 

This addresses the issue of `git worktree add` failing when attempting to create
a worktree from a newly initialized repository (which can be seen in this SO
question [1]).

NOTE: Resend of Patch v10 as my mail setup tampered with and broke the patchset. 
original v10 cover: <[email-masked]>

This patchset has eight parts:
  * adding `-B` to the usage docs (noticed during dev and it seemed too small
    to justify a separate submission)
  * cleaning up a left-behind worktree in t2400
  * adding a helper fn to simplify testing for mutual exclusion of options
    in `t/t2400-worktree-add.sh`
  * adding additional test cases to verify both that behavior doesn't change
    when using `--quiet` and that the extraneous output is properly suppressed.
  * adding the ability to create a worktree from an unborn/orphan branch
    to `git-worktree-add`
  * adding an advise for using --orphan when `git worktree add` fails due to 
    a bad ref.
  * adding functionality to DWIM when there are no existing branches and the
    user likely intends to create an orphan branch.
  * updating worktree add to emit a warning (containing debug information 
    about the current HEAD) when trying to use a HEAD that points to a
    non-existant (or unborn) reference and there exist other valid branches.

Changes from v9:
  * Revert `test_when_finished cat actual` changes in t2400 (2/8)[2].
  * Rename commit 2/8 to reflect changes.
  * Revert `test_when_finished cat actual` changes in t2400 (3/8)[3].
  * Revert `test_when_finished cat actual` changes in t2400 (4/8)[4].
  * Revert `test_when_finished cat actual` changes in t2400 (5/8).
  * Remove extraneous whitespace from command in t2400 (5/8).
  * Revert `test_when_finished cat actual` changes in t2400 (6/8).
  * Include `advice.h` in `worktree.c` to resolve missing include when 
    applying patch on top of main (6/8).
  * Revert `test_when_finished cat actual` changes in t2400 (7/8).
  * Remove extraneous whitespace from comment in `worktree.c` (7/8).

1. https://stackoverflow.com/a/68717229/15064705/
2. https://lore.kernel.org/git/[email-masked]/
3. https://lore.kernel.org/git/[email-masked]/
4. https://lore.kernel.org/git/[email-masked]/

Jacob Abel (8):
  worktree add: include -B in usage docs
  t2400: cleanup created worktree in test
  t2400: refactor "worktree add" opt exclusion tests
  t2400: add tests to verify --quiet
  worktree add: add --orphan flag
  worktree add: introduce "try --orphan" hint
  worktree add: extend DWIM to infer --orphan
  worktree add: emit warn when there is a bad HEAD

 Documentation/config/advice.txt |   4 +
 Documentation/git-worktree.txt  |  16 +-
 advice.c                        |   1 +
 advice.h                        |   1 +
 builtin/worktree.c              | 227 +++++++++++++-
 t/t2400-worktree-add.sh         | 507 +++++++++++++++++++++++++++++++-
 6 files changed, 735 insertions(+), 21 deletions(-)

Range-diff against v9:
1:  91153fdb4c = 1:  91153fdb4c worktree add: include -B in usage docs
2:  8cfbc89dd5 ! 2:  0f30e9a9e3 t2400: print captured git output when finished
    @@ Metadata
     Author: Jacob Abel <[email-masked]>
     
      ## Commit message ##
    -    t2400: print captured git output when finished
    -
    -    Update tests that capture stderr so that at the end of the test they
    -    print the captured text back out to stderr. This simplifies debugging
    -    when inspecting test logs after executing with `-x`.
    +    t2400: cleanup created worktree in test
     
         Signed-off-by: Jacob Abel <[email-masked]>
     
    @@ t/t2400-worktree-add.sh: test_expect_success 'add -B' '
      
      test_expect_success 'add --quiet' '
     +	test_when_finished "git worktree remove -f -f another-worktree" &&
    -+	test_when_finished cat actual >&2 &&
      	git worktree add --quiet another-worktree main 2>actual &&
      	test_must_be_empty actual
      '
3:  ab03d92c3a ! 3:  06e8c53bc6 t2400: refactor "worktree add" opt exclusion tests
    @@ t/t2400-worktree-add.sh: test_expect_success '"add" no auto-vivify with --detach
     +test_wt_add_excl () {
     +	local opts="$*" &&
     +	test_expect_success "'worktree add' with '$opts' has mutually exclusive options" '
    -+		test_when_finished cat actual >&2 &&
     +		test_must_fail git worktree add $opts 2>actual &&
     +		grep -E "fatal:( options)? .* cannot be used together" actual
     +	'
4:  d9a3468c93 ! 4:  d9330db91f t2400: add tests to verify --quiet
    @@ t/t2400-worktree-add.sh: test_expect_success 'add --quiet' '
     +test_expect_success 'add --quiet -b' '
     +	test_when_finished "git branch -D quietnewbranch" &&
     +	test_when_finished "git worktree remove -f -f another-worktree" &&
    -+	test_when_finished cat actual >&2 &&
     +	git worktree add --quiet -b quietnewbranch another-worktree 2>actual &&
     +	test_must_be_empty actual
     +'
    @@ t/t2400-worktree-add.sh: test_expect_success 'git worktree add --guess-remote se
      '
     +test_expect_success 'git worktree add --guess-remote sets up tracking (quiet)' '
     +	test_when_finished rm -rf repo_a repo_b foo &&
    -+	test_when_finished cat repo_b/actual >&2 &&
     +	setup_remote_repo repo_a repo_b &&
     +	(
     +		cd repo_b &&
5:  8ef9587deb ! 5:  a5a78e5f53 worktree add: add --orphan flag
    @@ t/t2400-worktree-add.sh: test_expect_success 'add --quiet -b' '
     +
     +test_expect_success '"add --orphan --quiet"' '
     +	test_when_finished "git worktree remove -f -f orphandir" &&
    -+	test_when_finished cat log.actual >&2 &&
     +	git worktree add --quiet --orphan -b neworphan orphandir 2>log.actual &&
     +	test_must_be_empty log.actual &&
     +	echo refs/heads/neworphan >expected &&
    @@ t/t2400-worktree-add.sh: test_expect_success 'add --quiet -b' '
     +	test_when_finished "rm -rf empty_repo" &&
     +	echo refs/heads/newbranch >expected &&
     +	GIT_DIR="empty_repo" git init --bare &&
    -+	git -C empty_repo  worktree add --orphan -b newbranch worktreedir &&
    ++	git -C empty_repo worktree add --orphan -b newbranch worktreedir &&
     +	git -C empty_repo/worktreedir symbolic-ref HEAD >actual &&
     +	test_cmp expected actual
     +'
6:  d2800266f9 ! 6:  96b1946e64 worktree add: introduce "try --orphan" hint
    @@ advice.h: struct string_list;
      int git_default_advice_config(const char *var, const char *value);
     
      ## builtin/worktree.c ##
    +@@
    + #include "cache.h"
    + #include "abspath.h"
    ++#include "advice.h"
    + #include "checkout.h"
    + #include "config.h"
    + #include "builtin.h"
     @@
      #define BUILTIN_WORKTREE_UNLOCK_USAGE \
      	N_("git worktree unlock <worktree>")
    @@ t/t2400-worktree-add.sh: test_expect_success '"add" worktree with orphan branch,
     +		git init repo &&
     +		(cd repo && test_commit commit) &&
     +		git -C repo switch --orphan noref &&
    -+		test_when_finished cat actual >&2 &&
     +		test_must_fail git -C repo worktree add $opts foobar/ 2>actual &&
     +		! grep "error: unknown switch" actual &&
     +		grep "hint: If you meant to create a worktree containing a new orphan branch" actual &&
    @@ t/t2400-worktree-add.sh: test_expect_success '"add" worktree with orphan branch,
     +	test_when_finished "rm -rf repo" &&
     +	git init repo &&
     +	(cd repo && test_commit commit) &&
    -+	test_when_finished cat actual >&2 &&
     +	test_must_fail git -C repo worktree add --quiet foobar_branch foobar/ 2>actual &&
     +	! grep "error: unknown switch" actual &&
     +	! grep "hint: If you meant to create a worktree containing a new orphan branch" actual
7:  e5e139766c ! 7:  52fef9672c worktree add: extend DWIM to infer --orphan
    @@ builtin/worktree.c: static void print_preparing_worktree_line(int detach,
     +/**
     + * Determines whether `--orphan` should be inferred in the evaluation of
     + * `worktree add path/` or `worktree add -b branch path/` and emits an error
    -+ * if the supplied arguments would produce an illegal combination  when the
    ++ * if the supplied arguments would produce an illegal combination when the
     + * `--orphan` flag is included.
     + *
     + * `opts` and `opt_track` contain the other options & flags supplied to the
    @@ t/t2400-worktree-add.sh: test_expect_success 'git worktree --no-guess-remote opt
     +		then
     +			test_when_finished git -C repo worktree remove ../foo
     +		fi &&
    -+		if [ $use_cd -eq 1 ]
    -+		then
    -+			test_when_finished cat "$git_ns/actual" >&2
    -+		else
    -+			test_when_finished cat actual >&2
    -+		fi &&
     +		(
     +			if [ $use_cd -eq 1 ]
     +			then
8:  296226ffd5 = 8:  8c3fded12b worktree add: emit warn when there is a bad HEAD
-- 
2.39.3