Merge branch 'nd/resolve-ref'
authorJunio C Hamano <gitster@pobox.com>
Tue, 20 Dec 2011 00:05:50 +0000 (16:05 -0800)
committerJunio C Hamano <gitster@pobox.com>
Tue, 20 Dec 2011 00:05:50 +0000 (16:05 -0800)
* nd/resolve-ref:
Rename resolve_ref() to resolve_ref_unsafe()
Convert resolve_ref+xstrdup to new resolve_refdup function
revert: convert resolve_ref() to read_ref_full()

1  2 
branch.c
builtin/branch.c
builtin/checkout.c
builtin/commit.c
builtin/merge.c
builtin/revert.c
cache.h
diff --combined branch.c
index c2e625f40c9d77fa048b905ca4a3982da563b299,772a4c251d3df674e6aec0091f7b792820c2f665..9971820a184d9713126c3c9f763dd8f6ec1b1a50
+++ b/branch.c
@@@ -3,6 -3,7 +3,6 @@@
  #include "refs.h"
  #include "remote.h"
  #include "commit.h"
 -#include "sequencer.h"
  
  struct tracking {
        struct refspec spec;
@@@ -181,7 -182,7 +181,7 @@@ int validate_new_branchname(const char 
                const char *head;
                unsigned char sha1[20];
  
-               head = resolve_ref("HEAD", sha1, 0, NULL);
+               head = resolve_ref_unsafe("HEAD", sha1, 0, NULL);
                if (!is_bare_repository() && head && !strcmp(head, ref->buf))
                        die("Cannot force update the current branch.");
        }
  
  void create_branch(const char *head,
                   const char *name, const char *start_name,
 -                 int force, int reflog, enum branch_track track)
 +                 int force, int reflog, int clobber_head,
 +                 enum branch_track track)
  {
        struct ref_lock *lock = NULL;
        struct commit *commit;
                explicit_tracking = 1;
  
        if (validate_new_branchname(name, &ref, force,
 -                                  track == BRANCH_TRACK_OVERRIDE)) {
 +                                  track == BRANCH_TRACK_OVERRIDE ||
 +                                  clobber_head)) {
                if (!force)
                        dont_change_ref = 1;
                else
@@@ -279,4 -278,5 +279,4 @@@ void remove_branch_state(void
        unlink(git_path("MERGE_MSG"));
        unlink(git_path("MERGE_MODE"));
        unlink(git_path("SQUASH_MSG"));
 -      remove_sequencer_state(0);
  }
diff --combined builtin/branch.c
index 465ff6a513f3e314d4a526b6f8ee9f7a7c7b43f4,642b5bd31702abc343232ea5f4431472a20ebb5b..7095718c13b5c4f39186548f5ed12198a3b9e609
@@@ -104,6 -104,7 +104,7 @@@ static int branch_merged(int kind, cons
         */
        struct commit *reference_rev = NULL;
        const char *reference_name = NULL;
+       void *reference_name_to_free = NULL;
        int merged;
  
        if (kind == REF_LOCAL_BRANCH) {
                    branch->merge &&
                    branch->merge[0] &&
                    branch->merge[0]->dst &&
-                   (reference_name =
-                    resolve_ref(branch->merge[0]->dst, sha1, 1, NULL)) != NULL) {
-                       reference_name = xstrdup(reference_name);
+                   (reference_name = reference_name_to_free =
+                    resolve_refdup(branch->merge[0]->dst, sha1, 1, NULL)) != NULL)
                        reference_rev = lookup_commit_reference(sha1);
-               }
        }
        if (!reference_rev)
                reference_rev = head_rev;
                                "         '%s', even though it is merged to HEAD."),
                                name, reference_name);
        }
-       free((char *)reference_name);
+       free(reference_name_to_free);
        return merged;
  }
  
@@@ -253,7 -252,7 +252,7 @@@ static char *resolve_symref(const char 
        int flag;
        const char *dst, *cp;
  
-       dst = resolve_ref(src, sha1, 0, &flag);
+       dst = resolve_ref_unsafe(src, sha1, 0, &flag);
        if (!(dst && (flag & REF_ISSYMREF)))
                return NULL;
        if (prefix && (cp = skip_prefix(dst, prefix)))
@@@ -570,7 -569,6 +569,7 @@@ static void rename_branch(const char *o
        struct strbuf oldref = STRBUF_INIT, newref = STRBUF_INIT, logmsg = STRBUF_INIT;
        struct strbuf oldsection = STRBUF_INIT, newsection = STRBUF_INIT;
        int recovery = 0;
 +      int clobber_head_ok;
  
        if (!oldname)
                die(_("cannot rename the current branch while not on any."));
                        die(_("Invalid branch name: '%s'"), oldname);
        }
  
 -      validate_new_branchname(newname, &newref, force, 0);
 +      /*
 +       * A command like "git branch -M currentbranch currentbranch" cannot
 +       * cause the worktree to become inconsistent with HEAD, so allow it.
 +       */
 +      clobber_head_ok = !strcmp(oldname, newname);
 +
 +      validate_new_branchname(newname, &newref, force, clobber_head_ok);
  
        strbuf_addf(&logmsg, "Branch: renamed %s to %s",
                 oldref.buf, newref.buf);
@@@ -738,10 -730,9 +737,9 @@@ int cmd_branch(int argc, const char **a
  
        track = git_branch_track;
  
-       head = resolve_ref("HEAD", head_sha1, 0, NULL);
+       head = resolve_refdup("HEAD", head_sha1, 0, NULL);
        if (!head)
                die(_("Failed to resolve HEAD as a valid ref."));
-       head = xstrdup(head);
        if (!strcmp(head, "HEAD")) {
                detached = 1;
        } else {
                if (kinds != REF_LOCAL_BRANCH)
                        die(_("-a and -r options to 'git branch' do not make sense with a branch name"));
                create_branch(head, argv[0], (argc == 2) ? argv[1] : head,
 -                            force_create, reflog, track);
 +                            force_create, reflog, 0, track);
        } else
                usage_with_options(builtin_branch_usage, options);
  
diff --combined builtin/checkout.c
index fdd2e0b9d8fc6781810fbf17db956997265f99ea,00740bd6796785cedd8d6baf730016f93a379cd8..011c0561d980064513379601ad6fe230f086d138
@@@ -34,7 -34,6 +34,7 @@@ struct checkout_opts 
        int force_detach;
        int writeout_stage;
        int writeout_error;
 +      int overwrite_ignore;
  
        /* not set by parse_options */
        int branch_exists;
@@@ -410,11 -409,9 +410,11 @@@ static int merge_working_tree(struct ch
                topts.gently = opts->merge && old->commit;
                topts.verbose_update = !opts->quiet;
                topts.fn = twoway_merge;
 -              topts.dir = xcalloc(1, sizeof(*topts.dir));
 -              topts.dir->flags |= DIR_SHOW_IGNORED;
 -              setup_standard_excludes(topts.dir);
 +              if (opts->overwrite_ignore) {
 +                      topts.dir = xcalloc(1, sizeof(*topts.dir));
 +                      topts.dir->flags |= DIR_SHOW_IGNORED;
 +                      setup_standard_excludes(topts.dir);
 +              }
                tree = parse_tree_indirect(old->commit ?
                                           old->commit->object.sha1 :
                                           EMPTY_TREE_SHA1_BIN);
@@@ -543,9 -540,7 +543,9 @@@ static void update_refs_for_switch(stru
                else
                        create_branch(old->name, opts->new_branch, new->name,
                                      opts->new_branch_force ? 1 : 0,
 -                                    opts->new_branch_log, opts->track);
 +                                    opts->new_branch_log,
 +                                    opts->new_branch_force ? 1 : 0,
 +                                    opts->track);
                new->name = opts->new_branch;
                setup_branch_path(new);
        }
                create_symref("HEAD", new->path, msg.buf);
                if (!opts->quiet) {
                        if (old->path && !strcmp(new->path, old->path)) {
 -                              fprintf(stderr, _("Already on '%s'\n"),
 -                                      new->name);
 +                              if (opts->new_branch_force)
 +                                      fprintf(stderr, _("Reset branch '%s'\n"),
 +                                              new->name);
 +                              else
 +                                      fprintf(stderr, _("Already on '%s'\n"),
 +                                              new->name);
                        } else if (opts->new_branch) {
                                if (opts->branch_exists)
                                        fprintf(stderr, _("Switched to and reset branch '%s'\n"), new->name);
@@@ -705,17 -696,14 +705,14 @@@ static int switch_branches(struct check
  {
        int ret = 0;
        struct branch_info old;
+       void *path_to_free;
        unsigned char rev[20];
        int flag;
        memset(&old, 0, sizeof(old));
-       old.path = resolve_ref("HEAD", rev, 0, &flag);
-       if (old.path)
-               old.path = xstrdup(old.path);
+       old.path = path_to_free = resolve_refdup("HEAD", rev, 0, &flag);
        old.commit = lookup_commit_reference_gently(rev, 1);
-       if (!(flag & REF_ISSYMREF)) {
-               free((char *)old.path);
+       if (!(flag & REF_ISSYMREF))
                old.path = NULL;
-       }
  
        if (old.path && !prefixcmp(old.path, "refs/heads/"))
                old.name = old.path + strlen("refs/heads/");
        }
  
        ret = merge_working_tree(opts, &old, new);
-       if (ret)
+       if (ret) {
+               free(path_to_free);
                return ret;
+       }
  
        if (!opts->quiet && !old.path && old.commit && new->commit != old.commit)
                orphaned_commit_warning(old.commit);
        update_refs_for_switch(opts, &old, new);
  
        ret = post_checkout_hook(old.commit, new->commit, 1);
-       free((char *)old.path);
+       free(path_to_free);
        return ret || opts->writeout_error;
  }
  
@@@ -937,7 -927,6 +936,7 @@@ int cmd_checkout(int argc, const char *
                            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", &patch_mode, "select hunks interactively"),
  
        memset(&opts, 0, sizeof(opts));
        memset(&new, 0, sizeof(new));
 +      opts.overwrite_ignore = 1;
  
        gitmodules_config();
        git_config(git_checkout_config, &opts);
                struct strbuf buf = STRBUF_INIT;
  
                opts.branch_exists = validate_new_branchname(opts.new_branch, &buf,
 -                                                           !!opts.new_branch_force, 0);
 +                                                           !!opts.new_branch_force,
 +                                                           !!opts.new_branch_force);
  
                strbuf_release(&buf);
        }
diff --combined builtin/commit.c
index 039c04fe9dbbeb4bea15a383f55c23c8c4e60f78,4d39d25109aa7c238246a79bea3d758d9da85026..d0f27f931aae51555083ed6192474eaeb8b1694c
@@@ -81,8 -81,7 +81,8 @@@ static const char *template_file
  static const char *author_message, *author_message_buffer;
  static char *edit_message, *use_message;
  static char *fixup_message, *squash_message;
 -static int all, edit_flag, also, interactive, patch_interactive, only, amend, signoff;
 +static int all, also, interactive, patch_interactive, only, amend, signoff;
 +static int edit_flag = -1; /* unspecified */
  static int quiet, verbose, no_verify, allow_empty, dry_run, renew_authorship;
  static int no_post_rewrite, allow_empty_message;
  static char *untracked_files_arg, *force_date, *ignore_submodule_arg;
@@@ -142,7 -141,7 +142,7 @@@ static struct option builtin_commit_opt
        OPT_BOOLEAN(0, "reset-author", &renew_authorship, "the commit is authored by me now (used with -C-c/--amend)"),
        OPT_BOOLEAN('s', "signoff", &signoff, "add Signed-off-by:"),
        OPT_FILENAME('t', "template", &template_file, "use specified template file"),
 -      OPT_BOOLEAN('e', "edit", &edit_flag, "force edit of commit"),
 +      OPT_BOOL('e', "edit", &edit_flag, "force edit of commit"),
        OPT_STRING(0, "cleanup", &cleanup_arg, "default", "how to strip spaces and #comments from message"),
        OPT_BOOLEAN(0, "status", &include_status, "include status in commit message template"),
        /* end commit message options */
@@@ -395,7 -394,6 +395,7 @@@ static char *prepare_index(int argc, co
                fd = hold_locked_index(&index_lock, 1);
                add_files_to_cache(also ? prefix : NULL, pathspec, 0);
                refresh_cache_or_die(refresh_flags);
 +              update_main_cache_tree(1);
                if (write_cache(fd, active_cache, active_nr) ||
                    close_lock_file(&index_lock))
                        die(_("unable to write new_index file"));
                fd = hold_locked_index(&index_lock, 1);
                refresh_cache_or_die(refresh_flags);
                if (active_cache_changed) {
 +                      update_main_cache_tree(1);
                        if (write_cache(fd, active_cache, active_nr) ||
                            commit_locked_index(&index_lock))
                                die(_("unable to write new_index file"));
@@@ -865,7 -862,10 +865,7 @@@ static int prepare_to_commit(const cha
         */
        discard_cache();
        read_cache_from(index_file);
 -      if (!active_cache_tree)
 -              active_cache_tree = cache_tree();
 -      if (cache_tree_update(active_cache_tree,
 -                            active_cache, active_nr, 0, 0) < 0) {
 +      if (update_main_cache_tree(0)) {
                error(_("Error building trees"));
                return 0;
        }
@@@ -1020,8 -1020,8 +1020,8 @@@ static int parse_and_validate_options(i
  
        if (logfile || message.len || use_message || fixup_message)
                use_editor = 0;
 -      if (edit_flag)
 -              use_editor = 1;
 +      if (0 <= edit_flag)
 +              use_editor = edit_flag;
        if (!use_editor)
                setenv("GIT_EDITOR", ":", 1);
  
@@@ -1304,7 -1304,7 +1304,7 @@@ static void print_summary(const char *p
        rev.diffopt.break_opt = 0;
        diff_setup_done(&rev.diffopt);
  
-       head = resolve_ref("HEAD", junk_sha1, 0, NULL);
+       head = resolve_ref_unsafe("HEAD", junk_sha1, 0, NULL);
        printf("[%s%s ",
                !prefixcmp(head, "refs/heads/") ?
                        head + 11 :
diff --combined builtin/merge.c
index 98ed54a5f5722aba1146cbf627e3b95cc8c14f30,a3cd5e8566af7300703dc925708bce23d6acd7a5..24579409c08f2e24ef3e5f2599a6af1aab8d28cd
@@@ -49,7 -49,6 +49,7 @@@ static int show_diffstat = 1, shortlog_
  static int option_commit = 1, allow_fast_forward = 1;
  static int fast_forward_only, option_edit;
  static int allow_trivial = 1, have_message;
 +static int overwrite_ignore = 1;
  static struct strbuf merge_msg;
  static struct commit_list *remoteheads;
  static struct strategy **use_strategies;
@@@ -209,7 -208,6 +209,7 @@@ static struct option builtin_merge_opti
        OPT_BOOLEAN(0, "abort", &abort_current_merge,
                "abort the current in-progress merge"),
        OPT_SET_INT(0, "progress", &show_progress, "force progress reporting", 1),
 +      OPT_BOOLEAN(0, "overwrite-ignore", &overwrite_ignore, "update ignored files (default)"),
        OPT_END()
  };
  
@@@ -768,12 -766,10 +768,12 @@@ int checkout_fast_forward(const unsigne
        memset(&trees, 0, sizeof(trees));
        memset(&opts, 0, sizeof(opts));
        memset(&t, 0, sizeof(t));
 -      memset(&dir, 0, sizeof(dir));
 -      dir.flags |= DIR_SHOW_IGNORED;
 -      setup_standard_excludes(&dir);
 -      opts.dir = &dir;
 +      if (overwrite_ignore) {
 +              memset(&dir, 0, sizeof(dir));
 +              dir.flags |= DIR_SHOW_IGNORED;
 +              setup_standard_excludes(&dir);
 +              opts.dir = &dir;
 +      }
  
        opts.head_idx = 1;
        opts.src_index = &the_index;
@@@ -1100,6 -1096,7 +1100,7 @@@ int cmd_merge(int argc, const char **ar
        struct commit_list *common = NULL;
        const char *best_strategy = NULL, *wt_strategy = NULL;
        struct commit_list **remotes = &remoteheads;
+       void *branch_to_free;
  
        if (argc == 2 && !strcmp(argv[1], "-h"))
                usage_with_options(builtin_merge_usage, builtin_merge_options);
         * Check if we are _not_ on a detached HEAD, i.e. if there is a
         * current branch.
         */
-       branch = resolve_ref("HEAD", head_sha1, 0, &flag);
-       if (branch) {
-               if (!prefixcmp(branch, "refs/heads/"))
-                       branch += 11;
-               branch = xstrdup(branch);
-       }
+       branch = branch_to_free = resolve_refdup("HEAD", head_sha1, 0, &flag);
+       if (branch && !prefixcmp(branch, "refs/heads/"))
+               branch += 11;
        if (!branch || is_null_sha1(head_sha1))
                head_commit = NULL;
        else
                ret = suggest_conflicts(option_renormalize);
  
  done:
-       free((char *)branch);
+       free(branch_to_free);
        return ret;
  }
diff --combined builtin/revert.c
index 028bcbcd75d21ada2bc0406ff74e3073014bb41f,0c52a8339da655082be22f1ecf9b9bec5e7863e3..fce3f929818d6a7faac5933d585a5217e564f6ba
@@@ -60,14 -60,13 +60,14 @@@ struct replay_opts 
        int allow_rerere_auto;
  
        int mainline;
 -      int commit_argc;
 -      const char **commit_argv;
  
        /* Merge strategy */
        const char *strategy;
        const char **xopts;
        size_t xopts_nr, xopts_alloc;
 +
 +      /* Only used by REPLAY_NONE */
 +      struct rev_info *revs;
  };
  
  #define GIT_REFLOG_ACTION "GIT_REFLOG_ACTION"
@@@ -170,9 -169,9 +170,9 @@@ static void parse_args(int argc, const 
                        die(_("program error"));
        }
  
 -      opts->commit_argc = parse_options(argc, argv, NULL, options, usage_str,
 -                                      PARSE_OPT_KEEP_ARGV0 |
 -                                      PARSE_OPT_KEEP_UNKNOWN);
 +      argc = parse_options(argc, argv, NULL, options, usage_str,
 +                      PARSE_OPT_KEEP_ARGV0 |
 +                      PARSE_OPT_KEEP_UNKNOWN);
  
        /* Check for incompatible subcommands */
        verify_opt_mutually_compatible(me,
                                NULL);
        }
  
 -      else if (opts->commit_argc < 2)
 -              usage_with_options(usage_str, options);
 -
        if (opts->allow_ff)
                verify_opt_compatible(me, "--ff",
                                "--signoff", opts->signoff,
                                "-x", opts->record_origin,
                                "--edit", opts->edit,
                                NULL);
 -      opts->commit_argv = argv;
 +
 +      if (opts->subcommand != REPLAY_NONE) {
 +              opts->revs = NULL;
 +      } else {
 +              opts->revs = xmalloc(sizeof(*opts->revs));
 +              init_revisions(opts->revs, NULL);
 +              opts->revs->no_walk = 1;
 +              if (argc < 2)
 +                      usage_with_options(usage_str, options);
 +              argc = setup_revisions(argc, argv, opts->revs, NULL);
 +      }
 +
 +      if (argc > 1)
 +              usage_with_options(usage_str, options);
  }
  
  struct commit_message {
@@@ -642,15 -631,23 +642,15 @@@ static int do_pick_commit(struct commi
        return res;
  }
  
 -static void prepare_revs(struct rev_info *revs, struct replay_opts *opts)
 +static void prepare_revs(struct replay_opts *opts)
  {
 -      int argc;
 -
 -      init_revisions(revs, NULL);
 -      revs->no_walk = 1;
        if (opts->action != REVERT)
 -              revs->reverse = 1;
 +              opts->revs->reverse ^= 1;
  
 -      argc = setup_revisions(opts->commit_argc, opts->commit_argv, revs, NULL);
 -      if (argc > 1)
 -              usage(*revert_or_cherry_pick_usage(opts));
 -
 -      if (prepare_revision_walk(revs))
 +      if (prepare_revision_walk(opts->revs))
                die(_("revision walk setup failed"));
  
 -      if (!revs->commits)
 +      if (!opts->revs->commits)
                die(_("empty commit set passed"));
  }
  
@@@ -847,13 -844,14 +847,13 @@@ static void read_populate_opts(struct r
  static void walk_revs_populate_todo(struct commit_list **todo_list,
                                struct replay_opts *opts)
  {
 -      struct rev_info revs;
        struct commit *commit;
        struct commit_list **next;
  
 -      prepare_revs(&revs, opts);
 +      prepare_revs(opts);
  
        next = todo_list;
 -      while ((commit = get_revision(&revs)))
 +      while ((commit = get_revision(opts->revs)))
                next = commit_list_append(commit, next);
  }
  
@@@ -903,7 -901,7 +903,7 @@@ static int rollback_single_pick(void
        if (!file_exists(git_path("CHERRY_PICK_HEAD")) &&
            !file_exists(git_path("REVERT_HEAD")))
                return error(_("no cherry-pick or revert in progress"));
-       if (!resolve_ref("HEAD", head_sha1, 0, NULL))
+       if (read_ref_full("HEAD", head_sha1, 0, NULL))
                return error(_("cannot resolve HEAD"));
        if (is_null_sha1(head_sha1))
                return error(_("cannot abort from a branch yet to be born"));
@@@ -944,7 -942,7 +944,7 @@@ static int sequencer_rollback(struct re
        }
        if (reset_for_rollback(sha1))
                goto fail;
 -      remove_sequencer_state(1);
 +      remove_sequencer_state();
        strbuf_release(&buf);
        return 0;
  fail:
@@@ -1018,64 -1016,33 +1018,64 @@@ static int pick_commits(struct commit_l
        for (cur = todo_list; cur; cur = cur->next) {
                save_todo(cur, opts);
                res = do_pick_commit(cur->item, opts);
 -              if (res) {
 -                      if (!cur->next)
 -                              /*
 -                               * An error was encountered while
 -                               * picking the last commit; the
 -                               * sequencer state is useless now --
 -                               * the user simply needs to resolve
 -                               * the conflict and commit
 -                               */
 -                              remove_sequencer_state(0);
 +              if (res)
                        return res;
 -              }
        }
  
        /*
         * Sequence of picks finished successfully; cleanup by
         * removing the .git/sequencer directory
         */
 -      remove_sequencer_state(1);
 +      remove_sequencer_state();
        return 0;
  }
  
 +static int continue_single_pick(void)
 +{
 +      const char *argv[] = { "commit", NULL };
 +
 +      if (!file_exists(git_path("CHERRY_PICK_HEAD")) &&
 +          !file_exists(git_path("REVERT_HEAD")))
 +              return error(_("no cherry-pick or revert in progress"));
 +      return run_command_v_opt(argv, RUN_GIT_CMD);
 +}
 +
 +static int sequencer_continue(struct replay_opts *opts)
 +{
 +      struct commit_list *todo_list = NULL;
 +
 +      if (!file_exists(git_path(SEQ_TODO_FILE)))
 +              return continue_single_pick();
 +      read_populate_opts(&opts);
 +      read_populate_todo(&todo_list, opts);
 +
 +      /* Verify that the conflict has been resolved */
 +      if (file_exists(git_path("CHERRY_PICK_HEAD")) ||
 +          file_exists(git_path("REVERT_HEAD"))) {
 +              int ret = continue_single_pick();
 +              if (ret)
 +                      return ret;
 +      }
 +      if (index_differs_from("HEAD", 0))
 +              return error_dirty_index(opts);
 +      todo_list = todo_list->next;
 +      return pick_commits(todo_list, opts);
 +}
 +
 +static int single_pick(struct commit *cmit, struct replay_opts *opts)
 +{
 +      setenv(GIT_REFLOG_ACTION, action_name(opts), 0);
 +      return do_pick_commit(cmit, opts);
 +}
 +
  static int pick_revisions(struct replay_opts *opts)
  {
        struct commit_list *todo_list = NULL;
        unsigned char sha1[20];
  
 +      if (opts->subcommand == REPLAY_NONE)
 +              assert(opts->revs);
 +
        read_and_refresh_cache(opts);
  
        /*
         * one that is being continued
         */
        if (opts->subcommand == REPLAY_REMOVE_STATE) {
 -              remove_sequencer_state(1);
 +              remove_sequencer_state();
                return 0;
        }
        if (opts->subcommand == REPLAY_ROLLBACK)
                return sequencer_rollback(opts);
 -      if (opts->subcommand == REPLAY_CONTINUE) {
 -              if (!file_exists(git_path(SEQ_TODO_FILE)))
 -                      return error(_("No %s in progress"), action_name(opts));
 -              read_populate_opts(&opts);
 -              read_populate_todo(&todo_list, opts);
 -
 -              /* Verify that the conflict has been resolved */
 -              if (!index_differs_from("HEAD", 0))
 -                      todo_list = todo_list->next;
 -              return pick_commits(todo_list, opts);
 +      if (opts->subcommand == REPLAY_CONTINUE)
 +              return sequencer_continue(opts);
 +
 +      /*
 +       * If we were called as "git cherry-pick <commit>", just
 +       * cherry-pick/revert it, set CHERRY_PICK_HEAD /
 +       * REVERT_HEAD, and don't touch the sequencer state.
 +       * This means it is possible to cherry-pick in the middle
 +       * of a cherry-pick sequence.
 +       */
 +      if (opts->revs->cmdline.nr == 1 &&
 +          opts->revs->cmdline.rev->whence == REV_CMD_REV &&
 +          opts->revs->no_walk &&
 +          !opts->revs->cmdline.rev->flags) {
 +              struct commit *cmit;
 +              if (prepare_revision_walk(opts->revs))
 +                      die(_("revision walk setup failed"));
 +              cmit = get_revision(opts->revs);
 +              if (!cmit || get_revision(opts->revs))
 +                      die("BUG: expected exactly one commit from walk");
 +              return single_pick(cmit, opts);
        }
  
        /*
diff --combined cache.h
index 627fb6a084b3d3e60b10121928c59edb384b96c4,e6436e08e9b4e3335c93930f10e6543e56e8458f..af203fcab0821d667e58fd30eceb5b0be43bf507
+++ b/cache.h
@@@ -35,7 -35,6 +35,7 @@@ int git_inflate(git_zstream *, int flus
  void git_deflate_init(git_zstream *, int level);
  void git_deflate_init_gzip(git_zstream *, int level);
  void git_deflate_end(git_zstream *);
 +int git_deflate_abort(git_zstream *);
  int git_deflate_end_gently(git_zstream *);
  int git_deflate(git_zstream *, int flush);
  unsigned long git_deflate_bound(git_zstream *, unsigned long);
@@@ -598,7 -597,6 +598,7 @@@ extern size_t packed_git_window_size
  extern size_t packed_git_limit;
  extern size_t delta_base_cache_limit;
  extern unsigned long big_file_threshold;
 +extern unsigned long pack_size_limit_cfg;
  extern int read_replace_refs;
  extern int fsync_object_files;
  extern int core_preload_index;
@@@ -867,7 -865,8 +867,8 @@@ extern int read_ref(const char *filenam
   *
   * errno is sometimes set on errors, but not always.
   */
- extern const char *resolve_ref(const char *ref, unsigned char *sha1, int reading, int *flag);
+ extern const char *resolve_ref_unsafe(const char *ref, unsigned char *sha1, int reading, int *flag);
+ extern char *resolve_refdup(const char *ref, unsigned char *sha1, int reading, int *flag);
  
  extern int dwim_ref(const char *str, int len, unsigned char *sha1, char **ref);
  extern int dwim_log(const char *str, int len, unsigned char *sha1, char **ref);