summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: ba19a80)
raw | patch | inline | side by side (parent: ba19a80)
author | Junio C Hamano <gitster@pobox.com> | |
Mon, 9 Feb 2009 06:31:21 +0000 (22:31 -0800) | ||
committer | Junio C Hamano <gitster@pobox.com> | |
Wed, 11 Feb 2009 06:26:49 +0000 (22:26 -0800) |
This is a companion patch to the recent 3d95d92 (receive-pack: explain
what to do when push updates the current branch, 2009-01-31).
Deleting the current branch from a remote will result in the next clone
from it not check out anything, among other things. It also is one of the
cause that makes remotes/origin/HEAD a dangling symbolic ref. This patch
still allows the traditional behaviour but with a big warning, and promises
that the default will change to 'refuse' in a future release.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
what to do when push updates the current branch, 2009-01-31).
Deleting the current branch from a remote will result in the next clone
from it not check out anything, among other things. It also is one of the
cause that makes remotes/origin/HEAD a dangling symbolic ref. This patch
still allows the traditional behaviour but with a big warning, and promises
that the default will change to 'refuse' in a future release.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
builtin-receive-pack.c | patch | blob | history | |
t/t5400-send-pack.sh | patch | blob | history |
diff --git a/builtin-receive-pack.c b/builtin-receive-pack.c
index 6de186c397fcd5eaab2331db56546acab5f545f4..1dc373e31036eaf34842c97b63f728ad5cfdb0e9 100644 (file)
--- a/builtin-receive-pack.c
+++ b/builtin-receive-pack.c
static int deny_deletes = 0;
static int deny_non_fast_forwards = 0;
static enum deny_action deny_current_branch = DENY_UNCONFIGURED;
+static enum deny_action deny_delete_current = DENY_UNCONFIGURED;
static int receive_fsck_objects;
static int receive_unpack_limit = -1;
static int transfer_unpack_limit = -1;
static int unpack_limit = 100;
static int report_status;
+static const char *head_name;
static char capabilities[] = " report-status delete-refs ";
static int capabilities_sent;
return 0;
}
+ if (strcmp(var, "receive.denydeletecurrent") == 0) {
+ deny_delete_current = parse_deny_action(var, value);
+ return 0;
+ }
+
return git_default_config(var, value, cb);
}
static int is_ref_checked_out(const char *ref)
{
- unsigned char sha1[20];
- const char *head;
-
if (is_bare_repository())
return 0;
- head = resolve_ref("HEAD", sha1, 0, NULL);
- if (!head)
+ if (!head_name)
return 0;
- return !strcmp(head, ref);
+ return !strcmp(head_name, ref);
}
static char *warn_unconfigured_deny_msg[] = {
warning(warn_unconfigured_deny_msg[i]);
}
+static char *warn_unconfigured_deny_delete_current_msg[] = {
+ "Deleting the current branch can cause confusion by making the next",
+ "'git clone' not check out any file.",
+ "",
+ "You can set 'receive.denyDeleteCurrent' configuration variable to",
+ "'refuse' in the remote repository to disallow deleting the current",
+ "branch.",
+ "",
+ "You can set it to 'ignore' to allow such a delete without a warning.",
+ "",
+ "To make this warning message less loud, you can set it to 'warn'.",
+ "",
+ "Note that the default will change in a future version of git",
+ "to refuse deleting the current branch unless you have the",
+ "configuration variable set to either 'ignore' or 'warn'."
+};
+
+static void warn_unconfigured_deny_delete_current(void)
+{
+ int i;
+ for (i = 0;
+ i < ARRAY_SIZE(warn_unconfigured_deny_delete_current_msg);
+ i++)
+ warning(warn_unconfigured_deny_delete_current_msg[i]);
+}
+
static const char *update(struct command *cmd)
{
const char *name = cmd->ref_name;
"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 (!is_null_sha1(old_sha1) && is_null_sha1(new_sha1)) {
+ if (deny_deletes && !prefixcmp(name, "refs/heads/")) {
+ error("denying ref deletion for %s", name);
+ return "deletion prohibited";
+ }
+
+ if (!strcmp(name, head_name)) {
+ switch (deny_delete_current) {
+ case DENY_IGNORE:
+ break;
+ case DENY_WARN:
+ case DENY_UNCONFIGURED:
+ if (deny_delete_current == DENY_UNCONFIGURED)
+ warn_unconfigured_deny_delete_current();
+ warning("deleting the current branch");
+ break;
+ case DENY_REFUSE:
+ error("refusing to delete the current branch: %s", name);
+ return "deletion of the current branch prohibited";
+ }
+ }
}
+
if (deny_non_fast_forwards && !is_null_sha1(new_sha1) &&
!is_null_sha1(old_sha1) &&
!prefixcmp(name, "refs/heads/")) {
static void execute_commands(const char *unpacker_error)
{
struct command *cmd = commands;
+ unsigned char sha1[20];
if (unpacker_error) {
while (cmd) {
return;
}
+ head_name = resolve_ref("HEAD", sha1, 0, NULL);
+
while (cmd) {
cmd->error_string = update(cmd);
cmd = cmd->next;
diff --git a/t/t5400-send-pack.sh b/t/t5400-send-pack.sh
index d6151f885476e9c4f0f90c3c102f9fa41576e74c..f2d5581b12f7d70c9f346da75dced81e12bd4c7f 100755 (executable)
--- a/t/t5400-send-pack.sh
+++ b/t/t5400-send-pack.sh
test "$parent_head" = "$child_head"
'
+test_expect_success 'warn pushing to delete current branch' '
+ rewound_push_setup &&
+ (
+ cd child &&
+ git send-pack ../parent :refs/heads/master 2>errs
+ ) &&
+ grep "warning: to refuse deleting" child/errs &&
+ (
+ cd parent &&
+ test_must_fail git rev-parse --verify master
+ )
+'
+
test_done