push-to-deploy: allow pushing into an unborn branch and updating it

Setting receive.denycurrentbranch to updateinstead and pushing into
the current branch, when the working tree and the index is truly
clean, is supposed to reset the working tree and the index to match
the tree of the pushed commit.  This did not work when pushing into
an unborn branch.

The code that drives push-to-checkout hook needs no change, as the
interface is defined so that hook can decide what to do when the
push is coming to an unborn branch and take an appropriate action
since the beginning.

Acked-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Junio C Hamano 2015-03-31 23:15:45 -07:00
parent 0855331941
commit 1a51b52422
2 changed files with 74 additions and 2 deletions

View file

@ -733,6 +733,22 @@ static int update_shallow_ref(struct command *cmd, struct shallow_info *si)
return 0;
}
/*
* NEEDSWORK: we should consolidate various implementions 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)
{
unsigned char sha1[20];
return !get_sha1("HEAD", sha1);
}
static const char *push_to_deploy(unsigned char *sha1,
struct argv_array *env,
const char *work_tree)
@ -745,7 +761,7 @@ static const char *push_to_deploy(unsigned char *sha1,
};
const char *diff_index[] = {
"diff-index", "--quiet", "--cached", "--ignore-submodules",
"HEAD", "--", NULL
NULL, "--", NULL
};
const char *read_tree[] = {
"read-tree", "-u", "-m", NULL, NULL
@ -772,6 +788,9 @@ static const char *push_to_deploy(unsigned char *sha1,
if (run_command(&child))
return "Working directory has unstaged changes";
/* diff-index with either HEAD or an empty tree */
diff_index[4] = head_has_history() ? "HEAD" : EMPTY_TREE_SHA1_HEX;
child_process_init(&child);
child.argv = diff_index;
child.env = env->argv;

View file

@ -1430,8 +1430,22 @@ test_expect_success 'receive.denyCurrentBranch = updateInstead' '
test $(git -C .. rev-parse HEAD^^) = $(git rev-parse HEAD) &&
git diff --quiet &&
test fifth = "$(cat path3)"
)
) &&
# (5) push into void
rm -fr void &&
git init void &&
(
cd void &&
git config receive.denyCurrentBranch updateInstead
) &&
git push void master &&
(
cd void &&
test $(git -C .. rev-parse master) = $(git rev-parse HEAD) &&
git diff --quiet &&
git diff --cached --quiet
)
'
test_expect_success 'updateInstead with push-to-checkout hook' '
@ -1494,6 +1508,45 @@ test_expect_success 'updateInstead with push-to-checkout hook' '
test "$(cat path5)" = irrelevant &&
test "$(git diff --name-only --cached HEAD)" = path5 &&
test $(git -C .. rev-parse HEAD) = $(git rev-parse HEAD)
) &&
# push into void
rm -fr void &&
git init void &&
(
cd void &&
git config receive.denyCurrentBranch updateInstead &&
write_script .git/hooks/push-to-checkout <<-\EOF
if git rev-parse --quiet --verify HEAD
then
has_head=yes
echo >&2 updating from $(git rev-parse HEAD)
else
has_head=no
echo >&2 pushing into void
fi
echo >&2 updating to "$1"
git update-index -q --refresh &&
case "$has_head" in
yes)
git read-tree -u -m HEAD "$1" ;;
no)
git read-tree -u -m "$1" ;;
esac || {
status=$?
echo >&2 read-tree failed
exit $status
}
EOF
) &&
git push void master &&
(
cd void &&
git diff --quiet &&
git diff --cached --quiet &&
test $(git -C .. rev-parse HEAD) = $(git rev-parse HEAD)
)
'