Occasionally, it may be useful to prevent branches from getting deleted from a centralized repository, particularly when no administrative access to the server is available to undo it via reflog. It also makes receive.denyNonFastForwards more useful if it is used for access control since it prevents force-updating by deleting and re-creating a ref. Signed-off-by: Jan Krüger <jk@xxxxx> --- Like this, then? Documentation/config.txt | 4 ++++ builtin-receive-pack.c | 12 ++++++++++++ t/t5400-send-pack.sh | 11 +++++++++++ 3 files changed, 27 insertions(+), 0 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 29369d0..965ed74 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -1188,6 +1188,10 @@ receive.unpackLimit:: especially on slow filesystems. If not set, the value of `transfer.unpackLimit` is used instead. +receive.denyDeletes:: + If set to true, git-receive-pack will deny a ref update that deletes + the ref. Use this to prevent such a ref deletion via a push. + receive.denyNonFastForwards:: If set to true, git-receive-pack will deny a ref update which is not a fast forward. Use this to prevent such an update via a push, diff --git a/builtin-receive-pack.c b/builtin-receive-pack.c index 9f60f31..2c0225c 100644 --- a/builtin-receive-pack.c +++ b/builtin-receive-pack.c @@ -11,6 +11,7 @@ static const char receive_pack_usage[] = "git-receive-pack <git-dir>"; +static int deny_deletes = 0; static int deny_non_fast_forwards = 0; static int receive_fsck_objects; static int receive_unpack_limit = -1; @@ -23,6 +24,11 @@ static int capabilities_sent; static int receive_pack_config(const char *var, const char *value, void *cb) { + if (strcmp(var, "receive.denydeletes") == 0) { + deny_deletes = git_config_bool(var, value); + return 0; + } + if (strcmp(var, "receive.denynonfastforwards") == 0) { deny_non_fast_forwards = git_config_bool(var, value); return 0; @@ -185,6 +191,12 @@ static const char *update(struct command *cmd) "but I can't find it!", sha1_to_hex(new_sha1)); return "bad pack"; } + if (deny_deletes && is_null_sha1(new_sha1) && + !is_null_sha1(old_sha1) && + !prefixcmp(name, "refs/heads/")) { + error("denying ref deletion for %s", name); + return "deletion prohibited"; + } if (deny_non_fast_forwards && !is_null_sha1(new_sha1) && !is_null_sha1(old_sha1) && !prefixcmp(name, "refs/heads/")) { diff --git a/t/t5400-send-pack.sh b/t/t5400-send-pack.sh index 544771d..6fe2f87 100755 --- a/t/t5400-send-pack.sh +++ b/t/t5400-send-pack.sh @@ -103,6 +103,17 @@ unset GIT_CONFIG GIT_CONFIG_LOCAL HOME=`pwd`/no-such-directory export HOME ;# this way we force the victim/.git/config to be used. +test_expect_failure \ + 'pushing a delete should be denied with denyDeletes' ' + cd victim && + git config receive.denyDeletes true && + git branch extra master && + cd .. && + test -f victim/.git/refs/heads/extra && + test_must_fail git send-pack ./victim/.git/ :extra master +' +rm -f victim/.git/refs/heads/extra + test_expect_success \ 'pushing with --force should be denied with denyNonFastforwards' ' cd victim && -- 1.6.0.3.524.g86cf.dirty -- 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