Merge branch 'ps/receive-pack-updateinstead-in-worktree'

The check in "receive-pack" to prevent a checked out branch from
getting updated via updateInstead mechanism has been corrected.

* ps/receive-pack-updateinstead-in-worktree:
  receive-pack: use worktree HEAD for updateInstead
  t5516: clean up cloned and new-wt in denyCurrentBranch and worktrees test
  t5516: test updateInstead with worktree and unborn bare HEAD
This commit is contained in:
Junio C Hamano
2026-04-07 14:59:27 -07:00
2 changed files with 30 additions and 24 deletions

View File

@@ -1384,32 +1384,16 @@ static int update_shallow_ref(struct command *cmd, struct shallow_info *si)
return 0;
}
/*
* NEEDSWORK: we should consolidate various implementations of "are we
* on an unborn branch?" test into one, and make the unified one more
* robust. !get_sha1() based check used here and elsewhere would not
* allow us to tell an unborn branch from corrupt ref, for example.
* For the purpose of fixing "deploy-to-update does not work when
* pushing into an empty repository" issue, this should suffice for
* now.
*/
static int head_has_history(void)
{
struct object_id oid;
return !repo_get_oid(the_repository, "HEAD", &oid);
}
static const char *push_to_deploy(unsigned char *sha1,
struct strvec *env,
const char *work_tree)
const struct worktree *worktree)
{
struct child_process child = CHILD_PROCESS_INIT;
strvec_pushl(&child.args, "update-index", "-q", "--ignore-submodules",
"--refresh", NULL);
strvec_pushv(&child.env, env->v);
child.dir = work_tree;
child.dir = worktree->path;
child.no_stdin = 1;
child.stdout_to_stderr = 1;
child.git_cmd = 1;
@@ -1421,7 +1405,7 @@ static const char *push_to_deploy(unsigned char *sha1,
strvec_pushl(&child.args, "diff-files", "--quiet",
"--ignore-submodules", "--", NULL);
strvec_pushv(&child.env, env->v);
child.dir = work_tree;
child.dir = worktree->path;
child.no_stdin = 1;
child.stdout_to_stderr = 1;
child.git_cmd = 1;
@@ -1431,9 +1415,16 @@ static const char *push_to_deploy(unsigned char *sha1,
child_process_init(&child);
strvec_pushl(&child.args, "diff-index", "--quiet", "--cached",
"--ignore-submodules",
/* diff-index with either HEAD or an empty tree */
head_has_history() ? "HEAD" : empty_tree_oid_hex(the_repository->hash_algo),
"--", NULL);
/*
* diff-index with either HEAD or an empty tree
*
* NEEDSWORK: is_null_oid() cannot know whether it's an
* unborn HEAD or a corrupt ref. It works for now because
* it's only needed to know if we are comparing HEAD or an
* empty tree.
*/
!is_null_oid(&worktree->head_oid) ? "HEAD" :
empty_tree_oid_hex(the_repository->hash_algo), "--", NULL);
strvec_pushv(&child.env, env->v);
child.no_stdin = 1;
child.no_stdout = 1;
@@ -1446,7 +1437,7 @@ static const char *push_to_deploy(unsigned char *sha1,
strvec_pushl(&child.args, "read-tree", "-u", "-m", hash_to_hex(sha1),
NULL);
strvec_pushv(&child.env, env->v);
child.dir = work_tree;
child.dir = worktree->path;
child.no_stdin = 1;
child.no_stdout = 1;
child.stdout_to_stderr = 0;
@@ -1494,7 +1485,7 @@ static const char *update_worktree(unsigned char *sha1, const struct worktree *w
retval = push_to_checkout(sha1, &invoked_hook, &env, worktree->path);
if (!invoked_hook)
retval = push_to_deploy(sha1, &env, worktree->path);
retval = push_to_deploy(sha1, &env, worktree);
strvec_clear(&env);
free(git_dir);

View File

@@ -1792,6 +1792,7 @@ test_expect_success 'updateInstead with push-to-checkout hook' '
'
test_expect_success 'denyCurrentBranch and worktrees' '
test_when_finished "rm -fr cloned && git worktree remove --force new-wt" &&
git worktree add new-wt &&
git clone . cloned &&
test_commit -C cloned first &&
@@ -1816,6 +1817,20 @@ test_expect_success 'denyCurrentBranch and bare repository worktrees' '
test_must_fail git push --delete bare.git wt
'
test_expect_success 'updateInstead with bare repository worktree and unborn bare HEAD' '
test_when_finished "rm -fr bare.git cloned" &&
git clone --bare . bare.git &&
git -C bare.git worktree add wt &&
git -C bare.git config receive.denyCurrentBranch updateInstead &&
git -C bare.git symbolic-ref HEAD refs/heads/unborn &&
test_must_fail git -C bare.git rev-parse -q --verify HEAD^{commit} &&
git clone . cloned &&
test_commit -C cloned mozzarella &&
git -C cloned push ../bare.git HEAD:wt &&
test_path_exists bare.git/wt/mozzarella.t &&
test "$(git -C cloned rev-parse HEAD)" = "$(git -C bare.git/wt rev-parse HEAD)"
'
test_expect_success 'refuse fetch to current branch of worktree' '
test_when_finished "git worktree remove --force wt && git branch -D wt" &&
git worktree add wt &&