receive-pack: protect current branch for bare repository worktree

A bare repository won’t have a working tree at "..", but it may still have separate working trees created with git worktree. We should protect the current branch of such working trees from being updated or deleted, according to receive.denyCurrentBranch. Signed-off-by: Anders Kaseorg <andersk@mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Anders Kaseorg committed Dec 1, 2021 at 14:15 UTC 9fdf4f1db422cc259e4a3ce0023a255102c6fa3b
2 files changed +17 -5
builtin/receive-pack.c
+3 -5
@@ -1455,7 +1455,7 @@ static const char *update_worktree(unsigned char *sha1, const struct worktree *w
1455 if (!worktree || !worktree->path)
1456 BUG("worktree->path must be non-NULL");
1457
1458 - if (is_bare_repository())
1458 + if (worktree->is_bare)
1459 return "denyCurrentBranch = updateInstead needs a worktree";
1460 git_dir = get_worktree_git_dir(worktree);
1461
@@ -1481,9 +1481,7 @@ static const char *update(struct command *cmd, struct shallow_info *si)
1481 int do_update_worktree = 0;
1482 struct worktree **worktrees = get_worktrees();
1483 const struct worktree *worktree =
1484 - is_bare_repository() ?
1485 - NULL :
1486 - find_shared_symref(worktrees, "HEAD", name);
1484 + find_shared_symref(worktrees, "HEAD", name);
1485
1486 /* only refs/... are allowed */
1487 if (!starts_with(name, "refs/") || check_refname_format(name + 5, 0)) {
@@ -1496,7 +1494,7 @@ static const char *update(struct command *cmd, struct shallow_info *si)
1494 free(namespaced_name);
1495 namespaced_name = strbuf_detach(&namespaced_name_buf, NULL);
1496
1499 - if (worktree) {
1497 + if (worktree && !worktree->is_bare) {
1498 switch (deny_current_branch) {
1499 case DENY_IGNORE:
1500 break;
t/t5516-fetch-push.sh
+14
@@ -1769,9 +1769,23 @@ test_expect_success 'denyCurrentBranch and worktrees' '
1769 test_must_fail git -C cloned push origin HEAD:new-wt &&
1770 test_config receive.denyCurrentBranch updateInstead &&
1771 git -C cloned push origin HEAD:new-wt &&
1772 + test_path_exists new-wt/first.t &&
1773 test_must_fail git -C cloned push --delete origin new-wt
1774 '
1775
1776 +test_expect_success 'denyCurrentBranch and bare repository worktrees' '
1777 + test_when_finished "rm -fr bare.git" &&
1778 + git clone --bare . bare.git &&
1779 + git -C bare.git worktree add wt &&
1780 + test_commit grape &&
1781 + git -C bare.git config receive.denyCurrentBranch refuse &&
1782 + test_must_fail git push bare.git HEAD:wt &&
1783 + git -C bare.git config receive.denyCurrentBranch updateInstead &&
1784 + git push bare.git HEAD:wt &&
1785 + test_path_exists bare.git/wt/grape.t &&
1786 + test_must_fail git push --delete bare.git wt
1787 +'
1788 +
1789 test_expect_success 'refuse fetch to current branch of worktree' '
1790 test_when_finished "git worktree remove --force wt && git branch -D wt" &&
1791 git worktree add wt &&