All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/26] git-log: implement new --diff-merge options
@ 2020-11-01 19:33 Sergey Organov
  2020-11-01 19:33 ` [PATCH 01/26] revision: factor out parsing of diff-merge related options Sergey Organov
                   ` (29 more replies)
  0 siblings, 30 replies; 232+ messages in thread
From: Sergey Organov @ 2020-11-01 19:33 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, git, Sergey Organov

These patch series implement new set of options governing the diff output
of merge commits, all under the umbrella of the single --diff-merges=<mode>
option. Most of the new options being synonyms for -m/-c/--cc options,
there is also additional functionality provided, allowing to get the format
of "-p --first-parent" without change in history traversal that
--first-parent option causes.

The net result of these series are the following new options:

--diff-merges=	 |  old equivalent
-----------------+----------------
first-parent     | --first-parent (only format implications)
separate         | -m
combined         | -c
dense-combined   | --cc

The series also cleanup logic of handling of diff merges options and fix an
issue found in the original implementation where logically mutually
exclusive options -m/-c/--cc failed to actually override each other.

The series start with the set of pure refactoring commits that are expected
to introduce no functional changes. These are all commits up to and
including:

"diff-merges: revise revs->diff flag handling"

The aim of these commits is to isolate options handling for diff merges so
that it could be easily understood and tweaked to ease introduction of the
new options.

Then the fix of -m/-c/-cc overriding issue follows, starting with a failing
test and followed by the fix.

Then follows a little bit of additional refactoring in order to prepare for
introduction of the new options, and finally the series are finished by the
implementation, testing, and documentation update for the new options.

Sergey Organov (26):
  revision: factor out parsing of diff-merge related options
  revision: factor out setup of diff-merge related settings
  revision: factor out initialization of diff-merge related settings
  revision: provide implementation for diff merges tweaks
  revision: move diff merges functions to its own diff-merges.c
  diff-merges: rename all functions to have common prefix
  diff-merges: move checks for first_parent_only out of the module
  diff-merges: rename diff_merges_default_to_enable() to match semantics
  diff-merges: re-arrange functions to match the order they are called
    in
  diff-merges: new function diff_merges_suppress()
  diff-merges: new function diff_merges_set_dense_combined_if_unset()
  diff-merges: introduce revs->first_parent_merges flag
  diff-merges: revise revs->diff flag handling
  t4013: support test_expect_failure through ':failure' magic
  t4013: add tests for -m failing to override -c/--cc
  diff-merges: fix -m to properly override -c/--cc
  diff-merges: split 'ignore_merges' field
  diff-merges: group diff-merge flags next to each other inside
    'rev_info'
  diff-merges: get rid of now empty diff_merges_init_revs()
  diff-merges: refactor opt settings into separate functions
  diff-merges: make -m/-c/--cc explicitly mutually exclusive
  diff-merges: implement new values for --diff-merges
  t4013: add test for --diff-merges=first-parent
  doc/git-log: describe new --diff-merges options
  doc/diff-generate-patch: mention new --diff-merges option
  doc/rev-list-options: document --first-parent implies
    --diff-merges=first-parent

 Documentation/diff-generate-patch.txt         |   6 +-
 Documentation/git-log.txt                     |  79 ++++---
 Documentation/rev-list-options.txt            |   3 +
 Makefile                                      |   1 +
 builtin/diff-files.c                          |   5 +-
 builtin/diff.c                                |   9 +-
 builtin/log.c                                 |  18 +-
 builtin/merge.c                               |   3 +-
 diff-merges.c                                 | 120 +++++++++++
 diff-merges.h                                 |  18 ++
 fmt-merge-msg.c                               |   3 +-
 log-tree.c                                    |  17 +-
 revision.c                                    |  38 +---
 revision.h                                    |   7 +-
 t/t4013-diff-various.sh                       |  10 +-
 t/t4013/diff.log_--cc_-m_-p_master            | 200 ++++++++++++++++++
 t/t4013/diff.log_-c_-m_-p_master              | 200 ++++++++++++++++++
 ...f.log_-p_--diff-merges=first-parent_master | 137 ++++++++++++
 18 files changed, 774 insertions(+), 100 deletions(-)
 create mode 100644 diff-merges.c
 create mode 100644 diff-merges.h
 create mode 100644 t/t4013/diff.log_--cc_-m_-p_master
 create mode 100644 t/t4013/diff.log_-c_-m_-p_master
 create mode 100644 t/t4013/diff.log_-p_--diff-merges=first-parent_master

-- 
2.25.1


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

* [PATCH 01/26] revision: factor out parsing of diff-merge related options
  2020-11-01 19:33 [PATCH 00/26] git-log: implement new --diff-merge options Sergey Organov
@ 2020-11-01 19:33 ` Sergey Organov
  2020-11-01 19:33 ` [PATCH 02/26] revision: factor out setup of diff-merge related settings Sergey Organov
                   ` (28 subsequent siblings)
  29 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-11-01 19:33 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, git, Sergey Organov

Move all the parsing code related to diffing merges into new
parse_diff_merge_opts() function.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 revision.c | 66 ++++++++++++++++++++++++++++++++----------------------
 1 file changed, 39 insertions(+), 27 deletions(-)

diff --git a/revision.c b/revision.c
index aa6221204081..a09f4872acd7 100644
--- a/revision.c
+++ b/revision.c
@@ -2153,6 +2153,44 @@ static void add_message_grep(struct rev_info *revs, const char *pattern)
 	add_grep(revs, pattern, GREP_PATTERN_BODY);
 }
 
+static int parse_diff_merge_opts(struct rev_info *revs, const char **argv) {
+	int argcount;
+	const char *optarg;
+	const char *arg = argv[0];
+
+	if (!strcmp(arg, "-m")) {
+		/*
+		 * To "diff-index", "-m" means "match missing", and to the "log"
+		 * family of commands, it means "show full diff for merges". Set
+		 * both fields appropriately.
+		 */
+		revs->ignore_merges = 0;
+		revs->match_missing = 1;
+	} else if (!strcmp(arg, "-c")) {
+		revs->diff = 1;
+		revs->dense_combined_merges = 0;
+		revs->combine_merges = 1;
+	} else if (!strcmp(arg, "--cc")) {
+		revs->diff = 1;
+		revs->dense_combined_merges = 1;
+		revs->combine_merges = 1;
+	} else if (!strcmp(arg, "--no-diff-merges")) {
+		revs->ignore_merges = 1;
+	} else if (!strcmp(arg, "--combined-all-paths")) {
+		revs->diff = 1;
+		revs->combined_all_paths = 1;
+	} else if ((argcount = parse_long_opt("diff-merges", argv, &optarg))) {
+		if (!strcmp(optarg, "off")) {
+			revs->ignore_merges = 1;
+		} else {
+			die(_("unknown value for --diff-merges: %s"), optarg);
+		}
+	} else
+		return 0;
+
+	return 1;
+}
+
 static int handle_revision_opt(struct rev_info *revs, int argc, const char **argv,
 			       int *unkc, const char **unkv,
 			       const struct setup_revision_opt* opt)
@@ -2349,34 +2387,8 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
 		revs->diff = 1;
 		revs->diffopt.flags.recursive = 1;
 		revs->diffopt.flags.tree_in_recursive = 1;
-	} else if (!strcmp(arg, "-m")) {
-		/*
-		 * To "diff-index", "-m" means "match missing", and to the "log"
-		 * family of commands, it means "show full diff for merges". Set
-		 * both fields appropriately.
-		 */
-		revs->ignore_merges = 0;
-		revs->match_missing = 1;
-	} else if ((argcount = parse_long_opt("diff-merges", argv, &optarg))) {
-		if (!strcmp(optarg, "off")) {
-			revs->ignore_merges = 1;
-		} else {
-			die(_("unknown value for --diff-merges: %s"), optarg);
-		}
+	} else if ((argcount = parse_diff_merge_opts(revs, argv))) {
 		return argcount;
-	} else if (!strcmp(arg, "--no-diff-merges")) {
-		revs->ignore_merges = 1;
-	} else if (!strcmp(arg, "-c")) {
-		revs->diff = 1;
-		revs->dense_combined_merges = 0;
-		revs->combine_merges = 1;
-	} else if (!strcmp(arg, "--combined-all-paths")) {
-		revs->diff = 1;
-		revs->combined_all_paths = 1;
-	} else if (!strcmp(arg, "--cc")) {
-		revs->diff = 1;
-		revs->dense_combined_merges = 1;
-		revs->combine_merges = 1;
 	} else if (!strcmp(arg, "-v")) {
 		revs->verbose_header = 1;
 	} else if (!strcmp(arg, "--pretty")) {
-- 
2.25.1


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

* [PATCH 02/26] revision: factor out setup of diff-merge related settings
  2020-11-01 19:33 [PATCH 00/26] git-log: implement new --diff-merge options Sergey Organov
  2020-11-01 19:33 ` [PATCH 01/26] revision: factor out parsing of diff-merge related options Sergey Organov
@ 2020-11-01 19:33 ` Sergey Organov
  2020-11-01 19:33 ` [PATCH 03/26] revision: factor out initialization " Sergey Organov
                   ` (27 subsequent siblings)
  29 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-11-01 19:33 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, git, Sergey Organov

Move all the setting code related to diffing merges into new
setup_diff_merge_revs() function.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 revision.c | 18 ++++++++++++------
 1 file changed, 12 insertions(+), 6 deletions(-)

diff --git a/revision.c b/revision.c
index a09f4872acd7..739295bb9ff4 100644
--- a/revision.c
+++ b/revision.c
@@ -2191,6 +2191,16 @@ static int parse_diff_merge_opts(struct rev_info *revs, const char **argv) {
 	return 1;
 }
 
+static void setup_diff_merges_revs(struct rev_info *revs)
+{
+	if (revs->combine_merges && revs->ignore_merges < 0)
+		revs->ignore_merges = 0;
+	if (revs->ignore_merges < 0)
+		revs->ignore_merges = 1;
+	if (revs->combined_all_paths && !revs->combine_merges)
+		die("--combined-all-paths makes no sense without -c or --cc");
+}
+
 static int handle_revision_opt(struct rev_info *revs, int argc, const char **argv,
 			       int *unkc, const char **unkv,
 			       const struct setup_revision_opt* opt)
@@ -2885,12 +2895,8 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
 			copy_pathspec(&revs->diffopt.pathspec,
 				      &revs->prune_data);
 	}
-	if (revs->combine_merges && revs->ignore_merges < 0)
-		revs->ignore_merges = 0;
-	if (revs->ignore_merges < 0)
-		revs->ignore_merges = 1;
-	if (revs->combined_all_paths && !revs->combine_merges)
-		die("--combined-all-paths makes no sense without -c or --cc");
+
+	setup_diff_merges_revs(revs);
 
 	revs->diffopt.abbrev = revs->abbrev;
 
-- 
2.25.1


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

* [PATCH 03/26] revision: factor out initialization of diff-merge related settings
  2020-11-01 19:33 [PATCH 00/26] git-log: implement new --diff-merge options Sergey Organov
  2020-11-01 19:33 ` [PATCH 01/26] revision: factor out parsing of diff-merge related options Sergey Organov
  2020-11-01 19:33 ` [PATCH 02/26] revision: factor out setup of diff-merge related settings Sergey Organov
@ 2020-11-01 19:33 ` Sergey Organov
  2020-11-01 19:33 ` [PATCH 04/26] revision: provide implementation for diff merges tweaks Sergey Organov
                   ` (26 subsequent siblings)
  29 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-11-01 19:33 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, git, Sergey Organov

Move initialization code related to diffing merges into new
init_diff_merge_revs() function.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 revision.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/revision.c b/revision.c
index 739295bb9ff4..bc568fb79778 100644
--- a/revision.c
+++ b/revision.c
@@ -1805,6 +1805,8 @@ static int add_parents_only(struct rev_info *revs, const char *arg_, int flags,
 	return 1;
 }
 
+static void init_diff_merge_revs(struct rev_info *revs);
+
 void repo_init_revisions(struct repository *r,
 			 struct rev_info *revs,
 			 const char *prefix)
@@ -1813,7 +1815,7 @@ void repo_init_revisions(struct repository *r,
 
 	revs->repo = r;
 	revs->abbrev = DEFAULT_ABBREV;
-	revs->ignore_merges = -1;
+	init_diff_merge_revs(revs);
 	revs->simplify_history = 1;
 	revs->pruning.repo = r;
 	revs->pruning.flags.recursive = 1;
@@ -2153,6 +2155,10 @@ static void add_message_grep(struct rev_info *revs, const char *pattern)
 	add_grep(revs, pattern, GREP_PATTERN_BODY);
 }
 
+static void init_diff_merge_revs(struct rev_info *revs) {
+	revs->ignore_merges = -1;
+}
+
 static int parse_diff_merge_opts(struct rev_info *revs, const char **argv) {
 	int argcount;
 	const char *optarg;
-- 
2.25.1


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

* [PATCH 04/26] revision: provide implementation for diff merges tweaks
  2020-11-01 19:33 [PATCH 00/26] git-log: implement new --diff-merge options Sergey Organov
                   ` (2 preceding siblings ...)
  2020-11-01 19:33 ` [PATCH 03/26] revision: factor out initialization " Sergey Organov
@ 2020-11-01 19:33 ` Sergey Organov
  2020-11-01 19:33 ` [PATCH 05/26] revision: move diff merges functions to its own diff-merges.c Sergey Organov
                   ` (25 subsequent siblings)
  29 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-11-01 19:33 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, git, Sergey Organov

Use these implementations from show_setup_revisions_tweak() and
log_setup_revisions_tweak() in builtin/log.c.

This completes moving of management of diff merges parameters to a
single place, where we can finally observe them simultaneously.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 builtin/log.c | 13 ++-----------
 revision.c    | 17 +++++++++++++++++
 revision.h    |  3 +++
 3 files changed, 22 insertions(+), 11 deletions(-)

diff --git a/builtin/log.c b/builtin/log.c
index 0a7ed4bef92b..717855a49e90 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -598,15 +598,7 @@ static int show_tree_object(const struct object_id *oid,
 static void show_setup_revisions_tweak(struct rev_info *rev,
 				       struct setup_revision_opt *opt)
 {
-	if (rev->ignore_merges < 0) {
-		/* There was no "-m" variant on the command line */
-		rev->ignore_merges = 0;
-		if (!rev->first_parent_only && !rev->combine_merges) {
-			/* No "--first-parent", "-c", or "--cc" */
-			rev->combine_merges = 1;
-			rev->dense_combined_merges = 1;
-		}
-	}
+	rev_diff_merges_default_to_dense_combined(rev);
 	if (!rev->diffopt.output_format)
 		rev->diffopt.output_format = DIFF_FORMAT_PATCH;
 }
@@ -731,8 +723,7 @@ static void log_setup_revisions_tweak(struct rev_info *rev,
 	if (!rev->diffopt.output_format && rev->combine_merges)
 		rev->diffopt.output_format = DIFF_FORMAT_PATCH;
 
-	if (rev->first_parent_only && rev->ignore_merges < 0)
-		rev->ignore_merges = 0;
+	rev_diff_merges_first_parent_defaults_to_enable(rev);
 }
 
 int cmd_log(int argc, const char **argv, const char *prefix)
diff --git a/revision.c b/revision.c
index bc568fb79778..ce90c2991657 100644
--- a/revision.c
+++ b/revision.c
@@ -2207,6 +2207,23 @@ static void setup_diff_merges_revs(struct rev_info *revs)
 		die("--combined-all-paths makes no sense without -c or --cc");
 }
 
+void rev_diff_merges_first_parent_defaults_to_enable(struct rev_info *revs) {
+	if (revs->first_parent_only && revs->ignore_merges < 0)
+		revs->ignore_merges = 0;
+}
+
+void rev_diff_merges_default_to_dense_combined(struct rev_info *revs) {
+	if (revs->ignore_merges < 0) {
+		/* There was no "-m" variant on the command line */
+		revs->ignore_merges = 0;
+		if (!revs->first_parent_only && !revs->combine_merges) {
+			/* No "--first-parent", "-c", or "--cc" */
+			revs->combine_merges = 1;
+			revs->dense_combined_merges = 1;
+		}
+	}
+}
+
 static int handle_revision_opt(struct rev_info *revs, int argc, const char **argv,
 			       int *unkc, const char **unkv,
 			       const struct setup_revision_opt* opt)
diff --git a/revision.h b/revision.h
index f6bf860d19e5..3dd0229f4edc 100644
--- a/revision.h
+++ b/revision.h
@@ -456,4 +456,7 @@ int rewrite_parents(struct rev_info *revs,
  */
 struct commit_list *get_saved_parents(struct rev_info *revs, const struct commit *commit);
 
+void rev_diff_merges_default_to_dense_combined(struct rev_info *revs);
+void rev_diff_merges_first_parent_defaults_to_enable(struct rev_info *revs);
+
 #endif
-- 
2.25.1


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

* [PATCH 05/26] revision: move diff merges functions to its own diff-merges.c
  2020-11-01 19:33 [PATCH 00/26] git-log: implement new --diff-merge options Sergey Organov
                   ` (3 preceding siblings ...)
  2020-11-01 19:33 ` [PATCH 04/26] revision: provide implementation for diff merges tweaks Sergey Organov
@ 2020-11-01 19:33 ` Sergey Organov
  2020-11-01 19:33 ` [PATCH 06/26] diff-merges: rename all functions to have common prefix Sergey Organov
                   ` (24 subsequent siblings)
  29 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-11-01 19:33 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, git, Sergey Organov

Create separate diff-merges.c and diff-merges.h files, and move all
the code related to handling of diff merges there.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 Makefile      |  1 +
 builtin/log.c |  1 +
 diff-merges.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++
 diff-merges.h | 12 +++++++++
 revision.c    | 72 +--------------------------------------------------
 revision.h    |  3 ---
 6 files changed, 87 insertions(+), 74 deletions(-)
 create mode 100644 diff-merges.c
 create mode 100644 diff-merges.h

diff --git a/Makefile b/Makefile
index 1fb0ec17059a..d1347ef262cf 100644
--- a/Makefile
+++ b/Makefile
@@ -872,6 +872,7 @@ LIB_OBJS += date.o
 LIB_OBJS += decorate.o
 LIB_OBJS += delta-islands.o
 LIB_OBJS += diff-delta.o
+LIB_OBJS += diff-merges.o
 LIB_OBJS += diff-lib.o
 LIB_OBJS += diff-no-index.o
 LIB_OBJS += diff.o
diff --git a/builtin/log.c b/builtin/log.c
index 717855a49e90..ad3092fdd854 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -12,6 +12,7 @@
 #include "color.h"
 #include "commit.h"
 #include "diff.h"
+#include "diff-merges.h"
 #include "revision.h"
 #include "log-tree.h"
 #include "builtin.h"
diff --git a/diff-merges.c b/diff-merges.c
new file mode 100644
index 000000000000..8b9dd4ad5625
--- /dev/null
+++ b/diff-merges.c
@@ -0,0 +1,72 @@
+#include "diff-merges.h"
+
+#include "revision.h"
+
+void init_diff_merge_revs(struct rev_info *revs) {
+	revs->ignore_merges = -1;
+}
+
+int parse_diff_merge_opts(struct rev_info *revs, const char **argv) {
+	int argcount;
+	const char *optarg;
+	const char *arg = argv[0];
+
+	if (!strcmp(arg, "-m")) {
+		/*
+		 * To "diff-index", "-m" means "match missing", and to the "log"
+		 * family of commands, it means "show full diff for merges". Set
+		 * both fields appropriately.
+		 */
+		revs->ignore_merges = 0;
+		revs->match_missing = 1;
+	} else if (!strcmp(arg, "-c")) {
+		revs->diff = 1;
+		revs->dense_combined_merges = 0;
+		revs->combine_merges = 1;
+	} else if (!strcmp(arg, "--cc")) {
+		revs->diff = 1;
+		revs->dense_combined_merges = 1;
+		revs->combine_merges = 1;
+	} else if (!strcmp(arg, "--no-diff-merges")) {
+		revs->ignore_merges = 1;
+	} else if (!strcmp(arg, "--combined-all-paths")) {
+		revs->diff = 1;
+		revs->combined_all_paths = 1;
+	} else if ((argcount = parse_long_opt("diff-merges", argv, &optarg))) {
+		if (!strcmp(optarg, "off")) {
+			revs->ignore_merges = 1;
+		} else {
+			die(_("unknown value for --diff-merges: %s"), optarg);
+		}
+	} else
+		return 0;
+
+	return 1;
+}
+
+void setup_diff_merges_revs(struct rev_info *revs)
+{
+	if (revs->combine_merges && revs->ignore_merges < 0)
+		revs->ignore_merges = 0;
+	if (revs->ignore_merges < 0)
+		revs->ignore_merges = 1;
+	if (revs->combined_all_paths && !revs->combine_merges)
+		die("--combined-all-paths makes no sense without -c or --cc");
+}
+
+void rev_diff_merges_first_parent_defaults_to_enable(struct rev_info *revs) {
+	if (revs->first_parent_only && revs->ignore_merges < 0)
+		revs->ignore_merges = 0;
+}
+
+void rev_diff_merges_default_to_dense_combined(struct rev_info *revs) {
+	if (revs->ignore_merges < 0) {
+		/* There was no "-m" variant on the command line */
+		revs->ignore_merges = 0;
+		if (!revs->first_parent_only && !revs->combine_merges) {
+			/* No "--first-parent", "-c", or "--cc" */
+			revs->combine_merges = 1;
+			revs->dense_combined_merges = 1;
+		}
+	}
+}
diff --git a/diff-merges.h b/diff-merges.h
new file mode 100644
index 000000000000..e0cca3d935d3
--- /dev/null
+++ b/diff-merges.h
@@ -0,0 +1,12 @@
+#ifndef DIFF_MERGES_H
+#define DIFF_MERGES_H
+
+struct rev_info;
+
+void init_diff_merge_revs(struct rev_info *revs);
+int parse_diff_merge_opts(struct rev_info *revs, const char **argv);
+void setup_diff_merges_revs(struct rev_info *revs);
+void rev_diff_merges_default_to_dense_combined(struct rev_info *revs);
+void rev_diff_merges_first_parent_defaults_to_enable(struct rev_info *revs);
+
+#endif
diff --git a/revision.c b/revision.c
index ce90c2991657..4bc14a08a624 100644
--- a/revision.c
+++ b/revision.c
@@ -5,6 +5,7 @@
 #include "tree.h"
 #include "commit.h"
 #include "diff.h"
+#include "diff-merges.h"
 #include "refs.h"
 #include "revision.h"
 #include "repository.h"
@@ -1805,8 +1806,6 @@ static int add_parents_only(struct rev_info *revs, const char *arg_, int flags,
 	return 1;
 }
 
-static void init_diff_merge_revs(struct rev_info *revs);
-
 void repo_init_revisions(struct repository *r,
 			 struct rev_info *revs,
 			 const char *prefix)
@@ -2155,75 +2154,6 @@ static void add_message_grep(struct rev_info *revs, const char *pattern)
 	add_grep(revs, pattern, GREP_PATTERN_BODY);
 }
 
-static void init_diff_merge_revs(struct rev_info *revs) {
-	revs->ignore_merges = -1;
-}
-
-static int parse_diff_merge_opts(struct rev_info *revs, const char **argv) {
-	int argcount;
-	const char *optarg;
-	const char *arg = argv[0];
-
-	if (!strcmp(arg, "-m")) {
-		/*
-		 * To "diff-index", "-m" means "match missing", and to the "log"
-		 * family of commands, it means "show full diff for merges". Set
-		 * both fields appropriately.
-		 */
-		revs->ignore_merges = 0;
-		revs->match_missing = 1;
-	} else if (!strcmp(arg, "-c")) {
-		revs->diff = 1;
-		revs->dense_combined_merges = 0;
-		revs->combine_merges = 1;
-	} else if (!strcmp(arg, "--cc")) {
-		revs->diff = 1;
-		revs->dense_combined_merges = 1;
-		revs->combine_merges = 1;
-	} else if (!strcmp(arg, "--no-diff-merges")) {
-		revs->ignore_merges = 1;
-	} else if (!strcmp(arg, "--combined-all-paths")) {
-		revs->diff = 1;
-		revs->combined_all_paths = 1;
-	} else if ((argcount = parse_long_opt("diff-merges", argv, &optarg))) {
-		if (!strcmp(optarg, "off")) {
-			revs->ignore_merges = 1;
-		} else {
-			die(_("unknown value for --diff-merges: %s"), optarg);
-		}
-	} else
-		return 0;
-
-	return 1;
-}
-
-static void setup_diff_merges_revs(struct rev_info *revs)
-{
-	if (revs->combine_merges && revs->ignore_merges < 0)
-		revs->ignore_merges = 0;
-	if (revs->ignore_merges < 0)
-		revs->ignore_merges = 1;
-	if (revs->combined_all_paths && !revs->combine_merges)
-		die("--combined-all-paths makes no sense without -c or --cc");
-}
-
-void rev_diff_merges_first_parent_defaults_to_enable(struct rev_info *revs) {
-	if (revs->first_parent_only && revs->ignore_merges < 0)
-		revs->ignore_merges = 0;
-}
-
-void rev_diff_merges_default_to_dense_combined(struct rev_info *revs) {
-	if (revs->ignore_merges < 0) {
-		/* There was no "-m" variant on the command line */
-		revs->ignore_merges = 0;
-		if (!revs->first_parent_only && !revs->combine_merges) {
-			/* No "--first-parent", "-c", or "--cc" */
-			revs->combine_merges = 1;
-			revs->dense_combined_merges = 1;
-		}
-	}
-}
-
 static int handle_revision_opt(struct rev_info *revs, int argc, const char **argv,
 			       int *unkc, const char **unkv,
 			       const struct setup_revision_opt* opt)
diff --git a/revision.h b/revision.h
index 3dd0229f4edc..f6bf860d19e5 100644
--- a/revision.h
+++ b/revision.h
@@ -456,7 +456,4 @@ int rewrite_parents(struct rev_info *revs,
  */
 struct commit_list *get_saved_parents(struct rev_info *revs, const struct commit *commit);
 
-void rev_diff_merges_default_to_dense_combined(struct rev_info *revs);
-void rev_diff_merges_first_parent_defaults_to_enable(struct rev_info *revs);
-
 #endif
-- 
2.25.1


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

* [PATCH 06/26] diff-merges: rename all functions to have common prefix
  2020-11-01 19:33 [PATCH 00/26] git-log: implement new --diff-merge options Sergey Organov
                   ` (4 preceding siblings ...)
  2020-11-01 19:33 ` [PATCH 05/26] revision: move diff merges functions to its own diff-merges.c Sergey Organov
@ 2020-11-01 19:33 ` Sergey Organov
  2020-11-01 19:33 ` [PATCH 07/26] diff-merges: move checks for first_parent_only out of the module Sergey Organov
                   ` (23 subsequent siblings)
  29 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-11-01 19:33 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, git, Sergey Organov

Use the same "diff_merges" prefix for all the diff merges function
names.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 builtin/log.c |  4 ++--
 diff-merges.c | 10 +++++-----
 diff-merges.h | 15 ++++++++++-----
 revision.c    |  6 +++---
 4 files changed, 20 insertions(+), 15 deletions(-)

diff --git a/builtin/log.c b/builtin/log.c
index ad3092fdd854..77a7bba543ad 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -599,7 +599,7 @@ static int show_tree_object(const struct object_id *oid,
 static void show_setup_revisions_tweak(struct rev_info *rev,
 				       struct setup_revision_opt *opt)
 {
-	rev_diff_merges_default_to_dense_combined(rev);
+	diff_merges_default_to_dense_combined(rev);
 	if (!rev->diffopt.output_format)
 		rev->diffopt.output_format = DIFF_FORMAT_PATCH;
 }
@@ -724,7 +724,7 @@ static void log_setup_revisions_tweak(struct rev_info *rev,
 	if (!rev->diffopt.output_format && rev->combine_merges)
 		rev->diffopt.output_format = DIFF_FORMAT_PATCH;
 
-	rev_diff_merges_first_parent_defaults_to_enable(rev);
+	diff_merges_first_parent_defaults_to_enable(rev);
 }
 
 int cmd_log(int argc, const char **argv, const char *prefix)
diff --git a/diff-merges.c b/diff-merges.c
index 8b9dd4ad5625..85bf0b6d1d1d 100644
--- a/diff-merges.c
+++ b/diff-merges.c
@@ -2,11 +2,11 @@
 
 #include "revision.h"
 
-void init_diff_merge_revs(struct rev_info *revs) {
+void diff_merges_init_revs(struct rev_info *revs) {
 	revs->ignore_merges = -1;
 }
 
-int parse_diff_merge_opts(struct rev_info *revs, const char **argv) {
+int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {
 	int argcount;
 	const char *optarg;
 	const char *arg = argv[0];
@@ -44,7 +44,7 @@ int parse_diff_merge_opts(struct rev_info *revs, const char **argv) {
 	return 1;
 }
 
-void setup_diff_merges_revs(struct rev_info *revs)
+void diff_merges_setup_revs(struct rev_info *revs)
 {
 	if (revs->combine_merges && revs->ignore_merges < 0)
 		revs->ignore_merges = 0;
@@ -54,12 +54,12 @@ void setup_diff_merges_revs(struct rev_info *revs)
 		die("--combined-all-paths makes no sense without -c or --cc");
 }
 
-void rev_diff_merges_first_parent_defaults_to_enable(struct rev_info *revs) {
+void diff_merges_first_parent_defaults_to_enable(struct rev_info *revs) {
 	if (revs->first_parent_only && revs->ignore_merges < 0)
 		revs->ignore_merges = 0;
 }
 
-void rev_diff_merges_default_to_dense_combined(struct rev_info *revs) {
+void diff_merges_default_to_dense_combined(struct rev_info *revs) {
 	if (revs->ignore_merges < 0) {
 		/* There was no "-m" variant on the command line */
 		revs->ignore_merges = 0;
diff --git a/diff-merges.h b/diff-merges.h
index e0cca3d935d3..648c410497cb 100644
--- a/diff-merges.h
+++ b/diff-merges.h
@@ -3,10 +3,15 @@
 
 struct rev_info;
 
-void init_diff_merge_revs(struct rev_info *revs);
-int parse_diff_merge_opts(struct rev_info *revs, const char **argv);
-void setup_diff_merges_revs(struct rev_info *revs);
-void rev_diff_merges_default_to_dense_combined(struct rev_info *revs);
-void rev_diff_merges_first_parent_defaults_to_enable(struct rev_info *revs);
+void diff_merges_init_revs(struct rev_info *revs);
+
+int diff_merges_parse_opts(struct rev_info *revs, const char **argv);
+
+void diff_merges_setup_revs(struct rev_info *revs);
+
+void diff_merges_default_to_dense_combined(struct rev_info *revs);
+
+void diff_merges_first_parent_defaults_to_enable(struct rev_info *revs);
+
 
 #endif
diff --git a/revision.c b/revision.c
index 4bc14a08a624..5a0e3d6ad542 100644
--- a/revision.c
+++ b/revision.c
@@ -1814,7 +1814,7 @@ void repo_init_revisions(struct repository *r,
 
 	revs->repo = r;
 	revs->abbrev = DEFAULT_ABBREV;
-	init_diff_merge_revs(revs);
+	diff_merges_init_revs(revs);
 	revs->simplify_history = 1;
 	revs->pruning.repo = r;
 	revs->pruning.flags.recursive = 1;
@@ -2350,7 +2350,7 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
 		revs->diff = 1;
 		revs->diffopt.flags.recursive = 1;
 		revs->diffopt.flags.tree_in_recursive = 1;
-	} else if ((argcount = parse_diff_merge_opts(revs, argv))) {
+	} else if ((argcount = diff_merges_parse_opts(revs, argv))) {
 		return argcount;
 	} else if (!strcmp(arg, "-v")) {
 		revs->verbose_header = 1;
@@ -2849,7 +2849,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
 				      &revs->prune_data);
 	}
 
-	setup_diff_merges_revs(revs);
+	diff_merges_setup_revs(revs);
 
 	revs->diffopt.abbrev = revs->abbrev;
 
-- 
2.25.1


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

* [PATCH 07/26] diff-merges: move checks for first_parent_only out of the module
  2020-11-01 19:33 [PATCH 00/26] git-log: implement new --diff-merge options Sergey Organov
                   ` (5 preceding siblings ...)
  2020-11-01 19:33 ` [PATCH 06/26] diff-merges: rename all functions to have common prefix Sergey Organov
@ 2020-11-01 19:33 ` Sergey Organov
  2020-11-01 19:33 ` [PATCH 08/26] diff-merges: rename diff_merges_default_to_enable() to match semantics Sergey Organov
                   ` (22 subsequent siblings)
  29 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-11-01 19:33 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, git, Sergey Organov

The checks for first_parent_only don't in fact belong to this module,
as the primary purpose of this flag is history traversal limiting, so
get it out of this module and rename the

diff_merges_first_parent_defaults_to_enable()

to

diff_merges_default_to_enable()

to match new semantics.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 builtin/log.c |  8 ++++++--
 diff-merges.c | 10 ++++------
 diff-merges.h |  2 +-
 3 files changed, 11 insertions(+), 9 deletions(-)

diff --git a/builtin/log.c b/builtin/log.c
index 77a7bba543ad..a7791c003c91 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -599,7 +599,10 @@ static int show_tree_object(const struct object_id *oid,
 static void show_setup_revisions_tweak(struct rev_info *rev,
 				       struct setup_revision_opt *opt)
 {
-	diff_merges_default_to_dense_combined(rev);
+	if (rev->first_parent_only)
+		diff_merges_default_to_enable(rev);
+	else
+		diff_merges_default_to_dense_combined(rev);
 	if (!rev->diffopt.output_format)
 		rev->diffopt.output_format = DIFF_FORMAT_PATCH;
 }
@@ -724,7 +727,8 @@ static void log_setup_revisions_tweak(struct rev_info *rev,
 	if (!rev->diffopt.output_format && rev->combine_merges)
 		rev->diffopt.output_format = DIFF_FORMAT_PATCH;
 
-	diff_merges_first_parent_defaults_to_enable(rev);
+	if (rev->first_parent_only)
+		diff_merges_default_to_enable(rev);
 }
 
 int cmd_log(int argc, const char **argv, const char *prefix)
diff --git a/diff-merges.c b/diff-merges.c
index 85bf0b6d1d1d..9dd472803d15 100644
--- a/diff-merges.c
+++ b/diff-merges.c
@@ -54,17 +54,15 @@ void diff_merges_setup_revs(struct rev_info *revs)
 		die("--combined-all-paths makes no sense without -c or --cc");
 }
 
-void diff_merges_first_parent_defaults_to_enable(struct rev_info *revs) {
-	if (revs->first_parent_only && revs->ignore_merges < 0)
+void diff_merges_default_to_enable(struct rev_info *revs) {
+	if (revs->ignore_merges < 0)		/* No -m */
 		revs->ignore_merges = 0;
 }
 
 void diff_merges_default_to_dense_combined(struct rev_info *revs) {
-	if (revs->ignore_merges < 0) {
-		/* There was no "-m" variant on the command line */
+	if (revs->ignore_merges < 0) {		/* No -m */
 		revs->ignore_merges = 0;
-		if (!revs->first_parent_only && !revs->combine_merges) {
-			/* No "--first-parent", "-c", or "--cc" */
+		if (!revs->combine_merges) {	/* No -c/--cc" */
 			revs->combine_merges = 1;
 			revs->dense_combined_merges = 1;
 		}
diff --git a/diff-merges.h b/diff-merges.h
index 648c410497cb..cf411414898d 100644
--- a/diff-merges.h
+++ b/diff-merges.h
@@ -11,7 +11,7 @@ void diff_merges_setup_revs(struct rev_info *revs);
 
 void diff_merges_default_to_dense_combined(struct rev_info *revs);
 
-void diff_merges_first_parent_defaults_to_enable(struct rev_info *revs);
+void diff_merges_default_to_enable(struct rev_info *revs);
 
 
 #endif
-- 
2.25.1


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

* [PATCH 08/26] diff-merges: rename diff_merges_default_to_enable() to match semantics
  2020-11-01 19:33 [PATCH 00/26] git-log: implement new --diff-merge options Sergey Organov
                   ` (6 preceding siblings ...)
  2020-11-01 19:33 ` [PATCH 07/26] diff-merges: move checks for first_parent_only out of the module Sergey Organov
@ 2020-11-01 19:33 ` Sergey Organov
  2020-11-01 19:33 ` [PATCH 09/26] diff-merges: re-arrange functions to match the order they are called in Sergey Organov
                   ` (21 subsequent siblings)
  29 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-11-01 19:33 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, git, Sergey Organov

Rename diff_merges_default_to_enable() to
diff_merges_default_to_first_parent() to match its semantics.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 builtin/log.c | 4 ++--
 diff-merges.c | 2 +-
 diff-merges.h | 2 +-
 3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/builtin/log.c b/builtin/log.c
index a7791c003c91..63875c3aeec9 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -600,7 +600,7 @@ static void show_setup_revisions_tweak(struct rev_info *rev,
 				       struct setup_revision_opt *opt)
 {
 	if (rev->first_parent_only)
-		diff_merges_default_to_enable(rev);
+		diff_merges_default_to_first_parent(rev);
 	else
 		diff_merges_default_to_dense_combined(rev);
 	if (!rev->diffopt.output_format)
@@ -728,7 +728,7 @@ static void log_setup_revisions_tweak(struct rev_info *rev,
 		rev->diffopt.output_format = DIFF_FORMAT_PATCH;
 
 	if (rev->first_parent_only)
-		diff_merges_default_to_enable(rev);
+		diff_merges_default_to_first_parent(rev);
 }
 
 int cmd_log(int argc, const char **argv, const char *prefix)
diff --git a/diff-merges.c b/diff-merges.c
index 9dd472803d15..bb08a92e3b36 100644
--- a/diff-merges.c
+++ b/diff-merges.c
@@ -54,7 +54,7 @@ void diff_merges_setup_revs(struct rev_info *revs)
 		die("--combined-all-paths makes no sense without -c or --cc");
 }
 
-void diff_merges_default_to_enable(struct rev_info *revs) {
+void diff_merges_default_to_first_parent(struct rev_info *revs) {
 	if (revs->ignore_merges < 0)		/* No -m */
 		revs->ignore_merges = 0;
 }
diff --git a/diff-merges.h b/diff-merges.h
index cf411414898d..20b727bd734f 100644
--- a/diff-merges.h
+++ b/diff-merges.h
@@ -11,7 +11,7 @@ void diff_merges_setup_revs(struct rev_info *revs);
 
 void diff_merges_default_to_dense_combined(struct rev_info *revs);
 
-void diff_merges_default_to_enable(struct rev_info *revs);
+void diff_merges_default_to_first_parent(struct rev_info *revs);
 
 
 #endif
-- 
2.25.1


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

* [PATCH 09/26] diff-merges: re-arrange functions to match the order they are called in
  2020-11-01 19:33 [PATCH 00/26] git-log: implement new --diff-merge options Sergey Organov
                   ` (7 preceding siblings ...)
  2020-11-01 19:33 ` [PATCH 08/26] diff-merges: rename diff_merges_default_to_enable() to match semantics Sergey Organov
@ 2020-11-01 19:33 ` Sergey Organov
  2020-11-01 19:33 ` [PATCH 10/26] diff-merges: new function diff_merges_suppress() Sergey Organov
                   ` (20 subsequent siblings)
  29 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-11-01 19:33 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, git, Sergey Organov

For clarity, define public functions in the order they are called, to
make logic inter-dependencies easier to grok.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 diff-merges.c | 24 ++++++++++++++----------
 diff-merges.h |  7 +++----
 2 files changed, 17 insertions(+), 14 deletions(-)

diff --git a/diff-merges.c b/diff-merges.c
index bb08a92e3b36..8536941e0b56 100644
--- a/diff-merges.c
+++ b/diff-merges.c
@@ -2,6 +2,10 @@
 
 #include "revision.h"
 
+/*
+ * Public functions. They are in the order they are called.
+ */
+
 void diff_merges_init_revs(struct rev_info *revs) {
 	revs->ignore_merges = -1;
 }
@@ -44,16 +48,6 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {
 	return 1;
 }
 
-void diff_merges_setup_revs(struct rev_info *revs)
-{
-	if (revs->combine_merges && revs->ignore_merges < 0)
-		revs->ignore_merges = 0;
-	if (revs->ignore_merges < 0)
-		revs->ignore_merges = 1;
-	if (revs->combined_all_paths && !revs->combine_merges)
-		die("--combined-all-paths makes no sense without -c or --cc");
-}
-
 void diff_merges_default_to_first_parent(struct rev_info *revs) {
 	if (revs->ignore_merges < 0)		/* No -m */
 		revs->ignore_merges = 0;
@@ -68,3 +62,13 @@ void diff_merges_default_to_dense_combined(struct rev_info *revs) {
 		}
 	}
 }
+
+void diff_merges_setup_revs(struct rev_info *revs)
+{
+	if (revs->combine_merges && revs->ignore_merges < 0)
+		revs->ignore_merges = 0;
+	if (revs->ignore_merges < 0)
+		revs->ignore_merges = 1;
+	if (revs->combined_all_paths && !revs->combine_merges)
+		die("--combined-all-paths makes no sense without -c or --cc");
+}
diff --git a/diff-merges.h b/diff-merges.h
index 20b727bd734f..4b023c385d00 100644
--- a/diff-merges.h
+++ b/diff-merges.h
@@ -7,11 +7,10 @@ void diff_merges_init_revs(struct rev_info *revs);
 
 int diff_merges_parse_opts(struct rev_info *revs, const char **argv);
 
-void diff_merges_setup_revs(struct rev_info *revs);
-
-void diff_merges_default_to_dense_combined(struct rev_info *revs);
-
 void diff_merges_default_to_first_parent(struct rev_info *revs);
 
+void diff_merges_default_to_dense_combined(struct rev_info *revs);
+
+void diff_merges_setup_revs(struct rev_info *revs);
 
 #endif
-- 
2.25.1


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

* [PATCH 10/26] diff-merges: new function diff_merges_suppress()
  2020-11-01 19:33 [PATCH 00/26] git-log: implement new --diff-merge options Sergey Organov
                   ` (8 preceding siblings ...)
  2020-11-01 19:33 ` [PATCH 09/26] diff-merges: re-arrange functions to match the order they are called in Sergey Organov
@ 2020-11-01 19:33 ` Sergey Organov
  2020-12-03  5:52   ` Elijah Newren
  2020-11-01 19:33 ` [PATCH 11/26] diff-merges: new function diff_merges_set_dense_combined_if_unset() Sergey Organov
                   ` (19 subsequent siblings)
  29 siblings, 1 reply; 232+ messages in thread
From: Sergey Organov @ 2020-11-01 19:33 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, git, Sergey Organov

This function sets all the relevant flags to disabled state, so that
no code that checks only one of them get it wrong.

Then we call this new function everywhere where diff merges output
suppression is needed.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 builtin/merge.c |  3 ++-
 diff-merges.c   | 18 ++++++++++++++----
 diff-merges.h   |  2 ++
 fmt-merge-msg.c |  3 ++-
 4 files changed, 20 insertions(+), 6 deletions(-)

diff --git a/builtin/merge.c b/builtin/merge.c
index 9d5359edc2f7..1f7b69982b40 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -14,6 +14,7 @@
 #include "lockfile.h"
 #include "run-command.h"
 #include "diff.h"
+#include "diff-merges.h"
 #include "refs.h"
 #include "refspec.h"
 #include "commit.h"
@@ -400,7 +401,7 @@ static void squash_message(struct commit *commit, struct commit_list *remotehead
 	printf(_("Squash commit -- not updating HEAD\n"));
 
 	repo_init_revisions(the_repository, &rev, NULL);
-	rev.ignore_merges = 1;
+	diff_merges_suppress(&rev);
 	rev.commit_format = CMIT_FMT_MEDIUM;
 
 	commit->object.flags |= UNINTERESTING;
diff --git a/diff-merges.c b/diff-merges.c
index 8536941e0b56..25bd9b12e667 100644
--- a/diff-merges.c
+++ b/diff-merges.c
@@ -2,6 +2,13 @@
 
 #include "revision.h"
 
+static void suppress(struct rev_info *revs) {
+	revs->ignore_merges = 1;
+	revs->first_parent_merges = 0;
+	revs->combine_merges = 0;
+	revs->dense_combined_merges = 0;
+}
+
 /*
  * Public functions. They are in the order they are called.
  */
@@ -29,16 +36,15 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {
 		revs->combine_merges = 1;
 	} else if (!strcmp(arg, "--cc")) {
 		revs->diff = 1;
-		revs->dense_combined_merges = 1;
-		revs->combine_merges = 1;
+		set_dense_combined(revs);
 	} else if (!strcmp(arg, "--no-diff-merges")) {
-		revs->ignore_merges = 1;
+		suppress(revs);
 	} else if (!strcmp(arg, "--combined-all-paths")) {
 		revs->diff = 1;
 		revs->combined_all_paths = 1;
 	} else if ((argcount = parse_long_opt("diff-merges", argv, &optarg))) {
 		if (!strcmp(optarg, "off")) {
-			revs->ignore_merges = 1;
+			suppress(revs);
 		} else {
 			die(_("unknown value for --diff-merges: %s"), optarg);
 		}
@@ -48,6 +54,10 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {
 	return 1;
 }
 
+void diff_merges_suppress(struct rev_info *revs) {
+	suppress(revs);
+}
+
 void diff_merges_default_to_first_parent(struct rev_info *revs) {
 	if (revs->ignore_merges < 0)		/* No -m */
 		revs->ignore_merges = 0;
diff --git a/diff-merges.h b/diff-merges.h
index 4b023c385d00..32720bc9b40f 100644
--- a/diff-merges.h
+++ b/diff-merges.h
@@ -7,6 +7,8 @@ void diff_merges_init_revs(struct rev_info *revs);
 
 int diff_merges_parse_opts(struct rev_info *revs, const char **argv);
 
+void diff_merges_suppress(struct rev_info *revs);
+
 void diff_merges_default_to_first_parent(struct rev_info *revs);
 
 void diff_merges_default_to_dense_combined(struct rev_info *revs);
diff --git a/fmt-merge-msg.c b/fmt-merge-msg.c
index bd22e1ea8865..abc3403fb820 100644
--- a/fmt-merge-msg.c
+++ b/fmt-merge-msg.c
@@ -2,6 +2,7 @@
 #include "refs.h"
 #include "object-store.h"
 #include "diff.h"
+#include "diff-merges.h"
 #include "revision.h"
 #include "tag.h"
 #include "string-list.h"
@@ -668,7 +669,7 @@ int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
 		head = lookup_commit_or_die(&head_oid, "HEAD");
 		repo_init_revisions(the_repository, &rev, NULL);
 		rev.commit_format = CMIT_FMT_ONELINE;
-		rev.ignore_merges = 1;
+		diff_merges_suppress(&rev);
 		rev.limited = 1;
 
 		strbuf_complete_line(out);
-- 
2.25.1


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

* [PATCH 11/26] diff-merges: new function diff_merges_set_dense_combined_if_unset()
  2020-11-01 19:33 [PATCH 00/26] git-log: implement new --diff-merge options Sergey Organov
                   ` (9 preceding siblings ...)
  2020-11-01 19:33 ` [PATCH 10/26] diff-merges: new function diff_merges_suppress() Sergey Organov
@ 2020-11-01 19:33 ` Sergey Organov
  2020-11-01 19:33 ` [PATCH 12/26] diff-merges: introduce revs->first_parent_merges flag Sergey Organov
                   ` (18 subsequent siblings)
  29 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-11-01 19:33 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, git, Sergey Organov

Call it where given functionality is needed instead of direct
checking/tweaking of diff merges related fields.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 builtin/diff-files.c |  5 +++--
 builtin/diff.c       |  9 +++++----
 diff-merges.c        | 11 +++++++++++
 diff-merges.h        |  2 ++
 4 files changed, 21 insertions(+), 6 deletions(-)

diff --git a/builtin/diff-files.c b/builtin/diff-files.c
index 1e352dd8f77c..4742a4559b21 100644
--- a/builtin/diff-files.c
+++ b/builtin/diff-files.c
@@ -7,6 +7,7 @@
 #include "cache.h"
 #include "config.h"
 #include "diff.h"
+#include "diff-merges.h"
 #include "commit.h"
 #include "revision.h"
 #include "builtin.h"
@@ -69,9 +70,9 @@ int cmd_diff_files(int argc, const char **argv, const char *prefix)
 	 * was not asked to.  "diff-files -c -p" should not densify
 	 * (the user should ask with "diff-files --cc" explicitly).
 	 */
-	if (rev.max_count == -1 && !rev.combine_merges &&
+	if (rev.max_count == -1 &&
 	    (rev.diffopt.output_format & DIFF_FORMAT_PATCH))
-		rev.combine_merges = rev.dense_combined_merges = 1;
+		diff_merges_set_dense_combined_if_unset(&rev);
 
 	if (read_cache_preload(&rev.diffopt.pathspec) < 0) {
 		perror("read_cache_preload");
diff --git a/builtin/diff.c b/builtin/diff.c
index cd4083fed96e..2f570a3131cb 100644
--- a/builtin/diff.c
+++ b/builtin/diff.c
@@ -13,6 +13,7 @@
 #include "blob.h"
 #include "tag.h"
 #include "diff.h"
+#include "diff-merges.h"
 #include "diffcore.h"
 #include "revision.h"
 #include "log-tree.h"
@@ -199,8 +200,8 @@ static int builtin_diff_combined(struct rev_info *revs,
 	if (argc > 1)
 		usage(builtin_diff_usage);
 
-	if (!revs->dense_combined_merges && !revs->combine_merges)
-		revs->dense_combined_merges = revs->combine_merges = 1;
+	diff_merges_set_dense_combined_if_unset(revs);
+
 	for (i = 1; i < ents; i++)
 		oid_array_append(&parents, &ent[i].item->oid);
 	diff_tree_combined(&ent[0].item->oid, &parents, revs);
@@ -248,9 +249,9 @@ static int builtin_diff_files(struct rev_info *revs, int argc, const char **argv
 	 * dense one, --cc can be explicitly asked for, or just rely
 	 * on the default).
 	 */
-	if (revs->max_count == -1 && !revs->combine_merges &&
+	if (revs->max_count == -1 &&
 	    (revs->diffopt.output_format & DIFF_FORMAT_PATCH))
-		revs->combine_merges = revs->dense_combined_merges = 1;
+		diff_merges_set_dense_combined_if_unset(revs);
 
 	setup_work_tree();
 	if (read_cache_preload(&revs->diffopt.pathspec) < 0) {
diff --git a/diff-merges.c b/diff-merges.c
index 25bd9b12e667..691aabadbb32 100644
--- a/diff-merges.c
+++ b/diff-merges.c
@@ -9,6 +9,12 @@ static void suppress(struct rev_info *revs) {
 	revs->dense_combined_merges = 0;
 }
 
+static void set_dense_combined(struct rev_info *revs) {
+	revs->combine_merges = 1;
+	revs->dense_combined_merges = 1;
+}
+
+
 /*
  * Public functions. They are in the order they are called.
  */
@@ -73,6 +79,11 @@ void diff_merges_default_to_dense_combined(struct rev_info *revs) {
 	}
 }
 
+void diff_merges_set_dense_combined_if_unset(struct rev_info *revs) {
+	if (!revs->combine_merges)
+		set_dense_combined(revs);
+}
+
 void diff_merges_setup_revs(struct rev_info *revs)
 {
 	if (revs->combine_merges && revs->ignore_merges < 0)
diff --git a/diff-merges.h b/diff-merges.h
index 32720bc9b40f..ae1cc8ef9410 100644
--- a/diff-merges.h
+++ b/diff-merges.h
@@ -13,6 +13,8 @@ void diff_merges_default_to_first_parent(struct rev_info *revs);
 
 void diff_merges_default_to_dense_combined(struct rev_info *revs);
 
+void diff_merges_set_dense_combined_if_unset(struct rev_info *revs);
+
 void diff_merges_setup_revs(struct rev_info *revs);
 
 #endif
-- 
2.25.1


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

* [PATCH 12/26] diff-merges: introduce revs->first_parent_merges flag
  2020-11-01 19:33 [PATCH 00/26] git-log: implement new --diff-merge options Sergey Organov
                   ` (10 preceding siblings ...)
  2020-11-01 19:33 ` [PATCH 11/26] diff-merges: new function diff_merges_set_dense_combined_if_unset() Sergey Organov
@ 2020-11-01 19:33 ` Sergey Organov
  2020-11-01 19:33 ` [PATCH 13/26] diff-merges: revise revs->diff flag handling Sergey Organov
                   ` (17 subsequent siblings)
  29 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-11-01 19:33 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, git, Sergey Organov

This new field allows us to separate format of diff for merges from
'first_parent_only' flag which primary purpose is limiting history
traversal.

This change further localizes diff format selection logic into the
diff-merges.c file.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 diff-merges.c | 2 ++
 log-tree.c    | 4 ++--
 revision.h    | 1 +
 3 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/diff-merges.c b/diff-merges.c
index 691aabadbb32..63912ddedc76 100644
--- a/diff-merges.c
+++ b/diff-merges.c
@@ -67,6 +67,8 @@ void diff_merges_suppress(struct rev_info *revs) {
 void diff_merges_default_to_first_parent(struct rev_info *revs) {
 	if (revs->ignore_merges < 0)		/* No -m */
 		revs->ignore_merges = 0;
+	if (!revs->combine_merges)		/* No -c/--cc" */
+		revs->first_parent_merges = 1;
 }
 
 void diff_merges_default_to_dense_combined(struct rev_info *revs) {
diff --git a/log-tree.c b/log-tree.c
index 1927f917ce94..3fdc0fc64bfb 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -922,7 +922,7 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log
 			return 0;
 		else if (opt->combine_merges)
 			return do_diff_combined(opt, commit);
-		else if (!opt->first_parent_only) {
+		else if (!opt->first_parent_merges) {
 			/* If we show multiple diffs, show the parent info */
 			log->parent = parents->item;
 		}
@@ -941,7 +941,7 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log
 
 		/* Set up the log info for the next parent, if any.. */
 		parents = parents->next;
-		if (!parents || opt->first_parent_only)
+		if (!parents || opt->first_parent_merges)
 			break;
 		log->parent = parents->item;
 		opt->loginfo = log;
diff --git a/revision.h b/revision.h
index f6bf860d19e5..ba2aef79215e 100644
--- a/revision.h
+++ b/revision.h
@@ -194,6 +194,7 @@ struct rev_info {
 			combine_merges:1,
 			combined_all_paths:1,
 			dense_combined_merges:1,
+			first_parent_merges:1,
 			always_show_header:1;
 	int             ignore_merges:2;
 
-- 
2.25.1


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

* [PATCH 13/26] diff-merges: revise revs->diff flag handling
  2020-11-01 19:33 [PATCH 00/26] git-log: implement new --diff-merge options Sergey Organov
                   ` (11 preceding siblings ...)
  2020-11-01 19:33 ` [PATCH 12/26] diff-merges: introduce revs->first_parent_merges flag Sergey Organov
@ 2020-11-01 19:33 ` Sergey Organov
  2020-11-01 19:33 ` [PATCH 14/26] t4013: support test_expect_failure through ':failure' magic Sergey Organov
                   ` (16 subsequent siblings)
  29 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-11-01 19:33 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, git, Sergey Organov

Do not set revs->diff when we encounter an option that needs it, as
it'd be impossible to undo later. Besides, some other options than
what we handle here set this flag as well, and we'd interfere with
them trying to clear this flag later.

Rather set revs->diff, if finally needed, in diff_merges_setup_revs().

As an additional bonus, this also makes our code shorter.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 diff-merges.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/diff-merges.c b/diff-merges.c
index 63912ddedc76..a30c730a457f 100644
--- a/diff-merges.c
+++ b/diff-merges.c
@@ -37,16 +37,13 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {
 		revs->ignore_merges = 0;
 		revs->match_missing = 1;
 	} else if (!strcmp(arg, "-c")) {
-		revs->diff = 1;
 		revs->dense_combined_merges = 0;
 		revs->combine_merges = 1;
 	} else if (!strcmp(arg, "--cc")) {
-		revs->diff = 1;
 		set_dense_combined(revs);
 	} else if (!strcmp(arg, "--no-diff-merges")) {
 		suppress(revs);
 	} else if (!strcmp(arg, "--combined-all-paths")) {
-		revs->diff = 1;
 		revs->combined_all_paths = 1;
 	} else if ((argcount = parse_long_opt("diff-merges", argv, &optarg))) {
 		if (!strcmp(optarg, "off")) {
@@ -94,4 +91,6 @@ void diff_merges_setup_revs(struct rev_info *revs)
 		revs->ignore_merges = 1;
 	if (revs->combined_all_paths && !revs->combine_merges)
 		die("--combined-all-paths makes no sense without -c or --cc");
+	if (revs->combine_merges)
+		revs->diff = 1;
 }
-- 
2.25.1


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

* [PATCH 14/26] t4013: support test_expect_failure through ':failure' magic
  2020-11-01 19:33 [PATCH 00/26] git-log: implement new --diff-merge options Sergey Organov
                   ` (12 preceding siblings ...)
  2020-11-01 19:33 ` [PATCH 13/26] diff-merges: revise revs->diff flag handling Sergey Organov
@ 2020-11-01 19:33 ` Sergey Organov
  2020-11-01 19:33 ` [PATCH 15/26] t4013: add tests for -m failing to override -c/--cc Sergey Organov
                   ` (15 subsequent siblings)
  29 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-11-01 19:33 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, git, Sergey Organov

Add support to be able to specify expected failure, through :failure
magic, like this:

:failure cmd args

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 t/t4013-diff-various.sh | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh
index 5c7b0122b4f1..935d10ac0572 100755
--- a/t/t4013-diff-various.sh
+++ b/t/t4013-diff-various.sh
@@ -174,6 +174,7 @@ process_diffs () {
 V=$(git version | sed -e 's/^git version //' -e 's/\./\\./g')
 while read magic cmd
 do
+	status=success
 	case "$magic" in
 	'' | '#'*)
 		continue ;;
@@ -182,6 +183,10 @@ do
 		label="$magic-$cmd"
 		case "$magic" in
 		noellipses) ;;
+		failure)
+			status=failure
+			magic=
+			label="$cmd" ;;
 		*)
 			BUG "unknown magic $magic" ;;
 		esac ;;
@@ -194,7 +199,7 @@ do
 	expect="$TEST_DIRECTORY/t4013/diff.$test"
 	actual="$pfx-diff.$test"
 
-	test_expect_success "git $cmd # magic is ${magic:-(not used)}" '
+	test_expect_$status "git $cmd # magic is ${magic:-(not used)}" '
 		{
 			echo "$ git $cmd"
 			case "$magic" in
-- 
2.25.1


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

* [PATCH 15/26] t4013: add tests for -m failing to override -c/--cc
  2020-11-01 19:33 [PATCH 00/26] git-log: implement new --diff-merge options Sergey Organov
                   ` (13 preceding siblings ...)
  2020-11-01 19:33 ` [PATCH 14/26] t4013: support test_expect_failure through ':failure' magic Sergey Organov
@ 2020-11-01 19:33 ` Sergey Organov
  2020-11-01 19:33 ` [PATCH 16/26] diff-merges: fix -m to properly " Sergey Organov
                   ` (14 subsequent siblings)
  29 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-11-01 19:33 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, git, Sergey Organov

Logically, -m, -c, --cc specify 3 different formats for representing
merge commits, yet -m doesn't in fact override -c or --cc, that makes
no sense.

Add 2 expected to fail tests that demonstrate the problem.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 t/t4013-diff-various.sh            |   2 +
 t/t4013/diff.log_--cc_-m_-p_master | 200 +++++++++++++++++++++++++++++
 t/t4013/diff.log_-c_-m_-p_master   | 200 +++++++++++++++++++++++++++++
 3 files changed, 402 insertions(+)
 create mode 100644 t/t4013/diff.log_--cc_-m_-p_master
 create mode 100644 t/t4013/diff.log_-c_-m_-p_master

diff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh
index 935d10ac0572..64d9fce44614 100755
--- a/t/t4013-diff-various.sh
+++ b/t/t4013-diff-various.sh
@@ -329,6 +329,8 @@ log --first-parent --diff-merges=off -p master
 log -p --first-parent master
 log -m -p --first-parent master
 log -m -p master
+:failure log --cc -m -p master
+:failure log -c -m -p master
 log -SF master
 log -S F master
 log -SF -p master
diff --git a/t/t4013/diff.log_--cc_-m_-p_master b/t/t4013/diff.log_--cc_-m_-p_master
new file mode 100644
index 000000000000..7c217cf348c7
--- /dev/null
+++ b/t/t4013/diff.log_--cc_-m_-p_master
@@ -0,0 +1,200 @@
+$ git log --cc -m -p master
+commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (from 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0)
+Merge: 9a6d494 c7a2ab9
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:04:00 2006 +0000
+
+    Merge branch 'side'
+
+diff --git a/dir/sub b/dir/sub
+index cead32e..992913c 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -4,3 +4,5 @@ C
+ D
+ E
+ F
++1
++2
+diff --git a/file0 b/file0
+index b414108..10a8a9f 100644
+--- a/file0
++++ b/file0
+@@ -4,3 +4,6 @@
+ 4
+ 5
+ 6
++A
++B
++C
+
+commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (from c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a)
+Merge: 9a6d494 c7a2ab9
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:04:00 2006 +0000
+
+    Merge branch 'side'
+
+diff --git a/dir/sub b/dir/sub
+index 7289e35..992913c 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,4 +1,8 @@
+ A
+ B
++C
++D
++E
++F
+ 1
+ 2
+diff --git a/file0 b/file0
+index f4615da..10a8a9f 100644
+--- a/file0
++++ b/file0
+@@ -1,6 +1,9 @@
+ 1
+ 2
+ 3
++4
++5
++6
+ A
+ B
+ C
+diff --git a/file1 b/file1
+new file mode 100644
+index 0000000..b1e6722
+--- /dev/null
++++ b/file1
+@@ -0,0 +1,3 @@
++A
++B
++C
+diff --git a/file2 b/file2
+deleted file mode 100644
+index 01e79c3..0000000
+--- a/file2
++++ /dev/null
+@@ -1,3 +0,0 @@
+-1
+-2
+-3
+diff --git a/file3 b/file3
+deleted file mode 100644
+index 7289e35..0000000
+--- a/file3
++++ /dev/null
+@@ -1,4 +0,0 @@
+-A
+-B
+-1
+-2
+
+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:03:00 2006 +0000
+
+    Side
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..7289e35 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++1
++2
+diff --git a/file0 b/file0
+index 01e79c3..f4615da 100644
+--- a/file0
++++ b/file0
+@@ -1,3 +1,6 @@
+ 1
+ 2
+ 3
++A
++B
++C
+diff --git a/file3 b/file3
+new file mode 100644
+index 0000000..7289e35
+--- /dev/null
++++ b/file3
+@@ -0,0 +1,4 @@
++A
++B
++1
++2
+
+commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:02:00 2006 +0000
+
+    Third
+
+diff --git a/dir/sub b/dir/sub
+index 8422d40..cead32e 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -2,3 +2,5 @@ A
+ B
+ C
+ D
++E
++F
+diff --git a/file1 b/file1
+new file mode 100644
+index 0000000..b1e6722
+--- /dev/null
++++ b/file1
+@@ -0,0 +1,3 @@
++A
++B
++C
+
+commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:01:00 2006 +0000
+
+    Second
+    
+    This is the second commit.
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..8422d40 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++C
++D
+diff --git a/file0 b/file0
+index 01e79c3..b414108 100644
+--- a/file0
++++ b/file0
+@@ -1,3 +1,6 @@
+ 1
+ 2
+ 3
++4
++5
++6
+diff --git a/file2 b/file2
+deleted file mode 100644
+index 01e79c3..0000000
+--- a/file2
++++ /dev/null
+@@ -1,3 +0,0 @@
+-1
+-2
+-3
+
+commit 444ac553ac7612cc88969031b02b3767fb8a353a
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:00:00 2006 +0000
+
+    Initial
+$
diff --git a/t/t4013/diff.log_-c_-m_-p_master b/t/t4013/diff.log_-c_-m_-p_master
new file mode 100644
index 000000000000..b660f3d5f28e
--- /dev/null
+++ b/t/t4013/diff.log_-c_-m_-p_master
@@ -0,0 +1,200 @@
+$ git log -c -m -p master
+commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (from 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0)
+Merge: 9a6d494 c7a2ab9
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:04:00 2006 +0000
+
+    Merge branch 'side'
+
+diff --git a/dir/sub b/dir/sub
+index cead32e..992913c 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -4,3 +4,5 @@ C
+ D
+ E
+ F
++1
++2
+diff --git a/file0 b/file0
+index b414108..10a8a9f 100644
+--- a/file0
++++ b/file0
+@@ -4,3 +4,6 @@
+ 4
+ 5
+ 6
++A
++B
++C
+
+commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (from c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a)
+Merge: 9a6d494 c7a2ab9
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:04:00 2006 +0000
+
+    Merge branch 'side'
+
+diff --git a/dir/sub b/dir/sub
+index 7289e35..992913c 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,4 +1,8 @@
+ A
+ B
++C
++D
++E
++F
+ 1
+ 2
+diff --git a/file0 b/file0
+index f4615da..10a8a9f 100644
+--- a/file0
++++ b/file0
+@@ -1,6 +1,9 @@
+ 1
+ 2
+ 3
++4
++5
++6
+ A
+ B
+ C
+diff --git a/file1 b/file1
+new file mode 100644
+index 0000000..b1e6722
+--- /dev/null
++++ b/file1
+@@ -0,0 +1,3 @@
++A
++B
++C
+diff --git a/file2 b/file2
+deleted file mode 100644
+index 01e79c3..0000000
+--- a/file2
++++ /dev/null
+@@ -1,3 +0,0 @@
+-1
+-2
+-3
+diff --git a/file3 b/file3
+deleted file mode 100644
+index 7289e35..0000000
+--- a/file3
++++ /dev/null
+@@ -1,4 +0,0 @@
+-A
+-B
+-1
+-2
+
+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:03:00 2006 +0000
+
+    Side
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..7289e35 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++1
++2
+diff --git a/file0 b/file0
+index 01e79c3..f4615da 100644
+--- a/file0
++++ b/file0
+@@ -1,3 +1,6 @@
+ 1
+ 2
+ 3
++A
++B
++C
+diff --git a/file3 b/file3
+new file mode 100644
+index 0000000..7289e35
+--- /dev/null
++++ b/file3
+@@ -0,0 +1,4 @@
++A
++B
++1
++2
+
+commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:02:00 2006 +0000
+
+    Third
+
+diff --git a/dir/sub b/dir/sub
+index 8422d40..cead32e 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -2,3 +2,5 @@ A
+ B
+ C
+ D
++E
++F
+diff --git a/file1 b/file1
+new file mode 100644
+index 0000000..b1e6722
+--- /dev/null
++++ b/file1
+@@ -0,0 +1,3 @@
++A
++B
++C
+
+commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:01:00 2006 +0000
+
+    Second
+    
+    This is the second commit.
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..8422d40 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++C
++D
+diff --git a/file0 b/file0
+index 01e79c3..b414108 100644
+--- a/file0
++++ b/file0
+@@ -1,3 +1,6 @@
+ 1
+ 2
+ 3
++4
++5
++6
+diff --git a/file2 b/file2
+deleted file mode 100644
+index 01e79c3..0000000
+--- a/file2
++++ /dev/null
+@@ -1,3 +0,0 @@
+-1
+-2
+-3
+
+commit 444ac553ac7612cc88969031b02b3767fb8a353a
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:00:00 2006 +0000
+
+    Initial
+$
-- 
2.25.1


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

* [PATCH 16/26] diff-merges: fix -m to properly override -c/--cc
  2020-11-01 19:33 [PATCH 00/26] git-log: implement new --diff-merge options Sergey Organov
                   ` (14 preceding siblings ...)
  2020-11-01 19:33 ` [PATCH 15/26] t4013: add tests for -m failing to override -c/--cc Sergey Organov
@ 2020-11-01 19:33 ` Sergey Organov
  2020-11-01 19:33 ` [PATCH 17/26] diff-merges: split 'ignore_merges' field Sergey Organov
                   ` (13 subsequent siblings)
  29 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-11-01 19:33 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, git, Sergey Organov

Logically, -m, -c, --cc specify 3 different formats for representing
merge commits, yet -m doesn't in fact override -c or --cc, that makes
no sense.

Fix -m to properly override -c/--cc, and change the tests accordingly.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 diff-merges.c           | 1 +
 t/t4013-diff-various.sh | 4 ++--
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/diff-merges.c b/diff-merges.c
index a30c730a457f..f2b9ed789ca8 100644
--- a/diff-merges.c
+++ b/diff-merges.c
@@ -29,6 +29,7 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {
 	const char *arg = argv[0];
 
 	if (!strcmp(arg, "-m")) {
+		suppress(revs);
 		/*
 		 * To "diff-index", "-m" means "match missing", and to the "log"
 		 * family of commands, it means "show full diff for merges". Set
diff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh
index 64d9fce44614..8d8178a8a616 100755
--- a/t/t4013-diff-various.sh
+++ b/t/t4013-diff-various.sh
@@ -329,8 +329,8 @@ log --first-parent --diff-merges=off -p master
 log -p --first-parent master
 log -m -p --first-parent master
 log -m -p master
-:failure log --cc -m -p master
-:failure log -c -m -p master
+log --cc -m -p master
+log -c -m -p master
 log -SF master
 log -S F master
 log -SF -p master
-- 
2.25.1


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

* [PATCH 17/26] diff-merges: split 'ignore_merges' field
  2020-11-01 19:33 [PATCH 00/26] git-log: implement new --diff-merge options Sergey Organov
                   ` (15 preceding siblings ...)
  2020-11-01 19:33 ` [PATCH 16/26] diff-merges: fix -m to properly " Sergey Organov
@ 2020-11-01 19:33 ` Sergey Organov
  2020-11-02 10:48   ` Philip Oakley
  2020-11-01 19:33 ` [PATCH 18/26] diff-merges: group diff-merge flags next to each other inside 'rev_info' Sergey Organov
                   ` (12 subsequent siblings)
  29 siblings, 1 reply; 232+ messages in thread
From: Sergey Organov @ 2020-11-01 19:33 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, git, Sergey Organov

'ignore_meres' was 3-way field that served two distinct purposes that
we now assign to 2 new independent flags: 'separate_merges', and
'explicit_diff_merges'.

'separate_merges' tells that we need to output diff format containing
separate diff for every parent (as opposed to 'combine_merges').

'explicit_diff_merges' tells that at least one of diff-merges options
has been explicitly specified on the command line, so no defaults
should apply.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 diff-merges.c | 29 ++++++++++++-----------------
 log-tree.c    | 15 ++++++++-------
 revision.h    |  3 ++-
 3 files changed, 22 insertions(+), 25 deletions(-)

diff --git a/diff-merges.c b/diff-merges.c
index f2b9ed789ca8..19cdad1aa4a1 100644
--- a/diff-merges.c
+++ b/diff-merges.c
@@ -3,7 +3,7 @@
 #include "revision.h"
 
 static void suppress(struct rev_info *revs) {
-	revs->ignore_merges = 1;
+	revs->separate_merges = 0;
 	revs->first_parent_merges = 0;
 	revs->combine_merges = 0;
 	revs->dense_combined_merges = 0;
@@ -20,7 +20,6 @@ static void set_dense_combined(struct rev_info *revs) {
  */
 
 void diff_merges_init_revs(struct rev_info *revs) {
-	revs->ignore_merges = -1;
 }
 
 int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {
@@ -35,7 +34,7 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {
 		 * family of commands, it means "show full diff for merges". Set
 		 * both fields appropriately.
 		 */
-		revs->ignore_merges = 0;
+		revs->separate_merges = 1;
 		revs->match_missing = 1;
 	} else if (!strcmp(arg, "-c")) {
 		revs->dense_combined_merges = 0;
@@ -55,6 +54,7 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {
 	} else
 		return 0;
 
+	revs->explicit_diff_merges = 1;
 	return 1;
 }
 
@@ -63,20 +63,15 @@ void diff_merges_suppress(struct rev_info *revs) {
 }
 
 void diff_merges_default_to_first_parent(struct rev_info *revs) {
-	if (revs->ignore_merges < 0)		/* No -m */
-		revs->ignore_merges = 0;
-	if (!revs->combine_merges)		/* No -c/--cc" */
+	if (!revs->explicit_diff_merges)
+		revs->separate_merges = 1;
+	if (revs->separate_merges)
 		revs->first_parent_merges = 1;
 }
 
 void diff_merges_default_to_dense_combined(struct rev_info *revs) {
-	if (revs->ignore_merges < 0) {		/* No -m */
-		revs->ignore_merges = 0;
-		if (!revs->combine_merges) {	/* No -c/--cc" */
-			revs->combine_merges = 1;
-			revs->dense_combined_merges = 1;
-		}
-	}
+	if (!revs->explicit_diff_merges)
+		set_dense_combined(revs);
 }
 
 void diff_merges_set_dense_combined_if_unset(struct rev_info *revs) {
@@ -86,10 +81,10 @@ void diff_merges_set_dense_combined_if_unset(struct rev_info *revs) {
 
 void diff_merges_setup_revs(struct rev_info *revs)
 {
-	if (revs->combine_merges && revs->ignore_merges < 0)
-		revs->ignore_merges = 0;
-	if (revs->ignore_merges < 0)
-		revs->ignore_merges = 1;
+	if (revs->combine_merges == 0)
+		revs->dense_combined_merges = 0;
+	if (revs->separate_merges == 0)
+		revs->first_parent_merges = 0;
 	if (revs->combined_all_paths && !revs->combine_merges)
 		die("--combined-all-paths makes no sense without -c or --cc");
 	if (revs->combine_merges)
diff --git a/log-tree.c b/log-tree.c
index 3fdc0fc64bfb..f9385b1dae6f 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -918,14 +918,15 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log
 
 	/* More than one parent? */
 	if (parents->next) {
-		if (opt->ignore_merges)
-			return 0;
-		else if (opt->combine_merges)
+		if (opt->combine_merges)
 			return do_diff_combined(opt, commit);
-		else if (!opt->first_parent_merges) {
-			/* If we show multiple diffs, show the parent info */
-			log->parent = parents->item;
-		}
+		if (opt->separate_merges) {
+			if (!opt->first_parent_merges) {
+				/* Show parent info for multiple diffs */
+				log->parent = parents->item;
+			}
+		} else
+			return 0;
 	}
 
 	showed_log = 0;
diff --git a/revision.h b/revision.h
index ba2aef79215e..fcc532c873d1 100644
--- a/revision.h
+++ b/revision.h
@@ -191,12 +191,13 @@ struct rev_info {
 			match_missing:1,
 			no_commit_id:1,
 			verbose_header:1,
+			explicit_diff_merges: 1,
+			separate_merges: 1,
 			combine_merges:1,
 			combined_all_paths:1,
 			dense_combined_merges:1,
 			first_parent_merges:1,
 			always_show_header:1;
-	int             ignore_merges:2;
 
 	/* Format info */
 	int		show_notes;
-- 
2.25.1


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

* [PATCH 18/26] diff-merges: group diff-merge flags next to each other inside 'rev_info'
  2020-11-01 19:33 [PATCH 00/26] git-log: implement new --diff-merge options Sergey Organov
                   ` (16 preceding siblings ...)
  2020-11-01 19:33 ` [PATCH 17/26] diff-merges: split 'ignore_merges' field Sergey Organov
@ 2020-11-01 19:33 ` Sergey Organov
  2020-11-01 19:33 ` [PATCH 19/26] diff-merges: get rid of now empty diff_merges_init_revs() Sergey Organov
                   ` (11 subsequent siblings)
  29 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-11-01 19:33 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, git, Sergey Organov

The relevant flags were somewhat scattered over definition of 'struct
rev_info'. Rearrange them to group them together.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 revision.h | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/revision.h b/revision.h
index fcc532c873d1..dcfa14454a55 100644
--- a/revision.h
+++ b/revision.h
@@ -191,13 +191,14 @@ struct rev_info {
 			match_missing:1,
 			no_commit_id:1,
 			verbose_header:1,
+			always_show_header:1,
+			/* Diff-merge flags */
 			explicit_diff_merges: 1,
 			separate_merges: 1,
 			combine_merges:1,
 			combined_all_paths:1,
 			dense_combined_merges:1,
-			first_parent_merges:1,
-			always_show_header:1;
+			first_parent_merges:1;
 
 	/* Format info */
 	int		show_notes;
-- 
2.25.1


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

* [PATCH 19/26] diff-merges: get rid of now empty diff_merges_init_revs()
  2020-11-01 19:33 [PATCH 00/26] git-log: implement new --diff-merge options Sergey Organov
                   ` (17 preceding siblings ...)
  2020-11-01 19:33 ` [PATCH 18/26] diff-merges: group diff-merge flags next to each other inside 'rev_info' Sergey Organov
@ 2020-11-01 19:33 ` Sergey Organov
  2020-11-02 10:51   ` Philip Oakley
  2020-11-01 19:33 ` [PATCH 20/26] diff-merges: refactor opt settings into separate functions Sergey Organov
                   ` (10 subsequent siblings)
  29 siblings, 1 reply; 232+ messages in thread
From: Sergey Organov @ 2020-11-01 19:33 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, git, Sergey Organov

After getting rid of 'ignore_meres' field, the diff_merges_init_revs()
function became empty. Get rid of it.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 diff-merges.c | 3 ---
 diff-merges.h | 2 --
 revision.c    | 1 -
 3 files changed, 6 deletions(-)

diff --git a/diff-merges.c b/diff-merges.c
index 19cdad1aa4a1..29818abcc00e 100644
--- a/diff-merges.c
+++ b/diff-merges.c
@@ -19,9 +19,6 @@ static void set_dense_combined(struct rev_info *revs) {
  * Public functions. They are in the order they are called.
  */
 
-void diff_merges_init_revs(struct rev_info *revs) {
-}
-
 int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {
 	int argcount;
 	const char *optarg;
diff --git a/diff-merges.h b/diff-merges.h
index ae1cc8ef9410..9c69b8f3bd69 100644
--- a/diff-merges.h
+++ b/diff-merges.h
@@ -3,8 +3,6 @@
 
 struct rev_info;
 
-void diff_merges_init_revs(struct rev_info *revs);
-
 int diff_merges_parse_opts(struct rev_info *revs, const char **argv);
 
 void diff_merges_suppress(struct rev_info *revs);
diff --git a/revision.c b/revision.c
index 5a0e3d6ad542..46645ca0b6df 100644
--- a/revision.c
+++ b/revision.c
@@ -1814,7 +1814,6 @@ void repo_init_revisions(struct repository *r,
 
 	revs->repo = r;
 	revs->abbrev = DEFAULT_ABBREV;
-	diff_merges_init_revs(revs);
 	revs->simplify_history = 1;
 	revs->pruning.repo = r;
 	revs->pruning.flags.recursive = 1;
-- 
2.25.1


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

* [PATCH 20/26] diff-merges: refactor opt settings into separate functions
  2020-11-01 19:33 [PATCH 00/26] git-log: implement new --diff-merge options Sergey Organov
                   ` (18 preceding siblings ...)
  2020-11-01 19:33 ` [PATCH 19/26] diff-merges: get rid of now empty diff_merges_init_revs() Sergey Organov
@ 2020-11-01 19:33 ` Sergey Organov
  2020-11-01 19:33 ` [PATCH 21/26] diff-merges: make -m/-c/--cc explicitly mutually exclusive Sergey Organov
                   ` (9 subsequent siblings)
  29 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-11-01 19:33 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, git, Sergey Organov

To prepare introduction of new options some of which will be synonyms
to existing options, let every option handling code just call
corresponding function.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 diff-merges.c | 59 ++++++++++++++++++++++++++++++++-------------------
 1 file changed, 37 insertions(+), 22 deletions(-)

diff --git a/diff-merges.c b/diff-merges.c
index 29818abcc00e..8c22b447f106 100644
--- a/diff-merges.c
+++ b/diff-merges.c
@@ -9,11 +9,38 @@ static void suppress(struct rev_info *revs) {
 	revs->dense_combined_merges = 0;
 }
 
+static void set_separate(struct rev_info *revs) {
+	suppress(revs);
+	revs->separate_merges = 1;
+}
+
+static void set_m(struct rev_info *revs) {
+	/*
+	 * To "diff-index", "-m" means "match missing", and to the "log"
+	 * family of commands, it means "show full diff for merges". Set
+	 * both fields appropriately.
+	 */
+	set_separate(revs);
+	revs->match_missing = 1;
+}
+
+static void set_combined(struct rev_info *revs) {
+	revs->combine_merges = 1;
+	revs->dense_combined_merges = 0;
+}
+
 static void set_dense_combined(struct rev_info *revs) {
 	revs->combine_merges = 1;
 	revs->dense_combined_merges = 1;
 }
 
+static void set_diff_merges(struct rev_info *revs, const char *optarg) {
+	if (!strcmp(optarg, "off")) {
+		suppress(revs);
+	} else {
+		die(_("unknown value for --diff-merges: %s"), optarg);
+	}
+}
 
 /*
  * Public functions. They are in the order they are called.
@@ -24,31 +51,19 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {
 	const char *optarg;
 	const char *arg = argv[0];
 
-	if (!strcmp(arg, "-m")) {
-		suppress(revs);
-		/*
-		 * To "diff-index", "-m" means "match missing", and to the "log"
-		 * family of commands, it means "show full diff for merges". Set
-		 * both fields appropriately.
-		 */
-		revs->separate_merges = 1;
-		revs->match_missing = 1;
-	} else if (!strcmp(arg, "-c")) {
-		revs->dense_combined_merges = 0;
-		revs->combine_merges = 1;
-	} else if (!strcmp(arg, "--cc")) {
+	if (!strcmp(arg, "-m"))
+		set_m(revs);
+	else if (!strcmp(arg, "-c"))
+		set_combined(revs);
+	else if (!strcmp(arg, "--cc"))
 		set_dense_combined(revs);
-	} else if (!strcmp(arg, "--no-diff-merges")) {
+	else if (!strcmp(arg, "--no-diff-merges"))
 		suppress(revs);
-	} else if (!strcmp(arg, "--combined-all-paths")) {
+	else if (!strcmp(arg, "--combined-all-paths"))
 		revs->combined_all_paths = 1;
-	} else if ((argcount = parse_long_opt("diff-merges", argv, &optarg))) {
-		if (!strcmp(optarg, "off")) {
-			suppress(revs);
-		} else {
-			die(_("unknown value for --diff-merges: %s"), optarg);
-		}
-	} else
+	else if ((argcount = parse_long_opt("diff-merges", argv, &optarg)))
+		set_diff_merges(revs, optarg);
+	else
 		return 0;
 
 	revs->explicit_diff_merges = 1;
-- 
2.25.1


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

* [PATCH 21/26] diff-merges: make -m/-c/--cc explicitly mutually exclusive
  2020-11-01 19:33 [PATCH 00/26] git-log: implement new --diff-merge options Sergey Organov
                   ` (19 preceding siblings ...)
  2020-11-01 19:33 ` [PATCH 20/26] diff-merges: refactor opt settings into separate functions Sergey Organov
@ 2020-11-01 19:33 ` Sergey Organov
  2020-11-01 19:33 ` [PATCH 22/26] diff-merges: implement new values for --diff-merges Sergey Organov
                   ` (8 subsequent siblings)
  29 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-11-01 19:33 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, git, Sergey Organov

-c/--cc got precedence over -m only because of external logic where
corresponding flags are checked before that for -m. This is too
error-prone, so add code that explicitly makes these 3 options
mutually exclusive, so that the last option specified on the
command-line gets precedence.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 diff-merges.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/diff-merges.c b/diff-merges.c
index 8c22b447f106..db2217171442 100644
--- a/diff-merges.c
+++ b/diff-merges.c
@@ -7,6 +7,7 @@ static void suppress(struct rev_info *revs) {
 	revs->first_parent_merges = 0;
 	revs->combine_merges = 0;
 	revs->dense_combined_merges = 0;
+	revs->combined_all_paths = 0;
 }
 
 static void set_separate(struct rev_info *revs) {
@@ -25,11 +26,13 @@ static void set_m(struct rev_info *revs) {
 }
 
 static void set_combined(struct rev_info *revs) {
+	suppress(revs);
 	revs->combine_merges = 1;
 	revs->dense_combined_merges = 0;
 }
 
 static void set_dense_combined(struct rev_info *revs) {
+	suppress(revs);
 	revs->combine_merges = 1;
 	revs->dense_combined_merges = 1;
 }
-- 
2.25.1


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

* [PATCH 22/26] diff-merges: implement new values for --diff-merges
  2020-11-01 19:33 [PATCH 00/26] git-log: implement new --diff-merge options Sergey Organov
                   ` (20 preceding siblings ...)
  2020-11-01 19:33 ` [PATCH 21/26] diff-merges: make -m/-c/--cc explicitly mutually exclusive Sergey Organov
@ 2020-11-01 19:33 ` Sergey Organov
  2020-11-01 19:33 ` [PATCH 23/26] t4013: add test for --diff-merges=first-parent Sergey Organov
                   ` (7 subsequent siblings)
  29 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-11-01 19:33 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, git, Sergey Organov

The following values are implemented:

--diff-merges=	        old equivalent
first|first-parent    = --first-parent (only format implications)
sep|separate          = -m
comb|combined         = -c
dense| dense-combined = --cc

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 diff-merges.c | 19 ++++++++++++++++---
 1 file changed, 16 insertions(+), 3 deletions(-)

diff --git a/diff-merges.c b/diff-merges.c
index db2217171442..5c35369f7a8c 100644
--- a/diff-merges.c
+++ b/diff-merges.c
@@ -15,6 +15,11 @@ static void set_separate(struct rev_info *revs) {
 	revs->separate_merges = 1;
 }
 
+static void set_first_parent(struct rev_info *revs) {
+	set_separate(revs);
+	revs->first_parent_merges = 1;
+}
+
 static void set_m(struct rev_info *revs) {
 	/*
 	 * To "diff-index", "-m" means "match missing", and to the "log"
@@ -38,11 +43,19 @@ static void set_dense_combined(struct rev_info *revs) {
 }
 
 static void set_diff_merges(struct rev_info *revs, const char *optarg) {
-	if (!strcmp(optarg, "off")) {
+	if (0) ;
+	else if (!strcmp(optarg, "off")   || !strcmp(optarg, "none"))
 		suppress(revs);
-	} else {
+	else if (!strcmp(optarg, "first") || !strcmp(optarg, "first-parent"))
+		set_first_parent(revs);
+	else if (!strcmp(optarg, "sep")   || !strcmp(optarg, "separate"))
+		set_separate(revs);
+	else if (!strcmp(optarg, "comb")  || !strcmp(optarg, "combined"))
+		set_combined(revs);
+	else if (!strcmp(optarg, "dense") || !strcmp(optarg, "dense-combined"))
+		set_dense_combined(revs);
+	else
 		die(_("unknown value for --diff-merges: %s"), optarg);
-	}
 }
 
 /*
-- 
2.25.1


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

* [PATCH 23/26] t4013: add test for --diff-merges=first-parent
  2020-11-01 19:33 [PATCH 00/26] git-log: implement new --diff-merge options Sergey Organov
                   ` (21 preceding siblings ...)
  2020-11-01 19:33 ` [PATCH 22/26] diff-merges: implement new values for --diff-merges Sergey Organov
@ 2020-11-01 19:33 ` Sergey Organov
  2020-11-01 19:33 ` [PATCH 24/26] doc/git-log: describe new --diff-merges options Sergey Organov
                   ` (6 subsequent siblings)
  29 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-11-01 19:33 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, git, Sergey Organov

This new option provides essential new functionality, changing diff
output to first parent only without changing history traversal mode,
so it deserves its own test.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 t/t4013-diff-various.sh                       |   1 +
 ...f.log_-p_--diff-merges=first-parent_master | 137 ++++++++++++++++++
 2 files changed, 138 insertions(+)
 create mode 100644 t/t4013/diff.log_-p_--diff-merges=first-parent_master

diff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh
index 8d8178a8a616..ce56a9349d1c 100755
--- a/t/t4013-diff-various.sh
+++ b/t/t4013-diff-various.sh
@@ -327,6 +327,7 @@ log --no-diff-merges -p --first-parent master
 log --diff-merges=off -p --first-parent master
 log --first-parent --diff-merges=off -p master
 log -p --first-parent master
+log -p --diff-merges=first-parent master
 log -m -p --first-parent master
 log -m -p master
 log --cc -m -p master
diff --git a/t/t4013/diff.log_-p_--diff-merges=first-parent_master b/t/t4013/diff.log_-p_--diff-merges=first-parent_master
new file mode 100644
index 000000000000..9538a2751123
--- /dev/null
+++ b/t/t4013/diff.log_-p_--diff-merges=first-parent_master
@@ -0,0 +1,137 @@
+$ git log -p --diff-merges=first-parent master
+commit 59d314ad6f356dd08601a4cd5e530381da3e3c64
+Merge: 9a6d494 c7a2ab9
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:04:00 2006 +0000
+
+    Merge branch 'side'
+
+diff --git a/dir/sub b/dir/sub
+index cead32e..992913c 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -4,3 +4,5 @@ C
+ D
+ E
+ F
++1
++2
+diff --git a/file0 b/file0
+index b414108..10a8a9f 100644
+--- a/file0
++++ b/file0
+@@ -4,3 +4,6 @@
+ 4
+ 5
+ 6
++A
++B
++C
+
+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:03:00 2006 +0000
+
+    Side
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..7289e35 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++1
++2
+diff --git a/file0 b/file0
+index 01e79c3..f4615da 100644
+--- a/file0
++++ b/file0
+@@ -1,3 +1,6 @@
+ 1
+ 2
+ 3
++A
++B
++C
+diff --git a/file3 b/file3
+new file mode 100644
+index 0000000..7289e35
+--- /dev/null
++++ b/file3
+@@ -0,0 +1,4 @@
++A
++B
++1
++2
+
+commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:02:00 2006 +0000
+
+    Third
+
+diff --git a/dir/sub b/dir/sub
+index 8422d40..cead32e 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -2,3 +2,5 @@ A
+ B
+ C
+ D
++E
++F
+diff --git a/file1 b/file1
+new file mode 100644
+index 0000000..b1e6722
+--- /dev/null
++++ b/file1
+@@ -0,0 +1,3 @@
++A
++B
++C
+
+commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:01:00 2006 +0000
+
+    Second
+    
+    This is the second commit.
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..8422d40 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++C
++D
+diff --git a/file0 b/file0
+index 01e79c3..b414108 100644
+--- a/file0
++++ b/file0
+@@ -1,3 +1,6 @@
+ 1
+ 2
+ 3
++4
++5
++6
+diff --git a/file2 b/file2
+deleted file mode 100644
+index 01e79c3..0000000
+--- a/file2
++++ /dev/null
+@@ -1,3 +0,0 @@
+-1
+-2
+-3
+
+commit 444ac553ac7612cc88969031b02b3767fb8a353a
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:00:00 2006 +0000
+
+    Initial
+$
-- 
2.25.1


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

* [PATCH 24/26] doc/git-log: describe new --diff-merges options
  2020-11-01 19:33 [PATCH 00/26] git-log: implement new --diff-merge options Sergey Organov
                   ` (22 preceding siblings ...)
  2020-11-01 19:33 ` [PATCH 23/26] t4013: add test for --diff-merges=first-parent Sergey Organov
@ 2020-11-01 19:33 ` Sergey Organov
  2020-11-01 19:33 ` [PATCH 25/26] doc/diff-generate-patch: mention new --diff-merges option Sergey Organov
                   ` (5 subsequent siblings)
  29 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-11-01 19:33 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, git, Sergey Organov

Describe all the new --diff-merges options in the git-log.txt

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 Documentation/git-log.txt | 79 +++++++++++++++++++++++----------------
 1 file changed, 46 insertions(+), 33 deletions(-)

diff --git a/Documentation/git-log.txt b/Documentation/git-log.txt
index 2b8ac5ff882a..de498a189646 100644
--- a/Documentation/git-log.txt
+++ b/Documentation/git-log.txt
@@ -120,45 +120,58 @@ DIFF FORMATTING
 By default, `git log` does not generate any diff output. The options
 below can be used to show the changes made by each commit.
 
-Note that unless one of `-c`, `--cc`, or `-m` is given, merge commits
-will never show a diff, even if a diff format like `--patch` is
-selected, nor will they match search options like `-S`. The exception is
-when `--first-parent` is in use, in which merges are treated like normal
-single-parent commits (this can be overridden by providing a
-combined-diff option or with `--no-diff-merges`).
+Note that unless one of `--diff-merges` variants (including short
+`-m`, `-c`, and `--cc` options) is explicitly given, merge commits
+will not show a diff, even if a diff format like `--patch` is
+selected, nor will they match search options like `-S`. The exception
+is when `--first-parent` is in use, in which case
+`--diff-merges=first-parent` is implied.
 
--c::
-	With this option, diff output for a merge commit
-	shows the differences from each of the parents to the merge result
-	simultaneously instead of showing pairwise diff between a parent
-	and the result one at a time. Furthermore, it lists only files
-	which were modified from all parents.
-
---cc::
-	This flag implies the `-c` option and further compresses the
-	patch output by omitting uninteresting hunks whose contents in
-	the parents have only two variants and the merge result picks
-	one of them without modification.
+--diff-merges=(off|none|first-parent|separate|combined|dense-combined)::
+--no-diff-merges::
+	Specify diff format to be used for merge commits. This has no
+	effect unless diff output is enabled in the first place (e.g.,
+	with `--patch` option.)
++
+--diff-merges=(off|none):::
+--no-diff-merges:::
+	(default) Disable output of diffs for merge commits. Useful to
+	override implied value.
++
+--diff-merges=first-parent:::
+	This option makes merge commits show the full diff with
+	respect to the first parent only, exactly like	regular
+	commits.
++
+--diff-merges=separate:::
+-m:::
+	This makes merge commits show the full diff with respect to
+	each of the parents. Separate log entry and diff is generated
+	for each parent.
++
+--diff-merges=combined:::
+-c:::
+	With this option, diff output for a merge commit shows the
+	differences from each of the parents to the merge result
+	simultaneously instead of showing pairwise diff between a
+	parent and the result one at a time. Furthermore, it lists
+	only files which were modified from all parents.
++
+--diff-merges=dense-combined:::
+--cc:::
+	With this option the output produced by
+	`--diff-merges=combined` is further compressed by omitting
+	uninteresting hunks whose contents in the parents have only
+	two variants and the merge result picks one of them without
+	modification.
 
 --combined-all-paths::
 	This flag causes combined diffs (used for merge commits) to
 	list the name of the file from all parents.  It thus only has
-	effect when -c or --cc are specified, and is likely only
-	useful if filename changes are detected (i.e. when either
-	rename or copy detection have been requested).
+	effect when `--diff-merges=[dense-]combined` is in use, and
+	is likely only useful if filename changes are detected (i.e.
+	when either rename or copy detection have been requested).
 
--m::
-	This flag makes the merge commits show the full diff like
-	regular commits; for each merge parent, a separate log entry
-	and diff is generated. An exception is that only diff against
-	the first parent is shown when `--first-parent` option is given;
-	in that case, the output represents the changes the merge
-	brought _into_ the then-current branch.
-
---diff-merges=off::
---no-diff-merges::
-	Disable output of diffs for merge commits (default). Useful to
-	override `-m`, `-c`, or `--cc`.
 
 :git-log: 1
 include::diff-options.txt[]
-- 
2.25.1


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

* [PATCH 25/26] doc/diff-generate-patch: mention new --diff-merges option
  2020-11-01 19:33 [PATCH 00/26] git-log: implement new --diff-merge options Sergey Organov
                   ` (23 preceding siblings ...)
  2020-11-01 19:33 ` [PATCH 24/26] doc/git-log: describe new --diff-merges options Sergey Organov
@ 2020-11-01 19:33 ` Sergey Organov
  2020-11-01 19:33 ` [PATCH 26/26] doc/rev-list-options: document --first-parent implies --diff-merges=first-parent Sergey Organov
                   ` (4 subsequent siblings)
  29 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-11-01 19:33 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, git, Sergey Organov

Mention --diff-merges instead of -m in a note to merge formats to aid
discoverability, as -m is now described among --diff-merges options
anyway.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 Documentation/diff-generate-patch.txt | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/Documentation/diff-generate-patch.txt b/Documentation/diff-generate-patch.txt
index b10ff4caa6c5..2db8eacc3ec7 100644
--- a/Documentation/diff-generate-patch.txt
+++ b/Documentation/diff-generate-patch.txt
@@ -81,9 +81,9 @@ Combined diff format
 Any diff-generating command can take the `-c` or `--cc` option to
 produce a 'combined diff' when showing a merge. This is the default
 format when showing merges with linkgit:git-diff[1] or
-linkgit:git-show[1]. Note also that you can give the `-m` option to any
-of these commands to force generation of diffs with individual parents
-of a merge.
+linkgit:git-show[1]. Note also that you can give suitable
+`--diff-merges` option to any of these commands to force generation of
+diffs in specific format.
 
 A "combined diff" format looks like this:
 
-- 
2.25.1


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

* [PATCH 26/26] doc/rev-list-options: document --first-parent implies --diff-merges=first-parent
  2020-11-01 19:33 [PATCH 00/26] git-log: implement new --diff-merge options Sergey Organov
                   ` (24 preceding siblings ...)
  2020-11-01 19:33 ` [PATCH 25/26] doc/diff-generate-patch: mention new --diff-merges option Sergey Organov
@ 2020-11-01 19:33 ` Sergey Organov
  2020-11-08 21:38 ` [PATCH v1 00/27] git-log: implement new --diff-merge options Sergey Organov
                   ` (3 subsequent siblings)
  29 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-11-01 19:33 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, git, Sergey Organov

Before introduction of new --diff-merges options, --first-parent
implicitly changed the default diff format for merge commits to
showing only the diff with respect to the first parent, and there were
no way to get such format from "git log" without affecting history
traversal logic that --first-parent causes.

Now, after introduction of the --diff-merges=first-parent, the
--first-parent simply implies the former, and this patch corrects
documentation accordingly.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 Documentation/rev-list-options.txt | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt
index 002379056a07..ded383e62ae5 100644
--- a/Documentation/rev-list-options.txt
+++ b/Documentation/rev-list-options.txt
@@ -129,6 +129,9 @@ parents) and `--max-parents=-1` (negative numbers denote no upper limit).
 	adjusting to updated upstream from time to time, and
 	this option allows you to ignore the individual commits
 	brought in to your history by such a merge.
+ifdef::git-log[]
+	Implies `--diff-merges=first-parent`.
+endif::git-log[]
 
 --not::
 	Reverses the meaning of the '{caret}' prefix (or lack thereof)
-- 
2.25.1


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

* Re: [PATCH 17/26] diff-merges: split 'ignore_merges' field
  2020-11-01 19:33 ` [PATCH 17/26] diff-merges: split 'ignore_merges' field Sergey Organov
@ 2020-11-02 10:48   ` Philip Oakley
  2020-11-02 16:15     ` Sergey Organov
  0 siblings, 1 reply; 232+ messages in thread
From: Philip Oakley @ 2020-11-02 10:48 UTC (permalink / raw)
  To: Sergey Organov, Junio C Hamano; +Cc: Jeff King, git

micro-nit while browsing..

On 01/11/2020 19:33, Sergey Organov wrote:
> 'ignore_meres' was 3-way field that served two distinct purposes that
ignore_merges (missing 'g')
> we now assign to 2 new independent flags: 'separate_merges', and
> 'explicit_diff_merges'.
--
Philip

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

* Re: [PATCH 19/26] diff-merges: get rid of now empty diff_merges_init_revs()
  2020-11-01 19:33 ` [PATCH 19/26] diff-merges: get rid of now empty diff_merges_init_revs() Sergey Organov
@ 2020-11-02 10:51   ` Philip Oakley
  0 siblings, 0 replies; 232+ messages in thread
From: Philip Oakley @ 2020-11-02 10:51 UTC (permalink / raw)
  To: Sergey Organov, Junio C Hamano; +Cc: Jeff King, git

micro-nit again:

On 01/11/2020 19:33, Sergey Organov wrote:
> After getting rid of 'ignore_meres' field, the diff_merges_init_revs()
merges
> function became empty. Get rid of it.
>
> Signed-off-by: Sergey Organov <sorganov@gmail.com>
> ---
--
Philip

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

* Re: [PATCH 17/26] diff-merges: split 'ignore_merges' field
  2020-11-02 10:48   ` Philip Oakley
@ 2020-11-02 16:15     ` Sergey Organov
  0 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-11-02 16:15 UTC (permalink / raw)
  To: Philip Oakley; +Cc: Junio C Hamano, Jeff King, git

Philip Oakley <philipoakley@iee.email> writes:

> micro-nit while browsing..
>> 'ignore_meres' was 3-way field that served two distinct purposes that
> ignore_merges (missing 'g')

Philip Oakley <philipoakley@iee.email> writes:

> micro-nit again:
>> After getting rid of 'ignore_meres' field, the diff_merges_init_revs()
> merges

Thanks, Philip! Fixed for next re-roll.

-- Sergey

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

* [PATCH v1 00/27] git-log: implement new --diff-merge options
  2020-11-01 19:33 [PATCH 00/26] git-log: implement new --diff-merge options Sergey Organov
                   ` (25 preceding siblings ...)
  2020-11-01 19:33 ` [PATCH 26/26] doc/rev-list-options: document --first-parent implies --diff-merges=first-parent Sergey Organov
@ 2020-11-08 21:38 ` Sergey Organov
  2020-11-08 21:38   ` [PATCH v1 01/27] revision: factor out parsing of diff-merge related options Sergey Organov
                     ` (27 more replies)
  2020-12-08 20:07 ` [PATCH 00/26] " Sergey Organov
                   ` (2 subsequent siblings)
  29 siblings, 28 replies; 232+ messages in thread
From: Sergey Organov @ 2020-11-08 21:38 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, Philip Oakley, git, Sergey Organov

These patch series implement new set of options governing the diff output
of merge commits, all under the umbrella of the single --diff-merges=<mode>
option. Most of the new options being synonyms for -m/-c/--cc options,
there is also additional functionality provided, allowing to get the format
of "-p --first-parent" without change in history traversal that
--first-parent option causes.

The net result of these series are the following new options:

--diff-merges=	 |  old equivalent
-----------------+----------------
first-parent     | --first-parent (only format implications)
separate         | -m
combined         | -c
dense-combined   | --cc

The series also cleanup logic of handling of diff merges options and fix an
issue found in the original implementation where logically mutually
exclusive options -m/-c/--cc failed to actually override each other.

The series start with the set of pure refactoring commits that are expected
to introduce no functional changes. These are all commits up to and
including:

"diff-merges: revise revs->diff flag handling"

The aim of these commits is to isolate options handling for diff merges so
that it could be easily understood and tweaked to ease introduction of the
new options.

Then the fix of -m/-c/-cc overriding issue follows, starting with a failing
test and followed by the fix.

Then follows a little bit of additional refactoring in order to prepare for
introduction of the new options, and finally the series are finished by the
implementation, testing, and documentation update for the new options.

Updates in v1:

	* Added documentation fix for git-show to include --diff-merges.
	* Fixed typos in commit messages noticed by Philip Oakley.

Sergey Organov (27):
  revision: factor out parsing of diff-merge related options
  revision: factor out setup of diff-merge related settings
  revision: factor out initialization of diff-merge related settings
  revision: provide implementation for diff merges tweaks
  revision: move diff merges functions to its own diff-merges.c
  diff-merges: rename all functions to have common prefix
  diff-merges: move checks for first_parent_only out of the module
  diff-merges: rename diff_merges_default_to_enable() to match semantics
  diff-merges: re-arrange functions to match the order they are called
    in
  diff-merges: new function diff_merges_suppress()
  diff-merges: new function diff_merges_set_dense_combined_if_unset()
  diff-merges: introduce revs->first_parent_merges flag
  diff-merges: revise revs->diff flag handling
  t4013: support test_expect_failure through ':failure' magic
  t4013: add tests for -m failing to override -c/--cc
  diff-merges: fix -m to properly override -c/--cc
  diff-merges: split 'ignore_merges' field
  diff-merges: group diff-merge flags next to each other inside
    'rev_info'
  diff-merges: get rid of now empty diff_merges_init_revs()
  diff-merges: refactor opt settings into separate functions
  diff-merges: make -m/-c/--cc explicitly mutually exclusive
  diff-merges: implement new values for --diff-merges
  t4013: add test for --diff-merges=first-parent
  doc/git-log: describe new --diff-merges options
  doc/diff-generate-patch: mention new --diff-merges option
  doc/rev-list-options: document --first-parent implies
    --diff-merges=first-parent
  doc/git-show: include --diff-merges description

 Documentation/diff-generate-patch.txt         |   6 +-
 Documentation/diff-options.txt                |  54 +++++
 Documentation/git-log.txt                     |  39 ----
 Documentation/git-show.txt                    |   8 +-
 Documentation/rev-list-options.txt            |   3 +
 Makefile                                      |   1 +
 builtin/diff-files.c                          |   5 +-
 builtin/diff.c                                |   9 +-
 builtin/log.c                                 |  18 +-
 builtin/merge.c                               |   3 +-
 diff-merges.c                                 | 120 +++++++++++
 diff-merges.h                                 |  18 ++
 fmt-merge-msg.c                               |   3 +-
 log-tree.c                                    |  17 +-
 revision.c                                    |  38 +---
 revision.h                                    |   7 +-
 t/t4013-diff-various.sh                       |  10 +-
 t/t4013/diff.log_--cc_-m_-p_master            | 200 ++++++++++++++++++
 t/t4013/diff.log_-c_-m_-p_master              | 200 ++++++++++++++++++
 ...f.log_-p_--diff-merges=first-parent_master | 137 ++++++++++++
 20 files changed, 788 insertions(+), 108 deletions(-)
 create mode 100644 diff-merges.c
 create mode 100644 diff-merges.h
 create mode 100644 t/t4013/diff.log_--cc_-m_-p_master
 create mode 100644 t/t4013/diff.log_-c_-m_-p_master
 create mode 100644 t/t4013/diff.log_-p_--diff-merges=first-parent_master

-- 
2.25.1


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

* [PATCH v1 01/27] revision: factor out parsing of diff-merge related options
  2020-11-08 21:38 ` [PATCH v1 00/27] git-log: implement new --diff-merge options Sergey Organov
@ 2020-11-08 21:38   ` Sergey Organov
  2020-12-03  0:33     ` Junio C Hamano
  2020-11-08 21:38   ` [PATCH v1 02/27] revision: factor out setup of diff-merge related settings Sergey Organov
                     ` (26 subsequent siblings)
  27 siblings, 1 reply; 232+ messages in thread
From: Sergey Organov @ 2020-11-08 21:38 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, Philip Oakley, git, Sergey Organov

Move all the parsing code related to diffing merges into new
parse_diff_merge_opts() function.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 revision.c | 66 ++++++++++++++++++++++++++++++++----------------------
 1 file changed, 39 insertions(+), 27 deletions(-)

diff --git a/revision.c b/revision.c
index aa6221204081..a09f4872acd7 100644
--- a/revision.c
+++ b/revision.c
@@ -2153,6 +2153,44 @@ static void add_message_grep(struct rev_info *revs, const char *pattern)
 	add_grep(revs, pattern, GREP_PATTERN_BODY);
 }
 
+static int parse_diff_merge_opts(struct rev_info *revs, const char **argv) {
+	int argcount;
+	const char *optarg;
+	const char *arg = argv[0];
+
+	if (!strcmp(arg, "-m")) {
+		/*
+		 * To "diff-index", "-m" means "match missing", and to the "log"
+		 * family of commands, it means "show full diff for merges". Set
+		 * both fields appropriately.
+		 */
+		revs->ignore_merges = 0;
+		revs->match_missing = 1;
+	} else if (!strcmp(arg, "-c")) {
+		revs->diff = 1;
+		revs->dense_combined_merges = 0;
+		revs->combine_merges = 1;
+	} else if (!strcmp(arg, "--cc")) {
+		revs->diff = 1;
+		revs->dense_combined_merges = 1;
+		revs->combine_merges = 1;
+	} else if (!strcmp(arg, "--no-diff-merges")) {
+		revs->ignore_merges = 1;
+	} else if (!strcmp(arg, "--combined-all-paths")) {
+		revs->diff = 1;
+		revs->combined_all_paths = 1;
+	} else if ((argcount = parse_long_opt("diff-merges", argv, &optarg))) {
+		if (!strcmp(optarg, "off")) {
+			revs->ignore_merges = 1;
+		} else {
+			die(_("unknown value for --diff-merges: %s"), optarg);
+		}
+	} else
+		return 0;
+
+	return 1;
+}
+
 static int handle_revision_opt(struct rev_info *revs, int argc, const char **argv,
 			       int *unkc, const char **unkv,
 			       const struct setup_revision_opt* opt)
@@ -2349,34 +2387,8 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
 		revs->diff = 1;
 		revs->diffopt.flags.recursive = 1;
 		revs->diffopt.flags.tree_in_recursive = 1;
-	} else if (!strcmp(arg, "-m")) {
-		/*
-		 * To "diff-index", "-m" means "match missing", and to the "log"
-		 * family of commands, it means "show full diff for merges". Set
-		 * both fields appropriately.
-		 */
-		revs->ignore_merges = 0;
-		revs->match_missing = 1;
-	} else if ((argcount = parse_long_opt("diff-merges", argv, &optarg))) {
-		if (!strcmp(optarg, "off")) {
-			revs->ignore_merges = 1;
-		} else {
-			die(_("unknown value for --diff-merges: %s"), optarg);
-		}
+	} else if ((argcount = parse_diff_merge_opts(revs, argv))) {
 		return argcount;
-	} else if (!strcmp(arg, "--no-diff-merges")) {
-		revs->ignore_merges = 1;
-	} else if (!strcmp(arg, "-c")) {
-		revs->diff = 1;
-		revs->dense_combined_merges = 0;
-		revs->combine_merges = 1;
-	} else if (!strcmp(arg, "--combined-all-paths")) {
-		revs->diff = 1;
-		revs->combined_all_paths = 1;
-	} else if (!strcmp(arg, "--cc")) {
-		revs->diff = 1;
-		revs->dense_combined_merges = 1;
-		revs->combine_merges = 1;
 	} else if (!strcmp(arg, "-v")) {
 		revs->verbose_header = 1;
 	} else if (!strcmp(arg, "--pretty")) {
-- 
2.25.1


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

* [PATCH v1 02/27] revision: factor out setup of diff-merge related settings
  2020-11-08 21:38 ` [PATCH v1 00/27] git-log: implement new --diff-merge options Sergey Organov
  2020-11-08 21:38   ` [PATCH v1 01/27] revision: factor out parsing of diff-merge related options Sergey Organov
@ 2020-11-08 21:38   ` Sergey Organov
  2020-12-03  0:34     ` Junio C Hamano
  2020-11-08 21:38   ` [PATCH v1 03/27] revision: factor out initialization " Sergey Organov
                     ` (25 subsequent siblings)
  27 siblings, 1 reply; 232+ messages in thread
From: Sergey Organov @ 2020-11-08 21:38 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, Philip Oakley, git, Sergey Organov

Move all the setting code related to diffing merges into new
setup_diff_merge_revs() function.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 revision.c | 18 ++++++++++++------
 1 file changed, 12 insertions(+), 6 deletions(-)

diff --git a/revision.c b/revision.c
index a09f4872acd7..739295bb9ff4 100644
--- a/revision.c
+++ b/revision.c
@@ -2191,6 +2191,16 @@ static int parse_diff_merge_opts(struct rev_info *revs, const char **argv) {
 	return 1;
 }
 
+static void setup_diff_merges_revs(struct rev_info *revs)
+{
+	if (revs->combine_merges && revs->ignore_merges < 0)
+		revs->ignore_merges = 0;
+	if (revs->ignore_merges < 0)
+		revs->ignore_merges = 1;
+	if (revs->combined_all_paths && !revs->combine_merges)
+		die("--combined-all-paths makes no sense without -c or --cc");
+}
+
 static int handle_revision_opt(struct rev_info *revs, int argc, const char **argv,
 			       int *unkc, const char **unkv,
 			       const struct setup_revision_opt* opt)
@@ -2885,12 +2895,8 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
 			copy_pathspec(&revs->diffopt.pathspec,
 				      &revs->prune_data);
 	}
-	if (revs->combine_merges && revs->ignore_merges < 0)
-		revs->ignore_merges = 0;
-	if (revs->ignore_merges < 0)
-		revs->ignore_merges = 1;
-	if (revs->combined_all_paths && !revs->combine_merges)
-		die("--combined-all-paths makes no sense without -c or --cc");
+
+	setup_diff_merges_revs(revs);
 
 	revs->diffopt.abbrev = revs->abbrev;
 
-- 
2.25.1


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

* [PATCH v1 03/27] revision: factor out initialization of diff-merge related settings
  2020-11-08 21:38 ` [PATCH v1 00/27] git-log: implement new --diff-merge options Sergey Organov
  2020-11-08 21:38   ` [PATCH v1 01/27] revision: factor out parsing of diff-merge related options Sergey Organov
  2020-11-08 21:38   ` [PATCH v1 02/27] revision: factor out setup of diff-merge related settings Sergey Organov
@ 2020-11-08 21:38   ` Sergey Organov
  2020-12-03  0:39     ` Junio C Hamano
  2020-11-08 21:38   ` [PATCH v1 04/27] revision: provide implementation for diff merges tweaks Sergey Organov
                     ` (24 subsequent siblings)
  27 siblings, 1 reply; 232+ messages in thread
From: Sergey Organov @ 2020-11-08 21:38 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, Philip Oakley, git, Sergey Organov

Move initialization code related to diffing merges into new
init_diff_merge_revs() function.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 revision.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/revision.c b/revision.c
index 739295bb9ff4..bc568fb79778 100644
--- a/revision.c
+++ b/revision.c
@@ -1805,6 +1805,8 @@ static int add_parents_only(struct rev_info *revs, const char *arg_, int flags,
 	return 1;
 }
 
+static void init_diff_merge_revs(struct rev_info *revs);
+
 void repo_init_revisions(struct repository *r,
 			 struct rev_info *revs,
 			 const char *prefix)
@@ -1813,7 +1815,7 @@ void repo_init_revisions(struct repository *r,
 
 	revs->repo = r;
 	revs->abbrev = DEFAULT_ABBREV;
-	revs->ignore_merges = -1;
+	init_diff_merge_revs(revs);
 	revs->simplify_history = 1;
 	revs->pruning.repo = r;
 	revs->pruning.flags.recursive = 1;
@@ -2153,6 +2155,10 @@ static void add_message_grep(struct rev_info *revs, const char *pattern)
 	add_grep(revs, pattern, GREP_PATTERN_BODY);
 }
 
+static void init_diff_merge_revs(struct rev_info *revs) {
+	revs->ignore_merges = -1;
+}
+
 static int parse_diff_merge_opts(struct rev_info *revs, const char **argv) {
 	int argcount;
 	const char *optarg;
-- 
2.25.1


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

* [PATCH v1 04/27] revision: provide implementation for diff merges tweaks
  2020-11-08 21:38 ` [PATCH v1 00/27] git-log: implement new --diff-merge options Sergey Organov
                     ` (2 preceding siblings ...)
  2020-11-08 21:38   ` [PATCH v1 03/27] revision: factor out initialization " Sergey Organov
@ 2020-11-08 21:38   ` Sergey Organov
  2020-12-03  0:51     ` Junio C Hamano
  2020-11-08 21:38   ` [PATCH v1 05/27] revision: move diff merges functions to its own diff-merges.c Sergey Organov
                     ` (23 subsequent siblings)
  27 siblings, 1 reply; 232+ messages in thread
From: Sergey Organov @ 2020-11-08 21:38 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, Philip Oakley, git, Sergey Organov

Use these implementations from show_setup_revisions_tweak() and
log_setup_revisions_tweak() in builtin/log.c.

This completes moving of management of diff merges parameters to a
single place, where we can finally observe them simultaneously.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 builtin/log.c | 13 ++-----------
 revision.c    | 17 +++++++++++++++++
 revision.h    |  3 +++
 3 files changed, 22 insertions(+), 11 deletions(-)

diff --git a/builtin/log.c b/builtin/log.c
index 0a7ed4bef92b..717855a49e90 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -598,15 +598,7 @@ static int show_tree_object(const struct object_id *oid,
 static void show_setup_revisions_tweak(struct rev_info *rev,
 				       struct setup_revision_opt *opt)
 {
-	if (rev->ignore_merges < 0) {
-		/* There was no "-m" variant on the command line */
-		rev->ignore_merges = 0;
-		if (!rev->first_parent_only && !rev->combine_merges) {
-			/* No "--first-parent", "-c", or "--cc" */
-			rev->combine_merges = 1;
-			rev->dense_combined_merges = 1;
-		}
-	}
+	rev_diff_merges_default_to_dense_combined(rev);
 	if (!rev->diffopt.output_format)
 		rev->diffopt.output_format = DIFF_FORMAT_PATCH;
 }
@@ -731,8 +723,7 @@ static void log_setup_revisions_tweak(struct rev_info *rev,
 	if (!rev->diffopt.output_format && rev->combine_merges)
 		rev->diffopt.output_format = DIFF_FORMAT_PATCH;
 
-	if (rev->first_parent_only && rev->ignore_merges < 0)
-		rev->ignore_merges = 0;
+	rev_diff_merges_first_parent_defaults_to_enable(rev);
 }
 
 int cmd_log(int argc, const char **argv, const char *prefix)
diff --git a/revision.c b/revision.c
index bc568fb79778..ce90c2991657 100644
--- a/revision.c
+++ b/revision.c
@@ -2207,6 +2207,23 @@ static void setup_diff_merges_revs(struct rev_info *revs)
 		die("--combined-all-paths makes no sense without -c or --cc");
 }
 
+void rev_diff_merges_first_parent_defaults_to_enable(struct rev_info *revs) {
+	if (revs->first_parent_only && revs->ignore_merges < 0)
+		revs->ignore_merges = 0;
+}
+
+void rev_diff_merges_default_to_dense_combined(struct rev_info *revs) {
+	if (revs->ignore_merges < 0) {
+		/* There was no "-m" variant on the command line */
+		revs->ignore_merges = 0;
+		if (!revs->first_parent_only && !revs->combine_merges) {
+			/* No "--first-parent", "-c", or "--cc" */
+			revs->combine_merges = 1;
+			revs->dense_combined_merges = 1;
+		}
+	}
+}
+
 static int handle_revision_opt(struct rev_info *revs, int argc, const char **argv,
 			       int *unkc, const char **unkv,
 			       const struct setup_revision_opt* opt)
diff --git a/revision.h b/revision.h
index f6bf860d19e5..3dd0229f4edc 100644
--- a/revision.h
+++ b/revision.h
@@ -456,4 +456,7 @@ int rewrite_parents(struct rev_info *revs,
  */
 struct commit_list *get_saved_parents(struct rev_info *revs, const struct commit *commit);
 
+void rev_diff_merges_default_to_dense_combined(struct rev_info *revs);
+void rev_diff_merges_first_parent_defaults_to_enable(struct rev_info *revs);
+
 #endif
-- 
2.25.1


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

* [PATCH v1 05/27] revision: move diff merges functions to its own diff-merges.c
  2020-11-08 21:38 ` [PATCH v1 00/27] git-log: implement new --diff-merge options Sergey Organov
                     ` (3 preceding siblings ...)
  2020-11-08 21:38   ` [PATCH v1 04/27] revision: provide implementation for diff merges tweaks Sergey Organov
@ 2020-11-08 21:38   ` Sergey Organov
  2020-12-03  0:58     ` Junio C Hamano
  2020-11-08 21:38   ` [PATCH v1 06/27] diff-merges: rename all functions to have common prefix Sergey Organov
                     ` (22 subsequent siblings)
  27 siblings, 1 reply; 232+ messages in thread
From: Sergey Organov @ 2020-11-08 21:38 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, Philip Oakley, git, Sergey Organov

Create separate diff-merges.c and diff-merges.h files, and move all
the code related to handling of diff merges there.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 Makefile      |  1 +
 builtin/log.c |  1 +
 diff-merges.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++
 diff-merges.h | 12 +++++++++
 revision.c    | 72 +--------------------------------------------------
 revision.h    |  3 ---
 6 files changed, 87 insertions(+), 74 deletions(-)
 create mode 100644 diff-merges.c
 create mode 100644 diff-merges.h

diff --git a/Makefile b/Makefile
index 1fb0ec17059a..d1347ef262cf 100644
--- a/Makefile
+++ b/Makefile
@@ -872,6 +872,7 @@ LIB_OBJS += date.o
 LIB_OBJS += decorate.o
 LIB_OBJS += delta-islands.o
 LIB_OBJS += diff-delta.o
+LIB_OBJS += diff-merges.o
 LIB_OBJS += diff-lib.o
 LIB_OBJS += diff-no-index.o
 LIB_OBJS += diff.o
diff --git a/builtin/log.c b/builtin/log.c
index 717855a49e90..ad3092fdd854 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -12,6 +12,7 @@
 #include "color.h"
 #include "commit.h"
 #include "diff.h"
+#include "diff-merges.h"
 #include "revision.h"
 #include "log-tree.h"
 #include "builtin.h"
diff --git a/diff-merges.c b/diff-merges.c
new file mode 100644
index 000000000000..8b9dd4ad5625
--- /dev/null
+++ b/diff-merges.c
@@ -0,0 +1,72 @@
+#include "diff-merges.h"
+
+#include "revision.h"
+
+void init_diff_merge_revs(struct rev_info *revs) {
+	revs->ignore_merges = -1;
+}
+
+int parse_diff_merge_opts(struct rev_info *revs, const char **argv) {
+	int argcount;
+	const char *optarg;
+	const char *arg = argv[0];
+
+	if (!strcmp(arg, "-m")) {
+		/*
+		 * To "diff-index", "-m" means "match missing", and to the "log"
+		 * family of commands, it means "show full diff for merges". Set
+		 * both fields appropriately.
+		 */
+		revs->ignore_merges = 0;
+		revs->match_missing = 1;
+	} else if (!strcmp(arg, "-c")) {
+		revs->diff = 1;
+		revs->dense_combined_merges = 0;
+		revs->combine_merges = 1;
+	} else if (!strcmp(arg, "--cc")) {
+		revs->diff = 1;
+		revs->dense_combined_merges = 1;
+		revs->combine_merges = 1;
+	} else if (!strcmp(arg, "--no-diff-merges")) {
+		revs->ignore_merges = 1;
+	} else if (!strcmp(arg, "--combined-all-paths")) {
+		revs->diff = 1;
+		revs->combined_all_paths = 1;
+	} else if ((argcount = parse_long_opt("diff-merges", argv, &optarg))) {
+		if (!strcmp(optarg, "off")) {
+			revs->ignore_merges = 1;
+		} else {
+			die(_("unknown value for --diff-merges: %s"), optarg);
+		}
+	} else
+		return 0;
+
+	return 1;
+}
+
+void setup_diff_merges_revs(struct rev_info *revs)
+{
+	if (revs->combine_merges && revs->ignore_merges < 0)
+		revs->ignore_merges = 0;
+	if (revs->ignore_merges < 0)
+		revs->ignore_merges = 1;
+	if (revs->combined_all_paths && !revs->combine_merges)
+		die("--combined-all-paths makes no sense without -c or --cc");
+}
+
+void rev_diff_merges_first_parent_defaults_to_enable(struct rev_info *revs) {
+	if (revs->first_parent_only && revs->ignore_merges < 0)
+		revs->ignore_merges = 0;
+}
+
+void rev_diff_merges_default_to_dense_combined(struct rev_info *revs) {
+	if (revs->ignore_merges < 0) {
+		/* There was no "-m" variant on the command line */
+		revs->ignore_merges = 0;
+		if (!revs->first_parent_only && !revs->combine_merges) {
+			/* No "--first-parent", "-c", or "--cc" */
+			revs->combine_merges = 1;
+			revs->dense_combined_merges = 1;
+		}
+	}
+}
diff --git a/diff-merges.h b/diff-merges.h
new file mode 100644
index 000000000000..e0cca3d935d3
--- /dev/null
+++ b/diff-merges.h
@@ -0,0 +1,12 @@
+#ifndef DIFF_MERGES_H
+#define DIFF_MERGES_H
+
+struct rev_info;
+
+void init_diff_merge_revs(struct rev_info *revs);
+int parse_diff_merge_opts(struct rev_info *revs, const char **argv);
+void setup_diff_merges_revs(struct rev_info *revs);
+void rev_diff_merges_default_to_dense_combined(struct rev_info *revs);
+void rev_diff_merges_first_parent_defaults_to_enable(struct rev_info *revs);
+
+#endif
diff --git a/revision.c b/revision.c
index ce90c2991657..4bc14a08a624 100644
--- a/revision.c
+++ b/revision.c
@@ -5,6 +5,7 @@
 #include "tree.h"
 #include "commit.h"
 #include "diff.h"
+#include "diff-merges.h"
 #include "refs.h"
 #include "revision.h"
 #include "repository.h"
@@ -1805,8 +1806,6 @@ static int add_parents_only(struct rev_info *revs, const char *arg_, int flags,
 	return 1;
 }
 
-static void init_diff_merge_revs(struct rev_info *revs);
-
 void repo_init_revisions(struct repository *r,
 			 struct rev_info *revs,
 			 const char *prefix)
@@ -2155,75 +2154,6 @@ static void add_message_grep(struct rev_info *revs, const char *pattern)
 	add_grep(revs, pattern, GREP_PATTERN_BODY);
 }
 
-static void init_diff_merge_revs(struct rev_info *revs) {
-	revs->ignore_merges = -1;
-}
-
-static int parse_diff_merge_opts(struct rev_info *revs, const char **argv) {
-	int argcount;
-	const char *optarg;
-	const char *arg = argv[0];
-
-	if (!strcmp(arg, "-m")) {
-		/*
-		 * To "diff-index", "-m" means "match missing", and to the "log"
-		 * family of commands, it means "show full diff for merges". Set
-		 * both fields appropriately.
-		 */
-		revs->ignore_merges = 0;
-		revs->match_missing = 1;
-	} else if (!strcmp(arg, "-c")) {
-		revs->diff = 1;
-		revs->dense_combined_merges = 0;
-		revs->combine_merges = 1;
-	} else if (!strcmp(arg, "--cc")) {
-		revs->diff = 1;
-		revs->dense_combined_merges = 1;
-		revs->combine_merges = 1;
-	} else if (!strcmp(arg, "--no-diff-merges")) {
-		revs->ignore_merges = 1;
-	} else if (!strcmp(arg, "--combined-all-paths")) {
-		revs->diff = 1;
-		revs->combined_all_paths = 1;
-	} else if ((argcount = parse_long_opt("diff-merges", argv, &optarg))) {
-		if (!strcmp(optarg, "off")) {
-			revs->ignore_merges = 1;
-		} else {
-			die(_("unknown value for --diff-merges: %s"), optarg);
-		}
-	} else
-		return 0;
-
-	return 1;
-}
-
-static void setup_diff_merges_revs(struct rev_info *revs)
-{
-	if (revs->combine_merges && revs->ignore_merges < 0)
-		revs->ignore_merges = 0;
-	if (revs->ignore_merges < 0)
-		revs->ignore_merges = 1;
-	if (revs->combined_all_paths && !revs->combine_merges)
-		die("--combined-all-paths makes no sense without -c or --cc");
-}
-
-void rev_diff_merges_first_parent_defaults_to_enable(struct rev_info *revs) {
-	if (revs->first_parent_only && revs->ignore_merges < 0)
-		revs->ignore_merges = 0;
-}
-
-void rev_diff_merges_default_to_dense_combined(struct rev_info *revs) {
-	if (revs->ignore_merges < 0) {
-		/* There was no "-m" variant on the command line */
-		revs->ignore_merges = 0;
-		if (!revs->first_parent_only && !revs->combine_merges) {
-			/* No "--first-parent", "-c", or "--cc" */
-			revs->combine_merges = 1;
-			revs->dense_combined_merges = 1;
-		}
-	}
-}
-
 static int handle_revision_opt(struct rev_info *revs, int argc, const char **argv,
 			       int *unkc, const char **unkv,
 			       const struct setup_revision_opt* opt)
diff --git a/revision.h b/revision.h
index 3dd0229f4edc..f6bf860d19e5 100644
--- a/revision.h
+++ b/revision.h
@@ -456,7 +456,4 @@ int rewrite_parents(struct rev_info *revs,
  */
 struct commit_list *get_saved_parents(struct rev_info *revs, const struct commit *commit);
 
-void rev_diff_merges_default_to_dense_combined(struct rev_info *revs);
-void rev_diff_merges_first_parent_defaults_to_enable(struct rev_info *revs);
-
 #endif
-- 
2.25.1


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

* [PATCH v1 06/27] diff-merges: rename all functions to have common prefix
  2020-11-08 21:38 ` [PATCH v1 00/27] git-log: implement new --diff-merge options Sergey Organov
                     ` (4 preceding siblings ...)
  2020-11-08 21:38   ` [PATCH v1 05/27] revision: move diff merges functions to its own diff-merges.c Sergey Organov
@ 2020-11-08 21:38   ` Sergey Organov
  2020-12-03  0:52     ` Junio C Hamano
  2020-11-08 21:38   ` [PATCH v1 07/27] diff-merges: move checks for first_parent_only out of the module Sergey Organov
                     ` (21 subsequent siblings)
  27 siblings, 1 reply; 232+ messages in thread
From: Sergey Organov @ 2020-11-08 21:38 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, Philip Oakley, git, Sergey Organov

Use the same "diff_merges" prefix for all the diff merges function
names.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 builtin/log.c |  4 ++--
 diff-merges.c | 10 +++++-----
 diff-merges.h | 15 ++++++++++-----
 revision.c    |  6 +++---
 4 files changed, 20 insertions(+), 15 deletions(-)

diff --git a/builtin/log.c b/builtin/log.c
index ad3092fdd854..77a7bba543ad 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -599,7 +599,7 @@ static int show_tree_object(const struct object_id *oid,
 static void show_setup_revisions_tweak(struct rev_info *rev,
 				       struct setup_revision_opt *opt)
 {
-	rev_diff_merges_default_to_dense_combined(rev);
+	diff_merges_default_to_dense_combined(rev);
 	if (!rev->diffopt.output_format)
 		rev->diffopt.output_format = DIFF_FORMAT_PATCH;
 }
@@ -724,7 +724,7 @@ static void log_setup_revisions_tweak(struct rev_info *rev,
 	if (!rev->diffopt.output_format && rev->combine_merges)
 		rev->diffopt.output_format = DIFF_FORMAT_PATCH;
 
-	rev_diff_merges_first_parent_defaults_to_enable(rev);
+	diff_merges_first_parent_defaults_to_enable(rev);
 }
 
 int cmd_log(int argc, const char **argv, const char *prefix)
diff --git a/diff-merges.c b/diff-merges.c
index 8b9dd4ad5625..85bf0b6d1d1d 100644
--- a/diff-merges.c
+++ b/diff-merges.c
@@ -2,11 +2,11 @@
 
 #include "revision.h"
 
-void init_diff_merge_revs(struct rev_info *revs) {
+void diff_merges_init_revs(struct rev_info *revs) {
 	revs->ignore_merges = -1;
 }
 
-int parse_diff_merge_opts(struct rev_info *revs, const char **argv) {
+int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {
 	int argcount;
 	const char *optarg;
 	const char *arg = argv[0];
@@ -44,7 +44,7 @@ int parse_diff_merge_opts(struct rev_info *revs, const char **argv) {
 	return 1;
 }
 
-void setup_diff_merges_revs(struct rev_info *revs)
+void diff_merges_setup_revs(struct rev_info *revs)
 {
 	if (revs->combine_merges && revs->ignore_merges < 0)
 		revs->ignore_merges = 0;
@@ -54,12 +54,12 @@ void setup_diff_merges_revs(struct rev_info *revs)
 		die("--combined-all-paths makes no sense without -c or --cc");
 }
 
-void rev_diff_merges_first_parent_defaults_to_enable(struct rev_info *revs) {
+void diff_merges_first_parent_defaults_to_enable(struct rev_info *revs) {
 	if (revs->first_parent_only && revs->ignore_merges < 0)
 		revs->ignore_merges = 0;
 }
 
-void rev_diff_merges_default_to_dense_combined(struct rev_info *revs) {
+void diff_merges_default_to_dense_combined(struct rev_info *revs) {
 	if (revs->ignore_merges < 0) {
 		/* There was no "-m" variant on the command line */
 		revs->ignore_merges = 0;
diff --git a/diff-merges.h b/diff-merges.h
index e0cca3d935d3..648c410497cb 100644
--- a/diff-merges.h
+++ b/diff-merges.h
@@ -3,10 +3,15 @@
 
 struct rev_info;
 
-void init_diff_merge_revs(struct rev_info *revs);
-int parse_diff_merge_opts(struct rev_info *revs, const char **argv);
-void setup_diff_merges_revs(struct rev_info *revs);
-void rev_diff_merges_default_to_dense_combined(struct rev_info *revs);
-void rev_diff_merges_first_parent_defaults_to_enable(struct rev_info *revs);
+void diff_merges_init_revs(struct rev_info *revs);
+
+int diff_merges_parse_opts(struct rev_info *revs, const char **argv);
+
+void diff_merges_setup_revs(struct rev_info *revs);
+
+void diff_merges_default_to_dense_combined(struct rev_info *revs);
+
+void diff_merges_first_parent_defaults_to_enable(struct rev_info *revs);
+
 
 #endif
diff --git a/revision.c b/revision.c
index 4bc14a08a624..5a0e3d6ad542 100644
--- a/revision.c
+++ b/revision.c
@@ -1814,7 +1814,7 @@ void repo_init_revisions(struct repository *r,
 
 	revs->repo = r;
 	revs->abbrev = DEFAULT_ABBREV;
-	init_diff_merge_revs(revs);
+	diff_merges_init_revs(revs);
 	revs->simplify_history = 1;
 	revs->pruning.repo = r;
 	revs->pruning.flags.recursive = 1;
@@ -2350,7 +2350,7 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
 		revs->diff = 1;
 		revs->diffopt.flags.recursive = 1;
 		revs->diffopt.flags.tree_in_recursive = 1;
-	} else if ((argcount = parse_diff_merge_opts(revs, argv))) {
+	} else if ((argcount = diff_merges_parse_opts(revs, argv))) {
 		return argcount;
 	} else if (!strcmp(arg, "-v")) {
 		revs->verbose_header = 1;
@@ -2849,7 +2849,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
 				      &revs->prune_data);
 	}
 
-	setup_diff_merges_revs(revs);
+	diff_merges_setup_revs(revs);
 
 	revs->diffopt.abbrev = revs->abbrev;
 
-- 
2.25.1


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

* [PATCH v1 07/27] diff-merges: move checks for first_parent_only out of the module
  2020-11-08 21:38 ` [PATCH v1 00/27] git-log: implement new --diff-merge options Sergey Organov
                     ` (5 preceding siblings ...)
  2020-11-08 21:38   ` [PATCH v1 06/27] diff-merges: rename all functions to have common prefix Sergey Organov
@ 2020-11-08 21:38   ` Sergey Organov
  2020-12-03  1:09     ` Junio C Hamano
  2020-11-08 21:38   ` [PATCH v1 08/27] diff-merges: rename diff_merges_default_to_enable() to match semantics Sergey Organov
                     ` (20 subsequent siblings)
  27 siblings, 1 reply; 232+ messages in thread
From: Sergey Organov @ 2020-11-08 21:38 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, Philip Oakley, git, Sergey Organov

The checks for first_parent_only don't in fact belong to this module,
as the primary purpose of this flag is history traversal limiting, so
get it out of this module and rename the

diff_merges_first_parent_defaults_to_enable()

to

diff_merges_default_to_enable()

to match new semantics.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 builtin/log.c |  8 ++++++--
 diff-merges.c | 10 ++++------
 diff-merges.h |  2 +-
 3 files changed, 11 insertions(+), 9 deletions(-)

diff --git a/builtin/log.c b/builtin/log.c
index 77a7bba543ad..a7791c003c91 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -599,7 +599,10 @@ static int show_tree_object(const struct object_id *oid,
 static void show_setup_revisions_tweak(struct rev_info *rev,
 				       struct setup_revision_opt *opt)
 {
-	diff_merges_default_to_dense_combined(rev);
+	if (rev->first_parent_only)
+		diff_merges_default_to_enable(rev);
+	else
+		diff_merges_default_to_dense_combined(rev);
 	if (!rev->diffopt.output_format)
 		rev->diffopt.output_format = DIFF_FORMAT_PATCH;
 }
@@ -724,7 +727,8 @@ static void log_setup_revisions_tweak(struct rev_info *rev,
 	if (!rev->diffopt.output_format && rev->combine_merges)
 		rev->diffopt.output_format = DIFF_FORMAT_PATCH;
 
-	diff_merges_first_parent_defaults_to_enable(rev);
+	if (rev->first_parent_only)
+		diff_merges_default_to_enable(rev);
 }
 
 int cmd_log(int argc, const char **argv, const char *prefix)
diff --git a/diff-merges.c b/diff-merges.c
index 85bf0b6d1d1d..9dd472803d15 100644
--- a/diff-merges.c
+++ b/diff-merges.c
@@ -54,17 +54,15 @@ void diff_merges_setup_revs(struct rev_info *revs)
 		die("--combined-all-paths makes no sense without -c or --cc");
 }
 
-void diff_merges_first_parent_defaults_to_enable(struct rev_info *revs) {
-	if (revs->first_parent_only && revs->ignore_merges < 0)
+void diff_merges_default_to_enable(struct rev_info *revs) {
+	if (revs->ignore_merges < 0)		/* No -m */
 		revs->ignore_merges = 0;
 }
 
 void diff_merges_default_to_dense_combined(struct rev_info *revs) {
-	if (revs->ignore_merges < 0) {
-		/* There was no "-m" variant on the command line */
+	if (revs->ignore_merges < 0) {		/* No -m */
 		revs->ignore_merges = 0;
-		if (!revs->first_parent_only && !revs->combine_merges) {
-			/* No "--first-parent", "-c", or "--cc" */
+		if (!revs->combine_merges) {	/* No -c/--cc" */
 			revs->combine_merges = 1;
 			revs->dense_combined_merges = 1;
 		}
diff --git a/diff-merges.h b/diff-merges.h
index 648c410497cb..cf411414898d 100644
--- a/diff-merges.h
+++ b/diff-merges.h
@@ -11,7 +11,7 @@ void diff_merges_setup_revs(struct rev_info *revs);
 
 void diff_merges_default_to_dense_combined(struct rev_info *revs);
 
-void diff_merges_first_parent_defaults_to_enable(struct rev_info *revs);
+void diff_merges_default_to_enable(struct rev_info *revs);
 
 
 #endif
-- 
2.25.1


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

* [PATCH v1 08/27] diff-merges: rename diff_merges_default_to_enable() to match semantics
  2020-11-08 21:38 ` [PATCH v1 00/27] git-log: implement new --diff-merge options Sergey Organov
                     ` (6 preceding siblings ...)
  2020-11-08 21:38   ` [PATCH v1 07/27] diff-merges: move checks for first_parent_only out of the module Sergey Organov
@ 2020-11-08 21:38   ` Sergey Organov
  2020-11-08 21:38   ` [PATCH v1 09/27] diff-merges: re-arrange functions to match the order they are called in Sergey Organov
                     ` (19 subsequent siblings)
  27 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-11-08 21:38 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, Philip Oakley, git, Sergey Organov

Rename diff_merges_default_to_enable() to
diff_merges_default_to_first_parent() to match its semantics.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 builtin/log.c | 4 ++--
 diff-merges.c | 2 +-
 diff-merges.h | 2 +-
 3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/builtin/log.c b/builtin/log.c
index a7791c003c91..63875c3aeec9 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -600,7 +600,7 @@ static void show_setup_revisions_tweak(struct rev_info *rev,
 				       struct setup_revision_opt *opt)
 {
 	if (rev->first_parent_only)
-		diff_merges_default_to_enable(rev);
+		diff_merges_default_to_first_parent(rev);
 	else
 		diff_merges_default_to_dense_combined(rev);
 	if (!rev->diffopt.output_format)
@@ -728,7 +728,7 @@ static void log_setup_revisions_tweak(struct rev_info *rev,
 		rev->diffopt.output_format = DIFF_FORMAT_PATCH;
 
 	if (rev->first_parent_only)
-		diff_merges_default_to_enable(rev);
+		diff_merges_default_to_first_parent(rev);
 }
 
 int cmd_log(int argc, const char **argv, const char *prefix)
diff --git a/diff-merges.c b/diff-merges.c
index 9dd472803d15..bb08a92e3b36 100644
--- a/diff-merges.c
+++ b/diff-merges.c
@@ -54,7 +54,7 @@ void diff_merges_setup_revs(struct rev_info *revs)
 		die("--combined-all-paths makes no sense without -c or --cc");
 }
 
-void diff_merges_default_to_enable(struct rev_info *revs) {
+void diff_merges_default_to_first_parent(struct rev_info *revs) {
 	if (revs->ignore_merges < 0)		/* No -m */
 		revs->ignore_merges = 0;
 }
diff --git a/diff-merges.h b/diff-merges.h
index cf411414898d..20b727bd734f 100644
--- a/diff-merges.h
+++ b/diff-merges.h
@@ -11,7 +11,7 @@ void diff_merges_setup_revs(struct rev_info *revs);
 
 void diff_merges_default_to_dense_combined(struct rev_info *revs);
 
-void diff_merges_default_to_enable(struct rev_info *revs);
+void diff_merges_default_to_first_parent(struct rev_info *revs);
 
 
 #endif
-- 
2.25.1


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

* [PATCH v1 09/27] diff-merges: re-arrange functions to match the order they are called in
  2020-11-08 21:38 ` [PATCH v1 00/27] git-log: implement new --diff-merge options Sergey Organov
                     ` (7 preceding siblings ...)
  2020-11-08 21:38   ` [PATCH v1 08/27] diff-merges: rename diff_merges_default_to_enable() to match semantics Sergey Organov
@ 2020-11-08 21:38   ` Sergey Organov
  2020-12-03  5:52     ` Elijah Newren
  2020-11-08 21:38   ` [PATCH v1 10/27] diff-merges: new function diff_merges_suppress() Sergey Organov
                     ` (18 subsequent siblings)
  27 siblings, 1 reply; 232+ messages in thread
From: Sergey Organov @ 2020-11-08 21:38 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, Philip Oakley, git, Sergey Organov

For clarity, define public functions in the order they are called, to
make logic inter-dependencies easier to grok.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 diff-merges.c | 24 ++++++++++++++----------
 diff-merges.h |  7 +++----
 2 files changed, 17 insertions(+), 14 deletions(-)

diff --git a/diff-merges.c b/diff-merges.c
index bb08a92e3b36..8536941e0b56 100644
--- a/diff-merges.c
+++ b/diff-merges.c
@@ -2,6 +2,10 @@
 
 #include "revision.h"
 
+/*
+ * Public functions. They are in the order they are called.
+ */
+
 void diff_merges_init_revs(struct rev_info *revs) {
 	revs->ignore_merges = -1;
 }
@@ -44,16 +48,6 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {
 	return 1;
 }
 
-void diff_merges_setup_revs(struct rev_info *revs)
-{
-	if (revs->combine_merges && revs->ignore_merges < 0)
-		revs->ignore_merges = 0;
-	if (revs->ignore_merges < 0)
-		revs->ignore_merges = 1;
-	if (revs->combined_all_paths && !revs->combine_merges)
-		die("--combined-all-paths makes no sense without -c or --cc");
-}
-
 void diff_merges_default_to_first_parent(struct rev_info *revs) {
 	if (revs->ignore_merges < 0)		/* No -m */
 		revs->ignore_merges = 0;
@@ -68,3 +62,13 @@ void diff_merges_default_to_dense_combined(struct rev_info *revs) {
 		}
 	}
 }
+
+void diff_merges_setup_revs(struct rev_info *revs)
+{
+	if (revs->combine_merges && revs->ignore_merges < 0)
+		revs->ignore_merges = 0;
+	if (revs->ignore_merges < 0)
+		revs->ignore_merges = 1;
+	if (revs->combined_all_paths && !revs->combine_merges)
+		die("--combined-all-paths makes no sense without -c or --cc");
+}
diff --git a/diff-merges.h b/diff-merges.h
index 20b727bd734f..4b023c385d00 100644
--- a/diff-merges.h
+++ b/diff-merges.h
@@ -7,11 +7,10 @@ void diff_merges_init_revs(struct rev_info *revs);
 
 int diff_merges_parse_opts(struct rev_info *revs, const char **argv);
 
-void diff_merges_setup_revs(struct rev_info *revs);
-
-void diff_merges_default_to_dense_combined(struct rev_info *revs);
-
 void diff_merges_default_to_first_parent(struct rev_info *revs);
 
+void diff_merges_default_to_dense_combined(struct rev_info *revs);
+
+void diff_merges_setup_revs(struct rev_info *revs);
 
 #endif
-- 
2.25.1


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

* [PATCH v1 10/27] diff-merges: new function diff_merges_suppress()
  2020-11-08 21:38 ` [PATCH v1 00/27] git-log: implement new --diff-merge options Sergey Organov
                     ` (8 preceding siblings ...)
  2020-11-08 21:38   ` [PATCH v1 09/27] diff-merges: re-arrange functions to match the order they are called in Sergey Organov
@ 2020-11-08 21:38   ` Sergey Organov
  2020-11-08 21:38   ` [PATCH v1 11/27] diff-merges: new function diff_merges_set_dense_combined_if_unset() Sergey Organov
                     ` (17 subsequent siblings)
  27 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-11-08 21:38 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, Philip Oakley, git, Sergey Organov

This function sets all the relevant flags to disabled state, so that
no code that checks only one of them get it wrong.

Then we call this new function everywhere where diff merges output
suppression is needed.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 builtin/merge.c |  3 ++-
 diff-merges.c   | 18 ++++++++++++++----
 diff-merges.h   |  2 ++
 fmt-merge-msg.c |  3 ++-
 4 files changed, 20 insertions(+), 6 deletions(-)

diff --git a/builtin/merge.c b/builtin/merge.c
index 9d5359edc2f7..1f7b69982b40 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -14,6 +14,7 @@
 #include "lockfile.h"
 #include "run-command.h"
 #include "diff.h"
+#include "diff-merges.h"
 #include "refs.h"
 #include "refspec.h"
 #include "commit.h"
@@ -400,7 +401,7 @@ static void squash_message(struct commit *commit, struct commit_list *remotehead
 	printf(_("Squash commit -- not updating HEAD\n"));
 
 	repo_init_revisions(the_repository, &rev, NULL);
-	rev.ignore_merges = 1;
+	diff_merges_suppress(&rev);
 	rev.commit_format = CMIT_FMT_MEDIUM;
 
 	commit->object.flags |= UNINTERESTING;
diff --git a/diff-merges.c b/diff-merges.c
index 8536941e0b56..25bd9b12e667 100644
--- a/diff-merges.c
+++ b/diff-merges.c
@@ -2,6 +2,13 @@
 
 #include "revision.h"
 
+static void suppress(struct rev_info *revs) {
+	revs->ignore_merges = 1;
+	revs->first_parent_merges = 0;
+	revs->combine_merges = 0;
+	revs->dense_combined_merges = 0;
+}
+
 /*
  * Public functions. They are in the order they are called.
  */
@@ -29,16 +36,15 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {
 		revs->combine_merges = 1;
 	} else if (!strcmp(arg, "--cc")) {
 		revs->diff = 1;
-		revs->dense_combined_merges = 1;
-		revs->combine_merges = 1;
+		set_dense_combined(revs);
 	} else if (!strcmp(arg, "--no-diff-merges")) {
-		revs->ignore_merges = 1;
+		suppress(revs);
 	} else if (!strcmp(arg, "--combined-all-paths")) {
 		revs->diff = 1;
 		revs->combined_all_paths = 1;
 	} else if ((argcount = parse_long_opt("diff-merges", argv, &optarg))) {
 		if (!strcmp(optarg, "off")) {
-			revs->ignore_merges = 1;
+			suppress(revs);
 		} else {
 			die(_("unknown value for --diff-merges: %s"), optarg);
 		}
@@ -48,6 +54,10 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {
 	return 1;
 }
 
+void diff_merges_suppress(struct rev_info *revs) {
+	suppress(revs);
+}
+
 void diff_merges_default_to_first_parent(struct rev_info *revs) {
 	if (revs->ignore_merges < 0)		/* No -m */
 		revs->ignore_merges = 0;
diff --git a/diff-merges.h b/diff-merges.h
index 4b023c385d00..32720bc9b40f 100644
--- a/diff-merges.h
+++ b/diff-merges.h
@@ -7,6 +7,8 @@ void diff_merges_init_revs(struct rev_info *revs);
 
 int diff_merges_parse_opts(struct rev_info *revs, const char **argv);
 
+void diff_merges_suppress(struct rev_info *revs);
+
 void diff_merges_default_to_first_parent(struct rev_info *revs);
 
 void diff_merges_default_to_dense_combined(struct rev_info *revs);
diff --git a/fmt-merge-msg.c b/fmt-merge-msg.c
index bd22e1ea8865..abc3403fb820 100644
--- a/fmt-merge-msg.c
+++ b/fmt-merge-msg.c
@@ -2,6 +2,7 @@
 #include "refs.h"
 #include "object-store.h"
 #include "diff.h"
+#include "diff-merges.h"
 #include "revision.h"
 #include "tag.h"
 #include "string-list.h"
@@ -668,7 +669,7 @@ int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
 		head = lookup_commit_or_die(&head_oid, "HEAD");
 		repo_init_revisions(the_repository, &rev, NULL);
 		rev.commit_format = CMIT_FMT_ONELINE;
-		rev.ignore_merges = 1;
+		diff_merges_suppress(&rev);
 		rev.limited = 1;
 
 		strbuf_complete_line(out);
-- 
2.25.1


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

* [PATCH v1 11/27] diff-merges: new function diff_merges_set_dense_combined_if_unset()
  2020-11-08 21:38 ` [PATCH v1 00/27] git-log: implement new --diff-merge options Sergey Organov
                     ` (9 preceding siblings ...)
  2020-11-08 21:38   ` [PATCH v1 10/27] diff-merges: new function diff_merges_suppress() Sergey Organov
@ 2020-11-08 21:38   ` Sergey Organov
  2020-11-08 21:38   ` [PATCH v1 12/27] diff-merges: introduce revs->first_parent_merges flag Sergey Organov
                     ` (16 subsequent siblings)
  27 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-11-08 21:38 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, Philip Oakley, git, Sergey Organov

Call it where given functionality is needed instead of direct
checking/tweaking of diff merges related fields.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 builtin/diff-files.c |  5 +++--
 builtin/diff.c       |  9 +++++----
 diff-merges.c        | 11 +++++++++++
 diff-merges.h        |  2 ++
 4 files changed, 21 insertions(+), 6 deletions(-)

diff --git a/builtin/diff-files.c b/builtin/diff-files.c
index 1e352dd8f77c..4742a4559b21 100644
--- a/builtin/diff-files.c
+++ b/builtin/diff-files.c
@@ -7,6 +7,7 @@
 #include "cache.h"
 #include "config.h"
 #include "diff.h"
+#include "diff-merges.h"
 #include "commit.h"
 #include "revision.h"
 #include "builtin.h"
@@ -69,9 +70,9 @@ int cmd_diff_files(int argc, const char **argv, const char *prefix)
 	 * was not asked to.  "diff-files -c -p" should not densify
 	 * (the user should ask with "diff-files --cc" explicitly).
 	 */
-	if (rev.max_count == -1 && !rev.combine_merges &&
+	if (rev.max_count == -1 &&
 	    (rev.diffopt.output_format & DIFF_FORMAT_PATCH))
-		rev.combine_merges = rev.dense_combined_merges = 1;
+		diff_merges_set_dense_combined_if_unset(&rev);
 
 	if (read_cache_preload(&rev.diffopt.pathspec) < 0) {
 		perror("read_cache_preload");
diff --git a/builtin/diff.c b/builtin/diff.c
index cd4083fed96e..2f570a3131cb 100644
--- a/builtin/diff.c
+++ b/builtin/diff.c
@@ -13,6 +13,7 @@
 #include "blob.h"
 #include "tag.h"
 #include "diff.h"
+#include "diff-merges.h"
 #include "diffcore.h"
 #include "revision.h"
 #include "log-tree.h"
@@ -199,8 +200,8 @@ static int builtin_diff_combined(struct rev_info *revs,
 	if (argc > 1)
 		usage(builtin_diff_usage);
 
-	if (!revs->dense_combined_merges && !revs->combine_merges)
-		revs->dense_combined_merges = revs->combine_merges = 1;
+	diff_merges_set_dense_combined_if_unset(revs);
+
 	for (i = 1; i < ents; i++)
 		oid_array_append(&parents, &ent[i].item->oid);
 	diff_tree_combined(&ent[0].item->oid, &parents, revs);
@@ -248,9 +249,9 @@ static int builtin_diff_files(struct rev_info *revs, int argc, const char **argv
 	 * dense one, --cc can be explicitly asked for, or just rely
 	 * on the default).
 	 */
-	if (revs->max_count == -1 && !revs->combine_merges &&
+	if (revs->max_count == -1 &&
 	    (revs->diffopt.output_format & DIFF_FORMAT_PATCH))
-		revs->combine_merges = revs->dense_combined_merges = 1;
+		diff_merges_set_dense_combined_if_unset(revs);
 
 	setup_work_tree();
 	if (read_cache_preload(&revs->diffopt.pathspec) < 0) {
diff --git a/diff-merges.c b/diff-merges.c
index 25bd9b12e667..691aabadbb32 100644
--- a/diff-merges.c
+++ b/diff-merges.c
@@ -9,6 +9,12 @@ static void suppress(struct rev_info *revs) {
 	revs->dense_combined_merges = 0;
 }
 
+static void set_dense_combined(struct rev_info *revs) {
+	revs->combine_merges = 1;
+	revs->dense_combined_merges = 1;
+}
+
+
 /*
  * Public functions. They are in the order they are called.
  */
@@ -73,6 +79,11 @@ void diff_merges_default_to_dense_combined(struct rev_info *revs) {
 	}
 }
 
+void diff_merges_set_dense_combined_if_unset(struct rev_info *revs) {
+	if (!revs->combine_merges)
+		set_dense_combined(revs);
+}
+
 void diff_merges_setup_revs(struct rev_info *revs)
 {
 	if (revs->combine_merges && revs->ignore_merges < 0)
diff --git a/diff-merges.h b/diff-merges.h
index 32720bc9b40f..ae1cc8ef9410 100644
--- a/diff-merges.h
+++ b/diff-merges.h
@@ -13,6 +13,8 @@ void diff_merges_default_to_first_parent(struct rev_info *revs);
 
 void diff_merges_default_to_dense_combined(struct rev_info *revs);
 
+void diff_merges_set_dense_combined_if_unset(struct rev_info *revs);
+
 void diff_merges_setup_revs(struct rev_info *revs);
 
 #endif
-- 
2.25.1


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

* [PATCH v1 12/27] diff-merges: introduce revs->first_parent_merges flag
  2020-11-08 21:38 ` [PATCH v1 00/27] git-log: implement new --diff-merge options Sergey Organov
                     ` (10 preceding siblings ...)
  2020-11-08 21:38   ` [PATCH v1 11/27] diff-merges: new function diff_merges_set_dense_combined_if_unset() Sergey Organov
@ 2020-11-08 21:38   ` Sergey Organov
  2020-11-08 21:38   ` [PATCH v1 13/27] diff-merges: revise revs->diff flag handling Sergey Organov
                     ` (15 subsequent siblings)
  27 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-11-08 21:38 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, Philip Oakley, git, Sergey Organov

This new field allows us to separate format of diff for merges from
'first_parent_only' flag which primary purpose is limiting history
traversal.

This change further localizes diff format selection logic into the
diff-merges.c file.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 diff-merges.c | 2 ++
 log-tree.c    | 4 ++--
 revision.h    | 1 +
 3 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/diff-merges.c b/diff-merges.c
index 691aabadbb32..63912ddedc76 100644
--- a/diff-merges.c
+++ b/diff-merges.c
@@ -67,6 +67,8 @@ void diff_merges_suppress(struct rev_info *revs) {
 void diff_merges_default_to_first_parent(struct rev_info *revs) {
 	if (revs->ignore_merges < 0)		/* No -m */
 		revs->ignore_merges = 0;
+	if (!revs->combine_merges)		/* No -c/--cc" */
+		revs->first_parent_merges = 1;
 }
 
 void diff_merges_default_to_dense_combined(struct rev_info *revs) {
diff --git a/log-tree.c b/log-tree.c
index 1927f917ce94..3fdc0fc64bfb 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -922,7 +922,7 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log
 			return 0;
 		else if (opt->combine_merges)
 			return do_diff_combined(opt, commit);
-		else if (!opt->first_parent_only) {
+		else if (!opt->first_parent_merges) {
 			/* If we show multiple diffs, show the parent info */
 			log->parent = parents->item;
 		}
@@ -941,7 +941,7 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log
 
 		/* Set up the log info for the next parent, if any.. */
 		parents = parents->next;
-		if (!parents || opt->first_parent_only)
+		if (!parents || opt->first_parent_merges)
 			break;
 		log->parent = parents->item;
 		opt->loginfo = log;
diff --git a/revision.h b/revision.h
index f6bf860d19e5..ba2aef79215e 100644
--- a/revision.h
+++ b/revision.h
@@ -194,6 +194,7 @@ struct rev_info {
 			combine_merges:1,
 			combined_all_paths:1,
 			dense_combined_merges:1,
+			first_parent_merges:1,
 			always_show_header:1;
 	int             ignore_merges:2;
 
-- 
2.25.1


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

* [PATCH v1 13/27] diff-merges: revise revs->diff flag handling
  2020-11-08 21:38 ` [PATCH v1 00/27] git-log: implement new --diff-merge options Sergey Organov
                     ` (11 preceding siblings ...)
  2020-11-08 21:38   ` [PATCH v1 12/27] diff-merges: introduce revs->first_parent_merges flag Sergey Organov
@ 2020-11-08 21:38   ` Sergey Organov
  2020-11-08 21:38   ` [PATCH v1 14/27] t4013: support test_expect_failure through ':failure' magic Sergey Organov
                     ` (14 subsequent siblings)
  27 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-11-08 21:38 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, Philip Oakley, git, Sergey Organov

Do not set revs->diff when we encounter an option that needs it, as
it'd be impossible to undo later. Besides, some other options than
what we handle here set this flag as well, and we'd interfere with
them trying to clear this flag later.

Rather set revs->diff, if finally needed, in diff_merges_setup_revs().

As an additional bonus, this also makes our code shorter.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 diff-merges.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/diff-merges.c b/diff-merges.c
index 63912ddedc76..a30c730a457f 100644
--- a/diff-merges.c
+++ b/diff-merges.c
@@ -37,16 +37,13 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {
 		revs->ignore_merges = 0;
 		revs->match_missing = 1;
 	} else if (!strcmp(arg, "-c")) {
-		revs->diff = 1;
 		revs->dense_combined_merges = 0;
 		revs->combine_merges = 1;
 	} else if (!strcmp(arg, "--cc")) {
-		revs->diff = 1;
 		set_dense_combined(revs);
 	} else if (!strcmp(arg, "--no-diff-merges")) {
 		suppress(revs);
 	} else if (!strcmp(arg, "--combined-all-paths")) {
-		revs->diff = 1;
 		revs->combined_all_paths = 1;
 	} else if ((argcount = parse_long_opt("diff-merges", argv, &optarg))) {
 		if (!strcmp(optarg, "off")) {
@@ -94,4 +91,6 @@ void diff_merges_setup_revs(struct rev_info *revs)
 		revs->ignore_merges = 1;
 	if (revs->combined_all_paths && !revs->combine_merges)
 		die("--combined-all-paths makes no sense without -c or --cc");
+	if (revs->combine_merges)
+		revs->diff = 1;
 }
-- 
2.25.1


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

* [PATCH v1 14/27] t4013: support test_expect_failure through ':failure' magic
  2020-11-08 21:38 ` [PATCH v1 00/27] git-log: implement new --diff-merge options Sergey Organov
                     ` (12 preceding siblings ...)
  2020-11-08 21:38   ` [PATCH v1 13/27] diff-merges: revise revs->diff flag handling Sergey Organov
@ 2020-11-08 21:38   ` Sergey Organov
  2020-11-08 21:38   ` [PATCH v1 15/27] t4013: add tests for -m failing to override -c/--cc Sergey Organov
                     ` (13 subsequent siblings)
  27 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-11-08 21:38 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, Philip Oakley, git, Sergey Organov

Add support to be able to specify expected failure, through :failure
magic, like this:

:failure cmd args

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 t/t4013-diff-various.sh | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh
index 5c7b0122b4f1..935d10ac0572 100755
--- a/t/t4013-diff-various.sh
+++ b/t/t4013-diff-various.sh
@@ -174,6 +174,7 @@ process_diffs () {
 V=$(git version | sed -e 's/^git version //' -e 's/\./\\./g')
 while read magic cmd
 do
+	status=success
 	case "$magic" in
 	'' | '#'*)
 		continue ;;
@@ -182,6 +183,10 @@ do
 		label="$magic-$cmd"
 		case "$magic" in
 		noellipses) ;;
+		failure)
+			status=failure
+			magic=
+			label="$cmd" ;;
 		*)
 			BUG "unknown magic $magic" ;;
 		esac ;;
@@ -194,7 +199,7 @@ do
 	expect="$TEST_DIRECTORY/t4013/diff.$test"
 	actual="$pfx-diff.$test"
 
-	test_expect_success "git $cmd # magic is ${magic:-(not used)}" '
+	test_expect_$status "git $cmd # magic is ${magic:-(not used)}" '
 		{
 			echo "$ git $cmd"
 			case "$magic" in
-- 
2.25.1


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

* [PATCH v1 15/27] t4013: add tests for -m failing to override -c/--cc
  2020-11-08 21:38 ` [PATCH v1 00/27] git-log: implement new --diff-merge options Sergey Organov
                     ` (13 preceding siblings ...)
  2020-11-08 21:38   ` [PATCH v1 14/27] t4013: support test_expect_failure through ':failure' magic Sergey Organov
@ 2020-11-08 21:38   ` Sergey Organov
  2020-11-08 21:38   ` [PATCH v1 16/27] diff-merges: fix -m to properly " Sergey Organov
                     ` (12 subsequent siblings)
  27 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-11-08 21:38 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, Philip Oakley, git, Sergey Organov

Logically, -m, -c, --cc specify 3 different formats for representing
merge commits, yet -m doesn't in fact override -c or --cc, that makes
no sense.

Add 2 expected to fail tests that demonstrate the problem.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 t/t4013-diff-various.sh            |   2 +
 t/t4013/diff.log_--cc_-m_-p_master | 200 +++++++++++++++++++++++++++++
 t/t4013/diff.log_-c_-m_-p_master   | 200 +++++++++++++++++++++++++++++
 3 files changed, 402 insertions(+)
 create mode 100644 t/t4013/diff.log_--cc_-m_-p_master
 create mode 100644 t/t4013/diff.log_-c_-m_-p_master

diff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh
index 935d10ac0572..64d9fce44614 100755
--- a/t/t4013-diff-various.sh
+++ b/t/t4013-diff-various.sh
@@ -329,6 +329,8 @@ log --first-parent --diff-merges=off -p master
 log -p --first-parent master
 log -m -p --first-parent master
 log -m -p master
+:failure log --cc -m -p master
+:failure log -c -m -p master
 log -SF master
 log -S F master
 log -SF -p master
diff --git a/t/t4013/diff.log_--cc_-m_-p_master b/t/t4013/diff.log_--cc_-m_-p_master
new file mode 100644
index 000000000000..7c217cf348c7
--- /dev/null
+++ b/t/t4013/diff.log_--cc_-m_-p_master
@@ -0,0 +1,200 @@
+$ git log --cc -m -p master
+commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (from 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0)
+Merge: 9a6d494 c7a2ab9
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:04:00 2006 +0000
+
+    Merge branch 'side'
+
+diff --git a/dir/sub b/dir/sub
+index cead32e..992913c 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -4,3 +4,5 @@ C
+ D
+ E
+ F
++1
++2
+diff --git a/file0 b/file0
+index b414108..10a8a9f 100644
+--- a/file0
++++ b/file0
+@@ -4,3 +4,6 @@
+ 4
+ 5
+ 6
++A
++B
++C
+
+commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (from c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a)
+Merge: 9a6d494 c7a2ab9
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:04:00 2006 +0000
+
+    Merge branch 'side'
+
+diff --git a/dir/sub b/dir/sub
+index 7289e35..992913c 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,4 +1,8 @@
+ A
+ B
++C
++D
++E
++F
+ 1
+ 2
+diff --git a/file0 b/file0
+index f4615da..10a8a9f 100644
+--- a/file0
++++ b/file0
+@@ -1,6 +1,9 @@
+ 1
+ 2
+ 3
++4
++5
++6
+ A
+ B
+ C
+diff --git a/file1 b/file1
+new file mode 100644
+index 0000000..b1e6722
+--- /dev/null
++++ b/file1
+@@ -0,0 +1,3 @@
++A
++B
++C
+diff --git a/file2 b/file2
+deleted file mode 100644
+index 01e79c3..0000000
+--- a/file2
++++ /dev/null
+@@ -1,3 +0,0 @@
+-1
+-2
+-3
+diff --git a/file3 b/file3
+deleted file mode 100644
+index 7289e35..0000000
+--- a/file3
++++ /dev/null
+@@ -1,4 +0,0 @@
+-A
+-B
+-1
+-2
+
+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:03:00 2006 +0000
+
+    Side
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..7289e35 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++1
++2
+diff --git a/file0 b/file0
+index 01e79c3..f4615da 100644
+--- a/file0
++++ b/file0
+@@ -1,3 +1,6 @@
+ 1
+ 2
+ 3
++A
++B
++C
+diff --git a/file3 b/file3
+new file mode 100644
+index 0000000..7289e35
+--- /dev/null
++++ b/file3
+@@ -0,0 +1,4 @@
++A
++B
++1
++2
+
+commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:02:00 2006 +0000
+
+    Third
+
+diff --git a/dir/sub b/dir/sub
+index 8422d40..cead32e 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -2,3 +2,5 @@ A
+ B
+ C
+ D
++E
++F
+diff --git a/file1 b/file1
+new file mode 100644
+index 0000000..b1e6722
+--- /dev/null
++++ b/file1
+@@ -0,0 +1,3 @@
++A
++B
++C
+
+commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:01:00 2006 +0000
+
+    Second
+    
+    This is the second commit.
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..8422d40 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++C
++D
+diff --git a/file0 b/file0
+index 01e79c3..b414108 100644
+--- a/file0
++++ b/file0
+@@ -1,3 +1,6 @@
+ 1
+ 2
+ 3
++4
++5
++6
+diff --git a/file2 b/file2
+deleted file mode 100644
+index 01e79c3..0000000
+--- a/file2
++++ /dev/null
+@@ -1,3 +0,0 @@
+-1
+-2
+-3
+
+commit 444ac553ac7612cc88969031b02b3767fb8a353a
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:00:00 2006 +0000
+
+    Initial
+$
diff --git a/t/t4013/diff.log_-c_-m_-p_master b/t/t4013/diff.log_-c_-m_-p_master
new file mode 100644
index 000000000000..b660f3d5f28e
--- /dev/null
+++ b/t/t4013/diff.log_-c_-m_-p_master
@@ -0,0 +1,200 @@
+$ git log -c -m -p master
+commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (from 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0)
+Merge: 9a6d494 c7a2ab9
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:04:00 2006 +0000
+
+    Merge branch 'side'
+
+diff --git a/dir/sub b/dir/sub
+index cead32e..992913c 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -4,3 +4,5 @@ C
+ D
+ E
+ F
++1
++2
+diff --git a/file0 b/file0
+index b414108..10a8a9f 100644
+--- a/file0
++++ b/file0
+@@ -4,3 +4,6 @@
+ 4
+ 5
+ 6
++A
++B
++C
+
+commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (from c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a)
+Merge: 9a6d494 c7a2ab9
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:04:00 2006 +0000
+
+    Merge branch 'side'
+
+diff --git a/dir/sub b/dir/sub
+index 7289e35..992913c 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,4 +1,8 @@
+ A
+ B
++C
++D
++E
++F
+ 1
+ 2
+diff --git a/file0 b/file0
+index f4615da..10a8a9f 100644
+--- a/file0
++++ b/file0
+@@ -1,6 +1,9 @@
+ 1
+ 2
+ 3
++4
++5
++6
+ A
+ B
+ C
+diff --git a/file1 b/file1
+new file mode 100644
+index 0000000..b1e6722
+--- /dev/null
++++ b/file1
+@@ -0,0 +1,3 @@
++A
++B
++C
+diff --git a/file2 b/file2
+deleted file mode 100644
+index 01e79c3..0000000
+--- a/file2
++++ /dev/null
+@@ -1,3 +0,0 @@
+-1
+-2
+-3
+diff --git a/file3 b/file3
+deleted file mode 100644
+index 7289e35..0000000
+--- a/file3
++++ /dev/null
+@@ -1,4 +0,0 @@
+-A
+-B
+-1
+-2
+
+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:03:00 2006 +0000
+
+    Side
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..7289e35 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++1
++2
+diff --git a/file0 b/file0
+index 01e79c3..f4615da 100644
+--- a/file0
++++ b/file0
+@@ -1,3 +1,6 @@
+ 1
+ 2
+ 3
++A
++B
++C
+diff --git a/file3 b/file3
+new file mode 100644
+index 0000000..7289e35
+--- /dev/null
++++ b/file3
+@@ -0,0 +1,4 @@
++A
++B
++1
++2
+
+commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:02:00 2006 +0000
+
+    Third
+
+diff --git a/dir/sub b/dir/sub
+index 8422d40..cead32e 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -2,3 +2,5 @@ A
+ B
+ C
+ D
++E
++F
+diff --git a/file1 b/file1
+new file mode 100644
+index 0000000..b1e6722
+--- /dev/null
++++ b/file1
+@@ -0,0 +1,3 @@
++A
++B
++C
+
+commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:01:00 2006 +0000
+
+    Second
+    
+    This is the second commit.
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..8422d40 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++C
++D
+diff --git a/file0 b/file0
+index 01e79c3..b414108 100644
+--- a/file0
++++ b/file0
+@@ -1,3 +1,6 @@
+ 1
+ 2
+ 3
++4
++5
++6
+diff --git a/file2 b/file2
+deleted file mode 100644
+index 01e79c3..0000000
+--- a/file2
++++ /dev/null
+@@ -1,3 +0,0 @@
+-1
+-2
+-3
+
+commit 444ac553ac7612cc88969031b02b3767fb8a353a
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:00:00 2006 +0000
+
+    Initial
+$
-- 
2.25.1


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

* [PATCH v1 16/27] diff-merges: fix -m to properly override -c/--cc
  2020-11-08 21:38 ` [PATCH v1 00/27] git-log: implement new --diff-merge options Sergey Organov
                     ` (14 preceding siblings ...)
  2020-11-08 21:38   ` [PATCH v1 15/27] t4013: add tests for -m failing to override -c/--cc Sergey Organov
@ 2020-11-08 21:38   ` Sergey Organov
  2020-11-08 21:38   ` [PATCH v1 17/27] diff-merges: split 'ignore_merges' field Sergey Organov
                     ` (11 subsequent siblings)
  27 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-11-08 21:38 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, Philip Oakley, git, Sergey Organov

Logically, -m, -c, --cc specify 3 different formats for representing
merge commits, yet -m doesn't in fact override -c or --cc, that makes
no sense.

Fix -m to properly override -c/--cc, and change the tests accordingly.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 diff-merges.c           | 1 +
 t/t4013-diff-various.sh | 4 ++--
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/diff-merges.c b/diff-merges.c
index a30c730a457f..f2b9ed789ca8 100644
--- a/diff-merges.c
+++ b/diff-merges.c
@@ -29,6 +29,7 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {
 	const char *arg = argv[0];
 
 	if (!strcmp(arg, "-m")) {
+		suppress(revs);
 		/*
 		 * To "diff-index", "-m" means "match missing", and to the "log"
 		 * family of commands, it means "show full diff for merges". Set
diff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh
index 64d9fce44614..8d8178a8a616 100755
--- a/t/t4013-diff-various.sh
+++ b/t/t4013-diff-various.sh
@@ -329,8 +329,8 @@ log --first-parent --diff-merges=off -p master
 log -p --first-parent master
 log -m -p --first-parent master
 log -m -p master
-:failure log --cc -m -p master
-:failure log -c -m -p master
+log --cc -m -p master
+log -c -m -p master
 log -SF master
 log -S F master
 log -SF -p master
-- 
2.25.1


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

* [PATCH v1 17/27] diff-merges: split 'ignore_merges' field
  2020-11-08 21:38 ` [PATCH v1 00/27] git-log: implement new --diff-merge options Sergey Organov
                     ` (15 preceding siblings ...)
  2020-11-08 21:38   ` [PATCH v1 16/27] diff-merges: fix -m to properly " Sergey Organov
@ 2020-11-08 21:38   ` Sergey Organov
  2020-11-08 21:38   ` [PATCH v1 18/27] diff-merges: group diff-merge flags next to each other inside 'rev_info' Sergey Organov
                     ` (10 subsequent siblings)
  27 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-11-08 21:38 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, Philip Oakley, git, Sergey Organov

'ignore_merges' was 3-way field that served two distinct purposes that
we now assign to 2 new independent flags: 'separate_merges', and
'explicit_diff_merges'.

'separate_merges' tells that we need to output diff format containing
separate diff for every parent (as opposed to 'combine_merges').

'explicit_diff_merges' tells that at least one of diff-merges options
has been explicitly specified on the command line, so no defaults
should apply.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 diff-merges.c | 29 ++++++++++++-----------------
 log-tree.c    | 15 ++++++++-------
 revision.h    |  3 ++-
 3 files changed, 22 insertions(+), 25 deletions(-)

diff --git a/diff-merges.c b/diff-merges.c
index f2b9ed789ca8..19cdad1aa4a1 100644
--- a/diff-merges.c
+++ b/diff-merges.c
@@ -3,7 +3,7 @@
 #include "revision.h"
 
 static void suppress(struct rev_info *revs) {
-	revs->ignore_merges = 1;
+	revs->separate_merges = 0;
 	revs->first_parent_merges = 0;
 	revs->combine_merges = 0;
 	revs->dense_combined_merges = 0;
@@ -20,7 +20,6 @@ static void set_dense_combined(struct rev_info *revs) {
  */
 
 void diff_merges_init_revs(struct rev_info *revs) {
-	revs->ignore_merges = -1;
 }
 
 int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {
@@ -35,7 +34,7 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {
 		 * family of commands, it means "show full diff for merges". Set
 		 * both fields appropriately.
 		 */
-		revs->ignore_merges = 0;
+		revs->separate_merges = 1;
 		revs->match_missing = 1;
 	} else if (!strcmp(arg, "-c")) {
 		revs->dense_combined_merges = 0;
@@ -55,6 +54,7 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {
 	} else
 		return 0;
 
+	revs->explicit_diff_merges = 1;
 	return 1;
 }
 
@@ -63,20 +63,15 @@ void diff_merges_suppress(struct rev_info *revs) {
 }
 
 void diff_merges_default_to_first_parent(struct rev_info *revs) {
-	if (revs->ignore_merges < 0)		/* No -m */
-		revs->ignore_merges = 0;
-	if (!revs->combine_merges)		/* No -c/--cc" */
+	if (!revs->explicit_diff_merges)
+		revs->separate_merges = 1;
+	if (revs->separate_merges)
 		revs->first_parent_merges = 1;
 }
 
 void diff_merges_default_to_dense_combined(struct rev_info *revs) {
-	if (revs->ignore_merges < 0) {		/* No -m */
-		revs->ignore_merges = 0;
-		if (!revs->combine_merges) {	/* No -c/--cc" */
-			revs->combine_merges = 1;
-			revs->dense_combined_merges = 1;
-		}
-	}
+	if (!revs->explicit_diff_merges)
+		set_dense_combined(revs);
 }
 
 void diff_merges_set_dense_combined_if_unset(struct rev_info *revs) {
@@ -86,10 +81,10 @@ void diff_merges_set_dense_combined_if_unset(struct rev_info *revs) {
 
 void diff_merges_setup_revs(struct rev_info *revs)
 {
-	if (revs->combine_merges && revs->ignore_merges < 0)
-		revs->ignore_merges = 0;
-	if (revs->ignore_merges < 0)
-		revs->ignore_merges = 1;
+	if (revs->combine_merges == 0)
+		revs->dense_combined_merges = 0;
+	if (revs->separate_merges == 0)
+		revs->first_parent_merges = 0;
 	if (revs->combined_all_paths && !revs->combine_merges)
 		die("--combined-all-paths makes no sense without -c or --cc");
 	if (revs->combine_merges)
diff --git a/log-tree.c b/log-tree.c
index 3fdc0fc64bfb..f9385b1dae6f 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -918,14 +918,15 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log
 
 	/* More than one parent? */
 	if (parents->next) {
-		if (opt->ignore_merges)
-			return 0;
-		else if (opt->combine_merges)
+		if (opt->combine_merges)
 			return do_diff_combined(opt, commit);
-		else if (!opt->first_parent_merges) {
-			/* If we show multiple diffs, show the parent info */
-			log->parent = parents->item;
-		}
+		if (opt->separate_merges) {
+			if (!opt->first_parent_merges) {
+				/* Show parent info for multiple diffs */
+				log->parent = parents->item;
+			}
+		} else
+			return 0;
 	}
 
 	showed_log = 0;
diff --git a/revision.h b/revision.h
index ba2aef79215e..fcc532c873d1 100644
--- a/revision.h
+++ b/revision.h
@@ -191,12 +191,13 @@ struct rev_info {
 			match_missing:1,
 			no_commit_id:1,
 			verbose_header:1,
+			explicit_diff_merges: 1,
+			separate_merges: 1,
 			combine_merges:1,
 			combined_all_paths:1,
 			dense_combined_merges:1,
 			first_parent_merges:1,
 			always_show_header:1;
-	int             ignore_merges:2;
 
 	/* Format info */
 	int		show_notes;
-- 
2.25.1


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

* [PATCH v1 18/27] diff-merges: group diff-merge flags next to each other inside 'rev_info'
  2020-11-08 21:38 ` [PATCH v1 00/27] git-log: implement new --diff-merge options Sergey Organov
                     ` (16 preceding siblings ...)
  2020-11-08 21:38   ` [PATCH v1 17/27] diff-merges: split 'ignore_merges' field Sergey Organov
@ 2020-11-08 21:38   ` Sergey Organov
  2020-11-08 21:38   ` [PATCH v1 19/27] diff-merges: get rid of now empty diff_merges_init_revs() Sergey Organov
                     ` (9 subsequent siblings)
  27 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-11-08 21:38 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, Philip Oakley, git, Sergey Organov

The relevant flags were somewhat scattered over definition of 'struct
rev_info'. Rearrange them to group them together.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 revision.h | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/revision.h b/revision.h
index fcc532c873d1..dcfa14454a55 100644
--- a/revision.h
+++ b/revision.h
@@ -191,13 +191,14 @@ struct rev_info {
 			match_missing:1,
 			no_commit_id:1,
 			verbose_header:1,
+			always_show_header:1,
+			/* Diff-merge flags */
 			explicit_diff_merges: 1,
 			separate_merges: 1,
 			combine_merges:1,
 			combined_all_paths:1,
 			dense_combined_merges:1,
-			first_parent_merges:1,
-			always_show_header:1;
+			first_parent_merges:1;
 
 	/* Format info */
 	int		show_notes;
-- 
2.25.1


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

* [PATCH v1 19/27] diff-merges: get rid of now empty diff_merges_init_revs()
  2020-11-08 21:38 ` [PATCH v1 00/27] git-log: implement new --diff-merge options Sergey Organov
                     ` (17 preceding siblings ...)
  2020-11-08 21:38   ` [PATCH v1 18/27] diff-merges: group diff-merge flags next to each other inside 'rev_info' Sergey Organov
@ 2020-11-08 21:38   ` Sergey Organov
  2020-11-08 21:38   ` [PATCH v1 20/27] diff-merges: refactor opt settings into separate functions Sergey Organov
                     ` (8 subsequent siblings)
  27 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-11-08 21:38 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, Philip Oakley, git, Sergey Organov

After getting rid of 'ignore_merges' field, the diff_merges_init_revs()
function became empty. Get rid of it.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 diff-merges.c | 3 ---
 diff-merges.h | 2 --
 revision.c    | 1 -
 3 files changed, 6 deletions(-)

diff --git a/diff-merges.c b/diff-merges.c
index 19cdad1aa4a1..29818abcc00e 100644
--- a/diff-merges.c
+++ b/diff-merges.c
@@ -19,9 +19,6 @@ static void set_dense_combined(struct rev_info *revs) {
  * Public functions. They are in the order they are called.
  */
 
-void diff_merges_init_revs(struct rev_info *revs) {
-}
-
 int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {
 	int argcount;
 	const char *optarg;
diff --git a/diff-merges.h b/diff-merges.h
index ae1cc8ef9410..9c69b8f3bd69 100644
--- a/diff-merges.h
+++ b/diff-merges.h
@@ -3,8 +3,6 @@
 
 struct rev_info;
 
-void diff_merges_init_revs(struct rev_info *revs);
-
 int diff_merges_parse_opts(struct rev_info *revs, const char **argv);
 
 void diff_merges_suppress(struct rev_info *revs);
diff --git a/revision.c b/revision.c
index 5a0e3d6ad542..46645ca0b6df 100644
--- a/revision.c
+++ b/revision.c
@@ -1814,7 +1814,6 @@ void repo_init_revisions(struct repository *r,
 
 	revs->repo = r;
 	revs->abbrev = DEFAULT_ABBREV;
-	diff_merges_init_revs(revs);
 	revs->simplify_history = 1;
 	revs->pruning.repo = r;
 	revs->pruning.flags.recursive = 1;
-- 
2.25.1


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

* [PATCH v1 20/27] diff-merges: refactor opt settings into separate functions
  2020-11-08 21:38 ` [PATCH v1 00/27] git-log: implement new --diff-merge options Sergey Organov
                     ` (18 preceding siblings ...)
  2020-11-08 21:38   ` [PATCH v1 19/27] diff-merges: get rid of now empty diff_merges_init_revs() Sergey Organov
@ 2020-11-08 21:38   ` Sergey Organov
  2020-11-08 21:38   ` [PATCH v1 21/27] diff-merges: make -m/-c/--cc explicitly mutually exclusive Sergey Organov
                     ` (7 subsequent siblings)
  27 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-11-08 21:38 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, Philip Oakley, git, Sergey Organov

To prepare introduction of new options some of which will be synonyms
to existing options, let every option handling code just call
corresponding function.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 diff-merges.c | 59 ++++++++++++++++++++++++++++++++-------------------
 1 file changed, 37 insertions(+), 22 deletions(-)

diff --git a/diff-merges.c b/diff-merges.c
index 29818abcc00e..8c22b447f106 100644
--- a/diff-merges.c
+++ b/diff-merges.c
@@ -9,11 +9,38 @@ static void suppress(struct rev_info *revs) {
 	revs->dense_combined_merges = 0;
 }
 
+static void set_separate(struct rev_info *revs) {
+	suppress(revs);
+	revs->separate_merges = 1;
+}
+
+static void set_m(struct rev_info *revs) {
+	/*
+	 * To "diff-index", "-m" means "match missing", and to the "log"
+	 * family of commands, it means "show full diff for merges". Set
+	 * both fields appropriately.
+	 */
+	set_separate(revs);
+	revs->match_missing = 1;
+}
+
+static void set_combined(struct rev_info *revs) {
+	revs->combine_merges = 1;
+	revs->dense_combined_merges = 0;
+}
+
 static void set_dense_combined(struct rev_info *revs) {
 	revs->combine_merges = 1;
 	revs->dense_combined_merges = 1;
 }
 
+static void set_diff_merges(struct rev_info *revs, const char *optarg) {
+	if (!strcmp(optarg, "off")) {
+		suppress(revs);
+	} else {
+		die(_("unknown value for --diff-merges: %s"), optarg);
+	}
+}
 
 /*
  * Public functions. They are in the order they are called.
@@ -24,31 +51,19 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {
 	const char *optarg;
 	const char *arg = argv[0];
 
-	if (!strcmp(arg, "-m")) {
-		suppress(revs);
-		/*
-		 * To "diff-index", "-m" means "match missing", and to the "log"
-		 * family of commands, it means "show full diff for merges". Set
-		 * both fields appropriately.
-		 */
-		revs->separate_merges = 1;
-		revs->match_missing = 1;
-	} else if (!strcmp(arg, "-c")) {
-		revs->dense_combined_merges = 0;
-		revs->combine_merges = 1;
-	} else if (!strcmp(arg, "--cc")) {
+	if (!strcmp(arg, "-m"))
+		set_m(revs);
+	else if (!strcmp(arg, "-c"))
+		set_combined(revs);
+	else if (!strcmp(arg, "--cc"))
 		set_dense_combined(revs);
-	} else if (!strcmp(arg, "--no-diff-merges")) {
+	else if (!strcmp(arg, "--no-diff-merges"))
 		suppress(revs);
-	} else if (!strcmp(arg, "--combined-all-paths")) {
+	else if (!strcmp(arg, "--combined-all-paths"))
 		revs->combined_all_paths = 1;
-	} else if ((argcount = parse_long_opt("diff-merges", argv, &optarg))) {
-		if (!strcmp(optarg, "off")) {
-			suppress(revs);
-		} else {
-			die(_("unknown value for --diff-merges: %s"), optarg);
-		}
-	} else
+	else if ((argcount = parse_long_opt("diff-merges", argv, &optarg)))
+		set_diff_merges(revs, optarg);
+	else
 		return 0;
 
 	revs->explicit_diff_merges = 1;
-- 
2.25.1


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

* [PATCH v1 21/27] diff-merges: make -m/-c/--cc explicitly mutually exclusive
  2020-11-08 21:38 ` [PATCH v1 00/27] git-log: implement new --diff-merge options Sergey Organov
                     ` (19 preceding siblings ...)
  2020-11-08 21:38   ` [PATCH v1 20/27] diff-merges: refactor opt settings into separate functions Sergey Organov
@ 2020-11-08 21:38   ` Sergey Organov
  2020-11-08 21:38   ` [PATCH v1 22/27] diff-merges: implement new values for --diff-merges Sergey Organov
                     ` (6 subsequent siblings)
  27 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-11-08 21:38 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, Philip Oakley, git, Sergey Organov

-c/--cc got precedence over -m only because of external logic where
corresponding flags are checked before that for -m. This is too
error-prone, so add code that explicitly makes these 3 options
mutually exclusive, so that the last option specified on the
command-line gets precedence.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 diff-merges.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/diff-merges.c b/diff-merges.c
index 8c22b447f106..db2217171442 100644
--- a/diff-merges.c
+++ b/diff-merges.c
@@ -7,6 +7,7 @@ static void suppress(struct rev_info *revs) {
 	revs->first_parent_merges = 0;
 	revs->combine_merges = 0;
 	revs->dense_combined_merges = 0;
+	revs->combined_all_paths = 0;
 }
 
 static void set_separate(struct rev_info *revs) {
@@ -25,11 +26,13 @@ static void set_m(struct rev_info *revs) {
 }
 
 static void set_combined(struct rev_info *revs) {
+	suppress(revs);
 	revs->combine_merges = 1;
 	revs->dense_combined_merges = 0;
 }
 
 static void set_dense_combined(struct rev_info *revs) {
+	suppress(revs);
 	revs->combine_merges = 1;
 	revs->dense_combined_merges = 1;
 }
-- 
2.25.1


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

* [PATCH v1 22/27] diff-merges: implement new values for --diff-merges
  2020-11-08 21:38 ` [PATCH v1 00/27] git-log: implement new --diff-merge options Sergey Organov
                     ` (20 preceding siblings ...)
  2020-11-08 21:38   ` [PATCH v1 21/27] diff-merges: make -m/-c/--cc explicitly mutually exclusive Sergey Organov
@ 2020-11-08 21:38   ` Sergey Organov
  2020-11-08 21:38   ` [PATCH v1 23/27] t4013: add test for --diff-merges=first-parent Sergey Organov
                     ` (5 subsequent siblings)
  27 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-11-08 21:38 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, Philip Oakley, git, Sergey Organov

The following values are implemented:

--diff-merges=	        old equivalent
first|first-parent    = --first-parent (only format implications)
sep|separate          = -m
comb|combined         = -c
dense| dense-combined = --cc

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 diff-merges.c | 19 ++++++++++++++++---
 1 file changed, 16 insertions(+), 3 deletions(-)

diff --git a/diff-merges.c b/diff-merges.c
index db2217171442..5c35369f7a8c 100644
--- a/diff-merges.c
+++ b/diff-merges.c
@@ -15,6 +15,11 @@ static void set_separate(struct rev_info *revs) {
 	revs->separate_merges = 1;
 }
 
+static void set_first_parent(struct rev_info *revs) {
+	set_separate(revs);
+	revs->first_parent_merges = 1;
+}
+
 static void set_m(struct rev_info *revs) {
 	/*
 	 * To "diff-index", "-m" means "match missing", and to the "log"
@@ -38,11 +43,19 @@ static void set_dense_combined(struct rev_info *revs) {
 }
 
 static void set_diff_merges(struct rev_info *revs, const char *optarg) {
-	if (!strcmp(optarg, "off")) {
+	if (0) ;
+	else if (!strcmp(optarg, "off")   || !strcmp(optarg, "none"))
 		suppress(revs);
-	} else {
+	else if (!strcmp(optarg, "first") || !strcmp(optarg, "first-parent"))
+		set_first_parent(revs);
+	else if (!strcmp(optarg, "sep")   || !strcmp(optarg, "separate"))
+		set_separate(revs);
+	else if (!strcmp(optarg, "comb")  || !strcmp(optarg, "combined"))
+		set_combined(revs);
+	else if (!strcmp(optarg, "dense") || !strcmp(optarg, "dense-combined"))
+		set_dense_combined(revs);
+	else
 		die(_("unknown value for --diff-merges: %s"), optarg);
-	}
 }
 
 /*
-- 
2.25.1


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

* [PATCH v1 23/27] t4013: add test for --diff-merges=first-parent
  2020-11-08 21:38 ` [PATCH v1 00/27] git-log: implement new --diff-merge options Sergey Organov
                     ` (21 preceding siblings ...)
  2020-11-08 21:38   ` [PATCH v1 22/27] diff-merges: implement new values for --diff-merges Sergey Organov
@ 2020-11-08 21:38   ` Sergey Organov
  2020-11-08 21:38   ` [PATCH v1 24/27] doc/git-log: describe new --diff-merges options Sergey Organov
                     ` (4 subsequent siblings)
  27 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-11-08 21:38 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, Philip Oakley, git, Sergey Organov

This new option provides essential new functionality, changing diff
output to first parent only without changing history traversal mode,
so it deserves its own test.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 t/t4013-diff-various.sh                       |   1 +
 ...f.log_-p_--diff-merges=first-parent_master | 137 ++++++++++++++++++
 2 files changed, 138 insertions(+)
 create mode 100644 t/t4013/diff.log_-p_--diff-merges=first-parent_master

diff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh
index 8d8178a8a616..ce56a9349d1c 100755
--- a/t/t4013-diff-various.sh
+++ b/t/t4013-diff-various.sh
@@ -327,6 +327,7 @@ log --no-diff-merges -p --first-parent master
 log --diff-merges=off -p --first-parent master
 log --first-parent --diff-merges=off -p master
 log -p --first-parent master
+log -p --diff-merges=first-parent master
 log -m -p --first-parent master
 log -m -p master
 log --cc -m -p master
diff --git a/t/t4013/diff.log_-p_--diff-merges=first-parent_master b/t/t4013/diff.log_-p_--diff-merges=first-parent_master
new file mode 100644
index 000000000000..9538a2751123
--- /dev/null
+++ b/t/t4013/diff.log_-p_--diff-merges=first-parent_master
@@ -0,0 +1,137 @@
+$ git log -p --diff-merges=first-parent master
+commit 59d314ad6f356dd08601a4cd5e530381da3e3c64
+Merge: 9a6d494 c7a2ab9
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:04:00 2006 +0000
+
+    Merge branch 'side'
+
+diff --git a/dir/sub b/dir/sub
+index cead32e..992913c 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -4,3 +4,5 @@ C
+ D
+ E
+ F
++1
++2
+diff --git a/file0 b/file0
+index b414108..10a8a9f 100644
+--- a/file0
++++ b/file0
+@@ -4,3 +4,6 @@
+ 4
+ 5
+ 6
++A
++B
++C
+
+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:03:00 2006 +0000
+
+    Side
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..7289e35 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++1
++2
+diff --git a/file0 b/file0
+index 01e79c3..f4615da 100644
+--- a/file0
++++ b/file0
+@@ -1,3 +1,6 @@
+ 1
+ 2
+ 3
++A
++B
++C
+diff --git a/file3 b/file3
+new file mode 100644
+index 0000000..7289e35
+--- /dev/null
++++ b/file3
+@@ -0,0 +1,4 @@
++A
++B
++1
++2
+
+commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:02:00 2006 +0000
+
+    Third
+
+diff --git a/dir/sub b/dir/sub
+index 8422d40..cead32e 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -2,3 +2,5 @@ A
+ B
+ C
+ D
++E
++F
+diff --git a/file1 b/file1
+new file mode 100644
+index 0000000..b1e6722
+--- /dev/null
++++ b/file1
+@@ -0,0 +1,3 @@
++A
++B
++C
+
+commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:01:00 2006 +0000
+
+    Second
+    
+    This is the second commit.
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..8422d40 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++C
++D
+diff --git a/file0 b/file0
+index 01e79c3..b414108 100644
+--- a/file0
++++ b/file0
+@@ -1,3 +1,6 @@
+ 1
+ 2
+ 3
++4
++5
++6
+diff --git a/file2 b/file2
+deleted file mode 100644
+index 01e79c3..0000000
+--- a/file2
++++ /dev/null
+@@ -1,3 +0,0 @@
+-1
+-2
+-3
+
+commit 444ac553ac7612cc88969031b02b3767fb8a353a
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:00:00 2006 +0000
+
+    Initial
+$
-- 
2.25.1


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

* [PATCH v1 24/27] doc/git-log: describe new --diff-merges options
  2020-11-08 21:38 ` [PATCH v1 00/27] git-log: implement new --diff-merge options Sergey Organov
                     ` (22 preceding siblings ...)
  2020-11-08 21:38   ` [PATCH v1 23/27] t4013: add test for --diff-merges=first-parent Sergey Organov
@ 2020-11-08 21:38   ` Sergey Organov
  2020-12-03  6:09     ` Elijah Newren
  2020-11-08 21:38   ` [PATCH v1 25/27] doc/diff-generate-patch: mention new --diff-merges option Sergey Organov
                     ` (3 subsequent siblings)
  27 siblings, 1 reply; 232+ messages in thread
From: Sergey Organov @ 2020-11-08 21:38 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, Philip Oakley, git, Sergey Organov

Describe all the new --diff-merges options in the git-log.txt

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 Documentation/git-log.txt | 79 +++++++++++++++++++++++----------------
 1 file changed, 46 insertions(+), 33 deletions(-)

diff --git a/Documentation/git-log.txt b/Documentation/git-log.txt
index 2b8ac5ff882a..de498a189646 100644
--- a/Documentation/git-log.txt
+++ b/Documentation/git-log.txt
@@ -120,45 +120,58 @@ DIFF FORMATTING
 By default, `git log` does not generate any diff output. The options
 below can be used to show the changes made by each commit.
 
-Note that unless one of `-c`, `--cc`, or `-m` is given, merge commits
-will never show a diff, even if a diff format like `--patch` is
-selected, nor will they match search options like `-S`. The exception is
-when `--first-parent` is in use, in which merges are treated like normal
-single-parent commits (this can be overridden by providing a
-combined-diff option or with `--no-diff-merges`).
+Note that unless one of `--diff-merges` variants (including short
+`-m`, `-c`, and `--cc` options) is explicitly given, merge commits
+will not show a diff, even if a diff format like `--patch` is
+selected, nor will they match search options like `-S`. The exception
+is when `--first-parent` is in use, in which case
+`--diff-merges=first-parent` is implied.
 
--c::
-	With this option, diff output for a merge commit
-	shows the differences from each of the parents to the merge result
-	simultaneously instead of showing pairwise diff between a parent
-	and the result one at a time. Furthermore, it lists only files
-	which were modified from all parents.
-
---cc::
-	This flag implies the `-c` option and further compresses the
-	patch output by omitting uninteresting hunks whose contents in
-	the parents have only two variants and the merge result picks
-	one of them without modification.
+--diff-merges=(off|none|first-parent|separate|combined|dense-combined)::
+--no-diff-merges::
+	Specify diff format to be used for merge commits. This has no
+	effect unless diff output is enabled in the first place (e.g.,
+	with `--patch` option.)
++
+--diff-merges=(off|none):::
+--no-diff-merges:::
+	(default) Disable output of diffs for merge commits. Useful to
+	override implied value.
++
+--diff-merges=first-parent:::
+	This option makes merge commits show the full diff with
+	respect to the first parent only, exactly like	regular
+	commits.
++
+--diff-merges=separate:::
+-m:::
+	This makes merge commits show the full diff with respect to
+	each of the parents. Separate log entry and diff is generated
+	for each parent.
++
+--diff-merges=combined:::
+-c:::
+	With this option, diff output for a merge commit shows the
+	differences from each of the parents to the merge result
+	simultaneously instead of showing pairwise diff between a
+	parent and the result one at a time. Furthermore, it lists
+	only files which were modified from all parents.
++
+--diff-merges=dense-combined:::
+--cc:::
+	With this option the output produced by
+	`--diff-merges=combined` is further compressed by omitting
+	uninteresting hunks whose contents in the parents have only
+	two variants and the merge result picks one of them without
+	modification.
 
 --combined-all-paths::
 	This flag causes combined diffs (used for merge commits) to
 	list the name of the file from all parents.  It thus only has
-	effect when -c or --cc are specified, and is likely only
-	useful if filename changes are detected (i.e. when either
-	rename or copy detection have been requested).
+	effect when `--diff-merges=[dense-]combined` is in use, and
+	is likely only useful if filename changes are detected (i.e.
+	when either rename or copy detection have been requested).
 
--m::
-	This flag makes the merge commits show the full diff like
-	regular commits; for each merge parent, a separate log entry
-	and diff is generated. An exception is that only diff against
-	the first parent is shown when `--first-parent` option is given;
-	in that case, the output represents the changes the merge
-	brought _into_ the then-current branch.
-
---diff-merges=off::
---no-diff-merges::
-	Disable output of diffs for merge commits (default). Useful to
-	override `-m`, `-c`, or `--cc`.
 
 :git-log: 1
 include::diff-options.txt[]
-- 
2.25.1


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

* [PATCH v1 25/27] doc/diff-generate-patch: mention new --diff-merges option
  2020-11-08 21:38 ` [PATCH v1 00/27] git-log: implement new --diff-merge options Sergey Organov
                     ` (23 preceding siblings ...)
  2020-11-08 21:38   ` [PATCH v1 24/27] doc/git-log: describe new --diff-merges options Sergey Organov
@ 2020-11-08 21:38   ` Sergey Organov
  2020-11-08 21:38   ` [PATCH v1 26/27] doc/rev-list-options: document --first-parent implies --diff-merges=first-parent Sergey Organov
                     ` (2 subsequent siblings)
  27 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-11-08 21:38 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, Philip Oakley, git, Sergey Organov

Mention --diff-merges instead of -m in a note to merge formats to aid
discoverability, as -m is now described among --diff-merges options
anyway.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 Documentation/diff-generate-patch.txt | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/Documentation/diff-generate-patch.txt b/Documentation/diff-generate-patch.txt
index b10ff4caa6c5..2db8eacc3ec7 100644
--- a/Documentation/diff-generate-patch.txt
+++ b/Documentation/diff-generate-patch.txt
@@ -81,9 +81,9 @@ Combined diff format
 Any diff-generating command can take the `-c` or `--cc` option to
 produce a 'combined diff' when showing a merge. This is the default
 format when showing merges with linkgit:git-diff[1] or
-linkgit:git-show[1]. Note also that you can give the `-m` option to any
-of these commands to force generation of diffs with individual parents
-of a merge.
+linkgit:git-show[1]. Note also that you can give suitable
+`--diff-merges` option to any of these commands to force generation of
+diffs in specific format.
 
 A "combined diff" format looks like this:
 
-- 
2.25.1


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

* [PATCH v1 26/27] doc/rev-list-options: document --first-parent implies --diff-merges=first-parent
  2020-11-08 21:38 ` [PATCH v1 00/27] git-log: implement new --diff-merge options Sergey Organov
                     ` (24 preceding siblings ...)
  2020-11-08 21:38   ` [PATCH v1 25/27] doc/diff-generate-patch: mention new --diff-merges option Sergey Organov
@ 2020-11-08 21:38   ` Sergey Organov
  2020-11-08 21:38   ` [PATCH v1 27/27] doc/git-show: include --diff-merges description Sergey Organov
  2020-12-03  7:54   ` [PATCH v1 00/27] git-log: implement new --diff-merge options Elijah Newren
  27 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-11-08 21:38 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, Philip Oakley, git, Sergey Organov

Before introduction of new --diff-merges options, --first-parent
implicitly changed the default diff format for merge commits to
showing only the diff with respect to the first parent, and there were
no way to get such format from "git log" without affecting history
traversal logic that --first-parent causes.

Now, after introduction of the --diff-merges=first-parent, the
--first-parent simply implies the former, and this patch corrects
documentation accordingly.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 Documentation/rev-list-options.txt | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt
index 002379056a07..ded383e62ae5 100644
--- a/Documentation/rev-list-options.txt
+++ b/Documentation/rev-list-options.txt
@@ -129,6 +129,9 @@ parents) and `--max-parents=-1` (negative numbers denote no upper limit).
 	adjusting to updated upstream from time to time, and
 	this option allows you to ignore the individual commits
 	brought in to your history by such a merge.
+ifdef::git-log[]
+	Implies `--diff-merges=first-parent`.
+endif::git-log[]
 
 --not::
 	Reverses the meaning of the '{caret}' prefix (or lack thereof)
-- 
2.25.1


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

* [PATCH v1 27/27] doc/git-show: include --diff-merges description
  2020-11-08 21:38 ` [PATCH v1 00/27] git-log: implement new --diff-merge options Sergey Organov
                     ` (25 preceding siblings ...)
  2020-11-08 21:38   ` [PATCH v1 26/27] doc/rev-list-options: document --first-parent implies --diff-merges=first-parent Sergey Organov
@ 2020-11-08 21:38   ` Sergey Organov
  2020-12-03 16:47     ` Elijah Newren
  2020-12-03  7:54   ` [PATCH v1 00/27] git-log: implement new --diff-merge options Elijah Newren
  27 siblings, 1 reply; 232+ messages in thread
From: Sergey Organov @ 2020-11-08 21:38 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, Philip Oakley, git, Sergey Organov

Move description of --diff-merges option from git-log.txt to
diff-options.txt so that it is included in the git-show help.

While we are at it, make git-show closer to git-log in this area by
providing similar wording in the introduction of diff options.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 Documentation/diff-options.txt | 54 ++++++++++++++++++++++++++++++++++
 Documentation/git-log.txt      | 52 --------------------------------
 Documentation/git-show.txt     |  8 +++--
 3 files changed, 60 insertions(+), 54 deletions(-)

diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt
index 573fb9bb71e2..f1629887103e 100644
--- a/Documentation/diff-options.txt
+++ b/Documentation/diff-options.txt
@@ -33,6 +33,60 @@ endif::git-diff[]
 	show the patch by default, or to cancel the effect of `--patch`.
 endif::git-format-patch[]
 
+ifdef::git-log[]
+Note that unless one of `--diff-merges` variants (including short
+`-m`, `-c`, and `--cc` options) is explicitly given, merge commits
+will not show a diff, even if a diff format like `--patch` is
+selected, nor will they match search options like `-S`. The exception
+is when `--first-parent` is in use, in which case
+`--diff-merges=first-parent` is implied.
+
+--diff-merges=(off|none|first-parent|separate|combined|dense-combined)::
+--no-diff-merges::
+	Specify diff format to be used for merge commits. This has no
+	effect unless diff output is enabled in the first place (e.g.,
+	with `--patch` option.)
++
+--diff-merges=(off|none):::
+--no-diff-merges:::
+	(default) Disable output of diffs for merge commits. Useful to
+	override implied value.
++
+--diff-merges=first-parent:::
+	This option makes merge commits show the full diff with
+	respect to the first parent only, exactly like	regular
+	commits.
++
+--diff-merges=separate:::
+-m:::
+	This makes merge commits show the full diff with respect to
+	each of the parents. Separate log entry and diff is generated
+	for each parent.
++
+--diff-merges=combined:::
+-c:::
+	With this option, diff output for a merge commit shows the
+	differences from each of the parents to the merge result
+	simultaneously instead of showing pairwise diff between a
+	parent and the result one at a time. Furthermore, it lists
+	only files which were modified from all parents.
++
+--diff-merges=dense-combined:::
+--cc:::
+	With this option the output produced by
+	`--diff-merges=combined` is further compressed by omitting
+	uninteresting hunks whose contents in the parents have only
+	two variants and the merge result picks one of them without
+	modification.
+
+--combined-all-paths::
+	This flag causes combined diffs (used for merge commits) to
+	list the name of the file from all parents.  It thus only has
+	effect when `--diff-merges=[dense-]combined` is in use, and
+	is likely only useful if filename changes are detected (i.e.
+	when either rename or copy detection have been requested).
+endif::git-log[]
+
 -U<n>::
 --unified=<n>::
 	Generate diffs with <n> lines of context instead of
diff --git a/Documentation/git-log.txt b/Documentation/git-log.txt
index de498a189646..0cacc780bf30 100644
--- a/Documentation/git-log.txt
+++ b/Documentation/git-log.txt
@@ -120,58 +120,6 @@ DIFF FORMATTING
 By default, `git log` does not generate any diff output. The options
 below can be used to show the changes made by each commit.
 
-Note that unless one of `--diff-merges` variants (including short
-`-m`, `-c`, and `--cc` options) is explicitly given, merge commits
-will not show a diff, even if a diff format like `--patch` is
-selected, nor will they match search options like `-S`. The exception
-is when `--first-parent` is in use, in which case
-`--diff-merges=first-parent` is implied.
-
---diff-merges=(off|none|first-parent|separate|combined|dense-combined)::
---no-diff-merges::
-	Specify diff format to be used for merge commits. This has no
-	effect unless diff output is enabled in the first place (e.g.,
-	with `--patch` option.)
-+
---diff-merges=(off|none):::
---no-diff-merges:::
-	(default) Disable output of diffs for merge commits. Useful to
-	override implied value.
-+
---diff-merges=first-parent:::
-	This option makes merge commits show the full diff with
-	respect to the first parent only, exactly like	regular
-	commits.
-+
---diff-merges=separate:::
--m:::
-	This makes merge commits show the full diff with respect to
-	each of the parents. Separate log entry and diff is generated
-	for each parent.
-+
---diff-merges=combined:::
--c:::
-	With this option, diff output for a merge commit shows the
-	differences from each of the parents to the merge result
-	simultaneously instead of showing pairwise diff between a
-	parent and the result one at a time. Furthermore, it lists
-	only files which were modified from all parents.
-+
---diff-merges=dense-combined:::
---cc:::
-	With this option the output produced by
-	`--diff-merges=combined` is further compressed by omitting
-	uninteresting hunks whose contents in the parents have only
-	two variants and the merge result picks one of them without
-	modification.
-
---combined-all-paths::
-	This flag causes combined diffs (used for merge commits) to
-	list the name of the file from all parents.  It thus only has
-	effect when `--diff-merges=[dense-]combined` is in use, and
-	is likely only useful if filename changes are detected (i.e.
-	when either rename or copy detection have been requested).
-
 
 :git-log: 1
 include::diff-options.txt[]
diff --git a/Documentation/git-show.txt b/Documentation/git-show.txt
index fcf528c1b30d..abe58ce5d3a8 100644
--- a/Documentation/git-show.txt
+++ b/Documentation/git-show.txt
@@ -45,8 +45,12 @@ include::pretty-options.txt[]
 include::pretty-formats.txt[]
 
 
-COMMON DIFF OPTIONS
--------------------
+DIFF FORMATTING
+---------------
+
+By default, `git show` does not generate any diff output. The options
+below can be used to show the changes made by each commit.
+
 
 :git-log: 1
 include::diff-options.txt[]
-- 
2.25.1


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

* Re: [PATCH v1 01/27] revision: factor out parsing of diff-merge related options
  2020-11-08 21:38   ` [PATCH v1 01/27] revision: factor out parsing of diff-merge related options Sergey Organov
@ 2020-12-03  0:33     ` Junio C Hamano
  2020-12-03 15:16       ` Sergey Organov
  0 siblings, 1 reply; 232+ messages in thread
From: Junio C Hamano @ 2020-12-03  0:33 UTC (permalink / raw)
  To: Sergey Organov; +Cc: Jeff King, Philip Oakley, git

Sergey Organov <sorganov@gmail.com> writes:

> Move all the parsing code related to diffing merges into new
> parse_diff_merge_opts() function.
>
> Signed-off-by: Sergey Organov <sorganov@gmail.com>
> ---
>  revision.c | 66 ++++++++++++++++++++++++++++++++----------------------
>  1 file changed, 39 insertions(+), 27 deletions(-)
>
> diff --git a/revision.c b/revision.c
> index aa6221204081..a09f4872acd7 100644
> --- a/revision.c
> +++ b/revision.c
> @@ -2153,6 +2153,44 @@ static void add_message_grep(struct rev_info *revs, const char *pattern)
>  	add_grep(revs, pattern, GREP_PATTERN_BODY);
>  }
>  
> +static int parse_diff_merge_opts(struct rev_info *revs, const char **argv) {
> +	int argcount;
> +	const char *optarg;
> +	const char *arg = argv[0];
> +
> +	if (!strcmp(arg, "-m")) {
> +		/*
> +		 * To "diff-index", "-m" means "match missing", and to the "log"
> +		 * family of commands, it means "show full diff for merges". Set
> +		 * both fields appropriately.
> +		 */
> +		revs->ignore_merges = 0;
> +		revs->match_missing = 1;
> +	} else if (!strcmp(arg, "-c")) {
> +		revs->diff = 1;
> +		revs->dense_combined_merges = 0;
> +		revs->combine_merges = 1;
> +	} else if (!strcmp(arg, "--cc")) {
> +		revs->diff = 1;
> +		revs->dense_combined_merges = 1;
> +		revs->combine_merges = 1;
> +	} else if (!strcmp(arg, "--no-diff-merges")) {
> +		revs->ignore_merges = 1;
> +	} else if (!strcmp(arg, "--combined-all-paths")) {
> +		revs->diff = 1;
> +		revs->combined_all_paths = 1;
> +	} else if ((argcount = parse_long_opt("diff-merges", argv, &optarg))) {

The reordering of if/else if/ cascade from the original, which
serves no apparent purpose, makes reviewing a tad harder than
necessary, but the conversion at this point seems wrong.

The original allowed parse_long_opt() to potentially return 2
(i.e. "diff-merges" and "off" appear as separate tokens on the
command line), but the return value stored in argcount here is
discarded, without affecting the return value from this function,
which is fed back to the original in handle_revision_opt() below.

> +		if (!strcmp(optarg, "off")) {
> +			revs->ignore_merges = 1;
> +		} else {
> +			die(_("unknown value for --diff-merges: %s"), optarg);
> +		}

To correct the above bug, it probably is sufficient to add

		return argcount;

here.  That will be fed back to ...

> +	} else
> +		return 0;
> +
> +	return 1;
> +}

> @@ -2349,34 +2387,8 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
> ...
> -	} else if ((argcount = parse_long_opt("diff-merges", argv, &optarg))) {
> -		if (!strcmp(optarg, "off")) {
> -			revs->ignore_merges = 1;
> -		} else {
> -			die(_("unknown value for --diff-merges: %s"), optarg);
> -		}
> +	} else if ((argcount = parse_diff_merge_opts(revs, argv))) {
>  		return argcount;

... this part and cause the number of options and arguments consumed
to the caller of handle_revision_opt().

I wonder if we can cover it with a test to prevent a similar mistake
in the future?

> -	} else if (!strcmp(arg, "--no-diff-merges")) {
> -		revs->ignore_merges = 1;
> -	} else if (!strcmp(arg, "-c")) {
> -		revs->diff = 1;
> -		revs->dense_combined_merges = 0;
> -		revs->combine_merges = 1;
> -	} else if (!strcmp(arg, "--combined-all-paths")) {
> -		revs->diff = 1;
> -		revs->combined_all_paths = 1;
> -	} else if (!strcmp(arg, "--cc")) {
> -		revs->diff = 1;
> -		revs->dense_combined_merges = 1;
> -		revs->combine_merges = 1;
>  	} else if (!strcmp(arg, "-v")) {
>  		revs->verbose_header = 1;
>  	} else if (!strcmp(arg, "--pretty")) {

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

* Re: [PATCH v1 02/27] revision: factor out setup of diff-merge related settings
  2020-11-08 21:38   ` [PATCH v1 02/27] revision: factor out setup of diff-merge related settings Sergey Organov
@ 2020-12-03  0:34     ` Junio C Hamano
  0 siblings, 0 replies; 232+ messages in thread
From: Junio C Hamano @ 2020-12-03  0:34 UTC (permalink / raw)
  To: Sergey Organov; +Cc: Jeff King, Philip Oakley, git

Sergey Organov <sorganov@gmail.com> writes:

> Move all the setting code related to diffing merges into new
> setup_diff_merge_revs() function.
>
> Signed-off-by: Sergey Organov <sorganov@gmail.com>
> ---
>  revision.c | 18 ++++++++++++------
>  1 file changed, 12 insertions(+), 6 deletions(-)

Looks trivially correct.

> diff --git a/revision.c b/revision.c
> index a09f4872acd7..739295bb9ff4 100644
> --- a/revision.c
> +++ b/revision.c
> @@ -2191,6 +2191,16 @@ static int parse_diff_merge_opts(struct rev_info *revs, const char **argv) {
>  	return 1;
>  }
>  
> +static void setup_diff_merges_revs(struct rev_info *revs)
> +{
> +	if (revs->combine_merges && revs->ignore_merges < 0)
> +		revs->ignore_merges = 0;
> +	if (revs->ignore_merges < 0)
> +		revs->ignore_merges = 1;
> +	if (revs->combined_all_paths && !revs->combine_merges)
> +		die("--combined-all-paths makes no sense without -c or --cc");
> +}
> +
>  static int handle_revision_opt(struct rev_info *revs, int argc, const char **argv,
>  			       int *unkc, const char **unkv,
>  			       const struct setup_revision_opt* opt)
> @@ -2885,12 +2895,8 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
>  			copy_pathspec(&revs->diffopt.pathspec,
>  				      &revs->prune_data);
>  	}
> -	if (revs->combine_merges && revs->ignore_merges < 0)
> -		revs->ignore_merges = 0;
> -	if (revs->ignore_merges < 0)
> -		revs->ignore_merges = 1;
> -	if (revs->combined_all_paths && !revs->combine_merges)
> -		die("--combined-all-paths makes no sense without -c or --cc");
> +
> +	setup_diff_merges_revs(revs);
>  
>  	revs->diffopt.abbrev = revs->abbrev;

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

* Re: [PATCH v1 03/27] revision: factor out initialization of diff-merge related settings
  2020-11-08 21:38   ` [PATCH v1 03/27] revision: factor out initialization " Sergey Organov
@ 2020-12-03  0:39     ` Junio C Hamano
  2020-12-03 15:35       ` Sergey Organov
  0 siblings, 1 reply; 232+ messages in thread
From: Junio C Hamano @ 2020-12-03  0:39 UTC (permalink / raw)
  To: Sergey Organov; +Cc: Jeff King, Philip Oakley, git

Sergey Organov <sorganov@gmail.com> writes:

> Move initialization code related to diffing merges into new
> init_diff_merge_revs() function.
>
> Signed-off-by: Sergey Organov <sorganov@gmail.com>
> ---
>  revision.c | 8 +++++++-
>  1 file changed, 7 insertions(+), 1 deletion(-)
>
> diff --git a/revision.c b/revision.c
> index 739295bb9ff4..bc568fb79778 100644
> --- a/revision.c
> +++ b/revision.c
> @@ -1805,6 +1805,8 @@ static int add_parents_only(struct rev_info *revs, const char *arg_, int flags,
>  	return 1;
>  }
>  
> +static void init_diff_merge_revs(struct rev_info *revs);
> +

It is not wrong per-se, but I do not see why we do not define the
function here, not just forward-declare it like so.

>  void repo_init_revisions(struct repository *r,
>  			 struct rev_info *revs,
>  			 const char *prefix)
> @@ -1813,7 +1815,7 @@ void repo_init_revisions(struct repository *r,
>  
>  	revs->repo = r;
>  	revs->abbrev = DEFAULT_ABBREV;
> -	revs->ignore_merges = -1;
> +	init_diff_merge_revs(revs);
>  	revs->simplify_history = 1;
>  	revs->pruning.repo = r;
>  	revs->pruning.flags.recursive = 1;
> @@ -2153,6 +2155,10 @@ static void add_message_grep(struct rev_info *revs, const char *pattern)
>  	add_grep(revs, pattern, GREP_PATTERN_BODY);
>  }
>  
> +static void init_diff_merge_revs(struct rev_info *revs) {
> +	revs->ignore_merges = -1;
> +}

Style.  A brace that begins a function body begins its own line.  In
any case, I'd move this new definition before its sole caller; that
way we do not even need an extra forward-declaration.

>  static int parse_diff_merge_opts(struct rev_info *revs, const char **argv) {
>  	int argcount;
>  	const char *optarg;

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

* Re: [PATCH v1 04/27] revision: provide implementation for diff merges tweaks
  2020-11-08 21:38   ` [PATCH v1 04/27] revision: provide implementation for diff merges tweaks Sergey Organov
@ 2020-12-03  0:51     ` Junio C Hamano
  2020-12-03  5:28       ` Junio C Hamano
  2020-12-03 17:53       ` Sergey Organov
  0 siblings, 2 replies; 232+ messages in thread
From: Junio C Hamano @ 2020-12-03  0:51 UTC (permalink / raw)
  To: Sergey Organov; +Cc: Jeff King, Philip Oakley, git

Sergey Organov <sorganov@gmail.com> writes:

> -	if (rev->ignore_merges < 0) {
> -		/* There was no "-m" variant on the command line */
> -		rev->ignore_merges = 0;
> -		if (!rev->first_parent_only && !rev->combine_merges) {
> -			/* No "--first-parent", "-c", or "--cc" */
> -			rev->combine_merges = 1;
> -			rev->dense_combined_merges = 1;
> -		}
> -	}
> +	rev_diff_merges_default_to_dense_combined(rev);

The name makes sense.  "Unless otherwise specified, we do not ignore
merges.  Further, when we are not doing first-parent traversal,
default to dense combined merges, unless told otherwise" is what the
code says, and the name of the helper captures it well.

> @@ -731,8 +723,7 @@ static void log_setup_revisions_tweak(struct rev_info *rev,
>  	if (!rev->diffopt.output_format && rev->combine_merges)
>  		rev->diffopt.output_format = DIFF_FORMAT_PATCH;
>  
> -	if (rev->first_parent_only && rev->ignore_merges < 0)
> -		rev->ignore_merges = 0;
> +	rev_diff_merges_first_parent_defaults_to_enable(rev);

This on the other hand is not so great a name.  "When we are doing
first-parent traversal, do not exclude merge commits from being
shown" is what log_setup_revisions_tweak() does here.  "default to
enable" is not clear at all what we are enabling.

Is your naming convention that "rev_diff_" is the common prefix?
What's the significance of "_diff" part?  After all, these are about
tweaking the setting in the rev_info structure, so how about

	revinfo_show_merges_in_dense_combined_by_default(rev);
	revinfo_show_merges_by_default_with_first_parent(rev);

perhaps, using just "revinfo_" as the common prefix?

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

* Re: [PATCH v1 06/27] diff-merges: rename all functions to have common prefix
  2020-11-08 21:38   ` [PATCH v1 06/27] diff-merges: rename all functions to have common prefix Sergey Organov
@ 2020-12-03  0:52     ` Junio C Hamano
  2020-12-03 17:49       ` Sergey Organov
  0 siblings, 1 reply; 232+ messages in thread
From: Junio C Hamano @ 2020-12-03  0:52 UTC (permalink / raw)
  To: Sergey Organov; +Cc: Jeff King, Philip Oakley, git

Sergey Organov <sorganov@gmail.com> writes:

> Use the same "diff_merges" prefix for all the diff merges function
> names.
>
> Signed-off-by: Sergey Organov <sorganov@gmail.com>
> ---
>  builtin/log.c |  4 ++--
>  diff-merges.c | 10 +++++-----
>  diff-merges.h | 15 ++++++++++-----
>  revision.c    |  6 +++---
>  4 files changed, 20 insertions(+), 15 deletions(-)
>
> diff --git a/builtin/log.c b/builtin/log.c
> index ad3092fdd854..77a7bba543ad 100644
> --- a/builtin/log.c
> +++ b/builtin/log.c
> @@ -599,7 +599,7 @@ static int show_tree_object(const struct object_id *oid,
>  static void show_setup_revisions_tweak(struct rev_info *rev,
>  				       struct setup_revision_opt *opt)
>  {
> -	rev_diff_merges_default_to_dense_combined(rev);
> +	diff_merges_default_to_dense_combined(rev);
>  	if (!rev->diffopt.output_format)
>  		rev->diffopt.output_format = DIFF_FORMAT_PATCH;
>  }
> @@ -724,7 +724,7 @@ static void log_setup_revisions_tweak(struct rev_info *rev,
>  	if (!rev->diffopt.output_format && rev->combine_merges)
>  		rev->diffopt.output_format = DIFF_FORMAT_PATCH;
>  
> -	rev_diff_merges_first_parent_defaults_to_enable(rev);
> +	diff_merges_first_parent_defaults_to_enable(rev);

Even with a different prefix, this name does not make it clear what
is going on to its readers.  The other name is OK, though.

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

* Re: [PATCH v1 05/27] revision: move diff merges functions to its own diff-merges.c
  2020-11-08 21:38   ` [PATCH v1 05/27] revision: move diff merges functions to its own diff-merges.c Sergey Organov
@ 2020-12-03  0:58     ` Junio C Hamano
  2020-12-03 16:44       ` Sergey Organov
  0 siblings, 1 reply; 232+ messages in thread
From: Junio C Hamano @ 2020-12-03  0:58 UTC (permalink / raw)
  To: Sergey Organov; +Cc: Jeff King, Philip Oakley, git

Sergey Organov <sorganov@gmail.com> writes:

> diff --git a/diff-merges.h b/diff-merges.h
> new file mode 100644
> index 000000000000..e0cca3d935d3
> --- /dev/null
> +++ b/diff-merges.h
> @@ -0,0 +1,12 @@
> +#ifndef DIFF_MERGES_H
> +#define DIFF_MERGES_H

Describe what "diff-merges" module is about in a comment here.

This matters because in 07/27 the log message complains that the
first-parent traversal option is checked in the module but it is out
of place.  Without defining what the "module" is about, the readers
would have a hard time agreeing with the justification.

My guess is that this is about deciding how a merge commit is shown
in 'log -p' and 'show' output, comparing the commit with its
parent(s) in patch output.  With that explained, it may make sense
for 07/27 to complain that --first-parent that is primarily a
traversal option does also affect how a merge is shown (I do not
necessarily agree with the complaint, though)

> +
> +struct rev_info;
> +
> +void init_diff_merge_revs(struct rev_info *revs);
> +int parse_diff_merge_opts(struct rev_info *revs, const char **argv);
> +void setup_diff_merges_revs(struct rev_info *revs);
> +void rev_diff_merges_default_to_dense_combined(struct rev_info *revs);
> +void rev_diff_merges_first_parent_defaults_to_enable(struct rev_info *revs);
> +
> +#endif
> diff --git a/revision.c b/revision.c
> index ce90c2991657..4bc14a08a624 100644
> --- a/revision.c
> +++ b/revision.c
> @@ -5,6 +5,7 @@
>  #include "tree.h"
>  #include "commit.h"
>  #include "diff.h"
> +#include "diff-merges.h"
>  #include "refs.h"
>  #include "revision.h"
>  #include "repository.h"
> @@ -1805,8 +1806,6 @@ static int add_parents_only(struct rev_info *revs, const char *arg_, int flags,
>  	return 1;
>  }
>  
> -static void init_diff_merge_revs(struct rev_info *revs);
> -
>  void repo_init_revisions(struct repository *r,
>  			 struct rev_info *revs,
>  			 const char *prefix)
> @@ -2155,75 +2154,6 @@ static void add_message_grep(struct rev_info *revs, const char *pattern)
>  	add_grep(revs, pattern, GREP_PATTERN_BODY);
>  }
>  
> -static void init_diff_merge_revs(struct rev_info *revs) {
> -	revs->ignore_merges = -1;
> -}
> -
> -static int parse_diff_merge_opts(struct rev_info *revs, const char **argv) {
> -	int argcount;
> -	const char *optarg;
> -	const char *arg = argv[0];
> -
> -	if (!strcmp(arg, "-m")) {
> -		/*
> -		 * To "diff-index", "-m" means "match missing", and to the "log"
> -		 * family of commands, it means "show full diff for merges". Set
> -		 * both fields appropriately.
> -		 */
> -		revs->ignore_merges = 0;
> -		revs->match_missing = 1;
> -	} else if (!strcmp(arg, "-c")) {
> -		revs->diff = 1;
> -		revs->dense_combined_merges = 0;
> -		revs->combine_merges = 1;
> -	} else if (!strcmp(arg, "--cc")) {
> -		revs->diff = 1;
> -		revs->dense_combined_merges = 1;
> -		revs->combine_merges = 1;
> -	} else if (!strcmp(arg, "--no-diff-merges")) {
> -		revs->ignore_merges = 1;
> -	} else if (!strcmp(arg, "--combined-all-paths")) {
> -		revs->diff = 1;
> -		revs->combined_all_paths = 1;
> -	} else if ((argcount = parse_long_opt("diff-merges", argv, &optarg))) {
> -		if (!strcmp(optarg, "off")) {
> -			revs->ignore_merges = 1;
> -		} else {
> -			die(_("unknown value for --diff-merges: %s"), optarg);
> -		}
> -	} else
> -		return 0;
> -
> -	return 1;
> -}
> -
> -static void setup_diff_merges_revs(struct rev_info *revs)
> -{
> -	if (revs->combine_merges && revs->ignore_merges < 0)
> -		revs->ignore_merges = 0;
> -	if (revs->ignore_merges < 0)
> -		revs->ignore_merges = 1;
> -	if (revs->combined_all_paths && !revs->combine_merges)
> -		die("--combined-all-paths makes no sense without -c or --cc");
> -}
> -
> -void rev_diff_merges_first_parent_defaults_to_enable(struct rev_info *revs) {
> -	if (revs->first_parent_only && revs->ignore_merges < 0)
> -		revs->ignore_merges = 0;
> -}
> -
> -void rev_diff_merges_default_to_dense_combined(struct rev_info *revs) {
> -	if (revs->ignore_merges < 0) {
> -		/* There was no "-m" variant on the command line */
> -		revs->ignore_merges = 0;
> -		if (!revs->first_parent_only && !revs->combine_merges) {
> -			/* No "--first-parent", "-c", or "--cc" */
> -			revs->combine_merges = 1;
> -			revs->dense_combined_merges = 1;
> -		}
> -	}
> -}
> -
>  static int handle_revision_opt(struct rev_info *revs, int argc, const char **argv,
>  			       int *unkc, const char **unkv,
>  			       const struct setup_revision_opt* opt)
> diff --git a/revision.h b/revision.h
> index 3dd0229f4edc..f6bf860d19e5 100644
> --- a/revision.h
> +++ b/revision.h
> @@ -456,7 +456,4 @@ int rewrite_parents(struct rev_info *revs,
>   */
>  struct commit_list *get_saved_parents(struct rev_info *revs, const struct commit *commit);
>  
> -void rev_diff_merges_default_to_dense_combined(struct rev_info *revs);
> -void rev_diff_merges_first_parent_defaults_to_enable(struct rev_info *revs);
> -
>  #endif

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

* Re: [PATCH v1 07/27] diff-merges: move checks for first_parent_only out of the module
  2020-11-08 21:38   ` [PATCH v1 07/27] diff-merges: move checks for first_parent_only out of the module Sergey Organov
@ 2020-12-03  1:09     ` Junio C Hamano
  2020-12-03 20:22       ` Sergey Organov
  0 siblings, 1 reply; 232+ messages in thread
From: Junio C Hamano @ 2020-12-03  1:09 UTC (permalink / raw)
  To: Sergey Organov; +Cc: Jeff King, Philip Oakley, git

Sergey Organov <sorganov@gmail.com> writes:

> The checks for first_parent_only don't in fact belong to this module,
> as the primary purpose of this flag is history traversal limiting, so
> get it out of this module and rename the
>
> diff_merges_first_parent_defaults_to_enable()
>
> to
>
> diff_merges_default_to_enable()

Again, neither is a great name.

More importantly, I do not think that I agree with the reasoning
given in the first paragraph.  The first-parent-only traversal means
that we pretend there is no second and later parents, so it makes
quite a lot of sense that the choice of that option affects how a
merge commit discovered during the traversal is show by default
(namely, as if it is just a single-parent commit).

If there are other reasons why we want to force the callers to check
for first-parent option (for example, it may make it easier to tweak
how each caller makes its decisions separately in later steps of
this series), the changes proposed by this step may be a right
solution, so I am not outright opposed to this patch, but the
rationale given above is not a strong enough justification for the
change, at least to me.

> +void diff_merges_default_to_enable(struct rev_info *revs) {

Perhaps "show_merges_by_default()".

> +	if (revs->ignore_merges < 0)		/* No -m */
>  		revs->ignore_merges = 0;

Perhaps "show_merges_in_cc_by_default()" (or "cc" spelled out as
"dense_combined").

>  void diff_merges_default_to_dense_combined(struct rev_info *revs) {
> -	if (revs->ignore_merges < 0) {
> -		/* There was no "-m" variant on the command line */
> +	if (revs->ignore_merges < 0) {		/* No -m */
>  		revs->ignore_merges = 0;
> -		if (!revs->first_parent_only && !revs->combine_merges) {
> -			/* No "--first-parent", "-c", or "--cc" */
> +		if (!revs->combine_merges) {	/* No -c/--cc" */
>  			revs->combine_merges = 1;
>  			revs->dense_combined_merges = 1;
>  		}
> diff --git a/diff-merges.h b/diff-merges.h
> index 648c410497cb..cf411414898d 100644
> --- a/diff-merges.h
> +++ b/diff-merges.h
> @@ -11,7 +11,7 @@ void diff_merges_setup_revs(struct rev_info *revs);
>  
>  void diff_merges_default_to_dense_combined(struct rev_info *revs);
>  
> -void diff_merges_first_parent_defaults_to_enable(struct rev_info *revs);
> +void diff_merges_default_to_enable(struct rev_info *revs);
>  
>  
>  #endif

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

* Re: [PATCH v1 04/27] revision: provide implementation for diff merges tweaks
  2020-12-03  0:51     ` Junio C Hamano
@ 2020-12-03  5:28       ` Junio C Hamano
  2020-12-03 16:03         ` Sergey Organov
  2020-12-03 17:53       ` Sergey Organov
  1 sibling, 1 reply; 232+ messages in thread
From: Junio C Hamano @ 2020-12-03  5:28 UTC (permalink / raw)
  To: Sergey Organov; +Cc: Jeff King, Philip Oakley, git

Junio C Hamano <gitster@pobox.com> writes:

> Is your naming convention that "rev_diff_" is the common prefix?
> What's the significance of "_diff" part?  After all, these are about
> tweaking the setting in the rev_info structure, so how about
>
> 	revinfo_show_merges_in_dense_combined_by_default(rev);
> 	revinfo_show_merges_by_default_with_first_parent(rev);
>
> perhaps, using just "revinfo_" as the common prefix?

Actually, I'd like to take these suggestions back.  I do not think
these names that describe "what the function does" are good names at
all.  If we can name them after what they are for, we'd be much
better off.

Given that one is part of the tweak for "show" and the other part of
"log", I presume that one is to set-up default for showing a merge
in the context of the "show" command, and the other is the same for
the "log" (actually "log -p") command.  So perhaps

	diff_merges_set_default_for_show(revs);
	diff_merges_set_default_for_log(revs);

are good names that tells us where they should be used and what for.
The former is to set up the default parameters to handle a merge
commit in the context of the "show" command, and the latter is the
same for the "log" command.  Naming them that way, we can then tweak
what should happen for "show" by default without touching the caller
if we wanted to (perhaps, "when doing first-parent traversal, really
pretend that all the commits we see are single-parent, so show the
change relative to its first parent by default without even
requiring -m" might be something the latter can learn later).

Thanks.



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

* Re: [PATCH v1 09/27] diff-merges: re-arrange functions to match the order they are called in
  2020-11-08 21:38   ` [PATCH v1 09/27] diff-merges: re-arrange functions to match the order they are called in Sergey Organov
@ 2020-12-03  5:52     ` Elijah Newren
  2020-12-03 15:41       ` Sergey Organov
  0 siblings, 1 reply; 232+ messages in thread
From: Elijah Newren @ 2020-12-03  5:52 UTC (permalink / raw)
  To: Sergey Organov; +Cc: Junio C Hamano, Jeff King, Philip Oakley, Git Mailing List

On Sun, Nov 8, 2020 at 1:43 PM Sergey Organov <sorganov@gmail.com> wrote:
>
> For clarity, define public functions in the order they are called, to
> make logic inter-dependencies easier to grok.

You added diff-merges.[ch] earlier in this series.  Why not just add
them in the correct order initially instead of adding another patch
later in the series?

>
> Signed-off-by: Sergey Organov <sorganov@gmail.com>
> ---
>  diff-merges.c | 24 ++++++++++++++----------
>  diff-merges.h |  7 +++----
>  2 files changed, 17 insertions(+), 14 deletions(-)
>
> diff --git a/diff-merges.c b/diff-merges.c
> index bb08a92e3b36..8536941e0b56 100644
> --- a/diff-merges.c
> +++ b/diff-merges.c
> @@ -2,6 +2,10 @@
>
>  #include "revision.h"
>
> +/*
> + * Public functions. They are in the order they are called.
> + */
> +
>  void diff_merges_init_revs(struct rev_info *revs) {
>         revs->ignore_merges = -1;
>  }
> @@ -44,16 +48,6 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {
>         return 1;
>  }
>
> -void diff_merges_setup_revs(struct rev_info *revs)
> -{
> -       if (revs->combine_merges && revs->ignore_merges < 0)
> -               revs->ignore_merges = 0;
> -       if (revs->ignore_merges < 0)
> -               revs->ignore_merges = 1;
> -       if (revs->combined_all_paths && !revs->combine_merges)
> -               die("--combined-all-paths makes no sense without -c or --cc");
> -}
> -
>  void diff_merges_default_to_first_parent(struct rev_info *revs) {
>         if (revs->ignore_merges < 0)            /* No -m */
>                 revs->ignore_merges = 0;
> @@ -68,3 +62,13 @@ void diff_merges_default_to_dense_combined(struct rev_info *revs) {
>                 }
>         }
>  }
> +
> +void diff_merges_setup_revs(struct rev_info *revs)
> +{
> +       if (revs->combine_merges && revs->ignore_merges < 0)
> +               revs->ignore_merges = 0;
> +       if (revs->ignore_merges < 0)
> +               revs->ignore_merges = 1;
> +       if (revs->combined_all_paths && !revs->combine_merges)
> +               die("--combined-all-paths makes no sense without -c or --cc");
> +}
> diff --git a/diff-merges.h b/diff-merges.h
> index 20b727bd734f..4b023c385d00 100644
> --- a/diff-merges.h
> +++ b/diff-merges.h
> @@ -7,11 +7,10 @@ void diff_merges_init_revs(struct rev_info *revs);
>
>  int diff_merges_parse_opts(struct rev_info *revs, const char **argv);
>
> -void diff_merges_setup_revs(struct rev_info *revs);
> -
> -void diff_merges_default_to_dense_combined(struct rev_info *revs);
> -
>  void diff_merges_default_to_first_parent(struct rev_info *revs);
>
> +void diff_merges_default_to_dense_combined(struct rev_info *revs);
> +
> +void diff_merges_setup_revs(struct rev_info *revs);
>
>  #endif
> --
> 2.25.1
>

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

* Re: [PATCH 10/26] diff-merges: new function diff_merges_suppress()
  2020-11-01 19:33 ` [PATCH 10/26] diff-merges: new function diff_merges_suppress() Sergey Organov
@ 2020-12-03  5:52   ` Elijah Newren
  2020-12-03 20:06     ` Sergey Organov
  0 siblings, 1 reply; 232+ messages in thread
From: Elijah Newren @ 2020-12-03  5:52 UTC (permalink / raw)
  To: Sergey Organov; +Cc: Junio C Hamano, Jeff King, Git Mailing List

On Sun, Nov 1, 2020 at 11:36 AM Sergey Organov <sorganov@gmail.com> wrote:
>
> This function sets all the relevant flags to disabled state, so that
> no code that checks only one of them get it wrong.
>
> Then we call this new function everywhere where diff merges output
> suppression is needed.
>
> Signed-off-by: Sergey Organov <sorganov@gmail.com>
> ---
>  builtin/merge.c |  3 ++-
>  diff-merges.c   | 18 ++++++++++++++----
>  diff-merges.h   |  2 ++
>  fmt-merge-msg.c |  3 ++-
>  4 files changed, 20 insertions(+), 6 deletions(-)
>
> diff --git a/builtin/merge.c b/builtin/merge.c
> index 9d5359edc2f7..1f7b69982b40 100644
> --- a/builtin/merge.c
> +++ b/builtin/merge.c
> @@ -14,6 +14,7 @@
>  #include "lockfile.h"
>  #include "run-command.h"
>  #include "diff.h"
> +#include "diff-merges.h"
>  #include "refs.h"
>  #include "refspec.h"
>  #include "commit.h"
> @@ -400,7 +401,7 @@ static void squash_message(struct commit *commit, struct commit_list *remotehead
>         printf(_("Squash commit -- not updating HEAD\n"));
>
>         repo_init_revisions(the_repository, &rev, NULL);
> -       rev.ignore_merges = 1;
> +       diff_merges_suppress(&rev);
>         rev.commit_format = CMIT_FMT_MEDIUM;
>
>         commit->object.flags |= UNINTERESTING;
> diff --git a/diff-merges.c b/diff-merges.c
> index 8536941e0b56..25bd9b12e667 100644
> --- a/diff-merges.c
> +++ b/diff-merges.c
> @@ -2,6 +2,13 @@
>
>  #include "revision.h"
>
> +static void suppress(struct rev_info *revs) {
> +       revs->ignore_merges = 1;
> +       revs->first_parent_merges = 0;
> +       revs->combine_merges = 0;
> +       revs->dense_combined_merges = 0;
> +}

The function name is not so helpful; why not put all this code
directly in diff_merges_suppress()?

> +
>  /*
>   * Public functions. They are in the order they are called.
>   */
> @@ -29,16 +36,15 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {
>                 revs->combine_merges = 1;
>         } else if (!strcmp(arg, "--cc")) {
>                 revs->diff = 1;
> -               revs->dense_combined_merges = 1;
> -               revs->combine_merges = 1;
> +               set_dense_combined(revs);
>         } else if (!strcmp(arg, "--no-diff-merges")) {
> -               revs->ignore_merges = 1;
> +               suppress(revs);
>         } else if (!strcmp(arg, "--combined-all-paths")) {
>                 revs->diff = 1;
>                 revs->combined_all_paths = 1;
>         } else if ((argcount = parse_long_opt("diff-merges", argv, &optarg))) {
>                 if (!strcmp(optarg, "off")) {
> -                       revs->ignore_merges = 1;
> +                       suppress(revs);
>                 } else {
>                         die(_("unknown value for --diff-merges: %s"), optarg);
>                 }
> @@ -48,6 +54,10 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {
>         return 1;
>  }
>
> +void diff_merges_suppress(struct rev_info *revs) {
> +       suppress(revs);
> +}

...especially since all this function does is call suppress()?


> +
>  void diff_merges_default_to_first_parent(struct rev_info *revs) {
>         if (revs->ignore_merges < 0)            /* No -m */
>                 revs->ignore_merges = 0;
> diff --git a/diff-merges.h b/diff-merges.h
> index 4b023c385d00..32720bc9b40f 100644
> --- a/diff-merges.h
> +++ b/diff-merges.h
> @@ -7,6 +7,8 @@ void diff_merges_init_revs(struct rev_info *revs);
>
>  int diff_merges_parse_opts(struct rev_info *revs, const char **argv);
>
> +void diff_merges_suppress(struct rev_info *revs);
> +
>  void diff_merges_default_to_first_parent(struct rev_info *revs);
>
>  void diff_merges_default_to_dense_combined(struct rev_info *revs);
> diff --git a/fmt-merge-msg.c b/fmt-merge-msg.c
> index bd22e1ea8865..abc3403fb820 100644
> --- a/fmt-merge-msg.c
> +++ b/fmt-merge-msg.c
> @@ -2,6 +2,7 @@
>  #include "refs.h"
>  #include "object-store.h"
>  #include "diff.h"
> +#include "diff-merges.h"
>  #include "revision.h"
>  #include "tag.h"
>  #include "string-list.h"
> @@ -668,7 +669,7 @@ int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
>                 head = lookup_commit_or_die(&head_oid, "HEAD");
>                 repo_init_revisions(the_repository, &rev, NULL);
>                 rev.commit_format = CMIT_FMT_ONELINE;
> -               rev.ignore_merges = 1;
> +               diff_merges_suppress(&rev);
>                 rev.limited = 1;
>
>                 strbuf_complete_line(out);
> --
> 2.25.1
>

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

* Re: [PATCH v1 24/27] doc/git-log: describe new --diff-merges options
  2020-11-08 21:38   ` [PATCH v1 24/27] doc/git-log: describe new --diff-merges options Sergey Organov
@ 2020-12-03  6:09     ` Elijah Newren
  2020-12-03 19:34       ` Sergey Organov
  0 siblings, 1 reply; 232+ messages in thread
From: Elijah Newren @ 2020-12-03  6:09 UTC (permalink / raw)
  To: Sergey Organov; +Cc: Junio C Hamano, Jeff King, Philip Oakley, Git Mailing List

On Sun, Nov 8, 2020 at 1:46 PM Sergey Organov <sorganov@gmail.com> wrote:
>
> Describe all the new --diff-merges options in the git-log.txt
>
> Signed-off-by: Sergey Organov <sorganov@gmail.com>
> ---
>  Documentation/git-log.txt | 79 +++++++++++++++++++++++----------------
>  1 file changed, 46 insertions(+), 33 deletions(-)
>
> diff --git a/Documentation/git-log.txt b/Documentation/git-log.txt
> index 2b8ac5ff882a..de498a189646 100644
> --- a/Documentation/git-log.txt
> +++ b/Documentation/git-log.txt
> @@ -120,45 +120,58 @@ DIFF FORMATTING
>  By default, `git log` does not generate any diff output. The options
>  below can be used to show the changes made by each commit.
>
> -Note that unless one of `-c`, `--cc`, or `-m` is given, merge commits
> -will never show a diff, even if a diff format like `--patch` is
> -selected, nor will they match search options like `-S`. The exception is
> -when `--first-parent` is in use, in which merges are treated like normal
> -single-parent commits (this can be overridden by providing a
> -combined-diff option or with `--no-diff-merges`).
> +Note that unless one of `--diff-merges` variants (including short
> +`-m`, `-c`, and `--cc` options) is explicitly given, merge commits
> +will not show a diff, even if a diff format like `--patch` is
> +selected, nor will they match search options like `-S`. The exception
> +is when `--first-parent` is in use, in which case
> +`--diff-merges=first-parent` is implied.
>
> --c::
> -       With this option, diff output for a merge commit
> -       shows the differences from each of the parents to the merge result
> -       simultaneously instead of showing pairwise diff between a parent
> -       and the result one at a time. Furthermore, it lists only files
> -       which were modified from all parents.
> -
> ---cc::
> -       This flag implies the `-c` option and further compresses the
> -       patch output by omitting uninteresting hunks whose contents in
> -       the parents have only two variants and the merge result picks
> -       one of them without modification.
> +--diff-merges=(off|none|first-parent|separate|combined|dense-combined)::
> +--no-diff-merges::
> +       Specify diff format to be used for merge commits. This has no
> +       effect unless diff output is enabled in the first place (e.g.,
> +       with `--patch` option.)

This seems inconsistent with c7eaf8b4c3 ("log: when --cc is given,
default to -p unless told otherwise", 2015-08-20); shouldn't these
imply -p?

> ++
> +--diff-merges=(off|none):::
> +--no-diff-merges:::
> +       (default) Disable output of diffs for merge commits. Useful to
> +       override implied value.
> ++
> +--diff-merges=first-parent:::
> +       This option makes merge commits show the full diff with
> +       respect to the first parent only, exactly like  regular
> +       commits.

Not sure that "exactly like regular commits" is helpful here; I'd
personally rather cut those four words out.  I'm worried it'll be
taken not as an implementation explanation, but as a "this treats
merge commits in the natural way that regular commits are" which users
may mistakenly translate to "it shows what changes the user manually
made as part of the commit" which is not at all the correct mapping.

> ++
> +--diff-merges=separate:::
> +-m:::
> +       This makes merge commits show the full diff with respect to
> +       each of the parents. Separate log entry and diff is generated
> +       for each parent.
> ++
> +--diff-merges=combined:::
> +-c:::
> +       With this option, diff output for a merge commit shows the
> +       differences from each of the parents to the merge result
> +       simultaneously instead of showing pairwise diff between a
> +       parent and the result one at a time. Furthermore, it lists
> +       only files which were modified from all parents.
> ++
> +--diff-merges=dense-combined:::
> +--cc:::
> +       With this option the output produced by
> +       `--diff-merges=combined` is further compressed by omitting
> +       uninteresting hunks whose contents in the parents have only
> +       two variants and the merge result picks one of them without
> +       modification.
>
>  --combined-all-paths::
>         This flag causes combined diffs (used for merge commits) to
>         list the name of the file from all parents.  It thus only has
> -       effect when -c or --cc are specified, and is likely only
> -       useful if filename changes are detected (i.e. when either
> -       rename or copy detection have been requested).
> +       effect when `--diff-merges=[dense-]combined` is in use, and
> +       is likely only useful if filename changes are detected (i.e.
> +       when either rename or copy detection have been requested).
>
> --m::
> -       This flag makes the merge commits show the full diff like
> -       regular commits; for each merge parent, a separate log entry
> -       and diff is generated. An exception is that only diff against
> -       the first parent is shown when `--first-parent` option is given;
> -       in that case, the output represents the changes the merge
> -       brought _into_ the then-current branch.
> -
> ---diff-merges=off::
> ---no-diff-merges::
> -       Disable output of diffs for merge commits (default). Useful to
> -       override `-m`, `-c`, or `--cc`.
>
>  :git-log: 1
>  include::diff-options.txt[]
> --
> 2.25.1

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

* Re: [PATCH v1 00/27] git-log: implement new --diff-merge options
  2020-11-08 21:38 ` [PATCH v1 00/27] git-log: implement new --diff-merge options Sergey Organov
                     ` (26 preceding siblings ...)
  2020-11-08 21:38   ` [PATCH v1 27/27] doc/git-show: include --diff-merges description Sergey Organov
@ 2020-12-03  7:54   ` Elijah Newren
  2020-12-03 19:48     ` Sergey Organov
  27 siblings, 1 reply; 232+ messages in thread
From: Elijah Newren @ 2020-12-03  7:54 UTC (permalink / raw)
  To: Sergey Organov; +Cc: Junio C Hamano, Jeff King, Philip Oakley, Git Mailing List

On Sun, Nov 8, 2020 at 1:43 PM Sergey Organov <sorganov@gmail.com> wrote:
>
> These patch series implement new set of options governing the diff output
> of merge commits, all under the umbrella of the single --diff-merges=<mode>
> option. Most of the new options being synonyms for -m/-c/--cc options,
> there is also additional functionality provided, allowing to get the format
> of "-p --first-parent" without change in history traversal that
> --first-parent option causes.
>
> The net result of these series are the following new options:
>
> --diff-merges=   |  old equivalent
> -----------------+----------------
> first-parent     | --first-parent (only format implications)
> separate         | -m
> combined         | -c
> dense-combined   | --cc

Interesting.  I have some local patches implementing another choice,
with the new flag --remerge-diff.  This flag will cause `git show` or
`git log` to automatically remerge the two parents in a 2-parent merge
commit, and then diff the merge commit against that automatic merge,
showing the result.  Thus, the diff for a merge commit is likely to be
empty if the merge was clean, and is likely to show the removal of
conflict markers if the merge was not clean.

I'm curious how it'd interact with this new option.  Would it also get
a name, e.g. --diff-merges=remerge-diff?  Feels like a mouthful, but I
can't come up with anything better.

Also, I'm curious how it'd interact with another option I added, named
--remerge-diff-only.  This latter option modifies revision traversal
in that it skips octopus merges, root commits, and single parent
commits IF no cherry-pick or revert information can be found.  If it
finds a 2-parent merge commit, it behaves like --remerge-diff.  If it
finds a 1-parent commit with cherry-pick or revert information, it'll
do an in memory repeat of that cherry-pick (or revert) and then diff
the actual commit against what the automatic cherry-pick would
perform.  Again, that likely means an empty diff if the automatic
cherry-pick was clean, and showing any changes made by the user to
complete the original cherry-pick (such as deleting conflict markers
and picking which chunks from which side to keep) if the automatic
cherry-pick was not clean.  (I suspect --remerge-diff-only is much
more likely to be used with `git show` than with `git log`.)  Anyway,
your changes seem to suggest that anything relating to how diffs for
merges are handled should be documented in the same section, but
--remerge-diff-only doesn't fit.  And it'd seem odd to have
--remerge-diff and --remerge-diff-only not show up in adjacently but
be split into separate sections.  Any ideas?

(This doesn't matter yet, since I'm waiting for merge-ort to be
completed before submitting the --remerge-diff and --remerge-diff-only
patches, but thought I'd bring it up as food for thought and to query
if others have good ideas about how to handle the names and
documentation location.)

> The series also cleanup logic of handling of diff merges options and fix an
> issue found in the original implementation where logically mutually
> exclusive options -m/-c/--cc failed to actually override each other.
>
> The series start with the set of pure refactoring commits that are expected
> to introduce no functional changes. These are all commits up to and
> including:
>
> "diff-merges: revise revs->diff flag handling"
>
> The aim of these commits is to isolate options handling for diff merges so
> that it could be easily understood and tweaked to ease introduction of the
> new options.
>
> Then the fix of -m/-c/-cc overriding issue follows, starting with a failing
> test and followed by the fix.
>
> Then follows a little bit of additional refactoring in order to prepare for
> introduction of the new options, and finally the series are finished by the
> implementation, testing, and documentation update for the new options.
>
> Updates in v1:

A minor point, but this should have been labelled v2.  The unlabelled
original submission is v1.

>
>         * Added documentation fix for git-show to include --diff-merges.
>         * Fixed typos in commit messages noticed by Philip Oakley.
>
> Sergey Organov (27):
>   revision: factor out parsing of diff-merge related options
>   revision: factor out setup of diff-merge related settings
>   revision: factor out initialization of diff-merge related settings
>   revision: provide implementation for diff merges tweaks
>   revision: move diff merges functions to its own diff-merges.c
>   diff-merges: rename all functions to have common prefix
>   diff-merges: move checks for first_parent_only out of the module
>   diff-merges: rename diff_merges_default_to_enable() to match semantics
>   diff-merges: re-arrange functions to match the order they are called
>     in
>   diff-merges: new function diff_merges_suppress()
>   diff-merges: new function diff_merges_set_dense_combined_if_unset()
>   diff-merges: introduce revs->first_parent_merges flag
>   diff-merges: revise revs->diff flag handling
>   t4013: support test_expect_failure through ':failure' magic
>   t4013: add tests for -m failing to override -c/--cc
>   diff-merges: fix -m to properly override -c/--cc
>   diff-merges: split 'ignore_merges' field
>   diff-merges: group diff-merge flags next to each other inside
>     'rev_info'
>   diff-merges: get rid of now empty diff_merges_init_revs()
>   diff-merges: refactor opt settings into separate functions
>   diff-merges: make -m/-c/--cc explicitly mutually exclusive
>   diff-merges: implement new values for --diff-merges
>   t4013: add test for --diff-merges=first-parent
>   doc/git-log: describe new --diff-merges options
>   doc/diff-generate-patch: mention new --diff-merges option
>   doc/rev-list-options: document --first-parent implies
>     --diff-merges=first-parent
>   doc/git-show: include --diff-merges description
>
>  Documentation/diff-generate-patch.txt         |   6 +-
>  Documentation/diff-options.txt                |  54 +++++
>  Documentation/git-log.txt                     |  39 ----
>  Documentation/git-show.txt                    |   8 +-
>  Documentation/rev-list-options.txt            |   3 +
>  Makefile                                      |   1 +
>  builtin/diff-files.c                          |   5 +-
>  builtin/diff.c                                |   9 +-
>  builtin/log.c                                 |  18 +-
>  builtin/merge.c                               |   3 +-
>  diff-merges.c                                 | 120 +++++++++++
>  diff-merges.h                                 |  18 ++
>  fmt-merge-msg.c                               |   3 +-
>  log-tree.c                                    |  17 +-
>  revision.c                                    |  38 +---
>  revision.h                                    |   7 +-
>  t/t4013-diff-various.sh                       |  10 +-
>  t/t4013/diff.log_--cc_-m_-p_master            | 200 ++++++++++++++++++
>  t/t4013/diff.log_-c_-m_-p_master              | 200 ++++++++++++++++++
>  ...f.log_-p_--diff-merges=first-parent_master | 137 ++++++++++++
>  20 files changed, 788 insertions(+), 108 deletions(-)
>  create mode 100644 diff-merges.c
>  create mode 100644 diff-merges.h
>  create mode 100644 t/t4013/diff.log_--cc_-m_-p_master
>  create mode 100644 t/t4013/diff.log_-c_-m_-p_master
>  create mode 100644 t/t4013/diff.log_-p_--diff-merges=first-parent_master
>
> --
> 2.25.1

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

* Re: [PATCH v1 01/27] revision: factor out parsing of diff-merge related options
  2020-12-03  0:33     ` Junio C Hamano
@ 2020-12-03 15:16       ` Sergey Organov
  2020-12-04  6:36         ` Junio C Hamano
  0 siblings, 1 reply; 232+ messages in thread
From: Sergey Organov @ 2020-12-03 15:16 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, Philip Oakley, git

Junio C Hamano <gitster@pobox.com> writes:

> Sergey Organov <sorganov@gmail.com> writes:
>
>> Move all the parsing code related to diffing merges into new
>> parse_diff_merge_opts() function.
>>
>> Signed-off-by: Sergey Organov <sorganov@gmail.com>
>> ---
>>  revision.c | 66 ++++++++++++++++++++++++++++++++----------------------
>>  1 file changed, 39 insertions(+), 27 deletions(-)
>>
>> diff --git a/revision.c b/revision.c
>> index aa6221204081..a09f4872acd7 100644
>> --- a/revision.c
>> +++ b/revision.c
>> @@ -2153,6 +2153,44 @@ static void add_message_grep(struct rev_info *revs, const char *pattern)
>>  	add_grep(revs, pattern, GREP_PATTERN_BODY);
>>  }
>>  
>> +static int parse_diff_merge_opts(struct rev_info *revs, const char **argv) {
>> +	int argcount;
>> +	const char *optarg;
>> +	const char *arg = argv[0];
>> +
>> +	if (!strcmp(arg, "-m")) {
>> +		/*
>> +		 * To "diff-index", "-m" means "match missing", and to the "log"
>> +		 * family of commands, it means "show full diff for merges". Set
>> +		 * both fields appropriately.
>> +		 */
>> +		revs->ignore_merges = 0;
>> +		revs->match_missing = 1;
>> +	} else if (!strcmp(arg, "-c")) {
>> +		revs->diff = 1;
>> +		revs->dense_combined_merges = 0;
>> +		revs->combine_merges = 1;
>> +	} else if (!strcmp(arg, "--cc")) {
>> +		revs->diff = 1;
>> +		revs->dense_combined_merges = 1;
>> +		revs->combine_merges = 1;
>> +	} else if (!strcmp(arg, "--no-diff-merges")) {
>> +		revs->ignore_merges = 1;
>> +	} else if (!strcmp(arg, "--combined-all-paths")) {
>> +		revs->diff = 1;
>> +		revs->combined_all_paths = 1;
>> +	} else if ((argcount = parse_long_opt("diff-merges", argv, &optarg))) {
>
> The reordering of if/else if/ cascade from the original, which
> serves no apparent purpose, makes reviewing a tad harder than
> necessary, but the conversion at this point seems wrong.

Sorry for the reordering, I didn't notice it when I cleared up the
series.

>
> The original allowed parse_long_opt() to potentially return 2
> (i.e. "diff-merges" and "off" appear as separate tokens on the
> command line), but the return value stored in argcount here is
> discarded, without affecting the return value from this function,
> which is fed back to the original in handle_revision_opt() below.

Nice catch!

>
>> +		if (!strcmp(optarg, "off")) {
>> +			revs->ignore_merges = 1;
>> +		} else {
>> +			die(_("unknown value for --diff-merges: %s"), optarg);
>> +		}
>
> To correct the above bug, it probably is sufficient to add
>
> 		return argcount;
>
> here.

Right, but not enough. "argcount" should also be set to 1 at the
beginning of the function, to avoid returning uninitialized value here.

Fixed for the next series.

Thanks,
-- Sergey Organov

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

* Re: [PATCH v1 03/27] revision: factor out initialization of diff-merge related settings
  2020-12-03  0:39     ` Junio C Hamano
@ 2020-12-03 15:35       ` Sergey Organov
  0 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-12-03 15:35 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, Philip Oakley, git

Junio C Hamano <gitster@pobox.com> writes:

> Sergey Organov <sorganov@gmail.com> writes:
>
>> Move initialization code related to diffing merges into new
>> init_diff_merge_revs() function.
>>
>> Signed-off-by: Sergey Organov <sorganov@gmail.com>
>> ---
>>  revision.c | 8 +++++++-
>>  1 file changed, 7 insertions(+), 1 deletion(-)
>>
>> diff --git a/revision.c b/revision.c
>> index 739295bb9ff4..bc568fb79778 100644
>> --- a/revision.c
>> +++ b/revision.c
>> @@ -1805,6 +1805,8 @@ static int add_parents_only(struct rev_info *revs, const char *arg_, int flags,
>>  	return 1;
>>  }
>>  
>> +static void init_diff_merge_revs(struct rev_info *revs);
>> +
>
> It is not wrong per-se, but I do not see why we do not define the
> function here, not just forward-declare it like so.

I wanted to keep merge-diff functions definitions at one place to
simplify future refactoring by moving all of them into separate file, to
avoid scatter-gathering definitions from multiple places in the
original file.

>
>>  void repo_init_revisions(struct repository *r,
>>  			 struct rev_info *revs,
>>  			 const char *prefix)
>> @@ -1813,7 +1815,7 @@ void repo_init_revisions(struct repository *r,
>>  
>>  	revs->repo = r;
>>  	revs->abbrev = DEFAULT_ABBREV;
>> -	revs->ignore_merges = -1;
>> +	init_diff_merge_revs(revs);
>>  	revs->simplify_history = 1;
>>  	revs->pruning.repo = r;
>>  	revs->pruning.flags.recursive = 1;
>> @@ -2153,6 +2155,10 @@ static void add_message_grep(struct rev_info *revs, const char *pattern)
>>  	add_grep(revs, pattern, GREP_PATTERN_BODY);
>>  }
>>  
>> +static void init_diff_merge_revs(struct rev_info *revs) {
>> +	revs->ignore_merges = -1;
>> +}
>
> Style.  A brace that begins a function body begins its own line.

Oops! There are a few cases in the git sources where this style is used,
and somehow my eye catch it and I did entire series in this style.

Now the question is: what do I do about it? Do I need to rework the
entire series in the correct style, or would it be enough to fix the
style as a separate commit at the end of the series?

> In any case, I'd move this new definition before its sole caller; that
> way we do not even need an extra forward-declaration.

I'd do it too, except in this particular case, first, it actually makes
some sense to have function definition here, see above, and second, it'd
disappear along with declaration in the next commit anyway. I'm OK to
change this though if you still find this issue essential.

Thanks,
-- Sergey Organov

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

* Re: [PATCH v1 09/27] diff-merges: re-arrange functions to match the order they are called in
  2020-12-03  5:52     ` Elijah Newren
@ 2020-12-03 15:41       ` Sergey Organov
  0 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-12-03 15:41 UTC (permalink / raw)
  To: Elijah Newren; +Cc: Junio C Hamano, Jeff King, Philip Oakley, Git Mailing List

Elijah Newren <newren@gmail.com> writes:

> On Sun, Nov 8, 2020 at 1:43 PM Sergey Organov <sorganov@gmail.com> wrote:
>>
>> For clarity, define public functions in the order they are called, to
>> make logic inter-dependencies easier to grok.
>
> You added diff-merges.[ch] earlier in this series.  Why not just add
> them in the correct order initially instead of adding another patch
> later in the series?

Well, I did consider it, but there are 2 issues that stopped me.

First, I didn't want to rearrange functions as I move them from
revision.c, to avoid mixed commit to simplify review, and second, I
didn't want to rearrange them in the original to perform as little
changes to the codebase as possible before isolating my work
into diff-merges.[ch].

Hope it makes sense.

Thanks,
-- Sergey Organov

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

* Re: [PATCH v1 04/27] revision: provide implementation for diff merges tweaks
  2020-12-03  5:28       ` Junio C Hamano
@ 2020-12-03 16:03         ` Sergey Organov
  0 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-12-03 16:03 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, Philip Oakley, git

Junio C Hamano <gitster@pobox.com> writes:

> Junio C Hamano <gitster@pobox.com> writes:
>
>> Is your naming convention that "rev_diff_" is the common prefix?
>> What's the significance of "_diff" part?  After all, these are about
>> tweaking the setting in the rev_info structure, so how about
>>
>> 	revinfo_show_merges_in_dense_combined_by_default(rev);
>> 	revinfo_show_merges_by_default_with_first_parent(rev);
>>
>> perhaps, using just "revinfo_" as the common prefix?
>
> Actually, I'd like to take these suggestions back.  I do not think
> these names that describe "what the function does" are good names at
> all.  If we can name them after what they are for, we'd be much
> better off.
>
> Given that one is part of the tweak for "show" and the other part of
> "log", I presume that one is to set-up default for showing a merge
> in the context of the "show" command, and the other is the same for
> the "log" (actually "log -p") command.  So perhaps
>
> 	diff_merges_set_default_for_show(revs);
> 	diff_merges_set_default_for_log(revs);
>
> are good names that tells us where they should be used and what for.

Sorry, here I disagree, see below.

> The former is to set up the default parameters to handle a merge
> commit in the context of the "show" command, and the latter is the
> same for the "log" command.  Naming them that way, we can then tweak
> what should happen for "show" by default without touching the caller
> if we wanted to (perhaps, "when doing first-parent traversal, really
> pretend that all the commits we see are single-parent, so show the
> change relative to its first parent by default without even
> requiring -m" might be something the latter can learn later).

I have multiple objections to this:

1. diff-merges, as a module or unit, is designed to provide needed
services to callers, not to dictate where exactly these services are
to be used.

2. diff-merges, as a module, should not care nor know if "git log" or
"git show" (or whatever top-level command), exists at all, so the
suggested names are not a good idea to have in the module.

3. The decision how exactly merge commits are to be shown for given user
command should better be expressed in that command, not hidden in the
implementation of diff-merges module.

4. Giving functions names by their place of call won't allow to sensibly
reuse them in other places, if needed, without renaming.

Overall, I believe the functions in the diff-merges unit must be called
after what they are doing to the format of the diff output for merges,
not after the places they are (currently) called at.

The functions you suggest, on the other hand, are fine and may have
their place, but they are at higher level of abstraction and should not
be part of the low-level diff-merges module.

Thanks,
-- Sergey Organov

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

* Re: [PATCH v1 05/27] revision: move diff merges functions to its own diff-merges.c
  2020-12-03  0:58     ` Junio C Hamano
@ 2020-12-03 16:44       ` Sergey Organov
  0 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-12-03 16:44 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, Philip Oakley, git

Junio C Hamano <gitster@pobox.com> writes:

> Sergey Organov <sorganov@gmail.com> writes:
>
>> diff --git a/diff-merges.h b/diff-merges.h
>> new file mode 100644
>> index 000000000000..e0cca3d935d3
>> --- /dev/null
>> +++ b/diff-merges.h
>> @@ -0,0 +1,12 @@
>> +#ifndef DIFF_MERGES_H
>> +#define DIFF_MERGES_H
>
> Describe what "diff-merges" module is about in a comment here.

Sure, will do.

> This matters because in 07/27 the log message complains that the
> first-parent traversal option is checked in the module but it is out
> of place.  Without defining what the "module" is about, the readers
> would have a hard time agreeing with the justification.

Yes, agreed.

>
> My guess is that this is about deciding how a merge commit is shown
> in 'log -p' and 'show' output, comparing the commit with its
> parent(s) in patch output.  With that explained, it may make sense
> for 07/27 to complain that --first-parent that is primarily a
> traversal option does also affect how a merge is shown (I do not
> necessarily agree with the complaint, though)

The is no complaint that --first-parent affects how merge is shown, at
least I didn't ever mean to complain about it.

From me there is a complaint that there is no way (before this series)
to make merge to be shown in the same manner without affecting
traversal, but that's not the problem of --first-parent user-visible
behavior.

I believe that in general, it'd be best that if an option makes more
than 1 thing, it does them by simply implying other options, so that
user is able to fine-tune each aspect of behavior independently.

For example, the design of --first-parent could have been that it simply
implies --follow-first-parent and --diff-merges=first-parent, each of
which do exactly one thing: the first defines how graph traversal is
performed, and the second defines how merge commits are shown.

OTOH, the resulting design of --first-parent after this series is an
example of another approach, also acceptable, where an option performs
its 1 primary action directly, and the rest -- by implying other
options. This design also covers all the possibilities, provided each
implicit option could be overridden.

Thanks,
Sergey Organov

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

* Re: [PATCH v1 27/27] doc/git-show: include --diff-merges description
  2020-11-08 21:38   ` [PATCH v1 27/27] doc/git-show: include --diff-merges description Sergey Organov
@ 2020-12-03 16:47     ` Elijah Newren
  2020-12-03 19:52       ` Sergey Organov
  0 siblings, 1 reply; 232+ messages in thread
From: Elijah Newren @ 2020-12-03 16:47 UTC (permalink / raw)
  To: Sergey Organov; +Cc: Junio C Hamano, Jeff King, Philip Oakley, Git Mailing List

Hi,

On Sun, Nov 8, 2020 at 1:44 PM Sergey Organov <sorganov@gmail.com> wrote:
>
> Move description of --diff-merges option from git-log.txt to
> diff-options.txt so that it is included in the git-show help.
>
> While we are at it, make git-show closer to git-log in this area by
> providing similar wording in the introduction of diff options.
>
> Signed-off-by: Sergey Organov <sorganov@gmail.com>
> ---
>  Documentation/diff-options.txt | 54 ++++++++++++++++++++++++++++++++++
>  Documentation/git-log.txt      | 52 --------------------------------
>  Documentation/git-show.txt     |  8 +++--
>  3 files changed, 60 insertions(+), 54 deletions(-)
>
> diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt
> index 573fb9bb71e2..f1629887103e 100644
> --- a/Documentation/diff-options.txt
> +++ b/Documentation/diff-options.txt
> @@ -33,6 +33,60 @@ endif::git-diff[]
>         show the patch by default, or to cancel the effect of `--patch`.
>  endif::git-format-patch[]
>
> +ifdef::git-log[]
> +Note that unless one of `--diff-merges` variants (including short
> +`-m`, `-c`, and `--cc` options) is explicitly given, merge commits
> +will not show a diff, even if a diff format like `--patch` is
> +selected, nor will they match search options like `-S`. The exception
> +is when `--first-parent` is in use, in which case
> +`--diff-merges=first-parent` is implied.

So, now diff-options says that no diffs are the defaults for merge commits...

> +
> +--diff-merges=(off|none|first-parent|separate|combined|dense-combined)::
> +--no-diff-merges::
> +       Specify diff format to be used for merge commits. This has no
> +       effect unless diff output is enabled in the first place (e.g.,
> +       with `--patch` option.)
> ++
> +--diff-merges=(off|none):::
> +--no-diff-merges:::
> +       (default) Disable output of diffs for merge commits. Useful to
> +       override implied value.
> ++
> +--diff-merges=first-parent:::
> +       This option makes merge commits show the full diff with
> +       respect to the first parent only, exactly like  regular
> +       commits.
> ++
> +--diff-merges=separate:::
> +-m:::
> +       This makes merge commits show the full diff with respect to
> +       each of the parents. Separate log entry and diff is generated
> +       for each parent.
> ++
> +--diff-merges=combined:::
> +-c:::
> +       With this option, diff output for a merge commit shows the
> +       differences from each of the parents to the merge result
> +       simultaneously instead of showing pairwise diff between a
> +       parent and the result one at a time. Furthermore, it lists
> +       only files which were modified from all parents.
> ++
> +--diff-merges=dense-combined:::
> +--cc:::
> +       With this option the output produced by
> +       `--diff-merges=combined` is further compressed by omitting
> +       uninteresting hunks whose contents in the parents have only
> +       two variants and the merge result picks one of them without
> +       modification.
> +
> +--combined-all-paths::
> +       This flag causes combined diffs (used for merge commits) to
> +       list the name of the file from all parents.  It thus only has
> +       effect when `--diff-merges=[dense-]combined` is in use, and
> +       is likely only useful if filename changes are detected (i.e.
> +       when either rename or copy detection have been requested).
> +endif::git-log[]
> +
>  -U<n>::
>  --unified=<n>::
>         Generate diffs with <n> lines of context instead of
> diff --git a/Documentation/git-log.txt b/Documentation/git-log.txt
> index de498a189646..0cacc780bf30 100644
> --- a/Documentation/git-log.txt
> +++ b/Documentation/git-log.txt
> @@ -120,58 +120,6 @@ DIFF FORMATTING
>  By default, `git log` does not generate any diff output. The options
>  below can be used to show the changes made by each commit.
>
> -Note that unless one of `--diff-merges` variants (including short
> -`-m`, `-c`, and `--cc` options) is explicitly given, merge commits
> -will not show a diff, even if a diff format like `--patch` is
> -selected, nor will they match search options like `-S`. The exception
> -is when `--first-parent` is in use, in which case
> -`--diff-merges=first-parent` is implied.
> -
> ---diff-merges=(off|none|first-parent|separate|combined|dense-combined)::
> ---no-diff-merges::
> -       Specify diff format to be used for merge commits. This has no
> -       effect unless diff output is enabled in the first place (e.g.,
> -       with `--patch` option.)
> -+
> ---diff-merges=(off|none):::
> ---no-diff-merges:::
> -       (default) Disable output of diffs for merge commits. Useful to
> -       override implied value.
> -+
> ---diff-merges=first-parent:::
> -       This option makes merge commits show the full diff with
> -       respect to the first parent only, exactly like  regular
> -       commits.
> -+
> ---diff-merges=separate:::
> --m:::
> -       This makes merge commits show the full diff with respect to
> -       each of the parents. Separate log entry and diff is generated
> -       for each parent.
> -+
> ---diff-merges=combined:::
> --c:::
> -       With this option, diff output for a merge commit shows the
> -       differences from each of the parents to the merge result
> -       simultaneously instead of showing pairwise diff between a
> -       parent and the result one at a time. Furthermore, it lists
> -       only files which were modified from all parents.
> -+
> ---diff-merges=dense-combined:::
> ---cc:::
> -       With this option the output produced by
> -       `--diff-merges=combined` is further compressed by omitting
> -       uninteresting hunks whose contents in the parents have only
> -       two variants and the merge result picks one of them without
> -       modification.
> -
> ---combined-all-paths::
> -       This flag causes combined diffs (used for merge commits) to
> -       list the name of the file from all parents.  It thus only has
> -       effect when `--diff-merges=[dense-]combined` is in use, and
> -       is likely only useful if filename changes are detected (i.e.
> -       when either rename or copy detection have been requested).
> -
>
>  :git-log: 1
>  include::diff-options.txt[]
> diff --git a/Documentation/git-show.txt b/Documentation/git-show.txt
> index fcf528c1b30d..abe58ce5d3a8 100644
> --- a/Documentation/git-show.txt
> +++ b/Documentation/git-show.txt
> @@ -45,8 +45,12 @@ include::pretty-options.txt[]
>  include::pretty-formats.txt[]
>
>
> -COMMON DIFF OPTIONS
> --------------------
> +DIFF FORMATTING
> +---------------
> +
> +By default, `git show` does not generate any diff output. The options
> +below can be used to show the changes made by each commit.
> +

This is not right, `git show` generates diff output by default for
both normal commits and merge commits -- it defaults to -p --cc (see
show_setup_revisions_tweak() of builtin/log.c).  Also see earlier in
git-show.txt where it says

       For commits it shows the log message and textual diff. It also presents
       the merge commit in a special format as produced by git diff-tree --cc.

>  :git-log: 1
>  include::diff-options.txt[]

...and the included text will contain the repeated claim that no diffs
are shown by default for merge commits, which is true for `git log`
but not `git show`.

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

* Re: [PATCH v1 06/27] diff-merges: rename all functions to have common prefix
  2020-12-03  0:52     ` Junio C Hamano
@ 2020-12-03 17:49       ` Sergey Organov
  0 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-12-03 17:49 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, Philip Oakley, git

Junio C Hamano <gitster@pobox.com> writes:

> Sergey Organov <sorganov@gmail.com> writes:
>
>> Use the same "diff_merges" prefix for all the diff merges function
>> names.
>>
>> Signed-off-by: Sergey Organov <sorganov@gmail.com>
>> ---
>>  builtin/log.c |  4 ++--
>>  diff-merges.c | 10 +++++-----
>>  diff-merges.h | 15 ++++++++++-----
>>  revision.c    |  6 +++---
>>  4 files changed, 20 insertions(+), 15 deletions(-)
>>
>> diff --git a/builtin/log.c b/builtin/log.c
>> index ad3092fdd854..77a7bba543ad 100644
>> --- a/builtin/log.c
>> +++ b/builtin/log.c
>> @@ -599,7 +599,7 @@ static int show_tree_object(const struct object_id *oid,
>>  static void show_setup_revisions_tweak(struct rev_info *rev,
>>  				       struct setup_revision_opt *opt)
>>  {
>> -	rev_diff_merges_default_to_dense_combined(rev);
>> +	diff_merges_default_to_dense_combined(rev);
>>  	if (!rev->diffopt.output_format)
>>  		rev->diffopt.output_format = DIFF_FORMAT_PATCH;
>>  }
>> @@ -724,7 +724,7 @@ static void log_setup_revisions_tweak(struct rev_info *rev,
>>  	if (!rev->diffopt.output_format && rev->combine_merges)
>>  		rev->diffopt.output_format = DIFF_FORMAT_PATCH;
>>  
>> -	rev_diff_merges_first_parent_defaults_to_enable(rev);
>> +	diff_merges_first_parent_defaults_to_enable(rev);
>
> Even with a different prefix, this name does not make it clear what
> is going on to its readers.  The other name is OK, though.

As this name goes away later, let's relax this one, and focus on the
final name, OK?

Thanks,
-- Sergey Organov

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

* Re: [PATCH v1 04/27] revision: provide implementation for diff merges tweaks
  2020-12-03  0:51     ` Junio C Hamano
  2020-12-03  5:28       ` Junio C Hamano
@ 2020-12-03 17:53       ` Sergey Organov
  1 sibling, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-12-03 17:53 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, Philip Oakley, git

Junio C Hamano <gitster@pobox.com> writes:

> Sergey Organov <sorganov@gmail.com> writes:
>
>> -	if (rev->ignore_merges < 0) {
>> -		/* There was no "-m" variant on the command line */
>> -		rev->ignore_merges = 0;
>> -		if (!rev->first_parent_only && !rev->combine_merges) {
>> -			/* No "--first-parent", "-c", or "--cc" */
>> -			rev->combine_merges = 1;
>> -			rev->dense_combined_merges = 1;
>> -		}
>> -	}
>> +	rev_diff_merges_default_to_dense_combined(rev);
>
> The name makes sense.  "Unless otherwise specified, we do not ignore
> merges.  Further, when we are not doing first-parent traversal,
> default to dense combined merges, unless told otherwise" is what the
> code says, and the name of the helper captures it well.
>
>> @@ -731,8 +723,7 @@ static void log_setup_revisions_tweak(struct rev_info *rev,
>>  	if (!rev->diffopt.output_format && rev->combine_merges)
>>  		rev->diffopt.output_format = DIFF_FORMAT_PATCH;
>>  
>> -	if (rev->first_parent_only && rev->ignore_merges < 0)
>> -		rev->ignore_merges = 0;
>> +	rev_diff_merges_first_parent_defaults_to_enable(rev);
>
> This on the other hand is not so great a name.  "When we are doing
> first-parent traversal, do not exclude merge commits from being
> shown" is what log_setup_revisions_tweak() does here.  "default to
> enable" is not clear at all what we are enabling.

As this name goes away later, let's relax this one, and focus on the
final name?

>
> Is your naming convention that "rev_diff_" is the common prefix?
> What's the significance of "_diff" part?  After all, these are about
> tweaking the setting in the rev_info structure, so how about
>
> 	revinfo_show_merges_in_dense_combined_by_default(rev);
> 	revinfo_show_merges_by_default_with_first_parent(rev);
>
> perhaps, using just "revinfo_" as the common prefix?

The prefixes here were selected just to have some to aid in refactoring,
without much thought. As all the prefixes change pretty soon in the
series anyway, can we let these be?

Thanks,
-- Sergey Organov

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

* Re: [PATCH v1 24/27] doc/git-log: describe new --diff-merges options
  2020-12-03  6:09     ` Elijah Newren
@ 2020-12-03 19:34       ` Sergey Organov
  2020-12-03 20:22         ` Elijah Newren
  0 siblings, 1 reply; 232+ messages in thread
From: Sergey Organov @ 2020-12-03 19:34 UTC (permalink / raw)
  To: Elijah Newren; +Cc: Junio C Hamano, Jeff King, Philip Oakley, Git Mailing List

Elijah Newren <newren@gmail.com> writes:

> On Sun, Nov 8, 2020 at 1:46 PM Sergey Organov <sorganov@gmail.com> wrote:
>>
>> Describe all the new --diff-merges options in the git-log.txt
>>
>> Signed-off-by: Sergey Organov <sorganov@gmail.com>
>> ---
>>  Documentation/git-log.txt | 79 +++++++++++++++++++++++----------------
>>  1 file changed, 46 insertions(+), 33 deletions(-)
>>
>> diff --git a/Documentation/git-log.txt b/Documentation/git-log.txt
>> index 2b8ac5ff882a..de498a189646 100644
>> --- a/Documentation/git-log.txt
>> +++ b/Documentation/git-log.txt
>> @@ -120,45 +120,58 @@ DIFF FORMATTING
>>  By default, `git log` does not generate any diff output. The options
>>  below can be used to show the changes made by each commit.
>>
>> -Note that unless one of `-c`, `--cc`, or `-m` is given, merge commits
>> -will never show a diff, even if a diff format like `--patch` is
>> -selected, nor will they match search options like `-S`. The exception is
>> -when `--first-parent` is in use, in which merges are treated like normal
>> -single-parent commits (this can be overridden by providing a
>> -combined-diff option or with `--no-diff-merges`).
>> +Note that unless one of `--diff-merges` variants (including short
>> +`-m`, `-c`, and `--cc` options) is explicitly given, merge commits
>> +will not show a diff, even if a diff format like `--patch` is
>> +selected, nor will they match search options like `-S`. The exception
>> +is when `--first-parent` is in use, in which case
>> +`--diff-merges=first-parent` is implied.
>>
>> --c::
>> -       With this option, diff output for a merge commit
>> -       shows the differences from each of the parents to the merge result
>> -       simultaneously instead of showing pairwise diff between a parent
>> -       and the result one at a time. Furthermore, it lists only files
>> -       which were modified from all parents.
>> -
>> ---cc::
>> -       This flag implies the `-c` option and further compresses the
>> -       patch output by omitting uninteresting hunks whose contents in
>> -       the parents have only two variants and the merge result picks
>> -       one of them without modification.
>> +--diff-merges=(off|none|first-parent|separate|combined|dense-combined)::
>> +--no-diff-merges::
>> +       Specify diff format to be used for merge commits. This has no
>> +       effect unless diff output is enabled in the first place (e.g.,
>> +       with `--patch` option.)
>
> This seems inconsistent with c7eaf8b4c3 ("log: when --cc is given,
> default to -p unless told otherwise", 2015-08-20); shouldn't these
> imply -p?

Looks like it is indeed, and worse yet, the patch series don't handle
this optimally due to my ignorance of this behavior. I think I need to
make changes to imply -p whenever some of diff-merge options (except
--diff-merges=none) are explicitly given, cause it's now, after these
patches, is unclear why only combined diffs imply -p, and not, say,
--diff-merges=first-parent.

Nice catch, thanks!

BTW, in the original, why only "git log" is affected? Ah, probably
because "git show" has -p by default?

While we are at it, why do we have "git show" at all? How is it
essentially different from "git log -n1 --first-parent ..."? I mean,
shouldn't it effectively be just an alias?

>
>> ++
>> +--diff-merges=(off|none):::
>> +--no-diff-merges:::
>> +       (default) Disable output of diffs for merge commits. Useful to
>> +       override implied value.
>> ++
>> +--diff-merges=first-parent:::
>> +       This option makes merge commits show the full diff with
>> +       respect to the first parent only, exactly like  regular
>> +       commits.
>
> Not sure that "exactly like regular commits" is helpful here; I'd
> personally rather cut those four words out.  I'm worried it'll be
> taken not as an implementation explanation, but as a "this treats
> merge commits in the natural way that regular commits are" which users
> may mistakenly translate to "it shows what changes the user manually
> made as part of the commit" which is not at all the correct mapping.

Dunno. Don't have strict preference here. Git has no idea how the
changes in a commit have been made in the first place. Changes are just
changes.

To my excuse, I took this from git:5fbb4bc191 that has:

+Note that unless one of `-c`, `--cc`, or `-m` is given, merge commits
+will never show a diff, even if a diff format like `--patch` is
+selected, nor will they match search options like `-S`. The exception is
+when `--first-parent` is in use, in which merges are treated like normal
+single-parent commits (this can be overridden by providing a
+combined-diff option or with `--no-diff-merges`).

Thanks,
-- Sergey Organov

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

* Re: [PATCH v1 00/27] git-log: implement new --diff-merge options
  2020-12-03  7:54   ` [PATCH v1 00/27] git-log: implement new --diff-merge options Elijah Newren
@ 2020-12-03 19:48     ` Sergey Organov
  2020-12-03 20:39       ` Elijah Newren
  0 siblings, 1 reply; 232+ messages in thread
From: Sergey Organov @ 2020-12-03 19:48 UTC (permalink / raw)
  To: Elijah Newren; +Cc: Junio C Hamano, Jeff King, Philip Oakley, Git Mailing List

Elijah Newren <newren@gmail.com> writes:

> On Sun, Nov 8, 2020 at 1:43 PM Sergey Organov <sorganov@gmail.com> wrote:
>>
>> These patch series implement new set of options governing the diff output
>> of merge commits, all under the umbrella of the single --diff-merges=<mode>
>> option. Most of the new options being synonyms for -m/-c/--cc options,
>> there is also additional functionality provided, allowing to get the format
>> of "-p --first-parent" without change in history traversal that
>> --first-parent option causes.
>>
>> The net result of these series are the following new options:
>>
>> --diff-merges=   |  old equivalent
>> -----------------+----------------
>> first-parent     | --first-parent (only format implications)
>> separate         | -m
>> combined         | -c
>> dense-combined   | --cc
>
> Interesting.  I have some local patches implementing another choice,
> with the new flag --remerge-diff.  This flag will cause `git show` or
> `git log` to automatically remerge the two parents in a 2-parent merge
> commit, and then diff the merge commit against that automatic merge,
> showing the result.  Thus, the diff for a merge commit is likely to be
> empty if the merge was clean, and is likely to show the removal of
> conflict markers if the merge was not clean.
>
> I'm curious how it'd interact with this new option.  Would it also get
> a name, e.g. --diff-merges=remerge-diff?  Feels like a mouthful, but I
> can't come up with anything better.

Maybe, --diff-merges=remerge?

>
> Also, I'm curious how it'd interact with another option I added, named
> --remerge-diff-only.  This latter option modifies revision traversal
> in that it skips octopus merges, root commits, and single parent
> commits IF no cherry-pick or revert information can be found.  If it
> finds a 2-parent merge commit, it behaves like --remerge-diff.  If it
> finds a 1-parent commit with cherry-pick or revert information, it'll
> do an in memory repeat of that cherry-pick (or revert) and then diff
> the actual commit against what the automatic cherry-pick would
> perform.  Again, that likely means an empty diff if the automatic
> cherry-pick was clean, and showing any changes made by the user to
> complete the original cherry-pick (such as deleting conflict markers
> and picking which chunks from which side to keep) if the automatic
> cherry-pick was not clean.  (I suspect --remerge-diff-only is much
> more likely to be used with `git show` than with `git log`.)  Anyway,
> your changes seem to suggest that anything relating to how diffs for
> merges are handled should be documented in the same section, but
> --remerge-diff-only doesn't fit.  And it'd seem odd to have
> --remerge-diff and --remerge-diff-only not show up in adjacently but
> be split into separate sections.  Any ideas?

Sounds like commits limiting option to me. I think it could be named by
its limiting behavior only, say, --remerges. Then it will imply
--diff-merges=remerge, that'd allow user to re-define diff format if she
needs to.

I mean, it looks very similar to --first-parent to me in the ways it
could be defined/implemented. Recall that --first-parent now implies
--diff-merges=first-parent.

[...]

>>
>> Updates in v1:
>
> A minor point, but this should have been labelled v2.  The unlabelled
> original submission is v1.

Well, I did consider it when prepared v1, but given:

  git format-patch --reroll-count=0

produces [PATCH], it only sounds natural to follow with

  git format-patch --reroll-count=1

that produces [PATCH v1].

Thanks,
-- Sergey Organov

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

* Re: [PATCH v1 27/27] doc/git-show: include --diff-merges description
  2020-12-03 16:47     ` Elijah Newren
@ 2020-12-03 19:52       ` Sergey Organov
  0 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-12-03 19:52 UTC (permalink / raw)
  To: Elijah Newren; +Cc: Junio C Hamano, Jeff King, Philip Oakley, Git Mailing List

Elijah Newren <newren@gmail.com> writes:
> Hi,
>
> On Sun, Nov 8, 2020 at 1:44 PM Sergey Organov <sorganov@gmail.com> wrote:
>>
>> Move description of --diff-merges option from git-log.txt to
>> diff-options.txt so that it is included in the git-show help.
>>
>> While we are at it, make git-show closer to git-log in this area by
>> providing similar wording in the introduction of diff options.
>>
>> Signed-off-by: Sergey Organov <sorganov@gmail.com>
>> ---
>>  Documentation/diff-options.txt | 54 ++++++++++++++++++++++++++++++++++
>>  Documentation/git-log.txt      | 52 --------------------------------
>>  Documentation/git-show.txt     |  8 +++--
>>  3 files changed, 60 insertions(+), 54 deletions(-)
>>
>> diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt
>> index 573fb9bb71e2..f1629887103e 100644
>> --- a/Documentation/diff-options.txt
>> +++ b/Documentation/diff-options.txt
>> @@ -33,6 +33,60 @@ endif::git-diff[]
>>         show the patch by default, or to cancel the effect of `--patch`.
>>  endif::git-format-patch[]
>>
>> +ifdef::git-log[]
>> +Note that unless one of `--diff-merges` variants (including short
>> +`-m`, `-c`, and `--cc` options) is explicitly given, merge commits
>> +will not show a diff, even if a diff format like `--patch` is
>> +selected, nor will they match search options like `-S`. The exception
>> +is when `--first-parent` is in use, in which case
>> +`--diff-merges=first-parent` is implied.
>
> So, now diff-options says that no diffs are the defaults for merge commits...
>
>> +
>> +--diff-merges=(off|none|first-parent|separate|combined|dense-combined)::
>> +--no-diff-merges::
>> +       Specify diff format to be used for merge commits. This has no
>> +       effect unless diff output is enabled in the first place (e.g.,
>> +       with `--patch` option.)
>> ++
>> +--diff-merges=(off|none):::
>> +--no-diff-merges:::
>> +       (default) Disable output of diffs for merge commits. Useful to
>> +       override implied value.
>> ++
>> +--diff-merges=first-parent:::
>> +       This option makes merge commits show the full diff with
>> +       respect to the first parent only, exactly like  regular
>> +       commits.
>> ++
>> +--diff-merges=separate:::
>> +-m:::
>> +       This makes merge commits show the full diff with respect to
>> +       each of the parents. Separate log entry and diff is generated
>> +       for each parent.
>> ++
>> +--diff-merges=combined:::
>> +-c:::
>> +       With this option, diff output for a merge commit shows the
>> +       differences from each of the parents to the merge result
>> +       simultaneously instead of showing pairwise diff between a
>> +       parent and the result one at a time. Furthermore, it lists
>> +       only files which were modified from all parents.
>> ++
>> +--diff-merges=dense-combined:::
>> +--cc:::
>> +       With this option the output produced by
>> +       `--diff-merges=combined` is further compressed by omitting
>> +       uninteresting hunks whose contents in the parents have only
>> +       two variants and the merge result picks one of them without
>> +       modification.
>> +
>> +--combined-all-paths::
>> +       This flag causes combined diffs (used for merge commits) to
>> +       list the name of the file from all parents.  It thus only has
>> +       effect when `--diff-merges=[dense-]combined` is in use, and
>> +       is likely only useful if filename changes are detected (i.e.
>> +       when either rename or copy detection have been requested).
>> +endif::git-log[]
>> +
>>  -U<n>::
>>  --unified=<n>::
>>         Generate diffs with <n> lines of context instead of
>> diff --git a/Documentation/git-log.txt b/Documentation/git-log.txt
>> index de498a189646..0cacc780bf30 100644
>> --- a/Documentation/git-log.txt
>> +++ b/Documentation/git-log.txt
>> @@ -120,58 +120,6 @@ DIFF FORMATTING
>>  By default, `git log` does not generate any diff output. The options
>>  below can be used to show the changes made by each commit.
>>
>> -Note that unless one of `--diff-merges` variants (including short
>> -`-m`, `-c`, and `--cc` options) is explicitly given, merge commits
>> -will not show a diff, even if a diff format like `--patch` is
>> -selected, nor will they match search options like `-S`. The exception
>> -is when `--first-parent` is in use, in which case
>> -`--diff-merges=first-parent` is implied.
>> -
>> ---diff-merges=(off|none|first-parent|separate|combined|dense-combined)::
>> ---no-diff-merges::
>> -       Specify diff format to be used for merge commits. This has no
>> -       effect unless diff output is enabled in the first place (e.g.,
>> -       with `--patch` option.)
>> -+
>> ---diff-merges=(off|none):::
>> ---no-diff-merges:::
>> -       (default) Disable output of diffs for merge commits. Useful to
>> -       override implied value.
>> -+
>> ---diff-merges=first-parent:::
>> -       This option makes merge commits show the full diff with
>> -       respect to the first parent only, exactly like  regular
>> -       commits.
>> -+
>> ---diff-merges=separate:::
>> --m:::
>> -       This makes merge commits show the full diff with respect to
>> -       each of the parents. Separate log entry and diff is generated
>> -       for each parent.
>> -+
>> ---diff-merges=combined:::
>> --c:::
>> -       With this option, diff output for a merge commit shows the
>> -       differences from each of the parents to the merge result
>> -       simultaneously instead of showing pairwise diff between a
>> -       parent and the result one at a time. Furthermore, it lists
>> -       only files which were modified from all parents.
>> -+
>> ---diff-merges=dense-combined:::
>> ---cc:::
>> -       With this option the output produced by
>> -       `--diff-merges=combined` is further compressed by omitting
>> -       uninteresting hunks whose contents in the parents have only
>> -       two variants and the merge result picks one of them without
>> -       modification.
>> -
>> ---combined-all-paths::
>> -       This flag causes combined diffs (used for merge commits) to
>> -       list the name of the file from all parents.  It thus only has
>> -       effect when `--diff-merges=[dense-]combined` is in use, and
>> -       is likely only useful if filename changes are detected (i.e.
>> -       when either rename or copy detection have been requested).
>> -
>>
>>  :git-log: 1
>>  include::diff-options.txt[]
>> diff --git a/Documentation/git-show.txt b/Documentation/git-show.txt
>> index fcf528c1b30d..abe58ce5d3a8 100644
>> --- a/Documentation/git-show.txt
>> +++ b/Documentation/git-show.txt
>> @@ -45,8 +45,12 @@ include::pretty-options.txt[]
>>  include::pretty-formats.txt[]
>>
>>
>> -COMMON DIFF OPTIONS
>> --------------------
>> +DIFF FORMATTING
>> +---------------
>> +
>> +By default, `git show` does not generate any diff output. The options
>> +below can be used to show the changes made by each commit.
>> +
>
> This is not right, `git show` generates diff output by default for
> both normal commits and merge commits -- it defaults to -p --cc (see
> show_setup_revisions_tweak() of builtin/log.c).  Also see earlier in
> git-show.txt where it says
>
>        For commits it shows the log message and textual diff. It also presents
>        the merge commit in a special format as produced by git diff-tree --cc.
>
>>  :git-log: 1
>>  include::diff-options.txt[]
>
> ...and the included text will contain the repeated claim that no diffs
> are shown by default for merge commits, which is true for `git log`
> but not `git show`.

Yes, I need to re-consider this, as I already admitted in my reply to
your previous catch of the related problem in the documentation.

They all came from single point of misunderstanding.

Will try to get it right in the next re-roll.

Thanks,
-- Sergey Organov

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

* Re: [PATCH 10/26] diff-merges: new function diff_merges_suppress()
  2020-12-03  5:52   ` Elijah Newren
@ 2020-12-03 20:06     ` Sergey Organov
  2020-12-03 20:28       ` Elijah Newren
  0 siblings, 1 reply; 232+ messages in thread
From: Sergey Organov @ 2020-12-03 20:06 UTC (permalink / raw)
  To: Elijah Newren; +Cc: Junio C Hamano, Jeff King, Git Mailing List

Elijah Newren <newren@gmail.com> writes:

> On Sun, Nov 1, 2020 at 11:36 AM Sergey Organov <sorganov@gmail.com> wrote:
>>
>> This function sets all the relevant flags to disabled state, so that
>> no code that checks only one of them get it wrong.
>>
>> Then we call this new function everywhere where diff merges output
>> suppression is needed.
>>
>> Signed-off-by: Sergey Organov <sorganov@gmail.com>
>> ---
>>  builtin/merge.c |  3 ++-
>>  diff-merges.c   | 18 ++++++++++++++----
>>  diff-merges.h   |  2 ++
>>  fmt-merge-msg.c |  3 ++-
>>  4 files changed, 20 insertions(+), 6 deletions(-)
>>
>> diff --git a/builtin/merge.c b/builtin/merge.c
>> index 9d5359edc2f7..1f7b69982b40 100644
>> --- a/builtin/merge.c
>> +++ b/builtin/merge.c
>> @@ -14,6 +14,7 @@
>>  #include "lockfile.h"
>>  #include "run-command.h"
>>  #include "diff.h"
>> +#include "diff-merges.h"
>>  #include "refs.h"
>>  #include "refspec.h"
>>  #include "commit.h"
>> @@ -400,7 +401,7 @@ static void squash_message(struct commit *commit, struct commit_list *remotehead
>>         printf(_("Squash commit -- not updating HEAD\n"));
>>
>>         repo_init_revisions(the_repository, &rev, NULL);
>> -       rev.ignore_merges = 1;
>> +       diff_merges_suppress(&rev);
>>         rev.commit_format = CMIT_FMT_MEDIUM;
>>
>>         commit->object.flags |= UNINTERESTING;
>> diff --git a/diff-merges.c b/diff-merges.c
>> index 8536941e0b56..25bd9b12e667 100644
>> --- a/diff-merges.c
>> +++ b/diff-merges.c
>> @@ -2,6 +2,13 @@
>>
>>  #include "revision.h"
>>
>> +static void suppress(struct rev_info *revs) {
>> +       revs->ignore_merges = 1;
>> +       revs->first_parent_merges = 0;
>> +       revs->combine_merges = 0;
>> +       revs->dense_combined_merges = 0;
>> +}
>
> The function name is not so helpful;

Do you have better suggestion? suppress_output()? supress_diff()?

> why not put all this code directly in diff_merges_suppress()?

I prefer the style where module implementation functions don't call its
interface functions, only vice versa.

>
>> +
>>  /*
>>   * Public functions. They are in the order they are called.
>>   */
>> @@ -29,16 +36,15 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {
>>                 revs->combine_merges = 1;
>>         } else if (!strcmp(arg, "--cc")) {
>>                 revs->diff = 1;
>> -               revs->dense_combined_merges = 1;
>> -               revs->combine_merges = 1;
>> +               set_dense_combined(revs);
>>         } else if (!strcmp(arg, "--no-diff-merges")) {
>> -               revs->ignore_merges = 1;
>> +               suppress(revs);
>>         } else if (!strcmp(arg, "--combined-all-paths")) {
>>                 revs->diff = 1;
>>                 revs->combined_all_paths = 1;
>>         } else if ((argcount = parse_long_opt("diff-merges", argv, &optarg))) {
>>                 if (!strcmp(optarg, "off")) {
>> -                       revs->ignore_merges = 1;
>> +                       suppress(revs);
>>                 } else {
>>                         die(_("unknown value for --diff-merges: %s"), optarg);
>>                 }
>> @@ -48,6 +54,10 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {
>>         return 1;
>>  }
>>
>> +void diff_merges_suppress(struct rev_info *revs) {
>> +       suppress(revs);
>> +}
>
> ...especially since all this function does is call suppress()?

Yes, it does, but it doesn't mean it will be that way forever. Interface
function might need to perform additional checks or actions, in general.

Besides, if diff_merges_suppress() is OK with you as interface function
name, why suppress() is not OK as local function name in diff-merges
module?

Thanks,
-- Sergey Organov

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

* Re: [PATCH v1 24/27] doc/git-log: describe new --diff-merges options
  2020-12-03 19:34       ` Sergey Organov
@ 2020-12-03 20:22         ` Elijah Newren
  2020-12-04 17:34           ` Sergey Organov
  0 siblings, 1 reply; 232+ messages in thread
From: Elijah Newren @ 2020-12-03 20:22 UTC (permalink / raw)
  To: Sergey Organov; +Cc: Junio C Hamano, Jeff King, Philip Oakley, Git Mailing List

On Thu, Dec 3, 2020 at 11:34 AM Sergey Organov <sorganov@gmail.com> wrote:
>
> Elijah Newren <newren@gmail.com> writes:
>
> > On Sun, Nov 8, 2020 at 1:46 PM Sergey Organov <sorganov@gmail.com> wrote:
> >>
> >> Describe all the new --diff-merges options in the git-log.txt
> >>
> >> Signed-off-by: Sergey Organov <sorganov@gmail.com>
> >> ---
> >>  Documentation/git-log.txt | 79 +++++++++++++++++++++++----------------
> >>  1 file changed, 46 insertions(+), 33 deletions(-)
> >>
> >> diff --git a/Documentation/git-log.txt b/Documentation/git-log.txt
> >> index 2b8ac5ff882a..de498a189646 100644
> >> --- a/Documentation/git-log.txt
> >> +++ b/Documentation/git-log.txt
> >> @@ -120,45 +120,58 @@ DIFF FORMATTING
> >>  By default, `git log` does not generate any diff output. The options
> >>  below can be used to show the changes made by each commit.
> >>
> >> -Note that unless one of `-c`, `--cc`, or `-m` is given, merge commits
> >> -will never show a diff, even if a diff format like `--patch` is
> >> -selected, nor will they match search options like `-S`. The exception is
> >> -when `--first-parent` is in use, in which merges are treated like normal
> >> -single-parent commits (this can be overridden by providing a
> >> -combined-diff option or with `--no-diff-merges`).
> >> +Note that unless one of `--diff-merges` variants (including short
> >> +`-m`, `-c`, and `--cc` options) is explicitly given, merge commits
> >> +will not show a diff, even if a diff format like `--patch` is
> >> +selected, nor will they match search options like `-S`. The exception
> >> +is when `--first-parent` is in use, in which case
> >> +`--diff-merges=first-parent` is implied.
> >>
> >> --c::
> >> -       With this option, diff output for a merge commit
> >> -       shows the differences from each of the parents to the merge result
> >> -       simultaneously instead of showing pairwise diff between a parent
> >> -       and the result one at a time. Furthermore, it lists only files
> >> -       which were modified from all parents.
> >> -
> >> ---cc::
> >> -       This flag implies the `-c` option and further compresses the
> >> -       patch output by omitting uninteresting hunks whose contents in
> >> -       the parents have only two variants and the merge result picks
> >> -       one of them without modification.
> >> +--diff-merges=(off|none|first-parent|separate|combined|dense-combined)::
> >> +--no-diff-merges::
> >> +       Specify diff format to be used for merge commits. This has no
> >> +       effect unless diff output is enabled in the first place (e.g.,
> >> +       with `--patch` option.)
> >
> > This seems inconsistent with c7eaf8b4c3 ("log: when --cc is given,
> > default to -p unless told otherwise", 2015-08-20); shouldn't these
> > imply -p?
>
> Looks like it is indeed, and worse yet, the patch series don't handle
> this optimally due to my ignorance of this behavior. I think I need to
> make changes to imply -p whenever some of diff-merge options (except
> --diff-merges=none) are explicitly given, cause it's now, after these
> patches, is unclear why only combined diffs imply -p, and not, say,
> --diff-merges=first-parent.
>
> Nice catch, thanks!
>
> BTW, in the original, why only "git log" is affected? Ah, probably
> because "git show" has -p by default?
>
> While we are at it, why do we have "git show" at all? How is it
> essentially different from "git log -n1 --first-parent ..."? I mean,
> shouldn't it effectively be just an alias?

git show does not just operate on commits.  It can also display blobs,
trees, or tags.  I see people use it with blobs in the form of
REVISION:FILENAME references.  git show also is not limited to
displaying just one object, hence -n1 would be problematic; you'd need
to use --no-walk instead when operating on commits.  Also, git show
uses --cc when operating on commits, not --first-parent.

However, you are right that it is pretty close to just being something
you could alias if you limited it to commits.  If I understand
correctly, that alias would be `git log --no-walk -p --cc ...` (though
you only need the explicit -p with pretty old versions of git).

> >
> >> ++
> >> +--diff-merges=(off|none):::
> >> +--no-diff-merges:::
> >> +       (default) Disable output of diffs for merge commits. Useful to
> >> +       override implied value.
> >> ++
> >> +--diff-merges=first-parent:::
> >> +       This option makes merge commits show the full diff with
> >> +       respect to the first parent only, exactly like  regular
> >> +       commits.
> >
> > Not sure that "exactly like regular commits" is helpful here; I'd
> > personally rather cut those four words out.  I'm worried it'll be
> > taken not as an implementation explanation, but as a "this treats
> > merge commits in the natural way that regular commits are" which users
> > may mistakenly translate to "it shows what changes the user manually
> > made as part of the commit" which is not at all the correct mapping.
>
> Dunno. Don't have strict preference here. Git has no idea how the
> changes in a commit have been made in the first place. Changes are just
> changes.

If you don't have a preference, can we drop those four words?  ;-)

> To my excuse, I took this from git:5fbb4bc191 that has:
>
> +Note that unless one of `-c`, `--cc`, or `-m` is given, merge commits
> +will never show a diff, even if a diff format like `--patch` is
> +selected, nor will they match search options like `-S`. The exception is
> +when `--first-parent` is in use, in which merges are treated like normal
> +single-parent commits (this can be overridden by providing a
> +combined-diff option or with `--no-diff-merges`).

Yeah, I can see where you're coming from, though the context change
feels like just enough different that the four words you added bother
me a bit more.  However, this existing wording does bother me now that
you highlight it.  Even though it's not something introduced by your
patch, I'd really like to drop "normal" here; I think it is prone to
cause confusion to users and as far as I can tell provides no useful
meaning for the sentence.  (There are multiple types of single-parent
commits?  What is an "unnormal" one?  How do I tell which kind I want?
 etc...).

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

* Re: [PATCH v1 07/27] diff-merges: move checks for first_parent_only out of the module
  2020-12-03  1:09     ` Junio C Hamano
@ 2020-12-03 20:22       ` Sergey Organov
  0 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-12-03 20:22 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, Philip Oakley, git

Junio C Hamano <gitster@pobox.com> writes:

> Sergey Organov <sorganov@gmail.com> writes:
>
>> The checks for first_parent_only don't in fact belong to this module,
>> as the primary purpose of this flag is history traversal limiting, so
>> get it out of this module and rename the
>>
>> diff_merges_first_parent_defaults_to_enable()
>>
>> to
>>
>> diff_merges_default_to_enable()
>
> Again, neither is a great name.
>
> More importantly, I do not think that I agree with the reasoning
> given in the first paragraph.  The first-parent-only traversal means
> that we pretend there is no second and later parents, so it makes
> quite a lot of sense that the choice of that option affects how a
> merge commit discovered during the traversal is show by default
> (namely, as if it is just a single-parent commit).

I have no objections against this behavior, nor did I change it, so I
don't understand what reasoning you disagree with.

The code that handles --first-parent now explicitly says it needs
corresponding format of diff output by default, exactly as you describe,
so what's the problem?

>
> If there are other reasons why we want to force the callers to check
> for first-parent option (for example, it may make it easier to tweak
> how each caller makes its decisions separately in later steps of
> this series), the changes proposed by this step may be a right
> solution, so I am not outright opposed to this patch, but the
> rationale given above is not a strong enough justification for the
> change, at least to me.
>
>> +void diff_merges_default_to_enable(struct rev_info *revs) {
>
> Perhaps "show_merges_by_default()".

Doesn't sound good to me either. We usually do show merges. We only
don't show any kind of diffs for them.

>
>> +	if (revs->ignore_merges < 0)		/* No -m */
>>  		revs->ignore_merges = 0;
>
> Perhaps "show_merges_in_cc_by_default()" (or "cc" spelled out as
> "dense_combined").

Well, I think it's better to discuss final names instead of intermediate
refactoring ones that will disappear anyway. At least as a fist step. If
we get them right, intermediates could be fixed accordingly more
easily, I think.


[...]

Thanks,
-- Sergey Organov

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

* Re: [PATCH 10/26] diff-merges: new function diff_merges_suppress()
  2020-12-03 20:06     ` Sergey Organov
@ 2020-12-03 20:28       ` Elijah Newren
  2020-12-04 17:23         ` Sergey Organov
  0 siblings, 1 reply; 232+ messages in thread
From: Elijah Newren @ 2020-12-03 20:28 UTC (permalink / raw)
  To: Sergey Organov; +Cc: Junio C Hamano, Jeff King, Git Mailing List

Hi Sergey,

On Thu, Dec 3, 2020 at 12:06 PM Sergey Organov <sorganov@gmail.com> wrote:
>
> Elijah Newren <newren@gmail.com> writes:
>
> > On Sun, Nov 1, 2020 at 11:36 AM Sergey Organov <sorganov@gmail.com> wrote:
> >>
> >> This function sets all the relevant flags to disabled state, so that
> >> no code that checks only one of them get it wrong.
> >>
> >> Then we call this new function everywhere where diff merges output
> >> suppression is needed.
> >>
> >> Signed-off-by: Sergey Organov <sorganov@gmail.com>
> >> ---
> >>  builtin/merge.c |  3 ++-
> >>  diff-merges.c   | 18 ++++++++++++++----
> >>  diff-merges.h   |  2 ++
> >>  fmt-merge-msg.c |  3 ++-
> >>  4 files changed, 20 insertions(+), 6 deletions(-)
> >>
> >> diff --git a/builtin/merge.c b/builtin/merge.c
> >> index 9d5359edc2f7..1f7b69982b40 100644
> >> --- a/builtin/merge.c
> >> +++ b/builtin/merge.c
> >> @@ -14,6 +14,7 @@
> >>  #include "lockfile.h"
> >>  #include "run-command.h"
> >>  #include "diff.h"
> >> +#include "diff-merges.h"
> >>  #include "refs.h"
> >>  #include "refspec.h"
> >>  #include "commit.h"
> >> @@ -400,7 +401,7 @@ static void squash_message(struct commit *commit, struct commit_list *remotehead
> >>         printf(_("Squash commit -- not updating HEAD\n"));
> >>
> >>         repo_init_revisions(the_repository, &rev, NULL);
> >> -       rev.ignore_merges = 1;
> >> +       diff_merges_suppress(&rev);
> >>         rev.commit_format = CMIT_FMT_MEDIUM;
> >>
> >>         commit->object.flags |= UNINTERESTING;
> >> diff --git a/diff-merges.c b/diff-merges.c
> >> index 8536941e0b56..25bd9b12e667 100644
> >> --- a/diff-merges.c
> >> +++ b/diff-merges.c
> >> @@ -2,6 +2,13 @@
> >>
> >>  #include "revision.h"
> >>
> >> +static void suppress(struct rev_info *revs) {
> >> +       revs->ignore_merges = 1;
> >> +       revs->first_parent_merges = 0;
> >> +       revs->combine_merges = 0;
> >> +       revs->dense_combined_merges = 0;
> >> +}
> >
> > The function name is not so helpful;
>
> Do you have better suggestion? suppress_output()? supress_diff()?
>
> > why not put all this code directly in diff_merges_suppress()?
>
> I prefer the style where module implementation functions don't call its
> interface functions, only vice versa.
>
> >
> >> +
> >>  /*
> >>   * Public functions. They are in the order they are called.
> >>   */
> >> @@ -29,16 +36,15 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {
> >>                 revs->combine_merges = 1;
> >>         } else if (!strcmp(arg, "--cc")) {
> >>                 revs->diff = 1;
> >> -               revs->dense_combined_merges = 1;
> >> -               revs->combine_merges = 1;
> >> +               set_dense_combined(revs);
> >>         } else if (!strcmp(arg, "--no-diff-merges")) {
> >> -               revs->ignore_merges = 1;
> >> +               suppress(revs);
> >>         } else if (!strcmp(arg, "--combined-all-paths")) {
> >>                 revs->diff = 1;
> >>                 revs->combined_all_paths = 1;
> >>         } else if ((argcount = parse_long_opt("diff-merges", argv, &optarg))) {
> >>                 if (!strcmp(optarg, "off")) {
> >> -                       revs->ignore_merges = 1;
> >> +                       suppress(revs);
> >>                 } else {
> >>                         die(_("unknown value for --diff-merges: %s"), optarg);
> >>                 }
> >> @@ -48,6 +54,10 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {
> >>         return 1;
> >>  }
> >>
> >> +void diff_merges_suppress(struct rev_info *revs) {
> >> +       suppress(revs);
> >> +}
> >
> > ...especially since all this function does is call suppress()?
>
> Yes, it does, but it doesn't mean it will be that way forever. Interface
> function might need to perform additional checks or actions, in general.

Ah, I didn't catch the distinction and thus the reasoning in having
the two different functions.

> Besides, if diff_merges_suppress() is OK with you as interface function
> name, why suppress() is not OK as local function name in diff-merges
> module?

Right, the fact that it's in the diff-merges module as opposed to more
general diff-lib code is probably hint enough.  I was skimming over
the patches looking for things that jumped out, and although I had
read that you were adding it to the new module, I forgot that when I
saw the "suppress()" function name.  Thanks for the reminder, and
sorry for the noise.

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

* Re: [PATCH v1 00/27] git-log: implement new --diff-merge options
  2020-12-03 19:48     ` Sergey Organov
@ 2020-12-03 20:39       ` Elijah Newren
  2020-12-04 19:23         ` Sergey Organov
  0 siblings, 1 reply; 232+ messages in thread
From: Elijah Newren @ 2020-12-03 20:39 UTC (permalink / raw)
  To: Sergey Organov; +Cc: Junio C Hamano, Jeff King, Philip Oakley, Git Mailing List

On Thu, Dec 3, 2020 at 11:48 AM Sergey Organov <sorganov@gmail.com> wrote:
>
> Elijah Newren <newren@gmail.com> writes:
>
> > On Sun, Nov 8, 2020 at 1:43 PM Sergey Organov <sorganov@gmail.com> wrote:
> >>
> >> These patch series implement new set of options governing the diff output
> >> of merge commits, all under the umbrella of the single --diff-merges=<mode>
> >> option. Most of the new options being synonyms for -m/-c/--cc options,
> >> there is also additional functionality provided, allowing to get the format
> >> of "-p --first-parent" without change in history traversal that
> >> --first-parent option causes.
> >>
> >> The net result of these series are the following new options:
> >>
> >> --diff-merges=   |  old equivalent
> >> -----------------+----------------
> >> first-parent     | --first-parent (only format implications)
> >> separate         | -m
> >> combined         | -c
> >> dense-combined   | --cc
> >
> > Interesting.  I have some local patches implementing another choice,
> > with the new flag --remerge-diff.  This flag will cause `git show` or
> > `git log` to automatically remerge the two parents in a 2-parent merge
> > commit, and then diff the merge commit against that automatic merge,
> > showing the result.  Thus, the diff for a merge commit is likely to be
> > empty if the merge was clean, and is likely to show the removal of
> > conflict markers if the merge was not clean.
> >
> > I'm curious how it'd interact with this new option.  Would it also get
> > a name, e.g. --diff-merges=remerge-diff?  Feels like a mouthful, but I
> > can't come up with anything better.
>
> Maybe, --diff-merges=remerge?
>
> >
> > Also, I'm curious how it'd interact with another option I added, named
> > --remerge-diff-only.  This latter option modifies revision traversal
> > in that it skips octopus merges, root commits, and single parent
> > commits IF no cherry-pick or revert information can be found.  If it
> > finds a 2-parent merge commit, it behaves like --remerge-diff.  If it
> > finds a 1-parent commit with cherry-pick or revert information, it'll
> > do an in memory repeat of that cherry-pick (or revert) and then diff
> > the actual commit against what the automatic cherry-pick would
> > perform.  Again, that likely means an empty diff if the automatic
> > cherry-pick was clean, and showing any changes made by the user to
> > complete the original cherry-pick (such as deleting conflict markers
> > and picking which chunks from which side to keep) if the automatic
> > cherry-pick was not clean.  (I suspect --remerge-diff-only is much
> > more likely to be used with `git show` than with `git log`.)  Anyway,
> > your changes seem to suggest that anything relating to how diffs for
> > merges are handled should be documented in the same section, but
> > --remerge-diff-only doesn't fit.  And it'd seem odd to have
> > --remerge-diff and --remerge-diff-only not show up in adjacently but
> > be split into separate sections.  Any ideas?
>
> Sounds like commits limiting option to me. I think it could be named by
> its limiting behavior only, say, --remerges. Then it will imply
> --diff-merges=remerge, that'd allow user to re-define diff format if she
> needs to.

It is commit limiting, but the focus is more on the behavioral change
in how diffs are shown:
  * for 2-parent merges
  * for single-parent commits with cherry-pick or revert information
and acknowledging that since it has _altered_ the normal way of
showing diffs for a number of single-parent commits, that it'd be
confusing to show normal diffs of unaffected commits (how would you be
able to tell what type of diff you're looking at if both appear in the
log?).  Thus, it does commit limiting to only select commits which
will make use of the new diff type.

(I suspect it will be more common for folks to use the
--remerge-diff-only option, or whatever we end up calling it, with
`git show` where the commit limiting doesn't matter -- but I have used
it with log to go looking for "evil" reverts/cherry-picks that might
have occurred in history.)

> I mean, it looks very similar to --first-parent to me in the ways it
> could be defined/implemented. Recall that --first-parent now implies
> --diff-merges=first-parent.
>
> [...]
>
> >>
> >> Updates in v1:
> >
> > A minor point, but this should have been labelled v2.  The unlabelled
> > original submission is v1.
>
> Well, I did consider it when prepared v1, but given:
>
>   git format-patch --reroll-count=0
>
> produces [PATCH], it only sounds natural to follow with
>
>   git format-patch --reroll-count=1
>
> that produces [PATCH v1].

I didn't know about --reroll-count, I've always just seen people jump
from [PATCH] to [PATCH v2].  Interesting.

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

* Re: [PATCH v1 01/27] revision: factor out parsing of diff-merge related options
  2020-12-03 15:16       ` Sergey Organov
@ 2020-12-04  6:36         ` Junio C Hamano
  2020-12-04 19:10           ` Sergey Organov
  0 siblings, 1 reply; 232+ messages in thread
From: Junio C Hamano @ 2020-12-04  6:36 UTC (permalink / raw)
  To: Sergey Organov; +Cc: Jeff King, Philip Oakley, git

Sergey Organov <sorganov@gmail.com> writes:

>>> +		if (!strcmp(optarg, "off")) {
>>> +			revs->ignore_merges = 1;
>>> +		} else {
>>> +			die(_("unknown value for --diff-merges: %s"), optarg);
>>> +		}
>>
>> To correct the above bug, it probably is sufficient to add
>>
>> 		return argcount;
>>
>> here.
>
> Right, but not enough. "argcount" should also be set to 1 at the
> beginning of the function, to avoid returning uninitialized value here.

You seem to be a bit confused.

The suggested fix is to ...

+static int parse_diff_merge_opts(struct rev_info *revs, const char **argv) {
+	int argcount;
+	const char *optarg;
+	const char *arg = argv[0];
+
+	if (!strcmp(arg, "-m")) {
+		/*
+		 * To "diff-index", "-m" means "match missing", and to the "log"
+		 * family of commands, it means "show full diff for merges". Set
+		 * both fields appropriately.
+		 */
+		revs->ignore_merges = 0;
+		revs->match_missing = 1;
+	} else if (!strcmp(arg, "-c")) {
+		revs->diff = 1;
+		revs->dense_combined_merges = 0;
+		revs->combine_merges = 1;
+	} else if (!strcmp(arg, "--cc")) {
+		revs->diff = 1;
+		revs->dense_combined_merges = 1;
+		revs->combine_merges = 1;
+	} else if (!strcmp(arg, "--no-diff-merges")) {
+		revs->ignore_merges = 1;
+	} else if (!strcmp(arg, "--combined-all-paths")) {
+		revs->diff = 1;
+		revs->combined_all_paths = 1;
+	} else if ((argcount = parse_long_opt("diff-merges", argv, &optarg))) {
+		if (!strcmp(optarg, "off")) {
+			revs->ignore_merges = 1;
+		} else {
+			die(_("unknown value for --diff-merges: %s"), optarg);
+		}

... add

		return argcount;

here.  We know argcount has a valid value that was returned from
parse_long_opt() at this point.  Nobody else needs to look at the
argcount variable.

+	} else
+		return 0;
+
+	return 1;
+}

Incidentally, that is consistent with the way the original function
handled the "diff-merges" option at ...

 static int handle_revision_opt(struct rev_info *revs, int argc, const char **argv,
 			       int *unkc, const char **unkv,
 			       const struct setup_revision_opt* opt)
 {
 	const char *arg = argv[0];
 	const char *optarg;
 	int argcount;
 	const unsigned hexsz = the_hash_algo->hexsz;
 ...
-		revs->ignore_merges = 0;
-		revs->match_missing = 1;
-	} else if ((argcount = parse_long_opt("diff-merges", argv, &optarg))) {
-		if (!strcmp(optarg, "off")) {
-			revs->ignore_merges = 1;
-		} else {
-			die(_("unknown value for --diff-merges: %s"), optarg);
-		}
+	} else if ((argcount = parse_diff_merge_opts(revs, argv))) {
 		return argcount;

... this point.  We asked parse_long_opt() to supply the return
value for us, and then returned that to our caller.

-	} else if (!strcmp(arg, "--no-diff-merges")) {
-		revs->ignore_merges = 1;

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

* Re: [PATCH 10/26] diff-merges: new function diff_merges_suppress()
  2020-12-03 20:28       ` Elijah Newren
@ 2020-12-04 17:23         ` Sergey Organov
  0 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-12-04 17:23 UTC (permalink / raw)
  To: Elijah Newren; +Cc: Junio C Hamano, Jeff King, Git Mailing List

Hi Elijah,

Elijah Newren <newren@gmail.com> writes:

> Hi Sergey,
>
> On Thu, Dec 3, 2020 at 12:06 PM Sergey Organov <sorganov@gmail.com> wrote:
>>
>> Elijah Newren <newren@gmail.com> writes:
>>
>> > On Sun, Nov 1, 2020 at 11:36 AM Sergey Organov <sorganov@gmail.com> wrote:
>> >>
>> >> This function sets all the relevant flags to disabled state, so that
>> >> no code that checks only one of them get it wrong.
>> >>
>> >> Then we call this new function everywhere where diff merges output
>> >> suppression is needed.
>> >>
>> >> Signed-off-by: Sergey Organov <sorganov@gmail.com>
>> >> ---
>> >>  builtin/merge.c |  3 ++-
>> >>  diff-merges.c   | 18 ++++++++++++++----
>> >>  diff-merges.h   |  2 ++
>> >>  fmt-merge-msg.c |  3 ++-
>> >>  4 files changed, 20 insertions(+), 6 deletions(-)
>> >>
>> >> diff --git a/builtin/merge.c b/builtin/merge.c
>> >> index 9d5359edc2f7..1f7b69982b40 100644
>> >> --- a/builtin/merge.c
>> >> +++ b/builtin/merge.c
>> >> @@ -14,6 +14,7 @@
>> >>  #include "lockfile.h"
>> >>  #include "run-command.h"
>> >>  #include "diff.h"
>> >> +#include "diff-merges.h"
>> >>  #include "refs.h"
>> >>  #include "refspec.h"
>> >>  #include "commit.h"
>> >> @@ -400,7 +401,7 @@ static void squash_message(struct commit *commit, struct commit_list *remotehead
>> >>         printf(_("Squash commit -- not updating HEAD\n"));
>> >>
>> >>         repo_init_revisions(the_repository, &rev, NULL);
>> >> -       rev.ignore_merges = 1;
>> >> +       diff_merges_suppress(&rev);
>> >>         rev.commit_format = CMIT_FMT_MEDIUM;
>> >>
>> >>         commit->object.flags |= UNINTERESTING;
>> >> diff --git a/diff-merges.c b/diff-merges.c
>> >> index 8536941e0b56..25bd9b12e667 100644
>> >> --- a/diff-merges.c
>> >> +++ b/diff-merges.c
>> >> @@ -2,6 +2,13 @@
>> >>
>> >>  #include "revision.h"
>> >>
>> >> +static void suppress(struct rev_info *revs) {
>> >> +       revs->ignore_merges = 1;
>> >> +       revs->first_parent_merges = 0;
>> >> +       revs->combine_merges = 0;
>> >> +       revs->dense_combined_merges = 0;
>> >> +}
>> >
>> > The function name is not so helpful;
>>
>> Do you have better suggestion? suppress_output()? supress_diff()?
>>
>> > why not put all this code directly in diff_merges_suppress()?
>>
>> I prefer the style where module implementation functions don't call its
>> interface functions, only vice versa.
>>
>> >
>> >> +
>> >>  /*
>> >>   * Public functions. They are in the order they are called.
>> >>   */
>> >> @@ -29,16 +36,15 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {
>> >>                 revs->combine_merges = 1;
>> >>         } else if (!strcmp(arg, "--cc")) {
>> >>                 revs->diff = 1;
>> >> -               revs->dense_combined_merges = 1;
>> >> -               revs->combine_merges = 1;
>> >> +               set_dense_combined(revs);
>> >>         } else if (!strcmp(arg, "--no-diff-merges")) {
>> >> -               revs->ignore_merges = 1;
>> >> +               suppress(revs);
>> >>         } else if (!strcmp(arg, "--combined-all-paths")) {
>> >>                 revs->diff = 1;
>> >>                 revs->combined_all_paths = 1;
>> >>         } else if ((argcount = parse_long_opt("diff-merges", argv, &optarg))) {
>> >>                 if (!strcmp(optarg, "off")) {
>> >> -                       revs->ignore_merges = 1;
>> >> +                       suppress(revs);
>> >>                 } else {
>> >>                         die(_("unknown value for --diff-merges: %s"), optarg);
>> >>                 }
>> >> @@ -48,6 +54,10 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {
>> >>         return 1;
>> >>  }
>> >>
>> >> +void diff_merges_suppress(struct rev_info *revs) {
>> >> +       suppress(revs);
>> >> +}
>> >
>> > ...especially since all this function does is call suppress()?
>>
>> Yes, it does, but it doesn't mean it will be that way forever. Interface
>> function might need to perform additional checks or actions, in general.
>
> Ah, I didn't catch the distinction and thus the reasoning in having
> the two different functions.
>
>> Besides, if diff_merges_suppress() is OK with you as interface function
>> name, why suppress() is not OK as local function name in diff-merges
>> module?
>
> Right, the fact that it's in the diff-merges module as opposed to more
> general diff-lib code is probably hint enough.  I was skimming over
> the patches looking for things that jumped out, and although I had
> read that you were adding it to the new module, I forgot that when I
> saw the "suppress()" function name.  Thanks for the reminder, and
> sorry for the noise.

Fine, thanks, and please don't mention it!

-- 
Sergey Organov

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

* Re: [PATCH v1 24/27] doc/git-log: describe new --diff-merges options
  2020-12-03 20:22         ` Elijah Newren
@ 2020-12-04 17:34           ` Sergey Organov
  2020-12-04 18:33             ` Elijah Newren
  0 siblings, 1 reply; 232+ messages in thread
From: Sergey Organov @ 2020-12-04 17:34 UTC (permalink / raw)
  To: Elijah Newren; +Cc: Junio C Hamano, Jeff King, Philip Oakley, Git Mailing List

Elijah Newren <newren@gmail.com> writes:

> On Thu, Dec 3, 2020 at 11:34 AM Sergey Organov <sorganov@gmail.com> wrote:
>>
>> Elijah Newren <newren@gmail.com> writes:

[...]

>> >> ++
>> >> +--diff-merges=(off|none):::
>> >> +--no-diff-merges:::
>> >> +       (default) Disable output of diffs for merge commits. Useful to
>> >> +       override implied value.
>> >> ++
>> >> +--diff-merges=first-parent:::
>> >> +       This option makes merge commits show the full diff with
>> >> +       respect to the first parent only, exactly like  regular
>> >> +       commits.
>> >
>> > Not sure that "exactly like regular commits" is helpful here; I'd
>> > personally rather cut those four words out.  I'm worried it'll be
>> > taken not as an implementation explanation, but as a "this treats
>> > merge commits in the natural way that regular commits are" which users
>> > may mistakenly translate to "it shows what changes the user manually
>> > made as part of the commit" which is not at all the correct mapping.
>>
>> Dunno. Don't have strict preference here. Git has no idea how the
>> changes in a commit have been made in the first place. Changes are just
>> changes.
>
> If you don't have a preference, can we drop those four words?  ;-)

Yeah, sure, dropped.

>
>> To my excuse, I took this from git:5fbb4bc191 that has:
>>
>> +Note that unless one of `-c`, `--cc`, or `-m` is given, merge commits
>> +will never show a diff, even if a diff format like `--patch` is
>> +selected, nor will they match search options like `-S`. The exception is
>> +when `--first-parent` is in use, in which merges are treated like normal
>> +single-parent commits (this can be overridden by providing a
>> +combined-diff option or with `--no-diff-merges`).
>
> Yeah, I can see where you're coming from, though the context change
> feels like just enough different that the four words you added bother
> me a bit more.  However, this existing wording does bother me now that
> you highlight it.  Even though it's not something introduced by your
> patch, I'd really like to drop "normal" here; I think it is prone to
> cause confusion to users and as far as I can tell provides no useful
> meaning for the sentence.  (There are multiple types of single-parent
> commits?  What is an "unnormal" one?  How do I tell which kind I want?
>  etc...).

I see your point, but I won't change it in these series. I think that
it'd be better if you change this yourself, independently.

Thanks,
-- 
Sergey Organov

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

* Re: [PATCH v1 24/27] doc/git-log: describe new --diff-merges options
  2020-12-04 17:34           ` Sergey Organov
@ 2020-12-04 18:33             ` Elijah Newren
  2020-12-04 19:58               ` Sergey Organov
  0 siblings, 1 reply; 232+ messages in thread
From: Elijah Newren @ 2020-12-04 18:33 UTC (permalink / raw)
  To: Sergey Organov; +Cc: Junio C Hamano, Jeff King, Philip Oakley, Git Mailing List

On Fri, Dec 4, 2020 at 9:34 AM Sergey Organov <sorganov@gmail.com> wrote:
>
> Elijah Newren <newren@gmail.com> writes:
>
> > On Thu, Dec 3, 2020 at 11:34 AM Sergey Organov <sorganov@gmail.com> wrote:
> >>
> >> Elijah Newren <newren@gmail.com> writes:
>
> [...]
>
> >> >> ++
> >> >> +--diff-merges=(off|none):::
> >> >> +--no-diff-merges:::
> >> >> +       (default) Disable output of diffs for merge commits. Useful to
> >> >> +       override implied value.
> >> >> ++
> >> >> +--diff-merges=first-parent:::
> >> >> +       This option makes merge commits show the full diff with
> >> >> +       respect to the first parent only, exactly like  regular
> >> >> +       commits.
> >> >
> >> > Not sure that "exactly like regular commits" is helpful here; I'd
> >> > personally rather cut those four words out.  I'm worried it'll be
> >> > taken not as an implementation explanation, but as a "this treats
> >> > merge commits in the natural way that regular commits are" which users
> >> > may mistakenly translate to "it shows what changes the user manually
> >> > made as part of the commit" which is not at all the correct mapping.
> >>
> >> Dunno. Don't have strict preference here. Git has no idea how the
> >> changes in a commit have been made in the first place. Changes are just
> >> changes.
> >
> > If you don't have a preference, can we drop those four words?  ;-)
>
> Yeah, sure, dropped.
>
> >
> >> To my excuse, I took this from git:5fbb4bc191 that has:
> >>
> >> +Note that unless one of `-c`, `--cc`, or `-m` is given, merge commits
> >> +will never show a diff, even if a diff format like `--patch` is
> >> +selected, nor will they match search options like `-S`. The exception is
> >> +when `--first-parent` is in use, in which merges are treated like normal
> >> +single-parent commits (this can be overridden by providing a
> >> +combined-diff option or with `--no-diff-merges`).
> >
> > Yeah, I can see where you're coming from, though the context change
> > feels like just enough different that the four words you added bother
> > me a bit more.  However, this existing wording does bother me now that
> > you highlight it.  Even though it's not something introduced by your
> > patch, I'd really like to drop "normal" here; I think it is prone to
> > cause confusion to users and as far as I can tell provides no useful
> > meaning for the sentence.  (There are multiple types of single-parent
> > commits?  What is an "unnormal" one?  How do I tell which kind I want?
> >  etc...).
>
> I see your point, but I won't change it in these series. I think that
> it'd be better if you change this yourself, independently.

Sounds good; I'll submit it after your series merges to avoid any conflicts.

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

* Re: [PATCH v1 01/27] revision: factor out parsing of diff-merge related options
  2020-12-04  6:36         ` Junio C Hamano
@ 2020-12-04 19:10           ` Sergey Organov
  0 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-12-04 19:10 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, Philip Oakley, git

Junio C Hamano <gitster@pobox.com> writes:

> Sergey Organov <sorganov@gmail.com> writes:
>
>>>> +		if (!strcmp(optarg, "off")) {
>>>> +			revs->ignore_merges = 1;
>>>> +		} else {
>>>> +			die(_("unknown value for --diff-merges: %s"), optarg);
>>>> +		}
>>>
>>> To correct the above bug, it probably is sufficient to add
>>>
>>> 		return argcount;
>>>
>>> here.
>>
>> Right, but not enough. "argcount" should also be set to 1 at the
>> beginning of the function, to avoid returning uninitialized value here.
>
> You seem to be a bit confused.
>
> The suggested fix is to ...
>
> +static int parse_diff_merge_opts(struct rev_info *revs, const char **argv) {
> +	int argcount;
> +	const char *optarg;
> +	const char *arg = argv[0];
> +
> +	if (!strcmp(arg, "-m")) {
> +		/*
> +		 * To "diff-index", "-m" means "match missing", and to the "log"
> +		 * family of commands, it means "show full diff for merges". Set
> +		 * both fields appropriately.
> +		 */
> +		revs->ignore_merges = 0;
> +		revs->match_missing = 1;
> +	} else if (!strcmp(arg, "-c")) {
> +		revs->diff = 1;
> +		revs->dense_combined_merges = 0;
> +		revs->combine_merges = 1;
> +	} else if (!strcmp(arg, "--cc")) {
> +		revs->diff = 1;
> +		revs->dense_combined_merges = 1;
> +		revs->combine_merges = 1;
> +	} else if (!strcmp(arg, "--no-diff-merges")) {
> +		revs->ignore_merges = 1;
> +	} else if (!strcmp(arg, "--combined-all-paths")) {
> +		revs->diff = 1;
> +		revs->combined_all_paths = 1;
> +	} else if ((argcount = parse_long_opt("diff-merges", argv, &optarg))) {
> +		if (!strcmp(optarg, "off")) {
> +			revs->ignore_merges = 1;
> +		} else {
> +			die(_("unknown value for --diff-merges: %s"), optarg);
> +		}
>
> ... add
>
> 		return argcount;
>
> here.  We know argcount has a valid value that was returned from
> parse_long_opt() at this point.  

[...]

OK, thanks, I now see what you meant, yet I now implemented it slightly
differently, as I finally need one point of return from the function
with non-zero value.

The end result is hopefully the same though.

Thanks,
-- Sergey Organov

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

* Re: [PATCH v1 00/27] git-log: implement new --diff-merge options
  2020-12-03 20:39       ` Elijah Newren
@ 2020-12-04 19:23         ` Sergey Organov
  2020-12-05 17:49           ` Elijah Newren
  0 siblings, 1 reply; 232+ messages in thread
From: Sergey Organov @ 2020-12-04 19:23 UTC (permalink / raw)
  To: Elijah Newren; +Cc: Junio C Hamano, Jeff King, Philip Oakley, Git Mailing List

Elijah Newren <newren@gmail.com> writes:

> On Thu, Dec 3, 2020 at 11:48 AM Sergey Organov <sorganov@gmail.com> wrote:
>>
>> Elijah Newren <newren@gmail.com> writes:
>>
>> > On Sun, Nov 8, 2020 at 1:43 PM Sergey Organov <sorganov@gmail.com> wrote:
>> >>
>> >> These patch series implement new set of options governing the diff output
>> >> of merge commits, all under the umbrella of the single
>> >> --diff-merges=<mode>
>> >> option. Most of the new options being synonyms for -m/-c/--cc options,
>> >> there is also additional functionality provided, allowing to get
>> >> the format
>> >> of "-p --first-parent" without change in history traversal that
>> >> --first-parent option causes.
>> >>
>> >> The net result of these series are the following new options:
>> >>
>> >> --diff-merges=   |  old equivalent
>> >> -----------------+----------------
>> >> first-parent     | --first-parent (only format implications)
>> >> separate         | -m
>> >> combined         | -c
>> >> dense-combined   | --cc
>> >
>> > Interesting.  I have some local patches implementing another choice,
>> > with the new flag --remerge-diff.  This flag will cause `git show` or
>> > `git log` to automatically remerge the two parents in a 2-parent merge
>> > commit, and then diff the merge commit against that automatic merge,
>> > showing the result.  Thus, the diff for a merge commit is likely to be
>> > empty if the merge was clean, and is likely to show the removal of
>> > conflict markers if the merge was not clean.
>> >
>> > I'm curious how it'd interact with this new option.  Would it also get
>> > a name, e.g. --diff-merges=remerge-diff?  Feels like a mouthful, but I
>> > can't come up with anything better.
>>
>> Maybe, --diff-merges=remerge?
>>
>> >
>> > Also, I'm curious how it'd interact with another option I added, named
>> > --remerge-diff-only.  This latter option modifies revision traversal
>> > in that it skips octopus merges, root commits, and single parent
>> > commits IF no cherry-pick or revert information can be found.  If it
>> > finds a 2-parent merge commit, it behaves like --remerge-diff.  If it
>> > finds a 1-parent commit with cherry-pick or revert information, it'll
>> > do an in memory repeat of that cherry-pick (or revert) and then diff
>> > the actual commit against what the automatic cherry-pick would
>> > perform.  Again, that likely means an empty diff if the automatic
>> > cherry-pick was clean, and showing any changes made by the user to
>> > complete the original cherry-pick (such as deleting conflict markers
>> > and picking which chunks from which side to keep) if the automatic
>> > cherry-pick was not clean.  (I suspect --remerge-diff-only is much
>> > more likely to be used with `git show` than with `git log`.)  Anyway,
>> > your changes seem to suggest that anything relating to how diffs for
>> > merges are handled should be documented in the same section, but
>> > --remerge-diff-only doesn't fit.  And it'd seem odd to have
>> > --remerge-diff and --remerge-diff-only not show up in adjacently but
>> > be split into separate sections.  Any ideas?
>>
>> Sounds like commits limiting option to me. I think it could be named by
>> its limiting behavior only, say, --remerges. Then it will imply
>> --diff-merges=remerge, that'd allow user to re-define diff format if she
>> needs to.
>
> It is commit limiting, but the focus is more on the behavioral change
> in how diffs are shown:
>   * for 2-parent merges
>   * for single-parent commits with cherry-pick or revert information
> and acknowledging that since it has _altered_ the normal way of
> showing diffs for a number of single-parent commits, that it'd be
> confusing to show normal diffs of unaffected commits (how would you be
> able to tell what type of diff you're looking at if both appear in the
> log?).  Thus, it does commit limiting to only select commits which
> will make use of the new diff type.

That's how you currently look at it.

For me it looks like pure commit limiting with these criteria might be
useful by itself, and with my suggestion one could then achieve it
using, say:

--remerge-diff-only --diff-merges=off

>
> (I suspect it will be more common for folks to use the
> --remerge-diff-only option, or whatever we end up calling it, with
> `git show` where the commit limiting doesn't matter -- but I have used
> it with log to go looking for "evil" reverts/cherry-picks that might
> have occurred in history.)

What you describe is complex enough to doubt it could be entirely
described by option name, so shorter --evils might be better choice
in this case.

Overall, if you add --diff-merges=remerge as a new diff format, and then
--evils that implies the former, then it seems like all possible
use-cases will be covered, and you have short option name for the most
useful case.

-- Sergey Organov

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

* Re: [PATCH v1 24/27] doc/git-log: describe new --diff-merges options
  2020-12-04 18:33             ` Elijah Newren
@ 2020-12-04 19:58               ` Sergey Organov
  2020-12-04 20:01                 ` Elijah Newren
  0 siblings, 1 reply; 232+ messages in thread
From: Sergey Organov @ 2020-12-04 19:58 UTC (permalink / raw)
  To: Elijah Newren; +Cc: Junio C Hamano, Jeff King, Philip Oakley, Git Mailing List

Elijah Newren <newren@gmail.com> writes:

> On Fri, Dec 4, 2020 at 9:34 AM Sergey Organov <sorganov@gmail.com> wrote:

[...]

>> >> To my excuse, I took this from git:5fbb4bc191 that has:
>> >>
>> >> +Note that unless one of `-c`, `--cc`, or `-m` is given, merge commits
>> >> +will never show a diff, even if a diff format like `--patch` is
>> >> +selected, nor will they match search options like `-S`. The exception is
>> >> +when `--first-parent` is in use, in which merges are treated like normal
>> >> +single-parent commits (this can be overridden by providing a
>> >> +combined-diff option or with `--no-diff-merges`).
>> >
>> > Yeah, I can see where you're coming from, though the context change
>> > feels like just enough different that the four words you added bother
>> > me a bit more.  However, this existing wording does bother me now that
>> > you highlight it.  Even though it's not something introduced by your
>> > patch, I'd really like to drop "normal" here; I think it is prone to
>> > cause confusion to users and as far as I can tell provides no useful
>> > meaning for the sentence.  (There are multiple types of single-parent
>> > commits?  What is an "unnormal" one?  How do I tell which kind I want?
>> >  etc...).
>>
>> I see your point, but I won't change it in these series. I think that
>> it'd be better if you change this yourself, independently.
>
> Sounds good; I'll submit it after your series merges to avoid any conflicts.

Ooops! I actually did change this in the series, and now it reads:

       Note that unless one of --diff-merges variants (including short
       -m, -c, and --cc options) is explicitly given, merge commits will
       not show a diff, even if a diff format like --patch is selected,
       nor will they match search options like -S. The exception is when
       --first-parent is in use, in which case
       --diff-merges=first-parent is implied.

that hopefully is OK with you.

-- Sergey Organov

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

* Re: [PATCH v1 24/27] doc/git-log: describe new --diff-merges options
  2020-12-04 19:58               ` Sergey Organov
@ 2020-12-04 20:01                 ` Elijah Newren
  0 siblings, 0 replies; 232+ messages in thread
From: Elijah Newren @ 2020-12-04 20:01 UTC (permalink / raw)
  To: Sergey Organov; +Cc: Junio C Hamano, Jeff King, Philip Oakley, Git Mailing List

On Fri, Dec 4, 2020 at 11:58 AM Sergey Organov <sorganov@gmail.com> wrote:
>
> Elijah Newren <newren@gmail.com> writes:
>
> > On Fri, Dec 4, 2020 at 9:34 AM Sergey Organov <sorganov@gmail.com> wrote:
>
> [...]
>
> >> >> To my excuse, I took this from git:5fbb4bc191 that has:
> >> >>
> >> >> +Note that unless one of `-c`, `--cc`, or `-m` is given, merge commits
> >> >> +will never show a diff, even if a diff format like `--patch` is
> >> >> +selected, nor will they match search options like `-S`. The exception is
> >> >> +when `--first-parent` is in use, in which merges are treated like normal
> >> >> +single-parent commits (this can be overridden by providing a
> >> >> +combined-diff option or with `--no-diff-merges`).
> >> >
> >> > Yeah, I can see where you're coming from, though the context change
> >> > feels like just enough different that the four words you added bother
> >> > me a bit more.  However, this existing wording does bother me now that
> >> > you highlight it.  Even though it's not something introduced by your
> >> > patch, I'd really like to drop "normal" here; I think it is prone to
> >> > cause confusion to users and as far as I can tell provides no useful
> >> > meaning for the sentence.  (There are multiple types of single-parent
> >> > commits?  What is an "unnormal" one?  How do I tell which kind I want?
> >> >  etc...).
> >>
> >> I see your point, but I won't change it in these series. I think that
> >> it'd be better if you change this yourself, independently.
> >
> > Sounds good; I'll submit it after your series merges to avoid any conflicts.
>
> Ooops! I actually did change this in the series, and now it reads:
>
>        Note that unless one of --diff-merges variants (including short
>        -m, -c, and --cc options) is explicitly given, merge commits will
>        not show a diff, even if a diff format like --patch is selected,
>        nor will they match search options like -S. The exception is when
>        --first-parent is in use, in which case
>        --diff-merges=first-parent is implied.
>
> that hopefully is OK with you.

Ah, together with the dropping of those four extra words on the
description of --diff-merges=first-parent, this seems great.  Thanks!
:-)

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

* Re: [PATCH v1 00/27] git-log: implement new --diff-merge options
  2020-12-04 19:23         ` Sergey Organov
@ 2020-12-05 17:49           ` Elijah Newren
  2020-12-05 19:44             ` Sergey Organov
  0 siblings, 1 reply; 232+ messages in thread
From: Elijah Newren @ 2020-12-05 17:49 UTC (permalink / raw)
  To: Sergey Organov; +Cc: Junio C Hamano, Jeff King, Philip Oakley, Git Mailing List

On Fri, Dec 4, 2020 at 11:23 AM Sergey Organov <sorganov@gmail.com> wrote:
>
> Elijah Newren <newren@gmail.com> writes:
>
> > On Thu, Dec 3, 2020 at 11:48 AM Sergey Organov <sorganov@gmail.com> wrote:
> >>
> >> Elijah Newren <newren@gmail.com> writes:
> >>
> >> > On Sun, Nov 8, 2020 at 1:43 PM Sergey Organov <sorganov@gmail.com> wrote:
> >> >>
> >> >> These patch series implement new set of options governing the diff output
> >> >> of merge commits, all under the umbrella of the single
> >> >> --diff-merges=<mode>
> >> >> option. Most of the new options being synonyms for -m/-c/--cc options,
> >> >> there is also additional functionality provided, allowing to get
> >> >> the format
> >> >> of "-p --first-parent" without change in history traversal that
> >> >> --first-parent option causes.
> >> >>
> >> >> The net result of these series are the following new options:
> >> >>
> >> >> --diff-merges=   |  old equivalent
> >> >> -----------------+----------------
> >> >> first-parent     | --first-parent (only format implications)
> >> >> separate         | -m
> >> >> combined         | -c
> >> >> dense-combined   | --cc
> >> >
> >> > Interesting.  I have some local patches implementing another choice,
> >> > with the new flag --remerge-diff.  This flag will cause `git show` or
> >> > `git log` to automatically remerge the two parents in a 2-parent merge
> >> > commit, and then diff the merge commit against that automatic merge,
> >> > showing the result.  Thus, the diff for a merge commit is likely to be
> >> > empty if the merge was clean, and is likely to show the removal of
> >> > conflict markers if the merge was not clean.
> >> >
> >> > I'm curious how it'd interact with this new option.  Would it also get
> >> > a name, e.g. --diff-merges=remerge-diff?  Feels like a mouthful, but I
> >> > can't come up with anything better.
> >>
> >> Maybe, --diff-merges=remerge?
> >>
> >> >
> >> > Also, I'm curious how it'd interact with another option I added, named
> >> > --remerge-diff-only.  This latter option modifies revision traversal
> >> > in that it skips octopus merges, root commits, and single parent
> >> > commits IF no cherry-pick or revert information can be found.  If it
> >> > finds a 2-parent merge commit, it behaves like --remerge-diff.  If it
> >> > finds a 1-parent commit with cherry-pick or revert information, it'll
> >> > do an in memory repeat of that cherry-pick (or revert) and then diff
> >> > the actual commit against what the automatic cherry-pick would
> >> > perform.  Again, that likely means an empty diff if the automatic
> >> > cherry-pick was clean, and showing any changes made by the user to
> >> > complete the original cherry-pick (such as deleting conflict markers
> >> > and picking which chunks from which side to keep) if the automatic
> >> > cherry-pick was not clean.  (I suspect --remerge-diff-only is much
> >> > more likely to be used with `git show` than with `git log`.)  Anyway,
> >> > your changes seem to suggest that anything relating to how diffs for
> >> > merges are handled should be documented in the same section, but
> >> > --remerge-diff-only doesn't fit.  And it'd seem odd to have
> >> > --remerge-diff and --remerge-diff-only not show up in adjacently but
> >> > be split into separate sections.  Any ideas?
> >>
> >> Sounds like commits limiting option to me. I think it could be named by
> >> its limiting behavior only, say, --remerges. Then it will imply
> >> --diff-merges=remerge, that'd allow user to re-define diff format if she
> >> needs to.
> >
> > It is commit limiting, but the focus is more on the behavioral change
> > in how diffs are shown:
> >   * for 2-parent merges
> >   * for single-parent commits with cherry-pick or revert information
> > and acknowledging that since it has _altered_ the normal way of
> > showing diffs for a number of single-parent commits, that it'd be
> > confusing to show normal diffs of unaffected commits (how would you be
> > able to tell what type of diff you're looking at if both appear in the
> > log?).  Thus, it does commit limiting to only select commits which
> > will make use of the new diff type.
>
> That's how you currently look at it.
>
> For me it looks like pure commit limiting with these criteria might be
> useful by itself, and with my suggestion one could then achieve it
> using, say:
>
> --remerge-diff-only --diff-merges=off

I see what you're saying, and I think there's some value in it.  But I
think there's something still missing.  For example, you suggest
getting the commit limiting I mention with

    --remerge-diff-only --diff-merges=off

But --diff-merges is only supposed to control _merge_ commits, which I
flagged as the big impedance mismatch for my new option.  Why would it
turn off diffs for non-merge commits like cherry-picks and rebases?

> >
> > (I suspect it will be more common for folks to use the
> > --remerge-diff-only option, or whatever we end up calling it, with
> > `git show` where the commit limiting doesn't matter -- but I have used
> > it with log to go looking for "evil" reverts/cherry-picks that might
> > have occurred in history.)
>
> What you describe is complex enough to doubt it could be entirely
> described by option name, so shorter --evils might be better choice
> in this case.
>
> Overall, if you add --diff-merges=remerge as a new diff format, and then
> --evils that implies the former, then it seems like all possible
> use-cases will be covered, and you have short option name for the most
> useful case.

Since you want things to have orthogonal subcomponents that can be
built up, let's assume we did make --remerge-diff-only be solely about
commit limiting.  In that case, --evils could be gotten by specifying
a combination of flags, and --evils would just be a shorthand.  What
are the flags that you would need to specify, though?  In particular,
you've only named two options above and they don't cover the necessary
behavior; a third is needed:

   --remerge-diff-only --diff-merges=remerge
--${DIFF_OPTION_NAME_FOR_CHERRY_PICKS_AND_REVERTS}=remerge

The first two aren't enough because --diff_merges only changes how
diffs for _merge_ commits are shown, and we need a flag for changing
how the single-parent cherry-pick and reverts are shown.

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

* Re: [PATCH v1 00/27] git-log: implement new --diff-merge options
  2020-12-05 17:49           ` Elijah Newren
@ 2020-12-05 19:44             ` Sergey Organov
  2020-12-05 20:09               ` Elijah Newren
  0 siblings, 1 reply; 232+ messages in thread
From: Sergey Organov @ 2020-12-05 19:44 UTC (permalink / raw)
  To: Elijah Newren; +Cc: Junio C Hamano, Jeff King, Philip Oakley, Git Mailing List

Elijah Newren <newren@gmail.com> writes:

> On Fri, Dec 4, 2020 at 11:23 AM Sergey Organov <sorganov@gmail.com> wrote:
>>
>> Elijah Newren <newren@gmail.com> writes:
>>
>> > On Thu, Dec 3, 2020 at 11:48 AM Sergey Organov <sorganov@gmail.com> wrote:
>> >>
>> >> Elijah Newren <newren@gmail.com> writes:
>> >>
>> >> > On Sun, Nov 8, 2020 at 1:43 PM Sergey Organov
>> >> > <sorganov@gmail.com> wrote:
>> >> >>
>> >> >> These patch series implement new set of options governing the
>> >> >> diff output
>> >> >> of merge commits, all under the umbrella of the single
>> >> >> --diff-merges=<mode>
>> >> >> option. Most of the new options being synonyms for -m/-c/--cc options,
>> >> >> there is also additional functionality provided, allowing to get
>> >> >> the format
>> >> >> of "-p --first-parent" without change in history traversal that
>> >> >> --first-parent option causes.
>> >> >>
>> >> >> The net result of these series are the following new options:
>> >> >>
>> >> >> --diff-merges=   |  old equivalent
>> >> >> -----------------+----------------
>> >> >> first-parent     | --first-parent (only format implications)
>> >> >> separate         | -m
>> >> >> combined         | -c
>> >> >> dense-combined   | --cc
>> >> >
>> >> > Interesting.  I have some local patches implementing another choice,
>> >> > with the new flag --remerge-diff.  This flag will cause `git show` or
>> >> > `git log` to automatically remerge the two parents in a 2-parent merge
>> >> > commit, and then diff the merge commit against that automatic merge,
>> >> > showing the result.  Thus, the diff for a merge commit is likely to be
>> >> > empty if the merge was clean, and is likely to show the removal of
>> >> > conflict markers if the merge was not clean.
>> >> >
>> >> > I'm curious how it'd interact with this new option.  Would it also get
>> >> > a name, e.g. --diff-merges=remerge-diff?  Feels like a mouthful, but I
>> >> > can't come up with anything better.
>> >>
>> >> Maybe, --diff-merges=remerge?
>> >>
>> >> >
>> >> > Also, I'm curious how it'd interact with another option I added, named
>> >> > --remerge-diff-only.  This latter option modifies revision traversal
>> >> > in that it skips octopus merges, root commits, and single parent
>> >> > commits IF no cherry-pick or revert information can be found.  If it
>> >> > finds a 2-parent merge commit, it behaves like --remerge-diff.  If it
>> >> > finds a 1-parent commit with cherry-pick or revert information, it'll
>> >> > do an in memory repeat of that cherry-pick (or revert) and then diff
>> >> > the actual commit against what the automatic cherry-pick would
>> >> > perform.  Again, that likely means an empty diff if the automatic
>> >> > cherry-pick was clean, and showing any changes made by the user to
>> >> > complete the original cherry-pick (such as deleting conflict markers
>> >> > and picking which chunks from which side to keep) if the automatic
>> >> > cherry-pick was not clean.  (I suspect --remerge-diff-only is much
>> >> > more likely to be used with `git show` than with `git log`.)  Anyway,
>> >> > your changes seem to suggest that anything relating to how diffs for
>> >> > merges are handled should be documented in the same section, but
>> >> > --remerge-diff-only doesn't fit.  And it'd seem odd to have
>> >> > --remerge-diff and --remerge-diff-only not show up in adjacently but
>> >> > be split into separate sections.  Any ideas?
>> >>
>> >> Sounds like commits limiting option to me. I think it could be named by
>> >> its limiting behavior only, say, --remerges. Then it will imply
>> >> --diff-merges=remerge, that'd allow user to re-define diff format if she
>> >> needs to.
>> >
>> > It is commit limiting, but the focus is more on the behavioral change
>> > in how diffs are shown:
>> >   * for 2-parent merges
>> >   * for single-parent commits with cherry-pick or revert information
>> > and acknowledging that since it has _altered_ the normal way of
>> > showing diffs for a number of single-parent commits, that it'd be
>> > confusing to show normal diffs of unaffected commits (how would you be
>> > able to tell what type of diff you're looking at if both appear in the
>> > log?).  Thus, it does commit limiting to only select commits which
>> > will make use of the new diff type.
>>
>> That's how you currently look at it.
>>
>> For me it looks like pure commit limiting with these criteria might be
>> useful by itself, and with my suggestion one could then achieve it
>> using, say:
>>
>> --remerge-diff-only --diff-merges=off
>
> I see what you're saying, and I think there's some value in it.  But I
> think there's something still missing.  For example, you suggest
> getting the commit limiting I mention with
>
>     --remerge-diff-only --diff-merges=off
>
> But --diff-merges is only supposed to control _merge_ commits, which I
> flagged as the big impedance mismatch for my new option.  Why would it
> turn off diffs for non-merge commits like cherry-picks and rebases?
>
>> >
>> > (I suspect it will be more common for folks to use the
>> > --remerge-diff-only option, or whatever we end up calling it, with
>> > `git show` where the commit limiting doesn't matter -- but I have used
>> > it with log to go looking for "evil" reverts/cherry-picks that might
>> > have occurred in history.)
>>
>> What you describe is complex enough to doubt it could be entirely
>> described by option name, so shorter --evils might be better choice
>> in this case.
>>
>> Overall, if you add --diff-merges=remerge as a new diff format, and then
>> --evils that implies the former, then it seems like all possible
>> use-cases will be covered, and you have short option name for the most
>> useful case.
>
> Since you want things to have orthogonal subcomponents that can be
> built up, let's assume we did make --remerge-diff-only be solely about
> commit limiting.  In that case, --evils could be gotten by specifying
> a combination of flags, and --evils would just be a shorthand.  What
> are the flags that you would need to specify, though?  In particular,
> you've only named two options above and they don't cover the necessary
> behavior; a third is needed:
>
>    --remerge-diff-only --diff-merges=remerge
> --${DIFF_OPTION_NAME_FOR_CHERRY_PICKS_AND_REVERTS}=remerge
>
> The first two aren't enough because --diff_merges only changes how
> diffs for _merge_ commits are shown, and we need a flag for changing
> how the single-parent cherry-pick and reverts are shown.

Yeah, I see your point. I didn't get it from the beginning that you want
yet another representation format for regular commits as well. However,
as far as I can tell, if --evils flag is active, you do consider
cherry-picks and reverts as kind of merges, that makes sense as they
actually /are/ expected to be results of specific /merge operation/,
even though they are not /merge commits/, so semantically they do have
second parent reference (to the original commit), even if a virtual one.

To further illustrate my point, reverts and cherry-picks could have been
implemented, for example, as merge commits with, say, 3-rd parent
pointing back to the original commit (not 2-nd parent, both to
differentiate from regular merges and to support cherry-picking of merge
commits.)

As a side-note, people rarely differentiate between
"merge-the-operation" and "merge-the-result" anyway, even when it leads
to confusion.

Overall, if we take the above into account, it seems to be fine if
--diff-merges does affect the representation or such "quasi-merge"
commits, for the purposes of --evils option.

-- Sergey Organov

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

* Re: [PATCH v1 00/27] git-log: implement new --diff-merge options
  2020-12-05 19:44             ` Sergey Organov
@ 2020-12-05 20:09               ` Elijah Newren
  2020-12-06 16:39                 ` Sergey Organov
  0 siblings, 1 reply; 232+ messages in thread
From: Elijah Newren @ 2020-12-05 20:09 UTC (permalink / raw)
  To: Sergey Organov; +Cc: Junio C Hamano, Jeff King, Philip Oakley, Git Mailing List

On Sat, Dec 5, 2020 at 11:44 AM Sergey Organov <sorganov@gmail.com> wrote:
>
> Elijah Newren <newren@gmail.com> writes:
>
> > On Fri, Dec 4, 2020 at 11:23 AM Sergey Organov <sorganov@gmail.com> wrote:
> >>
> >> Elijah Newren <newren@gmail.com> writes:
> >>
> >> > On Thu, Dec 3, 2020 at 11:48 AM Sergey Organov <sorganov@gmail.com> wrote:
> >> >>
> >> >> Elijah Newren <newren@gmail.com> writes:
> >> >>
> >> >> > On Sun, Nov 8, 2020 at 1:43 PM Sergey Organov
> >> >> > <sorganov@gmail.com> wrote:
> >> >> >>
> >> >> >> These patch series implement new set of options governing the
> >> >> >> diff output
> >> >> >> of merge commits, all under the umbrella of the single
> >> >> >> --diff-merges=<mode>
> >> >> >> option. Most of the new options being synonyms for -m/-c/--cc options,
> >> >> >> there is also additional functionality provided, allowing to get
> >> >> >> the format
> >> >> >> of "-p --first-parent" without change in history traversal that
> >> >> >> --first-parent option causes.
> >> >> >>
> >> >> >> The net result of these series are the following new options:
> >> >> >>
> >> >> >> --diff-merges=   |  old equivalent
> >> >> >> -----------------+----------------
> >> >> >> first-parent     | --first-parent (only format implications)
> >> >> >> separate         | -m
> >> >> >> combined         | -c
> >> >> >> dense-combined   | --cc
> >> >> >
> >> >> > Interesting.  I have some local patches implementing another choice,
> >> >> > with the new flag --remerge-diff.  This flag will cause `git show` or
> >> >> > `git log` to automatically remerge the two parents in a 2-parent merge
> >> >> > commit, and then diff the merge commit against that automatic merge,
> >> >> > showing the result.  Thus, the diff for a merge commit is likely to be
> >> >> > empty if the merge was clean, and is likely to show the removal of
> >> >> > conflict markers if the merge was not clean.
> >> >> >
> >> >> > I'm curious how it'd interact with this new option.  Would it also get
> >> >> > a name, e.g. --diff-merges=remerge-diff?  Feels like a mouthful, but I
> >> >> > can't come up with anything better.
> >> >>
> >> >> Maybe, --diff-merges=remerge?
> >> >>
> >> >> >
> >> >> > Also, I'm curious how it'd interact with another option I added, named
> >> >> > --remerge-diff-only.  This latter option modifies revision traversal
> >> >> > in that it skips octopus merges, root commits, and single parent
> >> >> > commits IF no cherry-pick or revert information can be found.  If it
> >> >> > finds a 2-parent merge commit, it behaves like --remerge-diff.  If it
> >> >> > finds a 1-parent commit with cherry-pick or revert information, it'll
> >> >> > do an in memory repeat of that cherry-pick (or revert) and then diff
> >> >> > the actual commit against what the automatic cherry-pick would
> >> >> > perform.  Again, that likely means an empty diff if the automatic
> >> >> > cherry-pick was clean, and showing any changes made by the user to
> >> >> > complete the original cherry-pick (such as deleting conflict markers
> >> >> > and picking which chunks from which side to keep) if the automatic
> >> >> > cherry-pick was not clean.  (I suspect --remerge-diff-only is much
> >> >> > more likely to be used with `git show` than with `git log`.)  Anyway,
> >> >> > your changes seem to suggest that anything relating to how diffs for
> >> >> > merges are handled should be documented in the same section, but
> >> >> > --remerge-diff-only doesn't fit.  And it'd seem odd to have
> >> >> > --remerge-diff and --remerge-diff-only not show up in adjacently but
> >> >> > be split into separate sections.  Any ideas?
> >> >>
> >> >> Sounds like commits limiting option to me. I think it could be named by
> >> >> its limiting behavior only, say, --remerges. Then it will imply
> >> >> --diff-merges=remerge, that'd allow user to re-define diff format if she
> >> >> needs to.
> >> >
> >> > It is commit limiting, but the focus is more on the behavioral change
> >> > in how diffs are shown:
> >> >   * for 2-parent merges
> >> >   * for single-parent commits with cherry-pick or revert information
> >> > and acknowledging that since it has _altered_ the normal way of
> >> > showing diffs for a number of single-parent commits, that it'd be
> >> > confusing to show normal diffs of unaffected commits (how would you be
> >> > able to tell what type of diff you're looking at if both appear in the
> >> > log?).  Thus, it does commit limiting to only select commits which
> >> > will make use of the new diff type.
> >>
> >> That's how you currently look at it.
> >>
> >> For me it looks like pure commit limiting with these criteria might be
> >> useful by itself, and with my suggestion one could then achieve it
> >> using, say:
> >>
> >> --remerge-diff-only --diff-merges=off
> >
> > I see what you're saying, and I think there's some value in it.  But I
> > think there's something still missing.  For example, you suggest
> > getting the commit limiting I mention with
> >
> >     --remerge-diff-only --diff-merges=off
> >
> > But --diff-merges is only supposed to control _merge_ commits, which I
> > flagged as the big impedance mismatch for my new option.  Why would it
> > turn off diffs for non-merge commits like cherry-picks and rebases?
> >
> >> >
> >> > (I suspect it will be more common for folks to use the
> >> > --remerge-diff-only option, or whatever we end up calling it, with
> >> > `git show` where the commit limiting doesn't matter -- but I have used
> >> > it with log to go looking for "evil" reverts/cherry-picks that might
> >> > have occurred in history.)
> >>
> >> What you describe is complex enough to doubt it could be entirely
> >> described by option name, so shorter --evils might be better choice
> >> in this case.
> >>
> >> Overall, if you add --diff-merges=remerge as a new diff format, and then
> >> --evils that implies the former, then it seems like all possible
> >> use-cases will be covered, and you have short option name for the most
> >> useful case.
> >
> > Since you want things to have orthogonal subcomponents that can be
> > built up, let's assume we did make --remerge-diff-only be solely about
> > commit limiting.  In that case, --evils could be gotten by specifying
> > a combination of flags, and --evils would just be a shorthand.  What
> > are the flags that you would need to specify, though?  In particular,
> > you've only named two options above and they don't cover the necessary
> > behavior; a third is needed:
> >
> >    --remerge-diff-only --diff-merges=remerge
> > --${DIFF_OPTION_NAME_FOR_CHERRY_PICKS_AND_REVERTS}=remerge
> >
> > The first two aren't enough because --diff_merges only changes how
> > diffs for _merge_ commits are shown, and we need a flag for changing
> > how the single-parent cherry-pick and reverts are shown.
>
> Yeah, I see your point. I didn't get it from the beginning that you want
> yet another representation format for regular commits as well. However,
> as far as I can tell, if --evils flag is active, you do consider
> cherry-picks and reverts as kind of merges, that makes sense as they
> actually /are/ expected to be results of specific /merge operation/,
> even though they are not /merge commits/, so semantically they do have
> second parent reference (to the original commit), even if a virtual one.
>
> To further illustrate my point, reverts and cherry-picks could have been
> implemented, for example, as merge commits with, say, 3-rd parent
> pointing back to the original commit (not 2-nd parent, both to
> differentiate from regular merges and to support cherry-picking of merge
> commits.)
>
> As a side-note, people rarely differentiate between
> "merge-the-operation" and "merge-the-result" anyway, even when it leads
> to confusion.
>
> Overall, if we take the above into account, it seems to be fine if
> --diff-merges does affect the representation or such "quasi-merge"
> commits, for the purposes of --evils option.

Yeah, that could make sense.  We'd still need some additional flag.
One flag, perhaps --diff-merges=remerge, would be the one that would
_only_ affect actual two-parent merges (which I use as the default
instead of --cc with `git show`, and which I make implied by default
with `git log --patch` at $DAYJOB), and we'd need another name for
whatever turned those special diffs on for cherry-picks and reverts.
Further, the extra flag that turns on special diffs for cherry-picks
and reverts should turn off diffs entirely for any other single-parent
commits.  (I think it's just too confusing for any command to show
multiple single-parent commits with a mixture of different types of
diffs.)

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

* Re: [PATCH v1 00/27] git-log: implement new --diff-merge options
  2020-12-05 20:09               ` Elijah Newren
@ 2020-12-06 16:39                 ` Sergey Organov
  0 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-12-06 16:39 UTC (permalink / raw)
  To: Elijah Newren; +Cc: Junio C Hamano, Jeff King, Philip Oakley, Git Mailing List

Elijah Newren <newren@gmail.com> writes:

> On Sat, Dec 5, 2020 at 11:44 AM Sergey Organov <sorganov@gmail.com> wrote:
>>
>> Elijah Newren <newren@gmail.com> writes:
>>
>> > On Fri, Dec 4, 2020 at 11:23 AM Sergey Organov <sorganov@gmail.com> wrote:
>> >>
>> >> Elijah Newren <newren@gmail.com> writes:
>> >>
>> >> > On Thu, Dec 3, 2020 at 11:48 AM Sergey Organov
>> >> > <sorganov@gmail.com> wrote:
>> >> >>
>> >> >> Elijah Newren <newren@gmail.com> writes:
>> >> >>
>> >> >> > On Sun, Nov 8, 2020 at 1:43 PM Sergey Organov
>> >> >> > <sorganov@gmail.com> wrote:
>> >> >> >>
>> >> >> >> These patch series implement new set of options governing the
>> >> >> >> diff output
>> >> >> >> of merge commits, all under the umbrella of the single
>> >> >> >> --diff-merges=<mode>
>> >> >> >> option. Most of the new options being synonyms for
>> >> >> >> -m/-c/--cc options,
>> >> >> >> there is also additional functionality provided, allowing to get
>> >> >> >> the format
>> >> >> >> of "-p --first-parent" without change in history traversal that
>> >> >> >> --first-parent option causes.
>> >> >> >>
>> >> >> >> The net result of these series are the following new options:
>> >> >> >>
>> >> >> >> --diff-merges=   |  old equivalent
>> >> >> >> -----------------+----------------
>> >> >> >> first-parent     | --first-parent (only format implications)
>> >> >> >> separate         | -m
>> >> >> >> combined         | -c
>> >> >> >> dense-combined   | --cc
>> >> >> >
>> >> >> > Interesting.  I have some local patches implementing another choice,
>> >> >> > with the new flag --remerge-diff.  This flag will cause `git show` or
>> >> >> > `git log` to automatically remerge the two parents in a
>> >> >> > 2-parent merge
>> >> >> > commit, and then diff the merge commit against that automatic merge,
>> >> >> > showing the result. Thus, the diff for a merge commit is
>> >> >> > likely to be
>> >> >> > empty if the merge was clean, and is likely to show the removal of
>> >> >> > conflict markers if the merge was not clean.
>> >> >> >
>> >> >> > I'm curious how it'd interact with this new option. Would it
>> >> >> > also get
>> >> >> > a name, e.g. --diff-merges=remerge-diff? Feels like a
>> >> >> > mouthful, but I
>> >> >> > can't come up with anything better.
>> >> >>
>> >> >> Maybe, --diff-merges=remerge?
>> >> >>
>> >> >> >
>> >> >> > Also, I'm curious how it'd interact with another option I
>> >> >> > added, named
>> >> >> > --remerge-diff-only.  This latter option modifies revision traversal
>> >> >> > in that it skips octopus merges, root commits, and single parent
>> >> >> > commits IF no cherry-pick or revert information can be found.  If it
>> >> >> > finds a 2-parent merge commit, it behaves like --remerge-diff.  If it
>> >> >> > finds a 1-parent commit with cherry-pick or revert information, it'll
>> >> >> > do an in memory repeat of that cherry-pick (or revert) and then diff
>> >> >> > the actual commit against what the automatic cherry-pick would
>> >> >> > perform.  Again, that likely means an empty diff if the automatic
>> >> >> > cherry-pick was clean, and showing any changes made by the user to
>> >> >> > complete the original cherry-pick (such as deleting conflict markers
>> >> >> > and picking which chunks from which side to keep) if the automatic
>> >> >> > cherry-pick was not clean.  (I suspect --remerge-diff-only is much
>> >> >> > more likely to be used with `git show` than with `git log`.)  Anyway,
>> >> >> > your changes seem to suggest that anything relating to how diffs for
>> >> >> > merges are handled should be documented in the same section, but
>> >> >> > --remerge-diff-only doesn't fit.  And it'd seem odd to have
>> >> >> > --remerge-diff and --remerge-diff-only not show up in adjacently but
>> >> >> > be split into separate sections.  Any ideas?
>> >> >>
>> >> >> Sounds like commits limiting option to me. I think it could be named by
>> >> >> its limiting behavior only, say, --remerges. Then it will imply
>> >> >> --diff-merges=remerge, that'd allow user to re-define diff
>> >> >> format if she
>> >> >> needs to.
>> >> >
>> >> > It is commit limiting, but the focus is more on the behavioral change
>> >> > in how diffs are shown:
>> >> >   * for 2-parent merges
>> >> >   * for single-parent commits with cherry-pick or revert information
>> >> > and acknowledging that since it has _altered_ the normal way of
>> >> > showing diffs for a number of single-parent commits, that it'd be
>> >> > confusing to show normal diffs of unaffected commits (how would you be
>> >> > able to tell what type of diff you're looking at if both appear in the
>> >> > log?).  Thus, it does commit limiting to only select commits which
>> >> > will make use of the new diff type.
>> >>
>> >> That's how you currently look at it.
>> >>
>> >> For me it looks like pure commit limiting with these criteria might be
>> >> useful by itself, and with my suggestion one could then achieve it
>> >> using, say:
>> >>
>> >> --remerge-diff-only --diff-merges=off
>> >
>> > I see what you're saying, and I think there's some value in it.  But I
>> > think there's something still missing.  For example, you suggest
>> > getting the commit limiting I mention with
>> >
>> >     --remerge-diff-only --diff-merges=off
>> >
>> > But --diff-merges is only supposed to control _merge_ commits, which I
>> > flagged as the big impedance mismatch for my new option.  Why would it
>> > turn off diffs for non-merge commits like cherry-picks and rebases?
>> >
>> >> >
>> >> > (I suspect it will be more common for folks to use the
>> >> > --remerge-diff-only option, or whatever we end up calling it, with
>> >> > `git show` where the commit limiting doesn't matter -- but I have used
>> >> > it with log to go looking for "evil" reverts/cherry-picks that might
>> >> > have occurred in history.)
>> >>
>> >> What you describe is complex enough to doubt it could be entirely
>> >> described by option name, so shorter --evils might be better choice
>> >> in this case.
>> >>
>> >> Overall, if you add --diff-merges=remerge as a new diff format, and then
>> >> --evils that implies the former, then it seems like all possible
>> >> use-cases will be covered, and you have short option name for the most
>> >> useful case.
>> >
>> > Since you want things to have orthogonal subcomponents that can be
>> > built up, let's assume we did make --remerge-diff-only be solely about
>> > commit limiting.  In that case, --evils could be gotten by specifying
>> > a combination of flags, and --evils would just be a shorthand.  What
>> > are the flags that you would need to specify, though?  In particular,
>> > you've only named two options above and they don't cover the necessary
>> > behavior; a third is needed:
>> >
>> >    --remerge-diff-only --diff-merges=remerge
>> > --${DIFF_OPTION_NAME_FOR_CHERRY_PICKS_AND_REVERTS}=remerge
>> >
>> > The first two aren't enough because --diff_merges only changes how
>> > diffs for _merge_ commits are shown, and we need a flag for changing
>> > how the single-parent cherry-pick and reverts are shown.
>>
>> Yeah, I see your point. I didn't get it from the beginning that you want
>> yet another representation format for regular commits as well. However,
>> as far as I can tell, if --evils flag is active, you do consider
>> cherry-picks and reverts as kind of merges, that makes sense as they
>> actually /are/ expected to be results of specific /merge operation/,
>> even though they are not /merge commits/, so semantically they do have
>> second parent reference (to the original commit), even if a virtual one.
>>
>> To further illustrate my point, reverts and cherry-picks could have been
>> implemented, for example, as merge commits with, say, 3-rd parent
>> pointing back to the original commit (not 2-nd parent, both to
>> differentiate from regular merges and to support cherry-picking of merge
>> commits.)
>>
>> As a side-note, people rarely differentiate between
>> "merge-the-operation" and "merge-the-result" anyway, even when it leads
>> to confusion.
>>
>> Overall, if we take the above into account, it seems to be fine if
>> --diff-merges does affect the representation or such "quasi-merge"
>> commits, for the purposes of --evils option.
>
> Yeah, that could make sense.  We'd still need some additional flag.
> One flag, perhaps --diff-merges=remerge, would be the one that would
> _only_ affect actual two-parent merges (which I use as the default
> instead of --cc with `git show`, and which I make implied by default
> with `git log --patch` at $DAYJOB), and we'd need another name for
> whatever turned those special diffs on for cherry-picks and reverts.
> Further, the extra flag that turns on special diffs for cherry-picks
> and reverts should turn off diffs entirely for any other single-parent
> commits.  (I think it's just too confusing for any command to show
> multiple single-parent commits with a mixture of different types of
> diffs.)

I think you may safely pretend this special diff always produces empty
diff for regular commits, so there will be no need to "disable"
anything.

-- Sergey Organov



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

* Re: [PATCH 00/26] git-log: implement new --diff-merge options
  2020-11-01 19:33 [PATCH 00/26] git-log: implement new --diff-merge options Sergey Organov
                   ` (26 preceding siblings ...)
  2020-11-08 21:38 ` [PATCH v1 00/27] git-log: implement new --diff-merge options Sergey Organov
@ 2020-12-08 20:07 ` Sergey Organov
  2020-12-08 20:52   ` Elijah Newren
  2020-12-16 18:48 ` [PATCH v2 00/33] " Sergey Organov
  2020-12-21 15:19 ` [PATCH v3 00/32] " Sergey Organov
  29 siblings, 1 reply; 232+ messages in thread
From: Sergey Organov @ 2020-12-08 20:07 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, Philip Oakley, Elijah Newren, git

Sergey Organov <sorganov@gmail.com> writes:


[...]

> The series also cleanup logic of handling of diff merges options and
> fix an issue found in the original implementation where logically
> mutually exclusive options -m/-c/--cc failed to actually override each
> other.

Working further on this, I've noticed very irregular interactions
between -m/-c/--cc and --oneline:

1. --oneline disables -m output for 'git log', and leaves -m output enabled
for 'git show':

$ /usr/bin/git show -n1 -m --oneline 2e673356aef | wc -l
80
$ /usr/bin/git log -n1 -m --oneline 2e673356aef | wc -l
1

2. For 'git log', --oneline disables -m output, and leaves -c/--cc output
enabled:

$ /usr/bin/git log -n1 -m --oneline 2e673356aef | wc -l
1
$ /usr/bin/git log -n1 -c --oneline 2e673356aef | wc -l
16
$ /usr/bin/git log -n1 --cc --oneline 2e673356aef | wc -l
16

The question is: what's the right interaction between --oneline and
-m/-c/--cc?

I tend to think they should be independent, so that --oneline doesn't
affect diff output, and then the only offender is -m.

What do you think?

$ /usr/bin/git --version
git version 2.25.1

Thanks,
-- Sergey Organov

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

* Re: [PATCH 00/26] git-log: implement new --diff-merge options
  2020-12-08 20:07 ` [PATCH 00/26] " Sergey Organov
@ 2020-12-08 20:52   ` Elijah Newren
  2020-12-08 22:30     ` Sergey Organov
  0 siblings, 1 reply; 232+ messages in thread
From: Elijah Newren @ 2020-12-08 20:52 UTC (permalink / raw)
  To: Sergey Organov; +Cc: Junio C Hamano, Jeff King, Philip Oakley, Git Mailing List

Hi Sergey,

On Tue, Dec 8, 2020 at 12:07 PM Sergey Organov <sorganov@gmail.com> wrote:
>
> Sergey Organov <sorganov@gmail.com> writes:
>
>
> [...]
>
> > The series also cleanup logic of handling of diff merges options and
> > fix an issue found in the original implementation where logically
> > mutually exclusive options -m/-c/--cc failed to actually override each
> > other.
>
> Working further on this, I've noticed very irregular interactions
> between -m/-c/--cc and --oneline:
>
> 1. --oneline disables -m output for 'git log', and leaves -m output enabled
> for 'git show':
>
> $ /usr/bin/git show -n1 -m --oneline 2e673356aef | wc -l
> 80
> $ /usr/bin/git log -n1 -m --oneline 2e673356aef | wc -l
> 1

If you leave off --oneline, you'll note that git show produces a diff
and git log does not (regardless of whether 2e673356aef is a merge
commit or a regular commit).  So, I don't think this is related to
--oneline.

> 2. For 'git log', --oneline disables -m output, and leaves -c/--cc output
> enabled:
>
> $ /usr/bin/git log -n1 -m --oneline 2e673356aef | wc -l
> 1
> $ /usr/bin/git log -n1 -c --oneline 2e673356aef | wc -l
> 16
> $ /usr/bin/git log -n1 --cc --oneline 2e673356aef | wc -l
> 16
>
> The question is: what's the right interaction between --oneline and
> -m/-c/--cc?

I believe the right question is: Should -m be a no-op unless -p is
also specified?  In the past, --cc and -c were no-ops except when -p
was also specified.  It was somewhat unfriendly and surprising, and
thus was changed so that --cc and -c implied -p (and thus would cause
output for non-merge commits to be shown differently, namely shown
with a diff, in addition to affecting the type of diff shown for merge
commits).  I think -m was overlooked at the time.

> I tend to think they should be independent, so that --oneline doesn't
> affect diff output, and then the only offender is -m.

I agree that they should be independent, but I believe they are
already independent unless you have more evidence of weirdness
somewhere.  The differences you are seeing are due to -m, -c, and --cc
being handled differently, and I think we should probably just give -m
the same treatment that we give to -c and --cc (namely, make all three
imply -p).

Hope that helps,
Elijah

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

* Re: [PATCH 00/26] git-log: implement new --diff-merge options
  2020-12-08 20:52   ` Elijah Newren
@ 2020-12-08 22:30     ` Sergey Organov
  2020-12-08 23:11       ` Elijah Newren
  0 siblings, 1 reply; 232+ messages in thread
From: Sergey Organov @ 2020-12-08 22:30 UTC (permalink / raw)
  To: Elijah Newren; +Cc: Junio C Hamano, Jeff King, Philip Oakley, Git Mailing List

Elijah Newren <newren@gmail.com> writes:

> Hi Sergey,

Hi Elijah,

>
> On Tue, Dec 8, 2020 at 12:07 PM Sergey Organov <sorganov@gmail.com> wrote:
>>
>> Sergey Organov <sorganov@gmail.com> writes:
>>
>>
>> [...]
>>
>> > The series also cleanup logic of handling of diff merges options and
>> > fix an issue found in the original implementation where logically
>> > mutually exclusive options -m/-c/--cc failed to actually override each
>> > other.
>>
>> Working further on this, I've noticed very irregular interactions
>> between -m/-c/--cc and --oneline:
>>
>> 1. --oneline disables -m output for 'git log', and leaves -m output enabled
>> for 'git show':
>>
>> $ /usr/bin/git show -n1 -m --oneline 2e673356aef | wc -l
>> 80
>> $ /usr/bin/git log -n1 -m --oneline 2e673356aef | wc -l
>> 1
>
> If you leave off --oneline, you'll note that git show produces a diff
> and git log does not (regardless of whether 2e673356aef is a merge
> commit or a regular commit).  So, I don't think this is related to
> --oneline.

Yeah, looks exactly like this, thanks for correcting!

>
>> 2. For 'git log', --oneline disables -m output, and leaves -c/--cc output
>> enabled:
>>
>> $ /usr/bin/git log -n1 -m --oneline 2e673356aef | wc -l
>> 1
>> $ /usr/bin/git log -n1 -c --oneline 2e673356aef | wc -l
>> 16
>> $ /usr/bin/git log -n1 --cc --oneline 2e673356aef | wc -l
>> 16
>>
>> The question is: what's the right interaction between --oneline and
>> -m/-c/--cc?
>
> I believe the right question is: Should -m be a no-op unless -p is
> also specified?

Right.

> In the past, --cc and -c were no-ops except when -p
> was also specified.  It was somewhat unfriendly and surprising, and
> thus was changed so that --cc and -c implied -p (and thus would cause
> output for non-merge commits to be shown differently, namely shown
> with a diff, in addition to affecting the type of diff shown for merge
> commits).

Well, so one surprise has been replaced with another, supposedly more
friendly, right?

I mean, obviously, with --cc I don't ask for diffs for non-merge
commits, so it is still a surprise they are thrown at me.

> I think -m was overlooked at the time.

Looks like it was, but maybe there was rather an actual reason for not
implying -p by -m? Maybe Junio will tell?

>
>> I tend to think they should be independent, so that --oneline doesn't
>> affect diff output, and then the only offender is -m.
>
> I agree that they should be independent, but I believe they are
> already independent unless you have more evidence of weirdness
> somewhere.  The differences you are seeing are due to -m, -c, and --cc
> being handled differently, and I think we should probably just give -m
> the same treatment that we give to -c and --cc (namely, make all three
> imply -p).

I think that either all diff-merge options should imply -p, or none,
from the POV of least surprise.

However, it'd give us yet another challenge: for some time already,
--first-parent implies -m, that once it starts to imply -p, will result in

  git log --first-parent

suddenly producing diff output for everything.

One way out I see is to specify that implied -m/-c/--cc don't imply
-p, only explicit do.

Entirely different approach is to get rid of -m/-c/--cc implying -p, and
just produce diff output for merges independently on -p being provided
or not. This will give us additional functionality (ability to get diff
for merges, but not for regulars), and will get rid of all the related
surprises.

Thoughts?

Thanks,
-- Sergey Organov

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

* Re: [PATCH 00/26] git-log: implement new --diff-merge options
  2020-12-08 22:30     ` Sergey Organov
@ 2020-12-08 23:11       ` Elijah Newren
  2020-12-09  1:17         ` Junio C Hamano
  0 siblings, 1 reply; 232+ messages in thread
From: Elijah Newren @ 2020-12-08 23:11 UTC (permalink / raw)
  To: Sergey Organov; +Cc: Junio C Hamano, Jeff King, Philip Oakley, Git Mailing List

On Tue, Dec 8, 2020 at 2:30 PM Sergey Organov <sorganov@gmail.com> wrote:
>
> Elijah Newren <newren@gmail.com> writes:
>
> > Hi Sergey,
>
> Hi Elijah,
>
> >
> > On Tue, Dec 8, 2020 at 12:07 PM Sergey Organov <sorganov@gmail.com> wrote:
> >>
> >> Sergey Organov <sorganov@gmail.com> writes:
> >>
> >>
> >> [...]
> >>
> >> > The series also cleanup logic of handling of diff merges options and
> >> > fix an issue found in the original implementation where logically
> >> > mutually exclusive options -m/-c/--cc failed to actually override each
> >> > other.
> >>
> >> Working further on this, I've noticed very irregular interactions
> >> between -m/-c/--cc and --oneline:
> >>
> >> 1. --oneline disables -m output for 'git log', and leaves -m output enabled
> >> for 'git show':
> >>
> >> $ /usr/bin/git show -n1 -m --oneline 2e673356aef | wc -l
> >> 80
> >> $ /usr/bin/git log -n1 -m --oneline 2e673356aef | wc -l
> >> 1
> >
> > If you leave off --oneline, you'll note that git show produces a diff
> > and git log does not (regardless of whether 2e673356aef is a merge
> > commit or a regular commit).  So, I don't think this is related to
> > --oneline.
>
> Yeah, looks exactly like this, thanks for correcting!
>
> >
> >> 2. For 'git log', --oneline disables -m output, and leaves -c/--cc output
> >> enabled:
> >>
> >> $ /usr/bin/git log -n1 -m --oneline 2e673356aef | wc -l
> >> 1
> >> $ /usr/bin/git log -n1 -c --oneline 2e673356aef | wc -l
> >> 16
> >> $ /usr/bin/git log -n1 --cc --oneline 2e673356aef | wc -l
> >> 16
> >>
> >> The question is: what's the right interaction between --oneline and
> >> -m/-c/--cc?
> >
> > I believe the right question is: Should -m be a no-op unless -p is
> > also specified?
>
> Right.
>
> > In the past, --cc and -c were no-ops except when -p
> > was also specified.  It was somewhat unfriendly and surprising, and
> > thus was changed so that --cc and -c implied -p (and thus would cause
> > output for non-merge commits to be shown differently, namely shown
> > with a diff, in addition to affecting the type of diff shown for merge
> > commits).
>
> Well, so one surprise has been replaced with another, supposedly more
> friendly, right?
>
> I mean, obviously, with --cc I don't ask for diffs for non-merge
> commits, so it is still a surprise they are thrown at me.

Actually, that wasn't a side-effect but part of the intended change --
see https://lore.kernel.org/git/1440110591-12941-1-git-send-email-gitster@pobox.com/.

> > I think -m was overlooked at the time.
>
> Looks like it was, but maybe there was rather an actual reason for not
> implying -p by -m? Maybe Junio will tell?
>
> >
> >> I tend to think they should be independent, so that --oneline doesn't
> >> affect diff output, and then the only offender is -m.
> >
> > I agree that they should be independent, but I believe they are
> > already independent unless you have more evidence of weirdness
> > somewhere.  The differences you are seeing are due to -m, -c, and --cc
> > being handled differently, and I think we should probably just give -m
> > the same treatment that we give to -c and --cc (namely, make all three
> > imply -p).
>
> I think that either all diff-merge options should imply -p, or none,
> from the POV of least surprise.
>
> However, it'd give us yet another challenge: for some time already,
> --first-parent implies -m, that once it starts to imply -p, will result in
>
>   git log --first-parent
>
> suddenly producing diff output for everything.

That is definitely a pickle.

> One way out I see is to specify that implied -m/-c/--cc don't imply
> -p, only explicit do.
>
> Entirely different approach is to get rid of -m/-c/--cc implying -p, and
> just produce diff output for merges independently on -p being provided
> or not. This will give us additional functionality (ability to get diff
> for merges, but not for regulars), and will get rid of all the related
> surprises.
>
> Thoughts?

I was happy when I found out that --cc had changed to imply -p; I
guess I felt the same as Junio did with his rationale in the link I
posted above.  I've made --remerge-diff behave like --cc (i.e. it
implies -p), and I like it there too.  I use it both to turn on diffs
for merges, and to turn on diffs for regular commits without having to
specify the extra -p flag.  I guess I'm not sure why one would ever
want to see diffs for merges and not for normal commits.  Even in the
unusual case someone did, couldn't they just pass --merges (to strip
out the normal commits entirely)?

I may not have the best vantage point on this, though, because I
personally don't see enough utility in diffing a merge to just one of
its parents that it'd merit having an option to git-log, and yet we
clearly have two such options already (-m and --first-parent when
combined with -p).

But, there is at least one more way to get out of this pickle besides
the two options you listed above: we could make --first-parent be just
about commit limiting and not imply anything about diff behavior.
Honestly, I find it a little surprising that despite the fact that log
-p shows nothing for merge commits, that when I add --first-parent to
see a subset of commits I suddenly get weird, huge diffs shown for the
merges (yeah, yeah, I learned recently that it's documented behavior,
so it's not surprising anymore, just weird).  So, this wouldn't just
get rid of this new nasty pickle, but would remove another negative
surprise too.  If we're going to make a behavioral change, I'd rather
we fixed this side rather than the (IMO) nicely working --cc/-c side.


Hope that helps,
Elijah

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

* Re: [PATCH 00/26] git-log: implement new --diff-merge options
  2020-12-08 23:11       ` Elijah Newren
@ 2020-12-09  1:17         ` Junio C Hamano
  2020-12-09  3:06           ` Elijah Newren
  0 siblings, 1 reply; 232+ messages in thread
From: Junio C Hamano @ 2020-12-09  1:17 UTC (permalink / raw)
  To: Elijah Newren; +Cc: Sergey Organov, Jeff King, Philip Oakley, Git Mailing List

Elijah Newren <newren@gmail.com> writes:

> ... I guess I'm not sure why one would ever
> want to see diffs for merges and not for normal commits.  Even in the
> unusual case someone did, couldn't they just pass --merges (to strip
> out the normal commits entirely)?

Giving "--merges" would skip the single-strand-of-pearls commits
entirely, not even showing their log messages, so it won't be an
equivalent substitute.

> Honestly, I find it a little surprising that despite the fact that log
> -p shows nothing for merge commits, that when I add --first-parent to
> see a subset of commits I suddenly get weird, huge diffs shown for the
> merges (yeah, yeah, I learned recently that it's documented behavior,
> so it's not surprising anymore, just weird).

I view "--first-parent" as telling "git log" to pretend all merges
are single-parent commits (as if you did squash merges), and it is a
natural consequence if "log --first-parent -p" showed each commit
with its first parent, whether it is a merge or a single-parent
commit.

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

* Re: [PATCH 00/26] git-log: implement new --diff-merge options
  2020-12-09  1:17         ` Junio C Hamano
@ 2020-12-09  3:06           ` Elijah Newren
  2020-12-09  3:22             ` Junio C Hamano
  0 siblings, 1 reply; 232+ messages in thread
From: Elijah Newren @ 2020-12-09  3:06 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Sergey Organov, Jeff King, Philip Oakley, Git Mailing List

Hi Junio,

On Tue, Dec 8, 2020 at 5:17 PM Junio C Hamano <gitster@pobox.com> wrote:
>
> Elijah Newren <newren@gmail.com> writes:
>
> > ... I guess I'm not sure why one would ever
> > want to see diffs for merges and not for normal commits.  Even in the
> > unusual case someone did, couldn't they just pass --merges (to strip
> > out the normal commits entirely)?
>
> Giving "--merges" would skip the single-strand-of-pearls commits
> entirely, not even showing their log messages, so it won't be an
> equivalent substitute.

Right, I said that too in my parenthetical comment; --merges would
strip out the normal commits entirely.  As I said, I'm not sure why
anyone would ever want to see diffs for merges and not for normal
commits, the closest useful thing I can imagine is commit messages +
diffs for just merges, stripping the normal commits.  Is there a
usecase here (other than the motivating example of trying to remove an
inconsistency between -m and --cc output)?

I'd personally dislike needing to specify --cc and -p together when
today I can specify just --cc.  You said as much too at [1].  Have you
since changed your mind?

[1] https://lore.kernel.org/git/1440110591-12941-1-git-send-email-gitster@pobox.com/

> > Honestly, I find it a little surprising that despite the fact that log
> > -p shows nothing for merge commits, that when I add --first-parent to
> > see a subset of commits I suddenly get weird, huge diffs shown for the
> > merges (yeah, yeah, I learned recently that it's documented behavior,
> > so it's not surprising anymore, just weird).
>
> I view "--first-parent" as telling "git log" to pretend all merges
> are single-parent commits (as if you did squash merges), and it is a
> natural consequence if "log --first-parent -p" showed each commit
> with its first parent, whether it is a merge or a single-parent
> commit.

Alright, fair enough.  I had always viewed it as commit limiting only
(and thus why it looked weird to me), but I really don't use
--first-parent or -m much.

But that leaves Sergey's question unanswered: should the inconsistency
between --cc and -m (namely that only the former implies -p) be
removed?  If so, since --first-parent implies -m, what's the right way
to avoid --first-parent becoming weird?  (Allow explicit -m to imply
-p, but not an implicit -m that came from --first-parent?)

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

* Re: [PATCH 00/26] git-log: implement new --diff-merge options
  2020-12-09  3:06           ` Elijah Newren
@ 2020-12-09  3:22             ` Junio C Hamano
  2020-12-09  3:31               ` Elijah Newren
  0 siblings, 1 reply; 232+ messages in thread
From: Junio C Hamano @ 2020-12-09  3:22 UTC (permalink / raw)
  To: Elijah Newren; +Cc: Sergey Organov, Jeff King, Philip Oakley, Git Mailing List

Elijah Newren <newren@gmail.com> writes:

> ...  As I said, I'm not sure why
> anyone would ever want to see diffs for merges and not for normal
> commits, the closest useful thing I can imagine is commit messages +
> diffs for just merges, stripping the normal commits.

If I can run "git log --some-options master..next" (or more
realistically, over the range ko/next..next) to get individual
commits (without patch) and merges (only when --cc gives some
interesting nearby-changes), I would be very happy.  But is there a
set of options that lets me do so?


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

* Re: [PATCH 00/26] git-log: implement new --diff-merge options
  2020-12-09  3:22             ` Junio C Hamano
@ 2020-12-09  3:31               ` Elijah Newren
  2020-12-09  4:18                 ` Junio C Hamano
  0 siblings, 1 reply; 232+ messages in thread
From: Elijah Newren @ 2020-12-09  3:31 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Sergey Organov, Jeff King, Philip Oakley, Git Mailing List

On Tue, Dec 8, 2020 at 7:22 PM Junio C Hamano <gitster@pobox.com> wrote:
>
> Elijah Newren <newren@gmail.com> writes:
>
> > ...  As I said, I'm not sure why
> > anyone would ever want to see diffs for merges and not for normal
> > commits, the closest useful thing I can imagine is commit messages +
> > diffs for just merges, stripping the normal commits.
>
> If I can run "git log --some-options master..next" (or more
> realistically, over the range ko/next..next) to get individual
> commits (without patch) and merges (only when --cc gives some
> interesting nearby-changes), I would be very happy.  But is there a
> set of options that lets me do so?

So, you're saying you changed your mind since five years ago?[1]  Or
that what you said five years ago is still valid, but you'd appreciate
more/different options that allow this new thing?

[1] https://lore.kernel.org/git/1440110591-12941-1-git-send-email-gitster@pobox.com/

We got to this point in this thread because Sergey suggested reverting
the above change (as one option) in order to bring more consistency
between -m and -c/--cc.

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

* Re: [PATCH 00/26] git-log: implement new --diff-merge options
  2020-12-09  3:31               ` Elijah Newren
@ 2020-12-09  4:18                 ` Junio C Hamano
  2020-12-09  4:54                   ` Elijah Newren
  0 siblings, 1 reply; 232+ messages in thread
From: Junio C Hamano @ 2020-12-09  4:18 UTC (permalink / raw)
  To: Elijah Newren; +Cc: Sergey Organov, Jeff King, Philip Oakley, Git Mailing List

Elijah Newren <newren@gmail.com> writes:

>> If I can run "git log --some-options master..next" (or more
>> realistically, over the range ko/next..next) to get individual
>> commits (without patch) and merges (only when --cc gives some
>> interesting nearby-changes), I would be very happy.  But is there a
>> set of options that lets me do so?
>
> So, you're saying you changed your mind since five years ago?[1]  Or
> that what you said five years ago is still valid, but you'd appreciate
> more/different options that allow this new thing?
>
> [1] https://lore.kernel.org/git/1440110591-12941-1-git-send-email-gitster@pobox.com/

Sorry, but I am not seeing in [1] anything that relates to the above
"want to see --cc patch for merge but just log message for single
parent commit". 5 years is a long time even in Git timescale, so I
would not be surprised if I changed my mind over time, but I am not
sure what opinion on the matter you think I expressed back then.

"git log --cc master..next" shows all commits' log messages, patch
for each single-parent commit, and combined-dense patch for each
merge.  There is no option to squelch the patch for only single
parent commits.  It may not be such a bad thing to have as an extra
option.

So, I think what I am saying is that ...

> > ...  As I said, I'm not sure why
> > anyone would ever want to see diffs for merges and not for normal
> > commits, the closest useful thing I can imagine is commit messages +
> > diffs for just merges, stripping the normal commits.

... I see use for such a feature (assuming that you didn't mean by
"diffs for merges" a regular "--first-parent -p" patch, but meant to
say "--cc" patch) in my workflow.  I'd review "log ko/next..next"
before deciding to push out the day's integration of 'next', and at
that point, I trust individual commits that came from contributors
well enough (otherwise I wouldn't be merging them to 'next'), but I
would appreciate the last chance to re-examine conflict resolutions
in merges.

It does not mean that I do not like the current behaviour that
"--cc" always implies "-p"; it is convenient.  It's just I find the
lack of feature slightly less than ideal, but I do not care deeply
enough to design how to express such a feature from the command
line.

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

* Re: [PATCH 00/26] git-log: implement new --diff-merge options
  2020-12-09  4:18                 ` Junio C Hamano
@ 2020-12-09  4:54                   ` Elijah Newren
  2020-12-09  5:24                     ` Junio C Hamano
  2020-12-09 13:34                     ` Sergey Organov
  0 siblings, 2 replies; 232+ messages in thread
From: Elijah Newren @ 2020-12-09  4:54 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Sergey Organov, Jeff King, Philip Oakley, Git Mailing List

On Tue, Dec 8, 2020 at 8:18 PM Junio C Hamano <gitster@pobox.com> wrote:
>
> Elijah Newren <newren@gmail.com> writes:
>
> >> If I can run "git log --some-options master..next" (or more
> >> realistically, over the range ko/next..next) to get individual
> >> commits (without patch) and merges (only when --cc gives some
> >> interesting nearby-changes), I would be very happy.  But is there a
> >> set of options that lets me do so?
> >
> > So, you're saying you changed your mind since five years ago?[1]  Or
> > that what you said five years ago is still valid, but you'd appreciate
> > more/different options that allow this new thing?
> >
> > [1] https://lore.kernel.org/git/1440110591-12941-1-git-send-email-gitster@pobox.com/
>
> Sorry, but I am not seeing in [1] anything that relates to the above
> "want to see --cc patch for merge but just log message for single
> parent commit". 5 years is a long time even in Git timescale, so I
> would not be surprised if I changed my mind over time, but I am not
> sure what opinion on the matter you think I expressed back then.
>
> "git log --cc master..next" shows all commits' log messages, patch
> for each single-parent commit, and combined-dense patch for each
> merge.  There is no option to squelch the patch for only single
> parent commits.  It may not be such a bad thing to have as an extra
> option.
>
> So, I think what I am saying is that ...
>
> > > ...  As I said, I'm not sure why
> > > anyone would ever want to see diffs for merges and not for normal
> > > commits, the closest useful thing I can imagine is commit messages +
> > > diffs for just merges, stripping the normal commits.
>
> ... I see use for such a feature (assuming that you didn't mean by
> "diffs for merges" a regular "--first-parent -p" patch, but meant to
> say "--cc" patch) in my workflow.  I'd review "log ko/next..next"
> before deciding to push out the day's integration of 'next', and at
> that point, I trust individual commits that came from contributors
> well enough (otherwise I wouldn't be merging them to 'next'), but I
> would appreciate the last chance to re-examine conflict resolutions
> in merges.
>
> It does not mean that I do not like the current behaviour that
> "--cc" always implies "-p"; it is convenient.  It's just I find the
> lack of feature slightly less than ideal, but I do not care deeply
> enough to design how to express such a feature from the command
> line.

Okay, thanks for clarifying.  It sounds like you were focusing on the
tangentially related comment I made (diffs for merges and not for
normal commits) while I was focusing on Sergey's question (should we
revert --cc implies -p).  I was having a hard time understanding if
you were answering his question or not.  This last paragraph of yours
acknowledges the question, though you still avoid answering it.  :-)

However, even my focus was on a secondary question.  His real original
question is: -m and --cc are inconsistent -- one requires -p, while
the other doesn't.  Should that be fixed...and which option(s) should
change?  He gave two possibilities I didn't like.  I added a third
that you didn't like.  So...

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

* Re: [PATCH 00/26] git-log: implement new --diff-merge options
  2020-12-09  4:54                   ` Elijah Newren
@ 2020-12-09  5:24                     ` Junio C Hamano
  2020-12-09  6:40                       ` Junio C Hamano
  2020-12-09 13:34                     ` Sergey Organov
  1 sibling, 1 reply; 232+ messages in thread
From: Junio C Hamano @ 2020-12-09  5:24 UTC (permalink / raw)
  To: Elijah Newren; +Cc: Sergey Organov, Jeff King, Philip Oakley, Git Mailing List

Elijah Newren <newren@gmail.com> writes:

>> It does not mean that I do not like the current behaviour that
>> "--cc" always implies "-p"; it is convenient.  It's just I find the
>> lack of feature slightly less than ideal, but I do not care deeply
>> enough to design how to express such a feature from the command
>> line.
>
> Okay, thanks for clarifying.  It sounds like you were focusing on the
> tangentially related comment I made (diffs for merges and not for
> normal commits) while I was focusing on Sergey's question (should we
> revert --cc implies -p).  I was having a hard time understanding if
> you were answering his question or not.  This last paragraph of yours
> acknowledges the question, though you still avoid answering it.  :-)

I do like the current behaviour that "--cc" always implies "-p"; it
is convenient.  I just wish there were a way to say "enable -p only
for merges" while taking advantage of the convenience.

So, no we should not stop "--cc" or "-c" implying "-p".

When the end-user gives "-m" on the command line of either "show" or
"log", it cleanly means the user is interested in "individual"
patches shown for each parent when showing a merge commit, so "-p"
implied by "-m" would make sense just as much as "-p" implied by
"--cc".  The same comment about the lack of "want -p to be implied
but only for merges" as an add-on feature applies here, though.

I suspect that the real reason why "-m" does not imply "-p" was
merely a historical implementation detail (e.g. imagine that we
wanted *not* to show things by default in a subcommand in "log"
family, but when "-p" is used, wanted it to mean "-m -p", or
something like that.  Setting "-m" on by default without explicitly
given from the command line, and making sure that m-bit does not
imply "-p", would be an easy-to-implement such a "when '-p' is
given, take it to mean as '-m -p'" _feature_).

If I were to decide now with hindsight, perhaps I'd make "--cc" and
"-m" imply "-p" only for merge commits, and the user can explicitly
give "--cc -p" and "-m -p" to ask patches for single-parent commits
to be shown as well.


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

* Re: [PATCH 00/26] git-log: implement new --diff-merge options
  2020-12-09  5:24                     ` Junio C Hamano
@ 2020-12-09  6:40                       ` Junio C Hamano
  2020-12-09 14:08                         ` Sergey Organov
  2020-12-09 19:44                         ` Sergey Organov
  0 siblings, 2 replies; 232+ messages in thread
From: Junio C Hamano @ 2020-12-09  6:40 UTC (permalink / raw)
  To: Elijah Newren; +Cc: Sergey Organov, Jeff King, Philip Oakley, Git Mailing List

Junio C Hamano <gitster@pobox.com> writes:

A clarification and a correction.

> I suspect that the real reason why "-m" does not imply "-p" was
> merely a historical implementation detail...

Now I remember better.  The reason was pure oversight.

In the beginning, there was no patch output for merges.  As most
merges just resolve cleanly, and back then the first-parent chains
were treated as much much less special than we treat them today,
"git log -p" showed only patches for single-parent commits and
everybody was happy.  It could have been a possible alternative
design to show first-parent diff for a merge instead of showing no
patch, but because the traversal went to side branches, the changes
made by the merge to the mainline as a single big patch would have
been redundant---we would be seeing individual patches from the side
branch anyway.

Then later we introduced "-m -p"; since the first-parent chain was
not considered all that special, we treated each parent equally.
Nobody, not even Linus and I, thought it was useful by itself even
back then, but we didn't have anything better.

I think it was Paul Mackerras's "gitk" that invented the concept of
combined merges.  We liked it quite a lot, and added "-c" and "--cc"
soon after that, to the core git and kept polishing, until "gitk"
stopped combining the patches with each parent in tcl/tk script and
instead started telling "git" to show with "--cc".

By the time the change to make "--cc" imply "-p" was introduced, it
was pretty much given that "-m -p" was useful to anybody, unless you
are consuming these individual patches in a script or something like
that.  So simply I didn't even think of making "-m" imply "-p".  It
would be logical to make it so, but it would not add much practical
value, I would have to say.

> If I were to decide now with hindsight, perhaps I'd make "--cc" and
> "-m" imply "-p" only for merge commits, and the user can explicitly
> give "--cc -p" and "-m -p" to ask patches for single-parent commits
> to be shown as well.

After "now with hindsight", I need to add "and without having to
worry about backward compatibility issues" here.  IOW, the above is
not my recommendation.  It would be the other way around: "--cc"
implies "-p" for both merges and non-merges, "-m" implies "-p" for
both merges and non-merges.  It is acceptable to add a new option
"--no-patch-for-non-merge" so that the user can ask to see only the
combined diff for merges and no patches for individual commits.

Both "--no-patch-for-non-merge" option, and making "-m" imply "-p"
are very low priority from my point of view, though, since our users
(including me) lived without the former and have been happily using
"log --cc" for a long time, and we've written off the latter as
pretty much useless combination unless you are a script.

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

* Re: [PATCH 00/26] git-log: implement new --diff-merge options
  2020-12-09  4:54                   ` Elijah Newren
  2020-12-09  5:24                     ` Junio C Hamano
@ 2020-12-09 13:34                     ` Sergey Organov
  1 sibling, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-12-09 13:34 UTC (permalink / raw)
  To: Elijah Newren; +Cc: Junio C Hamano, Jeff King, Philip Oakley, Git Mailing List

Elijah Newren <newren@gmail.com> writes:

> On Tue, Dec 8, 2020 at 8:18 PM Junio C Hamano <gitster@pobox.com> wrote:
>>
>> Elijah Newren <newren@gmail.com> writes:
>>
>> >> If I can run "git log --some-options master..next" (or more
>> >> realistically, over the range ko/next..next) to get individual
>> >> commits (without patch) and merges (only when --cc gives some
>> >> interesting nearby-changes), I would be very happy.  But is there a
>> >> set of options that lets me do so?
>> >
>> > So, you're saying you changed your mind since five years ago?[1]  Or
>> > that what you said five years ago is still valid, but you'd appreciate
>> > more/different options that allow this new thing?
>> >
>> > [1]
>> > https://lore.kernel.org/git/1440110591-12941-1-git-send-email-gitster@pobox.com/
>>
>> Sorry, but I am not seeing in [1] anything that relates to the above
>> "want to see --cc patch for merge but just log message for single
>> parent commit". 5 years is a long time even in Git timescale, so I
>> would not be surprised if I changed my mind over time, but I am not
>> sure what opinion on the matter you think I expressed back then.
>>
>> "git log --cc master..next" shows all commits' log messages, patch
>> for each single-parent commit, and combined-dense patch for each
>> merge.  There is no option to squelch the patch for only single
>> parent commits.  It may not be such a bad thing to have as an extra
>> option.
>>
>> So, I think what I am saying is that ...
>>
>> > > ...  As I said, I'm not sure why
>> > > anyone would ever want to see diffs for merges and not for normal
>> > > commits, the closest useful thing I can imagine is commit messages +
>> > > diffs for just merges, stripping the normal commits.
>>
>> ... I see use for such a feature (assuming that you didn't mean by
>> "diffs for merges" a regular "--first-parent -p" patch, but meant to
>> say "--cc" patch) in my workflow.  I'd review "log ko/next..next"
>> before deciding to push out the day's integration of 'next', and at
>> that point, I trust individual commits that came from contributors
>> well enough (otherwise I wouldn't be merging them to 'next'), but I
>> would appreciate the last chance to re-examine conflict resolutions
>> in merges.
>>
>> It does not mean that I do not like the current behaviour that
>> "--cc" always implies "-p"; it is convenient.  It's just I find the
>> lack of feature slightly less than ideal, but I do not care deeply
>> enough to design how to express such a feature from the command
>> line.
>
> Okay, thanks for clarifying.  It sounds like you were focusing on the
> tangentially related comment I made (diffs for merges and not for
> normal commits) while I was focusing on Sergey's question (should we
> revert --cc implies -p).  I was having a hard time understanding if
> you were answering his question or not.  This last paragraph of yours
> acknowledges the question, though you still avoid answering it.  :-)
>
> However, even my focus was on a secondary question.  His real original
> question is: -m and --cc are inconsistent -- one requires -p, while
> the other doesn't.  Should that be fixed...and which option(s) should
> change?  He gave two possibilities I didn't like.  I added a third
> that you didn't like.  So...

I believe you've misunderstood me slightly.

I didn't suggest bare reverting of the "-c/-cc imply -p" commit. I
rather suggested to modify current behavior to "-c/--cc enable diff
output for merge commits", then add "-m" to the mix, so that we finally
get:

  "-m/-c/--c enable diff output for merge commits".

And I should emphasize that what I mean differs from "-m/-c/--cc imply -p
for merge commits only" as Junio has put it in this discussion, even if
slightly, -- it won't imply -p, to avoid messing with --first-parent
that would imply -p through -m and enable diff for merges, that is not
what we want.

This is what I'd like to see, as it finally makes -m/-c/--cc (as well as
other --diff-merges options) focus on merge commits only and never
affect regular commits, -- the way it should be.

My alternative suggestion was to rather add "-m implies -p" to the
current state, resulting in:

  "-m/-c/--c imply -p".

However, the latter one has additional complication in handling of
"--first-parent" that currently implies -m that'd then imply -p and
suddenly give lengthy output on bare "git log --first-parent".

Fixing the latter is still possible by complicating of options handling
by specifying that implied options don't imply other options, only
explicit options do, but somehow I don't like this, -- too complex for
the job at hand. I'm still on position that option management in Git
could rather be done in much simpler manner, without need for such
complexities.

Thanks,
-- Sergey


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

* Re: [PATCH 00/26] git-log: implement new --diff-merge options
  2020-12-09  6:40                       ` Junio C Hamano
@ 2020-12-09 14:08                         ` Sergey Organov
  2020-12-09 20:53                           ` Junio C Hamano
  2020-12-09 19:44                         ` Sergey Organov
  1 sibling, 1 reply; 232+ messages in thread
From: Sergey Organov @ 2020-12-09 14:08 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Elijah Newren, Jeff King, Philip Oakley, Git Mailing List

Junio C Hamano <gitster@pobox.com> writes:

> Junio C Hamano <gitster@pobox.com> writes:
>
> A clarification and a correction.
>
>> I suspect that the real reason why "-m" does not imply "-p" was
>> merely a historical implementation detail...
>
> Now I remember better.  The reason was pure oversight.
>
> In the beginning, there was no patch output for merges.  As most
> merges just resolve cleanly, and back then the first-parent chains
> were treated as much much less special than we treat them today,
> "git log -p" showed only patches for single-parent commits and
> everybody was happy.  It could have been a possible alternative
> design to show first-parent diff for a merge instead of showing no
> patch, but because the traversal went to side branches, the changes
> made by the merge to the mainline as a single big patch would have
> been redundant---we would be seeing individual patches from the side
> branch anyway.
>
> Then later we introduced "-m -p"; since the first-parent chain was
> not considered all that special, we treated each parent equally.
> Nobody, not even Linus and I, thought it was useful by itself even
> back then, but we didn't have anything better.
>
> I think it was Paul Mackerras's "gitk" that invented the concept of
> combined merges.  We liked it quite a lot, and added "-c" and "--cc"
> soon after that, to the core git and kept polishing, until "gitk"
> stopped combining the patches with each parent in tcl/tk script and
> instead started telling "git" to show with "--cc".
>
> By the time the change to make "--cc" imply "-p" was introduced, it
> was pretty much given that "-m -p" was useful to anybody, unless you
> are consuming these individual patches in a script or something like
> that.  So simply I didn't even think of making "-m" imply "-p".  It
> would be logical to make it so, but it would not add much practical
> value, I would have to say.

... and then later the "--first-parent implies -m" change has been made,
that would't work as expected if -m implied -p in the fist place, as
it'd break "git log --first-parent".

>
>> If I were to decide now with hindsight, perhaps I'd make "--cc" and
>> "-m" imply "-p" only for merge commits, and the user can explicitly
>> give "--cc -p" and "-m -p" to ask patches for single-parent commits
>> to be shown as well.
>
> After "now with hindsight", I need to add "and without having to
> worry about backward compatibility issues" here.  IOW, the above is
> not my recommendation.  It would be the other way around: "--cc"
> implies "-p" for both merges and non-merges, "-m" implies "-p" for
> both merges and non-merges.  It is acceptable to add a new option
> "--no-patch-for-non-merge" so that the user can ask to see only the
> combined diff for merges and no patches for individual commits.

OK, so, do we decide that -c/--cc must continue to imply -p and thus
request diffs for everything?

If so, I can rather change --diff-merges=combined/dense-combined
behavior to /not/ imply -p, thus effectively making --cc a synonym for
"--diff-merges=dense-combined --patch", that will have zero backward
compatibility issues.

Looks like it'd have everything covered. Old options won't change their
behavior at all, and the new set of options will behave differently,
exactly if designed from scratch, providing new functionality.

>
> Both "--no-patch-for-non-merge" option, and making "-m" imply "-p"
> are very low priority from my point of view, though, since our users
> (including me) lived without the former and have been happily using
> "log --cc" for a long time, and we've written off the latter as
> pretty much useless combination unless you are a script.

I think my above suggestion covers all the worries without need for this
nasty "--no-patch-for-non-merge" option.

That said, -m is useless, period. It'd likely have some merit in
plumbing, but definitely not in porcelain. So I'm inclined to let it
rest in peace indeed, dying.

Thanks,
-- Sergey



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

* Re: [PATCH 00/26] git-log: implement new --diff-merge options
  2020-12-09  6:40                       ` Junio C Hamano
  2020-12-09 14:08                         ` Sergey Organov
@ 2020-12-09 19:44                         ` Sergey Organov
  2020-12-10  6:12                           ` Junio C Hamano
  2020-12-10  7:26                           ` Elijah Newren
  1 sibling, 2 replies; 232+ messages in thread
From: Sergey Organov @ 2020-12-09 19:44 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Elijah Newren, Jeff King, Philip Oakley, Git Mailing List

Junio C Hamano <gitster@pobox.com> writes:

[...]

> By the time the change to make "--cc" imply "-p" was introduced, it
> was pretty much given that "-m -p" was useful to anybody, unless you
> are consuming these individual patches in a script or something like
> that.  So simply I didn't even think of making "-m" imply "-p".  It
> would be logical to make it so, but it would not add much practical
> value, I would have to say.

I need some help here.

Looking at the code and trying to follow the flow, I can't figure what
rev->diff flag is for? Why rev->diffopt.output_format, that actually
affects the output, is not enough?

My confusion originates from the fact that the code in revision.c sets
rev->diff to 1 for -c/--cc , while it doesn't set it for -m, and this
was the case *before* -c/--cc started to imply -p and -m.

It seems that the only place where rev->diff is tested is at the start
of log_tree_diff(), and even there its absence could be ignored when
rev->diffopt.flags.exit_with_status is set.

Is rev->diff an optimization, does it play another significant role, or
is it a remnant?

Thanks,
-- Sergey

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

* Re: [PATCH 00/26] git-log: implement new --diff-merge options
  2020-12-09 14:08                         ` Sergey Organov
@ 2020-12-09 20:53                           ` Junio C Hamano
  0 siblings, 0 replies; 232+ messages in thread
From: Junio C Hamano @ 2020-12-09 20:53 UTC (permalink / raw)
  To: Sergey Organov; +Cc: Elijah Newren, Jeff King, Philip Oakley, Git Mailing List

Sergey Organov <sorganov@gmail.com> writes:

>>> If I were to decide now with hindsight, perhaps I'd make "--cc" and
>>> "-m" imply "-p" only for merge commits, and the user can explicitly
>>> give "--cc -p" and "-m -p" to ask patches for single-parent commits
>>> to be shown as well.
>>
>> After "now with hindsight", I need to add "and without having to
>> worry about backward compatibility issues" here.  IOW, the above is
>> not my recommendation.  It would be the other way around: "--cc"
>> implies "-p" for both merges and non-merges, "-m" implies "-p" for
>> both merges and non-merges.  It is acceptable to add a new option
>> "--no-patch-for-non-merge" so that the user can ask to see only the
>> combined diff for merges and no patches for individual commits.
>
> OK, so, do we decide that -c/--cc must continue to imply -p and thus
> request diffs for everything?

My vote goes to keep the above behaviour as-is for compatibility,
and probably match what happens when -m is given instead of -c/--cc,
if somebody cares enough about "-c/--cc/-m discrepancy".

> That said, -m is useless, period. It'd likely have some merit in
> plumbing, but definitely not in porcelain. So I'm inclined to let it
> rest in peace indeed, dying.

That is fine by me as well.

I do not speak for others, though ;-)

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

* Re: [PATCH 00/26] git-log: implement new --diff-merge options
  2020-12-09 19:44                         ` Sergey Organov
@ 2020-12-10  6:12                           ` Junio C Hamano
  2020-12-10  7:26                           ` Elijah Newren
  1 sibling, 0 replies; 232+ messages in thread
From: Junio C Hamano @ 2020-12-10  6:12 UTC (permalink / raw)
  To: Sergey Organov; +Cc: Elijah Newren, Jeff King, Philip Oakley, Git Mailing List

Sergey Organov <sorganov@gmail.com> writes:

> My confusion originates from the fact that the code in revision.c sets
> rev->diff to 1 for -c/--cc , while it doesn't set it for -m, and this
> was the case *before* -c/--cc started to imply -p and -m.

Yes, all of this was from cd2bdc53 (Common option parsing for "git
log --diff" and friends, 2006-04-14).  We can see that "-m" is not
treated among the first class citizen in the output of "git show" on
the commit.  Namely, "-m" alone is merely a modifier for "-p" and
does not cause a diff to be generated (in other words, it only
affects the output if used together with "-p").

"git show cd2bdc53:git.c" would give you how "git log" looked like
back then, and how rev.diff field is used.

    static int cmd_log(int argc, const char **argv, char **envp)
    {
    ...

	prepare_revision_walk(&rev);
	setup_pager();
	while ((commit = get_revision(&rev)) != NULL) {
		if (shown && rev.diff && rev.commit_format != CMIT_FMT_ONELINE)
			putchar('\n');

We grab the next commit to show, and if we have already shown
something in the previous iteration, and if we are told to produce
patch output, we put an extra blank line after the patch for the
previous commit.  We omit that extra blank when showing the log
message in oneline format.  And then ...

		fputs(commit_prefix, stdout);
		if (rev.abbrev_commit && rev.abbrev)
			fputs(find_unique_abbrev(commit->object.sha1, rev.abbrev),
			      stdout);
		else
			fputs(sha1_to_hex(commit->object.sha1), stdout);
		if (rev.parents) {
    ...
		}
		if (rev.commit_format == CMIT_FMT_ONELINE)
			putchar(' ');
		else
			putchar('\n');
		pretty_print_commit(rev.commit_format, commit, ~0, buf,
				    LOGSIZE, rev.abbrev);
		printf("%s\n", buf);

... after showing the log message, if we were told to produce diff,

		if (rev.diff)
			log_tree_commit(&rev, commit);

we ask log_tree_commit() to show the patch.

		shown = 1;
		free(commit->buffer);
		commit->buffer = NULL;
	}
    ...

I think the code these days have most of the per-commit logic moved
to log_tree_commit() compared to the code we see above, but the
check at the beginning of log_tree_diff() we have, i.e.

    static int log_tree_diff(struct rev_info *opt, struct commit *...
    {
	int showed_log;
	struct commit_list *parents;
	struct object_id *oid;

	if (!opt->diff && !opt->diffopt.flags.exit_with_status)
		return 0;

directly corresponds to the "if rev.diff is true, then call
log_tree_commit()" in the 2006 code.

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

* Re: [PATCH 00/26] git-log: implement new --diff-merge options
  2020-12-09 19:44                         ` Sergey Organov
  2020-12-10  6:12                           ` Junio C Hamano
@ 2020-12-10  7:26                           ` Elijah Newren
  2020-12-10 20:10                             ` Sergey Organov
  2020-12-10 21:26                             ` Junio C Hamano
  1 sibling, 2 replies; 232+ messages in thread
From: Elijah Newren @ 2020-12-10  7:26 UTC (permalink / raw)
  To: Sergey Organov; +Cc: Junio C Hamano, Jeff King, Philip Oakley, Git Mailing List

On Wed, Dec 9, 2020 at 11:44 AM Sergey Organov <sorganov@gmail.com> wrote:
>
> Junio C Hamano <gitster@pobox.com> writes:
>
> [...]
>
> > By the time the change to make "--cc" imply "-p" was introduced, it
> > was pretty much given that "-m -p" was useful to anybody, unless you
> > are consuming these individual patches in a script or something like
> > that.  So simply I didn't even think of making "-m" imply "-p".  It
> > would be logical to make it so, but it would not add much practical
> > value, I would have to say.
>
> I need some help here.
>
> Looking at the code and trying to follow the flow, I can't figure what
> rev->diff flag is for? Why rev->diffopt.output_format, that actually
> affects the output, is not enough?

I'm not a revision walking expert, but to the best of my understanding...

Showing a diff is not the only reason you might need to compute one.
You may also need to compute them if you are filtering commits by
pathspec (-- $filename), using the pickaxe (-S foo), checking if
commits are cherry-picks (--cherry-mark), checking for commits with
certain type of file changes (--diff-filter=A), selecting commits that
modified a certain function (-L :funcname:filename --no-patch), or
others I've overlooked.  None of these cause a diff to be shown.  I
don't know if all these set rev->diff to 1 or if they special case
some other way, but I suspect that rev->diff exists as a shorthand for
"need a diff", so that the code can check for it without having to
check a half dozen special conditions.

>> My confusion originates from the fact that the code in revision.c sets
> rev->diff to 1 for -c/--cc , while it doesn't set it for -m, and this
> was the case *before* -c/--cc started to imply -p and -m.
>
> It seems that the only place where rev->diff is tested is at the start
> of log_tree_diff(), and even there its absence could be ignored when
> rev->diffopt.flags.exit_with_status is set.

rev->diffopt.flags.exit_with_status seems quite unlikely to be set,
though.  That setting was added with the --exit-code flag to git log
in 2008 (in the pm/log-exit-code topic), but was never documented
(other than to say it's incompatible with --check), the commit message
adding it doesn't say what behavior was intended, and the commit
message which added it added no regression tests either.  I know what
diff --exit-code does, but I'm really not sure what git-log's
--exit-code does (random guess: sets the exit code to an OR of what
git diff would have shown for any one of the commits shown?).  Since I
don't know and can't even figure it out looking at the commits in
question, I suspect there aren't too many users out there using it.
As such, I suspect rev->diffopt.flags.exit_with_status will be 0 most
of the time and that the relevant check at the top of log_tree_diff()
really is the "if (!opt->diff)" part of it.

> Is rev->diff an optimization, does it play another significant role, or
> is it a remnant?

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

* Re: [PATCH 00/26] git-log: implement new --diff-merge options
  2020-12-10  7:26                           ` Elijah Newren
@ 2020-12-10 20:10                             ` Sergey Organov
  2020-12-10 21:15                               ` Junio C Hamano
  2020-12-10 21:26                             ` Junio C Hamano
  1 sibling, 1 reply; 232+ messages in thread
From: Sergey Organov @ 2020-12-10 20:10 UTC (permalink / raw)
  To: Elijah Newren; +Cc: Junio C Hamano, Jeff King, Philip Oakley, Git Mailing List

Elijah Newren <newren@gmail.com> writes:


[...]

> As such, I suspect rev->diffopt.flags.exit_with_status will be 0 most
> of the time and that the relevant check at the top of log_tree_diff()
> really is the "if (!opt->diff)" part of it.

Right, but *why* is it needed? If I do set opt->diff to 1 but don't set
opt->diffopt.output_format I get no diff, so the question essentially
is: which caller of log_tree_diff() would need to set
opt->diffopt.output_format but leave opt->diff to be 0, and why?

Even if such caller exists, it will get no diff, so it seems to be
entirely pointless.

>
>> Is rev->diff an optimization, does it play another significant role, or
>> is it a remnant?

I still don't see what's the correct answer to this question, sorry.

Well, I did a crush-test: commented-out entire if() at the beginning of
the log_tree_diff() and ran all the tests. The result was entirely
surprising: all the tests pass except one:

Test Summary Report
-------------------
./t1410-reflog.sh                                  (Wstat: 256 Tests: 22 Failed: 1)
  Failed test:  4
  Non-zero exit status: 1
Files=912, Tests=23039, 278 wallclock secs (10.48 usr  2.12 sys + 1034.98 cusr 650.30 csys = 1697.88 CPU)
Result: FAIL

And now I wonder how comes none of specific test are able to notice the
difference, yet seemingly unrelated test fails?

Thanks,
-- Sergey

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

* Re: [PATCH 00/26] git-log: implement new --diff-merge options
  2020-12-10 20:10                             ` Sergey Organov
@ 2020-12-10 21:15                               ` Junio C Hamano
  0 siblings, 0 replies; 232+ messages in thread
From: Junio C Hamano @ 2020-12-10 21:15 UTC (permalink / raw)
  To: Sergey Organov; +Cc: Elijah Newren, Jeff King, Philip Oakley, Git Mailing List

Sergey Organov <sorganov@gmail.com> writes:

> Well, I did a crush-test: commented-out entire if() at the beginning of
> the log_tree_diff() and ran all the tests.

Meaning "if we are not told to show diff and if we are not told to
indicate with the exit code whether there was any difference, we do
not have to do any of the following" was skipped?  

For most cases we do use the absense of "diff" as an optimization,
but I wouldn't be surprised if a caller of log_tree_commit() that
does not set "we want diff" bit leaves the other members of rev_info
that need to be set correctly for the body of the function, which is
essentially a repeated call into diff_tree machinerly, in order to
work correctly.


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

* Re: [PATCH 00/26] git-log: implement new --diff-merge options
  2020-12-10  7:26                           ` Elijah Newren
  2020-12-10 20:10                             ` Sergey Organov
@ 2020-12-10 21:26                             ` Junio C Hamano
  1 sibling, 0 replies; 232+ messages in thread
From: Junio C Hamano @ 2020-12-10 21:26 UTC (permalink / raw)
  To: Elijah Newren; +Cc: Sergey Organov, Jeff King, Philip Oakley, Git Mailing List

Elijah Newren <newren@gmail.com> writes:

> ....  I know what
> diff --exit-code does, but I'm really not sure what git-log's
> --exit-code does (random guess: sets the exit code to an OR of what
> git diff would have shown for any one of the commits shown?).

The end of cmd_log_walk() does try to return diff_result_code(), but
diff_flush() can reset .has_changes to 0 or set it to 1 each
iteration, so I do not think it is "set .has_changes to 0, and never
reset to 0, but flip it to 1 if any change is found", which would
have had some chance of giving us "OR'ed together" semantics.


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

* [PATCH v2 00/33] git-log: implement new --diff-merge options
  2020-11-01 19:33 [PATCH 00/26] git-log: implement new --diff-merge options Sergey Organov
                   ` (27 preceding siblings ...)
  2020-12-08 20:07 ` [PATCH 00/26] " Sergey Organov
@ 2020-12-16 18:48 ` Sergey Organov
  2020-12-16 18:48   ` [PATCH v2 01/33] revision: factor out parsing of diff-merge related options Sergey Organov
                     ` (33 more replies)
  2020-12-21 15:19 ` [PATCH v3 00/32] " Sergey Organov
  29 siblings, 34 replies; 232+ messages in thread
From: Sergey Organov @ 2020-12-16 18:48 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Jeff King, Philip Oakley, Elijah Newren, git, Sergey Organov

These patch series implement new set of options governing diff output
of merge commits, all under the umbrella of single
--diff-merges=<mode> option.

Unlike original -c/--cc options, these new options do not imply -p,
thus allowing for getting diffs for merge commits without provoking of
diff output for regular, non-merge commits. E.g.:

  git log --diff-merges=cc

will output diffs (in dense-combined format) only for merge commits,
whereas:

  git log --cc

enables diffs for all the commits being output, either merges or
simple ones.

There is also another additional functionality provided, allowing to
get the format of "-p --first-parent" without change in history
traversal that --first-parent option causes, like this:

  git log --diff-merges=first-parent

The net result of these series are the following new options:

--diff-merges=	  |  rough original equivalent
------------------+----------------
1|first-parent    | --first-parent (only diff format implications)
m|separate        | -m and enable diff for merges
c|combined        | -c and enable diff for merges, but not for regulars
cc|dense-combined | --cc and enable diff for merges, but not for
		  |      regulars

The series also cleanup logic of handling of diff merges options and
fix an issue found in the original implementation where logically
mutually exclusive options -m/-c/--cc failed to actually override each
other. Neither semantics of these old options nor their interactions
with other options, such as --first-parent and -p, is supposed to be
changed.

The series start with the set of pure refactoring commits that are expected
to introduce no functional changes. These are all commits up to and
including:

"diff-merges: revise revs->diff flag handling"

The aim of these commits is to isolate options handling for diff merges so
that it could be easily understood and tweaked to ease introduction of the
new options.

Then the fix of -m/-c/-cc overriding issue follows, starting with a failing
test and followed by the fix.

Then follows a little bit of additional refactoring in order to
prepare for introduction of the new options, and finally the series
are finished by the implementation, documentation updates, and
some testing for the new options.

Updates in v2:

  * Move logic of "-c/--cc imply -p" to this module and do not imply
    -p by new --diff-merges options. Instead enable corresponding diff
    output without affecting non-merge commits. This is the most
    significant change with respect to v1 and it starts at 24/33.

  * Add support for old mnemonics: --diff-merges=(m|c|cc) to help
    those who are used to them, and add --diff-merges=1 to cover all
    variants with short mnemonics.

  * Fixed functions definitions style to have open curly brace on its
    own line, pointed to by Junio C Hamano.

  * Tweak --diff-merges=first-parent description, requested by Elijah
    Newren.

  * Fixed git-show documentation not to include description chunk
    relevant to git-log only, noticed by Elijah Newren.

  * Fixed documentation mistake claiming that -p is needed for
    diff-merges options to take effect, noticed by Elijah Newren.

  * Fixed a case where a change was put into wrong commit. The change
    moved to 11/27 form 10/27. Didn't affect end-result in any way.

  * Added short module description to diff-merges.h, as suggested by
    Junio C Hamano.

  * Fixed not returning "argcount" from	diff_merges_parse_opts(),
    noticed by Junio C Hamano.

Updates in v1:

  * Added documentation fix for git-show to include --diff-merges.

  * Fixed typos in commit messages noticed by Philip Oakley.

Sergey Organov (33):
  revision: factor out parsing of diff-merge related options
  revision: factor out setup of diff-merge related settings
  revision: factor out initialization of diff-merge related settings
  revision: provide implementation for diff merges tweaks
  revision: move diff merges functions to its own diff-merges.c
  diff-merges: rename all functions to have common prefix
  diff-merges: move checks for first_parent_only out of the module
  diff-merges: rename diff_merges_default_to_enable() to match semantics
  diff-merges: re-arrange functions to match the order they are called
    in
  diff-merges: new function diff_merges_suppress()
  diff-merges: new function diff_merges_set_dense_combined_if_unset()
  diff-merges: introduce revs->first_parent_merges flag
  diff-merges: revise revs->diff flag handling
  t4013: support test_expect_failure through ':failure' magic
  t4013: add tests for -m failing to override -c/--cc
  diff-merges: fix -m to properly override -c/--cc
  diff-merges: split 'ignore_merges' field
  diff-merges: group diff-merge flags next to each other inside
    'rev_info'
  diff-merges: get rid of now empty diff_merges_init_revs()
  diff-merges: refactor opt settings into separate functions
  diff-merges: make -m/-c/--cc explicitly mutually exclusive
  diff-merges: implement new values for --diff-merges
  diff-merges: fix style of functions definitions
  diff-merges: handle imply -p on -c/--cc logic for log.c
  diff-merges: do not imply -p for new options
  diff-merges: let new options enable diff without -p
  diff-merges: add old mnemonic counterparts to --diff-merges
  diff-merges: add '--diff-merges=1' as synonym for 'first-parent'
  doc/git-log: describe new --diff-merges options
  doc/diff-generate-patch: mention new --diff-merges option
  doc/rev-list-options: document --first-parent changes merges format
  doc/git-show: include --diff-merges description
  t4013: add tests for --diff-merges=first-parent

 Documentation/diff-generate-patch.txt         |   6 +-
 Documentation/diff-options.txt                |  53 +++++
 Documentation/git-log.txt                     |  46 +---
 Documentation/git-show.txt                    |   7 +-
 Documentation/rev-list-options.txt            |   5 +
 Makefile                                      |   1 +
 builtin/diff-files.c                          |   5 +-
 builtin/diff.c                                |   9 +-
 builtin/log.c                                 |  22 +-
 builtin/merge.c                               |   3 +-
 diff-merges.c                                 | 151 +++++++++++++
 diff-merges.h                                 |  24 +++
 fmt-merge-msg.c                               |   3 +-
 log-tree.c                                    |  30 +--
 revision.c                                    |  38 +---
 revision.h                                    |   9 +-
 t/t4013-diff-various.sh                       |  11 +-
 t/t4013/diff.log_--cc_-m_-p_master            | 200 ++++++++++++++++++
 ...diff.log_--diff-merges=first-parent_master |  56 +++++
 t/t4013/diff.log_-c_-m_-p_master              | 200 ++++++++++++++++++
 ...f.log_-p_--diff-merges=first-parent_master | 137 ++++++++++++
 21 files changed, 900 insertions(+), 116 deletions(-)
 create mode 100644 diff-merges.c
 create mode 100644 diff-merges.h
 create mode 100644 t/t4013/diff.log_--cc_-m_-p_master
 create mode 100644 t/t4013/diff.log_--diff-merges=first-parent_master
 create mode 100644 t/t4013/diff.log_-c_-m_-p_master
 create mode 100644 t/t4013/diff.log_-p_--diff-merges=first-parent_master

-- 
2.25.1


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

* [PATCH v2 01/33] revision: factor out parsing of diff-merge related options
  2020-12-16 18:48 ` [PATCH v2 00/33] " Sergey Organov
@ 2020-12-16 18:48   ` Sergey Organov
  2020-12-16 18:48   ` [PATCH v2 02/33] revision: factor out setup of diff-merge related settings Sergey Organov
                     ` (32 subsequent siblings)
  33 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-12-16 18:48 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Jeff King, Philip Oakley, Elijah Newren, git, Sergey Organov

Move all the parsing code related to diffing merges into new
parse_diff_merge_opts() function.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 revision.c | 66 ++++++++++++++++++++++++++++++++----------------------
 1 file changed, 39 insertions(+), 27 deletions(-)

diff --git a/revision.c b/revision.c
index aa6221204081..917b14e6ad5b 100644
--- a/revision.c
+++ b/revision.c
@@ -2153,6 +2153,44 @@ static void add_message_grep(struct rev_info *revs, const char *pattern)
 	add_grep(revs, pattern, GREP_PATTERN_BODY);
 }
 
+static int parse_diff_merge_opts(struct rev_info *revs, const char **argv) {
+	int argcount = 1;
+	const char *optarg;
+	const char *arg = argv[0];
+
+	if (!strcmp(arg, "-m")) {
+		/*
+		 * To "diff-index", "-m" means "match missing", and to the "log"
+		 * family of commands, it means "show full diff for merges". Set
+		 * both fields appropriately.
+		 */
+		revs->ignore_merges = 0;
+		revs->match_missing = 1;
+	} else if (!strcmp(arg, "-c")) {
+		revs->diff = 1;
+		revs->dense_combined_merges = 0;
+		revs->combine_merges = 1;
+	} else if (!strcmp(arg, "--cc")) {
+		revs->diff = 1;
+		revs->dense_combined_merges = 1;
+		revs->combine_merges = 1;
+	} else if (!strcmp(arg, "--no-diff-merges")) {
+		revs->ignore_merges = 1;
+	} else if (!strcmp(arg, "--combined-all-paths")) {
+		revs->diff = 1;
+		revs->combined_all_paths = 1;
+	} else if ((argcount = parse_long_opt("diff-merges", argv, &optarg))) {
+		if (!strcmp(optarg, "off")) {
+			revs->ignore_merges = 1;
+		} else {
+			die(_("unknown value for --diff-merges: %s"), optarg);
+		}
+	} else
+		argcount = 0;
+
+	return argcount;
+}
+
 static int handle_revision_opt(struct rev_info *revs, int argc, const char **argv,
 			       int *unkc, const char **unkv,
 			       const struct setup_revision_opt* opt)
@@ -2349,34 +2387,8 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
 		revs->diff = 1;
 		revs->diffopt.flags.recursive = 1;
 		revs->diffopt.flags.tree_in_recursive = 1;
-	} else if (!strcmp(arg, "-m")) {
-		/*
-		 * To "diff-index", "-m" means "match missing", and to the "log"
-		 * family of commands, it means "show full diff for merges". Set
-		 * both fields appropriately.
-		 */
-		revs->ignore_merges = 0;
-		revs->match_missing = 1;
-	} else if ((argcount = parse_long_opt("diff-merges", argv, &optarg))) {
-		if (!strcmp(optarg, "off")) {
-			revs->ignore_merges = 1;
-		} else {
-			die(_("unknown value for --diff-merges: %s"), optarg);
-		}
+	} else if ((argcount = parse_diff_merge_opts(revs, argv))) {
 		return argcount;
-	} else if (!strcmp(arg, "--no-diff-merges")) {
-		revs->ignore_merges = 1;
-	} else if (!strcmp(arg, "-c")) {
-		revs->diff = 1;
-		revs->dense_combined_merges = 0;
-		revs->combine_merges = 1;
-	} else if (!strcmp(arg, "--combined-all-paths")) {
-		revs->diff = 1;
-		revs->combined_all_paths = 1;
-	} else if (!strcmp(arg, "--cc")) {
-		revs->diff = 1;
-		revs->dense_combined_merges = 1;
-		revs->combine_merges = 1;
 	} else if (!strcmp(arg, "-v")) {
 		revs->verbose_header = 1;
 	} else if (!strcmp(arg, "--pretty")) {
-- 
2.25.1


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

* [PATCH v2 02/33] revision: factor out setup of diff-merge related settings
  2020-12-16 18:48 ` [PATCH v2 00/33] " Sergey Organov
  2020-12-16 18:48   ` [PATCH v2 01/33] revision: factor out parsing of diff-merge related options Sergey Organov
@ 2020-12-16 18:48   ` Sergey Organov
  2020-12-16 18:48   ` [PATCH v2 03/33] revision: factor out initialization " Sergey Organov
                     ` (31 subsequent siblings)
  33 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-12-16 18:48 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Jeff King, Philip Oakley, Elijah Newren, git, Sergey Organov

Move all the setting code related to diffing merges into new
setup_diff_merge_revs() function.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 revision.c | 18 ++++++++++++------
 1 file changed, 12 insertions(+), 6 deletions(-)

diff --git a/revision.c b/revision.c
index 917b14e6ad5b..e4c75d9278c4 100644
--- a/revision.c
+++ b/revision.c
@@ -2191,6 +2191,16 @@ static int parse_diff_merge_opts(struct rev_info *revs, const char **argv) {
 	return argcount;
 }
 
+static void setup_diff_merges_revs(struct rev_info *revs)
+{
+	if (revs->combine_merges && revs->ignore_merges < 0)
+		revs->ignore_merges = 0;
+	if (revs->ignore_merges < 0)
+		revs->ignore_merges = 1;
+	if (revs->combined_all_paths && !revs->combine_merges)
+		die("--combined-all-paths makes no sense without -c or --cc");
+}
+
 static int handle_revision_opt(struct rev_info *revs, int argc, const char **argv,
 			       int *unkc, const char **unkv,
 			       const struct setup_revision_opt* opt)
@@ -2885,12 +2895,8 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
 			copy_pathspec(&revs->diffopt.pathspec,
 				      &revs->prune_data);
 	}
-	if (revs->combine_merges && revs->ignore_merges < 0)
-		revs->ignore_merges = 0;
-	if (revs->ignore_merges < 0)
-		revs->ignore_merges = 1;
-	if (revs->combined_all_paths && !revs->combine_merges)
-		die("--combined-all-paths makes no sense without -c or --cc");
+
+	setup_diff_merges_revs(revs);
 
 	revs->diffopt.abbrev = revs->abbrev;
 
-- 
2.25.1


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

* [PATCH v2 03/33] revision: factor out initialization of diff-merge related settings
  2020-12-16 18:48 ` [PATCH v2 00/33] " Sergey Organov
  2020-12-16 18:48   ` [PATCH v2 01/33] revision: factor out parsing of diff-merge related options Sergey Organov
  2020-12-16 18:48   ` [PATCH v2 02/33] revision: factor out setup of diff-merge related settings Sergey Organov
@ 2020-12-16 18:48   ` Sergey Organov
  2020-12-16 18:49   ` [PATCH v2 04/33] revision: provide implementation for diff merges tweaks Sergey Organov
                     ` (30 subsequent siblings)
  33 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-12-16 18:48 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Jeff King, Philip Oakley, Elijah Newren, git, Sergey Organov

Move initialization code related to diffing merges into new
init_diff_merge_revs() function.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 revision.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/revision.c b/revision.c
index e4c75d9278c4..da82663c8ce1 100644
--- a/revision.c
+++ b/revision.c
@@ -1805,6 +1805,8 @@ static int add_parents_only(struct rev_info *revs, const char *arg_, int flags,
 	return 1;
 }
 
+static void init_diff_merge_revs(struct rev_info *revs);
+
 void repo_init_revisions(struct repository *r,
 			 struct rev_info *revs,
 			 const char *prefix)
@@ -1813,7 +1815,7 @@ void repo_init_revisions(struct repository *r,
 
 	revs->repo = r;
 	revs->abbrev = DEFAULT_ABBREV;
-	revs->ignore_merges = -1;
+	init_diff_merge_revs(revs);
 	revs->simplify_history = 1;
 	revs->pruning.repo = r;
 	revs->pruning.flags.recursive = 1;
@@ -2153,6 +2155,10 @@ static void add_message_grep(struct rev_info *revs, const char *pattern)
 	add_grep(revs, pattern, GREP_PATTERN_BODY);
 }
 
+static void init_diff_merge_revs(struct rev_info *revs) {
+	revs->ignore_merges = -1;
+}
+
 static int parse_diff_merge_opts(struct rev_info *revs, const char **argv) {
 	int argcount = 1;
 	const char *optarg;
-- 
2.25.1


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

* [PATCH v2 04/33] revision: provide implementation for diff merges tweaks
  2020-12-16 18:48 ` [PATCH v2 00/33] " Sergey Organov
                     ` (2 preceding siblings ...)
  2020-12-16 18:48   ` [PATCH v2 03/33] revision: factor out initialization " Sergey Organov
@ 2020-12-16 18:49   ` Sergey Organov
  2020-12-16 18:49   ` [PATCH v2 05/33] revision: move diff merges functions to its own diff-merges.c Sergey Organov
                     ` (29 subsequent siblings)
  33 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-12-16 18:49 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Jeff King, Philip Oakley, Elijah Newren, git, Sergey Organov

Use these implementations from show_setup_revisions_tweak() and
log_setup_revisions_tweak() in builtin/log.c.

This completes moving of management of diff merges parameters to a
single place, where we can finally observe them simultaneously.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 builtin/log.c | 13 ++-----------
 revision.c    | 17 +++++++++++++++++
 revision.h    |  3 +++
 3 files changed, 22 insertions(+), 11 deletions(-)

diff --git a/builtin/log.c b/builtin/log.c
index 0a7ed4bef92b..717855a49e90 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -598,15 +598,7 @@ static int show_tree_object(const struct object_id *oid,
 static void show_setup_revisions_tweak(struct rev_info *rev,
 				       struct setup_revision_opt *opt)
 {
-	if (rev->ignore_merges < 0) {
-		/* There was no "-m" variant on the command line */
-		rev->ignore_merges = 0;
-		if (!rev->first_parent_only && !rev->combine_merges) {
-			/* No "--first-parent", "-c", or "--cc" */
-			rev->combine_merges = 1;
-			rev->dense_combined_merges = 1;
-		}
-	}
+	rev_diff_merges_default_to_dense_combined(rev);
 	if (!rev->diffopt.output_format)
 		rev->diffopt.output_format = DIFF_FORMAT_PATCH;
 }
@@ -731,8 +723,7 @@ static void log_setup_revisions_tweak(struct rev_info *rev,
 	if (!rev->diffopt.output_format && rev->combine_merges)
 		rev->diffopt.output_format = DIFF_FORMAT_PATCH;
 
-	if (rev->first_parent_only && rev->ignore_merges < 0)
-		rev->ignore_merges = 0;
+	rev_diff_merges_first_parent_defaults_to_enable(rev);
 }
 
 int cmd_log(int argc, const char **argv, const char *prefix)
diff --git a/revision.c b/revision.c
index da82663c8ce1..7b5b59a3c848 100644
--- a/revision.c
+++ b/revision.c
@@ -2207,6 +2207,23 @@ static void setup_diff_merges_revs(struct rev_info *revs)
 		die("--combined-all-paths makes no sense without -c or --cc");
 }
 
+void rev_diff_merges_first_parent_defaults_to_enable(struct rev_info *revs) {
+	if (revs->first_parent_only && revs->ignore_merges < 0)
+		revs->ignore_merges = 0;
+}
+
+void rev_diff_merges_default_to_dense_combined(struct rev_info *revs) {
+	if (revs->ignore_merges < 0) {
+		/* There was no "-m" variant on the command line */
+		revs->ignore_merges = 0;
+		if (!revs->first_parent_only && !revs->combine_merges) {
+			/* No "--first-parent", "-c", or "--cc" */
+			revs->combine_merges = 1;
+			revs->dense_combined_merges = 1;
+		}
+	}
+}
+
 static int handle_revision_opt(struct rev_info *revs, int argc, const char **argv,
 			       int *unkc, const char **unkv,
 			       const struct setup_revision_opt* opt)
diff --git a/revision.h b/revision.h
index f6bf860d19e5..3dd0229f4edc 100644
--- a/revision.h
+++ b/revision.h
@@ -456,4 +456,7 @@ int rewrite_parents(struct rev_info *revs,
  */
 struct commit_list *get_saved_parents(struct rev_info *revs, const struct commit *commit);
 
+void rev_diff_merges_default_to_dense_combined(struct rev_info *revs);
+void rev_diff_merges_first_parent_defaults_to_enable(struct rev_info *revs);
+
 #endif
-- 
2.25.1


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

* [PATCH v2 05/33] revision: move diff merges functions to its own diff-merges.c
  2020-12-16 18:48 ` [PATCH v2 00/33] " Sergey Organov
                     ` (3 preceding siblings ...)
  2020-12-16 18:49   ` [PATCH v2 04/33] revision: provide implementation for diff merges tweaks Sergey Organov
@ 2020-12-16 18:49   ` Sergey Organov
  2020-12-16 18:49   ` [PATCH v2 06/33] diff-merges: rename all functions to have common prefix Sergey Organov
                     ` (28 subsequent siblings)
  33 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-12-16 18:49 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Jeff King, Philip Oakley, Elijah Newren, git, Sergey Organov

Create separate diff-merges.c and diff-merges.h files, and move all
the code related to handling of diff merges there.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 Makefile      |  1 +
 builtin/log.c |  1 +
 diff-merges.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++
 diff-merges.h | 18 +++++++++++++
 revision.c    | 72 +--------------------------------------------------
 revision.h    |  3 ---
 6 files changed, 93 insertions(+), 74 deletions(-)
 create mode 100644 diff-merges.c
 create mode 100644 diff-merges.h

diff --git a/Makefile b/Makefile
index 1fb0ec17059a..d1347ef262cf 100644
--- a/Makefile
+++ b/Makefile
@@ -872,6 +872,7 @@ LIB_OBJS += date.o
 LIB_OBJS += decorate.o
 LIB_OBJS += delta-islands.o
 LIB_OBJS += diff-delta.o
+LIB_OBJS += diff-merges.o
 LIB_OBJS += diff-lib.o
 LIB_OBJS += diff-no-index.o
 LIB_OBJS += diff.o
diff --git a/builtin/log.c b/builtin/log.c
index 717855a49e90..ad3092fdd854 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -12,6 +12,7 @@
 #include "color.h"
 #include "commit.h"
 #include "diff.h"
+#include "diff-merges.h"
 #include "revision.h"
 #include "log-tree.h"
 #include "builtin.h"
diff --git a/diff-merges.c b/diff-merges.c
new file mode 100644
index 000000000000..eb25bcca2494
--- /dev/null
+++ b/diff-merges.c
@@ -0,0 +1,72 @@
+#include "diff-merges.h"
+
+#include "revision.h"
+
+void init_diff_merge_revs(struct rev_info *revs) {
+	revs->ignore_merges = -1;
+}
+
+int parse_diff_merge_opts(struct rev_info *revs, const char **argv) {
+	int argcount = 1;
+	const char *optarg;
+	const char *arg = argv[0];
+
+	if (!strcmp(arg, "-m")) {
+		/*
+		 * To "diff-index", "-m" means "match missing", and to the "log"
+		 * family of commands, it means "show full diff for merges". Set
+		 * both fields appropriately.
+		 */
+		revs->ignore_merges = 0;
+		revs->match_missing = 1;
+	} else if (!strcmp(arg, "-c")) {
+		revs->diff = 1;
+		revs->dense_combined_merges = 0;
+		revs->combine_merges = 1;
+	} else if (!strcmp(arg, "--cc")) {
+		revs->diff = 1;
+		revs->dense_combined_merges = 1;
+		revs->combine_merges = 1;
+	} else if (!strcmp(arg, "--no-diff-merges")) {
+		revs->ignore_merges = 1;
+	} else if (!strcmp(arg, "--combined-all-paths")) {
+		revs->diff = 1;
+		revs->combined_all_paths = 1;
+	} else if ((argcount = parse_long_opt("diff-merges", argv, &optarg))) {
+		if (!strcmp(optarg, "off")) {
+			revs->ignore_merges = 1;
+		} else {
+			die(_("unknown value for --diff-merges: %s"), optarg);
+		}
+	} else
+		argcount = 0;
+
+	return argcount;
+}
+
+void setup_diff_merges_revs(struct rev_info *revs)
+{
+	if (revs->combine_merges && revs->ignore_merges < 0)
+		revs->ignore_merges = 0;
+	if (revs->ignore_merges < 0)
+		revs->ignore_merges = 1;
+	if (revs->combined_all_paths && !revs->combine_merges)
+		die("--combined-all-paths makes no sense without -c or --cc");
+}
+
+void rev_diff_merges_first_parent_defaults_to_enable(struct rev_info *revs) {
+	if (revs->first_parent_only && revs->ignore_merges < 0)
+		revs->ignore_merges = 0;
+}
+
+void rev_diff_merges_default_to_dense_combined(struct rev_info *revs) {
+	if (revs->ignore_merges < 0) {
+		/* There was no "-m" variant on the command line */
+		revs->ignore_merges = 0;
+		if (!revs->first_parent_only && !revs->combine_merges) {
+			/* No "--first-parent", "-c", or "--cc" */
+			revs->combine_merges = 1;
+			revs->dense_combined_merges = 1;
+		}
+	}
+}
diff --git a/diff-merges.h b/diff-merges.h
new file mode 100644
index 000000000000..7e970b266cf5
--- /dev/null
+++ b/diff-merges.h
@@ -0,0 +1,18 @@
+#ifndef DIFF_MERGES_H
+#define DIFF_MERGES_H
+
+/*
+ * diff-merges - utility module to handle command-line options for
+ * selection of particular diff format of merge commits
+ * representation.
+ */
+
+struct rev_info;
+
+void init_diff_merge_revs(struct rev_info *revs);
+int parse_diff_merge_opts(struct rev_info *revs, const char **argv);
+void setup_diff_merges_revs(struct rev_info *revs);
+void rev_diff_merges_default_to_dense_combined(struct rev_info *revs);
+void rev_diff_merges_first_parent_defaults_to_enable(struct rev_info *revs);
+
+#endif
diff --git a/revision.c b/revision.c
index 7b5b59a3c848..4bc14a08a624 100644
--- a/revision.c
+++ b/revision.c
@@ -5,6 +5,7 @@
 #include "tree.h"
 #include "commit.h"
 #include "diff.h"
+#include "diff-merges.h"
 #include "refs.h"
 #include "revision.h"
 #include "repository.h"
@@ -1805,8 +1806,6 @@ static int add_parents_only(struct rev_info *revs, const char *arg_, int flags,
 	return 1;
 }
 
-static void init_diff_merge_revs(struct rev_info *revs);
-
 void repo_init_revisions(struct repository *r,
 			 struct rev_info *revs,
 			 const char *prefix)
@@ -2155,75 +2154,6 @@ static void add_message_grep(struct rev_info *revs, const char *pattern)
 	add_grep(revs, pattern, GREP_PATTERN_BODY);
 }
 
-static void init_diff_merge_revs(struct rev_info *revs) {
-	revs->ignore_merges = -1;
-}
-
-static int parse_diff_merge_opts(struct rev_info *revs, const char **argv) {
-	int argcount = 1;
-	const char *optarg;
-	const char *arg = argv[0];
-
-	if (!strcmp(arg, "-m")) {
-		/*
-		 * To "diff-index", "-m" means "match missing", and to the "log"
-		 * family of commands, it means "show full diff for merges". Set
-		 * both fields appropriately.
-		 */
-		revs->ignore_merges = 0;
-		revs->match_missing = 1;
-	} else if (!strcmp(arg, "-c")) {
-		revs->diff = 1;
-		revs->dense_combined_merges = 0;
-		revs->combine_merges = 1;
-	} else if (!strcmp(arg, "--cc")) {
-		revs->diff = 1;
-		revs->dense_combined_merges = 1;
-		revs->combine_merges = 1;
-	} else if (!strcmp(arg, "--no-diff-merges")) {
-		revs->ignore_merges = 1;
-	} else if (!strcmp(arg, "--combined-all-paths")) {
-		revs->diff = 1;
-		revs->combined_all_paths = 1;
-	} else if ((argcount = parse_long_opt("diff-merges", argv, &optarg))) {
-		if (!strcmp(optarg, "off")) {
-			revs->ignore_merges = 1;
-		} else {
-			die(_("unknown value for --diff-merges: %s"), optarg);
-		}
-	} else
-		argcount = 0;
-
-	return argcount;
-}
-
-static void setup_diff_merges_revs(struct rev_info *revs)
-{
-	if (revs->combine_merges && revs->ignore_merges < 0)
-		revs->ignore_merges = 0;
-	if (revs->ignore_merges < 0)
-		revs->ignore_merges = 1;
-	if (revs->combined_all_paths && !revs->combine_merges)
-		die("--combined-all-paths makes no sense without -c or --cc");
-}
-
-void rev_diff_merges_first_parent_defaults_to_enable(struct rev_info *revs) {
-	if (revs->first_parent_only && revs->ignore_merges < 0)
-		revs->ignore_merges = 0;
-}
-
-void rev_diff_merges_default_to_dense_combined(struct rev_info *revs) {
-	if (revs->ignore_merges < 0) {
-		/* There was no "-m" variant on the command line */
-		revs->ignore_merges = 0;
-		if (!revs->first_parent_only && !revs->combine_merges) {
-			/* No "--first-parent", "-c", or "--cc" */
-			revs->combine_merges = 1;
-			revs->dense_combined_merges = 1;
-		}
-	}
-}
-
 static int handle_revision_opt(struct rev_info *revs, int argc, const char **argv,
 			       int *unkc, const char **unkv,
 			       const struct setup_revision_opt* opt)
diff --git a/revision.h b/revision.h
index 3dd0229f4edc..f6bf860d19e5 100644
--- a/revision.h
+++ b/revision.h
@@ -456,7 +456,4 @@ int rewrite_parents(struct rev_info *revs,
  */
 struct commit_list *get_saved_parents(struct rev_info *revs, const struct commit *commit);
 
-void rev_diff_merges_default_to_dense_combined(struct rev_info *revs);
-void rev_diff_merges_first_parent_defaults_to_enable(struct rev_info *revs);
-
 #endif
-- 
2.25.1


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

* [PATCH v2 06/33] diff-merges: rename all functions to have common prefix
  2020-12-16 18:48 ` [PATCH v2 00/33] " Sergey Organov
                     ` (4 preceding siblings ...)
  2020-12-16 18:49   ` [PATCH v2 05/33] revision: move diff merges functions to its own diff-merges.c Sergey Organov
@ 2020-12-16 18:49   ` Sergey Organov
  2020-12-16 18:49   ` [PATCH v2 07/33] diff-merges: move checks for first_parent_only out of the module Sergey Organov
                     ` (27 subsequent siblings)
  33 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-12-16 18:49 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Jeff King, Philip Oakley, Elijah Newren, git, Sergey Organov

Use the same "diff_merges" prefix for all the diff merges function
names.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 builtin/log.c |  4 ++--
 diff-merges.c | 10 +++++-----
 diff-merges.h | 15 ++++++++++-----
 revision.c    |  6 +++---
 4 files changed, 20 insertions(+), 15 deletions(-)

diff --git a/builtin/log.c b/builtin/log.c
index ad3092fdd854..77a7bba543ad 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -599,7 +599,7 @@ static int show_tree_object(const struct object_id *oid,
 static void show_setup_revisions_tweak(struct rev_info *rev,
 				       struct setup_revision_opt *opt)
 {
-	rev_diff_merges_default_to_dense_combined(rev);
+	diff_merges_default_to_dense_combined(rev);
 	if (!rev->diffopt.output_format)
 		rev->diffopt.output_format = DIFF_FORMAT_PATCH;
 }
@@ -724,7 +724,7 @@ static void log_setup_revisions_tweak(struct rev_info *rev,
 	if (!rev->diffopt.output_format && rev->combine_merges)
 		rev->diffopt.output_format = DIFF_FORMAT_PATCH;
 
-	rev_diff_merges_first_parent_defaults_to_enable(rev);
+	diff_merges_first_parent_defaults_to_enable(rev);
 }
 
 int cmd_log(int argc, const char **argv, const char *prefix)
diff --git a/diff-merges.c b/diff-merges.c
index eb25bcca2494..b647920bdb22 100644
--- a/diff-merges.c
+++ b/diff-merges.c
@@ -2,11 +2,11 @@
 
 #include "revision.h"
 
-void init_diff_merge_revs(struct rev_info *revs) {
+void diff_merges_init_revs(struct rev_info *revs) {
 	revs->ignore_merges = -1;
 }
 
-int parse_diff_merge_opts(struct rev_info *revs, const char **argv) {
+int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {
 	int argcount = 1;
 	const char *optarg;
 	const char *arg = argv[0];
@@ -44,7 +44,7 @@ int parse_diff_merge_opts(struct rev_info *revs, const char **argv) {
 	return argcount;
 }
 
-void setup_diff_merges_revs(struct rev_info *revs)
+void diff_merges_setup_revs(struct rev_info *revs)
 {
 	if (revs->combine_merges && revs->ignore_merges < 0)
 		revs->ignore_merges = 0;
@@ -54,12 +54,12 @@ void setup_diff_merges_revs(struct rev_info *revs)
 		die("--combined-all-paths makes no sense without -c or --cc");
 }
 
-void rev_diff_merges_first_parent_defaults_to_enable(struct rev_info *revs) {
+void diff_merges_first_parent_defaults_to_enable(struct rev_info *revs) {
 	if (revs->first_parent_only && revs->ignore_merges < 0)
 		revs->ignore_merges = 0;
 }
 
-void rev_diff_merges_default_to_dense_combined(struct rev_info *revs) {
+void diff_merges_default_to_dense_combined(struct rev_info *revs) {
 	if (revs->ignore_merges < 0) {
 		/* There was no "-m" variant on the command line */
 		revs->ignore_merges = 0;
diff --git a/diff-merges.h b/diff-merges.h
index 7e970b266cf5..4ced909b795e 100644
--- a/diff-merges.h
+++ b/diff-merges.h
@@ -9,10 +9,15 @@
 
 struct rev_info;
 
-void init_diff_merge_revs(struct rev_info *revs);
-int parse_diff_merge_opts(struct rev_info *revs, const char **argv);
-void setup_diff_merges_revs(struct rev_info *revs);
-void rev_diff_merges_default_to_dense_combined(struct rev_info *revs);
-void rev_diff_merges_first_parent_defaults_to_enable(struct rev_info *revs);
+void diff_merges_init_revs(struct rev_info *revs);
+
+int diff_merges_parse_opts(struct rev_info *revs, const char **argv);
+
+void diff_merges_setup_revs(struct rev_info *revs);
+
+void diff_merges_default_to_dense_combined(struct rev_info *revs);
+
+void diff_merges_first_parent_defaults_to_enable(struct rev_info *revs);
+
 
 #endif
diff --git a/revision.c b/revision.c
index 4bc14a08a624..5a0e3d6ad542 100644
--- a/revision.c
+++ b/revision.c
@@ -1814,7 +1814,7 @@ void repo_init_revisions(struct repository *r,
 
 	revs->repo = r;
 	revs->abbrev = DEFAULT_ABBREV;
-	init_diff_merge_revs(revs);
+	diff_merges_init_revs(revs);
 	revs->simplify_history = 1;
 	revs->pruning.repo = r;
 	revs->pruning.flags.recursive = 1;
@@ -2350,7 +2350,7 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
 		revs->diff = 1;
 		revs->diffopt.flags.recursive = 1;
 		revs->diffopt.flags.tree_in_recursive = 1;
-	} else if ((argcount = parse_diff_merge_opts(revs, argv))) {
+	} else if ((argcount = diff_merges_parse_opts(revs, argv))) {
 		return argcount;
 	} else if (!strcmp(arg, "-v")) {
 		revs->verbose_header = 1;
@@ -2849,7 +2849,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
 				      &revs->prune_data);
 	}
 
-	setup_diff_merges_revs(revs);
+	diff_merges_setup_revs(revs);
 
 	revs->diffopt.abbrev = revs->abbrev;
 
-- 
2.25.1


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

* [PATCH v2 07/33] diff-merges: move checks for first_parent_only out of the module
  2020-12-16 18:48 ` [PATCH v2 00/33] " Sergey Organov
                     ` (5 preceding siblings ...)
  2020-12-16 18:49   ` [PATCH v2 06/33] diff-merges: rename all functions to have common prefix Sergey Organov
@ 2020-12-16 18:49   ` Sergey Organov
  2020-12-16 18:49   ` [PATCH v2 08/33] diff-merges: rename diff_merges_default_to_enable() to match semantics Sergey Organov
                     ` (26 subsequent siblings)
  33 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-12-16 18:49 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Jeff King, Philip Oakley, Elijah Newren, git, Sergey Organov

The checks for first_parent_only don't in fact belong to this module,
as the primary purpose of this flag is history traversal limiting, so
get it out of this module and rename the

diff_merges_first_parent_defaults_to_enable()

to

diff_merges_default_to_enable()

to match new semantics.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 builtin/log.c |  8 ++++++--
 diff-merges.c | 10 ++++------
 diff-merges.h |  2 +-
 3 files changed, 11 insertions(+), 9 deletions(-)

diff --git a/builtin/log.c b/builtin/log.c
index 77a7bba543ad..a7791c003c91 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -599,7 +599,10 @@ static int show_tree_object(const struct object_id *oid,
 static void show_setup_revisions_tweak(struct rev_info *rev,
 				       struct setup_revision_opt *opt)
 {
-	diff_merges_default_to_dense_combined(rev);
+	if (rev->first_parent_only)
+		diff_merges_default_to_enable(rev);
+	else
+		diff_merges_default_to_dense_combined(rev);
 	if (!rev->diffopt.output_format)
 		rev->diffopt.output_format = DIFF_FORMAT_PATCH;
 }
@@ -724,7 +727,8 @@ static void log_setup_revisions_tweak(struct rev_info *rev,
 	if (!rev->diffopt.output_format && rev->combine_merges)
 		rev->diffopt.output_format = DIFF_FORMAT_PATCH;
 
-	diff_merges_first_parent_defaults_to_enable(rev);
+	if (rev->first_parent_only)
+		diff_merges_default_to_enable(rev);
 }
 
 int cmd_log(int argc, const char **argv, const char *prefix)
diff --git a/diff-merges.c b/diff-merges.c
index b647920bdb22..f0d0ae208213 100644
--- a/diff-merges.c
+++ b/diff-merges.c
@@ -54,17 +54,15 @@ void diff_merges_setup_revs(struct rev_info *revs)
 		die("--combined-all-paths makes no sense without -c or --cc");
 }
 
-void diff_merges_first_parent_defaults_to_enable(struct rev_info *revs) {
-	if (revs->first_parent_only && revs->ignore_merges < 0)
+void diff_merges_default_to_enable(struct rev_info *revs) {
+	if (revs->ignore_merges < 0)		/* No -m */
 		revs->ignore_merges = 0;
 }
 
 void diff_merges_default_to_dense_combined(struct rev_info *revs) {
-	if (revs->ignore_merges < 0) {
-		/* There was no "-m" variant on the command line */
+	if (revs->ignore_merges < 0) {		/* No -m */
 		revs->ignore_merges = 0;
-		if (!revs->first_parent_only && !revs->combine_merges) {
-			/* No "--first-parent", "-c", or "--cc" */
+		if (!revs->combine_merges) {	/* No -c/--cc" */
 			revs->combine_merges = 1;
 			revs->dense_combined_merges = 1;
 		}
diff --git a/diff-merges.h b/diff-merges.h
index 4ced909b795e..6937d46219f1 100644
--- a/diff-merges.h
+++ b/diff-merges.h
@@ -17,7 +17,7 @@ void diff_merges_setup_revs(struct rev_info *revs);
 
 void diff_merges_default_to_dense_combined(struct rev_info *revs);
 
-void diff_merges_first_parent_defaults_to_enable(struct rev_info *revs);
+void diff_merges_default_to_enable(struct rev_info *revs);
 
 
 #endif
-- 
2.25.1


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

* [PATCH v2 08/33] diff-merges: rename diff_merges_default_to_enable() to match semantics
  2020-12-16 18:48 ` [PATCH v2 00/33] " Sergey Organov
                     ` (6 preceding siblings ...)
  2020-12-16 18:49   ` [PATCH v2 07/33] diff-merges: move checks for first_parent_only out of the module Sergey Organov
@ 2020-12-16 18:49   ` Sergey Organov
  2020-12-16 18:49   ` [PATCH v2 09/33] diff-merges: re-arrange functions to match the order they are called in Sergey Organov
                     ` (25 subsequent siblings)
  33 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-12-16 18:49 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Jeff King, Philip Oakley, Elijah Newren, git, Sergey Organov

Rename diff_merges_default_to_enable() to
diff_merges_default_to_first_parent() to match its semantics.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 builtin/log.c | 4 ++--
 diff-merges.c | 2 +-
 diff-merges.h | 2 +-
 3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/builtin/log.c b/builtin/log.c
index a7791c003c91..63875c3aeec9 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -600,7 +600,7 @@ static void show_setup_revisions_tweak(struct rev_info *rev,
 				       struct setup_revision_opt *opt)
 {
 	if (rev->first_parent_only)
-		diff_merges_default_to_enable(rev);
+		diff_merges_default_to_first_parent(rev);
 	else
 		diff_merges_default_to_dense_combined(rev);
 	if (!rev->diffopt.output_format)
@@ -728,7 +728,7 @@ static void log_setup_revisions_tweak(struct rev_info *rev,
 		rev->diffopt.output_format = DIFF_FORMAT_PATCH;
 
 	if (rev->first_parent_only)
-		diff_merges_default_to_enable(rev);
+		diff_merges_default_to_first_parent(rev);
 }
 
 int cmd_log(int argc, const char **argv, const char *prefix)
diff --git a/diff-merges.c b/diff-merges.c
index f0d0ae208213..19b85bfdba6f 100644
--- a/diff-merges.c
+++ b/diff-merges.c
@@ -54,7 +54,7 @@ void diff_merges_setup_revs(struct rev_info *revs)
 		die("--combined-all-paths makes no sense without -c or --cc");
 }
 
-void diff_merges_default_to_enable(struct rev_info *revs) {
+void diff_merges_default_to_first_parent(struct rev_info *revs) {
 	if (revs->ignore_merges < 0)		/* No -m */
 		revs->ignore_merges = 0;
 }
diff --git a/diff-merges.h b/diff-merges.h
index 6937d46219f1..18861dc5480e 100644
--- a/diff-merges.h
+++ b/diff-merges.h
@@ -17,7 +17,7 @@ void diff_merges_setup_revs(struct rev_info *revs);
 
 void diff_merges_default_to_dense_combined(struct rev_info *revs);
 
-void diff_merges_default_to_enable(struct rev_info *revs);
+void diff_merges_default_to_first_parent(struct rev_info *revs);
 
 
 #endif
-- 
2.25.1


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

* [PATCH v2 09/33] diff-merges: re-arrange functions to match the order they are called in
  2020-12-16 18:48 ` [PATCH v2 00/33] " Sergey Organov
                     ` (7 preceding siblings ...)
  2020-12-16 18:49   ` [PATCH v2 08/33] diff-merges: rename diff_merges_default_to_enable() to match semantics Sergey Organov
@ 2020-12-16 18:49   ` Sergey Organov
  2020-12-16 18:49   ` [PATCH v2 10/33] diff-merges: new function diff_merges_suppress() Sergey Organov
                     ` (24 subsequent siblings)
  33 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-12-16 18:49 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Jeff King, Philip Oakley, Elijah Newren, git, Sergey Organov

For clarity, define public functions in the order they are called, to
make logic inter-dependencies easier to grok.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 diff-merges.c | 24 ++++++++++++++----------
 diff-merges.h |  7 +++----
 2 files changed, 17 insertions(+), 14 deletions(-)

diff --git a/diff-merges.c b/diff-merges.c
index 19b85bfdba6f..a3b732c34717 100644
--- a/diff-merges.c
+++ b/diff-merges.c
@@ -2,6 +2,10 @@
 
 #include "revision.h"
 
+/*
+ * Public functions. They are in the order they are called.
+ */
+
 void diff_merges_init_revs(struct rev_info *revs) {
 	revs->ignore_merges = -1;
 }
@@ -44,16 +48,6 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {
 	return argcount;
 }
 
-void diff_merges_setup_revs(struct rev_info *revs)
-{
-	if (revs->combine_merges && revs->ignore_merges < 0)
-		revs->ignore_merges = 0;
-	if (revs->ignore_merges < 0)
-		revs->ignore_merges = 1;
-	if (revs->combined_all_paths && !revs->combine_merges)
-		die("--combined-all-paths makes no sense without -c or --cc");
-}
-
 void diff_merges_default_to_first_parent(struct rev_info *revs) {
 	if (revs->ignore_merges < 0)		/* No -m */
 		revs->ignore_merges = 0;
@@ -68,3 +62,13 @@ void diff_merges_default_to_dense_combined(struct rev_info *revs) {
 		}
 	}
 }
+
+void diff_merges_setup_revs(struct rev_info *revs)
+{
+	if (revs->combine_merges && revs->ignore_merges < 0)
+		revs->ignore_merges = 0;
+	if (revs->ignore_merges < 0)
+		revs->ignore_merges = 1;
+	if (revs->combined_all_paths && !revs->combine_merges)
+		die("--combined-all-paths makes no sense without -c or --cc");
+}
diff --git a/diff-merges.h b/diff-merges.h
index 18861dc5480e..243ef915c4cd 100644
--- a/diff-merges.h
+++ b/diff-merges.h
@@ -13,11 +13,10 @@ void diff_merges_init_revs(struct rev_info *revs);
 
 int diff_merges_parse_opts(struct rev_info *revs, const char **argv);
 
-void diff_merges_setup_revs(struct rev_info *revs);
-
-void diff_merges_default_to_dense_combined(struct rev_info *revs);
-
 void diff_merges_default_to_first_parent(struct rev_info *revs);
 
+void diff_merges_default_to_dense_combined(struct rev_info *revs);
+
+void diff_merges_setup_revs(struct rev_info *revs);
 
 #endif
-- 
2.25.1


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

* [PATCH v2 10/33] diff-merges: new function diff_merges_suppress()
  2020-12-16 18:48 ` [PATCH v2 00/33] " Sergey Organov
                     ` (8 preceding siblings ...)
  2020-12-16 18:49   ` [PATCH v2 09/33] diff-merges: re-arrange functions to match the order they are called in Sergey Organov
@ 2020-12-16 18:49   ` Sergey Organov
  2020-12-16 18:49   ` [PATCH v2 11/33] diff-merges: new function diff_merges_set_dense_combined_if_unset() Sergey Organov
                     ` (23 subsequent siblings)
  33 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-12-16 18:49 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Jeff King, Philip Oakley, Elijah Newren, git, Sergey Organov

This function sets all the relevant flags to disabled state, so that
no code that checks only one of them get it wrong.

Then we call this new function everywhere where diff merges output
suppression is needed.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 builtin/merge.c |  3 ++-
 diff-merges.c   | 15 +++++++++++++--
 diff-merges.h   |  2 ++
 fmt-merge-msg.c |  3 ++-
 4 files changed, 19 insertions(+), 4 deletions(-)

diff --git a/builtin/merge.c b/builtin/merge.c
index 9d5359edc2f7..1f7b69982b40 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -14,6 +14,7 @@
 #include "lockfile.h"
 #include "run-command.h"
 #include "diff.h"
+#include "diff-merges.h"
 #include "refs.h"
 #include "refspec.h"
 #include "commit.h"
@@ -400,7 +401,7 @@ static void squash_message(struct commit *commit, struct commit_list *remotehead
 	printf(_("Squash commit -- not updating HEAD\n"));
 
 	repo_init_revisions(the_repository, &rev, NULL);
-	rev.ignore_merges = 1;
+	diff_merges_suppress(&rev);
 	rev.commit_format = CMIT_FMT_MEDIUM;
 
 	commit->object.flags |= UNINTERESTING;
diff --git a/diff-merges.c b/diff-merges.c
index a3b732c34717..b150c0490b1d 100644
--- a/diff-merges.c
+++ b/diff-merges.c
@@ -2,6 +2,13 @@
 
 #include "revision.h"
 
+static void suppress(struct rev_info *revs) {
+	revs->ignore_merges = 1;
+	revs->first_parent_merges = 0;
+	revs->combine_merges = 0;
+	revs->dense_combined_merges = 0;
+}
+
 /*
  * Public functions. They are in the order they are called.
  */
@@ -32,13 +39,13 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {
 		revs->dense_combined_merges = 1;
 		revs->combine_merges = 1;
 	} else if (!strcmp(arg, "--no-diff-merges")) {
-		revs->ignore_merges = 1;
+		suppress(revs);
 	} else if (!strcmp(arg, "--combined-all-paths")) {
 		revs->diff = 1;
 		revs->combined_all_paths = 1;
 	} else if ((argcount = parse_long_opt("diff-merges", argv, &optarg))) {
 		if (!strcmp(optarg, "off")) {
-			revs->ignore_merges = 1;
+			suppress(revs);
 		} else {
 			die(_("unknown value for --diff-merges: %s"), optarg);
 		}
@@ -48,6 +55,10 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {
 	return argcount;
 }
 
+void diff_merges_suppress(struct rev_info *revs) {
+	suppress(revs);
+}
+
 void diff_merges_default_to_first_parent(struct rev_info *revs) {
 	if (revs->ignore_merges < 0)		/* No -m */
 		revs->ignore_merges = 0;
diff --git a/diff-merges.h b/diff-merges.h
index 243ef915c4cd..a031240576f7 100644
--- a/diff-merges.h
+++ b/diff-merges.h
@@ -13,6 +13,8 @@ void diff_merges_init_revs(struct rev_info *revs);
 
 int diff_merges_parse_opts(struct rev_info *revs, const char **argv);
 
+void diff_merges_suppress(struct rev_info *revs);
+
 void diff_merges_default_to_first_parent(struct rev_info *revs);
 
 void diff_merges_default_to_dense_combined(struct rev_info *revs);
diff --git a/fmt-merge-msg.c b/fmt-merge-msg.c
index bd22e1ea8865..abc3403fb820 100644
--- a/fmt-merge-msg.c
+++ b/fmt-merge-msg.c
@@ -2,6 +2,7 @@
 #include "refs.h"
 #include "object-store.h"
 #include "diff.h"
+#include "diff-merges.h"
 #include "revision.h"
 #include "tag.h"
 #include "string-list.h"
@@ -668,7 +669,7 @@ int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
 		head = lookup_commit_or_die(&head_oid, "HEAD");
 		repo_init_revisions(the_repository, &rev, NULL);
 		rev.commit_format = CMIT_FMT_ONELINE;
-		rev.ignore_merges = 1;
+		diff_merges_suppress(&rev);
 		rev.limited = 1;
 
 		strbuf_complete_line(out);
-- 
2.25.1


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

* [PATCH v2 11/33] diff-merges: new function diff_merges_set_dense_combined_if_unset()
  2020-12-16 18:48 ` [PATCH v2 00/33] " Sergey Organov
                     ` (9 preceding siblings ...)
  2020-12-16 18:49   ` [PATCH v2 10/33] diff-merges: new function diff_merges_suppress() Sergey Organov
@ 2020-12-16 18:49   ` Sergey Organov
  2020-12-16 18:49   ` [PATCH v2 12/33] diff-merges: introduce revs->first_parent_merges flag Sergey Organov
                     ` (22 subsequent siblings)
  33 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-12-16 18:49 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Jeff King, Philip Oakley, Elijah Newren, git, Sergey Organov

Call it where given functionality is needed instead of direct
checking/tweaking of diff merges related fields.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 builtin/diff-files.c |  5 +++--
 builtin/diff.c       |  9 +++++----
 diff-merges.c        | 14 ++++++++++++--
 diff-merges.h        |  2 ++
 4 files changed, 22 insertions(+), 8 deletions(-)

diff --git a/builtin/diff-files.c b/builtin/diff-files.c
index 1e352dd8f77c..4742a4559b21 100644
--- a/builtin/diff-files.c
+++ b/builtin/diff-files.c
@@ -7,6 +7,7 @@
 #include "cache.h"
 #include "config.h"
 #include "diff.h"
+#include "diff-merges.h"
 #include "commit.h"
 #include "revision.h"
 #include "builtin.h"
@@ -69,9 +70,9 @@ int cmd_diff_files(int argc, const char **argv, const char *prefix)
 	 * was not asked to.  "diff-files -c -p" should not densify
 	 * (the user should ask with "diff-files --cc" explicitly).
 	 */
-	if (rev.max_count == -1 && !rev.combine_merges &&
+	if (rev.max_count == -1 &&
 	    (rev.diffopt.output_format & DIFF_FORMAT_PATCH))
-		rev.combine_merges = rev.dense_combined_merges = 1;
+		diff_merges_set_dense_combined_if_unset(&rev);
 
 	if (read_cache_preload(&rev.diffopt.pathspec) < 0) {
 		perror("read_cache_preload");
diff --git a/builtin/diff.c b/builtin/diff.c
index cd4083fed96e..2f570a3131cb 100644
--- a/builtin/diff.c
+++ b/builtin/diff.c
@@ -13,6 +13,7 @@
 #include "blob.h"
 #include "tag.h"
 #include "diff.h"
+#include "diff-merges.h"
 #include "diffcore.h"
 #include "revision.h"
 #include "log-tree.h"
@@ -199,8 +200,8 @@ static int builtin_diff_combined(struct rev_info *revs,
 	if (argc > 1)
 		usage(builtin_diff_usage);
 
-	if (!revs->dense_combined_merges && !revs->combine_merges)
-		revs->dense_combined_merges = revs->combine_merges = 1;
+	diff_merges_set_dense_combined_if_unset(revs);
+
 	for (i = 1; i < ents; i++)
 		oid_array_append(&parents, &ent[i].item->oid);
 	diff_tree_combined(&ent[0].item->oid, &parents, revs);
@@ -248,9 +249,9 @@ static int builtin_diff_files(struct rev_info *revs, int argc, const char **argv
 	 * dense one, --cc can be explicitly asked for, or just rely
 	 * on the default).
 	 */
-	if (revs->max_count == -1 && !revs->combine_merges &&
+	if (revs->max_count == -1 &&
 	    (revs->diffopt.output_format & DIFF_FORMAT_PATCH))
-		revs->combine_merges = revs->dense_combined_merges = 1;
+		diff_merges_set_dense_combined_if_unset(revs);
 
 	setup_work_tree();
 	if (read_cache_preload(&revs->diffopt.pathspec) < 0) {
diff --git a/diff-merges.c b/diff-merges.c
index b150c0490b1d..899f9e905d3c 100644
--- a/diff-merges.c
+++ b/diff-merges.c
@@ -9,6 +9,12 @@ static void suppress(struct rev_info *revs) {
 	revs->dense_combined_merges = 0;
 }
 
+static void set_dense_combined(struct rev_info *revs) {
+	revs->combine_merges = 1;
+	revs->dense_combined_merges = 1;
+}
+
+
 /*
  * Public functions. They are in the order they are called.
  */
@@ -36,8 +42,7 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {
 		revs->combine_merges = 1;
 	} else if (!strcmp(arg, "--cc")) {
 		revs->diff = 1;
-		revs->dense_combined_merges = 1;
-		revs->combine_merges = 1;
+		set_dense_combined(revs);
 	} else if (!strcmp(arg, "--no-diff-merges")) {
 		suppress(revs);
 	} else if (!strcmp(arg, "--combined-all-paths")) {
@@ -74,6 +79,11 @@ void diff_merges_default_to_dense_combined(struct rev_info *revs) {
 	}
 }
 
+void diff_merges_set_dense_combined_if_unset(struct rev_info *revs) {
+	if (!revs->combine_merges)
+		set_dense_combined(revs);
+}
+
 void diff_merges_setup_revs(struct rev_info *revs)
 {
 	if (revs->combine_merges && revs->ignore_merges < 0)
diff --git a/diff-merges.h b/diff-merges.h
index a031240576f7..f92de137d3a0 100644
--- a/diff-merges.h
+++ b/diff-merges.h
@@ -19,6 +19,8 @@ void diff_merges_default_to_first_parent(struct rev_info *revs);
 
 void diff_merges_default_to_dense_combined(struct rev_info *revs);
 
+void diff_merges_set_dense_combined_if_unset(struct rev_info *revs);
+
 void diff_merges_setup_revs(struct rev_info *revs);
 
 #endif
-- 
2.25.1


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

* [PATCH v2 12/33] diff-merges: introduce revs->first_parent_merges flag
  2020-12-16 18:48 ` [PATCH v2 00/33] " Sergey Organov
                     ` (10 preceding siblings ...)
  2020-12-16 18:49   ` [PATCH v2 11/33] diff-merges: new function diff_merges_set_dense_combined_if_unset() Sergey Organov
@ 2020-12-16 18:49   ` Sergey Organov
  2020-12-16 18:49   ` [PATCH v2 13/33] diff-merges: revise revs->diff flag handling Sergey Organov
                     ` (21 subsequent siblings)
  33 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-12-16 18:49 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Jeff King, Philip Oakley, Elijah Newren, git, Sergey Organov

This new field allows us to separate format of diff for merges from
'first_parent_only' flag which primary purpose is limiting history
traversal.

This change further localizes diff format selection logic into the
diff-merges.c file.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 diff-merges.c | 2 ++
 log-tree.c    | 4 ++--
 revision.h    | 1 +
 3 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/diff-merges.c b/diff-merges.c
index 899f9e905d3c..c99d77a318dc 100644
--- a/diff-merges.c
+++ b/diff-merges.c
@@ -67,6 +67,8 @@ void diff_merges_suppress(struct rev_info *revs) {
 void diff_merges_default_to_first_parent(struct rev_info *revs) {
 	if (revs->ignore_merges < 0)		/* No -m */
 		revs->ignore_merges = 0;
+	if (!revs->combine_merges)		/* No -c/--cc" */
+		revs->first_parent_merges = 1;
 }
 
 void diff_merges_default_to_dense_combined(struct rev_info *revs) {
diff --git a/log-tree.c b/log-tree.c
index 1927f917ce94..3fdc0fc64bfb 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -922,7 +922,7 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log
 			return 0;
 		else if (opt->combine_merges)
 			return do_diff_combined(opt, commit);
-		else if (!opt->first_parent_only) {
+		else if (!opt->first_parent_merges) {
 			/* If we show multiple diffs, show the parent info */
 			log->parent = parents->item;
 		}
@@ -941,7 +941,7 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log
 
 		/* Set up the log info for the next parent, if any.. */
 		parents = parents->next;
-		if (!parents || opt->first_parent_only)
+		if (!parents || opt->first_parent_merges)
 			break;
 		log->parent = parents->item;
 		opt->loginfo = log;
diff --git a/revision.h b/revision.h
index f6bf860d19e5..ba2aef79215e 100644
--- a/revision.h
+++ b/revision.h
@@ -194,6 +194,7 @@ struct rev_info {
 			combine_merges:1,
 			combined_all_paths:1,
 			dense_combined_merges:1,
+			first_parent_merges:1,
 			always_show_header:1;
 	int             ignore_merges:2;
 
-- 
2.25.1


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

* [PATCH v2 13/33] diff-merges: revise revs->diff flag handling
  2020-12-16 18:48 ` [PATCH v2 00/33] " Sergey Organov
                     ` (11 preceding siblings ...)
  2020-12-16 18:49   ` [PATCH v2 12/33] diff-merges: introduce revs->first_parent_merges flag Sergey Organov
@ 2020-12-16 18:49   ` Sergey Organov
  2020-12-16 18:49   ` [PATCH v2 14/33] t4013: support test_expect_failure through ':failure' magic Sergey Organov
                     ` (20 subsequent siblings)
  33 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-12-16 18:49 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Jeff King, Philip Oakley, Elijah Newren, git, Sergey Organov

Do not set revs->diff when we encounter an option that needs it, as
it'd be impossible to undo later. Besides, some other options than
what we handle here set this flag as well, and we'd interfere with
them trying to clear this flag later.

Rather set revs->diff, if finally needed, in diff_merges_setup_revs().

As an additional bonus, this also makes our code shorter.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 diff-merges.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/diff-merges.c b/diff-merges.c
index c99d77a318dc..76ddbc37bd59 100644
--- a/diff-merges.c
+++ b/diff-merges.c
@@ -37,16 +37,13 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {
 		revs->ignore_merges = 0;
 		revs->match_missing = 1;
 	} else if (!strcmp(arg, "-c")) {
-		revs->diff = 1;
 		revs->dense_combined_merges = 0;
 		revs->combine_merges = 1;
 	} else if (!strcmp(arg, "--cc")) {
-		revs->diff = 1;
 		set_dense_combined(revs);
 	} else if (!strcmp(arg, "--no-diff-merges")) {
 		suppress(revs);
 	} else if (!strcmp(arg, "--combined-all-paths")) {
-		revs->diff = 1;
 		revs->combined_all_paths = 1;
 	} else if ((argcount = parse_long_opt("diff-merges", argv, &optarg))) {
 		if (!strcmp(optarg, "off")) {
@@ -94,4 +91,6 @@ void diff_merges_setup_revs(struct rev_info *revs)
 		revs->ignore_merges = 1;
 	if (revs->combined_all_paths && !revs->combine_merges)
 		die("--combined-all-paths makes no sense without -c or --cc");
+	if (revs->combine_merges)
+		revs->diff = 1;
 }
-- 
2.25.1


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

* [PATCH v2 14/33] t4013: support test_expect_failure through ':failure' magic
  2020-12-16 18:48 ` [PATCH v2 00/33] " Sergey Organov
                     ` (12 preceding siblings ...)
  2020-12-16 18:49   ` [PATCH v2 13/33] diff-merges: revise revs->diff flag handling Sergey Organov
@ 2020-12-16 18:49   ` Sergey Organov
  2020-12-16 18:49   ` [PATCH v2 15/33] t4013: add tests for -m failing to override -c/--cc Sergey Organov
                     ` (19 subsequent siblings)
  33 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-12-16 18:49 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Jeff King, Philip Oakley, Elijah Newren, git, Sergey Organov

Add support to be able to specify expected failure, through :failure
magic, like this:

:failure cmd args

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 t/t4013-diff-various.sh | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh
index 5c7b0122b4f1..935d10ac0572 100755
--- a/t/t4013-diff-various.sh
+++ b/t/t4013-diff-various.sh
@@ -174,6 +174,7 @@ process_diffs () {
 V=$(git version | sed -e 's/^git version //' -e 's/\./\\./g')
 while read magic cmd
 do
+	status=success
 	case "$magic" in
 	'' | '#'*)
 		continue ;;
@@ -182,6 +183,10 @@ do
 		label="$magic-$cmd"
 		case "$magic" in
 		noellipses) ;;
+		failure)
+			status=failure
+			magic=
+			label="$cmd" ;;
 		*)
 			BUG "unknown magic $magic" ;;
 		esac ;;
@@ -194,7 +199,7 @@ do
 	expect="$TEST_DIRECTORY/t4013/diff.$test"
 	actual="$pfx-diff.$test"
 
-	test_expect_success "git $cmd # magic is ${magic:-(not used)}" '
+	test_expect_$status "git $cmd # magic is ${magic:-(not used)}" '
 		{
 			echo "$ git $cmd"
 			case "$magic" in
-- 
2.25.1


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

* [PATCH v2 15/33] t4013: add tests for -m failing to override -c/--cc
  2020-12-16 18:48 ` [PATCH v2 00/33] " Sergey Organov
                     ` (13 preceding siblings ...)
  2020-12-16 18:49   ` [PATCH v2 14/33] t4013: support test_expect_failure through ':failure' magic Sergey Organov
@ 2020-12-16 18:49   ` Sergey Organov
  2020-12-16 18:49   ` [PATCH v2 16/33] diff-merges: fix -m to properly " Sergey Organov
                     ` (18 subsequent siblings)
  33 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-12-16 18:49 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Jeff King, Philip Oakley, Elijah Newren, git, Sergey Organov

Logically, -m, -c, --cc specify 3 different formats for representing
merge commits, yet -m doesn't in fact override -c or --cc, that makes
no sense.

Add 2 expected to fail tests that demonstrate the problem.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 t/t4013-diff-various.sh            |   2 +
 t/t4013/diff.log_--cc_-m_-p_master | 200 +++++++++++++++++++++++++++++
 t/t4013/diff.log_-c_-m_-p_master   | 200 +++++++++++++++++++++++++++++
 3 files changed, 402 insertions(+)
 create mode 100644 t/t4013/diff.log_--cc_-m_-p_master
 create mode 100644 t/t4013/diff.log_-c_-m_-p_master

diff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh
index 935d10ac0572..64d9fce44614 100755
--- a/t/t4013-diff-various.sh
+++ b/t/t4013-diff-various.sh
@@ -329,6 +329,8 @@ log --first-parent --diff-merges=off -p master
 log -p --first-parent master
 log -m -p --first-parent master
 log -m -p master
+:failure log --cc -m -p master
+:failure log -c -m -p master
 log -SF master
 log -S F master
 log -SF -p master
diff --git a/t/t4013/diff.log_--cc_-m_-p_master b/t/t4013/diff.log_--cc_-m_-p_master
new file mode 100644
index 000000000000..7c217cf348c7
--- /dev/null
+++ b/t/t4013/diff.log_--cc_-m_-p_master
@@ -0,0 +1,200 @@
+$ git log --cc -m -p master
+commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (from 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0)
+Merge: 9a6d494 c7a2ab9
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:04:00 2006 +0000
+
+    Merge branch 'side'
+
+diff --git a/dir/sub b/dir/sub
+index cead32e..992913c 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -4,3 +4,5 @@ C
+ D
+ E
+ F
++1
++2
+diff --git a/file0 b/file0
+index b414108..10a8a9f 100644
+--- a/file0
++++ b/file0
+@@ -4,3 +4,6 @@
+ 4
+ 5
+ 6
++A
++B
++C
+
+commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (from c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a)
+Merge: 9a6d494 c7a2ab9
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:04:00 2006 +0000
+
+    Merge branch 'side'
+
+diff --git a/dir/sub b/dir/sub
+index 7289e35..992913c 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,4 +1,8 @@
+ A
+ B
++C
++D
++E
++F
+ 1
+ 2
+diff --git a/file0 b/file0
+index f4615da..10a8a9f 100644
+--- a/file0
++++ b/file0
+@@ -1,6 +1,9 @@
+ 1
+ 2
+ 3
++4
++5
++6
+ A
+ B
+ C
+diff --git a/file1 b/file1
+new file mode 100644
+index 0000000..b1e6722
+--- /dev/null
++++ b/file1
+@@ -0,0 +1,3 @@
++A
++B
++C
+diff --git a/file2 b/file2
+deleted file mode 100644
+index 01e79c3..0000000
+--- a/file2
++++ /dev/null
+@@ -1,3 +0,0 @@
+-1
+-2
+-3
+diff --git a/file3 b/file3
+deleted file mode 100644
+index 7289e35..0000000
+--- a/file3
++++ /dev/null
+@@ -1,4 +0,0 @@
+-A
+-B
+-1
+-2
+
+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:03:00 2006 +0000
+
+    Side
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..7289e35 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++1
++2
+diff --git a/file0 b/file0
+index 01e79c3..f4615da 100644
+--- a/file0
++++ b/file0
+@@ -1,3 +1,6 @@
+ 1
+ 2
+ 3
++A
++B
++C
+diff --git a/file3 b/file3
+new file mode 100644
+index 0000000..7289e35
+--- /dev/null
++++ b/file3
+@@ -0,0 +1,4 @@
++A
++B
++1
++2
+
+commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:02:00 2006 +0000
+
+    Third
+
+diff --git a/dir/sub b/dir/sub
+index 8422d40..cead32e 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -2,3 +2,5 @@ A
+ B
+ C
+ D
++E
++F
+diff --git a/file1 b/file1
+new file mode 100644
+index 0000000..b1e6722
+--- /dev/null
++++ b/file1
+@@ -0,0 +1,3 @@
++A
++B
++C
+
+commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:01:00 2006 +0000
+
+    Second
+    
+    This is the second commit.
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..8422d40 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++C
++D
+diff --git a/file0 b/file0
+index 01e79c3..b414108 100644
+--- a/file0
++++ b/file0
+@@ -1,3 +1,6 @@
+ 1
+ 2
+ 3
++4
++5
++6
+diff --git a/file2 b/file2
+deleted file mode 100644
+index 01e79c3..0000000
+--- a/file2
++++ /dev/null
+@@ -1,3 +0,0 @@
+-1
+-2
+-3
+
+commit 444ac553ac7612cc88969031b02b3767fb8a353a
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:00:00 2006 +0000
+
+    Initial
+$
diff --git a/t/t4013/diff.log_-c_-m_-p_master b/t/t4013/diff.log_-c_-m_-p_master
new file mode 100644
index 000000000000..b660f3d5f28e
--- /dev/null
+++ b/t/t4013/diff.log_-c_-m_-p_master
@@ -0,0 +1,200 @@
+$ git log -c -m -p master
+commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (from 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0)
+Merge: 9a6d494 c7a2ab9
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:04:00 2006 +0000
+
+    Merge branch 'side'
+
+diff --git a/dir/sub b/dir/sub
+index cead32e..992913c 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -4,3 +4,5 @@ C
+ D
+ E
+ F
++1
++2
+diff --git a/file0 b/file0
+index b414108..10a8a9f 100644
+--- a/file0
++++ b/file0
+@@ -4,3 +4,6 @@
+ 4
+ 5
+ 6
++A
++B
++C
+
+commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (from c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a)
+Merge: 9a6d494 c7a2ab9
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:04:00 2006 +0000
+
+    Merge branch 'side'
+
+diff --git a/dir/sub b/dir/sub
+index 7289e35..992913c 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,4 +1,8 @@
+ A
+ B
++C
++D
++E
++F
+ 1
+ 2
+diff --git a/file0 b/file0
+index f4615da..10a8a9f 100644
+--- a/file0
++++ b/file0
+@@ -1,6 +1,9 @@
+ 1
+ 2
+ 3
++4
++5
++6
+ A
+ B
+ C
+diff --git a/file1 b/file1
+new file mode 100644
+index 0000000..b1e6722
+--- /dev/null
++++ b/file1
+@@ -0,0 +1,3 @@
++A
++B
++C
+diff --git a/file2 b/file2
+deleted file mode 100644
+index 01e79c3..0000000
+--- a/file2
++++ /dev/null
+@@ -1,3 +0,0 @@
+-1
+-2
+-3
+diff --git a/file3 b/file3
+deleted file mode 100644
+index 7289e35..0000000
+--- a/file3
++++ /dev/null
+@@ -1,4 +0,0 @@
+-A
+-B
+-1
+-2
+
+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:03:00 2006 +0000
+
+    Side
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..7289e35 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++1
++2
+diff --git a/file0 b/file0
+index 01e79c3..f4615da 100644
+--- a/file0
++++ b/file0
+@@ -1,3 +1,6 @@
+ 1
+ 2
+ 3
++A
++B
++C
+diff --git a/file3 b/file3
+new file mode 100644
+index 0000000..7289e35
+--- /dev/null
++++ b/file3
+@@ -0,0 +1,4 @@
++A
++B
++1
++2
+
+commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:02:00 2006 +0000
+
+    Third
+
+diff --git a/dir/sub b/dir/sub
+index 8422d40..cead32e 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -2,3 +2,5 @@ A
+ B
+ C
+ D
++E
++F
+diff --git a/file1 b/file1
+new file mode 100644
+index 0000000..b1e6722
+--- /dev/null
++++ b/file1
+@@ -0,0 +1,3 @@
++A
++B
++C
+
+commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:01:00 2006 +0000
+
+    Second
+    
+    This is the second commit.
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..8422d40 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++C
++D
+diff --git a/file0 b/file0
+index 01e79c3..b414108 100644
+--- a/file0
++++ b/file0
+@@ -1,3 +1,6 @@
+ 1
+ 2
+ 3
++4
++5
++6
+diff --git a/file2 b/file2
+deleted file mode 100644
+index 01e79c3..0000000
+--- a/file2
++++ /dev/null
+@@ -1,3 +0,0 @@
+-1
+-2
+-3
+
+commit 444ac553ac7612cc88969031b02b3767fb8a353a
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:00:00 2006 +0000
+
+    Initial
+$
-- 
2.25.1


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

* [PATCH v2 16/33] diff-merges: fix -m to properly override -c/--cc
  2020-12-16 18:48 ` [PATCH v2 00/33] " Sergey Organov
                     ` (14 preceding siblings ...)
  2020-12-16 18:49   ` [PATCH v2 15/33] t4013: add tests for -m failing to override -c/--cc Sergey Organov
@ 2020-12-16 18:49   ` Sergey Organov
  2020-12-16 18:49   ` [PATCH v2 17/33] diff-merges: split 'ignore_merges' field Sergey Organov
                     ` (17 subsequent siblings)
  33 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-12-16 18:49 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Jeff King, Philip Oakley, Elijah Newren, git, Sergey Organov

Logically, -m, -c, --cc specify 3 different formats for representing
merge commits, yet -m doesn't in fact override -c or --cc, that makes
no sense.

Fix -m to properly override -c/--cc, and change the tests accordingly.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 diff-merges.c           | 1 +
 t/t4013-diff-various.sh | 4 ++--
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/diff-merges.c b/diff-merges.c
index 76ddbc37bd59..5d20e329a661 100644
--- a/diff-merges.c
+++ b/diff-merges.c
@@ -29,6 +29,7 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {
 	const char *arg = argv[0];
 
 	if (!strcmp(arg, "-m")) {
+		suppress(revs);
 		/*
 		 * To "diff-index", "-m" means "match missing", and to the "log"
 		 * family of commands, it means "show full diff for merges". Set
diff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh
index 64d9fce44614..8d8178a8a616 100755
--- a/t/t4013-diff-various.sh
+++ b/t/t4013-diff-various.sh
@@ -329,8 +329,8 @@ log --first-parent --diff-merges=off -p master
 log -p --first-parent master
 log -m -p --first-parent master
 log -m -p master
-:failure log --cc -m -p master
-:failure log -c -m -p master
+log --cc -m -p master
+log -c -m -p master
 log -SF master
 log -S F master
 log -SF -p master
-- 
2.25.1


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

* [PATCH v2 17/33] diff-merges: split 'ignore_merges' field
  2020-12-16 18:48 ` [PATCH v2 00/33] " Sergey Organov
                     ` (15 preceding siblings ...)
  2020-12-16 18:49   ` [PATCH v2 16/33] diff-merges: fix -m to properly " Sergey Organov
@ 2020-12-16 18:49   ` Sergey Organov
  2020-12-16 18:49   ` [PATCH v2 18/33] diff-merges: group diff-merge flags next to each other inside 'rev_info' Sergey Organov
                     ` (16 subsequent siblings)
  33 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-12-16 18:49 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Jeff King, Philip Oakley, Elijah Newren, git, Sergey Organov

'ignore_merges' was 3-way field that served two distinct purposes that
we now assign to 2 new independent flags: 'separate_merges', and
'explicit_diff_merges'.

'separate_merges' tells that we need to output diff format containing
separate diff for every parent (as opposed to 'combine_merges').

'explicit_diff_merges' tells that at least one of diff-merges options
has been explicitly specified on the command line, so no defaults
should apply.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 diff-merges.c | 31 +++++++++++++------------------
 log-tree.c    | 15 ++++++++-------
 revision.h    |  3 ++-
 3 files changed, 23 insertions(+), 26 deletions(-)

diff --git a/diff-merges.c b/diff-merges.c
index 5d20e329a661..711df9975dd5 100644
--- a/diff-merges.c
+++ b/diff-merges.c
@@ -3,7 +3,7 @@
 #include "revision.h"
 
 static void suppress(struct rev_info *revs) {
-	revs->ignore_merges = 1;
+	revs->separate_merges = 0;
 	revs->first_parent_merges = 0;
 	revs->combine_merges = 0;
 	revs->dense_combined_merges = 0;
@@ -20,7 +20,6 @@ static void set_dense_combined(struct rev_info *revs) {
  */
 
 void diff_merges_init_revs(struct rev_info *revs) {
-	revs->ignore_merges = -1;
 }
 
 int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {
@@ -35,7 +34,7 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {
 		 * family of commands, it means "show full diff for merges". Set
 		 * both fields appropriately.
 		 */
-		revs->ignore_merges = 0;
+		revs->separate_merges = 1;
 		revs->match_missing = 1;
 	} else if (!strcmp(arg, "-c")) {
 		revs->dense_combined_merges = 0;
@@ -53,8 +52,9 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {
 			die(_("unknown value for --diff-merges: %s"), optarg);
 		}
 	} else
-		argcount = 0;
+		return 0;
 
+	revs->explicit_diff_merges = 1;
 	return argcount;
 }
 
@@ -63,20 +63,15 @@ void diff_merges_suppress(struct rev_info *revs) {
 }
 
 void diff_merges_default_to_first_parent(struct rev_info *revs) {
-	if (revs->ignore_merges < 0)		/* No -m */
-		revs->ignore_merges = 0;
-	if (!revs->combine_merges)		/* No -c/--cc" */
+	if (!revs->explicit_diff_merges)
+		revs->separate_merges = 1;
+	if (revs->separate_merges)
 		revs->first_parent_merges = 1;
 }
 
 void diff_merges_default_to_dense_combined(struct rev_info *revs) {
-	if (revs->ignore_merges < 0) {		/* No -m */
-		revs->ignore_merges = 0;
-		if (!revs->combine_merges) {	/* No -c/--cc" */
-			revs->combine_merges = 1;
-			revs->dense_combined_merges = 1;
-		}
-	}
+	if (!revs->explicit_diff_merges)
+		set_dense_combined(revs);
 }
 
 void diff_merges_set_dense_combined_if_unset(struct rev_info *revs) {
@@ -86,10 +81,10 @@ void diff_merges_set_dense_combined_if_unset(struct rev_info *revs) {
 
 void diff_merges_setup_revs(struct rev_info *revs)
 {
-	if (revs->combine_merges && revs->ignore_merges < 0)
-		revs->ignore_merges = 0;
-	if (revs->ignore_merges < 0)
-		revs->ignore_merges = 1;
+	if (revs->combine_merges == 0)
+		revs->dense_combined_merges = 0;
+	if (revs->separate_merges == 0)
+		revs->first_parent_merges = 0;
 	if (revs->combined_all_paths && !revs->combine_merges)
 		die("--combined-all-paths makes no sense without -c or --cc");
 	if (revs->combine_merges)
diff --git a/log-tree.c b/log-tree.c
index 3fdc0fc64bfb..f9385b1dae6f 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -918,14 +918,15 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log
 
 	/* More than one parent? */
 	if (parents->next) {
-		if (opt->ignore_merges)
-			return 0;
-		else if (opt->combine_merges)
+		if (opt->combine_merges)
 			return do_diff_combined(opt, commit);
-		else if (!opt->first_parent_merges) {
-			/* If we show multiple diffs, show the parent info */
-			log->parent = parents->item;
-		}
+		if (opt->separate_merges) {
+			if (!opt->first_parent_merges) {
+				/* Show parent info for multiple diffs */
+				log->parent = parents->item;
+			}
+		} else
+			return 0;
 	}
 
 	showed_log = 0;
diff --git a/revision.h b/revision.h
index ba2aef79215e..fcc532c873d1 100644
--- a/revision.h
+++ b/revision.h
@@ -191,12 +191,13 @@ struct rev_info {
 			match_missing:1,
 			no_commit_id:1,
 			verbose_header:1,
+			explicit_diff_merges: 1,
+			separate_merges: 1,
 			combine_merges:1,
 			combined_all_paths:1,
 			dense_combined_merges:1,
 			first_parent_merges:1,
 			always_show_header:1;
-	int             ignore_merges:2;
 
 	/* Format info */
 	int		show_notes;
-- 
2.25.1


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

* [PATCH v2 18/33] diff-merges: group diff-merge flags next to each other inside 'rev_info'
  2020-12-16 18:48 ` [PATCH v2 00/33] " Sergey Organov
                     ` (16 preceding siblings ...)
  2020-12-16 18:49   ` [PATCH v2 17/33] diff-merges: split 'ignore_merges' field Sergey Organov
@ 2020-12-16 18:49   ` Sergey Organov
  2020-12-16 18:49   ` [PATCH v2 19/33] diff-merges: get rid of now empty diff_merges_init_revs() Sergey Organov
                     ` (15 subsequent siblings)
  33 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-12-16 18:49 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Jeff King, Philip Oakley, Elijah Newren, git, Sergey Organov

The relevant flags were somewhat scattered over definition of 'struct
rev_info'. Rearrange them to group them together.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 revision.h | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/revision.h b/revision.h
index fcc532c873d1..dcfa14454a55 100644
--- a/revision.h
+++ b/revision.h
@@ -191,13 +191,14 @@ struct rev_info {
 			match_missing:1,
 			no_commit_id:1,
 			verbose_header:1,
+			always_show_header:1,
+			/* Diff-merge flags */
 			explicit_diff_merges: 1,
 			separate_merges: 1,
 			combine_merges:1,
 			combined_all_paths:1,
 			dense_combined_merges:1,
-			first_parent_merges:1,
-			always_show_header:1;
+			first_parent_merges:1;
 
 	/* Format info */
 	int		show_notes;
-- 
2.25.1


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

* [PATCH v2 19/33] diff-merges: get rid of now empty diff_merges_init_revs()
  2020-12-16 18:48 ` [PATCH v2 00/33] " Sergey Organov
                     ` (17 preceding siblings ...)
  2020-12-16 18:49   ` [PATCH v2 18/33] diff-merges: group diff-merge flags next to each other inside 'rev_info' Sergey Organov
@ 2020-12-16 18:49   ` Sergey Organov
  2020-12-16 18:49   ` [PATCH v2 20/33] diff-merges: refactor opt settings into separate functions Sergey Organov
                     ` (14 subsequent siblings)
  33 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-12-16 18:49 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Jeff King, Philip Oakley, Elijah Newren, git, Sergey Organov

After getting rid of 'ignore_merges' field, the diff_merges_init_revs()
function became empty. Get rid of it.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 diff-merges.c | 3 ---
 diff-merges.h | 2 --
 revision.c    | 1 -
 3 files changed, 6 deletions(-)

diff --git a/diff-merges.c b/diff-merges.c
index 711df9975dd5..9ff6ea02edb8 100644
--- a/diff-merges.c
+++ b/diff-merges.c
@@ -19,9 +19,6 @@ static void set_dense_combined(struct rev_info *revs) {
  * Public functions. They are in the order they are called.
  */
 
-void diff_merges_init_revs(struct rev_info *revs) {
-}
-
 int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {
 	int argcount = 1;
 	const char *optarg;
diff --git a/diff-merges.h b/diff-merges.h
index f92de137d3a0..659467c99a4f 100644
--- a/diff-merges.h
+++ b/diff-merges.h
@@ -9,8 +9,6 @@
 
 struct rev_info;
 
-void diff_merges_init_revs(struct rev_info *revs);
-
 int diff_merges_parse_opts(struct rev_info *revs, const char **argv);
 
 void diff_merges_suppress(struct rev_info *revs);
diff --git a/revision.c b/revision.c
index 5a0e3d6ad542..46645ca0b6df 100644
--- a/revision.c
+++ b/revision.c
@@ -1814,7 +1814,6 @@ void repo_init_revisions(struct repository *r,
 
 	revs->repo = r;
 	revs->abbrev = DEFAULT_ABBREV;
-	diff_merges_init_revs(revs);
 	revs->simplify_history = 1;
 	revs->pruning.repo = r;
 	revs->pruning.flags.recursive = 1;
-- 
2.25.1


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

* [PATCH v2 20/33] diff-merges: refactor opt settings into separate functions
  2020-12-16 18:48 ` [PATCH v2 00/33] " Sergey Organov
                     ` (18 preceding siblings ...)
  2020-12-16 18:49   ` [PATCH v2 19/33] diff-merges: get rid of now empty diff_merges_init_revs() Sergey Organov
@ 2020-12-16 18:49   ` Sergey Organov
  2020-12-16 18:49   ` [PATCH v2 21/33] diff-merges: make -m/-c/--cc explicitly mutually exclusive Sergey Organov
                     ` (13 subsequent siblings)
  33 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-12-16 18:49 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Jeff King, Philip Oakley, Elijah Newren, git, Sergey Organov

To prepare introduction of new options some of which will be synonyms
to existing options, let every option handling code just call
corresponding function.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 diff-merges.c | 59 ++++++++++++++++++++++++++++++++-------------------
 1 file changed, 37 insertions(+), 22 deletions(-)

diff --git a/diff-merges.c b/diff-merges.c
index 9ff6ea02edb8..4c434e914c8d 100644
--- a/diff-merges.c
+++ b/diff-merges.c
@@ -9,11 +9,38 @@ static void suppress(struct rev_info *revs) {
 	revs->dense_combined_merges = 0;
 }
 
+static void set_separate(struct rev_info *revs) {
+	suppress(revs);
+	revs->separate_merges = 1;
+}
+
+static void set_m(struct rev_info *revs) {
+	/*
+	 * To "diff-index", "-m" means "match missing", and to the "log"
+	 * family of commands, it means "show full diff for merges". Set
+	 * both fields appropriately.
+	 */
+	set_separate(revs);
+	revs->match_missing = 1;
+}
+
+static void set_combined(struct rev_info *revs) {
+	revs->combine_merges = 1;
+	revs->dense_combined_merges = 0;
+}
+
 static void set_dense_combined(struct rev_info *revs) {
 	revs->combine_merges = 1;
 	revs->dense_combined_merges = 1;
 }
 
+static void set_diff_merges(struct rev_info *revs, const char *optarg) {
+	if (!strcmp(optarg, "off")) {
+		suppress(revs);
+	} else {
+		die(_("unknown value for --diff-merges: %s"), optarg);
+	}
+}
 
 /*
  * Public functions. They are in the order they are called.
@@ -24,31 +51,19 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {
 	const char *optarg;
 	const char *arg = argv[0];
 
-	if (!strcmp(arg, "-m")) {
-		suppress(revs);
-		/*
-		 * To "diff-index", "-m" means "match missing", and to the "log"
-		 * family of commands, it means "show full diff for merges". Set
-		 * both fields appropriately.
-		 */
-		revs->separate_merges = 1;
-		revs->match_missing = 1;
-	} else if (!strcmp(arg, "-c")) {
-		revs->dense_combined_merges = 0;
-		revs->combine_merges = 1;
-	} else if (!strcmp(arg, "--cc")) {
+	if (!strcmp(arg, "-m"))
+		set_m(revs);
+	else if (!strcmp(arg, "-c"))
+		set_combined(revs);
+	else if (!strcmp(arg, "--cc"))
 		set_dense_combined(revs);
-	} else if (!strcmp(arg, "--no-diff-merges")) {
+	else if (!strcmp(arg, "--no-diff-merges"))
 		suppress(revs);
-	} else if (!strcmp(arg, "--combined-all-paths")) {
+	else if (!strcmp(arg, "--combined-all-paths"))
 		revs->combined_all_paths = 1;
-	} else if ((argcount = parse_long_opt("diff-merges", argv, &optarg))) {
-		if (!strcmp(optarg, "off")) {
-			suppress(revs);
-		} else {
-			die(_("unknown value for --diff-merges: %s"), optarg);
-		}
-	} else
+	else if ((argcount = parse_long_opt("diff-merges", argv, &optarg)))
+		set_diff_merges(revs, optarg);
+	else
 		return 0;
 
 	revs->explicit_diff_merges = 1;
-- 
2.25.1


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

* [PATCH v2 21/33] diff-merges: make -m/-c/--cc explicitly mutually exclusive
  2020-12-16 18:48 ` [PATCH v2 00/33] " Sergey Organov
                     ` (19 preceding siblings ...)
  2020-12-16 18:49   ` [PATCH v2 20/33] diff-merges: refactor opt settings into separate functions Sergey Organov
@ 2020-12-16 18:49   ` Sergey Organov
  2020-12-16 18:49   ` [PATCH v2 22/33] diff-merges: implement new values for --diff-merges Sergey Organov
                     ` (12 subsequent siblings)
  33 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-12-16 18:49 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Jeff King, Philip Oakley, Elijah Newren, git, Sergey Organov

-c/--cc got precedence over -m only because of external logic where
corresponding flags are checked before that for -m. This is too
error-prone, so add code that explicitly makes these 3 options
mutually exclusive, so that the last option specified on the
command-line gets precedence.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 diff-merges.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/diff-merges.c b/diff-merges.c
index 4c434e914c8d..6446e2093661 100644
--- a/diff-merges.c
+++ b/diff-merges.c
@@ -7,6 +7,7 @@ static void suppress(struct rev_info *revs) {
 	revs->first_parent_merges = 0;
 	revs->combine_merges = 0;
 	revs->dense_combined_merges = 0;
+	revs->combined_all_paths = 0;
 }
 
 static void set_separate(struct rev_info *revs) {
@@ -25,11 +26,13 @@ static void set_m(struct rev_info *revs) {
 }
 
 static void set_combined(struct rev_info *revs) {
+	suppress(revs);
 	revs->combine_merges = 1;
 	revs->dense_combined_merges = 0;
 }
 
 static void set_dense_combined(struct rev_info *revs) {
+	suppress(revs);
 	revs->combine_merges = 1;
 	revs->dense_combined_merges = 1;
 }
-- 
2.25.1


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

* [PATCH v2 22/33] diff-merges: implement new values for --diff-merges
  2020-12-16 18:48 ` [PATCH v2 00/33] " Sergey Organov
                     ` (20 preceding siblings ...)
  2020-12-16 18:49   ` [PATCH v2 21/33] diff-merges: make -m/-c/--cc explicitly mutually exclusive Sergey Organov
@ 2020-12-16 18:49   ` Sergey Organov
  2020-12-18  5:39     ` Elijah Newren
  2020-12-16 18:49   ` [PATCH v2 23/33] diff-merges: fix style of functions definitions Sergey Organov
                     ` (11 subsequent siblings)
  33 siblings, 1 reply; 232+ messages in thread
From: Sergey Organov @ 2020-12-16 18:49 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Jeff King, Philip Oakley, Elijah Newren, git, Sergey Organov

We first implement new options as exact synonyms for their original
counterparts, to get all the infrastructure right, and keep functional
improvements for later commits.

The following values are implemented:

--diff-merges=	        old equivalent
first|first-parent    = --first-parent (only format implications)
sep|separate          = -m
comb|combined         = -c
dense| dense-combined = --cc

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 diff-merges.c | 19 ++++++++++++++++---
 1 file changed, 16 insertions(+), 3 deletions(-)

diff --git a/diff-merges.c b/diff-merges.c
index 6446e2093661..cba391604ac7 100644
--- a/diff-merges.c
+++ b/diff-merges.c
@@ -15,6 +15,11 @@ static void set_separate(struct rev_info *revs) {
 	revs->separate_merges = 1;
 }
 
+static void set_first_parent(struct rev_info *revs) {
+	set_separate(revs);
+	revs->first_parent_merges = 1;
+}
+
 static void set_m(struct rev_info *revs) {
 	/*
 	 * To "diff-index", "-m" means "match missing", and to the "log"
@@ -38,11 +43,19 @@ static void set_dense_combined(struct rev_info *revs) {
 }
 
 static void set_diff_merges(struct rev_info *revs, const char *optarg) {
-	if (!strcmp(optarg, "off")) {
+	if (0) ;
+	else if (!strcmp(optarg, "off")   || !strcmp(optarg, "none"))
 		suppress(revs);
-	} else {
+	else if (!strcmp(optarg, "first") || !strcmp(optarg, "first-parent"))
+		set_first_parent(revs);
+	else if (!strcmp(optarg, "sep")   || !strcmp(optarg, "separate"))
+		set_separate(revs);
+	else if (!strcmp(optarg, "comb")  || !strcmp(optarg, "combined"))
+		set_combined(revs);
+	else if (!strcmp(optarg, "dense") || !strcmp(optarg, "dense-combined"))
+		set_dense_combined(revs);
+	else
 		die(_("unknown value for --diff-merges: %s"), optarg);
-	}
 }
 
 /*
-- 
2.25.1


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

* [PATCH v2 23/33] diff-merges: fix style of functions definitions
  2020-12-16 18:48 ` [PATCH v2 00/33] " Sergey Organov
                     ` (21 preceding siblings ...)
  2020-12-16 18:49   ` [PATCH v2 22/33] diff-merges: implement new values for --diff-merges Sergey Organov
@ 2020-12-16 18:49   ` Sergey Organov
  2020-12-18  5:42     ` Elijah Newren
  2020-12-16 18:49   ` [PATCH v2 24/33] diff-merges: handle imply -p on -c/--cc logic for log.c Sergey Organov
                     ` (10 subsequent siblings)
  33 siblings, 1 reply; 232+ messages in thread
From: Sergey Organov @ 2020-12-16 18:49 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Jeff King, Philip Oakley, Elijah Newren, git, Sergey Organov

Put open curly brace on its own line

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 diff-merges.c | 36 ++++++++++++++++++++++++------------
 1 file changed, 24 insertions(+), 12 deletions(-)

diff --git a/diff-merges.c b/diff-merges.c
index cba391604ac7..0165fa22fcd1 100644
--- a/diff-merges.c
+++ b/diff-merges.c
@@ -2,7 +2,8 @@
 
 #include "revision.h"
 
-static void suppress(struct rev_info *revs) {
+static void suppress(struct rev_info *revs)
+{
 	revs->separate_merges = 0;
 	revs->first_parent_merges = 0;
 	revs->combine_merges = 0;
@@ -10,17 +11,20 @@ static void suppress(struct rev_info *revs) {
 	revs->combined_all_paths = 0;
 }
 
-static void set_separate(struct rev_info *revs) {
+static void set_separate(struct rev_info *revs)
+{
 	suppress(revs);
 	revs->separate_merges = 1;
 }
 
-static void set_first_parent(struct rev_info *revs) {
+static void set_first_parent(struct rev_info *revs)
+{
 	set_separate(revs);
 	revs->first_parent_merges = 1;
 }
 
-static void set_m(struct rev_info *revs) {
+static void set_m(struct rev_info *revs)
+{
 	/*
 	 * To "diff-index", "-m" means "match missing", and to the "log"
 	 * family of commands, it means "show full diff for merges". Set
@@ -30,19 +34,22 @@ static void set_m(struct rev_info *revs) {
 	revs->match_missing = 1;
 }
 
-static void set_combined(struct rev_info *revs) {
+static void set_combined(struct rev_info *revs)
+{
 	suppress(revs);
 	revs->combine_merges = 1;
 	revs->dense_combined_merges = 0;
 }
 
-static void set_dense_combined(struct rev_info *revs) {
+static void set_dense_combined(struct rev_info *revs)
+{
 	suppress(revs);
 	revs->combine_merges = 1;
 	revs->dense_combined_merges = 1;
 }
 
-static void set_diff_merges(struct rev_info *revs, const char *optarg) {
+static void set_diff_merges(struct rev_info *revs, const char *optarg)
+{
 	if (0) ;
 	else if (!strcmp(optarg, "off")   || !strcmp(optarg, "none"))
 		suppress(revs);
@@ -62,7 +69,8 @@ static void set_diff_merges(struct rev_info *revs, const char *optarg) {
  * Public functions. They are in the order they are called.
  */
 
-int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {
+int diff_merges_parse_opts(struct rev_info *revs, const char **argv)
+{
 	int argcount = 1;
 	const char *optarg;
 	const char *arg = argv[0];
@@ -86,23 +94,27 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {
 	return argcount;
 }
 
-void diff_merges_suppress(struct rev_info *revs) {
+void diff_merges_suppress(struct rev_info *revs)
+{
 	suppress(revs);
 }
 
-void diff_merges_default_to_first_parent(struct rev_info *revs) {
+void diff_merges_default_to_first_parent(struct rev_info *revs)
+{
 	if (!revs->explicit_diff_merges)
 		revs->separate_merges = 1;
 	if (revs->separate_merges)
 		revs->first_parent_merges = 1;
 }
 
-void diff_merges_default_to_dense_combined(struct rev_info *revs) {
+void diff_merges_default_to_dense_combined(struct rev_info *revs)
+{
 	if (!revs->explicit_diff_merges)
 		set_dense_combined(revs);
 }
 
-void diff_merges_set_dense_combined_if_unset(struct rev_info *revs) {
+void diff_merges_set_dense_combined_if_unset(struct rev_info *revs)
+{
 	if (!revs->combine_merges)
 		set_dense_combined(revs);
 }
-- 
2.25.1


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

* [PATCH v2 24/33] diff-merges: handle imply -p on -c/--cc logic for log.c
  2020-12-16 18:48 ` [PATCH v2 00/33] " Sergey Organov
                     ` (22 preceding siblings ...)
  2020-12-16 18:49   ` [PATCH v2 23/33] diff-merges: fix style of functions definitions Sergey Organov
@ 2020-12-16 18:49   ` Sergey Organov
  2020-12-18  6:00     ` Elijah Newren
  2020-12-16 18:49   ` [PATCH v2 25/33] diff-merges: do not imply -p for new options Sergey Organov
                     ` (9 subsequent siblings)
  33 siblings, 1 reply; 232+ messages in thread
From: Sergey Organov @ 2020-12-16 18:49 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Jeff King, Philip Oakley, Elijah Newren, git, Sergey Organov

Move logic that handles implying -p on -c/--cc from
log_setup_revisions_tweak() to diff_merges_setup_revs(), where it
belongs.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 builtin/log.c | 4 ----
 diff-merges.c | 7 ++++++-
 2 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/builtin/log.c b/builtin/log.c
index 63875c3aeec9..c3caf0955b2b 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -723,10 +723,6 @@ static void log_setup_revisions_tweak(struct rev_info *rev,
 	    rev->prune_data.nr == 1)
 		rev->diffopt.flags.follow_renames = 1;
 
-	/* Turn --cc/-c into -p --cc/-c when -p was not given */
-	if (!rev->diffopt.output_format && rev->combine_merges)
-		rev->diffopt.output_format = DIFF_FORMAT_PATCH;
-
 	if (rev->first_parent_only)
 		diff_merges_default_to_first_parent(rev);
 }
diff --git a/diff-merges.c b/diff-merges.c
index 0165fa22fcd1..2ac25488d53e 100644
--- a/diff-merges.c
+++ b/diff-merges.c
@@ -127,6 +127,11 @@ void diff_merges_setup_revs(struct rev_info *revs)
 		revs->first_parent_merges = 0;
 	if (revs->combined_all_paths && !revs->combine_merges)
 		die("--combined-all-paths makes no sense without -c or --cc");
-	if (revs->combine_merges)
+	if (revs->combine_merges) {
 		revs->diff = 1;
+		/* Turn --cc/-c into -p --cc/-c when -p was not given */
+		if (!revs->diffopt.output_format)
+			revs->diffopt.output_format = DIFF_FORMAT_PATCH;
+	}
+
 }
-- 
2.25.1


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

* [PATCH v2 25/33] diff-merges: do not imply -p for new options
  2020-12-16 18:48 ` [PATCH v2 00/33] " Sergey Organov
                     ` (23 preceding siblings ...)
  2020-12-16 18:49   ` [PATCH v2 24/33] diff-merges: handle imply -p on -c/--cc logic for log.c Sergey Organov
@ 2020-12-16 18:49   ` Sergey Organov
  2020-12-16 18:49   ` [PATCH v2 26/33] diff-merges: let new options enable diff without -p Sergey Organov
                     ` (8 subsequent siblings)
  33 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-12-16 18:49 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Jeff King, Philip Oakley, Elijah Newren, git, Sergey Organov

Add 'combined_imply_patch' field and set it only for old --cc/-c
options, then imply -p if this flag is set instead of implying -p
whenever 'combined_merge' flag is set.

We don't want new --diff-merge options to imply -p, to make it
possible to enable output of diffs for merges independently from
non-merge commits. At the same time we want to preserve behavior of
old --c/-c/-m options and their interactions with --first-parent, to
stay backward-compatible.

This patch is first step in this direction: it separates old "--cc/-c
imply -p" logic from the rest of the options.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 diff-merges.c | 12 +++++++++---
 revision.h    |  1 +
 2 files changed, 10 insertions(+), 3 deletions(-)

diff --git a/diff-merges.c b/diff-merges.c
index 2ac25488d53e..725db2312074 100644
--- a/diff-merges.c
+++ b/diff-merges.c
@@ -9,6 +9,7 @@ static void suppress(struct rev_info *revs)
 	revs->combine_merges = 0;
 	revs->dense_combined_merges = 0;
 	revs->combined_all_paths = 0;
+	revs->combined_imply_patch = 0;
 }
 
 static void set_separate(struct rev_info *revs)
@@ -77,10 +78,14 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv)
 
 	if (!strcmp(arg, "-m"))
 		set_m(revs);
-	else if (!strcmp(arg, "-c"))
+	else if (!strcmp(arg, "-c")) {
 		set_combined(revs);
-	else if (!strcmp(arg, "--cc"))
+		revs->combined_imply_patch = 1;
+	}
+	else if (!strcmp(arg, "--cc")) {
 		set_dense_combined(revs);
+		revs->combined_imply_patch = 1;
+	}
 	else if (!strcmp(arg, "--no-diff-merges"))
 		suppress(revs);
 	else if (!strcmp(arg, "--combined-all-paths"))
@@ -127,8 +132,9 @@ void diff_merges_setup_revs(struct rev_info *revs)
 		revs->first_parent_merges = 0;
 	if (revs->combined_all_paths && !revs->combine_merges)
 		die("--combined-all-paths makes no sense without -c or --cc");
-	if (revs->combine_merges) {
+	if (revs->combine_merges)
 		revs->diff = 1;
+	if (revs->combined_imply_patch) {
 		/* Turn --cc/-c into -p --cc/-c when -p was not given */
 		if (!revs->diffopt.output_format)
 			revs->diffopt.output_format = DIFF_FORMAT_PATCH;
diff --git a/revision.h b/revision.h
index dcfa14454a55..bfbae526ad6e 100644
--- a/revision.h
+++ b/revision.h
@@ -197,6 +197,7 @@ struct rev_info {
 			separate_merges: 1,
 			combine_merges:1,
 			combined_all_paths:1,
+			combined_imply_patch:1,
 			dense_combined_merges:1,
 			first_parent_merges:1;
 
-- 
2.25.1


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

* [PATCH v2 26/33] diff-merges: let new options enable diff without -p
  2020-12-16 18:48 ` [PATCH v2 00/33] " Sergey Organov
                     ` (24 preceding siblings ...)
  2020-12-16 18:49   ` [PATCH v2 25/33] diff-merges: do not imply -p for new options Sergey Organov
@ 2020-12-16 18:49   ` Sergey Organov
  2020-12-18  6:12     ` Elijah Newren
  2020-12-19 13:36     ` Felipe Contreras
  2020-12-16 18:49   ` [PATCH v2 27/33] diff-merges: add old mnemonic counterparts to --diff-merges Sergey Organov
                     ` (7 subsequent siblings)
  33 siblings, 2 replies; 232+ messages in thread
From: Sergey Organov @ 2020-12-16 18:49 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Jeff King, Philip Oakley, Elijah Newren, git, Sergey Organov

New options don't have any visible effect unless -p is either given or
implied, as unlike -c/-cc we don't imply -p with --diff-merges. To fix
this, this patch adds new functionality by letting new options enable
output of diffs for merge commits only.

Add 'merges_need_diff' field and set it whenever diff output for merges is
enabled by any of the new options.

Extend diff output logic accordingly, to output diffs for merges when
'merges_need_diff' is set even when no -p has been provided.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 diff-merges.c | 16 ++++++++++------
 log-tree.c    | 13 +++++++++----
 revision.h    |  1 +
 3 files changed, 20 insertions(+), 10 deletions(-)

diff --git a/diff-merges.c b/diff-merges.c
index 725db2312074..ffe20d8daa4a 100644
--- a/diff-merges.c
+++ b/diff-merges.c
@@ -10,6 +10,7 @@ static void suppress(struct rev_info *revs)
 	revs->dense_combined_merges = 0;
 	revs->combined_all_paths = 0;
 	revs->combined_imply_patch = 0;
+	revs->merges_need_diff = 0;
 }
 
 static void set_separate(struct rev_info *revs)
@@ -51,9 +52,11 @@ static void set_dense_combined(struct rev_info *revs)
 
 static void set_diff_merges(struct rev_info *revs, const char *optarg)
 {
+	if (!strcmp(optarg, "off") || !strcmp(optarg, "none")) {
+		suppress(revs);
+		return;
+	}
 	if (0) ;
-	else if (!strcmp(optarg, "off")   || !strcmp(optarg, "none"))
-		suppress(revs);
 	else if (!strcmp(optarg, "first") || !strcmp(optarg, "first-parent"))
 		set_first_parent(revs);
 	else if (!strcmp(optarg, "sep")   || !strcmp(optarg, "separate"))
@@ -64,6 +67,7 @@ static void set_diff_merges(struct rev_info *revs, const char *optarg)
 		set_dense_combined(revs);
 	else
 		die(_("unknown value for --diff-merges: %s"), optarg);
+	revs->merges_need_diff = 1;
 }
 
 /*
@@ -132,12 +136,12 @@ void diff_merges_setup_revs(struct rev_info *revs)
 		revs->first_parent_merges = 0;
 	if (revs->combined_all_paths && !revs->combine_merges)
 		die("--combined-all-paths makes no sense without -c or --cc");
-	if (revs->combine_merges)
+
+	if (revs->combined_imply_patch)
 		revs->diff = 1;
-	if (revs->combined_imply_patch) {
-		/* Turn --cc/-c into -p --cc/-c when -p was not given */
+
+	if (revs->combined_imply_patch || revs->merges_need_diff) {
 		if (!revs->diffopt.output_format)
 			revs->diffopt.output_format = DIFF_FORMAT_PATCH;
 	}
-
 }
diff --git a/log-tree.c b/log-tree.c
index f9385b1dae6f..67060492ca0a 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -899,15 +899,21 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log
 	int showed_log;
 	struct commit_list *parents;
 	struct object_id *oid;
+	int is_merge;
+	int regulars_need_diff = opt->diff || opt->diffopt.flags.exit_with_status;
 
-	if (!opt->diff && !opt->diffopt.flags.exit_with_status)
+	if (!regulars_need_diff && !opt->merges_need_diff)
 		return 0;
 
 	parse_commit_or_die(commit);
 	oid = get_commit_tree_oid(commit);
 
-	/* Root commit? */
 	parents = get_saved_parents(opt, commit);
+	is_merge = parents && parents->next;
+	if(!is_merge && !regulars_need_diff)
+		return 0;
+
+	/* Root commit? */
 	if (!parents) {
 		if (opt->show_root_diff) {
 			diff_root_tree_oid(oid, "", &opt->diffopt);
@@ -916,8 +922,7 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log
 		return !opt->loginfo;
 	}
 
-	/* More than one parent? */
-	if (parents->next) {
+	if (is_merge) {
 		if (opt->combine_merges)
 			return do_diff_combined(opt, commit);
 		if (opt->separate_merges) {
diff --git a/revision.h b/revision.h
index bfbae526ad6e..494d86142454 100644
--- a/revision.h
+++ b/revision.h
@@ -194,6 +194,7 @@ struct rev_info {
 			always_show_header:1,
 			/* Diff-merge flags */
 			explicit_diff_merges: 1,
+			merges_need_diff: 1,
 			separate_merges: 1,
 			combine_merges:1,
 			combined_all_paths:1,
-- 
2.25.1


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

* [PATCH v2 27/33] diff-merges: add old mnemonic counterparts to --diff-merges
  2020-12-16 18:48 ` [PATCH v2 00/33] " Sergey Organov
                     ` (25 preceding siblings ...)
  2020-12-16 18:49   ` [PATCH v2 26/33] diff-merges: let new options enable diff without -p Sergey Organov
@ 2020-12-16 18:49   ` Sergey Organov
  2020-12-16 18:49   ` [PATCH v2 28/33] diff-merges: add '--diff-merges=1' as synonym for 'first-parent' Sergey Organov
                     ` (6 subsequent siblings)
  33 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-12-16 18:49 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Jeff King, Philip Oakley, Elijah Newren, git, Sergey Organov

This adds --diff-merges={m|c|cc} values that match mnemonics of old
options, for those who are used to them.

Note that, say, --diff-meres=cc behaves differently than --cc, as the
latter implies -p and therefore enables diffs for all the commits,
while the former enables output of diffs for merge commits only.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 diff-merges.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/diff-merges.c b/diff-merges.c
index ffe20d8daa4a..9492cd2b871d 100644
--- a/diff-merges.c
+++ b/diff-merges.c
@@ -59,11 +59,14 @@ static void set_diff_merges(struct rev_info *revs, const char *optarg)
 	if (0) ;
 	else if (!strcmp(optarg, "first") || !strcmp(optarg, "first-parent"))
 		set_first_parent(revs);
-	else if (!strcmp(optarg, "sep")   || !strcmp(optarg, "separate"))
+	else if (!strcmp(optarg, "sep")   || !strcmp(optarg, "separate") ||
+		 !strcmp(optarg, "m"))
 		set_separate(revs);
-	else if (!strcmp(optarg, "comb")  || !strcmp(optarg, "combined"))
+	else if (!strcmp(optarg, "comb")  || !strcmp(optarg, "combined") ||
+		 !strcmp(optarg, "c"))
 		set_combined(revs);
-	else if (!strcmp(optarg, "dense") || !strcmp(optarg, "dense-combined"))
+	else if (!strcmp(optarg, "dense") || !strcmp(optarg, "dense-combined") ||
+		 !strcmp(optarg, "cc"))
 		set_dense_combined(revs);
 	else
 		die(_("unknown value for --diff-merges: %s"), optarg);
-- 
2.25.1


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

* [PATCH v2 28/33] diff-merges: add '--diff-merges=1' as synonym for 'first-parent'
  2020-12-16 18:48 ` [PATCH v2 00/33] " Sergey Organov
                     ` (26 preceding siblings ...)
  2020-12-16 18:49   ` [PATCH v2 27/33] diff-merges: add old mnemonic counterparts to --diff-merges Sergey Organov
@ 2020-12-16 18:49   ` Sergey Organov
  2020-12-18  6:19     ` Elijah Newren
  2020-12-16 18:49   ` [PATCH v2 29/33] doc/git-log: describe new --diff-merges options Sergey Organov
                     ` (5 subsequent siblings)
  33 siblings, 1 reply; 232+ messages in thread
From: Sergey Organov @ 2020-12-16 18:49 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Jeff King, Philip Oakley, Elijah Newren, git, Sergey Organov

As we now have --diff-merges={m|c|cc}, add --diff-merges=1 as synonym
for --diff-merges=first-parent, to have shorter mnemonics for it as
well.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 diff-merges.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/diff-merges.c b/diff-merges.c
index 9492cd2b871d..63a0d78b7730 100644
--- a/diff-merges.c
+++ b/diff-merges.c
@@ -57,7 +57,8 @@ static void set_diff_merges(struct rev_info *revs, const char *optarg)
 		return;
 	}
 	if (0) ;
-	else if (!strcmp(optarg, "first") || !strcmp(optarg, "first-parent"))
+	else if (!strcmp(optarg, "first") || !strcmp(optarg, "first-parent") ||
+		 !strcmp(optarg, "1"))
 		set_first_parent(revs);
 	else if (!strcmp(optarg, "sep")   || !strcmp(optarg, "separate") ||
 		 !strcmp(optarg, "m"))
-- 
2.25.1


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

* [PATCH v2 29/33] doc/git-log: describe new --diff-merges options
  2020-12-16 18:48 ` [PATCH v2 00/33] " Sergey Organov
                     ` (27 preceding siblings ...)
  2020-12-16 18:49   ` [PATCH v2 28/33] diff-merges: add '--diff-merges=1' as synonym for 'first-parent' Sergey Organov
@ 2020-12-16 18:49   ` Sergey Organov
  2020-12-18  5:53     ` Elijah Newren
  2020-12-16 18:49   ` [PATCH v2 30/33] doc/diff-generate-patch: mention new --diff-merges option Sergey Organov
                     ` (4 subsequent siblings)
  33 siblings, 1 reply; 232+ messages in thread
From: Sergey Organov @ 2020-12-16 18:49 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Jeff King, Philip Oakley, Elijah Newren, git, Sergey Organov

Describe all the new --diff-merges options in the git-log.txt and
adopt description of originals accordingly.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 Documentation/git-log.txt | 85 ++++++++++++++++++++++++---------------
 1 file changed, 52 insertions(+), 33 deletions(-)

diff --git a/Documentation/git-log.txt b/Documentation/git-log.txt
index 2b8ac5ff882a..27bc619490c6 100644
--- a/Documentation/git-log.txt
+++ b/Documentation/git-log.txt
@@ -120,45 +120,64 @@ DIFF FORMATTING
 By default, `git log` does not generate any diff output. The options
 below can be used to show the changes made by each commit.
 
-Note that unless one of `-c`, `--cc`, or `-m` is given, merge commits
-will never show a diff, even if a diff format like `--patch` is
-selected, nor will they match search options like `-S`. The exception is
-when `--first-parent` is in use, in which merges are treated like normal
-single-parent commits (this can be overridden by providing a
-combined-diff option or with `--no-diff-merges`).
+Note that unless one of `--diff-merges` variants (including short
+`-m`, `-c`, and `--cc` options) is explicitly given, merge commits
+will not show a diff, even if a diff format like `--patch` is
+selected, nor will they match search options like `-S`. The exception
+is when `--first-parent` is in use, in which case `first-parent` is
+the default format.
 
--c::
-	With this option, diff output for a merge commit
-	shows the differences from each of the parents to the merge result
-	simultaneously instead of showing pairwise diff between a parent
-	and the result one at a time. Furthermore, it lists only files
-	which were modified from all parents.
-
---cc::
-	This flag implies the `-c` option and further compresses the
-	patch output by omitting uninteresting hunks whose contents in
-	the parents have only two variants and the merge result picks
-	one of them without modification.
+--diff-merges=(off|none|first-parent|1|separate|m|combined|c|dense-combined|cc)::
+--no-diff-merges::
+	Specify diff format to be used for merge commits. Default is
+	`off` unless `--first-parent` is in use, in which case
+	`first-parent` is the default.
++
+--diff-merges=(off|none):::
+--no-diff-merges:::
+	Disable output of diffs for merge commits. Useful to override
+	implied value.
++
+--diff-merges=first-parent:::
+--diff-merges=1:::
+	This option makes merge commits show the full diff with
+	respect to the first parent only.
++
+--diff-merges=separate:::
+--diff-merges=m:::
+-m:::
+	This makes merge commits show the full diff with respect to
+	each of the parents. Separate log entry and diff is generated
+	for each parent. `-m` is different in that it doesn't produce
+	any output without `-p`.
++
+--diff-merges=combined:::
+--diff-merges=c:::
+-c:::
+	With this option, diff output for a merge commit shows the
+	differences from each of the parents to the merge result
+	simultaneously instead of showing pairwise diff between a
+	parent and the result one at a time. Furthermore, it lists
+	only files which were modified from all parents. Historically,
+	`-c` enables diff output for non-merge commits as well.
++
+--diff-merges=dense-combined:::
+--diff-merges=cc:::
+--cc:::
+	With this option the output produced by
+	`--diff-merges=combined` is further compressed by omitting
+	uninteresting hunks whose contents in the parents have only
+	two variants and the merge result picks one of them without
+	modification.  Historically, `--c` enables diff output for
+	non-merge commits as well.
 
 --combined-all-paths::
 	This flag causes combined diffs (used for merge commits) to
 	list the name of the file from all parents.  It thus only has
-	effect when -c or --cc are specified, and is likely only
-	useful if filename changes are detected (i.e. when either
-	rename or copy detection have been requested).
+	effect when `--diff-merges=[dense-]combined` is in use, and
+	is likely only useful if filename changes are detected (i.e.
+	when either rename or copy detection have been requested).
 
--m::
-	This flag makes the merge commits show the full diff like
-	regular commits; for each merge parent, a separate log entry
-	and diff is generated. An exception is that only diff against
-	the first parent is shown when `--first-parent` option is given;
-	in that case, the output represents the changes the merge
-	brought _into_ the then-current branch.
-
---diff-merges=off::
---no-diff-merges::
-	Disable output of diffs for merge commits (default). Useful to
-	override `-m`, `-c`, or `--cc`.
 
 :git-log: 1
 include::diff-options.txt[]
-- 
2.25.1


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

* [PATCH v2 30/33] doc/diff-generate-patch: mention new --diff-merges option
  2020-12-16 18:48 ` [PATCH v2 00/33] " Sergey Organov
                     ` (28 preceding siblings ...)
  2020-12-16 18:49   ` [PATCH v2 29/33] doc/git-log: describe new --diff-merges options Sergey Organov
@ 2020-12-16 18:49   ` Sergey Organov
  2020-12-16 18:49   ` [PATCH v2 31/33] doc/rev-list-options: document --first-parent changes merges format Sergey Organov
                     ` (3 subsequent siblings)
  33 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-12-16 18:49 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Jeff King, Philip Oakley, Elijah Newren, git, Sergey Organov

Mention --diff-merges instead of -m in a note to merge formats to aid
discoverability, as -m is now described among --diff-merges options
anyway.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 Documentation/diff-generate-patch.txt | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/Documentation/diff-generate-patch.txt b/Documentation/diff-generate-patch.txt
index b10ff4caa6c5..2db8eacc3ec7 100644
--- a/Documentation/diff-generate-patch.txt
+++ b/Documentation/diff-generate-patch.txt
@@ -81,9 +81,9 @@ Combined diff format
 Any diff-generating command can take the `-c` or `--cc` option to
 produce a 'combined diff' when showing a merge. This is the default
 format when showing merges with linkgit:git-diff[1] or
-linkgit:git-show[1]. Note also that you can give the `-m` option to any
-of these commands to force generation of diffs with individual parents
-of a merge.
+linkgit:git-show[1]. Note also that you can give suitable
+`--diff-merges` option to any of these commands to force generation of
+diffs in specific format.
 
 A "combined diff" format looks like this:
 
-- 
2.25.1


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

* [PATCH v2 31/33] doc/rev-list-options: document --first-parent changes merges format
  2020-12-16 18:48 ` [PATCH v2 00/33] " Sergey Organov
                     ` (29 preceding siblings ...)
  2020-12-16 18:49   ` [PATCH v2 30/33] doc/diff-generate-patch: mention new --diff-merges option Sergey Organov
@ 2020-12-16 18:49   ` Sergey Organov
  2020-12-16 18:49   ` [PATCH v2 32/33] doc/git-show: include --diff-merges description Sergey Organov
                     ` (2 subsequent siblings)
  33 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-12-16 18:49 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Jeff King, Philip Oakley, Elijah Newren, git, Sergey Organov

After introduction of the --diff-merges=first-parent, the
--first-parent sets the default format for merges to the same value as
this new option. Document this behavior and add corresponding
reference to --diff-merges.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 Documentation/rev-list-options.txt | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt
index 002379056a07..96cc89d157d2 100644
--- a/Documentation/rev-list-options.txt
+++ b/Documentation/rev-list-options.txt
@@ -130,6 +130,11 @@ parents) and `--max-parents=-1` (negative numbers denote no upper limit).
 	this option allows you to ignore the individual commits
 	brought in to your history by such a merge.
 
+ifdef::git-log[]
+	This option also changes default diff format for merge commits
+	to `first-parent`, see `--diff-merges=first-parent` for details.
+endif::git-log[]
+
 --not::
 	Reverses the meaning of the '{caret}' prefix (or lack thereof)
 	for all following revision specifiers, up to the next `--not`.
-- 
2.25.1


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

* [PATCH v2 32/33] doc/git-show: include --diff-merges description
  2020-12-16 18:48 ` [PATCH v2 00/33] " Sergey Organov
                     ` (30 preceding siblings ...)
  2020-12-16 18:49   ` [PATCH v2 31/33] doc/rev-list-options: document --first-parent changes merges format Sergey Organov
@ 2020-12-16 18:49   ` Sergey Organov
  2020-12-16 18:49   ` [PATCH v2 33/33] t4013: add tests for --diff-merges=first-parent Sergey Organov
  2020-12-18  6:54   ` [PATCH v2 00/33] git-log: implement new --diff-merge options Elijah Newren
  33 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-12-16 18:49 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Jeff King, Philip Oakley, Elijah Newren, git, Sergey Organov

Move description of --diff-merges option from git-log.txt to
diff-options.txt so that it is included in the git-show help.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 Documentation/diff-options.txt | 53 ++++++++++++++++++++++++++++++++++
 Documentation/git-log.txt      | 53 +---------------------------------
 Documentation/git-show.txt     |  7 +++--
 3 files changed, 59 insertions(+), 54 deletions(-)

diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt
index 573fb9bb71e2..98db2be423dc 100644
--- a/Documentation/diff-options.txt
+++ b/Documentation/diff-options.txt
@@ -33,6 +33,59 @@ endif::git-diff[]
 	show the patch by default, or to cancel the effect of `--patch`.
 endif::git-format-patch[]
 
+ifdef::git-log[]
+--diff-merges=(off|none|first-parent|1|separate|m|combined|c|dense-combined|cc)::
+--no-diff-merges::
+	Specify diff format to be used for merge commits. Default is
+	{diff-merges-default} unless `--first-parent` is in use, in which case
+	`first-parent` is the default.
++
+--diff-merges=(off|none):::
+--no-diff-merges:::
+	Disable output of diffs for merge commits. Useful to override
+	implied value.
++
+--diff-merges=first-parent:::
+--diff-merges=1:::
+	This option makes merge commits show the full diff with
+	respect to the first parent only.
++
+--diff-merges=separate:::
+--diff-merges=m:::
+-m:::
+	This makes merge commits show the full diff with respect to
+	each of the parents. Separate log entry and diff is generated
+	for each parent. `-m` is different in that it doesn't produce
+	any output without `-p`.
++
+--diff-merges=combined:::
+--diff-merges=c:::
+-c:::
+	With this option, diff output for a merge commit shows the
+	differences from each of the parents to the merge result
+	simultaneously instead of showing pairwise diff between a
+	parent and the result one at a time. Furthermore, it lists
+	only files which were modified from all parents. Historically,
+	`-c` enables diff output for non-merge commits as well.
++
+--diff-merges=dense-combined:::
+--diff-merges=cc:::
+--cc:::
+	With this option the output produced by
+	`--diff-merges=combined` is further compressed by omitting
+	uninteresting hunks whose contents in the parents have only
+	two variants and the merge result picks one of them without
+	modification.  Historically, `--c` enables diff output for
+	non-merge commits as well.
+
+--combined-all-paths::
+	This flag causes combined diffs (used for merge commits) to
+	list the name of the file from all parents.  It thus only has
+	effect when `--diff-merges=[dense-]combined` is in use, and
+	is likely only useful if filename changes are detected (i.e.
+	when either rename or copy detection have been requested).
+endif::git-log[]
+
 -U<n>::
 --unified=<n>::
 	Generate diffs with <n> lines of context instead of
diff --git a/Documentation/git-log.txt b/Documentation/git-log.txt
index 27bc619490c6..727d20e1a2ab 100644
--- a/Documentation/git-log.txt
+++ b/Documentation/git-log.txt
@@ -127,59 +127,8 @@ selected, nor will they match search options like `-S`. The exception
 is when `--first-parent` is in use, in which case `first-parent` is
 the default format.
 
---diff-merges=(off|none|first-parent|1|separate|m|combined|c|dense-combined|cc)::
---no-diff-merges::
-	Specify diff format to be used for merge commits. Default is
-	`off` unless `--first-parent` is in use, in which case
-	`first-parent` is the default.
-+
---diff-merges=(off|none):::
---no-diff-merges:::
-	Disable output of diffs for merge commits. Useful to override
-	implied value.
-+
---diff-merges=first-parent:::
---diff-merges=1:::
-	This option makes merge commits show the full diff with
-	respect to the first parent only.
-+
---diff-merges=separate:::
---diff-merges=m:::
--m:::
-	This makes merge commits show the full diff with respect to
-	each of the parents. Separate log entry and diff is generated
-	for each parent. `-m` is different in that it doesn't produce
-	any output without `-p`.
-+
---diff-merges=combined:::
---diff-merges=c:::
--c:::
-	With this option, diff output for a merge commit shows the
-	differences from each of the parents to the merge result
-	simultaneously instead of showing pairwise diff between a
-	parent and the result one at a time. Furthermore, it lists
-	only files which were modified from all parents. Historically,
-	`-c` enables diff output for non-merge commits as well.
-+
---diff-merges=dense-combined:::
---diff-merges=cc:::
---cc:::
-	With this option the output produced by
-	`--diff-merges=combined` is further compressed by omitting
-	uninteresting hunks whose contents in the parents have only
-	two variants and the merge result picks one of them without
-	modification.  Historically, `--c` enables diff output for
-	non-merge commits as well.
-
---combined-all-paths::
-	This flag causes combined diffs (used for merge commits) to
-	list the name of the file from all parents.  It thus only has
-	effect when `--diff-merges=[dense-]combined` is in use, and
-	is likely only useful if filename changes are detected (i.e.
-	when either rename or copy detection have been requested).
-
-
 :git-log: 1
+:diff-merges-default: `off`
 include::diff-options.txt[]
 
 include::diff-generate-patch.txt[]
diff --git a/Documentation/git-show.txt b/Documentation/git-show.txt
index fcf528c1b30d..2b1bc7288d5f 100644
--- a/Documentation/git-show.txt
+++ b/Documentation/git-show.txt
@@ -45,10 +45,13 @@ include::pretty-options.txt[]
 include::pretty-formats.txt[]
 
 
-COMMON DIFF OPTIONS
--------------------
+DIFF FORMATTING
+---------------
+The options below can be used to change the way `git show` generates
+diff output.
 
 :git-log: 1
+:diff-merges-default: `dense-combined`
 include::diff-options.txt[]
 
 include::diff-generate-patch.txt[]
-- 
2.25.1


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

* [PATCH v2 33/33] t4013: add tests for --diff-merges=first-parent
  2020-12-16 18:48 ` [PATCH v2 00/33] " Sergey Organov
                     ` (31 preceding siblings ...)
  2020-12-16 18:49   ` [PATCH v2 32/33] doc/git-show: include --diff-merges description Sergey Organov
@ 2020-12-16 18:49   ` Sergey Organov
  2020-12-18  6:54   ` [PATCH v2 00/33] git-log: implement new --diff-merge options Elijah Newren
  33 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-12-16 18:49 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Jeff King, Philip Oakley, Elijah Newren, git, Sergey Organov

This new option provides essential new functionality, changing diff
output to first parent only, without changing history traversal mode,
so it deserves its own test.

As we do it, add additional test that --diff-merges=first-parent by
itself doesn't imply -p and only outputs diffs for merge commits.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 t/t4013-diff-various.sh                       |   2 +
 ...diff.log_--diff-merges=first-parent_master |  56 +++++++
 ...f.log_-p_--diff-merges=first-parent_master | 137 ++++++++++++++++++
 3 files changed, 195 insertions(+)
 create mode 100644 t/t4013/diff.log_--diff-merges=first-parent_master
 create mode 100644 t/t4013/diff.log_-p_--diff-merges=first-parent_master

diff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh
index 8d8178a8a616..fa82b5a8eed4 100755
--- a/t/t4013-diff-various.sh
+++ b/t/t4013-diff-various.sh
@@ -327,6 +327,8 @@ log --no-diff-merges -p --first-parent master
 log --diff-merges=off -p --first-parent master
 log --first-parent --diff-merges=off -p master
 log -p --first-parent master
+log -p --diff-merges=first-parent master
+log --diff-merges=first-parent master
 log -m -p --first-parent master
 log -m -p master
 log --cc -m -p master
diff --git a/t/t4013/diff.log_--diff-merges=first-parent_master b/t/t4013/diff.log_--diff-merges=first-parent_master
new file mode 100644
index 000000000000..fa63a557dd18
--- /dev/null
+++ b/t/t4013/diff.log_--diff-merges=first-parent_master
@@ -0,0 +1,56 @@
+$ git log --diff-merges=first-parent master
+commit 59d314ad6f356dd08601a4cd5e530381da3e3c64
+Merge: 9a6d494 c7a2ab9
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:04:00 2006 +0000
+
+    Merge branch 'side'
+
+diff --git a/dir/sub b/dir/sub
+index cead32e..992913c 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -4,3 +4,5 @@ C
+ D
+ E
+ F
++1
++2
+diff --git a/file0 b/file0
+index b414108..10a8a9f 100644
+--- a/file0
++++ b/file0
+@@ -4,3 +4,6 @@
+ 4
+ 5
+ 6
++A
++B
++C
+
+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:03:00 2006 +0000
+
+    Side
+
+commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:02:00 2006 +0000
+
+    Third
+
+commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:01:00 2006 +0000
+
+    Second
+    
+    This is the second commit.
+
+commit 444ac553ac7612cc88969031b02b3767fb8a353a
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:00:00 2006 +0000
+
+    Initial
+$
diff --git a/t/t4013/diff.log_-p_--diff-merges=first-parent_master b/t/t4013/diff.log_-p_--diff-merges=first-parent_master
new file mode 100644
index 000000000000..9538a2751123
--- /dev/null
+++ b/t/t4013/diff.log_-p_--diff-merges=first-parent_master
@@ -0,0 +1,137 @@
+$ git log -p --diff-merges=first-parent master
+commit 59d314ad6f356dd08601a4cd5e530381da3e3c64
+Merge: 9a6d494 c7a2ab9
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:04:00 2006 +0000
+
+    Merge branch 'side'
+
+diff --git a/dir/sub b/dir/sub
+index cead32e..992913c 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -4,3 +4,5 @@ C
+ D
+ E
+ F
++1
++2
+diff --git a/file0 b/file0
+index b414108..10a8a9f 100644
+--- a/file0
++++ b/file0
+@@ -4,3 +4,6 @@
+ 4
+ 5
+ 6
++A
++B
++C
+
+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:03:00 2006 +0000
+
+    Side
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..7289e35 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++1
++2
+diff --git a/file0 b/file0
+index 01e79c3..f4615da 100644
+--- a/file0
++++ b/file0
+@@ -1,3 +1,6 @@
+ 1
+ 2
+ 3
++A
++B
++C
+diff --git a/file3 b/file3
+new file mode 100644
+index 0000000..7289e35
+--- /dev/null
++++ b/file3
+@@ -0,0 +1,4 @@
++A
++B
++1
++2
+
+commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:02:00 2006 +0000
+
+    Third
+
+diff --git a/dir/sub b/dir/sub
+index 8422d40..cead32e 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -2,3 +2,5 @@ A
+ B
+ C
+ D
++E
++F
+diff --git a/file1 b/file1
+new file mode 100644
+index 0000000..b1e6722
+--- /dev/null
++++ b/file1
+@@ -0,0 +1,3 @@
++A
++B
++C
+
+commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:01:00 2006 +0000
+
+    Second
+    
+    This is the second commit.
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..8422d40 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++C
++D
+diff --git a/file0 b/file0
+index 01e79c3..b414108 100644
+--- a/file0
++++ b/file0
+@@ -1,3 +1,6 @@
+ 1
+ 2
+ 3
++4
++5
++6
+diff --git a/file2 b/file2
+deleted file mode 100644
+index 01e79c3..0000000
+--- a/file2
++++ /dev/null
+@@ -1,3 +0,0 @@
+-1
+-2
+-3
+
+commit 444ac553ac7612cc88969031b02b3767fb8a353a
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:00:00 2006 +0000
+
+    Initial
+$
-- 
2.25.1


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

* Re: [PATCH v2 22/33] diff-merges: implement new values for --diff-merges
  2020-12-16 18:49   ` [PATCH v2 22/33] diff-merges: implement new values for --diff-merges Sergey Organov
@ 2020-12-18  5:39     ` Elijah Newren
  2020-12-18 14:12       ` Sergey Organov
  0 siblings, 1 reply; 232+ messages in thread
From: Elijah Newren @ 2020-12-18  5:39 UTC (permalink / raw)
  To: Sergey Organov; +Cc: Junio C Hamano, Jeff King, Philip Oakley, Git Mailing List

On Wed, Dec 16, 2020 at 10:50 AM Sergey Organov <sorganov@gmail.com> wrote:
>
> We first implement new options as exact synonyms for their original
> counterparts, to get all the infrastructure right, and keep functional
> improvements for later commits.
>
> The following values are implemented:
>
> --diff-merges=          old equivalent
> first|first-parent    = --first-parent (only format implications)
> sep|separate          = -m
> comb|combined         = -c
> dense| dense-combined = --cc
>
> Signed-off-by: Sergey Organov <sorganov@gmail.com>
> ---
>  diff-merges.c | 19 ++++++++++++++++---
>  1 file changed, 16 insertions(+), 3 deletions(-)
>
> diff --git a/diff-merges.c b/diff-merges.c
> index 6446e2093661..cba391604ac7 100644
> --- a/diff-merges.c
> +++ b/diff-merges.c
> @@ -15,6 +15,11 @@ static void set_separate(struct rev_info *revs) {
>         revs->separate_merges = 1;
>  }
>
> +static void set_first_parent(struct rev_info *revs) {
> +       set_separate(revs);
> +       revs->first_parent_merges = 1;
> +}
> +
>  static void set_m(struct rev_info *revs) {
>         /*
>          * To "diff-index", "-m" means "match missing", and to the "log"
> @@ -38,11 +43,19 @@ static void set_dense_combined(struct rev_info *revs) {
>  }
>
>  static void set_diff_merges(struct rev_info *revs, const char *optarg) {
> -       if (!strcmp(optarg, "off")) {
> +       if (0) ;

Leftover cruft from some intermediate changes or something?

> +       else if (!strcmp(optarg, "off")   || !strcmp(optarg, "none"))
>                 suppress(revs);
> -       } else {
> +       else if (!strcmp(optarg, "first") || !strcmp(optarg, "first-parent"))
> +               set_first_parent(revs);
> +       else if (!strcmp(optarg, "sep")   || !strcmp(optarg, "separate"))
> +               set_separate(revs);
> +       else if (!strcmp(optarg, "comb")  || !strcmp(optarg, "combined"))
> +               set_combined(revs);
> +       else if (!strcmp(optarg, "dense") || !strcmp(optarg, "dense-combined"))
> +               set_dense_combined(revs);
> +       else

Not sure I like the special-casing for "sep" and "comb".  "dense"
seems okay since it's a real word.  Since you're adding short versions
of m, c, and cc later in the series, do we need these other
special-case forms?

>                 die(_("unknown value for --diff-merges: %s"), optarg);
> -       }
>  }
>
>  /*
> --
> 2.25.1
>

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

* Re: [PATCH v2 23/33] diff-merges: fix style of functions definitions
  2020-12-16 18:49   ` [PATCH v2 23/33] diff-merges: fix style of functions definitions Sergey Organov
@ 2020-12-18  5:42     ` Elijah Newren
  2020-12-18 13:41       ` Sergey Organov
  0 siblings, 1 reply; 232+ messages in thread
From: Elijah Newren @ 2020-12-18  5:42 UTC (permalink / raw)
  To: Sergey Organov; +Cc: Junio C Hamano, Jeff King, Philip Oakley, Git Mailing List

On Wed, Dec 16, 2020 at 10:50 AM Sergey Organov <sorganov@gmail.com> wrote:
>
> Put open curly brace on its own line
>
> Signed-off-by: Sergey Organov <sorganov@gmail.com>
> ---
>  diff-merges.c | 36 ++++++++++++++++++++++++------------
>  1 file changed, 24 insertions(+), 12 deletions(-)
>
> diff --git a/diff-merges.c b/diff-merges.c
> index cba391604ac7..0165fa22fcd1 100644
> --- a/diff-merges.c
> +++ b/diff-merges.c
> @@ -2,7 +2,8 @@
>
>  #include "revision.h"
>
> -static void suppress(struct rev_info *revs) {
> +static void suppress(struct rev_info *revs)
> +{
>         revs->separate_merges = 0;
>         revs->first_parent_merges = 0;
>         revs->combine_merges = 0;
> @@ -10,17 +11,20 @@ static void suppress(struct rev_info *revs) {
>         revs->combined_all_paths = 0;
>  }
>
> -static void set_separate(struct rev_info *revs) {
> +static void set_separate(struct rev_info *revs)
> +{
>         suppress(revs);
>         revs->separate_merges = 1;
>  }
>
> -static void set_first_parent(struct rev_info *revs) {
> +static void set_first_parent(struct rev_info *revs)
> +{
>         set_separate(revs);
>         revs->first_parent_merges = 1;
>  }
>
> -static void set_m(struct rev_info *revs) {
> +static void set_m(struct rev_info *revs)
> +{
>         /*
>          * To "diff-index", "-m" means "match missing", and to the "log"
>          * family of commands, it means "show full diff for merges". Set
> @@ -30,19 +34,22 @@ static void set_m(struct rev_info *revs) {
>         revs->match_missing = 1;
>  }
>
> -static void set_combined(struct rev_info *revs) {
> +static void set_combined(struct rev_info *revs)
> +{
>         suppress(revs);
>         revs->combine_merges = 1;
>         revs->dense_combined_merges = 0;
>  }
>
> -static void set_dense_combined(struct rev_info *revs) {
> +static void set_dense_combined(struct rev_info *revs)
> +{
>         suppress(revs);
>         revs->combine_merges = 1;
>         revs->dense_combined_merges = 1;
>  }
>
> -static void set_diff_merges(struct rev_info *revs, const char *optarg) {
> +static void set_diff_merges(struct rev_info *revs, const char *optarg)
> +{
>         if (0) ;
>         else if (!strcmp(optarg, "off")   || !strcmp(optarg, "none"))
>                 suppress(revs);
> @@ -62,7 +69,8 @@ static void set_diff_merges(struct rev_info *revs, const char *optarg) {
>   * Public functions. They are in the order they are called.
>   */
>
> -int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {
> +int diff_merges_parse_opts(struct rev_info *revs, const char **argv)
> +{
>         int argcount = 1;
>         const char *optarg;
>         const char *arg = argv[0];
> @@ -86,23 +94,27 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {
>         return argcount;
>  }
>
> -void diff_merges_suppress(struct rev_info *revs) {
> +void diff_merges_suppress(struct rev_info *revs)
> +{
>         suppress(revs);
>  }
>
> -void diff_merges_default_to_first_parent(struct rev_info *revs) {
> +void diff_merges_default_to_first_parent(struct rev_info *revs)
> +{
>         if (!revs->explicit_diff_merges)
>                 revs->separate_merges = 1;
>         if (revs->separate_merges)
>                 revs->first_parent_merges = 1;
>  }
>
> -void diff_merges_default_to_dense_combined(struct rev_info *revs) {
> +void diff_merges_default_to_dense_combined(struct rev_info *revs)
> +{
>         if (!revs->explicit_diff_merges)
>                 set_dense_combined(revs);
>  }
>
> -void diff_merges_set_dense_combined_if_unset(struct rev_info *revs) {
> +void diff_merges_set_dense_combined_if_unset(struct rev_info *revs)
> +{
>         if (!revs->combine_merges)
>                 set_dense_combined(revs);
>  }
> --
> 2.25.1
>

But...didn't you add all these functions yourself earlier in the
series?  Why didn't you split this patch up and squash it into the
relevant previous patches?

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

* Re: [PATCH v2 29/33] doc/git-log: describe new --diff-merges options
  2020-12-16 18:49   ` [PATCH v2 29/33] doc/git-log: describe new --diff-merges options Sergey Organov
@ 2020-12-18  5:53     ` Elijah Newren
  2020-12-18 16:05       ` Sergey Organov
  0 siblings, 1 reply; 232+ messages in thread
From: Elijah Newren @ 2020-12-18  5:53 UTC (permalink / raw)
  To: Sergey Organov; +Cc: Junio C Hamano, Jeff King, Philip Oakley, Git Mailing List

On Wed, Dec 16, 2020 at 10:50 AM Sergey Organov <sorganov@gmail.com> wrote:
>
> Describe all the new --diff-merges options in the git-log.txt and
> adopt description of originals accordingly.

You also took care to explain interactions of options with -p that
were previously undocumented, which is a nice bonus.  That wording
could still be improved a bit, though, as noted below.

> Signed-off-by: Sergey Organov <sorganov@gmail.com>
> ---
>  Documentation/git-log.txt | 85 ++++++++++++++++++++++++---------------
>  1 file changed, 52 insertions(+), 33 deletions(-)
>
> diff --git a/Documentation/git-log.txt b/Documentation/git-log.txt
> index 2b8ac5ff882a..27bc619490c6 100644
> --- a/Documentation/git-log.txt
> +++ b/Documentation/git-log.txt
> @@ -120,45 +120,64 @@ DIFF FORMATTING
>  By default, `git log` does not generate any diff output. The options
>  below can be used to show the changes made by each commit.
>
> -Note that unless one of `-c`, `--cc`, or `-m` is given, merge commits
> -will never show a diff, even if a diff format like `--patch` is
> -selected, nor will they match search options like `-S`. The exception is
> -when `--first-parent` is in use, in which merges are treated like normal
> -single-parent commits (this can be overridden by providing a
> -combined-diff option or with `--no-diff-merges`).
> +Note that unless one of `--diff-merges` variants (including short
> +`-m`, `-c`, and `--cc` options) is explicitly given, merge commits
> +will not show a diff, even if a diff format like `--patch` is
> +selected, nor will they match search options like `-S`. The exception
> +is when `--first-parent` is in use, in which case `first-parent` is
> +the default format.

Thanks for fixing this up.  :-)

>
> --c::
> -       With this option, diff output for a merge commit
> -       shows the differences from each of the parents to the merge result
> -       simultaneously instead of showing pairwise diff between a parent
> -       and the result one at a time. Furthermore, it lists only files
> -       which were modified from all parents.
> -
> ---cc::
> -       This flag implies the `-c` option and further compresses the
> -       patch output by omitting uninteresting hunks whose contents in
> -       the parents have only two variants and the merge result picks
> -       one of them without modification.
> +--diff-merges=(off|none|first-parent|1|separate|m|combined|c|dense-combined|cc)::
> +--no-diff-merges::
> +       Specify diff format to be used for merge commits. Default is
> +       `off` unless `--first-parent` is in use, in which case
> +       `first-parent` is the default.
> ++
> +--diff-merges=(off|none):::
> +--no-diff-merges:::
> +       Disable output of diffs for merge commits. Useful to override
> +       implied value.
> ++
> +--diff-merges=first-parent:::
> +--diff-merges=1:::
> +       This option makes merge commits show the full diff with
> +       respect to the first parent only.

Does it imply -p?

> ++
> +--diff-merges=separate:::
> +--diff-merges=m:::
> +-m:::
> +       This makes merge commits show the full diff with respect to
> +       each of the parents. Separate log entry and diff is generated
> +       for each parent. `-m` is different in that it doesn't produce
> +       any output without `-p`.

Different from what?  From --first-parent?  From flags that haven't
been covered yet?  (-c and --cc show up below)

> ++
> +--diff-merges=combined:::
> +--diff-merges=c:::
> +-c:::
> +       With this option, diff output for a merge commit shows the
> +       differences from each of the parents to the merge result
> +       simultaneously instead of showing pairwise diff between a
> +       parent and the result one at a time. Furthermore, it lists
> +       only files which were modified from all parents. Historically,
> +       `-c` enables diff output for non-merge commits as well.

"Historically"?  Does that mean it doesn't anymore?  (Maybe, "The
short form, `-c`, also enables diff output for non-merge commits as
well." or something like that?)

> ++
> +--diff-merges=dense-combined:::
> +--diff-merges=cc:::
> +--cc:::
> +       With this option the output produced by
> +       `--diff-merges=combined` is further compressed by omitting
> +       uninteresting hunks whose contents in the parents have only
> +       two variants and the merge result picks one of them without
> +       modification.  Historically, `--c` enables diff output for
> +       non-merge commits as well.

Same note as above.

>  --combined-all-paths::
>         This flag causes combined diffs (used for merge commits) to
>         list the name of the file from all parents.  It thus only has
> -       effect when -c or --cc are specified, and is likely only
> -       useful if filename changes are detected (i.e. when either
> -       rename or copy detection have been requested).
> +       effect when `--diff-merges=[dense-]combined` is in use, and
> +       is likely only useful if filename changes are detected (i.e.
> +       when either rename or copy detection have been requested).
>
> --m::
> -       This flag makes the merge commits show the full diff like
> -       regular commits; for each merge parent, a separate log entry
> -       and diff is generated. An exception is that only diff against
> -       the first parent is shown when `--first-parent` option is given;
> -       in that case, the output represents the changes the merge
> -       brought _into_ the then-current branch.
> -
> ---diff-merges=off::
> ---no-diff-merges::
> -       Disable output of diffs for merge commits (default). Useful to
> -       override `-m`, `-c`, or `--cc`.
>
>  :git-log: 1
>  include::diff-options.txt[]
> --
> 2.25.1

The rest looks good.

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

* Re: [PATCH v2 24/33] diff-merges: handle imply -p on -c/--cc logic for log.c
  2020-12-16 18:49   ` [PATCH v2 24/33] diff-merges: handle imply -p on -c/--cc logic for log.c Sergey Organov
@ 2020-12-18  6:00     ` Elijah Newren
  2020-12-18 14:01       ` Sergey Organov
  0 siblings, 1 reply; 232+ messages in thread
From: Elijah Newren @ 2020-12-18  6:00 UTC (permalink / raw)
  To: Sergey Organov; +Cc: Junio C Hamano, Jeff King, Philip Oakley, Git Mailing List

On Wed, Dec 16, 2020 at 10:50 AM Sergey Organov <sorganov@gmail.com> wrote:
>
> Move logic that handles implying -p on -c/--cc from
> log_setup_revisions_tweak() to diff_merges_setup_revs(), where it
> belongs.

A very minor point, but I'd probably drop the "where it belongs";
while I think the new place makes sense for it, it reads to me like
you're either relying on a consensus to move it or implying there was
a mistake to not put it here previously, neither of which makes sense.

Much more importantly, this patch doesn't do what you said in
discussions on the previous round.  It'd be helpful if the commit
message called out that you are just moving the logic for now and that
a subsequent patch will tweak the logic to only trigger this for
-c/--cc and not for --diff-merges=.* flags.


> Signed-off-by: Sergey Organov <sorganov@gmail.com>
> ---
>  builtin/log.c | 4 ----
>  diff-merges.c | 7 ++++++-
>  2 files changed, 6 insertions(+), 5 deletions(-)
>
> diff --git a/builtin/log.c b/builtin/log.c
> index 63875c3aeec9..c3caf0955b2b 100644
> --- a/builtin/log.c
> +++ b/builtin/log.c
> @@ -723,10 +723,6 @@ static void log_setup_revisions_tweak(struct rev_info *rev,
>             rev->prune_data.nr == 1)
>                 rev->diffopt.flags.follow_renames = 1;
>
> -       /* Turn --cc/-c into -p --cc/-c when -p was not given */
> -       if (!rev->diffopt.output_format && rev->combine_merges)
> -               rev->diffopt.output_format = DIFF_FORMAT_PATCH;
> -
>         if (rev->first_parent_only)
>                 diff_merges_default_to_first_parent(rev);
>  }
> diff --git a/diff-merges.c b/diff-merges.c
> index 0165fa22fcd1..2ac25488d53e 100644
> --- a/diff-merges.c
> +++ b/diff-merges.c
> @@ -127,6 +127,11 @@ void diff_merges_setup_revs(struct rev_info *revs)
>                 revs->first_parent_merges = 0;
>         if (revs->combined_all_paths && !revs->combine_merges)
>                 die("--combined-all-paths makes no sense without -c or --cc");
> -       if (revs->combine_merges)
> +       if (revs->combine_merges) {
>                 revs->diff = 1;
> +               /* Turn --cc/-c into -p --cc/-c when -p was not given */
> +               if (!revs->diffopt.output_format)
> +                       revs->diffopt.output_format = DIFF_FORMAT_PATCH;
> +       }
> +
>  }
> --
> 2.25.1
>

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

* Re: [PATCH v2 26/33] diff-merges: let new options enable diff without -p
  2020-12-16 18:49   ` [PATCH v2 26/33] diff-merges: let new options enable diff without -p Sergey Organov
@ 2020-12-18  6:12     ` Elijah Newren
  2020-12-18 14:42       ` Sergey Organov
  2020-12-19 13:36     ` Felipe Contreras
  1 sibling, 1 reply; 232+ messages in thread
From: Elijah Newren @ 2020-12-18  6:12 UTC (permalink / raw)
  To: Sergey Organov; +Cc: Junio C Hamano, Jeff King, Philip Oakley, Git Mailing List

On Wed, Dec 16, 2020 at 10:50 AM Sergey Organov <sorganov@gmail.com> wrote:
>
> New options don't have any visible effect unless -p is either given or
> implied, as unlike -c/-cc we don't imply -p with --diff-merges. To fix
> this, this patch adds new functionality by letting new options enable
> output of diffs for merge commits only.
>
> Add 'merges_need_diff' field and set it whenever diff output for merges is
> enabled by any of the new options.
>
> Extend diff output logic accordingly, to output diffs for merges when
> 'merges_need_diff' is set even when no -p has been provided.
>
> Signed-off-by: Sergey Organov <sorganov@gmail.com>
> ---
>  diff-merges.c | 16 ++++++++++------
>  log-tree.c    | 13 +++++++++----
>  revision.h    |  1 +
>  3 files changed, 20 insertions(+), 10 deletions(-)
>
> diff --git a/diff-merges.c b/diff-merges.c
> index 725db2312074..ffe20d8daa4a 100644
> --- a/diff-merges.c
> +++ b/diff-merges.c
> @@ -10,6 +10,7 @@ static void suppress(struct rev_info *revs)
>         revs->dense_combined_merges = 0;
>         revs->combined_all_paths = 0;
>         revs->combined_imply_patch = 0;
> +       revs->merges_need_diff = 0;
>  }
>
>  static void set_separate(struct rev_info *revs)
> @@ -51,9 +52,11 @@ static void set_dense_combined(struct rev_info *revs)
>
>  static void set_diff_merges(struct rev_info *revs, const char *optarg)
>  {

> +       if (!strcmp(optarg, "off") || !strcmp(optarg, "none")) {
> +               suppress(revs);
> +               return;
> +       }
>         if (0) ;
> -       else if (!strcmp(optarg, "off")   || !strcmp(optarg, "none"))
> -               suppress(revs);

The "if (0) ;" is still really weird.

>         else if (!strcmp(optarg, "first") || !strcmp(optarg, "first-parent"))
>                 set_first_parent(revs);
>         else if (!strcmp(optarg, "sep")   || !strcmp(optarg, "separate"))
> @@ -64,6 +67,7 @@ static void set_diff_merges(struct rev_info *revs, const char *optarg)
>                 set_dense_combined(revs);
>         else
>                 die(_("unknown value for --diff-merges: %s"), optarg);
> +       revs->merges_need_diff = 1;

I'd put this above the if-else-else block, to make it clearer why you
are returning early for the "off"/"none" case.

>  }
>
>  /*
> @@ -132,12 +136,12 @@ void diff_merges_setup_revs(struct rev_info *revs)
>                 revs->first_parent_merges = 0;
>         if (revs->combined_all_paths && !revs->combine_merges)
>                 die("--combined-all-paths makes no sense without -c or --cc");
> -       if (revs->combine_merges)
> +
> +       if (revs->combined_imply_patch)
>                 revs->diff = 1;
> -       if (revs->combined_imply_patch) {
> -               /* Turn --cc/-c into -p --cc/-c when -p was not given */
> +
> +       if (revs->combined_imply_patch || revs->merges_need_diff) {
>                 if (!revs->diffopt.output_format)
>                         revs->diffopt.output_format = DIFF_FORMAT_PATCH;
>         }
> -

The random space changes squashed in here instead of being combined
with the earlier patches that introduced the relevant areas break up
the reading.  Would be nice to clean this up.

>  }
> diff --git a/log-tree.c b/log-tree.c
> index f9385b1dae6f..67060492ca0a 100644
> --- a/log-tree.c
> +++ b/log-tree.c
> @@ -899,15 +899,21 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log
>         int showed_log;
>         struct commit_list *parents;
>         struct object_id *oid;
> +       int is_merge;
> +       int regulars_need_diff = opt->diff || opt->diffopt.flags.exit_with_status;

So rev_info.diff has changed in meaning from
commits-need-to-show-a-diff, to non-merge-commits-need-to-show-a-diff.
That's a somewhat subtle semantic shift.  Perhaps it's worth adding a
comment to the declaration of rev_info.diff to highlight this?  (And
perhaps even rename the flag?)

> -       if (!opt->diff && !opt->diffopt.flags.exit_with_status)
> +       if (!regulars_need_diff && !opt->merges_need_diff)
>                 return 0;
>
>         parse_commit_or_die(commit);
>         oid = get_commit_tree_oid(commit);
>
> -       /* Root commit? */
>         parents = get_saved_parents(opt, commit);
> +       is_merge = parents && parents->next;
> +       if(!is_merge && !regulars_need_diff)
> +               return 0;
> +
> +       /* Root commit? */
>         if (!parents) {
>                 if (opt->show_root_diff) {
>                         diff_root_tree_oid(oid, "", &opt->diffopt);
> @@ -916,8 +922,7 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log
>                 return !opt->loginfo;
>         }
>
> -       /* More than one parent? */
> -       if (parents->next) {
> +       if (is_merge) {
>                 if (opt->combine_merges)
>                         return do_diff_combined(opt, commit);
>                 if (opt->separate_merges) {
> diff --git a/revision.h b/revision.h
> index bfbae526ad6e..494d86142454 100644
> --- a/revision.h
> +++ b/revision.h
> @@ -194,6 +194,7 @@ struct rev_info {
>                         always_show_header:1,
>                         /* Diff-merge flags */
>                         explicit_diff_merges: 1,
> +                       merges_need_diff: 1,
>                         separate_merges: 1,
>                         combine_merges:1,
>                         combined_all_paths:1,
> --
> 2.25.1

The rest makes sense.

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

* Re: [PATCH v2 28/33] diff-merges: add '--diff-merges=1' as synonym for 'first-parent'
  2020-12-16 18:49   ` [PATCH v2 28/33] diff-merges: add '--diff-merges=1' as synonym for 'first-parent' Sergey Organov
@ 2020-12-18  6:19     ` Elijah Newren
  2020-12-18 14:45       ` Sergey Organov
  0 siblings, 1 reply; 232+ messages in thread
From: Elijah Newren @ 2020-12-18  6:19 UTC (permalink / raw)
  To: Sergey Organov; +Cc: Junio C Hamano, Jeff King, Philip Oakley, Git Mailing List

On Wed, Dec 16, 2020 at 10:50 AM Sergey Organov <sorganov@gmail.com> wrote:
>
> As we now have --diff-merges={m|c|cc}, add --diff-merges=1 as synonym
> for --diff-merges=first-parent, to have shorter mnemonics for it as
> well.

In all the other cases, --diff-merges=<short> is equivalent to
-<short>.  Here, --diff-merges=1 and -1 do _very_ different things.
Is there any concern that might cause confusion?  (My gut reaction is
this is probably fine and people won't try to make such a connection,
but it made me worry just enough that I thought I'd flag it for you
and other reviewers to at least mull over and maybe comment on.)

> Signed-off-by: Sergey Organov <sorganov@gmail.com>
> ---
>  diff-merges.c | 3 ++-
>  1 file changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/diff-merges.c b/diff-merges.c
> index 9492cd2b871d..63a0d78b7730 100644
> --- a/diff-merges.c
> +++ b/diff-merges.c
> @@ -57,7 +57,8 @@ static void set_diff_merges(struct rev_info *revs, const char *optarg)
>                 return;
>         }
>         if (0) ;
> -       else if (!strcmp(optarg, "first") || !strcmp(optarg, "first-parent"))
> +       else if (!strcmp(optarg, "first") || !strcmp(optarg, "first-parent") ||
> +                !strcmp(optarg, "1"))
>                 set_first_parent(revs);
>         else if (!strcmp(optarg, "sep")   || !strcmp(optarg, "separate") ||
>                  !strcmp(optarg, "m"))
> --
> 2.25.1
>

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

* Re: [PATCH v2 00/33] git-log: implement new --diff-merge options
  2020-12-16 18:48 ` [PATCH v2 00/33] " Sergey Organov
                     ` (32 preceding siblings ...)
  2020-12-16 18:49   ` [PATCH v2 33/33] t4013: add tests for --diff-merges=first-parent Sergey Organov
@ 2020-12-18  6:54   ` Elijah Newren
  2020-12-18 13:39     ` Sergey Organov
  33 siblings, 1 reply; 232+ messages in thread
From: Elijah Newren @ 2020-12-18  6:54 UTC (permalink / raw)
  To: Sergey Organov; +Cc: Junio C Hamano, Jeff King, Philip Oakley, Git Mailing List

On Wed, Dec 16, 2020 at 10:50 AM Sergey Organov <sorganov@gmail.com> wrote:
>
> These patch series implement new set of options governing diff output
> of merge commits, all under the umbrella of single
> --diff-merges=<mode> option.

With this round, I was hoping to get a range-diff (using the
--range-diff option to format-patch), so I could more easily see what
was new.  Since I've been updating frequently enough, I was able to
generate this locally using Junio's published so/log-diff-merge topic,
but it'd be helpful if you could include it in any future rounds.

With your previous patch series, I scanned most the patches somewhat
briefly but looked at the final patches more closely (the series is
kind of long, and I noticed Junio had started reviewing the early part
of the series, so I figured it might be most helpful to jump in and
cover the end in case he didn't get that far).  With this round, I
read through the range-diff, and then looked at all the new patches
and have left a number of comments.  I think Junio reviewed the first
8 or so patches of an earlier round, so patches 9-21 probably could
benefit from someone reviewing more closely.

Overall, I like the direction of the series.  I think it'll make it
easier to add --remerge-diff later since it simplifies getting the
interaction between it and -m/-c/--cc/--first-parent right.  It also
adds some new capabilities you want (--diff-merges=first-parent, to
show merges as diff against first parent without only traversing first
parents), and that Junio wants (--diff-merges=dense-combined, to only
show merges for diffs without showing diffs for non-merge commits).

> Unlike original -c/--cc options, these new options do not imply -p,
> thus allowing for getting diffs for merge commits without provoking of
> diff output for regular, non-merge commits. E.g.:
>
>   git log --diff-merges=cc
>
> will output diffs (in dense-combined format) only for merge commits,
> whereas:
>
>   git log --cc
>
> enables diffs for all the commits being output, either merges or
> simple ones.
>
> There is also another additional functionality provided, allowing to
> get the format of "-p --first-parent" without change in history
> traversal that --first-parent option causes, like this:
>
>   git log --diff-merges=first-parent
>
> The net result of these series are the following new options:
>
> --diff-merges=    |  rough original equivalent
> ------------------+----------------
> 1|first-parent    | --first-parent (only diff format implications)
> m|separate        | -m and enable diff for merges
> c|combined        | -c and enable diff for merges, but not for regulars
> cc|dense-combined | --cc and enable diff for merges, but not for
>                   |      regulars
>
> The series also cleanup logic of handling of diff merges options and
> fix an issue found in the original implementation where logically
> mutually exclusive options -m/-c/--cc failed to actually override each
> other. Neither semantics of these old options nor their interactions
> with other options, such as --first-parent and -p, is supposed to be
> changed.
>
> The series start with the set of pure refactoring commits that are expected
> to introduce no functional changes. These are all commits up to and
> including:
>
> "diff-merges: revise revs->diff flag handling"
>
> The aim of these commits is to isolate options handling for diff merges so
> that it could be easily understood and tweaked to ease introduction of the
> new options.
>
> Then the fix of -m/-c/-cc overriding issue follows, starting with a failing
> test and followed by the fix.
>
> Then follows a little bit of additional refactoring in order to
> prepare for introduction of the new options, and finally the series
> are finished by the implementation, documentation updates, and
> some testing for the new options.
>
> Updates in v2:
>
>   * Move logic of "-c/--cc imply -p" to this module and do not imply
>     -p by new --diff-merges options. Instead enable corresponding diff
>     output without affecting non-merge commits. This is the most
>     significant change with respect to v1 and it starts at 24/33.
>
>   * Add support for old mnemonics: --diff-merges=(m|c|cc) to help
>     those who are used to them, and add --diff-merges=1 to cover all
>     variants with short mnemonics.
>
>   * Fixed functions definitions style to have open curly brace on its
>     own line, pointed to by Junio C Hamano.
>
>   * Tweak --diff-merges=first-parent description, requested by Elijah
>     Newren.
>
>   * Fixed git-show documentation not to include description chunk
>     relevant to git-log only, noticed by Elijah Newren.
>
>   * Fixed documentation mistake claiming that -p is needed for
>     diff-merges options to take effect, noticed by Elijah Newren.
>
>   * Fixed a case where a change was put into wrong commit. The change
>     moved to 11/27 form 10/27. Didn't affect end-result in any way.
>
>   * Added short module description to diff-merges.h, as suggested by
>     Junio C Hamano.
>
>   * Fixed not returning "argcount" from diff_merges_parse_opts(),
>     noticed by Junio C Hamano.
>
> Updates in v1:
>
>   * Added documentation fix for git-show to include --diff-merges.
>
>   * Fixed typos in commit messages noticed by Philip Oakley.
>
> Sergey Organov (33):
>   revision: factor out parsing of diff-merge related options
>   revision: factor out setup of diff-merge related settings
>   revision: factor out initialization of diff-merge related settings
>   revision: provide implementation for diff merges tweaks
>   revision: move diff merges functions to its own diff-merges.c
>   diff-merges: rename all functions to have common prefix
>   diff-merges: move checks for first_parent_only out of the module
>   diff-merges: rename diff_merges_default_to_enable() to match semantics
>   diff-merges: re-arrange functions to match the order they are called
>     in
>   diff-merges: new function diff_merges_suppress()
>   diff-merges: new function diff_merges_set_dense_combined_if_unset()
>   diff-merges: introduce revs->first_parent_merges flag
>   diff-merges: revise revs->diff flag handling
>   t4013: support test_expect_failure through ':failure' magic
>   t4013: add tests for -m failing to override -c/--cc
>   diff-merges: fix -m to properly override -c/--cc
>   diff-merges: split 'ignore_merges' field
>   diff-merges: group diff-merge flags next to each other inside
>     'rev_info'
>   diff-merges: get rid of now empty diff_merges_init_revs()
>   diff-merges: refactor opt settings into separate functions
>   diff-merges: make -m/-c/--cc explicitly mutually exclusive
>   diff-merges: implement new values for --diff-merges
>   diff-merges: fix style of functions definitions
>   diff-merges: handle imply -p on -c/--cc logic for log.c
>   diff-merges: do not imply -p for new options
>   diff-merges: let new options enable diff without -p
>   diff-merges: add old mnemonic counterparts to --diff-merges
>   diff-merges: add '--diff-merges=1' as synonym for 'first-parent'
>   doc/git-log: describe new --diff-merges options
>   doc/diff-generate-patch: mention new --diff-merges option
>   doc/rev-list-options: document --first-parent changes merges format
>   doc/git-show: include --diff-merges description
>   t4013: add tests for --diff-merges=first-parent
>
>  Documentation/diff-generate-patch.txt         |   6 +-
>  Documentation/diff-options.txt                |  53 +++++
>  Documentation/git-log.txt                     |  46 +---
>  Documentation/git-show.txt                    |   7 +-
>  Documentation/rev-list-options.txt            |   5 +
>  Makefile                                      |   1 +
>  builtin/diff-files.c                          |   5 +-
>  builtin/diff.c                                |   9 +-
>  builtin/log.c                                 |  22 +-
>  builtin/merge.c                               |   3 +-
>  diff-merges.c                                 | 151 +++++++++++++
>  diff-merges.h                                 |  24 +++
>  fmt-merge-msg.c                               |   3 +-
>  log-tree.c                                    |  30 +--
>  revision.c                                    |  38 +---
>  revision.h                                    |   9 +-
>  t/t4013-diff-various.sh                       |  11 +-
>  t/t4013/diff.log_--cc_-m_-p_master            | 200 ++++++++++++++++++
>  ...diff.log_--diff-merges=first-parent_master |  56 +++++
>  t/t4013/diff.log_-c_-m_-p_master              | 200 ++++++++++++++++++
>  ...f.log_-p_--diff-merges=first-parent_master | 137 ++++++++++++
>  21 files changed, 900 insertions(+), 116 deletions(-)
>  create mode 100644 diff-merges.c
>  create mode 100644 diff-merges.h
>  create mode 100644 t/t4013/diff.log_--cc_-m_-p_master
>  create mode 100644 t/t4013/diff.log_--diff-merges=first-parent_master
>  create mode 100644 t/t4013/diff.log_-c_-m_-p_master
>  create mode 100644 t/t4013/diff.log_-p_--diff-merges=first-parent_master
>
> --
> 2.25.1
>

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

* Re: [PATCH v2 00/33] git-log: implement new --diff-merge options
  2020-12-18  6:54   ` [PATCH v2 00/33] git-log: implement new --diff-merge options Elijah Newren
@ 2020-12-18 13:39     ` Sergey Organov
  0 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-12-18 13:39 UTC (permalink / raw)
  To: Elijah Newren; +Cc: Junio C Hamano, Jeff King, Philip Oakley, Git Mailing List

Hi Elijah,

Thanks a lot for reviewing the series!

Elijah Newren <newren@gmail.com> writes:

> On Wed, Dec 16, 2020 at 10:50 AM Sergey Organov <sorganov@gmail.com> wrote:
>>
>> These patch series implement new set of options governing diff output
>> of merge commits, all under the umbrella of single
>> --diff-merges=<mode> option.
>
> With this round, I was hoping to get a range-diff (using the
> --range-diff option to format-patch), so I could more easily see what
> was new.  Since I've been updating frequently enough, I was able to
> generate this locally using Junio's published so/log-diff-merge topic,
> but it'd be helpful if you could include it in any future rounds.

Well, documentation on contributing doesn't seem to mention this. I'll
try to learn it for the future though, thanks!

>
> With your previous patch series, I scanned most the patches somewhat
> briefly but looked at the final patches more closely (the series is
> kind of long, and I noticed Junio had started reviewing the early part
> of the series, so I figured it might be most helpful to jump in and
> cover the end in case he didn't get that far).  With this round, I
> read through the range-diff, and then looked at all the new patches
> and have left a number of comments.  I think Junio reviewed the first
> 8 or so patches of an earlier round, so patches 9-21 probably could
> benefit from someone reviewing more closely.
>
> Overall, I like the direction of the series.  I think it'll make it
> easier to add --remerge-diff later since it simplifies getting the
> interaction between it and -m/-c/--cc/--first-parent right.  It also
> adds some new capabilities you want (--diff-merges=first-parent, to
> show merges as diff against first parent without only traversing first
> parents), and that Junio wants (--diff-merges=dense-combined, to only
> show merges for diffs without showing diffs for non-merge commits).

Yeah, I hoped to address everything that has been discussed.

[...]

Thanks,
-- Sergey

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

* Re: [PATCH v2 23/33] diff-merges: fix style of functions definitions
  2020-12-18  5:42     ` Elijah Newren
@ 2020-12-18 13:41       ` Sergey Organov
  2020-12-18 16:12         ` Elijah Newren
  2020-12-19  1:41         ` Junio C Hamano
  0 siblings, 2 replies; 232+ messages in thread
From: Sergey Organov @ 2020-12-18 13:41 UTC (permalink / raw)
  To: Elijah Newren; +Cc: Junio C Hamano, Jeff King, Philip Oakley, Git Mailing List

Elijah Newren <newren@gmail.com> writes:

> On Wed, Dec 16, 2020 at 10:50 AM Sergey Organov <sorganov@gmail.com> wrote:
>>
>> Put open curly brace on its own line
>>
>> Signed-off-by: Sergey Organov <sorganov@gmail.com>
>> ---
>>  diff-merges.c | 36 ++++++++++++++++++++++++------------
>>  1 file changed, 24 insertions(+), 12 deletions(-)
>>
>> diff --git a/diff-merges.c b/diff-merges.c
>> index cba391604ac7..0165fa22fcd1 100644
>> --- a/diff-merges.c
>> +++ b/diff-merges.c
>> @@ -2,7 +2,8 @@
>>

[...]

>>
>> -void diff_merges_set_dense_combined_if_unset(struct rev_info *revs) {
>> +void diff_merges_set_dense_combined_if_unset(struct rev_info *revs)
>> +{
>>         if (!revs->combine_merges)
>>                 set_dense_combined(revs);
>>  }
>> --
>> 2.25.1
>>
>
> But...didn't you add all these functions yourself earlier in the
> series?

Yes, I did indeed and somehow picked wrong style from one of the
occurrences of this style in the existing Git codebase.

> Why didn't you split this patch up and squash it into the
> relevant previous patches?

When Junio noticed and pointed to this deficiency, I asked him if I
should fix all the series from the start, or it'd be OK to use fixup
commit. As he didn't answer and nobody else commented either, I opted
for the latter.

I can still do it if it's that essential, but I'd prefer not to, to
avoid both the hand-work and causing entire series to change. The
problem is that there were code movements in the series, so such a fix
to earlier patches would cause conflicts down the commits chain, to be
resolved by hand.

Thanks,
-- Sergey

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

* Re: [PATCH v2 24/33] diff-merges: handle imply -p on -c/--cc logic for log.c
  2020-12-18  6:00     ` Elijah Newren
@ 2020-12-18 14:01       ` Sergey Organov
  2020-12-18 16:37         ` Elijah Newren
  0 siblings, 1 reply; 232+ messages in thread
From: Sergey Organov @ 2020-12-18 14:01 UTC (permalink / raw)
  To: Elijah Newren; +Cc: Junio C Hamano, Jeff King, Philip Oakley, Git Mailing List

Elijah Newren <newren@gmail.com> writes:

> On Wed, Dec 16, 2020 at 10:50 AM Sergey Organov <sorganov@gmail.com> wrote:
>>
>> Move logic that handles implying -p on -c/--cc from
>> log_setup_revisions_tweak() to diff_merges_setup_revs(), where it
>> belongs.
>
> A very minor point, but I'd probably drop the "where it belongs";
> while I think the new place makes sense for it, it reads to me like
> you're either relying on a consensus to move it or implying there was
> a mistake to not put it here previously, neither of which makes sense.

Well, it was meant to be an excuse for not moving it there earlier in
the patch series indeed. I just overlooked this piece of code that
logically belongs to the diff-merges module. I think you need to
consider the state of the sources right before this patch to see the
point of phrasing it like this.

That said, I'm fine removing this either.

> Much more importantly, this patch doesn't do what you said in
> discussions on the previous round.  It'd be helpful if the commit
> message called out that you are just moving the logic for now and that
> a subsequent patch will tweak the logic to only trigger this for
> -c/--cc and not for --diff-merges=.* flags.

I believe this patch is useful by itself, even without any future
improvements (that we actually discussed), if any, so I don't see the
point in describing what this patch doesn't do.

OTOH, the commit message seems to be clear enough to expect this patch
to be pure refactoring, without any functional changes, no?

Thanks,
-- Sergey

>
>
>> Signed-off-by: Sergey Organov <sorganov@gmail.com>
>> ---
>>  builtin/log.c | 4 ----
>>  diff-merges.c | 7 ++++++-
>>  2 files changed, 6 insertions(+), 5 deletions(-)
>>
>> diff --git a/builtin/log.c b/builtin/log.c
>> index 63875c3aeec9..c3caf0955b2b 100644
>> --- a/builtin/log.c
>> +++ b/builtin/log.c
>> @@ -723,10 +723,6 @@ static void log_setup_revisions_tweak(struct rev_info *rev,
>>             rev->prune_data.nr == 1)
>>                 rev->diffopt.flags.follow_renames = 1;
>>
>> -       /* Turn --cc/-c into -p --cc/-c when -p was not given */
>> -       if (!rev->diffopt.output_format && rev->combine_merges)
>> -               rev->diffopt.output_format = DIFF_FORMAT_PATCH;
>> -
>>         if (rev->first_parent_only)
>>                 diff_merges_default_to_first_parent(rev);
>>  }
>> diff --git a/diff-merges.c b/diff-merges.c
>> index 0165fa22fcd1..2ac25488d53e 100644
>> --- a/diff-merges.c
>> +++ b/diff-merges.c
>> @@ -127,6 +127,11 @@ void diff_merges_setup_revs(struct rev_info *revs)
>>                 revs->first_parent_merges = 0;
>>         if (revs->combined_all_paths && !revs->combine_merges)
>>                 die("--combined-all-paths makes no sense without -c or --cc");
>> -       if (revs->combine_merges)
>> +       if (revs->combine_merges) {
>>                 revs->diff = 1;
>> +               /* Turn --cc/-c into -p --cc/-c when -p was not given */
>> +               if (!revs->diffopt.output_format)
>> +                       revs->diffopt.output_format = DIFF_FORMAT_PATCH;
>> +       }
>> +
>>  }
>> --
>> 2.25.1
>>


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

* Re: [PATCH v2 22/33] diff-merges: implement new values for --diff-merges
  2020-12-18  5:39     ` Elijah Newren
@ 2020-12-18 14:12       ` Sergey Organov
  2020-12-18 16:42         ` Elijah Newren
  0 siblings, 1 reply; 232+ messages in thread
From: Sergey Organov @ 2020-12-18 14:12 UTC (permalink / raw)
  To: Elijah Newren; +Cc: Junio C Hamano, Jeff King, Philip Oakley, Git Mailing List

Elijah Newren <newren@gmail.com> writes:

> On Wed, Dec 16, 2020 at 10:50 AM Sergey Organov <sorganov@gmail.com> wrote:
>>
>> We first implement new options as exact synonyms for their original
>> counterparts, to get all the infrastructure right, and keep functional
>> improvements for later commits.
>>
>> The following values are implemented:
>>
>> --diff-merges=          old equivalent
>> first|first-parent    = --first-parent (only format implications)
>> sep|separate          = -m
>> comb|combined         = -c
>> dense| dense-combined = --cc
>>
>> Signed-off-by: Sergey Organov <sorganov@gmail.com>
>> ---
>>  diff-merges.c | 19 ++++++++++++++++---
>>  1 file changed, 16 insertions(+), 3 deletions(-)
>>
>> diff --git a/diff-merges.c b/diff-merges.c
>> index 6446e2093661..cba391604ac7 100644
>> --- a/diff-merges.c
>> +++ b/diff-merges.c
>> @@ -15,6 +15,11 @@ static void set_separate(struct rev_info *revs) {
>>         revs->separate_merges = 1;
>>  }
>>
>> +static void set_first_parent(struct rev_info *revs) {
>> +       set_separate(revs);
>> +       revs->first_parent_merges = 1;
>> +}
>> +
>>  static void set_m(struct rev_info *revs) {
>>         /*
>>          * To "diff-index", "-m" means "match missing", and to the "log"
>> @@ -38,11 +43,19 @@ static void set_dense_combined(struct rev_info *revs) {
>>  }
>>
>>  static void set_diff_merges(struct rev_info *revs, const char *optarg) {
>> -       if (!strcmp(optarg, "off")) {
>> +       if (0) ;
>
> Leftover cruft from some intermediate changes or something?

No. It's just an idiom for if-switch, making all the actual cases look
the same. Without this the first one looks special when in fact it
isn't. I won't die for it though.

>
>> +       else if (!strcmp(optarg, "off")   || !strcmp(optarg, "none"))
>>                 suppress(revs);
>> -       } else {
>> +       else if (!strcmp(optarg, "first") || !strcmp(optarg, "first-parent"))
>> +               set_first_parent(revs);
>> +       else if (!strcmp(optarg, "sep")   || !strcmp(optarg, "separate"))
>> +               set_separate(revs);
>> +       else if (!strcmp(optarg, "comb")  || !strcmp(optarg, "combined"))
>> +               set_combined(revs);
>> + else if (!strcmp(optarg, "dense") || !strcmp(optarg,
>> "dense-combined"))
>> +               set_dense_combined(revs);
>> +       else
>
> Not sure I like the special-casing for "sep" and "comb".  "dense"
> seems okay since it's a real word.

That was a poor-man attempt at unique shortcuts made by hand, as well as
a reminder to consider to re-write this using generic options framework
that will do it automagically. They are just a few first letters,
nothing more. That's why I didn't even document them.

> Since you're adding short versions of m, c, and cc later in the
> series, do we need these other special-case forms?

No, I don't think we do necessarily need them, but then they do no harm
either, so I didn't remove them when I added m, c, and cc. Neither was I
sure we do need these m, c, and cc in the first place.

Thanks,
-- Sergey

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

* Re: [PATCH v2 26/33] diff-merges: let new options enable diff without -p
  2020-12-18  6:12     ` Elijah Newren
@ 2020-12-18 14:42       ` Sergey Organov
  2020-12-18 17:01         ` Elijah Newren
  2020-12-20 19:07         ` Sergey Organov
  0 siblings, 2 replies; 232+ messages in thread
From: Sergey Organov @ 2020-12-18 14:42 UTC (permalink / raw)
  To: Elijah Newren; +Cc: Junio C Hamano, Jeff King, Philip Oakley, Git Mailing List

Elijah Newren <newren@gmail.com> writes:

> On Wed, Dec 16, 2020 at 10:50 AM Sergey Organov <sorganov@gmail.com> wrote:
>>
>> New options don't have any visible effect unless -p is either given or
>> implied, as unlike -c/-cc we don't imply -p with --diff-merges. To fix
>> this, this patch adds new functionality by letting new options enable
>> output of diffs for merge commits only.
>>
>> Add 'merges_need_diff' field and set it whenever diff output for merges is
>> enabled by any of the new options.
>>
>> Extend diff output logic accordingly, to output diffs for merges when
>> 'merges_need_diff' is set even when no -p has been provided.
>>
>> Signed-off-by: Sergey Organov <sorganov@gmail.com>
>> ---
>>  diff-merges.c | 16 ++++++++++------
>>  log-tree.c    | 13 +++++++++----
>>  revision.h    |  1 +
>>  3 files changed, 20 insertions(+), 10 deletions(-)
>>
>> diff --git a/diff-merges.c b/diff-merges.c
>> index 725db2312074..ffe20d8daa4a 100644
>> --- a/diff-merges.c
>> +++ b/diff-merges.c
>> @@ -10,6 +10,7 @@ static void suppress(struct rev_info *revs)
>>         revs->dense_combined_merges = 0;
>>         revs->combined_all_paths = 0;
>>         revs->combined_imply_patch = 0;
>> +       revs->merges_need_diff = 0;
>>  }
>>
>>  static void set_separate(struct rev_info *revs)
>> @@ -51,9 +52,11 @@ static void set_dense_combined(struct rev_info *revs)
>>
>>  static void set_diff_merges(struct rev_info *revs, const char *optarg)
>>  {
>
>> +       if (!strcmp(optarg, "off") || !strcmp(optarg, "none")) {
>> +               suppress(revs);
>> +               return;
>> +       }
>>         if (0) ;
>> -       else if (!strcmp(optarg, "off")   || !strcmp(optarg, "none"))
>> -               suppress(revs);
>
> The "if (0) ;" is still really weird.

An idiom (see my previous answer). I'm fine getting rid of it if you
guys find it weird (that I'm not).

>
>>         else if (!strcmp(optarg, "first") || !strcmp(optarg, "first-parent"))
>>                 set_first_parent(revs);
>>         else if (!strcmp(optarg, "sep")   || !strcmp(optarg, "separate"))
>> @@ -64,6 +67,7 @@ static void set_diff_merges(struct rev_info *revs, const char *optarg)
>>                 set_dense_combined(revs);
>>         else
>>                 die(_("unknown value for --diff-merges: %s"), optarg);
>> +       revs->merges_need_diff = 1;
>
> I'd put this above the if-else-else block, to make it clearer why you
> are returning early for the "off"/"none" case.

Yeah, makes sense, thanks!

>
>>  }
>>
>>  /*
>> @@ -132,12 +136,12 @@ void diff_merges_setup_revs(struct rev_info *revs)
>>                 revs->first_parent_merges = 0;
>>         if (revs->combined_all_paths && !revs->combine_merges)
>>                 die("--combined-all-paths makes no sense without -c or --cc");
>> -       if (revs->combine_merges)
>> +
>> +       if (revs->combined_imply_patch)
>>                 revs->diff = 1;
>> -       if (revs->combined_imply_patch) {
>> -               /* Turn --cc/-c into -p --cc/-c when -p was not given */
>> +
>> +       if (revs->combined_imply_patch || revs->merges_need_diff) {
>>                 if (!revs->diffopt.output_format)
>>                         revs->diffopt.output_format = DIFF_FORMAT_PATCH;
>>         }
>> -
>
> The random space changes squashed in here instead of being combined
> with the earlier patches that introduced the relevant areas break up
> the reading.  Would be nice to clean this up.
>
>>  }
>> diff --git a/log-tree.c b/log-tree.c
>> index f9385b1dae6f..67060492ca0a 100644
>> --- a/log-tree.c
>> +++ b/log-tree.c
>> @@ -899,15 +899,21 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log
>>         int showed_log;
>>         struct commit_list *parents;
>>         struct object_id *oid;
>> +       int is_merge;
>> +       int regulars_need_diff = opt->diff || opt->diffopt.flags.exit_with_status;
>
> So rev_info.diff has changed in meaning from
> commits-need-to-show-a-diff, to non-merge-commits-need-to-show-a-diff.
> That's a somewhat subtle semantic shift.  Perhaps it's worth adding a
> comment to the declaration of rev_info.diff to highlight this?  (And
> perhaps even rename the flag?)

No, the meaning of rev_info.diff hopefully didn't change. rev_info.diff
still enables all the commits to pass further once set. It is still
exactly the same old condition, just assigned to a variable for reuse.
My aim was to avoid touching existing logic of this function and only
add a new functionality when opt->merges_need_diff is set.

It looks like I rather choose confusing name for the variable, and it'd
be more clear if I'd call this, say:

  int need_diff = opt->diff || opt->diffopt.flags.exit_with_status;

?

What do you think?

>
>> -       if (!opt->diff && !opt->diffopt.flags.exit_with_status)
>> +       if (!regulars_need_diff && !opt->merges_need_diff)
>>                 return 0;
>>
>>         parse_commit_or_die(commit);
>>         oid = get_commit_tree_oid(commit);
>>
>> -       /* Root commit? */
>>         parents = get_saved_parents(opt, commit);
>> +       is_merge = parents && parents->next;
>> +       if(!is_merge && !regulars_need_diff)
>> +               return 0;
>> +
>> +       /* Root commit? */
>>         if (!parents) {
>>                 if (opt->show_root_diff) {
>>                         diff_root_tree_oid(oid, "", &opt->diffopt);
>> @@ -916,8 +922,7 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log
>>                 return !opt->loginfo;
>>         }
>>
>> -       /* More than one parent? */
>> -       if (parents->next) {
>> +       if (is_merge) {
>>                 if (opt->combine_merges)
>>                         return do_diff_combined(opt, commit);
>>                 if (opt->separate_merges) {
>> diff --git a/revision.h b/revision.h
>> index bfbae526ad6e..494d86142454 100644
>> --- a/revision.h
>> +++ b/revision.h
>> @@ -194,6 +194,7 @@ struct rev_info {
>>                         always_show_header:1,
>>                         /* Diff-merge flags */
>>                         explicit_diff_merges: 1,
>> +                       merges_need_diff: 1,
>>                         separate_merges: 1,
>>                         combine_merges:1,
>>                         combined_all_paths:1,
>> --
>> 2.25.1
>
> The rest makes sense.

Thanks,
-- Sergey


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

* Re: [PATCH v2 28/33] diff-merges: add '--diff-merges=1' as synonym for 'first-parent'
  2020-12-18  6:19     ` Elijah Newren
@ 2020-12-18 14:45       ` Sergey Organov
  0 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-12-18 14:45 UTC (permalink / raw)
  To: Elijah Newren; +Cc: Junio C Hamano, Jeff King, Philip Oakley, Git Mailing List

Elijah Newren <newren@gmail.com> writes:

> On Wed, Dec 16, 2020 at 10:50 AM Sergey Organov <sorganov@gmail.com> wrote:
>>
>> As we now have --diff-merges={m|c|cc}, add --diff-merges=1 as synonym
>> for --diff-merges=first-parent, to have shorter mnemonics for it as
>> well.
>
> In all the other cases, --diff-merges=<short> is equivalent to
> -<short>.  Here, --diff-merges=1 and -1 do _very_ different things.
> Is there any concern that might cause confusion?  (My gut reaction is
> this is probably fine and people won't try to make such a connection,
> but it made me worry just enough that I thought I'd flag it for you
> and other reviewers to at least mull over and maybe comment on.)

I wasn't sure about this myself, and that was one reason to make this
separate commit.

I think this one also came from the idea that one might want to have,
say, --diff-merges=2 in the future and get diff with respect to the
second parent.

Thanks,
-- Sergey

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

* Re: [PATCH v2 29/33] doc/git-log: describe new --diff-merges options
  2020-12-18  5:53     ` Elijah Newren
@ 2020-12-18 16:05       ` Sergey Organov
  2020-12-18 17:25         ` Elijah Newren
  0 siblings, 1 reply; 232+ messages in thread
From: Sergey Organov @ 2020-12-18 16:05 UTC (permalink / raw)
  To: Elijah Newren; +Cc: Junio C Hamano, Jeff King, Philip Oakley, Git Mailing List

Elijah Newren <newren@gmail.com> writes:

> On Wed, Dec 16, 2020 at 10:50 AM Sergey Organov <sorganov@gmail.com> wrote:
>>
>> Describe all the new --diff-merges options in the git-log.txt and
>> adopt description of originals accordingly.
>
> You also took care to explain interactions of options with -p that
> were previously undocumented, which is a nice bonus.  That wording
> could still be improved a bit, though, as noted below.
>
>> Signed-off-by: Sergey Organov <sorganov@gmail.com>
>> ---
>>  Documentation/git-log.txt | 85 ++++++++++++++++++++++++---------------
>>  1 file changed, 52 insertions(+), 33 deletions(-)
>>
>> diff --git a/Documentation/git-log.txt b/Documentation/git-log.txt
>> index 2b8ac5ff882a..27bc619490c6 100644
>> --- a/Documentation/git-log.txt
>> +++ b/Documentation/git-log.txt
>> @@ -120,45 +120,64 @@ DIFF FORMATTING
>>  By default, `git log` does not generate any diff output. The options
>>  below can be used to show the changes made by each commit.
>>
>> -Note that unless one of `-c`, `--cc`, or `-m` is given, merge commits
>> -will never show a diff, even if a diff format like `--patch` is
>> -selected, nor will they match search options like `-S`. The exception is
>> -when `--first-parent` is in use, in which merges are treated like normal
>> -single-parent commits (this can be overridden by providing a
>> -combined-diff option or with `--no-diff-merges`).
>> +Note that unless one of `--diff-merges` variants (including short
>> +`-m`, `-c`, and `--cc` options) is explicitly given, merge commits
>> +will not show a diff, even if a diff format like `--patch` is
>> +selected, nor will they match search options like `-S`. The exception
>> +is when `--first-parent` is in use, in which case `first-parent` is
>> +the default format.
>
> Thanks for fixing this up.  :-)

Don't mention it :-)

>
>>
>> --c::
>> -       With this option, diff output for a merge commit
>> -       shows the differences from each of the parents to the merge result
>> -       simultaneously instead of showing pairwise diff between a parent
>> -       and the result one at a time. Furthermore, it lists only files
>> -       which were modified from all parents.
>> -
>> ---cc::
>> -       This flag implies the `-c` option and further compresses the
>> -       patch output by omitting uninteresting hunks whose contents in
>> -       the parents have only two variants and the merge result picks
>> -       one of them without modification.
>> +--diff-merges=(off|none|first-parent|1|separate|m|combined|c|dense-combined|cc)::
>> +--no-diff-merges::
>> +       Specify diff format to be used for merge commits. Default is
>> +       `off` unless `--first-parent` is in use, in which case
>> +       `first-parent` is the default.
>> ++
>> +--diff-merges=(off|none):::
>> +--no-diff-merges:::
>> +       Disable output of diffs for merge commits. Useful to override
>> +       implied value.
>> ++
>> +--diff-merges=first-parent:::
>> +--diff-merges=1:::
>> +       This option makes merge commits show the full diff with
>> +       respect to the first parent only.
>
> Does it imply -p?

No, none of --diff-merges options do. This one is not any special. Why
the question?

>> ++
>> +--diff-merges=separate:::
>> +--diff-merges=m:::
>> +-m:::
>> +       This makes merge commits show the full diff with respect to
>> +       each of the parents. Separate log entry and diff is generated
>> +       for each parent. `-m` is different in that it doesn't produce
>> +       any output without `-p`.
>
> Different from what?  From --first-parent?  From flags that haven't
> been covered yet?  (-c and --cc show up below)

Well, from --diff-merges=m and --diff-merges=separate, that, as any
other --diff-merge option, do produce output (for merge commits) even
without -p.

>
>> ++
>> +--diff-merges=combined:::
>> +--diff-merges=c:::
>> +-c:::
>> +       With this option, diff output for a merge commit shows the
>> +       differences from each of the parents to the merge result
>> +       simultaneously instead of showing pairwise diff between a
>> +       parent and the result one at a time. Furthermore, it lists
>> +       only files which were modified from all parents. Historically,
>> +       `-c` enables diff output for non-merge commits as well.
>
> "Historically"?  Does that mean it doesn't anymore?

Eh, I don't think "historically" means that, but I'm not sure, being
non-native English speaker.

> (Maybe, "The short form, `-c`, also enables diff output for non-merge
> commits as well." or something like that?)

... and then try to explain why this otherwise illogical behavior is
there? I thought "historically" would cover that.

>
>> ++
>> +--diff-merges=dense-combined:::
>> +--diff-merges=cc:::
>> +--cc:::
>> +       With this option the output produced by
>> +       `--diff-merges=combined` is further compressed by omitting
>> +       uninteresting hunks whose contents in the parents have only
>> +       two variants and the merge result picks one of them without
>> +       modification.  Historically, `--c` enables diff output for
>> +       non-merge commits as well.
>
> Same note as above.

Yep.

>
>>  --combined-all-paths::
>>         This flag causes combined diffs (used for merge commits) to
>>         list the name of the file from all parents.  It thus only has
>> -       effect when -c or --cc are specified, and is likely only
>> -       useful if filename changes are detected (i.e. when either
>> -       rename or copy detection have been requested).
>> +       effect when `--diff-merges=[dense-]combined` is in use, and
>> +       is likely only useful if filename changes are detected (i.e.
>> +       when either rename or copy detection have been requested).
>>
>> --m::
>> -       This flag makes the merge commits show the full diff like
>> -       regular commits; for each merge parent, a separate log entry
>> -       and diff is generated. An exception is that only diff against
>> -       the first parent is shown when `--first-parent` option is given;
>> -       in that case, the output represents the changes the merge
>> -       brought _into_ the then-current branch.
>> -
>> ---diff-merges=off::
>> ---no-diff-merges::
>> -       Disable output of diffs for merge commits (default). Useful to
>> -       override `-m`, `-c`, or `--cc`.
>>
>>  :git-log: 1
>>  include::diff-options.txt[]
>> --
>> 2.25.1
>
> The rest looks good.

Thanks,
-- Sergey

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

* Re: [PATCH v2 23/33] diff-merges: fix style of functions definitions
  2020-12-18 13:41       ` Sergey Organov
@ 2020-12-18 16:12         ` Elijah Newren
  2020-12-18 21:23           ` Sergey Organov
  2020-12-19  1:41         ` Junio C Hamano
  1 sibling, 1 reply; 232+ messages in thread
From: Elijah Newren @ 2020-12-18 16:12 UTC (permalink / raw)
  To: Sergey Organov; +Cc: Junio C Hamano, Jeff King, Philip Oakley, Git Mailing List

On Fri, Dec 18, 2020 at 5:41 AM Sergey Organov <sorganov@gmail.com> wrote:
>
> Elijah Newren <newren@gmail.com> writes:
>
> > On Wed, Dec 16, 2020 at 10:50 AM Sergey Organov <sorganov@gmail.com> wrote:
> >>
> >> Put open curly brace on its own line
> >>
> >> Signed-off-by: Sergey Organov <sorganov@gmail.com>
> >> ---
> >>  diff-merges.c | 36 ++++++++++++++++++++++++------------
> >>  1 file changed, 24 insertions(+), 12 deletions(-)
> >>
> >> diff --git a/diff-merges.c b/diff-merges.c
> >> index cba391604ac7..0165fa22fcd1 100644
> >> --- a/diff-merges.c
> >> +++ b/diff-merges.c
> >> @@ -2,7 +2,8 @@
> >>
>
> [...]
>
> >>
> >> -void diff_merges_set_dense_combined_if_unset(struct rev_info *revs) {
> >> +void diff_merges_set_dense_combined_if_unset(struct rev_info *revs)
> >> +{
> >>         if (!revs->combine_merges)
> >>                 set_dense_combined(revs);
> >>  }
> >> --
> >> 2.25.1
> >>
> >
> > But...didn't you add all these functions yourself earlier in the
> > series?
>
> Yes, I did indeed and somehow picked wrong style from one of the
> occurrences of this style in the existing Git codebase.
>
> > Why didn't you split this patch up and squash it into the
> > relevant previous patches?
>
> When Junio noticed and pointed to this deficiency, I asked him if I
> should fix all the series from the start, or it'd be OK to use fixup
> commit. As he didn't answer and nobody else commented either, I opted
> for the latter.
>
> I can still do it if it's that essential, but I'd prefer not to, to
> avoid both the hand-work and causing entire series to change. The
> problem is that there were code movements in the series, so such a fix
> to earlier patches would cause conflicts down the commits chain, to be
> resolved by hand.

That's what add -p and interactive rebase is for.  :-)  Code is read
more than it is written, so it's important to get things clean.  And
not just for immediate reviewers, but for people who look at it later.

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

* Re: [PATCH v2 24/33] diff-merges: handle imply -p on -c/--cc logic for log.c
  2020-12-18 14:01       ` Sergey Organov
@ 2020-12-18 16:37         ` Elijah Newren
  2020-12-18 21:45           ` Sergey Organov
  0 siblings, 1 reply; 232+ messages in thread
From: Elijah Newren @ 2020-12-18 16:37 UTC (permalink / raw)
  To: Sergey Organov; +Cc: Junio C Hamano, Jeff King, Philip Oakley, Git Mailing List

On Fri, Dec 18, 2020 at 6:01 AM Sergey Organov <sorganov@gmail.com> wrote:
>
> Elijah Newren <newren@gmail.com> writes:
>
> > On Wed, Dec 16, 2020 at 10:50 AM Sergey Organov <sorganov@gmail.com> wrote:
> >>
> >> Move logic that handles implying -p on -c/--cc from
> >> log_setup_revisions_tweak() to diff_merges_setup_revs(), where it
> >> belongs.
> >
> > A very minor point, but I'd probably drop the "where it belongs";
> > while I think the new place makes sense for it, it reads to me like
> > you're either relying on a consensus to move it or implying there was
> > a mistake to not put it here previously, neither of which makes sense.
>
> Well, it was meant to be an excuse for not moving it there earlier in
> the patch series indeed. I just overlooked this piece of code that
> logically belongs to the diff-merges module. I think you need to
> consider the state of the sources right before this patch to see the
> point of phrasing it like this.
>
> That said, I'm fine removing this either.

If it should have been moved there earlier, then you should amend the
relevant previous commit instead of making a new one.  rebase -i is
your friend and should be used, especially with long patch series.
:-)

> > Much more importantly, this patch doesn't do what you said in
> > discussions on the previous round.  It'd be helpful if the commit
> > message called out that you are just moving the logic for now and that
> > a subsequent patch will tweak the logic to only trigger this for
> > -c/--cc and not for --diff-merges=.* flags.
>
> I believe this patch is useful by itself, even without any future
> improvements (that we actually discussed), if any, so I don't see the
> point in describing what this patch doesn't do.
>
> OTOH, the commit message seems to be clear enough to expect this patch
> to be pure refactoring, without any functional changes, no?

I'm just pointing out that reading the patch triggers a "wait, you
said you wanted to enable diffs for merges without diffs for regular
commits" reaction and makes reviewers start diving into the code to
check if they missed where that happened.  Sometimes they'll even
respond to the commit asking about it...and then read a later patch
and find the answer.  Perhaps I'm more attuned to this, because I've
done this to reviewers a number of times and they have asked me to add
a note in the earlier commit message to make it easier for other
reviewers to follow and read the series.  You don't need to describe
in full detail the subsequent changes that will come, just highlight
that they are coming to give reviewers an aid.  For example, this
could be as simple as:

"""
Move logic that handles implying -p on -c/--cc from
log_setup_revisions_tweak() to diff_merges_setup_revs().  A
subsequent commit will tweak this logic further.
"""

(Note that 'git log --grep=subsequent' in git.git will find you
several examples of where people have done this kind of thing.)

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

* Re: [PATCH v2 22/33] diff-merges: implement new values for --diff-merges
  2020-12-18 14:12       ` Sergey Organov
@ 2020-12-18 16:42         ` Elijah Newren
  2020-12-18 21:00           ` Sergey Organov
  0 siblings, 1 reply; 232+ messages in thread
From: Elijah Newren @ 2020-12-18 16:42 UTC (permalink / raw)
  To: Sergey Organov; +Cc: Junio C Hamano, Jeff King, Philip Oakley, Git Mailing List

On Fri, Dec 18, 2020 at 6:12 AM Sergey Organov <sorganov@gmail.com> wrote:
>
> Elijah Newren <newren@gmail.com> writes:
>
> > On Wed, Dec 16, 2020 at 10:50 AM Sergey Organov <sorganov@gmail.com> wrote:
> >>
> >> We first implement new options as exact synonyms for their original
> >> counterparts, to get all the infrastructure right, and keep functional
> >> improvements for later commits.
> >>
> >> The following values are implemented:
> >>
> >> --diff-merges=          old equivalent
> >> first|first-parent    = --first-parent (only format implications)
> >> sep|separate          = -m
> >> comb|combined         = -c
> >> dense| dense-combined = --cc
> >>
> >> Signed-off-by: Sergey Organov <sorganov@gmail.com>
> >> ---
> >>  diff-merges.c | 19 ++++++++++++++++---
> >>  1 file changed, 16 insertions(+), 3 deletions(-)
> >>
> >> diff --git a/diff-merges.c b/diff-merges.c
> >> index 6446e2093661..cba391604ac7 100644
> >> --- a/diff-merges.c
> >> +++ b/diff-merges.c
> >> @@ -15,6 +15,11 @@ static void set_separate(struct rev_info *revs) {
> >>         revs->separate_merges = 1;
> >>  }
> >>
> >> +static void set_first_parent(struct rev_info *revs) {
> >> +       set_separate(revs);
> >> +       revs->first_parent_merges = 1;
> >> +}
> >> +
> >>  static void set_m(struct rev_info *revs) {
> >>         /*
> >>          * To "diff-index", "-m" means "match missing", and to the "log"
> >> @@ -38,11 +43,19 @@ static void set_dense_combined(struct rev_info *revs) {
> >>  }
> >>
> >>  static void set_diff_merges(struct rev_info *revs, const char *optarg) {
> >> -       if (!strcmp(optarg, "off")) {
> >> +       if (0) ;
> >
> > Leftover cruft from some intermediate changes or something?
>
> No. It's just an idiom for if-switch, making all the actual cases look
> the same. Without this the first one looks special when in fact it
> isn't. I won't die for it though.
>
> >
> >> +       else if (!strcmp(optarg, "off")   || !strcmp(optarg, "none"))
> >>                 suppress(revs);
> >> -       } else {
> >> +       else if (!strcmp(optarg, "first") || !strcmp(optarg, "first-parent"))
> >> +               set_first_parent(revs);
> >> +       else if (!strcmp(optarg, "sep")   || !strcmp(optarg, "separate"))
> >> +               set_separate(revs);
> >> +       else if (!strcmp(optarg, "comb")  || !strcmp(optarg, "combined"))
> >> +               set_combined(revs);
> >> + else if (!strcmp(optarg, "dense") || !strcmp(optarg,
> >> "dense-combined"))
> >> +               set_dense_combined(revs);
> >> +       else
> >
> > Not sure I like the special-casing for "sep" and "comb".  "dense"
> > seems okay since it's a real word.
>
> That was a poor-man attempt at unique shortcuts made by hand, as well as
> a reminder to consider to re-write this using generic options framework
> that will do it automagically. They are just a few first letters,
> nothing more. That's why I didn't even document them.

Seems like a
   /* TODO: use generic options framework to allow abbreviations */
would make that intent much more clear.

> > Since you're adding short versions of m, c, and cc later in the
> > series, do we need these other special-case forms?
>
> No, I don't think we do necessarily need them, but then they do no harm
> either, so I didn't remove them when I added m, c, and cc. Neither was I
> sure we do need these m, c, and cc in the first place.

Well, I'd say it certainly adds clutter for reviewers, so there is at
least a little harm.  ;-)  It was on the patch that added m, c, and cc
that it particularly stood out to me, so I looked up the relevant
commit so that I could add the comment at the right place to make it
easier for you to rip out.

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

* Re: [PATCH v2 26/33] diff-merges: let new options enable diff without -p
  2020-12-18 14:42       ` Sergey Organov
@ 2020-12-18 17:01         ` Elijah Newren
  2020-12-18 20:32           ` Sergey Organov
                             ` (2 more replies)
  2020-12-20 19:07         ` Sergey Organov
  1 sibling, 3 replies; 232+ messages in thread
From: Elijah Newren @ 2020-12-18 17:01 UTC (permalink / raw)
  To: Sergey Organov; +Cc: Junio C Hamano, Jeff King, Philip Oakley, Git Mailing List

On Fri, Dec 18, 2020 at 6:42 AM Sergey Organov <sorganov@gmail.com> wrote:
>
> Elijah Newren <newren@gmail.com> writes:
>
> > On Wed, Dec 16, 2020 at 10:50 AM Sergey Organov <sorganov@gmail.com> wrote:
> >>
> >> New options don't have any visible effect unless -p is either given or
> >> implied, as unlike -c/-cc we don't imply -p with --diff-merges. To fix
> >> this, this patch adds new functionality by letting new options enable
> >> output of diffs for merge commits only.
> >>
> >> Add 'merges_need_diff' field and set it whenever diff output for merges is
> >> enabled by any of the new options.
> >>
> >> Extend diff output logic accordingly, to output diffs for merges when
> >> 'merges_need_diff' is set even when no -p has been provided.
> >>
> >> Signed-off-by: Sergey Organov <sorganov@gmail.com>
> >> ---
> >>  diff-merges.c | 16 ++++++++++------
> >>  log-tree.c    | 13 +++++++++----
> >>  revision.h    |  1 +
> >>  3 files changed, 20 insertions(+), 10 deletions(-)
> >>
> >> diff --git a/diff-merges.c b/diff-merges.c
> >> index 725db2312074..ffe20d8daa4a 100644
> >> --- a/diff-merges.c
> >> +++ b/diff-merges.c
> >> @@ -10,6 +10,7 @@ static void suppress(struct rev_info *revs)
> >>         revs->dense_combined_merges = 0;
> >>         revs->combined_all_paths = 0;
> >>         revs->combined_imply_patch = 0;
> >> +       revs->merges_need_diff = 0;
> >>  }
> >>
> >>  static void set_separate(struct rev_info *revs)
> >> @@ -51,9 +52,11 @@ static void set_dense_combined(struct rev_info *revs)
> >>
> >>  static void set_diff_merges(struct rev_info *revs, const char *optarg)
> >>  {
> >
> >> +       if (!strcmp(optarg, "off") || !strcmp(optarg, "none")) {
> >> +               suppress(revs);
> >> +               return;
> >> +       }
> >>         if (0) ;
> >> -       else if (!strcmp(optarg, "off")   || !strcmp(optarg, "none"))
> >> -               suppress(revs);
> >
> > The "if (0) ;" is still really weird.
>
> An idiom (see my previous answer). I'm fine getting rid of it if you
> guys find it weird (that I'm not).

I've never seen this idiom, and we apparently have no uses of it in
the code.  If it were near any code I was editing, I think I'd rip it
out as a preliminary cleanup patch...but maybe others have other
opinions.

> >
> >>         else if (!strcmp(optarg, "first") || !strcmp(optarg, "first-parent"))
> >>                 set_first_parent(revs);
> >>         else if (!strcmp(optarg, "sep")   || !strcmp(optarg, "separate"))
> >> @@ -64,6 +67,7 @@ static void set_diff_merges(struct rev_info *revs, const char *optarg)
> >>                 set_dense_combined(revs);
> >>         else
> >>                 die(_("unknown value for --diff-merges: %s"), optarg);
> >> +       revs->merges_need_diff = 1;
> >
> > I'd put this above the if-else-else block, to make it clearer why you
> > are returning early for the "off"/"none" case.
>
> Yeah, makes sense, thanks!
>
> >
> >>  }
> >>
> >>  /*
> >> @@ -132,12 +136,12 @@ void diff_merges_setup_revs(struct rev_info *revs)
> >>                 revs->first_parent_merges = 0;
> >>         if (revs->combined_all_paths && !revs->combine_merges)
> >>                 die("--combined-all-paths makes no sense without -c or --cc");
> >> -       if (revs->combine_merges)
> >> +
> >> +       if (revs->combined_imply_patch)
> >>                 revs->diff = 1;
> >> -       if (revs->combined_imply_patch) {
> >> -               /* Turn --cc/-c into -p --cc/-c when -p was not given */
> >> +
> >> +       if (revs->combined_imply_patch || revs->merges_need_diff) {
> >>                 if (!revs->diffopt.output_format)
> >>                         revs->diffopt.output_format = DIFF_FORMAT_PATCH;
> >>         }
> >> -
> >
> > The random space changes squashed in here instead of being combined
> > with the earlier patches that introduced the relevant areas break up
> > the reading.  Would be nice to clean this up.
> >
> >>  }
> >> diff --git a/log-tree.c b/log-tree.c
> >> index f9385b1dae6f..67060492ca0a 100644
> >> --- a/log-tree.c
> >> +++ b/log-tree.c
> >> @@ -899,15 +899,21 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log
> >>         int showed_log;
> >>         struct commit_list *parents;
> >>         struct object_id *oid;
> >> +       int is_merge;
> >> +       int regulars_need_diff = opt->diff || opt->diffopt.flags.exit_with_status;
> >
> > So rev_info.diff has changed in meaning from
> > commits-need-to-show-a-diff, to non-merge-commits-need-to-show-a-diff.
> > That's a somewhat subtle semantic shift.  Perhaps it's worth adding a
> > comment to the declaration of rev_info.diff to highlight this?  (And
> > perhaps even rename the flag?)
>
> No, the meaning of rev_info.diff hopefully didn't change. rev_info.diff
> still enables all the commits to pass further once set. It is still
> exactly the same old condition, just assigned to a variable for reuse.
> My aim was to avoid touching existing logic of this function and only
> add a new functionality when opt->merges_need_diff is set.
>
> It looks like I rather choose confusing name for the variable, and it'd
> be more clear if I'd call this, say:
>
>   int need_diff = opt->diff || opt->diffopt.flags.exit_with_status;
>
> ?
>
> What do you think?

I think need_diff would actually be confusing.  It can be false when
you need diffs (e.g. --diff-merges=cc with no -p, because then you'd
need diffs for merge commits and not for non-merge commits).  I'd
stick with your original local variable name.

Perhaps opt->diff hasn't changed meaning and I just had a wrong mental
model in my head for what it meant, but even then what seems like its
obvious purpose given its name is mismatched with what it actually
does.  Since you are already changing struct rev_info in this series,
this was more a note that a name change or at least a comment for
opt->diff might be useful.  I mean, you asked a couple times on the
previous series for help trying to understand it, and I could only
offer some flailing guesses and Junio responded with a couple bits of
history.  Clearly, it isn't very clear and this patch reminded me of
that and made me wonder if we're possibly making it a little harder
for others further down the road to figure out.

> >> -       if (!opt->diff && !opt->diffopt.flags.exit_with_status)
> >> +       if (!regulars_need_diff && !opt->merges_need_diff)
> >>                 return 0;
> >>
> >>         parse_commit_or_die(commit);
> >>         oid = get_commit_tree_oid(commit);
> >>
> >> -       /* Root commit? */
> >>         parents = get_saved_parents(opt, commit);
> >> +       is_merge = parents && parents->next;
> >> +       if(!is_merge && !regulars_need_diff)
> >> +               return 0;
> >> +
> >> +       /* Root commit? */
> >>         if (!parents) {
> >>                 if (opt->show_root_diff) {
> >>                         diff_root_tree_oid(oid, "", &opt->diffopt);
> >> @@ -916,8 +922,7 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log
> >>                 return !opt->loginfo;
> >>         }
> >>
> >> -       /* More than one parent? */
> >> -       if (parents->next) {
> >> +       if (is_merge) {
> >>                 if (opt->combine_merges)
> >>                         return do_diff_combined(opt, commit);
> >>                 if (opt->separate_merges) {
> >> diff --git a/revision.h b/revision.h
> >> index bfbae526ad6e..494d86142454 100644
> >> --- a/revision.h
> >> +++ b/revision.h
> >> @@ -194,6 +194,7 @@ struct rev_info {
> >>                         always_show_header:1,
> >>                         /* Diff-merge flags */
> >>                         explicit_diff_merges: 1,
> >> +                       merges_need_diff: 1,
> >>                         separate_merges: 1,
> >>                         combine_merges:1,
> >>                         combined_all_paths:1,
> >> --
> >> 2.25.1
> >
> > The rest makes sense.
>
> Thanks,
> -- Sergey

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

* Re: [PATCH v2 29/33] doc/git-log: describe new --diff-merges options
  2020-12-18 16:05       ` Sergey Organov
@ 2020-12-18 17:25         ` Elijah Newren
  2020-12-18 22:11           ` Sergey Organov
  0 siblings, 1 reply; 232+ messages in thread
From: Elijah Newren @ 2020-12-18 17:25 UTC (permalink / raw)
  To: Sergey Organov; +Cc: Junio C Hamano, Jeff King, Philip Oakley, Git Mailing List

On Fri, Dec 18, 2020 at 8:05 AM Sergey Organov <sorganov@gmail.com> wrote:
>
> Elijah Newren <newren@gmail.com> writes:
>
> > On Wed, Dec 16, 2020 at 10:50 AM Sergey Organov <sorganov@gmail.com> wrote:
> >>
> >> Describe all the new --diff-merges options in the git-log.txt and
> >> adopt description of originals accordingly.
> >
> > You also took care to explain interactions of options with -p that
> > were previously undocumented, which is a nice bonus.  That wording
> > could still be improved a bit, though, as noted below.
> >
> >> Signed-off-by: Sergey Organov <sorganov@gmail.com>
> >> ---
> >>  Documentation/git-log.txt | 85 ++++++++++++++++++++++++---------------
> >>  1 file changed, 52 insertions(+), 33 deletions(-)
> >>
> >> diff --git a/Documentation/git-log.txt b/Documentation/git-log.txt
> >> index 2b8ac5ff882a..27bc619490c6 100644
> >> --- a/Documentation/git-log.txt
> >> +++ b/Documentation/git-log.txt
> >> @@ -120,45 +120,64 @@ DIFF FORMATTING
> >>  By default, `git log` does not generate any diff output. The options
> >>  below can be used to show the changes made by each commit.
> >>
> >> -Note that unless one of `-c`, `--cc`, or `-m` is given, merge commits
> >> -will never show a diff, even if a diff format like `--patch` is
> >> -selected, nor will they match search options like `-S`. The exception is
> >> -when `--first-parent` is in use, in which merges are treated like normal
> >> -single-parent commits (this can be overridden by providing a
> >> -combined-diff option or with `--no-diff-merges`).
> >> +Note that unless one of `--diff-merges` variants (including short
> >> +`-m`, `-c`, and `--cc` options) is explicitly given, merge commits
> >> +will not show a diff, even if a diff format like `--patch` is
> >> +selected, nor will they match search options like `-S`. The exception
> >> +is when `--first-parent` is in use, in which case `first-parent` is
> >> +the default format.
> >
> > Thanks for fixing this up.  :-)
>
> Don't mention it :-)
>
> >
> >>
> >> --c::
> >> -       With this option, diff output for a merge commit
> >> -       shows the differences from each of the parents to the merge result
> >> -       simultaneously instead of showing pairwise diff between a parent
> >> -       and the result one at a time. Furthermore, it lists only files
> >> -       which were modified from all parents.
> >> -
> >> ---cc::
> >> -       This flag implies the `-c` option and further compresses the
> >> -       patch output by omitting uninteresting hunks whose contents in
> >> -       the parents have only two variants and the merge result picks
> >> -       one of them without modification.
> >> +--diff-merges=(off|none|first-parent|1|separate|m|combined|c|dense-combined|cc)::
> >> +--no-diff-merges::
> >> +       Specify diff format to be used for merge commits. Default is
> >> +       `off` unless `--first-parent` is in use, in which case
> >> +       `first-parent` is the default.
> >> ++
> >> +--diff-merges=(off|none):::
> >> +--no-diff-merges:::
> >> +       Disable output of diffs for merge commits. Useful to override
> >> +       implied value.
> >> ++
> >> +--diff-merges=first-parent:::
> >> +--diff-merges=1:::
> >> +       This option makes merge commits show the full diff with
> >> +       respect to the first parent only.
> >
> > Does it imply -p?
>
> No, none of --diff-merges options do. This one is not any special. Why
> the question?

The documentation on -m was vague enough that it made me wonder.
Fixing it would probably prevent me from having asked this question.

> >> ++
> >> +--diff-merges=separate:::
> >> +--diff-merges=m:::
> >> +-m:::
> >> +       This makes merge commits show the full diff with respect to
> >> +       each of the parents. Separate log entry and diff is generated
> >> +       for each parent. `-m` is different in that it doesn't produce
> >> +       any output without `-p`.
> >
> > Different from what?  From --first-parent?  From flags that haven't
> > been covered yet?  (-c and --cc show up below)
>
> Well, from --diff-merges=m and --diff-merges=separate, that, as any
> other --diff-merge option, do produce output (for merge commits) even
> without -p.

That wasn't at all clear to me as the intent of the last sentence.

> >> ++
> >> +--diff-merges=combined:::
> >> +--diff-merges=c:::
> >> +-c:::
> >> +       With this option, diff output for a merge commit shows the
> >> +       differences from each of the parents to the merge result
> >> +       simultaneously instead of showing pairwise diff between a
> >> +       parent and the result one at a time. Furthermore, it lists
> >> +       only files which were modified from all parents. Historically,
> >> +       `-c` enables diff output for non-merge commits as well.
> >
> > "Historically"?  Does that mean it doesn't anymore?
>
> Eh, I don't think "historically" means that, but I'm not sure, being
> non-native English speaker.

Sometimes non-native speakers use the language more accurately.  This
might be such a case, but that sentence did make me think you might be
attempting to document past behavior as a way of helping people adjust
to current/new behavior.

> > (Maybe, "The short form, `-c`, also enables diff output for non-merge
> > commits as well." or something like that?)
>
> ... and then try to explain why this otherwise illogical behavior is
> there? I thought "historically" would cover that.

It doesn't seem like illogical behavior to me.   Perhaps the view of
-c as a diff-merges option, reinforced by placing -c right next to
--diff-merges in the documentation, is what causes you to think so?
If so, maybe we should document -c (and --cc) separately after all the
--diff-merges options, using something like the following:

-c:::
    Implies both --patch and --diff-merges=combined, i.e. turn on
patches for normal commits and show a combined diff format for merges.

> >
> >> ++
> >> +--diff-merges=dense-combined:::
> >> +--diff-merges=cc:::
> >> +--cc:::
> >> +       With this option the output produced by
> >> +       `--diff-merges=combined` is further compressed by omitting
> >> +       uninteresting hunks whose contents in the parents have only
> >> +       two variants and the merge result picks one of them without
> >> +       modification.  Historically, `--c` enables diff output for
> >> +       non-merge commits as well.
> >
> > Same note as above.
>
> Yep.
>
> >
> >>  --combined-all-paths::
> >>         This flag causes combined diffs (used for merge commits) to
> >>         list the name of the file from all parents.  It thus only has
> >> -       effect when -c or --cc are specified, and is likely only
> >> -       useful if filename changes are detected (i.e. when either
> >> -       rename or copy detection have been requested).
> >> +       effect when `--diff-merges=[dense-]combined` is in use, and
> >> +       is likely only useful if filename changes are detected (i.e.
> >> +       when either rename or copy detection have been requested).
> >>
> >> --m::
> >> -       This flag makes the merge commits show the full diff like
> >> -       regular commits; for each merge parent, a separate log entry
> >> -       and diff is generated. An exception is that only diff against
> >> -       the first parent is shown when `--first-parent` option is given;
> >> -       in that case, the output represents the changes the merge
> >> -       brought _into_ the then-current branch.
> >> -
> >> ---diff-merges=off::
> >> ---no-diff-merges::
> >> -       Disable output of diffs for merge commits (default). Useful to
> >> -       override `-m`, `-c`, or `--cc`.
> >>
> >>  :git-log: 1
> >>  include::diff-options.txt[]
> >> --
> >> 2.25.1
> >
> > The rest looks good.
>
> Thanks,
> -- Sergey

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

* Re: [PATCH v2 26/33] diff-merges: let new options enable diff without -p
  2020-12-18 17:01         ` Elijah Newren
@ 2020-12-18 20:32           ` Sergey Organov
  2020-12-18 22:06             ` Elijah Newren
  2020-12-18 20:53           ` Sergey Organov
  2020-12-19 12:11           ` Sergey Organov
  2 siblings, 1 reply; 232+ messages in thread
From: Sergey Organov @ 2020-12-18 20:32 UTC (permalink / raw)
  To: Elijah Newren; +Cc: Junio C Hamano, Jeff King, Philip Oakley, Git Mailing List

Elijah Newren <newren@gmail.com> writes:

> On Fri, Dec 18, 2020 at 6:42 AM Sergey Organov <sorganov@gmail.com> wrote:
>>
>> Elijah Newren <newren@gmail.com> writes:
>>
>> > On Wed, Dec 16, 2020 at 10:50 AM Sergey Organov <sorganov@gmail.com> wrote:

[...]

>> >> diff --git a/log-tree.c b/log-tree.c
>> >> index f9385b1dae6f..67060492ca0a 100644
>> >> --- a/log-tree.c
>> >> +++ b/log-tree.c
>> >> @@ -899,15 +899,21 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log
>> >>         int showed_log;
>> >>         struct commit_list *parents;
>> >>         struct object_id *oid;
>> >> +       int is_merge;
>> >> +       int regulars_need_diff = opt->diff || opt->diffopt.flags.exit_with_status;
>> >
>> > So rev_info.diff has changed in meaning from
>> > commits-need-to-show-a-diff, to non-merge-commits-need-to-show-a-diff.
>> > That's a somewhat subtle semantic shift.  Perhaps it's worth adding a
>> > comment to the declaration of rev_info.diff to highlight this?  (And
>> > perhaps even rename the flag?)
>>
>> No, the meaning of rev_info.diff hopefully didn't change. rev_info.diff
>> still enables all the commits to pass further once set. It is still
>> exactly the same old condition, just assigned to a variable for reuse.
>> My aim was to avoid touching existing logic of this function and only
>> add a new functionality when opt->merges_need_diff is set.
>>
>> It looks like I rather choose confusing name for the variable, and it'd
>> be more clear if I'd call this, say:
>>
>>   int need_diff = opt->diff || opt->diffopt.flags.exit_with_status;
>>
>> ?
>>
>> What do you think?
>
> I think need_diff would actually be confusing.  It can be false when
> you need diffs (e.g. --diff-merges=cc with no -p, because then you'd
> need diffs for merge commits and not for non-merge commits).  I'd
> stick with your original local variable name.
>
> Perhaps opt->diff hasn't changed meaning and I just had a wrong mental
> model in my head for what it meant, but even then what seems like its
> obvious purpose given its name is mismatched with what it actually
> does.  Since you are already changing struct rev_info in this series,
> this was more a note that a name change or at least a comment for
> opt->diff might be useful.  I mean, you asked a couple times on the
> previous series for help trying to understand it, and I could only
> offer some flailing guesses and Junio responded with a couple bits of
> history.  Clearly, it isn't very clear and this patch reminded me of
> that and made me wonder if we're possibly making it a little harder
> for others further down the road to figure out.

I still don't see why opt->diff is needed in the first place, and
second, why opt->diffopt.flags.exit_with_status check is here? Why
whoever sets opt->diffopt.flags.exit_with_status doesn't just set
opt->diff as well (provided opt->diff is needed in the first place)?

From the aforementioned discussion it looks like opt->diff is an
optimization (maybe a remnant from the times when diff was a separate
script), and that apparently there is some code instance somewhere that
actually relies on the fact that clearing opt->diff is enough to disable
diff machinery (as followed from my experiment of removing the check
altogether and then getting only single seemingly unrelated test
failing.)

Overall, neither have I any idea how to clarify this, nor do I want to
bother in this patch series. It'd be nice though if somebody who really
does understand diff machinery in Git does the job.

Thanks,
-- Sergey

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

* Re: [PATCH v2 26/33] diff-merges: let new options enable diff without -p
  2020-12-18 17:01         ` Elijah Newren
  2020-12-18 20:32           ` Sergey Organov
@ 2020-12-18 20:53           ` Sergey Organov
  2020-12-19 12:11           ` Sergey Organov
  2 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-12-18 20:53 UTC (permalink / raw)
  To: Elijah Newren; +Cc: Junio C Hamano, Jeff King, Philip Oakley, Git Mailing List

Elijah Newren <newren@gmail.com> writes:

> On Fri, Dec 18, 2020 at 6:42 AM Sergey Organov <sorganov@gmail.com> wrote:
>>
>> Elijah Newren <newren@gmail.com> writes:
>>
>> > On Wed, Dec 16, 2020 at 10:50 AM Sergey Organov <sorganov@gmail.com> wrote:
>> >>
>> >> New options don't have any visible effect unless -p is either given or
>> >> implied, as unlike -c/-cc we don't imply -p with --diff-merges. To fix
>> >> this, this patch adds new functionality by letting new options enable
>> >> output of diffs for merge commits only.
>> >>
>> >> Add 'merges_need_diff' field and set it whenever diff output for merges is
>> >> enabled by any of the new options.
>> >>
>> >> Extend diff output logic accordingly, to output diffs for merges when
>> >> 'merges_need_diff' is set even when no -p has been provided.
>> >>
>> >> Signed-off-by: Sergey Organov <sorganov@gmail.com>
>> >> ---
>> >>  diff-merges.c | 16 ++++++++++------
>> >>  log-tree.c    | 13 +++++++++----
>> >>  revision.h    |  1 +
>> >>  3 files changed, 20 insertions(+), 10 deletions(-)
>> >>
>> >> diff --git a/diff-merges.c b/diff-merges.c
>> >> index 725db2312074..ffe20d8daa4a 100644
>> >> --- a/diff-merges.c
>> >> +++ b/diff-merges.c
>> >> @@ -10,6 +10,7 @@ static void suppress(struct rev_info *revs)
>> >>         revs->dense_combined_merges = 0;
>> >>         revs->combined_all_paths = 0;
>> >>         revs->combined_imply_patch = 0;
>> >> +       revs->merges_need_diff = 0;
>> >>  }
>> >>
>> >>  static void set_separate(struct rev_info *revs)
>> >> @@ -51,9 +52,11 @@ static void set_dense_combined(struct rev_info *revs)
>> >>
>> >>  static void set_diff_merges(struct rev_info *revs, const char *optarg)
>> >>  {
>> >
>> >> +       if (!strcmp(optarg, "off") || !strcmp(optarg, "none")) {
>> >> +               suppress(revs);
>> >> +               return;
>> >> +       }
>> >>         if (0) ;
>> >> -       else if (!strcmp(optarg, "off")   || !strcmp(optarg, "none"))
>> >> -               suppress(revs);
>> >
>> > The "if (0) ;" is still really weird.
>>
>> An idiom (see my previous answer). I'm fine getting rid of it if you
>> guys find it weird (that I'm not).
>
> I've never seen this idiom, and we apparently have no uses of it in
> the code.  If it were near any code I was editing, I think I'd rip it
> out as a preliminary cleanup patch...but maybe others have other
> opinions.

Essentially, this is poor man replacement for non-existent:

    switch(s) {
      case "str11": case "str12":
         do_things1(); break;
      case "str21": case "str22":
         do_things2(); break;
      case "str31": case "str32":
         do_things3(); break;
      default:
         default(); break
    }

Notice that all the case statements, except the last one, look the same,
while with bare "if() else" constructs you get the first one looking
special:

    if (!strcmp(s, "str11") || !strcmp(s, "str12"))
       do_things1();
    else if (!strcmp(s, "str21") || !strcmp(s, "str22"))
       do_things2();
    else if (!strcmp(s, "str31") || !strcmp(s, "str32"))
       do_things3();
    else
       default();

Now, fixing it is as easy as:

    if (0);
    else if (!strcmp(s, "str11") || !strcmp(s, "str12"))
       do_things1();
    else if (!strcmp(s, "str21") || !strcmp(s, "str22"))
       do_things2();
    else if (!strcmp(s, "str31") || !strcmp(s, "str32"))
       do_things3();
    else
       default();

and it makes reordering and #ifdefing slightly less painful as well.

Just saying rather, than insisting on adopting or even accepting it for
the Git codebase.

Thanks,
-- Sergey

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

* Re: [PATCH v2 22/33] diff-merges: implement new values for --diff-merges
  2020-12-18 16:42         ` Elijah Newren
@ 2020-12-18 21:00           ` Sergey Organov
  0 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-12-18 21:00 UTC (permalink / raw)
  To: Elijah Newren; +Cc: Junio C Hamano, Jeff King, Philip Oakley, Git Mailing List

Elijah Newren <newren@gmail.com> writes:

> On Fri, Dec 18, 2020 at 6:12 AM Sergey Organov <sorganov@gmail.com> wrote:
>>
>> Elijah Newren <newren@gmail.com> writes:
>>
>> > On Wed, Dec 16, 2020 at 10:50 AM Sergey Organov <sorganov@gmail.com> wrote:
>> >>
>> >> We first implement new options as exact synonyms for their original
>> >> counterparts, to get all the infrastructure right, and keep functional
>> >> improvements for later commits.
>> >>
>> >> The following values are implemented:
>> >>
>> >> --diff-merges=          old equivalent
>> >> first|first-parent    = --first-parent (only format implications)
>> >> sep|separate          = -m
>> >> comb|combined         = -c
>> >> dense| dense-combined = --cc
>> >>
>> >> Signed-off-by: Sergey Organov <sorganov@gmail.com>
>> >> ---
>> >>  diff-merges.c | 19 ++++++++++++++++---
>> >>  1 file changed, 16 insertions(+), 3 deletions(-)
>> >>
>> >> diff --git a/diff-merges.c b/diff-merges.c
>> >> index 6446e2093661..cba391604ac7 100644
>> >> --- a/diff-merges.c
>> >> +++ b/diff-merges.c
>> >> @@ -15,6 +15,11 @@ static void set_separate(struct rev_info *revs) {
>> >>         revs->separate_merges = 1;
>> >>  }
>> >>
>> >> +static void set_first_parent(struct rev_info *revs) {
>> >> +       set_separate(revs);
>> >> +       revs->first_parent_merges = 1;
>> >> +}
>> >> +
>> >>  static void set_m(struct rev_info *revs) {
>> >>         /*
>> >>          * To "diff-index", "-m" means "match missing", and to the "log"
>> >> @@ -38,11 +43,19 @@ static void set_dense_combined(struct rev_info *revs) {
>> >>  }
>> >>
>> >>  static void set_diff_merges(struct rev_info *revs, const char *optarg) {
>> >> -       if (!strcmp(optarg, "off")) {
>> >> +       if (0) ;
>> >
>> > Leftover cruft from some intermediate changes or something?
>>
>> No. It's just an idiom for if-switch, making all the actual cases look
>> the same. Without this the first one looks special when in fact it
>> isn't. I won't die for it though.
>>
>> >
>> >> +       else if (!strcmp(optarg, "off")   || !strcmp(optarg, "none"))
>> >>                 suppress(revs);
>> >> -       } else {
>> >> + else if (!strcmp(optarg, "first") || !strcmp(optarg,
>> >> "first-parent"))
>> >> +               set_first_parent(revs);
>> >> +       else if (!strcmp(optarg, "sep")   || !strcmp(optarg, "separate"))
>> >> +               set_separate(revs);
>> >> +       else if (!strcmp(optarg, "comb")  || !strcmp(optarg, "combined"))
>> >> +               set_combined(revs);
>> >> + else if (!strcmp(optarg, "dense") || !strcmp(optarg,
>> >> "dense-combined"))
>> >> +               set_dense_combined(revs);
>> >> +       else
>> >
>> > Not sure I like the special-casing for "sep" and "comb".  "dense"
>> > seems okay since it's a real word.
>>
>> That was a poor-man attempt at unique shortcuts made by hand, as well as
>> a reminder to consider to re-write this using generic options framework
>> that will do it automagically. They are just a few first letters,
>> nothing more. That's why I didn't even document them.
>
> Seems like a
>    /* TODO: use generic options framework to allow abbreviations */
> would make that intent much more clear.
>
>> > Since you're adding short versions of m, c, and cc later in the
>> > series, do we need these other special-case forms?
>>
>> No, I don't think we do necessarily need them, but then they do no harm
>> either, so I didn't remove them when I added m, c, and cc. Neither was I
>> sure we do need these m, c, and cc in the first place.
>
> Well, I'd say it certainly adds clutter for reviewers, so there is at
> least a little harm.  ;-)  It was on the patch that added m, c, and cc
> that it particularly stood out to me, so I looked up the relevant
> commit so that I could add the comment at the right place to make it
> easier for you to rip out.

May that's because they did make sense before the patch that added m, c,
and cc, where they stood out for you.

Overall, if we do agree m, c, and cc mnemonics are good to have, I'd opt
for removing these hand-made abbrevs indeed.

Thanks,
-- Sergey

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

* Re: [PATCH v2 23/33] diff-merges: fix style of functions definitions
  2020-12-18 16:12         ` Elijah Newren
@ 2020-12-18 21:23           ` Sergey Organov
  2020-12-18 22:56             ` Elijah Newren
  0 siblings, 1 reply; 232+ messages in thread
From: Sergey Organov @ 2020-12-18 21:23 UTC (permalink / raw)
  To: Elijah Newren; +Cc: Junio C Hamano, Jeff King, Philip Oakley, Git Mailing List

Elijah Newren <newren@gmail.com> writes:

> On Fri, Dec 18, 2020 at 5:41 AM Sergey Organov <sorganov@gmail.com> wrote:
>>
>> Elijah Newren <newren@gmail.com> writes:
>>
>> > On Wed, Dec 16, 2020 at 10:50 AM Sergey Organov <sorganov@gmail.com> wrote:
>> >>
>> >> Put open curly brace on its own line
>> >>
>> >> Signed-off-by: Sergey Organov <sorganov@gmail.com>
>> >> ---
>> >>  diff-merges.c | 36 ++++++++++++++++++++++++------------
>> >>  1 file changed, 24 insertions(+), 12 deletions(-)
>> >>
>> >> diff --git a/diff-merges.c b/diff-merges.c
>> >> index cba391604ac7..0165fa22fcd1 100644
>> >> --- a/diff-merges.c
>> >> +++ b/diff-merges.c
>> >> @@ -2,7 +2,8 @@
>> >>
>>
>> [...]
>>
>> >>
>> >> -void diff_merges_set_dense_combined_if_unset(struct rev_info *revs) {
>> >> +void diff_merges_set_dense_combined_if_unset(struct rev_info *revs)
>> >> +{
>> >>         if (!revs->combine_merges)
>> >>                 set_dense_combined(revs);
>> >>  }
>> >> --
>> >> 2.25.1
>> >>
>> >
>> > But...didn't you add all these functions yourself earlier in the
>> > series?
>>
>> Yes, I did indeed and somehow picked wrong style from one of the
>> occurrences of this style in the existing Git codebase.
>>
>> > Why didn't you split this patch up and squash it into the
>> > relevant previous patches?
>>
>> When Junio noticed and pointed to this deficiency, I asked him if I
>> should fix all the series from the start, or it'd be OK to use fixup
>> commit. As he didn't answer and nobody else commented either, I opted
>> for the latter.
>>
>> I can still do it if it's that essential, but I'd prefer not to, to
>> avoid both the hand-work and causing entire series to change. The
>> problem is that there were code movements in the series, so such a fix
>> to earlier patches would cause conflicts down the commits chain, to be
>> resolved by hand.
>
> That's what add -p and interactive rebase is for.  :-)  Code is read
> more than it is written, so it's important to get things clean.  And
> not just for immediate reviewers, but for people who look at it later.

I do know how to do it, but I'd still prefer it to be accepted in its
current form, as I don't see this particular case being that important
to justify rewriting of all the series. I'll go through the pain if
it's a show-stopper though.

Thanks,
-- Sergey

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

* Re: [PATCH v2 24/33] diff-merges: handle imply -p on -c/--cc logic for log.c
  2020-12-18 16:37         ` Elijah Newren
@ 2020-12-18 21:45           ` Sergey Organov
  2020-12-18 22:12             ` Elijah Newren
  0 siblings, 1 reply; 232+ messages in thread
From: Sergey Organov @ 2020-12-18 21:45 UTC (permalink / raw)
  To: Elijah Newren; +Cc: Junio C Hamano, Jeff King, Philip Oakley, Git Mailing List

Elijah Newren <newren@gmail.com> writes:

> On Fri, Dec 18, 2020 at 6:01 AM Sergey Organov <sorganov@gmail.com> wrote:
>>
>> Elijah Newren <newren@gmail.com> writes:
>>
>> > On Wed, Dec 16, 2020 at 10:50 AM Sergey Organov <sorganov@gmail.com> wrote:
>> >>
>> >> Move logic that handles implying -p on -c/--cc from
>> >> log_setup_revisions_tweak() to diff_merges_setup_revs(), where it
>> >> belongs.
>> >
>> > A very minor point, but I'd probably drop the "where it belongs";
>> > while I think the new place makes sense for it, it reads to me like
>> > you're either relying on a consensus to move it or implying there was
>> > a mistake to not put it here previously, neither of which makes sense.
>>
>> Well, it was meant to be an excuse for not moving it there earlier in
>> the patch series indeed. I just overlooked this piece of code that
>> logically belongs to the diff-merges module. I think you need to
>> consider the state of the sources right before this patch to see the
>> point of phrasing it like this.
>>
>> That said, I'm fine removing this either.
>
> If it should have been moved there earlier, then you should amend the
> relevant previous commit instead of making a new one.  rebase -i is
> your friend and should be used, especially with long patch series.
> :-)

This is to be a separate commit anyway. I can move the commit itself
more closer to the beginning, but I don't see how it'd make things
any better.

By "earlier" above I mostly meant that I should have noticed and moved
it in the first issue or the patch series.

>
>> > Much more importantly, this patch doesn't do what you said in
>> > discussions on the previous round.  It'd be helpful if the commit
>> > message called out that you are just moving the logic for now and that
>> > a subsequent patch will tweak the logic to only trigger this for
>> > -c/--cc and not for --diff-merges=.* flags.
>>
>> I believe this patch is useful by itself, even without any future
>> improvements (that we actually discussed), if any, so I don't see the
>> point in describing what this patch doesn't do.
>>
>> OTOH, the commit message seems to be clear enough to expect this patch
>> to be pure refactoring, without any functional changes, no?
>
> I'm just pointing out that reading the patch triggers a "wait, you
> said you wanted to enable diffs for merges without diffs for regular
> commits" reaction and makes reviewers start diving into the code to
> check if they missed where that happened.  Sometimes they'll even
> respond to the commit asking about it...and then read a later patch
> and find the answer.  Perhaps I'm more attuned to this, because I've
> done this to reviewers a number of times and they have asked me to add
> a note in the earlier commit message to make it easier for other
> reviewers to follow and read the series.  You don't need to describe
> in full detail the subsequent changes that will come, just highlight
> that they are coming to give reviewers an aid.  For example, this
> could be as simple as:
>
> """
> Move logic that handles implying -p on -c/--cc from
> log_setup_revisions_tweak() to diff_merges_setup_revs().  A
> subsequent commit will tweak this logic further.
> """

I think I see what you mean, but I still don't like this, sorry, as:

First, this commit doesn't tweak the logic at all, so "further" doesn't
sound right.

Second, the purpose of this move is not to have subsequent commits that
will tweak this logic further in any particular way. One of the aims of
this commit is rather to make it more simple to have /any/ further
tweaks to the logic.

Third, if the "tweak" you mention is not accepted, I'd need not to only
get rid of the tweaking commit, but not to forget to edit the
description of this one, that is basically unrelated?

>
> (Note that 'git log --grep=subsequent' in git.git will find you
> several examples of where people have done this kind of thing.)

Yeah, I agree it's useful when commits are tightly coupled and thus the
purpose of single commit is unclear. I just don't think this one is such
a case.

Thanks,
-- Sergey

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

* Re: [PATCH v2 26/33] diff-merges: let new options enable diff without -p
  2020-12-18 20:32           ` Sergey Organov
@ 2020-12-18 22:06             ` Elijah Newren
  2020-12-18 22:19               ` Sergey Organov
  0 siblings, 1 reply; 232+ messages in thread
From: Elijah Newren @ 2020-12-18 22:06 UTC (permalink / raw)
  To: Sergey Organov; +Cc: Junio C Hamano, Jeff King, Philip Oakley, Git Mailing List

On Fri, Dec 18, 2020 at 12:32 PM Sergey Organov <sorganov@gmail.com> wrote:
>
> Elijah Newren <newren@gmail.com> writes:
>
> > On Fri, Dec 18, 2020 at 6:42 AM Sergey Organov <sorganov@gmail.com> wrote:
> >>
> >> Elijah Newren <newren@gmail.com> writes:
> >>
> >> > On Wed, Dec 16, 2020 at 10:50 AM Sergey Organov <sorganov@gmail.com> wrote:
>
> [...]
>
> >> >> diff --git a/log-tree.c b/log-tree.c
> >> >> index f9385b1dae6f..67060492ca0a 100644
> >> >> --- a/log-tree.c
> >> >> +++ b/log-tree.c
> >> >> @@ -899,15 +899,21 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log
> >> >>         int showed_log;
> >> >>         struct commit_list *parents;
> >> >>         struct object_id *oid;
> >> >> +       int is_merge;
> >> >> +       int regulars_need_diff = opt->diff || opt->diffopt.flags.exit_with_status;
> >> >
> >> > So rev_info.diff has changed in meaning from
> >> > commits-need-to-show-a-diff, to non-merge-commits-need-to-show-a-diff.
> >> > That's a somewhat subtle semantic shift.  Perhaps it's worth adding a
> >> > comment to the declaration of rev_info.diff to highlight this?  (And
> >> > perhaps even rename the flag?)
> >>
> >> No, the meaning of rev_info.diff hopefully didn't change. rev_info.diff
> >> still enables all the commits to pass further once set. It is still
> >> exactly the same old condition, just assigned to a variable for reuse.
> >> My aim was to avoid touching existing logic of this function and only
> >> add a new functionality when opt->merges_need_diff is set.
> >>
> >> It looks like I rather choose confusing name for the variable, and it'd
> >> be more clear if I'd call this, say:
> >>
> >>   int need_diff = opt->diff || opt->diffopt.flags.exit_with_status;
> >>
> >> ?
> >>
> >> What do you think?
> >
> > I think need_diff would actually be confusing.  It can be false when
> > you need diffs (e.g. --diff-merges=cc with no -p, because then you'd
> > need diffs for merge commits and not for non-merge commits).  I'd
> > stick with your original local variable name.
> >
> > Perhaps opt->diff hasn't changed meaning and I just had a wrong mental
> > model in my head for what it meant, but even then what seems like its
> > obvious purpose given its name is mismatched with what it actually
> > does.  Since you are already changing struct rev_info in this series,
> > this was more a note that a name change or at least a comment for
> > opt->diff might be useful.  I mean, you asked a couple times on the
> > previous series for help trying to understand it, and I could only
> > offer some flailing guesses and Junio responded with a couple bits of
> > history.  Clearly, it isn't very clear and this patch reminded me of
> > that and made me wonder if we're possibly making it a little harder
> > for others further down the road to figure out.
>
> I still don't see why opt->diff is needed in the first place, and
> second, why opt->diffopt.flags.exit_with_status check is here? Why
> whoever sets opt->diffopt.flags.exit_with_status doesn't just set
> opt->diff as well (provided opt->diff is needed in the first place)?
>
> From the aforementioned discussion it looks like opt->diff is an
> optimization (maybe a remnant from the times when diff was a separate
> script), and that apparently there is some code instance somewhere that
> actually relies on the fact that clearing opt->diff is enough to disable
> diff machinery (as followed from my experiment of removing the check
> altogether and then getting only single seemingly unrelated test
> failing.)
>
> Overall, neither have I any idea how to clarify this, nor do I want to
> bother in this patch series. It'd be nice though if somebody who really
> does understand diff machinery in Git does the job.

Doh, I was hoping you had it all figured out.  If not, then that's a
fair enough argument not to attempt to clarify.

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

* Re: [PATCH v2 29/33] doc/git-log: describe new --diff-merges options
  2020-12-18 17:25         ` Elijah Newren
@ 2020-12-18 22:11           ` Sergey Organov
  2020-12-18 22:28             ` Elijah Newren
  0 siblings, 1 reply; 232+ messages in thread
From: Sergey Organov @ 2020-12-18 22:11 UTC (permalink / raw)
  To: Elijah Newren; +Cc: Junio C Hamano, Jeff King, Philip Oakley, Git Mailing List

Elijah Newren <newren@gmail.com> writes:

> On Fri, Dec 18, 2020 at 8:05 AM Sergey Organov <sorganov@gmail.com> wrote:
>>
>> Elijah Newren <newren@gmail.com> writes:
>>
>> > On Wed, Dec 16, 2020 at 10:50 AM Sergey Organov <sorganov@gmail.com> wrote:
>> >>
>> >> Describe all the new --diff-merges options in the git-log.txt and
>> >> adopt description of originals accordingly.
>> >
>> > You also took care to explain interactions of options with -p that
>> > were previously undocumented, which is a nice bonus.  That wording
>> > could still be improved a bit, though, as noted below.
>> >
>> >> Signed-off-by: Sergey Organov <sorganov@gmail.com>
>> >> ---
>> >>  Documentation/git-log.txt | 85 ++++++++++++++++++++++++---------------
>> >>  1 file changed, 52 insertions(+), 33 deletions(-)
>> >>
>> >> diff --git a/Documentation/git-log.txt b/Documentation/git-log.txt
>> >> index 2b8ac5ff882a..27bc619490c6 100644
>> >> --- a/Documentation/git-log.txt
>> >> +++ b/Documentation/git-log.txt
>> >> @@ -120,45 +120,64 @@ DIFF FORMATTING
>> >>  By default, `git log` does not generate any diff output. The options
>> >>  below can be used to show the changes made by each commit.
>> >>
>> >> -Note that unless one of `-c`, `--cc`, or `-m` is given, merge commits
>> >> -will never show a diff, even if a diff format like `--patch` is
>> >> -selected, nor will they match search options like `-S`. The exception is
>> >> -when `--first-parent` is in use, in which merges are treated like normal
>> >> -single-parent commits (this can be overridden by providing a
>> >> -combined-diff option or with `--no-diff-merges`).
>> >> +Note that unless one of `--diff-merges` variants (including short
>> >> +`-m`, `-c`, and `--cc` options) is explicitly given, merge commits
>> >> +will not show a diff, even if a diff format like `--patch` is
>> >> +selected, nor will they match search options like `-S`. The exception
>> >> +is when `--first-parent` is in use, in which case `first-parent` is
>> >> +the default format.
>> >
>> > Thanks for fixing this up.  :-)
>>
>> Don't mention it :-)
>>
>> >
>> >>
>> >> --c::
>> >> -       With this option, diff output for a merge commit
>> >> -       shows the differences from each of the parents to the merge result
>> >> -       simultaneously instead of showing pairwise diff between a parent
>> >> -       and the result one at a time. Furthermore, it lists only files
>> >> -       which were modified from all parents.
>> >> -
>> >> ---cc::
>> >> -       This flag implies the `-c` option and further compresses the
>> >> -       patch output by omitting uninteresting hunks whose contents in
>> >> -       the parents have only two variants and the merge result picks
>> >> -       one of them without modification.
>> >> +--diff-merges=(off|none|first-parent|1|separate|m|combined|c|dense-combined|cc)::
>> >> +--no-diff-merges::
>> >> +       Specify diff format to be used for merge commits. Default is
>> >> +       `off` unless `--first-parent` is in use, in which case
>> >> +       `first-parent` is the default.
>> >> ++
>> >> +--diff-merges=(off|none):::
>> >> +--no-diff-merges:::
>> >> +       Disable output of diffs for merge commits. Useful to override
>> >> +       implied value.
>> >> ++
>> >> +--diff-merges=first-parent:::
>> >> +--diff-merges=1:::
>> >> +       This option makes merge commits show the full diff with
>> >> +       respect to the first parent only.
>> >
>> > Does it imply -p?
>>
>> No, none of --diff-merges options do. This one is not any special. Why
>> the question?
>
> The documentation on -m was vague enough that it made me wonder.
> Fixing it would probably prevent me from having asked this question.

OK, I see, so let's try to fix the cause, please see below.

>
>> >> ++
>> >> +--diff-merges=separate:::
>> >> +--diff-merges=m:::
>> >> +-m:::
>> >> +       This makes merge commits show the full diff with respect to
>> >> +       each of the parents. Separate log entry and diff is generated
>> >> +       for each parent. `-m` is different in that it doesn't produce
>> >> +       any output without `-p`.
>> >
>> > Different from what?  From --first-parent?  From flags that haven't
>> > been covered yet?  (-c and --cc show up below)
>>
>> Well, from --diff-merges=m and --diff-merges=separate, that, as any
>> other --diff-merge option, do produce output (for merge commits) even
>> without -p.
>
> That wasn't at all clear to me as the intent of the last sentence.

Well, actually, the right answer to your question is: -m is different
from *everything* ;-)

Maybe the confusion you got is not caused by the documentation, but
rather by some of your expectations? In particular, I wonder, how comes
--first-parent appeared in your question, that is entirely unrelated?

I mean I'm still unsure how to make this description more clear, maybe
this will do:

--diff-merges=separate:::
--diff-merges=m:::
-m:::
       This makes merge commits show the full diff with respect to
       each of the parents. Separate log entry and diff is generated
       for each parent. `-m` doesn't produce any output without `-p`.

>
>> >> ++
>> >> +--diff-merges=combined:::
>> >> +--diff-merges=c:::
>> >> +-c:::
>> >> +       With this option, diff output for a merge commit shows the
>> >> +       differences from each of the parents to the merge result
>> >> +       simultaneously instead of showing pairwise diff between a
>> >> +       parent and the result one at a time. Furthermore, it lists
>> >> +       only files which were modified from all parents. Historically,
>> >> +       `-c` enables diff output for non-merge commits as well.
>> >
>> > "Historically"?  Does that mean it doesn't anymore?
>>
>> Eh, I don't think "historically" means that, but I'm not sure, being
>> non-native English speaker.
>
> Sometimes non-native speakers use the language more accurately.  This
> might be such a case, but that sentence did make me think you might be
> attempting to document past behavior as a way of helping people adjust
> to current/new behavior.
>
>> > (Maybe, "The short form, `-c`, also enables diff output for non-merge
>> > commits as well." or something like that?)
>>
>> ... and then try to explain why this otherwise illogical behavior is
>> there? I thought "historically" would cover that.
>
> It doesn't seem like illogical behavior to me.   Perhaps the view of
> -c as a diff-merges option, reinforced by placing -c right next to
> --diff-merges in the documentation, is what causes you to think so?

-c, described as selecting specific format of representation of merge
commits, suddenly enabling diff output of non-merge commits, is logical?
No. Useful? Maybe. Logical? Not to me. Just saying, see below.

> If so, maybe we should document -c (and --cc) separately after all the
> --diff-merges options, using something like the following:
>
> -c:::
>     Implies both --patch and --diff-merges=combined, i.e. turn on
> patches for normal commits and show a combined diff format for merges.

The problem with this is that it'd then be preferable to describe -m
separately as well, and that's not that simple.

Overall, I'd rather change that in place, like this:

--diff-merges=combined:::
--diff-merges=c:::
-c:::
       With this option, diff output for a merge commit shows the
       differences from each of the parents to the merge result
       simultaneously instead of showing pairwise diff between a
       parent and the result one at a time. Furthermore, it lists
       only files which were modified from all parents. `-c` implies
       `--patch`.


Thanks,
-- Sergey

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

* Re: [PATCH v2 24/33] diff-merges: handle imply -p on -c/--cc logic for log.c
  2020-12-18 21:45           ` Sergey Organov
@ 2020-12-18 22:12             ` Elijah Newren
  2020-12-18 22:17               ` Sergey Organov
  0 siblings, 1 reply; 232+ messages in thread
From: Elijah Newren @ 2020-12-18 22:12 UTC (permalink / raw)
  To: Sergey Organov; +Cc: Junio C Hamano, Jeff King, Philip Oakley, Git Mailing List

On Fri, Dec 18, 2020 at 1:45 PM Sergey Organov <sorganov@gmail.com> wrote:
>
> Elijah Newren <newren@gmail.com> writes:
>
> > On Fri, Dec 18, 2020 at 6:01 AM Sergey Organov <sorganov@gmail.com> wrote:
> >>
> >> Elijah Newren <newren@gmail.com> writes:
> >>
> >> > On Wed, Dec 16, 2020 at 10:50 AM Sergey Organov <sorganov@gmail.com> wrote:
> >> >>
> >> >> Move logic that handles implying -p on -c/--cc from
> >> >> log_setup_revisions_tweak() to diff_merges_setup_revs(), where it
> >> >> belongs.
> >> >
> >> > A very minor point, but I'd probably drop the "where it belongs";
> >> > while I think the new place makes sense for it, it reads to me like
> >> > you're either relying on a consensus to move it or implying there was
> >> > a mistake to not put it here previously, neither of which makes sense.
> >>
> >> Well, it was meant to be an excuse for not moving it there earlier in
> >> the patch series indeed. I just overlooked this piece of code that
> >> logically belongs to the diff-merges module. I think you need to
> >> consider the state of the sources right before this patch to see the
> >> point of phrasing it like this.
> >>
> >> That said, I'm fine removing this either.
> >
> > If it should have been moved there earlier, then you should amend the
> > relevant previous commit instead of making a new one.  rebase -i is
> > your friend and should be used, especially with long patch series.
> > :-)
>
> This is to be a separate commit anyway. I can move the commit itself
> more closer to the beginning, but I don't see how it'd make things
> any better.
>
> By "earlier" above I mostly meant that I should have noticed and moved
> it in the first issue or the patch series.

Even if keeping the commit as-is, moving it earlier would have one benefit...

> >
> >> > Much more importantly, this patch doesn't do what you said in
> >> > discussions on the previous round.  It'd be helpful if the commit
> >> > message called out that you are just moving the logic for now and that
> >> > a subsequent patch will tweak the logic to only trigger this for
> >> > -c/--cc and not for --diff-merges=.* flags.
> >>
> >> I believe this patch is useful by itself, even without any future
> >> improvements (that we actually discussed), if any, so I don't see the
> >> point in describing what this patch doesn't do.
> >>
> >> OTOH, the commit message seems to be clear enough to expect this patch
> >> to be pure refactoring, without any functional changes, no?
> >
> > I'm just pointing out that reading the patch triggers a "wait, you
> > said you wanted to enable diffs for merges without diffs for regular
> > commits" reaction and makes reviewers start diving into the code to
> > check if they missed where that happened.  Sometimes they'll even
> > respond to the commit asking about it...and then read a later patch
> > and find the answer.  Perhaps I'm more attuned to this, because I've
> > done this to reviewers a number of times and they have asked me to add
> > a note in the earlier commit message to make it easier for other
> > reviewers to follow and read the series.  You don't need to describe
> > in full detail the subsequent changes that will come, just highlight
> > that they are coming to give reviewers an aid.  For example, this
> > could be as simple as:
> >
> > """
> > Move logic that handles implying -p on -c/--cc from
> > log_setup_revisions_tweak() to diff_merges_setup_revs().  A
> > subsequent commit will tweak this logic further.
> > """
>
> I think I see what you mean, but I still don't like this, sorry, as:
>
> First, this commit doesn't tweak the logic at all, so "further" doesn't
> sound right.

Good point, I should have left off "further".

> Second, the purpose of this move is not to have subsequent commits that
> will tweak this logic further in any particular way. One of the aims of
> this commit is rather to make it more simple to have /any/ further
> tweaks to the logic.
>
> Third, if the "tweak" you mention is not accepted, I'd need not to only
> get rid of the tweaking commit, but not to forget to edit the
> description of this one, that is basically unrelated?

...so, one advantage of moving this commit earlier in the series is
that if it appears before the introduction of --diff-merges, then it
doesn't trigger the "What?  I thought we weren't making the
diff-merges flags trigger patches for non-merge commits" reaction, and
thus makes it clearer that the patch is just pure refactoring.

> >
> > (Note that 'git log --grep=subsequent' in git.git will find you
> > several examples of where people have done this kind of thing.)
>
> Yeah, I agree it's useful when commits are tightly coupled and thus the
> purpose of single commit is unclear. I just don't think this one is such
> a case.

I think where it appears in the series makes its purpose unclear.

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

* Re: [PATCH v2 24/33] diff-merges: handle imply -p on -c/--cc logic for log.c
  2020-12-18 22:12             ` Elijah Newren
@ 2020-12-18 22:17               ` Sergey Organov
  0 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-12-18 22:17 UTC (permalink / raw)
  To: Elijah Newren; +Cc: Junio C Hamano, Jeff King, Philip Oakley, Git Mailing List

Elijah Newren <newren@gmail.com> writes:

> On Fri, Dec 18, 2020 at 1:45 PM Sergey Organov <sorganov@gmail.com> wrote:
>>
>> Elijah Newren <newren@gmail.com> writes:
>>
>> > On Fri, Dec 18, 2020 at 6:01 AM Sergey Organov <sorganov@gmail.com> wrote:
>> >>
>> >> Elijah Newren <newren@gmail.com> writes:
>> >>
>> >> > On Wed, Dec 16, 2020 at 10:50 AM Sergey Organov
>> >> > <sorganov@gmail.com> wrote:
>> >> >>
>> >> >> Move logic that handles implying -p on -c/--cc from
>> >> >> log_setup_revisions_tweak() to diff_merges_setup_revs(), where it
>> >> >> belongs.
>> >> >
>> >> > A very minor point, but I'd probably drop the "where it belongs";
>> >> > while I think the new place makes sense for it, it reads to me like
>> >> > you're either relying on a consensus to move it or implying there was
>> >> > a mistake to not put it here previously, neither of which makes sense.
>> >>
>> >> Well, it was meant to be an excuse for not moving it there earlier in
>> >> the patch series indeed. I just overlooked this piece of code that
>> >> logically belongs to the diff-merges module. I think you need to
>> >> consider the state of the sources right before this patch to see the
>> >> point of phrasing it like this.
>> >>
>> >> That said, I'm fine removing this either.
>> >
>> > If it should have been moved there earlier, then you should amend the
>> > relevant previous commit instead of making a new one.  rebase -i is
>> > your friend and should be used, especially with long patch series.
>> > :-)
>>
>> This is to be a separate commit anyway. I can move the commit itself
>> more closer to the beginning, but I don't see how it'd make things
>> any better.
>>
>> By "earlier" above I mostly meant that I should have noticed and moved
>> it in the first issue or the patch series.
>
> Even if keeping the commit as-is, moving it earlier would have one benefit...
>
>> >
>> >> > Much more importantly, this patch doesn't do what you said in
>> >> > discussions on the previous round.  It'd be helpful if the commit
>> >> > message called out that you are just moving the logic for now and that
>> >> > a subsequent patch will tweak the logic to only trigger this for
>> >> > -c/--cc and not for --diff-merges=.* flags.
>> >>
>> >> I believe this patch is useful by itself, even without any future
>> >> improvements (that we actually discussed), if any, so I don't see the
>> >> point in describing what this patch doesn't do.
>> >>
>> >> OTOH, the commit message seems to be clear enough to expect this patch
>> >> to be pure refactoring, without any functional changes, no?
>> >
>> > I'm just pointing out that reading the patch triggers a "wait, you
>> > said you wanted to enable diffs for merges without diffs for regular
>> > commits" reaction and makes reviewers start diving into the code to
>> > check if they missed where that happened.  Sometimes they'll even
>> > respond to the commit asking about it...and then read a later patch
>> > and find the answer.  Perhaps I'm more attuned to this, because I've
>> > done this to reviewers a number of times and they have asked me to add
>> > a note in the earlier commit message to make it easier for other
>> > reviewers to follow and read the series.  You don't need to describe
>> > in full detail the subsequent changes that will come, just highlight
>> > that they are coming to give reviewers an aid.  For example, this
>> > could be as simple as:
>> >
>> > """
>> > Move logic that handles implying -p on -c/--cc from
>> > log_setup_revisions_tweak() to diff_merges_setup_revs().  A
>> > subsequent commit will tweak this logic further.
>> > """
>>
>> I think I see what you mean, but I still don't like this, sorry, as:
>>
>> First, this commit doesn't tweak the logic at all, so "further" doesn't
>> sound right.
>
> Good point, I should have left off "further".
>
>> Second, the purpose of this move is not to have subsequent commits that
>> will tweak this logic further in any particular way. One of the aims of
>> this commit is rather to make it more simple to have /any/ further
>> tweaks to the logic.
>>
>> Third, if the "tweak" you mention is not accepted, I'd need not to only
>> get rid of the tweaking commit, but not to forget to edit the
>> description of this one, that is basically unrelated?
>
> ...so, one advantage of moving this commit earlier in the series is
> that if it appears before the introduction of --diff-merges, then it
> doesn't trigger the "What?  I thought we weren't making the
> diff-merges flags trigger patches for non-merge commits" reaction, and
> thus makes it clearer that the patch is just pure refactoring.
>
>> >
>> > (Note that 'git log --grep=subsequent' in git.git will find you
>> > several examples of where people have done this kind of thing.)
>>
>> Yeah, I agree it's useful when commits are tightly coupled and thus the
>> purpose of single commit is unclear. I just don't think this one is such
>> a case.
>
> I think where it appears in the series makes its purpose unclear.

Fine, I'll move it earlier in the series then.

Thanks,
-- Sergey

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

* Re: [PATCH v2 26/33] diff-merges: let new options enable diff without -p
  2020-12-18 22:06             ` Elijah Newren
@ 2020-12-18 22:19               ` Sergey Organov
  0 siblings, 0 replies; 232+ messages in thread
From: Sergey Organov @ 2020-12-18 22:19 UTC (permalink / raw)
  To: Elijah Newren; +Cc: Junio C Hamano, Jeff King, Philip Oakley, Git Mailing List

Elijah Newren <newren@gmail.com> writes:

> On Fri, Dec 18, 2020 at 12:32 PM Sergey Organov <sorganov@gmail.com> wrote:
>>
>> Elijah Newren <newren@gmail.com> writes:
>>
>> > On Fri, Dec 18, 2020 at 6:42 AM Sergey Organov <sorganov@gmail.com> wrote:
>> >>
>> >> Elijah Newren <newren@gmail.com> writes:
>> >>
>> >> > On Wed, Dec 16, 2020 at 10:50 AM Sergey Organov
>> >> > <sorganov@gmail.com> wrote:
>>
>> [...]
>>
>> >> >> diff --git a/log-tree.c b/log-tree.c
>> >> >> index f9385b1dae6f..67060492ca0a 100644
>> >> >> --- a/log-tree.c
>> >> >> +++ b/log-tree.c
>> >> >> @@ -899,15 +899,21 @@ static int log_tree_diff(struct rev_info
>> >> >> *opt, struct commit *commit, struct log
>> >> >>         int showed_log;
>> >> >>         struct commit_list *parents;
>> >> >>         struct object_id *oid;
>> >> >> +       int is_merge;
>> >> >> + int regulars_need_diff = opt->diff ||
>> >> >> opt->diffopt.flags.exit_with_status;
>> >> >
>> >> > So rev_info.diff has changed in meaning from
>> >> > commits-need-to-show-a-diff, to non-merge-commits-need-to-show-a-diff.
>> >> > That's a somewhat subtle semantic shift.  Perhaps it's worth adding a
>> >> > comment to the declaration of rev_info.diff to highlight this?  (And
>> >> > perhaps even rename the flag?)
>> >>
>> >> No, the meaning of rev_info.diff hopefully didn't change. rev_info.diff
>> >> still enables all the commits to pass further once set. It is still
>> >> exactly the same old condition, just assigned to a variable for reuse.
>> >> My aim was to avoid touching existing logic of this function and only
>> >> add a new functionality when opt->merges_need_diff is set.
>> >>
>> >> It looks like I rather choose confusing name for the variable, and it'd
>> >> be more clear if I'd call this, say:
>> >>
>> >>   int need_diff = opt->diff || opt->diffopt.flags.exit_with_status;
>> >>
>> >> ?
>> >>
>> >> What do you think?
>> >
>> > I think need_diff would actually be confusing.  It can be false when
>> > you need diffs (e.g. --diff-merges=cc with no -p, because then you'd
>> > need diffs for merge commits and not for non-merge commits).  I'd
>> > stick with your original local variable name.
>> >
>> > Perhaps opt->diff hasn't changed meaning and I just had a wrong mental
>> > model in my head for what it meant, but even then what seems like its
>> > obvious purpose given its name is mismatched with what it actually
>> > does.  Since you are already changing struct rev_info in this series,
>> > this was more a note that a name change or at least a comment for
>> > opt->diff might be useful.  I mean, you asked a couple times on the
>> > previous series for help trying to understand it, and I could only
>> > offer some flailing guesses and Junio responded with a couple bits of
>> > history.  Clearly, it isn't very clear and this patch reminded me of
>> > that and made me wonder if we're possibly making it a little harder
>> > for others further down the road to figure out.
>>
>> I still don't see why opt->diff is needed in the first place, and
>> second, why opt->diffopt.flags.exit_with_status check is here? Why
>> whoever sets opt->diffopt.flags.exit_with_status doesn't just set
>> opt->diff as well (provided opt->diff is needed in the first place)?
>>
>> From the aforementioned discussion it looks like opt->diff is an
>> optimization (maybe a remnant from the times when diff was a separate
>> script), and that apparently there is some code instance somewhere that
>> actually relies on the fact that clearing opt->diff is enough to disable
>> diff machinery (as followed from my experiment of removing the check
>> altogether and then getting only single seemingly unrelated test
>> failing.)
>>
>> Overall, neither have I any idea how to clarify this, nor do I want to
>> bother in this patch series. It'd be nice though if somebody who really
>> does understand diff machinery in Git does the job.
>
> Doh, I was hoping you had it all figured out.

I tried. I failed. :-)

> If not, then that's a fair enough argument not to attempt to clarify.

This.

Thanks,
-- Sergey

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

* Re: [PATCH v2 29/33] doc/git-log: describe new --diff-merges options
  2020-12-18 22:11           ` Sergey Organov
@ 2020-12-18 22:28             ` Elijah Newren
  0 siblings, 0 replies; 232+ messages in thread
From: Elijah Newren @ 2020-12-18 22:28 UTC (permalink / raw)
  To: Sergey Organov; +Cc: Junio C Hamano, Jeff King, Philip Oakley, Git Mailing List

On Fri, Dec 18, 2020 at 2:11 PM Sergey Organov <sorganov@gmail.com> wrote:
>
> Elijah Newren <newren@gmail.com> writes:
>
> > On Fri, Dec 18, 2020 at 8:05 AM Sergey Organov <sorganov@gmail.com> wrote:
> >>
> >> Elijah Newren <newren@gmail.com> writes:
> >>
> >> > On Wed, Dec 16, 2020 at 10:50 AM Sergey Organov <sorganov@gmail.com> wrote:
> >> >>
> >> >> Describe all the new --diff-merges options in the git-log.txt and
> >> >> adopt description of originals accordingly.
> >> >
> >> > You also took care to explain interactions of options with -p that
> >> > were previously undocumented, which is a nice bonus.  That wording
> >> > could still be improved a bit, though, as noted below.
> >> >
> >> >> Signed-off-by: Sergey Organov <sorganov@gmail.com>
> >> >> ---
> >> >>  Documentation/git-log.txt | 85 ++++++++++++++++++++++++---------------
> >> >>  1 file changed, 52 insertions(+), 33 deletions(-)
> >> >>
> >> >> diff --git a/Documentation/git-log.txt b/Documentation/git-log.txt
> >> >> index 2b8ac5ff882a..27bc619490c6 100644
> >> >> --- a/Documentation/git-log.txt
> >> >> +++ b/Documentation/git-log.txt
> >> >> @@ -120,45 +120,64 @@ DIFF FORMATTING
> >> >>  By default, `git log` does not generate any diff output. The options
> >> >>  below can be used to show the changes made by each commit.
> >> >>
> >> >> -Note that unless one of `-c`, `--cc`, or `-m` is given, merge commits
> >> >> -will never show a diff, even if a diff format like `--patch` is
> >> >> -selected, nor will they match search options like `-S`. The exception is
> >> >> -when `--first-parent` is in use, in which merges are treated like normal
> >> >> -single-parent commits (this can be overridden by providing a
> >> >> -combined-diff option or with `--no-diff-merges`).
> >> >> +Note that unless one of `--diff-merges` variants (including short
> >> >> +`-m`, `-c`, and `--cc` options) is explicitly given, merge commits
> >> >> +will not show a diff, even if a diff format like `--patch` is
> >> >> +selected, nor will they match search options like `-S`. The exception
> >> >> +is when `--first-parent` is in use, in which case `first-parent` is
> >> >> +the default format.
> >> >
> >> > Thanks for fixing this up.  :-)
> >>
> >> Don't mention it :-)
> >>
> >> >
> >> >>
> >> >> --c::
> >> >> -       With this option, diff output for a merge commit
> >> >> -       shows the differences from each of the parents to the merge result
> >> >> -       simultaneously instead of showing pairwise diff between a parent
> >> >> -       and the result one at a time. Furthermore, it lists only files
> >> >> -       which were modified from all parents.
> >> >> -
> >> >> ---cc::
> >> >> -       This flag implies the `-c` option and further compresses the
> >> >> -       patch output by omitting uninteresting hunks whose contents in
> >> >> -       the parents have only two variants and the merge result picks
> >> >> -       one of them without modification.
> >> >> +--diff-merges=(off|none|first-parent|1|separate|m|combined|c|dense-combined|cc)::
> >> >> +--no-diff-merges::
> >> >> +       Specify diff format to be used for merge commits. Default is
> >> >> +       `off` unless `--first-parent` is in use, in which case
> >> >> +       `first-parent` is the default.
> >> >> ++
> >> >> +--diff-merges=(off|none):::
> >> >> +--no-diff-merges:::
> >> >> +       Disable output of diffs for merge commits. Useful to override
> >> >> +       implied value.
> >> >> ++
> >> >> +--diff-merges=first-parent:::
> >> >> +--diff-merges=1:::
> >> >> +       This option makes merge commits show the full diff with
> >> >> +       respect to the first parent only.
> >> >
> >> > Does it imply -p?
> >>
> >> No, none of --diff-merges options do. This one is not any special. Why
> >> the question?
> >
> > The documentation on -m was vague enough that it made me wonder.
> > Fixing it would probably prevent me from having asked this question.
>
> OK, I see, so let's try to fix the cause, please see below.

Sounds good.

> >
> >> >> ++
> >> >> +--diff-merges=separate:::
> >> >> +--diff-merges=m:::
> >> >> +-m:::
> >> >> +       This makes merge commits show the full diff with respect to
> >> >> +       each of the parents. Separate log entry and diff is generated
> >> >> +       for each parent. `-m` is different in that it doesn't produce
> >> >> +       any output without `-p`.
> >> >
> >> > Different from what?  From --first-parent?  From flags that haven't
> >> > been covered yet?  (-c and --cc show up below)
> >>
> >> Well, from --diff-merges=m and --diff-merges=separate, that, as any
> >> other --diff-merge option, do produce output (for merge commits) even
> >> without -p.
> >
> > That wasn't at all clear to me as the intent of the last sentence.
>
> Well, actually, the right answer to your question is: -m is different
> from *everything* ;-)
>
> Maybe the confusion you got is not caused by the documentation, but
> rather by some of your expectations? In particular, I wonder, how comes
> --first-parent appeared in your question, that is entirely unrelated?

When you said "`-m` is different" it was not clear what you were
contrasting to.  The fact that you were contrasting to the other
values in the set of three being described by this paragraph may seem
obvious to you, and I suspect many other readers may catch on to that,
but that really honestly did not occur to me while reading it.  Maybe
I'm weird.  Maybe some subset of users will be like me and we should
tighten up the wording.  Hard to say.

> I mean I'm still unsure how to make this description more clear, maybe
> this will do:
>
> --diff-merges=separate:::
> --diff-merges=m:::
> -m:::
>        This makes merge commits show the full diff with respect to
>        each of the parents. Separate log entry and diff is generated
>        for each parent. `-m` doesn't produce any output without `-p`.

Works for me.  :-)

> >
> >> >> ++
> >> >> +--diff-merges=combined:::
> >> >> +--diff-merges=c:::
> >> >> +-c:::
> >> >> +       With this option, diff output for a merge commit shows the
> >> >> +       differences from each of the parents to the merge result
> >> >> +       simultaneously instead of showing pairwise diff between a
> >> >> +       parent and the result one at a time. Furthermore, it lists
> >> >> +       only files which were modified from all parents. Historically,
> >> >> +       `-c` enables diff output for non-merge commits as well.
> >> >
> >> > "Historically"?  Does that mean it doesn't anymore?
> >>
> >> Eh, I don't think "historically" means that, but I'm not sure, being
> >> non-native English speaker.
> >
> > Sometimes non-native speakers use the language more accurately.  This
> > might be such a case, but that sentence did make me think you might be
> > attempting to document past behavior as a way of helping people adjust
> > to current/new behavior.
> >
> >> > (Maybe, "The short form, `-c`, also enables diff output for non-merge
> >> > commits as well." or something like that?)
> >>
> >> ... and then try to explain why this otherwise illogical behavior is
> >> there? I thought "historically" would cover that.
> >
> > It doesn't seem like illogical behavior to me.   Perhaps the view of
> > -c as a diff-merges option, reinforced by placing -c right next to
> > --diff-merges in the documentation, is what causes you to think so?
>
> -c, described as selecting specific format of representation of merge
> commits, suddenly enabling diff output of non-merge commits, is logical?
> No. Useful? Maybe. Logical? Not to me. Just saying, see below.

:-)

I didn't say the former documentation was correct, or that the
behavior logically flowed from the documentation's claims.  And you do
bring up good points that the past documentation should have been
updated when -c and --cc were made to imply -p.  I only claimed that
-c and --cc provide logical behaviors (I want diffs for everything,
for merges do it this way...all expressed in a nice compact bundle).

> > If so, maybe we should document -c (and --cc) separately after all the
> > --diff-merges options, using something like the following:
> >
> > -c:::
> >     Implies both --patch and --diff-merges=combined, i.e. turn on
> > patches for normal commits and show a combined diff format for merges.
>
> The problem with this is that it'd then be preferable to describe -m
> separately as well, and that's not that simple.
>
> Overall, I'd rather change that in place, like this:
>
> --diff-merges=combined:::
> --diff-merges=c:::
> -c:::
>        With this option, diff output for a merge commit shows the
>        differences from each of the parents to the merge result
>        simultaneously instead of showing pairwise diff between a
>        parent and the result one at a time. Furthermore, it lists
>        only files which were modified from all parents. `-c` implies
>        `--patch`.

Works for me.  --cc needs a similar change, obviously.

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

* Re: [PATCH v2 23/33] diff-merges: fix style of functions definitions
  2020-12-18 21:23           ` Sergey Organov
@ 2020-12-18 22:56             ` Elijah Newren
  2020-12-19  1:00               ` Felipe Contreras
  2020-12-19 11:59               ` Sergey Organov
  0 siblings, 2 replies; 232+ messages in thread
From: Elijah Newren @ 2020-12-18 22:56 UTC (permalink / raw)
  To: Sergey Organov; +Cc: Junio C Hamano, Jeff King, Philip Oakley, Git Mailing List

On Fri, Dec 18, 2020 at 1:23 PM Sergey Organov <sorganov@gmail.com> wrote:
>
> Elijah Newren <newren@gmail.com> writes:
>
> > On Fri, Dec 18, 2020 at 5:41 AM Sergey Organov <sorganov@gmail.com> wrote:
> >>
> >> Elijah Newren <newren@gmail.com> writes:
> >>
> >> > On Wed, Dec 16, 2020 at 10:50 AM Sergey Organov <sorganov@gmail.com> wrote:
> >> >>
> >> >> Put open curly brace on its own line
> >> >>
> >> >> Signed-off-by: Sergey Organov <sorganov@gmail.com>
> >> >> ---
> >> >>  diff-merges.c | 36 ++++++++++++++++++++++++------------
> >> >>  1 file changed, 24 insertions(+), 12 deletions(-)
> >> >>
> >> >> diff --git a/diff-merges.c b/diff-merges.c
> >> >> index cba391604ac7..0165fa22fcd1 100644
> >> >> --- a/diff-merges.c
> >> >> +++ b/diff-merges.c
> >> >> @@ -2,7 +2,8 @@
> >> >>
> >>
> >> [...]
> >>
> >> >>
> >> >> -void diff_merges_set_dense_combined_if_unset(struct rev_info *revs) {
> >> >> +void diff_merges_set_dense_combined_if_unset(struct rev_info *revs)
> >> >> +{
> >> >>         if (!revs->combine_merges)
> >> >>                 set_dense_combined(revs);
> >> >>  }
> >> >> --
> >> >> 2.25.1
> >> >>
> >> >
> >> > But...didn't you add all these functions yourself earlier in the
> >> > series?
> >>
> >> Yes, I did indeed and somehow picked wrong style from one of the
> >> occurrences of this style in the existing Git codebase.
> >>
> >> > Why didn't you split this patch up and squash it into the
> >> > relevant previous patches?
> >>
> >> When Junio noticed and pointed to this deficiency, I asked him if I
> >> should fix all the series from the start, or it'd be OK to use fixup
> >> commit. As he didn't answer and nobody else commented either, I opted
> >> for the latter.
> >>
> >> I can still do it if it's that essential, but I'd prefer not to, to
> >> avoid both the hand-work and causing entire series to change. The
> >> problem is that there were code movements in the series, so such a fix
> >> to earlier patches would cause conflicts down the commits chain, to be
> >> resolved by hand.
> >
> > That's what add -p and interactive rebase is for.  :-)  Code is read
> > more than it is written, so it's important to get things clean.  And
> > not just for immediate reviewers, but for people who look at it later.
>
> I do know how to do it, but I'd still prefer it to be accepted in its
> current form, as I don't see this particular case being that important
> to justify rewriting of all the series. I'll go through the pain if
> it's a show-stopper though.

Personally, I think that a really important point to keep in mind when
submitting patch series is trying to figure out the easiest way to
move the code from point A to point B, not the route you took to get
from point A to point B.  This is especially true for longer patch
series.  It's common after you've finished a series to discover there
was an easier or cleaner route to follow that would have arrived at
the same end-point.  It's not uncommon for me to spend a significant
chunk of time rebasing and restructuring a patch series to try to
highlight such a better path.  This includes not just style fixups,
but different patch orderings, alternate ways to break up functions,
using different data structures, etc.

Al