Skip to content

Commit 926c40d

Browse files
OneDeuxTriSeiGogitster
authored andcommitted
worktree add: emit warn when there is a bad HEAD
Add a warning to `worktree add` when the command tries to reference HEAD, there exist valid local branches, and the HEAD points to a non-existent reference. Current Behavior: % git -C foo worktree list /path/to/repo/foo dadc8e6 [main] /path/to/repo/foo_wt 0000000000 [badref] % git -C foo worktree add ../wt1 Preparing worktree (new branch 'wt1') HEAD is now at dadc8e6 dummy commit % git -C foo_wt worktree add ../wt2 hint: If you meant to create a worktree containing a new orphan branch [...] hint: Disable this message with "git config advice.worktreeAddOrphan false" fatal: invalid reference: HEAD % New Behavior: % git -C foo worktree list /path/to/repo/foo dadc8e6 [main] /path/to/repo/foo_wt 0000000000 [badref] % git -C foo worktree add ../wt1 Preparing worktree (new branch 'wt1') HEAD is now at dadc8e6 dummy commit % git -C foo_wt worktree add ../wt2 warning: HEAD points to an invalid (or orphaned) reference. HEAD path: '/path/to/repo/foo/.git/worktrees/foo_wt/HEAD' HEAD contents: 'ref: refs/heads/badref' hint: If you meant to create a worktree containing a new orphan branch [...] hint: Disable this message with "git config advice.worktreeAddOrphan false" fatal: invalid reference: HEAD % Signed-off-by: Jacob Abel <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 128e549 commit 926c40d

File tree

2 files changed

+46
-6
lines changed

2 files changed

+46
-6
lines changed

builtin/worktree.c

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -638,13 +638,33 @@ static int first_valid_ref(const char *refname,
638638
*
639639
* - Checks whether any valid local branches exist.
640640
*
641+
* - Emits a warning if there exist any valid branches but HEAD does not point
642+
* to a valid reference.
643+
*
641644
* Returns 1 if any of the previous checks are true, otherwise returns 0.
642645
*/
643646
static int can_use_local_refs(const struct add_opts *opts)
644647
{
645648
if (head_ref(first_valid_ref, NULL)) {
646649
return 1;
647650
} else if (for_each_branch_ref(first_valid_ref, NULL)) {
651+
if (!opts->quiet) {
652+
struct strbuf path = STRBUF_INIT;
653+
struct strbuf contents = STRBUF_INIT;
654+
655+
strbuf_add_real_path(&path, get_worktree_git_dir(NULL));
656+
strbuf_addstr(&path, "/HEAD");
657+
strbuf_read_file(&contents, path.buf, 64);
658+
strbuf_stripspace(&contents, 0);
659+
strbuf_strip_suffix(&contents, "\n");
660+
661+
warning(_("HEAD points to an invalid (or orphaned) reference.\n"
662+
"HEAD path: '%s'\n"
663+
"HEAD contents: '%s'"),
664+
path.buf, contents.buf);
665+
strbuf_release(&path);
666+
strbuf_release(&contents);
667+
}
648668
return 1;
649669
}
650670
return 0;
@@ -666,16 +686,12 @@ static int can_use_local_refs(const struct add_opts *opts)
666686
static int can_use_remote_refs(const struct add_opts *opts)
667687
{
668688
if (!guess_remote) {
669-
if (!opts->quiet)
670-
fprintf_ln(stderr, WORKTREE_ADD_DWIM_ORPHAN_INFER_TEXT);
671689
return 0;
672690
} else if (for_each_remote_ref(first_valid_ref, NULL)) {
673691
return 1;
674692
} else if (!opts->force && remote_get(NULL)) {
675693
die(_("No local or remote refs exist despite at least one remote\n"
676694
"present, stopping; use 'add -f' to overide or fetch a remote first"));
677-
} else if (!opts->quiet) {
678-
fprintf_ln(stderr, WORKTREE_ADD_DWIM_ORPHAN_INFER_TEXT);
679695
}
680696
return 0;
681697
}
@@ -828,8 +844,12 @@ static int add(int ac, const char **av, const char *prefix)
828844
int n;
829845
const char *s = worktree_basename(path, &n);
830846
new_branch = xstrndup(s, n);
831-
} else if (opts.orphan || opts.detach) {
847+
} else if (opts.orphan) {
832848
// No-op
849+
} else if (opts.detach) {
850+
// Check HEAD
851+
if (!strcmp(branch, "HEAD"))
852+
can_use_local_refs(&opts);
833853
} else if (ac < 2 && new_branch) {
834854
// DWIM: Infer --orphan when repo has no refs.
835855
opts.orphan = dwim_orphan(&opts, !!opt_track, 0);
@@ -854,6 +874,10 @@ static int add(int ac, const char **av, const char *prefix)
854874
branch = remote;
855875
}
856876
}
877+
878+
if (!strcmp(branch, "HEAD"))
879+
can_use_local_refs(&opts);
880+
857881
}
858882

859883
if (!opts.orphan && !lookup_commit_reference_by_name(branch)) {

t/t2400-worktree-add.sh

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -722,6 +722,7 @@ test_dwim_orphan () {
722722
local use_quiet=0 &&
723723
local remote=0 &&
724724
local remote_ref=0 &&
725+
local use_detach=0 &&
725726
local use_new_branch=0 &&
726727

727728
local outcome="$1" &&
@@ -747,6 +748,10 @@ test_dwim_orphan () {
747748
success=0 &&
748749
outcome_text='"add" error inferred "--orphan" gives illegal opts combo'
749750
;;
751+
"warn_bad_head")
752+
success=0 &&
753+
outcome_text='"add" error, warn on bad HEAD, hint use orphan'
754+
;;
750755
*)
751756
echo "test_dwim_orphan(): invalid outcome: '$outcome'" >&2 &&
752757
return 1
@@ -818,7 +823,7 @@ test_dwim_orphan () {
818823
context="$context, invalid (or orphan) HEAD"
819824
;;
820825

821-
# Whether the code path is tested with the base add command or -b
826+
# Whether the code path is tested with the base add command, -b, or --detach
822827
"no_-b")
823828
use_new_branch=0 &&
824829
context="$context, no --branch"
@@ -827,6 +832,10 @@ test_dwim_orphan () {
827832
use_new_branch=1 &&
828833
context="$context, --branch"
829834
;;
835+
"detach")
836+
use_detach=1 &&
837+
context="$context, --detach"
838+
;;
830839

831840
# Whether to check that all output is suppressed (except errors)
832841
# or that the output is as expected
@@ -887,6 +896,9 @@ test_dwim_orphan () {
887896
if [ $use_new_branch -eq 1 ]
888897
then
889898
args="$args -b foo"
899+
elif [ $use_detach -eq 1 ]
900+
then
901+
args="$args --detach"
890902
else
891903
context="DWIM (no --branch), $context"
892904
fi &&
@@ -1023,6 +1035,10 @@ do
10231035
test_dwim_orphan 'infer' $dwim_test_args -b no_local_ref remote no_remote_ref no_guess_remote
10241036
test_dwim_orphan 'infer' $dwim_test_args -b no_local_ref remote no_remote_ref guess_remote
10251037
test_dwim_orphan 'infer' $dwim_test_args -b no_local_ref remote remote_ref guess_remote
1038+
1039+
test_dwim_orphan 'warn_bad_head' $dwim_test_args no_-b local_ref bad_head
1040+
test_dwim_orphan 'warn_bad_head' $dwim_test_args -b local_ref bad_head
1041+
test_dwim_orphan 'warn_bad_head' $dwim_test_args detach local_ref bad_head
10261042
done
10271043

10281044
test_dwim_orphan 'fatal_orphan_bad_combo' $quiet_mode no_-b no_checkout

0 commit comments

Comments
 (0)