{"thread":{"id":"17833","subject":"[DRY HUMOR PATCH] Add a few more values for receive.denyCurrentBranch","startedAt":"2009-02-16T21:52:05Z","lastAt":"2009-02-17T01:14:24Z","messageCount":4,"participants":["Johannes Schindelin","Jeff King","Mikael Magnusson"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"105016","messageId":"bfeaa5d164c9dc2d1080545e4bb9480920762ff2.1234820890u.git.johannes.schindelin@gmx.de","threadId":"17833","inReplyTo":"cover.1234820890u.git.johannes.schindelin@gmx.de","subject":"[DRY HUMOR PATCH] Add a few more values for receive.denyCurrentBranch","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2009-02-16T21:52:05Z","receivedAt":"2009-02-16T21:52:05Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Some people insist on work flows where they push into their checked-out\nbranches.\n\nNow, everybody should agree that these people better know what they\nare doing, and that most users are Better Of Avoiding That.\n\nHowever, it seems that the existing users of the feature-not-a-bug that\nyou can push into non-bare repositories are preparing to give the Git\ndevelopers as much grief as for the dashed -> undashed migration, and\ntherefore it may be wise to give them a gift in return.\n\nThe gift consists of two new options you can give the config variable\nreceive.denyCurrentBranch:\n\n'updateInstead':\n\tTry to merge the working tree with the new tip of the branch\n\t(which can lead to really horrible merge conflicts).\n\n'detachInstead':\n\tDetach the HEAD, thereby avoiding a disagreement between the\n\tHEAD and the index (as well as the working tree), possibly\n\tleaving the local user wondering how on earth her HEAD became\n\tso detached.\n\nAnd now everybody, sing!\n\n\tGimme rope, Johannes,\n\tGimme rope, Johannes,\n\tGimme rope, Johannes,\n\t'fore the moaning come,\n\tGimme rope, Johannes,\n\tRope, Johannes,\n\tRope before the moaning come.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n Documentation/config.txt |    5 ++++\n builtin-receive-pack.c   |   47 +++++++++++++++++++++++++++++++++++++++++++++-\n t/t5516-fetch-push.sh    |   36 +++++++++++++++++++++++++++++++++++\n 3 files changed, 87 insertions(+), 1 deletions(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex 3117d65..441c595 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -1201,6 +1201,11 @@ receive.denyCurrentBranch::\n \tprint a warning of such a push to stderr, but allow the push to\n \tproceed. If set to false or \"ignore\", allow such pushes with no\n \tmessage. Defaults to \"warn\".\n++\n+There are two more options that are meant for Git experts: \"updateInstead\"\n+which will run `read-tree -u -m HEAD` and \"detachInstead\" which will detach\n+the HEAD so it does not need to change.  Both options come with their own\n+set of possible *complications*, but can be appropriate in rare workflows.\n \n receive.denyNonFastForwards::\n \tIf set to true, git-receive-pack will deny a ref update which is\ndiff --git a/builtin-receive-pack.c b/builtin-receive-pack.c\nindex f7e04c4..23b8ceb 100644\n--- a/builtin-receive-pack.c\n+++ b/builtin-receive-pack.c\n@@ -16,6 +16,8 @@ enum deny_action {\n \tDENY_IGNORE,\n \tDENY_WARN,\n \tDENY_REFUSE,\n+\tDENY_UPDATE_INSTEAD,\n+\tDENY_DETACH_INSTEAD,\n };\n \n static int deny_deletes;\n@@ -75,7 +77,12 @@ static int receive_pack_config(const char *var, const char *value, void *cb)\n \t}\n \n \tif (!strcmp(var, \"receive.denycurrentbranch\")) {\n-\t\tdeny_current_branch = parse_deny_action(var, value);\n+\t\tif (value && !strcasecmp(value, \"updateinstead\"))\n+\t\t\tdeny_current_branch = DENY_UPDATE_INSTEAD;\n+\t\telse if (value && !strcasecmp(value, \"detachinstead\"))\n+\t\t\tdeny_current_branch = DENY_DETACH_INSTEAD;\n+\t\telse\n+\t\t\tdeny_current_branch = parse_deny_action(var, value);\n \t\treturn 0;\n \t}\n \n@@ -273,6 +280,35 @@ static void warn_unconfigured_deny_delete_current(void)\n \t\twarning(warn_unconfigured_deny_delete_current_msg[i]);\n }\n \n+static void merge_worktree(unsigned char *sha1)\n+{\n+\tconst char *argv_read_tree[] = {\n+\t\t\"read-tree\", \"-u\", \"-m\", sha1_to_hex(sha1), NULL\n+\t};\n+\tstruct child_process read_tree;\n+\tstruct strbuf git_env = STRBUF_INIT;\n+\tconst char *env[2];\n+\n+\tif (is_bare_repository())\n+\t\tdie (\"denyCurrentBranch = updateInstead needs a worktree\");\n+\n+\tstrbuf_addf(&git_env, \"GIT_DIR=%s\", make_absolute_path(get_git_dir()));\n+\tenv[0] = git_env.buf;\n+\tenv[1] = NULL;\n+\n+\tmemset(&read_tree, 0, sizeof(read_tree));\n+\tread_tree.argv = argv_read_tree;\n+\tread_tree.env = env;\n+\tread_tree.dir = git_work_tree_cfg ? git_work_tree_cfg : \"..\";\n+\tread_tree.no_stdin = 1;\n+\tread_tree.no_stdout = 1;\n+\tread_tree.git_cmd = 1;\n+\tif (run_command(&read_tree))\n+\t\tdie (\"Could not merge working tree with new HEAD.  Good luck.\");\n+\n+\tstrbuf_release(&git_env);\n+}\n+\n static const char *update(struct command *cmd)\n {\n \tconst char *name = cmd->ref_name;\n@@ -299,6 +335,13 @@ static const char *update(struct command *cmd)\n \t\tcase DENY_REFUSE:\n \t\t\terror(\"refusing to update checked out branch: %s\", name);\n \t\t\treturn \"branch is currently checked out\";\n+\t\tcase DENY_UPDATE_INSTEAD:\n+\t\t\tmerge_worktree(new_sha1);\n+\t\t\tbreak;\n+\t\tcase DENY_DETACH_INSTEAD:\n+\t\t\tupdate_ref(\"push into current branch (detach)\", \"HEAD\",\n+\t\t\t\told_sha1, NULL, REF_NODEREF, DIE_ON_ERR);\n+\t\t\tbreak;\n \t\t}\n \t}\n \n@@ -327,6 +370,8 @@ static const char *update(struct command *cmd)\n \t\t\tcase DENY_REFUSE:\n \t\t\t\terror(\"refusing to delete the current branch: %s\", name);\n \t\t\t\treturn \"deletion of the current branch prohibited\";\n+\t\t\tdefault:\n+\t\t\t\tdie (\"Invalid denyDeleteCurrent setting\");\n \t\t\t}\n \t\t}\n \t}\ndiff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh\nindex 89649e7..40b98d3 100755\n--- a/t/t5516-fetch-push.sh\n+++ b/t/t5516-fetch-push.sh\n@@ -573,4 +573,40 @@ test_expect_success 'push with branches containing #' '\n \tgit checkout master\n '\n \n+test_expect_success 'receive.denyCurrentBranch = updateInstead' '\n+\tgit push testrepo master &&\n+\t(cd testrepo &&\n+\t\tgit reset --hard &&\n+\t\tgit config receive.denyCurrentBranch updateInstead\n+\t) &&\n+\ttest_commit third path2 &&\n+\tgit push testrepo master &&\n+\ttest $(git rev-parse HEAD) = $(cd testrepo && git rev-parse HEAD) &&\n+\ttest third = \"$(cat testrepo/path2)\" &&\n+\t(cd testrepo &&\n+\t\tgit update-index --refresh &&\n+\t\tgit diff-files --quiet &&\n+\t\tgit diff-index --cached HEAD --\n+\t)\n+'\n+\n+test_expect_success 'receive.denyCurrentBranch = detachInstead' '\n+\t(cd testrepo &&\n+\t\tgit reset --hard &&\n+\t\tgit config receive.denyCurrentBranch detachInstead\n+\t) &&\n+\tOLDHEAD=$(cd testrepo && git rev-parse HEAD) &&\n+\ttest_commit fourth path2 &&\n+\ttest fourth = \"$(cat path2)\" &&\n+\tgit push testrepo master &&\n+\ttest $OLDHEAD = $(cd testrepo && git rev-parse HEAD) &&\n+\ttest fourth != \"$(cat testrepo/path2)\" &&\n+\t(cd testrepo &&\n+\t\ttest_must_fail git symbolic-ref HEAD &&\n+\t\tgit update-index --refresh &&\n+\t\tgit diff-files --quiet &&\n+\t\tgit diff-index --cached HEAD --\n+\t)\n+'\n+\n test_done\n-- \n1.6.1.1.825.g72a9f\n"},{"id":"105050","messageId":"20090217005824.GA23892@coredump.intra.peff.net","threadId":"17833","inReplyTo":"bfeaa5d164c9dc2d1080545e4bb9480920762ff2.1234820890u.git.johannes.schindelin@gmx.de","subject":"Re: [DRY HUMOR PATCH] Add a few more values for receive.denyCurrentBranch","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2009-02-17T00:58:24Z","receivedAt":"2009-02-17T00:58:24Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Feb 16, 2009 at 10:52:05PM +0100, Johannes Schindelin wrote:\n\n> @@ -75,7 +77,12 @@ static int receive_pack_config(const char *var, const char *value, void *cb)\n>  \t}\n>  \n>  \tif (!strcmp(var, \"receive.denycurrentbranch\")) {\n> -\t\tdeny_current_branch = parse_deny_action(var, value);\n> +\t\tif (value && !strcasecmp(value, \"updateinstead\"))\n> +\t\t\tdeny_current_branch = DENY_UPDATE_INSTEAD;\n> +\t\telse if (value && !strcasecmp(value, \"detachinstead\"))\n\nConfig variables are already lower-cased. ;P\n\n-Peff\n"},{"id":"105052","messageId":"237967ef0902161710k4672e972rdffab0357b8872a8@mail.gmail.com","threadId":"17833","inReplyTo":"20090217005824.GA23892@coredump.intra.peff.net","subject":"Re: [DRY HUMOR PATCH] Add a few more values for receive.denyCurrentBranch","fromName":"Mikael Magnusson","fromEmail":"mikachu@gmail.com","sentAt":"2009-02-17T01:10:33Z","receivedAt":"2009-02-17T01:10:33Z","isPatch":true,"sender":{"key":"mikachu@gmail.com","avatar":null},"body":"2009/2/17 Jeff King <peff@peff.net>:\n> On Mon, Feb 16, 2009 at 10:52:05PM +0100, Johannes Schindelin wrote:\n>\n>> @@ -75,7 +77,12 @@ static int receive_pack_config(const char *var, const char *value, void *cb)\n>>       }\n>>\n>>       if (!strcmp(var, \"receive.denycurrentbranch\")) {\n>> -             deny_current_branch = parse_deny_action(var, value);\n>> +             if (value && !strcasecmp(value, \"updateinstead\"))\n>> +                     deny_current_branch = DENY_UPDATE_INSTEAD;\n>> +             else if (value && !strcasecmp(value, \"detachinstead\"))\n>\n> Config variables are already lower-cased. ;P\n\nBut surely the values are not?\n\n-- \nMikael Magnusson\n"},{"id":"105054","messageId":"20090217011424.GA24822@coredump.intra.peff.net","threadId":"17833","inReplyTo":"237967ef0902161710k4672e972rdffab0357b8872a8@mail.gmail.com","subject":"Re: [DRY HUMOR PATCH] Add a few more values for receive.denyCurrentBranch","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2009-02-17T01:14:24Z","receivedAt":"2009-02-17T01:14:24Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Tue, Feb 17, 2009 at 02:10:33AM +0100, Mikael Magnusson wrote:\n\n> 2009/2/17 Jeff King <peff@peff.net>:\n> > On Mon, Feb 16, 2009 at 10:52:05PM +0100, Johannes Schindelin wrote:\n> >\n> >> @@ -75,7 +77,12 @@ static int receive_pack_config(const char *var, const char *value, void *cb)\n> >>       }\n> >>\n> >>       if (!strcmp(var, \"receive.denycurrentbranch\")) {\n> >> -             deny_current_branch = parse_deny_action(var, value);\n> >> +             if (value && !strcasecmp(value, \"updateinstead\"))\n> >> +                     deny_current_branch = DENY_UPDATE_INSTEAD;\n> >> +             else if (value && !strcasecmp(value, \"detachinstead\"))\n> >\n> > Config variables are already lower-cased. ;P\n> \n> But surely the values are not?\n\nHeh. Ouch. You are right, of course, and now I have been caught being\nwrong while making smart-ass comments, so I'll shut up. ;)\n\n-Peff\n"}]}