@matheusbsbs / matheus-bagliano / commits / 9db5ebf402
Fork 0

git checkout: create unparented branch by --orphan

Similar to -b, --orphan creates a new branch, but it starts without any commit. After running "git checkout --orphan newbranch", you are on a new branch "newbranch", and the first commit you create from this state will start a new history without any ancestry. "git checkout --orphan" keeps the index and the working tree files intact in order to make it convenient for creating a new history whose trees resemble the ones from the original branch. When creating a branch whose trees have no resemblance to the ones from the original branch, it may be easier to start work on the new branch by untracking and removing all working tree files that came from the original branch, by running a 'git rm -rf .' immediately after running "checkout --orphan". Signed-off-by: Erick Mattos <erick.mattos@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Erick Mattos committed Mar 21, 2010 at 12:34 UTC 9db5ebf4022d8e11ac20e75a3d43af161b752fcd
3 files changed +122 -3
Documentation/git-checkout.txt
+19 -1
@@ -9,7 +9,7 @@ SYNOPSIS
9 --------
10 [verse]
11 'git checkout' [-q] [-f] [-m] [<branch>]
12 -'git checkout' [-q] [-f] [-m] [-b <new_branch>] [<start_point>]
12 +'git checkout' [-q] [-f] [-m] [[-b|--orphan] <new_branch>] [<start_point>]
13 'git checkout' [-f|--ours|--theirs|-m|--conflict=<style>] [<tree-ish>] [--] <paths>...
14 'git checkout' --patch [<tree-ish>] [--] [<paths>...]
15
@@ -90,6 +90,24 @@ explicitly give a name with '-b' in such a case.
90 Create the new branch's reflog; see linkgit:git-branch[1] for
91 details.
92
93 +--orphan::
94 + Create a new branch named <new_branch>, unparented to any other
95 + branch. The new branch you switch to does not have any commit
96 + and after the first one it will become the root of a new history
97 + completely unconnected from all the other branches.
98 ++
99 +When you use "--orphan", the index and the working tree are kept intact.
100 +This allows you to start a new history that records set of paths similar
101 +to that of the start-point commit, which is useful when you want to keep
102 +different branches for different audiences you are working to like when
103 +you have an open source and commercial versions of a software, for example.
104 ++
105 +If you want to start a disconnected history that records set of paths
106 +totally different from the original branch, you may want to first clear
107 +the index and the working tree, by running "git rm -rf ." from the
108 +top-level of the working tree, before preparing your files (by copying
109 +from elsewhere, extracting a tarball, etc.) in the working tree.
110 +
111 -m::
112 --merge::
113 When switching branches,
builtin/checkout.c
+13 -2
@@ -33,6 +33,7 @@ struct checkout_opts {
33 int writeout_error;
34
35 const char *new_branch;
36 + const char *new_orphan_branch;
37 int new_branch_log;
38 enum branch_track track;
39 };
@@ -491,8 +492,9 @@ static void update_refs_for_switch(struct checkout_opts *opts,
492 struct strbuf msg = STRBUF_INIT;
493 const char *old_desc;
494 if (opts->new_branch) {
494 - create_branch(old->name, opts->new_branch, new->name, 0,
495 - opts->new_branch_log, opts->track);
495 + if (!opts->new_orphan_branch)
496 + create_branch(old->name, opts->new_branch, new->name, 0,
497 + opts->new_branch_log, opts->track);
498 new->name = opts->new_branch;
499 setup_branch_path(new);
500 }
@@ -632,6 +634,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
634 OPT_BOOLEAN('l', NULL, &opts.new_branch_log, "log for new branch"),
635 OPT_SET_INT('t', "track", &opts.track, "track",
636 BRANCH_TRACK_EXPLICIT),
637 + OPT_STRING(0, "orphan", &opts.new_orphan_branch, "new branch", "new unparented branch"),
638 OPT_SET_INT('2', "ours", &opts.writeout_stage, "stage",
639 2),
640 OPT_SET_INT('3', "theirs", &opts.writeout_stage, "stage",
@@ -677,6 +680,14 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
680 opts.new_branch = argv0 + 1;
681 }
682
683 + if (opts.new_orphan_branch) {
684 + if (opts.new_branch)
685 + die("--orphan and -b are mutually exclusive");
686 + if (opts.track > 0 || opts.new_branch_log)
687 + die("--orphan cannot be used with -t or -l");
688 + opts.new_branch = opts.new_orphan_branch;
689 + }
690 +
691 if (conflict_style) {
692 opts.merge = 1; /* implied */
693 git_xmerge_config("merge.conflictstyle", conflict_style, NULL);
t/t2017-checkout-orphan.sh new
+90
@@ -0,0 +1,90 @@
1 +#!/bin/sh
2 +#
3 +# Copyright (c) 2010 Erick Mattos
4 +#
5 +
6 +test_description='git checkout --orphan
7 +
8 +Main Tests for --orphan functionality.'
9 +
10 +. ./test-lib.sh
11 +
12 +TEST_FILE=foo
13 +
14 +test_expect_success 'Setup' '
15 + echo "Initial" >"$TEST_FILE" &&
16 + git add "$TEST_FILE" &&
17 + git commit -m "First Commit"
18 + test_tick &&
19 + echo "State 1" >>"$TEST_FILE" &&
20 + git add "$TEST_FILE" &&
21 + test_tick &&
22 + git commit -m "Second Commit"
23 +'
24 +
25 +test_expect_success '--orphan creates a new orphan branch from HEAD' '
26 + git checkout --orphan alpha &&
27 + test_must_fail git rev-parse --verify HEAD &&
28 + test "refs/heads/alpha" = "$(git symbolic-ref HEAD)" &&
29 + test_tick &&
30 + git commit -m "Third Commit" &&
31 + test_must_fail git rev-parse --verify HEAD^ &&
32 + git diff-tree --quiet master alpha
33 +'
34 +
35 +test_expect_success '--orphan creates a new orphan branch from <start_point>' '
36 + git checkout master &&
37 + git checkout --orphan beta master^ &&
38 + test_must_fail git rev-parse --verify HEAD &&
39 + test "refs/heads/beta" = "$(git symbolic-ref HEAD)" &&
40 + test_tick &&
41 + git commit -m "Fourth Commit" &&
42 + test_must_fail git rev-parse --verify HEAD^ &&
43 + git diff-tree --quiet master^ beta
44 +'
45 +
46 +test_expect_success '--orphan must be rejected with -b' '
47 + git checkout master &&
48 + test_must_fail git checkout --orphan new -b newer &&
49 + test refs/heads/master = "$(git symbolic-ref HEAD)"
50 +'
51 +
52 +test_expect_success '--orphan is rejected with an existing name' '
53 + git checkout master &&
54 + test_must_fail git checkout --orphan master &&
55 + test refs/heads/master = "$(git symbolic-ref HEAD)"
56 +'
57 +
58 +test_expect_success '--orphan refuses to switch if a merge is needed' '
59 + git checkout master &&
60 + git reset --hard &&
61 + echo local >>"$TEST_FILE" &&
62 + cat "$TEST_FILE" >"$TEST_FILE.saved" &&
63 + test_must_fail git checkout --orphan gamma master^ &&
64 + test refs/heads/master = "$(git symbolic-ref HEAD)" &&
65 + test_cmp "$TEST_FILE" "$TEST_FILE.saved" &&
66 + git diff-index --quiet --cached HEAD &&
67 + git reset --hard
68 +'
69 +
70 +test_expect_success '--orphan does not mix well with -t' '
71 + git checkout master &&
72 + test_must_fail git checkout -t master --orphan gamma &&
73 + test refs/heads/master = "$(git symbolic-ref HEAD)"
74 +'
75 +
76 +test_expect_success '--orphan ignores branch.autosetupmerge' '
77 + git checkout -f master &&
78 + git config branch.autosetupmerge always &&
79 + git checkout --orphan delta &&
80 + test -z "$(git config branch.delta.merge)" &&
81 + test refs/heads/delta = "$(git symbolic-ref HEAD)" &&
82 + test_must_fail git rev-parse --verify HEAD^
83 +'
84 +
85 +test_expect_success '--orphan does not mix well with -l' '
86 + git checkout -f master &&
87 + test_must_fail git checkout -l --orphan gamma
88 +'
89 +
90 +test_done