>From 9f9b9010cb0b8c2874428d2f4bd21f06f747bfee Mon Sep 17 00:00:00 2001 From: Kenneth Cochran <kenneth.cochran101@xxxxxxxxx> Date: Sun, 3 Mar 2019 15:34:20 -0600 Subject: [RFC PATCH 3/4] worktree: symref should be found anywhere in chain Cc: Sahil Dua <sahildua2305@xxxxxxxxx>, Duy Nguyen <pclouds@xxxxxxxxx>, Jeff King <peff@xxxxxxxx> Currently, when searching for a shared symref, a symref chain is fully dereferenced before checking the name. This poses problems for `git branch -d` which will happily delete a checked out symref. The existing behaviour (recognizing a non-symbolic ref by the same name) still exists, but it will now also find any symref that is in between the starting symref and the first non-symbolic ref. Concretely, for the following chain HEAD -> symref1 -> symref2 -> master previously the function was only able to find master. With these changes applied, it will be able to find any of the above references. Signed-off-by: Kenneth Cochran <kenneth.cochran101@xxxxxxxxx> --- t/t3207-branch-alias.sh | 13 +++++++++++++ worktree.c | 18 ++++++++++++------ 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/t/t3207-branch-alias.sh b/t/t3207-branch-alias.sh index 9d4c8c2914..c1edeed4eb 100755 --- a/t/t3207-branch-alias.sh +++ b/t/t3207-branch-alias.sh @@ -55,4 +55,17 @@ test_expect_success 'git branch --alias refuses to overwrite existing symref' ' test_must_fail git branch --alias syme ' +test_expect_success 'git branch -d refuses to delete a checked out symref' ' + git branch --alias symd && + git checkout symd && + test_must_fail git branch -d symd +' + +test_expect_success 'git branch -d refuses to delete an indirectly checked out symref' ' + git symbolic-ref refs/heads/symd2 refs/heads/symd && + git checkout symd2 && + test_must_fail git branch -d symd2 && + test_must_fail git branch -d symd +' + test_done diff --git a/worktree.c b/worktree.c index d6a0ee7f73..b58325c6c1 100644 --- a/worktree.c +++ b/worktree.c @@ -387,6 +387,17 @@ int is_worktree_being_bisected(const struct worktree *wt, return found_rebase; } +static int find_symref_by_name(const char *ref_name, const struct object_id *oid, + int flags, void *cb_data) +{ + const char *target = (const char *)cb_data; + + if ((flags & REF_ISSYMREF) && !strcmp(target, ref_name)) + return 1; + else + return 0; +} + /* * note: this function should be able to detect shared symref even if * HEAD is temporarily detached (e.g. in the middle of rebase or @@ -406,9 +417,7 @@ const struct worktree *find_shared_symref(const char *symref, for (i = 0; worktrees[i]; i++) { struct worktree *wt = worktrees[i]; - const char *symref_target; struct ref_store *refs; - int flags; if (wt->is_bare) continue; @@ -425,10 +434,7 @@ const struct worktree *find_shared_symref(const char *symref, } refs = get_worktree_ref_store(wt); - symref_target = refs_resolve_ref_unsafe(refs, symref, 0, - NULL, &flags); - if ((flags & REF_ISSYMREF) && - symref_target && !strcmp(symref_target, target)) { + if(refs_for_each_ref_in_chain(refs, find_symref_by_name, (void *)target, symref)) { existing = wt; break; } -- 2.17.1