Code

Merge branch 'jl/submodule-ignore-diff'
[git.git] / builtin / checkout.c
index 829442932f1711ecaea99180e7d3f6875f963832..560eae17159290c5adcefd2e2e2da5825ac6b75d 100644 (file)
@@ -33,7 +33,11 @@ struct checkout_opts {
        int writeout_stage;
        int writeout_error;
 
+       /* not set by parse_options */
+       int branch_exists;
+
        const char *new_branch;
+       const char *new_branch_force;
        const char *new_orphan_branch;
        int new_branch_log;
        enum branch_track track;
@@ -152,6 +156,10 @@ static int checkout_merged(int pos, struct checkout *state)
        read_mmblob(&ours, active_cache[pos+1]->sha1);
        read_mmblob(&theirs, active_cache[pos+2]->sha1);
 
+       /*
+        * NEEDSWORK: re-create conflicts from merges with
+        * merge.renormalize set, too
+        */
        status = ll_merge(&result_buf, path, &ancestor, "base",
                          &ours, "ours", &theirs, "theirs", 0);
        free(ancestor.ptr);
@@ -281,7 +289,6 @@ static void show_local_changes(struct object *head, struct diff_options *opts)
        struct rev_info rev;
        /* I think we want full paths, even if we're in a subdirectory. */
        init_revisions(&rev, NULL);
-       rev.abbrev = 0;
        rev.diffopt.flags = opts->flags;
        rev.diffopt.output_format |= DIFF_FORMAT_NAME_STATUS;
        if (diff_setup_done(&rev.diffopt) < 0)
@@ -376,7 +383,7 @@ static int merge_working_tree(struct checkout_opts *opts,
                topts.src_index = &the_index;
                topts.dst_index = &the_index;
 
-               topts.msgs.not_uptodate_file = "You have local changes to '%s'; cannot switch branches.";
+               setup_unpack_trees_porcelain(&topts, "checkout");
 
                refresh_cache(REFRESH_QUIET);
 
@@ -436,6 +443,13 @@ static int merge_working_tree(struct checkout_opts *opts,
                         */
 
                        add_files_to_cache(NULL, NULL, 0);
+                       /*
+                        * NEEDSWORK: carrying over local changes
+                        * when branches have different end-of-line
+                        * normalization (or clean+smudge rules) is
+                        * a pain; plumb in an option to set
+                        * o.renormalize?
+                        */
                        init_merge_options(&o);
                        o.verbosity = 0;
                        work = write_tree_from_memory(&o);
@@ -514,7 +528,8 @@ static void update_refs_for_switch(struct checkout_opts *opts,
                        }
                }
                else
-                       create_branch(old->name, opts->new_branch, new->name, 0,
+                       create_branch(old->name, opts->new_branch, new->name,
+                                     opts->new_branch_force ? 1 : 0,
                                      opts->new_branch_log, opts->track);
                new->name = opts->new_branch;
                setup_branch_path(new);
@@ -532,9 +547,12 @@ static void update_refs_for_switch(struct checkout_opts *opts,
                        if (old->path && !strcmp(new->path, old->path))
                                fprintf(stderr, "Already on '%s'\n",
                                        new->name);
-                       else
+                       else if (opts->new_branch)
                                fprintf(stderr, "Switched to%s branch '%s'\n",
-                                       opts->new_branch ? " a new" : "",
+                                       opts->branch_exists ? " and reset" : " a new",
+                                       new->name);
+                       else
+                               fprintf(stderr, "Switched to branch '%s'\n",
                                        new->name);
                }
                if (old->path && old->name) {
@@ -669,7 +687,10 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
        int dwim_new_local_branch = 1;
        struct option options[] = {
                OPT__QUIET(&opts.quiet),
-               OPT_STRING('b', NULL, &opts.new_branch, "new branch", "branch"),
+               OPT_STRING('b', NULL, &opts.new_branch, "branch",
+                          "create and checkout a new branch"),
+               OPT_STRING('B', NULL, &opts.new_branch_force, "branch",
+                          "create/reset and checkout a branch"),
                OPT_BOOLEAN('l', NULL, &opts.new_branch_log, "log for new branch"),
                OPT_SET_INT('t', "track",  &opts.track, "track",
                        BRANCH_TRACK_EXPLICIT),
@@ -701,6 +722,14 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
        argc = parse_options(argc, argv, prefix, options, checkout_usage,
                             PARSE_OPT_KEEP_DASHDASH);
 
+       /* we can assume from now on new_branch = !new_branch_force */
+       if (opts.new_branch && opts.new_branch_force)
+               die("-B cannot be used with -b");
+
+       /* copy -B over to -b, so that we can just check the latter */
+       if (opts.new_branch_force)
+               opts.new_branch = opts.new_branch_force;
+
        if (patch_mode && (opts.track > 0 || opts.new_branch
                           || opts.new_branch_log || opts.merge || opts.force))
                die ("--patch is incompatible with all other options");
@@ -722,7 +751,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
 
        if (opts.new_orphan_branch) {
                if (opts.new_branch)
-                       die("--orphan and -b are mutually exclusive");
+                       die("--orphan and -b|-B are mutually exclusive");
                if (opts.track > 0)
                        die("--orphan cannot be used with -t");
                opts.new_branch = opts.new_orphan_branch;
@@ -871,8 +900,12 @@ no_reference:
                if (strbuf_check_branch_ref(&buf, opts.new_branch))
                        die("git checkout: we do not like '%s' as a branch name.",
                            opts.new_branch);
-               if (!get_sha1(buf.buf, rev))
-                       die("git checkout: branch %s already exists", opts.new_branch);
+               if (!get_sha1(buf.buf, rev)) {
+                       opts.branch_exists = 1;
+                       if (!opts.new_branch_force)
+                               die("git checkout: branch %s already exists",
+                                   opts.new_branch);
+               }
                strbuf_release(&buf);
        }