push: avoid suggesting "merging" remote changes
[gitweb.git] / builtin / checkout.c
index b4030121c8e1ccd50c4049184ef7764e141f1cfd..81b4419da51f3211129833a472048d897385bca4 100644 (file)
@@ -22,8 +22,8 @@
 #include "argv-array.h"
 
 static const char * const checkout_usage[] = {
-       "git checkout [options] <branch>",
-       "git checkout [options] [<branch>] -- <file>...",
+       N_("git checkout [options] <branch>"),
+       N_("git checkout [options] [<branch>] -- <file>..."),
        NULL,
 };
 
@@ -35,6 +35,7 @@ struct checkout_opts {
        int force_detach;
        int writeout_stage;
        int overwrite_ignore;
+       int ignore_skipworktree;
 
        const char *new_branch;
        const char *new_branch_force;
@@ -271,24 +272,57 @@ static int checkout_paths(const struct checkout_opts *opts,
                ;
        ps_matched = xcalloc(1, pos);
 
+       /*
+        * Make sure all pathspecs participated in locating the paths
+        * to be checked out.
+        */
        for (pos = 0; pos < active_nr; pos++) {
                struct cache_entry *ce = active_cache[pos];
+               ce->ce_flags &= ~CE_MATCHED;
+               if (!opts->ignore_skipworktree && ce_skip_worktree(ce))
+                       continue;
                if (opts->source_tree && !(ce->ce_flags & CE_UPDATE))
+                       /*
+                        * "git checkout tree-ish -- path", but this entry
+                        * is in the original index; it will not be checked
+                        * out to the working tree and it does not matter
+                        * if pathspec matched this entry.  We will not do
+                        * anything to this entry at all.
+                        */
                        continue;
-               match_pathspec(opts->pathspec, ce->name, ce_namelen(ce), 0, ps_matched);
+               /*
+                * Either this entry came from the tree-ish we are
+                * checking the paths out of, or we are checking out
+                * of the index.
+                *
+                * If it comes from the tree-ish, we already know it
+                * matches the pathspec and could just stamp
+                * CE_MATCHED to it from update_some(). But we still
+                * need ps_matched and read_tree_recursive (and
+                * eventually tree_entry_interesting) cannot fill
+                * ps_matched yet. Once it can, we can avoid calling
+                * match_pathspec() for _all_ entries when
+                * opts->source_tree != NULL.
+                */
+               if (match_pathspec(opts->pathspec, ce->name, ce_namelen(ce),
+                                  0, ps_matched))
+                       ce->ce_flags |= CE_MATCHED;
        }
 
-       if (report_path_error(ps_matched, opts->pathspec, opts->prefix))
+       if (report_path_error(ps_matched, opts->pathspec, opts->prefix)) {
+               free(ps_matched);
                return 1;
+       }
+       free(ps_matched);
 
        /* "checkout -m path" to recreate conflicted state */
        if (opts->merge)
-               unmerge_cache(opts->pathspec);
+               unmerge_marked_index(&the_index);
 
        /* Any unmerged paths? */
        for (pos = 0; pos < active_nr; pos++) {
                struct cache_entry *ce = active_cache[pos];
-               if (match_pathspec(opts->pathspec, ce->name, ce_namelen(ce), 0, NULL)) {
+               if (ce->ce_flags & CE_MATCHED) {
                        if (!ce_stage(ce))
                                continue;
                        if (opts->force) {
@@ -313,9 +347,7 @@ static int checkout_paths(const struct checkout_opts *opts,
        state.refresh_cache = 1;
        for (pos = 0; pos < active_nr; pos++) {
                struct cache_entry *ce = active_cache[pos];
-               if (opts->source_tree && !(ce->ce_flags & CE_UPDATE))
-                       continue;
-               if (match_pathspec(opts->pathspec, ce->name, ce_namelen(ce), 0, NULL)) {
+               if (ce->ce_flags & CE_MATCHED) {
                        if (!ce_stage(ce)) {
                                errs |= checkout_entry(ce, &state, NULL);
                                continue;
@@ -700,7 +732,7 @@ static void suggest_reattach(struct commit *commit, struct rev_info *revs)
                        "If you want to keep them by creating a new branch, "
                        "this may be a good time\nto do so with:\n\n"
                        " git branch new_branch_name %s\n\n"),
-                       sha1_to_hex(commit->object.sha1));
+                       find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV));
 }
 
 /*
@@ -951,6 +983,9 @@ static int switch_unborn_to_new_branch(const struct checkout_opts *opts)
        strbuf_addf(&branch_ref, "refs/heads/%s", opts->new_branch);
        status = create_symref("HEAD", branch_ref.buf, "checkout -b");
        strbuf_release(&branch_ref);
+       if (!opts->quiet)
+               fprintf(stderr, _("Switched to a new branch '%s'\n"),
+                       opts->new_branch);
        return status;
 }
 
@@ -1006,28 +1041,30 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
        char *conflict_style = NULL;
        int dwim_new_local_branch = 1;
        struct option options[] = {
-               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",
-                          "create/reset and checkout a branch"),
-               OPT_BOOLEAN('l', NULL, &opts.new_branch_log, "create reflog for new branch"),
-               OPT_BOOLEAN(0, "detach", &opts.force_detach, "detach the HEAD at named commit"),
-               OPT_SET_INT('t', "track",  &opts.track, "set upstream info for new branch",
+               OPT__QUIET(&opts.quiet, N_("suppress progress reporting")),
+               OPT_STRING('b', NULL, &opts.new_branch, N_("branch"),
+                          N_("create and checkout a new branch")),
+               OPT_STRING('B', NULL, &opts.new_branch_force, N_("branch"),
+                          N_("create/reset and checkout a branch")),
+               OPT_BOOLEAN('l', NULL, &opts.new_branch_log, N_("create reflog for new branch")),
+               OPT_BOOLEAN(0, "detach", &opts.force_detach, N_("detach the HEAD at named commit")),
+               OPT_SET_INT('t', "track",  &opts.track, N_("set upstream info for new branch"),
                        BRANCH_TRACK_EXPLICIT),
-               OPT_STRING(0, "orphan", &opts.new_orphan_branch, "new branch", "new unparented branch"),
-               OPT_SET_INT('2', "ours", &opts.writeout_stage, "checkout our version for unmerged files",
+               OPT_STRING(0, "orphan", &opts.new_orphan_branch, N_("new branch"), N_("new unparented branch")),
+               OPT_SET_INT('2', "ours", &opts.writeout_stage, N_("checkout our version for unmerged files"),
                            2),
-               OPT_SET_INT('3', "theirs", &opts.writeout_stage, "checkout their version for unmerged files",
+               OPT_SET_INT('3', "theirs", &opts.writeout_stage, N_("checkout their version for unmerged files"),
                            3),
-               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_BOOLEAN(0, "overwrite-ignore", &opts.overwrite_ignore, "update ignored files (default)"),
-               OPT_STRING(0, "conflict", &conflict_style, "style",
-                          "conflict style (merge or diff3)"),
-               OPT_BOOLEAN('p', "patch", &opts.patch_mode, "select hunks interactively"),
+               OPT__FORCE(&opts.force, N_("force checkout (throw away local modifications)")),
+               OPT_BOOLEAN('m', "merge", &opts.merge, N_("perform a 3-way merge with the new branch")),
+               OPT_BOOLEAN(0, "overwrite-ignore", &opts.overwrite_ignore, N_("update ignored files (default)")),
+               OPT_STRING(0, "conflict", &conflict_style, N_("style"),
+                          N_("conflict style (merge or diff3)")),
+               OPT_BOOLEAN('p', "patch", &opts.patch_mode, N_("select hunks interactively")),
+               OPT_BOOL(0, "ignore-skip-worktree-bits", &opts.ignore_skipworktree,
+                        N_("do not limit pathspecs to sparse entries only")),
                { OPTION_BOOLEAN, 0, "guess", &dwim_new_local_branch, NULL,
-                 "second guess 'git checkout no-such-branch'",
+                 N_("second guess 'git checkout no-such-branch'"),
                  PARSE_OPT_NOARG | PARSE_OPT_HIDDEN },
                OPT_END(),
        };