git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: [PATCH 4/4] cherry-pick: Add `--empty` for more robust redundant commit handling

From
PWPhillip Wood <phillip.wood123@gmail.com>
Date
Jan 23, 2024, 14:25 UTC
Message-ID
<b897771e-c60e-4e41-bfae-3bcfdd832be1@gmail.com>
In-Reply-To
<20240119060721.3734775-5-brianmlyles@gmail.com>
Hi Brian
On 19/01/2024 05:59, brianmlyles@gmail.com wrote:
Show 26 quoted lines
> From: Brian Lyles <brianmlyles@gmail.com>
> 
> As with `git-rebase` and `git-am`, `git-cherry-pick` can result in a
> commit being made redundant if the content from the picked commit is
> already present in the target history. However, `git-cherry-pick` does
> not have the same options available that `git-rebase` and `git-am` have.
> 
> There are three things that can be done with these redundant commits:
> drop them, keep them, or have the cherry-pick stop and wait for the user
> to take an action. `git-rebase` has the `--empty` option added in commit
> e98c4269c8 (rebase (interactive-backend): fix handling of commits that
> become empty, 2020-02-15), which handles all three of these scenarios.
> Similarly, `git-am` got its own `--empty` in 7c096b8d61 (am: support
> --empty=<option> to handle empty patches, 2021-12-09).
> 
> `git-cherry-pick`, on the other hand, only supports two of the three
> possiblities: Keep the redundant commits via `--keep-redundant-commits`,
> or have the cherry-pick fail by not specifying that option. There is no
> way to automatically drop redundant commits.
> 
> In order to bring `git-cherry-pick` more in-line with `git-rebase` and
> `git-am`, this commit adds an `--empty` option to `git-cherry-pick`. It
> has the same three options (keep, drop, and stop), and largely behaves
> the same. The notable difference is that for `git-cherry-pick`, the
> default will be `stop`, which maintains the current behavior when the
> option is not specified.
Thanks for the well explained commit message
> The `--keep-redundant-commits` option will be documented as a deprecated
> synonym of `--empty=keep`, and will be supported for backwards
> compatibility for the time being.

I'm not sure if we need to deprecate it as in "it will be removed in the future" or just reduce it prominence in favor of --empty

Show 36 quoted lines
> Signed-off-by: Brian Lyles <brianmlyles@gmail.com>
> ---
>   Documentation/git-cherry-pick.txt | 28 ++++++++++++++++++-------
>   builtin/revert.c                  | 35 ++++++++++++++++++++++++++++++-
>   sequencer.c                       |  6 ++++++
>   t/t3505-cherry-pick-empty.sh      | 26 ++++++++++++++++++++++-
>   4 files changed, 86 insertions(+), 9 deletions(-)
> 
> diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt
> index 806295a730..8c20a10d4b 100644
> --- a/Documentation/git-cherry-pick.txt
> +++ b/Documentation/git-cherry-pick.txt
> @@ -132,23 +132,37 @@ effect to your index in a row.
>   	keeps commits that were initially empty (i.e. the commit recorded the
>   	same tree as its parent).  Commits which are made empty due to a
>   	previous commit will cause the cherry-pick to fail.  To force the
> -	inclusion of those commits use `--keep-redundant-commits`.
> +	inclusion of those commits use `--empty=keep`.
>   
>   --allow-empty-message::
>   	By default, cherry-picking a commit with an empty message will fail.
>   	This option overrides that behavior, allowing commits with empty
>   	messages to be cherry picked.
>   
> ---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. Note that use of this option only
> +--empty=(stop|drop|keep)::
> +	How to handle commits being cherry-picked that are redundant with
> +	changes already in the current history.
> ++
> +--
> +`stop`;;

I'm still on the fence about "stop" vs "ask". I see in your tests you've accidentally used "ask" which makes me wonder if that is the more familiar term for users who probably use "git rebase" more often than "git am".

Show 84 quoted lines
> +	The cherry-pick will stop when the empty commit is applied, allowing
> +	you to examine the commit. This is the default behavior.
> +`drop`;;
> +	The empty commit will be dropped.
> +`keep`;;
> +	The empty commit will be kept. Note that use of this option only
>   	results in an empty commit when the commit was not initially empty,
>   	but rather became empty due to a previous commit. Commits that were
>   	initially empty will cause the cherry-pick to fail. To force the
>   	inclusion of those commits use `--allow-empty`.
> +--
> ++
> +Note that commits which start empty will cause the cherry-pick to fail (unless
> +`--allow-empty` is specified).
> ++
> +
> +--keep-redundant-commits::
> +	Deprecated synonym for `--empty=keep`.
>   
>   --strategy=<strategy>::
>   	Use the given merge strategy.  Should only be used once.
> diff --git a/builtin/revert.c b/builtin/revert.c
> index b2cfde7a87..1491c45e26 100644
> --- a/builtin/revert.c
> +++ b/builtin/revert.c
> @@ -45,6 +45,30 @@ static const char * const *revert_or_cherry_pick_usage(struct replay_opts *opts)
>   	return opts->action == REPLAY_REVERT ? revert_usage : cherry_pick_usage;
>   }
>   
> +enum empty_action {
> +	STOP_ON_EMPTY_COMMIT = 0,  /* output errors and stop in the middle of a cherry-pick */
> +	DROP_EMPTY_COMMIT,         /* skip with a notice message */
> +	KEEP_EMPTY_COMMIT,         /* keep recording as empty commits */
> +};
> +
> +static int parse_opt_empty(const struct option *opt, const char *arg, int unset)
> +{
> +	int *opt_value = opt->value;
> +
> +	BUG_ON_OPT_NEG(unset);
> +
> +	if (!strcmp(arg, "stop"))
> +		*opt_value = STOP_ON_EMPTY_COMMIT;
> +	else if (!strcmp(arg, "drop"))
> +		*opt_value = DROP_EMPTY_COMMIT;
> +	else if (!strcmp(arg, "keep"))
> +		*opt_value = KEEP_EMPTY_COMMIT;
> +	else
> +		return error(_("invalid value for '%s': '%s'"), "--empty", arg);
> +
> +	return 0;
> +}
> +
>   static int option_parse_m(const struct option *opt,
>   			  const char *arg, int unset)
>   {
> @@ -87,6 +111,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_action empty_opt;
>   	int cmd = 0;
>   	struct option base_options[] = {
>   		OPT_CMDMODE(0, "quit", &cmd, N_("end revert or cherry-pick sequence"), 'q'),
> @@ -116,7 +141,10 @@ 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")),
> +			OPT_BOOL(0, "keep-redundant-commits", &opts->keep_redundant_commits, N_("deprecated: use --empty=keep instead")),
> +			OPT_CALLBACK_F(0, "empty", &empty_opt, "(stop|drop|keep)",
> +				       N_("how to handle commits that become empty"),
> +				       PARSE_OPT_NONEG, parse_opt_empty),
>   			OPT_END(),
>   		};
>   		options = parse_options_concat(options, cp_extra);
> @@ -136,6 +164,11 @@ 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;
>   
> +	if (opts->action == REPLAY_PICK) {
> +		opts->drop_redundant_commits = (empty_opt == DROP_EMPTY_COMMIT);
> +		opts->keep_redundant_commits = opts->keep_redundant_commits || (empty_opt == KEEP_EMPTY_COMMIT);
> +	}

The code changes look good but I think we want to update verify_opt_compatible() to check for "--empty" being combined with "--continue" etc. as well.

Show 24 quoted lines
>   	if (cleanup_arg) {
>   		opts->default_msg_cleanup = get_cleanup_mode(cleanup_arg, 1);
>   		opts->explicit_cleanup = 1;
> diff --git a/sequencer.c b/sequencer.c
> index 582bde8d46..c49c27c795 100644
> --- a/sequencer.c
> +++ b/sequencer.c
> @@ -2934,6 +2934,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);
> @@ -3478,6 +3481,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");

It is good that we're saving the option - it would be good to add a test to check that we remember --empty after stopping for a conflict resolution.

Show 24 quoted lines
>   	if (opts->keep_redundant_commits)
>   		res |= git_config_set_in_file_gently(opts_file,
>   				"options.keep-redundant-commits", "true");
> diff --git a/t/t3505-cherry-pick-empty.sh b/t/t3505-cherry-pick-empty.sh
> index 6adfd25351..ae0cf7886a 100755
> --- a/t/t3505-cherry-pick-empty.sh
> +++ b/t/t3505-cherry-pick-empty.sh
> @@ -89,7 +89,7 @@ test_expect_success 'cherry-pick a commit that becomes no-op (prep)' '
>   	git commit -m "add file2 on the side"
>   '
>   
> -test_expect_success 'cherry-pick a no-op without --keep-redundant' '
> +test_expect_success 'cherry-pick a no-op with neither --keep-redundant nor --empty' '
>   	git reset --hard &&
>   	git checkout fork^0 &&
>   	test_must_fail git cherry-pick main
> @@ -104,4 +104,28 @@ test_expect_success 'cherry-pick a no-op with --keep-redundant' '
>   	test_cmp expect actual
>   '
>   
> +test_expect_success 'cherry-pick a no-op with --empty=ask' '
> +	git reset --hard &&
> +	git checkout fork^0 &&
> +	test_must_fail git cherry-pick --empty=ask main

This is an example of why it is a good idea to check the error message when using "test_must_fail" as here the test will fail due to a bad value passed to "--empty" rather than for the reason we want the test to check. It would be good to add a separate test to check that we reject invalid "--empty" values.

Show 9 quoted lines
> +'
> +
> +test_expect_success 'cherry-pick a no-op with --empty=drop' '
> +	git reset --hard &&
> +	git checkout fork^0 &&
> +	git cherry-pick --empty=drop main &&
> +	git show -s --format=%s >actual &&
> +	echo "add file2 on the side" >expect &&
> +	test_cmp expect actual
I think you could simplify this by using test_commit_message
Best Wishes
Phillip
Previous: Junio C HamanoNext: Junio C Hamano
Message 23 of 118 in “sequencer: Do not require `allow_empty` for redundant commit options”
  1. 1/4 sequencer: Do not require `allow_empty` for redundant commit optionsbrianmlyles@gmail.com, Jan 19, 2024
  2. 2/4 docs: Clean up `--empty` formatting in `git-rebase` and `git-am`brianmlyles@gmail.com, Jan 19, 2024
  3. Phillip WoodJan 23, 2024
  4. Brian LylesJan 27, 2024
  5. Phillip WoodFeb 1, 2024
  6. 3/4 rebase: Update `--empty=ask` to `--empty=drop`brianmlyles@gmail.com, Jan 19, 2024
  7. Phillip WoodJan 23, 2024
  8. Brian LylesJan 27, 2024
  9. Phillip WoodFeb 1, 2024
  10. 4/4 cherry-pick: Add `--empty` for more robust redundant commit handlingbrianmlyles@gmail.com, Jan 19, 2024
  11. Kristoffer HaugsbakkJan 20, 2024
  12. Brian LylesJan 21, 2024
  13. Kristoffer HaugsbakkJan 21, 2024
  14. Junio C HamanoJan 21, 2024
  15. Phillip WoodJan 22, 2024
  16. Kristoffer HaugsbakkJan 22, 2024
  17. Brian LylesJan 23, 2024
  18. Kristoffer HaugsbakkJan 23, 2024
  19. Junio C HamanoJan 23, 2024
  20. Subject: [PATCH] CoC: whitespace fixJunio C Hamano, Jan 23, 2024
  21. Elijah NewrenJan 24, 2024
  22. Junio C HamanoJan 23, 2024
  23. Phillip WoodJan 23, 2024
  24. Junio C HamanoJan 23, 2024
  25. Brian LylesJan 28, 2024
  26. Brian LylesJan 27, 2024
  27. Kristoffer HaugsbakkJan 20, 2024
  28. Brian LylesJan 21, 2024
  29. Phillip WoodJan 23, 2024
  30. Junio C HamanoJan 23, 2024
  31. Phillip WoodJan 24, 2024
  32. Phillip WoodJan 24, 2024
  33. Brian LylesJan 27, 2024
  34. Brian LylesJan 28, 2024
  35. Phillip WoodJan 29, 2024
  36. Brian LylesFeb 10, 2024
  37. Phillip WoodFeb 1, 2024
  38. Brian LylesFeb 10, 2024
  39. 0/8 cherry-pick: add `--empty`Brian Lyles, Feb 10, 2024
  40. phillip.wood123@gmail.comFeb 22, 2024
  41. 1/8 docs: address inaccurate `--empty` default with `--exec`Brian Lyles, Feb 10, 2024
  42. 2/8 docs: clean up `--empty` formatting in git-rebase(1) and git-am(1)Brian Lyles, Feb 10, 2024
  43. 3/8 rebase: update `--empty=ask` to `--empty=drop`Brian Lyles, Feb 10, 2024
  44. Brian LylesFeb 11, 2024
  45. Phillip WoodFeb 14, 2024
  46. phillip.wood123@gmail.comFeb 22, 2024
  47. Junio C HamanoFeb 22, 2024
  48. 4/8 sequencer: treat error reading HEAD as unborn branchBrian Lyles, Feb 10, 2024
  49. phillip.wood123@gmail.comFeb 22, 2024
  50. Brian LylesFeb 23, 2024
  51. phillip.wood123@gmail.comFeb 25, 2024
  52. 5/8 sequencer: do not require `allow_empty` for redundant commit optionsBrian Lyles, Feb 10, 2024
  53. phillip.wood123@gmail.comFeb 22, 2024
  54. 6/8 cherry-pick: decouple `--allow-empty` and `--keep-redundant-commits`Brian Lyles, Feb 10, 2024
  55. Phillip WoodFeb 22, 2024
  56. Junio C HamanoFeb 22, 2024
  57. 7/8 cherry-pick: enforce `--keep-redundant-commits` incompatibilityBrian Lyles, Feb 10, 2024
  58. Phillip WoodFeb 22, 2024
  59. Brian LylesFeb 23, 2024
  60. Junio C HamanoFeb 23, 2024
  61. phillip.wood123@gmail.comFeb 25, 2024
  62. Brian LylesFeb 26, 2024
  63. 8/8 cherry-pick: add `--empty` for more robust redundant commit handlingBrian Lyles, Feb 10, 2024
  64. Jean-Noël AVILAFeb 11, 2024
  65. Brian LylesFeb 12, 2024
  66. phillip.wood123@gmail.comFeb 22, 2024
  67. Brian LylesFeb 23, 2024
  68. phillip.wood123@gmail.comFeb 25, 2024
  69. Brian LylesFeb 26, 2024
  70. Brian LylesFeb 26, 2024
  71. phillip.wood123@gmail.comFeb 27, 2024
  72. Junio C HamanoFeb 27, 2024
  73. 0/7 cherry-pick: add `--empty` for more robust redundant commit handlingBrian Lyles, Mar 10, 2024
  74. phillip.wood123@gmail.comMar 13, 2024
  75. 1/7 docs: address inaccurate `--empty` default with `--exec`Brian Lyles, Mar 10, 2024
  76. 2/7 docs: clean up `--empty` formatting in git-rebase(1) and git-am(1)Brian Lyles, Mar 10, 2024
  77. 3/7 rebase: update `--empty=ask` to `--empty=stop`Brian Lyles, Mar 10, 2024
  78. 4/7 sequencer: treat error reading HEAD as unborn branchBrian Lyles, Mar 10, 2024
  79. Junio C HamanoMar 11, 2024
  80. Junio C HamanoMar 11, 2024
  81. Brian LylesMar 12, 2024
  82. Junio C HamanoMar 12, 2024
  83. Brian LylesMar 16, 2024
  84. phillip.wood123@gmail.comMar 13, 2024
  85. Brian LylesMar 16, 2024
  86. 5/7 sequencer: do not require `allow_empty` for redundant commit optionsBrian Lyles, Mar 10, 2024
  87. 6/7 cherry-pick: enforce `--keep-redundant-commits` incompatibilityBrian Lyles, Mar 10, 2024
  88. 7/7 cherry-pick: add `--empty` for more robust redundant commit handlingBrian Lyles, Mar 10, 2024
  89. phillip.wood123@gmail.comMar 13, 2024
  90. Junio C HamanoMar 13, 2024
  91. Brian LylesMar 16, 2024
  92. phillip.wood123@gmail.comMar 20, 2024
  93. 0/7 cherry-pick: add `--empty` for more robust redundant commit handlingBrian Lyles, Mar 20, 2024
  94. phillip.wood123@gmail.comMar 25, 2024
  95. Brian LylesMar 25, 2024
  96. phillip.wood123@gmail.comMar 25, 2024
  97. Junio C HamanoMar 25, 2024
  98. 1/7 docs: address inaccurate `--empty` default with `--exec`Brian Lyles, Mar 20, 2024
  99. 2/7 docs: clean up `--empty` formatting in git-rebase(1) and git-am(1)Brian Lyles, Mar 20, 2024
  100. 3/7 rebase: update `--empty=ask` to `--empty=stop`Brian Lyles, Mar 20, 2024
  101. 4/7 sequencer: handle unborn branch with `--allow-empty`Brian Lyles, Mar 20, 2024
  102. Dirk GoudersMar 21, 2024
  103. Junio C HamanoMar 21, 2024
  104. Dirk GoudersMar 21, 2024
  105. 5/7 sequencer: do not require `allow_empty` for redundant commit optionsBrian Lyles, Mar 20, 2024
  106. 6/7 cherry-pick: enforce `--keep-redundant-commits` incompatibilityBrian Lyles, Mar 20, 2024
  107. 7/7 cherry-pick: add `--empty` for more robust redundant commit handlingBrian Lyles, Mar 20, 2024
  108. 0/7 cherry-pick: add `--empty` for more robust redundant commit handlingBrian Lyles, Mar 25, 2024
  109. phillip.wood123@gmail.comMar 26, 2024
  110. Junio C HamanoMar 26, 2024
  111. phillip.wood123@gmail.comMar 27, 2024
  112. 1/7 docs: address inaccurate `--empty` default with `--exec`Brian Lyles, Mar 25, 2024
  113. 2/7 docs: clean up `--empty` formatting in git-rebase(1) and git-am(1)Brian Lyles, Mar 25, 2024
  114. 3/7 rebase: update `--empty=ask` to `--empty=stop`Brian Lyles, Mar 25, 2024
  115. 4/7 sequencer: handle unborn branch with `--allow-empty`Brian Lyles, Mar 25, 2024
  116. 5/7 sequencer: do not require `allow_empty` for redundant commit optionsBrian Lyles, Mar 25, 2024
  117. 6/7 cherry-pick: enforce `--keep-redundant-commits` incompatibilityBrian Lyles, Mar 25, 2024
  118. 7/7 cherry-pick: add `--empty` for more robust redundant commit handlingBrian Lyles, Mar 25, 2024

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.