rebase: add --allow-empty-message option
This option allows commits with empty commit messages to be rebased, matching the same option in git-commit and git-cherry-pick. While empty log messages are frowned upon, sometimes one finds them in older repositories (e.g. translated from another VCS [0]), or have other reasons for desiring them. The option is available in git-commit and git-cherry-pick, so it is natural to make other git tools play nicely with them. Adding this as an option allows the default to be "give the user a chance to fix", while not interrupting the user's workflow otherwise [1]. [0]: https://stackoverflow.com/q/8542304 [1]: https://public-inbox.org/git/7vd33afqjh.fsf@alter.siamese.dyndns.org/ To implement this, add a new --allow-empty-message flag. Then propagate it to all calls of 'git commit', 'git cherry-pick', and 'git rebase--helper' within the rebase scripts. Signed-off-by: Genki Sky <sky@genki.is> Reviewed-by: Johannes Schindelin <Johannes.Schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>maint
							parent
							
								
									5be1f00a9a
								
							
						
					
					
						commit
						a6c612b528
					
				|  | @ -244,6 +244,11 @@ leave out at most one of A and B, in which case it defaults to HEAD. | ||||||
| 	Keep the commits that do not change anything from its | 	Keep the commits that do not change anything from its | ||||||
| 	parents in the result. | 	parents in the result. | ||||||
|  |  | ||||||
|  | --allow-empty-message:: | ||||||
|  | 	By default, rebasing commits with an empty message will fail. | ||||||
|  | 	This option overrides that behavior, allowing commits with empty | ||||||
|  | 	messages to be rebased. | ||||||
|  |  | ||||||
| --skip:: | --skip:: | ||||||
| 	Restart the rebasing process by skipping the current patch. | 	Restart the rebasing process by skipping the current patch. | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @ -22,6 +22,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) | ||||||
| 	struct option options[] = { | 	struct option options[] = { | ||||||
| 		OPT_BOOL(0, "ff", &opts.allow_ff, N_("allow fast-forward")), | 		OPT_BOOL(0, "ff", &opts.allow_ff, N_("allow fast-forward")), | ||||||
| 		OPT_BOOL(0, "keep-empty", &keep_empty, N_("keep empty commits")), | 		OPT_BOOL(0, "keep-empty", &keep_empty, N_("keep empty commits")), | ||||||
|  | 		OPT_BOOL(0, "allow-empty-message", &opts.allow_empty_message, | ||||||
|  | 			N_("allow commits with empty messages")), | ||||||
| 		OPT_CMDMODE(0, "continue", &command, N_("continue rebase"), | 		OPT_CMDMODE(0, "continue", &command, N_("continue rebase"), | ||||||
| 				CONTINUE), | 				CONTINUE), | ||||||
| 		OPT_CMDMODE(0, "abort", &command, N_("abort rebase"), | 		OPT_CMDMODE(0, "abort", &command, N_("abort rebase"), | ||||||
|  |  | ||||||
|  | @ -46,6 +46,7 @@ then | ||||||
| 	# makes this easy | 	# makes this easy | ||||||
| 	git cherry-pick ${gpg_sign_opt:+"$gpg_sign_opt"} --allow-empty \ | 	git cherry-pick ${gpg_sign_opt:+"$gpg_sign_opt"} --allow-empty \ | ||||||
| 		$allow_rerere_autoupdate --right-only "$revisions" \ | 		$allow_rerere_autoupdate --right-only "$revisions" \ | ||||||
|  | 		$allow_empty_message \ | ||||||
| 		${restrict_revision+^$restrict_revision} | 		${restrict_revision+^$restrict_revision} | ||||||
| 	ret=$? | 	ret=$? | ||||||
| else | else | ||||||
|  |  | ||||||
|  | @ -281,7 +281,7 @@ pick_one () { | ||||||
|  |  | ||||||
| 	test -d "$rewritten" && | 	test -d "$rewritten" && | ||||||
| 		pick_one_preserving_merges "$@" && return | 		pick_one_preserving_merges "$@" && return | ||||||
| 	output eval git cherry-pick $allow_rerere_autoupdate \ | 	output eval git cherry-pick $allow_rerere_autoupdate $allow_empty_message \ | ||||||
| 			${gpg_sign_opt:+$(git rev-parse --sq-quote "$gpg_sign_opt")} \ | 			${gpg_sign_opt:+$(git rev-parse --sq-quote "$gpg_sign_opt")} \ | ||||||
| 			"$strategy_args" $empty_args $ff "$@" | 			"$strategy_args" $empty_args $ff "$@" | ||||||
|  |  | ||||||
|  | @ -406,6 +406,7 @@ pick_one_preserving_merges () { | ||||||
| 			;; | 			;; | ||||||
| 		*) | 		*) | ||||||
| 			output eval git cherry-pick $allow_rerere_autoupdate \ | 			output eval git cherry-pick $allow_rerere_autoupdate \ | ||||||
|  | 				$allow_empty_message \ | ||||||
| 				${gpg_sign_opt:+$(git rev-parse --sq-quote "$gpg_sign_opt")} \ | 				${gpg_sign_opt:+$(git rev-parse --sq-quote "$gpg_sign_opt")} \ | ||||||
| 				"$strategy_args" "$@" || | 				"$strategy_args" "$@" || | ||||||
| 				die_with_patch $sha1 "$(eval_gettext "Could not pick \$sha1")" | 				die_with_patch $sha1 "$(eval_gettext "Could not pick \$sha1")" | ||||||
|  | @ -559,7 +560,8 @@ do_next () { | ||||||
|  |  | ||||||
| 		mark_action_done | 		mark_action_done | ||||||
| 		do_pick $sha1 "$rest" | 		do_pick $sha1 "$rest" | ||||||
| 		git commit --amend --no-post-rewrite ${gpg_sign_opt:+"$gpg_sign_opt"} || { | 		git commit --amend --no-post-rewrite ${gpg_sign_opt:+"$gpg_sign_opt"} \ | ||||||
|  | 			$allow_empty_message || { | ||||||
| 			warn "$(eval_gettext "\ | 			warn "$(eval_gettext "\ | ||||||
| Could not amend commit after successfully picking \$sha1... \$rest | Could not amend commit after successfully picking \$sha1... \$rest | ||||||
| This is most likely due to an empty commit message, or the pre-commit hook | This is most likely due to an empty commit message, or the pre-commit hook | ||||||
|  | @ -607,7 +609,7 @@ you are able to reword the commit.")" | ||||||
| 			# This is an intermediate commit; its message will only be | 			# This is an intermediate commit; its message will only be | ||||||
| 			# used in case of trouble.  So use the long version: | 			# used in case of trouble.  So use the long version: | ||||||
| 			do_with_author output git commit --amend --no-verify -F "$squash_msg" \ | 			do_with_author output git commit --amend --no-verify -F "$squash_msg" \ | ||||||
| 				${gpg_sign_opt:+"$gpg_sign_opt"} || | 				${gpg_sign_opt:+"$gpg_sign_opt"} $allow_empty_message || | ||||||
| 				die_failed_squash $sha1 "$rest" | 				die_failed_squash $sha1 "$rest" | ||||||
| 			;; | 			;; | ||||||
| 		*) | 		*) | ||||||
|  | @ -615,13 +617,13 @@ you are able to reword the commit.")" | ||||||
| 			if test -f "$fixup_msg" | 			if test -f "$fixup_msg" | ||||||
| 			then | 			then | ||||||
| 				do_with_author git commit --amend --no-verify -F "$fixup_msg" \ | 				do_with_author git commit --amend --no-verify -F "$fixup_msg" \ | ||||||
| 					${gpg_sign_opt:+"$gpg_sign_opt"} || | 					${gpg_sign_opt:+"$gpg_sign_opt"} $allow_empty_message || | ||||||
| 					die_failed_squash $sha1 "$rest" | 					die_failed_squash $sha1 "$rest" | ||||||
| 			else | 			else | ||||||
| 				cp "$squash_msg" "$GIT_DIR"/SQUASH_MSG || exit | 				cp "$squash_msg" "$GIT_DIR"/SQUASH_MSG || exit | ||||||
| 				rm -f "$GIT_DIR"/MERGE_MSG | 				rm -f "$GIT_DIR"/MERGE_MSG | ||||||
| 				do_with_author git commit --amend --no-verify -F "$GIT_DIR"/SQUASH_MSG -e \ | 				do_with_author git commit --amend --no-verify -F "$GIT_DIR"/SQUASH_MSG -e \ | ||||||
| 					${gpg_sign_opt:+"$gpg_sign_opt"} || | 					${gpg_sign_opt:+"$gpg_sign_opt"} $allow_empty_message || | ||||||
| 					die_failed_squash $sha1 "$rest" | 					die_failed_squash $sha1 "$rest" | ||||||
| 			fi | 			fi | ||||||
| 			rm -f "$squash_msg" "$fixup_msg" | 			rm -f "$squash_msg" "$fixup_msg" | ||||||
|  | @ -754,7 +756,8 @@ case "$action" in | ||||||
| continue) | continue) | ||||||
| 	if test ! -d "$rewritten" | 	if test ! -d "$rewritten" | ||||||
| 	then | 	then | ||||||
| 		exec git rebase--helper ${force_rebase:+--no-ff} --continue | 		exec git rebase--helper ${force_rebase:+--no-ff} $allow_empty_message \ | ||||||
|  | 			--continue | ||||||
| 	fi | 	fi | ||||||
| 	# do we have anything to commit? | 	# do we have anything to commit? | ||||||
| 	if git diff-index --cached --quiet HEAD -- | 	if git diff-index --cached --quiet HEAD -- | ||||||
|  | @ -794,11 +797,11 @@ In both cases, once you're done, continue with: | ||||||
| You have uncommitted changes in your working tree. Please commit them | You have uncommitted changes in your working tree. Please commit them | ||||||
| first and then run 'git rebase --continue' again.")" | first and then run 'git rebase --continue' again.")" | ||||||
| 			do_with_author git commit --amend --no-verify -F "$msg" -e \ | 			do_with_author git commit --amend --no-verify -F "$msg" -e \ | ||||||
| 				${gpg_sign_opt:+"$gpg_sign_opt"} || | 				${gpg_sign_opt:+"$gpg_sign_opt"} $allow_empty_message || | ||||||
| 				die "$(gettext "Could not commit staged changes.")" | 				die "$(gettext "Could not commit staged changes.")" | ||||||
| 		else | 		else | ||||||
| 			do_with_author git commit --no-verify -F "$msg" -e \ | 			do_with_author git commit --no-verify -F "$msg" -e \ | ||||||
| 				${gpg_sign_opt:+"$gpg_sign_opt"} || | 				${gpg_sign_opt:+"$gpg_sign_opt"} $allow_empty_message || | ||||||
| 				die "$(gettext "Could not commit staged changes.")" | 				die "$(gettext "Could not commit staged changes.")" | ||||||
| 		fi | 		fi | ||||||
| 	fi | 	fi | ||||||
|  | @ -817,7 +820,8 @@ skip) | ||||||
|  |  | ||||||
| 	if test ! -d "$rewritten" | 	if test ! -d "$rewritten" | ||||||
| 	then | 	then | ||||||
| 		exec git rebase--helper ${force_rebase:+--no-ff} --continue | 		exec git rebase--helper ${force_rebase:+--no-ff} $allow_empty_message \ | ||||||
|  | 			--continue | ||||||
| 	fi | 	fi | ||||||
| 	do_rest | 	do_rest | ||||||
| 	return 0 | 	return 0 | ||||||
|  | @ -1016,7 +1020,8 @@ checkout_onto | ||||||
| if test -z "$rebase_root" && test ! -d "$rewritten" | if test -z "$rebase_root" && test ! -d "$rewritten" | ||||||
| then | then | ||||||
| 	require_clean_work_tree "rebase" | 	require_clean_work_tree "rebase" | ||||||
| 	exec git rebase--helper ${force_rebase:+--no-ff} --continue | 	exec git rebase--helper ${force_rebase:+--no-ff} $allow_empty_message \ | ||||||
|  | 		--continue | ||||||
| fi | fi | ||||||
| do_rest | do_rest | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @ -27,7 +27,8 @@ continue_merge () { | ||||||
| 	cmt=$(cat "$state_dir/current") | 	cmt=$(cat "$state_dir/current") | ||||||
| 	if ! git diff-index --quiet --ignore-submodules HEAD -- | 	if ! git diff-index --quiet --ignore-submodules HEAD -- | ||||||
| 	then | 	then | ||||||
| 		if ! git commit ${gpg_sign_opt:+"$gpg_sign_opt"} --no-verify -C "$cmt" | 		if ! git commit ${gpg_sign_opt:+"$gpg_sign_opt"} $allow_empty_message \ | ||||||
|  | 			--no-verify -C "$cmt" | ||||||
| 		then | 		then | ||||||
| 			echo "Commit failed, please do not call \"git commit\"" | 			echo "Commit failed, please do not call \"git commit\"" | ||||||
| 			echo "directly, but instead do one of the following: " | 			echo "directly, but instead do one of the following: " | ||||||
|  |  | ||||||
|  | @ -24,6 +24,7 @@ m,merge!           use merging strategies to rebase | ||||||
| i,interactive!     let the user edit the list of commits to rebase | i,interactive!     let the user edit the list of commits to rebase | ||||||
| x,exec=!           add exec lines after each commit of the editable list | x,exec=!           add exec lines after each commit of the editable list | ||||||
| k,keep-empty	   preserve empty commits during rebase | k,keep-empty	   preserve empty commits during rebase | ||||||
|  | allow-empty-message allow rebasing commits with empty messages | ||||||
| f,force-rebase!    force rebase even if branch is up to date | f,force-rebase!    force rebase even if branch is up to date | ||||||
| X,strategy-option=! pass the argument through to the merge strategy | X,strategy-option=! pass the argument through to the merge strategy | ||||||
| stat!              display a diffstat of what changed upstream | stat!              display a diffstat of what changed upstream | ||||||
|  | @ -89,6 +90,7 @@ action= | ||||||
| preserve_merges= | preserve_merges= | ||||||
| autosquash= | autosquash= | ||||||
| keep_empty= | keep_empty= | ||||||
|  | allow_empty_message= | ||||||
| test "$(git config --bool rebase.autosquash)" = "true" && autosquash=t | test "$(git config --bool rebase.autosquash)" = "true" && autosquash=t | ||||||
| case "$(git config --bool commit.gpgsign)" in | case "$(git config --bool commit.gpgsign)" in | ||||||
| true)	gpg_sign_opt=-S ;; | true)	gpg_sign_opt=-S ;; | ||||||
|  | @ -262,6 +264,9 @@ do | ||||||
| 	--keep-empty) | 	--keep-empty) | ||||||
| 		keep_empty=yes | 		keep_empty=yes | ||||||
| 		;; | 		;; | ||||||
|  | 	--allow-empty-message) | ||||||
|  | 		allow_empty_message=--allow-empty-message | ||||||
|  | 		;; | ||||||
| 	--preserve-merges) | 	--preserve-merges) | ||||||
| 		preserve_merges=t | 		preserve_merges=t | ||||||
| 		test -z "$interactive_rebase" && interactive_rebase=implied | 		test -z "$interactive_rebase" && interactive_rebase=implied | ||||||
|  |  | ||||||
|  | @ -3,6 +3,7 @@ | ||||||
| test_description='rebase should handle arbitrary git message' | test_description='rebase should handle arbitrary git message' | ||||||
|  |  | ||||||
| . ./test-lib.sh | . ./test-lib.sh | ||||||
|  | . "$TEST_DIRECTORY"/lib-rebase.sh | ||||||
|  |  | ||||||
| cat >F <<\EOF | cat >F <<\EOF | ||||||
| This is an example of a commit log message | This is an example of a commit log message | ||||||
|  | @ -25,6 +26,7 @@ test_expect_success setup ' | ||||||
| 	test_tick && | 	test_tick && | ||||||
| 	git commit -m "Initial commit" && | 	git commit -m "Initial commit" && | ||||||
| 	git branch diff-in-message && | 	git branch diff-in-message && | ||||||
|  | 	git branch empty-message-merge && | ||||||
|  |  | ||||||
| 	git checkout -b multi-line-subject && | 	git checkout -b multi-line-subject && | ||||||
| 	cat F >file2 && | 	cat F >file2 && | ||||||
|  | @ -45,6 +47,11 @@ test_expect_success setup ' | ||||||
|  |  | ||||||
| 	git cat-file commit HEAD | sed -e "1,/^\$/d" >G0 && | 	git cat-file commit HEAD | sed -e "1,/^\$/d" >G0 && | ||||||
|  |  | ||||||
|  | 	git checkout empty-message-merge && | ||||||
|  | 	echo file3 >file3 && | ||||||
|  | 	git add file3 && | ||||||
|  | 	git commit --allow-empty-message -m "" && | ||||||
|  |  | ||||||
| 	git checkout master && | 	git checkout master && | ||||||
|  |  | ||||||
| 	echo One >file1 && | 	echo One >file1 && | ||||||
|  | @ -69,4 +76,20 @@ test_expect_success 'rebase commit with diff in message' ' | ||||||
| 	test_cmp G G0 | 	test_cmp G G0 | ||||||
| ' | ' | ||||||
|  |  | ||||||
|  | test_expect_success 'rebase -m commit with empty message' ' | ||||||
|  | 	test_must_fail git rebase -m master empty-message-merge && | ||||||
|  | 	git rebase --abort && | ||||||
|  | 	git rebase -m --allow-empty-message master empty-message-merge | ||||||
|  | ' | ||||||
|  |  | ||||||
|  | test_expect_success 'rebase -i commit with empty message' ' | ||||||
|  | 	git checkout diff-in-message && | ||||||
|  | 	set_fake_editor && | ||||||
|  | 	test_must_fail env FAKE_COMMIT_MESSAGE=" " FAKE_LINES="reword 1" \ | ||||||
|  | 		git rebase -i HEAD^ && | ||||||
|  | 	git rebase --abort && | ||||||
|  | 	FAKE_COMMIT_MESSAGE=" " FAKE_LINES="reword 1" \ | ||||||
|  | 		git rebase -i --allow-empty-message HEAD^ | ||||||
|  | ' | ||||||
|  |  | ||||||
| test_done | test_done | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	 Genki Sky
						Genki Sky