git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
From: "Ævar Arnfjörð Bjarmason" <avarab@gmail.com>
To: Eric Sunshine <sunshine@sunshineco.com>
Cc: Elijah Newren <newren@gmail.com>,
	Stefan Monnier <monnier@iro.umontreal.ca>,
	Git Mailing List <git@vger.kernel.org>
Subject: Re: New orphan worktree?
Date: Thu, 18 Feb 2021 02:26:27 +0100	[thread overview]
Message-ID: <87wnv688u4.fsf@evledraar.gmail.com> (raw)
In-Reply-To: <CAPig+cRzXd+zd+xVisaW+HToSaGzAE28acGmxwRxNU4bczHXbw@mail.gmail.com>


On Wed, Jan 06 2021, Eric Sunshine wrote:

> 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 &&


  reply	other threads:[~2021-02-18  1:29 UTC|newest]

Thread overview: 22+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-01-06 16:17 New orphan worktree? Stefan Monnier
2021-01-06 17:00 ` Jim Hill
2021-01-06 19:48   ` Elijah Newren
2021-01-06 20:33     ` Jim Hill
2021-01-06 19:40 ` Elijah Newren
2021-01-06 20:01   ` Eric Sunshine
2021-02-18  1:26     ` Ævar Arnfjörð Bjarmason [this message]
2021-02-21 19:55       ` Eric Sunshine
2021-02-22  9:44         ` Ævar Arnfjörð Bjarmason
2021-02-22 23:06           ` Eric Sunshine
2021-02-22 23:59             ` Junio C Hamano
2021-02-23  0:33               ` Eric Sunshine
2021-02-23  0:17             ` Ævar Arnfjörð Bjarmason
2021-02-23  0:55               ` Eric Sunshine
2021-02-23 11:06                 ` Ævar Arnfjörð Bjarmason
2021-02-23 18:14                   ` Junio C Hamano
2021-01-06 21:29   ` Junio C Hamano
2021-01-06 22:01     ` Jim Hill
2021-01-06 22:15       ` Junio C Hamano
2021-01-06 22:25         ` Jim Hill
2021-01-06 22:56           ` Stefan Monnier
2021-01-06 22:01     ` Stefan Monnier

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: http://vger.kernel.org/majordomo-info.html

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87wnv688u4.fsf@evledraar.gmail.com \
    --to=avarab@gmail.com \
    --cc=git@vger.kernel.org \
    --cc=monnier@iro.umontreal.ca \
    --cc=newren@gmail.com \
    --cc=sunshine@sunshineco.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).