Merge branch 'mg/maint-difftool-vim-readonly'
[gitweb.git] / builtin / checkout.c
index 51ec9778525e08d04d763c0d9e9c72a070c97945..cc97dbc30f1b064a44157897d9e325d934111cee 100644 (file)
@@ -162,7 +162,7 @@ static int checkout_merged(int pos, struct checkout *state)
         * merge.renormalize set, too
         */
        status = ll_merge(&result_buf, path, &ancestor, "base",
-                         &ours, "ours", &theirs, "theirs", 0);
+                         &ours, "ours", &theirs, "theirs", NULL);
        free(ancestor.ptr);
        free(ours.ptr);
        free(theirs.ptr);
@@ -298,7 +298,7 @@ static void show_local_changes(struct object *head, struct diff_options *opts)
        run_diff_index(&rev, 0);
 }
 
-static void describe_detached_head(char *msg, struct commit *commit)
+static void describe_detached_head(const char *msg, struct commit *commit)
 {
        struct strbuf sb = STRBUF_INIT;
        struct pretty_print_context ctx = {0};
@@ -405,7 +405,7 @@ static int merge_working_tree(struct checkout_opts *opts,
                topts.dir->exclude_per_dir = ".gitignore";
                tree = parse_tree_indirect(old->commit ?
                                           old->commit->object.sha1 :
-                                          (unsigned char *)EMPTY_TREE_SHA1_BIN);
+                                          EMPTY_TREE_SHA1_BIN);
                init_tree_desc(&trees[0], tree->buffer, tree->size);
                tree = parse_tree_indirect(new->commit->object.sha1);
                init_tree_desc(&trees[1], tree->buffer, tree->size);
@@ -542,7 +542,17 @@ static void update_refs_for_switch(struct checkout_opts *opts,
        strbuf_addf(&msg, "checkout: moving from %s to %s",
                    old_desc ? old_desc : "(invalid)", new->name);
 
-       if (new->path) {
+       if (!strcmp(new->name, "HEAD") && !new->path && !opts->force_detach) {
+               /* Nothing to do. */
+       } else if (opts->force_detach || !new->path) {  /* No longer on any branch. */
+               update_ref(msg.buf, "HEAD", new->commit->object.sha1, NULL,
+                          REF_NODEREF, DIE_ON_ERR);
+               if (!opts->quiet) {
+                       if (old->path && advice_detached_head)
+                               detach_advice(old->path, new->name);
+                       describe_detached_head("HEAD is now at", new->commit);
+               }
+       } else if (new->path) { /* Switch branches. */
                create_symref("HEAD", new->path, msg.buf);
                if (!opts->quiet) {
                        if (old->path && !strcmp(new->path, old->path))
@@ -564,14 +574,6 @@ static void update_refs_for_switch(struct checkout_opts *opts,
                        if (!file_exists(ref_file) && file_exists(log_file))
                                remove_path(log_file);
                }
-       } else if (opts->force_detach || strcmp(new->name, "HEAD")) {
-               update_ref(msg.buf, "HEAD", new->commit->object.sha1, NULL,
-                          REF_NODEREF, DIE_ON_ERR);
-               if (!opts->quiet) {
-                       if (old->path && advice_detached_head)
-                               detach_advice(old->path, new->name);
-                       describe_detached_head("HEAD is now at", new->commit);
-               }
        }
        remove_branch_state();
        strbuf_release(&msg);
@@ -679,7 +681,6 @@ static const char *unique_tracking_name(const char *name)
 
 static int parse_branchname_arg(int argc, const char **argv,
                                int dwim_new_local_branch_ok,
-                               int force_detach,
                                struct branch_info *new,
                                struct tree **source_tree,
                                unsigned char rev[20],
@@ -711,7 +712,7 @@ static int parse_branchname_arg(int argc, const char **argv,
         *   With no paths, if <something> is _not_ a commit, no -t nor -b
         *   was given, and there is a tracking branch whose name is
         *   <something> in one and only one remote, then this is a short-hand
-        *   to fork local <something> from that remote tracking branch.
+        *   to fork local <something> from that remote-tracking branch.
         *
         *   Otherwise <something> shall not be ambiguous.
         *   - If it's *only* a reference, treat it like case (1).
@@ -756,8 +757,7 @@ static int parse_branchname_arg(int argc, const char **argv,
        new->name = arg;
        setup_branch_path(new);
 
-       if (!force_detach &&
-           check_ref_format(new->path) == CHECK_REF_FORMAT_OK &&
+       if (check_ref_format(new->path) == CHECK_REF_FORMAT_OK &&
            resolve_ref(new->path, branch_rev, 1, NULL))
                hashcpy(rev, branch_rev);
        else
@@ -802,7 +802,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
        int patch_mode = 0;
        int dwim_new_local_branch = 1;
        struct option options[] = {
-               OPT__QUIET(&opts.quiet),
+               OPT__QUIET(&opts.quiet, "suppress progress reporting"),
                OPT_STRING('b', NULL, &opts.new_branch, "branch",
                           "create and checkout a new branch"),
                OPT_STRING('B', NULL, &opts.new_branch_force, "branch",
@@ -816,7 +816,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
                            2),
                OPT_SET_INT('3', "theirs", &opts.writeout_stage, "checkout their version for unmerged files",
                            3),
-               OPT_BOOLEAN('f', "force", &opts.force, "force checkout (throw away local modifications)"),
+               OPT__FORCE(&opts.force, "force checkout (throw away local modifications)"),
                OPT_BOOLEAN('m', "merge", &opts.merge, "perform a 3-way merge with the new branch"),
                OPT_STRING(0, "conflict", &conflict_style, "style",
                           "conflict style (merge or diff3)"),
@@ -906,8 +906,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
                        dwim_new_local_branch &&
                        opts.track == BRANCH_TRACK_UNSPECIFIED &&
                        !opts.new_branch;
-               int n = parse_branchname_arg(argc, argv,
-                               dwim_ok, opts.force_detach,
+               int n = parse_branchname_arg(argc, argv, dwim_ok,
                                &new, &source_tree, rev, &opts.new_branch);
                argv += n;
                argc -= n;