{"thread":{"id":"16543","subject":"Add 'sane' mode to 'git reset'","startedAt":"2008-12-01T17:30:31Z","lastAt":"2008-12-04T02:03:15Z","messageCount":8,"participants":["Linus Torvalds","Avery Pennarun","Jakub Narebski","Junio C Hamano"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"96875","messageId":"alpine.LFD.2.00.0812010908120.3256@nehalem.linux-foundation.org","threadId":"16543","inReplyTo":null,"subject":"Add 'sane' mode to 'git reset'","fromName":"Linus Torvalds","fromEmail":"torvalds@linux-foundation.org","sentAt":"2008-12-01T17:30:31Z","receivedAt":"2008-12-01T17:30:31Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\nWe have always had a nice way to reset a working tree to another state \nwhile carrying our changes around: \"git read-tree -u -m\". Yes, it fails if \nthe target tree is different in the paths that are dirty in the working \ntree, but this is how we used to switch branches in \"git checkout\", and it \nworked fine.\n\nHowever, perhaps exactly _because_ we've supported this from very early \non, another low-level command, namely \"git reset\", never did. \n\nBut as time went on, 'git reset' remains as a very common command, while \n'git read-tree' is now a very odd and low-level plumbing thing that nobody \nsane should ever use, because it only makes sense together with other \noperations like either switching branches or just rewriting HEAD.\n\nWhich means that we have effectively lost the ability to do something very \ncommon: jump to another point in time without always dropping all our \ndirty state.\n\nSo add this kind of mode to \"git reset\", and since it's probably the \nsanest form of reset (it will not throw any state away), just call it \nthat: \"git reset --sane\". It should probably be the default, but we likely \ncannot change the semantics of a regular \"git reset\", even though it is \nunlikely that very many people really use the current (insane) default \nmode of \"--mixed\" that only resets the index.\n\nI've wanted this for a long time, since I very commonly carry a dirty \ntree while working on things. My main 'Makefile' file quite often has the \nnext version already modified, and sometimes I have local modifications \nthat I don't want to commit, but I still do pulls and patch applications, \nand occasionally want to do \"git reset\" to undo them - while still keeping \nmy local modifications.\n\n(Maybe we could eventually change it to something like \"if we have a \nworking tree, default to --sane, otherwise default to --mixed\").\n\nNOTE! This new mode is certainly not perfect. There's a few things to look \nout for:\n\n - if the index has unmerged entries, \"--sane\" will currently simply \n   refuse to reset (\"you need to resolve your current index first\"). \n   You'll need to use \"--hard\" or similar in this case.\n\n   This is sad, because normally a unmerged index means that the working \n   tree file should have matched the source tree, so the correct action is \n   likely to make --sane reset such a path to the target (like --hard), \n   regardless of dirty state in-tree or in-index. But that's not how \n   read-tree has ever worked, so..\n\n - \"git checkout -m\" actually knows how to do a three-way merge, rather \n   than refuse to update the working tree. So we do know how to do that, \n   and arguably that would be even nicer behavior.\n\n   At the same time it's also arguably true that there is a chance of loss \n   of state (ie you cannot get back to the original tree if the three-way \n   merge ends up resolving cleanly to no diff at all), so the \"refuse to \n   do it\" is in some respects the safer - but less user-friendly - option.\n\nIn other words, I think 'git reset --sane' could become a bit more \nfriendly, but this is already a big improvement. It allows you to undo a \nrecent commit without having to throw your current work away.\n\nYes, yes, with a dirty tree you could always do\n\n\tgit stash\n\tgit reset --hard\n\tgit stash apply\n\ninstead, but isn't \"git reset --sane\" a nice way to handle one particular \nsimple case?\n\nSigned-off-by: Linus Torvalds <torvalds@linux-foundation.org>\n--\n\nHmm? Maybe I'm the only one that does a lot of work with a dirty tree, and \nsure, I can do other things like the \"git stash\" thing, or using \"git \ncheckout\" to actually create a new branch, and then playing games with \nbranch renaming etc to make it work like this one. \n\nBut I suspect others dislike how \"git reset\" works too. But see the \nsuggested improvements above.\n\n builtin-reset.c |   26 ++++++++++++++++++--------\n 1 files changed, 18 insertions(+), 8 deletions(-)\n\ndiff --git a/builtin-reset.c b/builtin-reset.c\nindex 9514b77..05c176d 100644\n--- a/builtin-reset.c\n+++ b/builtin-reset.c\n@@ -20,11 +20,14 @@\n #include \"parse-options.h\"\n \n static const char * const git_reset_usage[] = {\n-\t\"git reset [--mixed | --soft | --hard] [-q] [<commit>]\",\n+\t\"git reset [--mixed | --soft | --hard | --sane] [-q] [<commit>]\",\n \t\"git reset [--mixed] <commit> [--] <paths>...\",\n \tNULL\n };\n \n+enum reset_type { MIXED, SOFT, HARD, SANE, NONE };\n+static const char *reset_type_names[] = { \"mixed\", \"soft\", \"hard\", \"sane\", NULL };\n+\n static char *args_to_str(const char **argv)\n {\n \tchar *buf = NULL;\n@@ -49,7 +52,7 @@ static inline int is_merge(void)\n \treturn !access(git_path(\"MERGE_HEAD\"), F_OK);\n }\n \n-static int reset_index_file(const unsigned char *sha1, int is_hard_reset, int quiet)\n+static int reset_index_file(const unsigned char *sha1, int reset_type, int quiet)\n {\n \tint i = 0;\n \tconst char *args[6];\n@@ -57,9 +60,17 @@ static int reset_index_file(const unsigned char *sha1, int is_hard_reset, int qu\n \targs[i++] = \"read-tree\";\n \tif (!quiet)\n \t\targs[i++] = \"-v\";\n-\targs[i++] = \"--reset\";\n-\tif (is_hard_reset)\n+\tswitch (reset_type) {\n+\tcase SANE:\n \t\targs[i++] = \"-u\";\n+\t\targs[i++] = \"-m\";\n+\t\tbreak;\n+\tcase HARD:\n+\t\targs[i++] = \"-u\";\n+\t\t/* fallthrough */\n+\tdefault:\n+\t\targs[i++] = \"--reset\";\n+\t}\n \targs[i++] = sha1_to_hex(sha1);\n \targs[i] = NULL;\n \n@@ -169,9 +180,6 @@ static void prepend_reflog_action(const char *action, char *buf, size_t size)\n \t\twarning(\"Reflog action message too long: %.*s...\", 50, buf);\n }\n \n-enum reset_type { MIXED, SOFT, HARD, NONE };\n-static const char *reset_type_names[] = { \"mixed\", \"soft\", \"hard\", NULL };\n-\n int cmd_reset(int argc, const char **argv, const char *prefix)\n {\n \tint i = 0, reset_type = NONE, update_ref_status = 0, quiet = 0;\n@@ -186,6 +194,8 @@ int cmd_reset(int argc, const char **argv, const char *prefix)\n \t\tOPT_SET_INT(0, \"soft\", &reset_type, \"reset only HEAD\", SOFT),\n \t\tOPT_SET_INT(0, \"hard\", &reset_type,\n \t\t\t\t\"reset HEAD, index and working tree\", HARD),\n+\t\tOPT_SET_INT(0, \"sane\", &reset_type,\n+\t\t\t\t\"reset HEAD, index and working tree\", SANE),\n \t\tOPT_BOOLEAN('q', NULL, &quiet,\n \t\t\t\t\"disable showing new HEAD in hard reset and progress message\"),\n \t\tOPT_END()\n@@ -266,7 +276,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)\n \t\tif (is_merge() || read_cache() < 0 || unmerged_cache())\n \t\t\tdie(\"Cannot do a soft reset in the middle of a merge.\");\n \t}\n-\telse if (reset_index_file(sha1, (reset_type == HARD), quiet))\n+\telse if (reset_index_file(sha1, reset_type, quiet))\n \t\tdie(\"Could not reset index file to revision '%s'.\", rev);\n \n \t/* Any resets update HEAD to the head being switched to,\n"},{"id":"96879","messageId":"32541b130812010944k3dd825e4pfa8c270ecc75d539@mail.gmail.com","threadId":"16543","inReplyTo":"alpine.LFD.2.00.0812010908120.3256@nehalem.linux-foundation.org","subject":"Re: Add 'sane' mode to 'git reset'","fromName":"Avery Pennarun","fromEmail":"apenwarr@gmail.com","sentAt":"2008-12-01T17:44:52Z","receivedAt":"2008-12-01T17:44:52Z","isPatch":false,"sender":{"key":"apenwarr@gmail.com","avatar":"https://avatars.githubusercontent.com/u/20592?v=4"},"body":"On Mon, Dec 1, 2008 at 12:30 PM, Linus Torvalds\n<torvalds@linux-foundation.org> wrote:\n> So add this kind of mode to \"git reset\", and since it's probably the\n> sanest form of reset (it will not throw any state away), just call it\n> that: \"git reset --sane\". It should probably be the default, but we likely\n> cannot change the semantics of a regular \"git reset\", even though it is\n> unlikely that very many people really use the current (insane) default\n> mode of \"--mixed\" that only resets the index.\n\nFor reference, I advised someone just yesterday to use \"git reset\nHEAD^\" to undo an accidental \"commit -a\" instead of just \"commit\".\nAlso, as far as I know, \"git reset HEAD filename\" is the only\nrecommended way to undo an accidental \"git add\".  (Which I do\nsometimes when I meant to write \"git add -p\".)  Those two options are\npretty common, I think, and are also perfectly \"sane\".\n\nHow about calling it --merge instead?  That's really what it does:\nmerges the diffs from (your current index) to (the requested index)\ninto (your working tree and your index).\n\nOr --keep, because it keeps your working tree changes.\n\nHave fun,\n\nAvery\n"},{"id":"96881","messageId":"gh1907$vu5$1@ger.gmane.org","threadId":"16543","inReplyTo":"32541b130812010944k3dd825e4pfa8c270ecc75d539@mail.gmail.com","subject":"Re: Add 'sane' mode to 'git reset'","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2008-12-01T18:04:57Z","receivedAt":"2008-12-01T18:04:57Z","isPatch":false,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Avery Pennarun wrote:\n> On Mon, Dec 1, 2008 at 12:30 PM, Linus Torvalds\n> <torvalds@linux-foundation.org> wrote:\n\n>> So add this kind of mode to \"git reset\", and since it's probably the\n>> sanest form of reset (it will not throw any state away), just call it\n>> that: \"git reset --sane\". It should probably be the default, but we likely\n>> cannot change the semantics of a regular \"git reset\", even though it is\n>> unlikely that very many people really use the current (insane) default\n>> mode of \"--mixed\" that only resets the index.\n[...]\n\n> How about calling it --merge instead?  That's really what it does:\n> merges the diffs from (your current index) to (the requested index)\n> into (your working tree and your index).\n\nI like it, because it is similar to how \"git checkout --merge\" works.\n \n> Or --keep, because it keeps your working tree changes.\n\nThat is also better than --sane...\n\n-- \nJakub Narebski\nWarsaw, Poland\nShadeHawk on #git\n"},{"id":"96882","messageId":"alpine.LFD.2.00.0812011003360.3256@nehalem.linux-foundation.org","threadId":"16543","inReplyTo":"32541b130812010944k3dd825e4pfa8c270ecc75d539@mail.gmail.com","subject":"Re: Add 'sane' mode to 'git reset'","fromName":"Linus Torvalds","fromEmail":"torvalds@linux-foundation.org","sentAt":"2008-12-01T18:06:24Z","receivedAt":"2008-12-01T18:06:24Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Mon, 1 Dec 2008, Avery Pennarun wrote:\n> \n> For reference, I advised someone just yesterday to use \"git reset\n> HEAD^\" to undo an accidental \"commit -a\" instead of just \"commit\".\n\nYeah, I guess the --mixed default of \"git reset\" is occasionally useful.\n\n> Also, as far as I know, \"git reset HEAD filename\" is the only\n> recommended way to undo an accidental \"git add\".\n\nThe path-name based ones are actually a totally different animal than the \nnon-pathname version of \"git reset\". With pathnames, it won't change the \nactual HEAD, so it's really a totally different class of command, just \nsharing a name.\n\nBut:\n\n> How about calling it --merge instead?  That's really what it does:\n> merges the diffs from (your current index) to (the requested index)\n> into (your working tree and your index).\n\nSure, \"git reset --merge\" would probably be a fine form.\n\n\t\tLinus\n"},{"id":"97101","messageId":"7vr64oc30p.fsf@gitster.siamese.dyndns.org","threadId":"16543","inReplyTo":"alpine.LFD.2.00.0812010908120.3256@nehalem.linux-foundation.org","subject":"Re: Add 'sane' mode to 'git reset'","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-12-03T22:22:46Z","receivedAt":"2008-12-03T22:22:46Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Linus Torvalds <torvalds@linux-foundation.org> writes:\n\n> We have always had a nice way to reset a working tree to another state \n> while carrying our changes around: \"git read-tree -u -m\". Yes, it fails if \n> the target tree is different in the paths that are dirty in the working \n> tree, but this is how we used to switch branches in \"git checkout\", and it \n> worked fine.\n>\n> However, perhaps exactly _because_ we've supported this from very early \n> on, another low-level command, namely \"git reset\", never did. \n>\n> But as time went on, 'git reset' remains as a very common command, while \n> 'git read-tree' is now a very odd and low-level plumbing thing that nobody \n> sane should ever use, because it only makes sense together with other \n> operations like either switching branches or just rewriting HEAD.\n>\n> Which means that we have effectively lost the ability to do something very \n> common: jump to another point in time without always dropping all our \n> dirty state.\n> ...\n> I've wanted this for a long time, since I very commonly carry a dirty \n> tree while working on things. My main 'Makefile' file quite often has the \n> next version already modified, and sometimes I have local modifications \n> that I don't want to commit, but I still do pulls and patch applications, \n> and occasionally want to do \"git reset\" to undo them - while still keeping \n> my local modifications.\n\nI think a bit more explicit description with an example command sequence\nin the documentation is in order.  Here is what I managed to reconstruct\nfrom your description.\n\n    Let's say you have a small change in the Makefile and some other local\n    changes that you would want to keep uncommitted.  Then you receive a\n    pull request that you would want to respond to.  So you do this:\n\n\t$ git pull $URL $branch\n\n    knowing that your own local changes will be safe because pull will\n    refuse to clobber them if the changes in the other person did overlaps\n    with it.  Let's further say that the changes did not overlap, the\n    merge succeeded and you still have your own local changes.\n\n    But after inspecting the result, you realize that you do not want this\n    change after all.  That means rewinding the HEAD back to the previous\n    point (i.e. ORIG_HEAD), match the index to that commit, *and* rewind\n    the work tree back to the state before the merge (i.e. mostly matching\n    the index except for the local changes to Makefile and a handful other\n    files).  \"git reset\" is the command to move the HEAD.  What mode\n    should you use?\n\n    Unfortunately, the only two modes that touch the index and/or the work\n    tree are --mixed and --hard.\n\n    You do not want to use --hard, because it will discard your local\n    changes.  You do not want to use --mixed either, because it will keep\n    not just your local changes but also the changes the merge brought\n    into your work tree.  That's when you would want to use --merge mode.\n\n\t$ git reset --merge ORIG_HEAD\n\n    This command (1) resets the HEAD to the given commit (ORIG_HEAD in\n    this example), and runs \"read-tree -m -u HEAD ORIG_HEAD\" which means\n    (2) resets the index to match the tree recorded by that commit, and\n    (3) updates the files in the work tree for difference between HEAD and\n    ORIG_HEAD, i.e. undoing the changes made between ORIG_HEAD and HEAD.\n    Because you know the work undone in (3) does not overlap with your\n    local changes, this is exactly what you want in such a situation.\n\n    This procedure works just as well when you are accepting patches by\n    replacing \"git pull\" with \"git am\" and \"ORIG_HEAD\" with \"HEAD~$n\"\n    (where $n is the number of patches contained in the e-mailed series)\n    in the above description.\n\nDoes the above describe what you meant?\n\nAlthough I admit that I have used \"read-tree -m -u\" for probably more than\na couple of times in the past 6 months, I really do not recall the exact\nsequence that led me into the situation where it was the most appropriate\ncommand to use.  I do not think any of these occassions were about me\nhaving a wrong commit at HEAD (meaning, I really wanted to read the index\nand update the work tree, without changing where the next commit would\ngo), so obviously my workflow is quite different from yours.\n\nThe recovery procedure I would use in such a case (and I rarely pull while\nmanaging git.git even though I do so in my day job) would be:\n\n\t$ git checkout -b this-needs-more-work\n        $ git checkout master\n\nto stash away the \"topic\" that needs more work in a new branch, and have\n\"checkout\" take me back to where I was with my local modifications, and\nthat is probably why I never felt the need for this new mode (nor did not\nunderstand why you thought very strongly that --merge should be the\ndefault mode and not --mixed).\n"},{"id":"97117","messageId":"alpine.LFD.2.00.0812031634520.3256@nehalem.linux-foundation.org","threadId":"16543","inReplyTo":"7vr64oc30p.fsf@gitster.siamese.dyndns.org","subject":"Re: Add 'sane' mode to 'git reset'","fromName":"Linus Torvalds","fromEmail":"torvalds@linux-foundation.org","sentAt":"2008-12-04T00:39:49Z","receivedAt":"2008-12-04T00:39:49Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Wed, 3 Dec 2008, Junio C Hamano wrote:\n> \n> I think a bit more explicit description with an example command sequence\n> in the documentation is in order.  Here is what I managed to reconstruct\n> from your description.\n> \n>     Let's say you have a small change in the Makefile and some other local\n>     changes that you would want to keep uncommitted.  Then you receive a\n>     pull request that you would want to respond to.  So you do this:\n> \n> \t$ git pull $URL $branch\n> \n>     knowing that your own local changes will be safe because pull will\n>     refuse to clobber them if the changes in the other person did overlaps\n>     with it.  Let's further say that the changes did not overlap, the\n>     merge succeeded and you still have your own local changes.\n> \n>     But after inspecting the result, you realize that you do not want this\n>     change after all.  That means rewinding the HEAD back to the previous\n>     point (i.e. ORIG_HEAD), match the index to that commit, *and* rewind\n>     the work tree back to the state before the merge (i.e. mostly matching\n>     the index except for the local changes to Makefile and a handful other\n>     files).  \"git reset\" is the command to move the HEAD.  What mode\n>     should you use?\n> \n>     Unfortunately, the only two modes that touch the index and/or the work\n>     tree are --mixed and --hard.\n> \n>     You do not want to use --hard, because it will discard your local\n>     changes.  You do not want to use --mixed either, because it will keep\n>     not just your local changes but also the changes the merge brought\n>     into your work tree.  That's when you would want to use --merge mode.\n> \n> \t$ git reset --merge ORIG_HEAD\n\nExactly.\n\n> The recovery procedure I would use in such a case (and I rarely pull while\n> managing git.git even though I do so in my day job) would be:\n> \n> \t$ git checkout -b this-needs-more-work\n>         $ git checkout master\n\nNo, that won't work. The second 'git checkout' does nothing, since \n'master' still has all the broken code in it.\n\nIt would have worked had you started the new branch _before_ the pull, but \nif you had that, then you wouldn't have had anything to reset anyway, \nyou'd just switch back to master and get rid of the new temp-branch.\n\nBut you could probably do something like this:\n\n\tgit checkout -b temp-branch ORIG_HEAD\n\tgit branch -M master\n\nwhich depends on that checkout doing the right thing.\n\n\t\t\tLinus\n"},{"id":"97125","messageId":"7vprk87l8z.fsf_-_@gitster.siamese.dyndns.org","threadId":"16543","inReplyTo":"alpine.LFD.2.00.0812031634520.3256@nehalem.linux-foundation.org","subject":"[RFC/PATCH] Document \"git-reset --merge\"","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-12-04T02:00:12Z","receivedAt":"2008-12-04T02:00:12Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"The commit log message for the feature made it sound as if this is a saner\nversion of --mixed, but the use case presented makes it clear that it is a\nbetter variant of --hard when your changes and somebody else's changes are\nmixed together.\n\nPerhaps we would want to rewrite the example that shows the use of --hard\nnot to talk about recovering from a failed merge?  \n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n Documentation/git-reset.txt |   29 ++++++++++++++++++++++++++++-\n 1 files changed, 28 insertions(+), 1 deletions(-)\n\ndiff --git c/Documentation/git-reset.txt i/Documentation/git-reset.txt\nindex 52aab5e..c542b0c 100644\n--- c/Documentation/git-reset.txt\n+++ i/Documentation/git-reset.txt\n@@ -8,7 +8,7 @@ git-reset - Reset current HEAD to the specified state\n SYNOPSIS\n --------\n [verse]\n-'git reset' [--mixed | --soft | --hard] [-q] [<commit>]\n+'git reset' [--mixed | --soft | --hard | --merge] [-q] [<commit>]\n 'git reset' [-q] [<commit>] [--] <paths>...\n \n DESCRIPTION\n@@ -45,6 +45,11 @@ OPTIONS\n \tswitched to. Any changes to tracked files in the working tree\n \tsince <commit> are lost.\n \n+--merge::\n+\tResets the index to match the tree recorded by the named commit,\n+\tand updates the files that are different between the named commit\n+\tand the current commit in the working tree.\n+\n -q::\n \tBe quiet, only report errors.\n \n@@ -152,6 +157,28 @@ tip of the current branch in ORIG_HEAD, so resetting hard to it\n brings your index file and the working tree back to that state,\n and resets the tip of the branch to that commit.\n \n+Undo a merge or pull inside a dirty work tree::\n++\n+------------\n+$ git pull                         <1>\n+Auto-merging nitfol\n+Merge made by recursive.\n+ nitfol                |   20 +++++----\n+ ...\n+$ git reset --merge ORIG_HEAD      <2>\n+------------\n++\n+<1> Even if you may have local modifications in your\n+working tree, you can safely say \"git pull\" when you know\n+that the change in the other branch does not overlap with\n+them.\n+<2> After inspecting the result of the merge, you may find\n+that the change in the other branch is unsatisfactory.  Running\n+\"git reset --hard ORIG_HEAD\" will let you go back to where you\n+were, but it will discard your local changes, which you do not\n+want.  \"git reset --merge\" keeps your local changes.\n+\n+\n Interrupted workflow::\n +\n Suppose you are interrupted by an urgent fix request while you\n"},{"id":"97126","messageId":"7vk5ag7l3w.fsf@gitster.siamese.dyndns.org","threadId":"16543","inReplyTo":"alpine.LFD.2.00.0812031634520.3256@nehalem.linux-foundation.org","subject":"Re: Add 'sane' mode to 'git reset'","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-12-04T02:03:15Z","receivedAt":"2008-12-04T02:03:15Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Linus Torvalds <torvalds@linux-foundation.org> writes:\n\n> On Wed, 3 Dec 2008, Junio C Hamano wrote:\n>> \n>> The recovery procedure I would use in such a case (and I rarely pull while\n>> managing git.git even though I do so in my day job) would be:\n>> \n>> \t$ git checkout -b this-needs-more-work\n>>      $ git checkout master\n>\n> No, that won't work. The second 'git checkout' does nothing, since \n> 'master' still has all the broken code in it.\n\nYeah, brain-o.  I should have said\n\n\tgit checkout -b needs-more-work\n        git branch -f master master~$n\n        git checkout master\n\nor something like that.\n"}]}