threads / patch / 54550

patch, 26 partsgit-log: implement new --diff-merge options

Subject: [PATCH 00/26] git-log: implement new --diff-merge options

## tl;dr

232 messages between Nov 1, 2020 and Jan 16, 2021. Diffs are folded; open one to read it.

replies: 231people: 5as markdown or json

Sergey Organov· Nov 1, 2020, 19:33 UTC · lore

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
Sergey Organov· Nov 1, 2020, 19:33 UTC · re: Sergey Organov · lore

[PATCH 02/26] revision: factor out setup of diff-merge related settings

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(-)
Show changes to revision.c +12 −6
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
Sergey Organov· Nov 1, 2020, 19:33 UTC · re: Sergey Organov · lore

[PATCH 03/26] revision: factor out initialization of diff-merge related settings

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(-)
Show changes to revision.c +7 −1
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
Sergey Organov· Nov 1, 2020, 19:33 UTC · re: Sergey Organov · lore

[PATCH 01/26] revision: factor out parsing of diff-merge related options

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(-)
Show changes to revision.c +39 −27
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
Sergey Organov· Nov 1, 2020, 19:33 UTC · re: Sergey Organov · lore

[PATCH 05/26] revision: move diff merges functions to its own diff-merges.c

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
Show changes to 6 files +87 −74

Makefile, builtin/log.c, diff-merges.c, diff-merges.h, revision.c, revision.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
Sergey Organov· Nov 1, 2020, 19:33 UTC · re: Sergey Organov · lore

[PATCH 04/26] revision: provide implementation for diff merges tweaks

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(-)
Show changes to 3 files +22 −11

builtin/log.c, revision.c, revision.h

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
Sergey Organov· Nov 1, 2020, 19:33 UTC · re: Sergey Organov · lore

[PATCH 06/26] diff-merges: rename all functions to have common prefix

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(-)
Show changes to 4 files +20 −15

builtin/log.c, diff-merges.c, diff-merges.h, revision.c

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
Sergey Organov· Nov 1, 2020, 19:33 UTC · re: Sergey Organov · lore

[PATCH 08/26] diff-merges: rename diff_merges_default_to_enable() to match semantics

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(-)
Show changes to 3 files +4 −4

builtin/log.c, diff-merges.c, diff-merges.h

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
Sergey Organov· Nov 1, 2020, 19:33 UTC · re: Sergey Organov · lore

[PATCH 10/26] diff-merges: new function diff_merges_suppress()

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(-)
Show changes to 4 files +20 −6

builtin/merge.c, diff-merges.c, diff-merges.h, fmt-merge-msg.c

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
Elijah Newren· Dec 3, 2020, 05:52 UTC · re: Sergey Organov · lore

Re: [PATCH 10/26] diff-merges: new function diff_merges_suppress()

On Sun, Nov 1, 2020 at 11:36 AM Sergey Organov <sorganov@gmail.com> wrote:
Show 50 quoted lines
>
> 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()?

Show 31 quoted lines
> +
>  /*
>   * 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()?
Show 41 quoted lines
> +
>  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
>
Sergey Organov· Dec 3, 2020, 20:06 UTC · re: Elijah Newren · lore

Re: [PATCH 10/26] diff-merges: new function diff_merges_suppress()

Elijah Newren <newren@gmail.com> writes:
Show 53 quoted lines
> 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.

Show 34 quoted lines
>
>> +
>>  /*
>>   * 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

Elijah Newren· Dec 3, 2020, 20:28 UTC · re: Sergey Organov · lore

Re: [PATCH 10/26] diff-merges: new function diff_merges_suppress()

Hi Sergey,
On Thu, Dec 3, 2020 at 12:06 PM Sergey Organov <sorganov@gmail.com> wrote:
Show 101 quoted lines
>
> 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.

Sergey Organov· Dec 4, 2020, 17:23 UTC · re: Elijah Newren · lore

Re: [PATCH 10/26] diff-merges: new function diff_merges_suppress()

Hi Elijah,
Elijah Newren <newren@gmail.com> writes:
Show 118 quoted lines
> 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
Sergey Organov· Nov 1, 2020, 19:33 UTC · re: Sergey Organov · lore

[PATCH 07/26] diff-merges: move checks for first_parent_only out of the module

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(-)
Show changes to 3 files +11 −9

builtin/log.c, diff-merges.c, diff-merges.h

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
Sergey Organov· Nov 1, 2020, 19:33 UTC · re: Sergey Organov · lore

[PATCH 13/26] diff-merges: revise revs->diff flag handling

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(-)
Show changes to diff-merges.c +2 −3
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
Sergey Organov· Nov 1, 2020, 19:33 UTC · re: Sergey Organov · lore

[PATCH 12/26] diff-merges: introduce revs->first_parent_merges flag

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(-)
Show changes to 3 files +5 −2

diff-merges.c, log-tree.c, revision.h

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
Sergey Organov· Nov 1, 2020, 19:33 UTC · re: Sergey Organov · lore

[PATCH 11/26] diff-merges: new function diff_merges_set_dense_combined_if_unset()

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(-)
Show changes to 4 files +21 −6

builtin/diff-files.c, builtin/diff.c, diff-merges.c, diff-merges.h

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
Sergey Organov· Nov 1, 2020, 19:33 UTC · re: Sergey Organov · lore

[PATCH 18/26] diff-merges: group diff-merge flags next to each other inside 'rev_info'

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(-)
Show changes to revision.h +3 −2
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
Sergey Organov· Nov 1, 2020, 19:33 UTC · re: Sergey Organov · lore

[PATCH 20/26] diff-merges: refactor opt settings into separate functions

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(-)
Show changes to diff-merges.c +37 −22
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
Sergey Organov· Nov 1, 2020, 19:33 UTC · re: Sergey Organov · lore

[PATCH 21/26] diff-merges: make -m/-c/--cc explicitly mutually exclusive

-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(+)
Show changes to diff-merges.c +3 −0
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
Sergey Organov· Nov 1, 2020, 19:33 UTC · re: Sergey Organov · lore

[PATCH 19/26] diff-merges: get rid of now empty diff_merges_init_revs()

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(-)
Show changes to 3 files +0 −6

diff-merges.c, diff-merges.h, revision.c

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
Philip Oakley· Nov 2, 2020, 10:51 UTC · re: Sergey Organov · lore

Re: [PATCH 19/26] diff-merges: get rid of now empty diff_merges_init_revs()

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

Sergey Organov· Nov 1, 2020, 19:33 UTC · re: Sergey Organov · lore

[PATCH 22/26] diff-merges: implement new values for --diff-merges

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(-)
Show changes to diff-merges.c +16 −3
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
Sergey Organov· Nov 1, 2020, 19:33 UTC · re: Sergey Organov · lore

[PATCH 09/26] diff-merges: re-arrange functions to match the order they are called in

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(-)
Show changes to 2 files +17 −14

diff-merges.c, diff-merges.h

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
Sergey Organov· Nov 1, 2020, 19:33 UTC · re: Sergey Organov · lore

[PATCH 23/26] t4013: add test for --diff-merges=first-parent

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
Show changes to 2 files +128 −0

t/t4013-diff-various.sh, 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
Sergey Organov· Nov 1, 2020, 19:33 UTC · re: Sergey Organov · lore

[PATCH 25/26] doc/diff-generate-patch: mention new --diff-merges option

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(-)
Show changes to Documentation/diff-generate-patch.txt +3 −3
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
Sergey Organov· Nov 1, 2020, 19:33 UTC · re: Sergey Organov · lore

[PATCH 24/26] doc/git-log: describe new --diff-merges options

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(-)
Show changes to Documentation/git-log.txt +46 −30
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
Sergey Organov· Nov 1, 2020, 19:33 UTC · re: Sergey Organov · lore

[PATCH 17/26] diff-merges: split 'ignore_merges' field

'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(-)
Show changes to 3 files +22 −25

diff-merges.c, log-tree.c, revision.h

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
Philip Oakley· Nov 2, 2020, 10:48 UTC · re: Sergey Organov · lore

Re: [PATCH 17/26] diff-merges: split 'ignore_merges' field

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

Sergey Organov· Nov 2, 2020, 16:15 UTC · re: Philip Oakley · lore

Re: [PATCH 17/26] diff-merges: split 'ignore_merges' field

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
Sergey Organov· Nov 1, 2020, 19:33 UTC · re: Sergey Organov · lore

[PATCH 16/26] diff-merges: fix -m to properly override -c/--cc

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(-)
Show changes to 2 files +3 −2

diff-merges.c, t/t4013-diff-various.sh

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
Sergey Organov· Nov 1, 2020, 19:33 UTC · re: Sergey Organov · lore

[PATCH 26/26] doc/rev-list-options: document --first-parent implies --diff-merges=first-parent

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(+)
Show changes to Documentation/rev-list-options.txt +3 −0
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
Sergey Organov· Nov 1, 2020, 19:33 UTC · re: Sergey Organov · lore

[PATCH 15/26] t4013: add tests for -m failing to override -c/--cc

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
Show changes to 3 files +372 −0

t/t4013-diff-various.sh, t/t4013/diff.log_--cc_-m_-p_master, 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
Sergey Organov· Nov 1, 2020, 19:33 UTC · re: Sergey Organov · lore

[PATCH 14/26] t4013: support test_expect_failure through ':failure' magic

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(-)
Show changes to t/t4013-diff-various.sh +6 −1
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
Sergey Organov· Nov 8, 2020, 21:38 UTC · re: Sergey Organov · lore

[PATCH v1 00/27] git-log: implement new --diff-merge options

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
Sergey Organov· Nov 8, 2020, 21:38 UTC · re: Sergey Organov · lore

[PATCH v1 01/27] revision: factor out parsing of diff-merge related options

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(-)
Show changes to revision.c +39 −27
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
Junio C Hamano· Dec 3, 2020, 00:33 UTC · re: Sergey Organov · lore

Re: [PATCH v1 01/27] revision: factor out parsing of diff-merge related options

Sergey Organov <sorganov@gmail.com> writes:
Show 43 quoted lines
> 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.

Show 5 quoted lines
> +		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 ...
Show 5 quoted lines
> +	} else
> +		return 0;
> +
> +	return 1;
> +}
Show 10 quoted lines
> @@ -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?

Show 16 quoted lines
> -	} 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")) {
Sergey Organov· Dec 3, 2020, 15:16 UTC · re: Junio C Hamano · lore

Re: [PATCH v1 01/27] revision: factor out parsing of diff-merge related options

Junio C Hamano <gitster@pobox.com> writes:
Show 49 quoted lines
> 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.

Show 6 quoted lines
>
> 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!
Show 12 quoted lines
>
>> +		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

Junio C Hamano· Dec 4, 2020, 06:36 UTC · re: Sergey Organov · lore

Re: [PATCH v1 01/27] revision: factor out parsing of diff-merge related options

Sergey Organov <sorganov@gmail.com> writes:
Show 14 quoted lines
>>> +		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;

Sergey Organov· Dec 4, 2020, 19:10 UTC · re: Junio C Hamano · lore

Re: [PATCH v1 01/27] revision: factor out parsing of diff-merge related options

Junio C Hamano <gitster@pobox.com> writes:
Show 60 quoted lines
> 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

Sergey Organov· Nov 8, 2020, 21:38 UTC · re: Sergey Organov · lore

[PATCH v1 02/27] revision: factor out setup of diff-merge related settings

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(-)
Show changes to revision.c +12 −6
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
Junio C Hamano· Dec 3, 2020, 00:34 UTC · re: Sergey Organov · lore

Re: [PATCH v1 02/27] revision: factor out setup of diff-merge related settings

Sergey Organov <sorganov@gmail.com> writes:
Show 7 quoted lines
> 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.
Show 35 quoted lines
> 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;
Sergey Organov· Nov 8, 2020, 21:38 UTC · re: Sergey Organov · lore

[PATCH v1 03/27] revision: factor out initialization of diff-merge related settings

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(-)
Show changes to revision.c +7 −1
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
Junio C Hamano· Dec 3, 2020, 00:39 UTC · re: Sergey Organov · lore

Re: [PATCH v1 03/27] revision: factor out initialization of diff-merge related settings

Sergey Organov <sorganov@gmail.com> writes:
Show 18 quoted lines
> 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.

Show 19 quoted lines
>  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;
Sergey Organov· Dec 3, 2020, 15:35 UTC · re: Junio C Hamano · lore

Re: [PATCH v1 03/27] revision: factor out initialization of diff-merge related settings

Junio C Hamano <gitster@pobox.com> writes:
Show 23 quoted lines
> 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.

Show 22 quoted lines
>
>>  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

Sergey Organov· Nov 8, 2020, 21:38 UTC · re: Sergey Organov · lore

[PATCH v1 05/27] revision: move diff merges functions to its own diff-merges.c

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
Show changes to 6 files +87 −74

Makefile, builtin/log.c, diff-merges.c, diff-merges.h, revision.c, revision.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
Junio C Hamano· Dec 3, 2020, 00:58 UTC · re: Sergey Organov · lore

Re: [PATCH v1 05/27] revision: move diff merges functions to its own diff-merges.c

Sergey Organov <sorganov@gmail.com> writes:
Show 8 quoted lines
> 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)

Show 119 quoted lines
> +
> +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
Sergey Organov· Dec 3, 2020, 16:44 UTC · re: Junio C Hamano · lore

Re: [PATCH v1 05/27] revision: move diff merges functions to its own diff-merges.c

Junio C Hamano <gitster@pobox.com> writes:
Show 12 quoted lines
> 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.
Show 7 quoted lines
>
> 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

Sergey Organov· Nov 8, 2020, 21:38 UTC · re: Sergey Organov · lore

[PATCH v1 04/27] revision: provide implementation for diff merges tweaks

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(-)
Show changes to 3 files +22 −11

builtin/log.c, revision.c, revision.h

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
Junio C Hamano· Dec 3, 2020, 00:51 UTC · re: Sergey Organov · lore

Re: [PATCH v1 04/27] revision: provide implementation for diff merges tweaks

Sergey Organov <sorganov@gmail.com> writes:
Show 10 quoted lines
> -	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.

Show 7 quoted lines
> @@ -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?
Junio C Hamano· Dec 3, 2020, 05:28 UTC · re: Junio C Hamano · lore

Re: [PATCH v1 04/27] revision: provide implementation for diff merges tweaks

Junio C Hamano <gitster@pobox.com> writes:
Show 8 quoted lines
> 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.
Sergey Organov· Dec 3, 2020, 16:03 UTC · re: Junio C Hamano · lore

Re: [PATCH v1 04/27] revision: provide implementation for diff merges tweaks

Junio C Hamano <gitster@pobox.com> writes:
Show 25 quoted lines
> 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.
Show 8 quoted lines
> 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

Sergey Organov· Dec 3, 2020, 17:53 UTC · re: Junio C Hamano · lore

Re: [PATCH v1 04/27] revision: provide implementation for diff merges tweaks

Junio C Hamano <gitster@pobox.com> writes:
Show 30 quoted lines
> 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?

Show 9 quoted lines
>
> 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

Sergey Organov· Nov 8, 2020, 21:38 UTC · re: Sergey Organov · lore

[PATCH v1 07/27] diff-merges: move checks for first_parent_only out of the module

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(-)
Show changes to 3 files +11 −9

builtin/log.c, diff-merges.c, diff-merges.h

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
Junio C Hamano· Dec 3, 2020, 01:09 UTC · re: Sergey Organov · lore

Re: [PATCH v1 07/27] diff-merges: move checks for first_parent_only out of the module

Sergey Organov <sorganov@gmail.com> writes:
Show 9 quoted lines
> 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").

Show 24 quoted lines
>  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
Sergey Organov· Dec 3, 2020, 20:22 UTC · re: Junio C Hamano · lore

Re: [PATCH v1 07/27] diff-merges: move checks for first_parent_only out of the module

Junio C Hamano <gitster@pobox.com> writes:
Show 20 quoted lines
> 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?

Show 12 quoted lines
>
> 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.

Show 6 quoted lines
>
>> +	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

Sergey Organov· Nov 8, 2020, 21:38 UTC · re: Sergey Organov · lore

[PATCH v1 09/27] diff-merges: re-arrange functions to match the order they are called in

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(-)
Show changes to 2 files +17 −14

diff-merges.c, diff-merges.h

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
Elijah Newren· Dec 3, 2020, 05:52 UTC · re: Sergey Organov · lore

Re: [PATCH v1 09/27] diff-merges: re-arrange functions to match the order they are called in

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?

Show 75 quoted lines
>
> 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
>
Sergey Organov· Dec 3, 2020, 15:41 UTC · re: Elijah Newren · lore

Re: [PATCH v1 09/27] diff-merges: re-arrange functions to match the order they are called in

Elijah Newren <newren@gmail.com> writes:
Show 8 quoted lines
> 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

Sergey Organov· Nov 8, 2020, 21:38 UTC · re: Sergey Organov · lore

[PATCH v1 10/27] diff-merges: new function diff_merges_suppress()

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(-)
Show changes to 4 files +20 −6

builtin/merge.c, diff-merges.c, diff-merges.h, fmt-merge-msg.c

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
Sergey Organov· Nov 8, 2020, 21:38 UTC · re: Sergey Organov · lore

[PATCH v1 08/27] diff-merges: rename diff_merges_default_to_enable() to match semantics

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(-)
Show changes to 3 files +4 −4

builtin/log.c, diff-merges.c, diff-merges.h

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
Sergey Organov· Nov 8, 2020, 21:38 UTC · re: Sergey Organov · lore

[PATCH v1 11/27] diff-merges: new function diff_merges_set_dense_combined_if_unset()

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(-)
Show changes to 4 files +21 −6

builtin/diff-files.c, builtin/diff.c, diff-merges.c, diff-merges.h

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
Sergey Organov· Nov 8, 2020, 21:38 UTC · re: Sergey Organov · lore

[PATCH v1 12/27] diff-merges: introduce revs->first_parent_merges flag

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(-)
Show changes to 3 files +5 −2

diff-merges.c, log-tree.c, revision.h

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
Sergey Organov· Nov 8, 2020, 21:38 UTC · re: Sergey Organov · lore

[PATCH v1 13/27] diff-merges: revise revs->diff flag handling

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(-)
Show changes to diff-merges.c +2 −3
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
Sergey Organov· Nov 8, 2020, 21:38 UTC · re: Sergey Organov · lore

[PATCH v1 19/27] diff-merges: get rid of now empty diff_merges_init_revs()

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(-)
Show changes to 3 files +0 −6

diff-merges.c, diff-merges.h, revision.c

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
Sergey Organov· Nov 8, 2020, 21:38 UTC · re: Sergey Organov · lore

[PATCH v1 21/27] diff-merges: make -m/-c/--cc explicitly mutually exclusive

-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(+)
Show changes to diff-merges.c +3 −0
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
Sergey Organov· Nov 8, 2020, 21:38 UTC · re: Sergey Organov · lore

[PATCH v1 20/27] diff-merges: refactor opt settings into separate functions

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(-)
Show changes to diff-merges.c +37 −22
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
Sergey Organov· Nov 8, 2020, 21:38 UTC · re: Sergey Organov · lore

[PATCH v1 23/27] t4013: add test for --diff-merges=first-parent

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
Show changes to 2 files +128 −0

t/t4013-diff-various.sh, 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
Sergey Organov· Nov 8, 2020, 21:38 UTC · re: Sergey Organov · lore

[PATCH v1 24/27] doc/git-log: describe new --diff-merges options

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(-)
Show changes to Documentation/git-log.txt +46 −30
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
Elijah Newren· Dec 3, 2020, 06:09 UTC · re: Sergey Organov · lore

Re: [PATCH v1 24/27] doc/git-log: describe new --diff-merges options

On Sun, Nov 8, 2020 at 1:46 PM Sergey Organov <sorganov@gmail.com> wrote:
Show 46 quoted lines
>
> 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?

Show 10 quoted lines
> ++
> +--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.

Show 50 quoted lines
> ++
> +--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
Sergey Organov· Dec 3, 2020, 19:34 UTC · re: Elijah Newren · lore

Re: [PATCH v1 24/27] doc/git-log: describe new --diff-merges options

Elijah Newren <newren@gmail.com> writes:
Show 51 quoted lines
> 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?

Show 18 quoted lines
>
>> ++
>> +--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

Elijah Newren· Dec 3, 2020, 20:22 UTC · re: Sergey Organov · lore

Re: [PATCH v1 24/27] doc/git-log: describe new --diff-merges options

On Thu, Dec 3, 2020 at 11:34 AM Sergey Organov <sorganov@gmail.com> wrote:
Show 70 quoted lines
>
> 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).

Show 22 quoted lines
> >
> >> ++
> >> +--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?  ;-)
Show 8 quoted lines
> 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...).
Sergey Organov· Dec 4, 2020, 17:34 UTC · re: Elijah Newren · lore

Re: [PATCH v1 24/27] doc/git-log: describe new --diff-merges options

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:
[...]
Show 23 quoted lines
>> >> ++
>> >> +--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.
Show 19 quoted lines
>
>> 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
Elijah Newren· Dec 4, 2020, 18:33 UTC · re: Sergey Organov · lore

Re: [PATCH v1 24/27] doc/git-log: describe new --diff-merges options

On Fri, Dec 4, 2020 at 9:34 AM Sergey Organov <sorganov@gmail.com> wrote:
Show 57 quoted lines
>
> 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.
Sergey Organov· Dec 4, 2020, 19:58 UTC · re: Elijah Newren · lore

Re: [PATCH v1 24/27] doc/git-log: describe new --diff-merges options

Elijah Newren <newren@gmail.com> writes:
> On Fri, Dec 4, 2020 at 9:34 AM Sergey Organov <sorganov@gmail.com> wrote:
[...]
Show 23 quoted lines
>> >> 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
Elijah Newren· Dec 4, 2020, 20:01 UTC · re: Sergey Organov · lore

Re: [PATCH v1 24/27] doc/git-log: describe new --diff-merges options

On Fri, Dec 4, 2020 at 11:58 AM Sergey Organov <sorganov@gmail.com> wrote:
Show 41 quoted lines
>
> 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! :-)

Sergey Organov· Nov 8, 2020, 21:38 UTC · re: Sergey Organov · lore

[PATCH v1 22/27] diff-merges: implement new values for --diff-merges

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(-)
Show changes to diff-merges.c +16 −3
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
Sergey Organov· Nov 8, 2020, 21:38 UTC · re: Sergey Organov · lore

[PATCH v1 26/27] doc/rev-list-options: document --first-parent implies --diff-merges=first-parent

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(+)
Show changes to Documentation/rev-list-options.txt +3 −0
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
Sergey Organov· Nov 8, 2020, 21:38 UTC · re: Sergey Organov · lore

[PATCH v1 27/27] doc/git-show: include --diff-merges description

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(-)
Show changes to 3 files +60 −43

Documentation/diff-options.txt, Documentation/git-log.txt, Documentation/git-show.txt

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
Elijah Newren· Dec 3, 2020, 16:47 UTC · re: Sergey Organov · lore

Re: [PATCH v1 27/27] doc/git-show: include --diff-merges description

Hi,
On Sun, Nov 8, 2020 at 1:44 PM Sergey Organov <sorganov@gmail.com> wrote:
Show 29 quoted lines
>
> 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...
Show 129 quoted lines
> +
> +--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`.

Sergey Organov· Dec 3, 2020, 19:52 UTC · re: Elijah Newren · lore

Re: [PATCH v1 27/27] doc/git-show: include --diff-merges description

Elijah Newren <newren@gmail.com> writes:
Show 179 quoted lines
> 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

Sergey Organov· Nov 8, 2020, 21:38 UTC · re: Sergey Organov · lore

[PATCH v1 18/27] diff-merges: group diff-merge flags next to each other inside 'rev_info'

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(-)
Show changes to revision.h +3 −2
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
Sergey Organov· Nov 8, 2020, 21:38 UTC · re: Sergey Organov · lore

[PATCH v1 25/27] doc/diff-generate-patch: mention new --diff-merges option

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(-)
Show changes to Documentation/diff-generate-patch.txt +3 −3
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
Sergey Organov· Nov 8, 2020, 21:38 UTC · re: Sergey Organov · lore

[PATCH v1 17/27] diff-merges: split 'ignore_merges' field

'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(-)
Show changes to 3 files +22 −25

diff-merges.c, log-tree.c, revision.h

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
Sergey Organov· Nov 8, 2020, 21:38 UTC · re: Sergey Organov · lore

[PATCH v1 14/27] t4013: support test_expect_failure through ':failure' magic

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(-)
Show changes to t/t4013-diff-various.sh +6 −1
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
Sergey Organov· Nov 8, 2020, 21:38 UTC · re: Sergey Organov · lore

[PATCH v1 06/27] diff-merges: rename all functions to have common prefix

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(-)
Show changes to 4 files +20 −15

builtin/log.c, diff-merges.c, diff-merges.h, revision.c

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
Junio C Hamano· Dec 3, 2020, 00:52 UTC · re: Sergey Organov · lore

Re: [PATCH v1 06/27] diff-merges: rename all functions to have common prefix

Sergey Organov <sorganov@gmail.com> writes:
Show 30 quoted lines
> 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.

Sergey Organov· Dec 3, 2020, 17:49 UTC · re: Junio C Hamano · lore

Re: [PATCH v1 06/27] diff-merges: rename all functions to have common prefix

Junio C Hamano <gitster@pobox.com> writes:
Show 35 quoted lines
> 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

Sergey Organov· Nov 8, 2020, 21:38 UTC · re: Sergey Organov · lore

[PATCH v1 15/27] t4013: add tests for -m failing to override -c/--cc

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
Show changes to 3 files +372 −0

t/t4013-diff-various.sh, t/t4013/diff.log_--cc_-m_-p_master, 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
Sergey Organov· Nov 8, 2020, 21:38 UTC · re: Sergey Organov · lore

[PATCH v1 16/27] diff-merges: fix -m to properly override -c/--cc

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(-)
Show changes to 2 files +3 −2

diff-merges.c, t/t4013-diff-various.sh

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
Elijah Newren· Dec 3, 2020, 07:54 UTC · re: Sergey Organov · lore

Re: [PATCH v1 00/27] git-log: implement new --diff-merge options

On Sun, Nov 8, 2020 at 1:43 PM Sergey Organov <sorganov@gmail.com> wrote:
Show 16 quoted lines
>
> 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.)

Show 22 quoted lines
> 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.

Show 65 quoted lines
>
>         * 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
Sergey Organov· Dec 3, 2020, 19:48 UTC · re: Elijah Newren · lore

Re: [PATCH v1 00/27] git-log: implement new --diff-merge options

Elijah Newren <newren@gmail.com> writes:
Show 29 quoted lines
> 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?
Show 20 quoted lines
>
> 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.

[...]
Show 5 quoted lines
>>
>> 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

Elijah Newren· Dec 3, 2020, 20:39 UTC · re: Sergey Organov · lore

Re: [PATCH v1 00/27] git-log: implement new --diff-merge options

On Thu, Dec 3, 2020 at 11:48 AM Sergey Organov <sorganov@gmail.com> wrote:
Show 60 quoted lines
>
> 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.)

Show 21 quoted lines
> 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.

Sergey Organov· Dec 4, 2020, 19:23 UTC · re: Elijah Newren · lore

Re: [PATCH v1 00/27] git-log: implement new --diff-merge options

Elijah Newren <newren@gmail.com> writes:
Show 74 quoted lines
> 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
Show 6 quoted lines
>
> (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
Elijah Newren· Dec 5, 2020, 17:49 UTC · re: Sergey Organov · lore

Re: [PATCH v1 00/27] git-log: implement new --diff-merge options

On Fri, Dec 4, 2020 at 11:23 AM Sergey Organov <sorganov@gmail.com> wrote:
Show 85 quoted lines
>
> 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?

Show 15 quoted lines
> >
> > (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.

Sergey Organov· Dec 5, 2020, 19:44 UTC · re: Elijah Newren · lore

Re: [PATCH v1 00/27] git-log: implement new --diff-merge options

Elijah Newren <newren@gmail.com> writes:
Show 129 quoted lines
> 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
Elijah Newren· Dec 5, 2020, 20:09 UTC · re: Sergey Organov · lore

Re: [PATCH v1 00/27] git-log: implement new --diff-merge options

On Sat, Dec 5, 2020 at 11:44 AM Sergey Organov <sorganov@gmail.com> wrote:
Show 154 quoted lines
>
> 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.)

Sergey Organov· Dec 6, 2020, 16:39 UTC · re: Elijah Newren · lore

Re: [PATCH v1 00/27] git-log: implement new --diff-merge options

Elijah Newren <newren@gmail.com> writes:
Show 175 quoted lines
> 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
Sergey Organov· Dec 8, 2020, 20:07 UTC · re: Sergey Organov · lore

Re: [PATCH 00/26] git-log: implement new --diff-merge options

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

Elijah Newren· Dec 8, 2020, 20:52 UTC · re: Sergey Organov · lore

Re: [PATCH 00/26] git-log: implement new --diff-merge options

Hi Sergey,
On Tue, Dec 8, 2020 at 12:07 PM Sergey Organov <sorganov@gmail.com> wrote:
Show 21 quoted lines
>
> 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.

Show 12 quoted lines
> 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

Sergey Organov· Dec 8, 2020, 22:30 UTC · re: Elijah Newren · lore

Re: [PATCH 00/26] git-log: implement new --diff-merge options

Elijah Newren <newren@gmail.com> writes:
> Hi Sergey,
Hi Elijah,
Show 28 quoted lines
>
> 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!
Show 16 quoted lines
>
>> 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.
Show 6 quoted lines
> 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?

Show 10 quoted lines
>
>> 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

Elijah Newren· Dec 8, 2020, 23:11 UTC · re: Sergey Organov · lore

Re: [PATCH 00/26] git-log: implement new --diff-merge options

On Tue, Dec 8, 2020 at 2:30 PM Sergey Organov <sorganov@gmail.com> wrote:
Show 69 quoted lines
>
> 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/.

Show 25 quoted lines
> > 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.
Show 10 quoted lines
> 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

Junio C Hamano· Dec 9, 2020, 01:17 UTC · re: Elijah Newren · lore

Re: [PATCH 00/26] git-log: implement new --diff-merge options

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.

Show 5 quoted lines
> 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.

Elijah Newren· Dec 9, 2020, 03:06 UTC · re: Junio C Hamano · lore

Re: [PATCH 00/26] git-log: implement new --diff-merge options

Hi Junio,
On Tue, Dec 8, 2020 at 5:17 PM Junio C Hamano <gitster@pobox.com> wrote:
Show 11 quoted lines
>
> 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/
Show 11 quoted lines
> > 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?)

Junio C Hamano· Dec 9, 2020, 03:22 UTC · re: Elijah Newren · lore

Re: [PATCH 00/26] git-log: implement new --diff-merge options

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?

Elijah Newren· Dec 9, 2020, 03:31 UTC · re: Junio C Hamano · lore

Re: [PATCH 00/26] git-log: implement new --diff-merge options

On Tue, Dec 8, 2020 at 7:22 PM Junio C Hamano <gitster@pobox.com> wrote:
Show 13 quoted lines
>
> 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.

Junio C Hamano· Dec 9, 2020, 04:18 UTC · re: Elijah Newren · lore

Re: [PATCH 00/26] git-log: implement new --diff-merge options

Elijah Newren <newren@gmail.com> writes:
Show 11 quoted lines
>> 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.

Elijah Newren· Dec 9, 2020, 04:54 UTC · re: Junio C Hamano · lore

Re: [PATCH 00/26] git-log: implement new --diff-merge options

On Tue, Dec 8, 2020 at 8:18 PM Junio C Hamano <gitster@pobox.com> wrote:
Show 48 quoted lines
>
> 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...

Junio C Hamano· Dec 9, 2020, 05:24 UTC · re: Elijah Newren · lore

Re: [PATCH 00/26] git-log: implement new --diff-merge options

Elijah Newren <newren@gmail.com> writes:
Show 12 quoted lines
>> 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.

Junio C Hamano· Dec 9, 2020, 06:40 UTC · re: Junio C Hamano · lore

Re: [PATCH 00/26] git-log: implement new --diff-merge options

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.

Sergey Organov· Dec 9, 2020, 14:08 UTC · re: Junio C Hamano · lore

Re: [PATCH 00/26] git-log: implement new --diff-merge options

Junio C Hamano <gitster@pobox.com> writes:
Show 37 quoted lines
> 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".

Show 13 quoted lines
>
>> 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.

Show 6 quoted lines
>
> 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

Junio C Hamano· Dec 9, 2020, 20:53 UTC · re: Sergey Organov · lore

Re: [PATCH 00/26] git-log: implement new --diff-merge options

Sergey Organov <sorganov@gmail.com> writes:
Show 15 quoted lines
>>> 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 ;-)
Sergey Organov· Dec 9, 2020, 19:44 UTC · re: Junio C Hamano · lore

Re: [PATCH 00/26] git-log: implement new --diff-merge options

Junio C Hamano <gitster@pobox.com> writes:
[...]
Show 6 quoted lines
> 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

Junio C Hamano· Dec 10, 2020, 06:12 UTC · re: Sergey Organov · lore

Re: [PATCH 00/26] git-log: implement new --diff-merge options

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.

Elijah Newren· Dec 10, 2020, 07:26 UTC · re: Sergey Organov · lore

Re: [PATCH 00/26] git-log: implement new --diff-merge options

On Wed, Dec 9, 2020 at 11:44 AM Sergey Organov <sorganov@gmail.com> wrote:
Show 17 quoted lines
>
> 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.

Show 7 quoted lines
>> 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?
Sergey Organov· Dec 10, 2020, 20:10 UTC · re: Elijah Newren · lore

Re: [PATCH 00/26] git-log: implement new --diff-merge options

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

Junio C Hamano· Dec 10, 2020, 21:15 UTC · re: Sergey Organov · lore

Re: [PATCH 00/26] git-log: implement new --diff-merge options

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.

Junio C Hamano· Dec 10, 2020, 21:26 UTC · re: Elijah Newren · lore

Re: [PATCH 00/26] git-log: implement new --diff-merge options

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.

Sergey Organov· Dec 9, 2020, 13:34 UTC · re: Elijah Newren · lore

Re: [PATCH 00/26] git-log: implement new --diff-merge options

Elijah Newren <newren@gmail.com> writes:
Show 63 quoted lines
> 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

Sergey Organov· Dec 16, 2020, 18:48 UTC · re: Sergey Organov · lore

[PATCH v2 00/33] git-log: implement new --diff-merge options

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
Sergey Organov· Dec 16, 2020, 18:48 UTC · re: Sergey Organov · lore

[PATCH v2 01/33] revision: factor out parsing of diff-merge related options

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(-)
Show changes to revision.c +39 −27
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
Sergey Organov· Dec 16, 2020, 18:48 UTC · re: Sergey Organov · lore

[PATCH v2 02/33] revision: factor out setup of diff-merge related settings

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(-)
Show changes to revision.c +12 −6
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
Sergey Organov· Dec 16, 2020, 18:49 UTC · re: Sergey Organov · lore

[PATCH v2 04/33] revision: provide implementation for diff merges tweaks

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(-)
Show changes to 3 files +22 −11

builtin/log.c, revision.c, revision.h

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
Sergey Organov· Dec 16, 2020, 18:48 UTC · re: Sergey Organov · lore

[PATCH v2 03/33] revision: factor out initialization of diff-merge related settings

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(-)
Show changes to revision.c +7 −1
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
Sergey Organov· Dec 16, 2020, 18:49 UTC · re: Sergey Organov · lore

[PATCH v2 05/33] revision: move diff merges functions to its own diff-merges.c

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
Show changes to 6 files +93 −74

Makefile, builtin/log.c, diff-merges.c, diff-merges.h, revision.c, revision.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
Sergey Organov· Dec 16, 2020, 18:49 UTC · re: Sergey Organov · lore

[PATCH v2 06/33] diff-merges: rename all functions to have common prefix

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(-)
Show changes to 4 files +20 −15

builtin/log.c, diff-merges.c, diff-merges.h, revision.c

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
Sergey Organov· Dec 16, 2020, 18:49 UTC · re: Sergey Organov · lore

[PATCH v2 08/33] diff-merges: rename diff_merges_default_to_enable() to match semantics

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(-)
Show changes to 3 files +4 −4

builtin/log.c, diff-merges.c, diff-merges.h

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
Sergey Organov· Dec 16, 2020, 18:49 UTC · re: Sergey Organov · lore

[PATCH v2 07/33] diff-merges: move checks for first_parent_only out of the module

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(-)
Show changes to 3 files +11 −9

builtin/log.c, diff-merges.c, diff-merges.h

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
Sergey Organov· Dec 16, 2020, 18:49 UTC · re: Sergey Organov · lore

[PATCH v2 10/33] diff-merges: new function diff_merges_suppress()

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(-)
Show changes to 4 files +19 −4

builtin/merge.c, diff-merges.c, diff-merges.h, fmt-merge-msg.c

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
Sergey Organov· Dec 16, 2020, 18:49 UTC · re: Sergey Organov · lore

[PATCH v2 09/33] diff-merges: re-arrange functions to match the order they are called in

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(-)
Show changes to 2 files +17 −14

diff-merges.c, diff-merges.h

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
Sergey Organov· Dec 16, 2020, 18:49 UTC · re: Sergey Organov · lore

[PATCH v2 11/33] diff-merges: new function diff_merges_set_dense_combined_if_unset()

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(-)
Show changes to 4 files +22 −8

builtin/diff-files.c, builtin/diff.c, diff-merges.c, diff-merges.h

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
Sergey Organov· Dec 16, 2020, 18:49 UTC · re: Sergey Organov · lore

[PATCH v2 13/33] diff-merges: revise revs->diff flag handling

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(-)
Show changes to diff-merges.c +2 −3
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
Sergey Organov· Dec 16, 2020, 18:49 UTC · re: Sergey Organov · lore

[PATCH v2 12/33] diff-merges: introduce revs->first_parent_merges flag

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(-)
Show changes to 3 files +5 −2

diff-merges.c, log-tree.c, revision.h

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
Sergey Organov· Dec 16, 2020, 18:49 UTC · re: Sergey Organov · lore

[PATCH v2 14/33] t4013: support test_expect_failure through ':failure' magic

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(-)
Show changes to t/t4013-diff-various.sh +6 −1
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
Sergey Organov· Dec 16, 2020, 18:49 UTC · re: Sergey Organov · lore

[PATCH v2 15/33] t4013: add tests for -m failing to override -c/--cc

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
Show changes to 3 files +372 −0

t/t4013-diff-various.sh, t/t4013/diff.log_--cc_-m_-p_master, 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
Sergey Organov· Dec 16, 2020, 18:49 UTC · re: Sergey Organov · lore

[PATCH v2 16/33] diff-merges: fix -m to properly override -c/--cc

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(-)
Show changes to 2 files +3 −2

diff-merges.c, t/t4013-diff-various.sh

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
Sergey Organov· Dec 16, 2020, 18:49 UTC · re: Sergey Organov · lore

[PATCH v2 20/33] diff-merges: refactor opt settings into separate functions

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(-)
Show changes to diff-merges.c +37 −22
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
Sergey Organov· Dec 16, 2020, 18:49 UTC · re: Sergey Organov · lore

[PATCH v2 19/33] diff-merges: get rid of now empty diff_merges_init_revs()

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(-)
Show changes to 3 files +0 −6

diff-merges.c, diff-merges.h, revision.c

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
Sergey Organov· Dec 16, 2020, 18:49 UTC · re: Sergey Organov · lore

[PATCH v2 23/33] diff-merges: fix style of functions definitions

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(-)
Show changes to diff-merges.c +24 −12
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
Elijah Newren· Dec 18, 2020, 05:42 UTC · re: Sergey Organov · lore

Re: [PATCH v2 23/33] diff-merges: fix style of functions definitions

On Wed, Dec 16, 2020 at 10:50 AM Sergey Organov <sorganov@gmail.com> wrote:
Show 117 quoted lines
>
> 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?

Sergey Organov· Dec 18, 2020, 13:41 UTC · re: Elijah Newren · lore

Re: [PATCH v2 23/33] diff-merges: fix style of functions definitions

Elijah Newren <newren@gmail.com> writes:
Show 15 quoted lines
> 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 @@
>>
[...]
Show 13 quoted lines
>>
>> -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

Elijah Newren· Dec 18, 2020, 16:12 UTC · re: Sergey Organov · lore

Re: [PATCH v2 23/33] diff-merges: fix style of functions definitions

On Fri, Dec 18, 2020 at 5:41 AM Sergey Organov <sorganov@gmail.com> wrote:
Show 51 quoted lines
>
> 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.

Sergey Organov· Dec 18, 2020, 21:23 UTC · re: Elijah Newren · lore

Re: [PATCH v2 23/33] diff-merges: fix style of functions definitions

Elijah Newren <newren@gmail.com> writes:
Show 56 quoted lines
> 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

Elijah Newren· Dec 18, 2020, 22:56 UTC · re: Sergey Organov · lore

Re: [PATCH v2 23/33] diff-merges: fix style of functions definitions

On Fri, Dec 18, 2020 at 1:23 PM Sergey Organov <sorganov@gmail.com> wrote:
Show 64 quoted lines
>
> 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.

All that said, I don't get to choose what's accepted or not, so I can't say if it'll be required. What I can say is I like your series and I think it provides obvious improvements, but I'd still recommend against its inclusion as it stands for as long as this patch is still present. (I have a feeling that there are other things in this series that possibly should be squashed, restructured, or refactored, e.g. [1]). This is just my opinion, of course. You are free to disagree with me, and wait to see what others say and what Junio does.

[1] https://lore.kernel.org/git/CABPp-BESWpqska++EsfxfbncyV0kNo1RGLjF+1BiV=D6zLx2LQ@mail.gmail.com/
Felipe Contreras· Dec 19, 2020, 01:00 UTC · re: Elijah Newren · lore

Re: [PATCH v2 23/33] diff-merges: fix style of functions definitions

Elijah Newren wrote:
Show 11 quoted lines
> 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.
Me as well.

It's extra work for one person, but everyone else benefits, including that one person in the future (who usually forgets why he/she did things in that particular way).

Cheers.
-- 
Felipe Contreras
Sergey Organov· Dec 19, 2020, 11:59 UTC · re: Elijah Newren · lore

Re: [PATCH v2 23/33] diff-merges: fix style of functions definitions

[...]
Felipe Contreras <felipe.contreras@gmail.com> writes:
Show 20 quoted lines
> Elijah Newren wrote:
>> 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.
>
> Me as well.
>
> It's extra work for one person, but everyone else benefits, including
> that one person in the future (who usually forgets why he/she did things
> in that particular way).
>
> Cheers.
Junio C Hamano <gitster@pobox.com> writes:
Show 25 quoted lines
> Sergey Organov <sorganov@gmail.com> writes:
>
>> 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.
>
> Sorry if it slipped through the cracks---I get too many discussion
> threads to pay attention to.
>
> Yes, we strongly prefer *not* to keep the honest history that
> records all the mistakes we made along the way.  Rather, we take the
> time a topic is still in flight and not yet cast in stone by merged
> to 'next' as an opportunity to pretend that the topic came to
> existence in the perfect shape, thanks to collective brain effort.
>
> It is our basic courtesy to future developers who has to read our
> code (i.e. "log -p") to understand what we've been thinking, when
> they want to fix some stupid bugs we will inevitably leave in our
> codebase.  It is distracting to read from the beginning of a topic,
> notice something funny going on and keep moveing to later patches,
> while harboring puzzlement in our minds, then later discover that
> the funny thing we noticed earlier was a simple mistake that gets
> fixed, not some clever trick the reader needs to think deeply to
> understand.
OK, so I'll do it.

I'd like to have some agreement on the final shape of the topic though before I cleanup the series, if possible.

Thanks, -- Sergey

Sergey Organov· Dec 20, 2020, 19:15 UTC · re: Sergey Organov · lore

Re: [PATCH v2 23/33] diff-merges: fix style of functions definitions

Sergey Organov <sorganov@gmail.com> writes:
Show 55 quoted lines
> [...]
>
> Felipe Contreras <felipe.contreras@gmail.com> writes:
>
>> Elijah Newren wrote:
>>> 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.
>>
>> Me as well.
>>
>> It's extra work for one person, but everyone else benefits, including
>> that one person in the future (who usually forgets why he/she did things
>> in that particular way).
>>
>> Cheers.
>
> Junio C Hamano <gitster@pobox.com> writes:
>
>> Sergey Organov <sorganov@gmail.com> writes:
>>
>>> 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.
>>
>> Sorry if it slipped through the cracks---I get too many discussion
>> threads to pay attention to.
>>
>> Yes, we strongly prefer *not* to keep the honest history that
>> records all the mistakes we made along the way.  Rather, we take the
>> time a topic is still in flight and not yet cast in stone by merged
>> to 'next' as an opportunity to pretend that the topic came to
>> existence in the perfect shape, thanks to collective brain effort.
>>
>> It is our basic courtesy to future developers who has to read our
>> code (i.e. "log -p") to understand what we've been thinking, when
>> they want to fix some stupid bugs we will inevitably leave in our
>> codebase.  It is distracting to read from the beginning of a topic,
>> notice something funny going on and keep moveing to later patches,
>> while harboring puzzlement in our minds, then later discover that
>> the funny thing we noticed earlier was a simple mistake that gets
>> fixed, not some clever trick the reader needs to think deeply to
>> understand.
>
> OK, so I'll do it.
>

While we are at it, Linux kernel developers care enough about style to provide script that checks patch series for issues and to insist it is run before submitting.

I've used this script to cleanup these series for the next re-roll and I think that having semi-automated test makes a lot of sense, so you may wish to consider to adopt it for Git as well (it seems to have some requirements that are not enforced for Git sources, but not many).

The script is called scripts/checkpatch.pl in the Linux kernel sources.

Thanks, -- Sergey

Felipe Contreras· Dec 21, 2020, 03:09 UTC · re: Sergey Organov · lore

Re: [PATCH v2 23/33] diff-merges: fix style of functions definitions

Sergey Organov wrote:
Show 10 quoted lines
> While we are at it, Linux kernel developers care enough about style to
> provide script that checks patch series for issues and to insist it is
> run before submitting.
> 
> I've used this script to cleanup these series for the next re-roll and I
> think that having semi-automated test makes a lot of sense, so you may
> wish to consider to adopt it for Git as well (it seems to have some
> requirements that are not enforced for Git sources, but not many).
> 
> The script is called scripts/checkpatch.pl in the Linux kernel sources.
Yeah, this has been suggested before.

It would make the job of newcomers that haven't learned the style yet much easier. And also it would make suggestions about the style of patches a bit less subjective.

Cheers.
-- 
Felipe Contreras
Junio C Hamano· Dec 19, 2020, 01:41 UTC · re: Sergey Organov · lore

Re: [PATCH v2 23/33] diff-merges: fix style of functions definitions

Sergey Organov <sorganov@gmail.com> writes:
> 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.

Sorry if it slipped through the cracks---I get too many discussion threads to pay attention to.

Yes, we strongly prefer *not* to keep the honest history that records all the mistakes we made along the way. Rather, we take the time a topic is still in flight and not yet cast in stone by merged to 'next' as an opportunity to pretend that the topic came to existence in the perfect shape, thanks to collective brain effort.

It is our basic courtesy to future developers who has to read our code (i.e. "log -p") to understand what we've been thinking, when they want to fix some stupid bugs we will inevitably leave in our codebase. It is distracting to read from the beginning of a topic, notice something funny going on and keep moveing to later patches, while harboring puzzlement in our minds, then later discover that the funny thing we noticed earlier was a simple mistake that gets fixed, not some clever trick the reader needs to think deeply to understand.

Thanks.
Sergey Organov· Dec 16, 2020, 18:49 UTC · re: Sergey Organov · lore

[PATCH v2 24/33] diff-merges: handle imply -p on -c/--cc logic for log.c

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(-)
Show changes to 2 files +6 −5

builtin/log.c, diff-merges.c

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
Elijah Newren· Dec 18, 2020, 06:00 UTC · re: Sergey Organov · lore

Re: [PATCH v2 24/33] diff-merges: handle imply -p on -c/--cc logic for log.c

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.

Show 41 quoted lines
> 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
>
Sergey Organov· Dec 18, 2020, 14:01 UTC · re: Elijah Newren · lore

Re: [PATCH v2 24/33] diff-merges: handle imply -p on -c/--cc logic for log.c

Elijah Newren <newren@gmail.com> writes:
Show 10 quoted lines
> 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.
Show 5 quoted lines
> 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

Show 43 quoted lines
>
>
>> 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
>>
Elijah Newren· Dec 18, 2020, 16:37 UTC · re: Sergey Organov · lore

Re: [PATCH v2 24/33] diff-merges: handle imply -p on -c/--cc logic for log.c

On Fri, Dec 18, 2020 at 6:01 AM Sergey Organov <sorganov@gmail.com> wrote:
Show 21 quoted lines
>
> 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. :-)

Show 12 quoted lines
> > 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.)

Sergey Organov· Dec 18, 2020, 21:45 UTC · re: Elijah Newren · lore

Re: [PATCH v2 24/33] diff-merges: handle imply -p on -c/--cc logic for log.c

Elijah Newren <newren@gmail.com> writes:
Show 27 quoted lines
> 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.

Show 32 quoted lines
>
>> > 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

Elijah Newren· Dec 18, 2020, 22:12 UTC · re: Sergey Organov · lore

Re: [PATCH v2 24/33] diff-merges: handle imply -p on -c/--cc logic for log.c

On Fri, Dec 18, 2020 at 1:45 PM Sergey Organov <sorganov@gmail.com> wrote:
Show 37 quoted lines
>
> 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...
Show 37 quoted lines
> >
> >> > 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".
Show 8 quoted lines
> 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.

Show 7 quoted lines
> >
> > (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.
Sergey Organov· Dec 18, 2020, 22:17 UTC · re: Elijah Newren · lore

Re: [PATCH v2 24/33] diff-merges: handle imply -p on -c/--cc logic for log.c

Elijah Newren <newren@gmail.com> writes:
Show 106 quoted lines
> 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

Sergey Organov· Dec 16, 2020, 18:49 UTC · re: Sergey Organov · lore

[PATCH v2 28/33] diff-merges: add '--diff-merges=1' as synonym for 'first-parent'

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(-)
Show changes to diff-merges.c +2 −1
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
Elijah Newren· Dec 18, 2020, 06:19 UTC · re: Sergey Organov · lore

Re: [PATCH v2 28/33] diff-merges: add '--diff-merges=1' as synonym for 'first-parent'

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.)

Show 22 quoted lines
> 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
>
Sergey Organov· Dec 18, 2020, 14:45 UTC · re: Elijah Newren · lore

Re: [PATCH v2 28/33] diff-merges: add '--diff-merges=1' as synonym for 'first-parent'

Elijah Newren <newren@gmail.com> writes:
Show 12 quoted lines
> 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

Sergey Organov· Dec 16, 2020, 18:49 UTC · re: Sergey Organov · lore

[PATCH v2 27/33] diff-merges: add old mnemonic counterparts to --diff-merges

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(-)
Show changes to diff-merges.c +6 −3
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
Sergey Organov· Dec 16, 2020, 18:49 UTC · re: Sergey Organov · lore

[PATCH v2 31/33] doc/rev-list-options: document --first-parent changes merges format

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(+)
Show changes to Documentation/rev-list-options.txt +5 −0
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
Sergey Organov· Dec 16, 2020, 18:49 UTC · re: Sergey Organov · lore

[PATCH v2 30/33] doc/diff-generate-patch: mention new --diff-merges option

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(-)
Show changes to Documentation/diff-generate-patch.txt +3 −3
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
Sergey Organov· Dec 16, 2020, 18:49 UTC · re: Sergey Organov · lore

[PATCH v2 18/33] diff-merges: group diff-merge flags next to each other inside 'rev_info'

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(-)
Show changes to revision.h +3 −2
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
Sergey Organov· Dec 16, 2020, 18:49 UTC · re: Sergey Organov · lore

[PATCH v2 17/33] diff-merges: split 'ignore_merges' field

'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(-)
Show changes to 3 files +23 −26

diff-merges.c, log-tree.c, revision.h

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
Sergey Organov· Dec 16, 2020, 18:49 UTC · re: Sergey Organov · lore

[PATCH v2 21/33] diff-merges: make -m/-c/--cc explicitly mutually exclusive

-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(+)
Show changes to diff-merges.c +3 −0
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
Sergey Organov· Dec 16, 2020, 18:49 UTC · re: Sergey Organov · lore

[PATCH v2 26/33] diff-merges: let new options enable diff without -p

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(-)
Show changes to 3 files +20 −10

diff-merges.c, log-tree.c, revision.h

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
Elijah Newren· Dec 18, 2020, 06:12 UTC · re: Sergey Organov · lore

Re: [PATCH v2 26/33] diff-merges: let new options enable diff without -p

On Wed, Dec 16, 2020 at 10:50 AM Sergey Organov <sorganov@gmail.com> wrote:
Show 35 quoted lines
>
> 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)
>  {
Show 7 quoted lines
> +       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.
Show 8 quoted lines
>         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.

Show 19 quoted lines
>  }
>
>  /*
> @@ -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.

Show 11 quoted lines
>  }
> 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?)

Show 41 quoted lines
> -       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.
Sergey Organov· Dec 18, 2020, 14:42 UTC · re: Elijah Newren · lore

Re: [PATCH v2 26/33] diff-merges: let new options enable diff without -p

Elijah Newren <newren@gmail.com> writes:
Show 46 quoted lines
> 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).

Show 12 quoted lines
>
>>         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!
Show 42 quoted lines
>
>>  }
>>
>>  /*
>> @@ -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?
Show 44 quoted lines
>
>> -       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

Elijah Newren· Dec 18, 2020, 17:01 UTC · re: Sergey Organov · lore

Re: [PATCH v2 26/33] diff-merges: let new options enable diff without -p

On Fri, Dec 18, 2020 at 6:42 AM Sergey Organov <sorganov@gmail.com> wrote:
Show 52 quoted lines
>
> 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.

Show 72 quoted lines
> >
> >>         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.

Show 46 quoted lines
> >> -       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
Sergey Organov· Dec 18, 2020, 20:32 UTC · re: Elijah Newren · lore

Re: [PATCH v2 26/33] diff-merges: let new options enable diff without -p

Elijah Newren <newren@gmail.com> writes:
Show 5 quoted lines
> 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:
[...]
Show 48 quoted lines
>> >> 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

Elijah Newren· Dec 18, 2020, 22:06 UTC · re: Sergey Organov · lore

Re: [PATCH v2 26/33] diff-merges: let new options enable diff without -p

On Fri, Dec 18, 2020 at 12:32 PM Sergey Organov <sorganov@gmail.com> wrote:
Show 76 quoted lines
>
> 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.

Sergey Organov· Dec 18, 2020, 22:19 UTC · re: Elijah Newren · lore

Re: [PATCH v2 26/33] diff-merges: let new options enable diff without -p

Elijah Newren <newren@gmail.com> writes:
Show 82 quoted lines
> 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

Sergey Organov· Dec 18, 2020, 20:53 UTC · re: Elijah Newren · lore

Re: [PATCH v2 26/33] diff-merges: let new options enable diff without -p

Elijah Newren <newren@gmail.com> writes:
Show 58 quoted lines
> 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

Sergey Organov· Dec 19, 2020, 12:11 UTC · re: Elijah Newren · lore

Re: [PATCH v2 26/33] diff-merges: let new options enable diff without -p

Elijah Newren <newren@gmail.com> writes:
Show 23 quoted lines
> 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(-)
[...]
Show 36 quoted lines
>> >> 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.

The problem is that original name I've used lies to the reader, or, more precisely, tells half-truth. True meaning of the variable is "do run diff for any commit, no matter if it's merge or not". So "need_diff" is already better than "regulars_need_diff".

Maybe "diff_all_commits" will do?

Thanks, -- Sergey

Felipe Contreras· Dec 19, 2020, 13:35 UTC · re: Sergey Organov · lore

Re: [PATCH v2 26/33] diff-merges: let new options enable diff without -p

Sergey Organov wrote:
Show 6 quoted lines
> The problem is that original name I've used lies to the reader, or, more
> precisely, tells half-truth. True meaning of the variable is "do run
> diff for any commit, no matter if it's merge or not". So "need_diff" is
> already better than "regulars_need_diff".
> 
> Maybe "diff_all_commits" will do?
all_need_diff
-- 
Felipe Contreras
Sergey Organov· Dec 19, 2020, 16:23 UTC · re: Felipe Contreras · lore

Re: [PATCH v2 26/33] diff-merges: let new options enable diff without -p

Felipe Contreras <felipe.contreras@gmail.com> writes:
Show 9 quoted lines
> Sergey Organov wrote:
>> The problem is that original name I've used lies to the reader, or, more
>> precisely, tells half-truth. True meaning of the variable is "do run
>> diff for any commit, no matter if it's merge or not". So "need_diff" is
>> already better than "regulars_need_diff".
>> 
>> Maybe "diff_all_commits" will do?
>
> all_need_diff
Fine with me.

Thanks, -- Sergey

Sergey Organov· Dec 20, 2020, 19:07 UTC · re: Sergey Organov · lore

Re: [PATCH v2 26/33] diff-merges: let new options enable diff without -p

Sergey Organov <sorganov@gmail.com> writes:
> Elijah Newren <newren@gmail.com> writes:
>
>> On Wed, Dec 16, 2020 at 10:50 AM Sergey Organov <sorganov@gmail.com> wrote:
>>>
[...]
Show 14 quoted lines
>>
>>>         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!

In fact this can't be done as it changes the outcome, as set_xxx() functions clear the flag.

I rather added clarification comments to the code.

Thanks, -- Sergey

Felipe Contreras· Dec 19, 2020, 13:36 UTC · re: Sergey Organov · lore

RE: [PATCH v2 26/33] diff-merges: let new options enable diff without -p

Sergey Organov wrote:
Show 23 quoted lines
> 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;
Missed a space:
        if (!is_merge && !regulars_need_diff)
-- 
Felipe Contreras
Sergey Organov· Dec 19, 2020, 16:19 UTC · re: Felipe Contreras · lore

Re: [PATCH v2 26/33] diff-merges: let new options enable diff without -p

Felipe Contreras <felipe.contreras@gmail.com> writes:
Show 28 quoted lines
> Sergey Organov 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;
>>  
>> -	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;
>
> Missed a space:
>
>         if (!is_merge && !regulars_need_diff)
Oops, thanks!
-- Sergey
Sergey Organov· Dec 16, 2020, 18:49 UTC · re: Sergey Organov · lore

[PATCH v2 25/33] diff-merges: do not imply -p for new options

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(-)
Show changes to 2 files +10 −3

diff-merges.c, revision.h

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
Sergey Organov· Dec 16, 2020, 18:49 UTC · re: Sergey Organov · lore

[PATCH v2 29/33] doc/git-log: describe new --diff-merges options

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(-)
Show changes to Documentation/git-log.txt +52 −30
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
Elijah Newren· Dec 18, 2020, 05:53 UTC · re: Sergey Organov · lore

Re: [PATCH v2 29/33] doc/git-log: describe new --diff-merges options

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.

Show 25 quoted lines
> 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.  :-)
Show 28 quoted lines
>
> --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?
Show 8 quoted lines
> ++
> +--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)

Show 10 quoted lines
> ++
> +--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?)

Show 10 quoted lines
> ++
> +--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.
Show 27 quoted lines
>  --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.
Sergey Organov· Dec 18, 2020, 16:05 UTC · re: Elijah Newren · lore

Re: [PATCH v2 29/33] doc/git-log: describe new --diff-merges options

Elijah Newren <newren@gmail.com> writes:
Show 36 quoted lines
> 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 :-)
Show 31 quoted lines
>
>>
>> --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?

Show 11 quoted lines
>> ++
>> +--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.

Show 13 quoted lines
>
>> ++
>> +--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.

Show 13 quoted lines
>
>> ++
>> +--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.
Show 30 quoted lines
>
>>  --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

Elijah Newren· Dec 18, 2020, 17:25 UTC · re: Sergey Organov · lore

Re: [PATCH v2 29/33] doc/git-log: describe new --diff-merges options

On Fri, Dec 18, 2020 at 8:05 AM Sergey Organov <sorganov@gmail.com> wrote:
Show 76 quoted lines
>
> 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.

Show 15 quoted lines
> >> ++
> >> +--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.
Show 15 quoted lines
> >> ++
> >> +--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.

Show 5 quoted lines
> > (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.
Show 49 quoted lines
> >
> >> ++
> >> +--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
Sergey Organov· Dec 18, 2020, 22:11 UTC · re: Elijah Newren · lore

Re: [PATCH v2 29/33] doc/git-log: describe new --diff-merges options

Elijah Newren <newren@gmail.com> writes:
Show 80 quoted lines
> 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.
Show 18 quoted lines
>
>> >> ++
>> >> +--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`.
Show 31 quoted lines
>
>> >> ++
>> >> +--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.

Show 6 quoted lines
> 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

Elijah Newren· Dec 18, 2020, 22:28 UTC · re: Sergey Organov · lore

Re: [PATCH v2 29/33] doc/git-log: describe new --diff-merges options

On Fri, Dec 18, 2020 at 2:11 PM Sergey Organov <sorganov@gmail.com> wrote:
Show 85 quoted lines
>
> 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.
Show 25 quoted lines
> >
> >> >> ++
> >> >> +--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.

Show 9 quoted lines
> 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.  :-)
Show 35 quoted lines
> >
> >> >> ++
> >> >> +--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).

Show 21 quoted lines
> > 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.
Sergey Organov· Dec 16, 2020, 18:49 UTC · re: Sergey Organov · lore

[PATCH v2 32/33] doc/git-show: include --diff-merges description

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(-)
Show changes to 3 files +59 −39

Documentation/diff-options.txt, Documentation/git-log.txt, Documentation/git-show.txt

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
Sergey Organov· Dec 16, 2020, 18:49 UTC · re: Sergey Organov · lore

[PATCH v2 33/33] t4013: add tests for --diff-merges=first-parent

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
Show changes to 3 files +183 −0

t/t4013-diff-various.sh, t/t4013/diff.log_--diff-merges=first-parent_master, 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
Sergey Organov· Dec 16, 2020, 18:49 UTC · re: Sergey Organov · lore

[PATCH v2 22/33] diff-merges: implement new values for --diff-merges

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(-)
Show changes to diff-merges.c +16 −3
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
Elijah Newren· Dec 18, 2020, 05:39 UTC · re: Sergey Organov · lore

Re: [PATCH v2 22/33] diff-merges: implement new values for --diff-merges

On Wed, Dec 16, 2020 at 10:50 AM Sergey Organov <sorganov@gmail.com> wrote:
Show 40 quoted lines
>
> 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?
Show 12 quoted lines
> +       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?

Show 8 quoted lines
>                 die(_("unknown value for --diff-merges: %s"), optarg);
> -       }
>  }
>
>  /*
> --
> 2.25.1
>
Sergey Organov· Dec 18, 2020, 14:12 UTC · re: Elijah Newren · lore

Re: [PATCH v2 22/33] diff-merges: implement new values for --diff-merges

Elijah Newren <newren@gmail.com> writes:
Show 43 quoted lines
> 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.

Show 17 quoted lines
>
>> +       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

Elijah Newren· Dec 18, 2020, 16:42 UTC · re: Sergey Organov · lore

Re: [PATCH v2 22/33] diff-merges: implement new values for --diff-merges

On Fri, Dec 18, 2020 at 6:12 AM Sergey Organov <sorganov@gmail.com> wrote:
Show 73 quoted lines
>
> 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.
Show 6 quoted lines
> > 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.

Sergey Organov· Dec 18, 2020, 21:00 UTC · re: Elijah Newren · lore

Re: [PATCH v2 22/33] diff-merges: implement new values for --diff-merges

Elijah Newren <newren@gmail.com> writes:
Show 92 quoted lines
> 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

Elijah Newren· Dec 18, 2020, 06:54 UTC · re: Sergey Organov · lore

Re: [PATCH v2 00/33] git-log: implement new --diff-merge options

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).

Show 162 quoted lines
> 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
>
Sergey Organov· Dec 18, 2020, 13:39 UTC · re: Elijah Newren · lore

Re: [PATCH v2 00/33] git-log: implement new --diff-merge options

Hi Elijah,
Thanks a lot for reviewing the series!
Elijah Newren <newren@gmail.com> writes:
Show 11 quoted lines
> 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!

Show 18 quoted lines
>
> 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

Sergey Organov· Dec 21, 2020, 15:19 UTC · re: Sergey Organov · lore

[PATCH v3 00/32] git-log: implement new --diff-merge options

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 v3:
  * Fixed all the known style issues
  * Revised -m, -c, and -cc description as suggested by Elijah Newren
  * Removed manual abbrevs for diff-merge options
  * Got rid of if(0) ; idiom
  * Renamed regulars_need_diff to all_need_diff to better reflect
    the meaning of the variable.
  * Moved "diff-merges: handle imply -p on -c/--cc logic for log.c"
    closer to the beginning of the series, where it belongs as being
    pure refactoring of the old code.
  * Added code clarification comments to set_diff_merges()
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.
Signed-off-by: Sergey Organov <sorganov@gmail.com>
Sergey Organov (32):
  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: handle imply -p on -c/--cc logic for log.c
  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: 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                |  51 +++++
 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                                 | 146 +++++++++++++
 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, 893 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
Interdiff against v2:
Show changes to 3 files +22 −29

Documentation/diff-options.txt, diff-merges.c, log-tree.c

diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt
index 98db2be423dc..c995e82584f3 100644
--- a/Documentation/diff-options.txt
+++ b/Documentation/diff-options.txt
@@ -55,8 +55,7 @@ ifdef::git-log[]
 -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`.
+	for each parent. `-m` doesn't produce any output without `-p`.
 +
 --diff-merges=combined:::
 --diff-merges=c:::
@@ -65,8 +64,8 @@ ifdef::git-log[]
 	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.
+	only files which were modified from all parents. `-c` implies
+	`-p`.
 +
 --diff-merges=dense-combined:::
 --diff-merges=cc:::
@@ -75,8 +74,7 @@ ifdef::git-log[]
 	`--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.
+	modification.  `--cc` implies `-p`.
 
 --combined-all-paths::
 	This flag causes combined diffs (used for merge commits) to
diff --git a/diff-merges.c b/diff-merges.c
index 63a0d78b7730..146bb50316a6 100644
--- a/diff-merges.c
+++ b/diff-merges.c
@@ -54,23 +54,22 @@ static void set_diff_merges(struct rev_info *revs, const char *optarg)
 {
 	if (!strcmp(optarg, "off") || !strcmp(optarg, "none")) {
 		suppress(revs);
+		/* Return early to leave revs->merges_need_diff unset */
 		return;
 	}
-	if (0) ;
-	else if (!strcmp(optarg, "first") || !strcmp(optarg, "first-parent") ||
-		 !strcmp(optarg, "1"))
+
+	if (!strcmp(optarg, "1") || !strcmp(optarg, "first-parent"))
 		set_first_parent(revs);
-	else if (!strcmp(optarg, "sep")   || !strcmp(optarg, "separate") ||
-		 !strcmp(optarg, "m"))
+	else if (!strcmp(optarg, "m") || !strcmp(optarg, "separate"))
 		set_separate(revs);
-	else if (!strcmp(optarg, "comb")  || !strcmp(optarg, "combined") ||
-		 !strcmp(optarg, "c"))
+	else if (!strcmp(optarg, "c") || !strcmp(optarg, "combined"))
 		set_combined(revs);
-	else if (!strcmp(optarg, "dense") || !strcmp(optarg, "dense-combined") ||
-		 !strcmp(optarg, "cc"))
+	else if (!strcmp(optarg, "cc") || !strcmp(optarg, "dense-combined"))
 		set_dense_combined(revs);
 	else
 		die(_("unknown value for --diff-merges: %s"), optarg);
+
+	/* The flag is cleared by set_xxx() functions, so don't move this up */
 	revs->merges_need_diff = 1;
 }
 
@@ -84,23 +83,21 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv)
 	const char *optarg;
 	const char *arg = argv[0];
 
-	if (!strcmp(arg, "-m"))
+	if (!strcmp(arg, "-m")) {
 		set_m(revs);
-	else if (!strcmp(arg, "-c")) {
+	} else if (!strcmp(arg, "-c")) {
 		set_combined(revs);
 		revs->combined_imply_patch = 1;
-	}
-	else if (!strcmp(arg, "--cc")) {
+	} else if (!strcmp(arg, "--cc")) {
 		set_dense_combined(revs);
 		revs->combined_imply_patch = 1;
-	}
-	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)))
+	} else if ((argcount = parse_long_opt("diff-merges", argv, &optarg))) {
 		set_diff_merges(revs, optarg);
-	else
+	} else
 		return 0;
 
 	revs->explicit_diff_merges = 1;
@@ -140,10 +137,8 @@ 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->combined_imply_patch)
 		revs->diff = 1;
-
 	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 67060492ca0a..9f50a81e537e 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -900,9 +900,9 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log
 	struct commit_list *parents;
 	struct object_id *oid;
 	int is_merge;
-	int regulars_need_diff = opt->diff || opt->diffopt.flags.exit_with_status;
+	int all_need_diff = opt->diff || opt->diffopt.flags.exit_with_status;
 
-	if (!regulars_need_diff && !opt->merges_need_diff)
+	if (!all_need_diff && !opt->merges_need_diff)
 		return 0;
 
 	parse_commit_or_die(commit);
@@ -910,7 +910,7 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log
 
 	parents = get_saved_parents(opt, commit);
 	is_merge = parents && parents->next;
-	if(!is_merge && !regulars_need_diff)
+	if (!is_merge && !all_need_diff)
 		return 0;
 
 	/* Root commit? */
-- 
2.25.1
Sergey Organov· Dec 21, 2020, 15:20 UTC · re: Sergey Organov · lore

[PATCH v3 32/32] t4013: add tests for --diff-merges=first-parent

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
Show changes to 3 files +183 −0

t/t4013-diff-various.sh, t/t4013/diff.log_--diff-merges=first-parent_master, 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
Sergey Organov· Dec 21, 2020, 15:19 UTC · re: Sergey Organov · lore

[PATCH v3 09/32] diff-merges: re-arrange functions to match the order they are called in

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(-)
Show changes to 2 files +17 −14

diff-merges.c, diff-merges.h

diff --git a/diff-merges.c b/diff-merges.c
index 76c804579758..8325ab880166 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;
@@ -46,16 +50,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 */
@@ -72,3 +66,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
Sergey Organov· Dec 21, 2020, 15:19 UTC · re: Sergey Organov · lore

[PATCH v3 03/32] revision: factor out initialization of diff-merge related settings

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

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 revision.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)
Show changes to revision.c +8 −1
diff --git a/revision.c b/revision.c
index d818e0b18bbc..3250b2d7e112 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,11 @@ 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;
-- 
2.25.1
Sergey Organov· Dec 21, 2020, 15:19 UTC · re: Sergey Organov · lore

[PATCH v3 11/32] diff-merges: new function diff_merges_set_dense_combined_if_unset()

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        | 16 ++++++++++++++--
 diff-merges.h        |  2 ++
 4 files changed, 24 insertions(+), 8 deletions(-)
Show changes to 4 files +24 −8

builtin/diff-files.c, builtin/diff.c, diff-merges.c, diff-merges.h

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 23e6cb11d1ad..24f922cf8a0f 100644
--- a/diff-merges.c
+++ b/diff-merges.c
@@ -10,6 +10,13 @@ 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.
  */
@@ -39,8 +46,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")) {
@@ -80,6 +86,12 @@ 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
Sergey Organov· Dec 21, 2020, 15:19 UTC · re: Sergey Organov · lore

[PATCH v3 23/32] diff-merges: implement new values for --diff-merges

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(-)
Show changes to diff-merges.c +16 −3
diff --git a/diff-merges.c b/diff-merges.c
index e3c0190ebd95..4d22da179577 100644
--- a/diff-merges.c
+++ b/diff-merges.c
@@ -17,6 +17,12 @@ 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)
 {
 	/*
@@ -44,11 +50,18 @@ 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 (!strcmp(optarg, "off") || !strcmp(optarg, "none"))
 		suppress(revs);
-	} else {
+	else if (!strcmp(optarg, "first-parent"))
+		set_first_parent(revs);
+	else if (!strcmp(optarg, "separate"))
+		set_separate(revs);
+	else if (!strcmp(optarg, "combined"))
+		set_combined(revs);
+	else if (!strcmp(optarg, "dense-combined"))
+		set_dense_combined(revs);
+	else
 		die(_("unknown value for --diff-merges: %s"), optarg);
-	}
 }
 
 /*
-- 
2.25.1
Sergey Organov· Dec 21, 2020, 15:19 UTC · re: Sergey Organov · lore

[PATCH v3 22/32] diff-merges: make -m/-c/--cc explicitly mutually exclusive

-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(+)
Show changes to diff-merges.c +3 −0
diff --git a/diff-merges.c b/diff-merges.c
index b8fd92adcf16..e3c0190ebd95 100644
--- a/diff-merges.c
+++ b/diff-merges.c
@@ -8,6 +8,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)
@@ -29,12 +30,14 @@ 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
Sergey Organov· Dec 21, 2020, 15:19 UTC · re: Sergey Organov · lore

[PATCH v3 18/32] diff-merges: split 'ignore_merges' field

'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(-)
Show changes to 3 files +23 −26

diff-merges.c, log-tree.c, revision.h

diff --git a/diff-merges.c b/diff-merges.c
index 047bf81e6777..eff54cca8287 100644
--- a/diff-merges.c
+++ b/diff-merges.c
@@ -4,7 +4,7 @@
 
 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;
@@ -23,7 +23,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)
@@ -39,7 +38,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;
@@ -57,8 +56,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;
 }
 
@@ -69,21 +69,16 @@ 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)
@@ -94,10 +89,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
Sergey Organov· Dec 21, 2020, 15:19 UTC · re: Sergey Organov · lore

[PATCH v3 24/32] diff-merges: do not imply -p for new options

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 | 20 ++++++++++++--------
 revision.h    |  1 +
 2 files changed, 13 insertions(+), 8 deletions(-)
Show changes to 2 files +13 −8

diff-merges.c, revision.h

diff --git a/diff-merges.c b/diff-merges.c
index 4d22da179577..6d48ac5ab93d 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)
@@ -74,19 +75,21 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv)
 	const char *optarg;
 	const char *arg = argv[0];
 
-	if (!strcmp(arg, "-m"))
+	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);
-	else if (!strcmp(arg, "--no-diff-merges"))
+		revs->combined_imply_patch = 1;
+	} 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)))
+	} else if ((argcount = parse_long_opt("diff-merges", argv, &optarg))) {
 		set_diff_merges(revs, optarg);
-	else
+	} else
 		return 0;
 
 	revs->explicit_diff_merges = 1;
@@ -126,8 +129,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
Sergey Organov· Dec 21, 2020, 15:19 UTC · re: Sergey Organov · lore

[PATCH v3 17/32] diff-merges: fix -m to properly override -c/--cc

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(-)
Show changes to 2 files +3 −2

diff-merges.c, t/t4013-diff-various.sh

diff --git a/diff-merges.c b/diff-merges.c
index 225edd293b43..047bf81e6777 100644
--- a/diff-merges.c
+++ b/diff-merges.c
@@ -33,6 +33,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
Sergey Organov· Dec 21, 2020, 15:19 UTC · re: Sergey Organov · lore

[PATCH v3 15/32] t4013: support test_expect_failure through ':failure' magic

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(-)
Show changes to t/t4013-diff-various.sh +6 −1
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
Sergey Organov· Dec 21, 2020, 15:19 UTC · re: Sergey Organov · lore

[PATCH v3 26/32] diff-merges: add old mnemonic counterparts to --diff-merges

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 | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)
Show changes to diff-merges.c +3 −3
diff --git a/diff-merges.c b/diff-merges.c
index ee91ed0db409..011bfff1f135 100644
--- a/diff-merges.c
+++ b/diff-merges.c
@@ -60,11 +60,11 @@ static void set_diff_merges(struct rev_info *revs, const char *optarg)
 
 	if (!strcmp(optarg, "first-parent"))
 		set_first_parent(revs);
-	else if (!strcmp(optarg, "separate"))
+	else if (!strcmp(optarg, "m") || !strcmp(optarg, "separate"))
 		set_separate(revs);
-	else if (!strcmp(optarg, "combined"))
+	else if (!strcmp(optarg, "c") || !strcmp(optarg, "combined"))
 		set_combined(revs);
-	else if (!strcmp(optarg, "dense-combined"))
+	else if (!strcmp(optarg, "cc") || !strcmp(optarg, "dense-combined"))
 		set_dense_combined(revs);
 	else
 		die(_("unknown value for --diff-merges: %s"), optarg);
-- 
2.25.1
Sergey Organov· Dec 21, 2020, 15:19 UTC · re: Sergey Organov · lore

[PATCH v3 19/32] diff-merges: group diff-merge flags next to each other inside 'rev_info'

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(-)
Show changes to revision.h +3 −2
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
Sergey Organov· Dec 21, 2020, 15:19 UTC · re: Sergey Organov · lore

[PATCH v3 20/32] diff-merges: get rid of now empty diff_merges_init_revs()

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 | 4 ----
 diff-merges.h | 2 --
 revision.c    | 1 -
 3 files changed, 7 deletions(-)
Show changes to 3 files +0 −7

diff-merges.c, diff-merges.h, revision.c

diff --git a/diff-merges.c b/diff-merges.c
index eff54cca8287..34d7ed7c70b7 100644
--- a/diff-merges.c
+++ b/diff-merges.c
@@ -21,10 +21,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;
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
Sergey Organov· Dec 21, 2020, 15:19 UTC · re: Sergey Organov · lore

[PATCH v3 25/32] diff-merges: let new options enable diff without -p

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 | 17 ++++++++++++-----
 log-tree.c    | 13 +++++++++----
 revision.h    |  1 +
 3 files changed, 22 insertions(+), 9 deletions(-)
Show changes to 3 files +22 −9

diff-merges.c, log-tree.c, revision.h

diff --git a/diff-merges.c b/diff-merges.c
index 6d48ac5ab93d..ee91ed0db409 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,13 @@ 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"))
+	if (!strcmp(optarg, "off") || !strcmp(optarg, "none")) {
 		suppress(revs);
-	else if (!strcmp(optarg, "first-parent"))
+		/* Return early to leave revs->merges_need_diff unset */
+		return;
+	}
+
+	if (!strcmp(optarg, "first-parent"))
 		set_first_parent(revs);
 	else if (!strcmp(optarg, "separate"))
 		set_separate(revs);
@@ -63,6 +68,9 @@ 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);
+
+	/* The flag is cleared by set_xxx() functions, so don't move this up */
+	revs->merges_need_diff = 1;
 }
 
 /*
@@ -129,10 +137,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->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..9f50a81e537e 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 all_need_diff = opt->diff || opt->diffopt.flags.exit_with_status;
 
-	if (!opt->diff && !opt->diffopt.flags.exit_with_status)
+	if (!all_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 && !all_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
Felipe Contreras· Dec 21, 2020, 18:40 UTC · re: Sergey Organov · lore

RE: [PATCH v3 25/32] diff-merges: let new options enable diff without -p

Sergey Organov wrote:
Show 28 quoted lines
> diff --git a/log-tree.c b/log-tree.c
> index f9385b1dae6f..9f50a81e537e 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 all_need_diff = opt->diff || opt->diffopt.flags.exit_with_status;
>  
> -	if (!opt->diff && !opt->diffopt.flags.exit_with_status)
> +	if (!all_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 && !all_need_diff)
> +		return 0;
> +
> +	/* Root commit? */
>  	if (!parents) {
>  		if (opt->show_root_diff) {
>  			diff_root_tree_oid(oid, "", &opt->diffopt);
FWIW this logic does make sense to me.
-- 
Felipe Contreras
Sergey Organov· Dec 21, 2020, 20:07 UTC · re: Felipe Contreras · lore

Re: [PATCH v3 25/32] diff-merges: let new options enable diff without -p

Felipe Contreras <felipe.contreras@gmail.com> writes:
Show 31 quoted lines
> Sergey Organov wrote:
>> diff --git a/log-tree.c b/log-tree.c
>> index f9385b1dae6f..9f50a81e537e 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 all_need_diff = opt->diff || opt->diffopt.flags.exit_with_status;
>>  
>> -	if (!opt->diff && !opt->diffopt.flags.exit_with_status)
>> +	if (!all_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 && !all_need_diff)
>> +		return 0;
>> +
>> +	/* Root commit? */
>>  	if (!parents) {
>>  		if (opt->show_root_diff) {
>>  			diff_root_tree_oid(oid, "", &opt->diffopt);
>
> FWIW this logic does make sense to me.
Thanks for reviewing!
-- Sergey
Sergey Organov· Dec 21, 2020, 15:19 UTC · re: Sergey Organov · lore

[PATCH v3 06/32] diff-merges: rename all functions to have common prefix

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(-)
Show changes to 4 files +20 −15

builtin/log.c, diff-merges.c, diff-merges.h, revision.c

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 0204292aa9bb..9286dbbd4dfd 100644
--- a/diff-merges.c
+++ b/diff-merges.c
@@ -2,12 +2,12 @@
 
 #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;
@@ -46,7 +46,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;
@@ -56,13 +56,13 @@ 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 */
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
Sergey Organov· Dec 21, 2020, 15:19 UTC · re: Sergey Organov · lore

[PATCH v3 07/32] diff-merges: move checks for first_parent_only out of the module

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(-)
Show changes to 3 files +11 −9

builtin/log.c, diff-merges.c, diff-merges.h

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 9286dbbd4dfd..a3bafa92f3e1 100644
--- a/diff-merges.c
+++ b/diff-merges.c
@@ -56,19 +56,17 @@ 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)
+void diff_merges_default_to_enable(struct rev_info *revs)
 {
-	if (revs->first_parent_only && revs->ignore_merges < 0)
+	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
Sergey Organov· Dec 21, 2020, 15:19 UTC · re: Sergey Organov · lore

[PATCH v3 31/32] doc/git-show: include --diff-merges description

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 | 51 ++++++++++++++++++++++++++++++++++
 Documentation/git-log.txt      | 51 +---------------------------------
 Documentation/git-show.txt     |  7 +++--
 3 files changed, 57 insertions(+), 52 deletions(-)
Show changes to 3 files +57 −37

Documentation/diff-options.txt, Documentation/git-log.txt, Documentation/git-show.txt

diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt
index 573fb9bb71e2..c995e82584f3 100644
--- a/Documentation/diff-options.txt
+++ b/Documentation/diff-options.txt
@@ -33,6 +33,57 @@ 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` 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. `-c` implies
+	`-p`.
++
+--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.  `--cc` implies `-p`.
+
+--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 ff83dff14dd6..727d20e1a2ab 100644
--- a/Documentation/git-log.txt
+++ b/Documentation/git-log.txt
@@ -127,57 +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` 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. `-c` implies
-	`-p`.
-+
---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.  `--cc` implies `-p`.
-
---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
Sergey Organov· Dec 21, 2020, 15:19 UTC · re: Sergey Organov · lore

[PATCH v3 30/32] doc/rev-list-options: document --first-parent changes merges format

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(+)
Show changes to Documentation/rev-list-options.txt +5 −0
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
Sergey Organov· Dec 21, 2020, 15:19 UTC · re: Sergey Organov · lore

[PATCH v3 12/32] diff-merges: introduce revs->first_parent_merges flag

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(-)
Show changes to 3 files +5 −2

diff-merges.c, log-tree.c, revision.h

diff --git a/diff-merges.c b/diff-merges.c
index 24f922cf8a0f..fb591a933959 100644
--- a/diff-merges.c
+++ b/diff-merges.c
@@ -73,6 +73,8 @@ 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
Sergey Organov· Dec 21, 2020, 15:19 UTC · re: Sergey Organov · lore

[PATCH v3 21/32] diff-merges: refactor opt settings into separate functions

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 | 63 +++++++++++++++++++++++++++++++++------------------
 1 file changed, 41 insertions(+), 22 deletions(-)
Show changes to diff-merges.c +41 −22
diff --git a/diff-merges.c b/diff-merges.c
index 34d7ed7c70b7..b8fd92adcf16 100644
--- a/diff-merges.c
+++ b/diff-merges.c
@@ -10,12 +10,43 @@ 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.
@@ -27,31 +58,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
Sergey Organov· Dec 21, 2020, 15:19 UTC · re: Sergey Organov · lore

[PATCH v3 27/32] diff-merges: add '--diff-merges=1' as synonym for 'first-parent'

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 | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
Show changes to diff-merges.c +1 −1
diff --git a/diff-merges.c b/diff-merges.c
index 011bfff1f135..146bb50316a6 100644
--- a/diff-merges.c
+++ b/diff-merges.c
@@ -58,7 +58,7 @@ static void set_diff_merges(struct rev_info *revs, const char *optarg)
 		return;
 	}
 
-	if (!strcmp(optarg, "first-parent"))
+	if (!strcmp(optarg, "1") || !strcmp(optarg, "first-parent"))
 		set_first_parent(revs);
 	else if (!strcmp(optarg, "m") || !strcmp(optarg, "separate"))
 		set_separate(revs);
-- 
2.25.1
Sergey Organov· Dec 21, 2020, 15:19 UTC · re: Sergey Organov · lore

[PATCH v3 02/32] revision: factor out setup of diff-merge related settings

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(-)
Show changes to revision.c +12 −6
diff --git a/revision.c b/revision.c
index 8b17cfd754fe..d818e0b18bbc 100644
--- a/revision.c
+++ b/revision.c
@@ -2192,6 +2192,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)
@@ -2886,12 +2896,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
Sergey Organov· Dec 21, 2020, 15:19 UTC · re: Sergey Organov · lore

[PATCH v3 05/32] revision: move diff merges functions to its own diff-merges.c

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 | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++
 diff-merges.h | 18 ++++++++++++
 revision.c    | 76 +--------------------------------------------------
 revision.h    |  3 --
 6 files changed, 97 insertions(+), 78 deletions(-)
 create mode 100644 diff-merges.c
 create mode 100644 diff-merges.h
Show changes to 6 files +97 −78

Makefile, builtin/log.c, diff-merges.c, diff-merges.h, revision.c, revision.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..0204292aa9bb
--- /dev/null
+++ b/diff-merges.c
@@ -0,0 +1,76 @@
+#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 1c224d276474..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,79 +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
Sergey Organov· Dec 21, 2020, 15:19 UTC · re: Sergey Organov · lore

[PATCH v3 08/32] diff-merges: rename diff_merges_default_to_enable() to match semantics

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(-)
Show changes to 3 files +4 −4

builtin/log.c, diff-merges.c, diff-merges.h

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 a3bafa92f3e1..76c804579758 100644
--- a/diff-merges.c
+++ b/diff-merges.c
@@ -56,7 +56,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
Sergey Organov· Dec 21, 2020, 15:19 UTC · re: Sergey Organov · lore

[PATCH v3 28/32] doc/git-log: describe new --diff-merges options

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 | 83 +++++++++++++++++++++++----------------
 1 file changed, 50 insertions(+), 33 deletions(-)
Show changes to Documentation/git-log.txt +50 −30
diff --git a/Documentation/git-log.txt b/Documentation/git-log.txt
index 2b8ac5ff882a..ff83dff14dd6 100644
--- a/Documentation/git-log.txt
+++ b/Documentation/git-log.txt
@@ -120,45 +120,62 @@ 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` 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. `-c` implies
+	`-p`.
++
+--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.  `--cc` implies `-p`.
 
 --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
Sergey Organov· Dec 21, 2020, 15:19 UTC · re: Sergey Organov · lore

[PATCH v3 29/32] doc/diff-generate-patch: mention new --diff-merges option

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(-)
Show changes to Documentation/diff-generate-patch.txt +3 −3
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
Sergey Organov· Dec 21, 2020, 15:19 UTC · re: Sergey Organov · lore

[PATCH v3 01/32] revision: factor out parsing of diff-merge related options

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 | 67 ++++++++++++++++++++++++++++++++----------------------
 1 file changed, 40 insertions(+), 27 deletions(-)
Show changes to revision.c +40 −27
diff --git a/revision.c b/revision.c
index aa6221204081..8b17cfd754fe 100644
--- a/revision.c
+++ b/revision.c
@@ -2153,6 +2153,45 @@ 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 +2388,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
Sergey Organov· Dec 21, 2020, 15:19 UTC · re: Sergey Organov · lore

[PATCH v3 16/32] t4013: add tests for -m failing to override -c/--cc

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
Show changes to 3 files +372 −0

t/t4013-diff-various.sh, t/t4013/diff.log_--cc_-m_-p_master, 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
Sergey Organov· Dec 21, 2020, 15:19 UTC · re: Sergey Organov · lore

[PATCH v3 14/32] diff-merges: revise revs->diff flag handling

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 | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)
Show changes to diff-merges.c +1 −3
diff --git a/diff-merges.c b/diff-merges.c
index c48a65f8de64..225edd293b43 100644
--- a/diff-merges.c
+++ b/diff-merges.c
@@ -41,16 +41,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")) {
@@ -103,6 +100,7 @@ void diff_merges_setup_revs(struct rev_info *revs)
 	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;
 		/* 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
Sergey Organov· Dec 21, 2020, 15:19 UTC · re: Sergey Organov · lore

[PATCH v3 04/32] revision: provide implementation for diff merges tweaks

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    | 19 +++++++++++++++++++
 revision.h    |  3 +++
 3 files changed, 24 insertions(+), 11 deletions(-)
Show changes to 3 files +24 −11

builtin/log.c, revision.c, revision.h

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 3250b2d7e112..1c224d276474 100644
--- a/revision.c
+++ b/revision.c
@@ -2209,6 +2209,25 @@ 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
Sergey Organov· Dec 21, 2020, 15:19 UTC · re: Sergey Organov · lore

[PATCH v3 10/32] diff-merges: new function diff_merges_suppress()

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   | 17 +++++++++++++++--
 diff-merges.h   |  2 ++
 fmt-merge-msg.c |  3 ++-
 4 files changed, 21 insertions(+), 4 deletions(-)
Show changes to 4 files +21 −4

builtin/merge.c, diff-merges.c, diff-merges.h, fmt-merge-msg.c

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 8325ab880166..23e6cb11d1ad 100644
--- a/diff-merges.c
+++ b/diff-merges.c
@@ -2,6 +2,14 @@
 
 #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.
  */
@@ -34,13 +42,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);
 		}
@@ -50,6 +58,11 @@ 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 */
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
Sergey Organov· Dec 21, 2020, 15:19 UTC · re: Sergey Organov · lore

[PATCH v3 13/32] diff-merges: handle imply -p on -c/--cc logic for log.c

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 | 5 +++++
 2 files changed, 5 insertions(+), 4 deletions(-)
Show changes to 2 files +5 −4

builtin/log.c, diff-merges.c

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 fb591a933959..c48a65f8de64 100644
--- a/diff-merges.c
+++ b/diff-merges.c
@@ -102,4 +102,9 @@ 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) {
+		/* 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
Junio C Hamano· Jan 16, 2021, 07:01 UTC · re: Sergey Organov · lore

Re: [PATCH v3 00/32] git-log: implement new --diff-merge options

Sergey Organov <sorganov@gmail.com> writes:
> These patch series implement new set of options governing diff output
> of merge commits, all under the umbrella of single
> --diff-merges=<mode> option.

This latest round hasn't seen much review reactions, so I gave it a read-thru with fresh eyes. I didn't spot anything objectionable, so let's start merging it down to 'next'.

Thanks.
Sergey Organov· Jan 16, 2021, 09:17 UTC · re: Junio C Hamano · lore

Re: [PATCH v3 00/32] git-log: implement new --diff-merge options

Junio C Hamano <gitster@pobox.com> writes:
Show 9 quoted lines
> Sergey Organov <sorganov@gmail.com> writes:
>
>> These patch series implement new set of options governing diff output
>> of merge commits, all under the umbrella of single
>> --diff-merges=<mode> option.
>
> This latest round hasn't seen much review reactions, so I gave it a
> read-thru with fresh eyes.  I didn't spot anything objectionable, so
> let's start merging it down to 'next'.
Thanks, Junio!

In fact I'm planning to propose a few further improvements on top of this, and wanted to wait till these patches are settled.

-- Sergey Organov

← back to recent threads