git checkout -b: allow switching out of an unborn branch
authorJunio C Hamano <gitster@pobox.com>
Mon, 30 Jan 2012 20:10:08 +0000 (12:10 -0800)
committerJunio C Hamano <gitster@pobox.com>
Tue, 7 Feb 2012 00:32:15 +0000 (16:32 -0800)
Running "git checkout -b another" immediately after "git init" when you do
not even have a commit on 'master' fails with:

    $ git checkout -b another
    fatal: You are on a branch yet to be born

This is unnecessary, if we redefine "git checkout -b $name" that does not
take any $start_point (which has to be a commit) as "I want to check out a
new branch $name from the state I am in".

Signed-off-by: Junio C Hamano <gitster@pobox.com>
builtin/checkout.c
t/t2015-checkout-unborn.sh

index 4c20dae34d2fc095195d91adae0af26087306277..b76e2c0451cbeb73e1fd227c343413b1c8a33cc7 100644 (file)
@@ -916,6 +916,17 @@ static int parse_branchname_arg(int argc, const char **argv,
        return argcount;
 }
 
+static int switch_unborn_to_new_branch(struct checkout_opts *opts)
+{
+       int status;
+       struct strbuf branch_ref = STRBUF_INIT;
+
+       strbuf_addf(&branch_ref, "refs/heads/%s", opts->new_branch);
+       status = create_symref("HEAD", branch_ref.buf, "checkout -b");
+       strbuf_release(&branch_ref);
+       return status;
+}
+
 int cmd_checkout(int argc, const char **argv, const char *prefix)
 {
        struct checkout_opts opts;
@@ -1089,5 +1100,13 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
        if (opts.writeout_stage)
                die(_("--ours/--theirs is incompatible with switching branches."));
 
+       if (!new.commit) {
+               unsigned char rev[20];
+               int flag;
+
+               resolve_ref("HEAD", rev, 0, &flag);
+               if ((flag & REF_ISSYMREF) && is_null_sha1(rev))
+                       return switch_unborn_to_new_branch(&opts);
+       }
        return switch_branches(&opts, &new);
 }
index c551d39a66c19514e260a7c938b840ce2870d45a..6352b74e2e54e5e08941d8d5d90ac30b202b56c1 100755 (executable)
@@ -1,6 +1,6 @@
 #!/bin/sh
 
-test_description='checkout from unborn branch protects contents'
+test_description='checkout from unborn branch'
 . ./test-lib.sh
 
 test_expect_success 'setup' '
@@ -37,4 +37,13 @@ test_expect_success 'checkout from unborn merges identical index contents' '
        git checkout -b new origin
 '
 
+test_expect_success 'checking out another branch from unborn state' '
+       git checkout --orphan newroot &&
+       git checkout -b anothername &&
+       test_must_fail git show-ref --verify refs/heads/newroot &&
+       git symbolic-ref HEAD >actual &&
+       echo refs/heads/anothername >expect &&
+       test_cmp expect actual
+'
+
 test_done