Add a few more values for receive.denyCurrentBranch

For a long time, this developer thought that Git's insistence that
pushing into the current branch is evil was completely merited.

Just for fun, the original patch tried to show people that Git is right
there, and that it causes more trouble than it does good when Git allows
you to try to update the working tree for fast-forwards, or to detach the
HEAD, depending on some config settings.

Surprisingly, the opposite was shown.

So here is the support for two new options you can give the config
variable receive.denyCurrentBranch:

'updateInstead':
	Try to merge the working tree with the new tip of the branch
	(which can lead to really horrible merge conflicts).

'detachInstead':
	Detach the HEAD, thereby avoiding a disagreement between the
	HEAD and the index (as well as the working tree), possibly
	leaving the local user wondering how on earth her HEAD became
	so detached.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
This commit is contained in:
Johannes Schindelin
2009-02-16 21:52:51 +01:00
parent 2e07d86f48
commit 495281174b
3 changed files with 97 additions and 2 deletions

View File

@@ -17,7 +17,9 @@ enum deny_action {
DENY_UNCONFIGURED,
DENY_IGNORE,
DENY_WARN,
DENY_REFUSE
DENY_REFUSE,
DENY_UPDATE_INSTEAD,
DENY_DETACH_INSTEAD,
};
static int deny_deletes;
@@ -79,7 +81,12 @@ static int receive_pack_config(const char *var, const char *value, void *cb)
}
if (!strcmp(var, "receive.denycurrentbranch")) {
deny_current_branch = parse_deny_action(var, value);
if (value && !strcasecmp(value, "updateinstead"))
deny_current_branch = DENY_UPDATE_INSTEAD;
else if (value && !strcasecmp(value, "detachinstead"))
deny_current_branch = DENY_DETACH_INSTEAD;
else
deny_current_branch = parse_deny_action(var, value);
return 0;
}
@@ -329,6 +336,44 @@ static void refuse_unconfigured_deny_delete_current(void)
rp_error("%s", refuse_unconfigured_deny_delete_current_msg[i]);
}
static void merge_worktree(unsigned char *sha1)
{
const char *update_refresh[] = {
"update-index", "--refresh", NULL
};
const char *read_tree[] = {
"read-tree", "-u", "-m", sha1_to_hex(sha1), NULL
};
struct child_process child;
struct strbuf git_env = STRBUF_INIT;
const char *env[2];
if (is_bare_repository())
die ("denyCurrentBranch = updateInstead needs a worktree");
strbuf_addf(&git_env, "GIT_DIR=%s", make_absolute_path(get_git_dir()));
env[0] = git_env.buf;
env[1] = NULL;
memset(&child, 0, sizeof(child));
child.argv = update_refresh;
child.env = env;
child.dir = git_work_tree_cfg ? git_work_tree_cfg : "..";
child.stdout_to_stderr = 1;
child.git_cmd = 1;
if (run_command(&child))
die ("Could not refresh the index");
child.argv = read_tree;
child.no_stdin = 1;
child.no_stdout = 1;
child.stdout_to_stderr = 0;
if (run_command(&child))
die ("Could not merge working tree with new HEAD. Good luck.");
strbuf_release(&git_env);
}
static const char *update(struct command *cmd)
{
const char *name = cmd->ref_name;
@@ -355,6 +400,13 @@ static const char *update(struct command *cmd)
if (deny_current_branch == DENY_UNCONFIGURED)
refuse_unconfigured_deny();
return "branch is currently checked out";
case DENY_UPDATE_INSTEAD:
merge_worktree(new_sha1);
break;
case DENY_DETACH_INSTEAD:
update_ref("push into current branch (detach)", "HEAD",
old_sha1, NULL, REF_NODEREF, DIE_ON_ERR);
break;
}
}
@@ -383,6 +435,8 @@ static const char *update(struct command *cmd)
refuse_unconfigured_deny_delete_current();
rp_error("refusing to delete the current branch: %s", name);
return "deletion of the current branch prohibited";
default:
die ("Invalid denyDeleteCurrent setting");
}
}
}