git@vger.kernel.org list mirror (unofficial, one of many)
 help / color / mirror / Atom feed
* [RFC PATCH 0/2] Fix scissors bug during merge conflict
@ 2018-11-14  5:24 Denton Liu
  2018-11-14  5:24 ` [RFC PATCH 1/2] commit: don't add scissors line if one exists Denton Liu
                   ` (4 more replies)
  0 siblings, 5 replies; 105+ messages in thread
From: Denton Liu @ 2018-11-14  5:24 UTC (permalink / raw)
  To: git

I discovered a bug in Git a while ago where if one is using
commit.cleanup = scissors, if making a commit after a merge conflict,
the scissors line will be placed after the `Conflicts:` section. As a
result, a careless Git user (e.g. me) may accidentally commit the
`Conflicts:` section.

Here is a test case to replicate the behaviour:

	mkdir test
	cd test/
	git init
	git config commit.cleanup scissors
	touch a
	git add a
	git commit -m 'test'
	echo a > a
	git commit -am 'test2'
	git checkout -b new HEAD^
	echo b > a
	git commit -am 'test3'
	git merge master
	echo c > a
	git add a
	git commit # look at the commit message here

And the resulting message that's sent to the text editor:

	Merge branch 'master' into new

	# Conflicts:
	#	a
	# ------------------------ >8 ------------------------
	# Do not modify or remove the line above.
	# Everything below it will be ignored.
	#
	# It looks like you may be committing a merge.
	# If this is not correct, please remove the file
	#	.git/MERGE_HEAD
	# and try again.


	# Please enter the commit message for your changes. Lines starting
	# with '#' will be kept; you may remove them yourself if you want to.
	# An empty message aborts the commit.
	#
	# On branch new
	# All conflicts fixed but you are still merging.
	#
	# Changes to be committed:
	#	modified:   a
	#

With this fix, the message becomes the following:

	Merge branch 'master' into new

	# ------------------------ >8 ------------------------
	# Do not modify or remove the line above.
	# Everything below it will be ignored.
	#
	# Conflicts:
	#	a
	#
	# It looks like you may be committing a merge.
	# If this is not correct, please remove the file
	#	.git/MERGE_HEAD
	# and try again.


	# Please enter the commit message for your changes. Lines starting
	# with '#' will be kept; you may remove them yourself if you want to.
	# An empty message aborts the commit.
	#
	# On branch new
	# All conflicts fixed but you are still merging.
	#
	# Changes to be committed:
	#	modified:   a
	#

Let me know what you think of the change. Of course, documentation and
testing will come after this leaves the RFC phase.

Denton Liu (2):
  commit: don't add scissors line if one exists
  merge: add scissors line on merge conflict

 builtin/commit.c | 11 +++++++++--
 builtin/merge.c  | 16 ++++++++++++++++
 2 files changed, 25 insertions(+), 2 deletions(-)

-- 
2.19.1


^ permalink raw reply	[flat|nested] 105+ messages in thread

* [RFC PATCH 1/2] commit: don't add scissors line if one exists
  2018-11-14  5:24 [RFC PATCH 0/2] Fix scissors bug during merge conflict Denton Liu
@ 2018-11-14  5:24 ` Denton Liu
  2018-11-14  8:06   ` Junio C Hamano
  2018-11-14  5:25 ` [RFC PATCH 2/2] merge: add scissors line on merge conflict Denton Liu
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 105+ messages in thread
From: Denton Liu @ 2018-11-14  5:24 UTC (permalink / raw)
  To: git

If commit.cleanup = scissors is specified, don't produce a scissors line
if one already exists in the commit message.

Signed-off-by: Denton Liu <liu.denton@gmail.com>
---
 builtin/commit.c | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/builtin/commit.c b/builtin/commit.c
index 0d9828e29e..e486246329 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -659,6 +659,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
 	const char *hook_arg2 = NULL;
 	int clean_message_contents = (cleanup_mode != COMMIT_MSG_CLEANUP_NONE);
 	int old_display_comment_prefix;
+	int contains_scissors = 0;
 
 	/* This checks and barfs if author is badly specified */
 	determine_author_info(author_ident);
@@ -742,6 +743,10 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
 		clean_message_contents = 0;
 	}
 
+	if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS &&
+		wt_status_locate_end(sb.buf, sb.len) != sb.len)
+	    contains_scissors = 1;
+
 	/*
 	 * The remaining cases don't modify the template message, but
 	 * just set the argument(s) to the prepare-commit-msg hook.
@@ -798,7 +803,8 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
 		struct ident_split ci, ai;
 
 		if (whence != FROM_COMMIT) {
-			if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)
+			if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS &&
+				!contains_scissors)
 				wt_status_add_cut_line(s->fp);
 			status_printf_ln(s, GIT_COLOR_NORMAL,
 			    whence == FROM_MERGE
@@ -824,7 +830,8 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
 				  " Lines starting\nwith '%c' will be ignored, and an empty"
 				  " message aborts the commit.\n"), comment_line_char);
 		else if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS &&
-			 whence == FROM_COMMIT)
+			 whence == FROM_COMMIT &&
+			 !contains_scissors)
 			wt_status_add_cut_line(s->fp);
 		else /* COMMIT_MSG_CLEANUP_SPACE, that is. */
 			status_printf(s, GIT_COLOR_NORMAL,
-- 
2.19.1


^ permalink raw reply	[flat|nested] 105+ messages in thread

* [RFC PATCH 2/2] merge: add scissors line on merge conflict
  2018-11-14  5:24 [RFC PATCH 0/2] Fix scissors bug during merge conflict Denton Liu
  2018-11-14  5:24 ` [RFC PATCH 1/2] commit: don't add scissors line if one exists Denton Liu
@ 2018-11-14  5:25 ` Denton Liu
  2018-11-14  7:52 ` [RFC PATCH 0/2] Fix scissors bug during " Junio C Hamano
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 105+ messages in thread
From: Denton Liu @ 2018-11-14  5:25 UTC (permalink / raw)
  To: git

This fixes a bug where the scissors line is placed after the Conflicts:
section, in the case where a merge conflict occurs and
merge.cleanup = scissors.

Signed-off-by: Denton Liu <liu.denton@gmail.com>
---
 builtin/merge.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/builtin/merge.c b/builtin/merge.c
index 8f4a5065c2..c5010cee5e 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -36,6 +36,7 @@
 #include "packfile.h"
 #include "tag.h"
 #include "alias.h"
+#include "wt-status.h"
 
 #define DEFAULT_TWOHEAD (1<<0)
 #define DEFAULT_OCTOPUS (1<<1)
@@ -96,6 +97,9 @@ enum ff_type {
 
 static enum ff_type fast_forward = FF_ALLOW;
 
+const char *cleanup_arg;
+int put_scissors;
+
 static int option_parse_message(const struct option *opt,
 				const char *arg, int unset)
 {
@@ -243,6 +247,7 @@ static struct option builtin_merge_options[] = {
 		N_("perform a commit if the merge succeeds (default)")),
 	OPT_BOOL('e', "edit", &option_edit,
 		N_("edit message before committing")),
+	OPT_STRING(0, "cleanup", &cleanup_arg, N_("default"), N_("how to strip spaces and #comments from message")),
 	OPT_SET_INT(0, "ff", &fast_forward, N_("allow fast-forward (default)"), FF_ALLOW),
 	OPT_SET_INT_F(0, "ff-only", &fast_forward,
 		      N_("abort if fast-forward is not possible"),
@@ -606,6 +611,8 @@ static int git_merge_config(const char *k, const char *v, void *cb)
 		return git_config_string(&pull_twohead, k, v);
 	else if (!strcmp(k, "pull.octopus"))
 		return git_config_string(&pull_octopus, k, v);
+	else if (!strcmp(k, "commit.cleanup"))
+		return git_config_string(&cleanup_arg, k, v);
 	else if (!strcmp(k, "merge.renormalize"))
 		option_renormalize = git_config_bool(k, v);
 	else if (!strcmp(k, "merge.ff")) {
@@ -894,6 +901,13 @@ static int suggest_conflicts(void)
 	filename = git_path_merge_msg(the_repository);
 	fp = xfopen(filename, "a");
 
+	if (put_scissors) {
+	    fputc('\n', fp);
+	    wt_status_add_cut_line(fp);
+	    /* comments out the newline from append_conflicts_hint */
+	    fputc(comment_line_char, fp);
+	}
+
 	append_conflicts_hint(&msgbuf);
 	fputs(msgbuf.buf, fp);
 	strbuf_release(&msgbuf);
@@ -1402,6 +1416,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
 	if (option_edit < 0)
 		option_edit = default_edit_option();
 
+	put_scissors = cleanup_arg && !strcmp(cleanup_arg, "scissors");
+
 	if (!use_strategies) {
 		if (!remoteheads)
 			; /* already up-to-date */
-- 
2.19.1


^ permalink raw reply	[flat|nested] 105+ messages in thread

* Re: [RFC PATCH 0/2] Fix scissors bug during merge conflict
  2018-11-14  5:24 [RFC PATCH 0/2] Fix scissors bug during merge conflict Denton Liu
  2018-11-14  5:24 ` [RFC PATCH 1/2] commit: don't add scissors line if one exists Denton Liu
  2018-11-14  5:25 ` [RFC PATCH 2/2] merge: add scissors line on merge conflict Denton Liu
@ 2018-11-14  7:52 ` Junio C Hamano
  2018-11-14  8:10   ` Denton Liu
  2018-11-16 15:19 ` [PATCH v2 " Denton Liu
       [not found] ` <cover.1542380865.git.liu.denton@gmail.com>
  4 siblings, 1 reply; 105+ messages in thread
From: Junio C Hamano @ 2018-11-14  7:52 UTC (permalink / raw)
  To: Denton Liu; +Cc: git

Denton Liu <liu.denton@gmail.com> writes:

> With this fix, the message becomes the following:
>
> 	Merge branch 'master' into new
>
> 	# ------------------------ >8 ------------------------
> 	# Do not modify or remove the line above.
> 	# Everything below it will be ignored.
> 	#
> 	# Conflicts:
> 	#	a

I have a mixed feeling about this change and I certainly would not
call it a "fix".

The reason why we give the list of conflicted paths that is
commented out is to remind the user of them in order to help them
describe what area of the codebase had overlapping changes, why, and
how the overlap was resolved, which is relevant information when
somebody else later needs to dig into the history to understand how
the code came into today's shape and why.  For that reason, if a
careless user left conflicts list behind without describing these
details about the merge, it might be better to have the unexplained
list in the merge than nothing.

In theory, the above argument applies the same way for the paths to
be committed, but the list is fairly trivial to recreate with "git
diff $it^!", unlike "which paths had conflict", which can only be
found out by recreating the auto-merge.  So in practice, the paths
that had conflicts is more worth showing than the paths that were
modified.

So, I dunno.  If we value the "more expensive list to reproduce",
the fix might be not to place it (and possibly the comments and
everything under the scissors line) behind a "# " comment char on
the line, without moving its position.

.



^ permalink raw reply	[flat|nested] 105+ messages in thread

* Re: [RFC PATCH 1/2] commit: don't add scissors line if one exists
  2018-11-14  5:24 ` [RFC PATCH 1/2] commit: don't add scissors line if one exists Denton Liu
@ 2018-11-14  8:06   ` Junio C Hamano
  2018-11-14 18:06     ` Denton Liu
  0 siblings, 1 reply; 105+ messages in thread
From: Junio C Hamano @ 2018-11-14  8:06 UTC (permalink / raw)
  To: Denton Liu; +Cc: git

Denton Liu <liu.denton@gmail.com> writes:

> If commit.cleanup = scissors is specified, don't produce a scissors line
> if one already exists in the commit message.

It is good that you won't have two such lines in the end result, but
is this (1) hiding real problem under the rug? (2) losing information?

If the current invocation of "git commit" added a scissors line in
the buffer to be edited already, and we are adding another one in
this function, is it possible that the real problem that somebody
else has called wt_status_add_cut_line() before this function is
called, in which case that other caller is what we need to fix,
instead of this one?

If the existing line in the buffer came from the end user (perhaps
it was given from "-F <file>", etc., with "-e" option) or --amend,
how can we be sure if it is OK to lose everything after that
scissors looking line?  In other words, the scissors looking line
may just be part of the log message, in which case we may want to
quote/escape it, so that the true scissors we append at a later
place in the buffer would be noticed without losing the text before
and after that scissors looking line we already had when this
function was called?


^ permalink raw reply	[flat|nested] 105+ messages in thread

* Re: [RFC PATCH 0/2] Fix scissors bug during merge conflict
  2018-11-14  7:52 ` [RFC PATCH 0/2] Fix scissors bug during " Junio C Hamano
@ 2018-11-14  8:10   ` Denton Liu
  0 siblings, 0 replies; 105+ messages in thread
From: Denton Liu @ 2018-11-14  8:10 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

On Wed, Nov 14, 2018 at 04:52:59PM +0900, Junio C Hamano wrote:
> Denton Liu <liu.denton@gmail.com> writes:
> 
> > With this fix, the message becomes the following:
> >
> > 	Merge branch 'master' into new
> >
> > 	# ------------------------ >8 ------------------------
> > 	# Do not modify or remove the line above.
> > 	# Everything below it will be ignored.
> > 	#
> > 	# Conflicts:
> > 	#	a
> 
> I have a mixed feeling about this change and I certainly would not
> call it a "fix".
> 
> The reason why we give the list of conflicted paths that is
> commented out is to remind the user of them in order to help them
> describe what area of the codebase had overlapping changes, why, and
> how the overlap was resolved, which is relevant information when
> somebody else later needs to dig into the history to understand how
> the code came into today's shape and why.  For that reason, if a
> careless user left conflicts list behind without describing these
> details about the merge, it might be better to have the unexplained
> list in the merge than nothing.
> 

The reason why I implemented it this way is because the default
cleanup setting (strip) produces this message:

	Merge branch 'master' into new

	# Conflicts:
	#	a
	#
	# It looks like you may be committing a merge.
	# If this is not correct, please remove the file
	#	.git/MERGE_HEAD
	# and try again.


	# Please enter the commit message for your changes. Lines starting
	# with '#' will be ignored, and an empty message aborts the commit.
	#
	# On branch new
	# All conflicts fixed but you are still merging.
	#
	# Changes to be committed:
	#	modified:   a
	#

Which makes it seem like the `Conflicts:` section should be removed by
default.

> In theory, the above argument applies the same way for the paths to
> be committed, but the list is fairly trivial to recreate with "git
> diff $it^!", unlike "which paths had conflict", which can only be
> found out by recreating the auto-merge.  So in practice, the paths
> that had conflicts is more worth showing than the paths that were
> modified.
> 
> So, I dunno.  If we value the "more expensive list to reproduce",
> the fix might be not to place it (and possibly the comments and
> everything under the scissors line) behind a "# " comment char on
> the line, without moving its position.

If I understood correctly, then I have no strong opinions between
uncommenting the Conflicts section by default and this change; I just
think it'd be nice to have behaviour that's consistent.

> 
> .
> 
> 

^ permalink raw reply	[flat|nested] 105+ messages in thread

* Re: [RFC PATCH 1/2] commit: don't add scissors line if one exists
  2018-11-14  8:06   ` Junio C Hamano
@ 2018-11-14 18:06     ` Denton Liu
  2018-11-16  3:32       ` Junio C Hamano
  0 siblings, 1 reply; 105+ messages in thread
From: Denton Liu @ 2018-11-14 18:06 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

On Wed, Nov 14, 2018 at 05:06:32PM +0900, Junio C Hamano wrote:
> Denton Liu <liu.denton@gmail.com> writes:
> 
> > If commit.cleanup = scissors is specified, don't produce a scissors line
> > if one already exists in the commit message.
> 
> It is good that you won't have two such lines in the end result, but
> is this (1) hiding real problem under the rug? (2) losing information?
> 
> If the current invocation of "git commit" added a scissors line in
> the buffer to be edited already, and we are adding another one in
> this function, is it possible that the real problem that somebody
> else has called wt_status_add_cut_line() before this function is
> called, in which case that other caller is what we need to fix,
> instead of this one?
> 

In patch 2/2, I intentionally inserted a scissors line into MERGE_MSG so
this patch ensures that we don't get duplicate scissors.

> If the existing line in the buffer came from the end user (perhaps
> it was given from "-F <file>", etc., with "-e" option) or --amend,
> how can we be sure if it is OK to lose everything after that
> scissors looking line?  In other words, the scissors looking line
> may just be part of the log message, in which case we may want to
> quote/escape it, so that the true scissors we append at a later
> place in the buffer would be noticed without losing the text before
> and after that scissors looking line we already had when this
> function was called?
> 

With the existing behaviour, any messages that contain a scissors
looking line will get cut at the earliest scissors anyway, so I believe
that this patch would not change the behaviour. If the users were
dealing with commit messages with a scissors looking line, the current
behaviour already requires users to be extra careful to ensure that the
scissors don't get accidentally removed so in the interest of preserving
the existing behaviour, I don't think that any extra information would
be lost from this patch.

^ permalink raw reply	[flat|nested] 105+ messages in thread

* Re: [RFC PATCH 1/2] commit: don't add scissors line if one exists
  2018-11-14 18:06     ` Denton Liu
@ 2018-11-16  3:32       ` Junio C Hamano
  0 siblings, 0 replies; 105+ messages in thread
From: Junio C Hamano @ 2018-11-16  3:32 UTC (permalink / raw)
  To: Denton Liu; +Cc: git

Denton Liu <liu.denton@gmail.com> writes:

>> If the current invocation of "git commit" added a scissors line in
>> the buffer to be edited already, and we are adding another one in
>> this function, is it possible that the real problem that somebody
>> else has called wt_status_add_cut_line() before this function is
>> called, in which case that other caller is what we need to fix,
>> instead of this one?
>> 
>
> In patch 2/2, I intentionally inserted a scissors line into MERGE_MSG so
> this patch ensures that we don't get duplicate scissors.

That is exactly what the paragraph you are responding to questions.
Is the code that adds a scissors line before this function is called
done the right way?  Shouldn't it be doing something differnetly?
Looking for an existing scissors looking line in this function does
not let this function differenciate two cases, i.e. we deliberately
added one already before calling this function (in which case this
function should not add another one), or we didn't add anything on
our own, but the material supplied by the end user had one (in which
case, not adding ours is losing information---imagine that the user
notices a scissors-looking line that came from the original maerial
and want to munge it, as it is part of proper message, so that it
would remain in the committed result, but because [PATCH 1/2]
stopped adding a scissors line at the right location, the user would
have to guess where to add one).

There must be an explicit way (e.g. a bit in a flag word parameter
given to this function) for the caller who knows when the new code
in [PATCH 2/2] triggers, to tell this function not to add another
one, instead of a sloppy (and less efficient) "lets's scan to see if
there already is a scissors looking line".

> With the existing behaviour, any messages that contain a scissors
> looking line will get cut at the earliest scissors anyway, so I believe
> that this patch would not change the behaviour. If the users were
> dealing with commit messages with a scissors looking line, the current
> behaviour already requires users to be extra careful to ensure that the
> scissors don't get accidentally removed so in the interest of preserving
> the existing behaviour, I don't think that any extra information would
> be lost from this patch.

Doing the "is there already a scissors looing line" approach will
*make* it harder to fix that issue, so the patch is making things
worse.

^ permalink raw reply	[flat|nested] 105+ messages in thread

* [PATCH v2 0/2] Fix scissors bug during merge conflict
  2018-11-14  5:24 [RFC PATCH 0/2] Fix scissors bug during merge conflict Denton Liu
                   ` (2 preceding siblings ...)
  2018-11-14  7:52 ` [RFC PATCH 0/2] Fix scissors bug during " Junio C Hamano
@ 2018-11-16 15:19 ` Denton Liu
  2018-11-16 15:20   ` [PATCH v2 2/2] merge: add scissors line on " Denton Liu
  2018-11-17 23:32   ` [PATCH v3 0/1] Fix scissors bug during " Denton Liu
       [not found] ` <cover.1542380865.git.liu.denton@gmail.com>
  4 siblings, 2 replies; 105+ messages in thread
From: Denton Liu @ 2018-11-16 15:19 UTC (permalink / raw)
  To: git; +Cc: gitster

Thanks for your feedback, Junio.

I tried to reroll the patch by adding another option into the MERGE_MODE
file but unfortunately, it didn't work completely because doing `merge
--squash` doesn't produce a MERGE_MODE. In addition to this, because of
the way merge and commit were structured, I needed to reorder a lot of
calls because some variables were only being set after I needed them.
Unless we want to produce a MERGE_MODE during --squash (which I don't
think is worth it) I don't think that this is the way to go.

Instead, I just refined my first approach and only checked the contents
of MERGE_MSG for a scissors line. The MERGE_MSG is going to be
machine-generated anyway so we should be safe from accidentally ignoring
a human-placed scissors line.

Changes since V1:
-----------------
* Only check MERGE_MSG for a scissors line instead of all prepended files
* Make a variable static in merge where appropriate
* Add passthrough options in pull
* Add documentation for the new option
* Add tests to ensure desired behaviour

Denton Liu (2):
  commit: don't add scissors line if one exists
  merge: add scissors line on merge conflict

 Documentation/merge-options.txt |  6 +++++
 builtin/commit.c                | 15 +++++++++--
 builtin/merge.c                 | 16 +++++++++++
 builtin/pull.c                  |  6 +++++
 t/t7600-merge.sh                | 48 +++++++++++++++++++++++++++++++++
 5 files changed, 89 insertions(+), 2 deletions(-)

-- 
2.19.1


^ permalink raw reply	[flat|nested] 105+ messages in thread

* [PATCH v2 1/2] commit: don't add scissors line if one exists in MERGE_MSG
       [not found] ` <cover.1542380865.git.liu.denton@gmail.com>
@ 2018-11-16 15:19   ` Denton Liu
  2018-11-17  8:06     ` Junio C Hamano
  0 siblings, 1 reply; 105+ messages in thread
From: Denton Liu @ 2018-11-16 15:19 UTC (permalink / raw)
  To: git; +Cc: gitster

If commit.cleanup = scissors is specified, don't produce a scissors line
if one already exists in the MERGE_MSG file.

Signed-off-by: Denton Liu <liu.denton@gmail.com>
---
 builtin/commit.c | 15 +++++++++++++--
 1 file changed, 13 insertions(+), 2 deletions(-)

diff --git a/builtin/commit.c b/builtin/commit.c
index 0d9828e29e..a74a324b7a 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -659,6 +659,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
 	const char *hook_arg2 = NULL;
 	int clean_message_contents = (cleanup_mode != COMMIT_MSG_CLEANUP_NONE);
 	int old_display_comment_prefix;
+	int merge_contains_scissors = 0;
 
 	/* This checks and barfs if author is badly specified */
 	determine_author_info(author_ident);
@@ -719,6 +720,8 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
 			strbuf_addbuf(&sb, &message);
 		hook_arg1 = "message";
 	} else if (!stat(git_path_merge_msg(the_repository), &statbuf)) {
+		size_t merge_msg_start;
+
 		/*
 		 * prepend SQUASH_MSG here if it exists and a
 		 * "merge --squash" was originally performed
@@ -729,8 +732,14 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
 			hook_arg1 = "squash";
 		} else
 			hook_arg1 = "merge";
+
+		merge_msg_start = sb.len;
 		if (strbuf_read_file(&sb, git_path_merge_msg(the_repository), 0) < 0)
 			die_errno(_("could not read MERGE_MSG"));
+
+		if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS &&
+		    wt_status_locate_end(sb.buf + merge_msg_start, sb.len - merge_msg_start) < sb.len - merge_msg_start)
+			merge_contains_scissors = 1;
 	} else if (!stat(git_path_squash_msg(the_repository), &statbuf)) {
 		if (strbuf_read_file(&sb, git_path_squash_msg(the_repository), 0) < 0)
 			die_errno(_("could not read SQUASH_MSG"));
@@ -798,7 +807,8 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
 		struct ident_split ci, ai;
 
 		if (whence != FROM_COMMIT) {
-			if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)
+			if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS &&
+				!merge_contains_scissors)
 				wt_status_add_cut_line(s->fp);
 			status_printf_ln(s, GIT_COLOR_NORMAL,
 			    whence == FROM_MERGE
@@ -824,7 +834,8 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
 				  " Lines starting\nwith '%c' will be ignored, and an empty"
 				  " message aborts the commit.\n"), comment_line_char);
 		else if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS &&
-			 whence == FROM_COMMIT)
+			 whence == FROM_COMMIT &&
+			 !merge_contains_scissors)
 			wt_status_add_cut_line(s->fp);
 		else /* COMMIT_MSG_CLEANUP_SPACE, that is. */
 			status_printf(s, GIT_COLOR_NORMAL,
-- 
2.19.1


^ permalink raw reply	[flat|nested] 105+ messages in thread

* [PATCH v2 2/2] merge: add scissors line on merge conflict
  2018-11-16 15:19 ` [PATCH v2 " Denton Liu
@ 2018-11-16 15:20   ` Denton Liu
  2018-11-17 23:32   ` [PATCH v3 0/1] Fix scissors bug during " Denton Liu
  1 sibling, 0 replies; 105+ messages in thread
From: Denton Liu @ 2018-11-16 15:20 UTC (permalink / raw)
  To: git; +Cc: gitster

This fixes a bug where the scissors line is placed after the Conflicts:
section, in the case where a merge conflict occurs and
merge.cleanup = scissors.

In addition, we give pull the passthrough option of --cleanup so that it
can also take advantage of this change.

Signed-off-by: Denton Liu <liu.denton@gmail.com>
---
 Documentation/merge-options.txt |  6 +++++
 builtin/merge.c                 | 16 +++++++++++
 builtin/pull.c                  |  6 +++++
 t/t7600-merge.sh                | 48 +++++++++++++++++++++++++++++++++
 4 files changed, 76 insertions(+)

diff --git a/Documentation/merge-options.txt b/Documentation/merge-options.txt
index 63a3fc0954..115e0ca6f0 100644
--- a/Documentation/merge-options.txt
+++ b/Documentation/merge-options.txt
@@ -27,6 +27,12 @@ they run `git merge`. To make it easier to adjust such scripts to the
 updated behaviour, the environment variable `GIT_MERGE_AUTOEDIT` can be
 set to `no` at the beginning of them.
 
+--cleanup=<mode>::
+	This option determines how the merge message will be cleaned up
+	before being passed on. Specifically, if the '<mode>' is given a
+	value of `scissors`, scissors will be prepended to the message in
+	the case of a merge conflict. See also linkgit:git-commit[1].
+
 --ff::
 	When the merge resolves as a fast-forward, only update the branch
 	pointer, without creating a merge commit.  This is the default
diff --git a/builtin/merge.c b/builtin/merge.c
index 8f4a5065c2..23a6e6bb93 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -36,6 +36,7 @@
 #include "packfile.h"
 #include "tag.h"
 #include "alias.h"
+#include "wt-status.h"
 
 #define DEFAULT_TWOHEAD (1<<0)
 #define DEFAULT_OCTOPUS (1<<1)
@@ -96,6 +97,9 @@ enum ff_type {
 
 static enum ff_type fast_forward = FF_ALLOW;
 
+static const char *cleanup_arg;
+static int put_scissors;
+
 static int option_parse_message(const struct option *opt,
 				const char *arg, int unset)
 {
@@ -243,6 +247,7 @@ static struct option builtin_merge_options[] = {
 		N_("perform a commit if the merge succeeds (default)")),
 	OPT_BOOL('e', "edit", &option_edit,
 		N_("edit message before committing")),
+	OPT_STRING(0, "cleanup", &cleanup_arg, N_("default"), N_("how to strip spaces and #comments from message")),
 	OPT_SET_INT(0, "ff", &fast_forward, N_("allow fast-forward (default)"), FF_ALLOW),
 	OPT_SET_INT_F(0, "ff-only", &fast_forward,
 		      N_("abort if fast-forward is not possible"),
@@ -606,6 +611,8 @@ static int git_merge_config(const char *k, const char *v, void *cb)
 		return git_config_string(&pull_twohead, k, v);
 	else if (!strcmp(k, "pull.octopus"))
 		return git_config_string(&pull_octopus, k, v);
+	else if (!strcmp(k, "commit.cleanup"))
+		return git_config_string(&cleanup_arg, k, v);
 	else if (!strcmp(k, "merge.renormalize"))
 		option_renormalize = git_config_bool(k, v);
 	else if (!strcmp(k, "merge.ff")) {
@@ -894,6 +901,13 @@ static int suggest_conflicts(void)
 	filename = git_path_merge_msg(the_repository);
 	fp = xfopen(filename, "a");
 
+	if (put_scissors) {
+	    fputc('\n', fp);
+	    wt_status_add_cut_line(fp);
+	    /* comments out the newline from append_conflicts_hint */
+	    fputc(comment_line_char, fp);
+	}
+
 	append_conflicts_hint(&msgbuf);
 	fputs(msgbuf.buf, fp);
 	strbuf_release(&msgbuf);
@@ -1402,6 +1416,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
 	if (option_edit < 0)
 		option_edit = default_edit_option();
 
+	put_scissors = cleanup_arg && !strcmp(cleanup_arg, "scissors");
+
 	if (!use_strategies) {
 		if (!remoteheads)
 			; /* already up-to-date */
diff --git a/builtin/pull.c b/builtin/pull.c
index 681c127a07..88245bce0e 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -95,6 +95,7 @@ static char *opt_signoff;
 static char *opt_squash;
 static char *opt_commit;
 static char *opt_edit;
+static char *opt_cleanup;
 static char *opt_ff;
 static char *opt_verify_signatures;
 static int opt_autostash = -1;
@@ -162,6 +163,9 @@ static struct option pull_options[] = {
 	OPT_PASSTHRU(0, "edit", &opt_edit, NULL,
 		N_("edit message before committing"),
 		PARSE_OPT_NOARG),
+	OPT_PASSTHRU(0, "cleanup", &opt_cleanup, NULL,
+		N_("how to strip spaces and #comments from message"),
+		PARSE_OPT_NOARG),
 	OPT_PASSTHRU(0, "ff", &opt_ff, NULL,
 		N_("allow fast-forward"),
 		PARSE_OPT_NOARG),
@@ -625,6 +629,8 @@ static int run_merge(void)
 		argv_array_push(&args, opt_commit);
 	if (opt_edit)
 		argv_array_push(&args, opt_edit);
+	if (opt_cleanup)
+		argv_array_push(&args, opt_cleanup);
 	if (opt_ff)
 		argv_array_push(&args, opt_ff);
 	if (opt_verify_signatures)
diff --git a/t/t7600-merge.sh b/t/t7600-merge.sh
index 106148254d..0d3db34f08 100755
--- a/t/t7600-merge.sh
+++ b/t/t7600-merge.sh
@@ -247,6 +247,54 @@ test_expect_success 'merge --squash c3 with c7' '
 	test_cmp expect actual
 '
 
+test_expect_success 'merge c3 with c7 with commit.cleanup = scissors' '
+	git config commit.cleanup scissors &&
+	git reset --hard c3 &&
+	test_must_fail git merge c7 &&
+	cat result.9z >file &&
+	git commit --no-edit -a &&
+
+	{
+		cat <<-EOF
+		Merge tag '"'"'c7'"'"'
+
+		# ------------------------ >8 ------------------------
+		# Do not modify or remove the line above.
+		# Everything below it will be ignored.
+		#
+		# Conflicts:
+		#	file
+		EOF
+	} >expect &&
+	git cat-file commit HEAD | sed -e '1,/^$/d' >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'merge c3 with c7 with --squash commit.cleanup = scissors' '
+	git config commit.cleanup scissors &&
+	git reset --hard c3 &&
+	test_must_fail git merge --squash c7 &&
+	cat result.9z >file &&
+	git commit --no-edit -a &&
+
+	{
+		cat <<-EOF
+		Squashed commit of the following:
+
+		$(git show -s c7)
+
+		# ------------------------ >8 ------------------------
+		# Do not modify or remove the line above.
+		# Everything below it will be ignored.
+		#
+		# Conflicts:
+		#	file
+		EOF
+	} >expect &&
+	git cat-file commit HEAD | sed -e '1,/^$/d' >actual &&
+	test_cmp expect actual
+'
+
 test_debug 'git log --graph --decorate --oneline --all'
 
 test_expect_success 'merge c1 with c2 and c3' '
-- 
2.19.1


^ permalink raw reply	[flat|nested] 105+ messages in thread

* Re: [PATCH v2 1/2] commit: don't add scissors line if one exists in MERGE_MSG
  2018-11-16 15:19   ` [PATCH v2 1/2] commit: don't add scissors line if one exists in MERGE_MSG Denton Liu
@ 2018-11-17  8:06     ` Junio C Hamano
  0 siblings, 0 replies; 105+ messages in thread
From: Junio C Hamano @ 2018-11-17  8:06 UTC (permalink / raw)
  To: Denton Liu; +Cc: git

Denton Liu <liu.denton@gmail.com> writes:

> If commit.cleanup = scissors is specified, don't produce a scissors line
> if one already exists in the MERGE_MSG file.

Are we already sometimes adding a scissors line in that file?  The
impression I was getting was that the change in the step 2/2 is the
only reason why this becomes necessary.  In which case this change
makes no sense as a standalone patch and requires 2/2 to be a
sensible change, no?

> @@ -798,7 +807,8 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
>  		struct ident_split ci, ai;
>  
>  		if (whence != FROM_COMMIT) {
> -			if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)
> +			if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS &&
> +				!merge_contains_scissors)
>  				wt_status_add_cut_line(s->fp);
>  			status_printf_ln(s, GIT_COLOR_NORMAL,
>  			    whence == FROM_MERGE

This one is done before we show a block of text, which looks correct.

> @@ -824,7 +834,8 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
>  				  " Lines starting\nwith '%c' will be ignored, and an empty"
>  				  " message aborts the commit.\n"), comment_line_char);
>  		else if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS &&
> -			 whence == FROM_COMMIT)
> +			 whence == FROM_COMMIT &&
> +			 !merge_contains_scissors)
>  			wt_status_add_cut_line(s->fp);
>  		else /* COMMIT_MSG_CLEANUP_SPACE, that is. */
>  			status_printf(s, GIT_COLOR_NORMAL,

The correctness of this one in an if/elseif/else cascade is less
clear.  When "contains scissors" logic does not kick in, we just
have a scissors line here (i.e. the original behaviour).  Now when
the new logic kicks in, we not just omit the (extra) scissors line,
but also say "Please enter the commit message..." which is the
message used with the "comment line char" mode of the clean-up.

I wonder if this is what you really meant to have instead:

>  		else if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS &&
> -			 whence == FROM_COMMIT)
> - 			wt_status_add_cut_line(s->fp);
> +			 whence == FROM_COMMIT) {
> +			 if (!merge_contains_scissors)
> +				wt_status_add_cut_line(s->fp);
> +		}
>  		else /* COMMIT_MSG_CLEANUP_SPACE, that is. */
>  			status_printf(s, GIT_COLOR_NORMAL,

That is, the only behaviour change in "merge contains scissors"
mode is to omit the cut line and nothing else.

^ permalink raw reply	[flat|nested] 105+ messages in thread

* [PATCH v3 0/1] Fix scissors bug during merge conflict
  2018-11-16 15:19 ` [PATCH v2 " Denton Liu
  2018-11-16 15:20   ` [PATCH v2 2/2] merge: add scissors line on " Denton Liu
@ 2018-11-17 23:32   ` Denton Liu
  2018-11-17 23:32     ` [PATCH v3 1/1] merge: add scissors line on " Denton Liu
                       ` (2 more replies)
  1 sibling, 3 replies; 105+ messages in thread
From: Denton Liu @ 2018-11-17 23:32 UTC (permalink / raw)
  To: git; +Cc: gitster

On Sat, Nov 17, 2018 at 05:06:43PM +0900, Junio C Hamano wrote:
> Are we already sometimes adding a scissors line in that file?  The
> impression I was getting was that the change in the step 2/2 is the
> only reason why this becomes necessary.  In which case this change
> makes no sense as a standalone patch and requires 2/2 to be a
> sensible change, no?
> 

My mistake, I guess I went a little overboard trying to split my
contribution into digestable patches.

> > @@ -798,7 +807,8 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
> >  		struct ident_split ci, ai;
> >  
> >  		if (whence != FROM_COMMIT) {
> > -			if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)
> > +			if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS &&
> > +				!merge_contains_scissors)
> >  				wt_status_add_cut_line(s->fp);
> >  			status_printf_ln(s, GIT_COLOR_NORMAL,
> >  			    whence == FROM_MERGE
> 
> This one is done before we show a block of text, which looks correct.
> 
> > @@ -824,7 +834,8 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
> >  				  " Lines starting\nwith '%c' will be ignored, and an empty"
> >  				  " message aborts the commit.\n"), comment_line_char);
> >  		else if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS &&
> > -			 whence == FROM_COMMIT)
> > +			 whence == FROM_COMMIT &&
> > +			 !merge_contains_scissors)
> >  			wt_status_add_cut_line(s->fp);
> >  		else /* COMMIT_MSG_CLEANUP_SPACE, that is. */
> >  			status_printf(s, GIT_COLOR_NORMAL,
> 
> The correctness of this one in an if/elseif/else cascade is less
> clear.  When "contains scissors" logic does not kick in, we just
> have a scissors line here (i.e. the original behaviour).  Now when
> the new logic kicks in, we not just omit the (extra) scissors line,
> but also say "Please enter the commit message..." which is the
> message used with the "comment line char" mode of the clean-up.
> 
> I wonder if this is what you really meant to have instead:
> 
> >  		else if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS &&
> > -			 whence == FROM_COMMIT)
> > - 			wt_status_add_cut_line(s->fp);
> > +			 whence == FROM_COMMIT) {
> > +			 if (!merge_contains_scissors)
> > +				wt_status_add_cut_line(s->fp);
> > +		}
> >  		else /* COMMIT_MSG_CLEANUP_SPACE, that is. */
> >  			status_printf(s, GIT_COLOR_NORMAL,
> 
> That is, the only behaviour change in "merge contains scissors"
> mode is to omit the cut line and nothing else.

Thanks for catching this. I noticed that the originally behaviour is
buggy too: in the case where we're merging a commit and scissors are
printed from the `if (whence != FROM_COMMIT)` block, the original
behaviour would drop us into the else (COMMIT_MSG_CLEANUP_SPACE)
statement, which is undesired. With this fix, the message about `#`
_not_ being removed is now silenced in both cases.

Changes since V1:
	* Only check MERGE_MSG for a scissors line instead of all prepended
	  files
	* Make a variable static in merge where appropriate
	* Add passthrough options in pull
	* Add documentation for the new option
	* Add tests to ensure desired behaviour

Changes since V2:
	* Merge both patches into one patch
	* Fix bug in help message printing logic

Denton Liu (1):
  merge: add scissors line on merge conflict

 Documentation/merge-options.txt |  6 +++++
 builtin/commit.c                | 20 ++++++++++----
 builtin/merge.c                 | 16 +++++++++++
 builtin/pull.c                  |  6 +++++
 t/t7600-merge.sh                | 48 +++++++++++++++++++++++++++++++++
 5 files changed, 91 insertions(+), 5 deletions(-)

-- 
2.19.1


^ permalink raw reply	[flat|nested] 105+ messages in thread

* [PATCH v3 1/1] merge: add scissors line on merge conflict
  2018-11-17 23:32   ` [PATCH v3 0/1] Fix scissors bug during " Denton Liu
@ 2018-11-17 23:32     ` Denton Liu
  2018-11-18 14:18       ` SZEDER Gábor
  2018-11-18  6:54     ` [PATCH v3 0/1] Fix scissors bug during " Junio C Hamano
  2018-11-21  3:13     ` [PATCH v4 0/2] " Denton Liu
  2 siblings, 1 reply; 105+ messages in thread
From: Denton Liu @ 2018-11-17 23:32 UTC (permalink / raw)
  To: git; +Cc: gitster

This fixes a bug where the scissors line is placed after the Conflicts:
section, in the case where a merge conflict occurs and
merge.cleanup = scissors.

Next, if commit.cleanup = scissors is specified, don't produce a
scissors line in commit if one already exists in the MERGE_MSG file.

Finally, we give pull the passthrough option of --cleanup so that it
can also take advantage of this change.

Signed-off-by: Denton Liu <liu.denton@gmail.com>
---
 Documentation/merge-options.txt |  6 +++++
 builtin/commit.c                | 20 ++++++++++----
 builtin/merge.c                 | 16 +++++++++++
 builtin/pull.c                  |  6 +++++
 t/t7600-merge.sh                | 48 +++++++++++++++++++++++++++++++++
 5 files changed, 91 insertions(+), 5 deletions(-)

diff --git a/Documentation/merge-options.txt b/Documentation/merge-options.txt
index 63a3fc0954..115e0ca6f0 100644
--- a/Documentation/merge-options.txt
+++ b/Documentation/merge-options.txt
@@ -27,6 +27,12 @@ they run `git merge`. To make it easier to adjust such scripts to the
 updated behaviour, the environment variable `GIT_MERGE_AUTOEDIT` can be
 set to `no` at the beginning of them.
 
+--cleanup=<mode>::
+	This option determines how the merge message will be cleaned up
+	before being passed on. Specifically, if the '<mode>' is given a
+	value of `scissors`, scissors will be prepended to the message in
+	the case of a merge conflict. See also linkgit:git-commit[1].
+
 --ff::
 	When the merge resolves as a fast-forward, only update the branch
 	pointer, without creating a merge commit.  This is the default
diff --git a/builtin/commit.c b/builtin/commit.c
index 0d9828e29e..7902645bc9 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -659,6 +659,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
 	const char *hook_arg2 = NULL;
 	int clean_message_contents = (cleanup_mode != COMMIT_MSG_CLEANUP_NONE);
 	int old_display_comment_prefix;
+	int merge_contains_scissors = 0;
 
 	/* This checks and barfs if author is badly specified */
 	determine_author_info(author_ident);
@@ -719,6 +720,8 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
 			strbuf_addbuf(&sb, &message);
 		hook_arg1 = "message";
 	} else if (!stat(git_path_merge_msg(the_repository), &statbuf)) {
+		size_t merge_msg_start;
+
 		/*
 		 * prepend SQUASH_MSG here if it exists and a
 		 * "merge --squash" was originally performed
@@ -729,8 +732,14 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
 			hook_arg1 = "squash";
 		} else
 			hook_arg1 = "merge";
+
+		merge_msg_start = sb.len;
 		if (strbuf_read_file(&sb, git_path_merge_msg(the_repository), 0) < 0)
 			die_errno(_("could not read MERGE_MSG"));
+
+		if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS &&
+		    wt_status_locate_end(sb.buf + merge_msg_start, sb.len - merge_msg_start) < sb.len - merge_msg_start)
+			merge_contains_scissors = 1;
 	} else if (!stat(git_path_squash_msg(the_repository), &statbuf)) {
 		if (strbuf_read_file(&sb, git_path_squash_msg(the_repository), 0) < 0)
 			die_errno(_("could not read SQUASH_MSG"));
@@ -798,7 +807,8 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
 		struct ident_split ci, ai;
 
 		if (whence != FROM_COMMIT) {
-			if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)
+			if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS &&
+				!merge_contains_scissors)
 				wt_status_add_cut_line(s->fp);
 			status_printf_ln(s, GIT_COLOR_NORMAL,
 			    whence == FROM_MERGE
@@ -823,10 +833,10 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
 				_("Please enter the commit message for your changes."
 				  " Lines starting\nwith '%c' will be ignored, and an empty"
 				  " message aborts the commit.\n"), comment_line_char);
-		else if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS &&
-			 whence == FROM_COMMIT)
-			wt_status_add_cut_line(s->fp);
-		else /* COMMIT_MSG_CLEANUP_SPACE, that is. */
+		else if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS) {
+			if (whence == FROM_COMMIT && !merge_contains_scissors)
+				wt_status_add_cut_line(s->fp);
+		} else /* COMMIT_MSG_CLEANUP_SPACE, that is. */
 			status_printf(s, GIT_COLOR_NORMAL,
 				_("Please enter the commit message for your changes."
 				  " Lines starting\n"
diff --git a/builtin/merge.c b/builtin/merge.c
index 8f4a5065c2..23a6e6bb93 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -36,6 +36,7 @@
 #include "packfile.h"
 #include "tag.h"
 #include "alias.h"
+#include "wt-status.h"
 
 #define DEFAULT_TWOHEAD (1<<0)
 #define DEFAULT_OCTOPUS (1<<1)
@@ -96,6 +97,9 @@ enum ff_type {
 
 static enum ff_type fast_forward = FF_ALLOW;
 
+static const char *cleanup_arg;
+static int put_scissors;
+
 static int option_parse_message(const struct option *opt,
 				const char *arg, int unset)
 {
@@ -243,6 +247,7 @@ static struct option builtin_merge_options[] = {
 		N_("perform a commit if the merge succeeds (default)")),
 	OPT_BOOL('e', "edit", &option_edit,
 		N_("edit message before committing")),
+	OPT_STRING(0, "cleanup", &cleanup_arg, N_("default"), N_("how to strip spaces and #comments from message")),
 	OPT_SET_INT(0, "ff", &fast_forward, N_("allow fast-forward (default)"), FF_ALLOW),
 	OPT_SET_INT_F(0, "ff-only", &fast_forward,
 		      N_("abort if fast-forward is not possible"),
@@ -606,6 +611,8 @@ static int git_merge_config(const char *k, const char *v, void *cb)
 		return git_config_string(&pull_twohead, k, v);
 	else if (!strcmp(k, "pull.octopus"))
 		return git_config_string(&pull_octopus, k, v);
+	else if (!strcmp(k, "commit.cleanup"))
+		return git_config_string(&cleanup_arg, k, v);
 	else if (!strcmp(k, "merge.renormalize"))
 		option_renormalize = git_config_bool(k, v);
 	else if (!strcmp(k, "merge.ff")) {
@@ -894,6 +901,13 @@ static int suggest_conflicts(void)
 	filename = git_path_merge_msg(the_repository);
 	fp = xfopen(filename, "a");
 
+	if (put_scissors) {
+	    fputc('\n', fp);
+	    wt_status_add_cut_line(fp);
+	    /* comments out the newline from append_conflicts_hint */
+	    fputc(comment_line_char, fp);
+	}
+
 	append_conflicts_hint(&msgbuf);
 	fputs(msgbuf.buf, fp);
 	strbuf_release(&msgbuf);
@@ -1402,6 +1416,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
 	if (option_edit < 0)
 		option_edit = default_edit_option();
 
+	put_scissors = cleanup_arg && !strcmp(cleanup_arg, "scissors");
+
 	if (!use_strategies) {
 		if (!remoteheads)
 			; /* already up-to-date */
diff --git a/builtin/pull.c b/builtin/pull.c
index 681c127a07..88245bce0e 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -95,6 +95,7 @@ static char *opt_signoff;
 static char *opt_squash;
 static char *opt_commit;
 static char *opt_edit;
+static char *opt_cleanup;
 static char *opt_ff;
 static char *opt_verify_signatures;
 static int opt_autostash = -1;
@@ -162,6 +163,9 @@ static struct option pull_options[] = {
 	OPT_PASSTHRU(0, "edit", &opt_edit, NULL,
 		N_("edit message before committing"),
 		PARSE_OPT_NOARG),
+	OPT_PASSTHRU(0, "cleanup", &opt_cleanup, NULL,
+		N_("how to strip spaces and #comments from message"),
+		PARSE_OPT_NOARG),
 	OPT_PASSTHRU(0, "ff", &opt_ff, NULL,
 		N_("allow fast-forward"),
 		PARSE_OPT_NOARG),
@@ -625,6 +629,8 @@ static int run_merge(void)
 		argv_array_push(&args, opt_commit);
 	if (opt_edit)
 		argv_array_push(&args, opt_edit);
+	if (opt_cleanup)
+		argv_array_push(&args, opt_cleanup);
 	if (opt_ff)
 		argv_array_push(&args, opt_ff);
 	if (opt_verify_signatures)
diff --git a/t/t7600-merge.sh b/t/t7600-merge.sh
index 106148254d..0d3db34f08 100755
--- a/t/t7600-merge.sh
+++ b/t/t7600-merge.sh
@@ -247,6 +247,54 @@ test_expect_success 'merge --squash c3 with c7' '
 	test_cmp expect actual
 '
 
+test_expect_success 'merge c3 with c7 with commit.cleanup = scissors' '
+	git config commit.cleanup scissors &&
+	git reset --hard c3 &&
+	test_must_fail git merge c7 &&
+	cat result.9z >file &&
+	git commit --no-edit -a &&
+
+	{
+		cat <<-EOF
+		Merge tag '"'"'c7'"'"'
+
+		# ------------------------ >8 ------------------------
+		# Do not modify or remove the line above.
+		# Everything below it will be ignored.
+		#
+		# Conflicts:
+		#	file
+		EOF
+	} >expect &&
+	git cat-file commit HEAD | sed -e '1,/^$/d' >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'merge c3 with c7 with --squash commit.cleanup = scissors' '
+	git config commit.cleanup scissors &&
+	git reset --hard c3 &&
+	test_must_fail git merge --squash c7 &&
+	cat result.9z >file &&
+	git commit --no-edit -a &&
+
+	{
+		cat <<-EOF
+		Squashed commit of the following:
+
+		$(git show -s c7)
+
+		# ------------------------ >8 ------------------------
+		# Do not modify or remove the line above.
+		# Everything below it will be ignored.
+		#
+		# Conflicts:
+		#	file
+		EOF
+	} >expect &&
+	git cat-file commit HEAD | sed -e '1,/^$/d' >actual &&
+	test_cmp expect actual
+'
+
 test_debug 'git log --graph --decorate --oneline --all'
 
 test_expect_success 'merge c1 with c2 and c3' '
-- 
2.19.1


^ permalink raw reply	[flat|nested] 105+ messages in thread

* Re: [PATCH v3 0/1] Fix scissors bug during merge conflict
  2018-11-17 23:32   ` [PATCH v3 0/1] Fix scissors bug during " Denton Liu
  2018-11-17 23:32     ` [PATCH v3 1/1] merge: add scissors line on " Denton Liu
@ 2018-11-18  6:54     ` Junio C Hamano
  2018-11-21  3:13     ` [PATCH v4 0/2] " Denton Liu
  2 siblings, 0 replies; 105+ messages in thread
From: Junio C Hamano @ 2018-11-18  6:54 UTC (permalink / raw)
  To: Denton Liu; +Cc: git

Denton Liu <liu.denton@gmail.com> writes:

>> I wonder if this is what you really meant to have instead:
>> 
>> >  		else if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS &&
>> > -			 whence == FROM_COMMIT)
>> > - 			wt_status_add_cut_line(s->fp);
>> > +			 whence == FROM_COMMIT) {
>> > +			 if (!merge_contains_scissors)
>> > +				wt_status_add_cut_line(s->fp);
>> > +		}
>> >  		else /* COMMIT_MSG_CLEANUP_SPACE, that is. */
>> >  			status_printf(s, GIT_COLOR_NORMAL,
>> 
>> That is, the only behaviour change in "merge contains scissors"
>> mode is to omit the cut line and nothing else.
>
> Thanks for catching this. I noticed that the originally behaviour is
> buggy too: in the case where we're merging a commit and scissors are
> printed from the `if (whence != FROM_COMMIT)` block, the original
> behaviour would drop us into the else (COMMIT_MSG_CLEANUP_SPACE)
> statement, which is undesired.

The original calls add-cut-line in the "whence != FROM_COMMIT" when
cleanup_mode is CLEANUP_SCISSORS (and then in that block it also adds
the message about committing a merge or cherry-pick).  After that,
the original does the three-arm if/else if/else cascade and we end
up showing the "lines starting with # will be kept" message.

Yeah, you read the original correctly and I agree that in that block
the right thing to do is not to say anything in CLEANUP_SCISSORS
mode.

Thanks for carefully reading the code again.



^ permalink raw reply	[flat|nested] 105+ messages in thread

* Re: [PATCH v3 1/1] merge: add scissors line on merge conflict
  2018-11-17 23:32     ` [PATCH v3 1/1] merge: add scissors line on " Denton Liu
@ 2018-11-18 14:18       ` SZEDER Gábor
  0 siblings, 0 replies; 105+ messages in thread
From: SZEDER Gábor @ 2018-11-18 14:18 UTC (permalink / raw)
  To: Denton Liu; +Cc: git, gitster

On Sat, Nov 17, 2018 at 06:32:33PM -0500, Denton Liu wrote:
> diff --git a/t/t7600-merge.sh b/t/t7600-merge.sh
> index 106148254d..0d3db34f08 100755
> --- a/t/t7600-merge.sh
> +++ b/t/t7600-merge.sh
> @@ -247,6 +247,54 @@ test_expect_success 'merge --squash c3 with c7' '
>  	test_cmp expect actual
>  '
>  
> +test_expect_success 'merge c3 with c7 with commit.cleanup = scissors' '
> +	git config commit.cleanup scissors &&
> +	git reset --hard c3 &&
> +	test_must_fail git merge c7 &&
> +	cat result.9z >file &&
> +	git commit --no-edit -a &&
> +
> +	{
> +		cat <<-EOF
> +		Merge tag '"'"'c7'"'"'
> +
> +		# ------------------------ >8 ------------------------
> +		# Do not modify or remove the line above.
> +		# Everything below it will be ignored.

Note that these two lines of advice text are translated; see the
consequences below.

> +		#
> +		# Conflicts:
> +		#	file
> +		EOF
> +	} >expect &&

The {...} block is unnecessary, because there is only a single command
in there.

> +	git cat-file commit HEAD | sed -e '1,/^$/d' >actual &&

Please don't run git commands upstream of a pipe, because the pipe
hides their exit code.  Furthermore, put the sed script inside double
quotes, because the whole test is already in a single-quoted block.

I presume you wrote the test this way because you simply followed suit
of the previous test 'merge --squash c3 with c7', which did all the
same.  Bonus points for a preparatory patch that cleans up the
previous test ;)

> +	test_cmp expect actual

But most importantly, here 'test_cmp' compares translated advice text
as well, which fails in the GETTEXT_POISON build.  Use 'test_i18ncmp'
instead.

> +'
> +
> +test_expect_success 'merge c3 with c7 with --squash commit.cleanup = scissors' '
> +	git config commit.cleanup scissors &&
> +	git reset --hard c3 &&
> +	test_must_fail git merge --squash c7 &&
> +	cat result.9z >file &&
> +	git commit --no-edit -a &&
> +
> +	{
> +		cat <<-EOF
> +		Squashed commit of the following:
> +
> +		$(git show -s c7)
> +
> +		# ------------------------ >8 ------------------------
> +		# Do not modify or remove the line above.
> +		# Everything below it will be ignored.
> +		#
> +		# Conflicts:
> +		#	file
> +		EOF
> +	} >expect &&
> +	git cat-file commit HEAD | sed -e '1,/^$/d' >actual &&
> +	test_cmp expect actual

Likewise.

> +'
> +
>  test_debug 'git log --graph --decorate --oneline --all'
>  
>  test_expect_success 'merge c1 with c2 and c3' '
> -- 
> 2.19.1
> 

^ permalink raw reply	[flat|nested] 105+ messages in thread

* [PATCH v4 0/2] Fix scissors bug during merge conflict
  2018-11-17 23:32   ` [PATCH v3 0/1] Fix scissors bug during " Denton Liu
  2018-11-17 23:32     ` [PATCH v3 1/1] merge: add scissors line on " Denton Liu
  2018-11-18  6:54     ` [PATCH v3 0/1] Fix scissors bug during " Junio C Hamano
@ 2018-11-21  3:13     ` Denton Liu
  2018-11-21  3:13       ` [PATCH v4 1/2] t7600: clean up 'merge --squash c3 with c7' test Denton Liu
                         ` (3 more replies)
  2 siblings, 4 replies; 105+ messages in thread
From: Denton Liu @ 2018-11-21  3:13 UTC (permalink / raw)
  To: git; +Cc: gitster, szeder.dev

Thanks for catching that, Szeder. I tested this revised patch under
GETTEXT_POISON and it should be passing tests now.

Changes since V1:
	* Only check MERGE_MSG for a scissors line instead of all prepended
	  files
	* Make a variable static in merge where appropriate
	* Add passthrough options in pull
	* Add documentation for the new option
	* Add tests to ensure desired behaviour

Changes since V2:
	* Merge both patches into one patch
	* Fix bug in help message printing logic

Changes since V3:
	* Add patch to cleanup 'merge --squash c3 with c7' test in t7600
	* Use test_i18ncmp instead of test_cmp to pass GETTEXT_POISON tests

Denton Liu (2):
  t7600: clean up 'merge --squash c3 with c7' test
  merge: add scissors line on merge conflict

 Documentation/merge-options.txt |  6 ++++
 builtin/commit.c                | 20 +++++++++----
 builtin/merge.c                 | 16 ++++++++++
 builtin/pull.c                  |  6 ++++
 t/t7600-merge.sh                | 53 ++++++++++++++++++++++++++++++---
 5 files changed, 92 insertions(+), 9 deletions(-)

-- 
2.19.1


^ permalink raw reply	[flat|nested] 105+ messages in thread

* [PATCH v4 1/2] t7600: clean up 'merge --squash c3 with c7' test
  2018-11-21  3:13     ` [PATCH v4 0/2] " Denton Liu
@ 2018-11-21  3:13       ` Denton Liu
  2018-11-21  3:13       ` [PATCH v4 2/2] merge: add scissors line on merge conflict Denton Liu
                         ` (2 subsequent siblings)
  3 siblings, 0 replies; 105+ messages in thread
From: Denton Liu @ 2018-11-21  3:13 UTC (permalink / raw)
  To: git; +Cc: gitster, szeder.dev

This cleans up the original test by removing some unnecessary braces and
removing a pipe.

Helped-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Denton Liu <liu.denton@gmail.com>
---
 t/t7600-merge.sh | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/t/t7600-merge.sh b/t/t7600-merge.sh
index 106148254d..d879efd330 100755
--- a/t/t7600-merge.sh
+++ b/t/t7600-merge.sh
@@ -233,8 +233,7 @@ test_expect_success 'merge --squash c3 with c7' '
 	cat result.9z >file &&
 	git commit --no-edit -a &&
 
-	{
-		cat <<-EOF
+	cat >expect <<-EOF &&
 		Squashed commit of the following:
 
 		$(git show -s c7)
@@ -242,8 +241,8 @@ test_expect_success 'merge --squash c3 with c7' '
 		# Conflicts:
 		#	file
 		EOF
-	} >expect &&
-	git cat-file commit HEAD | sed -e '1,/^$/d' >actual &&
+	git cat-file commit HEAD >tmp &&
+	sed -e '1,/^$/d' <tmp >actual &&
 	test_cmp expect actual
 '
 
-- 
2.19.1


^ permalink raw reply	[flat|nested] 105+ messages in thread

* [PATCH v4 2/2] merge: add scissors line on merge conflict
  2018-11-21  3:13     ` [PATCH v4 0/2] " Denton Liu
  2018-11-21  3:13       ` [PATCH v4 1/2] t7600: clean up 'merge --squash c3 with c7' test Denton Liu
@ 2018-11-21  3:13       ` Denton Liu
  2018-11-21  9:38       ` [PATCH v4 0/2] Fix scissors bug during " Junio C Hamano
  2018-12-25 13:55       ` [PATCH v5 0/4] Add git-merge --cleanup support Denton Liu
  3 siblings, 0 replies; 105+ messages in thread
From: Denton Liu @ 2018-11-21  3:13 UTC (permalink / raw)
  To: git; +Cc: gitster, szeder.dev

This fixes a bug where the scissors line is placed after the Conflicts:
section, in the case where a merge conflict occurs and
merge.cleanup = scissors.

Next, if commit.cleanup = scissors is specified, don't produce a
scissors line in commit if one already exists in the MERGE_MSG file.

Finally, we give pull the passthrough option of --cleanup so that it
can also take advantage of this change.

Signed-off-by: Denton Liu <liu.denton@gmail.com>
---
 Documentation/merge-options.txt |  6 +++++
 builtin/commit.c                | 20 ++++++++++----
 builtin/merge.c                 | 16 ++++++++++++
 builtin/pull.c                  |  6 +++++
 t/t7600-merge.sh                | 46 +++++++++++++++++++++++++++++++++
 5 files changed, 89 insertions(+), 5 deletions(-)

diff --git a/Documentation/merge-options.txt b/Documentation/merge-options.txt
index 63a3fc0954..115e0ca6f0 100644
--- a/Documentation/merge-options.txt
+++ b/Documentation/merge-options.txt
@@ -27,6 +27,12 @@ they run `git merge`. To make it easier to adjust such scripts to the
 updated behaviour, the environment variable `GIT_MERGE_AUTOEDIT` can be
 set to `no` at the beginning of them.
 
+--cleanup=<mode>::
+	This option determines how the merge message will be cleaned up
+	before being passed on. Specifically, if the '<mode>' is given a
+	value of `scissors`, scissors will be prepended to the message in
+	the case of a merge conflict. See also linkgit:git-commit[1].
+
 --ff::
 	When the merge resolves as a fast-forward, only update the branch
 	pointer, without creating a merge commit.  This is the default
diff --git a/builtin/commit.c b/builtin/commit.c
index 0d9828e29e..7902645bc9 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -659,6 +659,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
 	const char *hook_arg2 = NULL;
 	int clean_message_contents = (cleanup_mode != COMMIT_MSG_CLEANUP_NONE);
 	int old_display_comment_prefix;
+	int merge_contains_scissors = 0;
 
 	/* This checks and barfs if author is badly specified */
 	determine_author_info(author_ident);
@@ -719,6 +720,8 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
 			strbuf_addbuf(&sb, &message);
 		hook_arg1 = "message";
 	} else if (!stat(git_path_merge_msg(the_repository), &statbuf)) {
+		size_t merge_msg_start;
+
 		/*
 		 * prepend SQUASH_MSG here if it exists and a
 		 * "merge --squash" was originally performed
@@ -729,8 +732,14 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
 			hook_arg1 = "squash";
 		} else
 			hook_arg1 = "merge";
+
+		merge_msg_start = sb.len;
 		if (strbuf_read_file(&sb, git_path_merge_msg(the_repository), 0) < 0)
 			die_errno(_("could not read MERGE_MSG"));
+
+		if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS &&
+		    wt_status_locate_end(sb.buf + merge_msg_start, sb.len - merge_msg_start) < sb.len - merge_msg_start)
+			merge_contains_scissors = 1;
 	} else if (!stat(git_path_squash_msg(the_repository), &statbuf)) {
 		if (strbuf_read_file(&sb, git_path_squash_msg(the_repository), 0) < 0)
 			die_errno(_("could not read SQUASH_MSG"));
@@ -798,7 +807,8 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
 		struct ident_split ci, ai;
 
 		if (whence != FROM_COMMIT) {
-			if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)
+			if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS &&
+				!merge_contains_scissors)
 				wt_status_add_cut_line(s->fp);
 			status_printf_ln(s, GIT_COLOR_NORMAL,
 			    whence == FROM_MERGE
@@ -823,10 +833,10 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
 				_("Please enter the commit message for your changes."
 				  " Lines starting\nwith '%c' will be ignored, and an empty"
 				  " message aborts the commit.\n"), comment_line_char);
-		else if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS &&
-			 whence == FROM_COMMIT)
-			wt_status_add_cut_line(s->fp);
-		else /* COMMIT_MSG_CLEANUP_SPACE, that is. */
+		else if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS) {
+			if (whence == FROM_COMMIT && !merge_contains_scissors)
+				wt_status_add_cut_line(s->fp);
+		} else /* COMMIT_MSG_CLEANUP_SPACE, that is. */
 			status_printf(s, GIT_COLOR_NORMAL,
 				_("Please enter the commit message for your changes."
 				  " Lines starting\n"
diff --git a/builtin/merge.c b/builtin/merge.c
index 8f4a5065c2..23a6e6bb93 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -36,6 +36,7 @@
 #include "packfile.h"
 #include "tag.h"
 #include "alias.h"
+#include "wt-status.h"
 
 #define DEFAULT_TWOHEAD (1<<0)
 #define DEFAULT_OCTOPUS (1<<1)
@@ -96,6 +97,9 @@ enum ff_type {
 
 static enum ff_type fast_forward = FF_ALLOW;
 
+static const char *cleanup_arg;
+static int put_scissors;
+
 static int option_parse_message(const struct option *opt,
 				const char *arg, int unset)
 {
@@ -243,6 +247,7 @@ static struct option builtin_merge_options[] = {
 		N_("perform a commit if the merge succeeds (default)")),
 	OPT_BOOL('e', "edit", &option_edit,
 		N_("edit message before committing")),
+	OPT_STRING(0, "cleanup", &cleanup_arg, N_("default"), N_("how to strip spaces and #comments from message")),
 	OPT_SET_INT(0, "ff", &fast_forward, N_("allow fast-forward (default)"), FF_ALLOW),
 	OPT_SET_INT_F(0, "ff-only", &fast_forward,
 		      N_("abort if fast-forward is not possible"),
@@ -606,6 +611,8 @@ static int git_merge_config(const char *k, const char *v, void *cb)
 		return git_config_string(&pull_twohead, k, v);
 	else if (!strcmp(k, "pull.octopus"))
 		return git_config_string(&pull_octopus, k, v);
+	else if (!strcmp(k, "commit.cleanup"))
+		return git_config_string(&cleanup_arg, k, v);
 	else if (!strcmp(k, "merge.renormalize"))
 		option_renormalize = git_config_bool(k, v);
 	else if (!strcmp(k, "merge.ff")) {
@@ -894,6 +901,13 @@ static int suggest_conflicts(void)
 	filename = git_path_merge_msg(the_repository);
 	fp = xfopen(filename, "a");
 
+	if (put_scissors) {
+	    fputc('\n', fp);
+	    wt_status_add_cut_line(fp);
+	    /* comments out the newline from append_conflicts_hint */
+	    fputc(comment_line_char, fp);
+	}
+
 	append_conflicts_hint(&msgbuf);
 	fputs(msgbuf.buf, fp);
 	strbuf_release(&msgbuf);
@@ -1402,6 +1416,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
 	if (option_edit < 0)
 		option_edit = default_edit_option();
 
+	put_scissors = cleanup_arg && !strcmp(cleanup_arg, "scissors");
+
 	if (!use_strategies) {
 		if (!remoteheads)
 			; /* already up-to-date */
diff --git a/builtin/pull.c b/builtin/pull.c
index 681c127a07..88245bce0e 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -95,6 +95,7 @@ static char *opt_signoff;
 static char *opt_squash;
 static char *opt_commit;
 static char *opt_edit;
+static char *opt_cleanup;
 static char *opt_ff;
 static char *opt_verify_signatures;
 static int opt_autostash = -1;
@@ -162,6 +163,9 @@ static struct option pull_options[] = {
 	OPT_PASSTHRU(0, "edit", &opt_edit, NULL,
 		N_("edit message before committing"),
 		PARSE_OPT_NOARG),
+	OPT_PASSTHRU(0, "cleanup", &opt_cleanup, NULL,
+		N_("how to strip spaces and #comments from message"),
+		PARSE_OPT_NOARG),
 	OPT_PASSTHRU(0, "ff", &opt_ff, NULL,
 		N_("allow fast-forward"),
 		PARSE_OPT_NOARG),
@@ -625,6 +629,8 @@ static int run_merge(void)
 		argv_array_push(&args, opt_commit);
 	if (opt_edit)
 		argv_array_push(&args, opt_edit);
+	if (opt_cleanup)
+		argv_array_push(&args, opt_cleanup);
 	if (opt_ff)
 		argv_array_push(&args, opt_ff);
 	if (opt_verify_signatures)
diff --git a/t/t7600-merge.sh b/t/t7600-merge.sh
index d879efd330..2cb57e5878 100755
--- a/t/t7600-merge.sh
+++ b/t/t7600-merge.sh
@@ -246,6 +246,52 @@ test_expect_success 'merge --squash c3 with c7' '
 	test_cmp expect actual
 '
 
+test_expect_success 'merge c3 with c7 with commit.cleanup = scissors' '
+	git config commit.cleanup scissors &&
+	git reset --hard c3 &&
+	test_must_fail git merge c7 &&
+	cat result.9z >file &&
+	git commit --no-edit -a &&
+
+	cat >expect <<-EOF &&
+		Merge tag '"'"'c7'"'"'
+
+		# ------------------------ >8 ------------------------
+		# Do not modify or remove the line above.
+		# Everything below it will be ignored.
+		#
+		# Conflicts:
+		#	file
+		EOF
+	git cat-file commit HEAD >tmp &&
+	sed -e '1,/^$/d' <tmp >actual &&
+	test_i18ncmp expect actual
+'
+
+test_expect_success 'merge c3 with c7 with --squash commit.cleanup = scissors' '
+	git config commit.cleanup scissors &&
+	git reset --hard c3 &&
+	test_must_fail git merge --squash c7 &&
+	cat result.9z >file &&
+	git commit --no-edit -a &&
+
+	cat >expect <<-EOF &&
+		Squashed commit of the following:
+
+		$(git show -s c7)
+
+		# ------------------------ >8 ------------------------
+		# Do not modify or remove the line above.
+		# Everything below it will be ignored.
+		#
+		# Conflicts:
+		#	file
+		EOF
+	git cat-file commit HEAD >tmp &&
+	sed -e '1,/^$/d' <tmp >actual &&
+	test_i18ncmp expect actual
+'
+
 test_debug 'git log --graph --decorate --oneline --all'
 
 test_expect_success 'merge c1 with c2 and c3' '
-- 
2.19.1


^ permalink raw reply	[flat|nested] 105+ messages in thread

* Re: [PATCH v4 0/2] Fix scissors bug during merge conflict
  2018-11-21  3:13     ` [PATCH v4 0/2] " Denton Liu
  2018-11-21  3:13       ` [PATCH v4 1/2] t7600: clean up 'merge --squash c3 with c7' test Denton Liu
  2018-11-21  3:13       ` [PATCH v4 2/2] merge: add scissors line on merge conflict Denton Liu
@ 2018-11-21  9:38       ` Junio C Hamano
  2018-11-22  1:10         ` Denton Liu
  2018-12-25 13:55       ` [PATCH v5 0/4] Add git-merge --cleanup support Denton Liu
  3 siblings, 1 reply; 105+ messages in thread
From: Junio C Hamano @ 2018-11-21  9:38 UTC (permalink / raw)
  To: Denton Liu; +Cc: git, szeder.dev

Denton Liu <liu.denton@gmail.com> writes:

> Changes since V3:
> 	* Add patch to cleanup 'merge --squash c3 with c7' test in t7600
> 	* Use test_i18ncmp instead of test_cmp to pass GETTEXT_POISON tests

Queued. Thanks, both.

^ permalink raw reply	[flat|nested] 105+ messages in thread

* Re: [PATCH v4 0/2] Fix scissors bug during merge conflict
  2018-11-21  9:38       ` [PATCH v4 0/2] Fix scissors bug during " Junio C Hamano
@ 2018-11-22  1:10         ` Denton Liu
  2018-11-24  2:05           ` Junio C Hamano
  0 siblings, 1 reply; 105+ messages in thread
From: Denton Liu @ 2018-11-22  1:10 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, szeder.dev

On Wed, Nov 21, 2018 at 06:38:20PM +0900, Junio C Hamano wrote:
> Denton Liu <liu.denton@gmail.com> writes:
> 
> > Changes since V3:
> > 	* Add patch to cleanup 'merge --squash c3 with c7' test in t7600
> > 	* Use test_i18ncmp instead of test_cmp to pass GETTEXT_POISON tests
> 
> Queued. Thanks, both.

I just realised that there is a slight problem with the proposed change.
When we do a merge and there are no merge conflicts, at the end of the
merge, we get dropped into an editor with this text:

	Merge branch 'master' into new

	# Please enter a commit message to explain why this merge is necessary,
	# especially if it merges an updated upstream into a topic branch.
	#
	# Lines starting with '#' will be ignored, and an empty message aborts
	# the commit.

Note that in git-merge, the cleanup only removes commented lines and
this cannot be configured to be scissors or whatever else. I think that
the fact that it's not configurable isn't a problem; most hardcore
commit message editing happens in git-commit anyway.

However, since we taught git-merge the --cleanup option, this might be
misleading for the end-user since they would expect the MERGE_MSG to be
cleaned up as specified.

I see two resolutions for this. We can either rename --cleanup more
precisely so users won't be confused (perhaps something like
--merge-conflict-scissors but a lot more snappy) or we can actually make
git-merge respect the cleanup option and post-process the message
according to the specified cleanup rule.

I would personally think the first option is better than the second but
I'd like to hear your thoughts.

Thanks!

^ permalink raw reply	[flat|nested] 105+ messages in thread

* Re: [PATCH v4 0/2] Fix scissors bug during merge conflict
  2018-11-22  1:10         ` Denton Liu
@ 2018-11-24  2:05           ` Junio C Hamano
  0 siblings, 0 replies; 105+ messages in thread
From: Junio C Hamano @ 2018-11-24  2:05 UTC (permalink / raw)
  To: Denton Liu; +Cc: git, szeder.dev

Denton Liu <liu.denton@gmail.com> writes:

> I just realised that there is a slight problem with the proposed change.
> When we do a merge and there are no merge conflicts, at the end of the
> merge, we get dropped into an editor with this text:
>
> 	Merge branch 'master' into new
>
> 	# Please enter a commit message to explain why this merge is necessary,
> 	# especially if it merges an updated upstream into a topic branch.
> 	#
> 	# Lines starting with '#' will be ignored, and an empty message aborts
> 	# the commit.
>
> Note that in git-merge, the cleanup only removes commented lines and
> this cannot be configured to be scissors or whatever else. I think that
> the fact that it's not configurable isn't a problem; most hardcore
> commit message editing happens in git-commit anyway.

OK.

> However, since we taught git-merge the --cleanup option, this might be
> misleading for the end-user since they would expect the MERGE_MSG to be
> cleaned up as specified.
>
> I see two resolutions for this. We can either rename --cleanup more
> precisely so users won't be confused (perhaps something like
> --merge-conflict-scissors but a lot more snappy) or we can actually make
> git-merge respect the cleanup option and post-process the message
> according to the specified cleanup rule.

The former certainly would be simpler to implement, but feels more
like an excuse for not doing the right thing to me, when I put
myself in shoes of users who use 'scissors' clean-up option in
commit.  I dunno.


^ permalink raw reply	[flat|nested] 105+ messages in thread

* [PATCH v5 0/4] Add git-merge --cleanup support
  2018-11-21  3:13     ` [PATCH v4 0/2] " Denton Liu
                         ` (2 preceding siblings ...)
  2018-11-21  9:38       ` [PATCH v4 0/2] Fix scissors bug during " Junio C Hamano
@ 2018-12-25 13:55       ` Denton Liu
  2018-12-25 13:55         ` [PATCH v5 1/4] commit: extract cleanup_mode functions to sequencer Denton Liu
                           ` (4 more replies)
  3 siblings, 5 replies; 105+ messages in thread
From: Denton Liu @ 2018-12-25 13:55 UTC (permalink / raw)
  To: git; +Cc: gitster

Merry Christmas, everyone!

I've finally had some free time to throw together the changes I promised
a couple weeks ago, so now git-merge will support --cleanup just like
git-commit.

Not related to this but while I was making my changes, I noticed that -F
and -m don't die properly in git-merge when they accept invalid
arguments. Instead, they just print an error message to stderr and the
program keeps running. Is this the expected behaviour?

Changes since V1:
	* Only check MERGE_MSG for a scissors line instead of all prepended
	  files
	* Make a variable static in merge where appropriate
	* Add passthrough options in pull
	* Add documentation for the new option
	* Add tests to ensure desired behaviour

Changes since V2:
	* Merge both patches into one patch
	* Fix bug in help message printing logic

Changes since V3:
	* Add patch to cleanup 'merge --squash c3 with c7' test in t7600
	* Use test_i18ncmp instead of test_cmp to pass GETTEXT_POISON tests

Changes since V4:
	* Add patches so that git-merge messages will be cleaned up like in
      git-commit

Denton Liu (4):
  commit: extract cleanup_mode functions to sequencer
  t7600: clean up 'merge --squash c3 with c7' test
  merge: cleanup messages like commit
  merge: add scissors line on merge conflict

 Documentation/merge-options.txt |  7 ++++
 builtin/commit.c                | 41 +++++++++-------------
 builtin/merge.c                 | 45 ++++++++++++++++++++----
 builtin/pull.c                  |  6 ++++
 sequencer.c                     | 29 ++++++++++++++++
 sequencer.h                     |  4 +++
 t/t7600-merge.sh                | 53 +++++++++++++++++++++++++---
 t/t7604-merge-custom-message.sh | 61 +++++++++++++++++++++++++++++++++
 wt-status.c                     | 12 +++++--
 wt-status.h                     |  1 +
 10 files changed, 221 insertions(+), 38 deletions(-)

-- 
2.20.1


^ permalink raw reply	[flat|nested] 105+ messages in thread

* [PATCH v5 1/4] commit: extract cleanup_mode functions to sequencer
  2018-12-25 13:55       ` [PATCH v5 0/4] Add git-merge --cleanup support Denton Liu
@ 2018-12-25 13:55         ` Denton Liu
  2018-12-25 13:56         ` [PATCH v5 2/4] t7600: clean up 'merge --squash c3 with c7' test Denton Liu
                           ` (3 subsequent siblings)
  4 siblings, 0 replies; 105+ messages in thread
From: Denton Liu @ 2018-12-25 13:55 UTC (permalink / raw)
  To: git; +Cc: gitster

Signed-off-by: Denton Liu <liu.denton@gmail.com>
---
 builtin/commit.c | 21 ++-------------------
 sequencer.c      | 29 +++++++++++++++++++++++++++++
 sequencer.h      |  4 ++++
 3 files changed, 35 insertions(+), 19 deletions(-)

diff --git a/builtin/commit.c b/builtin/commit.c
index c021b119bb..9eb745b7ce 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -1164,20 +1164,7 @@ static int parse_and_validate_options(int argc, const char *argv[],
 		die(_("Only one of --include/--only/--all/--interactive/--patch can be used."));
 	if (argc == 0 && (also || (only && !amend && !allow_empty)))
 		die(_("No paths with --include/--only does not make sense."));
-	if (!cleanup_arg || !strcmp(cleanup_arg, "default"))
-		cleanup_mode = use_editor ? COMMIT_MSG_CLEANUP_ALL :
-					    COMMIT_MSG_CLEANUP_SPACE;
-	else if (!strcmp(cleanup_arg, "verbatim"))
-		cleanup_mode = COMMIT_MSG_CLEANUP_NONE;
-	else if (!strcmp(cleanup_arg, "whitespace"))
-		cleanup_mode = COMMIT_MSG_CLEANUP_SPACE;
-	else if (!strcmp(cleanup_arg, "strip"))
-		cleanup_mode = COMMIT_MSG_CLEANUP_ALL;
-	else if (!strcmp(cleanup_arg, "scissors"))
-		cleanup_mode = use_editor ? COMMIT_MSG_CLEANUP_SCISSORS :
-					    COMMIT_MSG_CLEANUP_SPACE;
-	else
-		die(_("Invalid cleanup mode %s"), cleanup_arg);
+	cleanup_mode = get_cleanup_mode(cleanup_arg, use_editor);
 
 	handle_untracked_files_arg(s);
 
@@ -1614,11 +1601,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
 		die(_("could not read commit message: %s"), strerror(saved_errno));
 	}
 
-	if (verbose || /* Truncate the message just before the diff, if any. */
-	    cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)
-		strbuf_setlen(&sb, wt_status_locate_end(sb.buf, sb.len));
-	if (cleanup_mode != COMMIT_MSG_CLEANUP_NONE)
-		strbuf_stripspace(&sb, cleanup_mode == COMMIT_MSG_CLEANUP_ALL);
+	cleanup_message(&sb, cleanup_mode, verbose);
 
 	if (message_is_empty(&sb, cleanup_mode) && !allow_empty_message) {
 		rollback_index_files();
diff --git a/sequencer.c b/sequencer.c
index e1a4dd15f1..9c4eba06dc 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -506,6 +506,25 @@ static int fast_forward_to(const struct object_id *to, const struct object_id *f
 	return 0;
 }
 
+enum commit_msg_cleanup_mode get_cleanup_mode(const char *cleanup_arg,
+	int use_editor)
+{
+	if (!cleanup_arg || !strcmp(cleanup_arg, "default"))
+		return use_editor ? COMMIT_MSG_CLEANUP_ALL :
+				    COMMIT_MSG_CLEANUP_SPACE;
+	else if (!strcmp(cleanup_arg, "verbatim"))
+		return COMMIT_MSG_CLEANUP_NONE;
+	else if (!strcmp(cleanup_arg, "whitespace"))
+		return COMMIT_MSG_CLEANUP_SPACE;
+	else if (!strcmp(cleanup_arg, "strip"))
+		return COMMIT_MSG_CLEANUP_ALL;
+	else if (!strcmp(cleanup_arg, "scissors"))
+		return use_editor ? COMMIT_MSG_CLEANUP_SCISSORS :
+				    COMMIT_MSG_CLEANUP_SPACE;
+	else
+		die(_("Invalid cleanup mode %s"), cleanup_arg);
+}
+
 void append_conflicts_hint(struct strbuf *msgbuf)
 {
 	int i;
@@ -1003,6 +1022,16 @@ static int rest_is_empty(const struct strbuf *sb, int start)
 	return 1;
 }
 
+void cleanup_message(struct strbuf *msgbuf,
+	enum commit_msg_cleanup_mode cleanup_mode, int verbose)
+{
+	if (verbose || /* Truncate the message just before the diff, if any. */
+	    cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)
+		strbuf_setlen(msgbuf, wt_status_locate_end(msgbuf->buf, msgbuf->len));
+	if (cleanup_mode != COMMIT_MSG_CLEANUP_NONE)
+		strbuf_stripspace(msgbuf, cleanup_mode == COMMIT_MSG_CLEANUP_ALL);
+}
+
 /*
  * Find out if the message in the strbuf contains only whitespace and
  * Signed-off-by lines.
diff --git a/sequencer.h b/sequencer.h
index 5071a73563..e6d937dd3c 100644
--- a/sequencer.h
+++ b/sequencer.h
@@ -112,7 +112,11 @@ extern const char sign_off_header[];
  */
 void append_signoff(struct strbuf *msgbuf, size_t ignore_footer, unsigned flag);
 
+enum commit_msg_cleanup_mode get_cleanup_mode(const char *cleanup_arg,
+	int use_editor);
 void append_conflicts_hint(struct strbuf *msgbuf);
+void cleanup_message(struct strbuf *msgbuf,
+	enum commit_msg_cleanup_mode cleanup_mode, int verbose);
 int message_is_empty(const struct strbuf *sb,
 		     enum commit_msg_cleanup_mode cleanup_mode);
 int template_untouched(const struct strbuf *sb, const char *template_file,
-- 
2.20.1


^ permalink raw reply	[flat|nested] 105+ messages in thread

* [PATCH v5 2/4] t7600: clean up 'merge --squash c3 with c7' test
  2018-12-25 13:55       ` [PATCH v5 0/4] Add git-merge --cleanup support Denton Liu
  2018-12-25 13:55         ` [PATCH v5 1/4] commit: extract cleanup_mode functions to sequencer Denton Liu
@ 2018-12-25 13:56         ` Denton Liu
  2018-12-25 13:56         ` [PATCH v5 3/4] merge: cleanup messages like commit Denton Liu
                           ` (2 subsequent siblings)
  4 siblings, 0 replies; 105+ messages in thread
From: Denton Liu @ 2018-12-25 13:56 UTC (permalink / raw)
  To: git; +Cc: gitster

This cleans up the original test by removing some unnecessary braces and
removing a pipe.

Helped-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Denton Liu <liu.denton@gmail.com>
---
 t/t7600-merge.sh | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/t/t7600-merge.sh b/t/t7600-merge.sh
index 106148254d..d879efd330 100755
--- a/t/t7600-merge.sh
+++ b/t/t7600-merge.sh
@@ -233,8 +233,7 @@ test_expect_success 'merge --squash c3 with c7' '
 	cat result.9z >file &&
 	git commit --no-edit -a &&
 
-	{
-		cat <<-EOF
+	cat >expect <<-EOF &&
 		Squashed commit of the following:
 
 		$(git show -s c7)
@@ -242,8 +241,8 @@ test_expect_success 'merge --squash c3 with c7' '
 		# Conflicts:
 		#	file
 		EOF
-	} >expect &&
-	git cat-file commit HEAD | sed -e '1,/^$/d' >actual &&
+	git cat-file commit HEAD >tmp &&
+	sed -e '1,/^$/d' <tmp >actual &&
 	test_cmp expect actual
 '
 
-- 
2.20.1


^ permalink raw reply	[flat|nested] 105+ messages in thread

* [PATCH v5 3/4] merge: cleanup messages like commit
  2018-12-25 13:55       ` [PATCH v5 0/4] Add git-merge --cleanup support Denton Liu
  2018-12-25 13:55         ` [PATCH v5 1/4] commit: extract cleanup_mode functions to sequencer Denton Liu
  2018-12-25 13:56         ` [PATCH v5 2/4] t7600: clean up 'merge --squash c3 with c7' test Denton Liu
@ 2018-12-25 13:56         ` Denton Liu
  2018-12-25 13:56         ` [PATCH v5 4/4] merge: add scissors line on merge conflict Denton Liu
  2019-01-23  5:06         ` [PATCH v6 0/4] Add git-merge --cleanup support Denton Liu
  4 siblings, 0 replies; 105+ messages in thread
From: Denton Liu @ 2018-12-25 13:56 UTC (permalink / raw)
  To: git; +Cc: gitster

This change allows git-merge messages to be cleaned up with the
commit.cleanup configuration or --cleanup option, just like how
git-commit does it.

We also give git-pull the passthrough option of --cleanup so that it can
also take advantage of this change.

Finally, add testing to ensure that messages are properly cleaned up.
Note that some newlines that were added to the commit message were
removed so that if a file were read via -F, it would be copied
faithfully.

Signed-off-by: Denton Liu <liu.denton@gmail.com>
---
 Documentation/merge-options.txt |  5 +++
 builtin/merge.c                 | 31 +++++++++++++----
 builtin/pull.c                  |  6 ++++
 t/t7604-merge-custom-message.sh | 61 +++++++++++++++++++++++++++++++++
 wt-status.c                     | 12 +++++--
 wt-status.h                     |  1 +
 6 files changed, 106 insertions(+), 10 deletions(-)

diff --git a/Documentation/merge-options.txt b/Documentation/merge-options.txt
index 63a3fc0954..22783651b6 100644
--- a/Documentation/merge-options.txt
+++ b/Documentation/merge-options.txt
@@ -27,6 +27,11 @@ they run `git merge`. To make it easier to adjust such scripts to the
 updated behaviour, the environment variable `GIT_MERGE_AUTOEDIT` can be
 set to `no` at the beginning of them.
 
+--cleanup=<mode>::
+	This option determines how the merge message will be cleaned up
+	before commiting or being passed on. See linkgit:git-commit[1] for more
+	details.
+
 --ff::
 	When the merge resolves as a fast-forward, only update the branch
 	pointer, without creating a merge commit.  This is the default
diff --git a/builtin/merge.c b/builtin/merge.c
index c3c976d471..ab0db46ede 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -37,6 +37,7 @@
 #include "tag.h"
 #include "alias.h"
 #include "commit-reach.h"
+#include "wt-status.h"
 
 #define DEFAULT_TWOHEAD (1<<0)
 #define DEFAULT_OCTOPUS (1<<1)
@@ -97,6 +98,9 @@ enum ff_type {
 
 static enum ff_type fast_forward = FF_ALLOW;
 
+static const char *cleanup_arg;
+static enum commit_msg_cleanup_mode cleanup_mode;
+
 static int option_parse_message(const struct option *opt,
 				const char *arg, int unset)
 {
@@ -245,6 +249,7 @@ static struct option builtin_merge_options[] = {
 		N_("perform a commit if the merge succeeds (default)")),
 	OPT_BOOL('e', "edit", &option_edit,
 		N_("edit message before committing")),
+	OPT_STRING(0, "cleanup", &cleanup_arg, N_("default"), N_("how to strip spaces and #comments from message")),
 	OPT_SET_INT(0, "ff", &fast_forward, N_("allow fast-forward (default)"), FF_ALLOW),
 	OPT_SET_INT_F(0, "ff-only", &fast_forward,
 		      N_("abort if fast-forward is not possible"),
@@ -608,6 +613,8 @@ static int git_merge_config(const char *k, const char *v, void *cb)
 		return git_config_string(&pull_twohead, k, v);
 	else if (!strcmp(k, "pull.octopus"))
 		return git_config_string(&pull_octopus, k, v);
+	else if (!strcmp(k, "commit.cleanup"))
+		return git_config_string(&cleanup_arg, k, v);
 	else if (!strcmp(k, "merge.renormalize"))
 		option_renormalize = git_config_bool(k, v);
 	else if (!strcmp(k, "merge.ff")) {
@@ -793,23 +800,32 @@ static void abort_commit(struct commit_list *remoteheads, const char *err_msg)
 	exit(1);
 }
 
+static const char comment_line_explanation[] =
+N_("Lines starting with '%c' will be ignored.\n");
+
 static const char merge_editor_comment[] =
 N_("Please enter a commit message to explain why this merge is necessary,\n"
    "especially if it merges an updated upstream into a topic branch.\n"
    "\n"
-   "Lines starting with '%c' will be ignored, and an empty message aborts\n"
-   "the commit.\n");
+   "An empty message aborts the commit.\n");
 
 static void write_merge_heads(struct commit_list *);
 static void prepare_to_commit(struct commit_list *remoteheads)
 {
 	struct strbuf msg = STRBUF_INIT;
 	strbuf_addbuf(&msg, &merge_msg);
-	strbuf_addch(&msg, '\n');
 	if (squash)
 		BUG("the control must not reach here under --squash");
-	if (0 < option_edit)
-		strbuf_commented_addf(&msg, _(merge_editor_comment), comment_line_char);
+	if (0 < option_edit) {
+		strbuf_addch(&msg, '\n');
+		if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)
+			wt_status_append_cut_line(&msg);
+		else
+			strbuf_commented_addf(&msg, _(comment_line_explanation), comment_line_char);
+
+		strbuf_commented_addf(&msg, "\n");
+		strbuf_commented_addf(&msg, _(merge_editor_comment));
+	}
 	if (signoff)
 		append_signoff(&msg, ignore_non_trailer(msg.buf, msg.len), 0);
 	write_merge_heads(remoteheads);
@@ -828,7 +844,7 @@ static void prepare_to_commit(struct commit_list *remoteheads)
 		abort_commit(remoteheads, NULL);
 
 	read_merge_msg(&msg);
-	strbuf_stripspace(&msg, 0 < option_edit);
+	cleanup_message(&msg, cleanup_mode, 0);
 	if (!msg.len)
 		abort_commit(remoteheads, _("Empty commit message."));
 	strbuf_release(&merge_msg);
@@ -876,7 +892,6 @@ static int finish_automerge(struct commit *head,
 	parents = remoteheads;
 	if (!head_subsumed || fast_forward == FF_NO)
 		commit_list_insert(head, &parents);
-	strbuf_addch(&merge_msg, '\n');
 	prepare_to_commit(remoteheads);
 	if (commit_tree(merge_msg.buf, merge_msg.len, result_tree, parents,
 			&result_commit, NULL, sign_commit))
@@ -1385,6 +1400,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
 	if (option_edit < 0)
 		option_edit = default_edit_option();
 
+	cleanup_mode = get_cleanup_mode(cleanup_arg, 0 < option_edit);
+
 	if (!use_strategies) {
 		if (!remoteheads)
 			; /* already up-to-date */
diff --git a/builtin/pull.c b/builtin/pull.c
index 1b90622b13..938be2f610 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -96,6 +96,7 @@ static char *opt_signoff;
 static char *opt_squash;
 static char *opt_commit;
 static char *opt_edit;
+static char *opt_cleanup;
 static char *opt_ff;
 static char *opt_verify_signatures;
 static int opt_autostash = -1;
@@ -163,6 +164,9 @@ static struct option pull_options[] = {
 	OPT_PASSTHRU(0, "edit", &opt_edit, NULL,
 		N_("edit message before committing"),
 		PARSE_OPT_NOARG),
+	OPT_PASSTHRU(0, "cleanup", &opt_cleanup, NULL,
+		N_("how to strip spaces and #comments from message"),
+		PARSE_OPT_NOARG),
 	OPT_PASSTHRU(0, "ff", &opt_ff, NULL,
 		N_("allow fast-forward"),
 		PARSE_OPT_NOARG),
@@ -639,6 +643,8 @@ static int run_merge(void)
 		argv_array_push(&args, opt_commit);
 	if (opt_edit)
 		argv_array_push(&args, opt_edit);
+	if (opt_cleanup)
+		argv_array_push(&args, opt_cleanup);
 	if (opt_ff)
 		argv_array_push(&args, opt_ff);
 	if (opt_verify_signatures)
diff --git a/t/t7604-merge-custom-message.sh b/t/t7604-merge-custom-message.sh
index 89619cf446..3fcd58eb2c 100755
--- a/t/t7604-merge-custom-message.sh
+++ b/t/t7604-merge-custom-message.sh
@@ -47,4 +47,65 @@ test_expect_success 'merge --log appends to custom message' '
 	test_cmp exp.log actual
 '
 
+mesg_with_comment_and_newlines='
+# text
+
+'
+
+test_expect_success 'prepare file with comment line and trailing newlines'  '
+	printf "%s" "$mesg_with_comment_and_newlines" >expect
+'
+
+test_expect_success 'cleanup commit messages (verbatim option)' '
+	git reset --hard c1 &&
+	git merge --cleanup=verbatim -F expect c2 &&
+	git cat-file -p HEAD |sed -e "1,/^\$/d" >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'cleanup commit messages (whitespace option)' '
+	git reset --hard c1 &&
+	{ echo;echo "# text";echo; } >text &&
+	echo "# text" >expect &&
+	git merge --cleanup=whitespace -F text c2 &&
+	git cat-file -p HEAD |sed -e "1,/^\$/d">actual &&
+	test_cmp expect actual
+
+'
+
+test_expect_success 'cleanup merge messages (scissors option)' '
+	git reset --hard c1 &&
+	cat >text <<EOF &&
+
+# to be kept
+
+  # ------------------------ >8 ------------------------
+# to be kept, too
+# ------------------------ >8 ------------------------
+to be removed
+# ------------------------ >8 ------------------------
+to be removed, too
+EOF
+
+	cat >expect <<EOF &&
+# to be kept
+
+  # ------------------------ >8 ------------------------
+# to be kept, too
+EOF
+	git merge --cleanup=scissors -e -F text c2 &&
+	git cat-file -p HEAD |sed -e "1,/^\$/d">actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'cleanup commit messages (strip option)' '
+	git reset --hard c1 &&
+	{ echo;echo "# text";echo sample;echo; } >text &&
+	echo sample >expect &&
+	git merge --cleanup=strip -F text c2 &&
+	git cat-file -p HEAD |sed -e "1,/^\$/d">actual &&
+	test_cmp expect actual
+
+'
+
 test_done
diff --git a/wt-status.c b/wt-status.c
index a24711374c..3dc2ff9a8d 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -991,13 +991,19 @@ size_t wt_status_locate_end(const char *s, size_t len)
 	return len;
 }
 
-void wt_status_add_cut_line(FILE *fp)
+void wt_status_append_cut_line(struct strbuf *buf)
 {
 	const char *explanation = _("Do not modify or remove the line above.\nEverything below it will be ignored.");
+
+	strbuf_commented_addf(buf, "%s", cut_line);
+	strbuf_add_commented_lines(buf, explanation, strlen(explanation));
+}
+
+void wt_status_add_cut_line(FILE *fp)
+{
 	struct strbuf buf = STRBUF_INIT;
 
-	fprintf(fp, "%c %s", comment_line_char, cut_line);
-	strbuf_add_commented_lines(&buf, explanation, strlen(explanation));
+	wt_status_append_cut_line(&buf);
 	fputs(buf.buf, fp);
 	strbuf_release(&buf);
 }
diff --git a/wt-status.h b/wt-status.h
index 1fcf93afbf..739a3e4dfb 100644
--- a/wt-status.h
+++ b/wt-status.h
@@ -127,6 +127,7 @@ struct wt_status {
 };
 
 size_t wt_status_locate_end(const char *s, size_t len);
+void wt_status_append_cut_line(struct strbuf *buf);
 void wt_status_add_cut_line(FILE *fp);
 void wt_status_prepare(struct wt_status *s);
 void wt_status_print(struct wt_status *s);
-- 
2.20.1


^ permalink raw reply	[flat|nested] 105+ messages in thread

* [PATCH v5 4/4] merge: add scissors line on merge conflict
  2018-12-25 13:55       ` [PATCH v5 0/4] Add git-merge --cleanup support Denton Liu
                           ` (2 preceding siblings ...)
  2018-12-25 13:56         ` [PATCH v5 3/4] merge: cleanup messages like commit Denton Liu
@ 2018-12-25 13:56         ` Denton Liu
  2019-01-23  5:06         ` [PATCH v6 0/4] Add git-merge --cleanup support Denton Liu
  4 siblings, 0 replies; 105+ messages in thread
From: Denton Liu @ 2018-12-25 13:56 UTC (permalink / raw)
  To: git; +Cc: gitster

This fixes a bug where the scissors line is placed after the Conflicts:
section, in the case where a merge conflict occurs and
commit.cleanup = scissors.

Next, if commit.cleanup = scissors is specified, don't produce a
scissors line in commit if one already exists in the MERGE_MSG file.

Signed-off-by: Denton Liu <liu.denton@gmail.com>
---
 Documentation/merge-options.txt |  4 ++-
 builtin/commit.c                | 20 ++++++++++----
 builtin/merge.c                 | 14 ++++++++++
 t/t7600-merge.sh                | 46 +++++++++++++++++++++++++++++++++
 4 files changed, 78 insertions(+), 6 deletions(-)

diff --git a/Documentation/merge-options.txt b/Documentation/merge-options.txt
index 22783651b6..c2a263ba74 100644
--- a/Documentation/merge-options.txt
+++ b/Documentation/merge-options.txt
@@ -30,7 +30,9 @@ set to `no` at the beginning of them.
 --cleanup=<mode>::
 	This option determines how the merge message will be cleaned up
 	before commiting or being passed on. See linkgit:git-commit[1] for more
-	details.
+	details. In addition, if the '<mode>' is given a value of `scissors`,
+	scissors will be prepended to MERGE_MSG before being passed on in the case
+	of a merge conflict.
 
 --ff::
 	When the merge resolves as a fast-forward, only update the branch
diff --git a/builtin/commit.c b/builtin/commit.c
index 9eb745b7ce..7923282ebb 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -665,6 +665,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
 	const char *hook_arg2 = NULL;
 	int clean_message_contents = (cleanup_mode != COMMIT_MSG_CLEANUP_NONE);
 	int old_display_comment_prefix;
+	int merge_contains_scissors = 0;
 
 	/* This checks and barfs if author is badly specified */
 	determine_author_info(author_ident);
@@ -725,6 +726,8 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
 			strbuf_addbuf(&sb, &message);
 		hook_arg1 = "message";
 	} else if (!stat(git_path_merge_msg(the_repository), &statbuf)) {
+		size_t merge_msg_start;
+
 		/*
 		 * prepend SQUASH_MSG here if it exists and a
 		 * "merge --squash" was originally performed
@@ -735,8 +738,14 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
 			hook_arg1 = "squash";
 		} else
 			hook_arg1 = "merge";
+
+		merge_msg_start = sb.len;
 		if (strbuf_read_file(&sb, git_path_merge_msg(the_repository), 0) < 0)
 			die_errno(_("could not read MERGE_MSG"));
+
+		if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS &&
+		    wt_status_locate_end(sb.buf + merge_msg_start, sb.len - merge_msg_start) < sb.len - merge_msg_start)
+			merge_contains_scissors = 1;
 	} else if (!stat(git_path_squash_msg(the_repository), &statbuf)) {
 		if (strbuf_read_file(&sb, git_path_squash_msg(the_repository), 0) < 0)
 			die_errno(_("could not read SQUASH_MSG"));
@@ -804,7 +813,8 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
 		struct ident_split ci, ai;
 
 		if (whence != FROM_COMMIT) {
-			if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)
+			if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS &&
+				!merge_contains_scissors)
 				wt_status_add_cut_line(s->fp);
 			status_printf_ln(s, GIT_COLOR_NORMAL,
 			    whence == FROM_MERGE
@@ -829,10 +839,10 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
 				_("Please enter the commit message for your changes."
 				  " Lines starting\nwith '%c' will be ignored, and an empty"
 				  " message aborts the commit.\n"), comment_line_char);
-		else if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS &&
-			 whence == FROM_COMMIT)
-			wt_status_add_cut_line(s->fp);
-		else /* COMMIT_MSG_CLEANUP_SPACE, that is. */
+		else if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS) {
+			if (whence == FROM_COMMIT && !merge_contains_scissors)
+				wt_status_add_cut_line(s->fp);
+		} else /* COMMIT_MSG_CLEANUP_SPACE, that is. */
 			status_printf(s, GIT_COLOR_NORMAL,
 				_("Please enter the commit message for your changes."
 				  " Lines starting\n"
diff --git a/builtin/merge.c b/builtin/merge.c
index ab0db46ede..6514267efc 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -912,6 +912,20 @@ static int suggest_conflicts(void)
 	filename = git_path_merge_msg(the_repository);
 	fp = xfopen(filename, "a");
 
+	/*
+	 * We can't use cleanup_mode because if we're not using the editor,
+	 * get_cleanup_mode will return COMMIT_MSG_CLEANUP_SPACE instead, even
+	 * though the message is meant to be processed later by git-commit.
+	 * Thus, we will get the cleanup mode is returned we _are_ using an
+	 * editor.
+	 */
+	if (get_cleanup_mode(cleanup_arg, 1) == COMMIT_MSG_CLEANUP_SCISSORS) {
+	    fputc('\n', fp);
+	    wt_status_add_cut_line(fp);
+	    /* comments out the newline from append_conflicts_hint */
+	    fputc(comment_line_char, fp);
+	}
+
 	append_conflicts_hint(&msgbuf);
 	fputs(msgbuf.buf, fp);
 	strbuf_release(&msgbuf);
diff --git a/t/t7600-merge.sh b/t/t7600-merge.sh
index d879efd330..2cb57e5878 100755
--- a/t/t7600-merge.sh
+++ b/t/t7600-merge.sh
@@ -246,6 +246,52 @@ test_expect_success 'merge --squash c3 with c7' '
 	test_cmp expect actual
 '
 
+test_expect_success 'merge c3 with c7 with commit.cleanup = scissors' '
+	git config commit.cleanup scissors &&
+	git reset --hard c3 &&
+	test_must_fail git merge c7 &&
+	cat result.9z >file &&
+	git commit --no-edit -a &&
+
+	cat >expect <<-EOF &&
+		Merge tag '"'"'c7'"'"'
+
+		# ------------------------ >8 ------------------------
+		# Do not modify or remove the line above.
+		# Everything below it will be ignored.
+		#
+		# Conflicts:
+		#	file
+		EOF
+	git cat-file commit HEAD >tmp &&
+	sed -e '1,/^$/d' <tmp >actual &&
+	test_i18ncmp expect actual
+'
+
+test_expect_success 'merge c3 with c7 with --squash commit.cleanup = scissors' '
+	git config commit.cleanup scissors &&
+	git reset --hard c3 &&
+	test_must_fail git merge --squash c7 &&
+	cat result.9z >file &&
+	git commit --no-edit -a &&
+
+	cat >expect <<-EOF &&
+		Squashed commit of the following:
+
+		$(git show -s c7)
+
+		# ------------------------ >8 ------------------------
+		# Do not modify or remove the line above.
+		# Everything below it will be ignored.
+		#
+		# Conflicts:
+		#	file
+		EOF
+	git cat-file commit HEAD >tmp &&
+	sed -e '1,/^$/d' <tmp >actual &&
+	test_i18ncmp expect actual
+'
+
 test_debug 'git log --graph --decorate --oneline --all'
 
 test_expect_success 'merge c1 with c2 and c3' '
-- 
2.20.1


^ permalink raw reply	[flat|nested] 105+ messages in thread

* [PATCH v6 0/4] Add git-merge --cleanup support
  2018-12-25 13:55       ` [PATCH v5 0/4] Add git-merge --cleanup support Denton Liu
                           ` (3 preceding siblings ...)
  2018-12-25 13:56         ` [PATCH v5 4/4] merge: add scissors line on merge conflict Denton Liu
@ 2019-01-23  5:06         ` Denton Liu
  2019-01-23  5:06           ` [PATCH v6 1/4] commit: extract cleanup_mode functions to sequencer Denton Liu
                             ` (4 more replies)
  4 siblings, 5 replies; 105+ messages in thread
From: Denton Liu @ 2019-01-23  5:06 UTC (permalink / raw)
  To: git; +Cc: gitster

There were some merge conflicts since v5 so I've rebased the last few
patches on the latest master and fixed the conflicts.

Not related to this but while I was making my changes, I noticed that -F
and -m don't die properly in git-merge when they accept invalid
arguments. Instead, they just print an error message to stderr and the
program keeps running. Is this the expected behaviour?


Changes since V1:
	* Only check MERGE_MSG for a scissors line instead of all prepended
	  files
	* Make a variable static in merge where appropriate
	* Add passthrough options in pull
	* Add documentation for the new option
	* Add tests to ensure desired behaviour

Changes since V2:
	* Merge both patches into one patch
	* Fix bug in help message printing logic

Changes since V3:
	* Add patch to cleanup 'merge --squash c3 with c7' test in t7600
	* Use test_i18ncmp instead of test_cmp to pass GETTEXT_POISON tests

Changes since V4:
	* Add patches so that git-merge messages will be cleaned up like in
	  git-commit

Changes since V5:
	* Rebase on latest master and resolve merge conflicts


Denton Liu (4):
  commit: extract cleanup_mode functions to sequencer
  t7600: clean up 'merge --squash c3 with c7' test
  merge: cleanup messages like commit
  merge: add scissors line on merge conflict

 Documentation/merge-options.txt |  7 ++++
 builtin/commit.c                | 41 +++++++++-------------
 builtin/merge.c                 | 45 ++++++++++++++++++++----
 builtin/pull.c                  |  6 ++++
 sequencer.c                     | 29 ++++++++++++++++
 sequencer.h                     |  4 +++
 t/t7600-merge.sh                | 53 +++++++++++++++++++++++++---
 t/t7604-merge-custom-message.sh | 61 +++++++++++++++++++++++++++++++++
 wt-status.c                     | 12 +++++--
 wt-status.h                     |  1 +
 10 files changed, 221 insertions(+), 38 deletions(-)

-- 
2.20.1.3.ge68552ea27.dirty


^ permalink raw reply	[flat|nested] 105+ messages in thread

* [PATCH v6 1/4] commit: extract cleanup_mode functions to sequencer
  2019-01-23  5:06         ` [PATCH v6 0/4] Add git-merge --cleanup support Denton Liu
@ 2019-01-23  5:06           ` Denton Liu
  2019-01-23  5:06           ` [PATCH v6 2/4] t7600: clean up 'merge --squash c3 with c7' test Denton Liu
                             ` (3 subsequent siblings)
  4 siblings, 0 replies; 105+ messages in thread
From: Denton Liu @ 2019-01-23  5:06 UTC (permalink / raw)
  To: git; +Cc: gitster

Signed-off-by: Denton Liu <liu.denton@gmail.com>
---
 builtin/commit.c | 21 ++-------------------
 sequencer.c      | 29 +++++++++++++++++++++++++++++
 sequencer.h      |  4 ++++
 3 files changed, 35 insertions(+), 19 deletions(-)

diff --git a/builtin/commit.c b/builtin/commit.c
index 004b816635..3ac0a21a22 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -1165,20 +1165,7 @@ static int parse_and_validate_options(int argc, const char *argv[],
 		die(_("Only one of --include/--only/--all/--interactive/--patch can be used."));
 	if (argc == 0 && (also || (only && !amend && !allow_empty)))
 		die(_("No paths with --include/--only does not make sense."));
-	if (!cleanup_arg || !strcmp(cleanup_arg, "default"))
-		cleanup_mode = use_editor ? COMMIT_MSG_CLEANUP_ALL :
-					    COMMIT_MSG_CLEANUP_SPACE;
-	else if (!strcmp(cleanup_arg, "verbatim"))
-		cleanup_mode = COMMIT_MSG_CLEANUP_NONE;
-	else if (!strcmp(cleanup_arg, "whitespace"))
-		cleanup_mode = COMMIT_MSG_CLEANUP_SPACE;
-	else if (!strcmp(cleanup_arg, "strip"))
-		cleanup_mode = COMMIT_MSG_CLEANUP_ALL;
-	else if (!strcmp(cleanup_arg, "scissors"))
-		cleanup_mode = use_editor ? COMMIT_MSG_CLEANUP_SCISSORS :
-					    COMMIT_MSG_CLEANUP_SPACE;
-	else
-		die(_("Invalid cleanup mode %s"), cleanup_arg);
+	cleanup_mode = get_cleanup_mode(cleanup_arg, use_editor);
 
 	handle_untracked_files_arg(s);
 
@@ -1615,11 +1602,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
 		die(_("could not read commit message: %s"), strerror(saved_errno));
 	}
 
-	if (verbose || /* Truncate the message just before the diff, if any. */
-	    cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)
-		strbuf_setlen(&sb, wt_status_locate_end(sb.buf, sb.len));
-	if (cleanup_mode != COMMIT_MSG_CLEANUP_NONE)
-		strbuf_stripspace(&sb, cleanup_mode == COMMIT_MSG_CLEANUP_ALL);
+	cleanup_message(&sb, cleanup_mode, verbose);
 
 	if (message_is_empty(&sb, cleanup_mode) && !allow_empty_message) {
 		rollback_index_files();
diff --git a/sequencer.c b/sequencer.c
index f5370f4965..4f79892801 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -510,6 +510,25 @@ static int fast_forward_to(struct repository *r,
 	return 0;
 }
 
+enum commit_msg_cleanup_mode get_cleanup_mode(const char *cleanup_arg,
+	int use_editor)
+{
+	if (!cleanup_arg || !strcmp(cleanup_arg, "default"))
+		return use_editor ? COMMIT_MSG_CLEANUP_ALL :
+				    COMMIT_MSG_CLEANUP_SPACE;
+	else if (!strcmp(cleanup_arg, "verbatim"))
+		return COMMIT_MSG_CLEANUP_NONE;
+	else if (!strcmp(cleanup_arg, "whitespace"))
+		return COMMIT_MSG_CLEANUP_SPACE;
+	else if (!strcmp(cleanup_arg, "strip"))
+		return COMMIT_MSG_CLEANUP_ALL;
+	else if (!strcmp(cleanup_arg, "scissors"))
+		return use_editor ? COMMIT_MSG_CLEANUP_SCISSORS :
+				    COMMIT_MSG_CLEANUP_SPACE;
+	else
+		die(_("Invalid cleanup mode %s"), cleanup_arg);
+}
+
 void append_conflicts_hint(struct index_state *istate,
 			   struct strbuf *msgbuf)
 {
@@ -1012,6 +1031,16 @@ static int rest_is_empty(const struct strbuf *sb, int start)
 	return 1;
 }
 
+void cleanup_message(struct strbuf *msgbuf,
+	enum commit_msg_cleanup_mode cleanup_mode, int verbose)
+{
+	if (verbose || /* Truncate the message just before the diff, if any. */
+	    cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)
+		strbuf_setlen(msgbuf, wt_status_locate_end(msgbuf->buf, msgbuf->len));
+	if (cleanup_mode != COMMIT_MSG_CLEANUP_NONE)
+		strbuf_stripspace(msgbuf, cleanup_mode == COMMIT_MSG_CLEANUP_ALL);
+}
+
 /*
  * Find out if the message in the strbuf contains only whitespace and
  * Signed-off-by lines.
diff --git a/sequencer.h b/sequencer.h
index 9d83f0f3e9..57ad6fc7de 100644
--- a/sequencer.h
+++ b/sequencer.h
@@ -115,7 +115,11 @@ extern const char sign_off_header[];
  */
 void append_signoff(struct strbuf *msgbuf, size_t ignore_footer, unsigned flag);
 
+enum commit_msg_cleanup_mode get_cleanup_mode(const char *cleanup_arg,
+	int use_editor);
 void append_conflicts_hint(struct index_state *istate, struct strbuf *msgbuf);
+void cleanup_message(struct strbuf *msgbuf,
+	enum commit_msg_cleanup_mode cleanup_mode, int verbose);
 int message_is_empty(const struct strbuf *sb,
 		     enum commit_msg_cleanup_mode cleanup_mode);
 int template_untouched(const struct strbuf *sb, const char *template_file,
-- 
2.20.1.3.ge68552ea27.dirty


^ permalink raw reply	[flat|nested] 105+ messages in thread

* [PATCH v6 2/4] t7600: clean up 'merge --squash c3 with c7' test
  2019-01-23  5:06         ` [PATCH v6 0/4] Add git-merge --cleanup support Denton Liu
  2019-01-23  5:06           ` [PATCH v6 1/4] commit: extract cleanup_mode functions to sequencer Denton Liu
@ 2019-01-23  5:06           ` Denton Liu
  2019-01-23  5:06           ` [PATCH v6 3/4] merge: cleanup messages like commit Denton Liu
                             ` (2 subsequent siblings)
  4 siblings, 0 replies; 105+ messages in thread
From: Denton Liu @ 2019-01-23  5:06 UTC (permalink / raw)
  To: git; +Cc: gitster

This cleans up the original test by removing some unnecessary braces and
removing a pipe.

Helped-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Denton Liu <liu.denton@gmail.com>
---
 t/t7600-merge.sh | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/t/t7600-merge.sh b/t/t7600-merge.sh
index 106148254d..d879efd330 100755
--- a/t/t7600-merge.sh
+++ b/t/t7600-merge.sh
@@ -233,8 +233,7 @@ test_expect_success 'merge --squash c3 with c7' '
 	cat result.9z >file &&
 	git commit --no-edit -a &&
 
-	{
-		cat <<-EOF
+	cat >expect <<-EOF &&
 		Squashed commit of the following:
 
 		$(git show -s c7)
@@ -242,8 +241,8 @@ test_expect_success 'merge --squash c3 with c7' '
 		# Conflicts:
 		#	file
 		EOF
-	} >expect &&
-	git cat-file commit HEAD | sed -e '1,/^$/d' >actual &&
+	git cat-file commit HEAD >tmp &&
+	sed -e '1,/^$/d' <tmp >actual &&
 	test_cmp expect actual
 '
 
-- 
2.20.1.3.ge68552ea27.dirty


^ permalink raw reply	[flat|nested] 105+ messages in thread

* [PATCH v6 3/4] merge: cleanup messages like commit
  2019-01-23  5:06         ` [PATCH v6 0/4] Add git-merge --cleanup support Denton Liu
  2019-01-23  5:06           ` [PATCH v6 1/4] commit: extract cleanup_mode functions to sequencer Denton Liu
  2019-01-23  5:06           ` [PATCH v6 2/4] t7600: clean up 'merge --squash c3 with c7' test Denton Liu
@ 2019-01-23  5:06           ` Denton Liu
  2019-01-23  5:06           ` [PATCH v6 4/4] merge: add scissors line on merge conflict Denton Liu
  2019-03-11  3:42           ` [PATCH v7 0/8] Fix scissors bug during conflict Denton Liu
  4 siblings, 0 replies; 105+ messages in thread
From: Denton Liu @ 2019-01-23  5:06 UTC (permalink / raw)
  To: git; +Cc: gitster

This change allows git-merge messages to be cleaned up with the
commit.cleanup configuration or --cleanup option, just like how
git-commit does it.

We also give git-pull the passthrough option of --cleanup so that it can
also take advantage of this change.

Finally, add testing to ensure that messages are properly cleaned up.
Note that some newlines that were added to the commit message were
removed so that if a file were read via -F, it would be copied
faithfully.

Signed-off-by: Denton Liu <liu.denton@gmail.com>
---
 Documentation/merge-options.txt |  5 +++
 builtin/merge.c                 | 31 +++++++++++++----
 builtin/pull.c                  |  6 ++++
 t/t7604-merge-custom-message.sh | 61 +++++++++++++++++++++++++++++++++
 wt-status.c                     | 12 +++++--
 wt-status.h                     |  1 +
 6 files changed, 106 insertions(+), 10 deletions(-)

diff --git a/Documentation/merge-options.txt b/Documentation/merge-options.txt
index 63a3fc0954..22783651b6 100644
--- a/Documentation/merge-options.txt
+++ b/Documentation/merge-options.txt
@@ -27,6 +27,11 @@ they run `git merge`. To make it easier to adjust such scripts to the
 updated behaviour, the environment variable `GIT_MERGE_AUTOEDIT` can be
 set to `no` at the beginning of them.
 
+--cleanup=<mode>::
+	This option determines how the merge message will be cleaned up
+	before commiting or being passed on. See linkgit:git-commit[1] for more
+	details.
+
 --ff::
 	When the merge resolves as a fast-forward, only update the branch
 	pointer, without creating a merge commit.  This is the default
diff --git a/builtin/merge.c b/builtin/merge.c
index dc0b7cc521..19fb3abb77 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -37,6 +37,7 @@
 #include "tag.h"
 #include "alias.h"
 #include "commit-reach.h"
+#include "wt-status.h"
 
 #define DEFAULT_TWOHEAD (1<<0)
 #define DEFAULT_OCTOPUS (1<<1)
@@ -97,6 +98,9 @@ enum ff_type {
 
 static enum ff_type fast_forward = FF_ALLOW;
 
+static const char *cleanup_arg;
+static enum commit_msg_cleanup_mode cleanup_mode;
+
 static int option_parse_message(const struct option *opt,
 				const char *arg, int unset)
 {
@@ -245,6 +249,7 @@ static struct option builtin_merge_options[] = {
 		N_("perform a commit if the merge succeeds (default)")),
 	OPT_BOOL('e', "edit", &option_edit,
 		N_("edit message before committing")),
+	OPT_STRING(0, "cleanup", &cleanup_arg, N_("default"), N_("how to strip spaces and #comments from message")),
 	OPT_SET_INT(0, "ff", &fast_forward, N_("allow fast-forward (default)"), FF_ALLOW),
 	OPT_SET_INT_F(0, "ff-only", &fast_forward,
 		      N_("abort if fast-forward is not possible"),
@@ -608,6 +613,8 @@ static int git_merge_config(const char *k, const char *v, void *cb)
 		return git_config_string(&pull_twohead, k, v);
 	else if (!strcmp(k, "pull.octopus"))
 		return git_config_string(&pull_octopus, k, v);
+	else if (!strcmp(k, "commit.cleanup"))
+		return git_config_string(&cleanup_arg, k, v);
 	else if (!strcmp(k, "merge.renormalize"))
 		option_renormalize = git_config_bool(k, v);
 	else if (!strcmp(k, "merge.ff")) {
@@ -793,23 +800,32 @@ static void abort_commit(struct commit_list *remoteheads, const char *err_msg)
 	exit(1);
 }
 
+static const char comment_line_explanation[] =
+N_("Lines starting with '%c' will be ignored.\n");
+
 static const char merge_editor_comment[] =
 N_("Please enter a commit message to explain why this merge is necessary,\n"
    "especially if it merges an updated upstream into a topic branch.\n"
    "\n"
-   "Lines starting with '%c' will be ignored, and an empty message aborts\n"
-   "the commit.\n");
+   "An empty message aborts the commit.\n");
 
 static void write_merge_heads(struct commit_list *);
 static void prepare_to_commit(struct commit_list *remoteheads)
 {
 	struct strbuf msg = STRBUF_INIT;
 	strbuf_addbuf(&msg, &merge_msg);
-	strbuf_addch(&msg, '\n');
 	if (squash)
 		BUG("the control must not reach here under --squash");
-	if (0 < option_edit)
-		strbuf_commented_addf(&msg, _(merge_editor_comment), comment_line_char);
+	if (0 < option_edit) {
+		strbuf_addch(&msg, '\n');
+		if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)
+			wt_status_append_cut_line(&msg);
+		else
+			strbuf_commented_addf(&msg, _(comment_line_explanation), comment_line_char);
+
+		strbuf_commented_addf(&msg, "\n");
+		strbuf_commented_addf(&msg, _(merge_editor_comment));
+	}
 	if (signoff)
 		append_signoff(&msg, ignore_non_trailer(msg.buf, msg.len), 0);
 	write_merge_heads(remoteheads);
@@ -828,7 +844,7 @@ static void prepare_to_commit(struct commit_list *remoteheads)
 		abort_commit(remoteheads, NULL);
 
 	read_merge_msg(&msg);
-	strbuf_stripspace(&msg, 0 < option_edit);
+	cleanup_message(&msg, cleanup_mode, 0);
 	if (!msg.len)
 		abort_commit(remoteheads, _("Empty commit message."));
 	strbuf_release(&merge_msg);
@@ -876,7 +892,6 @@ static int finish_automerge(struct commit *head,
 	parents = remoteheads;
 	if (!head_subsumed || fast_forward == FF_NO)
 		commit_list_insert(head, &parents);
-	strbuf_addch(&merge_msg, '\n');
 	prepare_to_commit(remoteheads);
 	if (commit_tree(merge_msg.buf, merge_msg.len, result_tree, parents,
 			&result_commit, NULL, sign_commit))
@@ -1385,6 +1400,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
 	if (option_edit < 0)
 		option_edit = default_edit_option();
 
+	cleanup_mode = get_cleanup_mode(cleanup_arg, 0 < option_edit);
+
 	if (!use_strategies) {
 		if (!remoteheads)
 			; /* already up-to-date */
diff --git a/builtin/pull.c b/builtin/pull.c
index 74808b9455..0cb458137b 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -96,6 +96,7 @@ static char *opt_signoff;
 static char *opt_squash;
 static char *opt_commit;
 static char *opt_edit;
+static char *opt_cleanup;
 static char *opt_ff;
 static char *opt_verify_signatures;
 static int opt_autostash = -1;
@@ -163,6 +164,9 @@ static struct option pull_options[] = {
 	OPT_PASSTHRU(0, "edit", &opt_edit, NULL,
 		N_("edit message before committing"),
 		PARSE_OPT_NOARG),
+	OPT_PASSTHRU(0, "cleanup", &opt_cleanup, NULL,
+		N_("how to strip spaces and #comments from message"),
+		PARSE_OPT_NOARG),
 	OPT_PASSTHRU(0, "ff", &opt_ff, NULL,
 		N_("allow fast-forward"),
 		PARSE_OPT_NOARG),
@@ -639,6 +643,8 @@ static int run_merge(void)
 		argv_array_push(&args, opt_commit);
 	if (opt_edit)
 		argv_array_push(&args, opt_edit);
+	if (opt_cleanup)
+		argv_array_push(&args, opt_cleanup);
 	if (opt_ff)
 		argv_array_push(&args, opt_ff);
 	if (opt_verify_signatures)
diff --git a/t/t7604-merge-custom-message.sh b/t/t7604-merge-custom-message.sh
index 89619cf446..3fcd58eb2c 100755
--- a/t/t7604-merge-custom-message.sh
+++ b/t/t7604-merge-custom-message.sh
@@ -47,4 +47,65 @@ test_expect_success 'merge --log appends to custom message' '
 	test_cmp exp.log actual
 '
 
+mesg_with_comment_and_newlines='
+# text
+
+'
+
+test_expect_success 'prepare file with comment line and trailing newlines'  '
+	printf "%s" "$mesg_with_comment_and_newlines" >expect
+'
+
+test_expect_success 'cleanup commit messages (verbatim option)' '
+	git reset --hard c1 &&
+	git merge --cleanup=verbatim -F expect c2 &&
+	git cat-file -p HEAD |sed -e "1,/^\$/d" >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'cleanup commit messages (whitespace option)' '
+	git reset --hard c1 &&
+	{ echo;echo "# text";echo; } >text &&
+	echo "# text" >expect &&
+	git merge --cleanup=whitespace -F text c2 &&
+	git cat-file -p HEAD |sed -e "1,/^\$/d">actual &&
+	test_cmp expect actual
+
+'
+
+test_expect_success 'cleanup merge messages (scissors option)' '
+	git reset --hard c1 &&
+	cat >text <<EOF &&
+
+# to be kept
+
+  # ------------------------ >8 ------------------------
+# to be kept, too
+# ------------------------ >8 ------------------------
+to be removed
+# ------------------------ >8 ------------------------
+to be removed, too
+EOF
+
+	cat >expect <<EOF &&
+# to be kept
+
+  # ------------------------ >8 ------------------------
+# to be kept, too
+EOF
+	git merge --cleanup=scissors -e -F text c2 &&
+	git cat-file -p HEAD |sed -e "1,/^\$/d">actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'cleanup commit messages (strip option)' '
+	git reset --hard c1 &&
+	{ echo;echo "# text";echo sample;echo; } >text &&
+	echo sample >expect &&
+	git merge --cleanup=strip -F text c2 &&
+	git cat-file -p HEAD |sed -e "1,/^\$/d">actual &&
+	test_cmp expect actual
+
+'
+
 test_done
diff --git a/wt-status.c b/wt-status.c
index 0fe3bcd4cd..2768205d78 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -995,13 +995,19 @@ size_t wt_status_locate_end(const char *s, size_t len)
 	return len;
 }
 
-void wt_status_add_cut_line(FILE *fp)
+void wt_status_append_cut_line(struct strbuf *buf)
 {
 	const char *explanation = _("Do not modify or remove the line above.\nEverything below it will be ignored.");
+
+	strbuf_commented_addf(buf, "%s", cut_line);
+	strbuf_add_commented_lines(buf, explanation, strlen(explanation));
+}
+
+void wt_status_add_cut_line(FILE *fp)
+{
 	struct strbuf buf = STRBUF_INIT;
 
-	fprintf(fp, "%c %s", comment_line_char, cut_line);
-	strbuf_add_commented_lines(&buf, explanation, strlen(explanation));
+	wt_status_append_cut_line(&buf);
 	fputs(buf.buf, fp);
 	strbuf_release(&buf);
 }
diff --git a/wt-status.h b/wt-status.h
index 3a95975032..64f1ddc9fd 100644
--- a/wt-status.h
+++ b/wt-status.h
@@ -129,6 +129,7 @@ struct wt_status {
 };
 
 size_t wt_status_locate_end(const char *s, size_t len);
+void wt_status_append_cut_line(struct strbuf *buf);
 void wt_status_add_cut_line(FILE *fp);
 void wt_status_prepare(struct repository *r, struct wt_status *s);
 void wt_status_print(struct wt_status *s);
-- 
2.20.1.3.ge68552ea27.dirty


^ permalink raw reply	[flat|nested] 105+ messages in thread

* [PATCH v6 4/4] merge: add scissors line on merge conflict
  2019-01-23  5:06         ` [PATCH v6 0/4] Add git-merge --cleanup support Denton Liu
                             ` (2 preceding siblings ...)
  2019-01-23  5:06           ` [PATCH v6 3/4] merge: cleanup messages like commit Denton Liu
@ 2019-01-23  5:06           ` Denton Liu
  2019-03-11  3:42           ` [PATCH v7 0/8] Fix scissors bug during conflict Denton Liu
  4 siblings, 0 replies; 105+ messages in thread
From: Denton Liu @ 2019-01-23  5:06 UTC (permalink / raw)
  To: git; +Cc: gitster

This fixes a bug where the scissors line is placed after the Conflicts:
section, in the case where a merge conflict occurs and
commit.cleanup = scissors.

Next, if commit.cleanup = scissors is specified, don't produce a
scissors line in commit if one already exists in the MERGE_MSG file.

Signed-off-by: Denton Liu <liu.denton@gmail.com>
---
 Documentation/merge-options.txt |  4 ++-
 builtin/commit.c                | 20 ++++++++++----
 builtin/merge.c                 | 14 ++++++++++
 t/t7600-merge.sh                | 46 +++++++++++++++++++++++++++++++++
 4 files changed, 78 insertions(+), 6 deletions(-)

diff --git a/Documentation/merge-options.txt b/Documentation/merge-options.txt
index 22783651b6..c2a263ba74 100644
--- a/Documentation/merge-options.txt
+++ b/Documentation/merge-options.txt
@@ -30,7 +30,9 @@ set to `no` at the beginning of them.
 --cleanup=<mode>::
 	This option determines how the merge message will be cleaned up
 	before commiting or being passed on. See linkgit:git-commit[1] for more
-	details.
+	details. In addition, if the '<mode>' is given a value of `scissors`,
+	scissors will be prepended to MERGE_MSG before being passed on in the case
+	of a merge conflict.
 
 --ff::
 	When the merge resolves as a fast-forward, only update the branch
diff --git a/builtin/commit.c b/builtin/commit.c
index 3ac0a21a22..eb549b57a3 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -665,6 +665,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
 	const char *hook_arg2 = NULL;
 	int clean_message_contents = (cleanup_mode != COMMIT_MSG_CLEANUP_NONE);
 	int old_display_comment_prefix;
+	int merge_contains_scissors = 0;
 
 	/* This checks and barfs if author is badly specified */
 	determine_author_info(author_ident);
@@ -725,6 +726,8 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
 			strbuf_addbuf(&sb, &message);
 		hook_arg1 = "message";
 	} else if (!stat(git_path_merge_msg(the_repository), &statbuf)) {
+		size_t merge_msg_start;
+
 		/*
 		 * prepend SQUASH_MSG here if it exists and a
 		 * "merge --squash" was originally performed
@@ -735,8 +738,14 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
 			hook_arg1 = "squash";
 		} else
 			hook_arg1 = "merge";
+
+		merge_msg_start = sb.len;
 		if (strbuf_read_file(&sb, git_path_merge_msg(the_repository), 0) < 0)
 			die_errno(_("could not read MERGE_MSG"));
+
+		if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS &&
+		    wt_status_locate_end(sb.buf + merge_msg_start, sb.len - merge_msg_start) < sb.len - merge_msg_start)
+			merge_contains_scissors = 1;
 	} else if (!stat(git_path_squash_msg(the_repository), &statbuf)) {
 		if (strbuf_read_file(&sb, git_path_squash_msg(the_repository), 0) < 0)
 			die_errno(_("could not read SQUASH_MSG"));
@@ -804,7 +813,8 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
 		struct ident_split ci, ai;
 
 		if (whence != FROM_COMMIT) {
-			if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)
+			if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS &&
+				!merge_contains_scissors)
 				wt_status_add_cut_line(s->fp);
 			status_printf_ln(s, GIT_COLOR_NORMAL,
 			    whence == FROM_MERGE
@@ -829,10 +839,10 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
 				_("Please enter the commit message for your changes."
 				  " Lines starting\nwith '%c' will be ignored, and an empty"
 				  " message aborts the commit.\n"), comment_line_char);
-		else if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS &&
-			 whence == FROM_COMMIT)
-			wt_status_add_cut_line(s->fp);
-		else /* COMMIT_MSG_CLEANUP_SPACE, that is. */
+		else if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS) {
+			if (whence == FROM_COMMIT && !merge_contains_scissors)
+				wt_status_add_cut_line(s->fp);
+		} else /* COMMIT_MSG_CLEANUP_SPACE, that is. */
 			status_printf(s, GIT_COLOR_NORMAL,
 				_("Please enter the commit message for your changes."
 				  " Lines starting\n"
diff --git a/builtin/merge.c b/builtin/merge.c
index 19fb3abb77..fbf4a24850 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -912,6 +912,20 @@ static int suggest_conflicts(void)
 	filename = git_path_merge_msg(the_repository);
 	fp = xfopen(filename, "a");
 
+	/*
+	 * We can't use cleanup_mode because if we're not using the editor,
+	 * get_cleanup_mode will return COMMIT_MSG_CLEANUP_SPACE instead, even
+	 * though the message is meant to be processed later by git-commit.
+	 * Thus, we will get the cleanup mode is returned we _are_ using an
+	 * editor.
+	 */
+	if (get_cleanup_mode(cleanup_arg, 1) == COMMIT_MSG_CLEANUP_SCISSORS) {
+	    fputc('\n', fp);
+	    wt_status_add_cut_line(fp);
+	    /* comments out the newline from append_conflicts_hint */
+	    fputc(comment_line_char, fp);
+	}
+
 	append_conflicts_hint(&the_index, &msgbuf);
 	fputs(msgbuf.buf, fp);
 	strbuf_release(&msgbuf);
diff --git a/t/t7600-merge.sh b/t/t7600-merge.sh
index d879efd330..2cb57e5878 100755
--- a/t/t7600-merge.sh
+++ b/t/t7600-merge.sh
@@ -246,6 +246,52 @@ test_expect_success 'merge --squash c3 with c7' '
 	test_cmp expect actual
 '
 
+test_expect_success 'merge c3 with c7 with commit.cleanup = scissors' '
+	git config commit.cleanup scissors &&
+	git reset --hard c3 &&
+	test_must_fail git merge c7 &&
+	cat result.9z >file &&
+	git commit --no-edit -a &&
+
+	cat >expect <<-EOF &&
+		Merge tag '"'"'c7'"'"'
+
+		# ------------------------ >8 ------------------------
+		# Do not modify or remove the line above.
+		# Everything below it will be ignored.
+		#
+		# Conflicts:
+		#	file
+		EOF
+	git cat-file commit HEAD >tmp &&
+	sed -e '1,/^$/d' <tmp >actual &&
+	test_i18ncmp expect actual
+'
+
+test_expect_success 'merge c3 with c7 with --squash commit.cleanup = scissors' '
+	git config commit.cleanup scissors &&
+	git reset --hard c3 &&
+	test_must_fail git merge --squash c7 &&
+	cat result.9z >file &&
+	git commit --no-edit -a &&
+
+	cat >expect <<-EOF &&
+		Squashed commit of the following:
+
+		$(git show -s c7)
+
+		# ------------------------ >8 ------------------------
+		# Do not modify or remove the line above.
+		# Everything below it will be ignored.
+		#
+		# Conflicts:
+		#	file
+		EOF
+	git cat-file commit HEAD >tmp &&
+	sed -e '1,/^$/d' <tmp >actual &&
+	test_i18ncmp expect actual
+'
+
 test_debug 'git log --graph --decorate --oneline --all'
 
 test_expect_success 'merge c1 with c2 and c3' '
-- 
2.20.1.3.ge68552ea27.dirty


^ permalink raw reply	[flat|nested] 105+ messages in thread

* [PATCH v7 0/8] Fix scissors bug during conflict
  2019-01-23  5:06         ` [PATCH v6 0/4] Add git-merge --cleanup support Denton Liu
                             ` (3 preceding siblings ...)
  2019-01-23  5:06           ` [PATCH v6 4/4] merge: add scissors line on merge conflict Denton Liu
@ 2019-03-11  3:42           ` Denton Liu
  2019-03-11  3:42             ` [PATCH v7 1/8] t7600: clean up 'merge --squash c3 with c7' test Denton Liu
                               ` (9 more replies)
  4 siblings, 10 replies; 105+ messages in thread
From: Denton Liu @ 2019-03-11  3:42 UTC (permalink / raw)
  To: Git Mailing List; +Cc: Phillip Wood, Junio C Hamano

This is a complete replacement for dl/merge-cleanup-scissors-fix.

Previous discussion on the cherry-pick/revert changes can be found here[1].

Changes since revert/cherry-pick v3:

* Rebased on top of latest master
* Reordered and squashed patches
* Added populate_opts_cb and save_opts to save default_msg_cleanup at Phillip's suggestion

[1]: https://public-inbox.org/git/cover.1551867827.git.liu.denton@gmail.com/T/#u


Denton Liu (8):
  t7600: clean up 'merge --squash c3 with c7' test
  t3507: cleanup space after redirection operators
  commit: extract cleanup_mode functions to sequencer
  sequencer.c: remove duplicate code
  merge: cleanup messages like commit
  merge: add scissors line on merge conflict
  sequencer.c: define get_config_from_cleanup
  cherry-pick/revert: add scissors line on merge conflict

 Documentation/git-cherry-pick.txt |   7 ++
 Documentation/git-revert.txt      |   7 ++
 Documentation/merge-options.txt   |   7 ++
 builtin/commit.c                  |  45 +++++------
 builtin/merge.c                   |  40 ++++++++--
 builtin/pull.c                    |   6 ++
 builtin/rebase--interactive.c     |   2 +-
 builtin/revert.c                  |   5 ++
 sequencer.c                       | 102 ++++++++++++++++++++-----
 sequencer.h                       |  10 ++-
 t/t3507-cherry-pick-conflict.sh   | 120 +++++++++++++++++++++++++-----
 t/t7600-merge.sh                  |  53 ++++++++++++-
 t/t7604-merge-custom-message.sh   |  61 +++++++++++++++
 wt-status.c                       |  12 ++-
 wt-status.h                       |   1 +
 15 files changed, 398 insertions(+), 80 deletions(-)


base-commit: 6e0cc6776106079ed4efa0cc9abace4107657abf
-- 
2.21.0.370.g4fdb13b891


^ permalink raw reply	[flat|nested] 105+ messages in thread

* [PATCH v7 1/8] t7600: clean up 'merge --squash c3 with c7' test
  2019-03-11  3:42           ` [PATCH v7 0/8] Fix scissors bug during conflict Denton Liu
@ 2019-03-11  3:42             ` Denton Liu
  2019-03-12  1:03               ` Junio C Hamano
  2019-03-11  3:42             ` [PATCH v7 2/8] t3507: cleanup space after redirection operators Denton Liu
                               ` (8 subsequent siblings)
  9 siblings, 1 reply; 105+ messages in thread
From: Denton Liu @ 2019-03-11  3:42 UTC (permalink / raw)
  To: Git Mailing List; +Cc: Phillip Wood, Junio C Hamano

This cleans up the original test by removing some unnecessary braces and
removing a pipe.

Helped-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Denton Liu <liu.denton@gmail.com>
---
 t/t7600-merge.sh | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/t/t7600-merge.sh b/t/t7600-merge.sh
index 106148254d..d879efd330 100755
--- a/t/t7600-merge.sh
+++ b/t/t7600-merge.sh
@@ -233,8 +233,7 @@ test_expect_success 'merge --squash c3 with c7' '
 	cat result.9z >file &&
 	git commit --no-edit -a &&
 
-	{
-		cat <<-EOF
+	cat >expect <<-EOF &&
 		Squashed commit of the following:
 
 		$(git show -s c7)
@@ -242,8 +241,8 @@ test_expect_success 'merge --squash c3 with c7' '
 		# Conflicts:
 		#	file
 		EOF
-	} >expect &&
-	git cat-file commit HEAD | sed -e '1,/^$/d' >actual &&
+	git cat-file commit HEAD >tmp &&
+	sed -e '1,/^$/d' <tmp >actual &&
 	test_cmp expect actual
 '
 
-- 
2.21.0.370.g4fdb13b891


^ permalink raw reply	[flat|nested] 105+ messages in thread

* [PATCH v7 2/8] t3507: cleanup space after redirection operators
  2019-03-11  3:42           ` [PATCH v7 0/8] Fix scissors bug during conflict Denton Liu
  2019-03-11  3:42             ` [PATCH v7 1/8] t7600: clean up 'merge --squash c3 with c7' test Denton Liu
@ 2019-03-11  3:42             ` Denton Liu
  2019-03-11  3:42             ` [PATCH v7 3/8] commit: extract cleanup_mode functions to sequencer Denton Liu
                               ` (7 subsequent siblings)
  9 siblings, 0 replies; 105+ messages in thread
From: Denton Liu @ 2019-03-11  3:42 UTC (permalink / raw)
  To: Git Mailing List; +Cc: Phillip Wood, Junio C Hamano

Signed-off-by: Denton Liu <liu.denton@gmail.com>
---
 t/t3507-cherry-pick-conflict.sh | 34 ++++++++++++++++-----------------
 1 file changed, 17 insertions(+), 17 deletions(-)

diff --git a/t/t3507-cherry-pick-conflict.sh b/t/t3507-cherry-pick-conflict.sh
index 0db166152a..74ff925526 100755
--- a/t/t3507-cherry-pick-conflict.sh
+++ b/t/t3507-cherry-pick-conflict.sh
@@ -88,7 +88,7 @@ test_expect_success 'cherry-pick --no-commit does not set CHERRY_PICK_HEAD' '
 
 test_expect_success 'cherry-pick w/dirty tree does not set CHERRY_PICK_HEAD' '
 	pristine_detach initial &&
-	echo foo > foo &&
+	echo foo >foo &&
 	test_must_fail git cherry-pick base &&
 	test_must_fail git rev-parse --verify CHERRY_PICK_HEAD
 '
@@ -96,7 +96,7 @@ test_expect_success 'cherry-pick w/dirty tree does not set CHERRY_PICK_HEAD' '
 test_expect_success \
 	'cherry-pick --strategy=resolve w/dirty tree does not set CHERRY_PICK_HEAD' '
 	pristine_detach initial &&
-	echo foo > foo &&
+	echo foo >foo &&
 	test_must_fail git cherry-pick --strategy=resolve base &&
 	test_must_fail git rev-parse --verify CHERRY_PICK_HEAD
 '
@@ -175,23 +175,23 @@ test_expect_success 'failed cherry-pick registers participants in index' '
 		git ls-files --stage foo &&
 		git checkout picked -- foo &&
 		git ls-files --stage foo
-	} > stages &&
+	} >stages &&
 	sed "
 		1 s/ 0	/ 1	/
 		2 s/ 0	/ 2	/
 		3 s/ 0	/ 3	/
-	" < stages > expected &&
+	" <stages >expected &&
 	git read-tree -u --reset HEAD &&
 
 	test_must_fail git cherry-pick picked &&
-	git ls-files --stage --unmerged > actual &&
+	git ls-files --stage --unmerged >actual &&
 
 	test_cmp expected actual
 '
 
 test_expect_success 'failed cherry-pick describes conflict in work tree' '
 	pristine_detach initial &&
-	cat <<-EOF > expected &&
+	cat <<-EOF >expected &&
 	<<<<<<< HEAD
 	a
 	=======
@@ -201,14 +201,14 @@ test_expect_success 'failed cherry-pick describes conflict in work tree' '
 
 	test_must_fail git cherry-pick picked &&
 
-	sed "s/[a-f0-9]*\.\.\./objid/" foo > actual &&
+	sed "s/[a-f0-9]*\.\.\./objid/" foo >actual &&
 	test_cmp expected actual
 '
 
 test_expect_success 'diff3 -m style' '
 	pristine_detach initial &&
 	git config merge.conflictstyle diff3 &&
-	cat <<-EOF > expected &&
+	cat <<-EOF >expected &&
 	<<<<<<< HEAD
 	a
 	||||||| parent of objid picked
@@ -220,14 +220,14 @@ test_expect_success 'diff3 -m style' '
 
 	test_must_fail git cherry-pick picked &&
 
-	sed "s/[a-f0-9]*\.\.\./objid/" foo > actual &&
+	sed "s/[a-f0-9]*\.\.\./objid/" foo >actual &&
 	test_cmp expected actual
 '
 
 test_expect_success 'revert also handles conflicts sanely' '
 	git config --unset merge.conflictstyle &&
 	pristine_detach initial &&
-	cat <<-EOF > expected &&
+	cat <<-EOF >expected &&
 	<<<<<<< HEAD
 	a
 	=======
@@ -241,24 +241,24 @@ test_expect_success 'revert also handles conflicts sanely' '
 		git ls-files --stage foo &&
 		git checkout base -- foo &&
 		git ls-files --stage foo
-	} > stages &&
+	} >stages &&
 	sed "
 		1 s/ 0	/ 1	/
 		2 s/ 0	/ 2	/
 		3 s/ 0	/ 3	/
-	" < stages > expected-stages &&
+	" <stages >expected-stages &&
 	git read-tree -u --reset HEAD &&
 
 	head=$(git rev-parse HEAD) &&
 	test_must_fail git revert picked &&
 	newhead=$(git rev-parse HEAD) &&
-	git ls-files --stage --unmerged > actual-stages &&
+	git ls-files --stage --unmerged >actual-stages &&
 
 	test "$head" = "$newhead" &&
 	test_must_fail git update-index --refresh -q &&
 	test_must_fail git diff-index --exit-code HEAD &&
 	test_cmp expected-stages actual-stages &&
-	sed "s/[a-f0-9]*\.\.\./objid/" foo > actual &&
+	sed "s/[a-f0-9]*\.\.\./objid/" foo >actual &&
 	test_cmp expected actual
 '
 
@@ -284,7 +284,7 @@ test_expect_success 'revert --no-commit sets REVERT_HEAD' '
 
 test_expect_success 'revert w/dirty tree does not set REVERT_HEAD' '
 	pristine_detach base &&
-	echo foo > foo &&
+	echo foo >foo &&
 	test_must_fail git revert base &&
 	test_must_fail git rev-parse --verify CHERRY_PICK_HEAD &&
 	test_must_fail git rev-parse --verify REVERT_HEAD
@@ -319,7 +319,7 @@ test_expect_success 'failed commit does not clear REVERT_HEAD' '
 test_expect_success 'revert conflict, diff3 -m style' '
 	pristine_detach initial &&
 	git config merge.conflictstyle diff3 &&
-	cat <<-EOF > expected &&
+	cat <<-EOF >expected &&
 	<<<<<<< HEAD
 	a
 	||||||| objid picked
@@ -331,7 +331,7 @@ test_expect_success 'revert conflict, diff3 -m style' '
 
 	test_must_fail git revert picked &&
 
-	sed "s/[a-f0-9]*\.\.\./objid/" foo > actual &&
+	sed "s/[a-f0-9]*\.\.\./objid/" foo >actual &&
 	test_cmp expected actual
 '
 
-- 
2.21.0.370.g4fdb13b891


^ permalink raw reply	[flat|nested] 105+ messages in thread

* [PATCH v7 3/8] commit: extract cleanup_mode functions to sequencer
  2019-03-11  3:42           ` [PATCH v7 0/8] Fix scissors bug during conflict Denton Liu
  2019-03-11  3:42             ` [PATCH v7 1/8] t7600: clean up 'merge --squash c3 with c7' test Denton Liu
  2019-03-11  3:42             ` [PATCH v7 2/8] t3507: cleanup space after redirection operators Denton Liu
@ 2019-03-11  3:42             ` Denton Liu
  2019-03-11  3:42             ` [PATCH v7 4/8] sequencer.c: remove duplicate code Denton Liu
                               ` (6 subsequent siblings)
  9 siblings, 0 replies; 105+ messages in thread
From: Denton Liu @ 2019-03-11  3:42 UTC (permalink / raw)
  To: Git Mailing List; +Cc: Phillip Wood, Junio C Hamano

Signed-off-by: Denton Liu <liu.denton@gmail.com>
---
 builtin/commit.c | 25 ++-----------------------
 sequencer.c      | 29 +++++++++++++++++++++++++++++
 sequencer.h      |  6 ++++++
 3 files changed, 37 insertions(+), 23 deletions(-)

diff --git a/builtin/commit.c b/builtin/commit.c
index f17537474a..0df15e4851 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -1172,24 +1172,7 @@ static int parse_and_validate_options(int argc, const char *argv[],
 		die(_("Only one of --include/--only/--all/--interactive/--patch can be used."));
 	if (argc == 0 && (also || (only && !amend && !allow_empty)))
 		die(_("No paths with --include/--only does not make sense."));
-	if (!cleanup_arg || !strcmp(cleanup_arg, "default"))
-		cleanup_mode = use_editor ? COMMIT_MSG_CLEANUP_ALL :
-					    COMMIT_MSG_CLEANUP_SPACE;
-	else if (!strcmp(cleanup_arg, "verbatim"))
-		cleanup_mode = COMMIT_MSG_CLEANUP_NONE;
-	else if (!strcmp(cleanup_arg, "whitespace"))
-		cleanup_mode = COMMIT_MSG_CLEANUP_SPACE;
-	else if (!strcmp(cleanup_arg, "strip"))
-		cleanup_mode = COMMIT_MSG_CLEANUP_ALL;
-	else if (!strcmp(cleanup_arg, "scissors"))
-		cleanup_mode = use_editor ? COMMIT_MSG_CLEANUP_SCISSORS :
-					    COMMIT_MSG_CLEANUP_SPACE;
-	/*
-	 * Please update _git_commit() in git-completion.bash when you
-	 * add new options.
-	 */
-	else
-		die(_("Invalid cleanup mode %s"), cleanup_arg);
+	cleanup_mode = get_cleanup_mode(cleanup_arg, use_editor);
 
 	handle_untracked_files_arg(s);
 
@@ -1626,11 +1609,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
 		die(_("could not read commit message: %s"), strerror(saved_errno));
 	}
 
-	if (verbose || /* Truncate the message just before the diff, if any. */
-	    cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)
-		strbuf_setlen(&sb, wt_status_locate_end(sb.buf, sb.len));
-	if (cleanup_mode != COMMIT_MSG_CLEANUP_NONE)
-		strbuf_stripspace(&sb, cleanup_mode == COMMIT_MSG_CLEANUP_ALL);
+	cleanup_message(&sb, cleanup_mode, verbose);
 
 	if (message_is_empty(&sb, cleanup_mode) && !allow_empty_message) {
 		rollback_index_files();
diff --git a/sequencer.c b/sequencer.c
index 95dda23eee..224c823b43 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -511,6 +511,25 @@ static int fast_forward_to(struct repository *r,
 	return 0;
 }
 
+enum commit_msg_cleanup_mode get_cleanup_mode(const char *cleanup_arg,
+	int use_editor)
+{
+	if (!cleanup_arg || !strcmp(cleanup_arg, "default"))
+		return use_editor ? COMMIT_MSG_CLEANUP_ALL :
+				    COMMIT_MSG_CLEANUP_SPACE;
+	else if (!strcmp(cleanup_arg, "verbatim"))
+		return COMMIT_MSG_CLEANUP_NONE;
+	else if (!strcmp(cleanup_arg, "whitespace"))
+		return COMMIT_MSG_CLEANUP_SPACE;
+	else if (!strcmp(cleanup_arg, "strip"))
+		return COMMIT_MSG_CLEANUP_ALL;
+	else if (!strcmp(cleanup_arg, "scissors"))
+		return use_editor ? COMMIT_MSG_CLEANUP_SCISSORS :
+				    COMMIT_MSG_CLEANUP_SPACE;
+	else
+		die(_("Invalid cleanup mode %s"), cleanup_arg);
+}
+
 void append_conflicts_hint(struct index_state *istate,
 			   struct strbuf *msgbuf)
 {
@@ -1013,6 +1032,16 @@ static int rest_is_empty(const struct strbuf *sb, int start)
 	return 1;
 }
 
+void cleanup_message(struct strbuf *msgbuf,
+	enum commit_msg_cleanup_mode cleanup_mode, int verbose)
+{
+	if (verbose || /* Truncate the message just before the diff, if any. */
+	    cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)
+		strbuf_setlen(msgbuf, wt_status_locate_end(msgbuf->buf, msgbuf->len));
+	if (cleanup_mode != COMMIT_MSG_CLEANUP_NONE)
+		strbuf_stripspace(msgbuf, cleanup_mode == COMMIT_MSG_CLEANUP_ALL);
+}
+
 /*
  * Find out if the message in the strbuf contains only whitespace and
  * Signed-off-by lines.
diff --git a/sequencer.h b/sequencer.h
index 4d505b3590..eb9bd97ef3 100644
--- a/sequencer.h
+++ b/sequencer.h
@@ -116,6 +116,12 @@ int rearrange_squash(struct repository *r);
 void append_signoff(struct strbuf *msgbuf, size_t ignore_footer, unsigned flag);
 
 void append_conflicts_hint(struct index_state *istate, struct strbuf *msgbuf);
+enum commit_msg_cleanup_mode get_cleanup_mode(const char *cleanup_arg,
+	int use_editor);
+
+void cleanup_message(struct strbuf *msgbuf,
+	enum commit_msg_cleanup_mode cleanup_mode, int verbose);
+
 int message_is_empty(const struct strbuf *sb,
 		     enum commit_msg_cleanup_mode cleanup_mode);
 int template_untouched(const struct strbuf *sb, const char *template_file,
-- 
2.21.0.370.g4fdb13b891


^ permalink raw reply	[flat|nested] 105+ messages in thread

* [PATCH v7 4/8] sequencer.c: remove duplicate code
  2019-03-11  3:42           ` [PATCH v7 0/8] Fix scissors bug during conflict Denton Liu
                               ` (2 preceding siblings ...)
  2019-03-11  3:42             ` [PATCH v7 3/8] commit: extract cleanup_mode functions to sequencer Denton Liu
@ 2019-03-11  3:42             ` Denton Liu
  2019-03-11 16:45               ` Phillip Wood
  2019-03-11  3:42             ` [PATCH v7 5/8] merge: cleanup messages like commit Denton Liu
                               ` (5 subsequent siblings)
  9 siblings, 1 reply; 105+ messages in thread
From: Denton Liu @ 2019-03-11  3:42 UTC (permalink / raw)
  To: Git Mailing List; +Cc: Phillip Wood, Junio C Hamano

Since we implemented get_cleanup_mode, we had some duplicate code in
git_sequencer_config which essentially performed the same operations.
Refactor git_sequencer_config to take advantage of the logic already in
get_cleanup_mode.

Note that we had to introduce a separate argument to get_cleanup_mode
indicating whether to die or not on an invalid value. This is because if
we are parsing a config, we do not want to die but instead, we only want
to warn the user, whereas if we are parsing a command-line option, we
would like to actually die.

Finally, this is almost a no-op refactor but not quite. Previously, in
the case that an invalid value is presented, default_msg_cleanup would
not be set. We change the behaviour so that default_msg_cleanup will now
take on the value as if "default" were provided as the cleanup_arg.

Signed-off-by: Denton Liu <liu.denton@gmail.com>
---
 builtin/commit.c |  2 +-
 sequencer.c      | 20 +++++++-------------
 sequencer.h      |  2 +-
 3 files changed, 9 insertions(+), 15 deletions(-)

diff --git a/builtin/commit.c b/builtin/commit.c
index 0df15e4851..81e3bd21ca 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -1172,7 +1172,7 @@ static int parse_and_validate_options(int argc, const char *argv[],
 		die(_("Only one of --include/--only/--all/--interactive/--patch can be used."));
 	if (argc == 0 && (also || (only && !amend && !allow_empty)))
 		die(_("No paths with --include/--only does not make sense."));
-	cleanup_mode = get_cleanup_mode(cleanup_arg, use_editor);
+	cleanup_mode = get_cleanup_mode(cleanup_arg, use_editor, 1);
 
 	handle_untracked_files_arg(s);
 
diff --git a/sequencer.c b/sequencer.c
index 224c823b43..612621f221 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -172,17 +172,7 @@ static int git_sequencer_config(const char *k, const char *v, void *cb)
 		if (status)
 			return status;
 
-		if (!strcmp(s, "verbatim"))
-			opts->default_msg_cleanup = COMMIT_MSG_CLEANUP_NONE;
-		else if (!strcmp(s, "whitespace"))
-			opts->default_msg_cleanup = COMMIT_MSG_CLEANUP_SPACE;
-		else if (!strcmp(s, "strip"))
-			opts->default_msg_cleanup = COMMIT_MSG_CLEANUP_ALL;
-		else if (!strcmp(s, "scissors"))
-			opts->default_msg_cleanup = COMMIT_MSG_CLEANUP_SPACE;
-		else
-			warning(_("invalid commit message cleanup mode '%s'"),
-				  s);
+		opts->default_msg_cleanup = get_cleanup_mode(s, 0, 0);
 
 		free((char *)s);
 		return status;
@@ -512,7 +502,7 @@ static int fast_forward_to(struct repository *r,
 }
 
 enum commit_msg_cleanup_mode get_cleanup_mode(const char *cleanup_arg,
-	int use_editor)
+	int use_editor, int die_on_error)
 {
 	if (!cleanup_arg || !strcmp(cleanup_arg, "default"))
 		return use_editor ? COMMIT_MSG_CLEANUP_ALL :
@@ -526,7 +516,11 @@ enum commit_msg_cleanup_mode get_cleanup_mode(const char *cleanup_arg,
 	else if (!strcmp(cleanup_arg, "scissors"))
 		return use_editor ? COMMIT_MSG_CLEANUP_SCISSORS :
 				    COMMIT_MSG_CLEANUP_SPACE;
-	else
+	else if (!die_on_error) {
+		warning(_("Invalid cleanup mode %s, falling back to default"), cleanup_arg);
+		return use_editor ? COMMIT_MSG_CLEANUP_ALL :
+				    COMMIT_MSG_CLEANUP_SPACE;
+	} else
 		die(_("Invalid cleanup mode %s"), cleanup_arg);
 }
 
diff --git a/sequencer.h b/sequencer.h
index eb9bd97ef3..e7908f558e 100644
--- a/sequencer.h
+++ b/sequencer.h
@@ -117,7 +117,7 @@ void append_signoff(struct strbuf *msgbuf, size_t ignore_footer, unsigned flag);
 
 void append_conflicts_hint(struct index_state *istate, struct strbuf *msgbuf);
 enum commit_msg_cleanup_mode get_cleanup_mode(const char *cleanup_arg,
-	int use_editor);
+	int use_editor, int die_on_error);
 
 void cleanup_message(struct strbuf *msgbuf,
 	enum commit_msg_cleanup_mode cleanup_mode, int verbose);
-- 
2.21.0.370.g4fdb13b891


^ permalink raw reply	[flat|nested] 105+ messages in thread

* [PATCH v7 5/8] merge: cleanup messages like commit
  2019-03-11  3:42           ` [PATCH v7 0/8] Fix scissors bug during conflict Denton Liu
                               ` (3 preceding siblings ...)
  2019-03-11  3:42             ` [PATCH v7 4/8] sequencer.c: remove duplicate code Denton Liu
@ 2019-03-11  3:42             ` Denton Liu
  2019-03-11  5:49               ` Eric Sunshine
  2019-03-11 16:58               ` Phillip Wood
  2019-03-11  3:42             ` [PATCH v7 6/8] merge: add scissors line on merge conflict Denton Liu
                               ` (4 subsequent siblings)
  9 siblings, 2 replies; 105+ messages in thread
From: Denton Liu @ 2019-03-11  3:42 UTC (permalink / raw)
  To: Git Mailing List; +Cc: Phillip Wood, Junio C Hamano

This change allows git-merge messages to be cleaned up with the
commit.cleanup configuration or --cleanup option, just like how
git-commit does it.

We also give git-pull the passthrough option of --cleanup so that it can
also take advantage of this change.

Finally, add testing to ensure that messages are properly cleaned up.
Note that some newlines that were added to the commit message were
removed so that if a file were read via -F, it would be copied
faithfully.

Signed-off-by: Denton Liu <liu.denton@gmail.com>
---
 Documentation/merge-options.txt |  5 +++
 builtin/merge.c                 | 31 +++++++++++++----
 builtin/pull.c                  |  6 ++++
 t/t7604-merge-custom-message.sh | 61 +++++++++++++++++++++++++++++++++
 wt-status.c                     | 12 +++++--
 wt-status.h                     |  1 +
 6 files changed, 106 insertions(+), 10 deletions(-)

diff --git a/Documentation/merge-options.txt b/Documentation/merge-options.txt
index 92a7d936c1..646100ea9a 100644
--- a/Documentation/merge-options.txt
+++ b/Documentation/merge-options.txt
@@ -32,6 +32,11 @@ they run `git merge`. To make it easier to adjust such scripts to the
 updated behaviour, the environment variable `GIT_MERGE_AUTOEDIT` can be
 set to `no` at the beginning of them.
 
+--cleanup=<mode>::
+	This option determines how the merge message will be cleaned up
+	before commiting or being passed on. See linkgit:git-commit[1] for more
+	details.
+
 --ff::
 	When the merge resolves as a fast-forward, only update the branch
 	pointer, without creating a merge commit.  This is the default
diff --git a/builtin/merge.c b/builtin/merge.c
index 5ce8946d39..4f5fcf5ce9 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -38,6 +38,7 @@
 #include "tag.h"
 #include "alias.h"
 #include "commit-reach.h"
+#include "wt-status.h"
 
 #define DEFAULT_TWOHEAD (1<<0)
 #define DEFAULT_OCTOPUS (1<<1)
@@ -98,6 +99,9 @@ enum ff_type {
 
 static enum ff_type fast_forward = FF_ALLOW;
 
+static const char *cleanup_arg;
+static enum commit_msg_cleanup_mode cleanup_mode;
+
 static int option_parse_message(const struct option *opt,
 				const char *arg, int unset)
 {
@@ -249,6 +253,7 @@ static struct option builtin_merge_options[] = {
 		N_("perform a commit if the merge succeeds (default)")),
 	OPT_BOOL('e', "edit", &option_edit,
 		N_("edit message before committing")),
+	OPT_STRING(0, "cleanup", &cleanup_arg, N_("default"), N_("how to strip spaces and #comments from message")),
 	OPT_SET_INT(0, "ff", &fast_forward, N_("allow fast-forward (default)"), FF_ALLOW),
 	OPT_SET_INT_F(0, "ff-only", &fast_forward,
 		      N_("abort if fast-forward is not possible"),
@@ -612,6 +617,8 @@ static int git_merge_config(const char *k, const char *v, void *cb)
 		return git_config_string(&pull_twohead, k, v);
 	else if (!strcmp(k, "pull.octopus"))
 		return git_config_string(&pull_octopus, k, v);
+	else if (!strcmp(k, "commit.cleanup"))
+		return git_config_string(&cleanup_arg, k, v);
 	else if (!strcmp(k, "merge.renormalize"))
 		option_renormalize = git_config_bool(k, v);
 	else if (!strcmp(k, "merge.ff")) {
@@ -797,23 +804,32 @@ static void abort_commit(struct commit_list *remoteheads, const char *err_msg)
 	exit(1);
 }
 
+static const char comment_line_explanation[] =
+N_("Lines starting with '%c' will be ignored.\n");
+
 static const char merge_editor_comment[] =
 N_("Please enter a commit message to explain why this merge is necessary,\n"
    "especially if it merges an updated upstream into a topic branch.\n"
    "\n"
-   "Lines starting with '%c' will be ignored, and an empty message aborts\n"
-   "the commit.\n");
+   "An empty message aborts the commit.\n");
 
 static void write_merge_heads(struct commit_list *);
 static void prepare_to_commit(struct commit_list *remoteheads)
 {
 	struct strbuf msg = STRBUF_INIT;
 	strbuf_addbuf(&msg, &merge_msg);
-	strbuf_addch(&msg, '\n');
 	if (squash)
 		BUG("the control must not reach here under --squash");
-	if (0 < option_edit)
-		strbuf_commented_addf(&msg, _(merge_editor_comment), comment_line_char);
+	if (0 < option_edit) {
+		strbuf_addch(&msg, '\n');
+		if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)
+			wt_status_append_cut_line(&msg);
+		else
+			strbuf_commented_addf(&msg, _(comment_line_explanation), comment_line_char);
+
+		strbuf_commented_addf(&msg, "\n");
+		strbuf_commented_addf(&msg, _(merge_editor_comment));
+	}
 	if (signoff)
 		append_signoff(&msg, ignore_non_trailer(msg.buf, msg.len), 0);
 	write_merge_heads(remoteheads);
@@ -832,7 +848,7 @@ static void prepare_to_commit(struct commit_list *remoteheads)
 		abort_commit(remoteheads, NULL);
 
 	read_merge_msg(&msg);
-	strbuf_stripspace(&msg, 0 < option_edit);
+	cleanup_message(&msg, cleanup_mode, 0);
 	if (!msg.len)
 		abort_commit(remoteheads, _("Empty commit message."));
 	strbuf_release(&merge_msg);
@@ -880,7 +896,6 @@ static int finish_automerge(struct commit *head,
 	parents = remoteheads;
 	if (!head_subsumed || fast_forward == FF_NO)
 		commit_list_insert(head, &parents);
-	strbuf_addch(&merge_msg, '\n');
 	prepare_to_commit(remoteheads);
 	if (commit_tree(merge_msg.buf, merge_msg.len, result_tree, parents,
 			&result_commit, NULL, sign_commit))
@@ -1389,6 +1404,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
 	if (option_edit < 0)
 		option_edit = default_edit_option();
 
+	cleanup_mode = get_cleanup_mode(cleanup_arg, 0 < option_edit, 1);
+
 	if (!use_strategies) {
 		if (!remoteheads)
 			; /* already up-to-date */
diff --git a/builtin/pull.c b/builtin/pull.c
index 33db889955..3ec7882375 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -101,6 +101,7 @@ static char *opt_signoff;
 static char *opt_squash;
 static char *opt_commit;
 static char *opt_edit;
+static char *opt_cleanup;
 static char *opt_ff;
 static char *opt_verify_signatures;
 static int opt_autostash = -1;
@@ -168,6 +169,9 @@ static struct option pull_options[] = {
 	OPT_PASSTHRU(0, "edit", &opt_edit, NULL,
 		N_("edit message before committing"),
 		PARSE_OPT_NOARG),
+	OPT_PASSTHRU(0, "cleanup", &opt_cleanup, NULL,
+		N_("how to strip spaces and #comments from message"),
+		PARSE_OPT_NOARG),
 	OPT_PASSTHRU(0, "ff", &opt_ff, NULL,
 		N_("allow fast-forward"),
 		PARSE_OPT_NOARG),
@@ -644,6 +648,8 @@ static int run_merge(void)
 		argv_array_push(&args, opt_commit);
 	if (opt_edit)
 		argv_array_push(&args, opt_edit);
+	if (opt_cleanup)
+		argv_array_push(&args, opt_cleanup);
 	if (opt_ff)
 		argv_array_push(&args, opt_ff);
 	if (opt_verify_signatures)
diff --git a/t/t7604-merge-custom-message.sh b/t/t7604-merge-custom-message.sh
index 89619cf446..3fcd58eb2c 100755
--- a/t/t7604-merge-custom-message.sh
+++ b/t/t7604-merge-custom-message.sh
@@ -47,4 +47,65 @@ test_expect_success 'merge --log appends to custom message' '
 	test_cmp exp.log actual
 '
 
+mesg_with_comment_and_newlines='
+# text
+
+'
+
+test_expect_success 'prepare file with comment line and trailing newlines'  '
+	printf "%s" "$mesg_with_comment_and_newlines" >expect
+'
+
+test_expect_success 'cleanup commit messages (verbatim option)' '
+	git reset --hard c1 &&
+	git merge --cleanup=verbatim -F expect c2 &&
+	git cat-file -p HEAD |sed -e "1,/^\$/d" >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'cleanup commit messages (whitespace option)' '
+	git reset --hard c1 &&
+	{ echo;echo "# text";echo; } >text &&
+	echo "# text" >expect &&
+	git merge --cleanup=whitespace -F text c2 &&
+	git cat-file -p HEAD |sed -e "1,/^\$/d">actual &&
+	test_cmp expect actual
+
+'
+
+test_expect_success 'cleanup merge messages (scissors option)' '
+	git reset --hard c1 &&
+	cat >text <<EOF &&
+
+# to be kept
+
+  # ------------------------ >8 ------------------------
+# to be kept, too
+# ------------------------ >8 ------------------------
+to be removed
+# ------------------------ >8 ------------------------
+to be removed, too
+EOF
+
+	cat >expect <<EOF &&
+# to be kept
+
+  # ------------------------ >8 ------------------------
+# to be kept, too
+EOF
+	git merge --cleanup=scissors -e -F text c2 &&
+	git cat-file -p HEAD |sed -e "1,/^\$/d">actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'cleanup commit messages (strip option)' '
+	git reset --hard c1 &&
+	{ echo;echo "# text";echo sample;echo; } >text &&
+	echo sample >expect &&
+	git merge --cleanup=strip -F text c2 &&
+	git cat-file -p HEAD |sed -e "1,/^\$/d">actual &&
+	test_cmp expect actual
+
+'
+
 test_done
diff --git a/wt-status.c b/wt-status.c
index 445a36204a..b81fcd428d 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -1006,13 +1006,19 @@ size_t wt_status_locate_end(const char *s, size_t len)
 	return len;
 }
 
-void wt_status_add_cut_line(FILE *fp)
+void wt_status_append_cut_line(struct strbuf *buf)
 {
 	const char *explanation = _("Do not modify or remove the line above.\nEverything below it will be ignored.");
+
+	strbuf_commented_addf(buf, "%s", cut_line);
+	strbuf_add_commented_lines(buf, explanation, strlen(explanation));
+}
+
+void wt_status_add_cut_line(FILE *fp)
+{
 	struct strbuf buf = STRBUF_INIT;
 
-	fprintf(fp, "%c %s", comment_line_char, cut_line);
-	strbuf_add_commented_lines(&buf, explanation, strlen(explanation));
+	wt_status_append_cut_line(&buf);
 	fputs(buf.buf, fp);
 	strbuf_release(&buf);
 }
diff --git a/wt-status.h b/wt-status.h
index 3a95975032..64f1ddc9fd 100644
--- a/wt-status.h
+++ b/wt-status.h
@@ -129,6 +129,7 @@ struct wt_status {
 };
 
 size_t wt_status_locate_end(const char *s, size_t len);
+void wt_status_append_cut_line(struct strbuf *buf);
 void wt_status_add_cut_line(FILE *fp);
 void wt_status_prepare(struct repository *r, struct wt_status *s);
 void wt_status_print(struct wt_status *s);
-- 
2.21.0.370.g4fdb13b891


^ permalink raw reply	[flat|nested] 105+ messages in thread

* [PATCH v7 6/8] merge: add scissors line on merge conflict
  2019-03-11  3:42           ` [PATCH v7 0/8] Fix scissors bug during conflict Denton Liu
                               ` (4 preceding siblings ...)
  2019-03-11  3:42             ` [PATCH v7 5/8] merge: cleanup messages like commit Denton Liu
@ 2019-03-11  3:42             ` Denton Liu
  2019-03-11  5:55               ` Eric Sunshine
  2019-03-11  3:42             ` [PATCH v7 7/8] sequencer.c: define get_config_from_cleanup Denton Liu
                               ` (3 subsequent siblings)
  9 siblings, 1 reply; 105+ messages in thread
From: Denton Liu @ 2019-03-11  3:42 UTC (permalink / raw)
  To: Git Mailing List; +Cc: Phillip Wood, Junio C Hamano

This fixes a bug where the scissors line is placed after the Conflicts:
section, in the case where a merge conflict occurs and
commit.cleanup = scissors.

Next, if commit.cleanup = scissors is specified, don't produce a
scissors line in commit if one already exists in the MERGE_MSG file.

Signed-off-by: Denton Liu <liu.denton@gmail.com>
---
 Documentation/merge-options.txt |  4 ++-
 builtin/commit.c                | 20 ++++++++++----
 builtin/merge.c                 | 14 ++++++++++
 t/t7600-merge.sh                | 46 +++++++++++++++++++++++++++++++++
 4 files changed, 78 insertions(+), 6 deletions(-)

diff --git a/Documentation/merge-options.txt b/Documentation/merge-options.txt
index 646100ea9a..c7b889d6f5 100644
--- a/Documentation/merge-options.txt
+++ b/Documentation/merge-options.txt
@@ -35,7 +35,9 @@ set to `no` at the beginning of them.
 --cleanup=<mode>::
 	This option determines how the merge message will be cleaned up
 	before commiting or being passed on. See linkgit:git-commit[1] for more
-	details.
+	details. In addition, if the '<mode>' is given a value of `scissors`,
+	scissors will be appended to MERGE_MSG before being passed on in the
+	case of a merge conflict.
 
 --ff::
 	When the merge resolves as a fast-forward, only update the branch
diff --git a/builtin/commit.c b/builtin/commit.c
index 81e3bd21ca..d8c4626a68 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -668,6 +668,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
 	const char *hook_arg2 = NULL;
 	int clean_message_contents = (cleanup_mode != COMMIT_MSG_CLEANUP_NONE);
 	int old_display_comment_prefix;
+	int merge_contains_scissors = 0;
 
 	/* This checks and barfs if author is badly specified */
 	determine_author_info(author_ident);
@@ -728,6 +729,8 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
 			strbuf_addbuf(&sb, &message);
 		hook_arg1 = "message";
 	} else if (!stat(git_path_merge_msg(the_repository), &statbuf)) {
+		size_t merge_msg_start;
+
 		/*
 		 * prepend SQUASH_MSG here if it exists and a
 		 * "merge --squash" was originally performed
@@ -738,8 +741,14 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
 			hook_arg1 = "squash";
 		} else
 			hook_arg1 = "merge";
+
+		merge_msg_start = sb.len;
 		if (strbuf_read_file(&sb, git_path_merge_msg(the_repository), 0) < 0)
 			die_errno(_("could not read MERGE_MSG"));
+
+		if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS &&
+		    wt_status_locate_end(sb.buf + merge_msg_start, sb.len - merge_msg_start) < sb.len - merge_msg_start)
+			merge_contains_scissors = 1;
 	} else if (!stat(git_path_squash_msg(the_repository), &statbuf)) {
 		if (strbuf_read_file(&sb, git_path_squash_msg(the_repository), 0) < 0)
 			die_errno(_("could not read SQUASH_MSG"));
@@ -807,7 +816,8 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
 		struct ident_split ci, ai;
 
 		if (whence != FROM_COMMIT) {
-			if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)
+			if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS &&
+				!merge_contains_scissors)
 				wt_status_add_cut_line(s->fp);
 			status_printf_ln(s, GIT_COLOR_NORMAL,
 			    whence == FROM_MERGE
@@ -832,10 +842,10 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
 				_("Please enter the commit message for your changes."
 				  " Lines starting\nwith '%c' will be ignored, and an empty"
 				  " message aborts the commit.\n"), comment_line_char);
-		else if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS &&
-			 whence == FROM_COMMIT)
-			wt_status_add_cut_line(s->fp);
-		else /* COMMIT_MSG_CLEANUP_SPACE, that is. */
+		else if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS) {
+			if (whence == FROM_COMMIT && !merge_contains_scissors)
+				wt_status_add_cut_line(s->fp);
+		} else /* COMMIT_MSG_CLEANUP_SPACE, that is. */
 			status_printf(s, GIT_COLOR_NORMAL,
 				_("Please enter the commit message for your changes."
 				  " Lines starting\n"
diff --git a/builtin/merge.c b/builtin/merge.c
index 4f5fcf5ce9..b620d4bfcb 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -916,6 +916,20 @@ static int suggest_conflicts(void)
 	filename = git_path_merge_msg(the_repository);
 	fp = xfopen(filename, "a");
 
+	/*
+	 * We can't use cleanup_mode because if we're not using the editor,
+	 * get_cleanup_mode will return COMMIT_MSG_CLEANUP_SPACE instead, even
+	 * though the message is meant to be processed later by git-commit.
+	 * Thus, we will get the cleanup mode which is returned when we _are_ using
+	 * an editor.
+	 */
+	if (get_cleanup_mode(cleanup_arg, 1, 1) == COMMIT_MSG_CLEANUP_SCISSORS) {
+	    fputc('\n', fp);
+	    wt_status_add_cut_line(fp);
+	    /* comments out the newline from append_conflicts_hint */
+	    fputc(comment_line_char, fp);
+	}
+
 	append_conflicts_hint(&the_index, &msgbuf);
 	fputs(msgbuf.buf, fp);
 	strbuf_release(&msgbuf);
diff --git a/t/t7600-merge.sh b/t/t7600-merge.sh
index d879efd330..2cb57e5878 100755
--- a/t/t7600-merge.sh
+++ b/t/t7600-merge.sh
@@ -246,6 +246,52 @@ test_expect_success 'merge --squash c3 with c7' '
 	test_cmp expect actual
 '
 
+test_expect_success 'merge c3 with c7 with commit.cleanup = scissors' '
+	git config commit.cleanup scissors &&
+	git reset --hard c3 &&
+	test_must_fail git merge c7 &&
+	cat result.9z >file &&
+	git commit --no-edit -a &&
+
+	cat >expect <<-EOF &&
+		Merge tag '"'"'c7'"'"'
+
+		# ------------------------ >8 ------------------------
+		# Do not modify or remove the line above.
+		# Everything below it will be ignored.
+		#
+		# Conflicts:
+		#	file
+		EOF
+	git cat-file commit HEAD >tmp &&
+	sed -e '1,/^$/d' <tmp >actual &&
+	test_i18ncmp expect actual
+'
+
+test_expect_success 'merge c3 with c7 with --squash commit.cleanup = scissors' '
+	git config commit.cleanup scissors &&
+	git reset --hard c3 &&
+	test_must_fail git merge --squash c7 &&
+	cat result.9z >file &&
+	git commit --no-edit -a &&
+
+	cat >expect <<-EOF &&
+		Squashed commit of the following:
+
+		$(git show -s c7)
+
+		# ------------------------ >8 ------------------------
+		# Do not modify or remove the line above.
+		# Everything below it will be ignored.
+		#
+		# Conflicts:
+		#	file
+		EOF
+	git cat-file commit HEAD >tmp &&
+	sed -e '1,/^$/d' <tmp >actual &&
+	test_i18ncmp expect actual
+'
+
 test_debug 'git log --graph --decorate --oneline --all'
 
 test_expect_success 'merge c1 with c2 and c3' '
-- 
2.21.0.370.g4fdb13b891


^ permalink raw reply	[flat|nested] 105+ messages in thread

* [PATCH v7 7/8] sequencer.c: define get_config_from_cleanup
  2019-03-11  3:42           ` [PATCH v7 0/8] Fix scissors bug during conflict Denton Liu
                               ` (5 preceding siblings ...)
  2019-03-11  3:42             ` [PATCH v7 6/8] merge: add scissors line on merge conflict Denton Liu
@ 2019-03-11  3:42             ` Denton Liu
  2019-03-11  6:19               ` Eric Sunshine
  2019-03-12  6:29               ` Junio C Hamano
  2019-03-11  3:42             ` [PATCH v7 8/8] cherry-pick/revert: add scissors line on merge conflict Denton Liu
                               ` (2 subsequent siblings)
  9 siblings, 2 replies; 105+ messages in thread
From: Denton Liu @ 2019-03-11  3:42 UTC (permalink / raw)
  To: Git Mailing List; +Cc: Phillip Wood, Junio C Hamano

Define a function which allows us to get the string configuration value
of a enum commit_msg_cleanup_mode. This is done by refactoring
get_cleanup_mode such that it uses a lookup table to find the mappings
between string and enum and then using the same LUT in reverse to define
get_config_from_cleanup.

Signed-off-by: Denton Liu <liu.denton@gmail.com>
---
 sequencer.c | 67 +++++++++++++++++++++++++++++++++++++++++------------
 sequencer.h |  1 +
 2 files changed, 53 insertions(+), 15 deletions(-)

diff --git a/sequencer.c b/sequencer.c
index 612621f221..5d94e2c865 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -160,6 +160,22 @@ static GIT_PATH_FUNC(rebase_path_strategy_opts, "rebase-merge/strategy_opts")
 static GIT_PATH_FUNC(rebase_path_allow_rerere_autoupdate, "rebase-merge/allow_rerere_autoupdate")
 static GIT_PATH_FUNC(rebase_path_reschedule_failed_exec, "rebase-merge/reschedule-failed-exec")
 
+struct cleanup_config_mapping {
+    const char *config_value;
+    enum commit_msg_cleanup_mode editor_cleanup;
+    enum commit_msg_cleanup_mode no_editor_cleanup;
+};
+
+/* note that we assume that cleanup_config_mapping[0] contains the default settings */
+struct cleanup_config_mapping cleanup_config_mappings[] = {
+	{ "default", COMMIT_MSG_CLEANUP_ALL, COMMIT_MSG_CLEANUP_SPACE },
+	{ "verbatim", COMMIT_MSG_CLEANUP_NONE, COMMIT_MSG_CLEANUP_NONE },
+	{ "whitespace", COMMIT_MSG_CLEANUP_SPACE, COMMIT_MSG_CLEANUP_SPACE },
+	{ "strip", COMMIT_MSG_CLEANUP_ALL, COMMIT_MSG_CLEANUP_ALL },
+	{ "scissors", COMMIT_MSG_CLEANUP_SCISSORS, COMMIT_MSG_CLEANUP_SPACE },
+	{ NULL, 0, 0 }
+};
+
 static int git_sequencer_config(const char *k, const char *v, void *cb)
 {
 	struct replay_opts *opts = cb;
@@ -504,26 +520,42 @@ static int fast_forward_to(struct repository *r,
 enum commit_msg_cleanup_mode get_cleanup_mode(const char *cleanup_arg,
 	int use_editor, int die_on_error)
 {
-	if (!cleanup_arg || !strcmp(cleanup_arg, "default"))
-		return use_editor ? COMMIT_MSG_CLEANUP_ALL :
-				    COMMIT_MSG_CLEANUP_SPACE;
-	else if (!strcmp(cleanup_arg, "verbatim"))
-		return COMMIT_MSG_CLEANUP_NONE;
-	else if (!strcmp(cleanup_arg, "whitespace"))
-		return COMMIT_MSG_CLEANUP_SPACE;
-	else if (!strcmp(cleanup_arg, "strip"))
-		return COMMIT_MSG_CLEANUP_ALL;
-	else if (!strcmp(cleanup_arg, "scissors"))
-		return use_editor ? COMMIT_MSG_CLEANUP_SCISSORS :
-				    COMMIT_MSG_CLEANUP_SPACE;
-	else if (!die_on_error) {
+	struct cleanup_config_mapping *default_mapping = &cleanup_config_mappings[0];
+	struct cleanup_config_mapping *current_mapping;
+
+	if (!cleanup_arg) {
+		return use_editor ? default_mapping->editor_cleanup :
+				    default_mapping->no_editor_cleanup;
+	}
+
+	for (current_mapping = cleanup_config_mappings; current_mapping->config_value; current_mapping++) {
+		if (!strcmp(cleanup_arg, current_mapping->config_value)) {
+			return use_editor ? current_mapping->editor_cleanup :
+					    current_mapping->no_editor_cleanup;
+		}
+	}
+
+	if (!die_on_error) {
 		warning(_("Invalid cleanup mode %s, falling back to default"), cleanup_arg);
-		return use_editor ? COMMIT_MSG_CLEANUP_ALL :
-				    COMMIT_MSG_CLEANUP_SPACE;
+		return use_editor ? default_mapping->editor_cleanup :
+				    default_mapping->no_editor_cleanup;
 	} else
 		die(_("Invalid cleanup mode %s"), cleanup_arg);
 }
 
+const char *get_config_from_cleanup(enum commit_msg_cleanup_mode cleanup_mode)
+{
+	struct cleanup_config_mapping *current_mapping;
+
+	for (current_mapping = &cleanup_config_mappings[1]; current_mapping->config_value; current_mapping++) {
+		if (cleanup_mode == current_mapping->editor_cleanup) {
+			return current_mapping->config_value;
+		}
+	}
+
+	BUG(_("invalid cleanup_mode provided"));
+}
+
 void append_conflicts_hint(struct index_state *istate,
 			   struct strbuf *msgbuf)
 {
@@ -2350,6 +2382,8 @@ static int populate_opts_cb(const char *key, const char *value, void *data)
 		opts->allow_rerere_auto =
 			git_config_bool_or_int(key, value, &error_flag) ?
 				RERERE_AUTOUPDATE : RERERE_NOAUTOUPDATE;
+	else if (!strcmp(key, "options.default-msg-cleanup"))
+		opts->default_msg_cleanup = get_cleanup_mode(value, 1, 1);
 	else
 		return error(_("invalid key: %s"), key);
 
@@ -2754,6 +2788,9 @@ static int save_opts(struct replay_opts *opts)
 		res |= git_config_set_in_file_gently(opts_file, "options.allow-rerere-auto",
 						     opts->allow_rerere_auto == RERERE_AUTOUPDATE ?
 						     "true" : "false");
+
+	res |= git_config_set_in_file_gently(opts_file, "options.default-msg-cleanup",
+					     get_config_from_cleanup(opts->default_msg_cleanup));
 	return res;
 }
 
diff --git a/sequencer.h b/sequencer.h
index e7908f558e..e3c1f44807 100644
--- a/sequencer.h
+++ b/sequencer.h
@@ -118,6 +118,7 @@ void append_signoff(struct strbuf *msgbuf, size_t ignore_footer, unsigned flag);
 void append_conflicts_hint(struct index_state *istate, struct strbuf *msgbuf);
 enum commit_msg_cleanup_mode get_cleanup_mode(const char *cleanup_arg,
 	int use_editor, int die_on_error);
+const char *get_config_from_cleanup(enum commit_msg_cleanup_mode cleanup_mode);
 
 void cleanup_message(struct strbuf *msgbuf,
 	enum commit_msg_cleanup_mode cleanup_mode, int verbose);
-- 
2.21.0.370.g4fdb13b891


^ permalink raw reply	[flat|nested] 105+ messages in thread

* [PATCH v7 8/8] cherry-pick/revert: add scissors line on merge conflict
  2019-03-11  3:42           ` [PATCH v7 0/8] Fix scissors bug during conflict Denton Liu
                               ` (6 preceding siblings ...)
  2019-03-11  3:42             ` [PATCH v7 7/8] sequencer.c: define get_config_from_cleanup Denton Liu
@ 2019-03-11  3:42             ` Denton Liu
  2019-03-12 11:11               ` Phillip Wood
  2019-03-11  6:44             ` [PATCH v7 0/8] Fix scissors bug during conflict Junio C Hamano
  2019-03-17 10:15             ` [PATCH v8 00/11] " Denton Liu
  9 siblings, 1 reply; 105+ messages in thread
From: Denton Liu @ 2019-03-11  3:42 UTC (permalink / raw)
  To: Git Mailing List; +Cc: Phillip Wood, Junio C Hamano

Fix a bug where the scissors line is placed after the Conflicts:
section, in the case where a merge conflict occurs and
commit.cleanup = scissors.

Signed-off-by: Denton Liu <liu.denton@gmail.com>
---
 Documentation/git-cherry-pick.txt |  7 +++
 Documentation/git-revert.txt      |  7 +++
 builtin/merge.c                   |  9 +---
 builtin/rebase--interactive.c     |  2 +-
 builtin/revert.c                  |  5 ++
 sequencer.c                       | 22 +++++---
 sequencer.h                       |  3 +-
 t/t3507-cherry-pick-conflict.sh   | 86 +++++++++++++++++++++++++++++++
 8 files changed, 123 insertions(+), 18 deletions(-)

diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt
index b8cfeec67e..b4ff8e136d 100644
--- a/Documentation/git-cherry-pick.txt
+++ b/Documentation/git-cherry-pick.txt
@@ -57,6 +57,13 @@ OPTIONS
 	With this option, 'git cherry-pick' will let you edit the commit
 	message prior to committing.
 
+--cleanup=<mode>::
+	This option determines how the commit message will be cleaned up before
+	being passed on. See linkgit:git-commit[1] for more details. In
+	addition, if the '<mode>' is given a value of `scissors`, scissors will
+	be appended to MERGE_MSG before being passed on in the case of a
+	conflict.
+
 -x::
 	When recording the commit, append a line that says
 	"(cherry picked from commit ...)" to the original commit
diff --git a/Documentation/git-revert.txt b/Documentation/git-revert.txt
index 837707a8fd..bd4ad395a9 100644
--- a/Documentation/git-revert.txt
+++ b/Documentation/git-revert.txt
@@ -66,6 +66,13 @@ more details.
 	With this option, 'git revert' will not start the commit
 	message editor.
 
+--cleanup=<mode>::
+	This option determines how the commit message will be cleaned up before
+	being passed on. See linkgit:git-commit[1] for more details. In
+	addition, if the '<mode>' is given a value of `scissors`, scissors will
+	be appended to MERGE_MSG before being passed on in the case of a
+	conflict.
+
 -n::
 --no-commit::
 	Usually the command automatically creates some commits with
diff --git a/builtin/merge.c b/builtin/merge.c
index b620d4bfcb..671d6a19a4 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -923,14 +923,7 @@ static int suggest_conflicts(void)
 	 * Thus, we will get the cleanup mode which is returned when we _are_ using
 	 * an editor.
 	 */
-	if (get_cleanup_mode(cleanup_arg, 1, 1) == COMMIT_MSG_CLEANUP_SCISSORS) {
-	    fputc('\n', fp);
-	    wt_status_add_cut_line(fp);
-	    /* comments out the newline from append_conflicts_hint */
-	    fputc(comment_line_char, fp);
-	}
-
-	append_conflicts_hint(&the_index, &msgbuf);
+	append_conflicts_hint(&the_index, &msgbuf, get_cleanup_mode(cleanup_arg, 1, 1));
 	fputs(msgbuf.buf, fp);
 	strbuf_release(&msgbuf);
 	fclose(fp);
diff --git a/builtin/rebase--interactive.c b/builtin/rebase--interactive.c
index 888390f911..cf2151b271 100644
--- a/builtin/rebase--interactive.c
+++ b/builtin/rebase--interactive.c
@@ -199,10 +199,10 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)
 		OPT_END()
 	};
 
+	opts.action = REPLAY_INTERACTIVE_REBASE;
 	sequencer_init_config(&opts);
 	git_config_get_bool("rebase.abbreviatecommands", &abbreviate_commands);
 
-	opts.action = REPLAY_INTERACTIVE_REBASE;
 	opts.allow_ff = 1;
 	opts.allow_empty = 1;
 
diff --git a/builtin/revert.c b/builtin/revert.c
index a47b53ceaf..e8168e0214 100644
--- a/builtin/revert.c
+++ b/builtin/revert.c
@@ -96,11 +96,13 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
 {
 	const char * const * usage_str = revert_or_cherry_pick_usage(opts);
 	const char *me = action_name(opts);
+	const char *cleanup_arg = NULL;
 	int cmd = 0;
 	struct option base_options[] = {
 		OPT_CMDMODE(0, "quit", &cmd, N_("end revert or cherry-pick sequence"), 'q'),
 		OPT_CMDMODE(0, "continue", &cmd, N_("resume revert or cherry-pick sequence"), 'c'),
 		OPT_CMDMODE(0, "abort", &cmd, N_("cancel revert or cherry-pick sequence"), 'a'),
+		OPT_STRING(0, "cleanup", &cleanup_arg, N_("default"), N_("how to strip spaces and #comments from message")),
 		OPT_BOOL('n', "no-commit", &opts->no_commit, N_("don't automatically commit")),
 		OPT_BOOL('e', "edit", &opts->edit, N_("edit the commit message")),
 		OPT_NOOP_NOARG('r', NULL),
@@ -137,6 +139,9 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
 	if (opts->keep_redundant_commits)
 		opts->allow_empty = 1;
 
+	if (cleanup_arg)
+		opts->default_msg_cleanup = get_cleanup_mode(cleanup_arg, 1, 1);
+
 	/* Check for incompatible command line arguments */
 	if (cmd) {
 		char *this_operation;
diff --git a/sequencer.c b/sequencer.c
index 5d94e2c865..496554a474 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -176,6 +176,11 @@ struct cleanup_config_mapping cleanup_config_mappings[] = {
 	{ NULL, 0, 0 }
 };
 
+static inline int is_rebase_i(const struct replay_opts *opts)
+{
+	return opts->action == REPLAY_INTERACTIVE_REBASE;
+}
+
 static int git_sequencer_config(const char *k, const char *v, void *cb)
 {
 	struct replay_opts *opts = cb;
@@ -188,7 +193,7 @@ static int git_sequencer_config(const char *k, const char *v, void *cb)
 		if (status)
 			return status;
 
-		opts->default_msg_cleanup = get_cleanup_mode(s, 0, 0);
+		opts->default_msg_cleanup = get_cleanup_mode(s, !is_rebase_i(opts), 0);
 
 		free((char *)s);
 		return status;
@@ -212,11 +217,6 @@ void sequencer_init_config(struct replay_opts *opts)
 	git_config(git_sequencer_config, opts);
 }
 
-static inline int is_rebase_i(const struct replay_opts *opts)
-{
-	return opts->action == REPLAY_INTERACTIVE_REBASE;
-}
-
 static const char *get_dir(const struct replay_opts *opts)
 {
 	if (is_rebase_i(opts))
@@ -557,10 +557,16 @@ const char *get_config_from_cleanup(enum commit_msg_cleanup_mode cleanup_mode)
 }
 
 void append_conflicts_hint(struct index_state *istate,
-			   struct strbuf *msgbuf)
+		struct strbuf *msgbuf, enum commit_msg_cleanup_mode cleanup_mode)
 {
 	int i;
 
+	if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS) {
+		strbuf_addch(msgbuf, '\n');
+		wt_status_append_cut_line(msgbuf);
+		strbuf_addch(msgbuf, comment_line_char);
+	}
+
 	strbuf_addch(msgbuf, '\n');
 	strbuf_commented_addf(msgbuf, "Conflicts:\n");
 	for (i = 0; i < istate->cache_nr;) {
@@ -628,7 +634,7 @@ static int do_recursive_merge(struct repository *r,
 			_(action_name(opts)));
 
 	if (!clean)
-		append_conflicts_hint(r->index, msgbuf);
+		append_conflicts_hint(r->index, msgbuf, opts->default_msg_cleanup);
 
 	return !clean;
 }
diff --git a/sequencer.h b/sequencer.h
index e3c1f44807..95ff9db508 100644
--- a/sequencer.h
+++ b/sequencer.h
@@ -115,7 +115,8 @@ int rearrange_squash(struct repository *r);
  */
 void append_signoff(struct strbuf *msgbuf, size_t ignore_footer, unsigned flag);
 
-void append_conflicts_hint(struct index_state *istate, struct strbuf *msgbuf);
+void append_conflicts_hint(struct index_state *istate,
+		struct strbuf *msgbuf, enum commit_msg_cleanup_mode cleanup_mode);
 enum commit_msg_cleanup_mode get_cleanup_mode(const char *cleanup_arg,
 	int use_editor, int die_on_error);
 const char *get_config_from_cleanup(enum commit_msg_cleanup_mode cleanup_mode);
diff --git a/t/t3507-cherry-pick-conflict.sh b/t/t3507-cherry-pick-conflict.sh
index 74ff925526..c3894ca9d6 100755
--- a/t/t3507-cherry-pick-conflict.sh
+++ b/t/t3507-cherry-pick-conflict.sh
@@ -189,6 +189,46 @@ test_expect_success 'failed cherry-pick registers participants in index' '
 	test_cmp expected actual
 '
 
+test_expect_success \
+	'cherry-pick conflict, ensure commit.cleanup = scissors places scissors line properly' '
+	pristine_detach initial &&
+	git config commit.cleanup scissors &&
+	cat <<-EOF >expected &&
+		picked
+
+		# ------------------------ >8 ------------------------
+		# Do not modify or remove the line above.
+		# Everything below it will be ignored.
+		#
+		# Conflicts:
+		#	foo
+		EOF
+
+	test_must_fail git cherry-pick picked &&
+
+	test_i18ncmp expected .git/MERGE_MSG
+'
+
+test_expect_success \
+	'cherry-pick conflict, ensure cleanup=scissors places scissors line properly' '
+	pristine_detach initial &&
+	git config --unset commit.cleanup &&
+	cat <<-EOF >expected &&
+		picked
+
+		# ------------------------ >8 ------------------------
+		# Do not modify or remove the line above.
+		# Everything below it will be ignored.
+		#
+		# Conflicts:
+		#	foo
+		EOF
+
+	test_must_fail git cherry-pick --cleanup=scissors picked &&
+
+	test_i18ncmp expected .git/MERGE_MSG
+'
+
 test_expect_success 'failed cherry-pick describes conflict in work tree' '
 	pristine_detach initial &&
 	cat <<-EOF >expected &&
@@ -335,6 +375,52 @@ test_expect_success 'revert conflict, diff3 -m style' '
 	test_cmp expected actual
 '
 
+test_expect_success \
+	'revert conflict, ensure commit.cleanup = scissors places scissors line properly' '
+	pristine_detach initial &&
+	git config commit.cleanup scissors &&
+	cat >expected <<-EOF &&
+		Revert "picked"
+
+		This reverts commit OBJID.
+
+		# ------------------------ >8 ------------------------
+		# Do not modify or remove the line above.
+		# Everything below it will be ignored.
+		#
+		# Conflicts:
+		#	foo
+		EOF
+
+	test_must_fail git revert picked &&
+
+	sed "s/$OID_REGEX/OBJID/" .git/MERGE_MSG >actual &&
+	test_i18ncmp expected actual
+'
+
+test_expect_success \
+	'revert conflict, ensure cleanup=scissors places scissors line properly' '
+	pristine_detach initial &&
+	git config --unset commit.cleanup &&
+	cat >expected <<-EOF &&
+		Revert "picked"
+
+		This reverts commit OBJID.
+
+		# ------------------------ >8 ------------------------
+		# Do not modify or remove the line above.
+		# Everything below it will be ignored.
+		#
+		# Conflicts:
+		#	foo
+		EOF
+
+	test_must_fail git revert --cleanup=scissors picked &&
+
+	sed "s/$OID_REGEX/OBJID/" .git/MERGE_MSG >actual &&
+	test_i18ncmp expected actual
+'
+
 test_expect_success 'failed cherry-pick does not forget -s' '
 	pristine_detach initial &&
 	test_must_fail git cherry-pick -s picked &&
-- 
2.21.0.370.g4fdb13b891


^ permalink raw reply	[flat|nested] 105+ messages in thread

* Re: [PATCH v7 5/8] merge: cleanup messages like commit
  2019-03-11  3:42             ` [PATCH v7 5/8] merge: cleanup messages like commit Denton Liu
@ 2019-03-11  5:49               ` Eric Sunshine
  2019-03-11 10:14                 ` Phillip Wood
  2019-03-11 16:58               ` Phillip Wood
  1 sibling, 1 reply; 105+ messages in thread
From: Eric Sunshine @ 2019-03-11  5:49 UTC (permalink / raw)
  To: Denton Liu; +Cc: Git Mailing List, Phillip Wood, Junio C Hamano

On Sun, Mar 10, 2019 at 11:42 PM Denton Liu <liu.denton@gmail.com> wrote:
> This change allows git-merge messages to be cleaned up with the
> commit.cleanup configuration or --cleanup option, just like how
> git-commit does it.
>
> We also give git-pull the passthrough option of --cleanup so that it can
> also take advantage of this change.
>
> Finally, add testing to ensure that messages are properly cleaned up.
> Note that some newlines that were added to the commit message were
> removed so that if a file were read via -F, it would be copied
> faithfully.
>
> Signed-off-by: Denton Liu <liu.denton@gmail.com>
> ---
> diff --git a/t/t7604-merge-custom-message.sh b/t/t7604-merge-custom-message.sh
> @@ -47,4 +47,65 @@ test_expect_success 'merge --log appends to custom message' '
> +test_expect_success 'cleanup commit messages (verbatim option)' '
> +       git reset --hard c1 &&
> +       git merge --cleanup=verbatim -F expect c2 &&
> +       git cat-file -p HEAD |sed -e "1,/^\$/d" >actual &&

An earlier patch in this series "fixed" a test with a Git command
upstream of a pipe. Yet, this test adds such an instance. (Also,
style: add space after '|'.)

> +       test_cmp expect actual
> +'
> +
> +test_expect_success 'cleanup commit messages (whitespace option)' '
> +       git reset --hard c1 &&
> +       { echo;echo "# text";echo; } >text &&

Style: add space after semicolon or use &&-chaining inside {...}.

Alternately, less ugly:

    test_write_lines "" "# text" "" >text &&

(Or even a here-doc, though the leading and trailing blank lines make
the here-doc ugly.)

> +       echo "# text" >expect &&
> +       git merge --cleanup=whitespace -F text c2 &&
> +       git cat-file -p HEAD |sed -e "1,/^\$/d">actual &&

Git upstream pipe.

> +       test_cmp expect actual
> +
> +'

Style: drop the blank line before the closing quote.

> +test_expect_success 'cleanup merge messages (scissors option)' '
> +       git reset --hard c1 &&
> +       cat >text <<EOF &&

This here-doc probably ought to be using '-' and '\', so:

    cat >text <<-\EOF &&

and indent the here-doc body.

> +# to be kept
> +
> +  # ------------------------ >8 ------------------------
> +# to be kept, too
> +# ------------------------ >8 ------------------------
> +to be removed
> +# ------------------------ >8 ------------------------
> +to be removed, too
> +EOF
> +
> +       cat >expect <<EOF &&

Ditto: <<-\EOF and indent body.

> +# to be kept
> +
> +  # ------------------------ >8 ------------------------
> +# to be kept, too
> +EOF
> +       git merge --cleanup=scissors -e -F text c2 &&
> +       git cat-file -p HEAD |sed -e "1,/^\$/d">actual &&

Git upstream pipe.

> +       test_cmp expect actual
> +'
> +
> +test_expect_success 'cleanup commit messages (strip option)' '
> +       git reset --hard c1 &&
> +       { echo;echo "# text";echo sample;echo; } >text &&

test_write_lines "" "# text" sample "" >text &&

> +       echo sample >expect &&
> +       git merge --cleanup=strip -F text c2 &&
> +       git cat-file -p HEAD |sed -e "1,/^\$/d">actual &&

Git upstream pipe.

> +       test_cmp expect actual
> +
> +'

Drop blank line before closing quote.

^ permalink raw reply	[flat|nested] 105+ messages in thread

* Re: [PATCH v7 6/8] merge: add scissors line on merge conflict
  2019-03-11  3:42             ` [PATCH v7 6/8] merge: add scissors line on merge conflict Denton Liu
@ 2019-03-11  5:55               ` Eric Sunshine
  0 siblings, 0 replies; 105+ messages in thread
From: Eric Sunshine @ 2019-03-11  5:55 UTC (permalink / raw)
  To: Denton Liu; +Cc: Git Mailing List, Phillip Wood, Junio C Hamano

On Sun, Mar 10, 2019 at 11:42 PM Denton Liu <liu.denton@gmail.com> wrote:
> This fixes a bug where the scissors line is placed after the Conflicts:
> section, in the case where a merge conflict occurs and
> commit.cleanup = scissors.
>
> Next, if commit.cleanup = scissors is specified, don't produce a
> scissors line in commit if one already exists in the MERGE_MSG file.
>
> Signed-off-by: Denton Liu <liu.denton@gmail.com>
> ---
> diff --git a/t/t7600-merge.sh b/t/t7600-merge.sh
> @@ -246,6 +246,52 @@ test_expect_success 'merge --squash c3 with c7' '
> +test_expect_success 'merge c3 with c7 with commit.cleanup = scissors' '
> +       git config commit.cleanup scissors &&
> +       git reset --hard c3 &&
> +       test_must_fail git merge c7 &&
> +       cat result.9z >file &&
> +       git commit --no-edit -a &&
> +
> +       cat >expect <<-EOF &&

Use <<-\EOF here.

> +               Merge tag '"'"'c7'"'"'
> +
> +               # ------------------------ >8 ------------------------
> +               # Do not modify or remove the line above.
> +               # Everything below it will be ignored.
> +               #
> +               # Conflicts:
> +               #       file
> +               EOF

Style: here-doc body is normally indented to the same level as the
command which starts the here-doc, so this body is indented too much.

Same comments apply to other new test added by this patch.

> +       git cat-file commit HEAD >tmp &&
> +       sed -e '1,/^$/d' <tmp >actual &&
> +       test_i18ncmp expect actual
> +'

^ permalink raw reply	[flat|nested] 105+ messages in thread

* Re: [PATCH v7 7/8] sequencer.c: define get_config_from_cleanup
  2019-03-11  3:42             ` [PATCH v7 7/8] sequencer.c: define get_config_from_cleanup Denton Liu
@ 2019-03-11  6:19               ` Eric Sunshine
  2019-03-12  6:29               ` Junio C Hamano
  1 sibling, 0 replies; 105+ messages in thread
From: Eric Sunshine @ 2019-03-11  6:19 UTC (permalink / raw)
  To: Denton Liu; +Cc: Git Mailing List, Phillip Wood, Junio C Hamano

On Sun, Mar 10, 2019 at 11:42 PM Denton Liu <liu.denton@gmail.com> wrote:
> Define a function which allows us to get the string configuration value
> of a enum commit_msg_cleanup_mode. This is done by refactoring
> get_cleanup_mode such that it uses a lookup table to find the mappings
> between string and enum and then using the same LUT in reverse to define
> get_config_from_cleanup.

Aside from a missing 'static', the comments below are mostly style
suggestions to make the new code less noisy. The basic idea is to
reduce the "wordiness" of the code so that the eye can glide over it
more easily, thus allowing the reader to grasp its meaning "at a
glance", without necessarily having to read it attentively. You may or
may not consider the suggestions actionable.

> Signed-off-by: Denton Liu <liu.denton@gmail.com>
> ---
> diff --git a/sequencer.c b/sequencer.c
> @@ -160,6 +160,22 @@ static GIT_PATH_FUNC(rebase_path_strategy_opts, "rebase-merge/strategy_opts")
> +struct cleanup_config_mapping {
> +    const char *config_value;
> +    enum commit_msg_cleanup_mode editor_cleanup;
> +    enum commit_msg_cleanup_mode no_editor_cleanup;
> +};

These members are already inside a struct named
"cleanup_config_mapping", so we can drop some of the wordiness from
the member names. For instance:

    config --or-- value --or-- val
    editor
    no_editor

> +/* note that we assume that cleanup_config_mapping[0] contains the default settings */
> +struct cleanup_config_mapping cleanup_config_mappings[] = {
> +       { "default", COMMIT_MSG_CLEANUP_ALL, COMMIT_MSG_CLEANUP_SPACE },
> +       { "verbatim", COMMIT_MSG_CLEANUP_NONE, COMMIT_MSG_CLEANUP_NONE },
> +       { "whitespace", COMMIT_MSG_CLEANUP_SPACE, COMMIT_MSG_CLEANUP_SPACE },
> +       { "strip", COMMIT_MSG_CLEANUP_ALL, COMMIT_MSG_CLEANUP_ALL },
> +       { "scissors", COMMIT_MSG_CLEANUP_SCISSORS, COMMIT_MSG_CLEANUP_SPACE },
> +       { NULL, 0, 0 }
> +};

This table should be 'static'.

> @@ -504,26 +520,42 @@ static int fast_forward_to(struct repository *r,
>  enum commit_msg_cleanup_mode get_cleanup_mode(const char *cleanup_arg,
>         int use_editor, int die_on_error)
>  {
> +       struct cleanup_config_mapping *default_mapping = &cleanup_config_mappings[0];
> +       struct cleanup_config_mapping *current_mapping;

We can shorten these two variable names to "def" and "p",
respectively, without losing clarity; there are only two variables in
the function, so it's not difficult to remember what they are. More
importantly, the rest of the code becomes considerably shorter,
allowing the eye to glide over it while easily taking in its meaning
rather than having to spend time actively reading it.

> +       if (!cleanup_arg) {
> +               return use_editor ? default_mapping->editor_cleanup :
> +                                   default_mapping->no_editor_cleanup;
> +       }
> +
> +       for (current_mapping = cleanup_config_mappings; current_mapping->config_value; current_mapping++) {
> +               if (!strcmp(cleanup_arg, current_mapping->config_value)) {
> +                       return use_editor ? current_mapping->editor_cleanup :
> +                                           current_mapping->no_editor_cleanup;
> +               }
> +       }

For instance, with the shorter names, the above loop (while also
dropping unnecessary braces) becomes:

    for (p = cleanup_config_mappings; p->val; p++)
        if (!strcmp(cleanup_arg, p->val))
            return use_editor ? p->editor : p->no_editor;

> +       if (!die_on_error) {
>                 warning(_("Invalid cleanup mode %s, falling back to default"), cleanup_arg);
> -               return use_editor ? COMMIT_MSG_CLEANUP_ALL :
> -                                   COMMIT_MSG_CLEANUP_SPACE;
> +               return use_editor ? default_mapping->editor_cleanup :
> +                                   default_mapping->no_editor_cleanup;
>         } else
>                 die(_("Invalid cleanup mode %s"), cleanup_arg);
>  }

Same comments apply to other new code introduced by this patch.

> +const char *get_config_from_cleanup(enum commit_msg_cleanup_mode cleanup_mode)
> +{
> +       struct cleanup_config_mapping *current_mapping;
> +
> +       for (current_mapping = &cleanup_config_mappings[1]; current_mapping->config_value; current_mapping++) {
> +               if (cleanup_mode == current_mapping->editor_cleanup) {
> +                       return current_mapping->config_value;
> +               }
> +       }
> +
> +       BUG(_("invalid cleanup_mode provided"));

Don't localize BUG() messages; they are intended only for developer
eyes, not end-users. So:

    BUG("invalid cleanup_mode provided");

> +}
> diff --git a/sequencer.h b/sequencer.h
> @@ -118,6 +118,7 @@ void append_signoff(struct strbuf *msgbuf, size_t ignore_footer, unsigned flag);
>  enum commit_msg_cleanup_mode get_cleanup_mode(const char *cleanup_arg,
>         int use_editor, int die_on_error);
> +const char *get_config_from_cleanup(enum commit_msg_cleanup_mode cleanup_mode);

A more intuitive name might be describe_cleanup_mode().

^ permalink raw reply	[flat|nested] 105+ messages in thread

* Re: [PATCH v7 0/8] Fix scissors bug during conflict
  2019-03-11  3:42           ` [PATCH v7 0/8] Fix scissors bug during conflict Denton Liu
                               ` (7 preceding siblings ...)
  2019-03-11  3:42             ` [PATCH v7 8/8] cherry-pick/revert: add scissors line on merge conflict Denton Liu
@ 2019-03-11  6:44             ` Junio C Hamano
  2019-03-17 10:15             ` [PATCH v8 00/11] " Denton Liu
  9 siblings, 0 replies; 105+ messages in thread
From: Junio C Hamano @ 2019-03-11  6:44 UTC (permalink / raw)
  To: Denton Liu; +Cc: Git Mailing List, Phillip Wood

Denton Liu <liu.denton@gmail.com> writes:

> This is a complete replacement for dl/merge-cleanup-scissors-fix.

Thanks; will take a look and requeue.

^ permalink raw reply	[flat|nested] 105+ messages in thread

* Re: [PATCH v7 5/8] merge: cleanup messages like commit
  2019-03-11  5:49               ` Eric Sunshine
@ 2019-03-11 10:14                 ` Phillip Wood
  2019-03-11 17:00                   ` Eric Sunshine
  0 siblings, 1 reply; 105+ messages in thread
From: Phillip Wood @ 2019-03-11 10:14 UTC (permalink / raw)
  To: Eric Sunshine, Denton Liu; +Cc: Git Mailing List, Junio C Hamano

Hi Denton/Eric

On 11/03/2019 05:49, Eric Sunshine wrote:
> On Sun, Mar 10, 2019 at 11:42 PM Denton Liu <liu.denton@gmail.com> wrote:
>> This change allows git-merge messages to be cleaned up with the
>> commit.cleanup configuration or --cleanup option, just like how
>> git-commit does it.
>>
>> We also give git-pull the passthrough option of --cleanup so that it can
>> also take advantage of this change.
>>
>> Finally, add testing to ensure that messages are properly cleaned up.
>> Note that some newlines that were added to the commit message were
>> removed so that if a file were read via -F, it would be copied
>> faithfully.
>>
>> Signed-off-by: Denton Liu <liu.denton@gmail.com>
>> ---
>> diff --git a/t/t7604-merge-custom-message.sh b/t/t7604-merge-custom-message.sh
>> @@ -47,4 +47,65 @@ test_expect_success 'merge --log appends to custom message' '
>> +test_expect_success 'cleanup commit messages (verbatim option)' '
>> +       git reset --hard c1 &&
>> +       git merge --cleanup=verbatim -F expect c2 &&
>> +       git cat-file -p HEAD |sed -e "1,/^\$/d" >actual &&
> 
> An earlier patch in this series "fixed" a test with a Git command
> upstream of a pipe. Yet, this test adds such an instance.

Is it worth worrying about? We're not trying to test cat-file here and 
if it does fail the test will fail as actual will be empty. You could use
git log --pretty=%B >actual
which is clearer and saves forking sed.

Best Wishes

Phillip

> (Also, style: add space after '|'.)
> 
>> +       test_cmp expect actual
>> +'
>> +
>> +test_expect_success 'cleanup commit messages (whitespace option)' '
>> +       git reset --hard c1 &&
>> +       { echo;echo "# text";echo; } >text &&
> 
> Style: add space after semicolon or use &&-chaining inside {...}.
> 
> Alternately, less ugly:
> 
>      test_write_lines "" "# text" "" >text &&
> 
> (Or even a here-doc, though the leading and trailing blank lines make
> the here-doc ugly.)
> 
>> +       echo "# text" >expect &&
>> +       git merge --cleanup=whitespace -F text c2 &&
>> +       git cat-file -p HEAD |sed -e "1,/^\$/d">actual &&
> 
> Git upstream pipe.
> 
>> +       test_cmp expect actual
>> +
>> +'
> 
> Style: drop the blank line before the closing quote.
> 
>> +test_expect_success 'cleanup merge messages (scissors option)' '
>> +       git reset --hard c1 &&
>> +       cat >text <<EOF &&
> 
> This here-doc probably ought to be using '-' and '\', so:
> 
>      cat >text <<-\EOF &&
> 
> and indent the here-doc body.
> 
>> +# to be kept
>> +
>> +  # ------------------------ >8 ------------------------
>> +# to be kept, too
>> +# ------------------------ >8 ------------------------
>> +to be removed
>> +# ------------------------ >8 ------------------------
>> +to be removed, too
>> +EOF
>> +
>> +       cat >expect <<EOF &&
> 
> Ditto: <<-\EOF and indent body.
> 
>> +# to be kept
>> +
>> +  # ------------------------ >8 ------------------------
>> +# to be kept, too
>> +EOF
>> +       git merge --cleanup=scissors -e -F text c2 &&
>> +       git cat-file -p HEAD |sed -e "1,/^\$/d">actual &&
> 
> Git upstream pipe.
> 
>> +       test_cmp expect actual
>> +'
>> +
>> +test_expect_success 'cleanup commit messages (strip option)' '
>> +       git reset --hard c1 &&
>> +       { echo;echo "# text";echo sample;echo; } >text &&
> 
> test_write_lines "" "# text" sample "" >text &&
> 
>> +       echo sample >expect &&
>> +       git merge --cleanup=strip -F text c2 &&
>> +       git cat-file -p HEAD |sed -e "1,/^\$/d">actual &&
> 
> Git upstream pipe.
> 
>> +       test_cmp expect actual
>> +
>> +'
> 
> Drop blank line before closing quote.
> 

^ permalink raw reply	[flat|nested] 105+ messages in thread

* Re: [PATCH v7 4/8] sequencer.c: remove duplicate code
  2019-03-11  3:42             ` [PATCH v7 4/8] sequencer.c: remove duplicate code Denton Liu
@ 2019-03-11 16:45               ` Phillip Wood
  0 siblings, 0 replies; 105+ messages in thread
From: Phillip Wood @ 2019-03-11 16:45 UTC (permalink / raw)
  To: Denton Liu, Git Mailing List; +Cc: Junio C Hamano

Hi Denton

One small comment below, this basically looks fine to me

On 11/03/2019 03:42, Denton Liu wrote:
> Since we implemented get_cleanup_mode, we had some duplicate code in
> git_sequencer_config which essentially performed the same operations.
> Refactor git_sequencer_config to take advantage of the logic already in
> get_cleanup_mode.
> 
> Note that we had to introduce a separate argument to get_cleanup_mode
> indicating whether to die or not on an invalid value. This is because if
> we are parsing a config, we do not want to die but instead, we only want
> to warn the user, whereas if we are parsing a command-line option, we
> would like to actually die.
> 
> Finally, this is almost a no-op refactor but not quite. Previously, in
> the case that an invalid value is presented, default_msg_cleanup would
> not be set. We change the behaviour so that default_msg_cleanup will now
> take on the value as if "default" were provided as the cleanup_arg.
> 
> Signed-off-by: Denton Liu <liu.denton@gmail.com>
> ---
>   builtin/commit.c |  2 +-
>   sequencer.c      | 20 +++++++-------------
>   sequencer.h      |  2 +-
>   3 files changed, 9 insertions(+), 15 deletions(-)
> 
> diff --git a/builtin/commit.c b/builtin/commit.c
> index 0df15e4851..81e3bd21ca 100644
> --- a/builtin/commit.c
> +++ b/builtin/commit.c
> @@ -1172,7 +1172,7 @@ static int parse_and_validate_options(int argc, const char *argv[],
>   		die(_("Only one of --include/--only/--all/--interactive/--patch can be used."));
>   	if (argc == 0 && (also || (only && !amend && !allow_empty)))
>   		die(_("No paths with --include/--only does not make sense."));
> -	cleanup_mode = get_cleanup_mode(cleanup_arg, use_editor);
> +	cleanup_mode = get_cleanup_mode(cleanup_arg, use_editor, 1);
>   
>   	handle_untracked_files_arg(s);
>   
> diff --git a/sequencer.c b/sequencer.c
> index 224c823b43..612621f221 100644
> --- a/sequencer.c
> +++ b/sequencer.c
> @@ -172,17 +172,7 @@ static int git_sequencer_config(const char *k, const char *v, void *cb)
>   		if (status)
>   			return status;
>   
> -		if (!strcmp(s, "verbatim"))
> -			opts->default_msg_cleanup = COMMIT_MSG_CLEANUP_NONE;
> -		else if (!strcmp(s, "whitespace"))
> -			opts->default_msg_cleanup = COMMIT_MSG_CLEANUP_SPACE;
> -		else if (!strcmp(s, "strip"))
> -			opts->default_msg_cleanup = COMMIT_MSG_CLEANUP_ALL;
> -		else if (!strcmp(s, "scissors"))
> -			opts->default_msg_cleanup = COMMIT_MSG_CLEANUP_SPACE;
> -		else
> -			warning(_("invalid commit message cleanup mode '%s'"),
> -				  s);
> +		opts->default_msg_cleanup = get_cleanup_mode(s, 0, 0);
>   
>   		free((char *)s);
>   		return status;
> @@ -512,7 +502,7 @@ static int fast_forward_to(struct repository *r,
>   }
>   
>   enum commit_msg_cleanup_mode get_cleanup_mode(const char *cleanup_arg,
> -	int use_editor)
> +	int use_editor, int die_on_error)
>   {
>   	if (!cleanup_arg || !strcmp(cleanup_arg, "default"))
>   		return use_editor ? COMMIT_MSG_CLEANUP_ALL :
> @@ -526,7 +516,11 @@ enum commit_msg_cleanup_mode get_cleanup_mode(const char *cleanup_arg,
>   	else if (!strcmp(cleanup_arg, "scissors"))
>   		return use_editor ? COMMIT_MSG_CLEANUP_SCISSORS :
>   				    COMMIT_MSG_CLEANUP_SPACE;
> -	else
> +	else if (!die_on_error) {
> +		warning(_("Invalid cleanup mode %s, falling back to default"), cleanup_arg);

git generally starts error messages with a lower-case letter so I would 
change the message in the previous patch to match that pattern rather 
than changing this one.


Best Wishes

Phillip


> +		return use_editor ? COMMIT_MSG_CLEANUP_ALL :
> +				    COMMIT_MSG_CLEANUP_SPACE;
> +	} else
>   		die(_("Invalid cleanup mode %s"), cleanup_arg);
>   }
>   
> diff --git a/sequencer.h b/sequencer.h
> index eb9bd97ef3..e7908f558e 100644
> --- a/sequencer.h
> +++ b/sequencer.h
> @@ -117,7 +117,7 @@ void append_signoff(struct strbuf *msgbuf, size_t ignore_footer, unsigned flag);
>   
>   void append_conflicts_hint(struct index_state *istate, struct strbuf *msgbuf);
>   enum commit_msg_cleanup_mode get_cleanup_mode(const char *cleanup_arg,
> -	int use_editor);
> +	int use_editor, int die_on_error);
>   
>   void cleanup_message(struct strbuf *msgbuf,
>   	enum commit_msg_cleanup_mode cleanup_mode, int verbose);
> 

^ permalink raw reply	[flat|nested] 105+ messages in thread

* Re: [PATCH v7 5/8] merge: cleanup messages like commit
  2019-03-11  3:42             ` [PATCH v7 5/8] merge: cleanup messages like commit Denton Liu
  2019-03-11  5:49               ` Eric Sunshine
@ 2019-03-11 16:58               ` Phillip Wood
  2019-03-12  5:50                 ` Junio C Hamano
  1 sibling, 1 reply; 105+ messages in thread
From: Phillip Wood @ 2019-03-11 16:58 UTC (permalink / raw)
  To: Denton Liu, Git Mailing List; +Cc: Junio C Hamano

Hi Denton

On 11/03/2019 03:42, Denton Liu wrote:
> This change allows git-merge messages to be cleaned up with the
> commit.cleanup configuration or --cleanup option, just like how
> git-commit does it.
> 
> We also give git-pull the passthrough option of --cleanup so that it can
> also take advantage of this change.
> 
> Finally, add testing to ensure that messages are properly cleaned up.
> Note that some newlines that were added to the commit message were
> removed so that if a file were read via -F, it would be copied
> faithfully.
> 
> Signed-off-by: Denton Liu <liu.denton@gmail.com>
> ---
>   Documentation/merge-options.txt |  5 +++
>   builtin/merge.c                 | 31 +++++++++++++----
>   builtin/pull.c                  |  6 ++++
>   t/t7604-merge-custom-message.sh | 61 +++++++++++++++++++++++++++++++++
>   wt-status.c                     | 12 +++++--
>   wt-status.h                     |  1 +
>   6 files changed, 106 insertions(+), 10 deletions(-)
> 
> diff --git a/Documentation/merge-options.txt b/Documentation/merge-options.txt
> index 92a7d936c1..646100ea9a 100644
> --- a/Documentation/merge-options.txt
> +++ b/Documentation/merge-options.txt
> @@ -32,6 +32,11 @@ they run `git merge`. To make it easier to adjust such scripts to the
>   updated behaviour, the environment variable `GIT_MERGE_AUTOEDIT` can be
>   set to `no` at the beginning of them.
>   
> +--cleanup=<mode>::
> +	This option determines how the merge message will be cleaned up
> +	before commiting or being passed on. See linkgit:git-commit[1] for more
> +	details.
> +
>   --ff::
>   	When the merge resolves as a fast-forward, only update the branch
>   	pointer, without creating a merge commit.  This is the default
> diff --git a/builtin/merge.c b/builtin/merge.c
> index 5ce8946d39..4f5fcf5ce9 100644
> --- a/builtin/merge.c
> +++ b/builtin/merge.c
> @@ -38,6 +38,7 @@
>   #include "tag.h"
>   #include "alias.h"
>   #include "commit-reach.h"
> +#include "wt-status.h"
>   
>   #define DEFAULT_TWOHEAD (1<<0)
>   #define DEFAULT_OCTOPUS (1<<1)
> @@ -98,6 +99,9 @@ enum ff_type {
>   
>   static enum ff_type fast_forward = FF_ALLOW;
>   
> +static const char *cleanup_arg;
> +static enum commit_msg_cleanup_mode cleanup_mode;
> +
>   static int option_parse_message(const struct option *opt,
>   				const char *arg, int unset)
>   {
> @@ -249,6 +253,7 @@ static struct option builtin_merge_options[] = {
>   		N_("perform a commit if the merge succeeds (default)")),
>   	OPT_BOOL('e', "edit", &option_edit,
>   		N_("edit message before committing")),
> +	OPT_STRING(0, "cleanup", &cleanup_arg, N_("default"), N_("how to strip spaces and #comments from message")),
>   	OPT_SET_INT(0, "ff", &fast_forward, N_("allow fast-forward (default)"), FF_ALLOW),
>   	OPT_SET_INT_F(0, "ff-only", &fast_forward,
>   		      N_("abort if fast-forward is not possible"),
> @@ -612,6 +617,8 @@ static int git_merge_config(const char *k, const char *v, void *cb)
>   		return git_config_string(&pull_twohead, k, v);
>   	else if (!strcmp(k, "pull.octopus"))
>   		return git_config_string(&pull_octopus, k, v);
> +	else if (!strcmp(k, "commit.cleanup"))
> +		return git_config_string(&cleanup_arg, k, v);
>   	else if (!strcmp(k, "merge.renormalize"))
>   		option_renormalize = git_config_bool(k, v);
>   	else if (!strcmp(k, "merge.ff")) {
> @@ -797,23 +804,32 @@ static void abort_commit(struct commit_list *remoteheads, const char *err_msg)
>   	exit(1);
>   }
>   
> +static const char comment_line_explanation[] =
> +N_("Lines starting with '%c' will be ignored.\n");
> +
>   static const char merge_editor_comment[] =
>   N_("Please enter a commit message to explain why this merge is necessary,\n"
>      "especially if it merges an updated upstream into a topic branch.\n"
>      "\n"
> -   "Lines starting with '%c' will be ignored, and an empty message aborts\n"
> -   "the commit.\n");
> +   "An empty message aborts the commit.\n");
>   
>   static void write_merge_heads(struct commit_list *);
>   static void prepare_to_commit(struct commit_list *remoteheads)
>   {
>   	struct strbuf msg = STRBUF_INIT;
>   	strbuf_addbuf(&msg, &merge_msg);
> -	strbuf_addch(&msg, '\n');
>   	if (squash)
>   		BUG("the control must not reach here under --squash");
> -	if (0 < option_edit)
> -		strbuf_commented_addf(&msg, _(merge_editor_comment), comment_line_char);
> +	if (0 < option_edit) {
> +		strbuf_addch(&msg, '\n');
> +		if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)
> +			wt_status_append_cut_line(&msg);
> +		else
> +			strbuf_commented_addf(&msg, _(comment_line_explanation), comment_line_char);
> +
> +		strbuf_commented_addf(&msg, "\n");
> +		strbuf_commented_addf(&msg, _(merge_editor_comment));

I think this has rearranged the message presented to the user so it now 
reads

Lines starting with '#' will be ignored.
Please enter a commit message to explain why this merge is necessary,
especially if it merges an updated upstream into a topic branch.

An empty message aborts the commit.

To me it read better before, it would be a little more work but I think 
it would be worth preserving the message (especially as this is the 
message people will see unless they specify --cleanup=scissors)

> +	}
>   	if (signoff)
>   		append_signoff(&msg, ignore_non_trailer(msg.buf, msg.len), 0);
>   	write_merge_heads(remoteheads);
> @@ -832,7 +848,7 @@ static void prepare_to_commit(struct commit_list *remoteheads)
>   		abort_commit(remoteheads, NULL);
>   
>   	read_merge_msg(&msg);
> -	strbuf_stripspace(&msg, 0 < option_edit);
> +	cleanup_message(&msg, cleanup_mode, 0);
>   	if (!msg.len)
>   		abort_commit(remoteheads, _("Empty commit message."));
>   	strbuf_release(&merge_msg);
> @@ -880,7 +896,6 @@ static int finish_automerge(struct commit *head,
>   	parents = remoteheads;
>   	if (!head_subsumed || fast_forward == FF_NO)
>   		commit_list_insert(head, &parents);
> -	strbuf_addch(&merge_msg, '\n');
>   	prepare_to_commit(remoteheads);
>   	if (commit_tree(merge_msg.buf, merge_msg.len, result_tree, parents,
>   			&result_commit, NULL, sign_commit))
> @@ -1389,6 +1404,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
>   	if (option_edit < 0)
>   		option_edit = default_edit_option();
>   
> +	cleanup_mode = get_cleanup_mode(cleanup_arg, 0 < option_edit, 1);
> +
>   	if (!use_strategies) {
>   		if (!remoteheads)
>   			; /* already up-to-date */
> diff --git a/builtin/pull.c b/builtin/pull.c
> index 33db889955..3ec7882375 100644
> --- a/builtin/pull.c
> +++ b/builtin/pull.c
> @@ -101,6 +101,7 @@ static char *opt_signoff;
>   static char *opt_squash;
>   static char *opt_commit;
>   static char *opt_edit;
> +static char *opt_cleanup;
>   static char *opt_ff;
>   static char *opt_verify_signatures;
>   static int opt_autostash = -1;
> @@ -168,6 +169,9 @@ static struct option pull_options[] = {
>   	OPT_PASSTHRU(0, "edit", &opt_edit, NULL,
>   		N_("edit message before committing"),
>   		PARSE_OPT_NOARG),
> +	OPT_PASSTHRU(0, "cleanup", &opt_cleanup, NULL,
> +		N_("how to strip spaces and #comments from message"),
> +		PARSE_OPT_NOARG),

cleanup needs to take an argument so PARSE_OPT_NOARG does not look 
right. Also I think it would be bettor from the user's point of view if 
the value of the argument was checked by pull before it does any work 
rather otherwise if they pass in invalid value pull mostly runs and then 
merge errors out at the end.

Best Wishes

Phillip


>   	OPT_PASSTHRU(0, "ff", &opt_ff, NULL,
>   		N_("allow fast-forward"),
>   		PARSE_OPT_NOARG),
> @@ -644,6 +648,8 @@ static int run_merge(void)
>   		argv_array_push(&args, opt_commit);
>   	if (opt_edit)
>   		argv_array_push(&args, opt_edit);
> +	if (opt_cleanup)
> +		argv_array_push(&args, opt_cleanup);
>   	if (opt_ff)
>   		argv_array_push(&args, opt_ff);
>   	if (opt_verify_signatures)
> diff --git a/t/t7604-merge-custom-message.sh b/t/t7604-merge-custom-message.sh
> index 89619cf446..3fcd58eb2c 100755
> --- a/t/t7604-merge-custom-message.sh
> +++ b/t/t7604-merge-custom-message.sh
> @@ -47,4 +47,65 @@ test_expect_success 'merge --log appends to custom message' '
>   	test_cmp exp.log actual
>   '
>   
> +mesg_with_comment_and_newlines='
> +# text
> +
> +'
> +
> +test_expect_success 'prepare file with comment line and trailing newlines'  '
> +	printf "%s" "$mesg_with_comment_and_newlines" >expect
> +'
> +
> +test_expect_success 'cleanup commit messages (verbatim option)' '
> +	git reset --hard c1 &&
> +	git merge --cleanup=verbatim -F expect c2 &&
> +	git cat-file -p HEAD |sed -e "1,/^\$/d" >actual &&
> +	test_cmp expect actual
> +'
> +
> +test_expect_success 'cleanup commit messages (whitespace option)' '
> +	git reset --hard c1 &&
> +	{ echo;echo "# text";echo; } >text &&
> +	echo "# text" >expect &&
> +	git merge --cleanup=whitespace -F text c2 &&
> +	git cat-file -p HEAD |sed -e "1,/^\$/d">actual &&
> +	test_cmp expect actual
> +
> +'
> +
> +test_expect_success 'cleanup merge messages (scissors option)' '
> +	git reset --hard c1 &&
> +	cat >text <<EOF &&
> +
> +# to be kept
> +
> +  # ------------------------ >8 ------------------------
> +# to be kept, too
> +# ------------------------ >8 ------------------------
> +to be removed
> +# ------------------------ >8 ------------------------
> +to be removed, too
> +EOF
> +
> +	cat >expect <<EOF &&
> +# to be kept
> +
> +  # ------------------------ >8 ------------------------
> +# to be kept, too
> +EOF
> +	git merge --cleanup=scissors -e -F text c2 &&
> +	git cat-file -p HEAD |sed -e "1,/^\$/d">actual &&
> +	test_cmp expect actual
> +'
> +
> +test_expect_success 'cleanup commit messages (strip option)' '
> +	git reset --hard c1 &&
> +	{ echo;echo "# text";echo sample;echo; } >text &&
> +	echo sample >expect &&
> +	git merge --cleanup=strip -F text c2 &&
> +	git cat-file -p HEAD |sed -e "1,/^\$/d">actual &&
> +	test_cmp expect actual
> +
> +'
> +
>   test_done
> diff --git a/wt-status.c b/wt-status.c
> index 445a36204a..b81fcd428d 100644
> --- a/wt-status.c
> +++ b/wt-status.c
> @@ -1006,13 +1006,19 @@ size_t wt_status_locate_end(const char *s, size_t len)
>   	return len;
>   }
>   
> -void wt_status_add_cut_line(FILE *fp)
> +void wt_status_append_cut_line(struct strbuf *buf)
>   {
>   	const char *explanation = _("Do not modify or remove the line above.\nEverything below it will be ignored.");
> +
> +	strbuf_commented_addf(buf, "%s", cut_line);
> +	strbuf_add_commented_lines(buf, explanation, strlen(explanation));
> +}
> +
> +void wt_status_add_cut_line(FILE *fp)
> +{
>   	struct strbuf buf = STRBUF_INIT;
>   
> -	fprintf(fp, "%c %s", comment_line_char, cut_line);
> -	strbuf_add_commented_lines(&buf, explanation, strlen(explanation));
> +	wt_status_append_cut_line(&buf);
>   	fputs(buf.buf, fp);
>   	strbuf_release(&buf);
>   }
> diff --git a/wt-status.h b/wt-status.h
> index 3a95975032..64f1ddc9fd 100644
> --- a/wt-status.h
> +++ b/wt-status.h
> @@ -129,6 +129,7 @@ struct wt_status {
>   };
>   
>   size_t wt_status_locate_end(const char *s, size_t len);
> +void wt_status_append_cut_line(struct strbuf *buf);
>   void wt_status_add_cut_line(FILE *fp);
>   void wt_status_prepare(struct repository *r, struct wt_status *s);
>   void wt_status_print(struct wt_status *s);
> 

^ permalink raw reply	[flat|nested] 105+ messages in thread

* Re: [PATCH v7 5/8] merge: cleanup messages like commit
  2019-03-11 10:14                 ` Phillip Wood
@ 2019-03-11 17:00                   ` Eric Sunshine
  0 siblings, 0 replies; 105+ messages in thread
From: Eric Sunshine @ 2019-03-11 17:00 UTC (permalink / raw)
  To: Phillip Wood; +Cc: Denton Liu, Git Mailing List, Junio C Hamano

On Mon, Mar 11, 2019 at 6:14 AM Phillip Wood <phillip.wood123@gmail.com> wrote:
> On 11/03/2019 05:49, Eric Sunshine wrote:
> > On Sun, Mar 10, 2019 at 11:42 PM Denton Liu <liu.denton@gmail.com> wrote:
> >> +       git cat-file -p HEAD |sed -e "1,/^\$/d" >actual &&
> >
> > An earlier patch in this series "fixed" a test with a Git command
> > upstream of a pipe. Yet, this test adds such an instance.
>
> Is it worth worrying about? We're not trying to test cat-file here and
> if it does fail the test will fail as actual will be empty.

git-cat-file could crash _after_ producing the expected output, in
which case we wouldn't learn about the crash at all since the pipe
would swallow it. While it's true that we're not specifically testing
git-cat-file here, with all the recent effort toward moving away from
having Git command upstream of a pipe, I don't think it makes sense to
add new cases. And it doesn't hurt to play it safe here: we might
actually catch a crash in git-cat-file which isn't caught by other
scripts which are genuinely testing that command.

^ permalink raw reply	[flat|nested] 105+ messages in thread

* Re: [PATCH v7 1/8] t7600: clean up 'merge --squash c3 with c7' test
  2019-03-11  3:42             ` [PATCH v7 1/8] t7600: clean up 'merge --squash c3 with c7' test Denton Liu
@ 2019-03-12  1:03               ` Junio C Hamano
  0 siblings, 0 replies; 105+ messages in thread
From: Junio C Hamano @ 2019-03-12  1:03 UTC (permalink / raw)
  To: Denton Liu; +Cc: Git Mailing List, Phillip Wood

Denton Liu <liu.denton@gmail.com> writes:

> -	{
> -		cat <<-EOF
> +	cat >expect <<-EOF &&
>  		Squashed commit of the following:
>  
>  		$(git show -s c7)
> @@ -242,8 +241,8 @@ test_expect_success 'merge --squash c3 with c7' '
>  		# Conflicts:
>  		#	file
>  		EOF
> -	} >expect &&

As you are dedenting the "cat <<-EOF", the body and closing EOF
should also be dedented one level, i.e.

	cat >expect <<-EOF &&
	Squashed commit of the following:
	...
	# Conflicts:
	#	file
	EOF

> -	git cat-file commit HEAD | sed -e '1,/^$/d' >actual &&
> +	git cat-file commit HEAD >tmp &&
> +	sed -e '1,/^$/d' <tmp >actual &&

The intermediary file may want a name better than 'tmp', if it is to
be left behind, but this will do for now.

>  	test_cmp expect actual
>  '

Thanks for the clean-up.

^ permalink raw reply	[flat|nested] 105+ messages in thread

* Re: [PATCH v7 5/8] merge: cleanup messages like commit
  2019-03-11 16:58               ` Phillip Wood
@ 2019-03-12  5:50                 ` Junio C Hamano
  0 siblings, 0 replies; 105+ messages in thread
From: Junio C Hamano @ 2019-03-12  5:50 UTC (permalink / raw)
  To: Phillip Wood; +Cc: Denton Liu, Git Mailing List

Phillip Wood <phillip.wood123@gmail.com> writes:

>> -	if (0 < option_edit)
>> -		strbuf_commented_addf(&msg, _(merge_editor_comment), comment_line_char);
>> +	if (0 < option_edit) {
>> +		strbuf_addch(&msg, '\n');
>> +		if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)
>> +			wt_status_append_cut_line(&msg);
>> +		else
>> +			strbuf_commented_addf(&msg, _(comment_line_explanation), comment_line_char);
>> +
>> +		strbuf_commented_addf(&msg, "\n");
>> +		strbuf_commented_addf(&msg, _(merge_editor_comment));
>
> I think this has rearranged the message presented to the user so it
> now reads
>
> Lines starting with '#' will be ignored.
> Please enter a commit message to explain why this merge is necessary,
> especially if it merges an updated upstream into a topic branch.
>
> An empty message aborts the commit.
>
> To me it read better before, it would be a little more work but I
> think it would be worth preserving the message (especially as this is
> the message people will see unless they specify --cleanup=scissors)

That may be subjective, but unless the new message is vastly and
uncontroversially better (which I do not think it is, with your
objection), I agree that we should avoid churning the message.

>> @@ -168,6 +169,9 @@ static struct option pull_options[] = {
>>   	OPT_PASSTHRU(0, "edit", &opt_edit, NULL,
>>   		N_("edit message before committing"),
>>   		PARSE_OPT_NOARG),
>> +	OPT_PASSTHRU(0, "cleanup", &opt_cleanup, NULL,
>> +		N_("how to strip spaces and #comments from message"),
>> +		PARSE_OPT_NOARG),
>
> cleanup needs to take an argument so PARSE_OPT_NOARG does not look
> right. Also I think it would be bettor from the user's point of view
> if the value of the argument was checked by pull before it does any
> work rather otherwise if they pass in invalid value pull mostly runs
> and then merge errors out at the end.

Both good points.

^ permalink raw reply	[flat|nested] 105+ messages in thread

* Re: [PATCH v7 7/8] sequencer.c: define get_config_from_cleanup
  2019-03-11  3:42             ` [PATCH v7 7/8] sequencer.c: define get_config_from_cleanup Denton Liu
  2019-03-11  6:19               ` Eric Sunshine
@ 2019-03-12  6:29               ` Junio C Hamano
  1 sibling, 0 replies; 105+ messages in thread
From: Junio C Hamano @ 2019-03-12  6:29 UTC (permalink / raw)
  To: Denton Liu; +Cc: Git Mailing List, Phillip Wood

Denton Liu <liu.denton@gmail.com> writes:

> +struct cleanup_config_mapping {
> +    const char *config_value;
> +    enum commit_msg_cleanup_mode editor_cleanup;
> +    enum commit_msg_cleanup_mode no_editor_cleanup;
> +};

Is this code using 4-space indent?  Please don't.  Also, I found
that Eric's comment on naming gave a good suggestion.

Is the cleanup_config_mapping[] array we see below supposed to be
constant, or does it allow further runtime configuration?  I am
assuming the former (i.e. when the user says "default", then
editor_cleanup will always become CLEANUP_ALL and no_editor_cleanup
will always become CLEANUP_SPACE), in which case, I wonder if we can
be more explicit about constness of the table.

> +/* note that we assume that cleanup_config_mapping[0] contains the default settings */

That sounds as if it is bad to make that assumption.  Be more
positive and direct to clearly tell future programmers what rule
they need to honor, e.g.

	/* the 0th element of this array must be the "default" */

> +struct cleanup_config_mapping cleanup_config_mappings[] = {

Do not give a plural name to an array.  Access to an element in a
array "type thing[]" can be written thing[4] and can be more
naturally read as "the fourth thing" (you do not say "the fourth
things") that way.

An exception is when you very often pass around the array as a whole
as one unit of datum across callchains.  

> +	struct cleanup_config_mapping *default_mapping = &cleanup_config_mappings[0];
> +	struct cleanup_config_mapping *current_mapping;
> +
> +	if (!cleanup_arg) {
> +		return use_editor ? default_mapping->editor_cleanup :
> +				    default_mapping->no_editor_cleanup;
> +	}

No need for extra {}.

> +
> +	for (current_mapping = cleanup_config_mappings; current_mapping->config_value; current_mapping++) {
> +		if (!strcmp(cleanup_arg, current_mapping->config_value)) {
> +			return use_editor ? current_mapping->editor_cleanup :
> +					    current_mapping->no_editor_cleanup;
> +		}
> +	}

Ditto.  In addition, perhaps split the for (...) like so:

	for (current_mapping = cleanup_config_mappings;
             current_mapping->config_value;
             current_mapping++)
		if (...)
			return ...;

> +const char *get_config_from_cleanup(enum commit_msg_cleanup_mode cleanup_mode)

static???

Is this really getting "config" from "cleanup"?  It rather smells
backwards i.e. grabbing the clean-up settings from the config system
to me.

> +{
> +	struct cleanup_config_mapping *current_mapping;
> +
> +	for (current_mapping = &cleanup_config_mappings[1]; current_mapping->config_value; current_mapping++) {
> +		if (cleanup_mode == current_mapping->editor_cleanup) {
> +			return current_mapping->config_value;
> +		}
> +	}
> +
> +	BUG(_("invalid cleanup_mode provided"));

Is that a bug (i.e. programming error) or a bad configuration file?
I think you meant the former, but then I do not think we want _()
around the message.  Instead, however, we may want to show the
cleanup_mode that was provided, possibly with the available values
in the .editor_cleanup field of cleanup_config_mapping[] entries.

^ permalink raw reply	[flat|nested] 105+ messages in thread

* Re: [PATCH v7 8/8] cherry-pick/revert: add scissors line on merge conflict
  2019-03-11  3:42             ` [PATCH v7 8/8] cherry-pick/revert: add scissors line on merge conflict Denton Liu
@ 2019-03-12 11:11               ` Phillip Wood
  0 siblings, 0 replies; 105+ messages in thread
From: Phillip Wood @ 2019-03-12 11:11 UTC (permalink / raw)
  To: Denton Liu, Git Mailing List; +Cc: Junio C Hamano

Hi Denton

I've got a couple of small comments, but this looks fine to me

On 11/03/2019 03:42, Denton Liu wrote:
> Fix a bug where the scissors line is placed after the Conflicts:
> section, in the case where a merge conflict occurs and
> commit.cleanup = scissors.
> 
> Signed-off-by: Denton Liu <liu.denton@gmail.com>
> ---
>   Documentation/git-cherry-pick.txt |  7 +++
>   Documentation/git-revert.txt      |  7 +++
>   builtin/merge.c                   |  9 +---
>   builtin/rebase--interactive.c     |  2 +-
>   builtin/revert.c                  |  5 ++
>   sequencer.c                       | 22 +++++---
>   sequencer.h                       |  3 +-
>   t/t3507-cherry-pick-conflict.sh   | 86 +++++++++++++++++++++++++++++++
>   8 files changed, 123 insertions(+), 18 deletions(-)
> 
> diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt
> index b8cfeec67e..b4ff8e136d 100644
> --- a/Documentation/git-cherry-pick.txt
> +++ b/Documentation/git-cherry-pick.txt
> @@ -57,6 +57,13 @@ OPTIONS
>   	With this option, 'git cherry-pick' will let you edit the commit
>   	message prior to committing.
>   
> +--cleanup=<mode>::
> +	This option determines how the commit message will be cleaned up before
> +	being passed on. See linkgit:git-commit[1] for more details. In
> +	addition, if the '<mode>' is given a value of `scissors`, scissors will
> +	be appended to MERGE_MSG before being passed on in the case of a
> +	conflict.

I'm not sure what you mean by before being passed on.

>   -x::
>   	When recording the commit, append a line that says
>   	"(cherry picked from commit ...)" to the original commit
> diff --git a/Documentation/git-revert.txt b/Documentation/git-revert.txt
> index 837707a8fd..bd4ad395a9 100644
> --- a/Documentation/git-revert.txt
> +++ b/Documentation/git-revert.txt
> @@ -66,6 +66,13 @@ more details.
>   	With this option, 'git revert' will not start the commit
>   	message editor.
>   
> +--cleanup=<mode>::
> +	This option determines how the commit message will be cleaned up before
> +	being passed on. See linkgit:git-commit[1] for more details. In
> +	addition, if the '<mode>' is given a value of `scissors`, scissors will
> +	be appended to MERGE_MSG before being passed on in the case of a
> +	conflict.
> +
>   -n::
>   --no-commit::
>   	Usually the command automatically creates some commits with
> diff --git a/builtin/merge.c b/builtin/merge.c
> index b620d4bfcb..671d6a19a4 100644
> --- a/builtin/merge.c
> +++ b/builtin/merge.c
> @@ -923,14 +923,7 @@ static int suggest_conflicts(void)
>   	 * Thus, we will get the cleanup mode which is returned when we _are_ using
>   	 * an editor.
>   	 */
> -	if (get_cleanup_mode(cleanup_arg, 1, 1) == COMMIT_MSG_CLEANUP_SCISSORS) {
> -	    fputc('\n', fp);
> -	    wt_status_add_cut_line(fp);
> -	    /* comments out the newline from append_conflicts_hint */
> -	    fputc(comment_line_char, fp);
> -	}
> -
> -	append_conflicts_hint(&the_index, &msgbuf);
> +	append_conflicts_hint(&the_index, &msgbuf, get_cleanup_mode(cleanup_arg, 1, 1));
>   	fputs(msgbuf.buf, fp);
>   	strbuf_release(&msgbuf);
>   	fclose(fp);
> diff --git a/builtin/rebase--interactive.c b/builtin/rebase--interactive.c
> index 888390f911..cf2151b271 100644
> --- a/builtin/rebase--interactive.c
> +++ b/builtin/rebase--interactive.c
> @@ -199,10 +199,10 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)
>   		OPT_END()
>   	};
>   
> +	opts.action = REPLAY_INTERACTIVE_REBASE;
>   	sequencer_init_config(&opts);
>   	git_config_get_bool("rebase.abbreviatecommands", &abbreviate_commands);
>   
> -	opts.action = REPLAY_INTERACTIVE_REBASE;
>   	opts.allow_ff = 1;
>   	opts.allow_empty = 1;
>   
> diff --git a/builtin/revert.c b/builtin/revert.c
> index a47b53ceaf..e8168e0214 100644
> --- a/builtin/revert.c
> +++ b/builtin/revert.c
> @@ -96,11 +96,13 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
>   {
>   	const char * const * usage_str = revert_or_cherry_pick_usage(opts);
>   	const char *me = action_name(opts);
> +	const char *cleanup_arg = NULL;
>   	int cmd = 0;
>   	struct option base_options[] = {
>   		OPT_CMDMODE(0, "quit", &cmd, N_("end revert or cherry-pick sequence"), 'q'),
>   		OPT_CMDMODE(0, "continue", &cmd, N_("resume revert or cherry-pick sequence"), 'c'),
>   		OPT_CMDMODE(0, "abort", &cmd, N_("cancel revert or cherry-pick sequence"), 'a'),
> +		OPT_STRING(0, "cleanup", &cleanup_arg, N_("default"), N_("how to strip spaces and #comments from message")),

This line is rather long. As you're adding --cleanup to several commands 
it might be an idea to add an OPT_CLEANUP macro to parse-options.h. That 
would ensure the help is consistent across all the commands and save 
repeating the option declaration.

Best Wishes

Phillip

>   		OPT_BOOL('n', "no-commit", &opts->no_commit, N_("don't automatically commit")),
>   		OPT_BOOL('e', "edit", &opts->edit, N_("edit the commit message")),
>   		OPT_NOOP_NOARG('r', NULL),
> @@ -137,6 +139,9 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
>   	if (opts->keep_redundant_commits)
>   		opts->allow_empty = 1;
>   
> +	if (cleanup_arg)
> +		opts->default_msg_cleanup = get_cleanup_mode(cleanup_arg, 1, 1);
> +
>   	/* Check for incompatible command line arguments */
>   	if (cmd) {
>   		char *this_operation;
> diff --git a/sequencer.c b/sequencer.c
> index 5d94e2c865..496554a474 100644
> --- a/sequencer.c
> +++ b/sequencer.c
> @@ -176,6 +176,11 @@ struct cleanup_config_mapping cleanup_config_mappings[] = {
>   	{ NULL, 0, 0 }
>   };
>   
> +static inline int is_rebase_i(const struct replay_opts *opts)
> +{
> +	return opts->action == REPLAY_INTERACTIVE_REBASE;
> +}
> +
>   static int git_sequencer_config(const char *k, const char *v, void *cb)
>   {
>   	struct replay_opts *opts = cb;
> @@ -188,7 +193,7 @@ static int git_sequencer_config(const char *k, const char *v, void *cb)
>   		if (status)
>   			return status;
>   
> -		opts->default_msg_cleanup = get_cleanup_mode(s, 0, 0);
> +		opts->default_msg_cleanup = get_cleanup_mode(s, !is_rebase_i(opts), 0);
>   
>   		free((char *)s);
>   		return status;
> @@ -212,11 +217,6 @@ void sequencer_init_config(struct replay_opts *opts)
>   	git_config(git_sequencer_config, opts);
>   }
>   
> -static inline int is_rebase_i(const struct replay_opts *opts)
> -{
> -	return opts->action == REPLAY_INTERACTIVE_REBASE;
> -}
> -
>   static const char *get_dir(const struct replay_opts *opts)
>   {
>   	if (is_rebase_i(opts))
> @@ -557,10 +557,16 @@ const char *get_config_from_cleanup(enum commit_msg_cleanup_mode cleanup_mode)
>   }
>   
>   void append_conflicts_hint(struct index_state *istate,
> -			   struct strbuf *msgbuf)
> +		struct strbuf *msgbuf, enum commit_msg_cleanup_mode cleanup_mode)
>   {
>   	int i;
>   
> +	if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS) {
> +		strbuf_addch(msgbuf, '\n');
> +		wt_status_append_cut_line(msgbuf);
> +		strbuf_addch(msgbuf, comment_line_char);
> +	}
> +
>   	strbuf_addch(msgbuf, '\n');
>   	strbuf_commented_addf(msgbuf, "Conflicts:\n");
>   	for (i = 0; i < istate->cache_nr;) {
> @@ -628,7 +634,7 @@ static int do_recursive_merge(struct repository *r,
>   			_(action_name(opts)));
>   
>   	if (!clean)
> -		append_conflicts_hint(r->index, msgbuf);
> +		append_conflicts_hint(r->index, msgbuf, opts->default_msg_cleanup);
>   
>   	return !clean;
>   }
> diff --git a/sequencer.h b/sequencer.h
> index e3c1f44807..95ff9db508 100644
> --- a/sequencer.h
> +++ b/sequencer.h
> @@ -115,7 +115,8 @@ int rearrange_squash(struct repository *r);
>    */
>   void append_signoff(struct strbuf *msgbuf, size_t ignore_footer, unsigned flag);
>   
> -void append_conflicts_hint(struct index_state *istate, struct strbuf *msgbuf);
> +void append_conflicts_hint(struct index_state *istate,
> +		struct strbuf *msgbuf, enum commit_msg_cleanup_mode cleanup_mode);
>   enum commit_msg_cleanup_mode get_cleanup_mode(const char *cleanup_arg,
>   	int use_editor, int die_on_error);
>   const char *get_config_from_cleanup(enum commit_msg_cleanup_mode cleanup_mode);
> diff --git a/t/t3507-cherry-pick-conflict.sh b/t/t3507-cherry-pick-conflict.sh
> index 74ff925526..c3894ca9d6 100755
> --- a/t/t3507-cherry-pick-conflict.sh
> +++ b/t/t3507-cherry-pick-conflict.sh
> @@ -189,6 +189,46 @@ test_expect_success 'failed cherry-pick registers participants in index' '
>   	test_cmp expected actual
>   '
>   
> +test_expect_success \
> +	'cherry-pick conflict, ensure commit.cleanup = scissors places scissors line properly' '
> +	pristine_detach initial &&
> +	git config commit.cleanup scissors &&
> +	cat <<-EOF >expected &&
> +		picked
> +
> +		# ------------------------ >8 ------------------------
> +		# Do not modify or remove the line above.
> +		# Everything below it will be ignored.
> +		#
> +		# Conflicts:
> +		#	foo
> +		EOF
> +
> +	test_must_fail git cherry-pick picked &&
> +
> +	test_i18ncmp expected .git/MERGE_MSG
> +'
> +
> +test_expect_success \
> +	'cherry-pick conflict, ensure cleanup=scissors places scissors line properly' '
> +	pristine_detach initial &&
> +	git config --unset commit.cleanup &&
> +	cat <<-EOF >expected &&
> +		picked
> +
> +		# ------------------------ >8 ------------------------
> +		# Do not modify or remove the line above.
> +		# Everything below it will be ignored.
> +		#
> +		# Conflicts:
> +		#	foo
> +		EOF
> +
> +	test_must_fail git cherry-pick --cleanup=scissors picked &&
> +
> +	test_i18ncmp expected .git/MERGE_MSG
> +'
> +
>   test_expect_success 'failed cherry-pick describes conflict in work tree' '
>   	pristine_detach initial &&
>   	cat <<-EOF >expected &&
> @@ -335,6 +375,52 @@ test_expect_success 'revert conflict, diff3 -m style' '
>   	test_cmp expected actual
>   '
>   
> +test_expect_success \
> +	'revert conflict, ensure commit.cleanup = scissors places scissors line properly' '
> +	pristine_detach initial &&
> +	git config commit.cleanup scissors &&
> +	cat >expected <<-EOF &&
> +		Revert "picked"
> +
> +		This reverts commit OBJID.
> +
> +		# ------------------------ >8 ------------------------
> +		# Do not modify or remove the line above.
> +		# Everything below it will be ignored.
> +		#
> +		# Conflicts:
> +		#	foo
> +		EOF
> +
> +	test_must_fail git revert picked &&
> +
> +	sed "s/$OID_REGEX/OBJID/" .git/MERGE_MSG >actual &&
> +	test_i18ncmp expected actual
> +'
> +
> +test_expect_success \
> +	'revert conflict, ensure cleanup=scissors places scissors line properly' '
> +	pristine_detach initial &&
> +	git config --unset commit.cleanup &&
> +	cat >expected <<-EOF &&
> +		Revert "picked"
> +
> +		This reverts commit OBJID.
> +
> +		# ------------------------ >8 ------------------------
> +		# Do not modify or remove the line above.
> +		# Everything below it will be ignored.
> +		#
> +		# Conflicts:
> +		#	foo
> +		EOF
> +
> +	test_must_fail git revert --cleanup=scissors picked &&
> +
> +	sed "s/$OID_REGEX/OBJID/" .git/MERGE_MSG >actual &&
> +	test_i18ncmp expected actual
> +'
> +
>   test_expect_success 'failed cherry-pick does not forget -s' '
>   	pristine_detach initial &&
>   	test_must_fail git cherry-pick -s picked &&
> 

^ permalink raw reply	[flat|nested] 105+ messages in thread

* [PATCH v8 00/11] Fix scissors bug during conflict
  2019-03-11  3:42           ` [PATCH v7 0/8] Fix scissors bug during conflict Denton Liu
                               ` (8 preceding siblings ...)
  2019-03-11  6:44             ` [PATCH v7 0/8] Fix scissors bug during conflict Junio C Hamano
@ 2019-03-17 10:15             ` Denton Liu
  2019-03-17 10:15               ` [PATCH v8 01/11] t7600: clean up style Denton Liu
                                 ` (12 more replies)
  9 siblings, 13 replies; 105+ messages in thread
From: Denton Liu @ 2019-03-17 10:15 UTC (permalink / raw)
  To: Git Mailing List
  Cc: Denton Liu, Eric Sunshine, Junio C Hamano, Phillip Wood,
	Ramsay Jones, SZEDER Gábor

Sorry for taking so long to do a reroll, I've been pretty busy this week
and I've only been able to find the time now.

Previous discussion on the cherry-pick/revert changes can be found here[1].

Changes since revert/cherry-pick v3:

* Rebased on top of latest master
* Reordered and squashed patches
* Added populate_opts_cb and save_opts to save default_msg_cleanup at Phillip's suggestion

Changes since v7:

* Cleaned up more tests according to Eric's advice (and added some more cleanup patches!)
* Clarify meaning of "passed on" in documentation
* Consolidate common options into OPT_CLEANUP macro in parse-options.h
* Fix space indent to tabs in sequencer.c
* Shorten variable names for readability
* Make comment about 0th element in array being default more assertive
* Remove unnecessary braces around if/for statements
* Lowercase warning/error messages
* Unmark BUG messages for translation
* Rename get_config_from_cleanup -> describe_cleanup_mode
* Squashed in Ramsay's static patch

[1]: https://public-inbox.org/git/cover.1551867827.git.liu.denton@gmail.com/T/#u


Denton Liu (11):
  t7600: clean up style
  t3507: cleanup space after redirection operators
  t7604: refactor out Git commands upstream of pipe
  t7502: clean up test style
  commit: extract cleanup_mode functions to sequencer
  parse-options.h: extract common --cleanup option
  sequencer.c: remove duplicate code
  merge: cleanup messages like commit
  merge: add scissors line on merge conflict
  sequencer.c: define describe_cleanup_mode
  cherry-pick/revert: add scissors line on merge conflict

 Documentation/git-cherry-pick.txt |   7 ++
 Documentation/git-revert.txt      |   7 ++
 Documentation/merge-options.txt   |   7 ++
 builtin/commit.c                  |  47 +++++-------
 builtin/merge.c                   |  40 ++++++++--
 builtin/pull.c                    |   6 ++
 builtin/rebase--interactive.c     |   2 +-
 builtin/revert.c                  |   5 ++
 builtin/tag.c                     |   3 +-
 parse-options.h                   |   1 +
 sequencer.c                       |  97 +++++++++++++++++++-----
 sequencer.h                       |   9 ++-
 t/t3507-cherry-pick-conflict.sh   | 120 +++++++++++++++++++++++++-----
 t/t7502-commit-porcelain.sh       | 100 +++++++++++++++----------
 t/t7600-merge.sh                  |  70 ++++++++++++++---
 t/t7604-merge-custom-message.sh   |  75 ++++++++++++++++++-
 wt-status.c                       |  12 ++-
 wt-status.h                       |   1 +
 18 files changed, 478 insertions(+), 131 deletions(-)

Interdiff against v7:
diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt
index b4ff8e136d..2601e1868e 100644
--- a/Documentation/git-cherry-pick.txt
+++ b/Documentation/git-cherry-pick.txt
@@ -60,9 +60,9 @@ OPTIONS
 --cleanup=<mode>::
 	This option determines how the commit message will be cleaned up before
 	being passed on. See linkgit:git-commit[1] for more details. In
-	addition, if the '<mode>' is given a value of `scissors`, scissors will
-	be appended to MERGE_MSG before being passed on in the case of a
-	conflict.
+	particular, if the '<mode>' is given a value of `scissors`, scissors
+	will be appended to `MERGE_MSG` before being passed on to the commit
+	machinery in the case of a conflict.
 
 -x::
 	When recording the commit, append a line that says
diff --git a/Documentation/git-revert.txt b/Documentation/git-revert.txt
index bd4ad395a9..cabeb9df2c 100644
--- a/Documentation/git-revert.txt
+++ b/Documentation/git-revert.txt
@@ -69,9 +69,9 @@ more details.
 --cleanup=<mode>::
 	This option determines how the commit message will be cleaned up before
 	being passed on. See linkgit:git-commit[1] for more details. In
-	addition, if the '<mode>' is given a value of `scissors`, scissors will
-	be appended to MERGE_MSG before being passed on in the case of a
-	conflict.
+	particular, if the '<mode>' is given a value of `scissors`, scissors
+	will be appended to `MERGE_MSG` before being passed on to the commit
+	machinery in the case of a conflict.
 
 -n::
 --no-commit::
diff --git a/Documentation/merge-options.txt b/Documentation/merge-options.txt
index c7b889d6f5..405e16c617 100644
--- a/Documentation/merge-options.txt
+++ b/Documentation/merge-options.txt
@@ -36,8 +36,8 @@ set to `no` at the beginning of them.
 	This option determines how the merge message will be cleaned up
 	before commiting or being passed on. See linkgit:git-commit[1] for more
 	details. In addition, if the '<mode>' is given a value of `scissors`,
-	scissors will be appended to MERGE_MSG before being passed on in the
-	case of a merge conflict.
+	scissors will be appended to `MERGE_MSG` before being passed on to the
+	commit machinery in the case of a merge conflict.
 
 --ff::
 	When the merge resolves as a fast-forward, only update the branch
diff --git a/builtin/commit.c b/builtin/commit.c
index d8c4626a68..b9159c2e7b 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -1483,7 +1483,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
 		OPT_BOOL('s', "signoff", &signoff, N_("add Signed-off-by:")),
 		OPT_FILENAME('t', "template", &template_file, N_("use specified template file")),
 		OPT_BOOL('e', "edit", &edit_flag, N_("force edit of commit")),
-		OPT_STRING(0, "cleanup", &cleanup_arg, N_("default"), N_("how to strip spaces and #comments from message")),
+		OPT_CLEANUP(&cleanup_arg),
 		OPT_BOOL(0, "status", &include_status, N_("include status in commit message template")),
 		{ OPTION_STRING, 'S', "gpg-sign", &sign_commit, N_("key-id"),
 		  N_("GPG sign commit"), PARSE_OPT_OPTARG, NULL, (intptr_t) "" },
diff --git a/builtin/merge.c b/builtin/merge.c
index 671d6a19a4..90c64346e9 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -253,7 +253,7 @@ static struct option builtin_merge_options[] = {
 		N_("perform a commit if the merge succeeds (default)")),
 	OPT_BOOL('e', "edit", &option_edit,
 		N_("edit message before committing")),
-	OPT_STRING(0, "cleanup", &cleanup_arg, N_("default"), N_("how to strip spaces and #comments from message")),
+	OPT_CLEANUP(&cleanup_arg),
 	OPT_SET_INT(0, "ff", &fast_forward, N_("allow fast-forward (default)"), FF_ALLOW),
 	OPT_SET_INT_F(0, "ff-only", &fast_forward,
 		      N_("abort if fast-forward is not possible"),
diff --git a/builtin/pull.c b/builtin/pull.c
index 3ec7882375..292c1dac27 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -171,7 +171,7 @@ static struct option pull_options[] = {
 		PARSE_OPT_NOARG),
 	OPT_PASSTHRU(0, "cleanup", &opt_cleanup, NULL,
 		N_("how to strip spaces and #comments from message"),
-		PARSE_OPT_NOARG),
+		0),
 	OPT_PASSTHRU(0, "ff", &opt_ff, NULL,
 		N_("allow fast-forward"),
 		PARSE_OPT_NOARG),
diff --git a/builtin/revert.c b/builtin/revert.c
index e8168e0214..41e7392c24 100644
--- a/builtin/revert.c
+++ b/builtin/revert.c
@@ -102,7 +102,7 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
 		OPT_CMDMODE(0, "quit", &cmd, N_("end revert or cherry-pick sequence"), 'q'),
 		OPT_CMDMODE(0, "continue", &cmd, N_("resume revert or cherry-pick sequence"), 'c'),
 		OPT_CMDMODE(0, "abort", &cmd, N_("cancel revert or cherry-pick sequence"), 'a'),
-		OPT_STRING(0, "cleanup", &cleanup_arg, N_("default"), N_("how to strip spaces and #comments from message")),
+		OPT_CLEANUP(&cleanup_arg),
 		OPT_BOOL('n', "no-commit", &opts->no_commit, N_("don't automatically commit")),
 		OPT_BOOL('e', "edit", &opts->edit, N_("edit the commit message")),
 		OPT_NOOP_NOARG('r', NULL),
diff --git a/builtin/tag.c b/builtin/tag.c
index 02f6bd1279..a3870fbdba 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -397,8 +397,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
 		OPT_FILENAME('F', "file", &msgfile, N_("read message from file")),
 		OPT_BOOL('e', "edit", &edit_flag, N_("force edit of tag message")),
 		OPT_BOOL('s', "sign", &opt.sign, N_("annotated and GPG-signed tag")),
-		OPT_STRING(0, "cleanup", &cleanup_arg, N_("mode"),
-			N_("how to strip spaces and #comments from message")),
+		OPT_CLEANUP(&cleanup_arg),
 		OPT_STRING('u', "local-user", &keyid, N_("key-id"),
 					N_("use another key to sign the tag")),
 		OPT__FORCE(&force, N_("replace the tag if exists"), 0),
diff --git a/parse-options.h b/parse-options.h
index 7d83e2971d..85faaee390 100644
--- a/parse-options.h
+++ b/parse-options.h
@@ -303,5 +303,6 @@ int parse_opt_passthru_argv(const struct option *, const char *, int);
 #define OPT_NO_CONTAINS(v, h) _OPT_CONTAINS_OR_WITH("no-contains", v, h, PARSE_OPT_NONEG)
 #define OPT_WITH(v, h) _OPT_CONTAINS_OR_WITH("with", v, h, PARSE_OPT_HIDDEN | PARSE_OPT_NONEG)
 #define OPT_WITHOUT(v, h) _OPT_CONTAINS_OR_WITH("without", v, h, PARSE_OPT_HIDDEN | PARSE_OPT_NONEG)
+#define OPT_CLEANUP(v) OPT_STRING(0, "cleanup", v, N_("mode"), N_("how to strip spaces and #comments from message"))
 
 #endif
diff --git a/sequencer.c b/sequencer.c
index 496554a474..ea4687c3da 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -161,13 +161,13 @@ static GIT_PATH_FUNC(rebase_path_allow_rerere_autoupdate, "rebase-merge/allow_re
 static GIT_PATH_FUNC(rebase_path_reschedule_failed_exec, "rebase-merge/reschedule-failed-exec")
 
 struct cleanup_config_mapping {
-    const char *config_value;
-    enum commit_msg_cleanup_mode editor_cleanup;
-    enum commit_msg_cleanup_mode no_editor_cleanup;
+	const char *value;
+	enum commit_msg_cleanup_mode editor;
+	enum commit_msg_cleanup_mode no_editor;
 };
 
-/* note that we assume that cleanup_config_mapping[0] contains the default settings */
-struct cleanup_config_mapping cleanup_config_mappings[] = {
+/* the 0th element of this array must be the "default" */
+static struct cleanup_config_mapping cleanup_config_mapping[] = {
 	{ "default", COMMIT_MSG_CLEANUP_ALL, COMMIT_MSG_CLEANUP_SPACE },
 	{ "verbatim", COMMIT_MSG_CLEANUP_NONE, COMMIT_MSG_CLEANUP_NONE },
 	{ "whitespace", COMMIT_MSG_CLEANUP_SPACE, COMMIT_MSG_CLEANUP_SPACE },
@@ -520,40 +520,35 @@ static int fast_forward_to(struct repository *r,
 enum commit_msg_cleanup_mode get_cleanup_mode(const char *cleanup_arg,
 	int use_editor, int die_on_error)
 {
-	struct cleanup_config_mapping *default_mapping = &cleanup_config_mappings[0];
-	struct cleanup_config_mapping *current_mapping;
+	struct cleanup_config_mapping *def = &cleanup_config_mapping[0];
+	struct cleanup_config_mapping *p;
 
-	if (!cleanup_arg) {
-		return use_editor ? default_mapping->editor_cleanup :
-				    default_mapping->no_editor_cleanup;
-	}
+	if (!cleanup_arg)
+		return use_editor ? def->editor :
+				    def->no_editor;
 
-	for (current_mapping = cleanup_config_mappings; current_mapping->config_value; current_mapping++) {
-		if (!strcmp(cleanup_arg, current_mapping->config_value)) {
-			return use_editor ? current_mapping->editor_cleanup :
-					    current_mapping->no_editor_cleanup;
-		}
-	}
+	for (p = cleanup_config_mapping; p->value; p++)
+		if (!strcmp(cleanup_arg, p->value))
+			return use_editor ? p->editor :
+					    p->no_editor;
 
 	if (!die_on_error) {
-		warning(_("Invalid cleanup mode %s, falling back to default"), cleanup_arg);
-		return use_editor ? default_mapping->editor_cleanup :
-				    default_mapping->no_editor_cleanup;
+		warning(_("invalid cleanup mode %s, falling back to default"), cleanup_arg);
+		return use_editor ? def->editor :
+				    def->no_editor;
 	} else
-		die(_("Invalid cleanup mode %s"), cleanup_arg);
+		die(_("invalid cleanup mode %s"), cleanup_arg);
 }
 
-const char *get_config_from_cleanup(enum commit_msg_cleanup_mode cleanup_mode)
+static const char *describe_cleanup_mode(enum commit_msg_cleanup_mode cleanup_mode)
 {
-	struct cleanup_config_mapping *current_mapping;
+	struct cleanup_config_mapping *curr;
 
-	for (current_mapping = &cleanup_config_mappings[1]; current_mapping->config_value; current_mapping++) {
-		if (cleanup_mode == current_mapping->editor_cleanup) {
-			return current_mapping->config_value;
-		}
-	}
+	for (curr = &cleanup_config_mapping[1]; curr->value; curr++)
+		if (cleanup_mode == curr->editor)
+			return curr->value;
 
-	BUG(_("invalid cleanup_mode provided"));
+	BUG("invalid cleanup_mode provided (%d)", cleanup_mode);
 }
 
 void append_conflicts_hint(struct index_state *istate,
@@ -2796,7 +2791,7 @@ static int save_opts(struct replay_opts *opts)
 						     "true" : "false");
 
 	res |= git_config_set_in_file_gently(opts_file, "options.default-msg-cleanup",
-					     get_config_from_cleanup(opts->default_msg_cleanup));
+					     describe_cleanup_mode(opts->default_msg_cleanup));
 	return res;
 }
 
diff --git a/sequencer.h b/sequencer.h
index 95ff9db508..830d8232f6 100644
--- a/sequencer.h
+++ b/sequencer.h
@@ -119,7 +119,6 @@ void append_conflicts_hint(struct index_state *istate,
 		struct strbuf *msgbuf, enum commit_msg_cleanup_mode cleanup_mode);
 enum commit_msg_cleanup_mode get_cleanup_mode(const char *cleanup_arg,
 	int use_editor, int die_on_error);
-const char *get_config_from_cleanup(enum commit_msg_cleanup_mode cleanup_mode);
 
 void cleanup_message(struct strbuf *msgbuf,
 	enum commit_msg_cleanup_mode cleanup_mode, int verbose);
diff --git a/t/t7502-commit-porcelain.sh b/t/t7502-commit-porcelain.sh
index ca4a740da0..f035e4a507 100755
--- a/t/t7502-commit-porcelain.sh
+++ b/t/t7502-commit-porcelain.sh
@@ -16,7 +16,9 @@ commit_msg_is () {
 # Arguments: [<prefix] [<commit message>] [<commit options>]
 check_summary_oneline() {
 	test_tick &&
-	git commit ${3+"$3"} -m "$2" | head -1 > act &&
+	git commit ${3+"$3"} -m "$2" >act &&
+	head -1 <act >tmp &&
+	mv tmp act &&
 
 	# branch name
 	SUMMARY_PREFIX="$(git name-rev --name-only HEAD)" &&
@@ -68,7 +70,7 @@ test_expect_success 'output summary format for merges' '
 	git checkout recursive-a &&
 	test_must_fail git merge recursive-b &&
 	# resolve the conflict
-	echo commit-a > file1 &&
+	echo commit-a >file1 &&
 	git add file1 &&
 	check_summary_oneline "" "Merge"
 '
@@ -142,8 +144,8 @@ test_expect_success 'sign off' '
 	>positive &&
 	git add positive &&
 	git commit -s -m "thank you" &&
-	actual=$(git cat-file commit HEAD | sed -ne "s/Signed-off-by: //p") &&
-	expected=$(git var GIT_COMMITTER_IDENT | sed -e "s/>.*/>/") &&
+	actual=$(git cat-file commit HEAD >tmp && sed -ne "s/Signed-off-by: //p" <tmp && rm tmp) &&
+	expected=$(git var GIT_COMMITTER_IDENT >tmp && sed -e "s/>.*/>/" <tmp && rm tmp) &&
 	test "z$actual" = "z$expected"
 
 '
@@ -153,8 +155,8 @@ test_expect_success 'multiple -m' '
 	>negative &&
 	git add negative &&
 	git commit -m "one" -m "two" -m "three" &&
-	actual=$(git cat-file commit HEAD | sed -e "1,/^\$/d") &&
-	expected=$(echo one; echo; echo two; echo; echo three) &&
+	actual=$(git cat-file commit HEAD >tmp && sed -e "1,/^\$/d" <tmp && rm tmp) &&
+	expected=$(test_write_lines "one" "" "two" "" "three") &&
 	test "z$actual" = "z$expected"
 
 '
@@ -163,7 +165,9 @@ test_expect_success 'verbose' '
 
 	echo minus >negative &&
 	git add negative &&
-	git status -v | sed -ne "/^diff --git /p" >actual &&
+	git status -v >actual &&
+	sed -ne "/^diff --git /p" <actual >tmp &&
+	mv tmp actual &&
 	echo "diff --git a/negative b/negative" >expect &&
 	test_cmp expect actual
 
@@ -189,7 +193,9 @@ test_expect_success 'cleanup commit messages (verbatim option,-t)' '
 
 	echo >>negative &&
 	git commit --cleanup=verbatim --no-status -t expect -a &&
-	git cat-file -p HEAD |sed -e "1,/^\$/d" >actual &&
+	git cat-file -p HEAD >actual &&
+	sed -e "1,/^\$/d" <actual >tmp &&
+	mv tmp actual &&
 	test_cmp expect actual
 
 '
@@ -198,7 +204,9 @@ test_expect_success 'cleanup commit messages (verbatim option,-F)' '
 
 	echo >>negative &&
 	git commit --cleanup=verbatim -F expect -a &&
-	git cat-file -p HEAD |sed -e "1,/^\$/d">actual &&
+	git cat-file -p HEAD >actual &&
+	sed -e "1,/^\$/d" <actual >tmp &&
+	mv tmp actual &&
 	test_cmp expect actual
 
 '
@@ -207,7 +215,9 @@ test_expect_success 'cleanup commit messages (verbatim option,-m)' '
 
 	echo >>negative &&
 	git commit --cleanup=verbatim -m "$mesg_with_comment_and_newlines" -a &&
-	git cat-file -p HEAD |sed -e "1,/^\$/d">actual &&
+	git cat-file -p HEAD >actual &&
+	sed -e "1,/^\$/d" <actual >tmp &&
+	mv tmp actual &&
 	test_cmp expect actual
 
 '
@@ -215,10 +225,12 @@ test_expect_success 'cleanup commit messages (verbatim option,-m)' '
 test_expect_success 'cleanup commit messages (whitespace option,-F)' '
 
 	echo >>negative &&
-	{ echo;echo "# text";echo; } >text &&
+	test_write_lines "" "# text" "" >text &&
 	echo "# text" >expect &&
 	git commit --cleanup=whitespace -F text -a &&
-	git cat-file -p HEAD |sed -e "1,/^\$/d">actual &&
+	git cat-file -p HEAD >actual &&
+	sed -e "1,/^\$/d" <actual >tmp &&
+	mv tmp actual &&
 	test_cmp expect actual
 
 '
@@ -226,48 +238,54 @@ test_expect_success 'cleanup commit messages (whitespace option,-F)' '
 test_expect_success 'cleanup commit messages (scissors option,-F,-e)' '
 
 	echo >>negative &&
-	cat >text <<EOF &&
+	cat >text <<-\EOF &&
 
-# to be kept
+	# to be kept
 
-  # ------------------------ >8 ------------------------
-# to be kept, too
-# ------------------------ >8 ------------------------
-to be removed
-# ------------------------ >8 ------------------------
-to be removed, too
-EOF
+	  # ------------------------ >8 ------------------------
+	# to be kept, too
+	# ------------------------ >8 ------------------------
+	to be removed
+	# ------------------------ >8 ------------------------
+	to be removed, too
+	EOF
 
-	cat >expect <<EOF &&
-# to be kept
+	cat >expect <<-\EOF &&
+	# to be kept
 
-  # ------------------------ >8 ------------------------
-# to be kept, too
-EOF
+	  # ------------------------ >8 ------------------------
+	# to be kept, too
+	EOF
 	git commit --cleanup=scissors -e -F text -a &&
-	git cat-file -p HEAD |sed -e "1,/^\$/d">actual &&
+	git cat-file -p HEAD >actual &&
+	sed -e "1,/^\$/d" <actual >tmp &&
+	mv tmp actual &&
 	test_cmp expect actual
 '
 
 test_expect_success 'cleanup commit messages (scissors option,-F,-e, scissors on first line)' '
 
 	echo >>negative &&
-	cat >text <<EOF &&
-# ------------------------ >8 ------------------------
-to be removed
-EOF
+	cat >text <<-\EOF &&
+	# ------------------------ >8 ------------------------
+	to be removed
+	EOF
 	git commit --cleanup=scissors -e -F text -a --allow-empty-message &&
-	git cat-file -p HEAD |sed -e "1,/^\$/d">actual &&
+	git cat-file -p HEAD >actual &&
+	sed -e "1,/^\$/d" <actual >tmp &&
+	mv tmp actual &&
 	test_must_be_empty actual
 '
 
 test_expect_success 'cleanup commit messages (strip option,-F)' '
 
 	echo >>negative &&
-	{ echo;echo "# text";echo sample;echo; } >text &&
+	test_write_lines "" "# text" "sample" "" >text &&
 	echo sample >expect &&
 	git commit --cleanup=strip -F text -a &&
-	git cat-file -p HEAD |sed -e "1,/^\$/d">actual &&
+	git cat-file -p HEAD >actual &&
+	sed -e "1,/^\$/d" <actual >tmp &&
+	mv tmp actual &&
 	test_cmp expect actual
 
 '
@@ -275,7 +293,7 @@ test_expect_success 'cleanup commit messages (strip option,-F)' '
 test_expect_success 'cleanup commit messages (strip option,-F,-e)' '
 
 	echo >>negative &&
-	{ echo;echo sample;echo; } >text &&
+	test_write_lines "" "sample" "" >text &&
 	git commit -e -F text -a &&
 	head -n 4 .git/COMMIT_EDITMSG >actual
 '
@@ -387,7 +405,7 @@ test_expect_success AUTOIDENT 'message shows committer when it is automatic' '
 '
 
 write_script .git/FAKE_EDITOR <<EOF
-echo editor started > "$(pwd)/.git/result"
+echo editor started >"$(pwd)/.git/result"
 exit 0
 EOF
 
@@ -455,7 +473,7 @@ EOF
 test_expect_success EXECKEEPSPID 'a SIGTERM should break locks' '
 	echo >>negative &&
 	! "$SHELL_PATH" -c '\''
-	  echo kill -TERM $$ >> .git/FAKE_EDITOR
+	  echo kill -TERM $$ >>.git/FAKE_EDITOR
 	  GIT_EDITOR=.git/FAKE_EDITOR
 	  export GIT_EDITOR
 	  exec git commit -a'\'' &&
@@ -471,7 +489,9 @@ test_expect_success 'Hand committing of a redundant merge removes dups' '
 	test_must_fail git merge second master &&
 	git checkout master g &&
 	EDITOR=: git commit -a &&
-	git cat-file commit HEAD | sed -n -e "s/^parent //p" -e "/^$/q" >actual &&
+	git cat-file commit HEAD >actual &&
+	sed -n -e "s/^parent //p" -e "/^$/q" <actual >tmp &&
+	mv tmp actual &&
 	test_cmp expect actual
 
 '
@@ -480,7 +500,9 @@ test_expect_success 'A single-liner subject with a token plus colon is not a foo
 
 	git reset --hard &&
 	git commit -s -m "hello: kitty" --allow-empty &&
-	git cat-file commit HEAD | sed -e "1,/^$/d" >actual &&
+	git cat-file commit HEAD >actual &&
+	sed -e "1,/^$/d" <actual >tmp &&
+	mv tmp actual &&
 	test_line_count = 3 actual
 
 '
diff --git a/t/t7600-merge.sh b/t/t7600-merge.sh
index 2cb57e5878..ed11b08db2 100755
--- a/t/t7600-merge.sh
+++ b/t/t7600-merge.sh
@@ -234,15 +234,16 @@ test_expect_success 'merge --squash c3 with c7' '
 	git commit --no-edit -a &&
 
 	cat >expect <<-EOF &&
-		Squashed commit of the following:
+	Squashed commit of the following:
 
-		$(git show -s c7)
+	$(git show -s c7)
 
-		# Conflicts:
-		#	file
-		EOF
-	git cat-file commit HEAD >tmp &&
-	sed -e '1,/^$/d' <tmp >actual &&
+	# Conflicts:
+	#	file
+	EOF
+	git cat-file commit HEAD >actual &&
+	sed -e '1,/^$/d' <actual >tmp &&
+	mv tmp actual &&
 	test_cmp expect actual
 '
 
@@ -253,18 +254,19 @@ test_expect_success 'merge c3 with c7 with commit.cleanup = scissors' '
 	cat result.9z >file &&
 	git commit --no-edit -a &&
 
-	cat >expect <<-EOF &&
-		Merge tag '"'"'c7'"'"'
-
-		# ------------------------ >8 ------------------------
-		# Do not modify or remove the line above.
-		# Everything below it will be ignored.
-		#
-		# Conflicts:
-		#	file
-		EOF
-	git cat-file commit HEAD >tmp &&
-	sed -e '1,/^$/d' <tmp >actual &&
+	cat >expect <<-\EOF &&
+	Merge tag '"'"'c7'"'"'
+
+	# ------------------------ >8 ------------------------
+	# Do not modify or remove the line above.
+	# Everything below it will be ignored.
+	#
+	# Conflicts:
+	#	file
+	EOF
+	git cat-file commit HEAD >actual &&
+	sed -e '1,/^$/d' <actual >tmp &&
+	mv tmp actual &&
 	test_i18ncmp expect actual
 '
 
@@ -276,19 +278,20 @@ test_expect_success 'merge c3 with c7 with --squash commit.cleanup = scissors' '
 	git commit --no-edit -a &&
 
 	cat >expect <<-EOF &&
-		Squashed commit of the following:
-
-		$(git show -s c7)
-
-		# ------------------------ >8 ------------------------
-		# Do not modify or remove the line above.
-		# Everything below it will be ignored.
-		#
-		# Conflicts:
-		#	file
-		EOF
-	git cat-file commit HEAD >tmp &&
-	sed -e '1,/^$/d' <tmp >actual &&
+	Squashed commit of the following:
+
+	$(git show -s c7)
+
+	# ------------------------ >8 ------------------------
+	# Do not modify or remove the line above.
+	# Everything below it will be ignored.
+	#
+	# Conflicts:
+	#	file
+	EOF
+	git cat-file commit HEAD >actual &&
+	sed -e '1,/^$/d' <actual >tmp &&
+	mv tmp actual &&
 	test_i18ncmp expect actual
 '
 
@@ -728,7 +731,7 @@ cat >editor <<\EOF
 	cat <"$1"
 ) >"$1.tmp" && mv "$1.tmp" "$1"
 # strip comments and blank lines from end of message
-sed -e '/^#/d' < "$1" | sed -e :a -e '/^\n*$/{$d;N;ba' -e '}' > expected
+sed -e '/^#/d' < "$1" | sed -e :a -e '/^\n*$/{$d;N;ba' -e '}' >expected
 EOF
 chmod 755 editor
 
@@ -859,7 +862,7 @@ EOF
 test_expect_success EXECKEEPSPID 'killed merge can be completed with --continue' '
 	git reset --hard c0 &&
 	! "$SHELL_PATH" -c '\''
-	  echo kill -TERM $$ >> .git/FAKE_EDITOR
+	  echo kill -TERM $$ >>.git/FAKE_EDITOR
 	  GIT_EDITOR=.git/FAKE_EDITOR
 	  export GIT_EDITOR
 	  exec git merge --no-ff --edit c1'\'' &&
diff --git a/t/t7604-merge-custom-message.sh b/t/t7604-merge-custom-message.sh
index 3fcd58eb2c..c9685a318d 100755
--- a/t/t7604-merge-custom-message.sh
+++ b/t/t7604-merge-custom-message.sh
@@ -36,14 +36,18 @@ test_expect_success 'setup' '
 test_expect_success 'merge c2 with a custom message' '
 	git reset --hard c1 &&
 	git merge -m "$(cat exp.subject)" c2 &&
-	git cat-file commit HEAD | sed -e "1,/^$/d" >actual &&
+	git cat-file commit HEAD >actual &&
+	sed -e "1,/^$/d" <actual >tmp &&
+	mv tmp actual &&
 	test_cmp exp.subject actual
 '
 
 test_expect_success 'merge --log appends to custom message' '
 	git reset --hard c1 &&
 	git merge --log -m "$(cat exp.subject)" c2 &&
-	git cat-file commit HEAD | sed -e "1,/^$/d" >actual &&
+	git cat-file commit HEAD >actual &&
+	sed -e "1,/^$/d" <actual >tmp &&
+	mv tmp actual &&
 	test_cmp exp.log actual
 '
 
@@ -59,53 +63,59 @@ test_expect_success 'prepare file with comment line and trailing newlines'  '
 test_expect_success 'cleanup commit messages (verbatim option)' '
 	git reset --hard c1 &&
 	git merge --cleanup=verbatim -F expect c2 &&
-	git cat-file -p HEAD |sed -e "1,/^\$/d" >actual &&
+	git cat-file commit HEAD >actual &&
+	sed -e "1,/^$/d" <actual >tmp &&
+	mv tmp actual &&
 	test_cmp expect actual
 '
 
 test_expect_success 'cleanup commit messages (whitespace option)' '
 	git reset --hard c1 &&
-	{ echo;echo "# text";echo; } >text &&
+	test_write_lines "" "# text" "" >text &&
 	echo "# text" >expect &&
 	git merge --cleanup=whitespace -F text c2 &&
-	git cat-file -p HEAD |sed -e "1,/^\$/d">actual &&
+	git cat-file commit HEAD >actual &&
+	sed -e "1,/^$/d" <actual >tmp &&
+	mv tmp actual &&
 	test_cmp expect actual
-
 '
 
 test_expect_success 'cleanup merge messages (scissors option)' '
 	git reset --hard c1 &&
-	cat >text <<EOF &&
+	cat >text <<-\EOF &&
 
-# to be kept
+	# to be kept
 
-  # ------------------------ >8 ------------------------
-# to be kept, too
-# ------------------------ >8 ------------------------
-to be removed
-# ------------------------ >8 ------------------------
-to be removed, too
-EOF
+	  # ------------------------ >8 ------------------------
+	# to be kept, too
+	# ------------------------ >8 ------------------------
+	to be removed
+	# ------------------------ >8 ------------------------
+	to be removed, too
+	EOF
 
-	cat >expect <<EOF &&
-# to be kept
+	cat >expect <<-\EOF &&
+	# to be kept
 
-  # ------------------------ >8 ------------------------
-# to be kept, too
-EOF
+	  # ------------------------ >8 ------------------------
+	# to be kept, too
+	EOF
 	git merge --cleanup=scissors -e -F text c2 &&
-	git cat-file -p HEAD |sed -e "1,/^\$/d">actual &&
+	git cat-file commit HEAD >actual &&
+	sed -e "1,/^$/d" <actual >tmp &&
+	mv tmp actual &&
 	test_cmp expect actual
 '
 
 test_expect_success 'cleanup commit messages (strip option)' '
 	git reset --hard c1 &&
-	{ echo;echo "# text";echo sample;echo; } >text &&
+	test_write_lines "" "# text" "sample" "" >text &&
 	echo sample >expect &&
 	git merge --cleanup=strip -F text c2 &&
-	git cat-file -p HEAD |sed -e "1,/^\$/d">actual &&
+	git cat-file commit HEAD >actual &&
+	sed -e "1,/^$/d" <actual >tmp &&
+	mv tmp actual &&
 	test_cmp expect actual
-
 '
 
 test_done
-- 
2.21.0.512.g57bf1b23e1


^ permalink raw reply	[flat|nested] 105+ messages in thread

* [PATCH v8 01/11] t7600: clean up style
  2019-03-17 10:15             ` [PATCH v8 00/11] " Denton Liu
@ 2019-03-17 10:15               ` Denton Liu
  2019-03-17 10:15               ` [PATCH v8 02/11] t3507: cleanup space after redirection operators Denton Liu
                                 ` (11 subsequent siblings)
  12 siblings, 0 replies; 105+ messages in thread
From: Denton Liu @ 2019-03-17 10:15 UTC (permalink / raw)
  To: Git Mailing List
  Cc: Denton Liu, Eric Sunshine, Junio C Hamano, Phillip Wood,
	Ramsay Jones, SZEDER Gábor

This cleans up the 'merge --squash c3 with c7' test by removing some
unnecessary braces and removing a pipe. Finally, unindent a here-doc for
style.

Also, remove stray spaces after "> " for style.

Helped-by: SZEDER Gábor <szeder.dev@gmail.com>
Helped-by: Eric Sunshine <sunshine@sunshineco.com>
Reviewed-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Denton Liu <liu.denton@gmail.com>
---
 t/t7600-merge.sh | 22 +++++++++++-----------
 1 file changed, 11 insertions(+), 11 deletions(-)

diff --git a/t/t7600-merge.sh b/t/t7600-merge.sh
index 106148254d..a9620cd991 100755
--- a/t/t7600-merge.sh
+++ b/t/t7600-merge.sh
@@ -233,17 +233,17 @@ test_expect_success 'merge --squash c3 with c7' '
 	cat result.9z >file &&
 	git commit --no-edit -a &&
 
-	{
-		cat <<-EOF
-		Squashed commit of the following:
+	cat >expect <<-EOF &&
+	Squashed commit of the following:
 
-		$(git show -s c7)
+	$(git show -s c7)
 
-		# Conflicts:
-		#	file
-		EOF
-	} >expect &&
-	git cat-file commit HEAD | sed -e '1,/^$/d' >actual &&
+	# Conflicts:
+	#	file
+	EOF
+	git cat-file commit HEAD >actual &&
+	sed -e '1,/^$/d' <actual >tmp &&
+	mv tmp actual &&
 	test_cmp expect actual
 '
 
@@ -683,7 +683,7 @@ cat >editor <<\EOF
 	cat <"$1"
 ) >"$1.tmp" && mv "$1.tmp" "$1"
 # strip comments and blank lines from end of message
-sed -e '/^#/d' < "$1" | sed -e :a -e '/^\n*$/{$d;N;ba' -e '}' > expected
+sed -e '/^#/d' < "$1" | sed -e :a -e '/^\n*$/{$d;N;ba' -e '}' >expected
 EOF
 chmod 755 editor
 
@@ -814,7 +814,7 @@ EOF
 test_expect_success EXECKEEPSPID 'killed merge can be completed with --continue' '
 	git reset --hard c0 &&
 	! "$SHELL_PATH" -c '\''
-	  echo kill -TERM $$ >> .git/FAKE_EDITOR
+	  echo kill -TERM $$ >>.git/FAKE_EDITOR
 	  GIT_EDITOR=.git/FAKE_EDITOR
 	  export GIT_EDITOR
 	  exec git merge --no-ff --edit c1'\'' &&
-- 
2.21.0.512.g57bf1b23e1


^ permalink raw reply	[flat|nested] 105+ messages in thread

* [PATCH v8 02/11] t3507: cleanup space after redirection operators
  2019-03-17 10:15             ` [PATCH v8 00/11] " Denton Liu
  2019-03-17 10:15               ` [PATCH v8 01/11] t7600: clean up style Denton Liu
@ 2019-03-17 10:15               ` Denton Liu
  2019-03-17 10:15               ` [PATCH v8 03/11] t7604: refactor out Git commands upstream of pipe Denton Liu
                                 ` (10 subsequent siblings)
  12 siblings, 0 replies; 105+ messages in thread
From: Denton Liu @ 2019-03-17 10:15 UTC (permalink / raw)
  To: Git Mailing List
  Cc: Denton Liu, Eric Sunshine, Junio C Hamano, Phillip Wood,
	Ramsay Jones, SZEDER Gábor

Signed-off-by: Denton Liu <liu.denton@gmail.com>
---
 t/t3507-cherry-pick-conflict.sh | 34 ++++++++++++++++-----------------
 1 file changed, 17 insertions(+), 17 deletions(-)

diff --git a/t/t3507-cherry-pick-conflict.sh b/t/t3507-cherry-pick-conflict.sh
index 0db166152a..74ff925526 100755
--- a/t/t3507-cherry-pick-conflict.sh
+++ b/t/t3507-cherry-pick-conflict.sh
@@ -88,7 +88,7 @@ test_expect_success 'cherry-pick --no-commit does not set CHERRY_PICK_HEAD' '
 
 test_expect_success 'cherry-pick w/dirty tree does not set CHERRY_PICK_HEAD' '
 	pristine_detach initial &&
-	echo foo > foo &&
+	echo foo >foo &&
 	test_must_fail git cherry-pick base &&
 	test_must_fail git rev-parse --verify CHERRY_PICK_HEAD
 '
@@ -96,7 +96,7 @@ test_expect_success 'cherry-pick w/dirty tree does not set CHERRY_PICK_HEAD' '
 test_expect_success \
 	'cherry-pick --strategy=resolve w/dirty tree does not set CHERRY_PICK_HEAD' '
 	pristine_detach initial &&
-	echo foo > foo &&
+	echo foo >foo &&
 	test_must_fail git cherry-pick --strategy=resolve base &&
 	test_must_fail git rev-parse --verify CHERRY_PICK_HEAD
 '
@@ -175,23 +175,23 @@ test_expect_success 'failed cherry-pick registers participants in index' '
 		git ls-files --stage foo &&
 		git checkout picked -- foo &&
 		git ls-files --stage foo
-	} > stages &&
+	} >stages &&
 	sed "
 		1 s/ 0	/ 1	/
 		2 s/ 0	/ 2	/
 		3 s/ 0	/ 3	/
-	" < stages > expected &&
+	" <stages >expected &&
 	git read-tree -u --reset HEAD &&
 
 	test_must_fail git cherry-pick picked &&
-	git ls-files --stage --unmerged > actual &&
+	git ls-files --stage --unmerged >actual &&
 
 	test_cmp expected actual
 '
 
 test_expect_success 'failed cherry-pick describes conflict in work tree' '
 	pristine_detach initial &&
-	cat <<-EOF > expected &&
+	cat <<-EOF >expected &&
 	<<<<<<< HEAD
 	a
 	=======
@@ -201,14 +201,14 @@ test_expect_success 'failed cherry-pick describes conflict in work tree' '
 
 	test_must_fail git cherry-pick picked &&
 
-	sed "s/[a-f0-9]*\.\.\./objid/" foo > actual &&
+	sed "s/[a-f0-9]*\.\.\./objid/" foo >actual &&
 	test_cmp expected actual
 '
 
 test_expect_success 'diff3 -m style' '
 	pristine_detach initial &&
 	git config merge.conflictstyle diff3 &&
-	cat <<-EOF > expected &&
+	cat <<-EOF >expected &&
 	<<<<<<< HEAD
 	a
 	||||||| parent of objid picked
@@ -220,14 +220,14 @@ test_expect_success 'diff3 -m style' '
 
 	test_must_fail git cherry-pick picked &&
 
-	sed "s/[a-f0-9]*\.\.\./objid/" foo > actual &&
+	sed "s/[a-f0-9]*\.\.\./objid/" foo >actual &&
 	test_cmp expected actual
 '
 
 test_expect_success 'revert also handles conflicts sanely' '
 	git config --unset merge.conflictstyle &&
 	pristine_detach initial &&
-	cat <<-EOF > expected &&
+	cat <<-EOF >expected &&
 	<<<<<<< HEAD
 	a
 	=======
@@ -241,24 +241,24 @@ test_expect_success 'revert also handles conflicts sanely' '
 		git ls-files --stage foo &&
 		git checkout base -- foo &&
 		git ls-files --stage foo
-	} > stages &&
+	} >stages &&
 	sed "
 		1 s/ 0	/ 1	/
 		2 s/ 0	/ 2	/
 		3 s/ 0	/ 3	/
-	" < stages > expected-stages &&
+	" <stages >expected-stages &&
 	git read-tree -u --reset HEAD &&
 
 	head=$(git rev-parse HEAD) &&
 	test_must_fail git revert picked &&
 	newhead=$(git rev-parse HEAD) &&
-	git ls-files --stage --unmerged > actual-stages &&
+	git ls-files --stage --unmerged >actual-stages &&
 
 	test "$head" = "$newhead" &&
 	test_must_fail git update-index --refresh -q &&
 	test_must_fail git diff-index --exit-code HEAD &&
 	test_cmp expected-stages actual-stages &&
-	sed "s/[a-f0-9]*\.\.\./objid/" foo > actual &&
+	sed "s/[a-f0-9]*\.\.\./objid/" foo >actual &&
 	test_cmp expected actual
 '
 
@@ -284,7 +284,7 @@ test_expect_success 'revert --no-commit sets REVERT_HEAD' '
 
 test_expect_success 'revert w/dirty tree does not set REVERT_HEAD' '
 	pristine_detach base &&
-	echo foo > foo &&
+	echo foo >foo &&
 	test_must_fail git revert base &&
 	test_must_fail git rev-parse --verify CHERRY_PICK_HEAD &&
 	test_must_fail git rev-parse --verify REVERT_HEAD
@@ -319,7 +319,7 @@ test_expect_success 'failed commit does not clear REVERT_HEAD' '
 test_expect_success 'revert conflict, diff3 -m style' '
 	pristine_detach initial &&
 	git config merge.conflictstyle diff3 &&
-	cat <<-EOF > expected &&
+	cat <<-EOF >expected &&
 	<<<<<<< HEAD
 	a
 	||||||| objid picked
@@ -331,7 +331,7 @@ test_expect_success 'revert conflict, diff3 -m style' '
 
 	test_must_fail git revert picked &&
 
-	sed "s/[a-f0-9]*\.\.\./objid/" foo > actual &&
+	sed "s/[a-f0-9]*\.\.\./objid/" foo >actual &&
 	test_cmp expected actual
 '
 
-- 
2.21.0.512.g57bf1b23e1


^ permalink raw reply	[flat|nested] 105+ messages in thread

* [PATCH v8 03/11] t7604: refactor out Git commands upstream of pipe
  2019-03-17 10:15             ` [PATCH v8 00/11] " Denton Liu
  2019-03-17 10:15               ` [PATCH v8 01/11] t7600: clean up style Denton Liu
  2019-03-17 10:15               ` [PATCH v8 02/11] t3507: cleanup space after redirection operators Denton Liu
@ 2019-03-17 10:15               ` Denton Liu
  2019-03-17 10:16               ` [PATCH v8 04/11] t7502: clean up test style Denton Liu
                                 ` (9 subsequent siblings)
  12 siblings, 0 replies; 105+ messages in thread
From: Denton Liu @ 2019-03-17 10:15 UTC (permalink / raw)
  To: Git Mailing List
  Cc: Denton Liu, Eric Sunshine, Junio C Hamano, Phillip Wood,
	Ramsay Jones, SZEDER Gábor

Before, we had some Git commands which were upstream of the pipe. This
meant that if it produced an error, it would've gone unnoticed. Refactor
to place Git commands on their own.

Helped-by: Eric Sunshine <sunshine@sunshineco.com>
Signed-off-by: Denton Liu <liu.denton@gmail.com>
---
 t/t7604-merge-custom-message.sh | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/t/t7604-merge-custom-message.sh b/t/t7604-merge-custom-message.sh
index 89619cf446..b045fdb413 100755
--- a/t/t7604-merge-custom-message.sh
+++ b/t/t7604-merge-custom-message.sh
@@ -36,14 +36,18 @@ test_expect_success 'setup' '
 test_expect_success 'merge c2 with a custom message' '
 	git reset --hard c1 &&
 	git merge -m "$(cat exp.subject)" c2 &&
-	git cat-file commit HEAD | sed -e "1,/^$/d" >actual &&
+	git cat-file commit HEAD >actual &&
+	sed -e "1,/^$/d" <actual >tmp &&
+	mv tmp actual &&
 	test_cmp exp.subject actual
 '
 
 test_expect_success 'merge --log appends to custom message' '
 	git reset --hard c1 &&
 	git merge --log -m "$(cat exp.subject)" c2 &&
-	git cat-file commit HEAD | sed -e "1,/^$/d" >actual &&
+	git cat-file commit HEAD >actual &&
+	sed -e "1,/^$/d" <actual >tmp &&
+	mv tmp actual &&
 	test_cmp exp.log actual
 '
 
-- 
2.21.0.512.g57bf1b23e1


^ permalink raw reply	[flat|nested] 105+ messages in thread

* [PATCH v8 04/11] t7502: clean up test style
  2019-03-17 10:15             ` [PATCH v8 00/11] " Denton Liu
                                 ` (2 preceding siblings ...)
  2019-03-17 10:15               ` [PATCH v8 03/11] t7604: refactor out Git commands upstream of pipe Denton Liu
@ 2019-03-17 10:16               ` Denton Liu
  2019-03-17 10:16               ` [PATCH v8 05/11] commit: extract cleanup_mode functions to sequencer Denton Liu
                                 ` (8 subsequent siblings)
  12 siblings, 0 replies; 105+ messages in thread
From: Denton Liu @ 2019-03-17 10:16 UTC (permalink / raw)
  To: Git Mailing List
  Cc: Denton Liu, Eric Sunshine, Junio C Hamano, Phillip Wood,
	Ramsay Jones, SZEDER Gábor

Refactor out git commands that were upstream of a pipe. Also, as a style
cleanup, remove spaces after "> ". Next, indent here-docs. Finally,
convert echo chains to use the test_write_lines function.

Helped-by: Eric Sunshine <sunshine@sunshineco.com>
Signed-off-by: Denton Liu <liu.denton@gmail.com>
---
 t/t7502-commit-porcelain.sh | 100 ++++++++++++++++++++++--------------
 1 file changed, 61 insertions(+), 39 deletions(-)

diff --git a/t/t7502-commit-porcelain.sh b/t/t7502-commit-porcelain.sh
index ca4a740da0..f035e4a507 100755
--- a/t/t7502-commit-porcelain.sh
+++ b/t/t7502-commit-porcelain.sh
@@ -16,7 +16,9 @@ commit_msg_is () {
 # Arguments: [<prefix] [<commit message>] [<commit options>]
 check_summary_oneline() {
 	test_tick &&
-	git commit ${3+"$3"} -m "$2" | head -1 > act &&
+	git commit ${3+"$3"} -m "$2" >act &&
+	head -1 <act >tmp &&
+	mv tmp act &&
 
 	# branch name
 	SUMMARY_PREFIX="$(git name-rev --name-only HEAD)" &&
@@ -68,7 +70,7 @@ test_expect_success 'output summary format for merges' '
 	git checkout recursive-a &&
 	test_must_fail git merge recursive-b &&
 	# resolve the conflict
-	echo commit-a > file1 &&
+	echo commit-a >file1 &&
 	git add file1 &&
 	check_summary_oneline "" "Merge"
 '
@@ -142,8 +144,8 @@ test_expect_success 'sign off' '
 	>positive &&
 	git add positive &&
 	git commit -s -m "thank you" &&
-	actual=$(git cat-file commit HEAD | sed -ne "s/Signed-off-by: //p") &&
-	expected=$(git var GIT_COMMITTER_IDENT | sed -e "s/>.*/>/") &&
+	actual=$(git cat-file commit HEAD >tmp && sed -ne "s/Signed-off-by: //p" <tmp && rm tmp) &&
+	expected=$(git var GIT_COMMITTER_IDENT >tmp && sed -e "s/>.*/>/" <tmp && rm tmp) &&
 	test "z$actual" = "z$expected"
 
 '
@@ -153,8 +155,8 @@ test_expect_success 'multiple -m' '
 	>negative &&
 	git add negative &&
 	git commit -m "one" -m "two" -m "three" &&
-	actual=$(git cat-file commit HEAD | sed -e "1,/^\$/d") &&
-	expected=$(echo one; echo; echo two; echo; echo three) &&
+	actual=$(git cat-file commit HEAD >tmp && sed -e "1,/^\$/d" <tmp && rm tmp) &&
+	expected=$(test_write_lines "one" "" "two" "" "three") &&
 	test "z$actual" = "z$expected"
 
 '
@@ -163,7 +165,9 @@ test_expect_success 'verbose' '
 
 	echo minus >negative &&
 	git add negative &&
-	git status -v | sed -ne "/^diff --git /p" >actual &&
+	git status -v >actual &&
+	sed -ne "/^diff --git /p" <actual >tmp &&
+	mv tmp actual &&
 	echo "diff --git a/negative b/negative" >expect &&
 	test_cmp expect actual
 
@@ -189,7 +193,9 @@ test_expect_success 'cleanup commit messages (verbatim option,-t)' '
 
 	echo >>negative &&
 	git commit --cleanup=verbatim --no-status -t expect -a &&
-	git cat-file -p HEAD |sed -e "1,/^\$/d" >actual &&
+	git cat-file -p HEAD >actual &&
+	sed -e "1,/^\$/d" <actual >tmp &&
+	mv tmp actual &&
 	test_cmp expect actual
 
 '
@@ -198,7 +204,9 @@ test_expect_success 'cleanup commit messages (verbatim option,-F)' '
 
 	echo >>negative &&
 	git commit --cleanup=verbatim -F expect -a &&
-	git cat-file -p HEAD |sed -e "1,/^\$/d">actual &&
+	git cat-file -p HEAD >actual &&
+	sed -e "1,/^\$/d" <actual >tmp &&
+	mv tmp actual &&
 	test_cmp expect actual
 
 '
@@ -207,7 +215,9 @@ test_expect_success 'cleanup commit messages (verbatim option,-m)' '
 
 	echo >>negative &&
 	git commit --cleanup=verbatim -m "$mesg_with_comment_and_newlines" -a &&
-	git cat-file -p HEAD |sed -e "1,/^\$/d">actual &&
+	git cat-file -p HEAD >actual &&
+	sed -e "1,/^\$/d" <actual >tmp &&
+	mv tmp actual &&
 	test_cmp expect actual
 
 '
@@ -215,10 +225,12 @@ test_expect_success 'cleanup commit messages (verbatim option,-m)' '
 test_expect_success 'cleanup commit messages (whitespace option,-F)' '
 
 	echo >>negative &&
-	{ echo;echo "# text";echo; } >text &&
+	test_write_lines "" "# text" "" >text &&
 	echo "# text" >expect &&
 	git commit --cleanup=whitespace -F text -a &&
-	git cat-file -p HEAD |sed -e "1,/^\$/d">actual &&
+	git cat-file -p HEAD >actual &&
+	sed -e "1,/^\$/d" <actual >tmp &&
+	mv tmp actual &&
 	test_cmp expect actual
 
 '
@@ -226,48 +238,54 @@ test_expect_success 'cleanup commit messages (whitespace option,-F)' '
 test_expect_success 'cleanup commit messages (scissors option,-F,-e)' '
 
 	echo >>negative &&
-	cat >text <<EOF &&
+	cat >text <<-\EOF &&
 
-# to be kept
+	# to be kept
 
-  # ------------------------ >8 ------------------------
-# to be kept, too
-# ------------------------ >8 ------------------------
-to be removed
-# ------------------------ >8 ------------------------
-to be removed, too
-EOF
+	  # ------------------------ >8 ------------------------
+	# to be kept, too
+	# ------------------------ >8 ------------------------
+	to be removed
+	# ------------------------ >8 ------------------------
+	to be removed, too
+	EOF
 
-	cat >expect <<EOF &&
-# to be kept
+	cat >expect <<-\EOF &&
+	# to be kept
 
-  # ------------------------ >8 ------------------------
-# to be kept, too
-EOF
+	  # ------------------------ >8 ------------------------
+	# to be kept, too
+	EOF
 	git commit --cleanup=scissors -e -F text -a &&
-	git cat-file -p HEAD |sed -e "1,/^\$/d">actual &&
+	git cat-file -p HEAD >actual &&
+	sed -e "1,/^\$/d" <actual >tmp &&
+	mv tmp actual &&
 	test_cmp expect actual
 '
 
 test_expect_success 'cleanup commit messages (scissors option,-F,-e, scissors on first line)' '
 
 	echo >>negative &&
-	cat >text <<EOF &&
-# ------------------------ >8 ------------------------
-to be removed
-EOF
+	cat >text <<-\EOF &&
+	# ------------------------ >8 ------------------------
+	to be removed
+	EOF
 	git commit --cleanup=scissors -e -F text -a --allow-empty-message &&
-	git cat-file -p HEAD |sed -e "1,/^\$/d">actual &&
+	git cat-file -p HEAD >actual &&
+	sed -e "1,/^\$/d" <actual >tmp &&
+	mv tmp actual &&
 	test_must_be_empty actual
 '
 
 test_expect_success 'cleanup commit messages (strip option,-F)' '
 
 	echo >>negative &&
-	{ echo;echo "# text";echo sample;echo; } >text &&
+	test_write_lines "" "# text" "sample" "" >text &&
 	echo sample >expect &&
 	git commit --cleanup=strip -F text -a &&
-	git cat-file -p HEAD |sed -e "1,/^\$/d">actual &&
+	git cat-file -p HEAD >actual &&
+	sed -e "1,/^\$/d" <actual >tmp &&
+	mv tmp actual &&
 	test_cmp expect actual
 
 '
@@ -275,7 +293,7 @@ test_expect_success 'cleanup commit messages (strip option,-F)' '
 test_expect_success 'cleanup commit messages (strip option,-F,-e)' '
 
 	echo >>negative &&
-	{ echo;echo sample;echo; } >text &&
+	test_write_lines "" "sample" "" >text &&
 	git commit -e -F text -a &&
 	head -n 4 .git/COMMIT_EDITMSG >actual
 '
@@ -387,7 +405,7 @@ test_expect_success AUTOIDENT 'message shows committer when it is automatic' '
 '
 
 write_script .git/FAKE_EDITOR <<EOF
-echo editor started > "$(pwd)/.git/result"
+echo editor started >"$(pwd)/.git/result"
 exit 0
 EOF
 
@@ -455,7 +473,7 @@ EOF
 test_expect_success EXECKEEPSPID 'a SIGTERM should break locks' '
 	echo >>negative &&
 	! "$SHELL_PATH" -c '\''
-	  echo kill -TERM $$ >> .git/FAKE_EDITOR
+	  echo kill -TERM $$ >>.git/FAKE_EDITOR
 	  GIT_EDITOR=.git/FAKE_EDITOR
 	  export GIT_EDITOR
 	  exec git commit -a'\'' &&
@@ -471,7 +489,9 @@ test_expect_success 'Hand committing of a redundant merge removes dups' '
 	test_must_fail git merge second master &&
 	git checkout master g &&
 	EDITOR=: git commit -a &&
-	git cat-file commit HEAD | sed -n -e "s/^parent //p" -e "/^$/q" >actual &&
+	git cat-file commit HEAD >actual &&
+	sed -n -e "s/^parent //p" -e "/^$/q" <actual >tmp &&
+	mv tmp actual &&
 	test_cmp expect actual
 
 '
@@ -480,7 +500,9 @@ test_expect_success 'A single-liner subject with a token plus colon is not a foo
 
 	git reset --hard &&
 	git commit -s -m "hello: kitty" --allow-empty &&
-	git cat-file commit HEAD | sed -e "1,/^$/d" >actual &&
+	git cat-file commit HEAD >actual &&
+	sed -e "1,/^$/d" <actual >tmp &&
+	mv tmp actual &&
 	test_line_count = 3 actual
 
 '
-- 
2.21.0.512.g57bf1b23e1


^ permalink raw reply	[flat|nested] 105+ messages in thread

* [PATCH v8 05/11] commit: extract cleanup_mode functions to sequencer
  2019-03-17 10:15             ` [PATCH v8 00/11] " Denton Liu
                                 ` (3 preceding siblings ...)
  2019-03-17 10:16               ` [PATCH v8 04/11] t7502: clean up test style Denton Liu
@ 2019-03-17 10:16               ` Denton Liu
  2019-03-17 10:16               ` [PATCH v8 06/11] parse-options.h: extract common --cleanup option Denton Liu
                                 ` (7 subsequent siblings)
  12 siblings, 0 replies; 105+ messages in thread
From: Denton Liu @ 2019-03-17 10:16 UTC (permalink / raw)
  To: Git Mailing List
  Cc: Denton Liu, Eric Sunshine, Junio C Hamano, Phillip Wood,
	Ramsay Jones, SZEDER Gábor

Signed-off-by: Denton Liu <liu.denton@gmail.com>
---
 builtin/commit.c | 25 ++-----------------------
 sequencer.c      | 29 +++++++++++++++++++++++++++++
 sequencer.h      |  6 ++++++
 3 files changed, 37 insertions(+), 23 deletions(-)

diff --git a/builtin/commit.c b/builtin/commit.c
index f17537474a..0df15e4851 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -1172,24 +1172,7 @@ static int parse_and_validate_options(int argc, const char *argv[],
 		die(_("Only one of --include/--only/--all/--interactive/--patch can be used."));
 	if (argc == 0 && (also || (only && !amend && !allow_empty)))
 		die(_("No paths with --include/--only does not make sense."));
-	if (!cleanup_arg || !strcmp(cleanup_arg, "default"))
-		cleanup_mode = use_editor ? COMMIT_MSG_CLEANUP_ALL :
-					    COMMIT_MSG_CLEANUP_SPACE;
-	else if (!strcmp(cleanup_arg, "verbatim"))
-		cleanup_mode = COMMIT_MSG_CLEANUP_NONE;
-	else if (!strcmp(cleanup_arg, "whitespace"))
-		cleanup_mode = COMMIT_MSG_CLEANUP_SPACE;
-	else if (!strcmp(cleanup_arg, "strip"))
-		cleanup_mode = COMMIT_MSG_CLEANUP_ALL;
-	else if (!strcmp(cleanup_arg, "scissors"))
-		cleanup_mode = use_editor ? COMMIT_MSG_CLEANUP_SCISSORS :
-					    COMMIT_MSG_CLEANUP_SPACE;
-	/*
-	 * Please update _git_commit() in git-completion.bash when you
-	 * add new options.
-	 */
-	else
-		die(_("Invalid cleanup mode %s"), cleanup_arg);
+	cleanup_mode = get_cleanup_mode(cleanup_arg, use_editor);
 
 	handle_untracked_files_arg(s);
 
@@ -1626,11 +1609,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
 		die(_("could not read commit message: %s"), strerror(saved_errno));
 	}
 
-	if (verbose || /* Truncate the message just before the diff, if any. */
-	    cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)
-		strbuf_setlen(&sb, wt_status_locate_end(sb.buf, sb.len));
-	if (cleanup_mode != COMMIT_MSG_CLEANUP_NONE)
-		strbuf_stripspace(&sb, cleanup_mode == COMMIT_MSG_CLEANUP_ALL);
+	cleanup_message(&sb, cleanup_mode, verbose);
 
 	if (message_is_empty(&sb, cleanup_mode) && !allow_empty_message) {
 		rollback_index_files();
diff --git a/sequencer.c b/sequencer.c
index 95dda23eee..224c823b43 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -511,6 +511,25 @@ static int fast_forward_to(struct repository *r,
 	return 0;
 }
 
+enum commit_msg_cleanup_mode get_cleanup_mode(const char *cleanup_arg,
+	int use_editor)
+{
+	if (!cleanup_arg || !strcmp(cleanup_arg, "default"))
+		return use_editor ? COMMIT_MSG_CLEANUP_ALL :
+				    COMMIT_MSG_CLEANUP_SPACE;
+	else if (!strcmp(cleanup_arg, "verbatim"))
+		return COMMIT_MSG_CLEANUP_NONE;
+	else if (!strcmp(cleanup_arg, "whitespace"))
+		return COMMIT_MSG_CLEANUP_SPACE;
+	else if (!strcmp(cleanup_arg, "strip"))
+		return COMMIT_MSG_CLEANUP_ALL;
+	else if (!strcmp(cleanup_arg, "scissors"))
+		return use_editor ? COMMIT_MSG_CLEANUP_SCISSORS :
+				    COMMIT_MSG_CLEANUP_SPACE;
+	else
+		die(_("Invalid cleanup mode %s"), cleanup_arg);
+}
+
 void append_conflicts_hint(struct index_state *istate,
 			   struct strbuf *msgbuf)
 {
@@ -1013,6 +1032,16 @@ static int rest_is_empty(const struct strbuf *sb, int start)
 	return 1;
 }
 
+void cleanup_message(struct strbuf *msgbuf,
+	enum commit_msg_cleanup_mode cleanup_mode, int verbose)
+{
+	if (verbose || /* Truncate the message just before the diff, if any. */
+	    cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)
+		strbuf_setlen(msgbuf, wt_status_locate_end(msgbuf->buf, msgbuf->len));
+	if (cleanup_mode != COMMIT_MSG_CLEANUP_NONE)
+		strbuf_stripspace(msgbuf, cleanup_mode == COMMIT_MSG_CLEANUP_ALL);
+}
+
 /*
  * Find out if the message in the strbuf contains only whitespace and
  * Signed-off-by lines.
diff --git a/sequencer.h b/sequencer.h
index 4d505b3590..eb9bd97ef3 100644
--- a/sequencer.h
+++ b/sequencer.h
@@ -116,6 +116,12 @@ int rearrange_squash(struct repository *r);
 void append_signoff(struct strbuf *msgbuf, size_t ignore_footer, unsigned flag);
 
 void append_conflicts_hint(struct index_state *istate, struct strbuf *msgbuf);
+enum commit_msg_cleanup_mode get_cleanup_mode(const char *cleanup_arg,
+	int use_editor);
+
+void cleanup_message(struct strbuf *msgbuf,
+	enum commit_msg_cleanup_mode cleanup_mode, int verbose);
+
 int message_is_empty(const struct strbuf *sb,
 		     enum commit_msg_cleanup_mode cleanup_mode);
 int template_untouched(const struct strbuf *sb, const char *template_file,
-- 
2.21.0.512.g57bf1b23e1


^ permalink raw reply	[flat|nested] 105+ messages in thread

* [PATCH v8 06/11] parse-options.h: extract common --cleanup option
  2019-03-17 10:15             ` [PATCH v8 00/11] " Denton Liu
                                 ` (4 preceding siblings ...)
  2019-03-17 10:16               ` [PATCH v8 05/11] commit: extract cleanup_mode functions to sequencer Denton Liu
@ 2019-03-17 10:16               ` Denton Liu
  2019-03-17 10:16               ` [PATCH v8 07/11] sequencer.c: remove duplicate code Denton Liu
                                 ` (6 subsequent siblings)
  12 siblings, 0 replies; 105+ messages in thread
From: Denton Liu @ 2019-03-17 10:16 UTC (permalink / raw)
  To: Git Mailing List
  Cc: Denton Liu, Eric Sunshine, Junio C Hamano, Phillip Wood,
	Ramsay Jones, SZEDER Gábor

The --cleanup option is commonly used. Extract it so that its definition
is not repeated.

Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Signed-off-by: Denton Liu <liu.denton@gmail.com>
---
 builtin/commit.c | 2 +-
 builtin/tag.c    | 3 +--
 parse-options.h  | 1 +
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/builtin/commit.c b/builtin/commit.c
index 0df15e4851..8277da8474 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -1473,7 +1473,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
 		OPT_BOOL('s', "signoff", &signoff, N_("add Signed-off-by:")),
 		OPT_FILENAME('t', "template", &template_file, N_("use specified template file")),
 		OPT_BOOL('e', "edit", &edit_flag, N_("force edit of commit")),
-		OPT_STRING(0, "cleanup", &cleanup_arg, N_("default"), N_("how to strip spaces and #comments from message")),
+		OPT_CLEANUP(&cleanup_arg),
 		OPT_BOOL(0, "status", &include_status, N_("include status in commit message template")),
 		{ OPTION_STRING, 'S', "gpg-sign", &sign_commit, N_("key-id"),
 		  N_("GPG sign commit"), PARSE_OPT_OPTARG, NULL, (intptr_t) "" },
diff --git a/builtin/tag.c b/builtin/tag.c
index 02f6bd1279..a3870fbdba 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -397,8 +397,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
 		OPT_FILENAME('F', "file", &msgfile, N_("read message from file")),
 		OPT_BOOL('e', "edit", &edit_flag, N_("force edit of tag message")),
 		OPT_BOOL('s', "sign", &opt.sign, N_("annotated and GPG-signed tag")),
-		OPT_STRING(0, "cleanup", &cleanup_arg, N_("mode"),
-			N_("how to strip spaces and #comments from message")),
+		OPT_CLEANUP(&cleanup_arg),
 		OPT_STRING('u', "local-user", &keyid, N_("key-id"),
 					N_("use another key to sign the tag")),
 		OPT__FORCE(&force, N_("replace the tag if exists"), 0),
diff --git a/parse-options.h b/parse-options.h
index 7d83e2971d..85faaee390 100644
--- a/parse-options.h
+++ b/parse-options.h
@@ -303,5 +303,6 @@ int parse_opt_passthru_argv(const struct option *, const char *, int);
 #define OPT_NO_CONTAINS(v, h) _OPT_CONTAINS_OR_WITH("no-contains", v, h, PARSE_OPT_NONEG)
 #define OPT_WITH(v, h) _OPT_CONTAINS_OR_WITH("with", v, h, PARSE_OPT_HIDDEN | PARSE_OPT_NONEG)
 #define OPT_WITHOUT(v, h) _OPT_CONTAINS_OR_WITH("without", v, h, PARSE_OPT_HIDDEN | PARSE_OPT_NONEG)
+#define OPT_CLEANUP(v) OPT_STRING(0, "cleanup", v, N_("mode"), N_("how to strip spaces and #comments from message"))
 
 #endif
-- 
2.21.0.512.g57bf1b23e1


^ permalink raw reply	[flat|nested] 105+ messages in thread

* [PATCH v8 07/11] sequencer.c: remove duplicate code
  2019-03-17 10:15             ` [PATCH v8 00/11] " Denton Liu
                                 ` (5 preceding siblings ...)
  2019-03-17 10:16               ` [PATCH v8 06/11] parse-options.h: extract common --cleanup option Denton Liu
@ 2019-03-17 10:16               ` Denton Liu
  2019-03-17 10:16               ` [PATCH v8 08/11] merge: cleanup messages like commit Denton Liu
                                 ` (5 subsequent siblings)
  12 siblings, 0 replies; 105+ messages in thread
From: Denton Liu @ 2019-03-17 10:16 UTC (permalink / raw)
  To: Git Mailing List
  Cc: Denton Liu, Eric Sunshine, Junio C Hamano, Phillip Wood,
	Ramsay Jones, SZEDER Gábor

Since we implemented get_cleanup_mode, we had some duplicate code in
git_sequencer_config which essentially performed the same operations.
Refactor git_sequencer_config to take advantage of the logic already in
get_cleanup_mode.

Note that we had to introduce a separate argument to get_cleanup_mode
indicating whether to die or not on an invalid value. This is because if
we are parsing a config, we do not want to die but instead, we only want
to warn the user, whereas if we are parsing a command-line option, we
would like to actually die.

Finally, this is almost a no-op refactor but not quite. Previously, in
the case that an invalid value is presented, default_msg_cleanup would
not be set. We change the behaviour so that default_msg_cleanup will now
take on the value as if "default" were provided as the cleanup_arg.
Also, we lowercase some user-facing strings.

Reviewed-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Signed-off-by: Denton Liu <liu.denton@gmail.com>
---
 builtin/commit.c |  2 +-
 sequencer.c      | 22 ++++++++--------------
 sequencer.h      |  2 +-
 3 files changed, 10 insertions(+), 16 deletions(-)

diff --git a/builtin/commit.c b/builtin/commit.c
index 8277da8474..ba1e6027ba 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -1172,7 +1172,7 @@ static int parse_and_validate_options(int argc, const char *argv[],
 		die(_("Only one of --include/--only/--all/--interactive/--patch can be used."));
 	if (argc == 0 && (also || (only && !amend && !allow_empty)))
 		die(_("No paths with --include/--only does not make sense."));
-	cleanup_mode = get_cleanup_mode(cleanup_arg, use_editor);
+	cleanup_mode = get_cleanup_mode(cleanup_arg, use_editor, 1);
 
 	handle_untracked_files_arg(s);
 
diff --git a/sequencer.c b/sequencer.c
index 224c823b43..2cbfb848dd 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -172,17 +172,7 @@ static int git_sequencer_config(const char *k, const char *v, void *cb)
 		if (status)
 			return status;
 
-		if (!strcmp(s, "verbatim"))
-			opts->default_msg_cleanup = COMMIT_MSG_CLEANUP_NONE;
-		else if (!strcmp(s, "whitespace"))
-			opts->default_msg_cleanup = COMMIT_MSG_CLEANUP_SPACE;
-		else if (!strcmp(s, "strip"))
-			opts->default_msg_cleanup = COMMIT_MSG_CLEANUP_ALL;
-		else if (!strcmp(s, "scissors"))
-			opts->default_msg_cleanup = COMMIT_MSG_CLEANUP_SPACE;
-		else
-			warning(_("invalid commit message cleanup mode '%s'"),
-				  s);
+		opts->default_msg_cleanup = get_cleanup_mode(s, 0, 0);
 
 		free((char *)s);
 		return status;
@@ -512,7 +502,7 @@ static int fast_forward_to(struct repository *r,
 }
 
 enum commit_msg_cleanup_mode get_cleanup_mode(const char *cleanup_arg,
-	int use_editor)
+	int use_editor, int die_on_error)
 {
 	if (!cleanup_arg || !strcmp(cleanup_arg, "default"))
 		return use_editor ? COMMIT_MSG_CLEANUP_ALL :
@@ -526,8 +516,12 @@ enum commit_msg_cleanup_mode get_cleanup_mode(const char *cleanup_arg,
 	else if (!strcmp(cleanup_arg, "scissors"))
 		return use_editor ? COMMIT_MSG_CLEANUP_SCISSORS :
 				    COMMIT_MSG_CLEANUP_SPACE;
-	else
-		die(_("Invalid cleanup mode %s"), cleanup_arg);
+	else if (!die_on_error) {
+		warning(_("invalid cleanup mode %s, falling back to default"), cleanup_arg);
+		return use_editor ? COMMIT_MSG_CLEANUP_ALL :
+				    COMMIT_MSG_CLEANUP_SPACE;
+	} else
+		die(_("invalid cleanup mode %s"), cleanup_arg);
 }
 
 void append_conflicts_hint(struct index_state *istate,
diff --git a/sequencer.h b/sequencer.h
index eb9bd97ef3..e7908f558e 100644
--- a/sequencer.h
+++ b/sequencer.h
@@ -117,7 +117,7 @@ void append_signoff(struct strbuf *msgbuf, size_t ignore_footer, unsigned flag);
 
 void append_conflicts_hint(struct index_state *istate, struct strbuf *msgbuf);
 enum commit_msg_cleanup_mode get_cleanup_mode(const char *cleanup_arg,
-	int use_editor);
+	int use_editor, int die_on_error);
 
 void cleanup_message(struct strbuf *msgbuf,
 	enum commit_msg_cleanup_mode cleanup_mode, int verbose);
-- 
2.21.0.512.g57bf1b23e1


^ permalink raw reply	[flat|nested] 105+ messages in thread

* [PATCH v8 08/11] merge: cleanup messages like commit
  2019-03-17 10:15             ` [PATCH v8 00/11] " Denton Liu
                                 ` (6 preceding siblings ...)
  2019-03-17 10:16               ` [PATCH v8 07/11] sequencer.c: remove duplicate code Denton Liu
@ 2019-03-17 10:16               ` Denton Liu
  2019-03-19 11:13                 ` Phillip Wood
  2019-03-17 10:16               ` [PATCH v8 09/11] merge: add scissors line on merge conflict Denton Liu
                                 ` (4 subsequent siblings)
  12 siblings, 1 reply; 105+ messages in thread
From: Denton Liu @ 2019-03-17 10:16 UTC (permalink / raw)
  To: Git Mailing List
  Cc: Denton Liu, Eric Sunshine, Junio C Hamano, Phillip Wood,
	Ramsay Jones, SZEDER Gábor

This change allows git-merge messages to be cleaned up with the
commit.cleanup configuration or --cleanup option, just like how
git-commit does it.

We also give git-pull the passthrough option of --cleanup so that it can
also take advantage of this change.

Finally, add testing to ensure that messages are properly cleaned up.
Note that some newlines that were added to the commit message were
removed so that if a file were read via -F, it would be copied
faithfully.

Reviewed-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Reviewed-by: Eric Sunshine <sunshine@sunshineco.com>
Signed-off-by: Denton Liu <liu.denton@gmail.com>
---

Phillip Wood wrote:
> cleanup needs to take an argument so PARSE_OPT_NOARG does not look 
> right. Also I think it would be bettor from the user's point of view if 
> the value of the argument was checked by pull before it does any work 
> rather otherwise if they pass in invalid value pull mostly runs and then 
> merge errors out at the end.

I opted not to do a check on the validity of the value of the
--cleanup-mode argument because the strategy options that existed before
also didn't verify the validity of their values. In the future, it might
be a good idea to check the values of both cleanup-mode and the
strategy options but for now, I think we can leave it as it is.

 Documentation/merge-options.txt |  5 +++
 builtin/merge.c                 | 31 +++++++++++----
 builtin/pull.c                  |  6 +++
 t/t7604-merge-custom-message.sh | 67 +++++++++++++++++++++++++++++++++
 wt-status.c                     | 12 ++++--
 wt-status.h                     |  1 +
 6 files changed, 112 insertions(+), 10 deletions(-)

diff --git a/Documentation/merge-options.txt b/Documentation/merge-options.txt
index 92a7d936c1..646100ea9a 100644
--- a/Documentation/merge-options.txt
+++ b/Documentation/merge-options.txt
@@ -32,6 +32,11 @@ they run `git merge`. To make it easier to adjust such scripts to the
 updated behaviour, the environment variable `GIT_MERGE_AUTOEDIT` can be
 set to `no` at the beginning of them.
 
+--cleanup=<mode>::
+	This option determines how the merge message will be cleaned up
+	before commiting or being passed on. See linkgit:git-commit[1] for more
+	details.
+
 --ff::
 	When the merge resolves as a fast-forward, only update the branch
 	pointer, without creating a merge commit.  This is the default
diff --git a/builtin/merge.c b/builtin/merge.c
index 5ce8946d39..7be03a2610 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -38,6 +38,7 @@
 #include "tag.h"
 #include "alias.h"
 #include "commit-reach.h"
+#include "wt-status.h"
 
 #define DEFAULT_TWOHEAD (1<<0)
 #define DEFAULT_OCTOPUS (1<<1)
@@ -98,6 +99,9 @@ enum ff_type {
 
 static enum ff_type fast_forward = FF_ALLOW;
 
+static const char *cleanup_arg;
+static enum commit_msg_cleanup_mode cleanup_mode;
+
 static int option_parse_message(const struct option *opt,
 				const char *arg, int unset)
 {
@@ -249,6 +253,7 @@ static struct option builtin_merge_options[] = {
 		N_("perform a commit if the merge succeeds (default)")),
 	OPT_BOOL('e', "edit", &option_edit,
 		N_("edit message before committing")),
+	OPT_CLEANUP(&cleanup_arg),
 	OPT_SET_INT(0, "ff", &fast_forward, N_("allow fast-forward (default)"), FF_ALLOW),
 	OPT_SET_INT_F(0, "ff-only", &fast_forward,
 		      N_("abort if fast-forward is not possible"),
@@ -612,6 +617,8 @@ static int git_merge_config(const char *k, const char *v, void *cb)
 		return git_config_string(&pull_twohead, k, v);
 	else if (!strcmp(k, "pull.octopus"))
 		return git_config_string(&pull_octopus, k, v);
+	else if (!strcmp(k, "commit.cleanup"))
+		return git_config_string(&cleanup_arg, k, v);
 	else if (!strcmp(k, "merge.renormalize"))
 		option_renormalize = git_config_bool(k, v);
 	else if (!strcmp(k, "merge.ff")) {
@@ -797,23 +804,32 @@ static void abort_commit(struct commit_list *remoteheads, const char *err_msg)
 	exit(1);
 }
 
+static const char comment_line_explanation[] =
+N_("Lines starting with '%c' will be ignored.\n");
+
 static const char merge_editor_comment[] =
 N_("Please enter a commit message to explain why this merge is necessary,\n"
    "especially if it merges an updated upstream into a topic branch.\n"
    "\n"
-   "Lines starting with '%c' will be ignored, and an empty message aborts\n"
-   "the commit.\n");
+   "An empty message aborts the commit.\n");
 
 static void write_merge_heads(struct commit_list *);
 static void prepare_to_commit(struct commit_list *remoteheads)
 {
 	struct strbuf msg = STRBUF_INIT;
 	strbuf_addbuf(&msg, &merge_msg);
-	strbuf_addch(&msg, '\n');
 	if (squash)
 		BUG("the control must not reach here under --squash");
-	if (0 < option_edit)
-		strbuf_commented_addf(&msg, _(merge_editor_comment), comment_line_char);
+	if (0 < option_edit) {
+		strbuf_addch(&msg, '\n');
+		if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)
+			wt_status_append_cut_line(&msg);
+		else
+			strbuf_commented_addf(&msg, _(comment_line_explanation), comment_line_char);
+
+		strbuf_commented_addf(&msg, "\n");
+		strbuf_commented_addf(&msg, _(merge_editor_comment));
+	}
 	if (signoff)
 		append_signoff(&msg, ignore_non_trailer(msg.buf, msg.len), 0);
 	write_merge_heads(remoteheads);
@@ -832,7 +848,7 @@ static void prepare_to_commit(struct commit_list *remoteheads)
 		abort_commit(remoteheads, NULL);
 
 	read_merge_msg(&msg);
-	strbuf_stripspace(&msg, 0 < option_edit);
+	cleanup_message(&msg, cleanup_mode, 0);
 	if (!msg.len)
 		abort_commit(remoteheads, _("Empty commit message."));
 	strbuf_release(&merge_msg);
@@ -880,7 +896,6 @@ static int finish_automerge(struct commit *head,
 	parents = remoteheads;
 	if (!head_subsumed || fast_forward == FF_NO)
 		commit_list_insert(head, &parents);
-	strbuf_addch(&merge_msg, '\n');
 	prepare_to_commit(remoteheads);
 	if (commit_tree(merge_msg.buf, merge_msg.len, result_tree, parents,
 			&result_commit, NULL, sign_commit))
@@ -1389,6 +1404,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
 	if (option_edit < 0)
 		option_edit = default_edit_option();
 
+	cleanup_mode = get_cleanup_mode(cleanup_arg, 0 < option_edit, 1);
+
 	if (!use_strategies) {
 		if (!remoteheads)
 			; /* already up-to-date */
diff --git a/builtin/pull.c b/builtin/pull.c
index 33db889955..292c1dac27 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -101,6 +101,7 @@ static char *opt_signoff;
 static char *opt_squash;
 static char *opt_commit;
 static char *opt_edit;
+static char *opt_cleanup;
 static char *opt_ff;
 static char *opt_verify_signatures;
 static int opt_autostash = -1;
@@ -168,6 +169,9 @@ static struct option pull_options[] = {
 	OPT_PASSTHRU(0, "edit", &opt_edit, NULL,
 		N_("edit message before committing"),
 		PARSE_OPT_NOARG),
+	OPT_PASSTHRU(0, "cleanup", &opt_cleanup, NULL,
+		N_("how to strip spaces and #comments from message"),
+		0),
 	OPT_PASSTHRU(0, "ff", &opt_ff, NULL,
 		N_("allow fast-forward"),
 		PARSE_OPT_NOARG),
@@ -644,6 +648,8 @@ static int run_merge(void)
 		argv_array_push(&args, opt_commit);
 	if (opt_edit)
 		argv_array_push(&args, opt_edit);
+	if (opt_cleanup)
+		argv_array_push(&args, opt_cleanup);
 	if (opt_ff)
 		argv_array_push(&args, opt_ff);
 	if (opt_verify_signatures)
diff --git a/t/t7604-merge-custom-message.sh b/t/t7604-merge-custom-message.sh
index b045fdb413..c9685a318d 100755
--- a/t/t7604-merge-custom-message.sh
+++ b/t/t7604-merge-custom-message.sh
@@ -51,4 +51,71 @@ test_expect_success 'merge --log appends to custom message' '
 	test_cmp exp.log actual
 '
 
+mesg_with_comment_and_newlines='
+# text
+
+'
+
+test_expect_success 'prepare file with comment line and trailing newlines'  '
+	printf "%s" "$mesg_with_comment_and_newlines" >expect
+'
+
+test_expect_success 'cleanup commit messages (verbatim option)' '
+	git reset --hard c1 &&
+	git merge --cleanup=verbatim -F expect c2 &&
+	git cat-file commit HEAD >actual &&
+	sed -e "1,/^$/d" <actual >tmp &&
+	mv tmp actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'cleanup commit messages (whitespace option)' '
+	git reset --hard c1 &&
+	test_write_lines "" "# text" "" >text &&
+	echo "# text" >expect &&
+	git merge --cleanup=whitespace -F text c2 &&
+	git cat-file commit HEAD >actual &&
+	sed -e "1,/^$/d" <actual >tmp &&
+	mv tmp actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'cleanup merge messages (scissors option)' '
+	git reset --hard c1 &&
+	cat >text <<-\EOF &&
+
+	# to be kept
+
+	  # ------------------------ >8 ------------------------
+	# to be kept, too
+	# ------------------------ >8 ------------------------
+	to be removed
+	# ------------------------ >8 ------------------------
+	to be removed, too
+	EOF
+
+	cat >expect <<-\EOF &&
+	# to be kept
+
+	  # ------------------------ >8 ------------------------
+	# to be kept, too
+	EOF
+	git merge --cleanup=scissors -e -F text c2 &&
+	git cat-file commit HEAD >actual &&
+	sed -e "1,/^$/d" <actual >tmp &&
+	mv tmp actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'cleanup commit messages (strip option)' '
+	git reset --hard c1 &&
+	test_write_lines "" "# text" "sample" "" >text &&
+	echo sample >expect &&
+	git merge --cleanup=strip -F text c2 &&
+	git cat-file commit HEAD >actual &&
+	sed -e "1,/^$/d" <actual >tmp &&
+	mv tmp actual &&
+	test_cmp expect actual
+'
+
 test_done
diff --git a/wt-status.c b/wt-status.c
index 445a36204a..b81fcd428d 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -1006,13 +1006,19 @@ size_t wt_status_locate_end(const char *s, size_t len)
 	return len;
 }
 
-void wt_status_add_cut_line(FILE *fp)
+void wt_status_append_cut_line(struct strbuf *buf)
 {
 	const char *explanation = _("Do not modify or remove the line above.\nEverything below it will be ignored.");
+
+	strbuf_commented_addf(buf, "%s", cut_line);
+	strbuf_add_commented_lines(buf, explanation, strlen(explanation));
+}
+
+void wt_status_add_cut_line(FILE *fp)
+{
 	struct strbuf buf = STRBUF_INIT;
 
-	fprintf(fp, "%c %s", comment_line_char, cut_line);
-	strbuf_add_commented_lines(&buf, explanation, strlen(explanation));
+	wt_status_append_cut_line(&buf);
 	fputs(buf.buf, fp);
 	strbuf_release(&buf);
 }
diff --git a/wt-status.h b/wt-status.h
index 3a95975032..64f1ddc9fd 100644
--- a/wt-status.h
+++ b/wt-status.h
@@ -129,6 +129,7 @@ struct wt_status {
 };
 
 size_t wt_status_locate_end(const char *s, size_t len);
+void wt_status_append_cut_line(struct strbuf *buf);
 void wt_status_add_cut_line(FILE *fp);
 void wt_status_prepare(struct repository *r, struct wt_status *s);
 void wt_status_print(struct wt_status *s);
-- 
2.21.0.512.g57bf1b23e1


^ permalink raw reply	[flat|nested] 105+ messages in thread

* [PATCH v8 09/11] merge: add scissors line on merge conflict
  2019-03-17 10:15             ` [PATCH v8 00/11] " Denton Liu
                                 ` (7 preceding siblings ...)
  2019-03-17 10:16               ` [PATCH v8 08/11] merge: cleanup messages like commit Denton Liu
@ 2019-03-17 10:16               ` Denton Liu
  2019-03-17 10:16               ` [PATCH v8 10/11] sequencer.c: define describe_cleanup_mode Denton Liu
                                 ` (3 subsequent siblings)
  12 siblings, 0 replies; 105+ messages in thread
From: Denton Liu @ 2019-03-17 10:16 UTC (permalink / raw)
  To: Git Mailing List
  Cc: Denton Liu, Eric Sunshine, Junio C Hamano, Phillip Wood,
	Ramsay Jones, SZEDER Gábor

This fixes a bug where the scissors line is placed after the Conflicts:
section, in the case where a merge conflict occurs and
commit.cleanup = scissors.

Next, if commit.cleanup = scissors is specified, don't produce a
scissors line in commit if one already exists in the MERGE_MSG file.

Reviewed-by: Eric Sunshine <sunshine@sunshineco.com>
Signed-off-by: Denton Liu <liu.denton@gmail.com>
---
 Documentation/merge-options.txt |  4 ++-
 builtin/commit.c                | 20 ++++++++++----
 builtin/merge.c                 | 14 ++++++++++
 t/t7600-merge.sh                | 48 +++++++++++++++++++++++++++++++++
 4 files changed, 80 insertions(+), 6 deletions(-)

diff --git a/Documentation/merge-options.txt b/Documentation/merge-options.txt
index 646100ea9a..405e16c617 100644
--- a/Documentation/merge-options.txt
+++ b/Documentation/merge-options.txt
@@ -35,7 +35,9 @@ set to `no` at the beginning of them.
 --cleanup=<mode>::
 	This option determines how the merge message will be cleaned up
 	before commiting or being passed on. See linkgit:git-commit[1] for more
-	details.
+	details. In addition, if the '<mode>' is given a value of `scissors`,
+	scissors will be appended to `MERGE_MSG` before being passed on to the
+	commit machinery in the case of a merge conflict.
 
 --ff::
 	When the merge resolves as a fast-forward, only update the branch
diff --git a/builtin/commit.c b/builtin/commit.c
index ba1e6027ba..b9159c2e7b 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -668,6 +668,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
 	const char *hook_arg2 = NULL;
 	int clean_message_contents = (cleanup_mode != COMMIT_MSG_CLEANUP_NONE);
 	int old_display_comment_prefix;
+	int merge_contains_scissors = 0;
 
 	/* This checks and barfs if author is badly specified */
 	determine_author_info(author_ident);
@@ -728,6 +729,8 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
 			strbuf_addbuf(&sb, &message);
 		hook_arg1 = "message";
 	} else if (!stat(git_path_merge_msg(the_repository), &statbuf)) {
+		size_t merge_msg_start;
+
 		/*
 		 * prepend SQUASH_MSG here if it exists and a
 		 * "merge --squash" was originally performed
@@ -738,8 +741,14 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
 			hook_arg1 = "squash";
 		} else
 			hook_arg1 = "merge";
+
+		merge_msg_start = sb.len;
 		if (strbuf_read_file(&sb, git_path_merge_msg(the_repository), 0) < 0)
 			die_errno(_("could not read MERGE_MSG"));
+
+		if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS &&
+		    wt_status_locate_end(sb.buf + merge_msg_start, sb.len - merge_msg_start) < sb.len - merge_msg_start)
+			merge_contains_scissors = 1;
 	} else if (!stat(git_path_squash_msg(the_repository), &statbuf)) {
 		if (strbuf_read_file(&sb, git_path_squash_msg(the_repository), 0) < 0)
 			die_errno(_("could not read SQUASH_MSG"));
@@ -807,7 +816,8 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
 		struct ident_split ci, ai;
 
 		if (whence != FROM_COMMIT) {
-			if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)
+			if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS &&
+				!merge_contains_scissors)
 				wt_status_add_cut_line(s->fp);
 			status_printf_ln(s, GIT_COLOR_NORMAL,
 			    whence == FROM_MERGE
@@ -832,10 +842,10 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
 				_("Please enter the commit message for your changes."
 				  " Lines starting\nwith '%c' will be ignored, and an empty"
 				  " message aborts the commit.\n"), comment_line_char);
-		else if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS &&
-			 whence == FROM_COMMIT)
-			wt_status_add_cut_line(s->fp);
-		else /* COMMIT_MSG_CLEANUP_SPACE, that is. */
+		else if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS) {
+			if (whence == FROM_COMMIT && !merge_contains_scissors)
+				wt_status_add_cut_line(s->fp);
+		} else /* COMMIT_MSG_CLEANUP_SPACE, that is. */
 			status_printf(s, GIT_COLOR_NORMAL,
 				_("Please enter the commit message for your changes."
 				  " Lines starting\n"
diff --git a/builtin/merge.c b/builtin/merge.c
index 7be03a2610..86c54bff76 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -916,6 +916,20 @@ static int suggest_conflicts(void)
 	filename = git_path_merge_msg(the_repository);
 	fp = xfopen(filename, "a");
 
+	/*
+	 * We can't use cleanup_mode because if we're not using the editor,
+	 * get_cleanup_mode will return COMMIT_MSG_CLEANUP_SPACE instead, even
+	 * though the message is meant to be processed later by git-commit.
+	 * Thus, we will get the cleanup mode which is returned when we _are_ using
+	 * an editor.
+	 */
+	if (get_cleanup_mode(cleanup_arg, 1, 1) == COMMIT_MSG_CLEANUP_SCISSORS) {
+	    fputc('\n', fp);
+	    wt_status_add_cut_line(fp);
+	    /* comments out the newline from append_conflicts_hint */
+	    fputc(comment_line_char, fp);
+	}
+
 	append_conflicts_hint(&the_index, &msgbuf);
 	fputs(msgbuf.buf, fp);
 	strbuf_release(&msgbuf);
diff --git a/t/t7600-merge.sh b/t/t7600-merge.sh
index a9620cd991..ed11b08db2 100755
--- a/t/t7600-merge.sh
+++ b/t/t7600-merge.sh
@@ -247,6 +247,54 @@ test_expect_success 'merge --squash c3 with c7' '
 	test_cmp expect actual
 '
 
+test_expect_success 'merge c3 with c7 with commit.cleanup = scissors' '
+	git config commit.cleanup scissors &&
+	git reset --hard c3 &&
+	test_must_fail git merge c7 &&
+	cat result.9z >file &&
+	git commit --no-edit -a &&
+
+	cat >expect <<-\EOF &&
+	Merge tag '"'"'c7'"'"'
+
+	# ------------------------ >8 ------------------------
+	# Do not modify or remove the line above.
+	# Everything below it will be ignored.
+	#
+	# Conflicts:
+	#	file
+	EOF
+	git cat-file commit HEAD >actual &&
+	sed -e '1,/^$/d' <actual >tmp &&
+	mv tmp actual &&
+	test_i18ncmp expect actual
+'
+
+test_expect_success 'merge c3 with c7 with --squash commit.cleanup = scissors' '
+	git config commit.cleanup scissors &&
+	git reset --hard c3 &&
+	test_must_fail git merge --squash c7 &&
+	cat result.9z >file &&
+	git commit --no-edit -a &&
+
+	cat >expect <<-EOF &&
+	Squashed commit of the following:
+
+	$(git show -s c7)
+
+	# ------------------------ >8 ------------------------
+	# Do not modify or remove the line above.
+	# Everything below it will be ignored.
+	#
+	# Conflicts:
+	#	file
+	EOF
+	git cat-file commit HEAD >actual &&
+	sed -e '1,/^$/d' <actual >tmp &&
+	mv tmp actual &&
+	test_i18ncmp expect actual
+'
+
 test_debug 'git log --graph --decorate --oneline --all'
 
 test_expect_success 'merge c1 with c2 and c3' '
-- 
2.21.0.512.g57bf1b23e1


^ permalink raw reply	[flat|nested] 105+ messages in thread

* [PATCH v8 10/11] sequencer.c: define describe_cleanup_mode
  2019-03-17 10:15             ` [PATCH v8 00/11] " Denton Liu
                                 ` (8 preceding siblings ...)
  2019-03-17 10:16               ` [PATCH v8 09/11] merge: add scissors line on merge conflict Denton Liu
@ 2019-03-17 10:16               ` Denton Liu
  2019-03-18 20:04                 ` Eric Sunshine
  2019-03-17 10:16               ` [PATCH v8 11/11] cherry-pick/revert: add scissors line on merge conflict Denton Liu
                                 ` (2 subsequent siblings)
  12 siblings, 1 reply; 105+ messages in thread
From: Denton Liu @ 2019-03-17 10:16 UTC (permalink / raw)
  To: Git Mailing List
  Cc: Denton Liu, Eric Sunshine, Junio C Hamano, Phillip Wood,
	Ramsay Jones, SZEDER Gábor

Define a function which allows us to get the string configuration value
of a enum commit_msg_cleanup_mode. This is done by refactoring
get_cleanup_mode such that it uses a lookup table to find the mappings
between string and enum and then using the same LUT in reverse to define
describe_cleanup_mode.

Reviewed-by: Eric Sunshine <sunshine@sunshineco.com>
Reviewed-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Ramsay Jones <ramsay@ramsayjones.plus.com>
Signed-off-by: Denton Liu <liu.denton@gmail.com>
---
 sequencer.c | 62 ++++++++++++++++++++++++++++++++++++++++-------------
 1 file changed, 47 insertions(+), 15 deletions(-)

diff --git a/sequencer.c b/sequencer.c
index 2cbfb848dd..f782e8bab2 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -160,6 +160,22 @@ static GIT_PATH_FUNC(rebase_path_strategy_opts, "rebase-merge/strategy_opts")
 static GIT_PATH_FUNC(rebase_path_allow_rerere_autoupdate, "rebase-merge/allow_rerere_autoupdate")
 static GIT_PATH_FUNC(rebase_path_reschedule_failed_exec, "rebase-merge/reschedule-failed-exec")
 
+struct cleanup_config_mapping {
+	const char *value;
+	enum commit_msg_cleanup_mode editor;
+	enum commit_msg_cleanup_mode no_editor;
+};
+
+/* the 0th element of this array must be the "default" */
+static struct cleanup_config_mapping cleanup_config_mapping[] = {
+	{ "default", COMMIT_MSG_CLEANUP_ALL, COMMIT_MSG_CLEANUP_SPACE },
+	{ "verbatim", COMMIT_MSG_CLEANUP_NONE, COMMIT_MSG_CLEANUP_NONE },
+	{ "whitespace", COMMIT_MSG_CLEANUP_SPACE, COMMIT_MSG_CLEANUP_SPACE },
+	{ "strip", COMMIT_MSG_CLEANUP_ALL, COMMIT_MSG_CLEANUP_ALL },
+	{ "scissors", COMMIT_MSG_CLEANUP_SCISSORS, COMMIT_MSG_CLEANUP_SPACE },
+	{ NULL, 0, 0 }
+};
+
 static int git_sequencer_config(const char *k, const char *v, void *cb)
 {
 	struct replay_opts *opts = cb;
@@ -504,26 +520,37 @@ static int fast_forward_to(struct repository *r,
 enum commit_msg_cleanup_mode get_cleanup_mode(const char *cleanup_arg,
 	int use_editor, int die_on_error)
 {
-	if (!cleanup_arg || !strcmp(cleanup_arg, "default"))
-		return use_editor ? COMMIT_MSG_CLEANUP_ALL :
-				    COMMIT_MSG_CLEANUP_SPACE;
-	else if (!strcmp(cleanup_arg, "verbatim"))
-		return COMMIT_MSG_CLEANUP_NONE;
-	else if (!strcmp(cleanup_arg, "whitespace"))
-		return COMMIT_MSG_CLEANUP_SPACE;
-	else if (!strcmp(cleanup_arg, "strip"))
-		return COMMIT_MSG_CLEANUP_ALL;
-	else if (!strcmp(cleanup_arg, "scissors"))
-		return use_editor ? COMMIT_MSG_CLEANUP_SCISSORS :
-				    COMMIT_MSG_CLEANUP_SPACE;
-	else if (!die_on_error) {
+	struct cleanup_config_mapping *def = &cleanup_config_mapping[0];
+	struct cleanup_config_mapping *p;
+
+	if (!cleanup_arg)
+		return use_editor ? def->editor :
+				    def->no_editor;
+
+	for (p = cleanup_config_mapping; p->value; p++)
+		if (!strcmp(cleanup_arg, p->value))
+			return use_editor ? p->editor :
+					    p->no_editor;
+
+	if (!die_on_error) {
 		warning(_("invalid cleanup mode %s, falling back to default"), cleanup_arg);
-		return use_editor ? COMMIT_MSG_CLEANUP_ALL :
-				    COMMIT_MSG_CLEANUP_SPACE;
+		return use_editor ? def->editor :
+				    def->no_editor;
 	} else
 		die(_("invalid cleanup mode %s"), cleanup_arg);
 }
 
+static const char *describe_cleanup_mode(enum commit_msg_cleanup_mode cleanup_mode)
+{
+	struct cleanup_config_mapping *curr;
+
+	for (curr = &cleanup_config_mapping[1]; curr->value; curr++)
+		if (cleanup_mode == curr->editor)
+			return curr->value;
+
+	BUG("invalid cleanup_mode provided (%d)", cleanup_mode);
+}
+
 void append_conflicts_hint(struct index_state *istate,
 			   struct strbuf *msgbuf)
 {
@@ -2350,6 +2377,8 @@ static int populate_opts_cb(const char *key, const char *value, void *data)
 		opts->allow_rerere_auto =
 			git_config_bool_or_int(key, value, &error_flag) ?
 				RERERE_AUTOUPDATE : RERERE_NOAUTOUPDATE;
+	else if (!strcmp(key, "options.default-msg-cleanup"))
+		opts->default_msg_cleanup = get_cleanup_mode(value, 1, 1);
 	else
 		return error(_("invalid key: %s"), key);
 
@@ -2754,6 +2783,9 @@ static int save_opts(struct replay_opts *opts)
 		res |= git_config_set_in_file_gently(opts_file, "options.allow-rerere-auto",
 						     opts->allow_rerere_auto == RERERE_AUTOUPDATE ?
 						     "true" : "false");
+
+	res |= git_config_set_in_file_gently(opts_file, "options.default-msg-cleanup",
+					     describe_cleanup_mode(opts->default_msg_cleanup));
 	return res;
 }
 
-- 
2.21.0.512.g57bf1b23e1


^ permalink raw reply	[flat|nested] 105+ messages in thread

* [PATCH v8 11/11] cherry-pick/revert: add scissors line on merge conflict
  2019-03-17 10:15             ` [PATCH v8 00/11] " Denton Liu
                                 ` (9 preceding siblings ...)
  2019-03-17 10:16               ` [PATCH v8 10/11] sequencer.c: define describe_cleanup_mode Denton Liu
@ 2019-03-17 10:16               ` Denton Liu
  2019-03-17 13:05               ` [PATCH v8 00/11] Fix scissors bug during conflict SZEDER Gábor
  2019-03-21  6:53               ` [PATCH v9 " Denton Liu
  12 siblings, 0 replies; 105+ messages in thread
From: Denton Liu @ 2019-03-17 10:16 UTC (permalink / raw)
  To: Git Mailing List
  Cc: Denton Liu, Eric Sunshine, Junio C Hamano, Phillip Wood,
	Ramsay Jones, SZEDER Gábor

Fix a bug where the scissors line is placed after the Conflicts:
section, in the case where a merge conflict occurs and
commit.cleanup = scissors.

Reviewed-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Signed-off-by: Denton Liu <liu.denton@gmail.com>
---
 Documentation/git-cherry-pick.txt |  7 +++
 Documentation/git-revert.txt      |  7 +++
 builtin/merge.c                   |  9 +---
 builtin/rebase--interactive.c     |  2 +-
 builtin/revert.c                  |  5 ++
 sequencer.c                       | 22 +++++---
 sequencer.h                       |  3 +-
 t/t3507-cherry-pick-conflict.sh   | 86 +++++++++++++++++++++++++++++++
 8 files changed, 123 insertions(+), 18 deletions(-)

diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt
index b8cfeec67e..2601e1868e 100644
--- a/Documentation/git-cherry-pick.txt
+++ b/Documentation/git-cherry-pick.txt
@@ -57,6 +57,13 @@ OPTIONS
 	With this option, 'git cherry-pick' will let you edit the commit
 	message prior to committing.
 
+--cleanup=<mode>::
+	This option determines how the commit message will be cleaned up before
+	being passed on. See linkgit:git-commit[1] for more details. In
+	particular, if the '<mode>' is given a value of `scissors`, scissors
+	will be appended to `MERGE_MSG` before being passed on to the commit
+	machinery in the case of a conflict.
+
 -x::
 	When recording the commit, append a line that says
 	"(cherry picked from commit ...)" to the original commit
diff --git a/Documentation/git-revert.txt b/Documentation/git-revert.txt
index 837707a8fd..cabeb9df2c 100644
--- a/Documentation/git-revert.txt
+++ b/Documentation/git-revert.txt
@@ -66,6 +66,13 @@ more details.
 	With this option, 'git revert' will not start the commit
 	message editor.
 
+--cleanup=<mode>::
+	This option determines how the commit message will be cleaned up before
+	being passed on. See linkgit:git-commit[1] for more details. In
+	particular, if the '<mode>' is given a value of `scissors`, scissors
+	will be appended to `MERGE_MSG` before being passed on to the commit
+	machinery in the case of a conflict.
+
 -n::
 --no-commit::
 	Usually the command automatically creates some commits with
diff --git a/builtin/merge.c b/builtin/merge.c
index 86c54bff76..90c64346e9 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -923,14 +923,7 @@ static int suggest_conflicts(void)
 	 * Thus, we will get the cleanup mode which is returned when we _are_ using
 	 * an editor.
 	 */
-	if (get_cleanup_mode(cleanup_arg, 1, 1) == COMMIT_MSG_CLEANUP_SCISSORS) {
-	    fputc('\n', fp);
-	    wt_status_add_cut_line(fp);
-	    /* comments out the newline from append_conflicts_hint */
-	    fputc(comment_line_char, fp);
-	}
-
-	append_conflicts_hint(&the_index, &msgbuf);
+	append_conflicts_hint(&the_index, &msgbuf, get_cleanup_mode(cleanup_arg, 1, 1));
 	fputs(msgbuf.buf, fp);
 	strbuf_release(&msgbuf);
 	fclose(fp);
diff --git a/builtin/rebase--interactive.c b/builtin/rebase--interactive.c
index 888390f911..cf2151b271 100644
--- a/builtin/rebase--interactive.c
+++ b/builtin/rebase--interactive.c
@@ -199,10 +199,10 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)
 		OPT_END()
 	};
 
+	opts.action = REPLAY_INTERACTIVE_REBASE;
 	sequencer_init_config(&opts);
 	git_config_get_bool("rebase.abbreviatecommands", &abbreviate_commands);
 
-	opts.action = REPLAY_INTERACTIVE_REBASE;
 	opts.allow_ff = 1;
 	opts.allow_empty = 1;
 
diff --git a/builtin/revert.c b/builtin/revert.c
index a47b53ceaf..41e7392c24 100644
--- a/builtin/revert.c
+++ b/builtin/revert.c
@@ -96,11 +96,13 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
 {
 	const char * const * usage_str = revert_or_cherry_pick_usage(opts);
 	const char *me = action_name(opts);
+	const char *cleanup_arg = NULL;
 	int cmd = 0;
 	struct option base_options[] = {
 		OPT_CMDMODE(0, "quit", &cmd, N_("end revert or cherry-pick sequence"), 'q'),
 		OPT_CMDMODE(0, "continue", &cmd, N_("resume revert or cherry-pick sequence"), 'c'),
 		OPT_CMDMODE(0, "abort", &cmd, N_("cancel revert or cherry-pick sequence"), 'a'),
+		OPT_CLEANUP(&cleanup_arg),
 		OPT_BOOL('n', "no-commit", &opts->no_commit, N_("don't automatically commit")),
 		OPT_BOOL('e', "edit", &opts->edit, N_("edit the commit message")),
 		OPT_NOOP_NOARG('r', NULL),
@@ -137,6 +139,9 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
 	if (opts->keep_redundant_commits)
 		opts->allow_empty = 1;
 
+	if (cleanup_arg)
+		opts->default_msg_cleanup = get_cleanup_mode(cleanup_arg, 1, 1);
+
 	/* Check for incompatible command line arguments */
 	if (cmd) {
 		char *this_operation;
diff --git a/sequencer.c b/sequencer.c
index f782e8bab2..ea4687c3da 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -176,6 +176,11 @@ static struct cleanup_config_mapping cleanup_config_mapping[] = {
 	{ NULL, 0, 0 }
 };
 
+static inline int is_rebase_i(const struct replay_opts *opts)
+{
+	return opts->action == REPLAY_INTERACTIVE_REBASE;
+}
+
 static int git_sequencer_config(const char *k, const char *v, void *cb)
 {
 	struct replay_opts *opts = cb;
@@ -188,7 +193,7 @@ static int git_sequencer_config(const char *k, const char *v, void *cb)
 		if (status)
 			return status;
 
-		opts->default_msg_cleanup = get_cleanup_mode(s, 0, 0);
+		opts->default_msg_cleanup = get_cleanup_mode(s, !is_rebase_i(opts), 0);
 
 		free((char *)s);
 		return status;
@@ -212,11 +217,6 @@ void sequencer_init_config(struct replay_opts *opts)
 	git_config(git_sequencer_config, opts);
 }
 
-static inline int is_rebase_i(const struct replay_opts *opts)
-{
-	return opts->action == REPLAY_INTERACTIVE_REBASE;
-}
-
 static const char *get_dir(const struct replay_opts *opts)
 {
 	if (is_rebase_i(opts))
@@ -552,10 +552,16 @@ static const char *describe_cleanup_mode(enum commit_msg_cleanup_mode cleanup_mo
 }
 
 void append_conflicts_hint(struct index_state *istate,
-			   struct strbuf *msgbuf)
+		struct strbuf *msgbuf, enum commit_msg_cleanup_mode cleanup_mode)
 {
 	int i;
 
+	if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS) {
+		strbuf_addch(msgbuf, '\n');
+		wt_status_append_cut_line(msgbuf);
+		strbuf_addch(msgbuf, comment_line_char);
+	}
+
 	strbuf_addch(msgbuf, '\n');
 	strbuf_commented_addf(msgbuf, "Conflicts:\n");
 	for (i = 0; i < istate->cache_nr;) {
@@ -623,7 +629,7 @@ static int do_recursive_merge(struct repository *r,
 			_(action_name(opts)));
 
 	if (!clean)
-		append_conflicts_hint(r->index, msgbuf);
+		append_conflicts_hint(r->index, msgbuf, opts->default_msg_cleanup);
 
 	return !clean;
 }
diff --git a/sequencer.h b/sequencer.h
index e7908f558e..830d8232f6 100644
--- a/sequencer.h
+++ b/sequencer.h
@@ -115,7 +115,8 @@ int rearrange_squash(struct repository *r);
  */
 void append_signoff(struct strbuf *msgbuf, size_t ignore_footer, unsigned flag);
 
-void append_conflicts_hint(struct index_state *istate, struct strbuf *msgbuf);
+void append_conflicts_hint(struct index_state *istate,
+		struct strbuf *msgbuf, enum commit_msg_cleanup_mode cleanup_mode);
 enum commit_msg_cleanup_mode get_cleanup_mode(const char *cleanup_arg,
 	int use_editor, int die_on_error);
 
diff --git a/t/t3507-cherry-pick-conflict.sh b/t/t3507-cherry-pick-conflict.sh
index 74ff925526..c3894ca9d6 100755
--- a/t/t3507-cherry-pick-conflict.sh
+++ b/t/t3507-cherry-pick-conflict.sh
@@ -189,6 +189,46 @@ test_expect_success 'failed cherry-pick registers participants in index' '
 	test_cmp expected actual
 '
 
+test_expect_success \
+	'cherry-pick conflict, ensure commit.cleanup = scissors places scissors line properly' '
+	pristine_detach initial &&
+	git config commit.cleanup scissors &&
+	cat <<-EOF >expected &&
+		picked
+
+		# ------------------------ >8 ------------------------
+		# Do not modify or remove the line above.
+		# Everything below it will be ignored.
+		#
+		# Conflicts:
+		#	foo
+		EOF
+
+	test_must_fail git cherry-pick picked &&
+
+	test_i18ncmp expected .git/MERGE_MSG
+'
+
+test_expect_success \
+	'cherry-pick conflict, ensure cleanup=scissors places scissors line properly' '
+	pristine_detach initial &&
+	git config --unset commit.cleanup &&
+	cat <<-EOF >expected &&
+		picked
+
+		# ------------------------ >8 ------------------------
+		# Do not modify or remove the line above.
+		# Everything below it will be ignored.
+		#
+		# Conflicts:
+		#	foo
+		EOF
+
+	test_must_fail git cherry-pick --cleanup=scissors picked &&
+
+	test_i18ncmp expected .git/MERGE_MSG
+'
+
 test_expect_success 'failed cherry-pick describes conflict in work tree' '
 	pristine_detach initial &&
 	cat <<-EOF >expected &&
@@ -335,6 +375,52 @@ test_expect_success 'revert conflict, diff3 -m style' '
 	test_cmp expected actual
 '
 
+test_expect_success \
+	'revert conflict, ensure commit.cleanup = scissors places scissors line properly' '
+	pristine_detach initial &&
+	git config commit.cleanup scissors &&
+	cat >expected <<-EOF &&
+		Revert "picked"
+
+		This reverts commit OBJID.
+
+		# ------------------------ >8 ------------------------
+		# Do not modify or remove the line above.
+		# Everything below it will be ignored.
+		#
+		# Conflicts:
+		#	foo
+		EOF
+
+	test_must_fail git revert picked &&
+
+	sed "s/$OID_REGEX/OBJID/" .git/MERGE_MSG >actual &&
+	test_i18ncmp expected actual
+'
+
+test_expect_success \
+	'revert conflict, ensure cleanup=scissors places scissors line properly' '
+	pristine_detach initial &&
+	git config --unset commit.cleanup &&
+	cat >expected <<-EOF &&
+		Revert "picked"
+
+		This reverts commit OBJID.
+
+		# ------------------------ >8 ------------------------
+		# Do not modify or remove the line above.
+		# Everything below it will be ignored.
+		#
+		# Conflicts:
+		#	foo
+		EOF
+
+	test_must_fail git revert --cleanup=scissors picked &&
+
+	sed "s/$OID_REGEX/OBJID/" .git/MERGE_MSG >actual &&
+	test_i18ncmp expected actual
+'
+
 test_expect_success 'failed cherry-pick does not forget -s' '
 	pristine_detach initial &&
 	test_must_fail git cherry-pick -s picked &&
-- 
2.21.0.512.g57bf1b23e1


^ permalink raw reply	[flat|nested] 105+ messages in thread

* Re: [PATCH v8 00/11] Fix scissors bug during conflict
  2019-03-17 10:15             ` [PATCH v8 00/11] " Denton Liu
                                 ` (10 preceding siblings ...)
  2019-03-17 10:16               ` [PATCH v8 11/11] cherry-pick/revert: add scissors line on merge conflict Denton Liu
@ 2019-03-17 13:05               ` SZEDER Gábor
  2019-03-18  3:02                 ` Denton Liu
  2019-03-18  6:35                 ` Junio C Hamano
  2019-03-21  6:53               ` [PATCH v9 " Denton Liu
  12 siblings, 2 replies; 105+ messages in thread
From: SZEDER Gábor @ 2019-03-17 13:05 UTC (permalink / raw)
  To: Denton Liu
  Cc: Git Mailing List, Eric Sunshine, Junio C Hamano, Phillip Wood,
	Ramsay Jones

On Sun, Mar 17, 2019 at 03:15:50AM -0700, Denton Liu wrote:
> Sorry for taking so long to do a reroll, I've been pretty busy this week
> and I've only been able to find the time now.

No problem, and thank you for sticking with it!


> diff --git a/t/t7502-commit-porcelain.sh b/t/t7502-commit-porcelain.sh
> index ca4a740da0..f035e4a507 100755
> --- a/t/t7502-commit-porcelain.sh
> +++ b/t/t7502-commit-porcelain.sh
> @@ -16,7 +16,9 @@ commit_msg_is () {
>  # Arguments: [<prefix] [<commit message>] [<commit options>]
>  check_summary_oneline() {
>  	test_tick &&
> -	git commit ${3+"$3"} -m "$2" | head -1 > act &&
> +	git commit ${3+"$3"} -m "$2" >act &&
> +	head -1 <act >tmp &&
> +	mv tmp act &&

Here you could swap the order of when you write to 'act' and 'tmp',
and thus make the 'mv' unnecessary, like this:

  git commit [...] >tmp &&
  head -1 act >tmp &&
  [...rest of the test...]

Note also that 'head' (or 'sed' in later tests) can open its input
file on its own, there's no need to redirect its standard input.

This is a recurring pattern in patches 1, 4, 8, and 9.

> @@ -142,8 +144,8 @@ test_expect_success 'sign off' '
>  	>positive &&
>  	git add positive &&
>  	git commit -s -m "thank you" &&
> -	actual=$(git cat-file commit HEAD | sed -ne "s/Signed-off-by: //p") &&
> -	expected=$(git var GIT_COMMITTER_IDENT | sed -e "s/>.*/>/") &&
> +	actual=$(git cat-file commit HEAD >tmp && sed -ne "s/Signed-off-by: //p" <tmp && rm tmp) &&
> +	expected=$(git var GIT_COMMITTER_IDENT >tmp && sed -e "s/>.*/>/" <tmp && rm tmp) &&
>  	test "z$actual" = "z$expected"

May I ask you to go one step further in restructuring this and the
following tests? :)  Instead of using 'test' to compare the contents
of the $actual and $expected variables, use 'test_cmp' to compare the
'actual' and 'expected' files, something like:

  git cat-file commit HEAD >tmp &&
  sed -ne "s/Signed-off-by: //p" tmp >actual &&
  git var GIT_COMMITTER_IDENT >tmp &&
  sed -e "s/>.*/>/" >expected &&
  test_cmp expected actual


 

^ permalink raw reply	[flat|nested] 105+ messages in thread

* Re: [PATCH v8 00/11] Fix scissors bug during conflict
  2019-03-17 13:05               ` [PATCH v8 00/11] Fix scissors bug during conflict SZEDER Gábor
@ 2019-03-18  3:02                 ` Denton Liu
  2019-03-18  6:35                 ` Junio C Hamano
  1 sibling, 0 replies; 105+ messages in thread
From: Denton Liu @ 2019-03-18  3:02 UTC (permalink / raw)
  To: SZEDER Gábor
  Cc: Git Mailing List, Eric Sunshine, Junio C Hamano, Phillip Wood,
	Ramsay Jones

Hi Szeder,

On Sun, Mar 17, 2019 at 02:05:39PM +0100, SZEDER Gábor wrote:
> On Sun, Mar 17, 2019 at 03:15:50AM -0700, Denton Liu wrote:
> > Sorry for taking so long to do a reroll, I've been pretty busy this week
> > and I've only been able to find the time now.
> 
> No problem, and thank you for sticking with it!
> 
> 
> > diff --git a/t/t7502-commit-porcelain.sh b/t/t7502-commit-porcelain.sh
> > index ca4a740da0..f035e4a507 100755
> > --- a/t/t7502-commit-porcelain.sh
> > +++ b/t/t7502-commit-porcelain.sh
> > @@ -16,7 +16,9 @@ commit_msg_is () {
> >  # Arguments: [<prefix] [<commit message>] [<commit options>]
> >  check_summary_oneline() {
> >  	test_tick &&
> > -	git commit ${3+"$3"} -m "$2" | head -1 > act &&
> > +	git commit ${3+"$3"} -m "$2" >act &&
> > +	head -1 <act >tmp &&
> > +	mv tmp act &&
> 
> Here you could swap the order of when you write to 'act' and 'tmp',
> and thus make the 'mv' unnecessary, like this:
> 
>   git commit [...] >tmp &&
>   head -1 act >tmp &&
>   [...rest of the test...]
> 
> Note also that 'head' (or 'sed' in later tests) can open its input
> file on its own, there's no need to redirect its standard input.
> 
> This is a recurring pattern in patches 1, 4, 8, and 9.
> 

The reason I did it this way was because earlier, Junio said:
> > -     git cat-file commit HEAD | sed -e '1,/^$/d' >actual &&
> > +     git cat-file commit HEAD >tmp &&
> > +     sed -e '1,/^$/d' <tmp >actual &&
> 
> The intermediary file may want a name better than 'tmp', if it is to
> be left behind, but this will do for now.

So I opted to write the tests in a way where a tmp file won't be
produced. This pattern was shamelessly stolen from 
'set up mod-256 conflict scenario' in t7600 where it does the following:

	# 256 near-identical stanzas...
	for i in $(test_seq 1 256); do
		for j in 1 2 3 4 5; do
			echo $i-$j
		done
	done >file &&
	git add file &&
	git commit -m base &&

	# one side changes the first line of each to "master"
	sed s/-1/-master/ <file >tmp &&
	mv tmp file &&
	git commit -am master &&

Good point about the heads and seds, though. I completely forgot that
they accept a file argument.

> > @@ -142,8 +144,8 @@ test_expect_success 'sign off' '
> >  	>positive &&
> >  	git add positive &&
> >  	git commit -s -m "thank you" &&
> > -	actual=$(git cat-file commit HEAD | sed -ne "s/Signed-off-by: //p") &&
> > -	expected=$(git var GIT_COMMITTER_IDENT | sed -e "s/>.*/>/") &&
> > +	actual=$(git cat-file commit HEAD >tmp && sed -ne "s/Signed-off-by: //p" <tmp && rm tmp) &&
> > +	expected=$(git var GIT_COMMITTER_IDENT >tmp && sed -e "s/>.*/>/" <tmp && rm tmp) &&
> >  	test "z$actual" = "z$expected"
> 
> May I ask you to go one step further in restructuring this and the
> following tests? :)  Instead of using 'test' to compare the contents
> of the $actual and $expected variables, use 'test_cmp' to compare the
> 'actual' and 'expected' files, something like:
> 
>   git cat-file commit HEAD >tmp &&
>   sed -ne "s/Signed-off-by: //p" tmp >actual &&
>   git var GIT_COMMITTER_IDENT >tmp &&
>   sed -e "s/>.*/>/" >expected &&
>   test_cmp expected actual

Will do.

Thanks,

Denton

^ permalink raw reply	[flat|nested] 105+ messages in thread

* Re: [PATCH v8 00/11] Fix scissors bug during conflict
  2019-03-17 13:05               ` [PATCH v8 00/11] Fix scissors bug during conflict SZEDER Gábor
  2019-03-18  3:02                 ` Denton Liu
@ 2019-03-18  6:35                 ` Junio C Hamano
  2019-03-18  8:03                   ` Denton Liu
  1 sibling, 1 reply; 105+ messages in thread
From: Junio C Hamano @ 2019-03-18  6:35 UTC (permalink / raw)
  To: SZEDER Gábor
  Cc: Denton Liu, Git Mailing List, Eric Sunshine, Phillip Wood, Ramsay Jones

SZEDER Gábor <szeder.dev@gmail.com> writes:

>> +	git commit ${3+"$3"} -m "$2" >act &&
>> +	head -1 <act >tmp &&
>> +	mv tmp act &&
>
> Here you could swap the order of when you write to 'act' and 'tmp',
> and thus make the 'mv' unnecessary, like this:
>
>   git commit [...] >tmp &&
>   head -1 act >tmp &&
>   [...rest of the test...]
>
> Note also that 'head' (or 'sed' in later tests) can open its input
> file on its own, there's no need to redirect its standard input.

Yup, that is better with a slight fix

	git testing-output-from-this-command ... >tmp &&
	head -n 1 tmp >actual &&

to actually read from the output kept in the temporary file.

Especially I think bare -<num> is a BSDism that has been
removed from POSIX some time ago.

^ permalink raw reply	[flat|nested] 105+ messages in thread

* Re: [PATCH v8 00/11] Fix scissors bug during conflict
  2019-03-18  6:35                 ` Junio C Hamano
@ 2019-03-18  8:03                   ` Denton Liu
  2019-03-18  8:25                     ` Junio C Hamano
  0 siblings, 1 reply; 105+ messages in thread
From: Denton Liu @ 2019-03-18  8:03 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: SZEDER Gábor, Git Mailing List, Eric Sunshine, Phillip Wood,
	Ramsay Jones

Hi Junio,

On Mon, Mar 18, 2019 at 03:35:56PM +0900, Junio C Hamano wrote:
> SZEDER Gábor <szeder.dev@gmail.com> writes:
> 
> >> +	git commit ${3+"$3"} -m "$2" >act &&
> >> +	head -1 <act >tmp &&
> >> +	mv tmp act &&
> >
> > Here you could swap the order of when you write to 'act' and 'tmp',
> > and thus make the 'mv' unnecessary, like this:
> >
> >   git commit [...] >tmp &&
> >   head -1 act >tmp &&
> >   [...rest of the test...]
> >
> > Note also that 'head' (or 'sed' in later tests) can open its input
> > file on its own, there's no need to redirect its standard input.
> 
> Yup, that is better with a slight fix
> 
> 	git testing-output-from-this-command ... >tmp &&
> 	head -n 1 tmp >actual &&
> 
> to actually read from the output kept in the temporary file.
> 
> Especially I think bare -<num> is a BSDism that has been
> removed from POSIX some time ago.

You mentioned in an earlier email that,

> The intermediary file may want a name better than 'tmp', if it is to
> be left behind, but this will do for now.

so I wrote it in a way temporary files wouldn't be produced, similar to
how 'set up mod-256 conflict scenario' in t7600 does it.

Would it be better to leave the temporary files behind like how v7 of
the patches did it or should keep the mv?

Thanks,

Denton

^ permalink raw reply	[flat|nested] 105+ messages in thread

* Re: [PATCH v8 00/11] Fix scissors bug during conflict
  2019-03-18  8:03                   ` Denton Liu
@ 2019-03-18  8:25                     ` Junio C Hamano
  0 siblings, 0 replies; 105+ messages in thread
From: Junio C Hamano @ 2019-03-18  8:25 UTC (permalink / raw)
  To: Denton Liu
  Cc: SZEDER Gábor, Git Mailing List, Eric Sunshine, Phillip Wood,
	Ramsay Jones

Denton Liu <liu.denton@gmail.com> writes:

>> > Here you could swap the order of when you write to 'act' and 'tmp',
>> > and thus make the 'mv' unnecessary, like this:
>> >
>> >   git commit [...] >tmp &&
>> >   head -1 act >tmp &&
>> >   [...rest of the test...]
>> >
>> > Note also that 'head' (or 'sed' in later tests) can open its input
>> > file on its own, there's no need to redirect its standard input.
>> 
>> Yup, that is better with a slight fix
>> 
>> 	git testing-output-from-this-command ... >tmp &&
>> 	head -n 1 tmp >actual &&
>> 
>> to actually read from the output kept in the temporary file.
>> 
>> Especially I think bare -<num> is a BSDism that has been
>> removed from POSIX some time ago.
>
> You mentioned in an earlier email that,
>
>> The intermediary file may want a name better than 'tmp', if it is to
>> be left behind, but this will do for now.
>
> so I wrote it in a way temporary files wouldn't be produced, similar to
> how 'set up mod-256 conflict scenario' in t7600 does it.

I didn't mean to say that the name of the final file should be
garbage, though ;-) I was hinting, by mentioning "if it is to be
left behind", to remove it when you are done with the temporary.

If we were to give more meaningful name, then perhaps just get rid
of the name "tmp", like so.

	echo what is expected >expect &&
	git testing-output-from-this-command ... >output.raw &&
	sed-or-something-to-extract-what-matters output.raw >actual &&
	test_cmp expect actual

which is also good (and when the test fails, looking at the trash
directory and finding the raw output named *.raw may be easier from
the output of "ls trash*" while debugging).


^ permalink raw reply	[flat|nested] 105+ messages in thread

* Re: [PATCH v8 10/11] sequencer.c: define describe_cleanup_mode
  2019-03-17 10:16               ` [PATCH v8 10/11] sequencer.c: define describe_cleanup_mode Denton Liu
@ 2019-03-18 20:04                 ` Eric Sunshine
  2019-03-18 20:30                   ` Denton Liu
  2019-03-19  0:55                   ` Ramsay Jones
  0 siblings, 2 replies; 105+ messages in thread
From: Eric Sunshine @ 2019-03-18 20:04 UTC (permalink / raw)
  To: Denton Liu
  Cc: Git Mailing List, Junio C Hamano, Phillip Wood, Ramsay Jones,
	SZEDER Gábor

On Sun, Mar 17, 2019 at 6:16 AM Denton Liu <liu.denton@gmail.com> wrote:
> Define a function which allows us to get the string configuration value
> of a enum commit_msg_cleanup_mode. This is done by refactoring
> get_cleanup_mode such that it uses a lookup table to find the mappings
> between string and enum and then using the same LUT in reverse to define
> describe_cleanup_mode.
>
> Reviewed-by: Eric Sunshine <sunshine@sunshineco.com>
> Reviewed-by: Junio C Hamano <gitster@pobox.com>

These two Reviewed-by: lines should be dropped for a couple reasons.

First, neither Junio nor I reviewed _this_ version of the patch.

Second, a Reviewed-by: is given explicitly (not taken). When a
reviewer has thoroughly read and understood a patch and considers it
problem-free, he or she may say explicitly "Reviewed-by: <me>",
stating satisfaction that the patch seems worthy of inclusion in the
project. If he sees fit, Junio may then pick up that Reviewed-by: at
the time he queues the patch in his tree.

> Signed-off-by: Ramsay Jones <ramsay@ramsayjones.plus.com>
> Signed-off-by: Denton Liu <liu.denton@gmail.com>

^ permalink raw reply	[flat|nested] 105+ messages in thread

* Re: [PATCH v8 10/11] sequencer.c: define describe_cleanup_mode
  2019-03-18 20:04                 ` Eric Sunshine
@ 2019-03-18 20:30                   ` Denton Liu
  2019-03-18 20:32                     ` Eric Sunshine
  2019-03-19  0:55                   ` Ramsay Jones
  1 sibling, 1 reply; 105+ messages in thread
From: Denton Liu @ 2019-03-18 20:30 UTC (permalink / raw)
  To: Eric Sunshine
  Cc: Git Mailing List, Junio C Hamano, Phillip Wood, Ramsay Jones,
	SZEDER Gábor

On Mon, Mar 18, 2019 at 04:04:22PM -0400, Eric Sunshine wrote:
> On Sun, Mar 17, 2019 at 6:16 AM Denton Liu <liu.denton@gmail.com> wrote:
> > Define a function which allows us to get the string configuration value
> > of a enum commit_msg_cleanup_mode. This is done by refactoring
> > get_cleanup_mode such that it uses a lookup table to find the mappings
> > between string and enum and then using the same LUT in reverse to define
> > describe_cleanup_mode.
> >
> > Reviewed-by: Eric Sunshine <sunshine@sunshineco.com>
> > Reviewed-by: Junio C Hamano <gitster@pobox.com>
> 
> These two Reviewed-by: lines should be dropped for a couple reasons.
> 
> First, neither Junio nor I reviewed _this_ version of the patch.
> 
> Second, a Reviewed-by: is given explicitly (not taken). When a
> reviewer has thoroughly read and understood a patch and considers it
> problem-free, he or she may say explicitly "Reviewed-by: <me>",
> stating satisfaction that the patch seems worthy of inclusion in the
> project. If he sees fit, Junio may then pick up that Reviewed-by: at
> the time he queues the patch in his tree.

My mistake, I misunderstood the purpose of the Reviewed-by tag.

I was using it to give credit for changes that I incorporated in
response to a review. In addition, it was helpful for bookkeeping who
suggested what where.

Would a Helped-by tag be more appropriate in this situation?

Thanks,

Denton

> 
> > Signed-off-by: Ramsay Jones <ramsay@ramsayjones.plus.com>
> > Signed-off-by: Denton Liu <liu.denton@gmail.com>

^ permalink raw reply	[flat|nested] 105+ messages in thread

* Re: [PATCH v8 10/11] sequencer.c: define describe_cleanup_mode
  2019-03-18 20:30                   ` Denton Liu
@ 2019-03-18 20:32                     ` Eric Sunshine
  0 siblings, 0 replies; 105+ messages in thread
From: Eric Sunshine @ 2019-03-18 20:32 UTC (permalink / raw)
  To: Denton Liu
  Cc: Git Mailing List, Junio C Hamano, Phillip Wood, Ramsay Jones,
	SZEDER Gábor

On Mon, Mar 18, 2019 at 4:30 PM Denton Liu <liu.denton@gmail.com> wrote:
> On Mon, Mar 18, 2019 at 04:04:22PM -0400, Eric Sunshine wrote:
> > These two Reviewed-by: lines should be dropped for a couple reasons.
> >
> I was using it to give credit for changes that I incorporated in
> response to a review. In addition, it was helpful for bookkeeping who
> suggested what where.
>
> Would a Helped-by tag be more appropriate in this situation?

Using Helped-by: would be quite appropriate.

^ permalink raw reply	[flat|nested] 105+ messages in thread

* Re: [PATCH v8 10/11] sequencer.c: define describe_cleanup_mode
  2019-03-18 20:04                 ` Eric Sunshine
  2019-03-18 20:30                   ` Denton Liu
@ 2019-03-19  0:55                   ` Ramsay Jones
  1 sibling, 0 replies; 105+ messages in thread
From: Ramsay Jones @ 2019-03-19  0:55 UTC (permalink / raw)
  To: Eric Sunshine, Denton Liu
  Cc: Git Mailing List, Junio C Hamano, Phillip Wood, SZEDER Gábor



On 18/03/2019 20:04, Eric Sunshine wrote:
> On Sun, Mar 17, 2019 at 6:16 AM Denton Liu <liu.denton@gmail.com> wrote:
>> Define a function which allows us to get the string configuration value
>> of a enum commit_msg_cleanup_mode. This is done by refactoring
>> get_cleanup_mode such that it uses a lookup table to find the mappings
>> between string and enum and then using the same LUT in reverse to define
>> describe_cleanup_mode.
>>
>> Reviewed-by: Eric Sunshine <sunshine@sunshineco.com>
>> Reviewed-by: Junio C Hamano <gitster@pobox.com>
> 
> These two Reviewed-by: lines should be dropped for a couple reasons.
> 
> First, neither Junio nor I reviewed _this_ version of the patch.
> 
> Second, a Reviewed-by: is given explicitly (not taken). When a
> reviewer has thoroughly read and understood a patch and considers it
> problem-free, he or she may say explicitly "Reviewed-by: <me>",
> stating satisfaction that the patch seems worthy of inclusion in the
> project. If he sees fit, Junio may then pick up that Reviewed-by: at
> the time he queues the patch in his tree.
> 
>> Signed-off-by: Ramsay Jones <ramsay@ramsayjones.plus.com>

I was similarly surprised to see this SOB line as well. There was
nothing copyright-able in the 'squash patch' I sent, so I don't
think this is warranted. (A 'Helped-by:' at _most_, I would think).
;-)

ATB,
Ramsay Jones

^ permalink raw reply	[flat|nested] 105+ messages in thread

* Re: [PATCH v8 08/11] merge: cleanup messages like commit
  2019-03-17 10:16               ` [PATCH v8 08/11] merge: cleanup messages like commit Denton Liu
@ 2019-03-19 11:13                 ` Phillip Wood
  2019-03-20  6:32                   ` Denton Liu
  0 siblings, 1 reply; 105+ messages in thread
From: Phillip Wood @ 2019-03-19 11:13 UTC (permalink / raw)
  To: Denton Liu, Git Mailing List
  Cc: Eric Sunshine, Junio C Hamano, Phillip Wood, Ramsay Jones,
	SZEDER Gábor

Hi Denton

On 17/03/2019 10:16, Denton Liu wrote:
> This change allows git-merge messages to be cleaned up with the
> commit.cleanup configuration or --cleanup option, just like how
> git-commit does it.
> 
> We also give git-pull the passthrough option of --cleanup so that it can
> also take advantage of this change.
> 
> Finally, add testing to ensure that messages are properly cleaned up.
> Note that some newlines that were added to the commit message were
> removed so that if a file were read via -F, it would be copied
> faithfully.
> 
> Reviewed-by: Phillip Wood <phillip.wood@dunelm.org.uk>

I'd echo Eric's comments about Reviewed-by tags.

> Reviewed-by: Eric Sunshine <sunshine@sunshineco.com>
> Signed-off-by: Denton Liu <liu.denton@gmail.com>
> ---
> 
> Phillip Wood wrote:
>> cleanup needs to take an argument so PARSE_OPT_NOARG does not look
>> right. Also I think it would be bettor from the user's point of view if
>> the value of the argument was checked by pull before it does any work
>> rather otherwise if they pass in invalid value pull mostly runs and then
>> merge errors out at the end.
> 
> I opted not to do a check on the validity of the value of the
> --cleanup-mode argument because the strategy options that existed before
> also didn't verify the validity of their values. In the future, it might
> be a good idea to check the values of both cleanup-mode and the
> strategy options but for now, I think we can leave it as it is.

With --strategy-option the valid values depend on the --strategy option 
which may invoke an external command so in general there is no way to 
check the values are valid (it could do for the strategies we know 
about). With --cleanup we know the valid values and have a function that 
can check for them so I think it would be worth doing.

>   Documentation/merge-options.txt |  5 +++
>   builtin/merge.c                 | 31 +++++++++++----
>   builtin/pull.c                  |  6 +++
>   t/t7604-merge-custom-message.sh | 67 +++++++++++++++++++++++++++++++++
>   wt-status.c                     | 12 ++++--
>   wt-status.h                     |  1 +
>   6 files changed, 112 insertions(+), 10 deletions(-)
> 
> diff --git a/Documentation/merge-options.txt b/Documentation/merge-options.txt
> index 92a7d936c1..646100ea9a 100644
> --- a/Documentation/merge-options.txt
> +++ b/Documentation/merge-options.txt
> @@ -32,6 +32,11 @@ they run `git merge`. To make it easier to adjust such scripts to the
>   updated behaviour, the environment variable `GIT_MERGE_AUTOEDIT` can be
>   set to `no` at the beginning of them.
>   
> +--cleanup=<mode>::
> +	This option determines how the merge message will be cleaned up
> +	before commiting or being passed on. See linkgit:git-commit[1] for more

As I commented before I don't understand 'passed on'

> +	details.
> +
>   --ff::
>   	When the merge resolves as a fast-forward, only update the branch
>   	pointer, without creating a merge commit.  This is the default
> diff --git a/builtin/merge.c b/builtin/merge.c
> index 5ce8946d39..7be03a2610 100644
> --- a/builtin/merge.c
> +++ b/builtin/merge.c
> @@ -38,6 +38,7 @@
>   #include "tag.h"
>   #include "alias.h"
>   #include "commit-reach.h"
> +#include "wt-status.h"
>   
>   #define DEFAULT_TWOHEAD (1<<0)
>   #define DEFAULT_OCTOPUS (1<<1)
> @@ -98,6 +99,9 @@ enum ff_type {
>   
>   static enum ff_type fast_forward = FF_ALLOW;
>   
> +static const char *cleanup_arg;
> +static enum commit_msg_cleanup_mode cleanup_mode;
> +
>   static int option_parse_message(const struct option *opt,
>   				const char *arg, int unset)
>   {
> @@ -249,6 +253,7 @@ static struct option builtin_merge_options[] = {
>   		N_("perform a commit if the merge succeeds (default)")),
>   	OPT_BOOL('e', "edit", &option_edit,
>   		N_("edit message before committing")),
> +	OPT_CLEANUP(&cleanup_arg),
>   	OPT_SET_INT(0, "ff", &fast_forward, N_("allow fast-forward (default)"), FF_ALLOW),
>   	OPT_SET_INT_F(0, "ff-only", &fast_forward,
>   		      N_("abort if fast-forward is not possible"),
> @@ -612,6 +617,8 @@ static int git_merge_config(const char *k, const char *v, void *cb)
>   		return git_config_string(&pull_twohead, k, v);
>   	else if (!strcmp(k, "pull.octopus"))
>   		return git_config_string(&pull_octopus, k, v);
> +	else if (!strcmp(k, "commit.cleanup"))
> +		return git_config_string(&cleanup_arg, k, v);
>   	else if (!strcmp(k, "merge.renormalize"))
>   		option_renormalize = git_config_bool(k, v);
>   	else if (!strcmp(k, "merge.ff")) {
> @@ -797,23 +804,32 @@ static void abort_commit(struct commit_list *remoteheads, const char *err_msg)
>   	exit(1);
>   }
>   
> +static const char comment_line_explanation[] =
> +N_("Lines starting with '%c' will be ignored.\n");
> +
>   static const char merge_editor_comment[] =
>   N_("Please enter a commit message to explain why this merge is necessary,\n"
>      "especially if it merges an updated upstream into a topic branch.\n"
>      "\n"
> -   "Lines starting with '%c' will be ignored, and an empty message aborts\n"
> -   "the commit.\n");
> +   "An empty message aborts the commit.\n");
>   
>   static void write_merge_heads(struct commit_list *);
>   static void prepare_to_commit(struct commit_list *remoteheads)
>   {
>   	struct strbuf msg = STRBUF_INIT;
>   	strbuf_addbuf(&msg, &merge_msg);
> -	strbuf_addch(&msg, '\n');
>   	if (squash)
>   		BUG("the control must not reach here under --squash");
> -	if (0 < option_edit)
> -		strbuf_commented_addf(&msg, _(merge_editor_comment), comment_line_char);
> +	if (0 < option_edit) {
> +		strbuf_addch(&msg, '\n');
> +		if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)
> +			wt_status_append_cut_line(&msg);
> +		else
> +			strbuf_commented_addf(&msg, _(comment_line_explanation), comment_line_char);
> +
> +		strbuf_commented_addf(&msg, "\n");
> +		strbuf_commented_addf(&msg, _(merge_editor_comment));
> +	}

This still changes the wording of the message cf 
https://public-inbox.org/git/cover.1552275703.git.liu.denton@gmail.com/T/#m09cb1a05eb3bffb47ee9f25572904a7279efa362

Best Wishes

Phillip

>   	if (signoff)
>   		append_signoff(&msg, ignore_non_trailer(msg.buf, msg.len), 0);
>   	write_merge_heads(remoteheads);
> @@ -832,7 +848,7 @@ static void prepare_to_commit(struct commit_list *remoteheads)
>   		abort_commit(remoteheads, NULL);
>   
>   	read_merge_msg(&msg);
> -	strbuf_stripspace(&msg, 0 < option_edit);
> +	cleanup_message(&msg, cleanup_mode, 0);
>   	if (!msg.len)
>   		abort_commit(remoteheads, _("Empty commit message."));
>   	strbuf_release(&merge_msg);
> @@ -880,7 +896,6 @@ static int finish_automerge(struct commit *head,
>   	parents = remoteheads;
>   	if (!head_subsumed || fast_forward == FF_NO)
>   		commit_list_insert(head, &parents);
> -	strbuf_addch(&merge_msg, '\n');
>   	prepare_to_commit(remoteheads);
>   	if (commit_tree(merge_msg.buf, merge_msg.len, result_tree, parents,
>   			&result_commit, NULL, sign_commit))
> @@ -1389,6 +1404,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
>   	if (option_edit < 0)
>   		option_edit = default_edit_option();
>   
> +	cleanup_mode = get_cleanup_mode(cleanup_arg, 0 < option_edit, 1);
> +
>   	if (!use_strategies) {
>   		if (!remoteheads)
>   			; /* already up-to-date */
> diff --git a/builtin/pull.c b/builtin/pull.c
> index 33db889955..292c1dac27 100644
> --- a/builtin/pull.c
> +++ b/builtin/pull.c
> @@ -101,6 +101,7 @@ static char *opt_signoff;
>   static char *opt_squash;
>   static char *opt_commit;
>   static char *opt_edit;
> +static char *opt_cleanup;
>   static char *opt_ff;
>   static char *opt_verify_signatures;
>   static int opt_autostash = -1;
> @@ -168,6 +169,9 @@ static struct option pull_options[] = {
>   	OPT_PASSTHRU(0, "edit", &opt_edit, NULL,
>   		N_("edit message before committing"),
>   		PARSE_OPT_NOARG),
> +	OPT_PASSTHRU(0, "cleanup", &opt_cleanup, NULL,
> +		N_("how to strip spaces and #comments from message"),
> +		0),
>   	OPT_PASSTHRU(0, "ff", &opt_ff, NULL,
>   		N_("allow fast-forward"),
>   		PARSE_OPT_NOARG),
> @@ -644,6 +648,8 @@ static int run_merge(void)
>   		argv_array_push(&args, opt_commit);
>   	if (opt_edit)
>   		argv_array_push(&args, opt_edit);
> +	if (opt_cleanup)
> +		argv_array_push(&args, opt_cleanup);
>   	if (opt_ff)
>   		argv_array_push(&args, opt_ff);
>   	if (opt_verify_signatures)
> diff --git a/t/t7604-merge-custom-message.sh b/t/t7604-merge-custom-message.sh
> index b045fdb413..c9685a318d 100755
> --- a/t/t7604-merge-custom-message.sh
> +++ b/t/t7604-merge-custom-message.sh
> @@ -51,4 +51,71 @@ test_expect_success 'merge --log appends to custom message' '
>   	test_cmp exp.log actual
>   '
>   
> +mesg_with_comment_and_newlines='
> +# text
> +
> +'
> +
> +test_expect_success 'prepare file with comment line and trailing newlines'  '
> +	printf "%s" "$mesg_with_comment_and_newlines" >expect
> +'
> +
> +test_expect_success 'cleanup commit messages (verbatim option)' '
> +	git reset --hard c1 &&
> +	git merge --cleanup=verbatim -F expect c2 &&
> +	git cat-file commit HEAD >actual &&
> +	sed -e "1,/^$/d" <actual >tmp &&
> +	mv tmp actual &&
> +	test_cmp expect actual
> +'
> +
> +test_expect_success 'cleanup commit messages (whitespace option)' '
> +	git reset --hard c1 &&
> +	test_write_lines "" "# text" "" >text &&
> +	echo "# text" >expect &&
> +	git merge --cleanup=whitespace -F text c2 &&
> +	git cat-file commit HEAD >actual &&
> +	sed -e "1,/^$/d" <actual >tmp &&
> +	mv tmp actual &&
> +	test_cmp expect actual
> +'
> +
> +test_expect_success 'cleanup merge messages (scissors option)' '
> +	git reset --hard c1 &&
> +	cat >text <<-\EOF &&
> +
> +	# to be kept
> +
> +	  # ------------------------ >8 ------------------------
> +	# to be kept, too
> +	# ------------------------ >8 ------------------------
> +	to be removed
> +	# ------------------------ >8 ------------------------
> +	to be removed, too
> +	EOF
> +
> +	cat >expect <<-\EOF &&
> +	# to be kept
> +
> +	  # ------------------------ >8 ------------------------
> +	# to be kept, too
> +	EOF
> +	git merge --cleanup=scissors -e -F text c2 &&
> +	git cat-file commit HEAD >actual &&
> +	sed -e "1,/^$/d" <actual >tmp &&
> +	mv tmp actual &&
> +	test_cmp expect actual
> +'
> +
> +test_expect_success 'cleanup commit messages (strip option)' '
> +	git reset --hard c1 &&
> +	test_write_lines "" "# text" "sample" "" >text &&
> +	echo sample >expect &&
> +	git merge --cleanup=strip -F text c2 &&
> +	git cat-file commit HEAD >actual &&
> +	sed -e "1,/^$/d" <actual >tmp &&
> +	mv tmp actual &&
> +	test_cmp expect actual
> +'
> +
>   test_done
> diff --git a/wt-status.c b/wt-status.c
> index 445a36204a..b81fcd428d 100644
> --- a/wt-status.c
> +++ b/wt-status.c
> @@ -1006,13 +1006,19 @@ size_t wt_status_locate_end(const char *s, size_t len)
>   	return len;
>   }
>   
> -void wt_status_add_cut_line(FILE *fp)
> +void wt_status_append_cut_line(struct strbuf *buf)
>   {
>   	const char *explanation = _("Do not modify or remove the line above.\nEverything below it will be ignored.");
> +
> +	strbuf_commented_addf(buf, "%s", cut_line);
> +	strbuf_add_commented_lines(buf, explanation, strlen(explanation));
> +}
> +
> +void wt_status_add_cut_line(FILE *fp)
> +{
>   	struct strbuf buf = STRBUF_INIT;
>   
> -	fprintf(fp, "%c %s", comment_line_char, cut_line);
> -	strbuf_add_commented_lines(&buf, explanation, strlen(explanation));
> +	wt_status_append_cut_line(&buf);
>   	fputs(buf.buf, fp);
>   	strbuf_release(&buf);
>   }
> diff --git a/wt-status.h b/wt-status.h
> index 3a95975032..64f1ddc9fd 100644
> --- a/wt-status.h
> +++ b/wt-status.h
> @@ -129,6 +129,7 @@ struct wt_status {
>   };
>   
>   size_t wt_status_locate_end(const char *s, size_t len);
> +void wt_status_append_cut_line(struct strbuf *buf);
>   void wt_status_add_cut_line(FILE *fp);
>   void wt_status_prepare(struct repository *r, struct wt_status *s);
>   void wt_status_print(struct wt_status *s);
> 

^ permalink raw reply	[flat|nested] 105+ messages in thread

* Re: [PATCH v8 08/11] merge: cleanup messages like commit
  2019-03-19 11:13                 ` Phillip Wood
@ 2019-03-20  6:32                   ` Denton Liu
  0 siblings, 0 replies; 105+ messages in thread
From: Denton Liu @ 2019-03-20  6:32 UTC (permalink / raw)
  To: phillip.wood
  Cc: Git Mailing List, Eric Sunshine, Junio C Hamano, Ramsay Jones,
	SZEDER Gábor

Hi Phillip,

On Tue, Mar 19, 2019 at 11:13:37AM +0000, Phillip Wood wrote:
> Hi Denton
> 
> On 17/03/2019 10:16, Denton Liu wrote:
> > This change allows git-merge messages to be cleaned up with the
> > commit.cleanup configuration or --cleanup option, just like how
> > git-commit does it.
> > 
> > We also give git-pull the passthrough option of --cleanup so that it can
> > also take advantage of this change.
> > 
> > Finally, add testing to ensure that messages are properly cleaned up.
> > Note that some newlines that were added to the commit message were
> > removed so that if a file were read via -F, it would be copied
> > faithfully.
> > 
> > Reviewed-by: Phillip Wood <phillip.wood@dunelm.org.uk>
> 
> I'd echo Eric's comments about Reviewed-by tags.

Will do.

> 
> > Reviewed-by: Eric Sunshine <sunshine@sunshineco.com>
> > Signed-off-by: Denton Liu <liu.denton@gmail.com>
> > ---
> > 
> > Phillip Wood wrote:
> > > cleanup needs to take an argument so PARSE_OPT_NOARG does not look
> > > right. Also I think it would be bettor from the user's point of view if
> > > the value of the argument was checked by pull before it does any work
> > > rather otherwise if they pass in invalid value pull mostly runs and then
> > > merge errors out at the end.
> > 
> > I opted not to do a check on the validity of the value of the
> > --cleanup-mode argument because the strategy options that existed before
> > also didn't verify the validity of their values. In the future, it might
> > be a good idea to check the values of both cleanup-mode and the
> > strategy options but for now, I think we can leave it as it is.
> 
> With --strategy-option the valid values depend on the --strategy option
> which may invoke an external command so in general there is no way to check
> the values are valid (it could do for the strategies we know about). With
> --cleanup we know the valid values and have a function that can check for
> them so I think it would be worth doing.

Makes sense, I'll do it (and throw in a test case for free ;) )

> 
> >   Documentation/merge-options.txt |  5 +++
> >   builtin/merge.c                 | 31 +++++++++++----
> >   builtin/pull.c                  |  6 +++
> >   t/t7604-merge-custom-message.sh | 67 +++++++++++++++++++++++++++++++++
> >   wt-status.c                     | 12 ++++--
> >   wt-status.h                     |  1 +
> >   6 files changed, 112 insertions(+), 10 deletions(-)
> > 
> > diff --git a/Documentation/merge-options.txt b/Documentation/merge-options.txt
> > index 92a7d936c1..646100ea9a 100644
> > --- a/Documentation/merge-options.txt
> > +++ b/Documentation/merge-options.txt
> > @@ -32,6 +32,11 @@ they run `git merge`. To make it easier to adjust such scripts to the
> >   updated behaviour, the environment variable `GIT_MERGE_AUTOEDIT` can be
> >   set to `no` at the beginning of them.
> > +--cleanup=<mode>::
> > +	This option determines how the merge message will be cleaned up
> > +	before commiting or being passed on. See linkgit:git-commit[1] for more
> 
> As I commented before I don't understand 'passed on'

I changed it in git-revert.txt and git-cherry-pick.txt but I forgot to
change it here. What do you think about this:

	--cleanup=<mode>::
		This option determines how the merge message will be cleaned up
		before commiting or being passed on to the commit machinery. See
		linkgit:git-commit[1] for more details.

> 
> > +	details.
> > +
> >   --ff::
> >   	When the merge resolves as a fast-forward, only update the branch
> >   	pointer, without creating a merge commit.  This is the default
> > diff --git a/builtin/merge.c b/builtin/merge.c
> > index 5ce8946d39..7be03a2610 100644
> > --- a/builtin/merge.c
> > +++ b/builtin/merge.c
> > @@ -38,6 +38,7 @@
> >   #include "tag.h"
> >   #include "alias.h"
> >   #include "commit-reach.h"
> > +#include "wt-status.h"
> >   #define DEFAULT_TWOHEAD (1<<0)
> >   #define DEFAULT_OCTOPUS (1<<1)
> > @@ -98,6 +99,9 @@ enum ff_type {
> >   static enum ff_type fast_forward = FF_ALLOW;
> > +static const char *cleanup_arg;
> > +static enum commit_msg_cleanup_mode cleanup_mode;
> > +
> >   static int option_parse_message(const struct option *opt,
> >   				const char *arg, int unset)
> >   {
> > @@ -249,6 +253,7 @@ static struct option builtin_merge_options[] = {
> >   		N_("perform a commit if the merge succeeds (default)")),
> >   	OPT_BOOL('e', "edit", &option_edit,
> >   		N_("edit message before committing")),
> > +	OPT_CLEANUP(&cleanup_arg),
> >   	OPT_SET_INT(0, "ff", &fast_forward, N_("allow fast-forward (default)"), FF_ALLOW),
> >   	OPT_SET_INT_F(0, "ff-only", &fast_forward,
> >   		      N_("abort if fast-forward is not possible"),
> > @@ -612,6 +617,8 @@ static int git_merge_config(const char *k, const char *v, void *cb)
> >   		return git_config_string(&pull_twohead, k, v);
> >   	else if (!strcmp(k, "pull.octopus"))
> >   		return git_config_string(&pull_octopus, k, v);
> > +	else if (!strcmp(k, "commit.cleanup"))
> > +		return git_config_string(&cleanup_arg, k, v);
> >   	else if (!strcmp(k, "merge.renormalize"))
> >   		option_renormalize = git_config_bool(k, v);
> >   	else if (!strcmp(k, "merge.ff")) {
> > @@ -797,23 +804,32 @@ static void abort_commit(struct commit_list *remoteheads, const char *err_msg)
> >   	exit(1);
> >   }
> > +static const char comment_line_explanation[] =
> > +N_("Lines starting with '%c' will be ignored.\n");
> > +
> >   static const char merge_editor_comment[] =
> >   N_("Please enter a commit message to explain why this merge is necessary,\n"
> >      "especially if it merges an updated upstream into a topic branch.\n"
> >      "\n"
> > -   "Lines starting with '%c' will be ignored, and an empty message aborts\n"
> > -   "the commit.\n");
> > +   "An empty message aborts the commit.\n");
> >   static void write_merge_heads(struct commit_list *);
> >   static void prepare_to_commit(struct commit_list *remoteheads)
> >   {
> >   	struct strbuf msg = STRBUF_INIT;
> >   	strbuf_addbuf(&msg, &merge_msg);
> > -	strbuf_addch(&msg, '\n');
> >   	if (squash)
> >   		BUG("the control must not reach here under --squash");
> > -	if (0 < option_edit)
> > -		strbuf_commented_addf(&msg, _(merge_editor_comment), comment_line_char);
> > +	if (0 < option_edit) {
> > +		strbuf_addch(&msg, '\n');
> > +		if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)
> > +			wt_status_append_cut_line(&msg);
> > +		else
> > +			strbuf_commented_addf(&msg, _(comment_line_explanation), comment_line_char);
> > +
> > +		strbuf_commented_addf(&msg, "\n");
> > +		strbuf_commented_addf(&msg, _(merge_editor_comment));
> > +	}
> 
> This still changes the wording of the message cf https://public-inbox.org/git/cover.1552275703.git.liu.denton@gmail.com/T/#m09cb1a05eb3bffb47ee9f25572904a7279efa362

Will do.

Thanks again for reviewing carefully!

> 
> Best Wishes
> 
> Phillip
> 
> >   	if (signoff)
> >   		append_signoff(&msg, ignore_non_trailer(msg.buf, msg.len), 0);
> >   	write_merge_heads(remoteheads);
> > @@ -832,7 +848,7 @@ static void prepare_to_commit(struct commit_list *remoteheads)
> >   		abort_commit(remoteheads, NULL);
> >   	read_merge_msg(&msg);
> > -	strbuf_stripspace(&msg, 0 < option_edit);
> > +	cleanup_message(&msg, cleanup_mode, 0);
> >   	if (!msg.len)
> >   		abort_commit(remoteheads, _("Empty commit message."));
> >   	strbuf_release(&merge_msg);
> > @@ -880,7 +896,6 @@ static int finish_automerge(struct commit *head,
> >   	parents = remoteheads;
> >   	if (!head_subsumed || fast_forward == FF_NO)
> >   		commit_list_insert(head, &parents);
> > -	strbuf_addch(&merge_msg, '\n');
> >   	prepare_to_commit(remoteheads);
> >   	if (commit_tree(merge_msg.buf, merge_msg.len, result_tree, parents,
> >   			&result_commit, NULL, sign_commit))
> > @@ -1389,6 +1404,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
> >   	if (option_edit < 0)
> >   		option_edit = default_edit_option();
> > +	cleanup_mode = get_cleanup_mode(cleanup_arg, 0 < option_edit, 1);
> > +
> >   	if (!use_strategies) {
> >   		if (!remoteheads)
> >   			; /* already up-to-date */
> > diff --git a/builtin/pull.c b/builtin/pull.c
> > index 33db889955..292c1dac27 100644
> > --- a/builtin/pull.c
> > +++ b/builtin/pull.c
> > @@ -101,6 +101,7 @@ static char *opt_signoff;
> >   static char *opt_squash;
> >   static char *opt_commit;
> >   static char *opt_edit;
> > +static char *opt_cleanup;
> >   static char *opt_ff;
> >   static char *opt_verify_signatures;
> >   static int opt_autostash = -1;
> > @@ -168,6 +169,9 @@ static struct option pull_options[] = {
> >   	OPT_PASSTHRU(0, "edit", &opt_edit, NULL,
> >   		N_("edit message before committing"),
> >   		PARSE_OPT_NOARG),
> > +	OPT_PASSTHRU(0, "cleanup", &opt_cleanup, NULL,
> > +		N_("how to strip spaces and #comments from message"),
> > +		0),
> >   	OPT_PASSTHRU(0, "ff", &opt_ff, NULL,
> >   		N_("allow fast-forward"),
> >   		PARSE_OPT_NOARG),
> > @@ -644,6 +648,8 @@ static int run_merge(void)
> >   		argv_array_push(&args, opt_commit);
> >   	if (opt_edit)
> >   		argv_array_push(&args, opt_edit);
> > +	if (opt_cleanup)
> > +		argv_array_push(&args, opt_cleanup);
> >   	if (opt_ff)
> >   		argv_array_push(&args, opt_ff);
> >   	if (opt_verify_signatures)
> > diff --git a/t/t7604-merge-custom-message.sh b/t/t7604-merge-custom-message.sh
> > index b045fdb413..c9685a318d 100755
> > --- a/t/t7604-merge-custom-message.sh
> > +++ b/t/t7604-merge-custom-message.sh
> > @@ -51,4 +51,71 @@ test_expect_success 'merge --log appends to custom message' '
> >   	test_cmp exp.log actual
> >   '
> > +mesg_with_comment_and_newlines='
> > +# text
> > +
> > +'
> > +
> > +test_expect_success 'prepare file with comment line and trailing newlines'  '
> > +	printf "%s" "$mesg_with_comment_and_newlines" >expect
> > +'
> > +
> > +test_expect_success 'cleanup commit messages (verbatim option)' '
> > +	git reset --hard c1 &&
> > +	git merge --cleanup=verbatim -F expect c2 &&
> > +	git cat-file commit HEAD >actual &&
> > +	sed -e "1,/^$/d" <actual >tmp &&
> > +	mv tmp actual &&
> > +	test_cmp expect actual
> > +'
> > +
> > +test_expect_success 'cleanup commit messages (whitespace option)' '
> > +	git reset --hard c1 &&
> > +	test_write_lines "" "# text" "" >text &&
> > +	echo "# text" >expect &&
> > +	git merge --cleanup=whitespace -F text c2 &&
> > +	git cat-file commit HEAD >actual &&
> > +	sed -e "1,/^$/d" <actual >tmp &&
> > +	mv tmp actual &&
> > +	test_cmp expect actual
> > +'
> > +
> > +test_expect_success 'cleanup merge messages (scissors option)' '
> > +	git reset --hard c1 &&
> > +	cat >text <<-\EOF &&
> > +
> > +	# to be kept
> > +
> > +	  # ------------------------ >8 ------------------------
> > +	# to be kept, too
> > +	# ------------------------ >8 ------------------------
> > +	to be removed
> > +	# ------------------------ >8 ------------------------
> > +	to be removed, too
> > +	EOF
> > +
> > +	cat >expect <<-\EOF &&
> > +	# to be kept
> > +
> > +	  # ------------------------ >8 ------------------------
> > +	# to be kept, too
> > +	EOF
> > +	git merge --cleanup=scissors -e -F text c2 &&
> > +	git cat-file commit HEAD >actual &&
> > +	sed -e "1,/^$/d" <actual >tmp &&
> > +	mv tmp actual &&
> > +	test_cmp expect actual
> > +'
> > +
> > +test_expect_success 'cleanup commit messages (strip option)' '
> > +	git reset --hard c1 &&
> > +	test_write_lines "" "# text" "sample" "" >text &&
> > +	echo sample >expect &&
> > +	git merge --cleanup=strip -F text c2 &&
> > +	git cat-file commit HEAD >actual &&
> > +	sed -e "1,/^$/d" <actual >tmp &&
> > +	mv tmp actual &&
> > +	test_cmp expect actual
> > +'
> > +
> >   test_done
> > diff --git a/wt-status.c b/wt-status.c
> > index 445a36204a..b81fcd428d 100644
> > --- a/wt-status.c
> > +++ b/wt-status.c
> > @@ -1006,13 +1006,19 @@ size_t wt_status_locate_end(const char *s, size_t len)
> >   	return len;
> >   }
> > -void wt_status_add_cut_line(FILE *fp)
> > +void wt_status_append_cut_line(struct strbuf *buf)
> >   {
> >   	const char *explanation = _("Do not modify or remove the line above.\nEverything below it will be ignored.");
> > +
> > +	strbuf_commented_addf(buf, "%s", cut_line);
> > +	strbuf_add_commented_lines(buf, explanation, strlen(explanation));
> > +}
> > +
> > +void wt_status_add_cut_line(FILE *fp)
> > +{
> >   	struct strbuf buf = STRBUF_INIT;
> > -	fprintf(fp, "%c %s", comment_line_char, cut_line);
> > -	strbuf_add_commented_lines(&buf, explanation, strlen(explanation));
> > +	wt_status_append_cut_line(&buf);
> >   	fputs(buf.buf, fp);
> >   	strbuf_release(&buf);
> >   }
> > diff --git a/wt-status.h b/wt-status.h
> > index 3a95975032..64f1ddc9fd 100644
> > --- a/wt-status.h
> > +++ b/wt-status.h
> > @@ -129,6 +129,7 @@ struct wt_status {
> >   };
> >   size_t wt_status_locate_end(const char *s, size_t len);
> > +void wt_status_append_cut_line(struct strbuf *buf);
> >   void wt_status_add_cut_line(FILE *fp);
> >   void wt_status_prepare(struct repository *r, struct wt_status *s);
> >   void wt_status_print(struct wt_status *s);
> > 

^ permalink raw reply	[flat|nested] 105+ messages in thread

* [PATCH v9 00/11] Fix scissors bug during conflict
  2019-03-17 10:15             ` [PATCH v8 00/11] " Denton Liu
                                 ` (11 preceding siblings ...)
  2019-03-17 13:05               ` [PATCH v8 00/11] Fix scissors bug during conflict SZEDER Gábor
@ 2019-03-21  6:53               ` Denton Liu
  2019-03-21  6:53                 ` [PATCH v9 01/11] t7600: clean up style Denton Liu
                                   ` (11 more replies)
  12 siblings, 12 replies; 105+ messages in thread
From: Denton Liu @ 2019-03-21  6:53 UTC (permalink / raw)
  To: Git Mailing List
  Cc: Denton Liu, Eric Sunshine, Junio C Hamano, Phillip Wood,
	Ramsay Jones, SZEDER Gábor

Thanks again for the reviews, everyone.

We're slowly making it there ;)



Previous discussion on the cherry-pick/revert changes can be found here[1].

Changes since revert/cherry-pick v3:

* Rebased on top of latest master
* Reordered and squashed patches
* Added populate_opts_cb and save_opts to save default_msg_cleanup at Phillip's suggestion

Changes since v7:

* Cleaned up more tests according to Eric's advice (and added some more cleanup patches!)
* Clarify meaning of "passed on" in documentation
* Consolidate common options into OPT_CLEANUP macro in parse-options.h
* Fix space indent to tabs in sequencer.c
* Shorten variable names for readability
* Make comment about 0th element in array being default more assertive
* Remove unnecessary braces around if/for statements
* Lowercase warning/error messages
* Unmark BUG messages for translation
* Rename get_config_from_cleanup -> describe_cleanup_mode
* Change PARSE_OPT_NOARG to 0 for --cleanup in git-pull
* Squashed in Ramsay's static patch

Changes since v8:

* More test cleanup
* Changed Reviewed-by: to Helped-by: in commit messages
* Check validity of --cleanup arg in git-pull
* Revised documentation to make "passed on" more clear (I hope!)
* Restore merge message to original text in the case of non-scissors

[1]: https://public-inbox.org/git/cover.1551867827.git.liu.denton@gmail.com/T/#u


Denton Liu (11):
  t7600: clean up style
  t3507: clean up style
  t7604: clean up style
  t7502: clean up style
  commit: extract cleanup_mode functions to sequencer
  parse-options.h: extract common --cleanup option
  sequencer.c: remove duplicate code
  merge: cleanup messages like commit
  merge: add scissors line on merge conflict
  sequencer.c: define describe_cleanup_mode
  cherry-pick/revert: add scissors line on merge conflict

 Documentation/git-cherry-pick.txt |   7 ++
 Documentation/git-revert.txt      |   7 ++
 Documentation/merge-options.txt   |   7 ++
 builtin/commit.c                  |  47 +++++------
 builtin/merge.c                   |  44 ++++++++--
 builtin/pull.c                    |  23 ++++++
 builtin/rebase--interactive.c     |   2 +-
 builtin/revert.c                  |   5 ++
 builtin/tag.c                     |   3 +-
 parse-options.h                   |   1 +
 sequencer.c                       |  97 +++++++++++++++++-----
 sequencer.h                       |   9 ++-
 t/t3507-cherry-pick-conflict.sh   | 128 +++++++++++++++++++++++++-----
 t/t5521-pull-options.sh           |   8 ++
 t/t7502-commit-porcelain.sh       |  93 ++++++++++++----------
 t/t7600-merge.sh                  |  73 +++++++++++++----
 t/t7604-merge-custom-message.sh   |  75 +++++++++++++++--
 wt-status.c                       |  12 ++-
 wt-status.h                       |   1 +
 19 files changed, 500 insertions(+), 142 deletions(-)

Interdiff against v8:
diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt
index 2601e1868e..cbb663a843 100644
--- a/Documentation/git-cherry-pick.txt
+++ b/Documentation/git-cherry-pick.txt
@@ -59,10 +59,10 @@ OPTIONS
 
 --cleanup=<mode>::
 	This option determines how the commit message will be cleaned up before
-	being passed on. See linkgit:git-commit[1] for more details. In
-	particular, if the '<mode>' is given a value of `scissors`, scissors
-	will be appended to `MERGE_MSG` before being passed on to the commit
-	machinery in the case of a conflict.
+	being passed on to the commit machinery. See linkgit:git-commit[1] for more
+	details. In particular, if the '<mode>' is given a value of `scissors`,
+	scissors will be appended to `MERGE_MSG` before being passed on in the case
+	of a conflict.
 
 -x::
 	When recording the commit, append a line that says
diff --git a/Documentation/git-revert.txt b/Documentation/git-revert.txt
index cabeb9df2c..7fd254df92 100644
--- a/Documentation/git-revert.txt
+++ b/Documentation/git-revert.txt
@@ -68,10 +68,10 @@ more details.
 
 --cleanup=<mode>::
 	This option determines how the commit message will be cleaned up before
-	being passed on. See linkgit:git-commit[1] for more details. In
-	particular, if the '<mode>' is given a value of `scissors`, scissors
-	will be appended to `MERGE_MSG` before being passed on to the commit
-	machinery in the case of a conflict.
+	being passed on to the commit machinery. See linkgit:git-commit[1] for more
+	details. In particular, if the '<mode>' is given a value of `scissors`,
+	scissors will be appended to `MERGE_MSG` before being passed on in the case
+	of a conflict.
 
 -n::
 --no-commit::
diff --git a/Documentation/merge-options.txt b/Documentation/merge-options.txt
index 405e16c617..61876dbc33 100644
--- a/Documentation/merge-options.txt
+++ b/Documentation/merge-options.txt
@@ -33,11 +33,11 @@ updated behaviour, the environment variable `GIT_MERGE_AUTOEDIT` can be
 set to `no` at the beginning of them.
 
 --cleanup=<mode>::
-	This option determines how the merge message will be cleaned up
-	before commiting or being passed on. See linkgit:git-commit[1] for more
-	details. In addition, if the '<mode>' is given a value of `scissors`,
-	scissors will be appended to `MERGE_MSG` before being passed on to the
-	commit machinery in the case of a merge conflict.
+	This option determines how the merge message will be cleaned up before
+	commiting. See linkgit:git-commit[1] for more details. In addition, if
+	the '<mode>' is given a value of `scissors`, scissors will be appended
+	to `MERGE_MSG` before being passed on to the commit machinery in the
+	case of a merge conflict.
 
 --ff::
 	When the merge resolves as a fast-forward, only update the branch
diff --git a/builtin/merge.c b/builtin/merge.c
index 90c64346e9..235cd3b2e1 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -804,14 +804,17 @@ static void abort_commit(struct commit_list *remoteheads, const char *err_msg)
 	exit(1);
 }
 
-static const char comment_line_explanation[] =
-N_("Lines starting with '%c' will be ignored.\n");
-
 static const char merge_editor_comment[] =
 N_("Please enter a commit message to explain why this merge is necessary,\n"
    "especially if it merges an updated upstream into a topic branch.\n"
-   "\n"
-   "An empty message aborts the commit.\n");
+   "\n");
+
+static const char scissors_editor_comment[] =
+N_("An empty message aborts the commit.\n");
+
+static const char no_scissors_editor_comment[] =
+N_("Lines starting with '%c' will be ignored, and an empty message aborts\n"
+   "the commit.\n");
 
 static void write_merge_heads(struct commit_list *);
 static void prepare_to_commit(struct commit_list *remoteheads)
@@ -824,11 +827,12 @@ static void prepare_to_commit(struct commit_list *remoteheads)
 		strbuf_addch(&msg, '\n');
 		if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)
 			wt_status_append_cut_line(&msg);
-		else
-			strbuf_commented_addf(&msg, _(comment_line_explanation), comment_line_char);
 
 		strbuf_commented_addf(&msg, "\n");
 		strbuf_commented_addf(&msg, _(merge_editor_comment));
+		strbuf_commented_addf(&msg, _(cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS ?
+			scissors_editor_comment :
+			no_scissors_editor_comment), comment_line_char);
 	}
 	if (signoff)
 		append_signoff(&msg, ignore_non_trailer(msg.buf, msg.len), 0);
diff --git a/builtin/pull.c b/builtin/pull.c
index 292c1dac27..55ebb5808e 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -24,6 +24,7 @@
 #include "lockfile.h"
 #include "wt-status.h"
 #include "commit-reach.h"
+#include "sequencer.h"
 
 enum rebase_type {
 	REBASE_INVALID = -1,
@@ -881,6 +882,22 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
 
 	argc = parse_options(argc, argv, prefix, pull_options, pull_usage, 0);
 
+	if (opt_cleanup) {
+		const char *prefix = "--cleanup=";
+		const char *cleanup_arg;
+
+		if (strncmp(opt_cleanup, prefix, strlen(prefix)))
+			BUG("expecting prefix %s, argument is %s", prefix, opt_cleanup);
+
+		cleanup_arg = &opt_cleanup[strlen(prefix)];
+
+		/*
+		 * this only checks the validity of cleanup_arg; we don't need
+		 * a valid value for use_editor
+		 */
+		get_cleanup_mode(cleanup_arg, 0, 1);
+	}
+
 	parse_repo_refspecs(argc, argv, &repo, &refspecs);
 
 	if (!opt_ff)
diff --git a/t/t3507-cherry-pick-conflict.sh b/t/t3507-cherry-pick-conflict.sh
index c3894ca9d6..a584b11c98 100755
--- a/t/t3507-cherry-pick-conflict.sh
+++ b/t/t3507-cherry-pick-conflict.sh
@@ -180,7 +180,7 @@ test_expect_success 'failed cherry-pick registers participants in index' '
 		1 s/ 0	/ 1	/
 		2 s/ 0	/ 2	/
 		3 s/ 0	/ 3	/
-	" <stages >expected &&
+	" stages >expected &&
 	git read-tree -u --reset HEAD &&
 
 	test_must_fail git cherry-pick picked &&
@@ -286,7 +286,7 @@ test_expect_success 'revert also handles conflicts sanely' '
 		1 s/ 0	/ 1	/
 		2 s/ 0	/ 2	/
 		3 s/ 0	/ 3	/
-	" <stages >expected-stages &&
+	" stages >expected-stages &&
 	git read-tree -u --reset HEAD &&
 
 	head=$(git rev-parse HEAD) &&
@@ -431,7 +431,7 @@ test_expect_success 'commit after failed cherry-pick does not add duplicated -s'
 	pristine_detach initial &&
 	test_must_fail git cherry-pick -s picked-signed &&
 	git commit -a -s &&
-	test $(git show -s |grep -c "Signed-off-by") = 1
+	test $(git show -s >tmp && grep -c "Signed-off-by" tmp && rm tmp) = 1
 '
 
 test_expect_success 'commit after failed cherry-pick adds -s at the right place' '
@@ -445,7 +445,7 @@ test_expect_success 'commit after failed cherry-pick adds -s at the right place'
 	Signed-off-by: C O Mitter <committer@example.com>
 	# Conflicts:
 	EOF
-	grep -e "^# Conflicts:" -e '^Signed-off-by' <.git/COMMIT_EDITMSG >actual &&
+	grep -e "^# Conflicts:" -e '^Signed-off-by' .git/COMMIT_EDITMSG >actual &&
 	test_cmp expect actual &&
 
 	cat <<-\EOF >expected &&
@@ -464,7 +464,7 @@ test_expect_success 'commit --amend -s places the sign-off at the right place' '
 
 	# emulate old-style conflicts block
 	mv .git/MERGE_MSG .git/MERGE_MSG+ &&
-	sed -e "/^# Conflicts:/,\$s/^# *//" <.git/MERGE_MSG+ >.git/MERGE_MSG &&
+	sed -e "/^# Conflicts:/,\$s/^# *//" .git/MERGE_MSG+ >.git/MERGE_MSG &&
 
 	git commit -a &&
 	git commit --amend -s &&
@@ -474,7 +474,7 @@ test_expect_success 'commit --amend -s places the sign-off at the right place' '
 	Signed-off-by: C O Mitter <committer@example.com>
 	Conflicts:
 	EOF
-	grep -e "^Conflicts:" -e '^Signed-off-by' <.git/COMMIT_EDITMSG >actual &&
+	grep -e "^Conflicts:" -e '^Signed-off-by' .git/COMMIT_EDITMSG >actual &&
 	test_cmp expect actual
 '
 
diff --git a/t/t5521-pull-options.sh b/t/t5521-pull-options.sh
index c19d8dbc9d..ccde8ba491 100755
--- a/t/t5521-pull-options.sh
+++ b/t/t5521-pull-options.sh
@@ -77,6 +77,14 @@ test_expect_success 'git pull -q -v' '
 	test_must_be_empty out &&
 	test -s err)
 '
+test_expect_success 'git pull --cleanup errors early on invalid argument' '
+	mkdir clonedcleanup &&
+	(cd clonedcleanup && git init &&
+	test_must_fail git pull --cleanup invalid "../parent" >out 2>err &&
+	test_must_be_empty out &&
+	test -s err)
+'
+
 
 test_expect_success 'git pull --force' '
 	mkdir clonedoldstyle &&
diff --git a/t/t7502-commit-porcelain.sh b/t/t7502-commit-porcelain.sh
index f035e4a507..5733d9cd34 100755
--- a/t/t7502-commit-porcelain.sh
+++ b/t/t7502-commit-porcelain.sh
@@ -16,9 +16,8 @@ commit_msg_is () {
 # Arguments: [<prefix] [<commit message>] [<commit options>]
 check_summary_oneline() {
 	test_tick &&
-	git commit ${3+"$3"} -m "$2" >act &&
-	head -1 <act >tmp &&
-	mv tmp act &&
+	git commit ${3+"$3"} -m "$2" >raw &&
+	head -n 1 raw >act &&
 
 	# branch name
 	SUMMARY_PREFIX="$(git name-rev --name-only HEAD)" &&
@@ -144,9 +143,11 @@ test_expect_success 'sign off' '
 	>positive &&
 	git add positive &&
 	git commit -s -m "thank you" &&
-	actual=$(git cat-file commit HEAD >tmp && sed -ne "s/Signed-off-by: //p" <tmp && rm tmp) &&
-	expected=$(git var GIT_COMMITTER_IDENT >tmp && sed -e "s/>.*/>/" <tmp && rm tmp) &&
-	test "z$actual" = "z$expected"
+	git cat-file commit HEAD >commit.msg &&
+	sed -ne "s/Signed-off-by: //p" commit.msg >actual &&
+	git var GIT_COMMITTER_IDENT >ident &&
+	sed -e "s/>.*/>/" ident >expected &&
+	test_cmp expected actual
 
 '
 
@@ -155,7 +156,7 @@ test_expect_success 'multiple -m' '
 	>negative &&
 	git add negative &&
 	git commit -m "one" -m "two" -m "three" &&
-	actual=$(git cat-file commit HEAD >tmp && sed -e "1,/^\$/d" <tmp && rm tmp) &&
+	actual=$(git cat-file commit HEAD >tmp && sed -e "1,/^\$/d" tmp && rm tmp) &&
 	expected=$(test_write_lines "one" "" "two" "" "three") &&
 	test "z$actual" = "z$expected"
 
@@ -165,9 +166,8 @@ test_expect_success 'verbose' '
 
 	echo minus >negative &&
 	git add negative &&
-	git status -v >actual &&
-	sed -ne "/^diff --git /p" <actual >tmp &&
-	mv tmp actual &&
+	git status -v >raw &&
+	sed -ne "/^diff --git /p" raw >actual &&
 	echo "diff --git a/negative b/negative" >expect &&
 	test_cmp expect actual
 
@@ -193,9 +193,8 @@ test_expect_success 'cleanup commit messages (verbatim option,-t)' '
 
 	echo >>negative &&
 	git commit --cleanup=verbatim --no-status -t expect -a &&
-	git cat-file -p HEAD >actual &&
-	sed -e "1,/^\$/d" <actual >tmp &&
-	mv tmp actual &&
+	git cat-file -p HEAD >raw &&
+	sed -e "1,/^\$/d" raw >actual &&
 	test_cmp expect actual
 
 '
@@ -204,9 +203,8 @@ test_expect_success 'cleanup commit messages (verbatim option,-F)' '
 
 	echo >>negative &&
 	git commit --cleanup=verbatim -F expect -a &&
-	git cat-file -p HEAD >actual &&
-	sed -e "1,/^\$/d" <actual >tmp &&
-	mv tmp actual &&
+	git cat-file -p HEAD >raw &&
+	sed -e "1,/^\$/d" raw >actual &&
 	test_cmp expect actual
 
 '
@@ -215,9 +213,8 @@ test_expect_success 'cleanup commit messages (verbatim option,-m)' '
 
 	echo >>negative &&
 	git commit --cleanup=verbatim -m "$mesg_with_comment_and_newlines" -a &&
-	git cat-file -p HEAD >actual &&
-	sed -e "1,/^\$/d" <actual >tmp &&
-	mv tmp actual &&
+	git cat-file -p HEAD >raw &&
+	sed -e "1,/^\$/d" raw >actual &&
 	test_cmp expect actual
 
 '
@@ -228,9 +225,8 @@ test_expect_success 'cleanup commit messages (whitespace option,-F)' '
 	test_write_lines "" "# text" "" >text &&
 	echo "# text" >expect &&
 	git commit --cleanup=whitespace -F text -a &&
-	git cat-file -p HEAD >actual &&
-	sed -e "1,/^\$/d" <actual >tmp &&
-	mv tmp actual &&
+	git cat-file -p HEAD >raw &&
+	sed -e "1,/^\$/d" raw >actual &&
 	test_cmp expect actual
 
 '
@@ -257,9 +253,8 @@ test_expect_success 'cleanup commit messages (scissors option,-F,-e)' '
 	# to be kept, too
 	EOF
 	git commit --cleanup=scissors -e -F text -a &&
-	git cat-file -p HEAD >actual &&
-	sed -e "1,/^\$/d" <actual >tmp &&
-	mv tmp actual &&
+	git cat-file -p HEAD >raw &&
+	sed -e "1,/^\$/d" raw >actual &&
 	test_cmp expect actual
 '
 
@@ -271,9 +266,8 @@ test_expect_success 'cleanup commit messages (scissors option,-F,-e, scissors on
 	to be removed
 	EOF
 	git commit --cleanup=scissors -e -F text -a --allow-empty-message &&
-	git cat-file -p HEAD >actual &&
-	sed -e "1,/^\$/d" <actual >tmp &&
-	mv tmp actual &&
+	git cat-file -p HEAD >raw &&
+	sed -e "1,/^\$/d" raw >actual &&
 	test_must_be_empty actual
 '
 
@@ -283,9 +277,8 @@ test_expect_success 'cleanup commit messages (strip option,-F)' '
 	test_write_lines "" "# text" "sample" "" >text &&
 	echo sample >expect &&
 	git commit --cleanup=strip -F text -a &&
-	git cat-file -p HEAD >actual &&
-	sed -e "1,/^\$/d" <actual >tmp &&
-	mv tmp actual &&
+	git cat-file -p HEAD >raw &&
+	sed -e "1,/^\$/d" raw >actual &&
 	test_cmp expect actual
 
 '
@@ -489,9 +482,8 @@ test_expect_success 'Hand committing of a redundant merge removes dups' '
 	test_must_fail git merge second master &&
 	git checkout master g &&
 	EDITOR=: git commit -a &&
-	git cat-file commit HEAD >actual &&
-	sed -n -e "s/^parent //p" -e "/^$/q" <actual >tmp &&
-	mv tmp actual &&
+	git cat-file commit HEAD >raw &&
+	sed -n -e "s/^parent //p" -e "/^$/q" raw >actual &&
 	test_cmp expect actual
 
 '
@@ -500,9 +492,8 @@ test_expect_success 'A single-liner subject with a token plus colon is not a foo
 
 	git reset --hard &&
 	git commit -s -m "hello: kitty" --allow-empty &&
-	git cat-file commit HEAD >actual &&
-	sed -e "1,/^$/d" <actual >tmp &&
-	mv tmp actual &&
+	git cat-file commit HEAD >raw &&
+	sed -e "1,/^$/d" raw >actual &&
 	test_line_count = 3 actual
 
 '
diff --git a/t/t7600-merge.sh b/t/t7600-merge.sh
index ed11b08db2..7f9c68cbe7 100755
--- a/t/t7600-merge.sh
+++ b/t/t7600-merge.sh
@@ -241,9 +241,8 @@ test_expect_success 'merge --squash c3 with c7' '
 	# Conflicts:
 	#	file
 	EOF
-	git cat-file commit HEAD >actual &&
-	sed -e '1,/^$/d' <actual >tmp &&
-	mv tmp actual &&
+	git cat-file commit HEAD >raw &&
+	sed -e '1,/^$/d' raw >actual &&
 	test_cmp expect actual
 '
 
@@ -264,9 +263,8 @@ test_expect_success 'merge c3 with c7 with commit.cleanup = scissors' '
 	# Conflicts:
 	#	file
 	EOF
-	git cat-file commit HEAD >actual &&
-	sed -e '1,/^$/d' <actual >tmp &&
-	mv tmp actual &&
+	git cat-file commit HEAD >raw &&
+	sed -e '1,/^$/d' raw >actual &&
 	test_i18ncmp expect actual
 '
 
@@ -289,9 +287,8 @@ test_expect_success 'merge c3 with c7 with --squash commit.cleanup = scissors' '
 	# Conflicts:
 	#	file
 	EOF
-	git cat-file commit HEAD >actual &&
-	sed -e '1,/^$/d' <actual >tmp &&
-	mv tmp actual &&
+	git cat-file commit HEAD >raw &&
+	sed -e '1,/^$/d' raw >actual &&
 	test_i18ncmp expect actual
 '
 
@@ -728,10 +725,10 @@ cat >editor <<\EOF
 (
 	echo "Merge work done on the side branch c1"
 	echo
-	cat <"$1"
+	cat "$1"
 ) >"$1.tmp" && mv "$1.tmp" "$1"
 # strip comments and blank lines from end of message
-sed -e '/^#/d' < "$1" | sed -e :a -e '/^\n*$/{$d;N;ba' -e '}' >expected
+sed -e '/^#/d' "$1" | sed -e :a -e '/^\n*$/{$d;N;ba' -e '}' >expected
 EOF
 chmod 755 editor
 
@@ -816,14 +813,14 @@ test_expect_success 'set up mod-256 conflict scenario' '
 	git commit -m base &&
 
 	# one side changes the first line of each to "master"
-	sed s/-1/-master/ <file >tmp &&
+	sed s/-1/-master/ file >tmp &&
 	mv tmp file &&
 	git commit -am master &&
 
 	# and the other to "side"; merging the two will
 	# yield 256 separate conflicts
 	git checkout -b side HEAD^ &&
-	sed s/-1/-side/ <file >tmp &&
+	sed s/-1/-side/ file >tmp &&
 	mv tmp file &&
 	git commit -am side
 '
diff --git a/t/t7604-merge-custom-message.sh b/t/t7604-merge-custom-message.sh
index c9685a318d..cd4f9607dc 100755
--- a/t/t7604-merge-custom-message.sh
+++ b/t/t7604-merge-custom-message.sh
@@ -16,16 +16,16 @@ create_merge_msgs() {
 }
 
 test_expect_success 'setup' '
-	echo c0 > c0.c &&
+	echo c0 >c0.c &&
 	git add c0.c &&
 	git commit -m c0 &&
 	git tag c0 &&
-	echo c1 > c1.c &&
+	echo c1 >c1.c &&
 	git add c1.c &&
 	git commit -m c1 &&
 	git tag c1 &&
 	git reset --hard c0 &&
-	echo c2 > c2.c &&
+	echo c2 >c2.c &&
 	git add c2.c &&
 	git commit -m c2 &&
 	git tag c2 &&
@@ -36,18 +36,16 @@ test_expect_success 'setup' '
 test_expect_success 'merge c2 with a custom message' '
 	git reset --hard c1 &&
 	git merge -m "$(cat exp.subject)" c2 &&
-	git cat-file commit HEAD >actual &&
-	sed -e "1,/^$/d" <actual >tmp &&
-	mv tmp actual &&
+	git cat-file commit HEAD >raw &&
+	sed -e "1,/^$/d" raw >actual &&
 	test_cmp exp.subject actual
 '
 
 test_expect_success 'merge --log appends to custom message' '
 	git reset --hard c1 &&
 	git merge --log -m "$(cat exp.subject)" c2 &&
-	git cat-file commit HEAD >actual &&
-	sed -e "1,/^$/d" <actual >tmp &&
-	mv tmp actual &&
+	git cat-file commit HEAD >raw &&
+	sed -e "1,/^$/d" raw >actual &&
 	test_cmp exp.log actual
 '
 
@@ -63,9 +61,8 @@ test_expect_success 'prepare file with comment line and trailing newlines'  '
 test_expect_success 'cleanup commit messages (verbatim option)' '
 	git reset --hard c1 &&
 	git merge --cleanup=verbatim -F expect c2 &&
-	git cat-file commit HEAD >actual &&
-	sed -e "1,/^$/d" <actual >tmp &&
-	mv tmp actual &&
+	git cat-file commit HEAD >raw &&
+	sed -e "1,/^$/d" raw >actual &&
 	test_cmp expect actual
 '
 
@@ -74,9 +71,8 @@ test_expect_success 'cleanup commit messages (whitespace option)' '
 	test_write_lines "" "# text" "" >text &&
 	echo "# text" >expect &&
 	git merge --cleanup=whitespace -F text c2 &&
-	git cat-file commit HEAD >actual &&
-	sed -e "1,/^$/d" <actual >tmp &&
-	mv tmp actual &&
+	git cat-file commit HEAD >raw &&
+	sed -e "1,/^$/d" raw >actual &&
 	test_cmp expect actual
 '
 
@@ -101,9 +97,8 @@ test_expect_success 'cleanup merge messages (scissors option)' '
 	# to be kept, too
 	EOF
 	git merge --cleanup=scissors -e -F text c2 &&
-	git cat-file commit HEAD >actual &&
-	sed -e "1,/^$/d" <actual >tmp &&
-	mv tmp actual &&
+	git cat-file commit HEAD >raw &&
+	sed -e "1,/^$/d" raw >actual &&
 	test_cmp expect actual
 '
 
@@ -112,9 +107,8 @@ test_expect_success 'cleanup commit messages (strip option)' '
 	test_write_lines "" "# text" "sample" "" >text &&
 	echo sample >expect &&
 	git merge --cleanup=strip -F text c2 &&
-	git cat-file commit HEAD >actual &&
-	sed -e "1,/^$/d" <actual >tmp &&
-	mv tmp actual &&
+	git cat-file commit HEAD >raw &&
+	sed -e "1,/^$/d" raw >actual &&
 	test_cmp expect actual
 '
 
-- 
2.21.0.512.g57bf1b23e1


^ permalink raw reply	[flat|nested] 105+ messages in thread

* [PATCH v9 01/11] t7600: clean up style
  2019-03-21  6:53               ` [PATCH v9 " Denton Liu
@ 2019-03-21  6:53                 ` Denton Liu
  2019-03-21  6:53                 ` [PATCH v9 02/11] t3507: " Denton Liu
                                   ` (10 subsequent siblings)
  11 siblings, 0 replies; 105+ messages in thread
From: Denton Liu @ 2019-03-21  6:53 UTC (permalink / raw)
  To: Git Mailing List
  Cc: Denton Liu, Eric Sunshine, Junio C Hamano, Phillip Wood,
	Ramsay Jones, SZEDER Gábor

Clean up the 'merge --squash c3 with c7' test by removing some
unnecessary braces and removing a pipe.

Also, generally cleanup style by unindenting a here-doc, removing stray
spaces after a redirection operator and allowing sed to open its own
input instead of redirecting input from the shell.

Helped-by: SZEDER Gábor <szeder.dev@gmail.com>
Helped-by: Eric Sunshine <sunshine@sunshineco.com>
Helped-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Denton Liu <liu.denton@gmail.com>
---
 t/t7600-merge.sh | 27 +++++++++++++--------------
 1 file changed, 13 insertions(+), 14 deletions(-)

diff --git a/t/t7600-merge.sh b/t/t7600-merge.sh
index 106148254d..2f4c2801fb 100755
--- a/t/t7600-merge.sh
+++ b/t/t7600-merge.sh
@@ -233,17 +233,16 @@ test_expect_success 'merge --squash c3 with c7' '
 	cat result.9z >file &&
 	git commit --no-edit -a &&
 
-	{
-		cat <<-EOF
-		Squashed commit of the following:
+	cat >expect <<-EOF &&
+	Squashed commit of the following:
 
-		$(git show -s c7)
+	$(git show -s c7)
 
-		# Conflicts:
-		#	file
-		EOF
-	} >expect &&
-	git cat-file commit HEAD | sed -e '1,/^$/d' >actual &&
+	# Conflicts:
+	#	file
+	EOF
+	git cat-file commit HEAD >raw &&
+	sed -e '1,/^$/d' raw >actual &&
 	test_cmp expect actual
 '
 
@@ -680,10 +679,10 @@ cat >editor <<\EOF
 (
 	echo "Merge work done on the side branch c1"
 	echo
-	cat <"$1"
+	cat "$1"
 ) >"$1.tmp" && mv "$1.tmp" "$1"
 # strip comments and blank lines from end of message
-sed -e '/^#/d' < "$1" | sed -e :a -e '/^\n*$/{$d;N;ba' -e '}' > expected
+sed -e '/^#/d' "$1" | sed -e :a -e '/^\n*$/{$d;N;ba' -e '}' >expected
 EOF
 chmod 755 editor
 
@@ -768,14 +767,14 @@ test_expect_success 'set up mod-256 conflict scenario' '
 	git commit -m base &&
 
 	# one side changes the first line of each to "master"
-	sed s/-1/-master/ <file >tmp &&
+	sed s/-1/-master/ file >tmp &&
 	mv tmp file &&
 	git commit -am master &&
 
 	# and the other to "side"; merging the two will
 	# yield 256 separate conflicts
 	git checkout -b side HEAD^ &&
-	sed s/-1/-side/ <file >tmp &&
+	sed s/-1/-side/ file >tmp &&
 	mv tmp file &&
 	git commit -am side
 '
@@ -814,7 +813,7 @@ EOF
 test_expect_success EXECKEEPSPID 'killed merge can be completed with --continue' '
 	git reset --hard c0 &&
 	! "$SHELL_PATH" -c '\''
-	  echo kill -TERM $$ >> .git/FAKE_EDITOR
+	  echo kill -TERM $$ >>.git/FAKE_EDITOR
 	  GIT_EDITOR=.git/FAKE_EDITOR
 	  export GIT_EDITOR
 	  exec git merge --no-ff --edit c1'\'' &&
-- 
2.21.0.512.g57bf1b23e1


^ permalink raw reply	[flat|nested] 105+ messages in thread

* [PATCH v9 02/11] t3507: clean up style
  2019-03-21  6:53               ` [PATCH v9 " Denton Liu
  2019-03-21  6:53                 ` [PATCH v9 01/11] t7600: clean up style Denton Liu
@ 2019-03-21  6:53                 ` Denton Liu
  2019-03-21  6:53                 ` [PATCH v9 03/11] t7604: " Denton Liu
                                   ` (9 subsequent siblings)
  11 siblings, 0 replies; 105+ messages in thread
From: Denton Liu @ 2019-03-21  6:53 UTC (permalink / raw)
  To: Git Mailing List
  Cc: Denton Liu, Eric Sunshine, Junio C Hamano, Phillip Wood,
	Ramsay Jones, SZEDER Gábor

Remove space after redirection operators for style. Also, remove a git
command which was upstream of a pipe. Finally, let grep and sed open
their own input instead of letting the shell redirect the input.

Helped-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Denton Liu <liu.denton@gmail.com>
---
 t/t3507-cherry-pick-conflict.sh | 42 ++++++++++++++++-----------------
 1 file changed, 21 insertions(+), 21 deletions(-)

diff --git a/t/t3507-cherry-pick-conflict.sh b/t/t3507-cherry-pick-conflict.sh
index 0db166152a..777fb23d18 100755
--- a/t/t3507-cherry-pick-conflict.sh
+++ b/t/t3507-cherry-pick-conflict.sh
@@ -88,7 +88,7 @@ test_expect_success 'cherry-pick --no-commit does not set CHERRY_PICK_HEAD' '
 
 test_expect_success 'cherry-pick w/dirty tree does not set CHERRY_PICK_HEAD' '
 	pristine_detach initial &&
-	echo foo > foo &&
+	echo foo >foo &&
 	test_must_fail git cherry-pick base &&
 	test_must_fail git rev-parse --verify CHERRY_PICK_HEAD
 '
@@ -96,7 +96,7 @@ test_expect_success 'cherry-pick w/dirty tree does not set CHERRY_PICK_HEAD' '
 test_expect_success \
 	'cherry-pick --strategy=resolve w/dirty tree does not set CHERRY_PICK_HEAD' '
 	pristine_detach initial &&
-	echo foo > foo &&
+	echo foo >foo &&
 	test_must_fail git cherry-pick --strategy=resolve base &&
 	test_must_fail git rev-parse --verify CHERRY_PICK_HEAD
 '
@@ -175,23 +175,23 @@ test_expect_success 'failed cherry-pick registers participants in index' '
 		git ls-files --stage foo &&
 		git checkout picked -- foo &&
 		git ls-files --stage foo
-	} > stages &&
+	} >stages &&
 	sed "
 		1 s/ 0	/ 1	/
 		2 s/ 0	/ 2	/
 		3 s/ 0	/ 3	/
-	" < stages > expected &&
+	" stages >expected &&
 	git read-tree -u --reset HEAD &&
 
 	test_must_fail git cherry-pick picked &&
-	git ls-files --stage --unmerged > actual &&
+	git ls-files --stage --unmerged >actual &&
 
 	test_cmp expected actual
 '
 
 test_expect_success 'failed cherry-pick describes conflict in work tree' '
 	pristine_detach initial &&
-	cat <<-EOF > expected &&
+	cat <<-EOF >expected &&
 	<<<<<<< HEAD
 	a
 	=======
@@ -201,14 +201,14 @@ test_expect_success 'failed cherry-pick describes conflict in work tree' '
 
 	test_must_fail git cherry-pick picked &&
 
-	sed "s/[a-f0-9]*\.\.\./objid/" foo > actual &&
+	sed "s/[a-f0-9]*\.\.\./objid/" foo >actual &&
 	test_cmp expected actual
 '
 
 test_expect_success 'diff3 -m style' '
 	pristine_detach initial &&
 	git config merge.conflictstyle diff3 &&
-	cat <<-EOF > expected &&
+	cat <<-EOF >expected &&
 	<<<<<<< HEAD
 	a
 	||||||| parent of objid picked
@@ -220,14 +220,14 @@ test_expect_success 'diff3 -m style' '
 
 	test_must_fail git cherry-pick picked &&
 
-	sed "s/[a-f0-9]*\.\.\./objid/" foo > actual &&
+	sed "s/[a-f0-9]*\.\.\./objid/" foo >actual &&
 	test_cmp expected actual
 '
 
 test_expect_success 'revert also handles conflicts sanely' '
 	git config --unset merge.conflictstyle &&
 	pristine_detach initial &&
-	cat <<-EOF > expected &&
+	cat <<-EOF >expected &&
 	<<<<<<< HEAD
 	a
 	=======
@@ -241,24 +241,24 @@ test_expect_success 'revert also handles conflicts sanely' '
 		git ls-files --stage foo &&
 		git checkout base -- foo &&
 		git ls-files --stage foo
-	} > stages &&
+	} >stages &&
 	sed "
 		1 s/ 0	/ 1	/
 		2 s/ 0	/ 2	/
 		3 s/ 0	/ 3	/
-	" < stages > expected-stages &&
+	" stages >expected-stages &&
 	git read-tree -u --reset HEAD &&
 
 	head=$(git rev-parse HEAD) &&
 	test_must_fail git revert picked &&
 	newhead=$(git rev-parse HEAD) &&
-	git ls-files --stage --unmerged > actual-stages &&
+	git ls-files --stage --unmerged >actual-stages &&
 
 	test "$head" = "$newhead" &&
 	test_must_fail git update-index --refresh -q &&
 	test_must_fail git diff-index --exit-code HEAD &&
 	test_cmp expected-stages actual-stages &&
-	sed "s/[a-f0-9]*\.\.\./objid/" foo > actual &&
+	sed "s/[a-f0-9]*\.\.\./objid/" foo >actual &&
 	test_cmp expected actual
 '
 
@@ -284,7 +284,7 @@ test_expect_success 'revert --no-commit sets REVERT_HEAD' '
 
 test_expect_success 'revert w/dirty tree does not set REVERT_HEAD' '
 	pristine_detach base &&
-	echo foo > foo &&
+	echo foo >foo &&
 	test_must_fail git revert base &&
 	test_must_fail git rev-parse --verify CHERRY_PICK_HEAD &&
 	test_must_fail git rev-parse --verify REVERT_HEAD
@@ -319,7 +319,7 @@ test_expect_success 'failed commit does not clear REVERT_HEAD' '
 test_expect_success 'revert conflict, diff3 -m style' '
 	pristine_detach initial &&
 	git config merge.conflictstyle diff3 &&
-	cat <<-EOF > expected &&
+	cat <<-EOF >expected &&
 	<<<<<<< HEAD
 	a
 	||||||| objid picked
@@ -331,7 +331,7 @@ test_expect_success 'revert conflict, diff3 -m style' '
 
 	test_must_fail git revert picked &&
 
-	sed "s/[a-f0-9]*\.\.\./objid/" foo > actual &&
+	sed "s/[a-f0-9]*\.\.\./objid/" foo >actual &&
 	test_cmp expected actual
 '
 
@@ -345,7 +345,7 @@ test_expect_success 'commit after failed cherry-pick does not add duplicated -s'
 	pristine_detach initial &&
 	test_must_fail git cherry-pick -s picked-signed &&
 	git commit -a -s &&
-	test $(git show -s |grep -c "Signed-off-by") = 1
+	test $(git show -s >tmp && grep -c "Signed-off-by" tmp && rm tmp) = 1
 '
 
 test_expect_success 'commit after failed cherry-pick adds -s at the right place' '
@@ -359,7 +359,7 @@ test_expect_success 'commit after failed cherry-pick adds -s at the right place'
 	Signed-off-by: C O Mitter <committer@example.com>
 	# Conflicts:
 	EOF
-	grep -e "^# Conflicts:" -e '^Signed-off-by' <.git/COMMIT_EDITMSG >actual &&
+	grep -e "^# Conflicts:" -e '^Signed-off-by' .git/COMMIT_EDITMSG >actual &&
 	test_cmp expect actual &&
 
 	cat <<-\EOF >expected &&
@@ -378,7 +378,7 @@ test_expect_success 'commit --amend -s places the sign-off at the right place' '
 
 	# emulate old-style conflicts block
 	mv .git/MERGE_MSG .git/MERGE_MSG+ &&
-	sed -e "/^# Conflicts:/,\$s/^# *//" <.git/MERGE_MSG+ >.git/MERGE_MSG &&
+	sed -e "/^# Conflicts:/,\$s/^# *//" .git/MERGE_MSG+ >.git/MERGE_MSG &&
 
 	git commit -a &&
 	git commit --amend -s &&
@@ -388,7 +388,7 @@ test_expect_success 'commit --amend -s places the sign-off at the right place' '
 	Signed-off-by: C O Mitter <committer@example.com>
 	Conflicts:
 	EOF
-	grep -e "^Conflicts:" -e '^Signed-off-by' <.git/COMMIT_EDITMSG >actual &&
+	grep -e "^Conflicts:" -e '^Signed-off-by' .git/COMMIT_EDITMSG >actual &&
 	test_cmp expect actual
 '
 
-- 
2.21.0.512.g57bf1b23e1


^ permalink raw reply	[flat|nested] 105+ messages in thread

* [PATCH v9 03/11] t7604: clean up style
  2019-03-21  6:53               ` [PATCH v9 " Denton Liu
  2019-03-21  6:53                 ` [PATCH v9 01/11] t7600: clean up style Denton Liu
  2019-03-21  6:53                 ` [PATCH v9 02/11] t3507: " Denton Liu
@ 2019-03-21  6:53                 ` Denton Liu
  2019-03-21  6:53                 ` [PATCH v9 04/11] t7502: " Denton Liu
                                   ` (8 subsequent siblings)
  11 siblings, 0 replies; 105+ messages in thread
From: Denton Liu @ 2019-03-21  6:53 UTC (permalink / raw)
  To: Git Mailing List
  Cc: Denton Liu, Eric Sunshine, Junio C Hamano, Phillip Wood,
	Ramsay Jones, SZEDER Gábor

Before, we had some Git commands which were upstream of the pipe. This
meant that if it produced an error, it would've gone unnoticed. Refactor
to place Git commands on their own.

Also, while we're at it, remove spaces after redirection operators.

Helped-by: Eric Sunshine <sunshine@sunshineco.com>
Helped-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Denton Liu <liu.denton@gmail.com>
---
 t/t7604-merge-custom-message.sh | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/t/t7604-merge-custom-message.sh b/t/t7604-merge-custom-message.sh
index 89619cf446..aba1279132 100755
--- a/t/t7604-merge-custom-message.sh
+++ b/t/t7604-merge-custom-message.sh
@@ -16,16 +16,16 @@ create_merge_msgs() {
 }
 
 test_expect_success 'setup' '
-	echo c0 > c0.c &&
+	echo c0 >c0.c &&
 	git add c0.c &&
 	git commit -m c0 &&
 	git tag c0 &&
-	echo c1 > c1.c &&
+	echo c1 >c1.c &&
 	git add c1.c &&
 	git commit -m c1 &&
 	git tag c1 &&
 	git reset --hard c0 &&
-	echo c2 > c2.c &&
+	echo c2 >c2.c &&
 	git add c2.c &&
 	git commit -m c2 &&
 	git tag c2 &&
@@ -36,14 +36,16 @@ test_expect_success 'setup' '
 test_expect_success 'merge c2 with a custom message' '
 	git reset --hard c1 &&
 	git merge -m "$(cat exp.subject)" c2 &&
-	git cat-file commit HEAD | sed -e "1,/^$/d" >actual &&
+	git cat-file commit HEAD >raw &&
+	sed -e "1,/^$/d" raw >actual &&
 	test_cmp exp.subject actual
 '
 
 test_expect_success 'merge --log appends to custom message' '
 	git reset --hard c1 &&
 	git merge --log -m "$(cat exp.subject)" c2 &&
-	git cat-file commit HEAD | sed -e "1,/^$/d" >actual &&
+	git cat-file commit HEAD >raw &&
+	sed -e "1,/^$/d" raw >actual &&
 	test_cmp exp.log actual
 '
 
-- 
2.21.0.512.g57bf1b23e1


^ permalink raw reply	[flat|nested] 105+ messages in thread

* [PATCH v9 04/11] t7502: clean up style
  2019-03-21  6:53               ` [PATCH v9 " Denton Liu
                                   ` (2 preceding siblings ...)
  2019-03-21  6:53                 ` [PATCH v9 03/11] t7604: " Denton Liu
@ 2019-03-21  6:53                 ` Denton Liu
  2019-03-21  6:53                 ` [PATCH v9 05/11] commit: extract cleanup_mode functions to sequencer Denton Liu
                                   ` (7 subsequent siblings)
  11 siblings, 0 replies; 105+ messages in thread
From: Denton Liu @ 2019-03-21  6:53 UTC (permalink / raw)
  To: Git Mailing List
  Cc: Denton Liu, Eric Sunshine, Junio C Hamano, Phillip Wood,
	Ramsay Jones, SZEDER Gábor

Refactor out Git commands that were upstream of a pipe. Remove spaces
after "> ". Indent here-docs appropriately. Convert echo chains to use
the test_write_lines function. Refactor 'sign off' test to use test_cmp
instead of comparing variables.

Helped-by: Eric Sunshine <sunshine@sunshineco.com>
Helped-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Denton Liu <liu.denton@gmail.com>
---
 t/t7502-commit-porcelain.sh | 93 +++++++++++++++++++++----------------
 1 file changed, 53 insertions(+), 40 deletions(-)

diff --git a/t/t7502-commit-porcelain.sh b/t/t7502-commit-porcelain.sh
index ca4a740da0..5733d9cd34 100755
--- a/t/t7502-commit-porcelain.sh
+++ b/t/t7502-commit-porcelain.sh
@@ -16,7 +16,8 @@ commit_msg_is () {
 # Arguments: [<prefix] [<commit message>] [<commit options>]
 check_summary_oneline() {
 	test_tick &&
-	git commit ${3+"$3"} -m "$2" | head -1 > act &&
+	git commit ${3+"$3"} -m "$2" >raw &&
+	head -n 1 raw >act &&
 
 	# branch name
 	SUMMARY_PREFIX="$(git name-rev --name-only HEAD)" &&
@@ -68,7 +69,7 @@ test_expect_success 'output summary format for merges' '
 	git checkout recursive-a &&
 	test_must_fail git merge recursive-b &&
 	# resolve the conflict
-	echo commit-a > file1 &&
+	echo commit-a >file1 &&
 	git add file1 &&
 	check_summary_oneline "" "Merge"
 '
@@ -142,9 +143,11 @@ test_expect_success 'sign off' '
 	>positive &&
 	git add positive &&
 	git commit -s -m "thank you" &&
-	actual=$(git cat-file commit HEAD | sed -ne "s/Signed-off-by: //p") &&
-	expected=$(git var GIT_COMMITTER_IDENT | sed -e "s/>.*/>/") &&
-	test "z$actual" = "z$expected"
+	git cat-file commit HEAD >commit.msg &&
+	sed -ne "s/Signed-off-by: //p" commit.msg >actual &&
+	git var GIT_COMMITTER_IDENT >ident &&
+	sed -e "s/>.*/>/" ident >expected &&
+	test_cmp expected actual
 
 '
 
@@ -153,8 +156,8 @@ test_expect_success 'multiple -m' '
 	>negative &&
 	git add negative &&
 	git commit -m "one" -m "two" -m "three" &&
-	actual=$(git cat-file commit HEAD | sed -e "1,/^\$/d") &&
-	expected=$(echo one; echo; echo two; echo; echo three) &&
+	actual=$(git cat-file commit HEAD >tmp && sed -e "1,/^\$/d" tmp && rm tmp) &&
+	expected=$(test_write_lines "one" "" "two" "" "three") &&
 	test "z$actual" = "z$expected"
 
 '
@@ -163,7 +166,8 @@ test_expect_success 'verbose' '
 
 	echo minus >negative &&
 	git add negative &&
-	git status -v | sed -ne "/^diff --git /p" >actual &&
+	git status -v >raw &&
+	sed -ne "/^diff --git /p" raw >actual &&
 	echo "diff --git a/negative b/negative" >expect &&
 	test_cmp expect actual
 
@@ -189,7 +193,8 @@ test_expect_success 'cleanup commit messages (verbatim option,-t)' '
 
 	echo >>negative &&
 	git commit --cleanup=verbatim --no-status -t expect -a &&
-	git cat-file -p HEAD |sed -e "1,/^\$/d" >actual &&
+	git cat-file -p HEAD >raw &&
+	sed -e "1,/^\$/d" raw >actual &&
 	test_cmp expect actual
 
 '
@@ -198,7 +203,8 @@ test_expect_success 'cleanup commit messages (verbatim option,-F)' '
 
 	echo >>negative &&
 	git commit --cleanup=verbatim -F expect -a &&
-	git cat-file -p HEAD |sed -e "1,/^\$/d">actual &&
+	git cat-file -p HEAD >raw &&
+	sed -e "1,/^\$/d" raw >actual &&
 	test_cmp expect actual
 
 '
@@ -207,7 +213,8 @@ test_expect_success 'cleanup commit messages (verbatim option,-m)' '
 
 	echo >>negative &&
 	git commit --cleanup=verbatim -m "$mesg_with_comment_and_newlines" -a &&
-	git cat-file -p HEAD |sed -e "1,/^\$/d">actual &&
+	git cat-file -p HEAD >raw &&
+	sed -e "1,/^\$/d" raw >actual &&
 	test_cmp expect actual
 
 '
@@ -215,10 +222,11 @@ test_expect_success 'cleanup commit messages (verbatim option,-m)' '
 test_expect_success 'cleanup commit messages (whitespace option,-F)' '
 
 	echo >>negative &&
-	{ echo;echo "# text";echo; } >text &&
+	test_write_lines "" "# text" "" >text &&
 	echo "# text" >expect &&
 	git commit --cleanup=whitespace -F text -a &&
-	git cat-file -p HEAD |sed -e "1,/^\$/d">actual &&
+	git cat-file -p HEAD >raw &&
+	sed -e "1,/^\$/d" raw >actual &&
 	test_cmp expect actual
 
 '
@@ -226,48 +234,51 @@ test_expect_success 'cleanup commit messages (whitespace option,-F)' '
 test_expect_success 'cleanup commit messages (scissors option,-F,-e)' '
 
 	echo >>negative &&
-	cat >text <<EOF &&
+	cat >text <<-\EOF &&
 
-# to be kept
+	# to be kept
 
-  # ------------------------ >8 ------------------------
-# to be kept, too
-# ------------------------ >8 ------------------------
-to be removed
-# ------------------------ >8 ------------------------
-to be removed, too
-EOF
+	  # ------------------------ >8 ------------------------
+	# to be kept, too
+	# ------------------------ >8 ------------------------
+	to be removed
+	# ------------------------ >8 ------------------------
+	to be removed, too
+	EOF
 
-	cat >expect <<EOF &&
-# to be kept
+	cat >expect <<-\EOF &&
+	# to be kept
 
-  # ------------------------ >8 ------------------------
-# to be kept, too
-EOF
+	  # ------------------------ >8 ------------------------
+	# to be kept, too
+	EOF
 	git commit --cleanup=scissors -e -F text -a &&
-	git cat-file -p HEAD |sed -e "1,/^\$/d">actual &&
+	git cat-file -p HEAD >raw &&
+	sed -e "1,/^\$/d" raw >actual &&
 	test_cmp expect actual
 '
 
 test_expect_success 'cleanup commit messages (scissors option,-F,-e, scissors on first line)' '
 
 	echo >>negative &&
-	cat >text <<EOF &&
-# ------------------------ >8 ------------------------
-to be removed
-EOF
+	cat >text <<-\EOF &&
+	# ------------------------ >8 ------------------------
+	to be removed
+	EOF
 	git commit --cleanup=scissors -e -F text -a --allow-empty-message &&
-	git cat-file -p HEAD |sed -e "1,/^\$/d">actual &&
+	git cat-file -p HEAD >raw &&
+	sed -e "1,/^\$/d" raw >actual &&
 	test_must_be_empty actual
 '
 
 test_expect_success 'cleanup commit messages (strip option,-F)' '
 
 	echo >>negative &&
-	{ echo;echo "# text";echo sample;echo; } >text &&
+	test_write_lines "" "# text" "sample" "" >text &&
 	echo sample >expect &&
 	git commit --cleanup=strip -F text -a &&
-	git cat-file -p HEAD |sed -e "1,/^\$/d">actual &&
+	git cat-file -p HEAD >raw &&
+	sed -e "1,/^\$/d" raw >actual &&
 	test_cmp expect actual
 
 '
@@ -275,7 +286,7 @@ test_expect_success 'cleanup commit messages (strip option,-F)' '
 test_expect_success 'cleanup commit messages (strip option,-F,-e)' '
 
 	echo >>negative &&
-	{ echo;echo sample;echo; } >text &&
+	test_write_lines "" "sample" "" >text &&
 	git commit -e -F text -a &&
 	head -n 4 .git/COMMIT_EDITMSG >actual
 '
@@ -387,7 +398,7 @@ test_expect_success AUTOIDENT 'message shows committer when it is automatic' '
 '
 
 write_script .git/FAKE_EDITOR <<EOF
-echo editor started > "$(pwd)/.git/result"
+echo editor started >"$(pwd)/.git/result"
 exit 0
 EOF
 
@@ -455,7 +466,7 @@ EOF
 test_expect_success EXECKEEPSPID 'a SIGTERM should break locks' '
 	echo >>negative &&
 	! "$SHELL_PATH" -c '\''
-	  echo kill -TERM $$ >> .git/FAKE_EDITOR
+	  echo kill -TERM $$ >>.git/FAKE_EDITOR
 	  GIT_EDITOR=.git/FAKE_EDITOR
 	  export GIT_EDITOR
 	  exec git commit -a'\'' &&
@@ -471,7 +482,8 @@ test_expect_success 'Hand committing of a redundant merge removes dups' '
 	test_must_fail git merge second master &&
 	git checkout master g &&
 	EDITOR=: git commit -a &&
-	git cat-file commit HEAD | sed -n -e "s/^parent //p" -e "/^$/q" >actual &&
+	git cat-file commit HEAD >raw &&
+	sed -n -e "s/^parent //p" -e "/^$/q" raw >actual &&
 	test_cmp expect actual
 
 '
@@ -480,7 +492,8 @@ test_expect_success 'A single-liner subject with a token plus colon is not a foo
 
 	git reset --hard &&
 	git commit -s -m "hello: kitty" --allow-empty &&
-	git cat-file commit HEAD | sed -e "1,/^$/d" >actual &&
+	git cat-file commit HEAD >raw &&
+	sed -e "1,/^$/d" raw >actual &&
 	test_line_count = 3 actual
 
 '
-- 
2.21.0.512.g57bf1b23e1


^ permalink raw reply	[flat|nested] 105+ messages in thread

* [PATCH v9 05/11] commit: extract cleanup_mode functions to sequencer
  2019-03-21  6:53               ` [PATCH v9 " Denton Liu
                                   ` (3 preceding siblings ...)
  2019-03-21  6:53                 ` [PATCH v9 04/11] t7502: " Denton Liu
@ 2019-03-21  6:53                 ` Denton Liu
  2019-03-21  6:53                 ` [PATCH v9 06/11] parse-options.h: extract common --cleanup option Denton Liu
                                   ` (6 subsequent siblings)
  11 siblings, 0 replies; 105+ messages in thread
From: Denton Liu @ 2019-03-21  6:53 UTC (permalink / raw)
  To: Git Mailing List
  Cc: Denton Liu, Eric Sunshine, Junio C Hamano, Phillip Wood,
	Ramsay Jones, SZEDER Gábor

Signed-off-by: Denton Liu <liu.denton@gmail.com>
---
 builtin/commit.c | 25 ++-----------------------
 sequencer.c      | 29 +++++++++++++++++++++++++++++
 sequencer.h      |  6 ++++++
 3 files changed, 37 insertions(+), 23 deletions(-)

diff --git a/builtin/commit.c b/builtin/commit.c
index f17537474a..0df15e4851 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -1172,24 +1172,7 @@ static int parse_and_validate_options(int argc, const char *argv[],
 		die(_("Only one of --include/--only/--all/--interactive/--patch can be used."));
 	if (argc == 0 && (also || (only && !amend && !allow_empty)))
 		die(_("No paths with --include/--only does not make sense."));
-	if (!cleanup_arg || !strcmp(cleanup_arg, "default"))
-		cleanup_mode = use_editor ? COMMIT_MSG_CLEANUP_ALL :
-					    COMMIT_MSG_CLEANUP_SPACE;
-	else if (!strcmp(cleanup_arg, "verbatim"))
-		cleanup_mode = COMMIT_MSG_CLEANUP_NONE;
-	else if (!strcmp(cleanup_arg, "whitespace"))
-		cleanup_mode = COMMIT_MSG_CLEANUP_SPACE;
-	else if (!strcmp(cleanup_arg, "strip"))
-		cleanup_mode = COMMIT_MSG_CLEANUP_ALL;
-	else if (!strcmp(cleanup_arg, "scissors"))
-		cleanup_mode = use_editor ? COMMIT_MSG_CLEANUP_SCISSORS :
-					    COMMIT_MSG_CLEANUP_SPACE;
-	/*
-	 * Please update _git_commit() in git-completion.bash when you
-	 * add new options.
-	 */
-	else
-		die(_("Invalid cleanup mode %s"), cleanup_arg);
+	cleanup_mode = get_cleanup_mode(cleanup_arg, use_editor);
 
 	handle_untracked_files_arg(s);
 
@@ -1626,11 +1609,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
 		die(_("could not read commit message: %s"), strerror(saved_errno));
 	}
 
-	if (verbose || /* Truncate the message just before the diff, if any. */
-	    cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)
-		strbuf_setlen(&sb, wt_status_locate_end(sb.buf, sb.len));
-	if (cleanup_mode != COMMIT_MSG_CLEANUP_NONE)
-		strbuf_stripspace(&sb, cleanup_mode == COMMIT_MSG_CLEANUP_ALL);
+	cleanup_message(&sb, cleanup_mode, verbose);
 
 	if (message_is_empty(&sb, cleanup_mode) && !allow_empty_message) {
 		rollback_index_files();
diff --git a/sequencer.c b/sequencer.c
index 95dda23eee..224c823b43 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -511,6 +511,25 @@ static int fast_forward_to(struct repository *r,
 	return 0;
 }
 
+enum commit_msg_cleanup_mode get_cleanup_mode(const char *cleanup_arg,
+	int use_editor)
+{
+	if (!cleanup_arg || !strcmp(cleanup_arg, "default"))
+		return use_editor ? COMMIT_MSG_CLEANUP_ALL :
+				    COMMIT_MSG_CLEANUP_SPACE;
+	else if (!strcmp(cleanup_arg, "verbatim"))
+		return COMMIT_MSG_CLEANUP_NONE;
+	else if (!strcmp(cleanup_arg, "whitespace"))
+		return COMMIT_MSG_CLEANUP_SPACE;
+	else if (!strcmp(cleanup_arg, "strip"))
+		return COMMIT_MSG_CLEANUP_ALL;
+	else if (!strcmp(cleanup_arg, "scissors"))
+		return use_editor ? COMMIT_MSG_CLEANUP_SCISSORS :
+				    COMMIT_MSG_CLEANUP_SPACE;
+	else
+		die(_("Invalid cleanup mode %s"), cleanup_arg);
+}
+
 void append_conflicts_hint(struct index_state *istate,
 			   struct strbuf *msgbuf)
 {
@@ -1013,6 +1032,16 @@ static int rest_is_empty(const struct strbuf *sb, int start)
 	return 1;
 }
 
+void cleanup_message(struct strbuf *msgbuf,
+	enum commit_msg_cleanup_mode cleanup_mode, int verbose)
+{
+	if (verbose || /* Truncate the message just before the diff, if any. */
+	    cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)
+		strbuf_setlen(msgbuf, wt_status_locate_end(msgbuf->buf, msgbuf->len));
+	if (cleanup_mode != COMMIT_MSG_CLEANUP_NONE)
+		strbuf_stripspace(msgbuf, cleanup_mode == COMMIT_MSG_CLEANUP_ALL);
+}
+
 /*
  * Find out if the message in the strbuf contains only whitespace and
  * Signed-off-by lines.
diff --git a/sequencer.h b/sequencer.h
index 4d505b3590..eb9bd97ef3 100644
--- a/sequencer.h
+++ b/sequencer.h
@@ -116,6 +116,12 @@ int rearrange_squash(struct repository *r);
 void append_signoff(struct strbuf *msgbuf, size_t ignore_footer, unsigned flag);
 
 void append_conflicts_hint(struct index_state *istate, struct strbuf *msgbuf);
+enum commit_msg_cleanup_mode get_cleanup_mode(const char *cleanup_arg,
+	int use_editor);
+
+void cleanup_message(struct strbuf *msgbuf,
+	enum commit_msg_cleanup_mode cleanup_mode, int verbose);
+
 int message_is_empty(const struct strbuf *sb,
 		     enum commit_msg_cleanup_mode cleanup_mode);
 int template_untouched(const struct strbuf *sb, const char *template_file,
-- 
2.21.0.512.g57bf1b23e1


^ permalink raw reply	[flat|nested] 105+ messages in thread

* [PATCH v9 06/11] parse-options.h: extract common --cleanup option
  2019-03-21  6:53               ` [PATCH v9 " Denton Liu
                                   ` (4 preceding siblings ...)
  2019-03-21  6:53                 ` [PATCH v9 05/11] commit: extract cleanup_mode functions to sequencer Denton Liu
@ 2019-03-21  6:53                 ` Denton Liu
  2019-03-21  6:53                 ` [PATCH v9 07/11] sequencer.c: remove duplicate code Denton Liu
                                   ` (5 subsequent siblings)
  11 siblings, 0 replies; 105+ messages in thread
From: Denton Liu @ 2019-03-21  6:53 UTC (permalink / raw)
  To: Git Mailing List
  Cc: Denton Liu, Eric Sunshine, Junio C Hamano, Phillip Wood,
	Ramsay Jones, SZEDER Gábor

The --cleanup option is commonly used. Extract it so that its definition
is not repeated.

Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Signed-off-by: Denton Liu <liu.denton@gmail.com>
---
 builtin/commit.c | 2 +-
 builtin/tag.c    | 3 +--
 parse-options.h  | 1 +
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/builtin/commit.c b/builtin/commit.c
index 0df15e4851..8277da8474 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -1473,7 +1473,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
 		OPT_BOOL('s', "signoff", &signoff, N_("add Signed-off-by:")),
 		OPT_FILENAME('t', "template", &template_file, N_("use specified template file")),
 		OPT_BOOL('e', "edit", &edit_flag, N_("force edit of commit")),
-		OPT_STRING(0, "cleanup", &cleanup_arg, N_("default"), N_("how to strip spaces and #comments from message")),
+		OPT_CLEANUP(&cleanup_arg),
 		OPT_BOOL(0, "status", &include_status, N_("include status in commit message template")),
 		{ OPTION_STRING, 'S', "gpg-sign", &sign_commit, N_("key-id"),
 		  N_("GPG sign commit"), PARSE_OPT_OPTARG, NULL, (intptr_t) "" },
diff --git a/builtin/tag.c b/builtin/tag.c
index 02f6bd1279..a3870fbdba 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -397,8 +397,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
 		OPT_FILENAME('F', "file", &msgfile, N_("read message from file")),
 		OPT_BOOL('e', "edit", &edit_flag, N_("force edit of tag message")),
 		OPT_BOOL('s', "sign", &opt.sign, N_("annotated and GPG-signed tag")),
-		OPT_STRING(0, "cleanup", &cleanup_arg, N_("mode"),
-			N_("how to strip spaces and #comments from message")),
+		OPT_CLEANUP(&cleanup_arg),
 		OPT_STRING('u', "local-user", &keyid, N_("key-id"),
 					N_("use another key to sign the tag")),
 		OPT__FORCE(&force, N_("replace the tag if exists"), 0),
diff --git a/parse-options.h b/parse-options.h
index 7d83e2971d..85faaee390 100644
--- a/parse-options.h
+++ b/parse-options.h
@@ -303,5 +303,6 @@ int parse_opt_passthru_argv(const struct option *, const char *, int);
 #define OPT_NO_CONTAINS(v, h) _OPT_CONTAINS_OR_WITH("no-contains", v, h, PARSE_OPT_NONEG)
 #define OPT_WITH(v, h) _OPT_CONTAINS_OR_WITH("with", v, h, PARSE_OPT_HIDDEN | PARSE_OPT_NONEG)
 #define OPT_WITHOUT(v, h) _OPT_CONTAINS_OR_WITH("without", v, h, PARSE_OPT_HIDDEN | PARSE_OPT_NONEG)
+#define OPT_CLEANUP(v) OPT_STRING(0, "cleanup", v, N_("mode"), N_("how to strip spaces and #comments from message"))
 
 #endif
-- 
2.21.0.512.g57bf1b23e1


^ permalink raw reply	[flat|nested] 105+ messages in thread

* [PATCH v9 07/11] sequencer.c: remove duplicate code
  2019-03-21  6:53               ` [PATCH v9 " Denton Liu
                                   ` (5 preceding siblings ...)
  2019-03-21  6:53                 ` [PATCH v9 06/11] parse-options.h: extract common --cleanup option Denton Liu
@ 2019-03-21  6:53                 ` Denton Liu
  2019-03-26 10:44                   ` Phillip Wood
  2019-03-21  6:53                 ` [PATCH v9 08/11] merge: cleanup messages like commit Denton Liu
                                   ` (4 subsequent siblings)
  11 siblings, 1 reply; 105+ messages in thread
From: Denton Liu @ 2019-03-21  6:53 UTC (permalink / raw)
  To: Git Mailing List
  Cc: Denton Liu, Eric Sunshine, Junio C Hamano, Phillip Wood,
	Ramsay Jones, SZEDER Gábor

Since we implemented get_cleanup_mode, we had some duplicate code in
git_sequencer_config which essentially performed the same operations.
Refactor git_sequencer_config to take advantage of the logic already in
get_cleanup_mode.

Note that we had to introduce a separate argument to get_cleanup_mode
indicating whether to die or not on an invalid value. This is because if
we are parsing a config, we do not want to die but instead, we only want
to warn the user, whereas if we are parsing a command-line option, we
would like to actually die.

Finally, this is almost a no-op refactor but not quite. Previously, in
the case that an invalid value is presented, default_msg_cleanup would
not be set. We change the behaviour so that default_msg_cleanup will now
take on the value as if "default" were provided as the cleanup_arg.
Also, we lowercase some user-facing strings.

Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Signed-off-by: Denton Liu <liu.denton@gmail.com>
---
 builtin/commit.c |  2 +-
 sequencer.c      | 22 ++++++++--------------
 sequencer.h      |  2 +-
 3 files changed, 10 insertions(+), 16 deletions(-)

diff --git a/builtin/commit.c b/builtin/commit.c
index 8277da8474..ba1e6027ba 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -1172,7 +1172,7 @@ static int parse_and_validate_options(int argc, const char *argv[],
 		die(_("Only one of --include/--only/--all/--interactive/--patch can be used."));
 	if (argc == 0 && (also || (only && !amend && !allow_empty)))
 		die(_("No paths with --include/--only does not make sense."));
-	cleanup_mode = get_cleanup_mode(cleanup_arg, use_editor);
+	cleanup_mode = get_cleanup_mode(cleanup_arg, use_editor, 1);
 
 	handle_untracked_files_arg(s);
 
diff --git a/sequencer.c b/sequencer.c
index 224c823b43..2cbfb848dd 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -172,17 +172,7 @@ static int git_sequencer_config(const char *k, const char *v, void *cb)
 		if (status)
 			return status;
 
-		if (!strcmp(s, "verbatim"))
-			opts->default_msg_cleanup = COMMIT_MSG_CLEANUP_NONE;
-		else if (!strcmp(s, "whitespace"))
-			opts->default_msg_cleanup = COMMIT_MSG_CLEANUP_SPACE;
-		else if (!strcmp(s, "strip"))
-			opts->default_msg_cleanup = COMMIT_MSG_CLEANUP_ALL;
-		else if (!strcmp(s, "scissors"))
-			opts->default_msg_cleanup = COMMIT_MSG_CLEANUP_SPACE;
-		else
-			warning(_("invalid commit message cleanup mode '%s'"),
-				  s);
+		opts->default_msg_cleanup = get_cleanup_mode(s, 0, 0);
 
 		free((char *)s);
 		return status;
@@ -512,7 +502,7 @@ static int fast_forward_to(struct repository *r,
 }
 
 enum commit_msg_cleanup_mode get_cleanup_mode(const char *cleanup_arg,
-	int use_editor)
+	int use_editor, int die_on_error)
 {
 	if (!cleanup_arg || !strcmp(cleanup_arg, "default"))
 		return use_editor ? COMMIT_MSG_CLEANUP_ALL :
@@ -526,8 +516,12 @@ enum commit_msg_cleanup_mode get_cleanup_mode(const char *cleanup_arg,
 	else if (!strcmp(cleanup_arg, "scissors"))
 		return use_editor ? COMMIT_MSG_CLEANUP_SCISSORS :
 				    COMMIT_MSG_CLEANUP_SPACE;
-	else
-		die(_("Invalid cleanup mode %s"), cleanup_arg);
+	else if (!die_on_error) {
+		warning(_("invalid cleanup mode %s, falling back to default"), cleanup_arg);
+		return use_editor ? COMMIT_MSG_CLEANUP_ALL :
+				    COMMIT_MSG_CLEANUP_SPACE;
+	} else
+		die(_("invalid cleanup mode %s"), cleanup_arg);
 }
 
 void append_conflicts_hint(struct index_state *istate,
diff --git a/sequencer.h b/sequencer.h
index eb9bd97ef3..e7908f558e 100644
--- a/sequencer.h
+++ b/sequencer.h
@@ -117,7 +117,7 @@ void append_signoff(struct strbuf *msgbuf, size_t ignore_footer, unsigned flag);
 
 void append_conflicts_hint(struct index_state *istate, struct strbuf *msgbuf);
 enum commit_msg_cleanup_mode get_cleanup_mode(const char *cleanup_arg,
-	int use_editor);
+	int use_editor, int die_on_error);
 
 void cleanup_message(struct strbuf *msgbuf,
 	enum commit_msg_cleanup_mode cleanup_mode, int verbose);
-- 
2.21.0.512.g57bf1b23e1


^ permalink raw reply	[flat|nested] 105+ messages in thread

* [PATCH v9 08/11] merge: cleanup messages like commit
  2019-03-21  6:53               ` [PATCH v9 " Denton Liu
                                   ` (6 preceding siblings ...)
  2019-03-21  6:53                 ` [PATCH v9 07/11] sequencer.c: remove duplicate code Denton Liu
@ 2019-03-21  6:53                 ` Denton Liu
  2019-03-21  6:53                 ` [PATCH v9 09/11] merge: add scissors line on merge conflict Denton Liu
                                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 105+ messages in thread
From: Denton Liu @ 2019-03-21  6:53 UTC (permalink / raw)
  To: Git Mailing List
  Cc: Denton Liu, Eric Sunshine, Junio C Hamano, Phillip Wood,
	Ramsay Jones, SZEDER Gábor

This change allows git-merge messages to be cleaned up with the
commit.cleanup configuration or --cleanup option, just like how
git-commit does it.

We also give git-pull the passthrough option of --cleanup so that it can
also take advantage of this change.

Finally, add testing to ensure that messages are properly cleaned up.
Note that some newlines that were added to the commit message were
removed so that if a file were read via -F, it would be copied
faithfully.

Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Helped-by: Eric Sunshine <sunshine@sunshineco.com>
Signed-off-by: Denton Liu <liu.denton@gmail.com>
---
 Documentation/merge-options.txt |  4 +++
 builtin/merge.c                 | 35 ++++++++++++++----
 builtin/pull.c                  | 23 ++++++++++++
 t/t5521-pull-options.sh         |  8 +++++
 t/t7604-merge-custom-message.sh | 63 +++++++++++++++++++++++++++++++++
 wt-status.c                     | 12 +++++--
 wt-status.h                     |  1 +
 7 files changed, 136 insertions(+), 10 deletions(-)

diff --git a/Documentation/merge-options.txt b/Documentation/merge-options.txt
index 92a7d936c1..bcf0b3e49c 100644
--- a/Documentation/merge-options.txt
+++ b/Documentation/merge-options.txt
@@ -32,6 +32,10 @@ they run `git merge`. To make it easier to adjust such scripts to the
 updated behaviour, the environment variable `GIT_MERGE_AUTOEDIT` can be
 set to `no` at the beginning of them.
 
+--cleanup=<mode>::
+	This option determines how the merge message will be cleaned up
+	before commiting. See linkgit:git-commit[1] for more details.
+
 --ff::
 	When the merge resolves as a fast-forward, only update the branch
 	pointer, without creating a merge commit.  This is the default
diff --git a/builtin/merge.c b/builtin/merge.c
index 5ce8946d39..f5783a901d 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -38,6 +38,7 @@
 #include "tag.h"
 #include "alias.h"
 #include "commit-reach.h"
+#include "wt-status.h"
 
 #define DEFAULT_TWOHEAD (1<<0)
 #define DEFAULT_OCTOPUS (1<<1)
@@ -98,6 +99,9 @@ enum ff_type {
 
 static enum ff_type fast_forward = FF_ALLOW;
 
+static const char *cleanup_arg;
+static enum commit_msg_cleanup_mode cleanup_mode;
+
 static int option_parse_message(const struct option *opt,
 				const char *arg, int unset)
 {
@@ -249,6 +253,7 @@ static struct option builtin_merge_options[] = {
 		N_("perform a commit if the merge succeeds (default)")),
 	OPT_BOOL('e', "edit", &option_edit,
 		N_("edit message before committing")),
+	OPT_CLEANUP(&cleanup_arg),
 	OPT_SET_INT(0, "ff", &fast_forward, N_("allow fast-forward (default)"), FF_ALLOW),
 	OPT_SET_INT_F(0, "ff-only", &fast_forward,
 		      N_("abort if fast-forward is not possible"),
@@ -612,6 +617,8 @@ static int git_merge_config(const char *k, const char *v, void *cb)
 		return git_config_string(&pull_twohead, k, v);
 	else if (!strcmp(k, "pull.octopus"))
 		return git_config_string(&pull_octopus, k, v);
+	else if (!strcmp(k, "commit.cleanup"))
+		return git_config_string(&cleanup_arg, k, v);
 	else if (!strcmp(k, "merge.renormalize"))
 		option_renormalize = git_config_bool(k, v);
 	else if (!strcmp(k, "merge.ff")) {
@@ -800,8 +807,13 @@ static void abort_commit(struct commit_list *remoteheads, const char *err_msg)
 static const char merge_editor_comment[] =
 N_("Please enter a commit message to explain why this merge is necessary,\n"
    "especially if it merges an updated upstream into a topic branch.\n"
-   "\n"
-   "Lines starting with '%c' will be ignored, and an empty message aborts\n"
+   "\n");
+
+static const char scissors_editor_comment[] =
+N_("An empty message aborts the commit.\n");
+
+static const char no_scissors_editor_comment[] =
+N_("Lines starting with '%c' will be ignored, and an empty message aborts\n"
    "the commit.\n");
 
 static void write_merge_heads(struct commit_list *);
@@ -809,11 +821,19 @@ static void prepare_to_commit(struct commit_list *remoteheads)
 {
 	struct strbuf msg = STRBUF_INIT;
 	strbuf_addbuf(&msg, &merge_msg);
-	strbuf_addch(&msg, '\n');
 	if (squash)
 		BUG("the control must not reach here under --squash");
-	if (0 < option_edit)
-		strbuf_commented_addf(&msg, _(merge_editor_comment), comment_line_char);
+	if (0 < option_edit) {
+		strbuf_addch(&msg, '\n');
+		if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)
+			wt_status_append_cut_line(&msg);
+
+		strbuf_commented_addf(&msg, "\n");
+		strbuf_commented_addf(&msg, _(merge_editor_comment));
+		strbuf_commented_addf(&msg, _(cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS ?
+			scissors_editor_comment :
+			no_scissors_editor_comment), comment_line_char);
+	}
 	if (signoff)
 		append_signoff(&msg, ignore_non_trailer(msg.buf, msg.len), 0);
 	write_merge_heads(remoteheads);
@@ -832,7 +852,7 @@ static void prepare_to_commit(struct commit_list *remoteheads)
 		abort_commit(remoteheads, NULL);
 
 	read_merge_msg(&msg);
-	strbuf_stripspace(&msg, 0 < option_edit);
+	cleanup_message(&msg, cleanup_mode, 0);
 	if (!msg.len)
 		abort_commit(remoteheads, _("Empty commit message."));
 	strbuf_release(&merge_msg);
@@ -880,7 +900,6 @@ static int finish_automerge(struct commit *head,
 	parents = remoteheads;
 	if (!head_subsumed || fast_forward == FF_NO)
 		commit_list_insert(head, &parents);
-	strbuf_addch(&merge_msg, '\n');
 	prepare_to_commit(remoteheads);
 	if (commit_tree(merge_msg.buf, merge_msg.len, result_tree, parents,
 			&result_commit, NULL, sign_commit))
@@ -1389,6 +1408,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
 	if (option_edit < 0)
 		option_edit = default_edit_option();
 
+	cleanup_mode = get_cleanup_mode(cleanup_arg, 0 < option_edit, 1);
+
 	if (!use_strategies) {
 		if (!remoteheads)
 			; /* already up-to-date */
diff --git a/builtin/pull.c b/builtin/pull.c
index 33db889955..55ebb5808e 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -24,6 +24,7 @@
 #include "lockfile.h"
 #include "wt-status.h"
 #include "commit-reach.h"
+#include "sequencer.h"
 
 enum rebase_type {
 	REBASE_INVALID = -1,
@@ -101,6 +102,7 @@ static char *opt_signoff;
 static char *opt_squash;
 static char *opt_commit;
 static char *opt_edit;
+static char *opt_cleanup;
 static char *opt_ff;
 static char *opt_verify_signatures;
 static int opt_autostash = -1;
@@ -168,6 +170,9 @@ static struct option pull_options[] = {
 	OPT_PASSTHRU(0, "edit", &opt_edit, NULL,
 		N_("edit message before committing"),
 		PARSE_OPT_NOARG),
+	OPT_PASSTHRU(0, "cleanup", &opt_cleanup, NULL,
+		N_("how to strip spaces and #comments from message"),
+		0),
 	OPT_PASSTHRU(0, "ff", &opt_ff, NULL,
 		N_("allow fast-forward"),
 		PARSE_OPT_NOARG),
@@ -644,6 +649,8 @@ static int run_merge(void)
 		argv_array_push(&args, opt_commit);
 	if (opt_edit)
 		argv_array_push(&args, opt_edit);
+	if (opt_cleanup)
+		argv_array_push(&args, opt_cleanup);
 	if (opt_ff)
 		argv_array_push(&args, opt_ff);
 	if (opt_verify_signatures)
@@ -875,6 +882,22 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
 
 	argc = parse_options(argc, argv, prefix, pull_options, pull_usage, 0);
 
+	if (opt_cleanup) {
+		const char *prefix = "--cleanup=";
+		const char *cleanup_arg;
+
+		if (strncmp(opt_cleanup, prefix, strlen(prefix)))
+			BUG("expecting prefix %s, argument is %s", prefix, opt_cleanup);
+
+		cleanup_arg = &opt_cleanup[strlen(prefix)];
+
+		/*
+		 * this only checks the validity of cleanup_arg; we don't need
+		 * a valid value for use_editor
+		 */
+		get_cleanup_mode(cleanup_arg, 0, 1);
+	}
+
 	parse_repo_refspecs(argc, argv, &repo, &refspecs);
 
 	if (!opt_ff)
diff --git a/t/t5521-pull-options.sh b/t/t5521-pull-options.sh
index c19d8dbc9d..ccde8ba491 100755
--- a/t/t5521-pull-options.sh
+++ b/t/t5521-pull-options.sh
@@ -77,6 +77,14 @@ test_expect_success 'git pull -q -v' '
 	test_must_be_empty out &&
 	test -s err)
 '
+test_expect_success 'git pull --cleanup errors early on invalid argument' '
+	mkdir clonedcleanup &&
+	(cd clonedcleanup && git init &&
+	test_must_fail git pull --cleanup invalid "../parent" >out 2>err &&
+	test_must_be_empty out &&
+	test -s err)
+'
+
 
 test_expect_success 'git pull --force' '
 	mkdir clonedoldstyle &&
diff --git a/t/t7604-merge-custom-message.sh b/t/t7604-merge-custom-message.sh
index aba1279132..cd4f9607dc 100755
--- a/t/t7604-merge-custom-message.sh
+++ b/t/t7604-merge-custom-message.sh
@@ -49,4 +49,67 @@ test_expect_success 'merge --log appends to custom message' '
 	test_cmp exp.log actual
 '
 
+mesg_with_comment_and_newlines='
+# text
+
+'
+
+test_expect_success 'prepare file with comment line and trailing newlines'  '
+	printf "%s" "$mesg_with_comment_and_newlines" >expect
+'
+
+test_expect_success 'cleanup commit messages (verbatim option)' '
+	git reset --hard c1 &&
+	git merge --cleanup=verbatim -F expect c2 &&
+	git cat-file commit HEAD >raw &&
+	sed -e "1,/^$/d" raw >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'cleanup commit messages (whitespace option)' '
+	git reset --hard c1 &&
+	test_write_lines "" "# text" "" >text &&
+	echo "# text" >expect &&
+	git merge --cleanup=whitespace -F text c2 &&
+	git cat-file commit HEAD >raw &&
+	sed -e "1,/^$/d" raw >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'cleanup merge messages (scissors option)' '
+	git reset --hard c1 &&
+	cat >text <<-\EOF &&
+
+	# to be kept
+
+	  # ------------------------ >8 ------------------------
+	# to be kept, too
+	# ------------------------ >8 ------------------------
+	to be removed
+	# ------------------------ >8 ------------------------
+	to be removed, too
+	EOF
+
+	cat >expect <<-\EOF &&
+	# to be kept
+
+	  # ------------------------ >8 ------------------------
+	# to be kept, too
+	EOF
+	git merge --cleanup=scissors -e -F text c2 &&
+	git cat-file commit HEAD >raw &&
+	sed -e "1,/^$/d" raw >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'cleanup commit messages (strip option)' '
+	git reset --hard c1 &&
+	test_write_lines "" "# text" "sample" "" >text &&
+	echo sample >expect &&
+	git merge --cleanup=strip -F text c2 &&
+	git cat-file commit HEAD >raw &&
+	sed -e "1,/^$/d" raw >actual &&
+	test_cmp expect actual
+'
+
 test_done
diff --git a/wt-status.c b/wt-status.c
index 445a36204a..b81fcd428d 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -1006,13 +1006,19 @@ size_t wt_status_locate_end(const char *s, size_t len)
 	return len;
 }
 
-void wt_status_add_cut_line(FILE *fp)
+void wt_status_append_cut_line(struct strbuf *buf)
 {
 	const char *explanation = _("Do not modify or remove the line above.\nEverything below it will be ignored.");
+
+	strbuf_commented_addf(buf, "%s", cut_line);
+	strbuf_add_commented_lines(buf, explanation, strlen(explanation));
+}
+
+void wt_status_add_cut_line(FILE *fp)
+{
 	struct strbuf buf = STRBUF_INIT;
 
-	fprintf(fp, "%c %s", comment_line_char, cut_line);
-	strbuf_add_commented_lines(&buf, explanation, strlen(explanation));
+	wt_status_append_cut_line(&buf);
 	fputs(buf.buf, fp);
 	strbuf_release(&buf);
 }
diff --git a/wt-status.h b/wt-status.h
index 3a95975032..64f1ddc9fd 100644
--- a/wt-status.h
+++ b/wt-status.h
@@ -129,6 +129,7 @@ struct wt_status {
 };
 
 size_t wt_status_locate_end(const char *s, size_t len);
+void wt_status_append_cut_line(struct strbuf *buf);
 void wt_status_add_cut_line(FILE *fp);
 void wt_status_prepare(struct repository *r, struct wt_status *s);
 void wt_status_print(struct wt_status *s);
-- 
2.21.0.512.g57bf1b23e1


^ permalink raw reply	[flat|nested] 105+ messages in thread

* [PATCH v9 09/11] merge: add scissors line on merge conflict
  2019-03-21  6:53               ` [PATCH v9 " Denton Liu
                                   ` (7 preceding siblings ...)
  2019-03-21  6:53                 ` [PATCH v9 08/11] merge: cleanup messages like commit Denton Liu
@ 2019-03-21  6:53                 ` Denton Liu
  2019-03-21  6:54                 ` [PATCH v9 10/11] sequencer.c: define describe_cleanup_mode Denton Liu
                                   ` (2 subsequent siblings)
  11 siblings, 0 replies; 105+ messages in thread
From: Denton Liu @ 2019-03-21  6:53 UTC (permalink / raw)
  To: Git Mailing List
  Cc: Denton Liu, Eric Sunshine, Junio C Hamano, Phillip Wood,
	Ramsay Jones, SZEDER Gábor

This fixes a bug where the scissors line is placed after the Conflicts:
section, in the case where a merge conflict occurs and
commit.cleanup = scissors.

Next, if commit.cleanup = scissors is specified, don't produce a
scissors line in commit if one already exists in the MERGE_MSG file.

Helped-by: Eric Sunshine <sunshine@sunshineco.com>
Signed-off-by: Denton Liu <liu.denton@gmail.com>
---
 Documentation/merge-options.txt |  7 +++--
 builtin/commit.c                | 20 ++++++++++----
 builtin/merge.c                 | 14 ++++++++++
 t/t7600-merge.sh                | 46 +++++++++++++++++++++++++++++++++
 4 files changed, 80 insertions(+), 7 deletions(-)

diff --git a/Documentation/merge-options.txt b/Documentation/merge-options.txt
index bcf0b3e49c..61876dbc33 100644
--- a/Documentation/merge-options.txt
+++ b/Documentation/merge-options.txt
@@ -33,8 +33,11 @@ updated behaviour, the environment variable `GIT_MERGE_AUTOEDIT` can be
 set to `no` at the beginning of them.
 
 --cleanup=<mode>::
-	This option determines how the merge message will be cleaned up
-	before commiting. See linkgit:git-commit[1] for more details.
+	This option determines how the merge message will be cleaned up before
+	commiting. See linkgit:git-commit[1] for more details. In addition, if
+	the '<mode>' is given a value of `scissors`, scissors will be appended
+	to `MERGE_MSG` before being passed on to the commit machinery in the
+	case of a merge conflict.
 
 --ff::
 	When the merge resolves as a fast-forward, only update the branch
diff --git a/builtin/commit.c b/builtin/commit.c
index ba1e6027ba..b9159c2e7b 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -668,6 +668,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
 	const char *hook_arg2 = NULL;
 	int clean_message_contents = (cleanup_mode != COMMIT_MSG_CLEANUP_NONE);
 	int old_display_comment_prefix;
+	int merge_contains_scissors = 0;
 
 	/* This checks and barfs if author is badly specified */
 	determine_author_info(author_ident);
@@ -728,6 +729,8 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
 			strbuf_addbuf(&sb, &message);
 		hook_arg1 = "message";
 	} else if (!stat(git_path_merge_msg(the_repository), &statbuf)) {
+		size_t merge_msg_start;
+
 		/*
 		 * prepend SQUASH_MSG here if it exists and a
 		 * "merge --squash" was originally performed
@@ -738,8 +741,14 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
 			hook_arg1 = "squash";
 		} else
 			hook_arg1 = "merge";
+
+		merge_msg_start = sb.len;
 		if (strbuf_read_file(&sb, git_path_merge_msg(the_repository), 0) < 0)
 			die_errno(_("could not read MERGE_MSG"));
+
+		if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS &&
+		    wt_status_locate_end(sb.buf + merge_msg_start, sb.len - merge_msg_start) < sb.len - merge_msg_start)
+			merge_contains_scissors = 1;
 	} else if (!stat(git_path_squash_msg(the_repository), &statbuf)) {
 		if (strbuf_read_file(&sb, git_path_squash_msg(the_repository), 0) < 0)
 			die_errno(_("could not read SQUASH_MSG"));
@@ -807,7 +816,8 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
 		struct ident_split ci, ai;
 
 		if (whence != FROM_COMMIT) {
-			if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)
+			if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS &&
+				!merge_contains_scissors)
 				wt_status_add_cut_line(s->fp);
 			status_printf_ln(s, GIT_COLOR_NORMAL,
 			    whence == FROM_MERGE
@@ -832,10 +842,10 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
 				_("Please enter the commit message for your changes."
 				  " Lines starting\nwith '%c' will be ignored, and an empty"
 				  " message aborts the commit.\n"), comment_line_char);
-		else if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS &&
-			 whence == FROM_COMMIT)
-			wt_status_add_cut_line(s->fp);
-		else /* COMMIT_MSG_CLEANUP_SPACE, that is. */
+		else if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS) {
+			if (whence == FROM_COMMIT && !merge_contains_scissors)
+				wt_status_add_cut_line(s->fp);
+		} else /* COMMIT_MSG_CLEANUP_SPACE, that is. */
 			status_printf(s, GIT_COLOR_NORMAL,
 				_("Please enter the commit message for your changes."
 				  " Lines starting\n"
diff --git a/builtin/merge.c b/builtin/merge.c
index f5783a901d..148554f08e 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -920,6 +920,20 @@ static int suggest_conflicts(void)
 	filename = git_path_merge_msg(the_repository);
 	fp = xfopen(filename, "a");
 
+	/*
+	 * We can't use cleanup_mode because if we're not using the editor,
+	 * get_cleanup_mode will return COMMIT_MSG_CLEANUP_SPACE instead, even
+	 * though the message is meant to be processed later by git-commit.
+	 * Thus, we will get the cleanup mode which is returned when we _are_ using
+	 * an editor.
+	 */
+	if (get_cleanup_mode(cleanup_arg, 1, 1) == COMMIT_MSG_CLEANUP_SCISSORS) {
+	    fputc('\n', fp);
+	    wt_status_add_cut_line(fp);
+	    /* comments out the newline from append_conflicts_hint */
+	    fputc(comment_line_char, fp);
+	}
+
 	append_conflicts_hint(&the_index, &msgbuf);
 	fputs(msgbuf.buf, fp);
 	strbuf_release(&msgbuf);
diff --git a/t/t7600-merge.sh b/t/t7600-merge.sh
index 2f4c2801fb..7f9c68cbe7 100755
--- a/t/t7600-merge.sh
+++ b/t/t7600-merge.sh
@@ -246,6 +246,52 @@ test_expect_success 'merge --squash c3 with c7' '
 	test_cmp expect actual
 '
 
+test_expect_success 'merge c3 with c7 with commit.cleanup = scissors' '
+	git config commit.cleanup scissors &&
+	git reset --hard c3 &&
+	test_must_fail git merge c7 &&
+	cat result.9z >file &&
+	git commit --no-edit -a &&
+
+	cat >expect <<-\EOF &&
+	Merge tag '"'"'c7'"'"'
+
+	# ------------------------ >8 ------------------------
+	# Do not modify or remove the line above.
+	# Everything below it will be ignored.
+	#
+	# Conflicts:
+	#	file
+	EOF
+	git cat-file commit HEAD >raw &&
+	sed -e '1,/^$/d' raw >actual &&
+	test_i18ncmp expect actual
+'
+
+test_expect_success 'merge c3 with c7 with --squash commit.cleanup = scissors' '
+	git config commit.cleanup scissors &&
+	git reset --hard c3 &&
+	test_must_fail git merge --squash c7 &&
+	cat result.9z >file &&
+	git commit --no-edit -a &&
+
+	cat >expect <<-EOF &&
+	Squashed commit of the following:
+
+	$(git show -s c7)
+
+	# ------------------------ >8 ------------------------
+	# Do not modify or remove the line above.
+	# Everything below it will be ignored.
+	#
+	# Conflicts:
+	#	file
+	EOF
+	git cat-file commit HEAD >raw &&
+	sed -e '1,/^$/d' raw >actual &&
+	test_i18ncmp expect actual
+'
+
 test_debug 'git log --graph --decorate --oneline --all'
 
 test_expect_success 'merge c1 with c2 and c3' '
-- 
2.21.0.512.g57bf1b23e1


^ permalink raw reply	[flat|nested] 105+ messages in thread

* [PATCH v9 10/11] sequencer.c: define describe_cleanup_mode
  2019-03-21  6:53               ` [PATCH v9 " Denton Liu
                                   ` (8 preceding siblings ...)
  2019-03-21  6:53                 ` [PATCH v9 09/11] merge: add scissors line on merge conflict Denton Liu
@ 2019-03-21  6:54                 ` Denton Liu
  2019-03-21  6:54                 ` [PATCH v9 11/11] cherry-pick/revert: add scissors line on merge conflict Denton Liu
  2019-04-17 10:23                 ` [PATCH v10 00/10] Fix scissors bug during conflict Phillip Wood
  11 siblings, 0 replies; 105+ messages in thread
From: Denton Liu @ 2019-03-21  6:54 UTC (permalink / raw)
  To: Git Mailing List
  Cc: Denton Liu, Eric Sunshine, Junio C Hamano, Phillip Wood,
	Ramsay Jones, SZEDER Gábor

Define a function which allows us to get the string configuration value
of a enum commit_msg_cleanup_mode. This is done by refactoring
get_cleanup_mode such that it uses a lookup table to find the mappings
between string and enum and then using the same LUT in reverse to define
describe_cleanup_mode.

Helped-by: Eric Sunshine <sunshine@sunshineco.com>
Helped-by: Junio C Hamano <gitster@pobox.com>
Helped-by: Ramsay Jones <ramsay@ramsayjones.plus.com>
Signed-off-by: Denton Liu <liu.denton@gmail.com>
---
 sequencer.c | 62 ++++++++++++++++++++++++++++++++++++++++-------------
 1 file changed, 47 insertions(+), 15 deletions(-)

diff --git a/sequencer.c b/sequencer.c
index 2cbfb848dd..f782e8bab2 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -160,6 +160,22 @@ static GIT_PATH_FUNC(rebase_path_strategy_opts, "rebase-merge/strategy_opts")
 static GIT_PATH_FUNC(rebase_path_allow_rerere_autoupdate, "rebase-merge/allow_rerere_autoupdate")
 static GIT_PATH_FUNC(rebase_path_reschedule_failed_exec, "rebase-merge/reschedule-failed-exec")
 
+struct cleanup_config_mapping {
+	const char *value;
+	enum commit_msg_cleanup_mode editor;
+	enum commit_msg_cleanup_mode no_editor;
+};
+
+/* the 0th element of this array must be the "default" */
+static struct cleanup_config_mapping cleanup_config_mapping[] = {
+	{ "default", COMMIT_MSG_CLEANUP_ALL, COMMIT_MSG_CLEANUP_SPACE },
+	{ "verbatim", COMMIT_MSG_CLEANUP_NONE, COMMIT_MSG_CLEANUP_NONE },
+	{ "whitespace", COMMIT_MSG_CLEANUP_SPACE, COMMIT_MSG_CLEANUP_SPACE },
+	{ "strip", COMMIT_MSG_CLEANUP_ALL, COMMIT_MSG_CLEANUP_ALL },
+	{ "scissors", COMMIT_MSG_CLEANUP_SCISSORS, COMMIT_MSG_CLEANUP_SPACE },
+	{ NULL, 0, 0 }
+};
+
 static int git_sequencer_config(const char *k, const char *v, void *cb)
 {
 	struct replay_opts *opts = cb;
@@ -504,26 +520,37 @@ static int fast_forward_to(struct repository *r,
 enum commit_msg_cleanup_mode get_cleanup_mode(const char *cleanup_arg,
 	int use_editor, int die_on_error)
 {
-	if (!cleanup_arg || !strcmp(cleanup_arg, "default"))
-		return use_editor ? COMMIT_MSG_CLEANUP_ALL :
-				    COMMIT_MSG_CLEANUP_SPACE;
-	else if (!strcmp(cleanup_arg, "verbatim"))
-		return COMMIT_MSG_CLEANUP_NONE;
-	else if (!strcmp(cleanup_arg, "whitespace"))
-		return COMMIT_MSG_CLEANUP_SPACE;
-	else if (!strcmp(cleanup_arg, "strip"))
-		return COMMIT_MSG_CLEANUP_ALL;
-	else if (!strcmp(cleanup_arg, "scissors"))
-		return use_editor ? COMMIT_MSG_CLEANUP_SCISSORS :
-				    COMMIT_MSG_CLEANUP_SPACE;
-	else if (!die_on_error) {
+	struct cleanup_config_mapping *def = &cleanup_config_mapping[0];
+	struct cleanup_config_mapping *p;
+
+	if (!cleanup_arg)
+		return use_editor ? def->editor :
+				    def->no_editor;
+
+	for (p = cleanup_config_mapping; p->value; p++)
+		if (!strcmp(cleanup_arg, p->value))
+			return use_editor ? p->editor :
+					    p->no_editor;
+
+	if (!die_on_error) {
 		warning(_("invalid cleanup mode %s, falling back to default"), cleanup_arg);
-		return use_editor ? COMMIT_MSG_CLEANUP_ALL :
-				    COMMIT_MSG_CLEANUP_SPACE;
+		return use_editor ? def->editor :
+				    def->no_editor;
 	} else
 		die(_("invalid cleanup mode %s"), cleanup_arg);
 }
 
+static const char *describe_cleanup_mode(enum commit_msg_cleanup_mode cleanup_mode)
+{
+	struct cleanup_config_mapping *curr;
+
+	for (curr = &cleanup_config_mapping[1]; curr->value; curr++)
+		if (cleanup_mode == curr->editor)
+			return curr->value;
+
+	BUG("invalid cleanup_mode provided (%d)", cleanup_mode);
+}
+
 void append_conflicts_hint(struct index_state *istate,
 			   struct strbuf *msgbuf)
 {
@@ -2350,6 +2377,8 @@ static int populate_opts_cb(const char *key, const char *value, void *data)
 		opts->allow_rerere_auto =
 			git_config_bool_or_int(key, value, &error_flag) ?
 				RERERE_AUTOUPDATE : RERERE_NOAUTOUPDATE;
+	else if (!strcmp(key, "options.default-msg-cleanup"))
+		opts->default_msg_cleanup = get_cleanup_mode(value, 1, 1);
 	else
 		return error(_("invalid key: %s"), key);
 
@@ -2754,6 +2783,9 @@ static int save_opts(struct replay_opts *opts)
 		res |= git_config_set_in_file_gently(opts_file, "options.allow-rerere-auto",
 						     opts->allow_rerere_auto == RERERE_AUTOUPDATE ?
 						     "true" : "false");
+
+	res |= git_config_set_in_file_gently(opts_file, "options.default-msg-cleanup",
+					     describe_cleanup_mode(opts->default_msg_cleanup));
 	return res;
 }
 
-- 
2.21.0.512.g57bf1b23e1


^ permalink raw reply	[flat|nested] 105+ messages in thread

* [PATCH v9 11/11] cherry-pick/revert: add scissors line on merge conflict
  2019-03-21  6:53               ` [PATCH v9 " Denton Liu
                                   ` (9 preceding siblings ...)
  2019-03-21  6:54                 ` [PATCH v9 10/11] sequencer.c: define describe_cleanup_mode Denton Liu
@ 2019-03-21  6:54                 ` Denton Liu
  2019-04-17 10:23                 ` [PATCH v10 00/10] Fix scissors bug during conflict Phillip Wood
  11 siblings, 0 replies; 105+ messages in thread
From: Denton Liu @ 2019-03-21  6:54 UTC (permalink / raw)
  To: Git Mailing List
  Cc: Denton Liu, Eric Sunshine, Junio C Hamano, Phillip Wood,
	Ramsay Jones, SZEDER Gábor

Fix a bug where the scissors line is placed after the Conflicts:
section, in the case where a merge conflict occurs and
commit.cleanup = scissors.

Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Signed-off-by: Denton Liu <liu.denton@gmail.com>
---
 Documentation/git-cherry-pick.txt |  7 +++
 Documentation/git-revert.txt      |  7 +++
 builtin/merge.c                   |  9 +---
 builtin/rebase--interactive.c     |  2 +-
 builtin/revert.c                  |  5 ++
 sequencer.c                       | 22 +++++---
 sequencer.h                       |  3 +-
 t/t3507-cherry-pick-conflict.sh   | 86 +++++++++++++++++++++++++++++++
 8 files changed, 123 insertions(+), 18 deletions(-)

diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt
index b8cfeec67e..cbb663a843 100644
--- a/Documentation/git-cherry-pick.txt
+++ b/Documentation/git-cherry-pick.txt
@@ -57,6 +57,13 @@ OPTIONS
 	With this option, 'git cherry-pick' will let you edit the commit
 	message prior to committing.
 
+--cleanup=<mode>::
+	This option determines how the commit message will be cleaned up before
+	being passed on to the commit machinery. See linkgit:git-commit[1] for more
+	details. In particular, if the '<mode>' is given a value of `scissors`,
+	scissors will be appended to `MERGE_MSG` before being passed on in the case
+	of a conflict.
+
 -x::
 	When recording the commit, append a line that says
 	"(cherry picked from commit ...)" to the original commit
diff --git a/Documentation/git-revert.txt b/Documentation/git-revert.txt
index 837707a8fd..7fd254df92 100644
--- a/Documentation/git-revert.txt
+++ b/Documentation/git-revert.txt
@@ -66,6 +66,13 @@ more details.
 	With this option, 'git revert' will not start the commit
 	message editor.
 
+--cleanup=<mode>::
+	This option determines how the commit message will be cleaned up before
+	being passed on to the commit machinery. See linkgit:git-commit[1] for more
+	details. In particular, if the '<mode>' is given a value of `scissors`,
+	scissors will be appended to `MERGE_MSG` before being passed on in the case
+	of a conflict.
+
 -n::
 --no-commit::
 	Usually the command automatically creates some commits with
diff --git a/builtin/merge.c b/builtin/merge.c
index 148554f08e..235cd3b2e1 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -927,14 +927,7 @@ static int suggest_conflicts(void)
 	 * Thus, we will get the cleanup mode which is returned when we _are_ using
 	 * an editor.
 	 */
-	if (get_cleanup_mode(cleanup_arg, 1, 1) == COMMIT_MSG_CLEANUP_SCISSORS) {
-	    fputc('\n', fp);
-	    wt_status_add_cut_line(fp);
-	    /* comments out the newline from append_conflicts_hint */
-	    fputc(comment_line_char, fp);
-	}
-
-	append_conflicts_hint(&the_index, &msgbuf);
+	append_conflicts_hint(&the_index, &msgbuf, get_cleanup_mode(cleanup_arg, 1, 1));
 	fputs(msgbuf.buf, fp);
 	strbuf_release(&msgbuf);
 	fclose(fp);
diff --git a/builtin/rebase--interactive.c b/builtin/rebase--interactive.c
index 888390f911..cf2151b271 100644
--- a/builtin/rebase--interactive.c
+++ b/builtin/rebase--interactive.c
@@ -199,10 +199,10 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)
 		OPT_END()
 	};
 
+	opts.action = REPLAY_INTERACTIVE_REBASE;
 	sequencer_init_config(&opts);
 	git_config_get_bool("rebase.abbreviatecommands", &abbreviate_commands);
 
-	opts.action = REPLAY_INTERACTIVE_REBASE;
 	opts.allow_ff = 1;
 	opts.allow_empty = 1;
 
diff --git a/builtin/revert.c b/builtin/revert.c
index a47b53ceaf..41e7392c24 100644
--- a/builtin/revert.c
+++ b/builtin/revert.c
@@ -96,11 +96,13 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
 {
 	const char * const * usage_str = revert_or_cherry_pick_usage(opts);
 	const char *me = action_name(opts);
+	const char *cleanup_arg = NULL;
 	int cmd = 0;
 	struct option base_options[] = {
 		OPT_CMDMODE(0, "quit", &cmd, N_("end revert or cherry-pick sequence"), 'q'),
 		OPT_CMDMODE(0, "continue", &cmd, N_("resume revert or cherry-pick sequence"), 'c'),
 		OPT_CMDMODE(0, "abort", &cmd, N_("cancel revert or cherry-pick sequence"), 'a'),
+		OPT_CLEANUP(&cleanup_arg),
 		OPT_BOOL('n', "no-commit", &opts->no_commit, N_("don't automatically commit")),
 		OPT_BOOL('e', "edit", &opts->edit, N_("edit the commit message")),
 		OPT_NOOP_NOARG('r', NULL),
@@ -137,6 +139,9 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
 	if (opts->keep_redundant_commits)
 		opts->allow_empty = 1;
 
+	if (cleanup_arg)
+		opts->default_msg_cleanup = get_cleanup_mode(cleanup_arg, 1, 1);
+
 	/* Check for incompatible command line arguments */
 	if (cmd) {
 		char *this_operation;
diff --git a/sequencer.c b/sequencer.c
index f782e8bab2..ea4687c3da 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -176,6 +176,11 @@ static struct cleanup_config_mapping cleanup_config_mapping[] = {
 	{ NULL, 0, 0 }
 };
 
+static inline int is_rebase_i(const struct replay_opts *opts)
+{
+	return opts->action == REPLAY_INTERACTIVE_REBASE;
+}
+
 static int git_sequencer_config(const char *k, const char *v, void *cb)
 {
 	struct replay_opts *opts = cb;
@@ -188,7 +193,7 @@ static int git_sequencer_config(const char *k, const char *v, void *cb)
 		if (status)
 			return status;
 
-		opts->default_msg_cleanup = get_cleanup_mode(s, 0, 0);
+		opts->default_msg_cleanup = get_cleanup_mode(s, !is_rebase_i(opts), 0);
 
 		free((char *)s);
 		return status;
@@ -212,11 +217,6 @@ void sequencer_init_config(struct replay_opts *opts)
 	git_config(git_sequencer_config, opts);
 }
 
-static inline int is_rebase_i(const struct replay_opts *opts)
-{
-	return opts->action == REPLAY_INTERACTIVE_REBASE;
-}
-
 static const char *get_dir(const struct replay_opts *opts)
 {
 	if (is_rebase_i(opts))
@@ -552,10 +552,16 @@ static const char *describe_cleanup_mode(enum commit_msg_cleanup_mode cleanup_mo
 }
 
 void append_conflicts_hint(struct index_state *istate,
-			   struct strbuf *msgbuf)
+		struct strbuf *msgbuf, enum commit_msg_cleanup_mode cleanup_mode)
 {
 	int i;
 
+	if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS) {
+		strbuf_addch(msgbuf, '\n');
+		wt_status_append_cut_line(msgbuf);
+		strbuf_addch(msgbuf, comment_line_char);
+	}
+
 	strbuf_addch(msgbuf, '\n');
 	strbuf_commented_addf(msgbuf, "Conflicts:\n");
 	for (i = 0; i < istate->cache_nr;) {
@@ -623,7 +629,7 @@ static int do_recursive_merge(struct repository *r,
 			_(action_name(opts)));
 
 	if (!clean)
-		append_conflicts_hint(r->index, msgbuf);
+		append_conflicts_hint(r->index, msgbuf, opts->default_msg_cleanup);
 
 	return !clean;
 }
diff --git a/sequencer.h b/sequencer.h
index e7908f558e..830d8232f6 100644
--- a/sequencer.h
+++ b/sequencer.h
@@ -115,7 +115,8 @@ int rearrange_squash(struct repository *r);
  */
 void append_signoff(struct strbuf *msgbuf, size_t ignore_footer, unsigned flag);
 
-void append_conflicts_hint(struct index_state *istate, struct strbuf *msgbuf);
+void append_conflicts_hint(struct index_state *istate,
+		struct strbuf *msgbuf, enum commit_msg_cleanup_mode cleanup_mode);
 enum commit_msg_cleanup_mode get_cleanup_mode(const char *cleanup_arg,
 	int use_editor, int die_on_error);
 
diff --git a/t/t3507-cherry-pick-conflict.sh b/t/t3507-cherry-pick-conflict.sh
index 777fb23d18..a584b11c98 100755
--- a/t/t3507-cherry-pick-conflict.sh
+++ b/t/t3507-cherry-pick-conflict.sh
@@ -189,6 +189,46 @@ test_expect_success 'failed cherry-pick registers participants in index' '
 	test_cmp expected actual
 '
 
+test_expect_success \
+	'cherry-pick conflict, ensure commit.cleanup = scissors places scissors line properly' '
+	pristine_detach initial &&
+	git config commit.cleanup scissors &&
+	cat <<-EOF >expected &&
+		picked
+
+		# ------------------------ >8 ------------------------
+		# Do not modify or remove the line above.
+		# Everything below it will be ignored.
+		#
+		# Conflicts:
+		#	foo
+		EOF
+
+	test_must_fail git cherry-pick picked &&
+
+	test_i18ncmp expected .git/MERGE_MSG
+'
+
+test_expect_success \
+	'cherry-pick conflict, ensure cleanup=scissors places scissors line properly' '
+	pristine_detach initial &&
+	git config --unset commit.cleanup &&
+	cat <<-EOF >expected &&
+		picked
+
+		# ------------------------ >8 ------------------------
+		# Do not modify or remove the line above.
+		# Everything below it will be ignored.
+		#
+		# Conflicts:
+		#	foo
+		EOF
+
+	test_must_fail git cherry-pick --cleanup=scissors picked &&
+
+	test_i18ncmp expected .git/MERGE_MSG
+'
+
 test_expect_success 'failed cherry-pick describes conflict in work tree' '
 	pristine_detach initial &&
 	cat <<-EOF >expected &&
@@ -335,6 +375,52 @@ test_expect_success 'revert conflict, diff3 -m style' '
 	test_cmp expected actual
 '
 
+test_expect_success \
+	'revert conflict, ensure commit.cleanup = scissors places scissors line properly' '
+	pristine_detach initial &&
+	git config commit.cleanup scissors &&
+	cat >expected <<-EOF &&
+		Revert "picked"
+
+		This reverts commit OBJID.
+
+		# ------------------------ >8 ------------------------
+		# Do not modify or remove the line above.
+		# Everything below it will be ignored.
+		#
+		# Conflicts:
+		#	foo
+		EOF
+
+	test_must_fail git revert picked &&
+
+	sed "s/$OID_REGEX/OBJID/" .git/MERGE_MSG >actual &&
+	test_i18ncmp expected actual
+'
+
+test_expect_success \
+	'revert conflict, ensure cleanup=scissors places scissors line properly' '
+	pristine_detach initial &&
+	git config --unset commit.cleanup &&
+	cat >expected <<-EOF &&
+		Revert "picked"
+
+		This reverts commit OBJID.
+
+		# ------------------------ >8 ------------------------
+		# Do not modify or remove the line above.
+		# Everything below it will be ignored.
+		#
+		# Conflicts:
+		#	foo
+		EOF
+
+	test_must_fail git revert --cleanup=scissors picked &&
+
+	sed "s/$OID_REGEX/OBJID/" .git/MERGE_MSG >actual &&
+	test_i18ncmp expected actual
+'
+
 test_expect_success 'failed cherry-pick does not forget -s' '
 	pristine_detach initial &&
 	test_must_fail git cherry-pick -s picked &&
-- 
2.21.0.512.g57bf1b23e1


^ permalink raw reply	[flat|nested] 105+ messages in thread

* Re: [PATCH v9 07/11] sequencer.c: remove duplicate code
  2019-03-21  6:53                 ` [PATCH v9 07/11] sequencer.c: remove duplicate code Denton Liu
@ 2019-03-26 10:44                   ` Phillip Wood
  0 siblings, 0 replies; 105+ messages in thread
From: Phillip Wood @ 2019-03-26 10:44 UTC (permalink / raw)
  To: Denton Liu, Git Mailing List
  Cc: Eric Sunshine, Junio C Hamano, Phillip Wood, Ramsay Jones,
	SZEDER Gábor



On 21/03/2019 06:53, Denton Liu wrote:
> Since we implemented get_cleanup_mode, we had some duplicate code in
> git_sequencer_config which essentially performed the same operations.
> Refactor git_sequencer_config to take advantage of the logic already in
> get_cleanup_mode.
> 
> Note that we had to introduce a separate argument to get_cleanup_mode
> indicating whether to die or not on an invalid value. This is because if
> we are parsing a config, we do not want to die but instead, we only want
> to warn the user, whereas if we are parsing a command-line option, we
> would like to actually die.
> 
> Finally, this is almost a no-op refactor but not quite. Previously, in
> the case that an invalid value is presented, default_msg_cleanup would
> not be set. 

Looking more closely at the code that's not correct, we set a default 
value before in sequencer_init_config() which unfortunately means my 
previous concerns about needing different values for rebase were not 
correct.

> We change the behaviour so that default_msg_cleanup will now
> take on the value as if "default" were provided as the cleanup_arg.

That is not the default value we want, if the user provides an invalid 
value in the config we're better off using --verbatim which is what the 
current code does.

While looking at all this I noticed that in run_git_commit() we set up 
the cleanup option for to use with

	if ((flags & CLEANUP_MSG))
		argv_array_push(&cmd.args, "--cleanup=strip");
	if ((flags & EDIT_MSG))
		argv_array_push(&cmd.args, "-e");
	else if (!(flags & CLEANUP_MSG) &&
		 !opts->signoff && !opts->record_origin &&
		 git_config_get_value("commit.cleanup", &value))
		argv_array_push(&cmd.args, "--cleanup=verbatim");

So we use --strip when editing (we always set CLEANUP_MSG when EDIT_MSG 
is set) otherwise if opts->signoff or opts->record_origin is set we use 
commit's default cleanup which is --whitespace as we're not editing 
unless the user has set something else. In all other cases we use 
--verbatim unless the user has something set in their config.

With your changes we need to change 
git_config_get_value("commit.cleanup", &value) to something that checks 
to see if --cleanup was given on the command line as well. I think the 
best way is to add an opts->explict_cleanup flag which will also help 
with a bug I introduced when I wrote try_to_commit().

In try_to_commit() we do

	cleanup = (flags & CLEANUP_MSG) ? COMMIT_MSG_CLEANUP_ALL :
					  opts->default_msg_cleanup;

Which does not special case the opts->signoff or opts->record_origin 
cases (opts->default_msg_cleanup will be --verbatim unless the user has 
set something else) I'm planning to send in a patch for that soonish, it 
will involve adding opts->explicit_cleanup which will interact badly 
with this series as it is, I'll try and do some fixups to address that.

I have a general question about this series. If I run 'merge 
--cleanup=scissors' or 'cherry-pick --cleanup=scissors' and there are 
conflicts what happens when if I run 'commit --no-edit' to commit the 
conflict resolution - does it know which cleanup mode to use?

Best Wishes

Phillip


> Also, we lowercase some user-facing strings.
> 
> Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
> Signed-off-by: Denton Liu <liu.denton@gmail.com>
> ---
>   builtin/commit.c |  2 +-
>   sequencer.c      | 22 ++++++++--------------
>   sequencer.h      |  2 +-
>   3 files changed, 10 insertions(+), 16 deletions(-)
> 
> diff --git a/builtin/commit.c b/builtin/commit.c
> index 8277da8474..ba1e6027ba 100644
> --- a/builtin/commit.c
> +++ b/builtin/commit.c
> @@ -1172,7 +1172,7 @@ static int parse_and_validate_options(int argc, const char *argv[],
>   		die(_("Only one of --include/--only/--all/--interactive/--patch can be used."));
>   	if (argc == 0 && (also || (only && !amend && !allow_empty)))
>   		die(_("No paths with --include/--only does not make sense."));
> -	cleanup_mode = get_cleanup_mode(cleanup_arg, use_editor);
> +	cleanup_mode = get_cleanup_mode(cleanup_arg, use_editor, 1);
>   
>   	handle_untracked_files_arg(s);
>   
> diff --git a/sequencer.c b/sequencer.c
> index 224c823b43..2cbfb848dd 100644
> --- a/sequencer.c
> +++ b/sequencer.c
> @@ -172,17 +172,7 @@ static int git_sequencer_config(const char *k, const char *v, void *cb)
>   		if (status)
>   			return status;
>   
> -		if (!strcmp(s, "verbatim"))
> -			opts->default_msg_cleanup = COMMIT_MSG_CLEANUP_NONE;
> -		else if (!strcmp(s, "whitespace"))
> -			opts->default_msg_cleanup = COMMIT_MSG_CLEANUP_SPACE;
> -		else if (!strcmp(s, "strip"))
> -			opts->default_msg_cleanup = COMMIT_MSG_CLEANUP_ALL;
> -		else if (!strcmp(s, "scissors"))
> -			opts->default_msg_cleanup = COMMIT_MSG_CLEANUP_SPACE;
> -		else
> -			warning(_("invalid commit message cleanup mode '%s'"),
> -				  s);
> +		opts->default_msg_cleanup = get_cleanup_mode(s, 0, 0);
>   
>   		free((char *)s);
>   		return status;
> @@ -512,7 +502,7 @@ static int fast_forward_to(struct repository *r,
>   }
>   
>   enum commit_msg_cleanup_mode get_cleanup_mode(const char *cleanup_arg,
> -	int use_editor)
> +	int use_editor, int die_on_error)
>   {
>   	if (!cleanup_arg || !strcmp(cleanup_arg, "default"))
>   		return use_editor ? COMMIT_MSG_CLEANUP_ALL :
> @@ -526,8 +516,12 @@ enum commit_msg_cleanup_mode get_cleanup_mode(const char *cleanup_arg,
>   	else if (!strcmp(cleanup_arg, "scissors"))
>   		return use_editor ? COMMIT_MSG_CLEANUP_SCISSORS :
>   				    COMMIT_MSG_CLEANUP_SPACE;
> -	else
> -		die(_("Invalid cleanup mode %s"), cleanup_arg);
> +	else if (!die_on_error) {
> +		warning(_("invalid cleanup mode %s, falling back to default"), cleanup_arg);
> +		return use_editor ? COMMIT_MSG_CLEANUP_ALL :
> +				    COMMIT_MSG_CLEANUP_SPACE;
> +	} else
> +		die(_("invalid cleanup mode %s"), cleanup_arg);
>   }
>   
>   void append_conflicts_hint(struct index_state *istate,
> diff --git a/sequencer.h b/sequencer.h
> index eb9bd97ef3..e7908f558e 100644
> --- a/sequencer.h
> +++ b/sequencer.h
> @@ -117,7 +117,7 @@ void append_signoff(struct strbuf *msgbuf, size_t ignore_footer, unsigned flag);
>   
>   void append_conflicts_hint(struct index_state *istate, struct strbuf *msgbuf);
>   enum commit_msg_cleanup_mode get_cleanup_mode(const char *cleanup_arg,
> -	int use_editor);
> +	int use_editor, int die_on_error);
>   
>   void cleanup_message(struct strbuf *msgbuf,
>   	enum commit_msg_cleanup_mode cleanup_mode, int verbose);
> 

^ permalink raw reply	[flat|nested] 105+ messages in thread

* [PATCH v10 00/10] Fix scissors bug during conflict
  2019-03-21  6:53               ` [PATCH v9 " Denton Liu
                                   ` (10 preceding siblings ...)
  2019-03-21  6:54                 ` [PATCH v9 11/11] cherry-pick/revert: add scissors line on merge conflict Denton Liu
@ 2019-04-17 10:23                 ` Phillip Wood
  2019-04-17 10:23                   ` [PATCH v10 01/10] t7600: clean up style Phillip Wood
                                     ` (10 more replies)
  11 siblings, 11 replies; 105+ messages in thread
From: Phillip Wood @ 2019-04-17 10:23 UTC (permalink / raw)
  To: Denton Liu, Git Mailing List
  Cc: Eric Sunshine, Ramsay Jones, Junio C Hamano, SZEDER Gábor,
	Phillip Wood

From: Phillip Wood <phillip.wood@dunelm.org.uk>

With Denton's blessing I've rebased his patches on top of my patch to
fix the message cleanup with cherry-pick --signoff and -x [1]. I've
also refactored a couple of the patches and cleaned up the coding
style in places. The refactoring aims to simplify the code that deals
with saving and restoring the cleanup option for cherry-pick/revert
and improve the --cleanup option handling/parsing in builtin/merge.c
and builtin/pull.c. I've dropped patch 7 as it didn't sit well with
the new opts->explicit_cleanup added by [1]. I think it is easier just
to keep the existing code in the sequencer for parsing the cleanup
option rather trying to create a single function that does two
slightly different things.

Apologies to those of you that received some of these patches
yesterday when I was sending them to Denton, I didn't realize that
send-email "helpfully" cc'd people in the *-by: footers.

Best Wishes

Phillip

[1] https://public-inbox.org/git/20190329110842.30604-1-phillip.wood123@gmail.com/

Denton Liu (10):
  t7600: clean up style
  t3507: clean up style
  t7604: clean up style
  t7502: clean up style
  commit: extract cleanup_mode functions to sequencer
  parse-options.h: extract common --cleanup option
  merge: cleanup messages like commit
  merge: add scissors line on merge conflict
  sequencer.c: save and restore cleanup mode
  cherry-pick/revert: add scissors line on merge conflict

 Documentation/git-cherry-pick.txt |   7 ++
 Documentation/git-revert.txt      |   7 ++
 Documentation/merge-options.txt   |   7 ++
 builtin/commit.c                  |  49 +++++-------
 builtin/merge.c                   |  51 +++++++++---
 builtin/pull.c                    |  12 +++
 builtin/revert.c                  |   7 ++
 builtin/tag.c                     |   3 +-
 parse-options.h                   |   1 +
 sequencer.c                       |  73 +++++++++++++++--
 sequencer.h                       |   9 ++-
 t/t3507-cherry-pick-conflict.sh   | 128 +++++++++++++++++++++++++-----
 t/t5521-pull-options.sh           |   8 ++
 t/t7502-commit-porcelain.sh       |  93 ++++++++++++----------
 t/t7600-merge.sh                  |  73 +++++++++++++----
 t/t7604-merge-custom-message.sh   |  75 +++++++++++++++--
 wt-status.c                       |  12 ++-
 wt-status.h                       |   1 +
 18 files changed, 484 insertions(+), 132 deletions(-)

Range-diff to pu
 1:  32caff17f2 !  1:  e660dff207 t7600: clean up style
    @@ -13,7 +13,6 @@
         Helped-by: Eric Sunshine <sunshine@sunshineco.com>
         Helped-by: Junio C Hamano <gitster@pobox.com>
         Signed-off-by: Denton Liu <liu.denton@gmail.com>
    -    Signed-off-by: Junio C Hamano <gitster@pobox.com>
     
      diff --git a/t/t7600-merge.sh b/t/t7600-merge.sh
      --- a/t/t7600-merge.sh
 2:  9af8efc5c2 !  2:  86ae21aff9 t3507: clean up style
    @@ -8,7 +8,6 @@
     
         Helped-by: SZEDER Gábor <szeder.dev@gmail.com>
         Signed-off-by: Denton Liu <liu.denton@gmail.com>
    -    Signed-off-by: Junio C Hamano <gitster@pobox.com>
     
      diff --git a/t/t3507-cherry-pick-conflict.sh b/t/t3507-cherry-pick-conflict.sh
      --- a/t/t3507-cherry-pick-conflict.sh
 3:  7d4e0b5f24 !  3:  6f3e0fcd3b t7604: clean up style
    @@ -11,7 +11,6 @@
         Helped-by: Eric Sunshine <sunshine@sunshineco.com>
         Helped-by: SZEDER Gábor <szeder.dev@gmail.com>
         Signed-off-by: Denton Liu <liu.denton@gmail.com>
    -    Signed-off-by: Junio C Hamano <gitster@pobox.com>
     
      diff --git a/t/t7604-merge-custom-message.sh b/t/t7604-merge-custom-message.sh
      --- a/t/t7604-merge-custom-message.sh
 4:  6743bfce4b !  4:  fa41595854 t7502: clean up style
    @@ -10,7 +10,6 @@
         Helped-by: Eric Sunshine <sunshine@sunshineco.com>
         Helped-by: SZEDER Gábor <szeder.dev@gmail.com>
         Signed-off-by: Denton Liu <liu.denton@gmail.com>
    -    Signed-off-by: Junio C Hamano <gitster@pobox.com>
     
      diff --git a/t/t7502-commit-porcelain.sh b/t/t7502-commit-porcelain.sh
      --- a/t/t7502-commit-porcelain.sh
 5:  9e699bcc45 !  5:  3e87ab3176 commit: extract cleanup_mode functions to sequencer
    @@ -3,7 +3,6 @@
         commit: extract cleanup_mode functions to sequencer
     
         Signed-off-by: Denton Liu <liu.denton@gmail.com>
    -    Signed-off-by: Junio C Hamano <gitster@pobox.com>
     
      diff --git a/builtin/commit.c b/builtin/commit.c
      --- a/builtin/commit.c
 6:  4753ea288a !  6:  d042d82f4f parse-options.h: extract common --cleanup option
    @@ -7,7 +7,6 @@
     
         Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
         Signed-off-by: Denton Liu <liu.denton@gmail.com>
    -    Signed-off-by: Junio C Hamano <gitster@pobox.com>
     
      diff --git a/builtin/commit.c b/builtin/commit.c
      --- a/builtin/commit.c
 7:  f2feeefc50 <  -:  ---------- sequencer.c: remove duplicate code
 8:  b4ad22cdb6 !  7:  c4821d47fc merge: cleanup messages like commit
    @@ -6,18 +6,17 @@
         commit.cleanup configuration or --cleanup option, just like how
         git-commit does it.
     
    -    We also give git-pull the passthrough option of --cleanup so that it can
    -    also take advantage of this change.
    +    We also give git-pull the option of --cleanup so that it can also take
    +    advantage of this change.
     
         Finally, add testing to ensure that messages are properly cleaned up.
         Note that some newlines that were added to the commit message were
         removed so that if a file were read via -F, it would be copied
         faithfully.
     
    -    Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
         Helped-by: Eric Sunshine <sunshine@sunshineco.com>
    +    Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>
         Signed-off-by: Denton Liu <liu.denton@gmail.com>
    -    Signed-off-by: Junio C Hamano <gitster@pobox.com>
     
      diff --git a/Documentation/merge-options.txt b/Documentation/merge-options.txt
      --- a/Documentation/merge-options.txt
    @@ -99,10 +98,10 @@
     -		strbuf_commented_addf(&msg, _(merge_editor_comment), comment_line_char);
     +	if (0 < option_edit) {
     +		strbuf_addch(&msg, '\n');
    -+		if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)
    ++		if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS) {
     +			wt_status_append_cut_line(&msg);
    -+
    -+		strbuf_commented_addf(&msg, "\n");
    ++			strbuf_commented_addf(&msg, "\n");
    ++		}
     +		strbuf_commented_addf(&msg, _(merge_editor_comment));
     +		strbuf_commented_addf(&msg, _(cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS ?
     +			scissors_editor_comment :
    @@ -129,11 +128,24 @@
      	if (commit_tree(merge_msg.buf, merge_msg.len, result_tree, parents,
      			&result_commit, NULL, sign_commit))
     @@
    - 	if (option_edit < 0)
    - 		option_edit = default_edit_option();
    + 	}
    + 	resolve_undo_clear();
      
    -+	cleanup_mode = get_cleanup_mode(cleanup_arg, 0 < option_edit, 1);
    ++	if (option_edit < 0)
    ++		option_edit = default_edit_option();
     +
    ++	cleanup_mode = get_cleanup_mode(cleanup_arg, 0 < option_edit);
    ++
    + 	if (verbosity < 0)
    + 		show_diffstat = 0;
    + 
    +@@
    + 			fast_forward = FF_NO;
    + 	}
    + 
    +-	if (option_edit < 0)
    +-		option_edit = default_edit_option();
    +-
      	if (!use_strategies) {
      		if (!remoteheads)
      			; /* already up-to-date */
    @@ -153,48 +165,37 @@
      static char *opt_squash;
      static char *opt_commit;
      static char *opt_edit;
    -+static char *opt_cleanup;
    ++static char *cleanup_arg;
      static char *opt_ff;
      static char *opt_verify_signatures;
      static int opt_autostash = -1;
     @@
      	OPT_PASSTHRU(0, "edit", &opt_edit, NULL,
      		N_("edit message before committing"),
      		PARSE_OPT_NOARG),
    -+	OPT_PASSTHRU(0, "cleanup", &opt_cleanup, NULL,
    -+		N_("how to strip spaces and #comments from message"),
    -+		0),
    ++	OPT_CLEANUP(&cleanup_arg),
      	OPT_PASSTHRU(0, "ff", &opt_ff, NULL,
      		N_("allow fast-forward"),
      		PARSE_OPT_NOARG),
     @@
      		argv_array_push(&args, opt_commit);
      	if (opt_edit)
      		argv_array_push(&args, opt_edit);
    -+	if (opt_cleanup)
    -+		argv_array_push(&args, opt_cleanup);
    ++	if (cleanup_arg)
    ++		argv_array_pushf(&args, "--cleanup=%s", cleanup_arg);
      	if (opt_ff)
      		argv_array_push(&args, opt_ff);
      	if (opt_verify_signatures)
     @@
      
      	argc = parse_options(argc, argv, prefix, pull_options, pull_usage, 0);
      
    -+	if (opt_cleanup) {
    -+		const char *prefix = "--cleanup=";
    -+		const char *cleanup_arg;
    -+
    -+		if (strncmp(opt_cleanup, prefix, strlen(prefix)))
    -+			BUG("expecting prefix %s, argument is %s", prefix, opt_cleanup);
    -+
    -+		cleanup_arg = &opt_cleanup[strlen(prefix)];
    -+
    ++	if (cleanup_arg)
     +		/*
     +		 * this only checks the validity of cleanup_arg; we don't need
     +		 * a valid value for use_editor
     +		 */
    -+		get_cleanup_mode(cleanup_arg, 0, 1);
    -+	}
    ++		get_cleanup_mode(cleanup_arg, 0);
     +
      	parse_repo_refspecs(argc, argv, &repo, &refspecs);
      
 9:  7bd6d4370f !  8:  4ad58797e4 merge: add scissors line on merge conflict
    @@ -11,7 +11,6 @@
     
         Helped-by: Eric Sunshine <sunshine@sunshineco.com>
         Signed-off-by: Denton Liu <liu.denton@gmail.com>
    -    Signed-off-by: Junio C Hamano <gitster@pobox.com>
     
      diff --git a/Documentation/merge-options.txt b/Documentation/merge-options.txt
      --- a/Documentation/merge-options.txt
    @@ -61,7 +60,9 @@
      			die_errno(_("could not read MERGE_MSG"));
     +
     +		if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS &&
    -+		    wt_status_locate_end(sb.buf + merge_msg_start, sb.len - merge_msg_start) < sb.len - merge_msg_start)
    ++		    wt_status_locate_end(sb.buf + merge_msg_start,
    ++					 sb.len - merge_msg_start) <
    ++				sb.len - merge_msg_start)
     +			merge_contains_scissors = 1;
      	} else if (!stat(git_path_squash_msg(the_repository), &statbuf)) {
      		if (strbuf_read_file(&sb, git_path_squash_msg(the_repository), 0) < 0)
    @@ -103,10 +104,10 @@
     +	 * We can't use cleanup_mode because if we're not using the editor,
     +	 * get_cleanup_mode will return COMMIT_MSG_CLEANUP_SPACE instead, even
     +	 * though the message is meant to be processed later by git-commit.
    -+	 * Thus, we will get the cleanup mode which is returned when we _are_ using
    -+	 * an editor.
    ++	 * Thus, we will get the cleanup mode which is returned when we _are_
    ++	 * using an editor.
     +	 */
    -+	if (get_cleanup_mode(cleanup_arg, 1, 1) == COMMIT_MSG_CLEANUP_SCISSORS) {
    ++	if (get_cleanup_mode(cleanup_arg, 1) == COMMIT_MSG_CLEANUP_SCISSORS) {
     +	    fputc('\n', fp);
     +	    wt_status_add_cut_line(fp);
     +	    /* comments out the newline from append_conflicts_hint */
10:  8805d809d4 <  -:  ---------- sequencer.c: define describe_cleanup_mode
 -:  ---------- >  9:  b3136d4fae sequencer.c: save and restore cleanup mode
11:  b86bb747c9 ! 10:  582f842b9e cherry-pick/revert: add scissors line on merge conflict
    @@ -8,7 +8,6 @@
     
         Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
         Signed-off-by: Denton Liu <liu.denton@gmail.com>
    -    Signed-off-by: Junio C Hamano <gitster@pobox.com>
     
      diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt
      --- a/Documentation/git-cherry-pick.txt
    @@ -50,38 +49,23 @@
      --- a/builtin/merge.c
      +++ b/builtin/merge.c
     @@
    - 	 * Thus, we will get the cleanup mode which is returned when we _are_ using
    - 	 * an editor.
    + 	 * Thus, we will get the cleanup mode which is returned when we _are_
    + 	 * using an editor.
      	 */
    --	if (get_cleanup_mode(cleanup_arg, 1, 1) == COMMIT_MSG_CLEANUP_SCISSORS) {
    +-	if (get_cleanup_mode(cleanup_arg, 1) == COMMIT_MSG_CLEANUP_SCISSORS) {
     -	    fputc('\n', fp);
     -	    wt_status_add_cut_line(fp);
     -	    /* comments out the newline from append_conflicts_hint */
     -	    fputc(comment_line_char, fp);
     -	}
     -
     -	append_conflicts_hint(&the_index, &msgbuf);
    -+	append_conflicts_hint(&the_index, &msgbuf, get_cleanup_mode(cleanup_arg, 1, 1));
    ++	append_conflicts_hint(&the_index, &msgbuf,
    ++			      get_cleanup_mode(cleanup_arg, 1));
      	fputs(msgbuf.buf, fp);
      	strbuf_release(&msgbuf);
      	fclose(fp);
     
    - diff --git a/builtin/rebase--interactive.c b/builtin/rebase--interactive.c
    - --- a/builtin/rebase--interactive.c
    - +++ b/builtin/rebase--interactive.c
    -@@
    - 		OPT_END()
    - 	};
    - 
    -+	opts.action = REPLAY_INTERACTIVE_REBASE;
    - 	sequencer_init_config(&opts);
    - 	git_config_get_bool("rebase.abbreviatecommands", &abbreviate_commands);
    - 
    --	opts.action = REPLAY_INTERACTIVE_REBASE;
    - 	opts.allow_ff = 1;
    - 	opts.allow_empty = 1;
    - 
    -
      diff --git a/builtin/revert.c b/builtin/revert.c
      --- a/builtin/revert.c
      +++ b/builtin/revert.c
    @@ -103,8 +87,10 @@
      	if (opts->keep_redundant_commits)
      		opts->allow_empty = 1;
      
    -+	if (cleanup_arg)
    -+		opts->default_msg_cleanup = get_cleanup_mode(cleanup_arg, 1, 1);
    ++	if (cleanup_arg) {
    ++		opts->default_msg_cleanup = get_cleanup_mode(cleanup_arg, 1);
    ++		opts->explicit_cleanup = 1;
    ++	}
     +
      	/* Check for incompatible command line arguments */
      	if (cmd) {
    @@ -114,44 +100,20 @@
      --- a/sequencer.c
      +++ b/sequencer.c
     @@
    - 	{ NULL, 0, 0 }
    - };
    - 
    -+static inline int is_rebase_i(const struct replay_opts *opts)
    -+{
    -+	return opts->action == REPLAY_INTERACTIVE_REBASE;
    -+}
    -+
    - static int git_sequencer_config(const char *k, const char *v, void *cb)
    - {
    - 	struct replay_opts *opts = cb;
    -@@
    - 		if (status)
    - 			return status;
    - 
    --		opts->default_msg_cleanup = get_cleanup_mode(s, 0, 0);
    -+		opts->default_msg_cleanup = get_cleanup_mode(s, !is_rebase_i(opts), 0);
    - 
    - 		free((char *)s);
    - 		return status;
    -@@
    - 	git_config(git_sequencer_config, opts);
    - }
    - 
    --static inline int is_rebase_i(const struct replay_opts *opts)
    --{
    --	return opts->action == REPLAY_INTERACTIVE_REBASE;
    --}
    --
    - static const char *get_dir(const struct replay_opts *opts)
    - {
    - 	if (is_rebase_i(opts))
    + 			opts->default_msg_cleanup = COMMIT_MSG_CLEANUP_ALL;
    + 			opts->explicit_cleanup = 1;
    + 		} else if (!strcmp(s, "scissors")) {
    +-			opts->default_msg_cleanup = COMMIT_MSG_CLEANUP_SPACE;
    ++			opts->default_msg_cleanup = COMMIT_MSG_CLEANUP_SCISSORS;
    + 			opts->explicit_cleanup = 1;
    + 		} else {
    + 			warning(_("invalid commit message cleanup mode '%s'"),
     @@
      }
      
      void append_conflicts_hint(struct index_state *istate,
     -			   struct strbuf *msgbuf)
    -+		struct strbuf *msgbuf, enum commit_msg_cleanup_mode cleanup_mode)
    ++	struct strbuf *msgbuf, enum commit_msg_cleanup_mode cleanup_mode)
      {
      	int i;
      
    @@ -169,10 +131,28 @@
      
      	if (!clean)
     -		append_conflicts_hint(r->index, msgbuf);
    -+		append_conflicts_hint(r->index, msgbuf, opts->default_msg_cleanup);
    ++		append_conflicts_hint(r->index, msgbuf,
    ++				      opts->default_msg_cleanup);
      
      	return !clean;
      }
    +@@
    + 			  unsigned int flags)
    + {
    + 	struct child_process cmd = CHILD_PROCESS_INIT;
    +-	const char *value;
    + 
    + 	if ((flags & CREATE_ROOT_COMMIT) && !(flags & AMEND_MSG)) {
    + 		struct strbuf msg = STRBUF_INIT, script = STRBUF_INIT;
    +@@
    + 		argv_array_push(&cmd.args, "-e");
    + 	else if (!(flags & CLEANUP_MSG) &&
    + 		 !opts->signoff && !opts->record_origin &&
    +-		 git_config_get_value("commit.cleanup", &value))
    ++		 !opts->explicit_cleanup)
    + 		argv_array_push(&cmd.args, "--cleanup=verbatim");
    + 
    + 	if ((flags & ALLOW_EMPTY))
     
      diff --git a/sequencer.h b/sequencer.h
      --- a/sequencer.h
    @@ -185,7 +165,7 @@
     +void append_conflicts_hint(struct index_state *istate,
     +		struct strbuf *msgbuf, enum commit_msg_cleanup_mode cleanup_mode);
      enum commit_msg_cleanup_mode get_cleanup_mode(const char *cleanup_arg,
    - 	int use_editor, int die_on_error);
    + 	int use_editor);
      
     
      diff --git a/t/t3507-cherry-pick-conflict.sh b/t/t3507-cherry-pick-conflict.sh


-- 
2.21.0


^ permalink raw reply	[flat|nested] 105+ messages in thread

* [PATCH v10 01/10] t7600: clean up style
  2019-04-17 10:23                 ` [PATCH v10 00/10] Fix scissors bug during conflict Phillip Wood
@ 2019-04-17 10:23                   ` Phillip Wood
  2019-04-17 10:23                   ` [PATCH v10 02/10] t3507: " Phillip Wood
                                     ` (9 subsequent siblings)
  10 siblings, 0 replies; 105+ messages in thread
From: Phillip Wood @ 2019-04-17 10:23 UTC (permalink / raw)
  To: Denton Liu, Git Mailing List
  Cc: Eric Sunshine, Ramsay Jones, Junio C Hamano, SZEDER Gábor

From: Denton Liu <liu.denton@gmail.com>

Clean up the 'merge --squash c3 with c7' test by removing some
unnecessary braces and removing a pipe.

Also, generally cleanup style by unindenting a here-doc, removing stray
spaces after a redirection operator and allowing sed to open its own
input instead of redirecting input from the shell.

Helped-by: SZEDER Gábor <szeder.dev@gmail.com>
Helped-by: Eric Sunshine <sunshine@sunshineco.com>
Helped-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Denton Liu <liu.denton@gmail.com>
---
 t/t7600-merge.sh | 27 +++++++++++++--------------
 1 file changed, 13 insertions(+), 14 deletions(-)

diff --git a/t/t7600-merge.sh b/t/t7600-merge.sh
index 106148254d..2f4c2801fb 100755
--- a/t/t7600-merge.sh
+++ b/t/t7600-merge.sh
@@ -233,17 +233,16 @@ test_expect_success 'merge --squash c3 with c7' '
 	cat result.9z >file &&
 	git commit --no-edit -a &&
 
-	{
-		cat <<-EOF
-		Squashed commit of the following:
+	cat >expect <<-EOF &&
+	Squashed commit of the following:
 
-		$(git show -s c7)
+	$(git show -s c7)
 
-		# Conflicts:
-		#	file
-		EOF
-	} >expect &&
-	git cat-file commit HEAD | sed -e '1,/^$/d' >actual &&
+	# Conflicts:
+	#	file
+	EOF
+	git cat-file commit HEAD >raw &&
+	sed -e '1,/^$/d' raw >actual &&
 	test_cmp expect actual
 '
 
@@ -680,10 +679,10 @@ cat >editor <<\EOF
 (
 	echo "Merge work done on the side branch c1"
 	echo
-	cat <"$1"
+	cat "$1"
 ) >"$1.tmp" && mv "$1.tmp" "$1"
 # strip comments and blank lines from end of message
-sed -e '/^#/d' < "$1" | sed -e :a -e '/^\n*$/{$d;N;ba' -e '}' > expected
+sed -e '/^#/d' "$1" | sed -e :a -e '/^\n*$/{$d;N;ba' -e '}' >expected
 EOF
 chmod 755 editor
 
@@ -768,14 +767,14 @@ test_expect_success 'set up mod-256 conflict scenario' '
 	git commit -m base &&
 
 	# one side changes the first line of each to "master"
-	sed s/-1/-master/ <file >tmp &&
+	sed s/-1/-master/ file >tmp &&
 	mv tmp file &&
 	git commit -am master &&
 
 	# and the other to "side"; merging the two will
 	# yield 256 separate conflicts
 	git checkout -b side HEAD^ &&
-	sed s/-1/-side/ <file >tmp &&
+	sed s/-1/-side/ file >tmp &&
 	mv tmp file &&
 	git commit -am side
 '
@@ -814,7 +813,7 @@ EOF
 test_expect_success EXECKEEPSPID 'killed merge can be completed with --continue' '
 	git reset --hard c0 &&
 	! "$SHELL_PATH" -c '\''
-	  echo kill -TERM $$ >> .git/FAKE_EDITOR
+	  echo kill -TERM $$ >>.git/FAKE_EDITOR
 	  GIT_EDITOR=.git/FAKE_EDITOR
 	  export GIT_EDITOR
 	  exec git merge --no-ff --edit c1'\'' &&
-- 
2.21.0


^ permalink raw reply	[flat|nested] 105+ messages in thread

* [PATCH v10 02/10] t3507: clean up style
  2019-04-17 10:23                 ` [PATCH v10 00/10] Fix scissors bug during conflict Phillip Wood
  2019-04-17 10:23                   ` [PATCH v10 01/10] t7600: clean up style Phillip Wood
@ 2019-04-17 10:23                   ` Phillip Wood
  2019-04-17 10:23                   ` [PATCH v10 03/10] t7604: " Phillip Wood
                                     ` (8 subsequent siblings)
  10 siblings, 0 replies; 105+ messages in thread
From: Phillip Wood @ 2019-04-17 10:23 UTC (permalink / raw)
  To: Denton Liu, Git Mailing List
  Cc: Eric Sunshine, Ramsay Jones, Junio C Hamano, SZEDER Gábor

From: Denton Liu <liu.denton@gmail.com>

Remove space after redirection operators for style. Also, remove a git
command which was upstream of a pipe. Finally, let grep and sed open
their own input instead of letting the shell redirect the input.

Helped-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Denton Liu <liu.denton@gmail.com>
---
 t/t3507-cherry-pick-conflict.sh | 42 ++++++++++++++++-----------------
 1 file changed, 21 insertions(+), 21 deletions(-)

diff --git a/t/t3507-cherry-pick-conflict.sh b/t/t3507-cherry-pick-conflict.sh
index 0db166152a..777fb23d18 100755
--- a/t/t3507-cherry-pick-conflict.sh
+++ b/t/t3507-cherry-pick-conflict.sh
@@ -88,15 +88,15 @@ test_expect_success 'cherry-pick --no-commit does not set CHERRY_PICK_HEAD' '
 
 test_expect_success 'cherry-pick w/dirty tree does not set CHERRY_PICK_HEAD' '
 	pristine_detach initial &&
-	echo foo > foo &&
+	echo foo >foo &&
 	test_must_fail git cherry-pick base &&
 	test_must_fail git rev-parse --verify CHERRY_PICK_HEAD
 '
 
 test_expect_success \
 	'cherry-pick --strategy=resolve w/dirty tree does not set CHERRY_PICK_HEAD' '
 	pristine_detach initial &&
-	echo foo > foo &&
+	echo foo >foo &&
 	test_must_fail git cherry-pick --strategy=resolve base &&
 	test_must_fail git rev-parse --verify CHERRY_PICK_HEAD
 '
@@ -175,23 +175,23 @@ test_expect_success 'failed cherry-pick registers participants in index' '
 		git ls-files --stage foo &&
 		git checkout picked -- foo &&
 		git ls-files --stage foo
-	} > stages &&
+	} >stages &&
 	sed "
 		1 s/ 0	/ 1	/
 		2 s/ 0	/ 2	/
 		3 s/ 0	/ 3	/
-	" < stages > expected &&
+	" stages >expected &&
 	git read-tree -u --reset HEAD &&
 
 	test_must_fail git cherry-pick picked &&
-	git ls-files --stage --unmerged > actual &&
+	git ls-files --stage --unmerged >actual &&
 
 	test_cmp expected actual
 '
 
 test_expect_success 'failed cherry-pick describes conflict in work tree' '
 	pristine_detach initial &&
-	cat <<-EOF > expected &&
+	cat <<-EOF >expected &&
 	<<<<<<< HEAD
 	a
 	=======
@@ -201,14 +201,14 @@ test_expect_success 'failed cherry-pick describes conflict in work tree' '
 
 	test_must_fail git cherry-pick picked &&
 
-	sed "s/[a-f0-9]*\.\.\./objid/" foo > actual &&
+	sed "s/[a-f0-9]*\.\.\./objid/" foo >actual &&
 	test_cmp expected actual
 '
 
 test_expect_success 'diff3 -m style' '
 	pristine_detach initial &&
 	git config merge.conflictstyle diff3 &&
-	cat <<-EOF > expected &&
+	cat <<-EOF >expected &&
 	<<<<<<< HEAD
 	a
 	||||||| parent of objid picked
@@ -220,14 +220,14 @@ test_expect_success 'diff3 -m style' '
 
 	test_must_fail git cherry-pick picked &&
 
-	sed "s/[a-f0-9]*\.\.\./objid/" foo > actual &&
+	sed "s/[a-f0-9]*\.\.\./objid/" foo >actual &&
 	test_cmp expected actual
 '
 
 test_expect_success 'revert also handles conflicts sanely' '
 	git config --unset merge.conflictstyle &&
 	pristine_detach initial &&
-	cat <<-EOF > expected &&
+	cat <<-EOF >expected &&
 	<<<<<<< HEAD
 	a
 	=======
@@ -241,24 +241,24 @@ test_expect_success 'revert also handles conflicts sanely' '
 		git ls-files --stage foo &&
 		git checkout base -- foo &&
 		git ls-files --stage foo
-	} > stages &&
+	} >stages &&
 	sed "
 		1 s/ 0	/ 1	/
 		2 s/ 0	/ 2	/
 		3 s/ 0	/ 3	/
-	" < stages > expected-stages &&
+	" stages >expected-stages &&
 	git read-tree -u --reset HEAD &&
 
 	head=$(git rev-parse HEAD) &&
 	test_must_fail git revert picked &&
 	newhead=$(git rev-parse HEAD) &&
-	git ls-files --stage --unmerged > actual-stages &&
+	git ls-files --stage --unmerged >actual-stages &&
 
 	test "$head" = "$newhead" &&
 	test_must_fail git update-index --refresh -q &&
 	test_must_fail git diff-index --exit-code HEAD &&
 	test_cmp expected-stages actual-stages &&
-	sed "s/[a-f0-9]*\.\.\./objid/" foo > actual &&
+	sed "s/[a-f0-9]*\.\.\./objid/" foo >actual &&
 	test_cmp expected actual
 '
 
@@ -284,7 +284,7 @@ test_expect_success 'revert --no-commit sets REVERT_HEAD' '
 
 test_expect_success 'revert w/dirty tree does not set REVERT_HEAD' '
 	pristine_detach base &&
-	echo foo > foo &&
+	echo foo >foo &&
 	test_must_fail git revert base &&
 	test_must_fail git rev-parse --verify CHERRY_PICK_HEAD &&
 	test_must_fail git rev-parse --verify REVERT_HEAD
@@ -319,7 +319,7 @@ test_expect_success 'failed commit does not clear REVERT_HEAD' '
 test_expect_success 'revert conflict, diff3 -m style' '
 	pristine_detach initial &&
 	git config merge.conflictstyle diff3 &&
-	cat <<-EOF > expected &&
+	cat <<-EOF >expected &&
 	<<<<<<< HEAD
 	a
 	||||||| objid picked
@@ -331,7 +331,7 @@ test_expect_success 'revert conflict, diff3 -m style' '
 
 	test_must_fail git revert picked &&
 
-	sed "s/[a-f0-9]*\.\.\./objid/" foo > actual &&
+	sed "s/[a-f0-9]*\.\.\./objid/" foo >actual &&
 	test_cmp expected actual
 '
 
@@ -345,7 +345,7 @@ test_expect_success 'commit after failed cherry-pick does not add duplicated -s'
 	pristine_detach initial &&
 	test_must_fail git cherry-pick -s picked-signed &&
 	git commit -a -s &&
-	test $(git show -s |grep -c "Signed-off-by") = 1
+	test $(git show -s >tmp && grep -c "Signed-off-by" tmp && rm tmp) = 1
 '
 
 test_expect_success 'commit after failed cherry-pick adds -s at the right place' '
@@ -359,7 +359,7 @@ test_expect_success 'commit after failed cherry-pick adds -s at the right place'
 	Signed-off-by: C O Mitter <committer@example.com>
 	# Conflicts:
 	EOF
-	grep -e "^# Conflicts:" -e '^Signed-off-by' <.git/COMMIT_EDITMSG >actual &&
+	grep -e "^# Conflicts:" -e '^Signed-off-by' .git/COMMIT_EDITMSG >actual &&
 	test_cmp expect actual &&
 
 	cat <<-\EOF >expected &&
@@ -378,7 +378,7 @@ test_expect_success 'commit --amend -s places the sign-off at the right place' '
 
 	# emulate old-style conflicts block
 	mv .git/MERGE_MSG .git/MERGE_MSG+ &&
-	sed -e "/^# Conflicts:/,\$s/^# *//" <.git/MERGE_MSG+ >.git/MERGE_MSG &&
+	sed -e "/^# Conflicts:/,\$s/^# *//" .git/MERGE_MSG+ >.git/MERGE_MSG &&
 
 	git commit -a &&
 	git commit --amend -s &&
@@ -388,7 +388,7 @@ test_expect_success 'commit --amend -s places the sign-off at the right place' '
 	Signed-off-by: C O Mitter <committer@example.com>
 	Conflicts:
 	EOF
-	grep -e "^Conflicts:" -e '^Signed-off-by' <.git/COMMIT_EDITMSG >actual &&
+	grep -e "^Conflicts:" -e '^Signed-off-by' .git/COMMIT_EDITMSG >actual &&
 	test_cmp expect actual
 '
 
-- 
2.21.0


^ permalink raw reply	[flat|nested] 105+ messages in thread

* [PATCH v10 03/10] t7604: clean up style
  2019-04-17 10:23                 ` [PATCH v10 00/10] Fix scissors bug during conflict Phillip Wood
  2019-04-17 10:23                   ` [PATCH v10 01/10] t7600: clean up style Phillip Wood
  2019-04-17 10:23                   ` [PATCH v10 02/10] t3507: " Phillip Wood
@ 2019-04-17 10:23                   ` Phillip Wood
  2019-04-17 10:23                   ` [PATCH v10 04/10] t7502: " Phillip Wood
                                     ` (7 subsequent siblings)
  10 siblings, 0 replies; 105+ messages in thread
From: Phillip Wood @ 2019-04-17 10:23 UTC (permalink / raw)
  To: Denton Liu, Git Mailing List
  Cc: Eric Sunshine, Ramsay Jones, Junio C Hamano, SZEDER Gábor

From: Denton Liu <liu.denton@gmail.com>

Before, we had some Git commands which were upstream of the pipe. This
meant that if it produced an error, it would've gone unnoticed. Refactor
to place Git commands on their own.

Also, while we're at it, remove spaces after redirection operators.

Helped-by: Eric Sunshine <sunshine@sunshineco.com>
Helped-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Denton Liu <liu.denton@gmail.com>
---
 t/t7604-merge-custom-message.sh | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/t/t7604-merge-custom-message.sh b/t/t7604-merge-custom-message.sh
index 89619cf446..aba1279132 100755
--- a/t/t7604-merge-custom-message.sh
+++ b/t/t7604-merge-custom-message.sh
@@ -16,16 +16,16 @@ create_merge_msgs() {
 }
 
 test_expect_success 'setup' '
-	echo c0 > c0.c &&
+	echo c0 >c0.c &&
 	git add c0.c &&
 	git commit -m c0 &&
 	git tag c0 &&
-	echo c1 > c1.c &&
+	echo c1 >c1.c &&
 	git add c1.c &&
 	git commit -m c1 &&
 	git tag c1 &&
 	git reset --hard c0 &&
-	echo c2 > c2.c &&
+	echo c2 >c2.c &&
 	git add c2.c &&
 	git commit -m c2 &&
 	git tag c2 &&
@@ -36,14 +36,16 @@ test_expect_success 'setup' '
 test_expect_success 'merge c2 with a custom message' '
 	git reset --hard c1 &&
 	git merge -m "$(cat exp.subject)" c2 &&
-	git cat-file commit HEAD | sed -e "1,/^$/d" >actual &&
+	git cat-file commit HEAD >raw &&
+	sed -e "1,/^$/d" raw >actual &&
 	test_cmp exp.subject actual
 '
 
 test_expect_success 'merge --log appends to custom message' '
 	git reset --hard c1 &&
 	git merge --log -m "$(cat exp.subject)" c2 &&
-	git cat-file commit HEAD | sed -e "1,/^$/d" >actual &&
+	git cat-file commit HEAD >raw &&
+	sed -e "1,/^$/d" raw >actual &&
 	test_cmp exp.log actual
 '
 
-- 
2.21.0


^ permalink raw reply	[flat|nested] 105+ messages in thread

* [PATCH v10 04/10] t7502: clean up style
  2019-04-17 10:23                 ` [PATCH v10 00/10] Fix scissors bug during conflict Phillip Wood
                                     ` (2 preceding siblings ...)
  2019-04-17 10:23                   ` [PATCH v10 03/10] t7604: " Phillip Wood
@ 2019-04-17 10:23                   ` Phillip Wood
  2019-04-17 10:23                   ` [PATCH v10 05/10] commit: extract cleanup_mode functions to sequencer Phillip Wood
                                     ` (6 subsequent siblings)
  10 siblings, 0 replies; 105+ messages in thread
From: Phillip Wood @ 2019-04-17 10:23 UTC (permalink / raw)
  To: Denton Liu, Git Mailing List
  Cc: Eric Sunshine, Ramsay Jones, Junio C Hamano, SZEDER Gábor

From: Denton Liu <liu.denton@gmail.com>

Refactor out Git commands that were upstream of a pipe. Remove spaces
after "> ". Indent here-docs appropriately. Convert echo chains to use
the test_write_lines function. Refactor 'sign off' test to use test_cmp
instead of comparing variables.

Helped-by: Eric Sunshine <sunshine@sunshineco.com>
Helped-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Denton Liu <liu.denton@gmail.com>
---
 t/t7502-commit-porcelain.sh | 93 +++++++++++++++++++++----------------
 1 file changed, 53 insertions(+), 40 deletions(-)

diff --git a/t/t7502-commit-porcelain.sh b/t/t7502-commit-porcelain.sh
index ca4a740da0..5733d9cd34 100755
--- a/t/t7502-commit-porcelain.sh
+++ b/t/t7502-commit-porcelain.sh
@@ -16,7 +16,8 @@ commit_msg_is () {
 # Arguments: [<prefix] [<commit message>] [<commit options>]
 check_summary_oneline() {
 	test_tick &&
-	git commit ${3+"$3"} -m "$2" | head -1 > act &&
+	git commit ${3+"$3"} -m "$2" >raw &&
+	head -n 1 raw >act &&
 
 	# branch name
 	SUMMARY_PREFIX="$(git name-rev --name-only HEAD)" &&
@@ -68,7 +69,7 @@ test_expect_success 'output summary format for merges' '
 	git checkout recursive-a &&
 	test_must_fail git merge recursive-b &&
 	# resolve the conflict
-	echo commit-a > file1 &&
+	echo commit-a >file1 &&
 	git add file1 &&
 	check_summary_oneline "" "Merge"
 '
@@ -142,9 +143,11 @@ test_expect_success 'sign off' '
 	>positive &&
 	git add positive &&
 	git commit -s -m "thank you" &&
-	actual=$(git cat-file commit HEAD | sed -ne "s/Signed-off-by: //p") &&
-	expected=$(git var GIT_COMMITTER_IDENT | sed -e "s/>.*/>/") &&
-	test "z$actual" = "z$expected"
+	git cat-file commit HEAD >commit.msg &&
+	sed -ne "s/Signed-off-by: //p" commit.msg >actual &&
+	git var GIT_COMMITTER_IDENT >ident &&
+	sed -e "s/>.*/>/" ident >expected &&
+	test_cmp expected actual
 
 '
 
@@ -153,8 +156,8 @@ test_expect_success 'multiple -m' '
 	>negative &&
 	git add negative &&
 	git commit -m "one" -m "two" -m "three" &&
-	actual=$(git cat-file commit HEAD | sed -e "1,/^\$/d") &&
-	expected=$(echo one; echo; echo two; echo; echo three) &&
+	actual=$(git cat-file commit HEAD >tmp && sed -e "1,/^\$/d" tmp && rm tmp) &&
+	expected=$(test_write_lines "one" "" "two" "" "three") &&
 	test "z$actual" = "z$expected"
 
 '
@@ -163,7 +166,8 @@ test_expect_success 'verbose' '
 
 	echo minus >negative &&
 	git add negative &&
-	git status -v | sed -ne "/^diff --git /p" >actual &&
+	git status -v >raw &&
+	sed -ne "/^diff --git /p" raw >actual &&
 	echo "diff --git a/negative b/negative" >expect &&
 	test_cmp expect actual
 
@@ -189,7 +193,8 @@ test_expect_success 'cleanup commit messages (verbatim option,-t)' '
 
 	echo >>negative &&
 	git commit --cleanup=verbatim --no-status -t expect -a &&
-	git cat-file -p HEAD |sed -e "1,/^\$/d" >actual &&
+	git cat-file -p HEAD >raw &&
+	sed -e "1,/^\$/d" raw >actual &&
 	test_cmp expect actual
 
 '
@@ -198,7 +203,8 @@ test_expect_success 'cleanup commit messages (verbatim option,-F)' '
 
 	echo >>negative &&
 	git commit --cleanup=verbatim -F expect -a &&
-	git cat-file -p HEAD |sed -e "1,/^\$/d">actual &&
+	git cat-file -p HEAD >raw &&
+	sed -e "1,/^\$/d" raw >actual &&
 	test_cmp expect actual
 
 '
@@ -207,75 +213,80 @@ test_expect_success 'cleanup commit messages (verbatim option,-m)' '
 
 	echo >>negative &&
 	git commit --cleanup=verbatim -m "$mesg_with_comment_and_newlines" -a &&
-	git cat-file -p HEAD |sed -e "1,/^\$/d">actual &&
+	git cat-file -p HEAD >raw &&
+	sed -e "1,/^\$/d" raw >actual &&
 	test_cmp expect actual
 
 '
 
 test_expect_success 'cleanup commit messages (whitespace option,-F)' '
 
 	echo >>negative &&
-	{ echo;echo "# text";echo; } >text &&
+	test_write_lines "" "# text" "" >text &&
 	echo "# text" >expect &&
 	git commit --cleanup=whitespace -F text -a &&
-	git cat-file -p HEAD |sed -e "1,/^\$/d">actual &&
+	git cat-file -p HEAD >raw &&
+	sed -e "1,/^\$/d" raw >actual &&
 	test_cmp expect actual
 
 '
 
 test_expect_success 'cleanup commit messages (scissors option,-F,-e)' '
 
 	echo >>negative &&
-	cat >text <<EOF &&
+	cat >text <<-\EOF &&
 
-# to be kept
+	# to be kept
 
-  # ------------------------ >8 ------------------------
-# to be kept, too
-# ------------------------ >8 ------------------------
-to be removed
-# ------------------------ >8 ------------------------
-to be removed, too
-EOF
+	  # ------------------------ >8 ------------------------
+	# to be kept, too
+	# ------------------------ >8 ------------------------
+	to be removed
+	# ------------------------ >8 ------------------------
+	to be removed, too
+	EOF
 
-	cat >expect <<EOF &&
-# to be kept
+	cat >expect <<-\EOF &&
+	# to be kept
 
-  # ------------------------ >8 ------------------------
-# to be kept, too
-EOF
+	  # ------------------------ >8 ------------------------
+	# to be kept, too
+	EOF
 	git commit --cleanup=scissors -e -F text -a &&
-	git cat-file -p HEAD |sed -e "1,/^\$/d">actual &&
+	git cat-file -p HEAD >raw &&
+	sed -e "1,/^\$/d" raw >actual &&
 	test_cmp expect actual
 '
 
 test_expect_success 'cleanup commit messages (scissors option,-F,-e, scissors on first line)' '
 
 	echo >>negative &&
-	cat >text <<EOF &&
-# ------------------------ >8 ------------------------
-to be removed
-EOF
+	cat >text <<-\EOF &&
+	# ------------------------ >8 ------------------------
+	to be removed
+	EOF
 	git commit --cleanup=scissors -e -F text -a --allow-empty-message &&
-	git cat-file -p HEAD |sed -e "1,/^\$/d">actual &&
+	git cat-file -p HEAD >raw &&
+	sed -e "1,/^\$/d" raw >actual &&
 	test_must_be_empty actual
 '
 
 test_expect_success 'cleanup commit messages (strip option,-F)' '
 
 	echo >>negative &&
-	{ echo;echo "# text";echo sample;echo; } >text &&
+	test_write_lines "" "# text" "sample" "" >text &&
 	echo sample >expect &&
 	git commit --cleanup=strip -F text -a &&
-	git cat-file -p HEAD |sed -e "1,/^\$/d">actual &&
+	git cat-file -p HEAD >raw &&
+	sed -e "1,/^\$/d" raw >actual &&
 	test_cmp expect actual
 
 '
 
 test_expect_success 'cleanup commit messages (strip option,-F,-e)' '
 
 	echo >>negative &&
-	{ echo;echo sample;echo; } >text &&
+	test_write_lines "" "sample" "" >text &&
 	git commit -e -F text -a &&
 	head -n 4 .git/COMMIT_EDITMSG >actual
 '
@@ -387,7 +398,7 @@ test_expect_success AUTOIDENT 'message shows committer when it is automatic' '
 '
 
 write_script .git/FAKE_EDITOR <<EOF
-echo editor started > "$(pwd)/.git/result"
+echo editor started >"$(pwd)/.git/result"
 exit 0
 EOF
 
@@ -455,7 +466,7 @@ EOF
 test_expect_success EXECKEEPSPID 'a SIGTERM should break locks' '
 	echo >>negative &&
 	! "$SHELL_PATH" -c '\''
-	  echo kill -TERM $$ >> .git/FAKE_EDITOR
+	  echo kill -TERM $$ >>.git/FAKE_EDITOR
 	  GIT_EDITOR=.git/FAKE_EDITOR
 	  export GIT_EDITOR
 	  exec git commit -a'\'' &&
@@ -471,7 +482,8 @@ test_expect_success 'Hand committing of a redundant merge removes dups' '
 	test_must_fail git merge second master &&
 	git checkout master g &&
 	EDITOR=: git commit -a &&
-	git cat-file commit HEAD | sed -n -e "s/^parent //p" -e "/^$/q" >actual &&
+	git cat-file commit HEAD >raw &&
+	sed -n -e "s/^parent //p" -e "/^$/q" raw >actual &&
 	test_cmp expect actual
 
 '
@@ -480,7 +492,8 @@ test_expect_success 'A single-liner subject with a token plus colon is not a foo
 
 	git reset --hard &&
 	git commit -s -m "hello: kitty" --allow-empty &&
-	git cat-file commit HEAD | sed -e "1,/^$/d" >actual &&
+	git cat-file commit HEAD >raw &&
+	sed -e "1,/^$/d" raw >actual &&
 	test_line_count = 3 actual
 
 '
-- 
2.21.0


^ permalink raw reply	[flat|nested] 105+ messages in thread

* [PATCH v10 05/10] commit: extract cleanup_mode functions to sequencer
  2019-04-17 10:23                 ` [PATCH v10 00/10] Fix scissors bug during conflict Phillip Wood
                                     ` (3 preceding siblings ...)
  2019-04-17 10:23                   ` [PATCH v10 04/10] t7502: " Phillip Wood
@ 2019-04-17 10:23                   ` Phillip Wood
  2019-04-17 10:23                   ` [PATCH v10 06/10] parse-options.h: extract common --cleanup option Phillip Wood
                                     ` (5 subsequent siblings)
  10 siblings, 0 replies; 105+ messages in thread
From: Phillip Wood @ 2019-04-17 10:23 UTC (permalink / raw)
  To: Denton Liu, Git Mailing List
  Cc: Eric Sunshine, Ramsay Jones, Junio C Hamano, SZEDER Gábor

From: Denton Liu <liu.denton@gmail.com>

Signed-off-by: Denton Liu <liu.denton@gmail.com>
---
 builtin/commit.c | 25 ++-----------------------
 sequencer.c      | 29 +++++++++++++++++++++++++++++
 sequencer.h      |  6 ++++++
 3 files changed, 37 insertions(+), 23 deletions(-)

diff --git a/builtin/commit.c b/builtin/commit.c
index f17537474a..0df15e4851 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -1172,24 +1172,7 @@ static int parse_and_validate_options(int argc, const char *argv[],
 		die(_("Only one of --include/--only/--all/--interactive/--patch can be used."));
 	if (argc == 0 && (also || (only && !amend && !allow_empty)))
 		die(_("No paths with --include/--only does not make sense."));
-	if (!cleanup_arg || !strcmp(cleanup_arg, "default"))
-		cleanup_mode = use_editor ? COMMIT_MSG_CLEANUP_ALL :
-					    COMMIT_MSG_CLEANUP_SPACE;
-	else if (!strcmp(cleanup_arg, "verbatim"))
-		cleanup_mode = COMMIT_MSG_CLEANUP_NONE;
-	else if (!strcmp(cleanup_arg, "whitespace"))
-		cleanup_mode = COMMIT_MSG_CLEANUP_SPACE;
-	else if (!strcmp(cleanup_arg, "strip"))
-		cleanup_mode = COMMIT_MSG_CLEANUP_ALL;
-	else if (!strcmp(cleanup_arg, "scissors"))
-		cleanup_mode = use_editor ? COMMIT_MSG_CLEANUP_SCISSORS :
-					    COMMIT_MSG_CLEANUP_SPACE;
-	/*
-	 * Please update _git_commit() in git-completion.bash when you
-	 * add new options.
-	 */
-	else
-		die(_("Invalid cleanup mode %s"), cleanup_arg);
+	cleanup_mode = get_cleanup_mode(cleanup_arg, use_editor);
 
 	handle_untracked_files_arg(s);
 
@@ -1626,11 +1609,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
 		die(_("could not read commit message: %s"), strerror(saved_errno));
 	}
 
-	if (verbose || /* Truncate the message just before the diff, if any. */
-	    cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)
-		strbuf_setlen(&sb, wt_status_locate_end(sb.buf, sb.len));
-	if (cleanup_mode != COMMIT_MSG_CLEANUP_NONE)
-		strbuf_stripspace(&sb, cleanup_mode == COMMIT_MSG_CLEANUP_ALL);
+	cleanup_message(&sb, cleanup_mode, verbose);
 
 	if (message_is_empty(&sb, cleanup_mode) && !allow_empty_message) {
 		rollback_index_files();
diff --git a/sequencer.c b/sequencer.c
index 87079ece5d..b049951c34 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -516,6 +516,25 @@ static int fast_forward_to(struct repository *r,
 	return 0;
 }
 
+enum commit_msg_cleanup_mode get_cleanup_mode(const char *cleanup_arg,
+	int use_editor)
+{
+	if (!cleanup_arg || !strcmp(cleanup_arg, "default"))
+		return use_editor ? COMMIT_MSG_CLEANUP_ALL :
+				    COMMIT_MSG_CLEANUP_SPACE;
+	else if (!strcmp(cleanup_arg, "verbatim"))
+		return COMMIT_MSG_CLEANUP_NONE;
+	else if (!strcmp(cleanup_arg, "whitespace"))
+		return COMMIT_MSG_CLEANUP_SPACE;
+	else if (!strcmp(cleanup_arg, "strip"))
+		return COMMIT_MSG_CLEANUP_ALL;
+	else if (!strcmp(cleanup_arg, "scissors"))
+		return use_editor ? COMMIT_MSG_CLEANUP_SCISSORS :
+				    COMMIT_MSG_CLEANUP_SPACE;
+	else
+		die(_("Invalid cleanup mode %s"), cleanup_arg);
+}
+
 void append_conflicts_hint(struct index_state *istate,
 			   struct strbuf *msgbuf)
 {
@@ -1018,6 +1037,16 @@ static int rest_is_empty(const struct strbuf *sb, int start)
 	return 1;
 }
 
+void cleanup_message(struct strbuf *msgbuf,
+	enum commit_msg_cleanup_mode cleanup_mode, int verbose)
+{
+	if (verbose || /* Truncate the message just before the diff, if any. */
+	    cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)
+		strbuf_setlen(msgbuf, wt_status_locate_end(msgbuf->buf, msgbuf->len));
+	if (cleanup_mode != COMMIT_MSG_CLEANUP_NONE)
+		strbuf_stripspace(msgbuf, cleanup_mode == COMMIT_MSG_CLEANUP_ALL);
+}
+
 /*
  * Find out if the message in the strbuf contains only whitespace and
  * Signed-off-by lines.
diff --git a/sequencer.h b/sequencer.h
index 82bc7a48d5..8295c8406f 100644
--- a/sequencer.h
+++ b/sequencer.h
@@ -117,6 +117,12 @@ int rearrange_squash(struct repository *r);
 void append_signoff(struct strbuf *msgbuf, size_t ignore_footer, unsigned flag);
 
 void append_conflicts_hint(struct index_state *istate, struct strbuf *msgbuf);
+enum commit_msg_cleanup_mode get_cleanup_mode(const char *cleanup_arg,
+	int use_editor);
+
+void cleanup_message(struct strbuf *msgbuf,
+	enum commit_msg_cleanup_mode cleanup_mode, int verbose);
+
 int message_is_empty(const struct strbuf *sb,
 		     enum commit_msg_cleanup_mode cleanup_mode);
 int template_untouched(const struct strbuf *sb, const char *template_file,
-- 
2.21.0


^ permalink raw reply	[flat|nested] 105+ messages in thread

* [PATCH v10 06/10] parse-options.h: extract common --cleanup option
  2019-04-17 10:23                 ` [PATCH v10 00/10] Fix scissors bug during conflict Phillip Wood
                                     ` (4 preceding siblings ...)
  2019-04-17 10:23                   ` [PATCH v10 05/10] commit: extract cleanup_mode functions to sequencer Phillip Wood
@ 2019-04-17 10:23                   ` Phillip Wood
  2019-04-17 10:23                   ` [PATCH v10 07/10] merge: cleanup messages like commit Phillip Wood
                                     ` (4 subsequent siblings)
  10 siblings, 0 replies; 105+ messages in thread
From: Phillip Wood @ 2019-04-17 10:23 UTC (permalink / raw)
  To: Denton Liu, Git Mailing List
  Cc: Eric Sunshine, Ramsay Jones, Junio C Hamano, SZEDER Gábor,
	Phillip Wood

From: Denton Liu <liu.denton@gmail.com>

The --cleanup option is commonly used. Extract it so that its definition
is not repeated.

Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Signed-off-by: Denton Liu <liu.denton@gmail.com>
---
 builtin/commit.c | 2 +-
 builtin/tag.c    | 3 +--
 parse-options.h  | 1 +
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/builtin/commit.c b/builtin/commit.c
index 0df15e4851..8277da8474 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -1473,7 +1473,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
 		OPT_BOOL('s', "signoff", &signoff, N_("add Signed-off-by:")),
 		OPT_FILENAME('t', "template", &template_file, N_("use specified template file")),
 		OPT_BOOL('e', "edit", &edit_flag, N_("force edit of commit")),
-		OPT_STRING(0, "cleanup", &cleanup_arg, N_("default"), N_("how to strip spaces and #comments from message")),
+		OPT_CLEANUP(&cleanup_arg),
 		OPT_BOOL(0, "status", &include_status, N_("include status in commit message template")),
 		{ OPTION_STRING, 'S', "gpg-sign", &sign_commit, N_("key-id"),
 		  N_("GPG sign commit"), PARSE_OPT_OPTARG, NULL, (intptr_t) "" },
diff --git a/builtin/tag.c b/builtin/tag.c
index 02f6bd1279..a3870fbdba 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -397,8 +397,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
 		OPT_FILENAME('F', "file", &msgfile, N_("read message from file")),
 		OPT_BOOL('e', "edit", &edit_flag, N_("force edit of tag message")),
 		OPT_BOOL('s', "sign", &opt.sign, N_("annotated and GPG-signed tag")),
-		OPT_STRING(0, "cleanup", &cleanup_arg, N_("mode"),
-			N_("how to strip spaces and #comments from message")),
+		OPT_CLEANUP(&cleanup_arg),
 		OPT_STRING('u', "local-user", &keyid, N_("key-id"),
 					N_("use another key to sign the tag")),
 		OPT__FORCE(&force, N_("replace the tag if exists"), 0),
diff --git a/parse-options.h b/parse-options.h
index 74cce4e7fc..b93169337f 100644
--- a/parse-options.h
+++ b/parse-options.h
@@ -314,5 +314,6 @@ int parse_opt_passthru_argv(const struct option *, const char *, int);
 #define OPT_NO_CONTAINS(v, h) _OPT_CONTAINS_OR_WITH("no-contains", v, h, PARSE_OPT_NONEG)
 #define OPT_WITH(v, h) _OPT_CONTAINS_OR_WITH("with", v, h, PARSE_OPT_HIDDEN | PARSE_OPT_NONEG)
 #define OPT_WITHOUT(v, h) _OPT_CONTAINS_OR_WITH("without", v, h, PARSE_OPT_HIDDEN | PARSE_OPT_NONEG)
+#define OPT_CLEANUP(v) OPT_STRING(0, "cleanup", v, N_("mode"), N_("how to strip spaces and #comments from message"))
 
 #endif
-- 
2.21.0


^ permalink raw reply	[flat|nested] 105+ messages in thread

* [PATCH v10 07/10] merge: cleanup messages like commit
  2019-04-17 10:23                 ` [PATCH v10 00/10] Fix scissors bug during conflict Phillip Wood
                                     ` (5 preceding siblings ...)
  2019-04-17 10:23                   ` [PATCH v10 06/10] parse-options.h: extract common --cleanup option Phillip Wood
@ 2019-04-17 10:23                   ` Phillip Wood
  2019-04-17 10:23                   ` [PATCH v10 08/10] merge: add scissors line on merge conflict Phillip Wood
                                     ` (3 subsequent siblings)
  10 siblings, 0 replies; 105+ messages in thread
From: Phillip Wood @ 2019-04-17 10:23 UTC (permalink / raw)
  To: Denton Liu, Git Mailing List
  Cc: Eric Sunshine, Ramsay Jones, Junio C Hamano, SZEDER Gábor,
	Phillip Wood

From: Denton Liu <liu.denton@gmail.com>

This change allows git-merge messages to be cleaned up with the
commit.cleanup configuration or --cleanup option, just like how
git-commit does it.

We also give git-pull the option of --cleanup so that it can also take
advantage of this change.

Finally, add testing to ensure that messages are properly cleaned up.
Note that some newlines that were added to the commit message were
removed so that if a file were read via -F, it would be copied
faithfully.

Helped-by: Eric Sunshine <sunshine@sunshineco.com>
Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Signed-off-by: Denton Liu <liu.denton@gmail.com>
---
 Documentation/merge-options.txt |  4 +++
 builtin/merge.c                 | 41 +++++++++++++++------
 builtin/pull.c                  | 12 +++++++
 t/t5521-pull-options.sh         |  8 +++++
 t/t7604-merge-custom-message.sh | 63 +++++++++++++++++++++++++++++++++
 wt-status.c                     | 12 +++++--
 wt-status.h                     |  1 +
 7 files changed, 128 insertions(+), 13 deletions(-)

diff --git a/Documentation/merge-options.txt b/Documentation/merge-options.txt
index 92a7d936c1..bcf0b3e49c 100644
--- a/Documentation/merge-options.txt
+++ b/Documentation/merge-options.txt
@@ -32,6 +32,10 @@ they run `git merge`. To make it easier to adjust such scripts to the
 updated behaviour, the environment variable `GIT_MERGE_AUTOEDIT` can be
 set to `no` at the beginning of them.
 
+--cleanup=<mode>::
+	This option determines how the merge message will be cleaned up
+	before commiting. See linkgit:git-commit[1] for more details.
+
 --ff::
 	When the merge resolves as a fast-forward, only update the branch
 	pointer, without creating a merge commit.  This is the default
diff --git a/builtin/merge.c b/builtin/merge.c
index 5ce8946d39..e1f7b7342d 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -38,6 +38,7 @@
 #include "tag.h"
 #include "alias.h"
 #include "commit-reach.h"
+#include "wt-status.h"
 
 #define DEFAULT_TWOHEAD (1<<0)
 #define DEFAULT_OCTOPUS (1<<1)
@@ -98,6 +99,9 @@ enum ff_type {
 
 static enum ff_type fast_forward = FF_ALLOW;
 
+static const char *cleanup_arg;
+static enum commit_msg_cleanup_mode cleanup_mode;
+
 static int option_parse_message(const struct option *opt,
 				const char *arg, int unset)
 {
@@ -249,6 +253,7 @@ static struct option builtin_merge_options[] = {
 		N_("perform a commit if the merge succeeds (default)")),
 	OPT_BOOL('e', "edit", &option_edit,
 		N_("edit message before committing")),
+	OPT_CLEANUP(&cleanup_arg),
 	OPT_SET_INT(0, "ff", &fast_forward, N_("allow fast-forward (default)"), FF_ALLOW),
 	OPT_SET_INT_F(0, "ff-only", &fast_forward,
 		      N_("abort if fast-forward is not possible"),
@@ -612,6 +617,8 @@ static int git_merge_config(const char *k, const char *v, void *cb)
 		return git_config_string(&pull_twohead, k, v);
 	else if (!strcmp(k, "pull.octopus"))
 		return git_config_string(&pull_octopus, k, v);
+	else if (!strcmp(k, "commit.cleanup"))
+		return git_config_string(&cleanup_arg, k, v);
 	else if (!strcmp(k, "merge.renormalize"))
 		option_renormalize = git_config_bool(k, v);
 	else if (!strcmp(k, "merge.ff")) {
@@ -800,20 +807,33 @@ static void abort_commit(struct commit_list *remoteheads, const char *err_msg)
 static const char merge_editor_comment[] =
 N_("Please enter a commit message to explain why this merge is necessary,\n"
    "especially if it merges an updated upstream into a topic branch.\n"
-   "\n"
-   "Lines starting with '%c' will be ignored, and an empty message aborts\n"
+   "\n");
+
+static const char scissors_editor_comment[] =
+N_("An empty message aborts the commit.\n");
+
+static const char no_scissors_editor_comment[] =
+N_("Lines starting with '%c' will be ignored, and an empty message aborts\n"
    "the commit.\n");
 
 static void write_merge_heads(struct commit_list *);
 static void prepare_to_commit(struct commit_list *remoteheads)
 {
 	struct strbuf msg = STRBUF_INIT;
 	strbuf_addbuf(&msg, &merge_msg);
-	strbuf_addch(&msg, '\n');
 	if (squash)
 		BUG("the control must not reach here under --squash");
-	if (0 < option_edit)
-		strbuf_commented_addf(&msg, _(merge_editor_comment), comment_line_char);
+	if (0 < option_edit) {
+		strbuf_addch(&msg, '\n');
+		if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS) {
+			wt_status_append_cut_line(&msg);
+			strbuf_commented_addf(&msg, "\n");
+		}
+		strbuf_commented_addf(&msg, _(merge_editor_comment));
+		strbuf_commented_addf(&msg, _(cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS ?
+			scissors_editor_comment :
+			no_scissors_editor_comment), comment_line_char);
+	}
 	if (signoff)
 		append_signoff(&msg, ignore_non_trailer(msg.buf, msg.len), 0);
 	write_merge_heads(remoteheads);
@@ -832,7 +852,7 @@ static void prepare_to_commit(struct commit_list *remoteheads)
 		abort_commit(remoteheads, NULL);
 
 	read_merge_msg(&msg);
-	strbuf_stripspace(&msg, 0 < option_edit);
+	cleanup_message(&msg, cleanup_mode, 0);
 	if (!msg.len)
 		abort_commit(remoteheads, _("Empty commit message."));
 	strbuf_release(&merge_msg);
@@ -880,7 +900,6 @@ static int finish_automerge(struct commit *head,
 	parents = remoteheads;
 	if (!head_subsumed || fast_forward == FF_NO)
 		commit_list_insert(head, &parents);
-	strbuf_addch(&merge_msg, '\n');
 	prepare_to_commit(remoteheads);
 	if (commit_tree(merge_msg.buf, merge_msg.len, result_tree, parents,
 			&result_commit, NULL, sign_commit))
@@ -1301,6 +1320,11 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
 	}
 	resolve_undo_clear();
 
+	if (option_edit < 0)
+		option_edit = default_edit_option();
+
+	cleanup_mode = get_cleanup_mode(cleanup_arg, 0 < option_edit);
+
 	if (verbosity < 0)
 		show_diffstat = 0;
 
@@ -1386,9 +1410,6 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
 			fast_forward = FF_NO;
 	}
 
-	if (option_edit < 0)
-		option_edit = default_edit_option();
-
 	if (!use_strategies) {
 		if (!remoteheads)
 			; /* already up-to-date */
diff --git a/builtin/pull.c b/builtin/pull.c
index 33db889955..5bf82b4b27 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -24,6 +24,7 @@
 #include "lockfile.h"
 #include "wt-status.h"
 #include "commit-reach.h"
+#include "sequencer.h"
 
 enum rebase_type {
 	REBASE_INVALID = -1,
@@ -101,6 +102,7 @@ static char *opt_signoff;
 static char *opt_squash;
 static char *opt_commit;
 static char *opt_edit;
+static char *cleanup_arg;
 static char *opt_ff;
 static char *opt_verify_signatures;
 static int opt_autostash = -1;
@@ -168,6 +170,7 @@ static struct option pull_options[] = {
 	OPT_PASSTHRU(0, "edit", &opt_edit, NULL,
 		N_("edit message before committing"),
 		PARSE_OPT_NOARG),
+	OPT_CLEANUP(&cleanup_arg),
 	OPT_PASSTHRU(0, "ff", &opt_ff, NULL,
 		N_("allow fast-forward"),
 		PARSE_OPT_NOARG),
@@ -644,6 +647,8 @@ static int run_merge(void)
 		argv_array_push(&args, opt_commit);
 	if (opt_edit)
 		argv_array_push(&args, opt_edit);
+	if (cleanup_arg)
+		argv_array_pushf(&args, "--cleanup=%s", cleanup_arg);
 	if (opt_ff)
 		argv_array_push(&args, opt_ff);
 	if (opt_verify_signatures)
@@ -875,6 +880,13 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
 
 	argc = parse_options(argc, argv, prefix, pull_options, pull_usage, 0);
 
+	if (cleanup_arg)
+		/*
+		 * this only checks the validity of cleanup_arg; we don't need
+		 * a valid value for use_editor
+		 */
+		get_cleanup_mode(cleanup_arg, 0);
+
 	parse_repo_refspecs(argc, argv, &repo, &refspecs);
 
 	if (!opt_ff)
diff --git a/t/t5521-pull-options.sh b/t/t5521-pull-options.sh
index c19d8dbc9d..ccde8ba491 100755
--- a/t/t5521-pull-options.sh
+++ b/t/t5521-pull-options.sh
@@ -77,6 +77,14 @@ test_expect_success 'git pull -q -v' '
 	test_must_be_empty out &&
 	test -s err)
 '
+test_expect_success 'git pull --cleanup errors early on invalid argument' '
+	mkdir clonedcleanup &&
+	(cd clonedcleanup && git init &&
+	test_must_fail git pull --cleanup invalid "../parent" >out 2>err &&
+	test_must_be_empty out &&
+	test -s err)
+'
+
 
 test_expect_success 'git pull --force' '
 	mkdir clonedoldstyle &&
diff --git a/t/t7604-merge-custom-message.sh b/t/t7604-merge-custom-message.sh
index aba1279132..cd4f9607dc 100755
--- a/t/t7604-merge-custom-message.sh
+++ b/t/t7604-merge-custom-message.sh
@@ -49,4 +49,67 @@ test_expect_success 'merge --log appends to custom message' '
 	test_cmp exp.log actual
 '
 
+mesg_with_comment_and_newlines='
+# text
+
+'
+
+test_expect_success 'prepare file with comment line and trailing newlines'  '
+	printf "%s" "$mesg_with_comment_and_newlines" >expect
+'
+
+test_expect_success 'cleanup commit messages (verbatim option)' '
+	git reset --hard c1 &&
+	git merge --cleanup=verbatim -F expect c2 &&
+	git cat-file commit HEAD >raw &&
+	sed -e "1,/^$/d" raw >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'cleanup commit messages (whitespace option)' '
+	git reset --hard c1 &&
+	test_write_lines "" "# text" "" >text &&
+	echo "# text" >expect &&
+	git merge --cleanup=whitespace -F text c2 &&
+	git cat-file commit HEAD >raw &&
+	sed -e "1,/^$/d" raw >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'cleanup merge messages (scissors option)' '
+	git reset --hard c1 &&
+	cat >text <<-\EOF &&
+
+	# to be kept
+
+	  # ------------------------ >8 ------------------------
+	# to be kept, too
+	# ------------------------ >8 ------------------------
+	to be removed
+	# ------------------------ >8 ------------------------
+	to be removed, too
+	EOF
+
+	cat >expect <<-\EOF &&
+	# to be kept
+
+	  # ------------------------ >8 ------------------------
+	# to be kept, too
+	EOF
+	git merge --cleanup=scissors -e -F text c2 &&
+	git cat-file commit HEAD >raw &&
+	sed -e "1,/^$/d" raw >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'cleanup commit messages (strip option)' '
+	git reset --hard c1 &&
+	test_write_lines "" "# text" "sample" "" >text &&
+	echo sample >expect &&
+	git merge --cleanup=strip -F text c2 &&
+	git cat-file commit HEAD >raw &&
+	sed -e "1,/^$/d" raw >actual &&
+	test_cmp expect actual
+'
+
 test_done
diff --git a/wt-status.c b/wt-status.c
index 445a36204a..b81fcd428d 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -1006,13 +1006,19 @@ size_t wt_status_locate_end(const char *s, size_t len)
 	return len;
 }
 
-void wt_status_add_cut_line(FILE *fp)
+void wt_status_append_cut_line(struct strbuf *buf)
 {
 	const char *explanation = _("Do not modify or remove the line above.\nEverything below it will be ignored.");
+
+	strbuf_commented_addf(buf, "%s", cut_line);
+	strbuf_add_commented_lines(buf, explanation, strlen(explanation));
+}
+
+void wt_status_add_cut_line(FILE *fp)
+{
 	struct strbuf buf = STRBUF_INIT;
 
-	fprintf(fp, "%c %s", comment_line_char, cut_line);
-	strbuf_add_commented_lines(&buf, explanation, strlen(explanation));
+	wt_status_append_cut_line(&buf);
 	fputs(buf.buf, fp);
 	strbuf_release(&buf);
 }
diff --git a/wt-status.h b/wt-status.h
index 3a95975032..64f1ddc9fd 100644
--- a/wt-status.h
+++ b/wt-status.h
@@ -129,6 +129,7 @@ struct wt_status {
 };
 
 size_t wt_status_locate_end(const char *s, size_t len);
+void wt_status_append_cut_line(struct strbuf *buf);
 void wt_status_add_cut_line(FILE *fp);
 void wt_status_prepare(struct repository *r, struct wt_status *s);
 void wt_status_print(struct wt_status *s);
-- 
2.21.0


^ permalink raw reply	[flat|nested] 105+ messages in thread

* [PATCH v10 08/10] merge: add scissors line on merge conflict
  2019-04-17 10:23                 ` [PATCH v10 00/10] Fix scissors bug during conflict Phillip Wood
                                     ` (6 preceding siblings ...)
  2019-04-17 10:23                   ` [PATCH v10 07/10] merge: cleanup messages like commit Phillip Wood
@ 2019-04-17 10:23                   ` Phillip Wood
  2019-04-17 10:23                   ` [PATCH v10 09/10] sequencer.c: save and restore cleanup mode Phillip Wood
                                     ` (2 subsequent siblings)
  10 siblings, 0 replies; 105+ messages in thread
From: Phillip Wood @ 2019-04-17 10:23 UTC (permalink / raw)
  To: Denton Liu, Git Mailing List
  Cc: Eric Sunshine, Ramsay Jones, Junio C Hamano, SZEDER Gábor

From: Denton Liu <liu.denton@gmail.com>

This fixes a bug where the scissors line is placed after the Conflicts:
section, in the case where a merge conflict occurs and
commit.cleanup = scissors.

Next, if commit.cleanup = scissors is specified, don't produce a
scissors line in commit if one already exists in the MERGE_MSG file.

Helped-by: Eric Sunshine <sunshine@sunshineco.com>
Signed-off-by: Denton Liu <liu.denton@gmail.com>
---
 Documentation/merge-options.txt |  7 +++--
 builtin/commit.c                | 22 ++++++++++++----
 builtin/merge.c                 | 14 ++++++++++
 t/t7600-merge.sh                | 46 +++++++++++++++++++++++++++++++++
 4 files changed, 82 insertions(+), 7 deletions(-)

diff --git a/Documentation/merge-options.txt b/Documentation/merge-options.txt
index bcf0b3e49c..61876dbc33 100644
--- a/Documentation/merge-options.txt
+++ b/Documentation/merge-options.txt
@@ -33,8 +33,11 @@ updated behaviour, the environment variable `GIT_MERGE_AUTOEDIT` can be
 set to `no` at the beginning of them.
 
 --cleanup=<mode>::
-	This option determines how the merge message will be cleaned up
-	before commiting. See linkgit:git-commit[1] for more details.
+	This option determines how the merge message will be cleaned up before
+	commiting. See linkgit:git-commit[1] for more details. In addition, if
+	the '<mode>' is given a value of `scissors`, scissors will be appended
+	to `MERGE_MSG` before being passed on to the commit machinery in the
+	case of a merge conflict.
 
 --ff::
 	When the merge resolves as a fast-forward, only update the branch
diff --git a/builtin/commit.c b/builtin/commit.c
index 8277da8474..5401a60cbe 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -668,6 +668,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
 	const char *hook_arg2 = NULL;
 	int clean_message_contents = (cleanup_mode != COMMIT_MSG_CLEANUP_NONE);
 	int old_display_comment_prefix;
+	int merge_contains_scissors = 0;
 
 	/* This checks and barfs if author is badly specified */
 	determine_author_info(author_ident);
@@ -728,6 +729,8 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
 			strbuf_addbuf(&sb, &message);
 		hook_arg1 = "message";
 	} else if (!stat(git_path_merge_msg(the_repository), &statbuf)) {
+		size_t merge_msg_start;
+
 		/*
 		 * prepend SQUASH_MSG here if it exists and a
 		 * "merge --squash" was originally performed
@@ -738,8 +741,16 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
 			hook_arg1 = "squash";
 		} else
 			hook_arg1 = "merge";
+
+		merge_msg_start = sb.len;
 		if (strbuf_read_file(&sb, git_path_merge_msg(the_repository), 0) < 0)
 			die_errno(_("could not read MERGE_MSG"));
+
+		if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS &&
+		    wt_status_locate_end(sb.buf + merge_msg_start,
+					 sb.len - merge_msg_start) <
+				sb.len - merge_msg_start)
+			merge_contains_scissors = 1;
 	} else if (!stat(git_path_squash_msg(the_repository), &statbuf)) {
 		if (strbuf_read_file(&sb, git_path_squash_msg(the_repository), 0) < 0)
 			die_errno(_("could not read SQUASH_MSG"));
@@ -807,7 +818,8 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
 		struct ident_split ci, ai;
 
 		if (whence != FROM_COMMIT) {
-			if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)
+			if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS &&
+				!merge_contains_scissors)
 				wt_status_add_cut_line(s->fp);
 			status_printf_ln(s, GIT_COLOR_NORMAL,
 			    whence == FROM_MERGE
@@ -832,10 +844,10 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
 				_("Please enter the commit message for your changes."
 				  " Lines starting\nwith '%c' will be ignored, and an empty"
 				  " message aborts the commit.\n"), comment_line_char);
-		else if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS &&
-			 whence == FROM_COMMIT)
-			wt_status_add_cut_line(s->fp);
-		else /* COMMIT_MSG_CLEANUP_SPACE, that is. */
+		else if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS) {
+			if (whence == FROM_COMMIT && !merge_contains_scissors)
+				wt_status_add_cut_line(s->fp);
+		} else /* COMMIT_MSG_CLEANUP_SPACE, that is. */
 			status_printf(s, GIT_COLOR_NORMAL,
 				_("Please enter the commit message for your changes."
 				  " Lines starting\n"
diff --git a/builtin/merge.c b/builtin/merge.c
index e1f7b7342d..03b9f7230a 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -920,6 +920,20 @@ static int suggest_conflicts(void)
 	filename = git_path_merge_msg(the_repository);
 	fp = xfopen(filename, "a");
 
+	/*
+	 * We can't use cleanup_mode because if we're not using the editor,
+	 * get_cleanup_mode will return COMMIT_MSG_CLEANUP_SPACE instead, even
+	 * though the message is meant to be processed later by git-commit.
+	 * Thus, we will get the cleanup mode which is returned when we _are_
+	 * using an editor.
+	 */
+	if (get_cleanup_mode(cleanup_arg, 1) == COMMIT_MSG_CLEANUP_SCISSORS) {
+	    fputc('\n', fp);
+	    wt_status_add_cut_line(fp);
+	    /* comments out the newline from append_conflicts_hint */
+	    fputc(comment_line_char, fp);
+	}
+
 	append_conflicts_hint(&the_index, &msgbuf);
 	fputs(msgbuf.buf, fp);
 	strbuf_release(&msgbuf);
diff --git a/t/t7600-merge.sh b/t/t7600-merge.sh
index 2f4c2801fb..7f9c68cbe7 100755
--- a/t/t7600-merge.sh
+++ b/t/t7600-merge.sh
@@ -246,6 +246,52 @@ test_expect_success 'merge --squash c3 with c7' '
 	test_cmp expect actual
 '
 
+test_expect_success 'merge c3 with c7 with commit.cleanup = scissors' '
+	git config commit.cleanup scissors &&
+	git reset --hard c3 &&
+	test_must_fail git merge c7 &&
+	cat result.9z >file &&
+	git commit --no-edit -a &&
+
+	cat >expect <<-\EOF &&
+	Merge tag '"'"'c7'"'"'
+
+	# ------------------------ >8 ------------------------
+	# Do not modify or remove the line above.
+	# Everything below it will be ignored.
+	#
+	# Conflicts:
+	#	file
+	EOF
+	git cat-file commit HEAD >raw &&
+	sed -e '1,/^$/d' raw >actual &&
+	test_i18ncmp expect actual
+'
+
+test_expect_success 'merge c3 with c7 with --squash commit.cleanup = scissors' '
+	git config commit.cleanup scissors &&
+	git reset --hard c3 &&
+	test_must_fail git merge --squash c7 &&
+	cat result.9z >file &&
+	git commit --no-edit -a &&
+
+	cat >expect <<-EOF &&
+	Squashed commit of the following:
+
+	$(git show -s c7)
+
+	# ------------------------ >8 ------------------------
+	# Do not modify or remove the line above.
+	# Everything below it will be ignored.
+	#
+	# Conflicts:
+	#	file
+	EOF
+	git cat-file commit HEAD >raw &&
+	sed -e '1,/^$/d' raw >actual &&
+	test_i18ncmp expect actual
+'
+
 test_debug 'git log --graph --decorate --oneline --all'
 
 test_expect_success 'merge c1 with c2 and c3' '
-- 
2.21.0


^ permalink raw reply	[flat|nested] 105+ messages in thread

* [PATCH v10 09/10] sequencer.c: save and restore cleanup mode
  2019-04-17 10:23                 ` [PATCH v10 00/10] Fix scissors bug during conflict Phillip Wood
                                     ` (7 preceding siblings ...)
  2019-04-17 10:23                   ` [PATCH v10 08/10] merge: add scissors line on merge conflict Phillip Wood
@ 2019-04-17 10:23                   ` Phillip Wood
  2019-04-17 17:02                     ` Denton Liu
  2019-04-17 10:23                   ` [PATCH v10 10/10] cherry-pick/revert: add scissors line on merge conflict Phillip Wood
  2019-04-18  5:19                   ` [PATCH v10 00/10] Fix scissors bug during conflict Junio C Hamano
  10 siblings, 1 reply; 105+ messages in thread
From: Phillip Wood @ 2019-04-17 10:23 UTC (permalink / raw)
  To: Denton Liu, Git Mailing List
  Cc: Eric Sunshine, Ramsay Jones, Junio C Hamano, SZEDER Gábor,
	Phillip Wood

From: Denton Liu <liu.denton@gmail.com>

If the user specifies an explicit cleanup mode then save and restore it
so that it is preserved by 'git cherry-pick --continue'.

Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>
---
 sequencer.c | 28 +++++++++++++++++++++++++++-
 1 file changed, 27 insertions(+), 1 deletion(-)

diff --git a/sequencer.c b/sequencer.c
index b049951c34..3f4b0896e3 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -535,6 +535,24 @@ enum commit_msg_cleanup_mode get_cleanup_mode(const char *cleanup_arg,
 		die(_("Invalid cleanup mode %s"), cleanup_arg);
 }
 
+/*
+ * NB using int rather than enum cleanup_mode to stop clang's
+ * -Wtautological-constant-out-of-range-compare complaining that the comparison
+ * is always true.
+ */
+static const char *describe_cleanup_mode(int cleanup_mode)
+{
+	static const char *modes[] = { "whitespace",
+				       "verbatim",
+				       "scissors",
+				       "strip" };
+
+	if (cleanup_mode < ARRAY_SIZE(modes))
+		return modes[cleanup_mode];
+
+	BUG("invalid cleanup_mode provided (%d)", cleanup_mode);
+}
+
 void append_conflicts_hint(struct index_state *istate,
 			   struct strbuf *msgbuf)
 {
@@ -2366,7 +2384,10 @@ static int populate_opts_cb(const char *key, const char *value, void *data)
 		opts->allow_rerere_auto =
 			git_config_bool_or_int(key, value, &error_flag) ?
 				RERERE_AUTOUPDATE : RERERE_NOAUTOUPDATE;
-	else
+	else if (!strcmp(key, "options.default-msg-cleanup")) {
+		opts->explicit_cleanup = 1;
+		opts->default_msg_cleanup = get_cleanup_mode(value, 1);
+	} else
 		return error(_("invalid key: %s"), key);
 
 	if (!error_flag)
@@ -2770,6 +2791,11 @@ static int save_opts(struct replay_opts *opts)
 		res |= git_config_set_in_file_gently(opts_file, "options.allow-rerere-auto",
 						     opts->allow_rerere_auto == RERERE_AUTOUPDATE ?
 						     "true" : "false");
+
+	if (opts->explicit_cleanup)
+		res |= git_config_set_in_file_gently(opts_file,
+				"options.default-msg-cleanup",
+				describe_cleanup_mode(opts->default_msg_cleanup));
 	return res;
 }
 
-- 
2.21.0


^ permalink raw reply	[flat|nested] 105+ messages in thread

* [PATCH v10 10/10] cherry-pick/revert: add scissors line on merge conflict
  2019-04-17 10:23                 ` [PATCH v10 00/10] Fix scissors bug during conflict Phillip Wood
                                     ` (8 preceding siblings ...)
  2019-04-17 10:23                   ` [PATCH v10 09/10] sequencer.c: save and restore cleanup mode Phillip Wood
@ 2019-04-17 10:23                   ` Phillip Wood
  2019-04-18  5:19                   ` [PATCH v10 00/10] Fix scissors bug during conflict Junio C Hamano
  10 siblings, 0 replies; 105+ messages in thread
From: Phillip Wood @ 2019-04-17 10:23 UTC (permalink / raw)
  To: Denton Liu, Git Mailing List
  Cc: Eric Sunshine, Ramsay Jones, Junio C Hamano, SZEDER Gábor,
	Phillip Wood

From: Denton Liu <liu.denton@gmail.com>

Fix a bug where the scissors line is placed after the Conflicts:
section, in the case where a merge conflict occurs and
commit.cleanup = scissors.

Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Signed-off-by: Denton Liu <liu.denton@gmail.com>
---
 Documentation/git-cherry-pick.txt |  7 +++
 Documentation/git-revert.txt      |  7 +++
 builtin/merge.c                   | 10 +---
 builtin/revert.c                  |  7 +++
 sequencer.c                       | 16 ++++--
 sequencer.h                       |  3 +-
 t/t3507-cherry-pick-conflict.sh   | 86 +++++++++++++++++++++++++++++++
 7 files changed, 122 insertions(+), 14 deletions(-)

diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt
index b8cfeec67e..cbb663a843 100644
--- a/Documentation/git-cherry-pick.txt
+++ b/Documentation/git-cherry-pick.txt
@@ -57,6 +57,13 @@ OPTIONS
 	With this option, 'git cherry-pick' will let you edit the commit
 	message prior to committing.
 
+--cleanup=<mode>::
+	This option determines how the commit message will be cleaned up before
+	being passed on to the commit machinery. See linkgit:git-commit[1] for more
+	details. In particular, if the '<mode>' is given a value of `scissors`,
+	scissors will be appended to `MERGE_MSG` before being passed on in the case
+	of a conflict.
+
 -x::
 	When recording the commit, append a line that says
 	"(cherry picked from commit ...)" to the original commit
diff --git a/Documentation/git-revert.txt b/Documentation/git-revert.txt
index 837707a8fd..7fd254df92 100644
--- a/Documentation/git-revert.txt
+++ b/Documentation/git-revert.txt
@@ -66,6 +66,13 @@ more details.
 	With this option, 'git revert' will not start the commit
 	message editor.
 
+--cleanup=<mode>::
+	This option determines how the commit message will be cleaned up before
+	being passed on to the commit machinery. See linkgit:git-commit[1] for more
+	details. In particular, if the '<mode>' is given a value of `scissors`,
+	scissors will be appended to `MERGE_MSG` before being passed on in the case
+	of a conflict.
+
 -n::
 --no-commit::
 	Usually the command automatically creates some commits with
diff --git a/builtin/merge.c b/builtin/merge.c
index 03b9f7230a..e96f72af80 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -927,14 +927,8 @@ static int suggest_conflicts(void)
 	 * Thus, we will get the cleanup mode which is returned when we _are_
 	 * using an editor.
 	 */
-	if (get_cleanup_mode(cleanup_arg, 1) == COMMIT_MSG_CLEANUP_SCISSORS) {
-	    fputc('\n', fp);
-	    wt_status_add_cut_line(fp);
-	    /* comments out the newline from append_conflicts_hint */
-	    fputc(comment_line_char, fp);
-	}
-
-	append_conflicts_hint(&the_index, &msgbuf);
+	append_conflicts_hint(&the_index, &msgbuf,
+			      get_cleanup_mode(cleanup_arg, 1));
 	fputs(msgbuf.buf, fp);
 	strbuf_release(&msgbuf);
 	fclose(fp);
diff --git a/builtin/revert.c b/builtin/revert.c
index a47b53ceaf..d4dcedbdc6 100644
--- a/builtin/revert.c
+++ b/builtin/revert.c
@@ -96,11 +96,13 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
 {
 	const char * const * usage_str = revert_or_cherry_pick_usage(opts);
 	const char *me = action_name(opts);
+	const char *cleanup_arg = NULL;
 	int cmd = 0;
 	struct option base_options[] = {
 		OPT_CMDMODE(0, "quit", &cmd, N_("end revert or cherry-pick sequence"), 'q'),
 		OPT_CMDMODE(0, "continue", &cmd, N_("resume revert or cherry-pick sequence"), 'c'),
 		OPT_CMDMODE(0, "abort", &cmd, N_("cancel revert or cherry-pick sequence"), 'a'),
+		OPT_CLEANUP(&cleanup_arg),
 		OPT_BOOL('n', "no-commit", &opts->no_commit, N_("don't automatically commit")),
 		OPT_BOOL('e', "edit", &opts->edit, N_("edit the commit message")),
 		OPT_NOOP_NOARG('r', NULL),
@@ -137,6 +139,11 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
 	if (opts->keep_redundant_commits)
 		opts->allow_empty = 1;
 
+	if (cleanup_arg) {
+		opts->default_msg_cleanup = get_cleanup_mode(cleanup_arg, 1);
+		opts->explicit_cleanup = 1;
+	}
+
 	/* Check for incompatible command line arguments */
 	if (cmd) {
 		char *this_operation;
diff --git a/sequencer.c b/sequencer.c
index 3f4b0896e3..cff07c1907 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -182,7 +182,7 @@ static int git_sequencer_config(const char *k, const char *v, void *cb)
 			opts->default_msg_cleanup = COMMIT_MSG_CLEANUP_ALL;
 			opts->explicit_cleanup = 1;
 		} else if (!strcmp(s, "scissors")) {
-			opts->default_msg_cleanup = COMMIT_MSG_CLEANUP_SPACE;
+			opts->default_msg_cleanup = COMMIT_MSG_CLEANUP_SCISSORS;
 			opts->explicit_cleanup = 1;
 		} else {
 			warning(_("invalid commit message cleanup mode '%s'"),
@@ -554,10 +554,16 @@ static const char *describe_cleanup_mode(int cleanup_mode)
 }
 
 void append_conflicts_hint(struct index_state *istate,
-			   struct strbuf *msgbuf)
+	struct strbuf *msgbuf, enum commit_msg_cleanup_mode cleanup_mode)
 {
 	int i;
 
+	if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS) {
+		strbuf_addch(msgbuf, '\n');
+		wt_status_append_cut_line(msgbuf);
+		strbuf_addch(msgbuf, comment_line_char);
+	}
+
 	strbuf_addch(msgbuf, '\n');
 	strbuf_commented_addf(msgbuf, "Conflicts:\n");
 	for (i = 0; i < istate->cache_nr;) {
@@ -625,7 +631,8 @@ static int do_recursive_merge(struct repository *r,
 			_(action_name(opts)));
 
 	if (!clean)
-		append_conflicts_hint(r->index, msgbuf);
+		append_conflicts_hint(r->index, msgbuf,
+				      opts->default_msg_cleanup);
 
 	return !clean;
 }
@@ -944,7 +951,6 @@ static int run_git_commit(struct repository *r,
 			  unsigned int flags)
 {
 	struct child_process cmd = CHILD_PROCESS_INIT;
-	const char *value;
 
 	if ((flags & CREATE_ROOT_COMMIT) && !(flags & AMEND_MSG)) {
 		struct strbuf msg = STRBUF_INIT, script = STRBUF_INIT;
@@ -1014,7 +1020,7 @@ static int run_git_commit(struct repository *r,
 		argv_array_push(&cmd.args, "-e");
 	else if (!(flags & CLEANUP_MSG) &&
 		 !opts->signoff && !opts->record_origin &&
-		 git_config_get_value("commit.cleanup", &value))
+		 !opts->explicit_cleanup)
 		argv_array_push(&cmd.args, "--cleanup=verbatim");
 
 	if ((flags & ALLOW_EMPTY))
diff --git a/sequencer.h b/sequencer.h
index 8295c8406f..7023da9b13 100644
--- a/sequencer.h
+++ b/sequencer.h
@@ -116,7 +116,8 @@ int rearrange_squash(struct repository *r);
  */
 void append_signoff(struct strbuf *msgbuf, size_t ignore_footer, unsigned flag);
 
-void append_conflicts_hint(struct index_state *istate, struct strbuf *msgbuf);
+void append_conflicts_hint(struct index_state *istate,
+		struct strbuf *msgbuf, enum commit_msg_cleanup_mode cleanup_mode);
 enum commit_msg_cleanup_mode get_cleanup_mode(const char *cleanup_arg,
 	int use_editor);
 
diff --git a/t/t3507-cherry-pick-conflict.sh b/t/t3507-cherry-pick-conflict.sh
index 777fb23d18..a584b11c98 100755
--- a/t/t3507-cherry-pick-conflict.sh
+++ b/t/t3507-cherry-pick-conflict.sh
@@ -189,6 +189,46 @@ test_expect_success 'failed cherry-pick registers participants in index' '
 	test_cmp expected actual
 '
 
+test_expect_success \
+	'cherry-pick conflict, ensure commit.cleanup = scissors places scissors line properly' '
+	pristine_detach initial &&
+	git config commit.cleanup scissors &&
+	cat <<-EOF >expected &&
+		picked
+
+		# ------------------------ >8 ------------------------
+		# Do not modify or remove the line above.
+		# Everything below it will be ignored.
+		#
+		# Conflicts:
+		#	foo
+		EOF
+
+	test_must_fail git cherry-pick picked &&
+
+	test_i18ncmp expected .git/MERGE_MSG
+'
+
+test_expect_success \
+	'cherry-pick conflict, ensure cleanup=scissors places scissors line properly' '
+	pristine_detach initial &&
+	git config --unset commit.cleanup &&
+	cat <<-EOF >expected &&
+		picked
+
+		# ------------------------ >8 ------------------------
+		# Do not modify or remove the line above.
+		# Everything below it will be ignored.
+		#
+		# Conflicts:
+		#	foo
+		EOF
+
+	test_must_fail git cherry-pick --cleanup=scissors picked &&
+
+	test_i18ncmp expected .git/MERGE_MSG
+'
+
 test_expect_success 'failed cherry-pick describes conflict in work tree' '
 	pristine_detach initial &&
 	cat <<-EOF >expected &&
@@ -335,6 +375,52 @@ test_expect_success 'revert conflict, diff3 -m style' '
 	test_cmp expected actual
 '
 
+test_expect_success \
+	'revert conflict, ensure commit.cleanup = scissors places scissors line properly' '
+	pristine_detach initial &&
+	git config commit.cleanup scissors &&
+	cat >expected <<-EOF &&
+		Revert "picked"
+
+		This reverts commit OBJID.
+
+		# ------------------------ >8 ------------------------
+		# Do not modify or remove the line above.
+		# Everything below it will be ignored.
+		#
+		# Conflicts:
+		#	foo
+		EOF
+
+	test_must_fail git revert picked &&
+
+	sed "s/$OID_REGEX/OBJID/" .git/MERGE_MSG >actual &&
+	test_i18ncmp expected actual
+'
+
+test_expect_success \
+	'revert conflict, ensure cleanup=scissors places scissors line properly' '
+	pristine_detach initial &&
+	git config --unset commit.cleanup &&
+	cat >expected <<-EOF &&
+		Revert "picked"
+
+		This reverts commit OBJID.
+
+		# ------------------------ >8 ------------------------
+		# Do not modify or remove the line above.
+		# Everything below it will be ignored.
+		#
+		# Conflicts:
+		#	foo
+		EOF
+
+	test_must_fail git revert --cleanup=scissors picked &&
+
+	sed "s/$OID_REGEX/OBJID/" .git/MERGE_MSG >actual &&
+	test_i18ncmp expected actual
+'
+
 test_expect_success 'failed cherry-pick does not forget -s' '
 	pristine_detach initial &&
 	test_must_fail git cherry-pick -s picked &&
-- 
2.21.0


^ permalink raw reply	[flat|nested] 105+ messages in thread

* Re: [PATCH v10 09/10] sequencer.c: save and restore cleanup mode
  2019-04-17 10:23                   ` [PATCH v10 09/10] sequencer.c: save and restore cleanup mode Phillip Wood
@ 2019-04-17 17:02                     ` Denton Liu
  2019-04-17 19:53                       ` Phillip Wood
  2019-04-18 17:21                       ` Denton Liu
  0 siblings, 2 replies; 105+ messages in thread
From: Denton Liu @ 2019-04-17 17:02 UTC (permalink / raw)
  To: Phillip Wood
  Cc: Git Mailing List, Eric Sunshine, Ramsay Jones, Junio C Hamano,
	SZEDER Gábor

On Wed, Apr 17, 2019 at 11:23:29AM +0100, Phillip Wood wrote:
> From: Denton Liu <liu.denton@gmail.com>

We should drop this line before applying the patch since Phillip did all
of the hard work for this patch and he's the primary author.

> 
> If the user specifies an explicit cleanup mode then save and restore it
> so that it is preserved by 'git cherry-pick --continue'.
> 
> Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>
> ---
>  sequencer.c | 28 +++++++++++++++++++++++++++-
>  1 file changed, 27 insertions(+), 1 deletion(-)
> 
> diff --git a/sequencer.c b/sequencer.c
> index b049951c34..3f4b0896e3 100644
> --- a/sequencer.c
> +++ b/sequencer.c
> @@ -535,6 +535,24 @@ enum commit_msg_cleanup_mode get_cleanup_mode(const char *cleanup_arg,
>  		die(_("Invalid cleanup mode %s"), cleanup_arg);
>  }
>  
> +/*
> + * NB using int rather than enum cleanup_mode to stop clang's
> + * -Wtautological-constant-out-of-range-compare complaining that the comparison
> + * is always true.
> + */
> +static const char *describe_cleanup_mode(int cleanup_mode)
> +{
> +	static const char *modes[] = { "whitespace",
> +				       "verbatim",
> +				       "scissors",
> +				       "strip" };
> +
> +	if (cleanup_mode < ARRAY_SIZE(modes))
> +		return modes[cleanup_mode];
> +
> +	BUG("invalid cleanup_mode provided (%d)", cleanup_mode);
> +}
> +
>  void append_conflicts_hint(struct index_state *istate,
>  			   struct strbuf *msgbuf)
>  {
> @@ -2366,7 +2384,10 @@ static int populate_opts_cb(const char *key, const char *value, void *data)
>  		opts->allow_rerere_auto =
>  			git_config_bool_or_int(key, value, &error_flag) ?
>  				RERERE_AUTOUPDATE : RERERE_NOAUTOUPDATE;
> -	else
> +	else if (!strcmp(key, "options.default-msg-cleanup")) {
> +		opts->explicit_cleanup = 1;
> +		opts->default_msg_cleanup = get_cleanup_mode(value, 1);
> +	} else
>  		return error(_("invalid key: %s"), key);
>  
>  	if (!error_flag)
> @@ -2770,6 +2791,11 @@ static int save_opts(struct replay_opts *opts)
>  		res |= git_config_set_in_file_gently(opts_file, "options.allow-rerere-auto",
>  						     opts->allow_rerere_auto == RERERE_AUTOUPDATE ?
>  						     "true" : "false");
> +
> +	if (opts->explicit_cleanup)
> +		res |= git_config_set_in_file_gently(opts_file,
> +				"options.default-msg-cleanup",
> +				describe_cleanup_mode(opts->default_msg_cleanup));
>  	return res;
>  }
>  
> -- 
> 2.21.0
> 

^ permalink raw reply	[flat|nested] 105+ messages in thread

* Re: [PATCH v10 09/10] sequencer.c: save and restore cleanup mode
  2019-04-17 17:02                     ` Denton Liu
@ 2019-04-17 19:53                       ` Phillip Wood
  2019-04-18 17:21                       ` Denton Liu
  1 sibling, 0 replies; 105+ messages in thread
From: Phillip Wood @ 2019-04-17 19:53 UTC (permalink / raw)
  To: Denton Liu, Phillip Wood
  Cc: Git Mailing List, Eric Sunshine, Ramsay Jones, Junio C Hamano,
	SZEDER Gábor

Hi Denton

On 17/04/2019 18:02, Denton Liu wrote:
> On Wed, Apr 17, 2019 at 11:23:29AM +0100, Phillip Wood wrote:
>> From: Denton Liu <liu.denton@gmail.com>
> 
> We should drop this line before applying the patch since Phillip did all
> of the hard work for this patch and he's the primary author.
> 
>>
>> If the user specifies an explicit cleanup mode then save and restore it
>> so that it is preserved by 'git cherry-pick --continue'.

Sorry when I removed your Signed-off-by: as you suggested I forget to 
change the authorship of the patch

Best Wishes

Phillip

>>
>> Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>
>> ---
>>   sequencer.c | 28 +++++++++++++++++++++++++++-
>>   1 file changed, 27 insertions(+), 1 deletion(-)
>>
>> diff --git a/sequencer.c b/sequencer.c
>> index b049951c34..3f4b0896e3 100644
>> --- a/sequencer.c
>> +++ b/sequencer.c
>> @@ -535,6 +535,24 @@ enum commit_msg_cleanup_mode get_cleanup_mode(const char *cleanup_arg,
>>   		die(_("Invalid cleanup mode %s"), cleanup_arg);
>>   }
>>   
>> +/*
>> + * NB using int rather than enum cleanup_mode to stop clang's
>> + * -Wtautological-constant-out-of-range-compare complaining that the comparison
>> + * is always true.
>> + */
>> +static const char *describe_cleanup_mode(int cleanup_mode)
>> +{
>> +	static const char *modes[] = { "whitespace",
>> +				       "verbatim",
>> +				       "scissors",
>> +				       "strip" };
>> +
>> +	if (cleanup_mode < ARRAY_SIZE(modes))
>> +		return modes[cleanup_mode];
>> +
>> +	BUG("invalid cleanup_mode provided (%d)", cleanup_mode);
>> +}
>> +
>>   void append_conflicts_hint(struct index_state *istate,
>>   			   struct strbuf *msgbuf)
>>   {
>> @@ -2366,7 +2384,10 @@ static int populate_opts_cb(const char *key, const char *value, void *data)
>>   		opts->allow_rerere_auto =
>>   			git_config_bool_or_int(key, value, &error_flag) ?
>>   				RERERE_AUTOUPDATE : RERERE_NOAUTOUPDATE;
>> -	else
>> +	else if (!strcmp(key, "options.default-msg-cleanup")) {
>> +		opts->explicit_cleanup = 1;
>> +		opts->default_msg_cleanup = get_cleanup_mode(value, 1);
>> +	} else
>>   		return error(_("invalid key: %s"), key);
>>   
>>   	if (!error_flag)
>> @@ -2770,6 +2791,11 @@ static int save_opts(struct replay_opts *opts)
>>   		res |= git_config_set_in_file_gently(opts_file, "options.allow-rerere-auto",
>>   						     opts->allow_rerere_auto == RERERE_AUTOUPDATE ?
>>   						     "true" : "false");
>> +
>> +	if (opts->explicit_cleanup)
>> +		res |= git_config_set_in_file_gently(opts_file,
>> +				"options.default-msg-cleanup",
>> +				describe_cleanup_mode(opts->default_msg_cleanup));
>>   	return res;
>>   }
>>   
>> -- 
>> 2.21.0
>>

^ permalink raw reply	[flat|nested] 105+ messages in thread

* Re: [PATCH v10 00/10] Fix scissors bug during conflict
  2019-04-17 10:23                 ` [PATCH v10 00/10] Fix scissors bug during conflict Phillip Wood
                                     ` (9 preceding siblings ...)
  2019-04-17 10:23                   ` [PATCH v10 10/10] cherry-pick/revert: add scissors line on merge conflict Phillip Wood
@ 2019-04-18  5:19                   ` Junio C Hamano
  2019-04-18  9:14                     ` Phillip Wood
  10 siblings, 1 reply; 105+ messages in thread
From: Junio C Hamano @ 2019-04-18  5:19 UTC (permalink / raw)
  To: Phillip Wood
  Cc: Denton Liu, Git Mailing List, Eric Sunshine, Ramsay Jones,
	SZEDER Gábor, Phillip Wood

Phillip Wood <phillip.wood123@gmail.com> writes:

> From: Phillip Wood <phillip.wood@dunelm.org.uk>
>
> With Denton's blessing I've rebased his patches on top of my patch to
> fix the message cleanup with cherry-pick --signoff and -x [1]. I've
>
> [1] https://public-inbox.org/git/20190329110842.30604-1-phillip.wood123@gmail.com/

Hmph, I certainly saw that patch, but I do not recall seeing any
in-depth review of it.  How ready is it?  Was it because it was
trivially obvious that we didn't see much activity on the patch?

^ permalink raw reply	[flat|nested] 105+ messages in thread

* Re: [PATCH v10 00/10] Fix scissors bug during conflict
  2019-04-18  5:19                   ` [PATCH v10 00/10] Fix scissors bug during conflict Junio C Hamano
@ 2019-04-18  9:14                     ` Phillip Wood
  0 siblings, 0 replies; 105+ messages in thread
From: Phillip Wood @ 2019-04-18  9:14 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Denton Liu, Git Mailing List, Eric Sunshine, Ramsay Jones,
	SZEDER Gábor, Phillip Wood

On 18/04/2019 06:19, Junio C Hamano wrote:
> Phillip Wood <phillip.wood123@gmail.com> writes:
> 
>> From: Phillip Wood <phillip.wood@dunelm.org.uk>
>>
>> With Denton's blessing I've rebased his patches on top of my patch to
>> fix the message cleanup with cherry-pick --signoff and -x [1]. I've

Note that the base is a merge of that patch (which is based on maint) 
with 041f5ea1cf ("The third batch", 2019-03-20)

>> [1] https://public-inbox.org/git/20190329110842.30604-1-phillip.wood123@gmail.com/
> 
> Hmph, I certainly saw that patch, but I do not recall seeing any
> in-depth review of it.  How ready is it?  Was it because it was
> trivially obvious that we didn't see much activity on the patch?

I think it is ready (it's a fairly simple change). Dscho said he was 
happy with it [1].

[1] 
https://public-inbox.org/git/nycvar.QRO.7.76.6.1903291651340.41@tvgsbejvaqbjf.bet/

Best Wishes

Phillip

^ permalink raw reply	[flat|nested] 105+ messages in thread

* Re: [PATCH v10 09/10] sequencer.c: save and restore cleanup mode
  2019-04-17 17:02                     ` Denton Liu
  2019-04-17 19:53                       ` Phillip Wood
@ 2019-04-18 17:21                       ` Denton Liu
  1 sibling, 0 replies; 105+ messages in thread
From: Denton Liu @ 2019-04-18 17:21 UTC (permalink / raw)
  To: Phillip Wood
  Cc: Git Mailing List, Eric Sunshine, Ramsay Jones, Junio C Hamano,
	SZEDER Gábor

Hi Junio,

On Wed, Apr 17, 2019 at 10:02:47AM -0700, Denton Liu wrote:
> On Wed, Apr 17, 2019 at 11:23:29AM +0100, Phillip Wood wrote:
> > From: Denton Liu <liu.denton@gmail.com>
> 
> We should drop this line before applying the patch since Phillip did all
> of the hard work for this patch and he's the primary author.

Sorry, I made the mistake of suggesting that this line be dropped. This
resulted in the patchset being queued with Phillip's gmail instead of
his dunelm email. We should probably change the authorship to
Phillip Wood <phillip.wood@dunelm.org.uk>.

Thanks,

Denton

> 
> > 
> > If the user specifies an explicit cleanup mode then save and restore it
> > so that it is preserved by 'git cherry-pick --continue'.
> > 
> > Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>
> > ---
> >  sequencer.c | 28 +++++++++++++++++++++++++++-
> >  1 file changed, 27 insertions(+), 1 deletion(-)
> > 
> > diff --git a/sequencer.c b/sequencer.c
> > index b049951c34..3f4b0896e3 100644
> > --- a/sequencer.c
> > +++ b/sequencer.c
> > @@ -535,6 +535,24 @@ enum commit_msg_cleanup_mode get_cleanup_mode(const char *cleanup_arg,
> >  		die(_("Invalid cleanup mode %s"), cleanup_arg);
> >  }
> >  
> > +/*
> > + * NB using int rather than enum cleanup_mode to stop clang's
> > + * -Wtautological-constant-out-of-range-compare complaining that the comparison
> > + * is always true.
> > + */
> > +static const char *describe_cleanup_mode(int cleanup_mode)
> > +{
> > +	static const char *modes[] = { "whitespace",
> > +				       "verbatim",
> > +				       "scissors",
> > +				       "strip" };
> > +
> > +	if (cleanup_mode < ARRAY_SIZE(modes))
> > +		return modes[cleanup_mode];
> > +
> > +	BUG("invalid cleanup_mode provided (%d)", cleanup_mode);
> > +}
> > +
> >  void append_conflicts_hint(struct index_state *istate,
> >  			   struct strbuf *msgbuf)
> >  {
> > @@ -2366,7 +2384,10 @@ static int populate_opts_cb(const char *key, const char *value, void *data)
> >  		opts->allow_rerere_auto =
> >  			git_config_bool_or_int(key, value, &error_flag) ?
> >  				RERERE_AUTOUPDATE : RERERE_NOAUTOUPDATE;
> > -	else
> > +	else if (!strcmp(key, "options.default-msg-cleanup")) {
> > +		opts->explicit_cleanup = 1;
> > +		opts->default_msg_cleanup = get_cleanup_mode(value, 1);
> > +	} else
> >  		return error(_("invalid key: %s"), key);
> >  
> >  	if (!error_flag)
> > @@ -2770,6 +2791,11 @@ static int save_opts(struct replay_opts *opts)
> >  		res |= git_config_set_in_file_gently(opts_file, "options.allow-rerere-auto",
> >  						     opts->allow_rerere_auto == RERERE_AUTOUPDATE ?
> >  						     "true" : "false");
> > +
> > +	if (opts->explicit_cleanup)
> > +		res |= git_config_set_in_file_gently(opts_file,
> > +				"options.default-msg-cleanup",
> > +				describe_cleanup_mode(opts->default_msg_cleanup));
> >  	return res;
> >  }
> >  
> > -- 
> > 2.21.0
> > 

^ permalink raw reply	[flat|nested] 105+ messages in thread

end of thread, other threads:[~2019-04-18 17:21 UTC | newest]

Thread overview: 105+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-11-14  5:24 [RFC PATCH 0/2] Fix scissors bug during merge conflict Denton Liu
2018-11-14  5:24 ` [RFC PATCH 1/2] commit: don't add scissors line if one exists Denton Liu
2018-11-14  8:06   ` Junio C Hamano
2018-11-14 18:06     ` Denton Liu
2018-11-16  3:32       ` Junio C Hamano
2018-11-14  5:25 ` [RFC PATCH 2/2] merge: add scissors line on merge conflict Denton Liu
2018-11-14  7:52 ` [RFC PATCH 0/2] Fix scissors bug during " Junio C Hamano
2018-11-14  8:10   ` Denton Liu
2018-11-16 15:19 ` [PATCH v2 " Denton Liu
2018-11-16 15:20   ` [PATCH v2 2/2] merge: add scissors line on " Denton Liu
2018-11-17 23:32   ` [PATCH v3 0/1] Fix scissors bug during " Denton Liu
2018-11-17 23:32     ` [PATCH v3 1/1] merge: add scissors line on " Denton Liu
2018-11-18 14:18       ` SZEDER Gábor
2018-11-18  6:54     ` [PATCH v3 0/1] Fix scissors bug during " Junio C Hamano
2018-11-21  3:13     ` [PATCH v4 0/2] " Denton Liu
2018-11-21  3:13       ` [PATCH v4 1/2] t7600: clean up 'merge --squash c3 with c7' test Denton Liu
2018-11-21  3:13       ` [PATCH v4 2/2] merge: add scissors line on merge conflict Denton Liu
2018-11-21  9:38       ` [PATCH v4 0/2] Fix scissors bug during " Junio C Hamano
2018-11-22  1:10         ` Denton Liu
2018-11-24  2:05           ` Junio C Hamano
2018-12-25 13:55       ` [PATCH v5 0/4] Add git-merge --cleanup support Denton Liu
2018-12-25 13:55         ` [PATCH v5 1/4] commit: extract cleanup_mode functions to sequencer Denton Liu
2018-12-25 13:56         ` [PATCH v5 2/4] t7600: clean up 'merge --squash c3 with c7' test Denton Liu
2018-12-25 13:56         ` [PATCH v5 3/4] merge: cleanup messages like commit Denton Liu
2018-12-25 13:56         ` [PATCH v5 4/4] merge: add scissors line on merge conflict Denton Liu
2019-01-23  5:06         ` [PATCH v6 0/4] Add git-merge --cleanup support Denton Liu
2019-01-23  5:06           ` [PATCH v6 1/4] commit: extract cleanup_mode functions to sequencer Denton Liu
2019-01-23  5:06           ` [PATCH v6 2/4] t7600: clean up 'merge --squash c3 with c7' test Denton Liu
2019-01-23  5:06           ` [PATCH v6 3/4] merge: cleanup messages like commit Denton Liu
2019-01-23  5:06           ` [PATCH v6 4/4] merge: add scissors line on merge conflict Denton Liu
2019-03-11  3:42           ` [PATCH v7 0/8] Fix scissors bug during conflict Denton Liu
2019-03-11  3:42             ` [PATCH v7 1/8] t7600: clean up 'merge --squash c3 with c7' test Denton Liu
2019-03-12  1:03               ` Junio C Hamano
2019-03-11  3:42             ` [PATCH v7 2/8] t3507: cleanup space after redirection operators Denton Liu
2019-03-11  3:42             ` [PATCH v7 3/8] commit: extract cleanup_mode functions to sequencer Denton Liu
2019-03-11  3:42             ` [PATCH v7 4/8] sequencer.c: remove duplicate code Denton Liu
2019-03-11 16:45               ` Phillip Wood
2019-03-11  3:42             ` [PATCH v7 5/8] merge: cleanup messages like commit Denton Liu
2019-03-11  5:49               ` Eric Sunshine
2019-03-11 10:14                 ` Phillip Wood
2019-03-11 17:00                   ` Eric Sunshine
2019-03-11 16:58               ` Phillip Wood
2019-03-12  5:50                 ` Junio C Hamano
2019-03-11  3:42             ` [PATCH v7 6/8] merge: add scissors line on merge conflict Denton Liu
2019-03-11  5:55               ` Eric Sunshine
2019-03-11  3:42             ` [PATCH v7 7/8] sequencer.c: define get_config_from_cleanup Denton Liu
2019-03-11  6:19               ` Eric Sunshine
2019-03-12  6:29               ` Junio C Hamano
2019-03-11  3:42             ` [PATCH v7 8/8] cherry-pick/revert: add scissors line on merge conflict Denton Liu
2019-03-12 11:11               ` Phillip Wood
2019-03-11  6:44             ` [PATCH v7 0/8] Fix scissors bug during conflict Junio C Hamano
2019-03-17 10:15             ` [PATCH v8 00/11] " Denton Liu
2019-03-17 10:15               ` [PATCH v8 01/11] t7600: clean up style Denton Liu
2019-03-17 10:15               ` [PATCH v8 02/11] t3507: cleanup space after redirection operators Denton Liu
2019-03-17 10:15               ` [PATCH v8 03/11] t7604: refactor out Git commands upstream of pipe Denton Liu
2019-03-17 10:16               ` [PATCH v8 04/11] t7502: clean up test style Denton Liu
2019-03-17 10:16               ` [PATCH v8 05/11] commit: extract cleanup_mode functions to sequencer Denton Liu
2019-03-17 10:16               ` [PATCH v8 06/11] parse-options.h: extract common --cleanup option Denton Liu
2019-03-17 10:16               ` [PATCH v8 07/11] sequencer.c: remove duplicate code Denton Liu
2019-03-17 10:16               ` [PATCH v8 08/11] merge: cleanup messages like commit Denton Liu
2019-03-19 11:13                 ` Phillip Wood
2019-03-20  6:32                   ` Denton Liu
2019-03-17 10:16               ` [PATCH v8 09/11] merge: add scissors line on merge conflict Denton Liu
2019-03-17 10:16               ` [PATCH v8 10/11] sequencer.c: define describe_cleanup_mode Denton Liu
2019-03-18 20:04                 ` Eric Sunshine
2019-03-18 20:30                   ` Denton Liu
2019-03-18 20:32                     ` Eric Sunshine
2019-03-19  0:55                   ` Ramsay Jones
2019-03-17 10:16               ` [PATCH v8 11/11] cherry-pick/revert: add scissors line on merge conflict Denton Liu
2019-03-17 13:05               ` [PATCH v8 00/11] Fix scissors bug during conflict SZEDER Gábor
2019-03-18  3:02                 ` Denton Liu
2019-03-18  6:35                 ` Junio C Hamano
2019-03-18  8:03                   ` Denton Liu
2019-03-18  8:25                     ` Junio C Hamano
2019-03-21  6:53               ` [PATCH v9 " Denton Liu
2019-03-21  6:53                 ` [PATCH v9 01/11] t7600: clean up style Denton Liu
2019-03-21  6:53                 ` [PATCH v9 02/11] t3507: " Denton Liu
2019-03-21  6:53                 ` [PATCH v9 03/11] t7604: " Denton Liu
2019-03-21  6:53                 ` [PATCH v9 04/11] t7502: " Denton Liu
2019-03-21  6:53                 ` [PATCH v9 05/11] commit: extract cleanup_mode functions to sequencer Denton Liu
2019-03-21  6:53                 ` [PATCH v9 06/11] parse-options.h: extract common --cleanup option Denton Liu
2019-03-21  6:53                 ` [PATCH v9 07/11] sequencer.c: remove duplicate code Denton Liu
2019-03-26 10:44                   ` Phillip Wood
2019-03-21  6:53                 ` [PATCH v9 08/11] merge: cleanup messages like commit Denton Liu
2019-03-21  6:53                 ` [PATCH v9 09/11] merge: add scissors line on merge conflict Denton Liu
2019-03-21  6:54                 ` [PATCH v9 10/11] sequencer.c: define describe_cleanup_mode Denton Liu
2019-03-21  6:54                 ` [PATCH v9 11/11] cherry-pick/revert: add scissors line on merge conflict Denton Liu
2019-04-17 10:23                 ` [PATCH v10 00/10] Fix scissors bug during conflict Phillip Wood
2019-04-17 10:23                   ` [PATCH v10 01/10] t7600: clean up style Phillip Wood
2019-04-17 10:23                   ` [PATCH v10 02/10] t3507: " Phillip Wood
2019-04-17 10:23                   ` [PATCH v10 03/10] t7604: " Phillip Wood
2019-04-17 10:23                   ` [PATCH v10 04/10] t7502: " Phillip Wood
2019-04-17 10:23                   ` [PATCH v10 05/10] commit: extract cleanup_mode functions to sequencer Phillip Wood
2019-04-17 10:23                   ` [PATCH v10 06/10] parse-options.h: extract common --cleanup option Phillip Wood
2019-04-17 10:23                   ` [PATCH v10 07/10] merge: cleanup messages like commit Phillip Wood
2019-04-17 10:23                   ` [PATCH v10 08/10] merge: add scissors line on merge conflict Phillip Wood
2019-04-17 10:23                   ` [PATCH v10 09/10] sequencer.c: save and restore cleanup mode Phillip Wood
2019-04-17 17:02                     ` Denton Liu
2019-04-17 19:53                       ` Phillip Wood
2019-04-18 17:21                       ` Denton Liu
2019-04-17 10:23                   ` [PATCH v10 10/10] cherry-pick/revert: add scissors line on merge conflict Phillip Wood
2019-04-18  5:19                   ` [PATCH v10 00/10] Fix scissors bug during conflict Junio C Hamano
2019-04-18  9:14                     ` Phillip Wood
     [not found] ` <cover.1542380865.git.liu.denton@gmail.com>
2018-11-16 15:19   ` [PATCH v2 1/2] commit: don't add scissors line if one exists in MERGE_MSG Denton Liu
2018-11-17  8:06     ` Junio C Hamano

git@vger.kernel.org list mirror (unofficial, one of many)

This inbox may be cloned and mirrored by anyone:

	git clone --mirror https://public-inbox.org/git
	git clone --mirror http://ou63pmih66umazou.onion/git
	git clone --mirror http://czquwvybam4bgbro.onion/git
	git clone --mirror http://hjrcffqmbrq6wope.onion/git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V1 git git/ https://public-inbox.org/git \
		git@vger.kernel.org
	public-inbox-index git

Example config snippet for mirrors.
Newsgroups are available over NNTP:
	nntp://news.public-inbox.org/inbox.comp.version-control.git
	nntp://ou63pmih66umazou.onion/inbox.comp.version-control.git
	nntp://czquwvybam4bgbro.onion/inbox.comp.version-control.git
	nntp://hjrcffqmbrq6wope.onion/inbox.comp.version-control.git
	nntp://news.gmane.io/gmane.comp.version-control.git
 note: .onion URLs require Tor: https://www.torproject.org/

code repositories for the project(s) associated with this inbox:

	https://80x24.org/mirrors/git.git

AGPL code for this site: git clone https://public-inbox.org/public-inbox.git