An attempt to update or delete a ref that is hidden from "git push" is rejected. With this the server side can implement refs that are only available for its own use, e.g. refs/pull/11/head used to hold an incoming pull request at GitHub. Signed-off-by: Junio C Hamano <gitster@xxxxxxxxx> --- Documentation/config.txt | 3 ++- builtin/receive-pack.c | 16 ++++++++++++++++ t/t5516-fetch-push.sh | 24 ++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 1 deletion(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 8e2853e..b7b407b 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -2063,7 +2063,8 @@ transfer.hiderefs:: more than one transfer.hiderefs configuration variables to specify multiple prefix strings. A ref that has one of these strings as its prefix is excluded, and is hidden from - `git clone --mirror` and `git push :`. + `git clone --mirror` and `git push :`. An attempt to update + or delete a hidden ref by `git push` is rejected. transfer.unpackLimit:: When `fetch.unpackLimit` or `receive.unpackLimit` are diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index 5ed40be..a8248d9 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -696,6 +696,20 @@ static int iterate_receive_command_list(void *cb_data, unsigned char sha1[20]) return -1; /* end of list */ } +static void reject_updates_to_hidden(struct command *commands) +{ + struct command *cmd; + + for (cmd = commands; cmd; cmd = cmd->next) { + if (cmd->error_string || !ref_is_hidden(cmd->ref_name)) + continue; + if (is_null_sha1(cmd->new_sha1)) + cmd->error_string = "deny deleting a hidden ref"; + else + cmd->error_string = "deny updating a hidden ref"; + } +} + static void execute_commands(struct command *commands, const char *unpacker_error) { struct command *cmd; @@ -712,6 +726,8 @@ static void execute_commands(struct command *commands, const char *unpacker_erro 0, &cmd)) set_connectivity_errors(commands); + reject_updates_to_hidden(commands); + if (run_receive_hook(commands, pre_receive_hook, 0)) { for (cmd = commands; cmd; cmd = cmd->next) { if (!cmd->error_string) diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh index 6009372..8e8287a 100755 --- a/t/t5516-fetch-push.sh +++ b/t/t5516-fetch-push.sh @@ -1037,4 +1037,28 @@ test_expect_success 'push --prune refspec' ' ! check_push_result $the_first_commit tmp/foo tmp/bar ' +test_expect_success 'push to update a hidden ref' ' + mk_test heads/master hidden/one hidden/two hidden/three && + ( + cd testrepo && + git config transfer.hiderefs refs/hidden + ) && + + # push to unhidden ref succeeds normally + git push testrepo master:refs/heads/master && + check_push_result $the_commit heads/master && + + # push to update a hidden ref should fail + test_must_fail git push testrepo master:refs/hidden/one && + check_push_result $the_first_commit hidden/one && + + # push to delete a hidden ref should fail + test_must_fail git push testrepo master:refs/hidden/two && + check_push_result $the_first_commit hidden/two && + + # idempotent push to update a hidden ref should fail + test_must_fail git push testrepo $the_first_commit:refs/hidden/three && + check_push_result $the_first_commit hidden/three +' + test_done -- 1.8.1.2.548.g0e4986f -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html