{"thread":{"id":"23112","subject":"[PATCH v2] git checkout: create unparented branch by --orphan","startedAt":"2010-03-20T20:05:11Z","lastAt":"2010-03-20T20:05:11Z","messageCount":1,"participants":["Erick Mattos"],"isPatch":true,"patchVersion":2,"patchTotal":null},"messages":[{"id":"137364","messageId":"1269115511-21804-1-git-send-email-erick.mattos@gmail.com","threadId":"23112","inReplyTo":null,"subject":"[PATCH v2] git checkout: create unparented branch by --orphan","fromName":"Erick Mattos","fromEmail":"erick.mattos@gmail.com","sentAt":"2010-03-20T20:05:11Z","receivedAt":"2010-03-20T20:05:11Z","isPatch":true,"sender":{"key":"erick.mattos@gmail.com","avatar":"https://avatars.githubusercontent.com/u/134001?v=4"},"body":"Similar to -b, --orphan creates a new branch, but it starts without any\ncommit.  After running \"git checkout --orphan newbranch\", you are on a\nnew branch \"newbranch\", and the first commit you create from this state\nwill start a new history without any ancestry.\n\n\"git checkout --orphan\" keeps the index and the working tree files\nintact in order to make it convenient for creating a new history whose\ntrees resemble the ones from the original branch.\n\nWhen creating a branch whose trees have no resemblance to the ones from\nthe original branch, it may be easier to start work on the new branch by\nuntracking and removing all working tree files that came from the\noriginal branch, by running a 'git rm -rf .' immediately after running\n\"checkout --orphan\".\n\nSigned-off-by: Erick Mattos <erick.mattos@gmail.com>\n---\n\nRearragements and minor changes.\n\n Documentation/git-checkout.txt |   21 ++++++++++++++++-\n builtin/checkout.c             |   13 ++++++++-\n t/t2017-checkout-orphan.sh     |   50 ++++++++++++++++++++++++++++++++++++++++\n 3 files changed, 81 insertions(+), 3 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..5a50997 100644\n--- a/Documentation/git-checkout.txt\n+++ b/Documentation/git-checkout.txt\n@@ -9,7 +9,7 @@ SYNOPSIS\n --------\n [verse]\n 'git checkout' [-q] [-f] [-m] [<branch>]\n-'git checkout' [-q] [-f] [-m] [-b <new_branch>] [<start_point>]\n+'git checkout' [-q] [-f] [-m] [[-b|--orphan] <new_branch>] [<start_point>]\n 'git checkout' [-f|--ours|--theirs|-m|--conflict=<style>] [<tree-ish>] [--] <paths>...\n 'git checkout' --patch [<tree-ish>] [--] [<paths>...]\n \n@@ -90,6 +90,25 @@ explicitly give a name with '-b' in such a case.\n \tCreate the new branch's reflog; see linkgit:git-branch[1] for\n \tdetails.\n \n+--orphan::\n+\tCreate a new branch named <new_branch>, unparented to any other\n+\tbranch.  The new branch you switch to does not have any commit\n+\tand after the first one it will become the root of a new history\n+\tcompletely unconnected from all the other branches.\n++\n+When you use \"--orphan\", a new unparented branch is created having the\n+index and the working tree intact.  This allows you to start a new\n+history that records set of paths similar to that of the start-point\n+commit, which is useful when you want to keep different branches for\n+different audiences you are working to like when you have an open source\n+and commercial versions of a software, 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 working tree, by running \"git rm -rf .\" from the\n+top-level of the working tree, before preparing your files (by copying\n+from elsewhere, extracting a tarball, etc.) in the working tree.\n+\n -m::\n --merge::\n \tWhen switching branches,\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex acefaaf..14b6d6b 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -33,6 +33,7 @@ struct checkout_opts {\n \tint writeout_error;\n \n \tconst char *new_branch;\n+\tconst char *new_orphan_branch;\n \tint new_branch_log;\n \tenum branch_track track;\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_orphan_branch)\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@@ -632,6 +634,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)\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+\t\tOPT_STRING(0, \"orphan\", &opts.new_orphan_branch, \"new branch\", \"new unparented branch\"),\n \t\tOPT_SET_INT('2', \"ours\", &opts.writeout_stage, \"stage\",\n \t\t\t    2),\n \t\tOPT_SET_INT('3', \"theirs\", &opts.writeout_stage, \"stage\",\n@@ -677,6 +680,12 @@ 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_orphan_branch) {\n+\t\tif (opts.new_branch)\n+\t\t\tdie(\"--orphan and -b are mutually exclusive\");\n+\t\topts.new_branch = opts.new_orphan_branch;\n+\t}\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..5a9a3fa\n--- /dev/null\n+++ b/t/t2017-checkout-orphan.sh\n@@ -0,0 +1,50 @@\n+#!/bin/sh\n+#\n+# Copyright (c) 2010 Erick Mattos\n+#\n+\n+test_description='git checkout --orphan\n+\n+Main Tests for --orphan 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+\ttest_tick &&\n+\techo \"State 1\" >>\"$TEST_FILE\" &&\n+\tgit add \"$TEST_FILE\" &&\n+\ttest_tick &&\n+\tgit commit -m \"Second Commit\"\n+'\n+\n+test_expect_success '--orphan creates a new orphan branch from HEAD' '\n+\tgit checkout --orphan alpha &&\n+\ttest_must_fail git rev-parse --verify HEAD &&\n+\ttest \"refs/heads/alpha\" = \"$(git symbolic-ref HEAD)\" &&\n+\ttest_tick &&\n+\tgit commit -m \"Third Commit\" &&\n+\ttest_must_fail git rev-parse --verify HEAD^ &&\n+\tgit diff-tree --quiet master alpha\n+'\n+\n+test_expect_success '--orphan creates a new orphan branch from <start_point>' '\n+\tgit checkout master &&\n+\tgit checkout --orphan beta master^ &&\n+\ttest_must_fail git rev-parse --verify HEAD &&\n+\ttest \"refs/heads/beta\" = \"$(git symbolic-ref HEAD)\" &&\n+\ttest_tick &&\n+\tgit commit -m \"Fourth Commit\" &&\n+\ttest_must_fail git rev-parse --verify HEAD^ &&\n+\tgit diff-tree --quiet master^ beta\n+'\n+\n+test_expect_success '--orphan must be rejected with -b' '\n+\ttest_must_fail git checkout --orphan new -b newer\n+'\n+\n+test_done\n-- \n1.7.0.2.280.g069ed\n"}]}