receive-pack: use worktree HEAD for updateInstead

When a bare repo has linked worktrees, and its HEAD points to an unborn branch, pushing to a wt branch with updateInstead fails and rejects the push, even if the wt is clean. This happens because HEAD is checked only for the bare repo context, instead of the wt. Remove head_has_history and check for worktree->head_oid which does have the correct HEAD of the wt. Update the test added by Runxi's patch to expect success. Signed-off-by: Pablo Sabater <pabloosabaterr@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Pablo Sabater committed Mar 30, 2026 at 13:18 UTC 8151f4fe7e4bf36f2656ae849a4ffaf386708178
2 files changed +16 -29
builtin/receive-pack.c
+15 -24
@@ -1380,32 +1380,16 @@ static int update_shallow_ref(struct command *cmd, struct shallow_info *si)
1380 return 0;
1381 }
1382
1383 -/*
1384 - * NEEDSWORK: we should consolidate various implementations of "are we
1385 - * on an unborn branch?" test into one, and make the unified one more
1386 - * robust. !get_sha1() based check used here and elsewhere would not
1387 - * allow us to tell an unborn branch from corrupt ref, for example.
1388 - * For the purpose of fixing "deploy-to-update does not work when
1389 - * pushing into an empty repository" issue, this should suffice for
1390 - * now.
1391 - */
1392 -static int head_has_history(void)
1393 -{
1394 - struct object_id oid;
1395 -
1396 - return !repo_get_oid(the_repository, "HEAD", &oid);
1397 -}
1398 -
1383 static const char *push_to_deploy(unsigned char *sha1,
1384 struct strvec *env,
1401 - const char *work_tree)
1385 + const struct worktree *worktree)
1386 {
1387 struct child_process child = CHILD_PROCESS_INIT;
1388
1389 strvec_pushl(&child.args, "update-index", "-q", "--ignore-submodules",
1390 "--refresh", NULL);
1391 strvec_pushv(&child.env, env->v);
1408 - child.dir = work_tree;
1392 + child.dir = worktree->path;
1393 child.no_stdin = 1;
1394 child.stdout_to_stderr = 1;
1395 child.git_cmd = 1;
@@ -1417,7 +1401,7 @@ static const char *push_to_deploy(unsigned char *sha1,
1401 strvec_pushl(&child.args, "diff-files", "--quiet",
1402 "--ignore-submodules", "--", NULL);
1403 strvec_pushv(&child.env, env->v);
1420 - child.dir = work_tree;
1404 + child.dir = worktree->path;
1405 child.no_stdin = 1;
1406 child.stdout_to_stderr = 1;
1407 child.git_cmd = 1;
@@ -1427,9 +1411,16 @@ static const char *push_to_deploy(unsigned char *sha1,
1411 child_process_init(&child);
1412 strvec_pushl(&child.args, "diff-index", "--quiet", "--cached",
1413 "--ignore-submodules",
1430 - /* diff-index with either HEAD or an empty tree */
1431 - head_has_history() ? "HEAD" : empty_tree_oid_hex(the_repository->hash_algo),
1432 - "--", NULL);
1414 + /*
1415 + * diff-index with either HEAD or an empty tree
1416 + *
1417 + * NEEDSWORK: is_null_oid() cannot know whether it's an
1418 + * unborn HEAD or a corrupt ref. It works for now because
1419 + * it's only needed to know if we are comparing HEAD or an
1420 + * empty tree.
1421 + */
1422 + !is_null_oid(&worktree->head_oid) ? "HEAD" :
1423 + empty_tree_oid_hex(the_repository->hash_algo), "--", NULL);
1424 strvec_pushv(&child.env, env->v);
1425 child.no_stdin = 1;
1426 child.no_stdout = 1;
@@ -1442,7 +1433,7 @@ static const char *push_to_deploy(unsigned char *sha1,
1433 strvec_pushl(&child.args, "read-tree", "-u", "-m", hash_to_hex(sha1),
1434 NULL);
1435 strvec_pushv(&child.env, env->v);
1445 - child.dir = work_tree;
1436 + child.dir = worktree->path;
1437 child.no_stdin = 1;
1438 child.no_stdout = 1;
1439 child.stdout_to_stderr = 0;
@@ -1490,7 +1481,7 @@ static const char *update_worktree(unsigned char *sha1, const struct worktree *w
1481
1482 retval = push_to_checkout(sha1, &invoked_hook, &env, worktree->path);
1483 if (!invoked_hook)
1493 - retval = push_to_deploy(sha1, &env, worktree->path);
1484 + retval = push_to_deploy(sha1, &env, worktree);
1485
1486 strvec_clear(&env);
1487 free(git_dir);
t/t5516-fetch-push.sh
+1 -5
@@ -1817,11 +1817,7 @@ test_expect_success 'denyCurrentBranch and bare repository worktrees' '
1817 test_must_fail git push --delete bare.git wt
1818 '
1819
1820 -# NEEDSWORK: updateInstead unexpectedly fails when bare HEAD points to unborn
1821 -# branch (or probably any ref that differs from the target worktree) despite
1822 -# the target worktree being clean. This seems to be because receive-pack.c
1823 -# diffs the target worktree index against the bare repository HEAD.
1824 -test_expect_failure 'updateInstead with bare repository worktree and unborn bare HEAD' '
1820 +test_expect_success 'updateInstead with bare repository worktree and unborn bare HEAD' '
1821 test_when_finished "rm -fr bare.git cloned" &&
1822 git clone --bare . bare.git &&
1823 git -C bare.git worktree add wt &&