From patchwork Tue Dec 20 02:37:31 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacob Abel X-Patchwork-Id: 13077408 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 1986CC4332F for ; Tue, 20 Dec 2022 02:37:49 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232782AbiLTChr (ORCPT ); Mon, 19 Dec 2022 21:37:47 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34842 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229540AbiLTChp (ORCPT ); Mon, 19 Dec 2022 21:37:45 -0500 Received: from mail-4317.proton.ch (mail-4317.proton.ch [185.70.43.17]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 10AC311A10 for ; Mon, 19 Dec 2022 18:37:45 -0800 (PST) Date: Tue, 20 Dec 2022 02:37:31 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nullpo.dev; s=protonmail3; t=1671503863; x=1671763063; bh=L0O4igHG0LDunpSyVYnuuUFv9k9l23naxaAa6b3ALj0=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: Feedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID: Message-ID:BIMI-Selector; b=fTDBRqGdsUsRX2FKKBwxNnQwkrqstx+1rGhrOiuqzDASd8kaosgTGRA4cgpOs/GIf wQ1svOQ/g1Q4TnbalwNIUMV5uP7AJLoPrc94b9w/ZCKcEbXzxRnItJ5gO0NUbz8YWa Yhvi90o14Fl6BPsnJKXui6DyrVTP97ld+0cHClv3rk4ksP1CpxXUPTR2QzVED4uITX w1AkjujKt/XgheyoY9wUTz5sFGPbF54VAVmy1OJheNi4aaUY50VtMnzGsss+neQLyH YW2M+NomE9qb9zohmrrtCVH1YLvWUo6w/xL739mJh/EB/Wf+19tEZmq0NMl4O6TKlY LMbzThSJNMANQ== To: git@vger.kernel.org From: Jacob Abel Cc: Jacob Abel , =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsCBC?= =?utf-8?b?amFybWFzb24=?= , Eric Sunshine , Phillip Wood , =?utf-8?q?Rub=C3=A9n_Justo?= , Taylor Blau , rsbecker@nexbridge.com Subject: [PATCH v5 1/4] worktree add: Include -B in usage docs Message-ID: <20221220023637.29042-2-jacobabel@nullpo.dev> In-Reply-To: <20221220023637.29042-1-jacobabel@nullpo.dev> References: <20221104010242.11555-1-jacobabel@nullpo.dev> <20221104213401.17393-1-jacobabel@nullpo.dev> <20221110233137.10414-1-jacobabel@nullpo.dev> <20221212014003.20290-1-jacobabel@nullpo.dev> <20221220023637.29042-1-jacobabel@nullpo.dev> Feedback-ID: 21506737:user:proton MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org While -B behavior is already documented, it was not included in the usage docs for either the man page or the help text. This change fixes that and brings the usage docs in line with how the flags are documented in other commands such as git checkout. Signed-off-by: Jacob Abel --- Documentation/git-worktree.txt | 2 +- builtin/worktree.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) -- 2.38.2 diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt index 063d6eeb99..4dd658012b 100644 --- a/Documentation/git-worktree.txt +++ b/Documentation/git-worktree.txt @@ -10,7 +10,7 @@ SYNOPSIS -------- [verse] 'git worktree add' [-f] [--detach] [--checkout] [--lock [--reason ]] - [-b ] [] + [[-b | -B] ] [] 'git worktree list' [-v | --porcelain [-z]] 'git worktree lock' [--reason ] 'git worktree move' diff --git a/builtin/worktree.c b/builtin/worktree.c index 4a24d53be1..fccb17f070 100644 --- a/builtin/worktree.c +++ b/builtin/worktree.c @@ -17,7 +17,7 @@ #define BUILTIN_WORKTREE_ADD_USAGE \ N_("git worktree add [-f] [--detach] [--checkout] [--lock [--reason ]]\n" \ - " [-b ] []") + " [[-b | -B] ] []") #define BUILTIN_WORKTREE_LIST_USAGE \ N_("git worktree list [-v | --porcelain [-z]]") #define BUILTIN_WORKTREE_LOCK_USAGE \ From patchwork Tue Dec 20 02:37:43 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacob Abel X-Patchwork-Id: 13077409 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 92153C001B2 for ; Tue, 20 Dec 2022 02:37:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232786AbiLTCh5 (ORCPT ); Mon, 19 Dec 2022 21:37:57 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34882 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229540AbiLTChz (ORCPT ); Mon, 19 Dec 2022 21:37:55 -0500 Received: from mail-4022.proton.ch (mail-4022.proton.ch [185.70.40.22]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 7A18011A10 for ; Mon, 19 Dec 2022 18:37:54 -0800 (PST) Date: Tue, 20 Dec 2022 02:37:43 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nullpo.dev; s=protonmail3; t=1671503872; x=1671763072; bh=faU8kScBoqh216ooqGRwQ5SXWm5kL5qnmX3EdUQPbFw=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: Feedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID: Message-ID:BIMI-Selector; b=r2tgELHegQu/atiet1N4l93BO9sG2ncHZ9CsNcizR8IvXnDu0i0yxV8ryn4t4oYBO gCt1wqdSV+8YFIBu7UgxOg/QspxWAlblk1TydQRQIAq1LS72Omr4WYoJWg+vpogQeC lnmiRPU4Gkffi0U+YE7CQytwyq2RjCTrhcOX6R92ScnoeDH4h57CnYpCyW86Ik2ago K+mWCn2JxNTiA1DEOU5a6PQmIR7AGIdDh4UGj/dK0ZhkySXblWLm1f1m+Dc45ZOqaU xsLlh1l/0ibz9cRrwaDEwtA0xVJrk208dzNYvHaRLhagkQusf6CpZboi6oCbyRz0+A Qcha78p28/EWA== To: git@vger.kernel.org From: Jacob Abel Cc: Jacob Abel , =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsCBC?= =?utf-8?b?amFybWFzb24=?= , Eric Sunshine , Phillip Wood , =?utf-8?q?Rub=C3=A9n_Justo?= , Taylor Blau , rsbecker@nexbridge.com Subject: [PATCH v5 2/4] worktree add: refactor opt exclusion tests Message-ID: <20221220023637.29042-3-jacobabel@nullpo.dev> In-Reply-To: <20221220023637.29042-1-jacobabel@nullpo.dev> References: <20221104010242.11555-1-jacobabel@nullpo.dev> <20221104213401.17393-1-jacobabel@nullpo.dev> <20221110233137.10414-1-jacobabel@nullpo.dev> <20221212014003.20290-1-jacobabel@nullpo.dev> <20221220023637.29042-1-jacobabel@nullpo.dev> Feedback-ID: 21506737:user:proton MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org Pull duplicate test code into a function so that additional opt combinations can be tested succinctly. Signed-off-by: Jacob Abel --- t/t2400-worktree-add.sh | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) -- 2.38.2 diff --git a/t/t2400-worktree-add.sh b/t/t2400-worktree-add.sh index d587e0b20d..f05e2483c2 100755 --- a/t/t2400-worktree-add.sh +++ b/t/t2400-worktree-add.sh @@ -298,17 +298,17 @@ test_expect_success '"add" no auto-vivify with --detach and omitted' ' test_must_fail git -C mish/mash symbolic-ref HEAD ' -test_expect_success '"add" -b/-B mutually exclusive' ' - test_must_fail git worktree add -b poodle -B poodle bamboo main -' - -test_expect_success '"add" -b/--detach mutually exclusive' ' - test_must_fail git worktree add -b poodle --detach bamboo main -' +# Helper function to test mutually exclusive options. +test_wt_add_excl() { + local opts="$@" && + test_expect_success "'worktree add' with '$opts' has mutually exclusive options" ' + test_must_fail git worktree add $opts + ' +} -test_expect_success '"add" -B/--detach mutually exclusive' ' - test_must_fail git worktree add -B poodle --detach bamboo main -' +test_wt_add_excl -b poodle -B poodle bamboo main +test_wt_add_excl -b poodle --detach bamboo main +test_wt_add_excl -B poodle --detach bamboo main test_expect_success '"add -B" fails if the branch is checked out' ' git rev-parse newmain >before && From patchwork Tue Dec 20 02:38:02 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Jacob Abel X-Patchwork-Id: 13077410 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id F1110C4332F for ; Tue, 20 Dec 2022 02:38:13 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232796AbiLTCiN (ORCPT ); Mon, 19 Dec 2022 21:38:13 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34954 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232432AbiLTCiL (ORCPT ); Mon, 19 Dec 2022 21:38:11 -0500 Received: from mail-4323.proton.ch (mail-4323.proton.ch [185.70.43.23]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 59A2A11A17 for ; Mon, 19 Dec 2022 18:38:10 -0800 (PST) Date: Tue, 20 Dec 2022 02:38:02 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nullpo.dev; s=protonmail3; t=1671503888; x=1671763088; bh=YQGpWb0HUyI14DxKglsWqpYkqI4UlqMb3uD60B70s5M=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: Feedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID: Message-ID:BIMI-Selector; b=upqgjy/KWDJAqj3KgKBrIsG1QqEApJ4vTMmE8ab86EJWgivPq30WJiGNKSL5qUTmV H2ic1c81hBHQB2EVa1FOhNjfJ0nOJb1ezUK4sZUD0+dnSPyxo0fNXHoPHsp14r6uRC NMYD/UYCulQC7lsal3b6z8i+eV+RpfwHiQhXtNsQqGotMxnp2xh6BocpHTPEfK/NLb uLto/QcGJj9c10CwBtC0S3VEOeOdgMXRaWUoKgpnjQQUYLMMjlU7yJUO1FrHwUn2pk W/H8VHAKY5r9oj3Td/JJeFZILxNA+pn4a8TW4w3No6S5Ahy0gGZYEDrqMpOGy/A+W5 jvKMrBq6C97XA== To: git@vger.kernel.org From: Jacob Abel Cc: Jacob Abel , =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsCBC?= =?utf-8?b?amFybWFzb24=?= , Eric Sunshine , Phillip Wood , =?utf-8?q?Rub=C3=A9n_Justo?= , Taylor Blau , rsbecker@nexbridge.com Subject: [PATCH v5 3/4] worktree add: add --orphan flag Message-ID: <20221220023637.29042-4-jacobabel@nullpo.dev> In-Reply-To: <20221220023637.29042-1-jacobabel@nullpo.dev> References: <20221104010242.11555-1-jacobabel@nullpo.dev> <20221104213401.17393-1-jacobabel@nullpo.dev> <20221110233137.10414-1-jacobabel@nullpo.dev> <20221212014003.20290-1-jacobabel@nullpo.dev> <20221220023637.29042-1-jacobabel@nullpo.dev> Feedback-ID: 21506737:user:proton MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org Adds support for creating an orphan branch when adding a new worktree. This functionality is equivalent to git switch's --orphan flag. The original reason this feature was implemented was to allow a user to initialise a new repository using solely the worktree oriented workflow. Current Behavior: % git init --bare foo.git Initialized empty Git repository in /path/to/foo.git/ % git -C foo.git worktree add main/ Preparing worktree (new branch 'main') fatal: not a valid object name: 'HEAD' % New Behavior: % git init --bare foo.git Initialized empty Git repository in /path/to/foo.git/ % git -C foo.git worktree add --orphan main main/ Preparing worktree (new branch 'main') % Signed-off-by: Jacob Abel Signed-off-by: Ævar Arnfjörð Bjarmason --- Documentation/git-worktree.txt | 15 +++++++++ builtin/worktree.c | 59 ++++++++++++++++++++++++++++++---- t/t2400-worktree-add.sh | 53 ++++++++++++++++++++++++++++++ 3 files changed, 120 insertions(+), 7 deletions(-) -- 2.38.2 diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt index 4dd658012b..c6e6899d8b 100644 --- a/Documentation/git-worktree.txt +++ b/Documentation/git-worktree.txt @@ -11,6 +11,8 @@ SYNOPSIS [verse] 'git worktree add' [-f] [--detach] [--checkout] [--lock [--reason ]] [[-b | -B] ] [] +'git worktree add' [-f] [--lock [--reason ]] + --orphan 'git worktree list' [-v | --porcelain [-z]] 'git worktree lock' [--reason ] 'git worktree move' @@ -95,6 +97,15 @@ exist, a new branch based on `HEAD` is automatically created as if `-b ` was given. If `` does exist, it will be checked out in the new worktree, if it's not checked out anywhere else, otherwise the command will refuse to create the worktree (unless `--force` is used). ++ +------------ +$ git worktree add --orphan +------------ ++ +Create a worktree containing no files, with an empty index, and associated +with a new orphan branch named ``. The first commit made on this new +branch will have no parents and will be the root of a new history disconnected +from any other branches. list:: @@ -222,6 +233,10 @@ This can also be set up as the default behaviour by using the With `prune`, do not remove anything; just report what it would remove. +--orphan :: + With `add`, make the new worktree and index empty, associating + the worktree with a new orphan branch named ``. + --porcelain:: With `list`, output in an easy-to-parse format for scripts. This format will remain stable across Git versions and regardless of user diff --git a/builtin/worktree.c b/builtin/worktree.c index fccb17f070..194c3ccabf 100644 --- a/builtin/worktree.c +++ b/builtin/worktree.c @@ -17,7 +17,10 @@ #define BUILTIN_WORKTREE_ADD_USAGE \ N_("git worktree add [-f] [--detach] [--checkout] [--lock [--reason ]]\n" \ - " [[-b | -B] ] []") + " [[-b | -B] ] []"), \ + N_("git worktree add [-f] [--lock [--reason ]]\n" \ + " --orphan ") + #define BUILTIN_WORKTREE_LIST_USAGE \ N_("git worktree list [-v | --porcelain [-z]]") #define BUILTIN_WORKTREE_LOCK_USAGE \ @@ -90,6 +93,7 @@ struct add_opts { int detach; int quiet; int checkout; + int orphan; const char *keep_locked; }; @@ -364,6 +368,22 @@ static int checkout_worktree(const struct add_opts *opts, return run_command(&cp); } +static int make_worktree_orphan(const char * ref, const struct add_opts *opts, + struct strvec *child_env) +{ + struct strbuf symref = STRBUF_INIT; + struct child_process cp = CHILD_PROCESS_INIT; + + validate_new_branchname(ref, &symref, 0); + strvec_pushl(&cp.args, "symbolic-ref", "HEAD", symref.buf, NULL); + if (opts->quiet) + strvec_push(&cp.args, "--quiet"); + strvec_pushv(&cp.env, child_env->v); + strbuf_release(&symref); + cp.git_cmd = 1; + return run_command(&cp); +} + static int add_worktree(const char *path, const char *refname, const struct add_opts *opts) { @@ -393,7 +413,7 @@ 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 (!commit && !opts->orphan) die(_("invalid reference: %s"), refname); name = worktree_basename(path, &len); @@ -482,10 +502,10 @@ 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 (!is_branch && commit) { strvec_pushl(&cp.args, "update-ref", "HEAD", oid_to_hex(&commit->object.oid), NULL); - else { + } else { strvec_pushl(&cp.args, "symbolic-ref", "HEAD", symref.buf, NULL); if (opts->quiet) @@ -497,6 +517,10 @@ static int add_worktree(const char *path, const char *refname, if (ret) goto done; + if (opts->orphan && + (ret = make_worktree_orphan(refname, opts, &child_env))) + goto done; + if (opts->checkout && (ret = checkout_worktree(opts, &child_env))) goto done; @@ -516,7 +540,7 @@ static int add_worktree(const char *path, const char *refname, * Hook failure does not warrant worktree deletion, so run hook after * is_junk is cleared, but do return appropriate code when hook fails. */ - if (!ret && opts->checkout) { + if (!ret && opts->checkout && !opts->orphan) { struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT; strvec_pushl(&opt.env, "GIT_DIR", "GIT_WORK_TREE", NULL); @@ -605,6 +629,7 @@ static int add(int ac, const char **av, const char *prefix) char *path; const char *branch; const char *new_branch = NULL; + const char *orphan_branch = NULL; const char *opt_track = NULL; const char *lock_reason = NULL; int keep_locked = 0; @@ -616,6 +641,8 @@ static int add(int ac, const char **av, const char *prefix) N_("create a new branch")), OPT_STRING('B', NULL, &new_branch_force, N_("branch"), N_("create or reset a branch")), + OPT_STRING(0, "orphan", &orphan_branch, N_("branch"), + N_("new unparented branch")), 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", &keep_locked, N_("keep the new working tree locked")), @@ -633,8 +660,20 @@ static int add(int ac, const char **av, const char *prefix) memset(&opts, 0, sizeof(opts)); opts.checkout = 1; ac = parse_options(ac, av, prefix, options, git_worktree_add_usage, 0); + opts.orphan = !!orphan_branch; if (!!opts.detach + !!new_branch + !!new_branch_force > 1) die(_("options '%s', '%s', and '%s' cannot be used together"), "-b", "-B", "--detach"); + if (!!opts.detach + !!opts.orphan + !!new_branch + !!new_branch_force > 1) + die(_("options '%s', '%s', '%s', and '%s' cannot be used together"), + "-b", "-B", "--orphan", "--detach"); + if (opts.orphan && opt_track) + die(_("'%s' and '%s' cannot be used together"), "--orphan", "--track"); + if (opts.orphan && !opts.checkout) + die(_("'%s' and '%s' cannot be used together"), "--orphan", + "--no-checkout"); + if (opts.orphan && ac == 2) + die(_("'%s' and '%s' cannot be used together"), "--orphan", + _("")); if (lock_reason && !keep_locked) die(_("the option '%s' requires '%s'"), "--reason", "--lock"); if (lock_reason) @@ -663,7 +702,9 @@ static int add(int ac, const char **av, const char *prefix) strbuf_release(&symref); } - if (ac < 2 && !new_branch && !opts.detach) { + if (opts.orphan) { + new_branch = orphan_branch; + } else if (ac < 2 && !new_branch && !opts.detach) { const char *s = dwim_branch(path, &new_branch); if (s) branch = s; @@ -686,7 +727,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); - if (new_branch) { + if (opts.orphan) { + branch = new_branch; + } else if (!lookup_commit_reference_by_name(branch)) { + die(_("invalid reference: %s"), branch); + } else if (new_branch) { struct child_process cp = CHILD_PROCESS_INIT; cp.git_cmd = 1; strvec_push(&cp.args, "branch"); diff --git a/t/t2400-worktree-add.sh b/t/t2400-worktree-add.sh index f05e2483c2..73ad26651e 100755 --- a/t/t2400-worktree-add.sh +++ b/t/t2400-worktree-add.sh @@ -309,6 +309,11 @@ test_wt_add_excl() { test_wt_add_excl -b poodle -B poodle bamboo main test_wt_add_excl -b poodle --detach bamboo main test_wt_add_excl -B poodle --detach bamboo main +test_wt_add_excl -B poodle --orphan poodle bamboo +test_wt_add_excl -b poodle --orphan poodle bamboo +test_wt_add_excl --orphan poodle --detach bamboo +test_wt_add_excl --orphan poodle --no-checkout bamboo +test_wt_add_excl --orphan poodle bamboo main test_expect_success '"add -B" fails if the branch is checked out' ' git rev-parse newmain >before && @@ -330,6 +335,46 @@ test_expect_success 'add --quiet' ' test_must_be_empty actual ' +test_expect_success '"add --orphan"' ' + test_when_finished "git worktree remove -f -f orphandir" && + git worktree add --orphan neworphan orphandir && + echo refs/heads/neworphan >expected && + git -C orphandir symbolic-ref HEAD >actual && + test_cmp expected actual +' + +test_expect_success '"add --orphan" fails if the branch already exists' ' + test_when_finished "git branch -D existingbranch" && + test_when_finished "git worktree remove -f -f orphandir" && + git worktree add -b existingbranch orphandir main && + test_must_fail git worktree add --orphan existingbranch orphandir2 && + test_path_is_missing orphandir2 +' + +test_expect_success '"add --orphan" with empty repository' ' + 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 newbranch worktreedir && + git -C empty_repo/worktreedir symbolic-ref HEAD >actual && + test_cmp expected actual +' + +test_expect_success '"add" worktree with orphan branch and lock' ' + git worktree add --lock --orphan orphanbr orphan-with-lock && + test_when_finished "git worktree unlock orphan-with-lock || :" && + test -f .git/worktrees/orphan-with-lock/locked +' + +test_expect_success '"add" worktree with orphan branch, lock, and reason' ' + lock_reason="why not" && + git worktree add --detach --lock --reason "$lock_reason" orphan-with-lock-reason main && + test_when_finished "git worktree unlock orphan-with-lock-reason || :" && + test -f .git/worktrees/orphan-with-lock-reason/locked && + echo "$lock_reason" >expect && + test_cmp expect .git/worktrees/orphan-with-lock-reason/locked +' + test_expect_success 'local clone from linked checkout' ' git clone --local here here-clone && ( cd here-clone && git fsck ) @@ -446,6 +491,14 @@ setup_remote_repo () { ) } +test_expect_success '"add" w/ no HEAD' ' + test_when_finished rm -rf repo_upstream repo_local foo && + setup_remote_repo repo_upstream repo_local && + git -C repo_local config --bool core.bare true && + git -C repo_local branch -D main && + git -C repo_local worktree add ./foo repo_upstream/foo +' + test_expect_success '--no-track avoids setting up tracking' ' test_when_finished rm -rf repo_upstream repo_local foo && setup_remote_repo repo_upstream repo_local && From patchwork Tue Dec 20 02:38:20 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacob Abel X-Patchwork-Id: 13077411 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 558F0C4332F for ; Tue, 20 Dec 2022 02:38:33 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232801AbiLTCic (ORCPT ); Mon, 19 Dec 2022 21:38:32 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35088 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232802AbiLTCia (ORCPT ); Mon, 19 Dec 2022 21:38:30 -0500 Received: from mail-4317.proton.ch (mail-4317.proton.ch [185.70.43.17]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 532DB11C04 for ; Mon, 19 Dec 2022 18:38:29 -0800 (PST) Date: Tue, 20 Dec 2022 02:38:20 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nullpo.dev; s=protonmail3; t=1671503907; x=1671763107; bh=agsApGEdvZ/sbPT9zs4G25gZiWR215kBggCWoBL+w5o=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: Feedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID: Message-ID:BIMI-Selector; b=H/f84RS+0x9860xR+RjPAfA48KDX3YJD6TRCzPs4DExsH8lrZLyNdLQ/tPiebOsnH AfoveZKgJ/YAKrpdm1e3jRhd/5GhenTbVwWzDRdwPfMNAORNYX7wJLMAGxsyrH7BfM BPw6iDG3R5Aje5WyCJXxmSnMJZFDniogeanTKdk1vf4j47Lf5YIiME4bE0a9e2/+ac EgZ3r6gn8kc9xQhT/C6GQEz/ubGchb3Sp5Ta/mtQSJlhQHroM+fcNcMW9TrxQ0K3HA N6BRtVmZPzqS5uw++oZuei8s2K2xYx/5cVcc+3p009vtFKItEwzduV4HMbnSslr3PL CGgIwEKbxx42g== To: git@vger.kernel.org From: Jacob Abel Cc: Jacob Abel , =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsCBC?= =?utf-8?b?amFybWFzb24=?= , Eric Sunshine , Phillip Wood , =?utf-8?q?Rub=C3=A9n_Justo?= , Taylor Blau , rsbecker@nexbridge.com Subject: [PATCH v5 4/4] worktree add: Add hint to use --orphan when bad ref Message-ID: <20221220023637.29042-5-jacobabel@nullpo.dev> In-Reply-To: <20221220023637.29042-1-jacobabel@nullpo.dev> References: <20221104010242.11555-1-jacobabel@nullpo.dev> <20221104213401.17393-1-jacobabel@nullpo.dev> <20221110233137.10414-1-jacobabel@nullpo.dev> <20221212014003.20290-1-jacobabel@nullpo.dev> <20221220023637.29042-1-jacobabel@nullpo.dev> Feedback-ID: 21506737:user:proton MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org Adds a new advice/hint in `git worktree add` for when the user tries to create a new worktree from a reference that doesn't exist. Signed-off-by: Jacob Abel --- Documentation/config/advice.txt | 4 ++++ advice.c | 1 + advice.h | 1 + builtin/worktree.c | 6 ++++++ t/t2400-worktree-add.sh | 16 ++++++++++++++++ 5 files changed, 28 insertions(+) -- 2.38.2 diff --git a/Documentation/config/advice.txt b/Documentation/config/advice.txt index a00d0100a8..3e58521613 100644 --- a/Documentation/config/advice.txt +++ b/Documentation/config/advice.txt @@ -136,4 +136,8 @@ advice.*:: Advice shown when either linkgit:git-add[1] or linkgit:git-rm[1] is asked to update index entries outside the current sparse checkout. + worktreeAddOrphan:: + Advice shown when a user tries to create a worktree from an + invalid reference, to instruct how to create a new orphan + branch instead. -- diff --git a/advice.c b/advice.c index fd18968943..53e91fdb85 100644 --- a/advice.c +++ b/advice.c @@ -75,6 +75,7 @@ static struct { [ADVICE_SUBMODULES_NOT_UPDATED] = { "submodulesNotUpdated", 1 }, [ADVICE_UPDATE_SPARSE_PATH] = { "updateSparsePath", 1 }, [ADVICE_WAITING_FOR_EDITOR] = { "waitingForEditor", 1 }, + [ADVICE_WORKTREE_ADD_ORPHAN] = { "worktreeAddOrphan", 1 }, }; static const char turn_off_instructions[] = diff --git a/advice.h b/advice.h index 07e0f76833..919d8c0064 100644 --- a/advice.h +++ b/advice.h @@ -50,6 +50,7 @@ struct string_list; ADVICE_UPDATE_SPARSE_PATH, ADVICE_WAITING_FOR_EDITOR, ADVICE_SKIPPED_CHERRY_PICKS, + ADVICE_WORKTREE_ADD_ORPHAN, }; int git_default_advice_config(const char *var, const char *value); diff --git a/builtin/worktree.c b/builtin/worktree.c index 194c3ccabf..1f44978616 100644 --- a/builtin/worktree.c +++ b/builtin/worktree.c @@ -730,6 +730,12 @@ static int add(int ac, const char **av, const char *prefix) if (opts.orphan) { branch = new_branch; } else if (!lookup_commit_reference_by_name(branch)) { + advise_if_enabled(ADVICE_WORKTREE_ADD_ORPHAN, + _("If you meant to create a worktree containing a new orphan branch\n" + "(branch with no commits) for this repository, you can do so\n" + "using the --orphan option:\n" + "\n" + " git worktree add --orphan %s %s\n"), new_branch, path); die(_("invalid reference: %s"), branch); } else if (new_branch) { struct child_process cp = CHILD_PROCESS_INIT; diff --git a/t/t2400-worktree-add.sh b/t/t2400-worktree-add.sh index 73ad26651e..05539aa03c 100755 --- a/t/t2400-worktree-add.sh +++ b/t/t2400-worktree-add.sh @@ -375,6 +375,22 @@ test_expect_success '"add" worktree with orphan branch, lock, and reason' ' test_cmp expect .git/worktrees/orphan-with-lock-reason/locked ' +test_wt_add_empty_repo_orphan_hint() { + local context="$1" + shift + local opts="$@" + test_expect_success "'worktree add' show orphan hint in empty repo w/ $context" ' + test_when_finished "rm -rf empty_repo" && + GIT_DIR="empty_repo" git init --bare && + test_must_fail git -C empty_repo worktree add $opts foobar/ 2> actual && + grep "hint: If you meant to create a worktree containing a new orphan branch" actual + ' +} + +test_wt_add_empty_repo_orphan_hint 'DWIM' +test_wt_add_empty_repo_orphan_hint '-b' -b foobar_branch +test_wt_add_empty_repo_orphan_hint '-B' -B foobar_branch + test_expect_success 'local clone from linked checkout' ' git clone --local here here-clone && ( cd here-clone && git fsck )