Merge branch 'jc/1.7.0-push-safety'

* jc/1.7.0-push-safety:
  Refuse deleting the current branch via push
  Refuse updating the current branch in a non-bare repository via push
This commit is contained in:
Junio C Hamano 2009-12-26 14:03:17 -08:00
commit 7ad9cec81d
8 changed files with 54 additions and 58 deletions

View File

@ -204,59 +204,47 @@ static int is_ref_checked_out(const char *ref)
return !strcmp(head_name, ref); return !strcmp(head_name, ref);
} }
static char *warn_unconfigured_deny_msg[] = { static char *refuse_unconfigured_deny_msg[] = {
"Updating the currently checked out branch may cause confusion,", "By default, updating the current branch in a non-bare repository",
"as the index and work tree do not reflect changes that are in HEAD.", "is denied, because it will make the index and work tree inconsistent",
"As a result, you may see the changes you just pushed into it", "with what you pushed, and will require 'git reset --hard' to match",
"reverted when you run 'git diff' over there, and you may want", "the work tree to HEAD.",
"to run 'git reset --hard' before starting to work to recover.",
"", "",
"You can set 'receive.denyCurrentBranch' configuration variable to", "You can set 'receive.denyCurrentBranch' configuration variable to",
"'refuse' in the remote repository to forbid pushing into its", "'ignore' or 'warn' in the remote repository to allow pushing into",
"current branch." "its current branch; however, this is not recommended unless you",
"arranged to update its work tree to match what you pushed in some",
"other way.",
"", "",
"To allow pushing into the current branch, you can set it to 'ignore';", "To squelch this message and still keep the default behaviour, set",
"but this is not recommended unless you arranged to update its work", "'receive.denyCurrentBranch' configuration variable to 'refuse'."
"tree to match what you pushed in some other way.",
"",
"To squelch this message, you can set it to 'warn'.",
"",
"Note that the default will change in a future version of git",
"to refuse updating the current branch unless you have the",
"configuration variable set to either 'ignore' or 'warn'."
}; };
static void warn_unconfigured_deny(void) static void refuse_unconfigured_deny(void)
{ {
int i; int i;
for (i = 0; i < ARRAY_SIZE(warn_unconfigured_deny_msg); i++) for (i = 0; i < ARRAY_SIZE(refuse_unconfigured_deny_msg); i++)
warning("%s", warn_unconfigured_deny_msg[i]); error("%s", refuse_unconfigured_deny_msg[i]);
} }
static char *warn_unconfigured_deny_delete_current_msg[] = { static char *refuse_unconfigured_deny_delete_current_msg[] = {
"Deleting the current branch can cause confusion by making the next", "By default, deleting the current branch is denied, because the next",
"'git clone' not check out any file.", "'git clone' won't result in any file checked out, causing confusion.",
"", "",
"You can set 'receive.denyDeleteCurrent' configuration variable to", "You can set 'receive.denyDeleteCurrent' configuration variable to",
"'refuse' in the remote repository to disallow deleting the current", "'warn' or 'ignore' in the remote repository to allow deleting the",
"branch.", "current branch, with or without a warning message.",
"", "",
"You can set it to 'ignore' to allow such a delete without a warning.", "To squelch this message, you can set it to 'refuse'."
"",
"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) static void refuse_unconfigured_deny_delete_current(void)
{ {
int i; int i;
for (i = 0; for (i = 0;
i < ARRAY_SIZE(warn_unconfigured_deny_delete_current_msg); i < ARRAY_SIZE(refuse_unconfigured_deny_delete_current_msg);
i++) i++)
warning("%s", warn_unconfigured_deny_delete_current_msg[i]); error("%s", refuse_unconfigured_deny_delete_current_msg[i]);
} }
static const char *update(struct command *cmd) static const char *update(struct command *cmd)
@ -276,14 +264,14 @@ static const char *update(struct command *cmd)
switch (deny_current_branch) { switch (deny_current_branch) {
case DENY_IGNORE: case DENY_IGNORE:
break; break;
case DENY_UNCONFIGURED:
case DENY_WARN: case DENY_WARN:
warning("updating the current branch"); warning("updating the current branch");
if (deny_current_branch == DENY_UNCONFIGURED)
warn_unconfigured_deny();
break; break;
case DENY_REFUSE: case DENY_REFUSE:
case DENY_UNCONFIGURED:
error("refusing to update checked out branch: %s", name); error("refusing to update checked out branch: %s", name);
if (deny_current_branch == DENY_UNCONFIGURED)
refuse_unconfigured_deny();
return "branch is currently checked out"; return "branch is currently checked out";
} }
} }
@ -305,12 +293,12 @@ static const char *update(struct command *cmd)
case DENY_IGNORE: case DENY_IGNORE:
break; break;
case DENY_WARN: case DENY_WARN:
case DENY_UNCONFIGURED:
if (deny_delete_current == DENY_UNCONFIGURED)
warn_unconfigured_deny_delete_current();
warning("deleting the current branch"); warning("deleting the current branch");
break; break;
case DENY_REFUSE: case DENY_REFUSE:
case DENY_UNCONFIGURED:
if (deny_delete_current == DENY_UNCONFIGURED)
refuse_unconfigured_deny_delete_current();
error("refusing to delete the current branch: %s", name); error("refusing to delete the current branch: %s", name);
return "deletion of the current branch prohibited"; return "deletion of the current branch prohibited";
} }

View File

@ -32,7 +32,7 @@ test_expect_success setup '
done && done &&
git update-ref HEAD "$commit" && git update-ref HEAD "$commit" &&
git clone ./. victim && git clone ./. victim &&
( cd victim && git log ) && ( cd victim && git config receive.denyCurrentBranch warn && git log ) &&
git update-ref HEAD "$zero" && git update-ref HEAD "$zero" &&
parent=$zero && parent=$zero &&
i=0 && i=0 &&
@ -129,6 +129,7 @@ rewound_push_setup() {
cd parent && cd parent &&
git init && git init &&
echo one >file && git add file && git commit -m one && echo one >file && git add file && git commit -m one &&
git config receive.denyCurrentBranch warn &&
echo two >file && git commit -a -m two echo two >file && git commit -a -m two
) && ) &&
git clone parent child && git clone parent child &&
@ -190,16 +191,11 @@ test_expect_success 'pushing wildcard refspecs respects forcing' '
test "$parent_head" = "$child_head" test "$parent_head" = "$child_head"
' '
test_expect_success 'warn pushing to delete current branch' ' test_expect_success 'deny pushing to delete current branch' '
rewound_push_setup && rewound_push_setup &&
( (
cd child && cd child &&
git send-pack ../parent :refs/heads/master 2>errs test_must_fail 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
) )
' '

View File

@ -18,6 +18,7 @@ test_expect_success setup '
git update-ref refs/heads/master $commit0 && git update-ref refs/heads/master $commit0 &&
git update-ref refs/heads/tofail $commit1 && git update-ref refs/heads/tofail $commit1 &&
git clone ./. victim && git clone ./. victim &&
GIT_DIR=victim/.git git config receive.denyCurrentBranch warn &&
GIT_DIR=victim/.git git update-ref refs/heads/tofail $commit1 && GIT_DIR=victim/.git git update-ref refs/heads/tofail $commit1 &&
git update-ref refs/heads/master $commit1 && git update-ref refs/heads/master $commit1 &&
git update-ref refs/heads/tofail $commit0 git update-ref refs/heads/tofail $commit0

View File

@ -8,6 +8,7 @@ test_expect_success setup '
>file1 && git add file1 && test_tick && >file1 && git add file1 && test_tick &&
git commit -m Initial && git commit -m Initial &&
git config receive.denyCurrentBranch warn &&
mkdir another && ( mkdir another && (
cd another && cd another &&

View File

@ -12,6 +12,7 @@ mk_empty () {
( (
cd testrepo && cd testrepo &&
git init && git init &&
git config receive.denyCurrentBranch warn &&
mv .git/hooks .git/hooks-disabled mv .git/hooks .git/hooks-disabled
) )
} }

View File

@ -19,7 +19,8 @@ mk_repo_pair () {
mkdir mirror && mkdir mirror &&
( (
cd mirror && cd mirror &&
git init git init &&
git config receive.denyCurrentBranch warn
) && ) &&
mkdir master && mkdir master &&
( (

View File

@ -20,13 +20,19 @@ fi
# #
# The working directory is subdir-link. # The working directory is subdir-link.
mkdir subdir test_expect_success setup '
echo file >subdir/file mkdir subdir &&
git add subdir/file echo file >subdir/file &&
git commit -q -m file git add subdir/file &&
git clone -q . clone-repo git commit -q -m file &&
ln -s clone-repo/subdir/ subdir-link git clone -q . clone-repo &&
ln -s clone-repo/subdir/ subdir-link &&
(
cd clone-repo &&
git config receive.denyCurrentBranch warn
) &&
git config receive.denyCurrentBranch warn
'
# Demonstrate that things work if we just avoid the symlink # Demonstrate that things work if we just avoid the symlink
# #

View File

@ -119,7 +119,9 @@ test_expect_success 'bundle clone with nonexistent HEAD' '
test_expect_success 'clone empty repository' ' test_expect_success 'clone empty repository' '
cd "$D" && cd "$D" &&
mkdir empty && mkdir empty &&
(cd empty && git init) && (cd empty &&
git init &&
git config receive.denyCurrentBranch warn) &&
git clone empty empty-clone && git clone empty empty-clone &&
test_tick && test_tick &&
(cd empty-clone (cd empty-clone