diff options
Diffstat (limited to 'builtin/revert.c')
-rw-r--r-- | builtin/revert.c | 52 |
1 files changed, 48 insertions, 4 deletions
diff --git a/builtin/revert.c b/builtin/revert.c index b70f4b0af3..7976b5a329 100644 --- a/builtin/revert.c +++ b/builtin/revert.c @@ -13,6 +13,7 @@ #include "revision.h" #include "rerere.h" #include "merge-recursive.h" +#include "refs.h" /* * This implements the builtins revert and cherry-pick. @@ -35,7 +36,7 @@ static const char * const cherry_pick_usage[] = { NULL }; -static int edit, no_replay, no_commit, mainline, signoff; +static int edit, no_replay, no_commit, mainline, signoff, allow_ff; static enum { REVERT, CHERRY_PICK } action; static struct commit *commit; static const char *commit_name; @@ -64,8 +65,19 @@ static void parse_args(int argc, const char **argv) OPT_RERERE_AUTOUPDATE(&allow_rerere_auto), OPT_STRING(0, "strategy", &strategy, "strategy", "merge strategy"), OPT_END(), + OPT_END(), + OPT_END(), }; + if (action == CHERRY_PICK) { + struct option cp_extra[] = { + OPT_BOOLEAN(0, "ff", &allow_ff, "allow fast-forward"), + OPT_END(), + }; + if (parse_options_concat(options, ARRAY_SIZE(options), cp_extra)) + die("program error"); + } + if (parse_options(argc, argv, NULL, options, usage_str, 0) != 1) usage_with_options(usage_str, options); @@ -99,8 +111,13 @@ static int get_message(const char *raw_message, struct commit_message *out) encoding = "UTF-8"; if (!git_commit_encoding) git_commit_encoding = "UTF-8"; - if ((out->reencoded_message = reencode_string(raw_message, - git_commit_encoding, encoding))) + + out->reencoded_message = NULL; + out->message = raw_message; + if (strcmp(encoding, git_commit_encoding)) + out->reencoded_message = reencode_string(raw_message, + git_commit_encoding, encoding); + if (out->reencoded_message) out->message = out->reencoded_message; abbrev = find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV); @@ -281,6 +298,17 @@ static NORETURN void die_dirty_index(const char *me) } } +static int fast_forward_to(const unsigned char *to, const unsigned char *from) +{ + struct ref_lock *ref_lock; + + read_cache(); + if (checkout_fast_forward(from, to)) + exit(1); /* the callee should have complained already */ + ref_lock = lock_any_ref_for_update("HEAD", from, 0); + return write_ref_sha1(ref_lock, to, "cherry-pick"); +} + static void do_recursive_merge(struct commit *base, struct commit *next, const char *base_label, const char *next_label, unsigned char *head, struct strbuf *msgbuf, @@ -343,7 +371,7 @@ static int revert_or_cherry_pick(int argc, const char **argv) struct commit *base, *next, *parent; const char *base_label, *next_label; struct commit_message msg = { NULL, NULL, NULL, NULL, NULL }; - char *defmsg = git_pathdup("MERGE_MSG"); + char *defmsg = NULL; struct strbuf msgbuf = STRBUF_INIT; git_config(git_default_config, NULL); @@ -355,6 +383,17 @@ static int revert_or_cherry_pick(int argc, const char **argv) if (action == REVERT && !no_replay) die("revert is incompatible with replay"); + if (allow_ff) { + if (signoff) + die("cherry-pick --ff cannot be used with --signoff"); + if (no_commit) + die("cherry-pick --ff cannot be used with --no-commit"); + if (no_replay) + die("cherry-pick --ff cannot be used with -x"); + if (edit) + die("cherry-pick --ff cannot be used with --edit"); + } + if (read_cache() < 0) die("git %s: failed to read the index", me); if (no_commit) { @@ -402,6 +441,9 @@ static int revert_or_cherry_pick(int argc, const char **argv) else parent = commit->parents->item; + if (allow_ff && !hashcmp(parent->object.sha1, head)) + return fast_forward_to(commit->object.sha1, head); + if (parent && parse_commit(parent) < 0) die("%s: cannot parse parent commit %s", me, sha1_to_hex(parent->object.sha1)); @@ -417,6 +459,8 @@ static int revert_or_cherry_pick(int argc, const char **argv) * reverse of it if we are revert. */ + defmsg = git_pathdup("MERGE_MSG"); + if (action == REVERT) { base = commit; base_label = msg.label; |