{"thread":{"id":"23054","subject":"[PATCH v4] git checkout -b: unparent the new branch with -o","startedAt":"2010-03-17T18:46:24Z","lastAt":"2010-03-17T21:48:06Z","messageCount":2,"participants":["Erick Mattos","Junio C Hamano"],"isPatch":true,"patchVersion":4,"patchTotal":null},"messages":[{"id":"137049","messageId":"1268851584-10988-1-git-send-email-erick.mattos@gmail.com","threadId":"23054","inReplyTo":null,"subject":"[PATCH v4] git checkout -b: unparent the new branch with -o","fromName":"Erick Mattos","fromEmail":"erick.mattos@gmail.com","sentAt":"2010-03-17T18:46:24Z","receivedAt":"2010-03-17T18:46:24Z","isPatch":true,"sender":{"key":"erick.mattos@gmail.com","avatar":"https://avatars.githubusercontent.com/u/134001?v=4"},"body":"Sometimes it is interesting to start a new unparented branch in an\nexisting repository.\n\nThe new -o/--orphan is intended to solve this situation allowing the\ncreation of a new branch unparented to any other.\n\nAfter the 'checkout -o -b' you are in an new unborn branch ready to be\ncommitted which will start a new history without any ancestry.\n\nBy a 'git commit -a' the commit tree is going to resemble the one from\nthe previous branch.  This way you begin a \"mostly common paths\" work\nflow.\n\nIn case you are doing this orphan branch intending to start a \"no common\npaths\" work flow then with a 'git rm -rf .' you are ready to go.\n\nSigned-off-by: Erick Mattos <erick.mattos@gmail.com>\n---\n\nTrying to be concise and more positive on this new option descriptions.  :-)\n\n Documentation/git-checkout.txt |   18 ++++++++++++++\n builtin/checkout.c             |   10 ++++++-\n t/t2017-checkout-orphan.sh     |   49 ++++++++++++++++++++++++++++++++++++++++\n 3 files changed, 75 insertions(+), 2 deletions(-)\n create mode 100755 t/t2017-checkout-orphan.sh\n\ndiff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt\nindex 37c1810..35a6194 100644\n--- a/Documentation/git-checkout.txt\n+++ b/Documentation/git-checkout.txt\n@@ -9,6 +9,7 @@ SYNOPSIS\n --------\n [verse]\n 'git checkout' [-q] [-f] [-m] [<branch>]\n+'git checkout' [-q] [-f] [-m] [-b <new_branch> [-o]]\n 'git checkout' [-q] [-f] [-m] [-b <new_branch>] [<start_point>]\n 'git checkout' [-f|--ours|--theirs|-m|--conflict=<style>] [<tree-ish>] [--] <paths>...\n 'git checkout' --patch [<tree-ish>] [--] [<paths>...]\n@@ -26,6 +27,18 @@ use the --track or --no-track options, which will be passed to `git\n branch`.  As a convenience, --track without `-b` implies branch\n creation; see the description of --track below.\n \n+When using -b, it is possible to use the option -o to set the new branch\n+as unparented thus unrelated to the previous branch.  After the command\n+you are in an new unborn branch ready to be committed which will start a\n+new history without any ancestry.\n+\n+By a 'git commit -a' the commit tree is going to resemble the one from\n+the previous branch.  This way you begin a \"mostly common paths\" work\n+flow.\n+\n+In case you are doing this orphan branch intending to start a \"no common\n+paths\" work flow then with a 'git rm -rf .' you are ready to go.\n+\n When <paths> or --patch are given, this command does *not* switch\n branches.  It updates the named paths in the working tree from\n the index file, or from a named <tree-ish> (most often a commit).  In\n@@ -86,6 +99,11 @@ explicitly give a name with '-b' in such a case.\n \tDo not set up \"upstream\" configuration, even if the\n \tbranch.autosetupmerge configuration variable is true.\n \n+-o::\n+--orphan::\n+\tWhen creating a new branch, set it up as unparented thus\n+\tunrelated to the previous branch.\n+\n -l::\n \tCreate the new branch's reflog; see linkgit:git-branch[1] for\n \tdetails.\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex acefaaf..405de7e 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -34,6 +34,7 @@ struct checkout_opts {\n \n \tconst char *new_branch;\n \tint new_branch_log;\n+\tint new_branch_orphan;\n \tenum branch_track track;\n };\n \n@@ -491,8 +492,9 @@ static void update_refs_for_switch(struct checkout_opts *opts,\n \tstruct strbuf msg = STRBUF_INIT;\n \tconst char *old_desc;\n \tif (opts->new_branch) {\n-\t\tcreate_branch(old->name, opts->new_branch, new->name, 0,\n-\t\t\t      opts->new_branch_log, opts->track);\n+\t\tif (!opts->new_branch_orphan)\n+\t\t\tcreate_branch(old->name, opts->new_branch, new->name, 0,\n+\t\t\t\t      opts->new_branch_log, opts->track);\n \t\tnew->name = opts->new_branch;\n \t\tsetup_branch_path(new);\n \t}\n@@ -629,6 +631,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)\n \tstruct option options[] = {\n \t\tOPT__QUIET(&opts.quiet),\n \t\tOPT_STRING('b', NULL, &opts.new_branch, \"new branch\", \"branch\"),\n+\t\tOPT_BOOLEAN('o', \"orphan\", &opts.new_branch_orphan, \"make the new branch unparented\"),\n \t\tOPT_BOOLEAN('l', NULL, &opts.new_branch_log, \"log for new branch\"),\n \t\tOPT_SET_INT('t', \"track\",  &opts.track, \"track\",\n \t\t\tBRANCH_TRACK_EXPLICIT),\n@@ -677,6 +680,9 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)\n \t\topts.new_branch = argv0 + 1;\n \t}\n \n+\tif (opts.new_branch_orphan && !opts.new_branch)\n+\t\tdie(\"-o is used only with -b\");\n+\n \tif (conflict_style) {\n \t\topts.merge = 1; /* implied */\n \t\tgit_xmerge_config(\"merge.conflictstyle\", conflict_style, NULL);\ndiff --git a/t/t2017-checkout-orphan.sh b/t/t2017-checkout-orphan.sh\nnew file mode 100755\nindex 0000000..c1b77ac\n--- /dev/null\n+++ b/t/t2017-checkout-orphan.sh\n@@ -0,0 +1,49 @@\n+#!/bin/sh\n+#\n+# Copyright (c) 2010 Erick Mattos\n+#\n+\n+test_description='git checkout -b\n+\n+Tests for -o functionality.'\n+\n+. ./test-lib.sh\n+\n+TEST_FILE=foo\n+\n+test_expect_success 'Setup' '\n+\techo \"initial\" >\"$TEST_FILE\" &&\n+\tgit add \"$TEST_FILE\" &&\n+\tgit commit -m \"First Commit\"\n+'\n+\n+test_expect_success '-b without -o checkout into a new clone branch' '\n+\ttest_tick &&\n+\techo \"Test 1\" >>\"$TEST_FILE\" &&\n+\tgit add \"$TEST_FILE\" &&\n+\tgit commit -m \"Second Commit\" &&\n+\tgit log --pretty=oneline >base &&\n+\tgit checkout -b alpha &&\n+\ttest \"alpha\" = \"$(git symbolic-ref HEAD | sed \"s,.*/,,\")\" &&\n+\tgit log --pretty=oneline >actual &&\n+\ttest_cmp base actual\n+'\n+\n+test_expect_success '-b with -o checkout into an orphan branch' '\n+\tgit checkout -ob beta &&\n+\ttest_must_fail PAGER= git log >/dev/null 2>/dev/null &&\n+\ttest \"beta\" = \"$(git symbolic-ref HEAD | sed \"s,.*/,,\")\" &&\n+\ttest_tick &&\n+\techo \"Test 2\" >>\"$TEST_FILE\" &&\n+\tgit add \"$TEST_FILE\" &&\n+\tgit commit -m \"Third Commit\" &&\n+\tgit log --pretty=oneline >actual &&\n+\ttest 1 -eq $(wc -l actual | sed \"s/ .*//\") &&\n+\t! test_cmp base actual\n+'\n+\n+test_expect_success '-o must be rejected without -b' '\n+\ttest_must_fail git checkout -o alpha\n+'\n+\n+test_done\n-- \n1.7.0.2.277.gc3e85\n"},{"id":"137061","messageId":"7vk4ta7h7t.fsf@alter.siamese.dyndns.org","threadId":"23054","inReplyTo":"1268851584-10988-1-git-send-email-erick.mattos@gmail.com","subject":"Re: [PATCH v4] git checkout -b: unparent the new branch with -o","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2010-03-17T21:48:06Z","receivedAt":"2010-03-17T21:48:06Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Erick Mattos <erick.mattos@gmail.com> writes:\n\n> Sometimes it is interesting to start a new unparented branch in an\n> existing repository.\n\nYou don't have to be \"interesting\".  It is enough to say what it does and\nhow it is used; leave it to readers to judge if they find it useful and\nworthwhile addition.\n\n> The new -o/--orphan is intended to solve this situation allowing the\n> creation of a new branch unparented to any other.\n>\n> After the 'checkout -o -b' you are in an new unborn branch ready to be\n> committed which will start a new history without any ancestry.\n>\n> By a 'git commit -a' the commit tree is going to resemble the one from\n> the previous branch.  This way you begin a \"mostly common paths\" work\n> flow.\n>\n> In case you are doing this orphan branch intending to start a \"no common\n> paths\" work flow then with a 'git rm -rf .' you are ready to go.\n>\n> Signed-off-by: Erick Mattos <erick.mattos@gmail.com>\n> ---\n>\n> Trying to be concise and more positive on this new option descriptions.  :-)\n\nHere is my take on it:\n\n    Similar to -b, --orphan creates a new branch, but it starts without\n    any commit.  After running \"git checkout --orphan newbranch\", you are\n    on a new branch \"newbranch\", and the first commit you create from this\n    state will start a new history without any ancestry before it.\n\n    \"git checkout --orphan\" keeps the index and the working tree files\n    intact, in order to make it convenient for creating a new history\n    whose trees either resemble, the one from the original branch.\n\n    When creating a branch whose trees have no resemblance to the one from\n    the original branch. it may be easier to start work on the new branch\n    by untracking and removing all working tree files that came from the\n    original branch, by running a 'git rm -rf .' immediately after running\n    \"checkout --orphan\".\n\nI realized that -o shouldn't be an additional option to -b, but should be\nan option that is incompatible with -b (and everything that is\nincompatible with -b); --orphan without -b does not make any sense, and\nhaving to type -b when you mean to also say --orphan feels silly.\n\nAlso it is a very special purpose mode of operation that would be rarely\nused in a normal workflow, so I'd rather not give it short-and-sweet -o\nfrom the beginning.  It is not too late to consider adding a short-hand\nonly after people gained experience with it, and found that they were\nusing the option every hour.\n\n> +'git checkout' [-q] [-f] [-m] [-b <new_branch> [-o]]\n>  'git checkout' [-q] [-f] [-m] [-b <new_branch>] [<start_point>]\n\nSo I think these two lines should instead be a single:\n\n'git checkout' [-q] [-f] [-m] [[-b|--orphan] <new_branch>] [<start_point>]\n\nI didn't see anything wrong to start a new rootless branch starting from a\ncommit that is different from where you currently are (did your\nimplementation forbid giving an explicit <start_point>, by the way?).\n\n        Side note:\n        Quiz: What does this sequence do?\n\t$ git checkout --orphan new\n        $ git checkout -\n\n> @@ -26,6 +27,18 @@ use the --track or --no-track options, which will be passed to `git\n>  branch`.  As a convenience, --track without `-b` implies branch\n>  creation; see the description of --track below.\n>  \n> +When using -b, it is possible to use the option -o to set the new branch\n> +as unparented thus unrelated to the previous branch.  After the command\n> +you are in an new unborn branch ready to be committed which will start a\n> +new history without any ancestry.\n> +\n> +By a 'git commit -a' the commit tree is going to resemble the one from\n> +the previous branch.  This way you begin a \"mostly common paths\" work\n> +flow.\n> +In case you are doing this orphan branch intending to start a \"no common\n> +paths\" work flow then with a 'git rm -rf .' you are ready to go.\n> +\n\nReaders won't know what you are talking about by \"mostly common paths\nworkflow\" nor \"no common paths workflow\".\n\nIn any case, I am suggesting to make --orphan separate and parallel to -b,\nso how about removing all of the above, and instead have this:\n\n  --orphan::\n    Creates a new branch and switches to it, but unlike \"-b\", the new\n    branch you switch to does not have any commit (yet).  The first commit\n    in this state will become the root commit of the new history that is\n    disconnected from all the other branches.\n  +\n  When you use \"--orphan\", the index and the working tree are kept intact;\n  this allows you to start a new history that records set of paths similar\n  to that of the start-point commit, which is useful when you want to\n  ... [insert the \"the original history cannot be shown\" example here],\n  for example.\n  +\n  If you want to start a disconnected history that records set of paths\n  totally different from the original branch, you may want to first clear\n  the index and the files in the working tree, by running \"git rm -rf .\"\n  from the top-level of the working tree, before preparing your files (by\n  copying from elsewhere, extracting a tarball, etc.) in the working tree.\n\nIf you cannot give a good use example in-line, you may instead only say\n\"see EXAMPLES section to see how this is useful\" in the above, and then\ngive a more detailed description in the EXAMPLES section.\n\nI already suggested a replacement above, so everything below is a bit of\nmoot point, but I am giving it just for a future reference.\n\n> +-o::\n> +--orphan::\n> +\tWhen creating a new branch, set it up as unparented thus\n> +\tunrelated to the previous branch.\n\nOne good trick I learned when writing\nmanual pages is that if you said \"A thus B\" or \"A (in other words B)\",\nstop and read it again to see if the description makes sense with only \"B\"\nwithout any frills.  It often becomes easier to understand, and if it\ndoesn't then it often means your rephasing with \"thus\" or \"in other words\"\nweren't very helpful for readers.  E.g.\n\n    Create a new branch that is unrelated to the previous branch.\n\nI think \"unrelated\" does not convey what we want to say.  Two topic\nbranches that fork from the same commit may be \"unrelated\" in the sense\nthat they try to fix two independent bugs.  What we want to say is not\n\"related or not\", but \"with a separate root\", or \"disconnected\".\n"}]}