Skip to content

Commit

Permalink
--empty for cherry-pick: working prototype
Browse files Browse the repository at this point in the history
  • Loading branch information
zivarah committed Jan 8, 2024
1 parent 564d025 commit d5b431a
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 9 deletions.
23 changes: 18 additions & 5 deletions Documentation/git-cherry-pick.txt
Original file line number Diff line number Diff line change
Expand Up @@ -139,12 +139,25 @@ effect to your index in a row.
This option overrides that behavior, allowing commits with empty
messages to be cherry picked.

--empty=(drop|keep|ask)::
If a commit being cherry picked duplicates changes already in the
current history, it will become empty.
+
This option determines how these empty commits are handled:
+
* `drop`: These empty commits are dropped.
+
* `keep`: These empty commits are kept. This implies `--allow-empty`.
+
* `ask`: These empty commits cause `cherry-pick` to stop so the user can examine
the commit. This is the default behavior.
+
Note that commits which start empty will cause the cherry-pick to fail (unless
`--allow-empty` is specified).
+

--keep-redundant-commits::
If a commit being cherry picked duplicates a commit already in the
current history, it will become empty. By default these
redundant commits cause `cherry-pick` to stop so the user can
examine the commit. This option overrides that behavior and
creates an empty commit object. Implies `--allow-empty`.
Deprecated synonym for `--empty=keep`.

--strategy=<strategy>::
Use the given merge strategy. Should only be used once.
Expand Down
46 changes: 42 additions & 4 deletions builtin/revert.c
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
//TODO: How to properly handle?
//Should previous empty rebase code have not used strcasecmp?
#include <strings.h>
#include "git-compat-util.h"
#include "config.h"
#include "builtin.h"
Expand Down Expand Up @@ -45,6 +48,31 @@ static const char * const *revert_or_cherry_pick_usage(struct replay_opts *opts)
return opts->action == REPLAY_REVERT ? revert_usage : cherry_pick_usage;
}

//TODO: Centralize?
enum empty_type {
EMPTY_UNSPECIFIED = -1,
EMPTY_DROP,
EMPTY_KEEP,
EMPTY_ASK
};

static int parse_opt_empty(const struct option *opt, const char *arg, int unset)
{
enum empty_type value = EMPTY_UNSPECIFIED;

if (unset || !strcasecmp(arg, "ask"))
value = EMPTY_ASK;
else if (!strcasecmp(arg, "drop"))
value = EMPTY_DROP;
else if (!strcasecmp(arg, "keep"))
value = EMPTY_KEEP;
else
return error(_("unrecognized empty type '%s'; valid values are \"drop\", \"keep\", and \"ask\"."), arg);

*(enum empty_type *)opt->value = value;
return 0;
}

static int option_parse_m(const struct option *opt,
const char *arg, int unset)
{
Expand Down Expand Up @@ -87,6 +115,7 @@ static int run_sequencer(int argc, const char **argv, const char *prefix,
const char * const * usage_str = revert_or_cherry_pick_usage(opts);
const char *me = action_name(opts);
const char *cleanup_arg = NULL;
enum empty_type empty_opt = EMPTY_UNSPECIFIED;
int cmd = 0;
struct option base_options[] = {
OPT_CMDMODE(0, "quit", &cmd, N_("end revert or cherry-pick sequence"), 'q'),
Expand Down Expand Up @@ -116,7 +145,12 @@ static int run_sequencer(int argc, const char **argv, const char *prefix,
OPT_BOOL(0, "ff", &opts->allow_ff, N_("allow fast-forward")),
OPT_BOOL(0, "allow-empty", &opts->allow_empty, N_("preserve initially empty commits")),
OPT_BOOL(0, "allow-empty-message", &opts->allow_empty_message, N_("allow commits with empty messages")),
OPT_BOOL(0, "keep-redundant-commits", &opts->keep_redundant_commits, N_("keep redundant, empty commits")),
//TODO: anything to do for translation here?
OPT_BOOL(0, "keep-redundant-commits", &opts->keep_redundant_commits, N_("deprecated: use --empty=keep instead")),
//TODO: Same - translation?
OPT_CALLBACK_F(0, "empty", &empty_opt, "(drop|keep|ask)",
N_("how to handle commits that become empty"),
PARSE_OPT_NONEG, parse_opt_empty),
OPT_END(),
};
options = parse_options_concat(options, cp_extra);
Expand All @@ -136,9 +170,13 @@ static int run_sequencer(int argc, const char **argv, const char *prefix,
prepare_repo_settings(the_repository);
the_repository->settings.command_requires_full_index = 0;

/* implies allow_empty */
if (opts->keep_redundant_commits)
opts->allow_empty = 1;

if (opts->action == REPLAY_PICK) {
opts->drop_redundant_commits = (empty_opt == EMPTY_DROP);
opts->keep_redundant_commits = opts->keep_redundant_commits || (empty_opt == EMPTY_KEEP);
if (opts->keep_redundant_commits)
opts->allow_empty = 1;
}

if (cleanup_arg) {
opts->default_msg_cleanup = get_cleanup_mode(cleanup_arg, 1);
Expand Down
6 changes: 6 additions & 0 deletions sequencer.c
Original file line number Diff line number Diff line change
Expand Up @@ -2932,6 +2932,9 @@ static int populate_opts_cb(const char *key, const char *value,
else if (!strcmp(key, "options.allow-empty-message"))
opts->allow_empty_message =
git_config_bool_or_int(key, value, ctx->kvi, &error_flag);
else if (!strcmp(key, "options.drop-redundant-commits"))
opts->drop_redundant_commits =
git_config_bool_or_int(key, value, ctx->kvi, &error_flag);
else if (!strcmp(key, "options.keep-redundant-commits"))
opts->keep_redundant_commits =
git_config_bool_or_int(key, value, ctx->kvi, &error_flag);
Expand Down Expand Up @@ -3476,6 +3479,9 @@ static int save_opts(struct replay_opts *opts)
if (opts->allow_empty_message)
res |= git_config_set_in_file_gently(opts_file,
"options.allow-empty-message", "true");
if (opts->drop_redundant_commits)
res |= git_config_set_in_file_gently(opts_file,
"options.drop-redundant-commits", "true");
if (opts->keep_redundant_commits)
res |= git_config_set_in_file_gently(opts_file,
"options.keep-redundant-commits", "true");
Expand Down

0 comments on commit d5b431a

Please sign in to comment.