threads / discuss / 54948

New orphan worktree?

Subject: New orphan worktree?

## tl;dr

22 messages between Jan 6, 2021 and Feb 23, 2021.

replies: 21people: 6as markdown or json

Stefan Monnier· Jan 6, 2021, 16:17 UTC · lore
I use worktrees extensively (and rarely use `git checkout`).

When I need to create a new orphan branch with a new matching worktree (or submodule), I find it is quite cumbersome. I basically have to do something like:

    git worktree add -b dummy foo
    cd foo
    git checkout --orphan newbranch
    git rm -rf .
    git branch -D dummy
I wish I could just do something like:
    git worktree add --orphan foo newbranch
instead,
        Stefan
Jim Hill· Jan 6, 2021, 17:00 UTC · re: Stefan Monnier · lore

Re: New orphan worktree?

On Wed, Jan 6, 2021 at 8:18 AM Stefan Monnier <monnier@iro.umontreal.ca> wrote:
> create a new orphan branch with a new matching worktree
There's a much shorter sequence
    git worktree add -b new new $(git commit-tree `git mktree <&-` <&-)
    rm .git/refs/heads/new
Elijah Newren· Jan 6, 2021, 19:48 UTC · re: Jim Hill · lore

Re: New orphan worktree?

On Wed, Jan 6, 2021 at 9:05 AM Jim Hill <gjthill@gmail.com> wrote:
Show 8 quoted lines
>
> On Wed, Jan 6, 2021 at 8:18 AM Stefan Monnier <monnier@iro.umontreal.ca> wrote:
> > create a new orphan branch with a new matching worktree
>
> There's a much shorter sequence
>
>     git worktree add -b new new $(git commit-tree `git mktree <&-` <&-)
>     rm .git/refs/heads/new

The rm command presumes the file-backend for refs. That might not work in the future with reftable.

Jim Hill· Jan 6, 2021, 20:33 UTC · re: Elijah Newren · lore

Re: New orphan worktree?

On Wed, Jan 6, 2021 at 11:48 AM Elijah Newren <newren@gmail.com> wrote:
> The rm command presumes the file-backend for refs.  That might not
> work in the future with reftable.
True dat. The pure way is
    git worktree add newbranch $(git commit-tree `git mktree <&-` <&-)
    git -C newbranch symbolic-ref HEAD refs/heads/newbranch
Elijah Newren· Jan 6, 2021, 19:40 UTC · re: Stefan Monnier · lore

Re: New orphan worktree?

On Wed, Jan 6, 2021 at 8:21 AM Stefan Monnier <monnier@iro.umontreal.ca> wrote:
Show 9 quoted lines
>
> I use worktrees extensively (and rarely use `git checkout`).
>
> When I need to create a new orphan branch with a new matching worktree
> (or submodule), I find it is quite cumbersome.  I basically have
> to do something like:
>
>     git worktree add -b dummy foo
>     cd foo
>     git checkout --orphan newbranch
>     git rm -rf .
Sidenote:

Yeah, checkout --orphan is broken. You should use switch --orphan, which doesn't require the extra 'git rm -rf .' step. That bit is definitely cumbersome.

Show 5 quoted lines
>     git branch -D dummy
>
> I wish I could just do something like:
>
>     git worktree add --orphan foo newbranch
I think you mean
    git worktree add --orphan newbranch foo
    cd foo

Because (a) the option to --orphan is the name of the new branch, and (b) you need the cd to be equivalent to the first sequence of commands.

Out of curiosity, why are you frequently creating orphan branches? Such an option would drop the number of commands you need to run from four down to two, but I'm surprised this would come up enough to matter enough to do much more than create a personal git alias for it.

Eric Sunshine· Jan 6, 2021, 20:01 UTC · re: Elijah Newren · lore

Re: New orphan worktree?

On Wed, Jan 6, 2021 at 2:41 PM Elijah Newren <newren@gmail.com> wrote:
Show 9 quoted lines
> On Wed, Jan 6, 2021 at 8:21 AM Stefan Monnier <monnier@iro.umontreal.ca> wrote:
> > I wish I could just do something like:
> >
> >     git worktree add --orphan foo newbranch
>
> Out of curiosity, why are you frequently creating orphan branches?
> Such an option would drop the number of commands you need to run from
> four down to two, but I'm surprised this would come up enough to
> matter enough to do much more than create a personal git alias for it.

I'm also curious about a use-case in which orphaned branches are used so frequently.

Nevertheless, I'm not at all opposed to seeing an --orphan option added to `git worktree add`. In fact, --orphan has been on the radar[1] from the very beginning. Although the original implementation of `git worktree add` mimicked a small set of options from git-checkout, the plan all along was to mimic additional options from git-checkout as demand for them arose, and several such options have already been added.

> Yeah, checkout --orphan is broken.  You should use switch --orphan,
> which doesn't require the extra 'git rm -rf .' step.  That bit is
> definitely cumbersome.

Yep, when/if --orphan is added to `git worktree add`, it should mimic the behavior of --orphan in git-switch rather than git-checkout.

Patches are welcome.
[1]: https://lore.kernel.org/git/CAPig+cQiJnrnz4jsGdT0=8kYogWfsNkjq5WQCGC4Zk6res5mtg@mail.gmail.com/
Ævar Arnfjörð Bjarmason· Feb 18, 2021, 01:26 UTC · re: Eric Sunshine · lore

Re: New orphan worktree?

On Wed, Jan 06 2021, Eric Sunshine wrote:
Show 28 quoted lines
> On Wed, Jan 6, 2021 at 2:41 PM Elijah Newren <newren@gmail.com> wrote:
>> On Wed, Jan 6, 2021 at 8:21 AM Stefan Monnier <monnier@iro.umontreal.ca> wrote:
>> > I wish I could just do something like:
>> >
>> >     git worktree add --orphan foo newbranch
>>
>> Out of curiosity, why are you frequently creating orphan branches?
>> Such an option would drop the number of commands you need to run from
>> four down to two, but I'm surprised this would come up enough to
>> matter enough to do much more than create a personal git alias for it.
>
> I'm also curious about a use-case in which orphaned branches are used
> so frequently.
>
> Nevertheless, I'm not at all opposed to seeing an --orphan option
> added to `git worktree add`. In fact, --orphan has been on the
> radar[1] from the very beginning. Although the original implementation
> of `git worktree add` mimicked a small set of options from
> git-checkout, the plan all along was to mimic additional options from
> git-checkout as demand for them arose, and several such options have
> already been added.
>
>> Yeah, checkout --orphan is broken.  You should use switch --orphan,
>> which doesn't require the extra 'git rm -rf .' step.  That bit is
>> definitely cumbersome.
>
> Yep, when/if --orphan is added to `git worktree add`, it should mimic
> the behavior of --orphan in git-switch rather than git-checkout.

How would a mode for "worktree add --orphan" that mimics checkout rather than switch even look like? The "checkout --orphan" special-case is because we retain the index, so you need to "git rm -rf .".

But with worktrees we always get a new index, so AFAICT the only way to make it work like "checkout" would be to have it be the only mode that copies over the current worktree's index.

In any case I implemented a rough version of this today, and it uses the "switch" semantics. I only discovered this ML thread afterwards.

It's surely full of bugs, and needs test work (see all the BUG(...)), but if someone's interested in taking it further all it should need is some more tests & dealing with the edge cases of incompatible options etc. It's Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>.

I'd tried crafting as simple worktree manually, and discovered that I could get worktree_add() to create it rather easily by jumping past some of the "commit exists?" checks.

diff --git a/builtin/worktree.c b/builtin/worktree.c
index 1cd5c2016e3..eeecb6da380 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -31,6 +31,7 @@ struct add_opts {
 	int quiet;
 	int checkout;
 	int keep_locked;
+	int orphan;
 };
 
 static int show_only;
@@ -266,8 +267,12 @@ static int add_worktree(const char *path, const char *refname,
 			die_if_checked_out(symref.buf, 0);
 	}
 	commit = lookup_commit_reference_by_name(refname);
-	if (!commit)
+	if (opts->orphan) {
+		if (commit)
+			die(_("valid reference: %s"), refname);
+	} else if  (!commit) {
 		die(_("invalid reference: %s"), refname);
+	}
 
 	name = worktree_basename(path, &len);
 	strbuf_add(&sb, name, path + len - name);
@@ -340,7 +345,7 @@ static int add_worktree(const char *path, const char *refname,
 	strvec_pushf(&child_env, "%s=%s", GIT_WORK_TREE_ENVIRONMENT, path);
 	cp.git_cmd = 1;
 
-	if (!is_branch)
+	if (!opts->orphan && !is_branch)
 		strvec_pushl(&cp.args, "update-ref", "HEAD",
 			     oid_to_hex(&commit->object.oid), NULL);
 	else {
@@ -414,18 +419,28 @@ static int add_worktree(const char *path, const char *refname,
 static void print_preparing_worktree_line(int detach,
 					  const char *branch,
 					  const char *new_branch,
-					  int force_new_branch)
+					  int force_new_branch,
+					  int orphan)
 {
 	if (force_new_branch) {
 		struct commit *commit = lookup_commit_reference_by_name(new_branch);
-		if (!commit)
-			printf_ln(_("Preparing worktree (new branch '%s')"), new_branch);
-		else
+		if (!commit) {
+			if (orphan)
+				printf_ln(_("Preparing worktree (new orphan branch '%s')"), new_branch);
+			else
+				printf_ln(_("Preparing worktree (new branch '%s')"), new_branch);
+		} else {
+			if (orphan)
+				BUG("TODO");
 			printf_ln(_("Preparing worktree (resetting branch '%s'; was at %s)"),
 				  new_branch,
 				  find_unique_abbrev(&commit->object.oid, DEFAULT_ABBREV));
+		}
 	} else if (new_branch) {
-		printf_ln(_("Preparing worktree (new branch '%s')"), new_branch);
+		if (orphan)
+			printf_ln(_("Preparing worktree (new orphan branch '%s')"), new_branch);
+		else
+			printf_ln(_("Preparing worktree (new branch '%s')"), new_branch);
 	} else {
 		struct strbuf s = STRBUF_INIT;
 		if (!detach && !strbuf_check_branch_ref(&s, branch) &&
@@ -486,6 +501,7 @@ static int add(int ac, const char **av, const char *prefix)
 		OPT_BOOL('d', "detach", &opts.detach, N_("detach HEAD at named commit")),
 		OPT_BOOL(0, "checkout", &opts.checkout, N_("populate the new working tree")),
 		OPT_BOOL(0, "lock", &opts.keep_locked, N_("keep the new working tree locked")),
+		OPT_BOOL(0, "orphan", &opts.orphan, N_("new unparented branch")),
 		OPT__QUIET(&opts.quiet, N_("suppress progress reporting")),
 		OPT_PASSTHRU(0, "track", &opt_track, NULL,
 			     N_("set up tracking mode (see git-branch(1))"),
@@ -505,6 +521,8 @@ static int add(int ac, const char **av, const char *prefix)
 
 	path = prefix_filename(prefix, av[0]);
 	branch = ac < 2 ? "HEAD" : av[1];
+	if (opts.orphan)
+		branch = "";
 
 	if (!strcmp(branch, "-"))
 		branch = "@{-1}";
@@ -542,9 +560,11 @@ static int add(int ac, const char **av, const char *prefix)
 		}
 	}
 	if (!opts.quiet)
-		print_preparing_worktree_line(opts.detach, branch, new_branch, !!new_branch_force);
+		print_preparing_worktree_line(opts.detach, branch, new_branch, !!new_branch_force, opts.orphan);
 
-	if (new_branch) {
+	if (opts.orphan && new_branch) {
+		branch = new_branch;
+	} else if (new_branch) {
 		struct child_process cp = CHILD_PROCESS_INIT;
 		cp.git_cmd = 1;
 		strvec_push(&cp.args, "branch");
@@ -560,6 +580,8 @@ static int add(int ac, const char **av, const char *prefix)
 			return -1;
 		branch = new_branch;
 	} else if (opt_track) {
+		if (opts.orphan)
+			BUG("TODO");
 		die(_("--[no-]track can only be used if a new branch is created"));
 	}
 
diff --git a/t/t2400-worktree-add.sh b/t/t2400-worktree-add.sh
index 96dfca15542..e52aa6a11a2 100755
--- a/t/t2400-worktree-add.sh
+++ b/t/t2400-worktree-add.sh
@@ -66,6 +66,19 @@ test_expect_success '"add" worktree' '
 	)
 '
 
+test_expect_success '"add" worktree orphan branch' '
+	git worktree add --orphan -b orphan here-orphan &&
+	echo refs/heads/orphan >expect &&
+	git -C here-orphan symbolic-ref HEAD >actual &&
+	test_cmp expect actual &&
+	test_must_fail git -C here-orphan rev-parse --verify HEAD &&
+	test_must_fail git -C here-orphan log &&
+
+	echo here-orphan/.git >expected &&
+	find here-orphan -type f >actual &&
+	test_cmp expected actual
+'
+
 test_expect_success '"add" worktree with lock' '
 	git rev-parse HEAD >expect &&
 	git worktree add --detach --lock here-with-lock main &&
Eric Sunshine· Feb 21, 2021, 19:55 UTC · re: Ævar Arnfjörð Bjarmason · lore

Re: New orphan worktree?

On Wed, Feb 17, 2021 at 8:26 PM Ævar Arnfjörð Bjarmason <avarab@gmail.com> wrote:

Show 11 quoted lines
> On Wed, Jan 06 2021, Eric Sunshine wrote:
> > Yep, when/if --orphan is added to `git worktree add`, it should mimic
> > the behavior of --orphan in git-switch rather than git-checkout.
>
> How would a mode for "worktree add --orphan" that mimics checkout rather
> than switch even look like? The "checkout --orphan" special-case is
> because we retain the index, so you need to "git rm -rf .".
>
> But with worktrees we always get a new index, so AFAICT the only way to
> make it work like "checkout" would be to have it be the only mode that
> copies over the current worktree's index.

I hadn't actually put any thought into it aside from (1) `--orphan` being a likely candidate for `git worktree add`, and (2) my uses of orphan branches always involved `git checkout --orphan && git rm -rf .`. I never got as far as thinking about the actual implementation.

Show 7 quoted lines
> In any case I implemented a rough version of this today, and it uses the
> "switch" semantics. I only discovered this ML thread afterwards.
>
> It's surely full of bugs, and needs test work (see all the BUG(...)),
> but if someone's interested in taking it further all it should need is
> some more tests & dealing with the edge cases of incompatible options
> etc. It's Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>.
Thanks. This looks like a good start.
> +test_expect_success '"add" worktree orphan branch' '
> +       git worktree add --orphan -b orphan here-orphan &&

Rather than making --orphan a boolean flag, we'd probably want to mirror the behavior of the other commands and have <branch> be an argument consumed by --orphan:

    git worktree add --orphan <branch> <path>

That would make --orphan, -b, and -B mutually exclusive, much like they are for git-checkout, and much like -c, -C, and --orphan are mutually exclusive for git-switch.

Ævar Arnfjörð Bjarmason· Feb 22, 2021, 09:44 UTC · re: Eric Sunshine · lore

Re: New orphan worktree?

On Sun, Feb 21 2021, Eric Sunshine wrote:
Show 41 quoted lines
> On Wed, Feb 17, 2021 at 8:26 PM Ævar Arnfjörð Bjarmason
> <avarab@gmail.com> wrote:
>> On Wed, Jan 06 2021, Eric Sunshine wrote:
>> > Yep, when/if --orphan is added to `git worktree add`, it should mimic
>> > the behavior of --orphan in git-switch rather than git-checkout.
>>
>> How would a mode for "worktree add --orphan" that mimics checkout rather
>> than switch even look like? The "checkout --orphan" special-case is
>> because we retain the index, so you need to "git rm -rf .".
>>
>> But with worktrees we always get a new index, so AFAICT the only way to
>> make it work like "checkout" would be to have it be the only mode that
>> copies over the current worktree's index.
>
> I hadn't actually put any thought into it aside from (1) `--orphan`
> being a likely candidate for `git worktree add`, and (2) my uses of
> orphan branches always involved `git checkout --orphan && git rm -rf
> .`. I never got as far as thinking about the actual implementation.
>
>> In any case I implemented a rough version of this today, and it uses the
>> "switch" semantics. I only discovered this ML thread afterwards.
>>
>> It's surely full of bugs, and needs test work (see all the BUG(...)),
>> but if someone's interested in taking it further all it should need is
>> some more tests & dealing with the edge cases of incompatible options
>> etc. It's Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>.
>
> Thanks. This looks like a good start.
>
>> +test_expect_success '"add" worktree orphan branch' '
>> +       git worktree add --orphan -b orphan here-orphan &&
>
> Rather than making --orphan a boolean flag, we'd probably want to
> mirror the behavior of the other commands and have <branch> be an
> argument consumed by --orphan:
>
>     git worktree add --orphan <branch> <path>
>
> That would make --orphan, -b, and -B mutually exclusive, much like
> they are for git-checkout, and much like -c, -C, and --orphan are
> mutually exclusive for git-switch.

I see now (but didn't before, I haven't really used "switch" before) that that's how it works.

But that doesn't seem to make much sense as a UI, maybe I'm missing something but how do you:

    git switch --orphan existing-branch
Just like you can:
    git switch -C existing-branch <start-point>

It's actually this exact use-case that prompted me to write the --orphan patch. I wanted to create a "meta" orphan branch in my git.git, but had an existing local "meta" (from Jeff King) that I'd happened to have checked out long ago which I first needed to "git branch -D".

Wouldn't it make more sense for a feature like this & back-compat to start with switch's "--orphan" implying "-c", but you could also supply "--orphan -C" instead? And in worktree have -b and -B work like they do for other branches.

Eric Sunshine· Feb 22, 2021, 23:06 UTC · re: Ævar Arnfjörð Bjarmason · lore

Re: New orphan worktree?

On Mon, Feb 22, 2021 at 4:45 AM Ævar Arnfjörð Bjarmason <avarab@gmail.com> wrote:

Show 22 quoted lines
> On Sun, Feb 21 2021, Eric Sunshine wrote:
> > Rather than making --orphan a boolean flag, we'd probably want to
> > mirror the behavior of the other commands and have <branch> be an
> > argument consumed by --orphan:
> >
> >     git worktree add --orphan <branch> <path>
> >
> > That would make --orphan, -b, and -B mutually exclusive, much like
> > they are for git-checkout, and much like -c, -C, and --orphan are
> > mutually exclusive for git-switch.
>
> I see now (but didn't before, I haven't really used "switch" before)
> that that's how it works.
>
> But that doesn't seem to make much sense as a UI, maybe I'm missing
> something but how do you:
>
>     git switch --orphan existing-branch
>
> Just like you can:
>
>     git switch -C existing-branch <start-point>

When responding to your initial email, I noticed this same shortcoming of --orphan in both git-branch and git-switch, and assumed that's why you made it a boolean in combination with -b/-B in "git worktree add". Before writing that email, I did put a bit of thought into how one might support a "force" mode but didn't include my thoughts in the message.

Show 9 quoted lines
> It's actually this exact use-case that prompted me to write the --orphan
> patch. I wanted to create a "meta" orphan branch in my git.git, but had
> an existing local "meta" (from Jeff King) that I'd happened to have
> checked out long ago which I first needed to "git branch -D".
>
> Wouldn't it make more sense for a feature like this & back-compat to
> start with switch's "--orphan" implying "-c", but you could also supply
> "--orphan -C" instead? And in worktree have -b and -B work like they do
> for other branches.

I'm not sure I follow. In git-switch, --orphan does not imply -c even though --orphan also creates a new branch (thus seems to work similar to -c); it is nevertheless mutually-exclusive with -c and -C. The same goes for --orphan in git-branch.

As far as combining --orphan and -C (or -c), I'm not sure how we would arrange that using the existing parse_options() mechanism. It seems too magical and has potential for weird corner cases.

Since git-worktree doesn't yet support --orphan, we certainly have more leeway and could go with your proposal of having --orphan be boolean and always requiring it to be used in conjunction with -b/-B. However, I'm quite hesitant to take that approach since it breaks with existing precedent in git-branch and git-switch, in which case --orphan takes its own argument (<branch>) and is mutually-exclusive with -b/-B/-c/-C.

When I was pondering the issue before writing my original response, two thoughts came to mind. (1) "git worktree add --force --orphan <branch>" would be one way to make your case work; (2) given how infrequently --orphan is used, we just punt and require people to first use "git branch -D <branch>" if necessary (which has been the status-quo for git-branch and git-switch). The latter thought is superficially tempting, though it doesn't help in automation situations since "git branch -D <branch>" errors out if <branch> doesn't exist, so a script would first have to check for existence of <branch> before attempting to delete it prior to using "git worktree add --orphan <branch>".

So, I don't have any great answers at this time.
Junio C Hamano· Feb 22, 2021, 23:59 UTC · re: Eric Sunshine · lore

Re: New orphan worktree?

Eric Sunshine <sunshine@sunshineco.com> writes:
Show 6 quoted lines
> When I was pondering the issue before writing my original response,
> two thoughts came to mind. (1) "git worktree add --force --orphan
> <branch>" would be one way to make your case work; (2) given how
> infrequently --orphan is used, we just punt and require people to
> first use "git branch -D <branch>" if necessary (which has been the
> status-quo for git-branch and git-switch).

FWIW, as I personally view that branch -d/-D, checkout -b/-B, and switch -c/-C were all mistakes (they should have been -d, -b and -c with and without --force, respectively), I find the combination of "--force --orphan" a reasonable way forward.

Eric Sunshine· Feb 23, 2021, 00:33 UTC · re: Junio C Hamano · lore

Re: New orphan worktree?

On Mon, Feb 22, 2021 at 6:59 PM Junio C Hamano <gitster@pobox.com> wrote:
Show 12 quoted lines
> Eric Sunshine <sunshine@sunshineco.com> writes:
> > When I was pondering the issue before writing my original response,
> > two thoughts came to mind. (1) "git worktree add --force --orphan
> > <branch>" would be one way to make your case work; (2) given how
> > infrequently --orphan is used, we just punt and require people to
> > first use "git branch -D <branch>" if necessary (which has been the
> > status-quo for git-branch and git-switch).
>
> FWIW, as I personally view that branch -d/-D, checkout -b/-B, and
> switch -c/-C were all mistakes (they should have been -d, -b and -c
> with and without --force, respectively), I find the combination of
> "--force --orphan" a reasonable way forward.

I'm also leaning toward `git worktree add --force --orphan <branch>` as a way forward. Indeed, `git worktree add --force -b <branch>` is a sensible extension even without --orphan being part of the equation, and it's easy to frame -B in documentation as equivalent to `--force -b`.

Ævar Arnfjörð Bjarmason· Feb 23, 2021, 00:17 UTC · re: Eric Sunshine · lore

Re: New orphan worktree?

On Tue, Feb 23 2021, Eric Sunshine wrote:
Show 46 quoted lines
> On Mon, Feb 22, 2021 at 4:45 AM Ævar Arnfjörð Bjarmason
> <avarab@gmail.com> wrote:
>> On Sun, Feb 21 2021, Eric Sunshine wrote:
>> > Rather than making --orphan a boolean flag, we'd probably want to
>> > mirror the behavior of the other commands and have <branch> be an
>> > argument consumed by --orphan:
>> >
>> >     git worktree add --orphan <branch> <path>
>> >
>> > That would make --orphan, -b, and -B mutually exclusive, much like
>> > they are for git-checkout, and much like -c, -C, and --orphan are
>> > mutually exclusive for git-switch.
>>
>> I see now (but didn't before, I haven't really used "switch" before)
>> that that's how it works.
>>
>> But that doesn't seem to make much sense as a UI, maybe I'm missing
>> something but how do you:
>>
>>     git switch --orphan existing-branch
>>
>> Just like you can:
>>
>>     git switch -C existing-branch <start-point>
>
> When responding to your initial email, I noticed this same shortcoming
> of --orphan in both git-branch and git-switch, and assumed that's why
> you made it a boolean in combination with -b/-B in "git worktree add".
> Before writing that email, I did put a bit of thought into how one
> might support a "force" mode but didn't include my thoughts in the
> message.
>
>> It's actually this exact use-case that prompted me to write the --orphan
>> patch. I wanted to create a "meta" orphan branch in my git.git, but had
>> an existing local "meta" (from Jeff King) that I'd happened to have
>> checked out long ago which I first needed to "git branch -D".
>>
>> Wouldn't it make more sense for a feature like this & back-compat to
>> start with switch's "--orphan" implying "-c", but you could also supply
>> "--orphan -C" instead? And in worktree have -b and -B work like they do
>> for other branches.
>
> I'm not sure I follow. In git-switch, --orphan does not imply -c even
> though --orphan also creates a new branch (thus seems to work similar
> to -c); it is nevertheless mutually-exclusive with -c and -C. The same
> goes for --orphan in git-branch.

I think we're on the same page with regards to what I meant. I.e. I don't see how it makes sense to conflate the type of branch we want (orphan or not orphan) with whether we want to clobber that branch or not (switch -c or -C, or worktree -b or -B)

> As far as combining --orphan and -C (or -c), I'm not sure how we would
> arrange that using the existing parse_options() mechanism. It seems
> too magical and has potential for weird corner cases.

Isn't it just having --orphan be an OPTION_STRING with PARSE_OPT_LASTARG_DEFAULT. I.e. to support:

    git switch -b branch --orphan
    git switch -B branch --orphan
    git switch --orphan branch
And:
    git worktree add -b branch --orphan
    git worktree add -B branch --orphan
I didn't test it, just skimmed the code.
Show 7 quoted lines
> Since git-worktree doesn't yet support --orphan, we certainly have
> more leeway and could go with your proposal of having --orphan be
> boolean and always requiring it to be used in conjunction with -b/-B.
> However, I'm quite hesitant to take that approach since it breaks with
> existing precedent in git-branch and git-switch, in which case
> --orphan takes its own argument (<branch>) and is mutually-exclusive
> with -b/-B/-c/-C.
In git-branch? Isn't it only git [checkout|switch] that takes --orphan?

But yeah, I agree that it makes sense for "worktree add" to be consistent with "switch". I was just wondering if we couldn't fix what seems to me to be a small options UI issue while we're at it.

Show 11 quoted lines
> When I was pondering the issue before writing my original response,
> two thoughts came to mind. (1) "git worktree add --force --orphan
> <branch>" would be one way to make your case work; (2) given how
> infrequently --orphan is used, we just punt and require people to
> first use "git branch -D <branch>" if necessary (which has been the
> status-quo for git-branch and git-switch). The latter thought is
> superficially tempting, though it doesn't help in automation
> situations since "git branch -D <branch>" errors out if <branch>
> doesn't exist, so a script would first have to check for existence of
> <branch> before attempting to delete it prior to using "git worktree
> add --orphan <branch>".

I think not having a -B or -C equivalent at all would be preferrable to having a --force special-case just to work around the lack of it for --orphan.

Eric Sunshine· Feb 23, 2021, 00:55 UTC · re: Ævar Arnfjörð Bjarmason · lore

Re: New orphan worktree?

On Mon, Feb 22, 2021 at 7:17 PM Ævar Arnfjörð Bjarmason <avarab@gmail.com> wrote:

Show 10 quoted lines
> On Tue, Feb 23 2021, Eric Sunshine wrote:
> > I'm not sure I follow. In git-switch, --orphan does not imply -c even
> > though --orphan also creates a new branch (thus seems to work similar
> > to -c); it is nevertheless mutually-exclusive with -c and -C. The same
> > goes for --orphan in git-branch.
>
> I think we're on the same page with regards to what I meant. I.e. I
> don't see how it makes sense to conflate the type of branch we want
> (orphan or not orphan) with whether we want to clobber that branch or
> not (switch -c or -C, or worktree -b or -B)

I see where you're coming from in viewing --orphan as a modifier of branch creation rather than as a branch-creation option itself. However, as far as UI is concerned, that ship sailed a long time ago, I suppose.

Show 17 quoted lines
> > As far as combining --orphan and -C (or -c), I'm not sure how we would
> > arrange that using the existing parse_options() mechanism. It seems
> > too magical and has potential for weird corner cases.
>
> Isn't it just having --orphan be an OPTION_STRING with
> PARSE_OPT_LASTARG_DEFAULT. I.e. to support:
>
>     git switch -b branch --orphan
>     git switch -B branch --orphan
>     git switch --orphan branch
>
> And:
>
>     git worktree add -b branch --orphan
>     git worktree add -B branch --orphan
>
> I didn't test it, just skimmed the code.

I haven't dived into this stuff in a long time, but I'm having trouble convincing myself that it would work out as intended. If I'm reading PARSE_OPT_LASTARG_DEFAULT correctly, `git switch -b <branch> --orphan` would not be the same as `git switch --orphan -b <branch>`, and I don't think it would work at all for git-worktree-add which has additional <path> and <commitish> arguments (i.e. `git worktree add -b <branch> --orphan <path> [<commitish>]`).

Anyhow, as I responded elsewhere to Junio, my present leaning is toward -b, -B, --orphan all being mutually-exclusive branch-creation options, each taking a <branch> argument -- just like they are in git-checkout and git-switch (-c/-C, in this case) -- and allowing --force to overwrite an existing branch (in which case, -B can be viewed as shorthand for `--force -b`).

Show 9 quoted lines
> > Since git-worktree doesn't yet support --orphan, we certainly have
> > more leeway and could go with your proposal of having --orphan be
> > boolean and always requiring it to be used in conjunction with -b/-B.
> > However, I'm quite hesitant to take that approach since it breaks with
> > existing precedent in git-branch and git-switch, in which case
> > --orphan takes its own argument (<branch>) and is mutually-exclusive
> > with -b/-B/-c/-C.
>
> In git-branch? Isn't it only git [checkout|switch] that takes --orphan?

Um, yes, I meant git-checkout everywhere I wrote git-branch. Sorry for the confusion.

> I think not having a -B or -C equivalent at all would be preferrable to
> having a --force special-case just to work around the lack of it for
> --orphan.
I'm having trouble wrapping my brain around this statement.
Ævar Arnfjörð Bjarmason· Feb 23, 2021, 11:06 UTC · re: Eric Sunshine · lore

Re: New orphan worktree?

On Tue, Feb 23 2021, Eric Sunshine wrote:
Show 17 quoted lines
> On Mon, Feb 22, 2021 at 7:17 PM Ævar Arnfjörð Bjarmason
> <avarab@gmail.com> wrote:
>> On Tue, Feb 23 2021, Eric Sunshine wrote:
>> > I'm not sure I follow. In git-switch, --orphan does not imply -c even
>> > though --orphan also creates a new branch (thus seems to work similar
>> > to -c); it is nevertheless mutually-exclusive with -c and -C. The same
>> > goes for --orphan in git-branch.
>>
>> I think we're on the same page with regards to what I meant. I.e. I
>> don't see how it makes sense to conflate the type of branch we want
>> (orphan or not orphan) with whether we want to clobber that branch or
>> not (switch -c or -C, or worktree -b or -B)
>
> I see where you're coming from in viewing --orphan as a modifier of
> branch creation rather than as a branch-creation option itself.
> However, as far as UI is concerned, that ship sailed a long time ago,
> I suppose.
Not really, I think we can have a new-style of it and just say:
    It is also possible to provide `--orphan <branch-name>`, but
    supplying it as an option to `-[cC]` as `-[cC] <branch-name>
    --orphan` is preferred these days.
Whether we should is another matter, see below...
Show 22 quoted lines
>> > As far as combining --orphan and -C (or -c), I'm not sure how we would
>> > arrange that using the existing parse_options() mechanism. It seems
>> > too magical and has potential for weird corner cases.
>>
>> Isn't it just having --orphan be an OPTION_STRING with
>> PARSE_OPT_LASTARG_DEFAULT. I.e. to support:
>>
>>     git switch -b branch --orphan
>>     git switch -B branch --orphan
>>     git switch --orphan branch
>>
>> And:
>>
>>     git worktree add -b branch --orphan
>>     git worktree add -B branch --orphan
>>
>> I didn't test it, just skimmed the code.
>
> I haven't dived into this stuff in a long time, but I'm having trouble
> convincing myself that it would work out as intended. If I'm reading
> PARSE_OPT_LASTARG_DEFAULT correctly, `git switch -b <branch> --orphan`
> would not be the same as `git switch --orphan -b <branch>`

Yeah, I think so. But I think for an option like that it would be more obvious. I.e. we could say:

    If "-b" or "-B" is provided a subsequent "--orphan" is a boolean.

We don't support the combination of the two now, so we could just mandate that the order matters.

Anyway...
> , and I don't think it would work at all for git-worktree-add which
> has additional <path> and <commitish> arguments (i.e. `git worktree
> add -b <branch> --orphan <path> [<commitish>]`).

...we can parse these options, whether it's easy or trivial with parse-options.c is something I'd like to leave aside for now.

Right now I'm not intending to re-roll this patch, but maybe someone else (or even me) will get to it sometime. I think it's more useful if/when that happens to get people's take on whether this makes sense as UI, not whether it's trivial with the current parse_options() API.

I think it's fairly easy to tease this behavior out of parse_options(). Worse case we can do a pre-loop over argv and see if both "--orphan" and "-b"/"-B" occur. if so parse it with "--orphan" as a BOOL, otherwise STRING.

Show 6 quoted lines
> Anyhow, as I responded elsewhere to Junio, my present leaning is
> toward -b, -B, --orphan all being mutually-exclusive branch-creation
> options, each taking a <branch> argument -- just like they are in
> git-checkout and git-switch (-c/-C, in this case) -- and allowing
> --force to overwrite an existing branch (in which case, -B can be
> viewed as shorthand for `--force -b`).

See https://lore.kernel.org/git/7vpqzlrmo4.fsf@alter.siamese.dyndns.org/ for past Junio arguing with his future self :)

I.e. the reason we had -B in the first place is because --force means something else. We'd need "--force-ref-deletion --force-work-tree-clobbering" or whatever, or "--force --force".

I like this lower/upper case convention. It started with "branch -D" in ba65af9c1f6 (git-branch -d <branch>: delete unused branch., 2005-09-14), but in checkout the --orphan option pre-dates -B. See 9db5ebf4022 (git checkout: create unparented branch by --orphan, 2010-03-21) and 02ac98374ee (builtin/checkout: learn -B, 2010-06-24).

I don't think we're going to change how "branch -D" and "switch -C" work at this point, so making things consistent with it makes sense.

Show 12 quoted lines
>> > Since git-worktree doesn't yet support --orphan, we certainly have
>> > more leeway and could go with your proposal of having --orphan be
>> > boolean and always requiring it to be used in conjunction with -b/-B.
>> > However, I'm quite hesitant to take that approach since it breaks with
>> > existing precedent in git-branch and git-switch, in which case
>> > --orphan takes its own argument (<branch>) and is mutually-exclusive
>> > with -b/-B/-c/-C.
>>
>> In git-branch? Isn't it only git [checkout|switch] that takes --orphan?
>
> Um, yes, I meant git-checkout everywhere I wrote git-branch. Sorry for
> the confusion.
*nod*
Show 5 quoted lines
>> I think not having a -B or -C equivalent at all would be preferrable to
>> having a --force special-case just to work around the lack of it for
>> --orphan.
>
> I'm having trouble wrapping my brain around this statement.

I mean I'd rather not have an --orphan mode that works like -B (as opposed to -b) at all instead of having one that's "--orphan --force-ref-deletion" or whatever.

It's an obscure enough thing that I don't think anyone *really* cares. I just wanted to find out if it not being a boolean was intentional, or a historical accident we would consider fixing if there was further work on it.

Junio C Hamano· Feb 23, 2021, 18:14 UTC · re: Ævar Arnfjörð Bjarmason · lore

Re: New orphan worktree?

Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:
Show 12 quoted lines
>> I see where you're coming from in viewing --orphan as a modifier of
>> branch creation rather than as a branch-creation option itself.
>> However, as far as UI is concerned, that ship sailed a long time ago,
>> I suppose.
>
> Not really, I think we can have a new-style of it and just say:
>
>     It is also possible to provide `--orphan <branch-name>`, but
>     supplying it as an option to `-[cC]` as `-[cC] <branch-name>
>     --orphan` is preferred these days.
>
> Whether we should is another matter, see below...

We cannot affored to give it a short-and-sweet "-[oO]", but if we could, we probably would have, and that would have made the UI consistent, at least (in other words, I'd see the act of creating an "orphan" branch something distinct from creation of a normal branch).

"You can treat --orphan as a standalone and distinct request to create this specific kind of branch, or you can treat as if it is just a modifier to specify which kind of branch, and -c/-C is still used to ask for creation or forced update" does not sound like a very end-user friendly explanation, at least to me. Extra choices that do not make a real difference invites "so, which should I use?", a question they do not have to ask.

Show 9 quoted lines
>>> I think not having a -B or -C equivalent at all would be preferrable to
>>> having a --force special-case just to work around the lack of it for
>>> --orphan.
>>
>> I'm having trouble wrapping my brain around this statement.
>
> I mean I'd rather not have an --orphan mode that works like -B (as
> opposed to -b) at all instead of having one that's "--orphan
> --force-ref-deletion" or whatever.
If you are saying that we should just have
    -c/-b/--orphan
    -c/-b/--orphan --force
    -C/-B (synonym for -c/-b --force)

then I fully agree. I think the uppercase ones (and "git branch -d/-D") were mistakes and should have used --force instead.

> It's an obscure enough thing that I don't think anyone *really* cares. I
> just wanted to find out if it not being a boolean was intentional, or a
> historical accident we would consider fixing if there was further work
> on it.
Junio C Hamano· Jan 6, 2021, 21:29 UTC · re: Elijah Newren · lore

Re: New orphan worktree?

Elijah Newren <newren@gmail.com> writes:
Show 5 quoted lines
> Sidenote:
>
> Yeah, checkout --orphan is broken.  You should use switch --orphan,
> which doesn't require the extra 'git rm -rf .' step.  That bit is
> definitely cumbersome.
I doubt "broken" is an appropriate word.  

It only targets a different workflow that wanted to start an unrelated history with a known contents.

> Out of curiosity, why are you frequently creating orphan branches?
> Such an option would drop the number of commands you need to run from
> four down to two, but I'm surprised this would come up enough to
> matter enough to do much more than create a personal git alias for it.

Yes, a need to have multiple unrelated line of histories in a single repository may not be there, even though a desire to do so might exist. What is done with these unrelated histories that record unrelated contents [*1*]?

For example, the answer might turn out to be "our hosting provider charge by number of publishing repositories, so I keep only one repository there and push unrelated stuff into it, on different branches", and such a use case to work around external limitation can be more naturally solved by having separate repositories on the producing side, and pushing into different branches in that single publishing repository, which does not require any "--orphan" at all.

[Footnote]
*1* if the trees in these unrelated histories record related
    contents, the user wouldn't be doing "git rm -f ." in the first
    place and "checkout --orphan" would be more appropriate than
    "switch --orphan".
Jim Hill· Jan 6, 2021, 22:01 UTC · re: Junio C Hamano · lore

Re: New orphan worktree?

On Wed, Jan 6, 2021 at 1:32 PM Junio C Hamano <gitster@pobox.com> wrote:
> a need to have multiple unrelated line of histories in a single
> repository may not be there, even though a desire to do so might
> exist.  What is done with these unrelated histories that record
> unrelated contents [*1*]?

Git itself is an example of other reasons for carrying disjoint dags as a set of related histories.

Also, I've taken to carrying submodule histories in the main repo, the setup is very easy, just a submodule init and worktree add. I think the pair of flows shows disjoint dags can be on a spectrum of relatedness.

Junio C Hamano· Jan 6, 2021, 22:15 UTC · re: Jim Hill · lore

Re: New orphan worktree?

Jim Hill <gjthill@gmail.com> writes:
Show 8 quoted lines
> On Wed, Jan 6, 2021 at 1:32 PM Junio C Hamano <gitster@pobox.com> wrote:
>> a need to have multiple unrelated line of histories in a single
>> repository may not be there, even though a desire to do so might
>> exist.  What is done with these unrelated histories that record
>> unrelated contents [*1*]?
>
> Git itself is an example of other reasons for carrying disjoint dags as a
> set of related histories.

Thanks, it is a good example why a repository may want to have unrelated histories stored in it, but it is not a good example to support the use of the "--orphan" option.

Histories for gitk, git-gui and todo come from different local repositories. gitk and git-gui histories come to my (local) repository by pulling from separate repositories that have only unrelated histories, and the todo branch does not exist even in my local repository working on git codebase.

You see git, gitk, git-gui histories in a single repository but these independent histories originate from and worked on each separate repositories. You see the todo history in the same repository as these other three lines, only because I used to have just a single publishing repository I can push into at kernel.org.

And none of the management above has any need to use "--orphan".

"gitk" and "git-gui" are worked in their own repositories, that do not even have any commits of "git" history. "todo" is worked in its own repository, that do not even have any commits of "git" history. The former two are pulled into my "git" repository and pushed out to the public repositories. The last one is pushed directly from my "git-todo" repository and pushed out.

Jim Hill· Jan 6, 2021, 22:25 UTC · re: Junio C Hamano · lore

Re: New orphan worktree?

On Wed, Jan 6, 2021 at 2:15 PM Junio C Hamano <gitster@pobox.com> wrote:
> not a good example to support the use of the "--orphan" option.

I agree with that part, slathering infrastructure and abstractions on oneliners (okay, twoliners) is suspect in my book. worktree add, symoblic ref (really, no need to get lowlevel there, checkout --orphan does it) done. Tag an empty commit and the sequence gets closer to a legit oneliner

    git worktree add foo empty; git -C foo checkout --orphan newbranch
Stefan Monnier· Jan 6, 2021, 22:56 UTC · re: Jim Hill · lore

Re: New orphan worktree?

Show 8 quoted lines
>> not a good example to support the use of the "--orphan" option.
> I agree with that part, slathering infrastructure and abstractions on
> oneliners (okay, twoliners) is suspect in my book. worktree add,
> symoblic ref (really, no need to get lowlevel there, checkout --orphan
> does it) done. Tag an empty commit and the sequence gets closer
> to a legit oneliner
>
>     git worktree add foo empty; git -C foo checkout --orphan newbranch

FWIW, I'd be quite happy to have an ad-hoc revision which represents "the (currently non-existing) ancestor shared by all branches". Assuming we'd call it "ORPHAN" (other names that come to mind would be "ROOT", "GOD", "∅", "BIGBANG", ...), then

    git checkout --orphan newbranch
would become
    git checkout -b newbranch ORPHAN
and then I'd also be able to say
    got worktree add -b newbranch foo ORPHAN

I've had occasional use for such a pseudo-revision in other circumstances as well and I think I'd find it easier to remember how to use this then the `--orphan` option.

        Stefan
Stefan Monnier· Jan 6, 2021, 22:01 UTC · re: Junio C Hamano · lore

Re: New orphan worktree?

> Yes, a need to have multiple unrelated line of histories in a single
> repository may not be there, even though a desire to do so might
> exist.  What is done with these unrelated histories that record
> unrelated contents [*1*]?

For the record, my use cases are basically subtrees of the project stashed in submodules instead of being kept as subdirectories in the main branch (the purpose being to be able to easily share&sync those subtrees between different projects).

        Stefan

← back to recent threads