{"thread":{"id":"54550","subject":"[PATCH 00/26] git-log: implement new --diff-merge options","startedAt":"2020-11-01T19:34:06Z","lastAt":"2021-01-16T09:18:12Z","messageCount":232,"participants":["Sergey Organov","Philip Oakley","Junio C Hamano","Elijah Newren","Felipe Contreras"],"isPatch":true,"patchVersion":1,"patchTotal":26},"messages":[{"id":"408823","messageId":"20201101193330.24775-1-sorganov@gmail.com","threadId":"54550","inReplyTo":null,"subject":"[PATCH 00/26] git-log: implement new --diff-merge options","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-11-01T19:33:04Z","receivedAt":"2020-11-01T19:34:06Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"These patch series implement new set of options governing the diff output\nof merge commits, all under the umbrella of the single --diff-merges=<mode>\noption. Most of the new options being synonyms for -m/-c/--cc options,\nthere is also additional functionality provided, allowing to get the format\nof \"-p --first-parent\" without change in history traversal that\n--first-parent option causes.\n\nThe net result of these series are the following new options:\n\n--diff-merges=\t |  old equivalent\n-----------------+----------------\nfirst-parent     | --first-parent (only format implications)\nseparate         | -m\ncombined         | -c\ndense-combined   | --cc\n\nThe series also cleanup logic of handling of diff merges options and fix an\nissue found in the original implementation where logically mutually\nexclusive options -m/-c/--cc failed to actually override each other.\n\nThe series start with the set of pure refactoring commits that are expected\nto introduce no functional changes. These are all commits up to and\nincluding:\n\n\"diff-merges: revise revs->diff flag handling\"\n\nThe aim of these commits is to isolate options handling for diff merges so\nthat it could be easily understood and tweaked to ease introduction of the\nnew options.\n\nThen the fix of -m/-c/-cc overriding issue follows, starting with a failing\ntest and followed by the fix.\n\nThen follows a little bit of additional refactoring in order to prepare for\nintroduction of the new options, and finally the series are finished by the\nimplementation, testing, and documentation update for the new options.\n\nSergey Organov (26):\n  revision: factor out parsing of diff-merge related options\n  revision: factor out setup of diff-merge related settings\n  revision: factor out initialization of diff-merge related settings\n  revision: provide implementation for diff merges tweaks\n  revision: move diff merges functions to its own diff-merges.c\n  diff-merges: rename all functions to have common prefix\n  diff-merges: move checks for first_parent_only out of the module\n  diff-merges: rename diff_merges_default_to_enable() to match semantics\n  diff-merges: re-arrange functions to match the order they are called\n    in\n  diff-merges: new function diff_merges_suppress()\n  diff-merges: new function diff_merges_set_dense_combined_if_unset()\n  diff-merges: introduce revs->first_parent_merges flag\n  diff-merges: revise revs->diff flag handling\n  t4013: support test_expect_failure through ':failure' magic\n  t4013: add tests for -m failing to override -c/--cc\n  diff-merges: fix -m to properly override -c/--cc\n  diff-merges: split 'ignore_merges' field\n  diff-merges: group diff-merge flags next to each other inside\n    'rev_info'\n  diff-merges: get rid of now empty diff_merges_init_revs()\n  diff-merges: refactor opt settings into separate functions\n  diff-merges: make -m/-c/--cc explicitly mutually exclusive\n  diff-merges: implement new values for --diff-merges\n  t4013: add test for --diff-merges=first-parent\n  doc/git-log: describe new --diff-merges options\n  doc/diff-generate-patch: mention new --diff-merges option\n  doc/rev-list-options: document --first-parent implies\n    --diff-merges=first-parent\n\n Documentation/diff-generate-patch.txt         |   6 +-\n Documentation/git-log.txt                     |  79 ++++---\n Documentation/rev-list-options.txt            |   3 +\n Makefile                                      |   1 +\n builtin/diff-files.c                          |   5 +-\n builtin/diff.c                                |   9 +-\n builtin/log.c                                 |  18 +-\n builtin/merge.c                               |   3 +-\n diff-merges.c                                 | 120 +++++++++++\n diff-merges.h                                 |  18 ++\n fmt-merge-msg.c                               |   3 +-\n log-tree.c                                    |  17 +-\n revision.c                                    |  38 +---\n revision.h                                    |   7 +-\n t/t4013-diff-various.sh                       |  10 +-\n t/t4013/diff.log_--cc_-m_-p_master            | 200 ++++++++++++++++++\n t/t4013/diff.log_-c_-m_-p_master              | 200 ++++++++++++++++++\n ...f.log_-p_--diff-merges=first-parent_master | 137 ++++++++++++\n 18 files changed, 774 insertions(+), 100 deletions(-)\n create mode 100644 diff-merges.c\n create mode 100644 diff-merges.h\n create mode 100644 t/t4013/diff.log_--cc_-m_-p_master\n create mode 100644 t/t4013/diff.log_-c_-m_-p_master\n create mode 100644 t/t4013/diff.log_-p_--diff-merges=first-parent_master\n\n-- \n2.25.1\n\n"},{"id":"408824","messageId":"20201101193330.24775-3-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201101193330.24775-1-sorganov@gmail.com","subject":"[PATCH 02/26] revision: factor out setup of diff-merge related settings","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-11-01T19:33:06Z","receivedAt":"2020-11-01T19:34:09Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Move all the setting code related to diffing merges into new\nsetup_diff_merge_revs() function.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n revision.c | 18 ++++++++++++------\n 1 file changed, 12 insertions(+), 6 deletions(-)\n\ndiff --git a/revision.c b/revision.c\nindex a09f4872acd7..739295bb9ff4 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -2191,6 +2191,16 @@ static int parse_diff_merge_opts(struct rev_info *revs, const char **argv) {\n \treturn 1;\n }\n \n+static void setup_diff_merges_revs(struct rev_info *revs)\n+{\n+\tif (revs->combine_merges && revs->ignore_merges < 0)\n+\t\trevs->ignore_merges = 0;\n+\tif (revs->ignore_merges < 0)\n+\t\trevs->ignore_merges = 1;\n+\tif (revs->combined_all_paths && !revs->combine_merges)\n+\t\tdie(\"--combined-all-paths makes no sense without -c or --cc\");\n+}\n+\n static int handle_revision_opt(struct rev_info *revs, int argc, const char **argv,\n \t\t\t       int *unkc, const char **unkv,\n \t\t\t       const struct setup_revision_opt* opt)\n@@ -2885,12 +2895,8 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s\n \t\t\tcopy_pathspec(&revs->diffopt.pathspec,\n \t\t\t\t      &revs->prune_data);\n \t}\n-\tif (revs->combine_merges && revs->ignore_merges < 0)\n-\t\trevs->ignore_merges = 0;\n-\tif (revs->ignore_merges < 0)\n-\t\trevs->ignore_merges = 1;\n-\tif (revs->combined_all_paths && !revs->combine_merges)\n-\t\tdie(\"--combined-all-paths makes no sense without -c or --cc\");\n+\n+\tsetup_diff_merges_revs(revs);\n \n \trevs->diffopt.abbrev = revs->abbrev;\n \n-- \n2.25.1\n\n"},{"id":"408825","messageId":"20201101193330.24775-4-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201101193330.24775-1-sorganov@gmail.com","subject":"[PATCH 03/26] revision: factor out initialization of diff-merge related settings","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-11-01T19:33:07Z","receivedAt":"2020-11-01T19:34:09Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Move initialization code related to diffing merges into new\ninit_diff_merge_revs() function.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n revision.c | 8 +++++++-\n 1 file changed, 7 insertions(+), 1 deletion(-)\n\ndiff --git a/revision.c b/revision.c\nindex 739295bb9ff4..bc568fb79778 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -1805,6 +1805,8 @@ static int add_parents_only(struct rev_info *revs, const char *arg_, int flags,\n \treturn 1;\n }\n \n+static void init_diff_merge_revs(struct rev_info *revs);\n+\n void repo_init_revisions(struct repository *r,\n \t\t\t struct rev_info *revs,\n \t\t\t const char *prefix)\n@@ -1813,7 +1815,7 @@ void repo_init_revisions(struct repository *r,\n \n \trevs->repo = r;\n \trevs->abbrev = DEFAULT_ABBREV;\n-\trevs->ignore_merges = -1;\n+\tinit_diff_merge_revs(revs);\n \trevs->simplify_history = 1;\n \trevs->pruning.repo = r;\n \trevs->pruning.flags.recursive = 1;\n@@ -2153,6 +2155,10 @@ static void add_message_grep(struct rev_info *revs, const char *pattern)\n \tadd_grep(revs, pattern, GREP_PATTERN_BODY);\n }\n \n+static void init_diff_merge_revs(struct rev_info *revs) {\n+\trevs->ignore_merges = -1;\n+}\n+\n static int parse_diff_merge_opts(struct rev_info *revs, const char **argv) {\n \tint argcount;\n \tconst char *optarg;\n-- \n2.25.1\n\n"},{"id":"408826","messageId":"20201101193330.24775-2-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201101193330.24775-1-sorganov@gmail.com","subject":"[PATCH 01/26] revision: factor out parsing of diff-merge related options","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-11-01T19:33:05Z","receivedAt":"2020-11-01T19:34:12Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Move all the parsing code related to diffing merges into new\nparse_diff_merge_opts() function.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n revision.c | 66 ++++++++++++++++++++++++++++++++----------------------\n 1 file changed, 39 insertions(+), 27 deletions(-)\n\ndiff --git a/revision.c b/revision.c\nindex aa6221204081..a09f4872acd7 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -2153,6 +2153,44 @@ static void add_message_grep(struct rev_info *revs, const char *pattern)\n \tadd_grep(revs, pattern, GREP_PATTERN_BODY);\n }\n \n+static int parse_diff_merge_opts(struct rev_info *revs, const char **argv) {\n+\tint argcount;\n+\tconst char *optarg;\n+\tconst char *arg = argv[0];\n+\n+\tif (!strcmp(arg, \"-m\")) {\n+\t\t/*\n+\t\t * To \"diff-index\", \"-m\" means \"match missing\", and to the \"log\"\n+\t\t * family of commands, it means \"show full diff for merges\". Set\n+\t\t * both fields appropriately.\n+\t\t */\n+\t\trevs->ignore_merges = 0;\n+\t\trevs->match_missing = 1;\n+\t} else if (!strcmp(arg, \"-c\")) {\n+\t\trevs->diff = 1;\n+\t\trevs->dense_combined_merges = 0;\n+\t\trevs->combine_merges = 1;\n+\t} else if (!strcmp(arg, \"--cc\")) {\n+\t\trevs->diff = 1;\n+\t\trevs->dense_combined_merges = 1;\n+\t\trevs->combine_merges = 1;\n+\t} else if (!strcmp(arg, \"--no-diff-merges\")) {\n+\t\trevs->ignore_merges = 1;\n+\t} else if (!strcmp(arg, \"--combined-all-paths\")) {\n+\t\trevs->diff = 1;\n+\t\trevs->combined_all_paths = 1;\n+\t} else if ((argcount = parse_long_opt(\"diff-merges\", argv, &optarg))) {\n+\t\tif (!strcmp(optarg, \"off\")) {\n+\t\t\trevs->ignore_merges = 1;\n+\t\t} else {\n+\t\t\tdie(_(\"unknown value for --diff-merges: %s\"), optarg);\n+\t\t}\n+\t} else\n+\t\treturn 0;\n+\n+\treturn 1;\n+}\n+\n static int handle_revision_opt(struct rev_info *revs, int argc, const char **argv,\n \t\t\t       int *unkc, const char **unkv,\n \t\t\t       const struct setup_revision_opt* opt)\n@@ -2349,34 +2387,8 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg\n \t\trevs->diff = 1;\n \t\trevs->diffopt.flags.recursive = 1;\n \t\trevs->diffopt.flags.tree_in_recursive = 1;\n-\t} else if (!strcmp(arg, \"-m\")) {\n-\t\t/*\n-\t\t * To \"diff-index\", \"-m\" means \"match missing\", and to the \"log\"\n-\t\t * family of commands, it means \"show full diff for merges\". Set\n-\t\t * both fields appropriately.\n-\t\t */\n-\t\trevs->ignore_merges = 0;\n-\t\trevs->match_missing = 1;\n-\t} else if ((argcount = parse_long_opt(\"diff-merges\", argv, &optarg))) {\n-\t\tif (!strcmp(optarg, \"off\")) {\n-\t\t\trevs->ignore_merges = 1;\n-\t\t} else {\n-\t\t\tdie(_(\"unknown value for --diff-merges: %s\"), optarg);\n-\t\t}\n+\t} else if ((argcount = parse_diff_merge_opts(revs, argv))) {\n \t\treturn argcount;\n-\t} else if (!strcmp(arg, \"--no-diff-merges\")) {\n-\t\trevs->ignore_merges = 1;\n-\t} else if (!strcmp(arg, \"-c\")) {\n-\t\trevs->diff = 1;\n-\t\trevs->dense_combined_merges = 0;\n-\t\trevs->combine_merges = 1;\n-\t} else if (!strcmp(arg, \"--combined-all-paths\")) {\n-\t\trevs->diff = 1;\n-\t\trevs->combined_all_paths = 1;\n-\t} else if (!strcmp(arg, \"--cc\")) {\n-\t\trevs->diff = 1;\n-\t\trevs->dense_combined_merges = 1;\n-\t\trevs->combine_merges = 1;\n \t} else if (!strcmp(arg, \"-v\")) {\n \t\trevs->verbose_header = 1;\n \t} else if (!strcmp(arg, \"--pretty\")) {\n-- \n2.25.1\n\n"},{"id":"408827","messageId":"20201101193330.24775-6-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201101193330.24775-1-sorganov@gmail.com","subject":"[PATCH 05/26] revision: move diff merges functions to its own diff-merges.c","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-11-01T19:33:09Z","receivedAt":"2020-11-01T19:34:13Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Create separate diff-merges.c and diff-merges.h files, and move all\nthe code related to handling of diff merges there.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n Makefile      |  1 +\n builtin/log.c |  1 +\n diff-merges.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++\n diff-merges.h | 12 +++++++++\n revision.c    | 72 +--------------------------------------------------\n revision.h    |  3 ---\n 6 files changed, 87 insertions(+), 74 deletions(-)\n create mode 100644 diff-merges.c\n create mode 100644 diff-merges.h\n\ndiff --git a/Makefile b/Makefile\nindex 1fb0ec17059a..d1347ef262cf 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -872,6 +872,7 @@ LIB_OBJS += date.o\n LIB_OBJS += decorate.o\n LIB_OBJS += delta-islands.o\n LIB_OBJS += diff-delta.o\n+LIB_OBJS += diff-merges.o\n LIB_OBJS += diff-lib.o\n LIB_OBJS += diff-no-index.o\n LIB_OBJS += diff.o\ndiff --git a/builtin/log.c b/builtin/log.c\nindex 717855a49e90..ad3092fdd854 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -12,6 +12,7 @@\n #include \"color.h\"\n #include \"commit.h\"\n #include \"diff.h\"\n+#include \"diff-merges.h\"\n #include \"revision.h\"\n #include \"log-tree.h\"\n #include \"builtin.h\"\ndiff --git a/diff-merges.c b/diff-merges.c\nnew file mode 100644\nindex 000000000000..8b9dd4ad5625\n--- /dev/null\n+++ b/diff-merges.c\n@@ -0,0 +1,72 @@\n+#include \"diff-merges.h\"\n+\n+#include \"revision.h\"\n+\n+void init_diff_merge_revs(struct rev_info *revs) {\n+\trevs->ignore_merges = -1;\n+}\n+\n+int parse_diff_merge_opts(struct rev_info *revs, const char **argv) {\n+\tint argcount;\n+\tconst char *optarg;\n+\tconst char *arg = argv[0];\n+\n+\tif (!strcmp(arg, \"-m\")) {\n+\t\t/*\n+\t\t * To \"diff-index\", \"-m\" means \"match missing\", and to the \"log\"\n+\t\t * family of commands, it means \"show full diff for merges\". Set\n+\t\t * both fields appropriately.\n+\t\t */\n+\t\trevs->ignore_merges = 0;\n+\t\trevs->match_missing = 1;\n+\t} else if (!strcmp(arg, \"-c\")) {\n+\t\trevs->diff = 1;\n+\t\trevs->dense_combined_merges = 0;\n+\t\trevs->combine_merges = 1;\n+\t} else if (!strcmp(arg, \"--cc\")) {\n+\t\trevs->diff = 1;\n+\t\trevs->dense_combined_merges = 1;\n+\t\trevs->combine_merges = 1;\n+\t} else if (!strcmp(arg, \"--no-diff-merges\")) {\n+\t\trevs->ignore_merges = 1;\n+\t} else if (!strcmp(arg, \"--combined-all-paths\")) {\n+\t\trevs->diff = 1;\n+\t\trevs->combined_all_paths = 1;\n+\t} else if ((argcount = parse_long_opt(\"diff-merges\", argv, &optarg))) {\n+\t\tif (!strcmp(optarg, \"off\")) {\n+\t\t\trevs->ignore_merges = 1;\n+\t\t} else {\n+\t\t\tdie(_(\"unknown value for --diff-merges: %s\"), optarg);\n+\t\t}\n+\t} else\n+\t\treturn 0;\n+\n+\treturn 1;\n+}\n+\n+void setup_diff_merges_revs(struct rev_info *revs)\n+{\n+\tif (revs->combine_merges && revs->ignore_merges < 0)\n+\t\trevs->ignore_merges = 0;\n+\tif (revs->ignore_merges < 0)\n+\t\trevs->ignore_merges = 1;\n+\tif (revs->combined_all_paths && !revs->combine_merges)\n+\t\tdie(\"--combined-all-paths makes no sense without -c or --cc\");\n+}\n+\n+void rev_diff_merges_first_parent_defaults_to_enable(struct rev_info *revs) {\n+\tif (revs->first_parent_only && revs->ignore_merges < 0)\n+\t\trevs->ignore_merges = 0;\n+}\n+\n+void rev_diff_merges_default_to_dense_combined(struct rev_info *revs) {\n+\tif (revs->ignore_merges < 0) {\n+\t\t/* There was no \"-m\" variant on the command line */\n+\t\trevs->ignore_merges = 0;\n+\t\tif (!revs->first_parent_only && !revs->combine_merges) {\n+\t\t\t/* No \"--first-parent\", \"-c\", or \"--cc\" */\n+\t\t\trevs->combine_merges = 1;\n+\t\t\trevs->dense_combined_merges = 1;\n+\t\t}\n+\t}\n+}\ndiff --git a/diff-merges.h b/diff-merges.h\nnew file mode 100644\nindex 000000000000..e0cca3d935d3\n--- /dev/null\n+++ b/diff-merges.h\n@@ -0,0 +1,12 @@\n+#ifndef DIFF_MERGES_H\n+#define DIFF_MERGES_H\n+\n+struct rev_info;\n+\n+void init_diff_merge_revs(struct rev_info *revs);\n+int parse_diff_merge_opts(struct rev_info *revs, const char **argv);\n+void setup_diff_merges_revs(struct rev_info *revs);\n+void rev_diff_merges_default_to_dense_combined(struct rev_info *revs);\n+void rev_diff_merges_first_parent_defaults_to_enable(struct rev_info *revs);\n+\n+#endif\ndiff --git a/revision.c b/revision.c\nindex ce90c2991657..4bc14a08a624 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -5,6 +5,7 @@\n #include \"tree.h\"\n #include \"commit.h\"\n #include \"diff.h\"\n+#include \"diff-merges.h\"\n #include \"refs.h\"\n #include \"revision.h\"\n #include \"repository.h\"\n@@ -1805,8 +1806,6 @@ static int add_parents_only(struct rev_info *revs, const char *arg_, int flags,\n \treturn 1;\n }\n \n-static void init_diff_merge_revs(struct rev_info *revs);\n-\n void repo_init_revisions(struct repository *r,\n \t\t\t struct rev_info *revs,\n \t\t\t const char *prefix)\n@@ -2155,75 +2154,6 @@ static void add_message_grep(struct rev_info *revs, const char *pattern)\n \tadd_grep(revs, pattern, GREP_PATTERN_BODY);\n }\n \n-static void init_diff_merge_revs(struct rev_info *revs) {\n-\trevs->ignore_merges = -1;\n-}\n-\n-static int parse_diff_merge_opts(struct rev_info *revs, const char **argv) {\n-\tint argcount;\n-\tconst char *optarg;\n-\tconst char *arg = argv[0];\n-\n-\tif (!strcmp(arg, \"-m\")) {\n-\t\t/*\n-\t\t * To \"diff-index\", \"-m\" means \"match missing\", and to the \"log\"\n-\t\t * family of commands, it means \"show full diff for merges\". Set\n-\t\t * both fields appropriately.\n-\t\t */\n-\t\trevs->ignore_merges = 0;\n-\t\trevs->match_missing = 1;\n-\t} else if (!strcmp(arg, \"-c\")) {\n-\t\trevs->diff = 1;\n-\t\trevs->dense_combined_merges = 0;\n-\t\trevs->combine_merges = 1;\n-\t} else if (!strcmp(arg, \"--cc\")) {\n-\t\trevs->diff = 1;\n-\t\trevs->dense_combined_merges = 1;\n-\t\trevs->combine_merges = 1;\n-\t} else if (!strcmp(arg, \"--no-diff-merges\")) {\n-\t\trevs->ignore_merges = 1;\n-\t} else if (!strcmp(arg, \"--combined-all-paths\")) {\n-\t\trevs->diff = 1;\n-\t\trevs->combined_all_paths = 1;\n-\t} else if ((argcount = parse_long_opt(\"diff-merges\", argv, &optarg))) {\n-\t\tif (!strcmp(optarg, \"off\")) {\n-\t\t\trevs->ignore_merges = 1;\n-\t\t} else {\n-\t\t\tdie(_(\"unknown value for --diff-merges: %s\"), optarg);\n-\t\t}\n-\t} else\n-\t\treturn 0;\n-\n-\treturn 1;\n-}\n-\n-static void setup_diff_merges_revs(struct rev_info *revs)\n-{\n-\tif (revs->combine_merges && revs->ignore_merges < 0)\n-\t\trevs->ignore_merges = 0;\n-\tif (revs->ignore_merges < 0)\n-\t\trevs->ignore_merges = 1;\n-\tif (revs->combined_all_paths && !revs->combine_merges)\n-\t\tdie(\"--combined-all-paths makes no sense without -c or --cc\");\n-}\n-\n-void rev_diff_merges_first_parent_defaults_to_enable(struct rev_info *revs) {\n-\tif (revs->first_parent_only && revs->ignore_merges < 0)\n-\t\trevs->ignore_merges = 0;\n-}\n-\n-void rev_diff_merges_default_to_dense_combined(struct rev_info *revs) {\n-\tif (revs->ignore_merges < 0) {\n-\t\t/* There was no \"-m\" variant on the command line */\n-\t\trevs->ignore_merges = 0;\n-\t\tif (!revs->first_parent_only && !revs->combine_merges) {\n-\t\t\t/* No \"--first-parent\", \"-c\", or \"--cc\" */\n-\t\t\trevs->combine_merges = 1;\n-\t\t\trevs->dense_combined_merges = 1;\n-\t\t}\n-\t}\n-}\n-\n static int handle_revision_opt(struct rev_info *revs, int argc, const char **argv,\n \t\t\t       int *unkc, const char **unkv,\n \t\t\t       const struct setup_revision_opt* opt)\ndiff --git a/revision.h b/revision.h\nindex 3dd0229f4edc..f6bf860d19e5 100644\n--- a/revision.h\n+++ b/revision.h\n@@ -456,7 +456,4 @@ int rewrite_parents(struct rev_info *revs,\n  */\n struct commit_list *get_saved_parents(struct rev_info *revs, const struct commit *commit);\n \n-void rev_diff_merges_default_to_dense_combined(struct rev_info *revs);\n-void rev_diff_merges_first_parent_defaults_to_enable(struct rev_info *revs);\n-\n #endif\n-- \n2.25.1\n\n"},{"id":"408828","messageId":"20201101193330.24775-5-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201101193330.24775-1-sorganov@gmail.com","subject":"[PATCH 04/26] revision: provide implementation for diff merges tweaks","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-11-01T19:33:08Z","receivedAt":"2020-11-01T19:34:13Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Use these implementations from show_setup_revisions_tweak() and\nlog_setup_revisions_tweak() in builtin/log.c.\n\nThis completes moving of management of diff merges parameters to a\nsingle place, where we can finally observe them simultaneously.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n builtin/log.c | 13 ++-----------\n revision.c    | 17 +++++++++++++++++\n revision.h    |  3 +++\n 3 files changed, 22 insertions(+), 11 deletions(-)\n\ndiff --git a/builtin/log.c b/builtin/log.c\nindex 0a7ed4bef92b..717855a49e90 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -598,15 +598,7 @@ static int show_tree_object(const struct object_id *oid,\n static void show_setup_revisions_tweak(struct rev_info *rev,\n \t\t\t\t       struct setup_revision_opt *opt)\n {\n-\tif (rev->ignore_merges < 0) {\n-\t\t/* There was no \"-m\" variant on the command line */\n-\t\trev->ignore_merges = 0;\n-\t\tif (!rev->first_parent_only && !rev->combine_merges) {\n-\t\t\t/* No \"--first-parent\", \"-c\", or \"--cc\" */\n-\t\t\trev->combine_merges = 1;\n-\t\t\trev->dense_combined_merges = 1;\n-\t\t}\n-\t}\n+\trev_diff_merges_default_to_dense_combined(rev);\n \tif (!rev->diffopt.output_format)\n \t\trev->diffopt.output_format = DIFF_FORMAT_PATCH;\n }\n@@ -731,8 +723,7 @@ static void log_setup_revisions_tweak(struct rev_info *rev,\n \tif (!rev->diffopt.output_format && rev->combine_merges)\n \t\trev->diffopt.output_format = DIFF_FORMAT_PATCH;\n \n-\tif (rev->first_parent_only && rev->ignore_merges < 0)\n-\t\trev->ignore_merges = 0;\n+\trev_diff_merges_first_parent_defaults_to_enable(rev);\n }\n \n int cmd_log(int argc, const char **argv, const char *prefix)\ndiff --git a/revision.c b/revision.c\nindex bc568fb79778..ce90c2991657 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -2207,6 +2207,23 @@ static void setup_diff_merges_revs(struct rev_info *revs)\n \t\tdie(\"--combined-all-paths makes no sense without -c or --cc\");\n }\n \n+void rev_diff_merges_first_parent_defaults_to_enable(struct rev_info *revs) {\n+\tif (revs->first_parent_only && revs->ignore_merges < 0)\n+\t\trevs->ignore_merges = 0;\n+}\n+\n+void rev_diff_merges_default_to_dense_combined(struct rev_info *revs) {\n+\tif (revs->ignore_merges < 0) {\n+\t\t/* There was no \"-m\" variant on the command line */\n+\t\trevs->ignore_merges = 0;\n+\t\tif (!revs->first_parent_only && !revs->combine_merges) {\n+\t\t\t/* No \"--first-parent\", \"-c\", or \"--cc\" */\n+\t\t\trevs->combine_merges = 1;\n+\t\t\trevs->dense_combined_merges = 1;\n+\t\t}\n+\t}\n+}\n+\n static int handle_revision_opt(struct rev_info *revs, int argc, const char **argv,\n \t\t\t       int *unkc, const char **unkv,\n \t\t\t       const struct setup_revision_opt* opt)\ndiff --git a/revision.h b/revision.h\nindex f6bf860d19e5..3dd0229f4edc 100644\n--- a/revision.h\n+++ b/revision.h\n@@ -456,4 +456,7 @@ int rewrite_parents(struct rev_info *revs,\n  */\n struct commit_list *get_saved_parents(struct rev_info *revs, const struct commit *commit);\n \n+void rev_diff_merges_default_to_dense_combined(struct rev_info *revs);\n+void rev_diff_merges_first_parent_defaults_to_enable(struct rev_info *revs);\n+\n #endif\n-- \n2.25.1\n\n"},{"id":"408829","messageId":"20201101193330.24775-7-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201101193330.24775-1-sorganov@gmail.com","subject":"[PATCH 06/26] diff-merges: rename all functions to have common prefix","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-11-01T19:33:10Z","receivedAt":"2020-11-01T19:34:15Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Use the same \"diff_merges\" prefix for all the diff merges function\nnames.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n builtin/log.c |  4 ++--\n diff-merges.c | 10 +++++-----\n diff-merges.h | 15 ++++++++++-----\n revision.c    |  6 +++---\n 4 files changed, 20 insertions(+), 15 deletions(-)\n\ndiff --git a/builtin/log.c b/builtin/log.c\nindex ad3092fdd854..77a7bba543ad 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -599,7 +599,7 @@ static int show_tree_object(const struct object_id *oid,\n static void show_setup_revisions_tweak(struct rev_info *rev,\n \t\t\t\t       struct setup_revision_opt *opt)\n {\n-\trev_diff_merges_default_to_dense_combined(rev);\n+\tdiff_merges_default_to_dense_combined(rev);\n \tif (!rev->diffopt.output_format)\n \t\trev->diffopt.output_format = DIFF_FORMAT_PATCH;\n }\n@@ -724,7 +724,7 @@ static void log_setup_revisions_tweak(struct rev_info *rev,\n \tif (!rev->diffopt.output_format && rev->combine_merges)\n \t\trev->diffopt.output_format = DIFF_FORMAT_PATCH;\n \n-\trev_diff_merges_first_parent_defaults_to_enable(rev);\n+\tdiff_merges_first_parent_defaults_to_enable(rev);\n }\n \n int cmd_log(int argc, const char **argv, const char *prefix)\ndiff --git a/diff-merges.c b/diff-merges.c\nindex 8b9dd4ad5625..85bf0b6d1d1d 100644\n--- a/diff-merges.c\n+++ b/diff-merges.c\n@@ -2,11 +2,11 @@\n \n #include \"revision.h\"\n \n-void init_diff_merge_revs(struct rev_info *revs) {\n+void diff_merges_init_revs(struct rev_info *revs) {\n \trevs->ignore_merges = -1;\n }\n \n-int parse_diff_merge_opts(struct rev_info *revs, const char **argv) {\n+int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {\n \tint argcount;\n \tconst char *optarg;\n \tconst char *arg = argv[0];\n@@ -44,7 +44,7 @@ int parse_diff_merge_opts(struct rev_info *revs, const char **argv) {\n \treturn 1;\n }\n \n-void setup_diff_merges_revs(struct rev_info *revs)\n+void diff_merges_setup_revs(struct rev_info *revs)\n {\n \tif (revs->combine_merges && revs->ignore_merges < 0)\n \t\trevs->ignore_merges = 0;\n@@ -54,12 +54,12 @@ void setup_diff_merges_revs(struct rev_info *revs)\n \t\tdie(\"--combined-all-paths makes no sense without -c or --cc\");\n }\n \n-void rev_diff_merges_first_parent_defaults_to_enable(struct rev_info *revs) {\n+void diff_merges_first_parent_defaults_to_enable(struct rev_info *revs) {\n \tif (revs->first_parent_only && revs->ignore_merges < 0)\n \t\trevs->ignore_merges = 0;\n }\n \n-void rev_diff_merges_default_to_dense_combined(struct rev_info *revs) {\n+void diff_merges_default_to_dense_combined(struct rev_info *revs) {\n \tif (revs->ignore_merges < 0) {\n \t\t/* There was no \"-m\" variant on the command line */\n \t\trevs->ignore_merges = 0;\ndiff --git a/diff-merges.h b/diff-merges.h\nindex e0cca3d935d3..648c410497cb 100644\n--- a/diff-merges.h\n+++ b/diff-merges.h\n@@ -3,10 +3,15 @@\n \n struct rev_info;\n \n-void init_diff_merge_revs(struct rev_info *revs);\n-int parse_diff_merge_opts(struct rev_info *revs, const char **argv);\n-void setup_diff_merges_revs(struct rev_info *revs);\n-void rev_diff_merges_default_to_dense_combined(struct rev_info *revs);\n-void rev_diff_merges_first_parent_defaults_to_enable(struct rev_info *revs);\n+void diff_merges_init_revs(struct rev_info *revs);\n+\n+int diff_merges_parse_opts(struct rev_info *revs, const char **argv);\n+\n+void diff_merges_setup_revs(struct rev_info *revs);\n+\n+void diff_merges_default_to_dense_combined(struct rev_info *revs);\n+\n+void diff_merges_first_parent_defaults_to_enable(struct rev_info *revs);\n+\n \n #endif\ndiff --git a/revision.c b/revision.c\nindex 4bc14a08a624..5a0e3d6ad542 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -1814,7 +1814,7 @@ void repo_init_revisions(struct repository *r,\n \n \trevs->repo = r;\n \trevs->abbrev = DEFAULT_ABBREV;\n-\tinit_diff_merge_revs(revs);\n+\tdiff_merges_init_revs(revs);\n \trevs->simplify_history = 1;\n \trevs->pruning.repo = r;\n \trevs->pruning.flags.recursive = 1;\n@@ -2350,7 +2350,7 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg\n \t\trevs->diff = 1;\n \t\trevs->diffopt.flags.recursive = 1;\n \t\trevs->diffopt.flags.tree_in_recursive = 1;\n-\t} else if ((argcount = parse_diff_merge_opts(revs, argv))) {\n+\t} else if ((argcount = diff_merges_parse_opts(revs, argv))) {\n \t\treturn argcount;\n \t} else if (!strcmp(arg, \"-v\")) {\n \t\trevs->verbose_header = 1;\n@@ -2849,7 +2849,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s\n \t\t\t\t      &revs->prune_data);\n \t}\n \n-\tsetup_diff_merges_revs(revs);\n+\tdiff_merges_setup_revs(revs);\n \n \trevs->diffopt.abbrev = revs->abbrev;\n \n-- \n2.25.1\n\n"},{"id":"408830","messageId":"20201101193330.24775-9-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201101193330.24775-1-sorganov@gmail.com","subject":"[PATCH 08/26] diff-merges: rename diff_merges_default_to_enable() to match semantics","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-11-01T19:33:12Z","receivedAt":"2020-11-01T19:34:16Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Rename diff_merges_default_to_enable() to\ndiff_merges_default_to_first_parent() to match its semantics.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n builtin/log.c | 4 ++--\n diff-merges.c | 2 +-\n diff-merges.h | 2 +-\n 3 files changed, 4 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/log.c b/builtin/log.c\nindex a7791c003c91..63875c3aeec9 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -600,7 +600,7 @@ static void show_setup_revisions_tweak(struct rev_info *rev,\n \t\t\t\t       struct setup_revision_opt *opt)\n {\n \tif (rev->first_parent_only)\n-\t\tdiff_merges_default_to_enable(rev);\n+\t\tdiff_merges_default_to_first_parent(rev);\n \telse\n \t\tdiff_merges_default_to_dense_combined(rev);\n \tif (!rev->diffopt.output_format)\n@@ -728,7 +728,7 @@ static void log_setup_revisions_tweak(struct rev_info *rev,\n \t\trev->diffopt.output_format = DIFF_FORMAT_PATCH;\n \n \tif (rev->first_parent_only)\n-\t\tdiff_merges_default_to_enable(rev);\n+\t\tdiff_merges_default_to_first_parent(rev);\n }\n \n int cmd_log(int argc, const char **argv, const char *prefix)\ndiff --git a/diff-merges.c b/diff-merges.c\nindex 9dd472803d15..bb08a92e3b36 100644\n--- a/diff-merges.c\n+++ b/diff-merges.c\n@@ -54,7 +54,7 @@ void diff_merges_setup_revs(struct rev_info *revs)\n \t\tdie(\"--combined-all-paths makes no sense without -c or --cc\");\n }\n \n-void diff_merges_default_to_enable(struct rev_info *revs) {\n+void diff_merges_default_to_first_parent(struct rev_info *revs) {\n \tif (revs->ignore_merges < 0)\t\t/* No -m */\n \t\trevs->ignore_merges = 0;\n }\ndiff --git a/diff-merges.h b/diff-merges.h\nindex cf411414898d..20b727bd734f 100644\n--- a/diff-merges.h\n+++ b/diff-merges.h\n@@ -11,7 +11,7 @@ void diff_merges_setup_revs(struct rev_info *revs);\n \n void diff_merges_default_to_dense_combined(struct rev_info *revs);\n \n-void diff_merges_default_to_enable(struct rev_info *revs);\n+void diff_merges_default_to_first_parent(struct rev_info *revs);\n \n \n #endif\n-- \n2.25.1\n\n"},{"id":"408831","messageId":"20201101193330.24775-11-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201101193330.24775-1-sorganov@gmail.com","subject":"[PATCH 10/26] diff-merges: new function diff_merges_suppress()","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-11-01T19:33:14Z","receivedAt":"2020-11-01T19:34:18Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"This function sets all the relevant flags to disabled state, so that\nno code that checks only one of them get it wrong.\n\nThen we call this new function everywhere where diff merges output\nsuppression is needed.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n builtin/merge.c |  3 ++-\n diff-merges.c   | 18 ++++++++++++++----\n diff-merges.h   |  2 ++\n fmt-merge-msg.c |  3 ++-\n 4 files changed, 20 insertions(+), 6 deletions(-)\n\ndiff --git a/builtin/merge.c b/builtin/merge.c\nindex 9d5359edc2f7..1f7b69982b40 100644\n--- a/builtin/merge.c\n+++ b/builtin/merge.c\n@@ -14,6 +14,7 @@\n #include \"lockfile.h\"\n #include \"run-command.h\"\n #include \"diff.h\"\n+#include \"diff-merges.h\"\n #include \"refs.h\"\n #include \"refspec.h\"\n #include \"commit.h\"\n@@ -400,7 +401,7 @@ static void squash_message(struct commit *commit, struct commit_list *remotehead\n \tprintf(_(\"Squash commit -- not updating HEAD\\n\"));\n \n \trepo_init_revisions(the_repository, &rev, NULL);\n-\trev.ignore_merges = 1;\n+\tdiff_merges_suppress(&rev);\n \trev.commit_format = CMIT_FMT_MEDIUM;\n \n \tcommit->object.flags |= UNINTERESTING;\ndiff --git a/diff-merges.c b/diff-merges.c\nindex 8536941e0b56..25bd9b12e667 100644\n--- a/diff-merges.c\n+++ b/diff-merges.c\n@@ -2,6 +2,13 @@\n \n #include \"revision.h\"\n \n+static void suppress(struct rev_info *revs) {\n+\trevs->ignore_merges = 1;\n+\trevs->first_parent_merges = 0;\n+\trevs->combine_merges = 0;\n+\trevs->dense_combined_merges = 0;\n+}\n+\n /*\n  * Public functions. They are in the order they are called.\n  */\n@@ -29,16 +36,15 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {\n \t\trevs->combine_merges = 1;\n \t} else if (!strcmp(arg, \"--cc\")) {\n \t\trevs->diff = 1;\n-\t\trevs->dense_combined_merges = 1;\n-\t\trevs->combine_merges = 1;\n+\t\tset_dense_combined(revs);\n \t} else if (!strcmp(arg, \"--no-diff-merges\")) {\n-\t\trevs->ignore_merges = 1;\n+\t\tsuppress(revs);\n \t} else if (!strcmp(arg, \"--combined-all-paths\")) {\n \t\trevs->diff = 1;\n \t\trevs->combined_all_paths = 1;\n \t} else if ((argcount = parse_long_opt(\"diff-merges\", argv, &optarg))) {\n \t\tif (!strcmp(optarg, \"off\")) {\n-\t\t\trevs->ignore_merges = 1;\n+\t\t\tsuppress(revs);\n \t\t} else {\n \t\t\tdie(_(\"unknown value for --diff-merges: %s\"), optarg);\n \t\t}\n@@ -48,6 +54,10 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {\n \treturn 1;\n }\n \n+void diff_merges_suppress(struct rev_info *revs) {\n+\tsuppress(revs);\n+}\n+\n void diff_merges_default_to_first_parent(struct rev_info *revs) {\n \tif (revs->ignore_merges < 0)\t\t/* No -m */\n \t\trevs->ignore_merges = 0;\ndiff --git a/diff-merges.h b/diff-merges.h\nindex 4b023c385d00..32720bc9b40f 100644\n--- a/diff-merges.h\n+++ b/diff-merges.h\n@@ -7,6 +7,8 @@ void diff_merges_init_revs(struct rev_info *revs);\n \n int diff_merges_parse_opts(struct rev_info *revs, const char **argv);\n \n+void diff_merges_suppress(struct rev_info *revs);\n+\n void diff_merges_default_to_first_parent(struct rev_info *revs);\n \n void diff_merges_default_to_dense_combined(struct rev_info *revs);\ndiff --git a/fmt-merge-msg.c b/fmt-merge-msg.c\nindex bd22e1ea8865..abc3403fb820 100644\n--- a/fmt-merge-msg.c\n+++ b/fmt-merge-msg.c\n@@ -2,6 +2,7 @@\n #include \"refs.h\"\n #include \"object-store.h\"\n #include \"diff.h\"\n+#include \"diff-merges.h\"\n #include \"revision.h\"\n #include \"tag.h\"\n #include \"string-list.h\"\n@@ -668,7 +669,7 @@ int fmt_merge_msg(struct strbuf *in, struct strbuf *out,\n \t\thead = lookup_commit_or_die(&head_oid, \"HEAD\");\n \t\trepo_init_revisions(the_repository, &rev, NULL);\n \t\trev.commit_format = CMIT_FMT_ONELINE;\n-\t\trev.ignore_merges = 1;\n+\t\tdiff_merges_suppress(&rev);\n \t\trev.limited = 1;\n \n \t\tstrbuf_complete_line(out);\n-- \n2.25.1\n\n"},{"id":"408832","messageId":"20201101193330.24775-8-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201101193330.24775-1-sorganov@gmail.com","subject":"[PATCH 07/26] diff-merges: move checks for first_parent_only out of the module","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-11-01T19:33:11Z","receivedAt":"2020-11-01T19:34:21Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"The checks for first_parent_only don't in fact belong to this module,\nas the primary purpose of this flag is history traversal limiting, so\nget it out of this module and rename the\n\ndiff_merges_first_parent_defaults_to_enable()\n\nto\n\ndiff_merges_default_to_enable()\n\nto match new semantics.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n builtin/log.c |  8 ++++++--\n diff-merges.c | 10 ++++------\n diff-merges.h |  2 +-\n 3 files changed, 11 insertions(+), 9 deletions(-)\n\ndiff --git a/builtin/log.c b/builtin/log.c\nindex 77a7bba543ad..a7791c003c91 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -599,7 +599,10 @@ static int show_tree_object(const struct object_id *oid,\n static void show_setup_revisions_tweak(struct rev_info *rev,\n \t\t\t\t       struct setup_revision_opt *opt)\n {\n-\tdiff_merges_default_to_dense_combined(rev);\n+\tif (rev->first_parent_only)\n+\t\tdiff_merges_default_to_enable(rev);\n+\telse\n+\t\tdiff_merges_default_to_dense_combined(rev);\n \tif (!rev->diffopt.output_format)\n \t\trev->diffopt.output_format = DIFF_FORMAT_PATCH;\n }\n@@ -724,7 +727,8 @@ static void log_setup_revisions_tweak(struct rev_info *rev,\n \tif (!rev->diffopt.output_format && rev->combine_merges)\n \t\trev->diffopt.output_format = DIFF_FORMAT_PATCH;\n \n-\tdiff_merges_first_parent_defaults_to_enable(rev);\n+\tif (rev->first_parent_only)\n+\t\tdiff_merges_default_to_enable(rev);\n }\n \n int cmd_log(int argc, const char **argv, const char *prefix)\ndiff --git a/diff-merges.c b/diff-merges.c\nindex 85bf0b6d1d1d..9dd472803d15 100644\n--- a/diff-merges.c\n+++ b/diff-merges.c\n@@ -54,17 +54,15 @@ void diff_merges_setup_revs(struct rev_info *revs)\n \t\tdie(\"--combined-all-paths makes no sense without -c or --cc\");\n }\n \n-void diff_merges_first_parent_defaults_to_enable(struct rev_info *revs) {\n-\tif (revs->first_parent_only && revs->ignore_merges < 0)\n+void diff_merges_default_to_enable(struct rev_info *revs) {\n+\tif (revs->ignore_merges < 0)\t\t/* No -m */\n \t\trevs->ignore_merges = 0;\n }\n \n void diff_merges_default_to_dense_combined(struct rev_info *revs) {\n-\tif (revs->ignore_merges < 0) {\n-\t\t/* There was no \"-m\" variant on the command line */\n+\tif (revs->ignore_merges < 0) {\t\t/* No -m */\n \t\trevs->ignore_merges = 0;\n-\t\tif (!revs->first_parent_only && !revs->combine_merges) {\n-\t\t\t/* No \"--first-parent\", \"-c\", or \"--cc\" */\n+\t\tif (!revs->combine_merges) {\t/* No -c/--cc\" */\n \t\t\trevs->combine_merges = 1;\n \t\t\trevs->dense_combined_merges = 1;\n \t\t}\ndiff --git a/diff-merges.h b/diff-merges.h\nindex 648c410497cb..cf411414898d 100644\n--- a/diff-merges.h\n+++ b/diff-merges.h\n@@ -11,7 +11,7 @@ void diff_merges_setup_revs(struct rev_info *revs);\n \n void diff_merges_default_to_dense_combined(struct rev_info *revs);\n \n-void diff_merges_first_parent_defaults_to_enable(struct rev_info *revs);\n+void diff_merges_default_to_enable(struct rev_info *revs);\n \n \n #endif\n-- \n2.25.1\n\n"},{"id":"408833","messageId":"20201101193330.24775-14-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201101193330.24775-1-sorganov@gmail.com","subject":"[PATCH 13/26] diff-merges: revise revs->diff flag handling","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-11-01T19:33:17Z","receivedAt":"2020-11-01T19:34:24Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Do not set revs->diff when we encounter an option that needs it, as\nit'd be impossible to undo later. Besides, some other options than\nwhat we handle here set this flag as well, and we'd interfere with\nthem trying to clear this flag later.\n\nRather set revs->diff, if finally needed, in diff_merges_setup_revs().\n\nAs an additional bonus, this also makes our code shorter.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n diff-merges.c | 5 ++---\n 1 file changed, 2 insertions(+), 3 deletions(-)\n\ndiff --git a/diff-merges.c b/diff-merges.c\nindex 63912ddedc76..a30c730a457f 100644\n--- a/diff-merges.c\n+++ b/diff-merges.c\n@@ -37,16 +37,13 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {\n \t\trevs->ignore_merges = 0;\n \t\trevs->match_missing = 1;\n \t} else if (!strcmp(arg, \"-c\")) {\n-\t\trevs->diff = 1;\n \t\trevs->dense_combined_merges = 0;\n \t\trevs->combine_merges = 1;\n \t} else if (!strcmp(arg, \"--cc\")) {\n-\t\trevs->diff = 1;\n \t\tset_dense_combined(revs);\n \t} else if (!strcmp(arg, \"--no-diff-merges\")) {\n \t\tsuppress(revs);\n \t} else if (!strcmp(arg, \"--combined-all-paths\")) {\n-\t\trevs->diff = 1;\n \t\trevs->combined_all_paths = 1;\n \t} else if ((argcount = parse_long_opt(\"diff-merges\", argv, &optarg))) {\n \t\tif (!strcmp(optarg, \"off\")) {\n@@ -94,4 +91,6 @@ void diff_merges_setup_revs(struct rev_info *revs)\n \t\trevs->ignore_merges = 1;\n \tif (revs->combined_all_paths && !revs->combine_merges)\n \t\tdie(\"--combined-all-paths makes no sense without -c or --cc\");\n+\tif (revs->combine_merges)\n+\t\trevs->diff = 1;\n }\n-- \n2.25.1\n\n"},{"id":"408834","messageId":"20201101193330.24775-13-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201101193330.24775-1-sorganov@gmail.com","subject":"[PATCH 12/26] diff-merges: introduce revs->first_parent_merges flag","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-11-01T19:33:16Z","receivedAt":"2020-11-01T19:34:26Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"This new field allows us to separate format of diff for merges from\n'first_parent_only' flag which primary purpose is limiting history\ntraversal.\n\nThis change further localizes diff format selection logic into the\ndiff-merges.c file.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n diff-merges.c | 2 ++\n log-tree.c    | 4 ++--\n revision.h    | 1 +\n 3 files changed, 5 insertions(+), 2 deletions(-)\n\ndiff --git a/diff-merges.c b/diff-merges.c\nindex 691aabadbb32..63912ddedc76 100644\n--- a/diff-merges.c\n+++ b/diff-merges.c\n@@ -67,6 +67,8 @@ void diff_merges_suppress(struct rev_info *revs) {\n void diff_merges_default_to_first_parent(struct rev_info *revs) {\n \tif (revs->ignore_merges < 0)\t\t/* No -m */\n \t\trevs->ignore_merges = 0;\n+\tif (!revs->combine_merges)\t\t/* No -c/--cc\" */\n+\t\trevs->first_parent_merges = 1;\n }\n \n void diff_merges_default_to_dense_combined(struct rev_info *revs) {\ndiff --git a/log-tree.c b/log-tree.c\nindex 1927f917ce94..3fdc0fc64bfb 100644\n--- a/log-tree.c\n+++ b/log-tree.c\n@@ -922,7 +922,7 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log\n \t\t\treturn 0;\n \t\telse if (opt->combine_merges)\n \t\t\treturn do_diff_combined(opt, commit);\n-\t\telse if (!opt->first_parent_only) {\n+\t\telse if (!opt->first_parent_merges) {\n \t\t\t/* If we show multiple diffs, show the parent info */\n \t\t\tlog->parent = parents->item;\n \t\t}\n@@ -941,7 +941,7 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log\n \n \t\t/* Set up the log info for the next parent, if any.. */\n \t\tparents = parents->next;\n-\t\tif (!parents || opt->first_parent_only)\n+\t\tif (!parents || opt->first_parent_merges)\n \t\t\tbreak;\n \t\tlog->parent = parents->item;\n \t\topt->loginfo = log;\ndiff --git a/revision.h b/revision.h\nindex f6bf860d19e5..ba2aef79215e 100644\n--- a/revision.h\n+++ b/revision.h\n@@ -194,6 +194,7 @@ struct rev_info {\n \t\t\tcombine_merges:1,\n \t\t\tcombined_all_paths:1,\n \t\t\tdense_combined_merges:1,\n+\t\t\tfirst_parent_merges:1,\n \t\t\talways_show_header:1;\n \tint             ignore_merges:2;\n \n-- \n2.25.1\n\n"},{"id":"408835","messageId":"20201101193330.24775-12-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201101193330.24775-1-sorganov@gmail.com","subject":"[PATCH 11/26] diff-merges: new function diff_merges_set_dense_combined_if_unset()","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-11-01T19:33:15Z","receivedAt":"2020-11-01T19:34:26Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Call it where given functionality is needed instead of direct\nchecking/tweaking of diff merges related fields.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n builtin/diff-files.c |  5 +++--\n builtin/diff.c       |  9 +++++----\n diff-merges.c        | 11 +++++++++++\n diff-merges.h        |  2 ++\n 4 files changed, 21 insertions(+), 6 deletions(-)\n\ndiff --git a/builtin/diff-files.c b/builtin/diff-files.c\nindex 1e352dd8f77c..4742a4559b21 100644\n--- a/builtin/diff-files.c\n+++ b/builtin/diff-files.c\n@@ -7,6 +7,7 @@\n #include \"cache.h\"\n #include \"config.h\"\n #include \"diff.h\"\n+#include \"diff-merges.h\"\n #include \"commit.h\"\n #include \"revision.h\"\n #include \"builtin.h\"\n@@ -69,9 +70,9 @@ int cmd_diff_files(int argc, const char **argv, const char *prefix)\n \t * was not asked to.  \"diff-files -c -p\" should not densify\n \t * (the user should ask with \"diff-files --cc\" explicitly).\n \t */\n-\tif (rev.max_count == -1 && !rev.combine_merges &&\n+\tif (rev.max_count == -1 &&\n \t    (rev.diffopt.output_format & DIFF_FORMAT_PATCH))\n-\t\trev.combine_merges = rev.dense_combined_merges = 1;\n+\t\tdiff_merges_set_dense_combined_if_unset(&rev);\n \n \tif (read_cache_preload(&rev.diffopt.pathspec) < 0) {\n \t\tperror(\"read_cache_preload\");\ndiff --git a/builtin/diff.c b/builtin/diff.c\nindex cd4083fed96e..2f570a3131cb 100644\n--- a/builtin/diff.c\n+++ b/builtin/diff.c\n@@ -13,6 +13,7 @@\n #include \"blob.h\"\n #include \"tag.h\"\n #include \"diff.h\"\n+#include \"diff-merges.h\"\n #include \"diffcore.h\"\n #include \"revision.h\"\n #include \"log-tree.h\"\n@@ -199,8 +200,8 @@ static int builtin_diff_combined(struct rev_info *revs,\n \tif (argc > 1)\n \t\tusage(builtin_diff_usage);\n \n-\tif (!revs->dense_combined_merges && !revs->combine_merges)\n-\t\trevs->dense_combined_merges = revs->combine_merges = 1;\n+\tdiff_merges_set_dense_combined_if_unset(revs);\n+\n \tfor (i = 1; i < ents; i++)\n \t\toid_array_append(&parents, &ent[i].item->oid);\n \tdiff_tree_combined(&ent[0].item->oid, &parents, revs);\n@@ -248,9 +249,9 @@ static int builtin_diff_files(struct rev_info *revs, int argc, const char **argv\n \t * dense one, --cc can be explicitly asked for, or just rely\n \t * on the default).\n \t */\n-\tif (revs->max_count == -1 && !revs->combine_merges &&\n+\tif (revs->max_count == -1 &&\n \t    (revs->diffopt.output_format & DIFF_FORMAT_PATCH))\n-\t\trevs->combine_merges = revs->dense_combined_merges = 1;\n+\t\tdiff_merges_set_dense_combined_if_unset(revs);\n \n \tsetup_work_tree();\n \tif (read_cache_preload(&revs->diffopt.pathspec) < 0) {\ndiff --git a/diff-merges.c b/diff-merges.c\nindex 25bd9b12e667..691aabadbb32 100644\n--- a/diff-merges.c\n+++ b/diff-merges.c\n@@ -9,6 +9,12 @@ static void suppress(struct rev_info *revs) {\n \trevs->dense_combined_merges = 0;\n }\n \n+static void set_dense_combined(struct rev_info *revs) {\n+\trevs->combine_merges = 1;\n+\trevs->dense_combined_merges = 1;\n+}\n+\n+\n /*\n  * Public functions. They are in the order they are called.\n  */\n@@ -73,6 +79,11 @@ void diff_merges_default_to_dense_combined(struct rev_info *revs) {\n \t}\n }\n \n+void diff_merges_set_dense_combined_if_unset(struct rev_info *revs) {\n+\tif (!revs->combine_merges)\n+\t\tset_dense_combined(revs);\n+}\n+\n void diff_merges_setup_revs(struct rev_info *revs)\n {\n \tif (revs->combine_merges && revs->ignore_merges < 0)\ndiff --git a/diff-merges.h b/diff-merges.h\nindex 32720bc9b40f..ae1cc8ef9410 100644\n--- a/diff-merges.h\n+++ b/diff-merges.h\n@@ -13,6 +13,8 @@ void diff_merges_default_to_first_parent(struct rev_info *revs);\n \n void diff_merges_default_to_dense_combined(struct rev_info *revs);\n \n+void diff_merges_set_dense_combined_if_unset(struct rev_info *revs);\n+\n void diff_merges_setup_revs(struct rev_info *revs);\n \n #endif\n-- \n2.25.1\n\n"},{"id":"408836","messageId":"20201101193330.24775-19-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201101193330.24775-1-sorganov@gmail.com","subject":"[PATCH 18/26] diff-merges: group diff-merge flags next to each other inside 'rev_info'","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-11-01T19:33:22Z","receivedAt":"2020-11-01T19:34:28Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"The relevant flags were somewhat scattered over definition of 'struct\nrev_info'. Rearrange them to group them together.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n revision.h | 5 +++--\n 1 file changed, 3 insertions(+), 2 deletions(-)\n\ndiff --git a/revision.h b/revision.h\nindex fcc532c873d1..dcfa14454a55 100644\n--- a/revision.h\n+++ b/revision.h\n@@ -191,13 +191,14 @@ struct rev_info {\n \t\t\tmatch_missing:1,\n \t\t\tno_commit_id:1,\n \t\t\tverbose_header:1,\n+\t\t\talways_show_header:1,\n+\t\t\t/* Diff-merge flags */\n \t\t\texplicit_diff_merges: 1,\n \t\t\tseparate_merges: 1,\n \t\t\tcombine_merges:1,\n \t\t\tcombined_all_paths:1,\n \t\t\tdense_combined_merges:1,\n-\t\t\tfirst_parent_merges:1,\n-\t\t\talways_show_header:1;\n+\t\t\tfirst_parent_merges:1;\n \n \t/* Format info */\n \tint\t\tshow_notes;\n-- \n2.25.1\n\n"},{"id":"408837","messageId":"20201101193330.24775-21-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201101193330.24775-1-sorganov@gmail.com","subject":"[PATCH 20/26] diff-merges: refactor opt settings into separate functions","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-11-01T19:33:24Z","receivedAt":"2020-11-01T19:34:29Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"To prepare introduction of new options some of which will be synonyms\nto existing options, let every option handling code just call\ncorresponding function.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n diff-merges.c | 59 ++++++++++++++++++++++++++++++++-------------------\n 1 file changed, 37 insertions(+), 22 deletions(-)\n\ndiff --git a/diff-merges.c b/diff-merges.c\nindex 29818abcc00e..8c22b447f106 100644\n--- a/diff-merges.c\n+++ b/diff-merges.c\n@@ -9,11 +9,38 @@ static void suppress(struct rev_info *revs) {\n \trevs->dense_combined_merges = 0;\n }\n \n+static void set_separate(struct rev_info *revs) {\n+\tsuppress(revs);\n+\trevs->separate_merges = 1;\n+}\n+\n+static void set_m(struct rev_info *revs) {\n+\t/*\n+\t * To \"diff-index\", \"-m\" means \"match missing\", and to the \"log\"\n+\t * family of commands, it means \"show full diff for merges\". Set\n+\t * both fields appropriately.\n+\t */\n+\tset_separate(revs);\n+\trevs->match_missing = 1;\n+}\n+\n+static void set_combined(struct rev_info *revs) {\n+\trevs->combine_merges = 1;\n+\trevs->dense_combined_merges = 0;\n+}\n+\n static void set_dense_combined(struct rev_info *revs) {\n \trevs->combine_merges = 1;\n \trevs->dense_combined_merges = 1;\n }\n \n+static void set_diff_merges(struct rev_info *revs, const char *optarg) {\n+\tif (!strcmp(optarg, \"off\")) {\n+\t\tsuppress(revs);\n+\t} else {\n+\t\tdie(_(\"unknown value for --diff-merges: %s\"), optarg);\n+\t}\n+}\n \n /*\n  * Public functions. They are in the order they are called.\n@@ -24,31 +51,19 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {\n \tconst char *optarg;\n \tconst char *arg = argv[0];\n \n-\tif (!strcmp(arg, \"-m\")) {\n-\t\tsuppress(revs);\n-\t\t/*\n-\t\t * To \"diff-index\", \"-m\" means \"match missing\", and to the \"log\"\n-\t\t * family of commands, it means \"show full diff for merges\". Set\n-\t\t * both fields appropriately.\n-\t\t */\n-\t\trevs->separate_merges = 1;\n-\t\trevs->match_missing = 1;\n-\t} else if (!strcmp(arg, \"-c\")) {\n-\t\trevs->dense_combined_merges = 0;\n-\t\trevs->combine_merges = 1;\n-\t} else if (!strcmp(arg, \"--cc\")) {\n+\tif (!strcmp(arg, \"-m\"))\n+\t\tset_m(revs);\n+\telse if (!strcmp(arg, \"-c\"))\n+\t\tset_combined(revs);\n+\telse if (!strcmp(arg, \"--cc\"))\n \t\tset_dense_combined(revs);\n-\t} else if (!strcmp(arg, \"--no-diff-merges\")) {\n+\telse if (!strcmp(arg, \"--no-diff-merges\"))\n \t\tsuppress(revs);\n-\t} else if (!strcmp(arg, \"--combined-all-paths\")) {\n+\telse if (!strcmp(arg, \"--combined-all-paths\"))\n \t\trevs->combined_all_paths = 1;\n-\t} else if ((argcount = parse_long_opt(\"diff-merges\", argv, &optarg))) {\n-\t\tif (!strcmp(optarg, \"off\")) {\n-\t\t\tsuppress(revs);\n-\t\t} else {\n-\t\t\tdie(_(\"unknown value for --diff-merges: %s\"), optarg);\n-\t\t}\n-\t} else\n+\telse if ((argcount = parse_long_opt(\"diff-merges\", argv, &optarg)))\n+\t\tset_diff_merges(revs, optarg);\n+\telse\n \t\treturn 0;\n \n \trevs->explicit_diff_merges = 1;\n-- \n2.25.1\n\n"},{"id":"408838","messageId":"20201101193330.24775-22-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201101193330.24775-1-sorganov@gmail.com","subject":"[PATCH 21/26] diff-merges: make -m/-c/--cc explicitly mutually exclusive","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-11-01T19:33:25Z","receivedAt":"2020-11-01T19:34:30Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"-c/--cc got precedence over -m only because of external logic where\ncorresponding flags are checked before that for -m. This is too\nerror-prone, so add code that explicitly makes these 3 options\nmutually exclusive, so that the last option specified on the\ncommand-line gets precedence.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n diff-merges.c | 3 +++\n 1 file changed, 3 insertions(+)\n\ndiff --git a/diff-merges.c b/diff-merges.c\nindex 8c22b447f106..db2217171442 100644\n--- a/diff-merges.c\n+++ b/diff-merges.c\n@@ -7,6 +7,7 @@ static void suppress(struct rev_info *revs) {\n \trevs->first_parent_merges = 0;\n \trevs->combine_merges = 0;\n \trevs->dense_combined_merges = 0;\n+\trevs->combined_all_paths = 0;\n }\n \n static void set_separate(struct rev_info *revs) {\n@@ -25,11 +26,13 @@ static void set_m(struct rev_info *revs) {\n }\n \n static void set_combined(struct rev_info *revs) {\n+\tsuppress(revs);\n \trevs->combine_merges = 1;\n \trevs->dense_combined_merges = 0;\n }\n \n static void set_dense_combined(struct rev_info *revs) {\n+\tsuppress(revs);\n \trevs->combine_merges = 1;\n \trevs->dense_combined_merges = 1;\n }\n-- \n2.25.1\n\n"},{"id":"408839","messageId":"20201101193330.24775-20-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201101193330.24775-1-sorganov@gmail.com","subject":"[PATCH 19/26] diff-merges: get rid of now empty diff_merges_init_revs()","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-11-01T19:33:23Z","receivedAt":"2020-11-01T19:34:31Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"After getting rid of 'ignore_meres' field, the diff_merges_init_revs()\nfunction became empty. Get rid of it.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n diff-merges.c | 3 ---\n diff-merges.h | 2 --\n revision.c    | 1 -\n 3 files changed, 6 deletions(-)\n\ndiff --git a/diff-merges.c b/diff-merges.c\nindex 19cdad1aa4a1..29818abcc00e 100644\n--- a/diff-merges.c\n+++ b/diff-merges.c\n@@ -19,9 +19,6 @@ static void set_dense_combined(struct rev_info *revs) {\n  * Public functions. They are in the order they are called.\n  */\n \n-void diff_merges_init_revs(struct rev_info *revs) {\n-}\n-\n int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {\n \tint argcount;\n \tconst char *optarg;\ndiff --git a/diff-merges.h b/diff-merges.h\nindex ae1cc8ef9410..9c69b8f3bd69 100644\n--- a/diff-merges.h\n+++ b/diff-merges.h\n@@ -3,8 +3,6 @@\n \n struct rev_info;\n \n-void diff_merges_init_revs(struct rev_info *revs);\n-\n int diff_merges_parse_opts(struct rev_info *revs, const char **argv);\n \n void diff_merges_suppress(struct rev_info *revs);\ndiff --git a/revision.c b/revision.c\nindex 5a0e3d6ad542..46645ca0b6df 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -1814,7 +1814,6 @@ void repo_init_revisions(struct repository *r,\n \n \trevs->repo = r;\n \trevs->abbrev = DEFAULT_ABBREV;\n-\tdiff_merges_init_revs(revs);\n \trevs->simplify_history = 1;\n \trevs->pruning.repo = r;\n \trevs->pruning.flags.recursive = 1;\n-- \n2.25.1\n\n"},{"id":"408840","messageId":"20201101193330.24775-23-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201101193330.24775-1-sorganov@gmail.com","subject":"[PATCH 22/26] diff-merges: implement new values for --diff-merges","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-11-01T19:33:26Z","receivedAt":"2020-11-01T19:34:33Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"The following values are implemented:\n\n--diff-merges=\t        old equivalent\nfirst|first-parent    = --first-parent (only format implications)\nsep|separate          = -m\ncomb|combined         = -c\ndense| dense-combined = --cc\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n diff-merges.c | 19 ++++++++++++++++---\n 1 file changed, 16 insertions(+), 3 deletions(-)\n\ndiff --git a/diff-merges.c b/diff-merges.c\nindex db2217171442..5c35369f7a8c 100644\n--- a/diff-merges.c\n+++ b/diff-merges.c\n@@ -15,6 +15,11 @@ static void set_separate(struct rev_info *revs) {\n \trevs->separate_merges = 1;\n }\n \n+static void set_first_parent(struct rev_info *revs) {\n+\tset_separate(revs);\n+\trevs->first_parent_merges = 1;\n+}\n+\n static void set_m(struct rev_info *revs) {\n \t/*\n \t * To \"diff-index\", \"-m\" means \"match missing\", and to the \"log\"\n@@ -38,11 +43,19 @@ static void set_dense_combined(struct rev_info *revs) {\n }\n \n static void set_diff_merges(struct rev_info *revs, const char *optarg) {\n-\tif (!strcmp(optarg, \"off\")) {\n+\tif (0) ;\n+\telse if (!strcmp(optarg, \"off\")   || !strcmp(optarg, \"none\"))\n \t\tsuppress(revs);\n-\t} else {\n+\telse if (!strcmp(optarg, \"first\") || !strcmp(optarg, \"first-parent\"))\n+\t\tset_first_parent(revs);\n+\telse if (!strcmp(optarg, \"sep\")   || !strcmp(optarg, \"separate\"))\n+\t\tset_separate(revs);\n+\telse if (!strcmp(optarg, \"comb\")  || !strcmp(optarg, \"combined\"))\n+\t\tset_combined(revs);\n+\telse if (!strcmp(optarg, \"dense\") || !strcmp(optarg, \"dense-combined\"))\n+\t\tset_dense_combined(revs);\n+\telse\n \t\tdie(_(\"unknown value for --diff-merges: %s\"), optarg);\n-\t}\n }\n \n /*\n-- \n2.25.1\n\n"},{"id":"408841","messageId":"20201101193330.24775-10-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201101193330.24775-1-sorganov@gmail.com","subject":"[PATCH 09/26] diff-merges: re-arrange functions to match the order they are called in","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-11-01T19:33:13Z","receivedAt":"2020-11-01T19:34:33Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"For clarity, define public functions in the order they are called, to\nmake logic inter-dependencies easier to grok.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n diff-merges.c | 24 ++++++++++++++----------\n diff-merges.h |  7 +++----\n 2 files changed, 17 insertions(+), 14 deletions(-)\n\ndiff --git a/diff-merges.c b/diff-merges.c\nindex bb08a92e3b36..8536941e0b56 100644\n--- a/diff-merges.c\n+++ b/diff-merges.c\n@@ -2,6 +2,10 @@\n \n #include \"revision.h\"\n \n+/*\n+ * Public functions. They are in the order they are called.\n+ */\n+\n void diff_merges_init_revs(struct rev_info *revs) {\n \trevs->ignore_merges = -1;\n }\n@@ -44,16 +48,6 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {\n \treturn 1;\n }\n \n-void diff_merges_setup_revs(struct rev_info *revs)\n-{\n-\tif (revs->combine_merges && revs->ignore_merges < 0)\n-\t\trevs->ignore_merges = 0;\n-\tif (revs->ignore_merges < 0)\n-\t\trevs->ignore_merges = 1;\n-\tif (revs->combined_all_paths && !revs->combine_merges)\n-\t\tdie(\"--combined-all-paths makes no sense without -c or --cc\");\n-}\n-\n void diff_merges_default_to_first_parent(struct rev_info *revs) {\n \tif (revs->ignore_merges < 0)\t\t/* No -m */\n \t\trevs->ignore_merges = 0;\n@@ -68,3 +62,13 @@ void diff_merges_default_to_dense_combined(struct rev_info *revs) {\n \t\t}\n \t}\n }\n+\n+void diff_merges_setup_revs(struct rev_info *revs)\n+{\n+\tif (revs->combine_merges && revs->ignore_merges < 0)\n+\t\trevs->ignore_merges = 0;\n+\tif (revs->ignore_merges < 0)\n+\t\trevs->ignore_merges = 1;\n+\tif (revs->combined_all_paths && !revs->combine_merges)\n+\t\tdie(\"--combined-all-paths makes no sense without -c or --cc\");\n+}\ndiff --git a/diff-merges.h b/diff-merges.h\nindex 20b727bd734f..4b023c385d00 100644\n--- a/diff-merges.h\n+++ b/diff-merges.h\n@@ -7,11 +7,10 @@ void diff_merges_init_revs(struct rev_info *revs);\n \n int diff_merges_parse_opts(struct rev_info *revs, const char **argv);\n \n-void diff_merges_setup_revs(struct rev_info *revs);\n-\n-void diff_merges_default_to_dense_combined(struct rev_info *revs);\n-\n void diff_merges_default_to_first_parent(struct rev_info *revs);\n \n+void diff_merges_default_to_dense_combined(struct rev_info *revs);\n+\n+void diff_merges_setup_revs(struct rev_info *revs);\n \n #endif\n-- \n2.25.1\n\n"},{"id":"408842","messageId":"20201101193330.24775-24-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201101193330.24775-1-sorganov@gmail.com","subject":"[PATCH 23/26] t4013: add test for --diff-merges=first-parent","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-11-01T19:33:27Z","receivedAt":"2020-11-01T19:34:34Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"This new option provides essential new functionality, changing diff\noutput to first parent only without changing history traversal mode,\nso it deserves its own test.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n t/t4013-diff-various.sh                       |   1 +\n ...f.log_-p_--diff-merges=first-parent_master | 137 ++++++++++++++++++\n 2 files changed, 138 insertions(+)\n create mode 100644 t/t4013/diff.log_-p_--diff-merges=first-parent_master\n\ndiff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh\nindex 8d8178a8a616..ce56a9349d1c 100755\n--- a/t/t4013-diff-various.sh\n+++ b/t/t4013-diff-various.sh\n@@ -327,6 +327,7 @@ log --no-diff-merges -p --first-parent master\n log --diff-merges=off -p --first-parent master\n log --first-parent --diff-merges=off -p master\n log -p --first-parent master\n+log -p --diff-merges=first-parent master\n log -m -p --first-parent master\n log -m -p master\n log --cc -m -p master\ndiff --git a/t/t4013/diff.log_-p_--diff-merges=first-parent_master b/t/t4013/diff.log_-p_--diff-merges=first-parent_master\nnew file mode 100644\nindex 000000000000..9538a2751123\n--- /dev/null\n+++ b/t/t4013/diff.log_-p_--diff-merges=first-parent_master\n@@ -0,0 +1,137 @@\n+$ git log -p --diff-merges=first-parent master\n+commit 59d314ad6f356dd08601a4cd5e530381da3e3c64\n+Merge: 9a6d494 c7a2ab9\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:04:00 2006 +0000\n+\n+    Merge branch 'side'\n+\n+diff --git a/dir/sub b/dir/sub\n+index cead32e..992913c 100644\n+--- a/dir/sub\n++++ b/dir/sub\n+@@ -4,3 +4,5 @@ C\n+ D\n+ E\n+ F\n++1\n++2\n+diff --git a/file0 b/file0\n+index b414108..10a8a9f 100644\n+--- a/file0\n++++ b/file0\n+@@ -4,3 +4,6 @@\n+ 4\n+ 5\n+ 6\n++A\n++B\n++C\n+\n+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:03:00 2006 +0000\n+\n+    Side\n+\n+diff --git a/dir/sub b/dir/sub\n+index 35d242b..7289e35 100644\n+--- a/dir/sub\n++++ b/dir/sub\n+@@ -1,2 +1,4 @@\n+ A\n+ B\n++1\n++2\n+diff --git a/file0 b/file0\n+index 01e79c3..f4615da 100644\n+--- a/file0\n++++ b/file0\n+@@ -1,3 +1,6 @@\n+ 1\n+ 2\n+ 3\n++A\n++B\n++C\n+diff --git a/file3 b/file3\n+new file mode 100644\n+index 0000000..7289e35\n+--- /dev/null\n++++ b/file3\n+@@ -0,0 +1,4 @@\n++A\n++B\n++1\n++2\n+\n+commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:02:00 2006 +0000\n+\n+    Third\n+\n+diff --git a/dir/sub b/dir/sub\n+index 8422d40..cead32e 100644\n+--- a/dir/sub\n++++ b/dir/sub\n+@@ -2,3 +2,5 @@ A\n+ B\n+ C\n+ D\n++E\n++F\n+diff --git a/file1 b/file1\n+new file mode 100644\n+index 0000000..b1e6722\n+--- /dev/null\n++++ b/file1\n+@@ -0,0 +1,3 @@\n++A\n++B\n++C\n+\n+commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:01:00 2006 +0000\n+\n+    Second\n+    \n+    This is the second commit.\n+\n+diff --git a/dir/sub b/dir/sub\n+index 35d242b..8422d40 100644\n+--- a/dir/sub\n++++ b/dir/sub\n+@@ -1,2 +1,4 @@\n+ A\n+ B\n++C\n++D\n+diff --git a/file0 b/file0\n+index 01e79c3..b414108 100644\n+--- a/file0\n++++ b/file0\n+@@ -1,3 +1,6 @@\n+ 1\n+ 2\n+ 3\n++4\n++5\n++6\n+diff --git a/file2 b/file2\n+deleted file mode 100644\n+index 01e79c3..0000000\n+--- a/file2\n++++ /dev/null\n+@@ -1,3 +0,0 @@\n+-1\n+-2\n+-3\n+\n+commit 444ac553ac7612cc88969031b02b3767fb8a353a\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:00:00 2006 +0000\n+\n+    Initial\n+$\n-- \n2.25.1\n\n"},{"id":"408843","messageId":"20201101193330.24775-26-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201101193330.24775-1-sorganov@gmail.com","subject":"[PATCH 25/26] doc/diff-generate-patch: mention new --diff-merges option","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-11-01T19:33:29Z","receivedAt":"2020-11-01T19:34:35Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Mention --diff-merges instead of -m in a note to merge formats to aid\ndiscoverability, as -m is now described among --diff-merges options\nanyway.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n Documentation/diff-generate-patch.txt | 6 +++---\n 1 file changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/Documentation/diff-generate-patch.txt b/Documentation/diff-generate-patch.txt\nindex b10ff4caa6c5..2db8eacc3ec7 100644\n--- a/Documentation/diff-generate-patch.txt\n+++ b/Documentation/diff-generate-patch.txt\n@@ -81,9 +81,9 @@ Combined diff format\n Any diff-generating command can take the `-c` or `--cc` option to\n produce a 'combined diff' when showing a merge. This is the default\n format when showing merges with linkgit:git-diff[1] or\n-linkgit:git-show[1]. Note also that you can give the `-m` option to any\n-of these commands to force generation of diffs with individual parents\n-of a merge.\n+linkgit:git-show[1]. Note also that you can give suitable\n+`--diff-merges` option to any of these commands to force generation of\n+diffs in specific format.\n \n A \"combined diff\" format looks like this:\n \n-- \n2.25.1\n\n"},{"id":"408844","messageId":"20201101193330.24775-25-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201101193330.24775-1-sorganov@gmail.com","subject":"[PATCH 24/26] doc/git-log: describe new --diff-merges options","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-11-01T19:33:28Z","receivedAt":"2020-11-01T19:34:37Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Describe all the new --diff-merges options in the git-log.txt\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n Documentation/git-log.txt | 79 +++++++++++++++++++++++----------------\n 1 file changed, 46 insertions(+), 33 deletions(-)\n\ndiff --git a/Documentation/git-log.txt b/Documentation/git-log.txt\nindex 2b8ac5ff882a..de498a189646 100644\n--- a/Documentation/git-log.txt\n+++ b/Documentation/git-log.txt\n@@ -120,45 +120,58 @@ DIFF FORMATTING\n By default, `git log` does not generate any diff output. The options\n below can be used to show the changes made by each commit.\n \n-Note that unless one of `-c`, `--cc`, or `-m` is given, merge commits\n-will never show a diff, even if a diff format like `--patch` is\n-selected, nor will they match search options like `-S`. The exception is\n-when `--first-parent` is in use, in which merges are treated like normal\n-single-parent commits (this can be overridden by providing a\n-combined-diff option or with `--no-diff-merges`).\n+Note that unless one of `--diff-merges` variants (including short\n+`-m`, `-c`, and `--cc` options) is explicitly given, merge commits\n+will not show a diff, even if a diff format like `--patch` is\n+selected, nor will they match search options like `-S`. The exception\n+is when `--first-parent` is in use, in which case\n+`--diff-merges=first-parent` is implied.\n \n--c::\n-\tWith this option, diff output for a merge commit\n-\tshows the differences from each of the parents to the merge result\n-\tsimultaneously instead of showing pairwise diff between a parent\n-\tand the result one at a time. Furthermore, it lists only files\n-\twhich were modified from all parents.\n-\n---cc::\n-\tThis flag implies the `-c` option and further compresses the\n-\tpatch output by omitting uninteresting hunks whose contents in\n-\tthe parents have only two variants and the merge result picks\n-\tone of them without modification.\n+--diff-merges=(off|none|first-parent|separate|combined|dense-combined)::\n+--no-diff-merges::\n+\tSpecify diff format to be used for merge commits. This has no\n+\teffect unless diff output is enabled in the first place (e.g.,\n+\twith `--patch` option.)\n++\n+--diff-merges=(off|none):::\n+--no-diff-merges:::\n+\t(default) Disable output of diffs for merge commits. Useful to\n+\toverride implied value.\n++\n+--diff-merges=first-parent:::\n+\tThis option makes merge commits show the full diff with\n+\trespect to the first parent only, exactly like\tregular\n+\tcommits.\n++\n+--diff-merges=separate:::\n+-m:::\n+\tThis makes merge commits show the full diff with respect to\n+\teach of the parents. Separate log entry and diff is generated\n+\tfor each parent.\n++\n+--diff-merges=combined:::\n+-c:::\n+\tWith this option, diff output for a merge commit shows the\n+\tdifferences from each of the parents to the merge result\n+\tsimultaneously instead of showing pairwise diff between a\n+\tparent and the result one at a time. Furthermore, it lists\n+\tonly files which were modified from all parents.\n++\n+--diff-merges=dense-combined:::\n+--cc:::\n+\tWith this option the output produced by\n+\t`--diff-merges=combined` is further compressed by omitting\n+\tuninteresting hunks whose contents in the parents have only\n+\ttwo variants and the merge result picks one of them without\n+\tmodification.\n \n --combined-all-paths::\n \tThis flag causes combined diffs (used for merge commits) to\n \tlist the name of the file from all parents.  It thus only has\n-\teffect when -c or --cc are specified, and is likely only\n-\tuseful if filename changes are detected (i.e. when either\n-\trename or copy detection have been requested).\n+\teffect when `--diff-merges=[dense-]combined` is in use, and\n+\tis likely only useful if filename changes are detected (i.e.\n+\twhen either rename or copy detection have been requested).\n \n--m::\n-\tThis flag makes the merge commits show the full diff like\n-\tregular commits; for each merge parent, a separate log entry\n-\tand diff is generated. An exception is that only diff against\n-\tthe first parent is shown when `--first-parent` option is given;\n-\tin that case, the output represents the changes the merge\n-\tbrought _into_ the then-current branch.\n-\n---diff-merges=off::\n---no-diff-merges::\n-\tDisable output of diffs for merge commits (default). Useful to\n-\toverride `-m`, `-c`, or `--cc`.\n \n :git-log: 1\n include::diff-options.txt[]\n-- \n2.25.1\n\n"},{"id":"408845","messageId":"20201101193330.24775-18-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201101193330.24775-1-sorganov@gmail.com","subject":"[PATCH 17/26] diff-merges: split 'ignore_merges' field","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-11-01T19:33:21Z","receivedAt":"2020-11-01T19:34:38Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"'ignore_meres' was 3-way field that served two distinct purposes that\nwe now assign to 2 new independent flags: 'separate_merges', and\n'explicit_diff_merges'.\n\n'separate_merges' tells that we need to output diff format containing\nseparate diff for every parent (as opposed to 'combine_merges').\n\n'explicit_diff_merges' tells that at least one of diff-merges options\nhas been explicitly specified on the command line, so no defaults\nshould apply.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n diff-merges.c | 29 ++++++++++++-----------------\n log-tree.c    | 15 ++++++++-------\n revision.h    |  3 ++-\n 3 files changed, 22 insertions(+), 25 deletions(-)\n\ndiff --git a/diff-merges.c b/diff-merges.c\nindex f2b9ed789ca8..19cdad1aa4a1 100644\n--- a/diff-merges.c\n+++ b/diff-merges.c\n@@ -3,7 +3,7 @@\n #include \"revision.h\"\n \n static void suppress(struct rev_info *revs) {\n-\trevs->ignore_merges = 1;\n+\trevs->separate_merges = 0;\n \trevs->first_parent_merges = 0;\n \trevs->combine_merges = 0;\n \trevs->dense_combined_merges = 0;\n@@ -20,7 +20,6 @@ static void set_dense_combined(struct rev_info *revs) {\n  */\n \n void diff_merges_init_revs(struct rev_info *revs) {\n-\trevs->ignore_merges = -1;\n }\n \n int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {\n@@ -35,7 +34,7 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {\n \t\t * family of commands, it means \"show full diff for merges\". Set\n \t\t * both fields appropriately.\n \t\t */\n-\t\trevs->ignore_merges = 0;\n+\t\trevs->separate_merges = 1;\n \t\trevs->match_missing = 1;\n \t} else if (!strcmp(arg, \"-c\")) {\n \t\trevs->dense_combined_merges = 0;\n@@ -55,6 +54,7 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {\n \t} else\n \t\treturn 0;\n \n+\trevs->explicit_diff_merges = 1;\n \treturn 1;\n }\n \n@@ -63,20 +63,15 @@ void diff_merges_suppress(struct rev_info *revs) {\n }\n \n void diff_merges_default_to_first_parent(struct rev_info *revs) {\n-\tif (revs->ignore_merges < 0)\t\t/* No -m */\n-\t\trevs->ignore_merges = 0;\n-\tif (!revs->combine_merges)\t\t/* No -c/--cc\" */\n+\tif (!revs->explicit_diff_merges)\n+\t\trevs->separate_merges = 1;\n+\tif (revs->separate_merges)\n \t\trevs->first_parent_merges = 1;\n }\n \n void diff_merges_default_to_dense_combined(struct rev_info *revs) {\n-\tif (revs->ignore_merges < 0) {\t\t/* No -m */\n-\t\trevs->ignore_merges = 0;\n-\t\tif (!revs->combine_merges) {\t/* No -c/--cc\" */\n-\t\t\trevs->combine_merges = 1;\n-\t\t\trevs->dense_combined_merges = 1;\n-\t\t}\n-\t}\n+\tif (!revs->explicit_diff_merges)\n+\t\tset_dense_combined(revs);\n }\n \n void diff_merges_set_dense_combined_if_unset(struct rev_info *revs) {\n@@ -86,10 +81,10 @@ void diff_merges_set_dense_combined_if_unset(struct rev_info *revs) {\n \n void diff_merges_setup_revs(struct rev_info *revs)\n {\n-\tif (revs->combine_merges && revs->ignore_merges < 0)\n-\t\trevs->ignore_merges = 0;\n-\tif (revs->ignore_merges < 0)\n-\t\trevs->ignore_merges = 1;\n+\tif (revs->combine_merges == 0)\n+\t\trevs->dense_combined_merges = 0;\n+\tif (revs->separate_merges == 0)\n+\t\trevs->first_parent_merges = 0;\n \tif (revs->combined_all_paths && !revs->combine_merges)\n \t\tdie(\"--combined-all-paths makes no sense without -c or --cc\");\n \tif (revs->combine_merges)\ndiff --git a/log-tree.c b/log-tree.c\nindex 3fdc0fc64bfb..f9385b1dae6f 100644\n--- a/log-tree.c\n+++ b/log-tree.c\n@@ -918,14 +918,15 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log\n \n \t/* More than one parent? */\n \tif (parents->next) {\n-\t\tif (opt->ignore_merges)\n-\t\t\treturn 0;\n-\t\telse if (opt->combine_merges)\n+\t\tif (opt->combine_merges)\n \t\t\treturn do_diff_combined(opt, commit);\n-\t\telse if (!opt->first_parent_merges) {\n-\t\t\t/* If we show multiple diffs, show the parent info */\n-\t\t\tlog->parent = parents->item;\n-\t\t}\n+\t\tif (opt->separate_merges) {\n+\t\t\tif (!opt->first_parent_merges) {\n+\t\t\t\t/* Show parent info for multiple diffs */\n+\t\t\t\tlog->parent = parents->item;\n+\t\t\t}\n+\t\t} else\n+\t\t\treturn 0;\n \t}\n \n \tshowed_log = 0;\ndiff --git a/revision.h b/revision.h\nindex ba2aef79215e..fcc532c873d1 100644\n--- a/revision.h\n+++ b/revision.h\n@@ -191,12 +191,13 @@ struct rev_info {\n \t\t\tmatch_missing:1,\n \t\t\tno_commit_id:1,\n \t\t\tverbose_header:1,\n+\t\t\texplicit_diff_merges: 1,\n+\t\t\tseparate_merges: 1,\n \t\t\tcombine_merges:1,\n \t\t\tcombined_all_paths:1,\n \t\t\tdense_combined_merges:1,\n \t\t\tfirst_parent_merges:1,\n \t\t\talways_show_header:1;\n-\tint             ignore_merges:2;\n \n \t/* Format info */\n \tint\t\tshow_notes;\n-- \n2.25.1\n\n"},{"id":"408846","messageId":"20201101193330.24775-17-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201101193330.24775-1-sorganov@gmail.com","subject":"[PATCH 16/26] diff-merges: fix -m to properly override -c/--cc","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-11-01T19:33:20Z","receivedAt":"2020-11-01T19:34:39Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Logically, -m, -c, --cc specify 3 different formats for representing\nmerge commits, yet -m doesn't in fact override -c or --cc, that makes\nno sense.\n\nFix -m to properly override -c/--cc, and change the tests accordingly.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n diff-merges.c           | 1 +\n t/t4013-diff-various.sh | 4 ++--\n 2 files changed, 3 insertions(+), 2 deletions(-)\n\ndiff --git a/diff-merges.c b/diff-merges.c\nindex a30c730a457f..f2b9ed789ca8 100644\n--- a/diff-merges.c\n+++ b/diff-merges.c\n@@ -29,6 +29,7 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {\n \tconst char *arg = argv[0];\n \n \tif (!strcmp(arg, \"-m\")) {\n+\t\tsuppress(revs);\n \t\t/*\n \t\t * To \"diff-index\", \"-m\" means \"match missing\", and to the \"log\"\n \t\t * family of commands, it means \"show full diff for merges\". Set\ndiff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh\nindex 64d9fce44614..8d8178a8a616 100755\n--- a/t/t4013-diff-various.sh\n+++ b/t/t4013-diff-various.sh\n@@ -329,8 +329,8 @@ log --first-parent --diff-merges=off -p master\n log -p --first-parent master\n log -m -p --first-parent master\n log -m -p master\n-:failure log --cc -m -p master\n-:failure log -c -m -p master\n+log --cc -m -p master\n+log -c -m -p master\n log -SF master\n log -S F master\n log -SF -p master\n-- \n2.25.1\n\n"},{"id":"408847","messageId":"20201101193330.24775-27-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201101193330.24775-1-sorganov@gmail.com","subject":"[PATCH 26/26] doc/rev-list-options: document --first-parent implies --diff-merges=first-parent","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-11-01T19:33:30Z","receivedAt":"2020-11-01T19:34:40Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Before introduction of new --diff-merges options, --first-parent\nimplicitly changed the default diff format for merge commits to\nshowing only the diff with respect to the first parent, and there were\nno way to get such format from \"git log\" without affecting history\ntraversal logic that --first-parent causes.\n\nNow, after introduction of the --diff-merges=first-parent, the\n--first-parent simply implies the former, and this patch corrects\ndocumentation accordingly.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n Documentation/rev-list-options.txt | 3 +++\n 1 file changed, 3 insertions(+)\n\ndiff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt\nindex 002379056a07..ded383e62ae5 100644\n--- a/Documentation/rev-list-options.txt\n+++ b/Documentation/rev-list-options.txt\n@@ -129,6 +129,9 @@ parents) and `--max-parents=-1` (negative numbers denote no upper limit).\n \tadjusting to updated upstream from time to time, and\n \tthis option allows you to ignore the individual commits\n \tbrought in to your history by such a merge.\n+ifdef::git-log[]\n+\tImplies `--diff-merges=first-parent`.\n+endif::git-log[]\n \n --not::\n \tReverses the meaning of the '{caret}' prefix (or lack thereof)\n-- \n2.25.1\n\n"},{"id":"408848","messageId":"20201101193330.24775-16-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201101193330.24775-1-sorganov@gmail.com","subject":"[PATCH 15/26] t4013: add tests for -m failing to override -c/--cc","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-11-01T19:33:19Z","receivedAt":"2020-11-01T19:34:41Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Logically, -m, -c, --cc specify 3 different formats for representing\nmerge commits, yet -m doesn't in fact override -c or --cc, that makes\nno sense.\n\nAdd 2 expected to fail tests that demonstrate the problem.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n t/t4013-diff-various.sh            |   2 +\n t/t4013/diff.log_--cc_-m_-p_master | 200 +++++++++++++++++++++++++++++\n t/t4013/diff.log_-c_-m_-p_master   | 200 +++++++++++++++++++++++++++++\n 3 files changed, 402 insertions(+)\n create mode 100644 t/t4013/diff.log_--cc_-m_-p_master\n create mode 100644 t/t4013/diff.log_-c_-m_-p_master\n\ndiff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh\nindex 935d10ac0572..64d9fce44614 100755\n--- a/t/t4013-diff-various.sh\n+++ b/t/t4013-diff-various.sh\n@@ -329,6 +329,8 @@ log --first-parent --diff-merges=off -p master\n log -p --first-parent master\n log -m -p --first-parent master\n log -m -p master\n+:failure log --cc -m -p master\n+:failure log -c -m -p master\n log -SF master\n log -S F master\n log -SF -p master\ndiff --git a/t/t4013/diff.log_--cc_-m_-p_master b/t/t4013/diff.log_--cc_-m_-p_master\nnew file mode 100644\nindex 000000000000..7c217cf348c7\n--- /dev/null\n+++ b/t/t4013/diff.log_--cc_-m_-p_master\n@@ -0,0 +1,200 @@\n+$ git log --cc -m -p master\n+commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (from 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0)\n+Merge: 9a6d494 c7a2ab9\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:04:00 2006 +0000\n+\n+    Merge branch 'side'\n+\n+diff --git a/dir/sub b/dir/sub\n+index cead32e..992913c 100644\n+--- a/dir/sub\n++++ b/dir/sub\n+@@ -4,3 +4,5 @@ C\n+ D\n+ E\n+ F\n++1\n++2\n+diff --git a/file0 b/file0\n+index b414108..10a8a9f 100644\n+--- a/file0\n++++ b/file0\n+@@ -4,3 +4,6 @@\n+ 4\n+ 5\n+ 6\n++A\n++B\n++C\n+\n+commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (from c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a)\n+Merge: 9a6d494 c7a2ab9\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:04:00 2006 +0000\n+\n+    Merge branch 'side'\n+\n+diff --git a/dir/sub b/dir/sub\n+index 7289e35..992913c 100644\n+--- a/dir/sub\n++++ b/dir/sub\n+@@ -1,4 +1,8 @@\n+ A\n+ B\n++C\n++D\n++E\n++F\n+ 1\n+ 2\n+diff --git a/file0 b/file0\n+index f4615da..10a8a9f 100644\n+--- a/file0\n++++ b/file0\n+@@ -1,6 +1,9 @@\n+ 1\n+ 2\n+ 3\n++4\n++5\n++6\n+ A\n+ B\n+ C\n+diff --git a/file1 b/file1\n+new file mode 100644\n+index 0000000..b1e6722\n+--- /dev/null\n++++ b/file1\n+@@ -0,0 +1,3 @@\n++A\n++B\n++C\n+diff --git a/file2 b/file2\n+deleted file mode 100644\n+index 01e79c3..0000000\n+--- a/file2\n++++ /dev/null\n+@@ -1,3 +0,0 @@\n+-1\n+-2\n+-3\n+diff --git a/file3 b/file3\n+deleted file mode 100644\n+index 7289e35..0000000\n+--- a/file3\n++++ /dev/null\n+@@ -1,4 +0,0 @@\n+-A\n+-B\n+-1\n+-2\n+\n+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:03:00 2006 +0000\n+\n+    Side\n+\n+diff --git a/dir/sub b/dir/sub\n+index 35d242b..7289e35 100644\n+--- a/dir/sub\n++++ b/dir/sub\n+@@ -1,2 +1,4 @@\n+ A\n+ B\n++1\n++2\n+diff --git a/file0 b/file0\n+index 01e79c3..f4615da 100644\n+--- a/file0\n++++ b/file0\n+@@ -1,3 +1,6 @@\n+ 1\n+ 2\n+ 3\n++A\n++B\n++C\n+diff --git a/file3 b/file3\n+new file mode 100644\n+index 0000000..7289e35\n+--- /dev/null\n++++ b/file3\n+@@ -0,0 +1,4 @@\n++A\n++B\n++1\n++2\n+\n+commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:02:00 2006 +0000\n+\n+    Third\n+\n+diff --git a/dir/sub b/dir/sub\n+index 8422d40..cead32e 100644\n+--- a/dir/sub\n++++ b/dir/sub\n+@@ -2,3 +2,5 @@ A\n+ B\n+ C\n+ D\n++E\n++F\n+diff --git a/file1 b/file1\n+new file mode 100644\n+index 0000000..b1e6722\n+--- /dev/null\n++++ b/file1\n+@@ -0,0 +1,3 @@\n++A\n++B\n++C\n+\n+commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:01:00 2006 +0000\n+\n+    Second\n+    \n+    This is the second commit.\n+\n+diff --git a/dir/sub b/dir/sub\n+index 35d242b..8422d40 100644\n+--- a/dir/sub\n++++ b/dir/sub\n+@@ -1,2 +1,4 @@\n+ A\n+ B\n++C\n++D\n+diff --git a/file0 b/file0\n+index 01e79c3..b414108 100644\n+--- a/file0\n++++ b/file0\n+@@ -1,3 +1,6 @@\n+ 1\n+ 2\n+ 3\n++4\n++5\n++6\n+diff --git a/file2 b/file2\n+deleted file mode 100644\n+index 01e79c3..0000000\n+--- a/file2\n++++ /dev/null\n+@@ -1,3 +0,0 @@\n+-1\n+-2\n+-3\n+\n+commit 444ac553ac7612cc88969031b02b3767fb8a353a\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:00:00 2006 +0000\n+\n+    Initial\n+$\ndiff --git a/t/t4013/diff.log_-c_-m_-p_master b/t/t4013/diff.log_-c_-m_-p_master\nnew file mode 100644\nindex 000000000000..b660f3d5f28e\n--- /dev/null\n+++ b/t/t4013/diff.log_-c_-m_-p_master\n@@ -0,0 +1,200 @@\n+$ git log -c -m -p master\n+commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (from 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0)\n+Merge: 9a6d494 c7a2ab9\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:04:00 2006 +0000\n+\n+    Merge branch 'side'\n+\n+diff --git a/dir/sub b/dir/sub\n+index cead32e..992913c 100644\n+--- a/dir/sub\n++++ b/dir/sub\n+@@ -4,3 +4,5 @@ C\n+ D\n+ E\n+ F\n++1\n++2\n+diff --git a/file0 b/file0\n+index b414108..10a8a9f 100644\n+--- a/file0\n++++ b/file0\n+@@ -4,3 +4,6 @@\n+ 4\n+ 5\n+ 6\n++A\n++B\n++C\n+\n+commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (from c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a)\n+Merge: 9a6d494 c7a2ab9\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:04:00 2006 +0000\n+\n+    Merge branch 'side'\n+\n+diff --git a/dir/sub b/dir/sub\n+index 7289e35..992913c 100644\n+--- a/dir/sub\n++++ b/dir/sub\n+@@ -1,4 +1,8 @@\n+ A\n+ B\n++C\n++D\n++E\n++F\n+ 1\n+ 2\n+diff --git a/file0 b/file0\n+index f4615da..10a8a9f 100644\n+--- a/file0\n++++ b/file0\n+@@ -1,6 +1,9 @@\n+ 1\n+ 2\n+ 3\n++4\n++5\n++6\n+ A\n+ B\n+ C\n+diff --git a/file1 b/file1\n+new file mode 100644\n+index 0000000..b1e6722\n+--- /dev/null\n++++ b/file1\n+@@ -0,0 +1,3 @@\n++A\n++B\n++C\n+diff --git a/file2 b/file2\n+deleted file mode 100644\n+index 01e79c3..0000000\n+--- a/file2\n++++ /dev/null\n+@@ -1,3 +0,0 @@\n+-1\n+-2\n+-3\n+diff --git a/file3 b/file3\n+deleted file mode 100644\n+index 7289e35..0000000\n+--- a/file3\n++++ /dev/null\n+@@ -1,4 +0,0 @@\n+-A\n+-B\n+-1\n+-2\n+\n+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:03:00 2006 +0000\n+\n+    Side\n+\n+diff --git a/dir/sub b/dir/sub\n+index 35d242b..7289e35 100644\n+--- a/dir/sub\n++++ b/dir/sub\n+@@ -1,2 +1,4 @@\n+ A\n+ B\n++1\n++2\n+diff --git a/file0 b/file0\n+index 01e79c3..f4615da 100644\n+--- a/file0\n++++ b/file0\n+@@ -1,3 +1,6 @@\n+ 1\n+ 2\n+ 3\n++A\n++B\n++C\n+diff --git a/file3 b/file3\n+new file mode 100644\n+index 0000000..7289e35\n+--- /dev/null\n++++ b/file3\n+@@ -0,0 +1,4 @@\n++A\n++B\n++1\n++2\n+\n+commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:02:00 2006 +0000\n+\n+    Third\n+\n+diff --git a/dir/sub b/dir/sub\n+index 8422d40..cead32e 100644\n+--- a/dir/sub\n++++ b/dir/sub\n+@@ -2,3 +2,5 @@ A\n+ B\n+ C\n+ D\n++E\n++F\n+diff --git a/file1 b/file1\n+new file mode 100644\n+index 0000000..b1e6722\n+--- /dev/null\n++++ b/file1\n+@@ -0,0 +1,3 @@\n++A\n++B\n++C\n+\n+commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:01:00 2006 +0000\n+\n+    Second\n+    \n+    This is the second commit.\n+\n+diff --git a/dir/sub b/dir/sub\n+index 35d242b..8422d40 100644\n+--- a/dir/sub\n++++ b/dir/sub\n+@@ -1,2 +1,4 @@\n+ A\n+ B\n++C\n++D\n+diff --git a/file0 b/file0\n+index 01e79c3..b414108 100644\n+--- a/file0\n++++ b/file0\n+@@ -1,3 +1,6 @@\n+ 1\n+ 2\n+ 3\n++4\n++5\n++6\n+diff --git a/file2 b/file2\n+deleted file mode 100644\n+index 01e79c3..0000000\n+--- a/file2\n++++ /dev/null\n+@@ -1,3 +0,0 @@\n+-1\n+-2\n+-3\n+\n+commit 444ac553ac7612cc88969031b02b3767fb8a353a\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:00:00 2006 +0000\n+\n+    Initial\n+$\n-- \n2.25.1\n\n"},{"id":"408849","messageId":"20201101193330.24775-15-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201101193330.24775-1-sorganov@gmail.com","subject":"[PATCH 14/26] t4013: support test_expect_failure through ':failure' magic","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-11-01T19:33:18Z","receivedAt":"2020-11-01T19:34:42Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Add support to be able to specify expected failure, through :failure\nmagic, like this:\n\n:failure cmd args\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n t/t4013-diff-various.sh | 7 ++++++-\n 1 file changed, 6 insertions(+), 1 deletion(-)\n\ndiff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh\nindex 5c7b0122b4f1..935d10ac0572 100755\n--- a/t/t4013-diff-various.sh\n+++ b/t/t4013-diff-various.sh\n@@ -174,6 +174,7 @@ process_diffs () {\n V=$(git version | sed -e 's/^git version //' -e 's/\\./\\\\./g')\n while read magic cmd\n do\n+\tstatus=success\n \tcase \"$magic\" in\n \t'' | '#'*)\n \t\tcontinue ;;\n@@ -182,6 +183,10 @@ do\n \t\tlabel=\"$magic-$cmd\"\n \t\tcase \"$magic\" in\n \t\tnoellipses) ;;\n+\t\tfailure)\n+\t\t\tstatus=failure\n+\t\t\tmagic=\n+\t\t\tlabel=\"$cmd\" ;;\n \t\t*)\n \t\t\tBUG \"unknown magic $magic\" ;;\n \t\tesac ;;\n@@ -194,7 +199,7 @@ do\n \texpect=\"$TEST_DIRECTORY/t4013/diff.$test\"\n \tactual=\"$pfx-diff.$test\"\n \n-\ttest_expect_success \"git $cmd # magic is ${magic:-(not used)}\" '\n+\ttest_expect_$status \"git $cmd # magic is ${magic:-(not used)}\" '\n \t\t{\n \t\t\techo \"$ git $cmd\"\n \t\t\tcase \"$magic\" in\n-- \n2.25.1\n\n"},{"id":"408856","messageId":"a1afac59-35c2-18cc-0d11-38d0b9479bf9@iee.email","threadId":"54550","inReplyTo":"20201101193330.24775-18-sorganov@gmail.com","subject":"Re: [PATCH 17/26] diff-merges: split 'ignore_merges' field","fromName":"Philip Oakley","fromEmail":"philipoakley@iee.email","sentAt":"2020-11-02T10:48:10Z","receivedAt":"2020-11-02T10:48:15Z","isPatch":true,"sender":{"key":"philipoakley@iee.email","avatar":"https://avatars.githubusercontent.com/u/914343?v=4"},"body":"micro-nit while browsing..\n\nOn 01/11/2020 19:33, Sergey Organov wrote:\n> 'ignore_meres' was 3-way field that served two distinct purposes that\nignore_merges (missing 'g')\n> we now assign to 2 new independent flags: 'separate_merges', and\n> 'explicit_diff_merges'.\n--\nPhilip\n"},{"id":"408857","messageId":"7dcadc50-5705-68e9-79be-191b5c52241c@iee.email","threadId":"54550","inReplyTo":"20201101193330.24775-20-sorganov@gmail.com","subject":"Re: [PATCH 19/26] diff-merges: get rid of now empty diff_merges_init_revs()","fromName":"Philip Oakley","fromEmail":"philipoakley@iee.email","sentAt":"2020-11-02T10:51:24Z","receivedAt":"2020-11-02T10:51:29Z","isPatch":true,"sender":{"key":"philipoakley@iee.email","avatar":"https://avatars.githubusercontent.com/u/914343?v=4"},"body":"micro-nit again:\n\nOn 01/11/2020 19:33, Sergey Organov wrote:\n> After getting rid of 'ignore_meres' field, the diff_merges_init_revs()\nmerges\n> function became empty. Get rid of it.\n>\n> Signed-off-by: Sergey Organov <sorganov@gmail.com>\n> ---\n--\nPhilip\n"},{"id":"408868","messageId":"87o8kfohuo.fsf@osv.gnss.ru","threadId":"54550","inReplyTo":"a1afac59-35c2-18cc-0d11-38d0b9479bf9@iee.email","subject":"Re: [PATCH 17/26] diff-merges: split 'ignore_merges' field","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-11-02T16:15:27Z","receivedAt":"2020-11-02T16:15:34Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Philip Oakley <philipoakley@iee.email> writes:\n\n> micro-nit while browsing..\n>> 'ignore_meres' was 3-way field that served two distinct purposes that\n> ignore_merges (missing 'g')\n\nPhilip Oakley <philipoakley@iee.email> writes:\n\n> micro-nit again:\n>> After getting rid of 'ignore_meres' field, the diff_merges_init_revs()\n> merges\n\nThanks, Philip! Fixed for next re-roll.\n\n-- Sergey\n"},{"id":"409339","messageId":"20201108213838.4880-1-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201101193330.24775-1-sorganov@gmail.com","subject":"[PATCH v1 00/27] git-log: implement new --diff-merge options","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-11-08T21:38:11Z","receivedAt":"2020-11-08T21:41:23Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"These patch series implement new set of options governing the diff output\nof merge commits, all under the umbrella of the single --diff-merges=<mode>\noption. Most of the new options being synonyms for -m/-c/--cc options,\nthere is also additional functionality provided, allowing to get the format\nof \"-p --first-parent\" without change in history traversal that\n--first-parent option causes.\n\nThe net result of these series are the following new options:\n\n--diff-merges=\t |  old equivalent\n-----------------+----------------\nfirst-parent     | --first-parent (only format implications)\nseparate         | -m\ncombined         | -c\ndense-combined   | --cc\n\nThe series also cleanup logic of handling of diff merges options and fix an\nissue found in the original implementation where logically mutually\nexclusive options -m/-c/--cc failed to actually override each other.\n\nThe series start with the set of pure refactoring commits that are expected\nto introduce no functional changes. These are all commits up to and\nincluding:\n\n\"diff-merges: revise revs->diff flag handling\"\n\nThe aim of these commits is to isolate options handling for diff merges so\nthat it could be easily understood and tweaked to ease introduction of the\nnew options.\n\nThen the fix of -m/-c/-cc overriding issue follows, starting with a failing\ntest and followed by the fix.\n\nThen follows a little bit of additional refactoring in order to prepare for\nintroduction of the new options, and finally the series are finished by the\nimplementation, testing, and documentation update for the new options.\n\nUpdates in v1:\n\n\t* Added documentation fix for git-show to include --diff-merges.\n\t* Fixed typos in commit messages noticed by Philip Oakley.\n\nSergey Organov (27):\n  revision: factor out parsing of diff-merge related options\n  revision: factor out setup of diff-merge related settings\n  revision: factor out initialization of diff-merge related settings\n  revision: provide implementation for diff merges tweaks\n  revision: move diff merges functions to its own diff-merges.c\n  diff-merges: rename all functions to have common prefix\n  diff-merges: move checks for first_parent_only out of the module\n  diff-merges: rename diff_merges_default_to_enable() to match semantics\n  diff-merges: re-arrange functions to match the order they are called\n    in\n  diff-merges: new function diff_merges_suppress()\n  diff-merges: new function diff_merges_set_dense_combined_if_unset()\n  diff-merges: introduce revs->first_parent_merges flag\n  diff-merges: revise revs->diff flag handling\n  t4013: support test_expect_failure through ':failure' magic\n  t4013: add tests for -m failing to override -c/--cc\n  diff-merges: fix -m to properly override -c/--cc\n  diff-merges: split 'ignore_merges' field\n  diff-merges: group diff-merge flags next to each other inside\n    'rev_info'\n  diff-merges: get rid of now empty diff_merges_init_revs()\n  diff-merges: refactor opt settings into separate functions\n  diff-merges: make -m/-c/--cc explicitly mutually exclusive\n  diff-merges: implement new values for --diff-merges\n  t4013: add test for --diff-merges=first-parent\n  doc/git-log: describe new --diff-merges options\n  doc/diff-generate-patch: mention new --diff-merges option\n  doc/rev-list-options: document --first-parent implies\n    --diff-merges=first-parent\n  doc/git-show: include --diff-merges description\n\n Documentation/diff-generate-patch.txt         |   6 +-\n Documentation/diff-options.txt                |  54 +++++\n Documentation/git-log.txt                     |  39 ----\n Documentation/git-show.txt                    |   8 +-\n Documentation/rev-list-options.txt            |   3 +\n Makefile                                      |   1 +\n builtin/diff-files.c                          |   5 +-\n builtin/diff.c                                |   9 +-\n builtin/log.c                                 |  18 +-\n builtin/merge.c                               |   3 +-\n diff-merges.c                                 | 120 +++++++++++\n diff-merges.h                                 |  18 ++\n fmt-merge-msg.c                               |   3 +-\n log-tree.c                                    |  17 +-\n revision.c                                    |  38 +---\n revision.h                                    |   7 +-\n t/t4013-diff-various.sh                       |  10 +-\n t/t4013/diff.log_--cc_-m_-p_master            | 200 ++++++++++++++++++\n t/t4013/diff.log_-c_-m_-p_master              | 200 ++++++++++++++++++\n ...f.log_-p_--diff-merges=first-parent_master | 137 ++++++++++++\n 20 files changed, 788 insertions(+), 108 deletions(-)\n create mode 100644 diff-merges.c\n create mode 100644 diff-merges.h\n create mode 100644 t/t4013/diff.log_--cc_-m_-p_master\n create mode 100644 t/t4013/diff.log_-c_-m_-p_master\n create mode 100644 t/t4013/diff.log_-p_--diff-merges=first-parent_master\n\n-- \n2.25.1\n\n"},{"id":"409340","messageId":"20201108213838.4880-2-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201108213838.4880-1-sorganov@gmail.com","subject":"[PATCH v1 01/27] revision: factor out parsing of diff-merge related options","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-11-08T21:38:12Z","receivedAt":"2020-11-08T21:41:35Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Move all the parsing code related to diffing merges into new\nparse_diff_merge_opts() function.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n revision.c | 66 ++++++++++++++++++++++++++++++++----------------------\n 1 file changed, 39 insertions(+), 27 deletions(-)\n\ndiff --git a/revision.c b/revision.c\nindex aa6221204081..a09f4872acd7 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -2153,6 +2153,44 @@ static void add_message_grep(struct rev_info *revs, const char *pattern)\n \tadd_grep(revs, pattern, GREP_PATTERN_BODY);\n }\n \n+static int parse_diff_merge_opts(struct rev_info *revs, const char **argv) {\n+\tint argcount;\n+\tconst char *optarg;\n+\tconst char *arg = argv[0];\n+\n+\tif (!strcmp(arg, \"-m\")) {\n+\t\t/*\n+\t\t * To \"diff-index\", \"-m\" means \"match missing\", and to the \"log\"\n+\t\t * family of commands, it means \"show full diff for merges\". Set\n+\t\t * both fields appropriately.\n+\t\t */\n+\t\trevs->ignore_merges = 0;\n+\t\trevs->match_missing = 1;\n+\t} else if (!strcmp(arg, \"-c\")) {\n+\t\trevs->diff = 1;\n+\t\trevs->dense_combined_merges = 0;\n+\t\trevs->combine_merges = 1;\n+\t} else if (!strcmp(arg, \"--cc\")) {\n+\t\trevs->diff = 1;\n+\t\trevs->dense_combined_merges = 1;\n+\t\trevs->combine_merges = 1;\n+\t} else if (!strcmp(arg, \"--no-diff-merges\")) {\n+\t\trevs->ignore_merges = 1;\n+\t} else if (!strcmp(arg, \"--combined-all-paths\")) {\n+\t\trevs->diff = 1;\n+\t\trevs->combined_all_paths = 1;\n+\t} else if ((argcount = parse_long_opt(\"diff-merges\", argv, &optarg))) {\n+\t\tif (!strcmp(optarg, \"off\")) {\n+\t\t\trevs->ignore_merges = 1;\n+\t\t} else {\n+\t\t\tdie(_(\"unknown value for --diff-merges: %s\"), optarg);\n+\t\t}\n+\t} else\n+\t\treturn 0;\n+\n+\treturn 1;\n+}\n+\n static int handle_revision_opt(struct rev_info *revs, int argc, const char **argv,\n \t\t\t       int *unkc, const char **unkv,\n \t\t\t       const struct setup_revision_opt* opt)\n@@ -2349,34 +2387,8 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg\n \t\trevs->diff = 1;\n \t\trevs->diffopt.flags.recursive = 1;\n \t\trevs->diffopt.flags.tree_in_recursive = 1;\n-\t} else if (!strcmp(arg, \"-m\")) {\n-\t\t/*\n-\t\t * To \"diff-index\", \"-m\" means \"match missing\", and to the \"log\"\n-\t\t * family of commands, it means \"show full diff for merges\". Set\n-\t\t * both fields appropriately.\n-\t\t */\n-\t\trevs->ignore_merges = 0;\n-\t\trevs->match_missing = 1;\n-\t} else if ((argcount = parse_long_opt(\"diff-merges\", argv, &optarg))) {\n-\t\tif (!strcmp(optarg, \"off\")) {\n-\t\t\trevs->ignore_merges = 1;\n-\t\t} else {\n-\t\t\tdie(_(\"unknown value for --diff-merges: %s\"), optarg);\n-\t\t}\n+\t} else if ((argcount = parse_diff_merge_opts(revs, argv))) {\n \t\treturn argcount;\n-\t} else if (!strcmp(arg, \"--no-diff-merges\")) {\n-\t\trevs->ignore_merges = 1;\n-\t} else if (!strcmp(arg, \"-c\")) {\n-\t\trevs->diff = 1;\n-\t\trevs->dense_combined_merges = 0;\n-\t\trevs->combine_merges = 1;\n-\t} else if (!strcmp(arg, \"--combined-all-paths\")) {\n-\t\trevs->diff = 1;\n-\t\trevs->combined_all_paths = 1;\n-\t} else if (!strcmp(arg, \"--cc\")) {\n-\t\trevs->diff = 1;\n-\t\trevs->dense_combined_merges = 1;\n-\t\trevs->combine_merges = 1;\n \t} else if (!strcmp(arg, \"-v\")) {\n \t\trevs->verbose_header = 1;\n \t} else if (!strcmp(arg, \"--pretty\")) {\n-- \n2.25.1\n\n"},{"id":"409341","messageId":"20201108213838.4880-3-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201108213838.4880-1-sorganov@gmail.com","subject":"[PATCH v1 02/27] revision: factor out setup of diff-merge related settings","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-11-08T21:38:13Z","receivedAt":"2020-11-08T21:41:36Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Move all the setting code related to diffing merges into new\nsetup_diff_merge_revs() function.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n revision.c | 18 ++++++++++++------\n 1 file changed, 12 insertions(+), 6 deletions(-)\n\ndiff --git a/revision.c b/revision.c\nindex a09f4872acd7..739295bb9ff4 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -2191,6 +2191,16 @@ static int parse_diff_merge_opts(struct rev_info *revs, const char **argv) {\n \treturn 1;\n }\n \n+static void setup_diff_merges_revs(struct rev_info *revs)\n+{\n+\tif (revs->combine_merges && revs->ignore_merges < 0)\n+\t\trevs->ignore_merges = 0;\n+\tif (revs->ignore_merges < 0)\n+\t\trevs->ignore_merges = 1;\n+\tif (revs->combined_all_paths && !revs->combine_merges)\n+\t\tdie(\"--combined-all-paths makes no sense without -c or --cc\");\n+}\n+\n static int handle_revision_opt(struct rev_info *revs, int argc, const char **argv,\n \t\t\t       int *unkc, const char **unkv,\n \t\t\t       const struct setup_revision_opt* opt)\n@@ -2885,12 +2895,8 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s\n \t\t\tcopy_pathspec(&revs->diffopt.pathspec,\n \t\t\t\t      &revs->prune_data);\n \t}\n-\tif (revs->combine_merges && revs->ignore_merges < 0)\n-\t\trevs->ignore_merges = 0;\n-\tif (revs->ignore_merges < 0)\n-\t\trevs->ignore_merges = 1;\n-\tif (revs->combined_all_paths && !revs->combine_merges)\n-\t\tdie(\"--combined-all-paths makes no sense without -c or --cc\");\n+\n+\tsetup_diff_merges_revs(revs);\n \n \trevs->diffopt.abbrev = revs->abbrev;\n \n-- \n2.25.1\n\n"},{"id":"409342","messageId":"20201108213838.4880-4-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201108213838.4880-1-sorganov@gmail.com","subject":"[PATCH v1 03/27] revision: factor out initialization of diff-merge related settings","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-11-08T21:38:14Z","receivedAt":"2020-11-08T21:41:36Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Move initialization code related to diffing merges into new\ninit_diff_merge_revs() function.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n revision.c | 8 +++++++-\n 1 file changed, 7 insertions(+), 1 deletion(-)\n\ndiff --git a/revision.c b/revision.c\nindex 739295bb9ff4..bc568fb79778 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -1805,6 +1805,8 @@ static int add_parents_only(struct rev_info *revs, const char *arg_, int flags,\n \treturn 1;\n }\n \n+static void init_diff_merge_revs(struct rev_info *revs);\n+\n void repo_init_revisions(struct repository *r,\n \t\t\t struct rev_info *revs,\n \t\t\t const char *prefix)\n@@ -1813,7 +1815,7 @@ void repo_init_revisions(struct repository *r,\n \n \trevs->repo = r;\n \trevs->abbrev = DEFAULT_ABBREV;\n-\trevs->ignore_merges = -1;\n+\tinit_diff_merge_revs(revs);\n \trevs->simplify_history = 1;\n \trevs->pruning.repo = r;\n \trevs->pruning.flags.recursive = 1;\n@@ -2153,6 +2155,10 @@ static void add_message_grep(struct rev_info *revs, const char *pattern)\n \tadd_grep(revs, pattern, GREP_PATTERN_BODY);\n }\n \n+static void init_diff_merge_revs(struct rev_info *revs) {\n+\trevs->ignore_merges = -1;\n+}\n+\n static int parse_diff_merge_opts(struct rev_info *revs, const char **argv) {\n \tint argcount;\n \tconst char *optarg;\n-- \n2.25.1\n\n"},{"id":"409343","messageId":"20201108213838.4880-6-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201108213838.4880-1-sorganov@gmail.com","subject":"[PATCH v1 05/27] revision: move diff merges functions to its own diff-merges.c","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-11-08T21:38:16Z","receivedAt":"2020-11-08T21:41:36Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Create separate diff-merges.c and diff-merges.h files, and move all\nthe code related to handling of diff merges there.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n Makefile      |  1 +\n builtin/log.c |  1 +\n diff-merges.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++\n diff-merges.h | 12 +++++++++\n revision.c    | 72 +--------------------------------------------------\n revision.h    |  3 ---\n 6 files changed, 87 insertions(+), 74 deletions(-)\n create mode 100644 diff-merges.c\n create mode 100644 diff-merges.h\n\ndiff --git a/Makefile b/Makefile\nindex 1fb0ec17059a..d1347ef262cf 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -872,6 +872,7 @@ LIB_OBJS += date.o\n LIB_OBJS += decorate.o\n LIB_OBJS += delta-islands.o\n LIB_OBJS += diff-delta.o\n+LIB_OBJS += diff-merges.o\n LIB_OBJS += diff-lib.o\n LIB_OBJS += diff-no-index.o\n LIB_OBJS += diff.o\ndiff --git a/builtin/log.c b/builtin/log.c\nindex 717855a49e90..ad3092fdd854 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -12,6 +12,7 @@\n #include \"color.h\"\n #include \"commit.h\"\n #include \"diff.h\"\n+#include \"diff-merges.h\"\n #include \"revision.h\"\n #include \"log-tree.h\"\n #include \"builtin.h\"\ndiff --git a/diff-merges.c b/diff-merges.c\nnew file mode 100644\nindex 000000000000..8b9dd4ad5625\n--- /dev/null\n+++ b/diff-merges.c\n@@ -0,0 +1,72 @@\n+#include \"diff-merges.h\"\n+\n+#include \"revision.h\"\n+\n+void init_diff_merge_revs(struct rev_info *revs) {\n+\trevs->ignore_merges = -1;\n+}\n+\n+int parse_diff_merge_opts(struct rev_info *revs, const char **argv) {\n+\tint argcount;\n+\tconst char *optarg;\n+\tconst char *arg = argv[0];\n+\n+\tif (!strcmp(arg, \"-m\")) {\n+\t\t/*\n+\t\t * To \"diff-index\", \"-m\" means \"match missing\", and to the \"log\"\n+\t\t * family of commands, it means \"show full diff for merges\". Set\n+\t\t * both fields appropriately.\n+\t\t */\n+\t\trevs->ignore_merges = 0;\n+\t\trevs->match_missing = 1;\n+\t} else if (!strcmp(arg, \"-c\")) {\n+\t\trevs->diff = 1;\n+\t\trevs->dense_combined_merges = 0;\n+\t\trevs->combine_merges = 1;\n+\t} else if (!strcmp(arg, \"--cc\")) {\n+\t\trevs->diff = 1;\n+\t\trevs->dense_combined_merges = 1;\n+\t\trevs->combine_merges = 1;\n+\t} else if (!strcmp(arg, \"--no-diff-merges\")) {\n+\t\trevs->ignore_merges = 1;\n+\t} else if (!strcmp(arg, \"--combined-all-paths\")) {\n+\t\trevs->diff = 1;\n+\t\trevs->combined_all_paths = 1;\n+\t} else if ((argcount = parse_long_opt(\"diff-merges\", argv, &optarg))) {\n+\t\tif (!strcmp(optarg, \"off\")) {\n+\t\t\trevs->ignore_merges = 1;\n+\t\t} else {\n+\t\t\tdie(_(\"unknown value for --diff-merges: %s\"), optarg);\n+\t\t}\n+\t} else\n+\t\treturn 0;\n+\n+\treturn 1;\n+}\n+\n+void setup_diff_merges_revs(struct rev_info *revs)\n+{\n+\tif (revs->combine_merges && revs->ignore_merges < 0)\n+\t\trevs->ignore_merges = 0;\n+\tif (revs->ignore_merges < 0)\n+\t\trevs->ignore_merges = 1;\n+\tif (revs->combined_all_paths && !revs->combine_merges)\n+\t\tdie(\"--combined-all-paths makes no sense without -c or --cc\");\n+}\n+\n+void rev_diff_merges_first_parent_defaults_to_enable(struct rev_info *revs) {\n+\tif (revs->first_parent_only && revs->ignore_merges < 0)\n+\t\trevs->ignore_merges = 0;\n+}\n+\n+void rev_diff_merges_default_to_dense_combined(struct rev_info *revs) {\n+\tif (revs->ignore_merges < 0) {\n+\t\t/* There was no \"-m\" variant on the command line */\n+\t\trevs->ignore_merges = 0;\n+\t\tif (!revs->first_parent_only && !revs->combine_merges) {\n+\t\t\t/* No \"--first-parent\", \"-c\", or \"--cc\" */\n+\t\t\trevs->combine_merges = 1;\n+\t\t\trevs->dense_combined_merges = 1;\n+\t\t}\n+\t}\n+}\ndiff --git a/diff-merges.h b/diff-merges.h\nnew file mode 100644\nindex 000000000000..e0cca3d935d3\n--- /dev/null\n+++ b/diff-merges.h\n@@ -0,0 +1,12 @@\n+#ifndef DIFF_MERGES_H\n+#define DIFF_MERGES_H\n+\n+struct rev_info;\n+\n+void init_diff_merge_revs(struct rev_info *revs);\n+int parse_diff_merge_opts(struct rev_info *revs, const char **argv);\n+void setup_diff_merges_revs(struct rev_info *revs);\n+void rev_diff_merges_default_to_dense_combined(struct rev_info *revs);\n+void rev_diff_merges_first_parent_defaults_to_enable(struct rev_info *revs);\n+\n+#endif\ndiff --git a/revision.c b/revision.c\nindex ce90c2991657..4bc14a08a624 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -5,6 +5,7 @@\n #include \"tree.h\"\n #include \"commit.h\"\n #include \"diff.h\"\n+#include \"diff-merges.h\"\n #include \"refs.h\"\n #include \"revision.h\"\n #include \"repository.h\"\n@@ -1805,8 +1806,6 @@ static int add_parents_only(struct rev_info *revs, const char *arg_, int flags,\n \treturn 1;\n }\n \n-static void init_diff_merge_revs(struct rev_info *revs);\n-\n void repo_init_revisions(struct repository *r,\n \t\t\t struct rev_info *revs,\n \t\t\t const char *prefix)\n@@ -2155,75 +2154,6 @@ static void add_message_grep(struct rev_info *revs, const char *pattern)\n \tadd_grep(revs, pattern, GREP_PATTERN_BODY);\n }\n \n-static void init_diff_merge_revs(struct rev_info *revs) {\n-\trevs->ignore_merges = -1;\n-}\n-\n-static int parse_diff_merge_opts(struct rev_info *revs, const char **argv) {\n-\tint argcount;\n-\tconst char *optarg;\n-\tconst char *arg = argv[0];\n-\n-\tif (!strcmp(arg, \"-m\")) {\n-\t\t/*\n-\t\t * To \"diff-index\", \"-m\" means \"match missing\", and to the \"log\"\n-\t\t * family of commands, it means \"show full diff for merges\". Set\n-\t\t * both fields appropriately.\n-\t\t */\n-\t\trevs->ignore_merges = 0;\n-\t\trevs->match_missing = 1;\n-\t} else if (!strcmp(arg, \"-c\")) {\n-\t\trevs->diff = 1;\n-\t\trevs->dense_combined_merges = 0;\n-\t\trevs->combine_merges = 1;\n-\t} else if (!strcmp(arg, \"--cc\")) {\n-\t\trevs->diff = 1;\n-\t\trevs->dense_combined_merges = 1;\n-\t\trevs->combine_merges = 1;\n-\t} else if (!strcmp(arg, \"--no-diff-merges\")) {\n-\t\trevs->ignore_merges = 1;\n-\t} else if (!strcmp(arg, \"--combined-all-paths\")) {\n-\t\trevs->diff = 1;\n-\t\trevs->combined_all_paths = 1;\n-\t} else if ((argcount = parse_long_opt(\"diff-merges\", argv, &optarg))) {\n-\t\tif (!strcmp(optarg, \"off\")) {\n-\t\t\trevs->ignore_merges = 1;\n-\t\t} else {\n-\t\t\tdie(_(\"unknown value for --diff-merges: %s\"), optarg);\n-\t\t}\n-\t} else\n-\t\treturn 0;\n-\n-\treturn 1;\n-}\n-\n-static void setup_diff_merges_revs(struct rev_info *revs)\n-{\n-\tif (revs->combine_merges && revs->ignore_merges < 0)\n-\t\trevs->ignore_merges = 0;\n-\tif (revs->ignore_merges < 0)\n-\t\trevs->ignore_merges = 1;\n-\tif (revs->combined_all_paths && !revs->combine_merges)\n-\t\tdie(\"--combined-all-paths makes no sense without -c or --cc\");\n-}\n-\n-void rev_diff_merges_first_parent_defaults_to_enable(struct rev_info *revs) {\n-\tif (revs->first_parent_only && revs->ignore_merges < 0)\n-\t\trevs->ignore_merges = 0;\n-}\n-\n-void rev_diff_merges_default_to_dense_combined(struct rev_info *revs) {\n-\tif (revs->ignore_merges < 0) {\n-\t\t/* There was no \"-m\" variant on the command line */\n-\t\trevs->ignore_merges = 0;\n-\t\tif (!revs->first_parent_only && !revs->combine_merges) {\n-\t\t\t/* No \"--first-parent\", \"-c\", or \"--cc\" */\n-\t\t\trevs->combine_merges = 1;\n-\t\t\trevs->dense_combined_merges = 1;\n-\t\t}\n-\t}\n-}\n-\n static int handle_revision_opt(struct rev_info *revs, int argc, const char **argv,\n \t\t\t       int *unkc, const char **unkv,\n \t\t\t       const struct setup_revision_opt* opt)\ndiff --git a/revision.h b/revision.h\nindex 3dd0229f4edc..f6bf860d19e5 100644\n--- a/revision.h\n+++ b/revision.h\n@@ -456,7 +456,4 @@ int rewrite_parents(struct rev_info *revs,\n  */\n struct commit_list *get_saved_parents(struct rev_info *revs, const struct commit *commit);\n \n-void rev_diff_merges_default_to_dense_combined(struct rev_info *revs);\n-void rev_diff_merges_first_parent_defaults_to_enable(struct rev_info *revs);\n-\n #endif\n-- \n2.25.1\n\n"},{"id":"409344","messageId":"20201108213838.4880-5-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201108213838.4880-1-sorganov@gmail.com","subject":"[PATCH v1 04/27] revision: provide implementation for diff merges tweaks","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-11-08T21:38:15Z","receivedAt":"2020-11-08T21:41:36Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Use these implementations from show_setup_revisions_tweak() and\nlog_setup_revisions_tweak() in builtin/log.c.\n\nThis completes moving of management of diff merges parameters to a\nsingle place, where we can finally observe them simultaneously.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n builtin/log.c | 13 ++-----------\n revision.c    | 17 +++++++++++++++++\n revision.h    |  3 +++\n 3 files changed, 22 insertions(+), 11 deletions(-)\n\ndiff --git a/builtin/log.c b/builtin/log.c\nindex 0a7ed4bef92b..717855a49e90 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -598,15 +598,7 @@ static int show_tree_object(const struct object_id *oid,\n static void show_setup_revisions_tweak(struct rev_info *rev,\n \t\t\t\t       struct setup_revision_opt *opt)\n {\n-\tif (rev->ignore_merges < 0) {\n-\t\t/* There was no \"-m\" variant on the command line */\n-\t\trev->ignore_merges = 0;\n-\t\tif (!rev->first_parent_only && !rev->combine_merges) {\n-\t\t\t/* No \"--first-parent\", \"-c\", or \"--cc\" */\n-\t\t\trev->combine_merges = 1;\n-\t\t\trev->dense_combined_merges = 1;\n-\t\t}\n-\t}\n+\trev_diff_merges_default_to_dense_combined(rev);\n \tif (!rev->diffopt.output_format)\n \t\trev->diffopt.output_format = DIFF_FORMAT_PATCH;\n }\n@@ -731,8 +723,7 @@ static void log_setup_revisions_tweak(struct rev_info *rev,\n \tif (!rev->diffopt.output_format && rev->combine_merges)\n \t\trev->diffopt.output_format = DIFF_FORMAT_PATCH;\n \n-\tif (rev->first_parent_only && rev->ignore_merges < 0)\n-\t\trev->ignore_merges = 0;\n+\trev_diff_merges_first_parent_defaults_to_enable(rev);\n }\n \n int cmd_log(int argc, const char **argv, const char *prefix)\ndiff --git a/revision.c b/revision.c\nindex bc568fb79778..ce90c2991657 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -2207,6 +2207,23 @@ static void setup_diff_merges_revs(struct rev_info *revs)\n \t\tdie(\"--combined-all-paths makes no sense without -c or --cc\");\n }\n \n+void rev_diff_merges_first_parent_defaults_to_enable(struct rev_info *revs) {\n+\tif (revs->first_parent_only && revs->ignore_merges < 0)\n+\t\trevs->ignore_merges = 0;\n+}\n+\n+void rev_diff_merges_default_to_dense_combined(struct rev_info *revs) {\n+\tif (revs->ignore_merges < 0) {\n+\t\t/* There was no \"-m\" variant on the command line */\n+\t\trevs->ignore_merges = 0;\n+\t\tif (!revs->first_parent_only && !revs->combine_merges) {\n+\t\t\t/* No \"--first-parent\", \"-c\", or \"--cc\" */\n+\t\t\trevs->combine_merges = 1;\n+\t\t\trevs->dense_combined_merges = 1;\n+\t\t}\n+\t}\n+}\n+\n static int handle_revision_opt(struct rev_info *revs, int argc, const char **argv,\n \t\t\t       int *unkc, const char **unkv,\n \t\t\t       const struct setup_revision_opt* opt)\ndiff --git a/revision.h b/revision.h\nindex f6bf860d19e5..3dd0229f4edc 100644\n--- a/revision.h\n+++ b/revision.h\n@@ -456,4 +456,7 @@ int rewrite_parents(struct rev_info *revs,\n  */\n struct commit_list *get_saved_parents(struct rev_info *revs, const struct commit *commit);\n \n+void rev_diff_merges_default_to_dense_combined(struct rev_info *revs);\n+void rev_diff_merges_first_parent_defaults_to_enable(struct rev_info *revs);\n+\n #endif\n-- \n2.25.1\n\n"},{"id":"409345","messageId":"20201108213838.4880-8-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201108213838.4880-1-sorganov@gmail.com","subject":"[PATCH v1 07/27] diff-merges: move checks for first_parent_only out of the module","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-11-08T21:38:18Z","receivedAt":"2020-11-08T21:41:36Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"The checks for first_parent_only don't in fact belong to this module,\nas the primary purpose of this flag is history traversal limiting, so\nget it out of this module and rename the\n\ndiff_merges_first_parent_defaults_to_enable()\n\nto\n\ndiff_merges_default_to_enable()\n\nto match new semantics.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n builtin/log.c |  8 ++++++--\n diff-merges.c | 10 ++++------\n diff-merges.h |  2 +-\n 3 files changed, 11 insertions(+), 9 deletions(-)\n\ndiff --git a/builtin/log.c b/builtin/log.c\nindex 77a7bba543ad..a7791c003c91 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -599,7 +599,10 @@ static int show_tree_object(const struct object_id *oid,\n static void show_setup_revisions_tweak(struct rev_info *rev,\n \t\t\t\t       struct setup_revision_opt *opt)\n {\n-\tdiff_merges_default_to_dense_combined(rev);\n+\tif (rev->first_parent_only)\n+\t\tdiff_merges_default_to_enable(rev);\n+\telse\n+\t\tdiff_merges_default_to_dense_combined(rev);\n \tif (!rev->diffopt.output_format)\n \t\trev->diffopt.output_format = DIFF_FORMAT_PATCH;\n }\n@@ -724,7 +727,8 @@ static void log_setup_revisions_tweak(struct rev_info *rev,\n \tif (!rev->diffopt.output_format && rev->combine_merges)\n \t\trev->diffopt.output_format = DIFF_FORMAT_PATCH;\n \n-\tdiff_merges_first_parent_defaults_to_enable(rev);\n+\tif (rev->first_parent_only)\n+\t\tdiff_merges_default_to_enable(rev);\n }\n \n int cmd_log(int argc, const char **argv, const char *prefix)\ndiff --git a/diff-merges.c b/diff-merges.c\nindex 85bf0b6d1d1d..9dd472803d15 100644\n--- a/diff-merges.c\n+++ b/diff-merges.c\n@@ -54,17 +54,15 @@ void diff_merges_setup_revs(struct rev_info *revs)\n \t\tdie(\"--combined-all-paths makes no sense without -c or --cc\");\n }\n \n-void diff_merges_first_parent_defaults_to_enable(struct rev_info *revs) {\n-\tif (revs->first_parent_only && revs->ignore_merges < 0)\n+void diff_merges_default_to_enable(struct rev_info *revs) {\n+\tif (revs->ignore_merges < 0)\t\t/* No -m */\n \t\trevs->ignore_merges = 0;\n }\n \n void diff_merges_default_to_dense_combined(struct rev_info *revs) {\n-\tif (revs->ignore_merges < 0) {\n-\t\t/* There was no \"-m\" variant on the command line */\n+\tif (revs->ignore_merges < 0) {\t\t/* No -m */\n \t\trevs->ignore_merges = 0;\n-\t\tif (!revs->first_parent_only && !revs->combine_merges) {\n-\t\t\t/* No \"--first-parent\", \"-c\", or \"--cc\" */\n+\t\tif (!revs->combine_merges) {\t/* No -c/--cc\" */\n \t\t\trevs->combine_merges = 1;\n \t\t\trevs->dense_combined_merges = 1;\n \t\t}\ndiff --git a/diff-merges.h b/diff-merges.h\nindex 648c410497cb..cf411414898d 100644\n--- a/diff-merges.h\n+++ b/diff-merges.h\n@@ -11,7 +11,7 @@ void diff_merges_setup_revs(struct rev_info *revs);\n \n void diff_merges_default_to_dense_combined(struct rev_info *revs);\n \n-void diff_merges_first_parent_defaults_to_enable(struct rev_info *revs);\n+void diff_merges_default_to_enable(struct rev_info *revs);\n \n \n #endif\n-- \n2.25.1\n\n"},{"id":"409347","messageId":"20201108213838.4880-10-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201108213838.4880-1-sorganov@gmail.com","subject":"[PATCH v1 09/27] diff-merges: re-arrange functions to match the order they are called in","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-11-08T21:38:20Z","receivedAt":"2020-11-08T21:41:37Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"For clarity, define public functions in the order they are called, to\nmake logic inter-dependencies easier to grok.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n diff-merges.c | 24 ++++++++++++++----------\n diff-merges.h |  7 +++----\n 2 files changed, 17 insertions(+), 14 deletions(-)\n\ndiff --git a/diff-merges.c b/diff-merges.c\nindex bb08a92e3b36..8536941e0b56 100644\n--- a/diff-merges.c\n+++ b/diff-merges.c\n@@ -2,6 +2,10 @@\n \n #include \"revision.h\"\n \n+/*\n+ * Public functions. They are in the order they are called.\n+ */\n+\n void diff_merges_init_revs(struct rev_info *revs) {\n \trevs->ignore_merges = -1;\n }\n@@ -44,16 +48,6 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {\n \treturn 1;\n }\n \n-void diff_merges_setup_revs(struct rev_info *revs)\n-{\n-\tif (revs->combine_merges && revs->ignore_merges < 0)\n-\t\trevs->ignore_merges = 0;\n-\tif (revs->ignore_merges < 0)\n-\t\trevs->ignore_merges = 1;\n-\tif (revs->combined_all_paths && !revs->combine_merges)\n-\t\tdie(\"--combined-all-paths makes no sense without -c or --cc\");\n-}\n-\n void diff_merges_default_to_first_parent(struct rev_info *revs) {\n \tif (revs->ignore_merges < 0)\t\t/* No -m */\n \t\trevs->ignore_merges = 0;\n@@ -68,3 +62,13 @@ void diff_merges_default_to_dense_combined(struct rev_info *revs) {\n \t\t}\n \t}\n }\n+\n+void diff_merges_setup_revs(struct rev_info *revs)\n+{\n+\tif (revs->combine_merges && revs->ignore_merges < 0)\n+\t\trevs->ignore_merges = 0;\n+\tif (revs->ignore_merges < 0)\n+\t\trevs->ignore_merges = 1;\n+\tif (revs->combined_all_paths && !revs->combine_merges)\n+\t\tdie(\"--combined-all-paths makes no sense without -c or --cc\");\n+}\ndiff --git a/diff-merges.h b/diff-merges.h\nindex 20b727bd734f..4b023c385d00 100644\n--- a/diff-merges.h\n+++ b/diff-merges.h\n@@ -7,11 +7,10 @@ void diff_merges_init_revs(struct rev_info *revs);\n \n int diff_merges_parse_opts(struct rev_info *revs, const char **argv);\n \n-void diff_merges_setup_revs(struct rev_info *revs);\n-\n-void diff_merges_default_to_dense_combined(struct rev_info *revs);\n-\n void diff_merges_default_to_first_parent(struct rev_info *revs);\n \n+void diff_merges_default_to_dense_combined(struct rev_info *revs);\n+\n+void diff_merges_setup_revs(struct rev_info *revs);\n \n #endif\n-- \n2.25.1\n\n"},{"id":"409349","messageId":"20201108213838.4880-11-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201108213838.4880-1-sorganov@gmail.com","subject":"[PATCH v1 10/27] diff-merges: new function diff_merges_suppress()","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-11-08T21:38:21Z","receivedAt":"2020-11-08T21:41:37Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"This function sets all the relevant flags to disabled state, so that\nno code that checks only one of them get it wrong.\n\nThen we call this new function everywhere where diff merges output\nsuppression is needed.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n builtin/merge.c |  3 ++-\n diff-merges.c   | 18 ++++++++++++++----\n diff-merges.h   |  2 ++\n fmt-merge-msg.c |  3 ++-\n 4 files changed, 20 insertions(+), 6 deletions(-)\n\ndiff --git a/builtin/merge.c b/builtin/merge.c\nindex 9d5359edc2f7..1f7b69982b40 100644\n--- a/builtin/merge.c\n+++ b/builtin/merge.c\n@@ -14,6 +14,7 @@\n #include \"lockfile.h\"\n #include \"run-command.h\"\n #include \"diff.h\"\n+#include \"diff-merges.h\"\n #include \"refs.h\"\n #include \"refspec.h\"\n #include \"commit.h\"\n@@ -400,7 +401,7 @@ static void squash_message(struct commit *commit, struct commit_list *remotehead\n \tprintf(_(\"Squash commit -- not updating HEAD\\n\"));\n \n \trepo_init_revisions(the_repository, &rev, NULL);\n-\trev.ignore_merges = 1;\n+\tdiff_merges_suppress(&rev);\n \trev.commit_format = CMIT_FMT_MEDIUM;\n \n \tcommit->object.flags |= UNINTERESTING;\ndiff --git a/diff-merges.c b/diff-merges.c\nindex 8536941e0b56..25bd9b12e667 100644\n--- a/diff-merges.c\n+++ b/diff-merges.c\n@@ -2,6 +2,13 @@\n \n #include \"revision.h\"\n \n+static void suppress(struct rev_info *revs) {\n+\trevs->ignore_merges = 1;\n+\trevs->first_parent_merges = 0;\n+\trevs->combine_merges = 0;\n+\trevs->dense_combined_merges = 0;\n+}\n+\n /*\n  * Public functions. They are in the order they are called.\n  */\n@@ -29,16 +36,15 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {\n \t\trevs->combine_merges = 1;\n \t} else if (!strcmp(arg, \"--cc\")) {\n \t\trevs->diff = 1;\n-\t\trevs->dense_combined_merges = 1;\n-\t\trevs->combine_merges = 1;\n+\t\tset_dense_combined(revs);\n \t} else if (!strcmp(arg, \"--no-diff-merges\")) {\n-\t\trevs->ignore_merges = 1;\n+\t\tsuppress(revs);\n \t} else if (!strcmp(arg, \"--combined-all-paths\")) {\n \t\trevs->diff = 1;\n \t\trevs->combined_all_paths = 1;\n \t} else if ((argcount = parse_long_opt(\"diff-merges\", argv, &optarg))) {\n \t\tif (!strcmp(optarg, \"off\")) {\n-\t\t\trevs->ignore_merges = 1;\n+\t\t\tsuppress(revs);\n \t\t} else {\n \t\t\tdie(_(\"unknown value for --diff-merges: %s\"), optarg);\n \t\t}\n@@ -48,6 +54,10 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {\n \treturn 1;\n }\n \n+void diff_merges_suppress(struct rev_info *revs) {\n+\tsuppress(revs);\n+}\n+\n void diff_merges_default_to_first_parent(struct rev_info *revs) {\n \tif (revs->ignore_merges < 0)\t\t/* No -m */\n \t\trevs->ignore_merges = 0;\ndiff --git a/diff-merges.h b/diff-merges.h\nindex 4b023c385d00..32720bc9b40f 100644\n--- a/diff-merges.h\n+++ b/diff-merges.h\n@@ -7,6 +7,8 @@ void diff_merges_init_revs(struct rev_info *revs);\n \n int diff_merges_parse_opts(struct rev_info *revs, const char **argv);\n \n+void diff_merges_suppress(struct rev_info *revs);\n+\n void diff_merges_default_to_first_parent(struct rev_info *revs);\n \n void diff_merges_default_to_dense_combined(struct rev_info *revs);\ndiff --git a/fmt-merge-msg.c b/fmt-merge-msg.c\nindex bd22e1ea8865..abc3403fb820 100644\n--- a/fmt-merge-msg.c\n+++ b/fmt-merge-msg.c\n@@ -2,6 +2,7 @@\n #include \"refs.h\"\n #include \"object-store.h\"\n #include \"diff.h\"\n+#include \"diff-merges.h\"\n #include \"revision.h\"\n #include \"tag.h\"\n #include \"string-list.h\"\n@@ -668,7 +669,7 @@ int fmt_merge_msg(struct strbuf *in, struct strbuf *out,\n \t\thead = lookup_commit_or_die(&head_oid, \"HEAD\");\n \t\trepo_init_revisions(the_repository, &rev, NULL);\n \t\trev.commit_format = CMIT_FMT_ONELINE;\n-\t\trev.ignore_merges = 1;\n+\t\tdiff_merges_suppress(&rev);\n \t\trev.limited = 1;\n \n \t\tstrbuf_complete_line(out);\n-- \n2.25.1\n\n"},{"id":"409353","messageId":"20201108213838.4880-9-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201108213838.4880-1-sorganov@gmail.com","subject":"[PATCH v1 08/27] diff-merges: rename diff_merges_default_to_enable() to match semantics","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-11-08T21:38:19Z","receivedAt":"2020-11-08T21:41:37Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Rename diff_merges_default_to_enable() to\ndiff_merges_default_to_first_parent() to match its semantics.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n builtin/log.c | 4 ++--\n diff-merges.c | 2 +-\n diff-merges.h | 2 +-\n 3 files changed, 4 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/log.c b/builtin/log.c\nindex a7791c003c91..63875c3aeec9 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -600,7 +600,7 @@ static void show_setup_revisions_tweak(struct rev_info *rev,\n \t\t\t\t       struct setup_revision_opt *opt)\n {\n \tif (rev->first_parent_only)\n-\t\tdiff_merges_default_to_enable(rev);\n+\t\tdiff_merges_default_to_first_parent(rev);\n \telse\n \t\tdiff_merges_default_to_dense_combined(rev);\n \tif (!rev->diffopt.output_format)\n@@ -728,7 +728,7 @@ static void log_setup_revisions_tweak(struct rev_info *rev,\n \t\trev->diffopt.output_format = DIFF_FORMAT_PATCH;\n \n \tif (rev->first_parent_only)\n-\t\tdiff_merges_default_to_enable(rev);\n+\t\tdiff_merges_default_to_first_parent(rev);\n }\n \n int cmd_log(int argc, const char **argv, const char *prefix)\ndiff --git a/diff-merges.c b/diff-merges.c\nindex 9dd472803d15..bb08a92e3b36 100644\n--- a/diff-merges.c\n+++ b/diff-merges.c\n@@ -54,7 +54,7 @@ void diff_merges_setup_revs(struct rev_info *revs)\n \t\tdie(\"--combined-all-paths makes no sense without -c or --cc\");\n }\n \n-void diff_merges_default_to_enable(struct rev_info *revs) {\n+void diff_merges_default_to_first_parent(struct rev_info *revs) {\n \tif (revs->ignore_merges < 0)\t\t/* No -m */\n \t\trevs->ignore_merges = 0;\n }\ndiff --git a/diff-merges.h b/diff-merges.h\nindex cf411414898d..20b727bd734f 100644\n--- a/diff-merges.h\n+++ b/diff-merges.h\n@@ -11,7 +11,7 @@ void diff_merges_setup_revs(struct rev_info *revs);\n \n void diff_merges_default_to_dense_combined(struct rev_info *revs);\n \n-void diff_merges_default_to_enable(struct rev_info *revs);\n+void diff_merges_default_to_first_parent(struct rev_info *revs);\n \n \n #endif\n-- \n2.25.1\n\n"},{"id":"409346","messageId":"20201108213838.4880-12-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201108213838.4880-1-sorganov@gmail.com","subject":"[PATCH v1 11/27] diff-merges: new function diff_merges_set_dense_combined_if_unset()","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-11-08T21:38:22Z","receivedAt":"2020-11-08T21:41:38Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Call it where given functionality is needed instead of direct\nchecking/tweaking of diff merges related fields.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n builtin/diff-files.c |  5 +++--\n builtin/diff.c       |  9 +++++----\n diff-merges.c        | 11 +++++++++++\n diff-merges.h        |  2 ++\n 4 files changed, 21 insertions(+), 6 deletions(-)\n\ndiff --git a/builtin/diff-files.c b/builtin/diff-files.c\nindex 1e352dd8f77c..4742a4559b21 100644\n--- a/builtin/diff-files.c\n+++ b/builtin/diff-files.c\n@@ -7,6 +7,7 @@\n #include \"cache.h\"\n #include \"config.h\"\n #include \"diff.h\"\n+#include \"diff-merges.h\"\n #include \"commit.h\"\n #include \"revision.h\"\n #include \"builtin.h\"\n@@ -69,9 +70,9 @@ int cmd_diff_files(int argc, const char **argv, const char *prefix)\n \t * was not asked to.  \"diff-files -c -p\" should not densify\n \t * (the user should ask with \"diff-files --cc\" explicitly).\n \t */\n-\tif (rev.max_count == -1 && !rev.combine_merges &&\n+\tif (rev.max_count == -1 &&\n \t    (rev.diffopt.output_format & DIFF_FORMAT_PATCH))\n-\t\trev.combine_merges = rev.dense_combined_merges = 1;\n+\t\tdiff_merges_set_dense_combined_if_unset(&rev);\n \n \tif (read_cache_preload(&rev.diffopt.pathspec) < 0) {\n \t\tperror(\"read_cache_preload\");\ndiff --git a/builtin/diff.c b/builtin/diff.c\nindex cd4083fed96e..2f570a3131cb 100644\n--- a/builtin/diff.c\n+++ b/builtin/diff.c\n@@ -13,6 +13,7 @@\n #include \"blob.h\"\n #include \"tag.h\"\n #include \"diff.h\"\n+#include \"diff-merges.h\"\n #include \"diffcore.h\"\n #include \"revision.h\"\n #include \"log-tree.h\"\n@@ -199,8 +200,8 @@ static int builtin_diff_combined(struct rev_info *revs,\n \tif (argc > 1)\n \t\tusage(builtin_diff_usage);\n \n-\tif (!revs->dense_combined_merges && !revs->combine_merges)\n-\t\trevs->dense_combined_merges = revs->combine_merges = 1;\n+\tdiff_merges_set_dense_combined_if_unset(revs);\n+\n \tfor (i = 1; i < ents; i++)\n \t\toid_array_append(&parents, &ent[i].item->oid);\n \tdiff_tree_combined(&ent[0].item->oid, &parents, revs);\n@@ -248,9 +249,9 @@ static int builtin_diff_files(struct rev_info *revs, int argc, const char **argv\n \t * dense one, --cc can be explicitly asked for, or just rely\n \t * on the default).\n \t */\n-\tif (revs->max_count == -1 && !revs->combine_merges &&\n+\tif (revs->max_count == -1 &&\n \t    (revs->diffopt.output_format & DIFF_FORMAT_PATCH))\n-\t\trevs->combine_merges = revs->dense_combined_merges = 1;\n+\t\tdiff_merges_set_dense_combined_if_unset(revs);\n \n \tsetup_work_tree();\n \tif (read_cache_preload(&revs->diffopt.pathspec) < 0) {\ndiff --git a/diff-merges.c b/diff-merges.c\nindex 25bd9b12e667..691aabadbb32 100644\n--- a/diff-merges.c\n+++ b/diff-merges.c\n@@ -9,6 +9,12 @@ static void suppress(struct rev_info *revs) {\n \trevs->dense_combined_merges = 0;\n }\n \n+static void set_dense_combined(struct rev_info *revs) {\n+\trevs->combine_merges = 1;\n+\trevs->dense_combined_merges = 1;\n+}\n+\n+\n /*\n  * Public functions. They are in the order they are called.\n  */\n@@ -73,6 +79,11 @@ void diff_merges_default_to_dense_combined(struct rev_info *revs) {\n \t}\n }\n \n+void diff_merges_set_dense_combined_if_unset(struct rev_info *revs) {\n+\tif (!revs->combine_merges)\n+\t\tset_dense_combined(revs);\n+}\n+\n void diff_merges_setup_revs(struct rev_info *revs)\n {\n \tif (revs->combine_merges && revs->ignore_merges < 0)\ndiff --git a/diff-merges.h b/diff-merges.h\nindex 32720bc9b40f..ae1cc8ef9410 100644\n--- a/diff-merges.h\n+++ b/diff-merges.h\n@@ -13,6 +13,8 @@ void diff_merges_default_to_first_parent(struct rev_info *revs);\n \n void diff_merges_default_to_dense_combined(struct rev_info *revs);\n \n+void diff_merges_set_dense_combined_if_unset(struct rev_info *revs);\n+\n void diff_merges_setup_revs(struct rev_info *revs);\n \n #endif\n-- \n2.25.1\n\n"},{"id":"409348","messageId":"20201108213838.4880-13-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201108213838.4880-1-sorganov@gmail.com","subject":"[PATCH v1 12/27] diff-merges: introduce revs->first_parent_merges flag","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-11-08T21:38:23Z","receivedAt":"2020-11-08T21:41:42Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"This new field allows us to separate format of diff for merges from\n'first_parent_only' flag which primary purpose is limiting history\ntraversal.\n\nThis change further localizes diff format selection logic into the\ndiff-merges.c file.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n diff-merges.c | 2 ++\n log-tree.c    | 4 ++--\n revision.h    | 1 +\n 3 files changed, 5 insertions(+), 2 deletions(-)\n\ndiff --git a/diff-merges.c b/diff-merges.c\nindex 691aabadbb32..63912ddedc76 100644\n--- a/diff-merges.c\n+++ b/diff-merges.c\n@@ -67,6 +67,8 @@ void diff_merges_suppress(struct rev_info *revs) {\n void diff_merges_default_to_first_parent(struct rev_info *revs) {\n \tif (revs->ignore_merges < 0)\t\t/* No -m */\n \t\trevs->ignore_merges = 0;\n+\tif (!revs->combine_merges)\t\t/* No -c/--cc\" */\n+\t\trevs->first_parent_merges = 1;\n }\n \n void diff_merges_default_to_dense_combined(struct rev_info *revs) {\ndiff --git a/log-tree.c b/log-tree.c\nindex 1927f917ce94..3fdc0fc64bfb 100644\n--- a/log-tree.c\n+++ b/log-tree.c\n@@ -922,7 +922,7 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log\n \t\t\treturn 0;\n \t\telse if (opt->combine_merges)\n \t\t\treturn do_diff_combined(opt, commit);\n-\t\telse if (!opt->first_parent_only) {\n+\t\telse if (!opt->first_parent_merges) {\n \t\t\t/* If we show multiple diffs, show the parent info */\n \t\t\tlog->parent = parents->item;\n \t\t}\n@@ -941,7 +941,7 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log\n \n \t\t/* Set up the log info for the next parent, if any.. */\n \t\tparents = parents->next;\n-\t\tif (!parents || opt->first_parent_only)\n+\t\tif (!parents || opt->first_parent_merges)\n \t\t\tbreak;\n \t\tlog->parent = parents->item;\n \t\topt->loginfo = log;\ndiff --git a/revision.h b/revision.h\nindex f6bf860d19e5..ba2aef79215e 100644\n--- a/revision.h\n+++ b/revision.h\n@@ -194,6 +194,7 @@ struct rev_info {\n \t\t\tcombine_merges:1,\n \t\t\tcombined_all_paths:1,\n \t\t\tdense_combined_merges:1,\n+\t\t\tfirst_parent_merges:1,\n \t\t\talways_show_header:1;\n \tint             ignore_merges:2;\n \n-- \n2.25.1\n\n"},{"id":"409351","messageId":"20201108213838.4880-14-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201108213838.4880-1-sorganov@gmail.com","subject":"[PATCH v1 13/27] diff-merges: revise revs->diff flag handling","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-11-08T21:38:24Z","receivedAt":"2020-11-08T21:41:42Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Do not set revs->diff when we encounter an option that needs it, as\nit'd be impossible to undo later. Besides, some other options than\nwhat we handle here set this flag as well, and we'd interfere with\nthem trying to clear this flag later.\n\nRather set revs->diff, if finally needed, in diff_merges_setup_revs().\n\nAs an additional bonus, this also makes our code shorter.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n diff-merges.c | 5 ++---\n 1 file changed, 2 insertions(+), 3 deletions(-)\n\ndiff --git a/diff-merges.c b/diff-merges.c\nindex 63912ddedc76..a30c730a457f 100644\n--- a/diff-merges.c\n+++ b/diff-merges.c\n@@ -37,16 +37,13 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {\n \t\trevs->ignore_merges = 0;\n \t\trevs->match_missing = 1;\n \t} else if (!strcmp(arg, \"-c\")) {\n-\t\trevs->diff = 1;\n \t\trevs->dense_combined_merges = 0;\n \t\trevs->combine_merges = 1;\n \t} else if (!strcmp(arg, \"--cc\")) {\n-\t\trevs->diff = 1;\n \t\tset_dense_combined(revs);\n \t} else if (!strcmp(arg, \"--no-diff-merges\")) {\n \t\tsuppress(revs);\n \t} else if (!strcmp(arg, \"--combined-all-paths\")) {\n-\t\trevs->diff = 1;\n \t\trevs->combined_all_paths = 1;\n \t} else if ((argcount = parse_long_opt(\"diff-merges\", argv, &optarg))) {\n \t\tif (!strcmp(optarg, \"off\")) {\n@@ -94,4 +91,6 @@ void diff_merges_setup_revs(struct rev_info *revs)\n \t\trevs->ignore_merges = 1;\n \tif (revs->combined_all_paths && !revs->combine_merges)\n \t\tdie(\"--combined-all-paths makes no sense without -c or --cc\");\n+\tif (revs->combine_merges)\n+\t\trevs->diff = 1;\n }\n-- \n2.25.1\n\n"},{"id":"409352","messageId":"20201108213838.4880-20-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201108213838.4880-1-sorganov@gmail.com","subject":"[PATCH v1 19/27] diff-merges: get rid of now empty diff_merges_init_revs()","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-11-08T21:38:30Z","receivedAt":"2020-11-08T21:41:44Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"After getting rid of 'ignore_merges' field, the diff_merges_init_revs()\nfunction became empty. Get rid of it.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n diff-merges.c | 3 ---\n diff-merges.h | 2 --\n revision.c    | 1 -\n 3 files changed, 6 deletions(-)\n\ndiff --git a/diff-merges.c b/diff-merges.c\nindex 19cdad1aa4a1..29818abcc00e 100644\n--- a/diff-merges.c\n+++ b/diff-merges.c\n@@ -19,9 +19,6 @@ static void set_dense_combined(struct rev_info *revs) {\n  * Public functions. They are in the order they are called.\n  */\n \n-void diff_merges_init_revs(struct rev_info *revs) {\n-}\n-\n int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {\n \tint argcount;\n \tconst char *optarg;\ndiff --git a/diff-merges.h b/diff-merges.h\nindex ae1cc8ef9410..9c69b8f3bd69 100644\n--- a/diff-merges.h\n+++ b/diff-merges.h\n@@ -3,8 +3,6 @@\n \n struct rev_info;\n \n-void diff_merges_init_revs(struct rev_info *revs);\n-\n int diff_merges_parse_opts(struct rev_info *revs, const char **argv);\n \n void diff_merges_suppress(struct rev_info *revs);\ndiff --git a/revision.c b/revision.c\nindex 5a0e3d6ad542..46645ca0b6df 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -1814,7 +1814,6 @@ void repo_init_revisions(struct repository *r,\n \n \trevs->repo = r;\n \trevs->abbrev = DEFAULT_ABBREV;\n-\tdiff_merges_init_revs(revs);\n \trevs->simplify_history = 1;\n \trevs->pruning.repo = r;\n \trevs->pruning.flags.recursive = 1;\n-- \n2.25.1\n\n"},{"id":"409350","messageId":"20201108213838.4880-22-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201108213838.4880-1-sorganov@gmail.com","subject":"[PATCH v1 21/27] diff-merges: make -m/-c/--cc explicitly mutually exclusive","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-11-08T21:38:32Z","receivedAt":"2020-11-08T21:41:45Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"-c/--cc got precedence over -m only because of external logic where\ncorresponding flags are checked before that for -m. This is too\nerror-prone, so add code that explicitly makes these 3 options\nmutually exclusive, so that the last option specified on the\ncommand-line gets precedence.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n diff-merges.c | 3 +++\n 1 file changed, 3 insertions(+)\n\ndiff --git a/diff-merges.c b/diff-merges.c\nindex 8c22b447f106..db2217171442 100644\n--- a/diff-merges.c\n+++ b/diff-merges.c\n@@ -7,6 +7,7 @@ static void suppress(struct rev_info *revs) {\n \trevs->first_parent_merges = 0;\n \trevs->combine_merges = 0;\n \trevs->dense_combined_merges = 0;\n+\trevs->combined_all_paths = 0;\n }\n \n static void set_separate(struct rev_info *revs) {\n@@ -25,11 +26,13 @@ static void set_m(struct rev_info *revs) {\n }\n \n static void set_combined(struct rev_info *revs) {\n+\tsuppress(revs);\n \trevs->combine_merges = 1;\n \trevs->dense_combined_merges = 0;\n }\n \n static void set_dense_combined(struct rev_info *revs) {\n+\tsuppress(revs);\n \trevs->combine_merges = 1;\n \trevs->dense_combined_merges = 1;\n }\n-- \n2.25.1\n\n"},{"id":"409355","messageId":"20201108213838.4880-21-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201108213838.4880-1-sorganov@gmail.com","subject":"[PATCH v1 20/27] diff-merges: refactor opt settings into separate functions","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-11-08T21:38:31Z","receivedAt":"2020-11-08T21:41:46Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"To prepare introduction of new options some of which will be synonyms\nto existing options, let every option handling code just call\ncorresponding function.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n diff-merges.c | 59 ++++++++++++++++++++++++++++++++-------------------\n 1 file changed, 37 insertions(+), 22 deletions(-)\n\ndiff --git a/diff-merges.c b/diff-merges.c\nindex 29818abcc00e..8c22b447f106 100644\n--- a/diff-merges.c\n+++ b/diff-merges.c\n@@ -9,11 +9,38 @@ static void suppress(struct rev_info *revs) {\n \trevs->dense_combined_merges = 0;\n }\n \n+static void set_separate(struct rev_info *revs) {\n+\tsuppress(revs);\n+\trevs->separate_merges = 1;\n+}\n+\n+static void set_m(struct rev_info *revs) {\n+\t/*\n+\t * To \"diff-index\", \"-m\" means \"match missing\", and to the \"log\"\n+\t * family of commands, it means \"show full diff for merges\". Set\n+\t * both fields appropriately.\n+\t */\n+\tset_separate(revs);\n+\trevs->match_missing = 1;\n+}\n+\n+static void set_combined(struct rev_info *revs) {\n+\trevs->combine_merges = 1;\n+\trevs->dense_combined_merges = 0;\n+}\n+\n static void set_dense_combined(struct rev_info *revs) {\n \trevs->combine_merges = 1;\n \trevs->dense_combined_merges = 1;\n }\n \n+static void set_diff_merges(struct rev_info *revs, const char *optarg) {\n+\tif (!strcmp(optarg, \"off\")) {\n+\t\tsuppress(revs);\n+\t} else {\n+\t\tdie(_(\"unknown value for --diff-merges: %s\"), optarg);\n+\t}\n+}\n \n /*\n  * Public functions. They are in the order they are called.\n@@ -24,31 +51,19 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {\n \tconst char *optarg;\n \tconst char *arg = argv[0];\n \n-\tif (!strcmp(arg, \"-m\")) {\n-\t\tsuppress(revs);\n-\t\t/*\n-\t\t * To \"diff-index\", \"-m\" means \"match missing\", and to the \"log\"\n-\t\t * family of commands, it means \"show full diff for merges\". Set\n-\t\t * both fields appropriately.\n-\t\t */\n-\t\trevs->separate_merges = 1;\n-\t\trevs->match_missing = 1;\n-\t} else if (!strcmp(arg, \"-c\")) {\n-\t\trevs->dense_combined_merges = 0;\n-\t\trevs->combine_merges = 1;\n-\t} else if (!strcmp(arg, \"--cc\")) {\n+\tif (!strcmp(arg, \"-m\"))\n+\t\tset_m(revs);\n+\telse if (!strcmp(arg, \"-c\"))\n+\t\tset_combined(revs);\n+\telse if (!strcmp(arg, \"--cc\"))\n \t\tset_dense_combined(revs);\n-\t} else if (!strcmp(arg, \"--no-diff-merges\")) {\n+\telse if (!strcmp(arg, \"--no-diff-merges\"))\n \t\tsuppress(revs);\n-\t} else if (!strcmp(arg, \"--combined-all-paths\")) {\n+\telse if (!strcmp(arg, \"--combined-all-paths\"))\n \t\trevs->combined_all_paths = 1;\n-\t} else if ((argcount = parse_long_opt(\"diff-merges\", argv, &optarg))) {\n-\t\tif (!strcmp(optarg, \"off\")) {\n-\t\t\tsuppress(revs);\n-\t\t} else {\n-\t\t\tdie(_(\"unknown value for --diff-merges: %s\"), optarg);\n-\t\t}\n-\t} else\n+\telse if ((argcount = parse_long_opt(\"diff-merges\", argv, &optarg)))\n+\t\tset_diff_merges(revs, optarg);\n+\telse\n \t\treturn 0;\n \n \trevs->explicit_diff_merges = 1;\n-- \n2.25.1\n\n"},{"id":"409354","messageId":"20201108213838.4880-24-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201108213838.4880-1-sorganov@gmail.com","subject":"[PATCH v1 23/27] t4013: add test for --diff-merges=first-parent","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-11-08T21:38:34Z","receivedAt":"2020-11-08T21:41:47Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"This new option provides essential new functionality, changing diff\noutput to first parent only without changing history traversal mode,\nso it deserves its own test.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n t/t4013-diff-various.sh                       |   1 +\n ...f.log_-p_--diff-merges=first-parent_master | 137 ++++++++++++++++++\n 2 files changed, 138 insertions(+)\n create mode 100644 t/t4013/diff.log_-p_--diff-merges=first-parent_master\n\ndiff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh\nindex 8d8178a8a616..ce56a9349d1c 100755\n--- a/t/t4013-diff-various.sh\n+++ b/t/t4013-diff-various.sh\n@@ -327,6 +327,7 @@ log --no-diff-merges -p --first-parent master\n log --diff-merges=off -p --first-parent master\n log --first-parent --diff-merges=off -p master\n log -p --first-parent master\n+log -p --diff-merges=first-parent master\n log -m -p --first-parent master\n log -m -p master\n log --cc -m -p master\ndiff --git a/t/t4013/diff.log_-p_--diff-merges=first-parent_master b/t/t4013/diff.log_-p_--diff-merges=first-parent_master\nnew file mode 100644\nindex 000000000000..9538a2751123\n--- /dev/null\n+++ b/t/t4013/diff.log_-p_--diff-merges=first-parent_master\n@@ -0,0 +1,137 @@\n+$ git log -p --diff-merges=first-parent master\n+commit 59d314ad6f356dd08601a4cd5e530381da3e3c64\n+Merge: 9a6d494 c7a2ab9\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:04:00 2006 +0000\n+\n+    Merge branch 'side'\n+\n+diff --git a/dir/sub b/dir/sub\n+index cead32e..992913c 100644\n+--- a/dir/sub\n++++ b/dir/sub\n+@@ -4,3 +4,5 @@ C\n+ D\n+ E\n+ F\n++1\n++2\n+diff --git a/file0 b/file0\n+index b414108..10a8a9f 100644\n+--- a/file0\n++++ b/file0\n+@@ -4,3 +4,6 @@\n+ 4\n+ 5\n+ 6\n++A\n++B\n++C\n+\n+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:03:00 2006 +0000\n+\n+    Side\n+\n+diff --git a/dir/sub b/dir/sub\n+index 35d242b..7289e35 100644\n+--- a/dir/sub\n++++ b/dir/sub\n+@@ -1,2 +1,4 @@\n+ A\n+ B\n++1\n++2\n+diff --git a/file0 b/file0\n+index 01e79c3..f4615da 100644\n+--- a/file0\n++++ b/file0\n+@@ -1,3 +1,6 @@\n+ 1\n+ 2\n+ 3\n++A\n++B\n++C\n+diff --git a/file3 b/file3\n+new file mode 100644\n+index 0000000..7289e35\n+--- /dev/null\n++++ b/file3\n+@@ -0,0 +1,4 @@\n++A\n++B\n++1\n++2\n+\n+commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:02:00 2006 +0000\n+\n+    Third\n+\n+diff --git a/dir/sub b/dir/sub\n+index 8422d40..cead32e 100644\n+--- a/dir/sub\n++++ b/dir/sub\n+@@ -2,3 +2,5 @@ A\n+ B\n+ C\n+ D\n++E\n++F\n+diff --git a/file1 b/file1\n+new file mode 100644\n+index 0000000..b1e6722\n+--- /dev/null\n++++ b/file1\n+@@ -0,0 +1,3 @@\n++A\n++B\n++C\n+\n+commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:01:00 2006 +0000\n+\n+    Second\n+    \n+    This is the second commit.\n+\n+diff --git a/dir/sub b/dir/sub\n+index 35d242b..8422d40 100644\n+--- a/dir/sub\n++++ b/dir/sub\n+@@ -1,2 +1,4 @@\n+ A\n+ B\n++C\n++D\n+diff --git a/file0 b/file0\n+index 01e79c3..b414108 100644\n+--- a/file0\n++++ b/file0\n+@@ -1,3 +1,6 @@\n+ 1\n+ 2\n+ 3\n++4\n++5\n++6\n+diff --git a/file2 b/file2\n+deleted file mode 100644\n+index 01e79c3..0000000\n+--- a/file2\n++++ /dev/null\n+@@ -1,3 +0,0 @@\n+-1\n+-2\n+-3\n+\n+commit 444ac553ac7612cc88969031b02b3767fb8a353a\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:00:00 2006 +0000\n+\n+    Initial\n+$\n-- \n2.25.1\n\n"},{"id":"409356","messageId":"20201108213838.4880-25-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201108213838.4880-1-sorganov@gmail.com","subject":"[PATCH v1 24/27] doc/git-log: describe new --diff-merges options","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-11-08T21:38:35Z","receivedAt":"2020-11-08T21:41:48Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Describe all the new --diff-merges options in the git-log.txt\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n Documentation/git-log.txt | 79 +++++++++++++++++++++++----------------\n 1 file changed, 46 insertions(+), 33 deletions(-)\n\ndiff --git a/Documentation/git-log.txt b/Documentation/git-log.txt\nindex 2b8ac5ff882a..de498a189646 100644\n--- a/Documentation/git-log.txt\n+++ b/Documentation/git-log.txt\n@@ -120,45 +120,58 @@ DIFF FORMATTING\n By default, `git log` does not generate any diff output. The options\n below can be used to show the changes made by each commit.\n \n-Note that unless one of `-c`, `--cc`, or `-m` is given, merge commits\n-will never show a diff, even if a diff format like `--patch` is\n-selected, nor will they match search options like `-S`. The exception is\n-when `--first-parent` is in use, in which merges are treated like normal\n-single-parent commits (this can be overridden by providing a\n-combined-diff option or with `--no-diff-merges`).\n+Note that unless one of `--diff-merges` variants (including short\n+`-m`, `-c`, and `--cc` options) is explicitly given, merge commits\n+will not show a diff, even if a diff format like `--patch` is\n+selected, nor will they match search options like `-S`. The exception\n+is when `--first-parent` is in use, in which case\n+`--diff-merges=first-parent` is implied.\n \n--c::\n-\tWith this option, diff output for a merge commit\n-\tshows the differences from each of the parents to the merge result\n-\tsimultaneously instead of showing pairwise diff between a parent\n-\tand the result one at a time. Furthermore, it lists only files\n-\twhich were modified from all parents.\n-\n---cc::\n-\tThis flag implies the `-c` option and further compresses the\n-\tpatch output by omitting uninteresting hunks whose contents in\n-\tthe parents have only two variants and the merge result picks\n-\tone of them without modification.\n+--diff-merges=(off|none|first-parent|separate|combined|dense-combined)::\n+--no-diff-merges::\n+\tSpecify diff format to be used for merge commits. This has no\n+\teffect unless diff output is enabled in the first place (e.g.,\n+\twith `--patch` option.)\n++\n+--diff-merges=(off|none):::\n+--no-diff-merges:::\n+\t(default) Disable output of diffs for merge commits. Useful to\n+\toverride implied value.\n++\n+--diff-merges=first-parent:::\n+\tThis option makes merge commits show the full diff with\n+\trespect to the first parent only, exactly like\tregular\n+\tcommits.\n++\n+--diff-merges=separate:::\n+-m:::\n+\tThis makes merge commits show the full diff with respect to\n+\teach of the parents. Separate log entry and diff is generated\n+\tfor each parent.\n++\n+--diff-merges=combined:::\n+-c:::\n+\tWith this option, diff output for a merge commit shows the\n+\tdifferences from each of the parents to the merge result\n+\tsimultaneously instead of showing pairwise diff between a\n+\tparent and the result one at a time. Furthermore, it lists\n+\tonly files which were modified from all parents.\n++\n+--diff-merges=dense-combined:::\n+--cc:::\n+\tWith this option the output produced by\n+\t`--diff-merges=combined` is further compressed by omitting\n+\tuninteresting hunks whose contents in the parents have only\n+\ttwo variants and the merge result picks one of them without\n+\tmodification.\n \n --combined-all-paths::\n \tThis flag causes combined diffs (used for merge commits) to\n \tlist the name of the file from all parents.  It thus only has\n-\teffect when -c or --cc are specified, and is likely only\n-\tuseful if filename changes are detected (i.e. when either\n-\trename or copy detection have been requested).\n+\teffect when `--diff-merges=[dense-]combined` is in use, and\n+\tis likely only useful if filename changes are detected (i.e.\n+\twhen either rename or copy detection have been requested).\n \n--m::\n-\tThis flag makes the merge commits show the full diff like\n-\tregular commits; for each merge parent, a separate log entry\n-\tand diff is generated. An exception is that only diff against\n-\tthe first parent is shown when `--first-parent` option is given;\n-\tin that case, the output represents the changes the merge\n-\tbrought _into_ the then-current branch.\n-\n---diff-merges=off::\n---no-diff-merges::\n-\tDisable output of diffs for merge commits (default). Useful to\n-\toverride `-m`, `-c`, or `--cc`.\n \n :git-log: 1\n include::diff-options.txt[]\n-- \n2.25.1\n\n"},{"id":"409357","messageId":"20201108213838.4880-23-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201108213838.4880-1-sorganov@gmail.com","subject":"[PATCH v1 22/27] diff-merges: implement new values for --diff-merges","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-11-08T21:38:33Z","receivedAt":"2020-11-08T21:41:49Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"The following values are implemented:\n\n--diff-merges=\t        old equivalent\nfirst|first-parent    = --first-parent (only format implications)\nsep|separate          = -m\ncomb|combined         = -c\ndense| dense-combined = --cc\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n diff-merges.c | 19 ++++++++++++++++---\n 1 file changed, 16 insertions(+), 3 deletions(-)\n\ndiff --git a/diff-merges.c b/diff-merges.c\nindex db2217171442..5c35369f7a8c 100644\n--- a/diff-merges.c\n+++ b/diff-merges.c\n@@ -15,6 +15,11 @@ static void set_separate(struct rev_info *revs) {\n \trevs->separate_merges = 1;\n }\n \n+static void set_first_parent(struct rev_info *revs) {\n+\tset_separate(revs);\n+\trevs->first_parent_merges = 1;\n+}\n+\n static void set_m(struct rev_info *revs) {\n \t/*\n \t * To \"diff-index\", \"-m\" means \"match missing\", and to the \"log\"\n@@ -38,11 +43,19 @@ static void set_dense_combined(struct rev_info *revs) {\n }\n \n static void set_diff_merges(struct rev_info *revs, const char *optarg) {\n-\tif (!strcmp(optarg, \"off\")) {\n+\tif (0) ;\n+\telse if (!strcmp(optarg, \"off\")   || !strcmp(optarg, \"none\"))\n \t\tsuppress(revs);\n-\t} else {\n+\telse if (!strcmp(optarg, \"first\") || !strcmp(optarg, \"first-parent\"))\n+\t\tset_first_parent(revs);\n+\telse if (!strcmp(optarg, \"sep\")   || !strcmp(optarg, \"separate\"))\n+\t\tset_separate(revs);\n+\telse if (!strcmp(optarg, \"comb\")  || !strcmp(optarg, \"combined\"))\n+\t\tset_combined(revs);\n+\telse if (!strcmp(optarg, \"dense\") || !strcmp(optarg, \"dense-combined\"))\n+\t\tset_dense_combined(revs);\n+\telse\n \t\tdie(_(\"unknown value for --diff-merges: %s\"), optarg);\n-\t}\n }\n \n /*\n-- \n2.25.1\n\n"},{"id":"409363","messageId":"20201108213838.4880-27-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201108213838.4880-1-sorganov@gmail.com","subject":"[PATCH v1 26/27] doc/rev-list-options: document --first-parent implies --diff-merges=first-parent","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-11-08T21:38:37Z","receivedAt":"2020-11-08T21:41:50Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Before introduction of new --diff-merges options, --first-parent\nimplicitly changed the default diff format for merge commits to\nshowing only the diff with respect to the first parent, and there were\nno way to get such format from \"git log\" without affecting history\ntraversal logic that --first-parent causes.\n\nNow, after introduction of the --diff-merges=first-parent, the\n--first-parent simply implies the former, and this patch corrects\ndocumentation accordingly.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n Documentation/rev-list-options.txt | 3 +++\n 1 file changed, 3 insertions(+)\n\ndiff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt\nindex 002379056a07..ded383e62ae5 100644\n--- a/Documentation/rev-list-options.txt\n+++ b/Documentation/rev-list-options.txt\n@@ -129,6 +129,9 @@ parents) and `--max-parents=-1` (negative numbers denote no upper limit).\n \tadjusting to updated upstream from time to time, and\n \tthis option allows you to ignore the individual commits\n \tbrought in to your history by such a merge.\n+ifdef::git-log[]\n+\tImplies `--diff-merges=first-parent`.\n+endif::git-log[]\n \n --not::\n \tReverses the meaning of the '{caret}' prefix (or lack thereof)\n-- \n2.25.1\n\n"},{"id":"409358","messageId":"20201108213838.4880-28-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201108213838.4880-1-sorganov@gmail.com","subject":"[PATCH v1 27/27] doc/git-show: include --diff-merges description","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-11-08T21:38:38Z","receivedAt":"2020-11-08T21:41:52Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Move description of --diff-merges option from git-log.txt to\ndiff-options.txt so that it is included in the git-show help.\n\nWhile we are at it, make git-show closer to git-log in this area by\nproviding similar wording in the introduction of diff options.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n Documentation/diff-options.txt | 54 ++++++++++++++++++++++++++++++++++\n Documentation/git-log.txt      | 52 --------------------------------\n Documentation/git-show.txt     |  8 +++--\n 3 files changed, 60 insertions(+), 54 deletions(-)\n\ndiff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt\nindex 573fb9bb71e2..f1629887103e 100644\n--- a/Documentation/diff-options.txt\n+++ b/Documentation/diff-options.txt\n@@ -33,6 +33,60 @@ endif::git-diff[]\n \tshow the patch by default, or to cancel the effect of `--patch`.\n endif::git-format-patch[]\n \n+ifdef::git-log[]\n+Note that unless one of `--diff-merges` variants (including short\n+`-m`, `-c`, and `--cc` options) is explicitly given, merge commits\n+will not show a diff, even if a diff format like `--patch` is\n+selected, nor will they match search options like `-S`. The exception\n+is when `--first-parent` is in use, in which case\n+`--diff-merges=first-parent` is implied.\n+\n+--diff-merges=(off|none|first-parent|separate|combined|dense-combined)::\n+--no-diff-merges::\n+\tSpecify diff format to be used for merge commits. This has no\n+\teffect unless diff output is enabled in the first place (e.g.,\n+\twith `--patch` option.)\n++\n+--diff-merges=(off|none):::\n+--no-diff-merges:::\n+\t(default) Disable output of diffs for merge commits. Useful to\n+\toverride implied value.\n++\n+--diff-merges=first-parent:::\n+\tThis option makes merge commits show the full diff with\n+\trespect to the first parent only, exactly like\tregular\n+\tcommits.\n++\n+--diff-merges=separate:::\n+-m:::\n+\tThis makes merge commits show the full diff with respect to\n+\teach of the parents. Separate log entry and diff is generated\n+\tfor each parent.\n++\n+--diff-merges=combined:::\n+-c:::\n+\tWith this option, diff output for a merge commit shows the\n+\tdifferences from each of the parents to the merge result\n+\tsimultaneously instead of showing pairwise diff between a\n+\tparent and the result one at a time. Furthermore, it lists\n+\tonly files which were modified from all parents.\n++\n+--diff-merges=dense-combined:::\n+--cc:::\n+\tWith this option the output produced by\n+\t`--diff-merges=combined` is further compressed by omitting\n+\tuninteresting hunks whose contents in the parents have only\n+\ttwo variants and the merge result picks one of them without\n+\tmodification.\n+\n+--combined-all-paths::\n+\tThis flag causes combined diffs (used for merge commits) to\n+\tlist the name of the file from all parents.  It thus only has\n+\teffect when `--diff-merges=[dense-]combined` is in use, and\n+\tis likely only useful if filename changes are detected (i.e.\n+\twhen either rename or copy detection have been requested).\n+endif::git-log[]\n+\n -U<n>::\n --unified=<n>::\n \tGenerate diffs with <n> lines of context instead of\ndiff --git a/Documentation/git-log.txt b/Documentation/git-log.txt\nindex de498a189646..0cacc780bf30 100644\n--- a/Documentation/git-log.txt\n+++ b/Documentation/git-log.txt\n@@ -120,58 +120,6 @@ DIFF FORMATTING\n By default, `git log` does not generate any diff output. The options\n below can be used to show the changes made by each commit.\n \n-Note that unless one of `--diff-merges` variants (including short\n-`-m`, `-c`, and `--cc` options) is explicitly given, merge commits\n-will not show a diff, even if a diff format like `--patch` is\n-selected, nor will they match search options like `-S`. The exception\n-is when `--first-parent` is in use, in which case\n-`--diff-merges=first-parent` is implied.\n-\n---diff-merges=(off|none|first-parent|separate|combined|dense-combined)::\n---no-diff-merges::\n-\tSpecify diff format to be used for merge commits. This has no\n-\teffect unless diff output is enabled in the first place (e.g.,\n-\twith `--patch` option.)\n-+\n---diff-merges=(off|none):::\n---no-diff-merges:::\n-\t(default) Disable output of diffs for merge commits. Useful to\n-\toverride implied value.\n-+\n---diff-merges=first-parent:::\n-\tThis option makes merge commits show the full diff with\n-\trespect to the first parent only, exactly like\tregular\n-\tcommits.\n-+\n---diff-merges=separate:::\n--m:::\n-\tThis makes merge commits show the full diff with respect to\n-\teach of the parents. Separate log entry and diff is generated\n-\tfor each parent.\n-+\n---diff-merges=combined:::\n--c:::\n-\tWith this option, diff output for a merge commit shows the\n-\tdifferences from each of the parents to the merge result\n-\tsimultaneously instead of showing pairwise diff between a\n-\tparent and the result one at a time. Furthermore, it lists\n-\tonly files which were modified from all parents.\n-+\n---diff-merges=dense-combined:::\n---cc:::\n-\tWith this option the output produced by\n-\t`--diff-merges=combined` is further compressed by omitting\n-\tuninteresting hunks whose contents in the parents have only\n-\ttwo variants and the merge result picks one of them without\n-\tmodification.\n-\n---combined-all-paths::\n-\tThis flag causes combined diffs (used for merge commits) to\n-\tlist the name of the file from all parents.  It thus only has\n-\teffect when `--diff-merges=[dense-]combined` is in use, and\n-\tis likely only useful if filename changes are detected (i.e.\n-\twhen either rename or copy detection have been requested).\n-\n \n :git-log: 1\n include::diff-options.txt[]\ndiff --git a/Documentation/git-show.txt b/Documentation/git-show.txt\nindex fcf528c1b30d..abe58ce5d3a8 100644\n--- a/Documentation/git-show.txt\n+++ b/Documentation/git-show.txt\n@@ -45,8 +45,12 @@ include::pretty-options.txt[]\n include::pretty-formats.txt[]\n \n \n-COMMON DIFF OPTIONS\n--------------------\n+DIFF FORMATTING\n+---------------\n+\n+By default, `git show` does not generate any diff output. The options\n+below can be used to show the changes made by each commit.\n+\n \n :git-log: 1\n include::diff-options.txt[]\n-- \n2.25.1\n\n"},{"id":"409360","messageId":"20201108213838.4880-19-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201108213838.4880-1-sorganov@gmail.com","subject":"[PATCH v1 18/27] diff-merges: group diff-merge flags next to each other inside 'rev_info'","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-11-08T21:38:29Z","receivedAt":"2020-11-08T21:41:52Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"The relevant flags were somewhat scattered over definition of 'struct\nrev_info'. Rearrange them to group them together.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n revision.h | 5 +++--\n 1 file changed, 3 insertions(+), 2 deletions(-)\n\ndiff --git a/revision.h b/revision.h\nindex fcc532c873d1..dcfa14454a55 100644\n--- a/revision.h\n+++ b/revision.h\n@@ -191,13 +191,14 @@ struct rev_info {\n \t\t\tmatch_missing:1,\n \t\t\tno_commit_id:1,\n \t\t\tverbose_header:1,\n+\t\t\talways_show_header:1,\n+\t\t\t/* Diff-merge flags */\n \t\t\texplicit_diff_merges: 1,\n \t\t\tseparate_merges: 1,\n \t\t\tcombine_merges:1,\n \t\t\tcombined_all_paths:1,\n \t\t\tdense_combined_merges:1,\n-\t\t\tfirst_parent_merges:1,\n-\t\t\talways_show_header:1;\n+\t\t\tfirst_parent_merges:1;\n \n \t/* Format info */\n \tint\t\tshow_notes;\n-- \n2.25.1\n\n"},{"id":"409359","messageId":"20201108213838.4880-26-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201108213838.4880-1-sorganov@gmail.com","subject":"[PATCH v1 25/27] doc/diff-generate-patch: mention new --diff-merges option","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-11-08T21:38:36Z","receivedAt":"2020-11-08T21:41:54Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Mention --diff-merges instead of -m in a note to merge formats to aid\ndiscoverability, as -m is now described among --diff-merges options\nanyway.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n Documentation/diff-generate-patch.txt | 6 +++---\n 1 file changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/Documentation/diff-generate-patch.txt b/Documentation/diff-generate-patch.txt\nindex b10ff4caa6c5..2db8eacc3ec7 100644\n--- a/Documentation/diff-generate-patch.txt\n+++ b/Documentation/diff-generate-patch.txt\n@@ -81,9 +81,9 @@ Combined diff format\n Any diff-generating command can take the `-c` or `--cc` option to\n produce a 'combined diff' when showing a merge. This is the default\n format when showing merges with linkgit:git-diff[1] or\n-linkgit:git-show[1]. Note also that you can give the `-m` option to any\n-of these commands to force generation of diffs with individual parents\n-of a merge.\n+linkgit:git-show[1]. Note also that you can give suitable\n+`--diff-merges` option to any of these commands to force generation of\n+diffs in specific format.\n \n A \"combined diff\" format looks like this:\n \n-- \n2.25.1\n\n"},{"id":"409361","messageId":"20201108213838.4880-18-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201108213838.4880-1-sorganov@gmail.com","subject":"[PATCH v1 17/27] diff-merges: split 'ignore_merges' field","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-11-08T21:38:28Z","receivedAt":"2020-11-08T21:41:55Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"'ignore_merges' was 3-way field that served two distinct purposes that\nwe now assign to 2 new independent flags: 'separate_merges', and\n'explicit_diff_merges'.\n\n'separate_merges' tells that we need to output diff format containing\nseparate diff for every parent (as opposed to 'combine_merges').\n\n'explicit_diff_merges' tells that at least one of diff-merges options\nhas been explicitly specified on the command line, so no defaults\nshould apply.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n diff-merges.c | 29 ++++++++++++-----------------\n log-tree.c    | 15 ++++++++-------\n revision.h    |  3 ++-\n 3 files changed, 22 insertions(+), 25 deletions(-)\n\ndiff --git a/diff-merges.c b/diff-merges.c\nindex f2b9ed789ca8..19cdad1aa4a1 100644\n--- a/diff-merges.c\n+++ b/diff-merges.c\n@@ -3,7 +3,7 @@\n #include \"revision.h\"\n \n static void suppress(struct rev_info *revs) {\n-\trevs->ignore_merges = 1;\n+\trevs->separate_merges = 0;\n \trevs->first_parent_merges = 0;\n \trevs->combine_merges = 0;\n \trevs->dense_combined_merges = 0;\n@@ -20,7 +20,6 @@ static void set_dense_combined(struct rev_info *revs) {\n  */\n \n void diff_merges_init_revs(struct rev_info *revs) {\n-\trevs->ignore_merges = -1;\n }\n \n int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {\n@@ -35,7 +34,7 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {\n \t\t * family of commands, it means \"show full diff for merges\". Set\n \t\t * both fields appropriately.\n \t\t */\n-\t\trevs->ignore_merges = 0;\n+\t\trevs->separate_merges = 1;\n \t\trevs->match_missing = 1;\n \t} else if (!strcmp(arg, \"-c\")) {\n \t\trevs->dense_combined_merges = 0;\n@@ -55,6 +54,7 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {\n \t} else\n \t\treturn 0;\n \n+\trevs->explicit_diff_merges = 1;\n \treturn 1;\n }\n \n@@ -63,20 +63,15 @@ void diff_merges_suppress(struct rev_info *revs) {\n }\n \n void diff_merges_default_to_first_parent(struct rev_info *revs) {\n-\tif (revs->ignore_merges < 0)\t\t/* No -m */\n-\t\trevs->ignore_merges = 0;\n-\tif (!revs->combine_merges)\t\t/* No -c/--cc\" */\n+\tif (!revs->explicit_diff_merges)\n+\t\trevs->separate_merges = 1;\n+\tif (revs->separate_merges)\n \t\trevs->first_parent_merges = 1;\n }\n \n void diff_merges_default_to_dense_combined(struct rev_info *revs) {\n-\tif (revs->ignore_merges < 0) {\t\t/* No -m */\n-\t\trevs->ignore_merges = 0;\n-\t\tif (!revs->combine_merges) {\t/* No -c/--cc\" */\n-\t\t\trevs->combine_merges = 1;\n-\t\t\trevs->dense_combined_merges = 1;\n-\t\t}\n-\t}\n+\tif (!revs->explicit_diff_merges)\n+\t\tset_dense_combined(revs);\n }\n \n void diff_merges_set_dense_combined_if_unset(struct rev_info *revs) {\n@@ -86,10 +81,10 @@ void diff_merges_set_dense_combined_if_unset(struct rev_info *revs) {\n \n void diff_merges_setup_revs(struct rev_info *revs)\n {\n-\tif (revs->combine_merges && revs->ignore_merges < 0)\n-\t\trevs->ignore_merges = 0;\n-\tif (revs->ignore_merges < 0)\n-\t\trevs->ignore_merges = 1;\n+\tif (revs->combine_merges == 0)\n+\t\trevs->dense_combined_merges = 0;\n+\tif (revs->separate_merges == 0)\n+\t\trevs->first_parent_merges = 0;\n \tif (revs->combined_all_paths && !revs->combine_merges)\n \t\tdie(\"--combined-all-paths makes no sense without -c or --cc\");\n \tif (revs->combine_merges)\ndiff --git a/log-tree.c b/log-tree.c\nindex 3fdc0fc64bfb..f9385b1dae6f 100644\n--- a/log-tree.c\n+++ b/log-tree.c\n@@ -918,14 +918,15 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log\n \n \t/* More than one parent? */\n \tif (parents->next) {\n-\t\tif (opt->ignore_merges)\n-\t\t\treturn 0;\n-\t\telse if (opt->combine_merges)\n+\t\tif (opt->combine_merges)\n \t\t\treturn do_diff_combined(opt, commit);\n-\t\telse if (!opt->first_parent_merges) {\n-\t\t\t/* If we show multiple diffs, show the parent info */\n-\t\t\tlog->parent = parents->item;\n-\t\t}\n+\t\tif (opt->separate_merges) {\n+\t\t\tif (!opt->first_parent_merges) {\n+\t\t\t\t/* Show parent info for multiple diffs */\n+\t\t\t\tlog->parent = parents->item;\n+\t\t\t}\n+\t\t} else\n+\t\t\treturn 0;\n \t}\n \n \tshowed_log = 0;\ndiff --git a/revision.h b/revision.h\nindex ba2aef79215e..fcc532c873d1 100644\n--- a/revision.h\n+++ b/revision.h\n@@ -191,12 +191,13 @@ struct rev_info {\n \t\t\tmatch_missing:1,\n \t\t\tno_commit_id:1,\n \t\t\tverbose_header:1,\n+\t\t\texplicit_diff_merges: 1,\n+\t\t\tseparate_merges: 1,\n \t\t\tcombine_merges:1,\n \t\t\tcombined_all_paths:1,\n \t\t\tdense_combined_merges:1,\n \t\t\tfirst_parent_merges:1,\n \t\t\talways_show_header:1;\n-\tint             ignore_merges:2;\n \n \t/* Format info */\n \tint\t\tshow_notes;\n-- \n2.25.1\n\n"},{"id":"409364","messageId":"20201108213838.4880-15-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201108213838.4880-1-sorganov@gmail.com","subject":"[PATCH v1 14/27] t4013: support test_expect_failure through ':failure' magic","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-11-08T21:38:25Z","receivedAt":"2020-11-08T21:41:56Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Add support to be able to specify expected failure, through :failure\nmagic, like this:\n\n:failure cmd args\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n t/t4013-diff-various.sh | 7 ++++++-\n 1 file changed, 6 insertions(+), 1 deletion(-)\n\ndiff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh\nindex 5c7b0122b4f1..935d10ac0572 100755\n--- a/t/t4013-diff-various.sh\n+++ b/t/t4013-diff-various.sh\n@@ -174,6 +174,7 @@ process_diffs () {\n V=$(git version | sed -e 's/^git version //' -e 's/\\./\\\\./g')\n while read magic cmd\n do\n+\tstatus=success\n \tcase \"$magic\" in\n \t'' | '#'*)\n \t\tcontinue ;;\n@@ -182,6 +183,10 @@ do\n \t\tlabel=\"$magic-$cmd\"\n \t\tcase \"$magic\" in\n \t\tnoellipses) ;;\n+\t\tfailure)\n+\t\t\tstatus=failure\n+\t\t\tmagic=\n+\t\t\tlabel=\"$cmd\" ;;\n \t\t*)\n \t\t\tBUG \"unknown magic $magic\" ;;\n \t\tesac ;;\n@@ -194,7 +199,7 @@ do\n \texpect=\"$TEST_DIRECTORY/t4013/diff.$test\"\n \tactual=\"$pfx-diff.$test\"\n \n-\ttest_expect_success \"git $cmd # magic is ${magic:-(not used)}\" '\n+\ttest_expect_$status \"git $cmd # magic is ${magic:-(not used)}\" '\n \t\t{\n \t\t\techo \"$ git $cmd\"\n \t\t\tcase \"$magic\" in\n-- \n2.25.1\n\n"},{"id":"409362","messageId":"20201108213838.4880-7-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201108213838.4880-1-sorganov@gmail.com","subject":"[PATCH v1 06/27] diff-merges: rename all functions to have common prefix","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-11-08T21:38:17Z","receivedAt":"2020-11-08T21:41:57Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Use the same \"diff_merges\" prefix for all the diff merges function\nnames.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n builtin/log.c |  4 ++--\n diff-merges.c | 10 +++++-----\n diff-merges.h | 15 ++++++++++-----\n revision.c    |  6 +++---\n 4 files changed, 20 insertions(+), 15 deletions(-)\n\ndiff --git a/builtin/log.c b/builtin/log.c\nindex ad3092fdd854..77a7bba543ad 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -599,7 +599,7 @@ static int show_tree_object(const struct object_id *oid,\n static void show_setup_revisions_tweak(struct rev_info *rev,\n \t\t\t\t       struct setup_revision_opt *opt)\n {\n-\trev_diff_merges_default_to_dense_combined(rev);\n+\tdiff_merges_default_to_dense_combined(rev);\n \tif (!rev->diffopt.output_format)\n \t\trev->diffopt.output_format = DIFF_FORMAT_PATCH;\n }\n@@ -724,7 +724,7 @@ static void log_setup_revisions_tweak(struct rev_info *rev,\n \tif (!rev->diffopt.output_format && rev->combine_merges)\n \t\trev->diffopt.output_format = DIFF_FORMAT_PATCH;\n \n-\trev_diff_merges_first_parent_defaults_to_enable(rev);\n+\tdiff_merges_first_parent_defaults_to_enable(rev);\n }\n \n int cmd_log(int argc, const char **argv, const char *prefix)\ndiff --git a/diff-merges.c b/diff-merges.c\nindex 8b9dd4ad5625..85bf0b6d1d1d 100644\n--- a/diff-merges.c\n+++ b/diff-merges.c\n@@ -2,11 +2,11 @@\n \n #include \"revision.h\"\n \n-void init_diff_merge_revs(struct rev_info *revs) {\n+void diff_merges_init_revs(struct rev_info *revs) {\n \trevs->ignore_merges = -1;\n }\n \n-int parse_diff_merge_opts(struct rev_info *revs, const char **argv) {\n+int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {\n \tint argcount;\n \tconst char *optarg;\n \tconst char *arg = argv[0];\n@@ -44,7 +44,7 @@ int parse_diff_merge_opts(struct rev_info *revs, const char **argv) {\n \treturn 1;\n }\n \n-void setup_diff_merges_revs(struct rev_info *revs)\n+void diff_merges_setup_revs(struct rev_info *revs)\n {\n \tif (revs->combine_merges && revs->ignore_merges < 0)\n \t\trevs->ignore_merges = 0;\n@@ -54,12 +54,12 @@ void setup_diff_merges_revs(struct rev_info *revs)\n \t\tdie(\"--combined-all-paths makes no sense without -c or --cc\");\n }\n \n-void rev_diff_merges_first_parent_defaults_to_enable(struct rev_info *revs) {\n+void diff_merges_first_parent_defaults_to_enable(struct rev_info *revs) {\n \tif (revs->first_parent_only && revs->ignore_merges < 0)\n \t\trevs->ignore_merges = 0;\n }\n \n-void rev_diff_merges_default_to_dense_combined(struct rev_info *revs) {\n+void diff_merges_default_to_dense_combined(struct rev_info *revs) {\n \tif (revs->ignore_merges < 0) {\n \t\t/* There was no \"-m\" variant on the command line */\n \t\trevs->ignore_merges = 0;\ndiff --git a/diff-merges.h b/diff-merges.h\nindex e0cca3d935d3..648c410497cb 100644\n--- a/diff-merges.h\n+++ b/diff-merges.h\n@@ -3,10 +3,15 @@\n \n struct rev_info;\n \n-void init_diff_merge_revs(struct rev_info *revs);\n-int parse_diff_merge_opts(struct rev_info *revs, const char **argv);\n-void setup_diff_merges_revs(struct rev_info *revs);\n-void rev_diff_merges_default_to_dense_combined(struct rev_info *revs);\n-void rev_diff_merges_first_parent_defaults_to_enable(struct rev_info *revs);\n+void diff_merges_init_revs(struct rev_info *revs);\n+\n+int diff_merges_parse_opts(struct rev_info *revs, const char **argv);\n+\n+void diff_merges_setup_revs(struct rev_info *revs);\n+\n+void diff_merges_default_to_dense_combined(struct rev_info *revs);\n+\n+void diff_merges_first_parent_defaults_to_enable(struct rev_info *revs);\n+\n \n #endif\ndiff --git a/revision.c b/revision.c\nindex 4bc14a08a624..5a0e3d6ad542 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -1814,7 +1814,7 @@ void repo_init_revisions(struct repository *r,\n \n \trevs->repo = r;\n \trevs->abbrev = DEFAULT_ABBREV;\n-\tinit_diff_merge_revs(revs);\n+\tdiff_merges_init_revs(revs);\n \trevs->simplify_history = 1;\n \trevs->pruning.repo = r;\n \trevs->pruning.flags.recursive = 1;\n@@ -2350,7 +2350,7 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg\n \t\trevs->diff = 1;\n \t\trevs->diffopt.flags.recursive = 1;\n \t\trevs->diffopt.flags.tree_in_recursive = 1;\n-\t} else if ((argcount = parse_diff_merge_opts(revs, argv))) {\n+\t} else if ((argcount = diff_merges_parse_opts(revs, argv))) {\n \t\treturn argcount;\n \t} else if (!strcmp(arg, \"-v\")) {\n \t\trevs->verbose_header = 1;\n@@ -2849,7 +2849,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s\n \t\t\t\t      &revs->prune_data);\n \t}\n \n-\tsetup_diff_merges_revs(revs);\n+\tdiff_merges_setup_revs(revs);\n \n \trevs->diffopt.abbrev = revs->abbrev;\n \n-- \n2.25.1\n\n"},{"id":"409365","messageId":"20201108213838.4880-16-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201108213838.4880-1-sorganov@gmail.com","subject":"[PATCH v1 15/27] t4013: add tests for -m failing to override -c/--cc","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-11-08T21:38:26Z","receivedAt":"2020-11-08T21:41:58Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Logically, -m, -c, --cc specify 3 different formats for representing\nmerge commits, yet -m doesn't in fact override -c or --cc, that makes\nno sense.\n\nAdd 2 expected to fail tests that demonstrate the problem.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n t/t4013-diff-various.sh            |   2 +\n t/t4013/diff.log_--cc_-m_-p_master | 200 +++++++++++++++++++++++++++++\n t/t4013/diff.log_-c_-m_-p_master   | 200 +++++++++++++++++++++++++++++\n 3 files changed, 402 insertions(+)\n create mode 100644 t/t4013/diff.log_--cc_-m_-p_master\n create mode 100644 t/t4013/diff.log_-c_-m_-p_master\n\ndiff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh\nindex 935d10ac0572..64d9fce44614 100755\n--- a/t/t4013-diff-various.sh\n+++ b/t/t4013-diff-various.sh\n@@ -329,6 +329,8 @@ log --first-parent --diff-merges=off -p master\n log -p --first-parent master\n log -m -p --first-parent master\n log -m -p master\n+:failure log --cc -m -p master\n+:failure log -c -m -p master\n log -SF master\n log -S F master\n log -SF -p master\ndiff --git a/t/t4013/diff.log_--cc_-m_-p_master b/t/t4013/diff.log_--cc_-m_-p_master\nnew file mode 100644\nindex 000000000000..7c217cf348c7\n--- /dev/null\n+++ b/t/t4013/diff.log_--cc_-m_-p_master\n@@ -0,0 +1,200 @@\n+$ git log --cc -m -p master\n+commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (from 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0)\n+Merge: 9a6d494 c7a2ab9\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:04:00 2006 +0000\n+\n+    Merge branch 'side'\n+\n+diff --git a/dir/sub b/dir/sub\n+index cead32e..992913c 100644\n+--- a/dir/sub\n++++ b/dir/sub\n+@@ -4,3 +4,5 @@ C\n+ D\n+ E\n+ F\n++1\n++2\n+diff --git a/file0 b/file0\n+index b414108..10a8a9f 100644\n+--- a/file0\n++++ b/file0\n+@@ -4,3 +4,6 @@\n+ 4\n+ 5\n+ 6\n++A\n++B\n++C\n+\n+commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (from c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a)\n+Merge: 9a6d494 c7a2ab9\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:04:00 2006 +0000\n+\n+    Merge branch 'side'\n+\n+diff --git a/dir/sub b/dir/sub\n+index 7289e35..992913c 100644\n+--- a/dir/sub\n++++ b/dir/sub\n+@@ -1,4 +1,8 @@\n+ A\n+ B\n++C\n++D\n++E\n++F\n+ 1\n+ 2\n+diff --git a/file0 b/file0\n+index f4615da..10a8a9f 100644\n+--- a/file0\n++++ b/file0\n+@@ -1,6 +1,9 @@\n+ 1\n+ 2\n+ 3\n++4\n++5\n++6\n+ A\n+ B\n+ C\n+diff --git a/file1 b/file1\n+new file mode 100644\n+index 0000000..b1e6722\n+--- /dev/null\n++++ b/file1\n+@@ -0,0 +1,3 @@\n++A\n++B\n++C\n+diff --git a/file2 b/file2\n+deleted file mode 100644\n+index 01e79c3..0000000\n+--- a/file2\n++++ /dev/null\n+@@ -1,3 +0,0 @@\n+-1\n+-2\n+-3\n+diff --git a/file3 b/file3\n+deleted file mode 100644\n+index 7289e35..0000000\n+--- a/file3\n++++ /dev/null\n+@@ -1,4 +0,0 @@\n+-A\n+-B\n+-1\n+-2\n+\n+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:03:00 2006 +0000\n+\n+    Side\n+\n+diff --git a/dir/sub b/dir/sub\n+index 35d242b..7289e35 100644\n+--- a/dir/sub\n++++ b/dir/sub\n+@@ -1,2 +1,4 @@\n+ A\n+ B\n++1\n++2\n+diff --git a/file0 b/file0\n+index 01e79c3..f4615da 100644\n+--- a/file0\n++++ b/file0\n+@@ -1,3 +1,6 @@\n+ 1\n+ 2\n+ 3\n++A\n++B\n++C\n+diff --git a/file3 b/file3\n+new file mode 100644\n+index 0000000..7289e35\n+--- /dev/null\n++++ b/file3\n+@@ -0,0 +1,4 @@\n++A\n++B\n++1\n++2\n+\n+commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:02:00 2006 +0000\n+\n+    Third\n+\n+diff --git a/dir/sub b/dir/sub\n+index 8422d40..cead32e 100644\n+--- a/dir/sub\n++++ b/dir/sub\n+@@ -2,3 +2,5 @@ A\n+ B\n+ C\n+ D\n++E\n++F\n+diff --git a/file1 b/file1\n+new file mode 100644\n+index 0000000..b1e6722\n+--- /dev/null\n++++ b/file1\n+@@ -0,0 +1,3 @@\n++A\n++B\n++C\n+\n+commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:01:00 2006 +0000\n+\n+    Second\n+    \n+    This is the second commit.\n+\n+diff --git a/dir/sub b/dir/sub\n+index 35d242b..8422d40 100644\n+--- a/dir/sub\n++++ b/dir/sub\n+@@ -1,2 +1,4 @@\n+ A\n+ B\n++C\n++D\n+diff --git a/file0 b/file0\n+index 01e79c3..b414108 100644\n+--- a/file0\n++++ b/file0\n+@@ -1,3 +1,6 @@\n+ 1\n+ 2\n+ 3\n++4\n++5\n++6\n+diff --git a/file2 b/file2\n+deleted file mode 100644\n+index 01e79c3..0000000\n+--- a/file2\n++++ /dev/null\n+@@ -1,3 +0,0 @@\n+-1\n+-2\n+-3\n+\n+commit 444ac553ac7612cc88969031b02b3767fb8a353a\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:00:00 2006 +0000\n+\n+    Initial\n+$\ndiff --git a/t/t4013/diff.log_-c_-m_-p_master b/t/t4013/diff.log_-c_-m_-p_master\nnew file mode 100644\nindex 000000000000..b660f3d5f28e\n--- /dev/null\n+++ b/t/t4013/diff.log_-c_-m_-p_master\n@@ -0,0 +1,200 @@\n+$ git log -c -m -p master\n+commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (from 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0)\n+Merge: 9a6d494 c7a2ab9\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:04:00 2006 +0000\n+\n+    Merge branch 'side'\n+\n+diff --git a/dir/sub b/dir/sub\n+index cead32e..992913c 100644\n+--- a/dir/sub\n++++ b/dir/sub\n+@@ -4,3 +4,5 @@ C\n+ D\n+ E\n+ F\n++1\n++2\n+diff --git a/file0 b/file0\n+index b414108..10a8a9f 100644\n+--- a/file0\n++++ b/file0\n+@@ -4,3 +4,6 @@\n+ 4\n+ 5\n+ 6\n++A\n++B\n++C\n+\n+commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (from c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a)\n+Merge: 9a6d494 c7a2ab9\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:04:00 2006 +0000\n+\n+    Merge branch 'side'\n+\n+diff --git a/dir/sub b/dir/sub\n+index 7289e35..992913c 100644\n+--- a/dir/sub\n++++ b/dir/sub\n+@@ -1,4 +1,8 @@\n+ A\n+ B\n++C\n++D\n++E\n++F\n+ 1\n+ 2\n+diff --git a/file0 b/file0\n+index f4615da..10a8a9f 100644\n+--- a/file0\n++++ b/file0\n+@@ -1,6 +1,9 @@\n+ 1\n+ 2\n+ 3\n++4\n++5\n++6\n+ A\n+ B\n+ C\n+diff --git a/file1 b/file1\n+new file mode 100644\n+index 0000000..b1e6722\n+--- /dev/null\n++++ b/file1\n+@@ -0,0 +1,3 @@\n++A\n++B\n++C\n+diff --git a/file2 b/file2\n+deleted file mode 100644\n+index 01e79c3..0000000\n+--- a/file2\n++++ /dev/null\n+@@ -1,3 +0,0 @@\n+-1\n+-2\n+-3\n+diff --git a/file3 b/file3\n+deleted file mode 100644\n+index 7289e35..0000000\n+--- a/file3\n++++ /dev/null\n+@@ -1,4 +0,0 @@\n+-A\n+-B\n+-1\n+-2\n+\n+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:03:00 2006 +0000\n+\n+    Side\n+\n+diff --git a/dir/sub b/dir/sub\n+index 35d242b..7289e35 100644\n+--- a/dir/sub\n++++ b/dir/sub\n+@@ -1,2 +1,4 @@\n+ A\n+ B\n++1\n++2\n+diff --git a/file0 b/file0\n+index 01e79c3..f4615da 100644\n+--- a/file0\n++++ b/file0\n+@@ -1,3 +1,6 @@\n+ 1\n+ 2\n+ 3\n++A\n++B\n++C\n+diff --git a/file3 b/file3\n+new file mode 100644\n+index 0000000..7289e35\n+--- /dev/null\n++++ b/file3\n+@@ -0,0 +1,4 @@\n++A\n++B\n++1\n++2\n+\n+commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:02:00 2006 +0000\n+\n+    Third\n+\n+diff --git a/dir/sub b/dir/sub\n+index 8422d40..cead32e 100644\n+--- a/dir/sub\n++++ b/dir/sub\n+@@ -2,3 +2,5 @@ A\n+ B\n+ C\n+ D\n++E\n++F\n+diff --git a/file1 b/file1\n+new file mode 100644\n+index 0000000..b1e6722\n+--- /dev/null\n++++ b/file1\n+@@ -0,0 +1,3 @@\n++A\n++B\n++C\n+\n+commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:01:00 2006 +0000\n+\n+    Second\n+    \n+    This is the second commit.\n+\n+diff --git a/dir/sub b/dir/sub\n+index 35d242b..8422d40 100644\n+--- a/dir/sub\n++++ b/dir/sub\n+@@ -1,2 +1,4 @@\n+ A\n+ B\n++C\n++D\n+diff --git a/file0 b/file0\n+index 01e79c3..b414108 100644\n+--- a/file0\n++++ b/file0\n+@@ -1,3 +1,6 @@\n+ 1\n+ 2\n+ 3\n++4\n++5\n++6\n+diff --git a/file2 b/file2\n+deleted file mode 100644\n+index 01e79c3..0000000\n+--- a/file2\n++++ /dev/null\n+@@ -1,3 +0,0 @@\n+-1\n+-2\n+-3\n+\n+commit 444ac553ac7612cc88969031b02b3767fb8a353a\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:00:00 2006 +0000\n+\n+    Initial\n+$\n-- \n2.25.1\n\n"},{"id":"409366","messageId":"20201108213838.4880-17-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201108213838.4880-1-sorganov@gmail.com","subject":"[PATCH v1 16/27] diff-merges: fix -m to properly override -c/--cc","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-11-08T21:38:27Z","receivedAt":"2020-11-08T21:41:58Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Logically, -m, -c, --cc specify 3 different formats for representing\nmerge commits, yet -m doesn't in fact override -c or --cc, that makes\nno sense.\n\nFix -m to properly override -c/--cc, and change the tests accordingly.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n diff-merges.c           | 1 +\n t/t4013-diff-various.sh | 4 ++--\n 2 files changed, 3 insertions(+), 2 deletions(-)\n\ndiff --git a/diff-merges.c b/diff-merges.c\nindex a30c730a457f..f2b9ed789ca8 100644\n--- a/diff-merges.c\n+++ b/diff-merges.c\n@@ -29,6 +29,7 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {\n \tconst char *arg = argv[0];\n \n \tif (!strcmp(arg, \"-m\")) {\n+\t\tsuppress(revs);\n \t\t/*\n \t\t * To \"diff-index\", \"-m\" means \"match missing\", and to the \"log\"\n \t\t * family of commands, it means \"show full diff for merges\". Set\ndiff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh\nindex 64d9fce44614..8d8178a8a616 100755\n--- a/t/t4013-diff-various.sh\n+++ b/t/t4013-diff-various.sh\n@@ -329,8 +329,8 @@ log --first-parent --diff-merges=off -p master\n log -p --first-parent master\n log -m -p --first-parent master\n log -m -p master\n-:failure log --cc -m -p master\n-:failure log -c -m -p master\n+log --cc -m -p master\n+log -c -m -p master\n log -SF master\n log -S F master\n log -SF -p master\n-- \n2.25.1\n\n"},{"id":"411188","messageId":"xmqqv9djk9tv.fsf@gitster.c.googlers.com","threadId":"54550","inReplyTo":"20201108213838.4880-2-sorganov@gmail.com","subject":"Re: [PATCH v1 01/27] revision: factor out parsing of diff-merge related options","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2020-12-03T00:33:00Z","receivedAt":"2020-12-03T00:33:47Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Sergey Organov <sorganov@gmail.com> writes:\n\n> Move all the parsing code related to diffing merges into new\n> parse_diff_merge_opts() function.\n>\n> Signed-off-by: Sergey Organov <sorganov@gmail.com>\n> ---\n>  revision.c | 66 ++++++++++++++++++++++++++++++++----------------------\n>  1 file changed, 39 insertions(+), 27 deletions(-)\n>\n> diff --git a/revision.c b/revision.c\n> index aa6221204081..a09f4872acd7 100644\n> --- a/revision.c\n> +++ b/revision.c\n> @@ -2153,6 +2153,44 @@ static void add_message_grep(struct rev_info *revs, const char *pattern)\n>  \tadd_grep(revs, pattern, GREP_PATTERN_BODY);\n>  }\n>  \n> +static int parse_diff_merge_opts(struct rev_info *revs, const char **argv) {\n> +\tint argcount;\n> +\tconst char *optarg;\n> +\tconst char *arg = argv[0];\n> +\n> +\tif (!strcmp(arg, \"-m\")) {\n> +\t\t/*\n> +\t\t * To \"diff-index\", \"-m\" means \"match missing\", and to the \"log\"\n> +\t\t * family of commands, it means \"show full diff for merges\". Set\n> +\t\t * both fields appropriately.\n> +\t\t */\n> +\t\trevs->ignore_merges = 0;\n> +\t\trevs->match_missing = 1;\n> +\t} else if (!strcmp(arg, \"-c\")) {\n> +\t\trevs->diff = 1;\n> +\t\trevs->dense_combined_merges = 0;\n> +\t\trevs->combine_merges = 1;\n> +\t} else if (!strcmp(arg, \"--cc\")) {\n> +\t\trevs->diff = 1;\n> +\t\trevs->dense_combined_merges = 1;\n> +\t\trevs->combine_merges = 1;\n> +\t} else if (!strcmp(arg, \"--no-diff-merges\")) {\n> +\t\trevs->ignore_merges = 1;\n> +\t} else if (!strcmp(arg, \"--combined-all-paths\")) {\n> +\t\trevs->diff = 1;\n> +\t\trevs->combined_all_paths = 1;\n> +\t} else if ((argcount = parse_long_opt(\"diff-merges\", argv, &optarg))) {\n\nThe reordering of if/else if/ cascade from the original, which\nserves no apparent purpose, makes reviewing a tad harder than\nnecessary, but the conversion at this point seems wrong.\n\nThe original allowed parse_long_opt() to potentially return 2\n(i.e. \"diff-merges\" and \"off\" appear as separate tokens on the\ncommand line), but the return value stored in argcount here is\ndiscarded, without affecting the return value from this function,\nwhich is fed back to the original in handle_revision_opt() below.\n\n> +\t\tif (!strcmp(optarg, \"off\")) {\n> +\t\t\trevs->ignore_merges = 1;\n> +\t\t} else {\n> +\t\t\tdie(_(\"unknown value for --diff-merges: %s\"), optarg);\n> +\t\t}\n\nTo correct the above bug, it probably is sufficient to add\n\n\t\treturn argcount;\n\nhere.  That will be fed back to ...\n\n> +\t} else\n> +\t\treturn 0;\n> +\n> +\treturn 1;\n> +}\n\n> @@ -2349,34 +2387,8 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg\n> ...\n> -\t} else if ((argcount = parse_long_opt(\"diff-merges\", argv, &optarg))) {\n> -\t\tif (!strcmp(optarg, \"off\")) {\n> -\t\t\trevs->ignore_merges = 1;\n> -\t\t} else {\n> -\t\t\tdie(_(\"unknown value for --diff-merges: %s\"), optarg);\n> -\t\t}\n> +\t} else if ((argcount = parse_diff_merge_opts(revs, argv))) {\n>  \t\treturn argcount;\n\n... this part and cause the number of options and arguments consumed\nto the caller of handle_revision_opt().\n\nI wonder if we can cover it with a test to prevent a similar mistake\nin the future?\n\n> -\t} else if (!strcmp(arg, \"--no-diff-merges\")) {\n> -\t\trevs->ignore_merges = 1;\n> -\t} else if (!strcmp(arg, \"-c\")) {\n> -\t\trevs->diff = 1;\n> -\t\trevs->dense_combined_merges = 0;\n> -\t\trevs->combine_merges = 1;\n> -\t} else if (!strcmp(arg, \"--combined-all-paths\")) {\n> -\t\trevs->diff = 1;\n> -\t\trevs->combined_all_paths = 1;\n> -\t} else if (!strcmp(arg, \"--cc\")) {\n> -\t\trevs->diff = 1;\n> -\t\trevs->dense_combined_merges = 1;\n> -\t\trevs->combine_merges = 1;\n>  \t} else if (!strcmp(arg, \"-v\")) {\n>  \t\trevs->verbose_header = 1;\n>  \t} else if (!strcmp(arg, \"--pretty\")) {\n"},{"id":"411189","messageId":"xmqqr1o7k9rq.fsf@gitster.c.googlers.com","threadId":"54550","inReplyTo":"20201108213838.4880-3-sorganov@gmail.com","subject":"Re: [PATCH v1 02/27] revision: factor out setup of diff-merge related settings","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2020-12-03T00:34:17Z","receivedAt":"2020-12-03T00:35:14Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Sergey Organov <sorganov@gmail.com> writes:\n\n> Move all the setting code related to diffing merges into new\n> setup_diff_merge_revs() function.\n>\n> Signed-off-by: Sergey Organov <sorganov@gmail.com>\n> ---\n>  revision.c | 18 ++++++++++++------\n>  1 file changed, 12 insertions(+), 6 deletions(-)\n\nLooks trivially correct.\n\n> diff --git a/revision.c b/revision.c\n> index a09f4872acd7..739295bb9ff4 100644\n> --- a/revision.c\n> +++ b/revision.c\n> @@ -2191,6 +2191,16 @@ static int parse_diff_merge_opts(struct rev_info *revs, const char **argv) {\n>  \treturn 1;\n>  }\n>  \n> +static void setup_diff_merges_revs(struct rev_info *revs)\n> +{\n> +\tif (revs->combine_merges && revs->ignore_merges < 0)\n> +\t\trevs->ignore_merges = 0;\n> +\tif (revs->ignore_merges < 0)\n> +\t\trevs->ignore_merges = 1;\n> +\tif (revs->combined_all_paths && !revs->combine_merges)\n> +\t\tdie(\"--combined-all-paths makes no sense without -c or --cc\");\n> +}\n> +\n>  static int handle_revision_opt(struct rev_info *revs, int argc, const char **argv,\n>  \t\t\t       int *unkc, const char **unkv,\n>  \t\t\t       const struct setup_revision_opt* opt)\n> @@ -2885,12 +2895,8 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s\n>  \t\t\tcopy_pathspec(&revs->diffopt.pathspec,\n>  \t\t\t\t      &revs->prune_data);\n>  \t}\n> -\tif (revs->combine_merges && revs->ignore_merges < 0)\n> -\t\trevs->ignore_merges = 0;\n> -\tif (revs->ignore_merges < 0)\n> -\t\trevs->ignore_merges = 1;\n> -\tif (revs->combined_all_paths && !revs->combine_merges)\n> -\t\tdie(\"--combined-all-paths makes no sense without -c or --cc\");\n> +\n> +\tsetup_diff_merges_revs(revs);\n>  \n>  \trevs->diffopt.abbrev = revs->abbrev;\n"},{"id":"411190","messageId":"xmqqmtyvk9jv.fsf@gitster.c.googlers.com","threadId":"54550","inReplyTo":"20201108213838.4880-4-sorganov@gmail.com","subject":"Re: [PATCH v1 03/27] revision: factor out initialization of diff-merge related settings","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2020-12-03T00:39:00Z","receivedAt":"2020-12-03T00:39:45Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Sergey Organov <sorganov@gmail.com> writes:\n\n> Move initialization code related to diffing merges into new\n> init_diff_merge_revs() function.\n>\n> Signed-off-by: Sergey Organov <sorganov@gmail.com>\n> ---\n>  revision.c | 8 +++++++-\n>  1 file changed, 7 insertions(+), 1 deletion(-)\n>\n> diff --git a/revision.c b/revision.c\n> index 739295bb9ff4..bc568fb79778 100644\n> --- a/revision.c\n> +++ b/revision.c\n> @@ -1805,6 +1805,8 @@ static int add_parents_only(struct rev_info *revs, const char *arg_, int flags,\n>  \treturn 1;\n>  }\n>  \n> +static void init_diff_merge_revs(struct rev_info *revs);\n> +\n\nIt is not wrong per-se, but I do not see why we do not define the\nfunction here, not just forward-declare it like so.\n\n>  void repo_init_revisions(struct repository *r,\n>  \t\t\t struct rev_info *revs,\n>  \t\t\t const char *prefix)\n> @@ -1813,7 +1815,7 @@ void repo_init_revisions(struct repository *r,\n>  \n>  \trevs->repo = r;\n>  \trevs->abbrev = DEFAULT_ABBREV;\n> -\trevs->ignore_merges = -1;\n> +\tinit_diff_merge_revs(revs);\n>  \trevs->simplify_history = 1;\n>  \trevs->pruning.repo = r;\n>  \trevs->pruning.flags.recursive = 1;\n> @@ -2153,6 +2155,10 @@ static void add_message_grep(struct rev_info *revs, const char *pattern)\n>  \tadd_grep(revs, pattern, GREP_PATTERN_BODY);\n>  }\n>  \n> +static void init_diff_merge_revs(struct rev_info *revs) {\n> +\trevs->ignore_merges = -1;\n> +}\n\nStyle.  A brace that begins a function body begins its own line.  In\nany case, I'd move this new definition before its sole caller; that\nway we do not even need an extra forward-declaration.\n\n>  static int parse_diff_merge_opts(struct rev_info *revs, const char **argv) {\n>  \tint argcount;\n>  \tconst char *optarg;\n"},{"id":"411191","messageId":"xmqqim9jk8zf.fsf@gitster.c.googlers.com","threadId":"54550","inReplyTo":"20201108213838.4880-5-sorganov@gmail.com","subject":"Re: [PATCH v1 04/27] revision: provide implementation for diff merges tweaks","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2020-12-03T00:51:16Z","receivedAt":"2020-12-03T00:52:06Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Sergey Organov <sorganov@gmail.com> writes:\n\n> -\tif (rev->ignore_merges < 0) {\n> -\t\t/* There was no \"-m\" variant on the command line */\n> -\t\trev->ignore_merges = 0;\n> -\t\tif (!rev->first_parent_only && !rev->combine_merges) {\n> -\t\t\t/* No \"--first-parent\", \"-c\", or \"--cc\" */\n> -\t\t\trev->combine_merges = 1;\n> -\t\t\trev->dense_combined_merges = 1;\n> -\t\t}\n> -\t}\n> +\trev_diff_merges_default_to_dense_combined(rev);\n\nThe name makes sense.  \"Unless otherwise specified, we do not ignore\nmerges.  Further, when we are not doing first-parent traversal,\ndefault to dense combined merges, unless told otherwise\" is what the\ncode says, and the name of the helper captures it well.\n\n> @@ -731,8 +723,7 @@ static void log_setup_revisions_tweak(struct rev_info *rev,\n>  \tif (!rev->diffopt.output_format && rev->combine_merges)\n>  \t\trev->diffopt.output_format = DIFF_FORMAT_PATCH;\n>  \n> -\tif (rev->first_parent_only && rev->ignore_merges < 0)\n> -\t\trev->ignore_merges = 0;\n> +\trev_diff_merges_first_parent_defaults_to_enable(rev);\n\nThis on the other hand is not so great a name.  \"When we are doing\nfirst-parent traversal, do not exclude merge commits from being\nshown\" is what log_setup_revisions_tweak() does here.  \"default to\nenable\" is not clear at all what we are enabling.\n\nIs your naming convention that \"rev_diff_\" is the common prefix?\nWhat's the significance of \"_diff\" part?  After all, these are about\ntweaking the setting in the rev_info structure, so how about\n\n\trevinfo_show_merges_in_dense_combined_by_default(rev);\n\trevinfo_show_merges_by_default_with_first_parent(rev);\n\nperhaps, using just \"revinfo_\" as the common prefix?\n"},{"id":"411192","messageId":"xmqqeek7k8wy.fsf@gitster.c.googlers.com","threadId":"54550","inReplyTo":"20201108213838.4880-7-sorganov@gmail.com","subject":"Re: [PATCH v1 06/27] diff-merges: rename all functions to have common prefix","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2020-12-03T00:52:45Z","receivedAt":"2020-12-03T00:53:45Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Sergey Organov <sorganov@gmail.com> writes:\n\n> Use the same \"diff_merges\" prefix for all the diff merges function\n> names.\n>\n> Signed-off-by: Sergey Organov <sorganov@gmail.com>\n> ---\n>  builtin/log.c |  4 ++--\n>  diff-merges.c | 10 +++++-----\n>  diff-merges.h | 15 ++++++++++-----\n>  revision.c    |  6 +++---\n>  4 files changed, 20 insertions(+), 15 deletions(-)\n>\n> diff --git a/builtin/log.c b/builtin/log.c\n> index ad3092fdd854..77a7bba543ad 100644\n> --- a/builtin/log.c\n> +++ b/builtin/log.c\n> @@ -599,7 +599,7 @@ static int show_tree_object(const struct object_id *oid,\n>  static void show_setup_revisions_tweak(struct rev_info *rev,\n>  \t\t\t\t       struct setup_revision_opt *opt)\n>  {\n> -\trev_diff_merges_default_to_dense_combined(rev);\n> +\tdiff_merges_default_to_dense_combined(rev);\n>  \tif (!rev->diffopt.output_format)\n>  \t\trev->diffopt.output_format = DIFF_FORMAT_PATCH;\n>  }\n> @@ -724,7 +724,7 @@ static void log_setup_revisions_tweak(struct rev_info *rev,\n>  \tif (!rev->diffopt.output_format && rev->combine_merges)\n>  \t\trev->diffopt.output_format = DIFF_FORMAT_PATCH;\n>  \n> -\trev_diff_merges_first_parent_defaults_to_enable(rev);\n> +\tdiff_merges_first_parent_defaults_to_enable(rev);\n\nEven with a different prefix, this name does not make it clear what\nis going on to its readers.  The other name is OK, though.\n"},{"id":"411193","messageId":"xmqqa6uvk8mv.fsf@gitster.c.googlers.com","threadId":"54550","inReplyTo":"20201108213838.4880-6-sorganov@gmail.com","subject":"Re: [PATCH v1 05/27] revision: move diff merges functions to its own diff-merges.c","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2020-12-03T00:58:48Z","receivedAt":"2020-12-03T00:59:36Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Sergey Organov <sorganov@gmail.com> writes:\n\n> diff --git a/diff-merges.h b/diff-merges.h\n> new file mode 100644\n> index 000000000000..e0cca3d935d3\n> --- /dev/null\n> +++ b/diff-merges.h\n> @@ -0,0 +1,12 @@\n> +#ifndef DIFF_MERGES_H\n> +#define DIFF_MERGES_H\n\nDescribe what \"diff-merges\" module is about in a comment here.\n\nThis matters because in 07/27 the log message complains that the\nfirst-parent traversal option is checked in the module but it is out\nof place.  Without defining what the \"module\" is about, the readers\nwould have a hard time agreeing with the justification.\n\nMy guess is that this is about deciding how a merge commit is shown\nin 'log -p' and 'show' output, comparing the commit with its\nparent(s) in patch output.  With that explained, it may make sense\nfor 07/27 to complain that --first-parent that is primarily a\ntraversal option does also affect how a merge is shown (I do not\nnecessarily agree with the complaint, though)\n\n> +\n> +struct rev_info;\n> +\n> +void init_diff_merge_revs(struct rev_info *revs);\n> +int parse_diff_merge_opts(struct rev_info *revs, const char **argv);\n> +void setup_diff_merges_revs(struct rev_info *revs);\n> +void rev_diff_merges_default_to_dense_combined(struct rev_info *revs);\n> +void rev_diff_merges_first_parent_defaults_to_enable(struct rev_info *revs);\n> +\n> +#endif\n> diff --git a/revision.c b/revision.c\n> index ce90c2991657..4bc14a08a624 100644\n> --- a/revision.c\n> +++ b/revision.c\n> @@ -5,6 +5,7 @@\n>  #include \"tree.h\"\n>  #include \"commit.h\"\n>  #include \"diff.h\"\n> +#include \"diff-merges.h\"\n>  #include \"refs.h\"\n>  #include \"revision.h\"\n>  #include \"repository.h\"\n> @@ -1805,8 +1806,6 @@ static int add_parents_only(struct rev_info *revs, const char *arg_, int flags,\n>  \treturn 1;\n>  }\n>  \n> -static void init_diff_merge_revs(struct rev_info *revs);\n> -\n>  void repo_init_revisions(struct repository *r,\n>  \t\t\t struct rev_info *revs,\n>  \t\t\t const char *prefix)\n> @@ -2155,75 +2154,6 @@ static void add_message_grep(struct rev_info *revs, const char *pattern)\n>  \tadd_grep(revs, pattern, GREP_PATTERN_BODY);\n>  }\n>  \n> -static void init_diff_merge_revs(struct rev_info *revs) {\n> -\trevs->ignore_merges = -1;\n> -}\n> -\n> -static int parse_diff_merge_opts(struct rev_info *revs, const char **argv) {\n> -\tint argcount;\n> -\tconst char *optarg;\n> -\tconst char *arg = argv[0];\n> -\n> -\tif (!strcmp(arg, \"-m\")) {\n> -\t\t/*\n> -\t\t * To \"diff-index\", \"-m\" means \"match missing\", and to the \"log\"\n> -\t\t * family of commands, it means \"show full diff for merges\". Set\n> -\t\t * both fields appropriately.\n> -\t\t */\n> -\t\trevs->ignore_merges = 0;\n> -\t\trevs->match_missing = 1;\n> -\t} else if (!strcmp(arg, \"-c\")) {\n> -\t\trevs->diff = 1;\n> -\t\trevs->dense_combined_merges = 0;\n> -\t\trevs->combine_merges = 1;\n> -\t} else if (!strcmp(arg, \"--cc\")) {\n> -\t\trevs->diff = 1;\n> -\t\trevs->dense_combined_merges = 1;\n> -\t\trevs->combine_merges = 1;\n> -\t} else if (!strcmp(arg, \"--no-diff-merges\")) {\n> -\t\trevs->ignore_merges = 1;\n> -\t} else if (!strcmp(arg, \"--combined-all-paths\")) {\n> -\t\trevs->diff = 1;\n> -\t\trevs->combined_all_paths = 1;\n> -\t} else if ((argcount = parse_long_opt(\"diff-merges\", argv, &optarg))) {\n> -\t\tif (!strcmp(optarg, \"off\")) {\n> -\t\t\trevs->ignore_merges = 1;\n> -\t\t} else {\n> -\t\t\tdie(_(\"unknown value for --diff-merges: %s\"), optarg);\n> -\t\t}\n> -\t} else\n> -\t\treturn 0;\n> -\n> -\treturn 1;\n> -}\n> -\n> -static void setup_diff_merges_revs(struct rev_info *revs)\n> -{\n> -\tif (revs->combine_merges && revs->ignore_merges < 0)\n> -\t\trevs->ignore_merges = 0;\n> -\tif (revs->ignore_merges < 0)\n> -\t\trevs->ignore_merges = 1;\n> -\tif (revs->combined_all_paths && !revs->combine_merges)\n> -\t\tdie(\"--combined-all-paths makes no sense without -c or --cc\");\n> -}\n> -\n> -void rev_diff_merges_first_parent_defaults_to_enable(struct rev_info *revs) {\n> -\tif (revs->first_parent_only && revs->ignore_merges < 0)\n> -\t\trevs->ignore_merges = 0;\n> -}\n> -\n> -void rev_diff_merges_default_to_dense_combined(struct rev_info *revs) {\n> -\tif (revs->ignore_merges < 0) {\n> -\t\t/* There was no \"-m\" variant on the command line */\n> -\t\trevs->ignore_merges = 0;\n> -\t\tif (!revs->first_parent_only && !revs->combine_merges) {\n> -\t\t\t/* No \"--first-parent\", \"-c\", or \"--cc\" */\n> -\t\t\trevs->combine_merges = 1;\n> -\t\t\trevs->dense_combined_merges = 1;\n> -\t\t}\n> -\t}\n> -}\n> -\n>  static int handle_revision_opt(struct rev_info *revs, int argc, const char **argv,\n>  \t\t\t       int *unkc, const char **unkv,\n>  \t\t\t       const struct setup_revision_opt* opt)\n> diff --git a/revision.h b/revision.h\n> index 3dd0229f4edc..f6bf860d19e5 100644\n> --- a/revision.h\n> +++ b/revision.h\n> @@ -456,7 +456,4 @@ int rewrite_parents(struct rev_info *revs,\n>   */\n>  struct commit_list *get_saved_parents(struct rev_info *revs, const struct commit *commit);\n>  \n> -void rev_diff_merges_default_to_dense_combined(struct rev_info *revs);\n> -void rev_diff_merges_first_parent_defaults_to_enable(struct rev_info *revs);\n> -\n>  #endif\n"},{"id":"411194","messageId":"xmqq360nk859.fsf@gitster.c.googlers.com","threadId":"54550","inReplyTo":"20201108213838.4880-8-sorganov@gmail.com","subject":"Re: [PATCH v1 07/27] diff-merges: move checks for first_parent_only out of the module","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2020-12-03T01:09:22Z","receivedAt":"2020-12-03T01:10:13Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Sergey Organov <sorganov@gmail.com> writes:\n\n> The checks for first_parent_only don't in fact belong to this module,\n> as the primary purpose of this flag is history traversal limiting, so\n> get it out of this module and rename the\n>\n> diff_merges_first_parent_defaults_to_enable()\n>\n> to\n>\n> diff_merges_default_to_enable()\n\nAgain, neither is a great name.\n\nMore importantly, I do not think that I agree with the reasoning\ngiven in the first paragraph.  The first-parent-only traversal means\nthat we pretend there is no second and later parents, so it makes\nquite a lot of sense that the choice of that option affects how a\nmerge commit discovered during the traversal is show by default\n(namely, as if it is just a single-parent commit).\n\nIf there are other reasons why we want to force the callers to check\nfor first-parent option (for example, it may make it easier to tweak\nhow each caller makes its decisions separately in later steps of\nthis series), the changes proposed by this step may be a right\nsolution, so I am not outright opposed to this patch, but the\nrationale given above is not a strong enough justification for the\nchange, at least to me.\n\n> +void diff_merges_default_to_enable(struct rev_info *revs) {\n\nPerhaps \"show_merges_by_default()\".\n\n> +\tif (revs->ignore_merges < 0)\t\t/* No -m */\n>  \t\trevs->ignore_merges = 0;\n\nPerhaps \"show_merges_in_cc_by_default()\" (or \"cc\" spelled out as\n\"dense_combined\").\n\n>  void diff_merges_default_to_dense_combined(struct rev_info *revs) {\n> -\tif (revs->ignore_merges < 0) {\n> -\t\t/* There was no \"-m\" variant on the command line */\n> +\tif (revs->ignore_merges < 0) {\t\t/* No -m */\n>  \t\trevs->ignore_merges = 0;\n> -\t\tif (!revs->first_parent_only && !revs->combine_merges) {\n> -\t\t\t/* No \"--first-parent\", \"-c\", or \"--cc\" */\n> +\t\tif (!revs->combine_merges) {\t/* No -c/--cc\" */\n>  \t\t\trevs->combine_merges = 1;\n>  \t\t\trevs->dense_combined_merges = 1;\n>  \t\t}\n> diff --git a/diff-merges.h b/diff-merges.h\n> index 648c410497cb..cf411414898d 100644\n> --- a/diff-merges.h\n> +++ b/diff-merges.h\n> @@ -11,7 +11,7 @@ void diff_merges_setup_revs(struct rev_info *revs);\n>  \n>  void diff_merges_default_to_dense_combined(struct rev_info *revs);\n>  \n> -void diff_merges_first_parent_defaults_to_enable(struct rev_info *revs);\n> +void diff_merges_default_to_enable(struct rev_info *revs);\n>  \n>  \n>  #endif\n"},{"id":"411201","messageId":"xmqqblfbihl9.fsf@gitster.c.googlers.com","threadId":"54550","inReplyTo":"xmqqim9jk8zf.fsf@gitster.c.googlers.com","subject":"Re: [PATCH v1 04/27] revision: provide implementation for diff merges tweaks","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2020-12-03T05:28:18Z","receivedAt":"2020-12-03T05:29:03Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Is your naming convention that \"rev_diff_\" is the common prefix?\n> What's the significance of \"_diff\" part?  After all, these are about\n> tweaking the setting in the rev_info structure, so how about\n>\n> \trevinfo_show_merges_in_dense_combined_by_default(rev);\n> \trevinfo_show_merges_by_default_with_first_parent(rev);\n>\n> perhaps, using just \"revinfo_\" as the common prefix?\n\nActually, I'd like to take these suggestions back.  I do not think\nthese names that describe \"what the function does\" are good names at\nall.  If we can name them after what they are for, we'd be much\nbetter off.\n\nGiven that one is part of the tweak for \"show\" and the other part of\n\"log\", I presume that one is to set-up default for showing a merge\nin the context of the \"show\" command, and the other is the same for\nthe \"log\" (actually \"log -p\") command.  So perhaps\n\n\tdiff_merges_set_default_for_show(revs);\n\tdiff_merges_set_default_for_log(revs);\n\nare good names that tells us where they should be used and what for.\nThe former is to set up the default parameters to handle a merge\ncommit in the context of the \"show\" command, and the latter is the\nsame for the \"log\" command.  Naming them that way, we can then tweak\nwhat should happen for \"show\" by default without touching the caller\nif we wanted to (perhaps, \"when doing first-parent traversal, really\npretend that all the commits we see are single-parent, so show the\nchange relative to its first parent by default without even\nrequiring -m\" might be something the latter can learn later).\n\nThanks.\n\n\n"},{"id":"411202","messageId":"CABPp-BESWpqska++EsfxfbncyV0kNo1RGLjF+1BiV=D6zLx2LQ@mail.gmail.com","threadId":"54550","inReplyTo":"20201108213838.4880-10-sorganov@gmail.com","subject":"Re: [PATCH v1 09/27] diff-merges: re-arrange functions to match the order they are called in","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2020-12-03T05:52:02Z","receivedAt":"2020-12-03T05:53:16Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Sun, Nov 8, 2020 at 1:43 PM Sergey Organov <sorganov@gmail.com> wrote:\n>\n> For clarity, define public functions in the order they are called, to\n> make logic inter-dependencies easier to grok.\n\nYou added diff-merges.[ch] earlier in this series.  Why not just add\nthem in the correct order initially instead of adding another patch\nlater in the series?\n\n>\n> Signed-off-by: Sergey Organov <sorganov@gmail.com>\n> ---\n>  diff-merges.c | 24 ++++++++++++++----------\n>  diff-merges.h |  7 +++----\n>  2 files changed, 17 insertions(+), 14 deletions(-)\n>\n> diff --git a/diff-merges.c b/diff-merges.c\n> index bb08a92e3b36..8536941e0b56 100644\n> --- a/diff-merges.c\n> +++ b/diff-merges.c\n> @@ -2,6 +2,10 @@\n>\n>  #include \"revision.h\"\n>\n> +/*\n> + * Public functions. They are in the order they are called.\n> + */\n> +\n>  void diff_merges_init_revs(struct rev_info *revs) {\n>         revs->ignore_merges = -1;\n>  }\n> @@ -44,16 +48,6 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {\n>         return 1;\n>  }\n>\n> -void diff_merges_setup_revs(struct rev_info *revs)\n> -{\n> -       if (revs->combine_merges && revs->ignore_merges < 0)\n> -               revs->ignore_merges = 0;\n> -       if (revs->ignore_merges < 0)\n> -               revs->ignore_merges = 1;\n> -       if (revs->combined_all_paths && !revs->combine_merges)\n> -               die(\"--combined-all-paths makes no sense without -c or --cc\");\n> -}\n> -\n>  void diff_merges_default_to_first_parent(struct rev_info *revs) {\n>         if (revs->ignore_merges < 0)            /* No -m */\n>                 revs->ignore_merges = 0;\n> @@ -68,3 +62,13 @@ void diff_merges_default_to_dense_combined(struct rev_info *revs) {\n>                 }\n>         }\n>  }\n> +\n> +void diff_merges_setup_revs(struct rev_info *revs)\n> +{\n> +       if (revs->combine_merges && revs->ignore_merges < 0)\n> +               revs->ignore_merges = 0;\n> +       if (revs->ignore_merges < 0)\n> +               revs->ignore_merges = 1;\n> +       if (revs->combined_all_paths && !revs->combine_merges)\n> +               die(\"--combined-all-paths makes no sense without -c or --cc\");\n> +}\n> diff --git a/diff-merges.h b/diff-merges.h\n> index 20b727bd734f..4b023c385d00 100644\n> --- a/diff-merges.h\n> +++ b/diff-merges.h\n> @@ -7,11 +7,10 @@ void diff_merges_init_revs(struct rev_info *revs);\n>\n>  int diff_merges_parse_opts(struct rev_info *revs, const char **argv);\n>\n> -void diff_merges_setup_revs(struct rev_info *revs);\n> -\n> -void diff_merges_default_to_dense_combined(struct rev_info *revs);\n> -\n>  void diff_merges_default_to_first_parent(struct rev_info *revs);\n>\n> +void diff_merges_default_to_dense_combined(struct rev_info *revs);\n> +\n> +void diff_merges_setup_revs(struct rev_info *revs);\n>\n>  #endif\n> --\n> 2.25.1\n>\n"},{"id":"411203","messageId":"CABPp-BGH0+M_6gYYfYsp54X9DjKM4mv8Vssoo3uZtDAY1_Zb1A@mail.gmail.com","threadId":"54550","inReplyTo":"20201101193330.24775-11-sorganov@gmail.com","subject":"Re: [PATCH 10/26] diff-merges: new function diff_merges_suppress()","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2020-12-03T05:52:36Z","receivedAt":"2020-12-03T05:54:24Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Sun, Nov 1, 2020 at 11:36 AM Sergey Organov <sorganov@gmail.com> wrote:\n>\n> This function sets all the relevant flags to disabled state, so that\n> no code that checks only one of them get it wrong.\n>\n> Then we call this new function everywhere where diff merges output\n> suppression is needed.\n>\n> Signed-off-by: Sergey Organov <sorganov@gmail.com>\n> ---\n>  builtin/merge.c |  3 ++-\n>  diff-merges.c   | 18 ++++++++++++++----\n>  diff-merges.h   |  2 ++\n>  fmt-merge-msg.c |  3 ++-\n>  4 files changed, 20 insertions(+), 6 deletions(-)\n>\n> diff --git a/builtin/merge.c b/builtin/merge.c\n> index 9d5359edc2f7..1f7b69982b40 100644\n> --- a/builtin/merge.c\n> +++ b/builtin/merge.c\n> @@ -14,6 +14,7 @@\n>  #include \"lockfile.h\"\n>  #include \"run-command.h\"\n>  #include \"diff.h\"\n> +#include \"diff-merges.h\"\n>  #include \"refs.h\"\n>  #include \"refspec.h\"\n>  #include \"commit.h\"\n> @@ -400,7 +401,7 @@ static void squash_message(struct commit *commit, struct commit_list *remotehead\n>         printf(_(\"Squash commit -- not updating HEAD\\n\"));\n>\n>         repo_init_revisions(the_repository, &rev, NULL);\n> -       rev.ignore_merges = 1;\n> +       diff_merges_suppress(&rev);\n>         rev.commit_format = CMIT_FMT_MEDIUM;\n>\n>         commit->object.flags |= UNINTERESTING;\n> diff --git a/diff-merges.c b/diff-merges.c\n> index 8536941e0b56..25bd9b12e667 100644\n> --- a/diff-merges.c\n> +++ b/diff-merges.c\n> @@ -2,6 +2,13 @@\n>\n>  #include \"revision.h\"\n>\n> +static void suppress(struct rev_info *revs) {\n> +       revs->ignore_merges = 1;\n> +       revs->first_parent_merges = 0;\n> +       revs->combine_merges = 0;\n> +       revs->dense_combined_merges = 0;\n> +}\n\nThe function name is not so helpful; why not put all this code\ndirectly in diff_merges_suppress()?\n\n> +\n>  /*\n>   * Public functions. They are in the order they are called.\n>   */\n> @@ -29,16 +36,15 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {\n>                 revs->combine_merges = 1;\n>         } else if (!strcmp(arg, \"--cc\")) {\n>                 revs->diff = 1;\n> -               revs->dense_combined_merges = 1;\n> -               revs->combine_merges = 1;\n> +               set_dense_combined(revs);\n>         } else if (!strcmp(arg, \"--no-diff-merges\")) {\n> -               revs->ignore_merges = 1;\n> +               suppress(revs);\n>         } else if (!strcmp(arg, \"--combined-all-paths\")) {\n>                 revs->diff = 1;\n>                 revs->combined_all_paths = 1;\n>         } else if ((argcount = parse_long_opt(\"diff-merges\", argv, &optarg))) {\n>                 if (!strcmp(optarg, \"off\")) {\n> -                       revs->ignore_merges = 1;\n> +                       suppress(revs);\n>                 } else {\n>                         die(_(\"unknown value for --diff-merges: %s\"), optarg);\n>                 }\n> @@ -48,6 +54,10 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {\n>         return 1;\n>  }\n>\n> +void diff_merges_suppress(struct rev_info *revs) {\n> +       suppress(revs);\n> +}\n\n...especially since all this function does is call suppress()?\n\n\n> +\n>  void diff_merges_default_to_first_parent(struct rev_info *revs) {\n>         if (revs->ignore_merges < 0)            /* No -m */\n>                 revs->ignore_merges = 0;\n> diff --git a/diff-merges.h b/diff-merges.h\n> index 4b023c385d00..32720bc9b40f 100644\n> --- a/diff-merges.h\n> +++ b/diff-merges.h\n> @@ -7,6 +7,8 @@ void diff_merges_init_revs(struct rev_info *revs);\n>\n>  int diff_merges_parse_opts(struct rev_info *revs, const char **argv);\n>\n> +void diff_merges_suppress(struct rev_info *revs);\n> +\n>  void diff_merges_default_to_first_parent(struct rev_info *revs);\n>\n>  void diff_merges_default_to_dense_combined(struct rev_info *revs);\n> diff --git a/fmt-merge-msg.c b/fmt-merge-msg.c\n> index bd22e1ea8865..abc3403fb820 100644\n> --- a/fmt-merge-msg.c\n> +++ b/fmt-merge-msg.c\n> @@ -2,6 +2,7 @@\n>  #include \"refs.h\"\n>  #include \"object-store.h\"\n>  #include \"diff.h\"\n> +#include \"diff-merges.h\"\n>  #include \"revision.h\"\n>  #include \"tag.h\"\n>  #include \"string-list.h\"\n> @@ -668,7 +669,7 @@ int fmt_merge_msg(struct strbuf *in, struct strbuf *out,\n>                 head = lookup_commit_or_die(&head_oid, \"HEAD\");\n>                 repo_init_revisions(the_repository, &rev, NULL);\n>                 rev.commit_format = CMIT_FMT_ONELINE;\n> -               rev.ignore_merges = 1;\n> +               diff_merges_suppress(&rev);\n>                 rev.limited = 1;\n>\n>                 strbuf_complete_line(out);\n> --\n> 2.25.1\n>\n"},{"id":"411204","messageId":"CABPp-BGZO+7bRdCAGFdetOkmwyFnHxDPQ=SD4f6TSa9ZYGFn=A@mail.gmail.com","threadId":"54550","inReplyTo":"20201108213838.4880-25-sorganov@gmail.com","subject":"Re: [PATCH v1 24/27] doc/git-log: describe new --diff-merges options","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2020-12-03T06:09:25Z","receivedAt":"2020-12-03T06:10:18Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Sun, Nov 8, 2020 at 1:46 PM Sergey Organov <sorganov@gmail.com> wrote:\n>\n> Describe all the new --diff-merges options in the git-log.txt\n>\n> Signed-off-by: Sergey Organov <sorganov@gmail.com>\n> ---\n>  Documentation/git-log.txt | 79 +++++++++++++++++++++++----------------\n>  1 file changed, 46 insertions(+), 33 deletions(-)\n>\n> diff --git a/Documentation/git-log.txt b/Documentation/git-log.txt\n> index 2b8ac5ff882a..de498a189646 100644\n> --- a/Documentation/git-log.txt\n> +++ b/Documentation/git-log.txt\n> @@ -120,45 +120,58 @@ DIFF FORMATTING\n>  By default, `git log` does not generate any diff output. The options\n>  below can be used to show the changes made by each commit.\n>\n> -Note that unless one of `-c`, `--cc`, or `-m` is given, merge commits\n> -will never show a diff, even if a diff format like `--patch` is\n> -selected, nor will they match search options like `-S`. The exception is\n> -when `--first-parent` is in use, in which merges are treated like normal\n> -single-parent commits (this can be overridden by providing a\n> -combined-diff option or with `--no-diff-merges`).\n> +Note that unless one of `--diff-merges` variants (including short\n> +`-m`, `-c`, and `--cc` options) is explicitly given, merge commits\n> +will not show a diff, even if a diff format like `--patch` is\n> +selected, nor will they match search options like `-S`. The exception\n> +is when `--first-parent` is in use, in which case\n> +`--diff-merges=first-parent` is implied.\n>\n> --c::\n> -       With this option, diff output for a merge commit\n> -       shows the differences from each of the parents to the merge result\n> -       simultaneously instead of showing pairwise diff between a parent\n> -       and the result one at a time. Furthermore, it lists only files\n> -       which were modified from all parents.\n> -\n> ---cc::\n> -       This flag implies the `-c` option and further compresses the\n> -       patch output by omitting uninteresting hunks whose contents in\n> -       the parents have only two variants and the merge result picks\n> -       one of them without modification.\n> +--diff-merges=(off|none|first-parent|separate|combined|dense-combined)::\n> +--no-diff-merges::\n> +       Specify diff format to be used for merge commits. This has no\n> +       effect unless diff output is enabled in the first place (e.g.,\n> +       with `--patch` option.)\n\nThis seems inconsistent with c7eaf8b4c3 (\"log: when --cc is given,\ndefault to -p unless told otherwise\", 2015-08-20); shouldn't these\nimply -p?\n\n> ++\n> +--diff-merges=(off|none):::\n> +--no-diff-merges:::\n> +       (default) Disable output of diffs for merge commits. Useful to\n> +       override implied value.\n> ++\n> +--diff-merges=first-parent:::\n> +       This option makes merge commits show the full diff with\n> +       respect to the first parent only, exactly like  regular\n> +       commits.\n\nNot sure that \"exactly like regular commits\" is helpful here; I'd\npersonally rather cut those four words out.  I'm worried it'll be\ntaken not as an implementation explanation, but as a \"this treats\nmerge commits in the natural way that regular commits are\" which users\nmay mistakenly translate to \"it shows what changes the user manually\nmade as part of the commit\" which is not at all the correct mapping.\n\n> ++\n> +--diff-merges=separate:::\n> +-m:::\n> +       This makes merge commits show the full diff with respect to\n> +       each of the parents. Separate log entry and diff is generated\n> +       for each parent.\n> ++\n> +--diff-merges=combined:::\n> +-c:::\n> +       With this option, diff output for a merge commit shows the\n> +       differences from each of the parents to the merge result\n> +       simultaneously instead of showing pairwise diff between a\n> +       parent and the result one at a time. Furthermore, it lists\n> +       only files which were modified from all parents.\n> ++\n> +--diff-merges=dense-combined:::\n> +--cc:::\n> +       With this option the output produced by\n> +       `--diff-merges=combined` is further compressed by omitting\n> +       uninteresting hunks whose contents in the parents have only\n> +       two variants and the merge result picks one of them without\n> +       modification.\n>\n>  --combined-all-paths::\n>         This flag causes combined diffs (used for merge commits) to\n>         list the name of the file from all parents.  It thus only has\n> -       effect when -c or --cc are specified, and is likely only\n> -       useful if filename changes are detected (i.e. when either\n> -       rename or copy detection have been requested).\n> +       effect when `--diff-merges=[dense-]combined` is in use, and\n> +       is likely only useful if filename changes are detected (i.e.\n> +       when either rename or copy detection have been requested).\n>\n> --m::\n> -       This flag makes the merge commits show the full diff like\n> -       regular commits; for each merge parent, a separate log entry\n> -       and diff is generated. An exception is that only diff against\n> -       the first parent is shown when `--first-parent` option is given;\n> -       in that case, the output represents the changes the merge\n> -       brought _into_ the then-current branch.\n> -\n> ---diff-merges=off::\n> ---no-diff-merges::\n> -       Disable output of diffs for merge commits (default). Useful to\n> -       override `-m`, `-c`, or `--cc`.\n>\n>  :git-log: 1\n>  include::diff-options.txt[]\n> --\n> 2.25.1\n"},{"id":"411207","messageId":"CABPp-BHdhvLRe4jCSsRtPrbh2=kwJxEQs0Dx+Ng1Vutx8Hdqqw@mail.gmail.com","threadId":"54550","inReplyTo":"20201108213838.4880-1-sorganov@gmail.com","subject":"Re: [PATCH v1 00/27] git-log: implement new --diff-merge options","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2020-12-03T07:54:08Z","receivedAt":"2020-12-03T07:55:23Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Sun, Nov 8, 2020 at 1:43 PM Sergey Organov <sorganov@gmail.com> wrote:\n>\n> These patch series implement new set of options governing the diff output\n> of merge commits, all under the umbrella of the single --diff-merges=<mode>\n> option. Most of the new options being synonyms for -m/-c/--cc options,\n> there is also additional functionality provided, allowing to get the format\n> of \"-p --first-parent\" without change in history traversal that\n> --first-parent option causes.\n>\n> The net result of these series are the following new options:\n>\n> --diff-merges=   |  old equivalent\n> -----------------+----------------\n> first-parent     | --first-parent (only format implications)\n> separate         | -m\n> combined         | -c\n> dense-combined   | --cc\n\nInteresting.  I have some local patches implementing another choice,\nwith the new flag --remerge-diff.  This flag will cause `git show` or\n`git log` to automatically remerge the two parents in a 2-parent merge\ncommit, and then diff the merge commit against that automatic merge,\nshowing the result.  Thus, the diff for a merge commit is likely to be\nempty if the merge was clean, and is likely to show the removal of\nconflict markers if the merge was not clean.\n\nI'm curious how it'd interact with this new option.  Would it also get\na name, e.g. --diff-merges=remerge-diff?  Feels like a mouthful, but I\ncan't come up with anything better.\n\nAlso, I'm curious how it'd interact with another option I added, named\n--remerge-diff-only.  This latter option modifies revision traversal\nin that it skips octopus merges, root commits, and single parent\ncommits IF no cherry-pick or revert information can be found.  If it\nfinds a 2-parent merge commit, it behaves like --remerge-diff.  If it\nfinds a 1-parent commit with cherry-pick or revert information, it'll\ndo an in memory repeat of that cherry-pick (or revert) and then diff\nthe actual commit against what the automatic cherry-pick would\nperform.  Again, that likely means an empty diff if the automatic\ncherry-pick was clean, and showing any changes made by the user to\ncomplete the original cherry-pick (such as deleting conflict markers\nand picking which chunks from which side to keep) if the automatic\ncherry-pick was not clean.  (I suspect --remerge-diff-only is much\nmore likely to be used with `git show` than with `git log`.)  Anyway,\nyour changes seem to suggest that anything relating to how diffs for\nmerges are handled should be documented in the same section, but\n--remerge-diff-only doesn't fit.  And it'd seem odd to have\n--remerge-diff and --remerge-diff-only not show up in adjacently but\nbe split into separate sections.  Any ideas?\n\n(This doesn't matter yet, since I'm waiting for merge-ort to be\ncompleted before submitting the --remerge-diff and --remerge-diff-only\npatches, but thought I'd bring it up as food for thought and to query\nif others have good ideas about how to handle the names and\ndocumentation location.)\n\n> The series also cleanup logic of handling of diff merges options and fix an\n> issue found in the original implementation where logically mutually\n> exclusive options -m/-c/--cc failed to actually override each other.\n>\n> The series start with the set of pure refactoring commits that are expected\n> to introduce no functional changes. These are all commits up to and\n> including:\n>\n> \"diff-merges: revise revs->diff flag handling\"\n>\n> The aim of these commits is to isolate options handling for diff merges so\n> that it could be easily understood and tweaked to ease introduction of the\n> new options.\n>\n> Then the fix of -m/-c/-cc overriding issue follows, starting with a failing\n> test and followed by the fix.\n>\n> Then follows a little bit of additional refactoring in order to prepare for\n> introduction of the new options, and finally the series are finished by the\n> implementation, testing, and documentation update for the new options.\n>\n> Updates in v1:\n\nA minor point, but this should have been labelled v2.  The unlabelled\noriginal submission is v1.\n\n>\n>         * Added documentation fix for git-show to include --diff-merges.\n>         * Fixed typos in commit messages noticed by Philip Oakley.\n>\n> Sergey Organov (27):\n>   revision: factor out parsing of diff-merge related options\n>   revision: factor out setup of diff-merge related settings\n>   revision: factor out initialization of diff-merge related settings\n>   revision: provide implementation for diff merges tweaks\n>   revision: move diff merges functions to its own diff-merges.c\n>   diff-merges: rename all functions to have common prefix\n>   diff-merges: move checks for first_parent_only out of the module\n>   diff-merges: rename diff_merges_default_to_enable() to match semantics\n>   diff-merges: re-arrange functions to match the order they are called\n>     in\n>   diff-merges: new function diff_merges_suppress()\n>   diff-merges: new function diff_merges_set_dense_combined_if_unset()\n>   diff-merges: introduce revs->first_parent_merges flag\n>   diff-merges: revise revs->diff flag handling\n>   t4013: support test_expect_failure through ':failure' magic\n>   t4013: add tests for -m failing to override -c/--cc\n>   diff-merges: fix -m to properly override -c/--cc\n>   diff-merges: split 'ignore_merges' field\n>   diff-merges: group diff-merge flags next to each other inside\n>     'rev_info'\n>   diff-merges: get rid of now empty diff_merges_init_revs()\n>   diff-merges: refactor opt settings into separate functions\n>   diff-merges: make -m/-c/--cc explicitly mutually exclusive\n>   diff-merges: implement new values for --diff-merges\n>   t4013: add test for --diff-merges=first-parent\n>   doc/git-log: describe new --diff-merges options\n>   doc/diff-generate-patch: mention new --diff-merges option\n>   doc/rev-list-options: document --first-parent implies\n>     --diff-merges=first-parent\n>   doc/git-show: include --diff-merges description\n>\n>  Documentation/diff-generate-patch.txt         |   6 +-\n>  Documentation/diff-options.txt                |  54 +++++\n>  Documentation/git-log.txt                     |  39 ----\n>  Documentation/git-show.txt                    |   8 +-\n>  Documentation/rev-list-options.txt            |   3 +\n>  Makefile                                      |   1 +\n>  builtin/diff-files.c                          |   5 +-\n>  builtin/diff.c                                |   9 +-\n>  builtin/log.c                                 |  18 +-\n>  builtin/merge.c                               |   3 +-\n>  diff-merges.c                                 | 120 +++++++++++\n>  diff-merges.h                                 |  18 ++\n>  fmt-merge-msg.c                               |   3 +-\n>  log-tree.c                                    |  17 +-\n>  revision.c                                    |  38 +---\n>  revision.h                                    |   7 +-\n>  t/t4013-diff-various.sh                       |  10 +-\n>  t/t4013/diff.log_--cc_-m_-p_master            | 200 ++++++++++++++++++\n>  t/t4013/diff.log_-c_-m_-p_master              | 200 ++++++++++++++++++\n>  ...f.log_-p_--diff-merges=first-parent_master | 137 ++++++++++++\n>  20 files changed, 788 insertions(+), 108 deletions(-)\n>  create mode 100644 diff-merges.c\n>  create mode 100644 diff-merges.h\n>  create mode 100644 t/t4013/diff.log_--cc_-m_-p_master\n>  create mode 100644 t/t4013/diff.log_-c_-m_-p_master\n>  create mode 100644 t/t4013/diff.log_-p_--diff-merges=first-parent_master\n>\n> --\n> 2.25.1\n"},{"id":"411223","messageId":"87a6uuj4wx.fsf@osv.gnss.ru","threadId":"54550","inReplyTo":"xmqqv9djk9tv.fsf@gitster.c.googlers.com","subject":"Re: [PATCH v1 01/27] revision: factor out parsing of diff-merge related options","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-03T15:16:46Z","receivedAt":"2020-12-03T15:17:33Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Sergey Organov <sorganov@gmail.com> writes:\n>\n>> Move all the parsing code related to diffing merges into new\n>> parse_diff_merge_opts() function.\n>>\n>> Signed-off-by: Sergey Organov <sorganov@gmail.com>\n>> ---\n>>  revision.c | 66 ++++++++++++++++++++++++++++++++----------------------\n>>  1 file changed, 39 insertions(+), 27 deletions(-)\n>>\n>> diff --git a/revision.c b/revision.c\n>> index aa6221204081..a09f4872acd7 100644\n>> --- a/revision.c\n>> +++ b/revision.c\n>> @@ -2153,6 +2153,44 @@ static void add_message_grep(struct rev_info *revs, const char *pattern)\n>>  \tadd_grep(revs, pattern, GREP_PATTERN_BODY);\n>>  }\n>>  \n>> +static int parse_diff_merge_opts(struct rev_info *revs, const char **argv) {\n>> +\tint argcount;\n>> +\tconst char *optarg;\n>> +\tconst char *arg = argv[0];\n>> +\n>> +\tif (!strcmp(arg, \"-m\")) {\n>> +\t\t/*\n>> +\t\t * To \"diff-index\", \"-m\" means \"match missing\", and to the \"log\"\n>> +\t\t * family of commands, it means \"show full diff for merges\". Set\n>> +\t\t * both fields appropriately.\n>> +\t\t */\n>> +\t\trevs->ignore_merges = 0;\n>> +\t\trevs->match_missing = 1;\n>> +\t} else if (!strcmp(arg, \"-c\")) {\n>> +\t\trevs->diff = 1;\n>> +\t\trevs->dense_combined_merges = 0;\n>> +\t\trevs->combine_merges = 1;\n>> +\t} else if (!strcmp(arg, \"--cc\")) {\n>> +\t\trevs->diff = 1;\n>> +\t\trevs->dense_combined_merges = 1;\n>> +\t\trevs->combine_merges = 1;\n>> +\t} else if (!strcmp(arg, \"--no-diff-merges\")) {\n>> +\t\trevs->ignore_merges = 1;\n>> +\t} else if (!strcmp(arg, \"--combined-all-paths\")) {\n>> +\t\trevs->diff = 1;\n>> +\t\trevs->combined_all_paths = 1;\n>> +\t} else if ((argcount = parse_long_opt(\"diff-merges\", argv, &optarg))) {\n>\n> The reordering of if/else if/ cascade from the original, which\n> serves no apparent purpose, makes reviewing a tad harder than\n> necessary, but the conversion at this point seems wrong.\n\nSorry for the reordering, I didn't notice it when I cleared up the\nseries.\n\n>\n> The original allowed parse_long_opt() to potentially return 2\n> (i.e. \"diff-merges\" and \"off\" appear as separate tokens on the\n> command line), but the return value stored in argcount here is\n> discarded, without affecting the return value from this function,\n> which is fed back to the original in handle_revision_opt() below.\n\nNice catch!\n\n>\n>> +\t\tif (!strcmp(optarg, \"off\")) {\n>> +\t\t\trevs->ignore_merges = 1;\n>> +\t\t} else {\n>> +\t\t\tdie(_(\"unknown value for --diff-merges: %s\"), optarg);\n>> +\t\t}\n>\n> To correct the above bug, it probably is sufficient to add\n>\n> \t\treturn argcount;\n>\n> here.\n\nRight, but not enough. \"argcount\" should also be set to 1 at the\nbeginning of the function, to avoid returning uninitialized value here.\n\nFixed for the next series.\n\nThanks,\n-- Sergey Organov\n"},{"id":"411227","messageId":"874kl2j42e.fsf@osv.gnss.ru","threadId":"54550","inReplyTo":"xmqqmtyvk9jv.fsf@gitster.c.googlers.com","subject":"Re: [PATCH v1 03/27] revision: factor out initialization of diff-merge related settings","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-03T15:35:05Z","receivedAt":"2020-12-03T15:36:07Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Sergey Organov <sorganov@gmail.com> writes:\n>\n>> Move initialization code related to diffing merges into new\n>> init_diff_merge_revs() function.\n>>\n>> Signed-off-by: Sergey Organov <sorganov@gmail.com>\n>> ---\n>>  revision.c | 8 +++++++-\n>>  1 file changed, 7 insertions(+), 1 deletion(-)\n>>\n>> diff --git a/revision.c b/revision.c\n>> index 739295bb9ff4..bc568fb79778 100644\n>> --- a/revision.c\n>> +++ b/revision.c\n>> @@ -1805,6 +1805,8 @@ static int add_parents_only(struct rev_info *revs, const char *arg_, int flags,\n>>  \treturn 1;\n>>  }\n>>  \n>> +static void init_diff_merge_revs(struct rev_info *revs);\n>> +\n>\n> It is not wrong per-se, but I do not see why we do not define the\n> function here, not just forward-declare it like so.\n\nI wanted to keep merge-diff functions definitions at one place to\nsimplify future refactoring by moving all of them into separate file, to\navoid scatter-gathering definitions from multiple places in the\noriginal file.\n\n>\n>>  void repo_init_revisions(struct repository *r,\n>>  \t\t\t struct rev_info *revs,\n>>  \t\t\t const char *prefix)\n>> @@ -1813,7 +1815,7 @@ void repo_init_revisions(struct repository *r,\n>>  \n>>  \trevs->repo = r;\n>>  \trevs->abbrev = DEFAULT_ABBREV;\n>> -\trevs->ignore_merges = -1;\n>> +\tinit_diff_merge_revs(revs);\n>>  \trevs->simplify_history = 1;\n>>  \trevs->pruning.repo = r;\n>>  \trevs->pruning.flags.recursive = 1;\n>> @@ -2153,6 +2155,10 @@ static void add_message_grep(struct rev_info *revs, const char *pattern)\n>>  \tadd_grep(revs, pattern, GREP_PATTERN_BODY);\n>>  }\n>>  \n>> +static void init_diff_merge_revs(struct rev_info *revs) {\n>> +\trevs->ignore_merges = -1;\n>> +}\n>\n> Style.  A brace that begins a function body begins its own line.\n\nOops! There are a few cases in the git sources where this style is used,\nand somehow my eye catch it and I did entire series in this style.\n\nNow the question is: what do I do about it? Do I need to rework the\nentire series in the correct style, or would it be enough to fix the\nstyle as a separate commit at the end of the series?\n\n> In any case, I'd move this new definition before its sole caller; that\n> way we do not even need an extra forward-declaration.\n\nI'd do it too, except in this particular case, first, it actually makes\nsome sense to have function definition here, see above, and second, it'd\ndisappear along with declaration in the next commit anyway. I'm OK to\nchange this though if you still find this issue essential.\n\nThanks,\n-- Sergey Organov\n"},{"id":"411228","messageId":"87wnxyhp6g.fsf@osv.gnss.ru","threadId":"54550","inReplyTo":"CABPp-BESWpqska++EsfxfbncyV0kNo1RGLjF+1BiV=D6zLx2LQ@mail.gmail.com","subject":"Re: [PATCH v1 09/27] diff-merges: re-arrange functions to match the order they are called in","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-03T15:41:59Z","receivedAt":"2020-12-03T15:42:58Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Elijah Newren <newren@gmail.com> writes:\n\n> On Sun, Nov 8, 2020 at 1:43 PM Sergey Organov <sorganov@gmail.com> wrote:\n>>\n>> For clarity, define public functions in the order they are called, to\n>> make logic inter-dependencies easier to grok.\n>\n> You added diff-merges.[ch] earlier in this series.  Why not just add\n> them in the correct order initially instead of adding another patch\n> later in the series?\n\nWell, I did consider it, but there are 2 issues that stopped me.\n\nFirst, I didn't want to rearrange functions as I move them from\nrevision.c, to avoid mixed commit to simplify review, and second, I\ndidn't want to rearrange them in the original to perform as little\nchanges to the codebase as possible before isolating my work\ninto diff-merges.[ch].\n\nHope it makes sense.\n\nThanks,\n-- Sergey Organov\n"},{"id":"411237","messageId":"87r1o6ho6h.fsf@osv.gnss.ru","threadId":"54550","inReplyTo":"xmqqblfbihl9.fsf@gitster.c.googlers.com","subject":"Re: [PATCH v1 04/27] revision: provide implementation for diff merges tweaks","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-03T16:03:34Z","receivedAt":"2020-12-03T16:04:22Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Junio C Hamano <gitster@pobox.com> writes:\n>\n>> Is your naming convention that \"rev_diff_\" is the common prefix?\n>> What's the significance of \"_diff\" part?  After all, these are about\n>> tweaking the setting in the rev_info structure, so how about\n>>\n>> \trevinfo_show_merges_in_dense_combined_by_default(rev);\n>> \trevinfo_show_merges_by_default_with_first_parent(rev);\n>>\n>> perhaps, using just \"revinfo_\" as the common prefix?\n>\n> Actually, I'd like to take these suggestions back.  I do not think\n> these names that describe \"what the function does\" are good names at\n> all.  If we can name them after what they are for, we'd be much\n> better off.\n>\n> Given that one is part of the tweak for \"show\" and the other part of\n> \"log\", I presume that one is to set-up default for showing a merge\n> in the context of the \"show\" command, and the other is the same for\n> the \"log\" (actually \"log -p\") command.  So perhaps\n>\n> \tdiff_merges_set_default_for_show(revs);\n> \tdiff_merges_set_default_for_log(revs);\n>\n> are good names that tells us where they should be used and what for.\n\nSorry, here I disagree, see below.\n\n> The former is to set up the default parameters to handle a merge\n> commit in the context of the \"show\" command, and the latter is the\n> same for the \"log\" command.  Naming them that way, we can then tweak\n> what should happen for \"show\" by default without touching the caller\n> if we wanted to (perhaps, \"when doing first-parent traversal, really\n> pretend that all the commits we see are single-parent, so show the\n> change relative to its first parent by default without even\n> requiring -m\" might be something the latter can learn later).\n\nI have multiple objections to this:\n\n1. diff-merges, as a module or unit, is designed to provide needed\nservices to callers, not to dictate where exactly these services are\nto be used.\n\n2. diff-merges, as a module, should not care nor know if \"git log\" or\n\"git show\" (or whatever top-level command), exists at all, so the\nsuggested names are not a good idea to have in the module.\n\n3. The decision how exactly merge commits are to be shown for given user\ncommand should better be expressed in that command, not hidden in the\nimplementation of diff-merges module.\n\n4. Giving functions names by their place of call won't allow to sensibly\nreuse them in other places, if needed, without renaming.\n\nOverall, I believe the functions in the diff-merges unit must be called\nafter what they are doing to the format of the diff output for merges,\nnot after the places they are (currently) called at.\n\nThe functions you suggest, on the other hand, are fine and may have\ntheir place, but they are at higher level of abstraction and should not\nbe part of the low-level diff-merges module.\n\nThanks,\n-- Sergey Organov\n"},{"id":"411255","messageId":"87k0tyhma7.fsf@osv.gnss.ru","threadId":"54550","inReplyTo":"xmqqa6uvk8mv.fsf@gitster.c.googlers.com","subject":"Re: [PATCH v1 05/27] revision: move diff merges functions to its own diff-merges.c","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-03T16:44:32Z","receivedAt":"2020-12-03T16:45:32Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Sergey Organov <sorganov@gmail.com> writes:\n>\n>> diff --git a/diff-merges.h b/diff-merges.h\n>> new file mode 100644\n>> index 000000000000..e0cca3d935d3\n>> --- /dev/null\n>> +++ b/diff-merges.h\n>> @@ -0,0 +1,12 @@\n>> +#ifndef DIFF_MERGES_H\n>> +#define DIFF_MERGES_H\n>\n> Describe what \"diff-merges\" module is about in a comment here.\n\nSure, will do.\n\n> This matters because in 07/27 the log message complains that the\n> first-parent traversal option is checked in the module but it is out\n> of place.  Without defining what the \"module\" is about, the readers\n> would have a hard time agreeing with the justification.\n\nYes, agreed.\n\n>\n> My guess is that this is about deciding how a merge commit is shown\n> in 'log -p' and 'show' output, comparing the commit with its\n> parent(s) in patch output.  With that explained, it may make sense\n> for 07/27 to complain that --first-parent that is primarily a\n> traversal option does also affect how a merge is shown (I do not\n> necessarily agree with the complaint, though)\n\nThe is no complaint that --first-parent affects how merge is shown, at\nleast I didn't ever mean to complain about it.\n\nFrom me there is a complaint that there is no way (before this series)\nto make merge to be shown in the same manner without affecting\ntraversal, but that's not the problem of --first-parent user-visible\nbehavior.\n\nI believe that in general, it'd be best that if an option makes more\nthan 1 thing, it does them by simply implying other options, so that\nuser is able to fine-tune each aspect of behavior independently.\n\nFor example, the design of --first-parent could have been that it simply\nimplies --follow-first-parent and --diff-merges=first-parent, each of\nwhich do exactly one thing: the first defines how graph traversal is\nperformed, and the second defines how merge commits are shown.\n\nOTOH, the resulting design of --first-parent after this series is an\nexample of another approach, also acceptable, where an option performs\nits 1 primary action directly, and the rest -- by implying other\noptions. This design also covers all the possibilities, provided each\nimplicit option could be overridden.\n\nThanks,\nSergey Organov\n"},{"id":"411257","messageId":"CABPp-BG_YT2i_27tqkh_e4mwfkYae-zDCEYL=F+NjYQed2gKAg@mail.gmail.com","threadId":"54550","inReplyTo":"20201108213838.4880-28-sorganov@gmail.com","subject":"Re: [PATCH v1 27/27] doc/git-show: include --diff-merges description","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2020-12-03T16:47:35Z","receivedAt":"2020-12-03T16:48:29Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"Hi,\n\nOn Sun, Nov 8, 2020 at 1:44 PM Sergey Organov <sorganov@gmail.com> wrote:\n>\n> Move description of --diff-merges option from git-log.txt to\n> diff-options.txt so that it is included in the git-show help.\n>\n> While we are at it, make git-show closer to git-log in this area by\n> providing similar wording in the introduction of diff options.\n>\n> Signed-off-by: Sergey Organov <sorganov@gmail.com>\n> ---\n>  Documentation/diff-options.txt | 54 ++++++++++++++++++++++++++++++++++\n>  Documentation/git-log.txt      | 52 --------------------------------\n>  Documentation/git-show.txt     |  8 +++--\n>  3 files changed, 60 insertions(+), 54 deletions(-)\n>\n> diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt\n> index 573fb9bb71e2..f1629887103e 100644\n> --- a/Documentation/diff-options.txt\n> +++ b/Documentation/diff-options.txt\n> @@ -33,6 +33,60 @@ endif::git-diff[]\n>         show the patch by default, or to cancel the effect of `--patch`.\n>  endif::git-format-patch[]\n>\n> +ifdef::git-log[]\n> +Note that unless one of `--diff-merges` variants (including short\n> +`-m`, `-c`, and `--cc` options) is explicitly given, merge commits\n> +will not show a diff, even if a diff format like `--patch` is\n> +selected, nor will they match search options like `-S`. The exception\n> +is when `--first-parent` is in use, in which case\n> +`--diff-merges=first-parent` is implied.\n\nSo, now diff-options says that no diffs are the defaults for merge commits...\n\n> +\n> +--diff-merges=(off|none|first-parent|separate|combined|dense-combined)::\n> +--no-diff-merges::\n> +       Specify diff format to be used for merge commits. This has no\n> +       effect unless diff output is enabled in the first place (e.g.,\n> +       with `--patch` option.)\n> ++\n> +--diff-merges=(off|none):::\n> +--no-diff-merges:::\n> +       (default) Disable output of diffs for merge commits. Useful to\n> +       override implied value.\n> ++\n> +--diff-merges=first-parent:::\n> +       This option makes merge commits show the full diff with\n> +       respect to the first parent only, exactly like  regular\n> +       commits.\n> ++\n> +--diff-merges=separate:::\n> +-m:::\n> +       This makes merge commits show the full diff with respect to\n> +       each of the parents. Separate log entry and diff is generated\n> +       for each parent.\n> ++\n> +--diff-merges=combined:::\n> +-c:::\n> +       With this option, diff output for a merge commit shows the\n> +       differences from each of the parents to the merge result\n> +       simultaneously instead of showing pairwise diff between a\n> +       parent and the result one at a time. Furthermore, it lists\n> +       only files which were modified from all parents.\n> ++\n> +--diff-merges=dense-combined:::\n> +--cc:::\n> +       With this option the output produced by\n> +       `--diff-merges=combined` is further compressed by omitting\n> +       uninteresting hunks whose contents in the parents have only\n> +       two variants and the merge result picks one of them without\n> +       modification.\n> +\n> +--combined-all-paths::\n> +       This flag causes combined diffs (used for merge commits) to\n> +       list the name of the file from all parents.  It thus only has\n> +       effect when `--diff-merges=[dense-]combined` is in use, and\n> +       is likely only useful if filename changes are detected (i.e.\n> +       when either rename or copy detection have been requested).\n> +endif::git-log[]\n> +\n>  -U<n>::\n>  --unified=<n>::\n>         Generate diffs with <n> lines of context instead of\n> diff --git a/Documentation/git-log.txt b/Documentation/git-log.txt\n> index de498a189646..0cacc780bf30 100644\n> --- a/Documentation/git-log.txt\n> +++ b/Documentation/git-log.txt\n> @@ -120,58 +120,6 @@ DIFF FORMATTING\n>  By default, `git log` does not generate any diff output. The options\n>  below can be used to show the changes made by each commit.\n>\n> -Note that unless one of `--diff-merges` variants (including short\n> -`-m`, `-c`, and `--cc` options) is explicitly given, merge commits\n> -will not show a diff, even if a diff format like `--patch` is\n> -selected, nor will they match search options like `-S`. The exception\n> -is when `--first-parent` is in use, in which case\n> -`--diff-merges=first-parent` is implied.\n> -\n> ---diff-merges=(off|none|first-parent|separate|combined|dense-combined)::\n> ---no-diff-merges::\n> -       Specify diff format to be used for merge commits. This has no\n> -       effect unless diff output is enabled in the first place (e.g.,\n> -       with `--patch` option.)\n> -+\n> ---diff-merges=(off|none):::\n> ---no-diff-merges:::\n> -       (default) Disable output of diffs for merge commits. Useful to\n> -       override implied value.\n> -+\n> ---diff-merges=first-parent:::\n> -       This option makes merge commits show the full diff with\n> -       respect to the first parent only, exactly like  regular\n> -       commits.\n> -+\n> ---diff-merges=separate:::\n> --m:::\n> -       This makes merge commits show the full diff with respect to\n> -       each of the parents. Separate log entry and diff is generated\n> -       for each parent.\n> -+\n> ---diff-merges=combined:::\n> --c:::\n> -       With this option, diff output for a merge commit shows the\n> -       differences from each of the parents to the merge result\n> -       simultaneously instead of showing pairwise diff between a\n> -       parent and the result one at a time. Furthermore, it lists\n> -       only files which were modified from all parents.\n> -+\n> ---diff-merges=dense-combined:::\n> ---cc:::\n> -       With this option the output produced by\n> -       `--diff-merges=combined` is further compressed by omitting\n> -       uninteresting hunks whose contents in the parents have only\n> -       two variants and the merge result picks one of them without\n> -       modification.\n> -\n> ---combined-all-paths::\n> -       This flag causes combined diffs (used for merge commits) to\n> -       list the name of the file from all parents.  It thus only has\n> -       effect when `--diff-merges=[dense-]combined` is in use, and\n> -       is likely only useful if filename changes are detected (i.e.\n> -       when either rename or copy detection have been requested).\n> -\n>\n>  :git-log: 1\n>  include::diff-options.txt[]\n> diff --git a/Documentation/git-show.txt b/Documentation/git-show.txt\n> index fcf528c1b30d..abe58ce5d3a8 100644\n> --- a/Documentation/git-show.txt\n> +++ b/Documentation/git-show.txt\n> @@ -45,8 +45,12 @@ include::pretty-options.txt[]\n>  include::pretty-formats.txt[]\n>\n>\n> -COMMON DIFF OPTIONS\n> --------------------\n> +DIFF FORMATTING\n> +---------------\n> +\n> +By default, `git show` does not generate any diff output. The options\n> +below can be used to show the changes made by each commit.\n> +\n\nThis is not right, `git show` generates diff output by default for\nboth normal commits and merge commits -- it defaults to -p --cc (see\nshow_setup_revisions_tweak() of builtin/log.c).  Also see earlier in\ngit-show.txt where it says\n\n       For commits it shows the log message and textual diff. It also presents\n       the merge commit in a special format as produced by git diff-tree --cc.\n\n>  :git-log: 1\n>  include::diff-options.txt[]\n\n...and the included text will contain the repeated claim that no diffs\nare shown by default for merge commits, which is true for `git log`\nbut not `git show`.\n"},{"id":"411259","messageId":"87ft4mhj9j.fsf@osv.gnss.ru","threadId":"54550","inReplyTo":"xmqqeek7k8wy.fsf@gitster.c.googlers.com","subject":"Re: [PATCH v1 06/27] diff-merges: rename all functions to have common prefix","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-03T17:49:44Z","receivedAt":"2020-12-03T17:50:47Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Sergey Organov <sorganov@gmail.com> writes:\n>\n>> Use the same \"diff_merges\" prefix for all the diff merges function\n>> names.\n>>\n>> Signed-off-by: Sergey Organov <sorganov@gmail.com>\n>> ---\n>>  builtin/log.c |  4 ++--\n>>  diff-merges.c | 10 +++++-----\n>>  diff-merges.h | 15 ++++++++++-----\n>>  revision.c    |  6 +++---\n>>  4 files changed, 20 insertions(+), 15 deletions(-)\n>>\n>> diff --git a/builtin/log.c b/builtin/log.c\n>> index ad3092fdd854..77a7bba543ad 100644\n>> --- a/builtin/log.c\n>> +++ b/builtin/log.c\n>> @@ -599,7 +599,7 @@ static int show_tree_object(const struct object_id *oid,\n>>  static void show_setup_revisions_tweak(struct rev_info *rev,\n>>  \t\t\t\t       struct setup_revision_opt *opt)\n>>  {\n>> -\trev_diff_merges_default_to_dense_combined(rev);\n>> +\tdiff_merges_default_to_dense_combined(rev);\n>>  \tif (!rev->diffopt.output_format)\n>>  \t\trev->diffopt.output_format = DIFF_FORMAT_PATCH;\n>>  }\n>> @@ -724,7 +724,7 @@ static void log_setup_revisions_tweak(struct rev_info *rev,\n>>  \tif (!rev->diffopt.output_format && rev->combine_merges)\n>>  \t\trev->diffopt.output_format = DIFF_FORMAT_PATCH;\n>>  \n>> -\trev_diff_merges_first_parent_defaults_to_enable(rev);\n>> +\tdiff_merges_first_parent_defaults_to_enable(rev);\n>\n> Even with a different prefix, this name does not make it clear what\n> is going on to its readers.  The other name is OK, though.\n\nAs this name goes away later, let's relax this one, and focus on the\nfinal name, OK?\n\nThanks,\n-- Sergey Organov\n"},{"id":"411260","messageId":"87blfahj35.fsf@osv.gnss.ru","threadId":"54550","inReplyTo":"xmqqim9jk8zf.fsf@gitster.c.googlers.com","subject":"Re: [PATCH v1 04/27] revision: provide implementation for diff merges tweaks","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-03T17:53:34Z","receivedAt":"2020-12-03T17:54:48Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Sergey Organov <sorganov@gmail.com> writes:\n>\n>> -\tif (rev->ignore_merges < 0) {\n>> -\t\t/* There was no \"-m\" variant on the command line */\n>> -\t\trev->ignore_merges = 0;\n>> -\t\tif (!rev->first_parent_only && !rev->combine_merges) {\n>> -\t\t\t/* No \"--first-parent\", \"-c\", or \"--cc\" */\n>> -\t\t\trev->combine_merges = 1;\n>> -\t\t\trev->dense_combined_merges = 1;\n>> -\t\t}\n>> -\t}\n>> +\trev_diff_merges_default_to_dense_combined(rev);\n>\n> The name makes sense.  \"Unless otherwise specified, we do not ignore\n> merges.  Further, when we are not doing first-parent traversal,\n> default to dense combined merges, unless told otherwise\" is what the\n> code says, and the name of the helper captures it well.\n>\n>> @@ -731,8 +723,7 @@ static void log_setup_revisions_tweak(struct rev_info *rev,\n>>  \tif (!rev->diffopt.output_format && rev->combine_merges)\n>>  \t\trev->diffopt.output_format = DIFF_FORMAT_PATCH;\n>>  \n>> -\tif (rev->first_parent_only && rev->ignore_merges < 0)\n>> -\t\trev->ignore_merges = 0;\n>> +\trev_diff_merges_first_parent_defaults_to_enable(rev);\n>\n> This on the other hand is not so great a name.  \"When we are doing\n> first-parent traversal, do not exclude merge commits from being\n> shown\" is what log_setup_revisions_tweak() does here.  \"default to\n> enable\" is not clear at all what we are enabling.\n\nAs this name goes away later, let's relax this one, and focus on the\nfinal name?\n\n>\n> Is your naming convention that \"rev_diff_\" is the common prefix?\n> What's the significance of \"_diff\" part?  After all, these are about\n> tweaking the setting in the rev_info structure, so how about\n>\n> \trevinfo_show_merges_in_dense_combined_by_default(rev);\n> \trevinfo_show_merges_by_default_with_first_parent(rev);\n>\n> perhaps, using just \"revinfo_\" as the common prefix?\n\nThe prefixes here were selected just to have some to aid in refactoring,\nwithout much thought. As all the prefixes change pretty soon in the\nseries anyway, can we let these be?\n\nThanks,\n-- Sergey Organov\n"},{"id":"411272","messageId":"877dpyhefj.fsf@osv.gnss.ru","threadId":"54550","inReplyTo":"CABPp-BGZO+7bRdCAGFdetOkmwyFnHxDPQ=SD4f6TSa9ZYGFn=A@mail.gmail.com","subject":"Re: [PATCH v1 24/27] doc/git-log: describe new --diff-merges options","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-03T19:34:08Z","receivedAt":"2020-12-03T19:35:03Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Elijah Newren <newren@gmail.com> writes:\n\n> On Sun, Nov 8, 2020 at 1:46 PM Sergey Organov <sorganov@gmail.com> wrote:\n>>\n>> Describe all the new --diff-merges options in the git-log.txt\n>>\n>> Signed-off-by: Sergey Organov <sorganov@gmail.com>\n>> ---\n>>  Documentation/git-log.txt | 79 +++++++++++++++++++++++----------------\n>>  1 file changed, 46 insertions(+), 33 deletions(-)\n>>\n>> diff --git a/Documentation/git-log.txt b/Documentation/git-log.txt\n>> index 2b8ac5ff882a..de498a189646 100644\n>> --- a/Documentation/git-log.txt\n>> +++ b/Documentation/git-log.txt\n>> @@ -120,45 +120,58 @@ DIFF FORMATTING\n>>  By default, `git log` does not generate any diff output. The options\n>>  below can be used to show the changes made by each commit.\n>>\n>> -Note that unless one of `-c`, `--cc`, or `-m` is given, merge commits\n>> -will never show a diff, even if a diff format like `--patch` is\n>> -selected, nor will they match search options like `-S`. The exception is\n>> -when `--first-parent` is in use, in which merges are treated like normal\n>> -single-parent commits (this can be overridden by providing a\n>> -combined-diff option or with `--no-diff-merges`).\n>> +Note that unless one of `--diff-merges` variants (including short\n>> +`-m`, `-c`, and `--cc` options) is explicitly given, merge commits\n>> +will not show a diff, even if a diff format like `--patch` is\n>> +selected, nor will they match search options like `-S`. The exception\n>> +is when `--first-parent` is in use, in which case\n>> +`--diff-merges=first-parent` is implied.\n>>\n>> --c::\n>> -       With this option, diff output for a merge commit\n>> -       shows the differences from each of the parents to the merge result\n>> -       simultaneously instead of showing pairwise diff between a parent\n>> -       and the result one at a time. Furthermore, it lists only files\n>> -       which were modified from all parents.\n>> -\n>> ---cc::\n>> -       This flag implies the `-c` option and further compresses the\n>> -       patch output by omitting uninteresting hunks whose contents in\n>> -       the parents have only two variants and the merge result picks\n>> -       one of them without modification.\n>> +--diff-merges=(off|none|first-parent|separate|combined|dense-combined)::\n>> +--no-diff-merges::\n>> +       Specify diff format to be used for merge commits. This has no\n>> +       effect unless diff output is enabled in the first place (e.g.,\n>> +       with `--patch` option.)\n>\n> This seems inconsistent with c7eaf8b4c3 (\"log: when --cc is given,\n> default to -p unless told otherwise\", 2015-08-20); shouldn't these\n> imply -p?\n\nLooks like it is indeed, and worse yet, the patch series don't handle\nthis optimally due to my ignorance of this behavior. I think I need to\nmake changes to imply -p whenever some of diff-merge options (except\n--diff-merges=none) are explicitly given, cause it's now, after these\npatches, is unclear why only combined diffs imply -p, and not, say,\n--diff-merges=first-parent.\n\nNice catch, thanks!\n\nBTW, in the original, why only \"git log\" is affected? Ah, probably\nbecause \"git show\" has -p by default?\n\nWhile we are at it, why do we have \"git show\" at all? How is it\nessentially different from \"git log -n1 --first-parent ...\"? I mean,\nshouldn't it effectively be just an alias?\n\n>\n>> ++\n>> +--diff-merges=(off|none):::\n>> +--no-diff-merges:::\n>> +       (default) Disable output of diffs for merge commits. Useful to\n>> +       override implied value.\n>> ++\n>> +--diff-merges=first-parent:::\n>> +       This option makes merge commits show the full diff with\n>> +       respect to the first parent only, exactly like  regular\n>> +       commits.\n>\n> Not sure that \"exactly like regular commits\" is helpful here; I'd\n> personally rather cut those four words out.  I'm worried it'll be\n> taken not as an implementation explanation, but as a \"this treats\n> merge commits in the natural way that regular commits are\" which users\n> may mistakenly translate to \"it shows what changes the user manually\n> made as part of the commit\" which is not at all the correct mapping.\n\nDunno. Don't have strict preference here. Git has no idea how the\nchanges in a commit have been made in the first place. Changes are just\nchanges.\n\nTo my excuse, I took this from git:5fbb4bc191 that has:\n\n+Note that unless one of `-c`, `--cc`, or `-m` is given, merge commits\n+will never show a diff, even if a diff format like `--patch` is\n+selected, nor will they match search options like `-S`. The exception is\n+when `--first-parent` is in use, in which merges are treated like normal\n+single-parent commits (this can be overridden by providing a\n+combined-diff option or with `--no-diff-merges`).\n\nThanks,\n-- Sergey Organov\n"},{"id":"411273","messageId":"871rg6hdrk.fsf@osv.gnss.ru","threadId":"54550","inReplyTo":"CABPp-BHdhvLRe4jCSsRtPrbh2=kwJxEQs0Dx+Ng1Vutx8Hdqqw@mail.gmail.com","subject":"Re: [PATCH v1 00/27] git-log: implement new --diff-merge options","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-03T19:48:31Z","receivedAt":"2020-12-03T19:49:16Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Elijah Newren <newren@gmail.com> writes:\n\n> On Sun, Nov 8, 2020 at 1:43 PM Sergey Organov <sorganov@gmail.com> wrote:\n>>\n>> These patch series implement new set of options governing the diff output\n>> of merge commits, all under the umbrella of the single --diff-merges=<mode>\n>> option. Most of the new options being synonyms for -m/-c/--cc options,\n>> there is also additional functionality provided, allowing to get the format\n>> of \"-p --first-parent\" without change in history traversal that\n>> --first-parent option causes.\n>>\n>> The net result of these series are the following new options:\n>>\n>> --diff-merges=   |  old equivalent\n>> -----------------+----------------\n>> first-parent     | --first-parent (only format implications)\n>> separate         | -m\n>> combined         | -c\n>> dense-combined   | --cc\n>\n> Interesting.  I have some local patches implementing another choice,\n> with the new flag --remerge-diff.  This flag will cause `git show` or\n> `git log` to automatically remerge the two parents in a 2-parent merge\n> commit, and then diff the merge commit against that automatic merge,\n> showing the result.  Thus, the diff for a merge commit is likely to be\n> empty if the merge was clean, and is likely to show the removal of\n> conflict markers if the merge was not clean.\n>\n> I'm curious how it'd interact with this new option.  Would it also get\n> a name, e.g. --diff-merges=remerge-diff?  Feels like a mouthful, but I\n> can't come up with anything better.\n\nMaybe, --diff-merges=remerge?\n\n>\n> Also, I'm curious how it'd interact with another option I added, named\n> --remerge-diff-only.  This latter option modifies revision traversal\n> in that it skips octopus merges, root commits, and single parent\n> commits IF no cherry-pick or revert information can be found.  If it\n> finds a 2-parent merge commit, it behaves like --remerge-diff.  If it\n> finds a 1-parent commit with cherry-pick or revert information, it'll\n> do an in memory repeat of that cherry-pick (or revert) and then diff\n> the actual commit against what the automatic cherry-pick would\n> perform.  Again, that likely means an empty diff if the automatic\n> cherry-pick was clean, and showing any changes made by the user to\n> complete the original cherry-pick (such as deleting conflict markers\n> and picking which chunks from which side to keep) if the automatic\n> cherry-pick was not clean.  (I suspect --remerge-diff-only is much\n> more likely to be used with `git show` than with `git log`.)  Anyway,\n> your changes seem to suggest that anything relating to how diffs for\n> merges are handled should be documented in the same section, but\n> --remerge-diff-only doesn't fit.  And it'd seem odd to have\n> --remerge-diff and --remerge-diff-only not show up in adjacently but\n> be split into separate sections.  Any ideas?\n\nSounds like commits limiting option to me. I think it could be named by\nits limiting behavior only, say, --remerges. Then it will imply\n--diff-merges=remerge, that'd allow user to re-define diff format if she\nneeds to.\n\nI mean, it looks very similar to --first-parent to me in the ways it\ncould be defined/implemented. Recall that --first-parent now implies\n--diff-merges=first-parent.\n\n[...]\n\n>>\n>> Updates in v1:\n>\n> A minor point, but this should have been labelled v2.  The unlabelled\n> original submission is v1.\n\nWell, I did consider it when prepared v1, but given:\n\n  git format-patch --reroll-count=0\n\nproduces [PATCH], it only sounds natural to follow with\n\n  git format-patch --reroll-count=1\n\nthat produces [PATCH v1].\n\nThanks,\n-- Sergey Organov\n"},{"id":"411274","messageId":"87wnxyfz07.fsf@osv.gnss.ru","threadId":"54550","inReplyTo":"CABPp-BG_YT2i_27tqkh_e4mwfkYae-zDCEYL=F+NjYQed2gKAg@mail.gmail.com","subject":"Re: [PATCH v1 27/27] doc/git-show: include --diff-merges description","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-03T19:52:40Z","receivedAt":"2020-12-03T19:53:40Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Elijah Newren <newren@gmail.com> writes:\n> Hi,\n>\n> On Sun, Nov 8, 2020 at 1:44 PM Sergey Organov <sorganov@gmail.com> wrote:\n>>\n>> Move description of --diff-merges option from git-log.txt to\n>> diff-options.txt so that it is included in the git-show help.\n>>\n>> While we are at it, make git-show closer to git-log in this area by\n>> providing similar wording in the introduction of diff options.\n>>\n>> Signed-off-by: Sergey Organov <sorganov@gmail.com>\n>> ---\n>>  Documentation/diff-options.txt | 54 ++++++++++++++++++++++++++++++++++\n>>  Documentation/git-log.txt      | 52 --------------------------------\n>>  Documentation/git-show.txt     |  8 +++--\n>>  3 files changed, 60 insertions(+), 54 deletions(-)\n>>\n>> diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt\n>> index 573fb9bb71e2..f1629887103e 100644\n>> --- a/Documentation/diff-options.txt\n>> +++ b/Documentation/diff-options.txt\n>> @@ -33,6 +33,60 @@ endif::git-diff[]\n>>         show the patch by default, or to cancel the effect of `--patch`.\n>>  endif::git-format-patch[]\n>>\n>> +ifdef::git-log[]\n>> +Note that unless one of `--diff-merges` variants (including short\n>> +`-m`, `-c`, and `--cc` options) is explicitly given, merge commits\n>> +will not show a diff, even if a diff format like `--patch` is\n>> +selected, nor will they match search options like `-S`. The exception\n>> +is when `--first-parent` is in use, in which case\n>> +`--diff-merges=first-parent` is implied.\n>\n> So, now diff-options says that no diffs are the defaults for merge commits...\n>\n>> +\n>> +--diff-merges=(off|none|first-parent|separate|combined|dense-combined)::\n>> +--no-diff-merges::\n>> +       Specify diff format to be used for merge commits. This has no\n>> +       effect unless diff output is enabled in the first place (e.g.,\n>> +       with `--patch` option.)\n>> ++\n>> +--diff-merges=(off|none):::\n>> +--no-diff-merges:::\n>> +       (default) Disable output of diffs for merge commits. Useful to\n>> +       override implied value.\n>> ++\n>> +--diff-merges=first-parent:::\n>> +       This option makes merge commits show the full diff with\n>> +       respect to the first parent only, exactly like  regular\n>> +       commits.\n>> ++\n>> +--diff-merges=separate:::\n>> +-m:::\n>> +       This makes merge commits show the full diff with respect to\n>> +       each of the parents. Separate log entry and diff is generated\n>> +       for each parent.\n>> ++\n>> +--diff-merges=combined:::\n>> +-c:::\n>> +       With this option, diff output for a merge commit shows the\n>> +       differences from each of the parents to the merge result\n>> +       simultaneously instead of showing pairwise diff between a\n>> +       parent and the result one at a time. Furthermore, it lists\n>> +       only files which were modified from all parents.\n>> ++\n>> +--diff-merges=dense-combined:::\n>> +--cc:::\n>> +       With this option the output produced by\n>> +       `--diff-merges=combined` is further compressed by omitting\n>> +       uninteresting hunks whose contents in the parents have only\n>> +       two variants and the merge result picks one of them without\n>> +       modification.\n>> +\n>> +--combined-all-paths::\n>> +       This flag causes combined diffs (used for merge commits) to\n>> +       list the name of the file from all parents.  It thus only has\n>> +       effect when `--diff-merges=[dense-]combined` is in use, and\n>> +       is likely only useful if filename changes are detected (i.e.\n>> +       when either rename or copy detection have been requested).\n>> +endif::git-log[]\n>> +\n>>  -U<n>::\n>>  --unified=<n>::\n>>         Generate diffs with <n> lines of context instead of\n>> diff --git a/Documentation/git-log.txt b/Documentation/git-log.txt\n>> index de498a189646..0cacc780bf30 100644\n>> --- a/Documentation/git-log.txt\n>> +++ b/Documentation/git-log.txt\n>> @@ -120,58 +120,6 @@ DIFF FORMATTING\n>>  By default, `git log` does not generate any diff output. The options\n>>  below can be used to show the changes made by each commit.\n>>\n>> -Note that unless one of `--diff-merges` variants (including short\n>> -`-m`, `-c`, and `--cc` options) is explicitly given, merge commits\n>> -will not show a diff, even if a diff format like `--patch` is\n>> -selected, nor will they match search options like `-S`. The exception\n>> -is when `--first-parent` is in use, in which case\n>> -`--diff-merges=first-parent` is implied.\n>> -\n>> ---diff-merges=(off|none|first-parent|separate|combined|dense-combined)::\n>> ---no-diff-merges::\n>> -       Specify diff format to be used for merge commits. This has no\n>> -       effect unless diff output is enabled in the first place (e.g.,\n>> -       with `--patch` option.)\n>> -+\n>> ---diff-merges=(off|none):::\n>> ---no-diff-merges:::\n>> -       (default) Disable output of diffs for merge commits. Useful to\n>> -       override implied value.\n>> -+\n>> ---diff-merges=first-parent:::\n>> -       This option makes merge commits show the full diff with\n>> -       respect to the first parent only, exactly like  regular\n>> -       commits.\n>> -+\n>> ---diff-merges=separate:::\n>> --m:::\n>> -       This makes merge commits show the full diff with respect to\n>> -       each of the parents. Separate log entry and diff is generated\n>> -       for each parent.\n>> -+\n>> ---diff-merges=combined:::\n>> --c:::\n>> -       With this option, diff output for a merge commit shows the\n>> -       differences from each of the parents to the merge result\n>> -       simultaneously instead of showing pairwise diff between a\n>> -       parent and the result one at a time. Furthermore, it lists\n>> -       only files which were modified from all parents.\n>> -+\n>> ---diff-merges=dense-combined:::\n>> ---cc:::\n>> -       With this option the output produced by\n>> -       `--diff-merges=combined` is further compressed by omitting\n>> -       uninteresting hunks whose contents in the parents have only\n>> -       two variants and the merge result picks one of them without\n>> -       modification.\n>> -\n>> ---combined-all-paths::\n>> -       This flag causes combined diffs (used for merge commits) to\n>> -       list the name of the file from all parents.  It thus only has\n>> -       effect when `--diff-merges=[dense-]combined` is in use, and\n>> -       is likely only useful if filename changes are detected (i.e.\n>> -       when either rename or copy detection have been requested).\n>> -\n>>\n>>  :git-log: 1\n>>  include::diff-options.txt[]\n>> diff --git a/Documentation/git-show.txt b/Documentation/git-show.txt\n>> index fcf528c1b30d..abe58ce5d3a8 100644\n>> --- a/Documentation/git-show.txt\n>> +++ b/Documentation/git-show.txt\n>> @@ -45,8 +45,12 @@ include::pretty-options.txt[]\n>>  include::pretty-formats.txt[]\n>>\n>>\n>> -COMMON DIFF OPTIONS\n>> --------------------\n>> +DIFF FORMATTING\n>> +---------------\n>> +\n>> +By default, `git show` does not generate any diff output. The options\n>> +below can be used to show the changes made by each commit.\n>> +\n>\n> This is not right, `git show` generates diff output by default for\n> both normal commits and merge commits -- it defaults to -p --cc (see\n> show_setup_revisions_tweak() of builtin/log.c).  Also see earlier in\n> git-show.txt where it says\n>\n>        For commits it shows the log message and textual diff. It also presents\n>        the merge commit in a special format as produced by git diff-tree --cc.\n>\n>>  :git-log: 1\n>>  include::diff-options.txt[]\n>\n> ...and the included text will contain the repeated claim that no diffs\n> are shown by default for merge commits, which is true for `git log`\n> but not `git show`.\n\nYes, I need to re-consider this, as I already admitted in my reply to\nyour previous catch of the related problem in the documentation.\n\nThey all came from single point of misunderstanding.\n\nWill try to get it right in the next re-roll.\n\nThanks,\n-- Sergey Organov\n"},{"id":"411276","messageId":"87ft4mfycq.fsf@osv.gnss.ru","threadId":"54550","inReplyTo":"CABPp-BGH0+M_6gYYfYsp54X9DjKM4mv8Vssoo3uZtDAY1_Zb1A@mail.gmail.com","subject":"Re: [PATCH 10/26] diff-merges: new function diff_merges_suppress()","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-03T20:06:45Z","receivedAt":"2020-12-03T20:07:39Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Elijah Newren <newren@gmail.com> writes:\n\n> On Sun, Nov 1, 2020 at 11:36 AM Sergey Organov <sorganov@gmail.com> wrote:\n>>\n>> This function sets all the relevant flags to disabled state, so that\n>> no code that checks only one of them get it wrong.\n>>\n>> Then we call this new function everywhere where diff merges output\n>> suppression is needed.\n>>\n>> Signed-off-by: Sergey Organov <sorganov@gmail.com>\n>> ---\n>>  builtin/merge.c |  3 ++-\n>>  diff-merges.c   | 18 ++++++++++++++----\n>>  diff-merges.h   |  2 ++\n>>  fmt-merge-msg.c |  3 ++-\n>>  4 files changed, 20 insertions(+), 6 deletions(-)\n>>\n>> diff --git a/builtin/merge.c b/builtin/merge.c\n>> index 9d5359edc2f7..1f7b69982b40 100644\n>> --- a/builtin/merge.c\n>> +++ b/builtin/merge.c\n>> @@ -14,6 +14,7 @@\n>>  #include \"lockfile.h\"\n>>  #include \"run-command.h\"\n>>  #include \"diff.h\"\n>> +#include \"diff-merges.h\"\n>>  #include \"refs.h\"\n>>  #include \"refspec.h\"\n>>  #include \"commit.h\"\n>> @@ -400,7 +401,7 @@ static void squash_message(struct commit *commit, struct commit_list *remotehead\n>>         printf(_(\"Squash commit -- not updating HEAD\\n\"));\n>>\n>>         repo_init_revisions(the_repository, &rev, NULL);\n>> -       rev.ignore_merges = 1;\n>> +       diff_merges_suppress(&rev);\n>>         rev.commit_format = CMIT_FMT_MEDIUM;\n>>\n>>         commit->object.flags |= UNINTERESTING;\n>> diff --git a/diff-merges.c b/diff-merges.c\n>> index 8536941e0b56..25bd9b12e667 100644\n>> --- a/diff-merges.c\n>> +++ b/diff-merges.c\n>> @@ -2,6 +2,13 @@\n>>\n>>  #include \"revision.h\"\n>>\n>> +static void suppress(struct rev_info *revs) {\n>> +       revs->ignore_merges = 1;\n>> +       revs->first_parent_merges = 0;\n>> +       revs->combine_merges = 0;\n>> +       revs->dense_combined_merges = 0;\n>> +}\n>\n> The function name is not so helpful;\n\nDo you have better suggestion? suppress_output()? supress_diff()?\n\n> why not put all this code directly in diff_merges_suppress()?\n\nI prefer the style where module implementation functions don't call its\ninterface functions, only vice versa.\n\n>\n>> +\n>>  /*\n>>   * Public functions. They are in the order they are called.\n>>   */\n>> @@ -29,16 +36,15 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {\n>>                 revs->combine_merges = 1;\n>>         } else if (!strcmp(arg, \"--cc\")) {\n>>                 revs->diff = 1;\n>> -               revs->dense_combined_merges = 1;\n>> -               revs->combine_merges = 1;\n>> +               set_dense_combined(revs);\n>>         } else if (!strcmp(arg, \"--no-diff-merges\")) {\n>> -               revs->ignore_merges = 1;\n>> +               suppress(revs);\n>>         } else if (!strcmp(arg, \"--combined-all-paths\")) {\n>>                 revs->diff = 1;\n>>                 revs->combined_all_paths = 1;\n>>         } else if ((argcount = parse_long_opt(\"diff-merges\", argv, &optarg))) {\n>>                 if (!strcmp(optarg, \"off\")) {\n>> -                       revs->ignore_merges = 1;\n>> +                       suppress(revs);\n>>                 } else {\n>>                         die(_(\"unknown value for --diff-merges: %s\"), optarg);\n>>                 }\n>> @@ -48,6 +54,10 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {\n>>         return 1;\n>>  }\n>>\n>> +void diff_merges_suppress(struct rev_info *revs) {\n>> +       suppress(revs);\n>> +}\n>\n> ...especially since all this function does is call suppress()?\n\nYes, it does, but it doesn't mean it will be that way forever. Interface\nfunction might need to perform additional checks or actions, in general.\n\nBesides, if diff_merges_suppress() is OK with you as interface function\nname, why suppress() is not OK as local function name in diff-merges\nmodule?\n\nThanks,\n-- Sergey Organov\n"},{"id":"411277","messageId":"87blfafxmx.fsf@osv.gnss.ru","threadId":"54550","inReplyTo":"xmqq360nk859.fsf@gitster.c.googlers.com","subject":"Re: [PATCH v1 07/27] diff-merges: move checks for first_parent_only out of the module","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-03T20:22:14Z","receivedAt":"2020-12-03T20:23:00Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Sergey Organov <sorganov@gmail.com> writes:\n>\n>> The checks for first_parent_only don't in fact belong to this module,\n>> as the primary purpose of this flag is history traversal limiting, so\n>> get it out of this module and rename the\n>>\n>> diff_merges_first_parent_defaults_to_enable()\n>>\n>> to\n>>\n>> diff_merges_default_to_enable()\n>\n> Again, neither is a great name.\n>\n> More importantly, I do not think that I agree with the reasoning\n> given in the first paragraph.  The first-parent-only traversal means\n> that we pretend there is no second and later parents, so it makes\n> quite a lot of sense that the choice of that option affects how a\n> merge commit discovered during the traversal is show by default\n> (namely, as if it is just a single-parent commit).\n\nI have no objections against this behavior, nor did I change it, so I\ndon't understand what reasoning you disagree with.\n\nThe code that handles --first-parent now explicitly says it needs\ncorresponding format of diff output by default, exactly as you describe,\nso what's the problem?\n\n>\n> If there are other reasons why we want to force the callers to check\n> for first-parent option (for example, it may make it easier to tweak\n> how each caller makes its decisions separately in later steps of\n> this series), the changes proposed by this step may be a right\n> solution, so I am not outright opposed to this patch, but the\n> rationale given above is not a strong enough justification for the\n> change, at least to me.\n>\n>> +void diff_merges_default_to_enable(struct rev_info *revs) {\n>\n> Perhaps \"show_merges_by_default()\".\n\nDoesn't sound good to me either. We usually do show merges. We only\ndon't show any kind of diffs for them.\n\n>\n>> +\tif (revs->ignore_merges < 0)\t\t/* No -m */\n>>  \t\trevs->ignore_merges = 0;\n>\n> Perhaps \"show_merges_in_cc_by_default()\" (or \"cc\" spelled out as\n> \"dense_combined\").\n\nWell, I think it's better to discuss final names instead of intermediate\nrefactoring ones that will disappear anyway. At least as a fist step. If\nwe get them right, intermediates could be fixed accordingly more\neasily, I think.\n\n\n[...]\n\nThanks,\n-- Sergey Organov\n"},{"id":"411278","messageId":"CABPp-BEyiLDZ5Ums1D5gL679EMmKXpqxWDF_xGT4scXLMkwseg@mail.gmail.com","threadId":"54550","inReplyTo":"877dpyhefj.fsf@osv.gnss.ru","subject":"Re: [PATCH v1 24/27] doc/git-log: describe new --diff-merges options","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2020-12-03T20:22:08Z","receivedAt":"2020-12-03T20:23:01Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Thu, Dec 3, 2020 at 11:34 AM Sergey Organov <sorganov@gmail.com> wrote:\n>\n> Elijah Newren <newren@gmail.com> writes:\n>\n> > On Sun, Nov 8, 2020 at 1:46 PM Sergey Organov <sorganov@gmail.com> wrote:\n> >>\n> >> Describe all the new --diff-merges options in the git-log.txt\n> >>\n> >> Signed-off-by: Sergey Organov <sorganov@gmail.com>\n> >> ---\n> >>  Documentation/git-log.txt | 79 +++++++++++++++++++++++----------------\n> >>  1 file changed, 46 insertions(+), 33 deletions(-)\n> >>\n> >> diff --git a/Documentation/git-log.txt b/Documentation/git-log.txt\n> >> index 2b8ac5ff882a..de498a189646 100644\n> >> --- a/Documentation/git-log.txt\n> >> +++ b/Documentation/git-log.txt\n> >> @@ -120,45 +120,58 @@ DIFF FORMATTING\n> >>  By default, `git log` does not generate any diff output. The options\n> >>  below can be used to show the changes made by each commit.\n> >>\n> >> -Note that unless one of `-c`, `--cc`, or `-m` is given, merge commits\n> >> -will never show a diff, even if a diff format like `--patch` is\n> >> -selected, nor will they match search options like `-S`. The exception is\n> >> -when `--first-parent` is in use, in which merges are treated like normal\n> >> -single-parent commits (this can be overridden by providing a\n> >> -combined-diff option or with `--no-diff-merges`).\n> >> +Note that unless one of `--diff-merges` variants (including short\n> >> +`-m`, `-c`, and `--cc` options) is explicitly given, merge commits\n> >> +will not show a diff, even if a diff format like `--patch` is\n> >> +selected, nor will they match search options like `-S`. The exception\n> >> +is when `--first-parent` is in use, in which case\n> >> +`--diff-merges=first-parent` is implied.\n> >>\n> >> --c::\n> >> -       With this option, diff output for a merge commit\n> >> -       shows the differences from each of the parents to the merge result\n> >> -       simultaneously instead of showing pairwise diff between a parent\n> >> -       and the result one at a time. Furthermore, it lists only files\n> >> -       which were modified from all parents.\n> >> -\n> >> ---cc::\n> >> -       This flag implies the `-c` option and further compresses the\n> >> -       patch output by omitting uninteresting hunks whose contents in\n> >> -       the parents have only two variants and the merge result picks\n> >> -       one of them without modification.\n> >> +--diff-merges=(off|none|first-parent|separate|combined|dense-combined)::\n> >> +--no-diff-merges::\n> >> +       Specify diff format to be used for merge commits. This has no\n> >> +       effect unless diff output is enabled in the first place (e.g.,\n> >> +       with `--patch` option.)\n> >\n> > This seems inconsistent with c7eaf8b4c3 (\"log: when --cc is given,\n> > default to -p unless told otherwise\", 2015-08-20); shouldn't these\n> > imply -p?\n>\n> Looks like it is indeed, and worse yet, the patch series don't handle\n> this optimally due to my ignorance of this behavior. I think I need to\n> make changes to imply -p whenever some of diff-merge options (except\n> --diff-merges=none) are explicitly given, cause it's now, after these\n> patches, is unclear why only combined diffs imply -p, and not, say,\n> --diff-merges=first-parent.\n>\n> Nice catch, thanks!\n>\n> BTW, in the original, why only \"git log\" is affected? Ah, probably\n> because \"git show\" has -p by default?\n>\n> While we are at it, why do we have \"git show\" at all? How is it\n> essentially different from \"git log -n1 --first-parent ...\"? I mean,\n> shouldn't it effectively be just an alias?\n\ngit show does not just operate on commits.  It can also display blobs,\ntrees, or tags.  I see people use it with blobs in the form of\nREVISION:FILENAME references.  git show also is not limited to\ndisplaying just one object, hence -n1 would be problematic; you'd need\nto use --no-walk instead when operating on commits.  Also, git show\nuses --cc when operating on commits, not --first-parent.\n\nHowever, you are right that it is pretty close to just being something\nyou could alias if you limited it to commits.  If I understand\ncorrectly, that alias would be `git log --no-walk -p --cc ...` (though\nyou only need the explicit -p with pretty old versions of git).\n\n> >\n> >> ++\n> >> +--diff-merges=(off|none):::\n> >> +--no-diff-merges:::\n> >> +       (default) Disable output of diffs for merge commits. Useful to\n> >> +       override implied value.\n> >> ++\n> >> +--diff-merges=first-parent:::\n> >> +       This option makes merge commits show the full diff with\n> >> +       respect to the first parent only, exactly like  regular\n> >> +       commits.\n> >\n> > Not sure that \"exactly like regular commits\" is helpful here; I'd\n> > personally rather cut those four words out.  I'm worried it'll be\n> > taken not as an implementation explanation, but as a \"this treats\n> > merge commits in the natural way that regular commits are\" which users\n> > may mistakenly translate to \"it shows what changes the user manually\n> > made as part of the commit\" which is not at all the correct mapping.\n>\n> Dunno. Don't have strict preference here. Git has no idea how the\n> changes in a commit have been made in the first place. Changes are just\n> changes.\n\nIf you don't have a preference, can we drop those four words?  ;-)\n\n> To my excuse, I took this from git:5fbb4bc191 that has:\n>\n> +Note that unless one of `-c`, `--cc`, or `-m` is given, merge commits\n> +will never show a diff, even if a diff format like `--patch` is\n> +selected, nor will they match search options like `-S`. The exception is\n> +when `--first-parent` is in use, in which merges are treated like normal\n> +single-parent commits (this can be overridden by providing a\n> +combined-diff option or with `--no-diff-merges`).\n\nYeah, I can see where you're coming from, though the context change\nfeels like just enough different that the four words you added bother\nme a bit more.  However, this existing wording does bother me now that\nyou highlight it.  Even though it's not something introduced by your\npatch, I'd really like to drop \"normal\" here; I think it is prone to\ncause confusion to users and as far as I can tell provides no useful\nmeaning for the sentence.  (There are multiple types of single-parent\ncommits?  What is an \"unnormal\" one?  How do I tell which kind I want?\n etc...).\n"},{"id":"411280","messageId":"CABPp-BFW5ZLvEHFuiRC3rGqdGHWBZRjGHtTq=vVky9U5rZXsvA@mail.gmail.com","threadId":"54550","inReplyTo":"87ft4mfycq.fsf@osv.gnss.ru","subject":"Re: [PATCH 10/26] diff-merges: new function diff_merges_suppress()","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2020-12-03T20:28:01Z","receivedAt":"2020-12-03T20:28:55Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"Hi Sergey,\n\nOn Thu, Dec 3, 2020 at 12:06 PM Sergey Organov <sorganov@gmail.com> wrote:\n>\n> Elijah Newren <newren@gmail.com> writes:\n>\n> > On Sun, Nov 1, 2020 at 11:36 AM Sergey Organov <sorganov@gmail.com> wrote:\n> >>\n> >> This function sets all the relevant flags to disabled state, so that\n> >> no code that checks only one of them get it wrong.\n> >>\n> >> Then we call this new function everywhere where diff merges output\n> >> suppression is needed.\n> >>\n> >> Signed-off-by: Sergey Organov <sorganov@gmail.com>\n> >> ---\n> >>  builtin/merge.c |  3 ++-\n> >>  diff-merges.c   | 18 ++++++++++++++----\n> >>  diff-merges.h   |  2 ++\n> >>  fmt-merge-msg.c |  3 ++-\n> >>  4 files changed, 20 insertions(+), 6 deletions(-)\n> >>\n> >> diff --git a/builtin/merge.c b/builtin/merge.c\n> >> index 9d5359edc2f7..1f7b69982b40 100644\n> >> --- a/builtin/merge.c\n> >> +++ b/builtin/merge.c\n> >> @@ -14,6 +14,7 @@\n> >>  #include \"lockfile.h\"\n> >>  #include \"run-command.h\"\n> >>  #include \"diff.h\"\n> >> +#include \"diff-merges.h\"\n> >>  #include \"refs.h\"\n> >>  #include \"refspec.h\"\n> >>  #include \"commit.h\"\n> >> @@ -400,7 +401,7 @@ static void squash_message(struct commit *commit, struct commit_list *remotehead\n> >>         printf(_(\"Squash commit -- not updating HEAD\\n\"));\n> >>\n> >>         repo_init_revisions(the_repository, &rev, NULL);\n> >> -       rev.ignore_merges = 1;\n> >> +       diff_merges_suppress(&rev);\n> >>         rev.commit_format = CMIT_FMT_MEDIUM;\n> >>\n> >>         commit->object.flags |= UNINTERESTING;\n> >> diff --git a/diff-merges.c b/diff-merges.c\n> >> index 8536941e0b56..25bd9b12e667 100644\n> >> --- a/diff-merges.c\n> >> +++ b/diff-merges.c\n> >> @@ -2,6 +2,13 @@\n> >>\n> >>  #include \"revision.h\"\n> >>\n> >> +static void suppress(struct rev_info *revs) {\n> >> +       revs->ignore_merges = 1;\n> >> +       revs->first_parent_merges = 0;\n> >> +       revs->combine_merges = 0;\n> >> +       revs->dense_combined_merges = 0;\n> >> +}\n> >\n> > The function name is not so helpful;\n>\n> Do you have better suggestion? suppress_output()? supress_diff()?\n>\n> > why not put all this code directly in diff_merges_suppress()?\n>\n> I prefer the style where module implementation functions don't call its\n> interface functions, only vice versa.\n>\n> >\n> >> +\n> >>  /*\n> >>   * Public functions. They are in the order they are called.\n> >>   */\n> >> @@ -29,16 +36,15 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {\n> >>                 revs->combine_merges = 1;\n> >>         } else if (!strcmp(arg, \"--cc\")) {\n> >>                 revs->diff = 1;\n> >> -               revs->dense_combined_merges = 1;\n> >> -               revs->combine_merges = 1;\n> >> +               set_dense_combined(revs);\n> >>         } else if (!strcmp(arg, \"--no-diff-merges\")) {\n> >> -               revs->ignore_merges = 1;\n> >> +               suppress(revs);\n> >>         } else if (!strcmp(arg, \"--combined-all-paths\")) {\n> >>                 revs->diff = 1;\n> >>                 revs->combined_all_paths = 1;\n> >>         } else if ((argcount = parse_long_opt(\"diff-merges\", argv, &optarg))) {\n> >>                 if (!strcmp(optarg, \"off\")) {\n> >> -                       revs->ignore_merges = 1;\n> >> +                       suppress(revs);\n> >>                 } else {\n> >>                         die(_(\"unknown value for --diff-merges: %s\"), optarg);\n> >>                 }\n> >> @@ -48,6 +54,10 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {\n> >>         return 1;\n> >>  }\n> >>\n> >> +void diff_merges_suppress(struct rev_info *revs) {\n> >> +       suppress(revs);\n> >> +}\n> >\n> > ...especially since all this function does is call suppress()?\n>\n> Yes, it does, but it doesn't mean it will be that way forever. Interface\n> function might need to perform additional checks or actions, in general.\n\nAh, I didn't catch the distinction and thus the reasoning in having\nthe two different functions.\n\n> Besides, if diff_merges_suppress() is OK with you as interface function\n> name, why suppress() is not OK as local function name in diff-merges\n> module?\n\nRight, the fact that it's in the diff-merges module as opposed to more\ngeneral diff-lib code is probably hint enough.  I was skimming over\nthe patches looking for things that jumped out, and although I had\nread that you were adding it to the new module, I forgot that when I\nsaw the \"suppress()\" function name.  Thanks for the reminder, and\nsorry for the noise.\n"},{"id":"411281","messageId":"CABPp-BGE4rA5=8NUaK5607moR13bE7PcyVKdbw6nDw5YBeq9bQ@mail.gmail.com","threadId":"54550","inReplyTo":"871rg6hdrk.fsf@osv.gnss.ru","subject":"Re: [PATCH v1 00/27] git-log: implement new --diff-merge options","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2020-12-03T20:39:15Z","receivedAt":"2020-12-03T20:40:23Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Thu, Dec 3, 2020 at 11:48 AM Sergey Organov <sorganov@gmail.com> wrote:\n>\n> Elijah Newren <newren@gmail.com> writes:\n>\n> > On Sun, Nov 8, 2020 at 1:43 PM Sergey Organov <sorganov@gmail.com> wrote:\n> >>\n> >> These patch series implement new set of options governing the diff output\n> >> of merge commits, all under the umbrella of the single --diff-merges=<mode>\n> >> option. Most of the new options being synonyms for -m/-c/--cc options,\n> >> there is also additional functionality provided, allowing to get the format\n> >> of \"-p --first-parent\" without change in history traversal that\n> >> --first-parent option causes.\n> >>\n> >> The net result of these series are the following new options:\n> >>\n> >> --diff-merges=   |  old equivalent\n> >> -----------------+----------------\n> >> first-parent     | --first-parent (only format implications)\n> >> separate         | -m\n> >> combined         | -c\n> >> dense-combined   | --cc\n> >\n> > Interesting.  I have some local patches implementing another choice,\n> > with the new flag --remerge-diff.  This flag will cause `git show` or\n> > `git log` to automatically remerge the two parents in a 2-parent merge\n> > commit, and then diff the merge commit against that automatic merge,\n> > showing the result.  Thus, the diff for a merge commit is likely to be\n> > empty if the merge was clean, and is likely to show the removal of\n> > conflict markers if the merge was not clean.\n> >\n> > I'm curious how it'd interact with this new option.  Would it also get\n> > a name, e.g. --diff-merges=remerge-diff?  Feels like a mouthful, but I\n> > can't come up with anything better.\n>\n> Maybe, --diff-merges=remerge?\n>\n> >\n> > Also, I'm curious how it'd interact with another option I added, named\n> > --remerge-diff-only.  This latter option modifies revision traversal\n> > in that it skips octopus merges, root commits, and single parent\n> > commits IF no cherry-pick or revert information can be found.  If it\n> > finds a 2-parent merge commit, it behaves like --remerge-diff.  If it\n> > finds a 1-parent commit with cherry-pick or revert information, it'll\n> > do an in memory repeat of that cherry-pick (or revert) and then diff\n> > the actual commit against what the automatic cherry-pick would\n> > perform.  Again, that likely means an empty diff if the automatic\n> > cherry-pick was clean, and showing any changes made by the user to\n> > complete the original cherry-pick (such as deleting conflict markers\n> > and picking which chunks from which side to keep) if the automatic\n> > cherry-pick was not clean.  (I suspect --remerge-diff-only is much\n> > more likely to be used with `git show` than with `git log`.)  Anyway,\n> > your changes seem to suggest that anything relating to how diffs for\n> > merges are handled should be documented in the same section, but\n> > --remerge-diff-only doesn't fit.  And it'd seem odd to have\n> > --remerge-diff and --remerge-diff-only not show up in adjacently but\n> > be split into separate sections.  Any ideas?\n>\n> Sounds like commits limiting option to me. I think it could be named by\n> its limiting behavior only, say, --remerges. Then it will imply\n> --diff-merges=remerge, that'd allow user to re-define diff format if she\n> needs to.\n\nIt is commit limiting, but the focus is more on the behavioral change\nin how diffs are shown:\n  * for 2-parent merges\n  * for single-parent commits with cherry-pick or revert information\nand acknowledging that since it has _altered_ the normal way of\nshowing diffs for a number of single-parent commits, that it'd be\nconfusing to show normal diffs of unaffected commits (how would you be\nable to tell what type of diff you're looking at if both appear in the\nlog?).  Thus, it does commit limiting to only select commits which\nwill make use of the new diff type.\n\n(I suspect it will be more common for folks to use the\n--remerge-diff-only option, or whatever we end up calling it, with\n`git show` where the commit limiting doesn't matter -- but I have used\nit with log to go looking for \"evil\" reverts/cherry-picks that might\nhave occurred in history.)\n\n> I mean, it looks very similar to --first-parent to me in the ways it\n> could be defined/implemented. Recall that --first-parent now implies\n> --diff-merges=first-parent.\n>\n> [...]\n>\n> >>\n> >> Updates in v1:\n> >\n> > A minor point, but this should have been labelled v2.  The unlabelled\n> > original submission is v1.\n>\n> Well, I did consider it when prepared v1, but given:\n>\n>   git format-patch --reroll-count=0\n>\n> produces [PATCH], it only sounds natural to follow with\n>\n>   git format-patch --reroll-count=1\n>\n> that produces [PATCH v1].\n\nI didn't know about --reroll-count, I've always just seen people jump\nfrom [PATCH] to [PATCH v2].  Interesting.\n"},{"id":"411316","messageId":"xmqqlfeef56k.fsf@gitster.c.googlers.com","threadId":"54550","inReplyTo":"87a6uuj4wx.fsf@osv.gnss.ru","subject":"Re: [PATCH v1 01/27] revision: factor out parsing of diff-merge related options","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2020-12-04T06:36:51Z","receivedAt":"2020-12-04T06:37:36Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Sergey Organov <sorganov@gmail.com> writes:\n\n>>> +\t\tif (!strcmp(optarg, \"off\")) {\n>>> +\t\t\trevs->ignore_merges = 1;\n>>> +\t\t} else {\n>>> +\t\t\tdie(_(\"unknown value for --diff-merges: %s\"), optarg);\n>>> +\t\t}\n>>\n>> To correct the above bug, it probably is sufficient to add\n>>\n>> \t\treturn argcount;\n>>\n>> here.\n>\n> Right, but not enough. \"argcount\" should also be set to 1 at the\n> beginning of the function, to avoid returning uninitialized value here.\n\nYou seem to be a bit confused.\n\nThe suggested fix is to ...\n\n+static int parse_diff_merge_opts(struct rev_info *revs, const char **argv) {\n+\tint argcount;\n+\tconst char *optarg;\n+\tconst char *arg = argv[0];\n+\n+\tif (!strcmp(arg, \"-m\")) {\n+\t\t/*\n+\t\t * To \"diff-index\", \"-m\" means \"match missing\", and to the \"log\"\n+\t\t * family of commands, it means \"show full diff for merges\". Set\n+\t\t * both fields appropriately.\n+\t\t */\n+\t\trevs->ignore_merges = 0;\n+\t\trevs->match_missing = 1;\n+\t} else if (!strcmp(arg, \"-c\")) {\n+\t\trevs->diff = 1;\n+\t\trevs->dense_combined_merges = 0;\n+\t\trevs->combine_merges = 1;\n+\t} else if (!strcmp(arg, \"--cc\")) {\n+\t\trevs->diff = 1;\n+\t\trevs->dense_combined_merges = 1;\n+\t\trevs->combine_merges = 1;\n+\t} else if (!strcmp(arg, \"--no-diff-merges\")) {\n+\t\trevs->ignore_merges = 1;\n+\t} else if (!strcmp(arg, \"--combined-all-paths\")) {\n+\t\trevs->diff = 1;\n+\t\trevs->combined_all_paths = 1;\n+\t} else if ((argcount = parse_long_opt(\"diff-merges\", argv, &optarg))) {\n+\t\tif (!strcmp(optarg, \"off\")) {\n+\t\t\trevs->ignore_merges = 1;\n+\t\t} else {\n+\t\t\tdie(_(\"unknown value for --diff-merges: %s\"), optarg);\n+\t\t}\n\n... add\n\n\t\treturn argcount;\n\nhere.  We know argcount has a valid value that was returned from\nparse_long_opt() at this point.  Nobody else needs to look at the\nargcount variable.\n\n+\t} else\n+\t\treturn 0;\n+\n+\treturn 1;\n+}\n\nIncidentally, that is consistent with the way the original function\nhandled the \"diff-merges\" option at ...\n\n static int handle_revision_opt(struct rev_info *revs, int argc, const char **argv,\n \t\t\t       int *unkc, const char **unkv,\n \t\t\t       const struct setup_revision_opt* opt)\n {\n \tconst char *arg = argv[0];\n \tconst char *optarg;\n \tint argcount;\n \tconst unsigned hexsz = the_hash_algo->hexsz;\n ...\n-\t\trevs->ignore_merges = 0;\n-\t\trevs->match_missing = 1;\n-\t} else if ((argcount = parse_long_opt(\"diff-merges\", argv, &optarg))) {\n-\t\tif (!strcmp(optarg, \"off\")) {\n-\t\t\trevs->ignore_merges = 1;\n-\t\t} else {\n-\t\t\tdie(_(\"unknown value for --diff-merges: %s\"), optarg);\n-\t\t}\n+\t} else if ((argcount = parse_diff_merge_opts(revs, argv))) {\n \t\treturn argcount;\n\n... this point.  We asked parse_long_opt() to supply the return\nvalue for us, and then returned that to our caller.\n\n-\t} else if (!strcmp(arg, \"--no-diff-merges\")) {\n-\t\trevs->ignore_merges = 1;\n"},{"id":"411336","messageId":"87blf9pjsx.fsf@osv.gnss.ru","threadId":"54550","inReplyTo":"CABPp-BFW5ZLvEHFuiRC3rGqdGHWBZRjGHtTq=vVky9U5rZXsvA@mail.gmail.com","subject":"Re: [PATCH 10/26] diff-merges: new function diff_merges_suppress()","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-04T17:23:10Z","receivedAt":"2020-12-04T17:24:00Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Hi Elijah,\n\nElijah Newren <newren@gmail.com> writes:\n\n> Hi Sergey,\n>\n> On Thu, Dec 3, 2020 at 12:06 PM Sergey Organov <sorganov@gmail.com> wrote:\n>>\n>> Elijah Newren <newren@gmail.com> writes:\n>>\n>> > On Sun, Nov 1, 2020 at 11:36 AM Sergey Organov <sorganov@gmail.com> wrote:\n>> >>\n>> >> This function sets all the relevant flags to disabled state, so that\n>> >> no code that checks only one of them get it wrong.\n>> >>\n>> >> Then we call this new function everywhere where diff merges output\n>> >> suppression is needed.\n>> >>\n>> >> Signed-off-by: Sergey Organov <sorganov@gmail.com>\n>> >> ---\n>> >>  builtin/merge.c |  3 ++-\n>> >>  diff-merges.c   | 18 ++++++++++++++----\n>> >>  diff-merges.h   |  2 ++\n>> >>  fmt-merge-msg.c |  3 ++-\n>> >>  4 files changed, 20 insertions(+), 6 deletions(-)\n>> >>\n>> >> diff --git a/builtin/merge.c b/builtin/merge.c\n>> >> index 9d5359edc2f7..1f7b69982b40 100644\n>> >> --- a/builtin/merge.c\n>> >> +++ b/builtin/merge.c\n>> >> @@ -14,6 +14,7 @@\n>> >>  #include \"lockfile.h\"\n>> >>  #include \"run-command.h\"\n>> >>  #include \"diff.h\"\n>> >> +#include \"diff-merges.h\"\n>> >>  #include \"refs.h\"\n>> >>  #include \"refspec.h\"\n>> >>  #include \"commit.h\"\n>> >> @@ -400,7 +401,7 @@ static void squash_message(struct commit *commit, struct commit_list *remotehead\n>> >>         printf(_(\"Squash commit -- not updating HEAD\\n\"));\n>> >>\n>> >>         repo_init_revisions(the_repository, &rev, NULL);\n>> >> -       rev.ignore_merges = 1;\n>> >> +       diff_merges_suppress(&rev);\n>> >>         rev.commit_format = CMIT_FMT_MEDIUM;\n>> >>\n>> >>         commit->object.flags |= UNINTERESTING;\n>> >> diff --git a/diff-merges.c b/diff-merges.c\n>> >> index 8536941e0b56..25bd9b12e667 100644\n>> >> --- a/diff-merges.c\n>> >> +++ b/diff-merges.c\n>> >> @@ -2,6 +2,13 @@\n>> >>\n>> >>  #include \"revision.h\"\n>> >>\n>> >> +static void suppress(struct rev_info *revs) {\n>> >> +       revs->ignore_merges = 1;\n>> >> +       revs->first_parent_merges = 0;\n>> >> +       revs->combine_merges = 0;\n>> >> +       revs->dense_combined_merges = 0;\n>> >> +}\n>> >\n>> > The function name is not so helpful;\n>>\n>> Do you have better suggestion? suppress_output()? supress_diff()?\n>>\n>> > why not put all this code directly in diff_merges_suppress()?\n>>\n>> I prefer the style where module implementation functions don't call its\n>> interface functions, only vice versa.\n>>\n>> >\n>> >> +\n>> >>  /*\n>> >>   * Public functions. They are in the order they are called.\n>> >>   */\n>> >> @@ -29,16 +36,15 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {\n>> >>                 revs->combine_merges = 1;\n>> >>         } else if (!strcmp(arg, \"--cc\")) {\n>> >>                 revs->diff = 1;\n>> >> -               revs->dense_combined_merges = 1;\n>> >> -               revs->combine_merges = 1;\n>> >> +               set_dense_combined(revs);\n>> >>         } else if (!strcmp(arg, \"--no-diff-merges\")) {\n>> >> -               revs->ignore_merges = 1;\n>> >> +               suppress(revs);\n>> >>         } else if (!strcmp(arg, \"--combined-all-paths\")) {\n>> >>                 revs->diff = 1;\n>> >>                 revs->combined_all_paths = 1;\n>> >>         } else if ((argcount = parse_long_opt(\"diff-merges\", argv, &optarg))) {\n>> >>                 if (!strcmp(optarg, \"off\")) {\n>> >> -                       revs->ignore_merges = 1;\n>> >> +                       suppress(revs);\n>> >>                 } else {\n>> >>                         die(_(\"unknown value for --diff-merges: %s\"), optarg);\n>> >>                 }\n>> >> @@ -48,6 +54,10 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {\n>> >>         return 1;\n>> >>  }\n>> >>\n>> >> +void diff_merges_suppress(struct rev_info *revs) {\n>> >> +       suppress(revs);\n>> >> +}\n>> >\n>> > ...especially since all this function does is call suppress()?\n>>\n>> Yes, it does, but it doesn't mean it will be that way forever. Interface\n>> function might need to perform additional checks or actions, in general.\n>\n> Ah, I didn't catch the distinction and thus the reasoning in having\n> the two different functions.\n>\n>> Besides, if diff_merges_suppress() is OK with you as interface function\n>> name, why suppress() is not OK as local function name in diff-merges\n>> module?\n>\n> Right, the fact that it's in the diff-merges module as opposed to more\n> general diff-lib code is probably hint enough.  I was skimming over\n> the patches looking for things that jumped out, and although I had\n> read that you were adding it to the new module, I forgot that when I\n> saw the \"suppress()\" function name.  Thanks for the reminder, and\n> sorry for the noise.\n\nFine, thanks, and please don't mention it!\n\n-- \nSergey Organov\n"},{"id":"411338","messageId":"877dpxpjae.fsf@osv.gnss.ru","threadId":"54550","inReplyTo":"CABPp-BEyiLDZ5Ums1D5gL679EMmKXpqxWDF_xGT4scXLMkwseg@mail.gmail.com","subject":"Re: [PATCH v1 24/27] doc/git-log: describe new --diff-merges options","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-04T17:34:17Z","receivedAt":"2020-12-04T17:35:08Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Elijah Newren <newren@gmail.com> writes:\n\n> On Thu, Dec 3, 2020 at 11:34 AM Sergey Organov <sorganov@gmail.com> wrote:\n>>\n>> Elijah Newren <newren@gmail.com> writes:\n\n[...]\n\n>> >> ++\n>> >> +--diff-merges=(off|none):::\n>> >> +--no-diff-merges:::\n>> >> +       (default) Disable output of diffs for merge commits. Useful to\n>> >> +       override implied value.\n>> >> ++\n>> >> +--diff-merges=first-parent:::\n>> >> +       This option makes merge commits show the full diff with\n>> >> +       respect to the first parent only, exactly like  regular\n>> >> +       commits.\n>> >\n>> > Not sure that \"exactly like regular commits\" is helpful here; I'd\n>> > personally rather cut those four words out.  I'm worried it'll be\n>> > taken not as an implementation explanation, but as a \"this treats\n>> > merge commits in the natural way that regular commits are\" which users\n>> > may mistakenly translate to \"it shows what changes the user manually\n>> > made as part of the commit\" which is not at all the correct mapping.\n>>\n>> Dunno. Don't have strict preference here. Git has no idea how the\n>> changes in a commit have been made in the first place. Changes are just\n>> changes.\n>\n> If you don't have a preference, can we drop those four words?  ;-)\n\nYeah, sure, dropped.\n\n>\n>> To my excuse, I took this from git:5fbb4bc191 that has:\n>>\n>> +Note that unless one of `-c`, `--cc`, or `-m` is given, merge commits\n>> +will never show a diff, even if a diff format like `--patch` is\n>> +selected, nor will they match search options like `-S`. The exception is\n>> +when `--first-parent` is in use, in which merges are treated like normal\n>> +single-parent commits (this can be overridden by providing a\n>> +combined-diff option or with `--no-diff-merges`).\n>\n> Yeah, I can see where you're coming from, though the context change\n> feels like just enough different that the four words you added bother\n> me a bit more.  However, this existing wording does bother me now that\n> you highlight it.  Even though it's not something introduced by your\n> patch, I'd really like to drop \"normal\" here; I think it is prone to\n> cause confusion to users and as far as I can tell provides no useful\n> meaning for the sentence.  (There are multiple types of single-parent\n> commits?  What is an \"unnormal\" one?  How do I tell which kind I want?\n>  etc...).\n\nI see your point, but I won't change it in these series. I think that\nit'd be better if you change this yourself, independently.\n\nThanks,\n-- \nSergey Organov\n"},{"id":"411340","messageId":"CABPp-BH1ORV8XYzM1ESH8NibAb2B-OszqZ6r2xnU2pxvR5AZwQ@mail.gmail.com","threadId":"54550","inReplyTo":"877dpxpjae.fsf@osv.gnss.ru","subject":"Re: [PATCH v1 24/27] doc/git-log: describe new --diff-merges options","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2020-12-04T18:33:57Z","receivedAt":"2020-12-04T18:34:50Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Fri, Dec 4, 2020 at 9:34 AM Sergey Organov <sorganov@gmail.com> wrote:\n>\n> Elijah Newren <newren@gmail.com> writes:\n>\n> > On Thu, Dec 3, 2020 at 11:34 AM Sergey Organov <sorganov@gmail.com> wrote:\n> >>\n> >> Elijah Newren <newren@gmail.com> writes:\n>\n> [...]\n>\n> >> >> ++\n> >> >> +--diff-merges=(off|none):::\n> >> >> +--no-diff-merges:::\n> >> >> +       (default) Disable output of diffs for merge commits. Useful to\n> >> >> +       override implied value.\n> >> >> ++\n> >> >> +--diff-merges=first-parent:::\n> >> >> +       This option makes merge commits show the full diff with\n> >> >> +       respect to the first parent only, exactly like  regular\n> >> >> +       commits.\n> >> >\n> >> > Not sure that \"exactly like regular commits\" is helpful here; I'd\n> >> > personally rather cut those four words out.  I'm worried it'll be\n> >> > taken not as an implementation explanation, but as a \"this treats\n> >> > merge commits in the natural way that regular commits are\" which users\n> >> > may mistakenly translate to \"it shows what changes the user manually\n> >> > made as part of the commit\" which is not at all the correct mapping.\n> >>\n> >> Dunno. Don't have strict preference here. Git has no idea how the\n> >> changes in a commit have been made in the first place. Changes are just\n> >> changes.\n> >\n> > If you don't have a preference, can we drop those four words?  ;-)\n>\n> Yeah, sure, dropped.\n>\n> >\n> >> To my excuse, I took this from git:5fbb4bc191 that has:\n> >>\n> >> +Note that unless one of `-c`, `--cc`, or `-m` is given, merge commits\n> >> +will never show a diff, even if a diff format like `--patch` is\n> >> +selected, nor will they match search options like `-S`. The exception is\n> >> +when `--first-parent` is in use, in which merges are treated like normal\n> >> +single-parent commits (this can be overridden by providing a\n> >> +combined-diff option or with `--no-diff-merges`).\n> >\n> > Yeah, I can see where you're coming from, though the context change\n> > feels like just enough different that the four words you added bother\n> > me a bit more.  However, this existing wording does bother me now that\n> > you highlight it.  Even though it's not something introduced by your\n> > patch, I'd really like to drop \"normal\" here; I think it is prone to\n> > cause confusion to users and as far as I can tell provides no useful\n> > meaning for the sentence.  (There are multiple types of single-parent\n> > commits?  What is an \"unnormal\" one?  How do I tell which kind I want?\n> >  etc...).\n>\n> I see your point, but I won't change it in these series. I think that\n> it'd be better if you change this yourself, independently.\n\nSounds good; I'll submit it after your series merges to avoid any conflicts.\n"},{"id":"411353","messageId":"87360lpeup.fsf@osv.gnss.ru","threadId":"54550","inReplyTo":"xmqqlfeef56k.fsf@gitster.c.googlers.com","subject":"Re: [PATCH v1 01/27] revision: factor out parsing of diff-merge related options","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-04T19:10:06Z","receivedAt":"2020-12-04T19:10:54Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Sergey Organov <sorganov@gmail.com> writes:\n>\n>>>> +\t\tif (!strcmp(optarg, \"off\")) {\n>>>> +\t\t\trevs->ignore_merges = 1;\n>>>> +\t\t} else {\n>>>> +\t\t\tdie(_(\"unknown value for --diff-merges: %s\"), optarg);\n>>>> +\t\t}\n>>>\n>>> To correct the above bug, it probably is sufficient to add\n>>>\n>>> \t\treturn argcount;\n>>>\n>>> here.\n>>\n>> Right, but not enough. \"argcount\" should also be set to 1 at the\n>> beginning of the function, to avoid returning uninitialized value here.\n>\n> You seem to be a bit confused.\n>\n> The suggested fix is to ...\n>\n> +static int parse_diff_merge_opts(struct rev_info *revs, const char **argv) {\n> +\tint argcount;\n> +\tconst char *optarg;\n> +\tconst char *arg = argv[0];\n> +\n> +\tif (!strcmp(arg, \"-m\")) {\n> +\t\t/*\n> +\t\t * To \"diff-index\", \"-m\" means \"match missing\", and to the \"log\"\n> +\t\t * family of commands, it means \"show full diff for merges\". Set\n> +\t\t * both fields appropriately.\n> +\t\t */\n> +\t\trevs->ignore_merges = 0;\n> +\t\trevs->match_missing = 1;\n> +\t} else if (!strcmp(arg, \"-c\")) {\n> +\t\trevs->diff = 1;\n> +\t\trevs->dense_combined_merges = 0;\n> +\t\trevs->combine_merges = 1;\n> +\t} else if (!strcmp(arg, \"--cc\")) {\n> +\t\trevs->diff = 1;\n> +\t\trevs->dense_combined_merges = 1;\n> +\t\trevs->combine_merges = 1;\n> +\t} else if (!strcmp(arg, \"--no-diff-merges\")) {\n> +\t\trevs->ignore_merges = 1;\n> +\t} else if (!strcmp(arg, \"--combined-all-paths\")) {\n> +\t\trevs->diff = 1;\n> +\t\trevs->combined_all_paths = 1;\n> +\t} else if ((argcount = parse_long_opt(\"diff-merges\", argv, &optarg))) {\n> +\t\tif (!strcmp(optarg, \"off\")) {\n> +\t\t\trevs->ignore_merges = 1;\n> +\t\t} else {\n> +\t\t\tdie(_(\"unknown value for --diff-merges: %s\"), optarg);\n> +\t\t}\n>\n> ... add\n>\n> \t\treturn argcount;\n>\n> here.  We know argcount has a valid value that was returned from\n> parse_long_opt() at this point.  \n\n[...]\n\nOK, thanks, I now see what you meant, yet I now implemented it slightly\ndifferently, as I finally need one point of return from the function\nwith non-zero value.\n\nThe end result is hopefully the same though.\n\nThanks,\n-- Sergey Organov\n"},{"id":"411358","messageId":"87sg8lnzor.fsf@osv.gnss.ru","threadId":"54550","inReplyTo":"CABPp-BGE4rA5=8NUaK5607moR13bE7PcyVKdbw6nDw5YBeq9bQ@mail.gmail.com","subject":"Re: [PATCH v1 00/27] git-log: implement new --diff-merge options","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-04T19:23:00Z","receivedAt":"2020-12-04T19:23:58Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Elijah Newren <newren@gmail.com> writes:\n\n> On Thu, Dec 3, 2020 at 11:48 AM Sergey Organov <sorganov@gmail.com> wrote:\n>>\n>> Elijah Newren <newren@gmail.com> writes:\n>>\n>> > On Sun, Nov 8, 2020 at 1:43 PM Sergey Organov <sorganov@gmail.com> wrote:\n>> >>\n>> >> These patch series implement new set of options governing the diff output\n>> >> of merge commits, all under the umbrella of the single\n>> >> --diff-merges=<mode>\n>> >> option. Most of the new options being synonyms for -m/-c/--cc options,\n>> >> there is also additional functionality provided, allowing to get\n>> >> the format\n>> >> of \"-p --first-parent\" without change in history traversal that\n>> >> --first-parent option causes.\n>> >>\n>> >> The net result of these series are the following new options:\n>> >>\n>> >> --diff-merges=   |  old equivalent\n>> >> -----------------+----------------\n>> >> first-parent     | --first-parent (only format implications)\n>> >> separate         | -m\n>> >> combined         | -c\n>> >> dense-combined   | --cc\n>> >\n>> > Interesting.  I have some local patches implementing another choice,\n>> > with the new flag --remerge-diff.  This flag will cause `git show` or\n>> > `git log` to automatically remerge the two parents in a 2-parent merge\n>> > commit, and then diff the merge commit against that automatic merge,\n>> > showing the result.  Thus, the diff for a merge commit is likely to be\n>> > empty if the merge was clean, and is likely to show the removal of\n>> > conflict markers if the merge was not clean.\n>> >\n>> > I'm curious how it'd interact with this new option.  Would it also get\n>> > a name, e.g. --diff-merges=remerge-diff?  Feels like a mouthful, but I\n>> > can't come up with anything better.\n>>\n>> Maybe, --diff-merges=remerge?\n>>\n>> >\n>> > Also, I'm curious how it'd interact with another option I added, named\n>> > --remerge-diff-only.  This latter option modifies revision traversal\n>> > in that it skips octopus merges, root commits, and single parent\n>> > commits IF no cherry-pick or revert information can be found.  If it\n>> > finds a 2-parent merge commit, it behaves like --remerge-diff.  If it\n>> > finds a 1-parent commit with cherry-pick or revert information, it'll\n>> > do an in memory repeat of that cherry-pick (or revert) and then diff\n>> > the actual commit against what the automatic cherry-pick would\n>> > perform.  Again, that likely means an empty diff if the automatic\n>> > cherry-pick was clean, and showing any changes made by the user to\n>> > complete the original cherry-pick (such as deleting conflict markers\n>> > and picking which chunks from which side to keep) if the automatic\n>> > cherry-pick was not clean.  (I suspect --remerge-diff-only is much\n>> > more likely to be used with `git show` than with `git log`.)  Anyway,\n>> > your changes seem to suggest that anything relating to how diffs for\n>> > merges are handled should be documented in the same section, but\n>> > --remerge-diff-only doesn't fit.  And it'd seem odd to have\n>> > --remerge-diff and --remerge-diff-only not show up in adjacently but\n>> > be split into separate sections.  Any ideas?\n>>\n>> Sounds like commits limiting option to me. I think it could be named by\n>> its limiting behavior only, say, --remerges. Then it will imply\n>> --diff-merges=remerge, that'd allow user to re-define diff format if she\n>> needs to.\n>\n> It is commit limiting, but the focus is more on the behavioral change\n> in how diffs are shown:\n>   * for 2-parent merges\n>   * for single-parent commits with cherry-pick or revert information\n> and acknowledging that since it has _altered_ the normal way of\n> showing diffs for a number of single-parent commits, that it'd be\n> confusing to show normal diffs of unaffected commits (how would you be\n> able to tell what type of diff you're looking at if both appear in the\n> log?).  Thus, it does commit limiting to only select commits which\n> will make use of the new diff type.\n\nThat's how you currently look at it.\n\nFor me it looks like pure commit limiting with these criteria might be\nuseful by itself, and with my suggestion one could then achieve it\nusing, say:\n\n--remerge-diff-only --diff-merges=off\n\n>\n> (I suspect it will be more common for folks to use the\n> --remerge-diff-only option, or whatever we end up calling it, with\n> `git show` where the commit limiting doesn't matter -- but I have used\n> it with log to go looking for \"evil\" reverts/cherry-picks that might\n> have occurred in history.)\n\nWhat you describe is complex enough to doubt it could be entirely\ndescribed by option name, so shorter --evils might be better choice\nin this case.\n\nOverall, if you add --diff-merges=remerge as a new diff format, and then\n--evils that implies the former, then it seems like all possible\nuse-cases will be covered, and you have short option name for the most\nuseful case.\n\n-- Sergey Organov\n"},{"id":"411365","messageId":"87o8j9ny22.fsf@osv.gnss.ru","threadId":"54550","inReplyTo":"CABPp-BH1ORV8XYzM1ESH8NibAb2B-OszqZ6r2xnU2pxvR5AZwQ@mail.gmail.com","subject":"Re: [PATCH v1 24/27] doc/git-log: describe new --diff-merges options","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-04T19:58:13Z","receivedAt":"2020-12-04T19:58:59Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Elijah Newren <newren@gmail.com> writes:\n\n> On Fri, Dec 4, 2020 at 9:34 AM Sergey Organov <sorganov@gmail.com> wrote:\n\n[...]\n\n>> >> To my excuse, I took this from git:5fbb4bc191 that has:\n>> >>\n>> >> +Note that unless one of `-c`, `--cc`, or `-m` is given, merge commits\n>> >> +will never show a diff, even if a diff format like `--patch` is\n>> >> +selected, nor will they match search options like `-S`. The exception is\n>> >> +when `--first-parent` is in use, in which merges are treated like normal\n>> >> +single-parent commits (this can be overridden by providing a\n>> >> +combined-diff option or with `--no-diff-merges`).\n>> >\n>> > Yeah, I can see where you're coming from, though the context change\n>> > feels like just enough different that the four words you added bother\n>> > me a bit more.  However, this existing wording does bother me now that\n>> > you highlight it.  Even though it's not something introduced by your\n>> > patch, I'd really like to drop \"normal\" here; I think it is prone to\n>> > cause confusion to users and as far as I can tell provides no useful\n>> > meaning for the sentence.  (There are multiple types of single-parent\n>> > commits?  What is an \"unnormal\" one?  How do I tell which kind I want?\n>> >  etc...).\n>>\n>> I see your point, but I won't change it in these series. I think that\n>> it'd be better if you change this yourself, independently.\n>\n> Sounds good; I'll submit it after your series merges to avoid any conflicts.\n\nOoops! I actually did change this in the series, and now it reads:\n\n       Note that unless one of --diff-merges variants (including short\n       -m, -c, and --cc options) is explicitly given, merge commits will\n       not show a diff, even if a diff format like --patch is selected,\n       nor will they match search options like -S. The exception is when\n       --first-parent is in use, in which case\n       --diff-merges=first-parent is implied.\n\nthat hopefully is OK with you.\n\n-- Sergey Organov\n"},{"id":"411366","messageId":"CABPp-BGT9S5av=X0UyLUXziSYbEj75bG8VLsf9A4-GCSHOQ5ug@mail.gmail.com","threadId":"54550","inReplyTo":"87o8j9ny22.fsf@osv.gnss.ru","subject":"Re: [PATCH v1 24/27] doc/git-log: describe new --diff-merges options","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2020-12-04T20:01:12Z","receivedAt":"2020-12-04T20:02:06Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Fri, Dec 4, 2020 at 11:58 AM Sergey Organov <sorganov@gmail.com> wrote:\n>\n> Elijah Newren <newren@gmail.com> writes:\n>\n> > On Fri, Dec 4, 2020 at 9:34 AM Sergey Organov <sorganov@gmail.com> wrote:\n>\n> [...]\n>\n> >> >> To my excuse, I took this from git:5fbb4bc191 that has:\n> >> >>\n> >> >> +Note that unless one of `-c`, `--cc`, or `-m` is given, merge commits\n> >> >> +will never show a diff, even if a diff format like `--patch` is\n> >> >> +selected, nor will they match search options like `-S`. The exception is\n> >> >> +when `--first-parent` is in use, in which merges are treated like normal\n> >> >> +single-parent commits (this can be overridden by providing a\n> >> >> +combined-diff option or with `--no-diff-merges`).\n> >> >\n> >> > Yeah, I can see where you're coming from, though the context change\n> >> > feels like just enough different that the four words you added bother\n> >> > me a bit more.  However, this existing wording does bother me now that\n> >> > you highlight it.  Even though it's not something introduced by your\n> >> > patch, I'd really like to drop \"normal\" here; I think it is prone to\n> >> > cause confusion to users and as far as I can tell provides no useful\n> >> > meaning for the sentence.  (There are multiple types of single-parent\n> >> > commits?  What is an \"unnormal\" one?  How do I tell which kind I want?\n> >> >  etc...).\n> >>\n> >> I see your point, but I won't change it in these series. I think that\n> >> it'd be better if you change this yourself, independently.\n> >\n> > Sounds good; I'll submit it after your series merges to avoid any conflicts.\n>\n> Ooops! I actually did change this in the series, and now it reads:\n>\n>        Note that unless one of --diff-merges variants (including short\n>        -m, -c, and --cc options) is explicitly given, merge commits will\n>        not show a diff, even if a diff format like --patch is selected,\n>        nor will they match search options like -S. The exception is when\n>        --first-parent is in use, in which case\n>        --diff-merges=first-parent is implied.\n>\n> that hopefully is OK with you.\n\nAh, together with the dropping of those four extra words on the\ndescription of --diff-merges=first-parent, this seems great.  Thanks!\n:-)\n"},{"id":"411508","messageId":"CABPp-BFB9aaJV1uvYk1QQ6E8zQ=_Jv6KhHb1grA5+Bh+qsTG8g@mail.gmail.com","threadId":"54550","inReplyTo":"87sg8lnzor.fsf@osv.gnss.ru","subject":"Re: [PATCH v1 00/27] git-log: implement new --diff-merge options","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2020-12-05T17:49:14Z","receivedAt":"2020-12-05T18:42:33Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Fri, Dec 4, 2020 at 11:23 AM Sergey Organov <sorganov@gmail.com> wrote:\n>\n> Elijah Newren <newren@gmail.com> writes:\n>\n> > On Thu, Dec 3, 2020 at 11:48 AM Sergey Organov <sorganov@gmail.com> wrote:\n> >>\n> >> Elijah Newren <newren@gmail.com> writes:\n> >>\n> >> > On Sun, Nov 8, 2020 at 1:43 PM Sergey Organov <sorganov@gmail.com> wrote:\n> >> >>\n> >> >> These patch series implement new set of options governing the diff output\n> >> >> of merge commits, all under the umbrella of the single\n> >> >> --diff-merges=<mode>\n> >> >> option. Most of the new options being synonyms for -m/-c/--cc options,\n> >> >> there is also additional functionality provided, allowing to get\n> >> >> the format\n> >> >> of \"-p --first-parent\" without change in history traversal that\n> >> >> --first-parent option causes.\n> >> >>\n> >> >> The net result of these series are the following new options:\n> >> >>\n> >> >> --diff-merges=   |  old equivalent\n> >> >> -----------------+----------------\n> >> >> first-parent     | --first-parent (only format implications)\n> >> >> separate         | -m\n> >> >> combined         | -c\n> >> >> dense-combined   | --cc\n> >> >\n> >> > Interesting.  I have some local patches implementing another choice,\n> >> > with the new flag --remerge-diff.  This flag will cause `git show` or\n> >> > `git log` to automatically remerge the two parents in a 2-parent merge\n> >> > commit, and then diff the merge commit against that automatic merge,\n> >> > showing the result.  Thus, the diff for a merge commit is likely to be\n> >> > empty if the merge was clean, and is likely to show the removal of\n> >> > conflict markers if the merge was not clean.\n> >> >\n> >> > I'm curious how it'd interact with this new option.  Would it also get\n> >> > a name, e.g. --diff-merges=remerge-diff?  Feels like a mouthful, but I\n> >> > can't come up with anything better.\n> >>\n> >> Maybe, --diff-merges=remerge?\n> >>\n> >> >\n> >> > Also, I'm curious how it'd interact with another option I added, named\n> >> > --remerge-diff-only.  This latter option modifies revision traversal\n> >> > in that it skips octopus merges, root commits, and single parent\n> >> > commits IF no cherry-pick or revert information can be found.  If it\n> >> > finds a 2-parent merge commit, it behaves like --remerge-diff.  If it\n> >> > finds a 1-parent commit with cherry-pick or revert information, it'll\n> >> > do an in memory repeat of that cherry-pick (or revert) and then diff\n> >> > the actual commit against what the automatic cherry-pick would\n> >> > perform.  Again, that likely means an empty diff if the automatic\n> >> > cherry-pick was clean, and showing any changes made by the user to\n> >> > complete the original cherry-pick (such as deleting conflict markers\n> >> > and picking which chunks from which side to keep) if the automatic\n> >> > cherry-pick was not clean.  (I suspect --remerge-diff-only is much\n> >> > more likely to be used with `git show` than with `git log`.)  Anyway,\n> >> > your changes seem to suggest that anything relating to how diffs for\n> >> > merges are handled should be documented in the same section, but\n> >> > --remerge-diff-only doesn't fit.  And it'd seem odd to have\n> >> > --remerge-diff and --remerge-diff-only not show up in adjacently but\n> >> > be split into separate sections.  Any ideas?\n> >>\n> >> Sounds like commits limiting option to me. I think it could be named by\n> >> its limiting behavior only, say, --remerges. Then it will imply\n> >> --diff-merges=remerge, that'd allow user to re-define diff format if she\n> >> needs to.\n> >\n> > It is commit limiting, but the focus is more on the behavioral change\n> > in how diffs are shown:\n> >   * for 2-parent merges\n> >   * for single-parent commits with cherry-pick or revert information\n> > and acknowledging that since it has _altered_ the normal way of\n> > showing diffs for a number of single-parent commits, that it'd be\n> > confusing to show normal diffs of unaffected commits (how would you be\n> > able to tell what type of diff you're looking at if both appear in the\n> > log?).  Thus, it does commit limiting to only select commits which\n> > will make use of the new diff type.\n>\n> That's how you currently look at it.\n>\n> For me it looks like pure commit limiting with these criteria might be\n> useful by itself, and with my suggestion one could then achieve it\n> using, say:\n>\n> --remerge-diff-only --diff-merges=off\n\nI see what you're saying, and I think there's some value in it.  But I\nthink there's something still missing.  For example, you suggest\ngetting the commit limiting I mention with\n\n    --remerge-diff-only --diff-merges=off\n\nBut --diff-merges is only supposed to control _merge_ commits, which I\nflagged as the big impedance mismatch for my new option.  Why would it\nturn off diffs for non-merge commits like cherry-picks and rebases?\n\n> >\n> > (I suspect it will be more common for folks to use the\n> > --remerge-diff-only option, or whatever we end up calling it, with\n> > `git show` where the commit limiting doesn't matter -- but I have used\n> > it with log to go looking for \"evil\" reverts/cherry-picks that might\n> > have occurred in history.)\n>\n> What you describe is complex enough to doubt it could be entirely\n> described by option name, so shorter --evils might be better choice\n> in this case.\n>\n> Overall, if you add --diff-merges=remerge as a new diff format, and then\n> --evils that implies the former, then it seems like all possible\n> use-cases will be covered, and you have short option name for the most\n> useful case.\n\nSince you want things to have orthogonal subcomponents that can be\nbuilt up, let's assume we did make --remerge-diff-only be solely about\ncommit limiting.  In that case, --evils could be gotten by specifying\na combination of flags, and --evils would just be a shorthand.  What\nare the flags that you would need to specify, though?  In particular,\nyou've only named two options above and they don't cover the necessary\nbehavior; a third is needed:\n\n   --remerge-diff-only --diff-merges=remerge\n--${DIFF_OPTION_NAME_FOR_CHERRY_PICKS_AND_REVERTS}=remerge\n\nThe first two aren't enough because --diff_merges only changes how\ndiffs for _merge_ commits are shown, and we need a flag for changing\nhow the single-parent cherry-pick and reverts are shown.\n"},{"id":"411512","messageId":"878sacjaws.fsf@osv.gnss.ru","threadId":"54550","inReplyTo":"CABPp-BFB9aaJV1uvYk1QQ6E8zQ=_Jv6KhHb1grA5+Bh+qsTG8g@mail.gmail.com","subject":"Re: [PATCH v1 00/27] git-log: implement new --diff-merge options","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-05T19:44:03Z","receivedAt":"2020-12-05T19:45:07Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Elijah Newren <newren@gmail.com> writes:\n\n> On Fri, Dec 4, 2020 at 11:23 AM Sergey Organov <sorganov@gmail.com> wrote:\n>>\n>> Elijah Newren <newren@gmail.com> writes:\n>>\n>> > On Thu, Dec 3, 2020 at 11:48 AM Sergey Organov <sorganov@gmail.com> wrote:\n>> >>\n>> >> Elijah Newren <newren@gmail.com> writes:\n>> >>\n>> >> > On Sun, Nov 8, 2020 at 1:43 PM Sergey Organov\n>> >> > <sorganov@gmail.com> wrote:\n>> >> >>\n>> >> >> These patch series implement new set of options governing the\n>> >> >> diff output\n>> >> >> of merge commits, all under the umbrella of the single\n>> >> >> --diff-merges=<mode>\n>> >> >> option. Most of the new options being synonyms for -m/-c/--cc options,\n>> >> >> there is also additional functionality provided, allowing to get\n>> >> >> the format\n>> >> >> of \"-p --first-parent\" without change in history traversal that\n>> >> >> --first-parent option causes.\n>> >> >>\n>> >> >> The net result of these series are the following new options:\n>> >> >>\n>> >> >> --diff-merges=   |  old equivalent\n>> >> >> -----------------+----------------\n>> >> >> first-parent     | --first-parent (only format implications)\n>> >> >> separate         | -m\n>> >> >> combined         | -c\n>> >> >> dense-combined   | --cc\n>> >> >\n>> >> > Interesting.  I have some local patches implementing another choice,\n>> >> > with the new flag --remerge-diff.  This flag will cause `git show` or\n>> >> > `git log` to automatically remerge the two parents in a 2-parent merge\n>> >> > commit, and then diff the merge commit against that automatic merge,\n>> >> > showing the result.  Thus, the diff for a merge commit is likely to be\n>> >> > empty if the merge was clean, and is likely to show the removal of\n>> >> > conflict markers if the merge was not clean.\n>> >> >\n>> >> > I'm curious how it'd interact with this new option.  Would it also get\n>> >> > a name, e.g. --diff-merges=remerge-diff?  Feels like a mouthful, but I\n>> >> > can't come up with anything better.\n>> >>\n>> >> Maybe, --diff-merges=remerge?\n>> >>\n>> >> >\n>> >> > Also, I'm curious how it'd interact with another option I added, named\n>> >> > --remerge-diff-only.  This latter option modifies revision traversal\n>> >> > in that it skips octopus merges, root commits, and single parent\n>> >> > commits IF no cherry-pick or revert information can be found.  If it\n>> >> > finds a 2-parent merge commit, it behaves like --remerge-diff.  If it\n>> >> > finds a 1-parent commit with cherry-pick or revert information, it'll\n>> >> > do an in memory repeat of that cherry-pick (or revert) and then diff\n>> >> > the actual commit against what the automatic cherry-pick would\n>> >> > perform.  Again, that likely means an empty diff if the automatic\n>> >> > cherry-pick was clean, and showing any changes made by the user to\n>> >> > complete the original cherry-pick (such as deleting conflict markers\n>> >> > and picking which chunks from which side to keep) if the automatic\n>> >> > cherry-pick was not clean.  (I suspect --remerge-diff-only is much\n>> >> > more likely to be used with `git show` than with `git log`.)  Anyway,\n>> >> > your changes seem to suggest that anything relating to how diffs for\n>> >> > merges are handled should be documented in the same section, but\n>> >> > --remerge-diff-only doesn't fit.  And it'd seem odd to have\n>> >> > --remerge-diff and --remerge-diff-only not show up in adjacently but\n>> >> > be split into separate sections.  Any ideas?\n>> >>\n>> >> Sounds like commits limiting option to me. I think it could be named by\n>> >> its limiting behavior only, say, --remerges. Then it will imply\n>> >> --diff-merges=remerge, that'd allow user to re-define diff format if she\n>> >> needs to.\n>> >\n>> > It is commit limiting, but the focus is more on the behavioral change\n>> > in how diffs are shown:\n>> >   * for 2-parent merges\n>> >   * for single-parent commits with cherry-pick or revert information\n>> > and acknowledging that since it has _altered_ the normal way of\n>> > showing diffs for a number of single-parent commits, that it'd be\n>> > confusing to show normal diffs of unaffected commits (how would you be\n>> > able to tell what type of diff you're looking at if both appear in the\n>> > log?).  Thus, it does commit limiting to only select commits which\n>> > will make use of the new diff type.\n>>\n>> That's how you currently look at it.\n>>\n>> For me it looks like pure commit limiting with these criteria might be\n>> useful by itself, and with my suggestion one could then achieve it\n>> using, say:\n>>\n>> --remerge-diff-only --diff-merges=off\n>\n> I see what you're saying, and I think there's some value in it.  But I\n> think there's something still missing.  For example, you suggest\n> getting the commit limiting I mention with\n>\n>     --remerge-diff-only --diff-merges=off\n>\n> But --diff-merges is only supposed to control _merge_ commits, which I\n> flagged as the big impedance mismatch for my new option.  Why would it\n> turn off diffs for non-merge commits like cherry-picks and rebases?\n>\n>> >\n>> > (I suspect it will be more common for folks to use the\n>> > --remerge-diff-only option, or whatever we end up calling it, with\n>> > `git show` where the commit limiting doesn't matter -- but I have used\n>> > it with log to go looking for \"evil\" reverts/cherry-picks that might\n>> > have occurred in history.)\n>>\n>> What you describe is complex enough to doubt it could be entirely\n>> described by option name, so shorter --evils might be better choice\n>> in this case.\n>>\n>> Overall, if you add --diff-merges=remerge as a new diff format, and then\n>> --evils that implies the former, then it seems like all possible\n>> use-cases will be covered, and you have short option name for the most\n>> useful case.\n>\n> Since you want things to have orthogonal subcomponents that can be\n> built up, let's assume we did make --remerge-diff-only be solely about\n> commit limiting.  In that case, --evils could be gotten by specifying\n> a combination of flags, and --evils would just be a shorthand.  What\n> are the flags that you would need to specify, though?  In particular,\n> you've only named two options above and they don't cover the necessary\n> behavior; a third is needed:\n>\n>    --remerge-diff-only --diff-merges=remerge\n> --${DIFF_OPTION_NAME_FOR_CHERRY_PICKS_AND_REVERTS}=remerge\n>\n> The first two aren't enough because --diff_merges only changes how\n> diffs for _merge_ commits are shown, and we need a flag for changing\n> how the single-parent cherry-pick and reverts are shown.\n\nYeah, I see your point. I didn't get it from the beginning that you want\nyet another representation format for regular commits as well. However,\nas far as I can tell, if --evils flag is active, you do consider\ncherry-picks and reverts as kind of merges, that makes sense as they\nactually /are/ expected to be results of specific /merge operation/,\neven though they are not /merge commits/, so semantically they do have\nsecond parent reference (to the original commit), even if a virtual one.\n\nTo further illustrate my point, reverts and cherry-picks could have been\nimplemented, for example, as merge commits with, say, 3-rd parent\npointing back to the original commit (not 2-nd parent, both to\ndifferentiate from regular merges and to support cherry-picking of merge\ncommits.)\n\nAs a side-note, people rarely differentiate between\n\"merge-the-operation\" and \"merge-the-result\" anyway, even when it leads\nto confusion.\n\nOverall, if we take the above into account, it seems to be fine if\n--diff-merges does affect the representation or such \"quasi-merge\"\ncommits, for the purposes of --evils option.\n\n-- Sergey Organov\n"},{"id":"411530","messageId":"CABPp-BFWsdb3ECcvQjN7_v2krsKAqhqv3CDWvQ9d20Oy521Vag@mail.gmail.com","threadId":"54550","inReplyTo":"878sacjaws.fsf@osv.gnss.ru","subject":"Re: [PATCH v1 00/27] git-log: implement new --diff-merge options","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2020-12-05T20:09:23Z","receivedAt":"2020-12-05T20:10:38Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Sat, Dec 5, 2020 at 11:44 AM Sergey Organov <sorganov@gmail.com> wrote:\n>\n> Elijah Newren <newren@gmail.com> writes:\n>\n> > On Fri, Dec 4, 2020 at 11:23 AM Sergey Organov <sorganov@gmail.com> wrote:\n> >>\n> >> Elijah Newren <newren@gmail.com> writes:\n> >>\n> >> > On Thu, Dec 3, 2020 at 11:48 AM Sergey Organov <sorganov@gmail.com> wrote:\n> >> >>\n> >> >> Elijah Newren <newren@gmail.com> writes:\n> >> >>\n> >> >> > On Sun, Nov 8, 2020 at 1:43 PM Sergey Organov\n> >> >> > <sorganov@gmail.com> wrote:\n> >> >> >>\n> >> >> >> These patch series implement new set of options governing the\n> >> >> >> diff output\n> >> >> >> of merge commits, all under the umbrella of the single\n> >> >> >> --diff-merges=<mode>\n> >> >> >> option. Most of the new options being synonyms for -m/-c/--cc options,\n> >> >> >> there is also additional functionality provided, allowing to get\n> >> >> >> the format\n> >> >> >> of \"-p --first-parent\" without change in history traversal that\n> >> >> >> --first-parent option causes.\n> >> >> >>\n> >> >> >> The net result of these series are the following new options:\n> >> >> >>\n> >> >> >> --diff-merges=   |  old equivalent\n> >> >> >> -----------------+----------------\n> >> >> >> first-parent     | --first-parent (only format implications)\n> >> >> >> separate         | -m\n> >> >> >> combined         | -c\n> >> >> >> dense-combined   | --cc\n> >> >> >\n> >> >> > Interesting.  I have some local patches implementing another choice,\n> >> >> > with the new flag --remerge-diff.  This flag will cause `git show` or\n> >> >> > `git log` to automatically remerge the two parents in a 2-parent merge\n> >> >> > commit, and then diff the merge commit against that automatic merge,\n> >> >> > showing the result.  Thus, the diff for a merge commit is likely to be\n> >> >> > empty if the merge was clean, and is likely to show the removal of\n> >> >> > conflict markers if the merge was not clean.\n> >> >> >\n> >> >> > I'm curious how it'd interact with this new option.  Would it also get\n> >> >> > a name, e.g. --diff-merges=remerge-diff?  Feels like a mouthful, but I\n> >> >> > can't come up with anything better.\n> >> >>\n> >> >> Maybe, --diff-merges=remerge?\n> >> >>\n> >> >> >\n> >> >> > Also, I'm curious how it'd interact with another option I added, named\n> >> >> > --remerge-diff-only.  This latter option modifies revision traversal\n> >> >> > in that it skips octopus merges, root commits, and single parent\n> >> >> > commits IF no cherry-pick or revert information can be found.  If it\n> >> >> > finds a 2-parent merge commit, it behaves like --remerge-diff.  If it\n> >> >> > finds a 1-parent commit with cherry-pick or revert information, it'll\n> >> >> > do an in memory repeat of that cherry-pick (or revert) and then diff\n> >> >> > the actual commit against what the automatic cherry-pick would\n> >> >> > perform.  Again, that likely means an empty diff if the automatic\n> >> >> > cherry-pick was clean, and showing any changes made by the user to\n> >> >> > complete the original cherry-pick (such as deleting conflict markers\n> >> >> > and picking which chunks from which side to keep) if the automatic\n> >> >> > cherry-pick was not clean.  (I suspect --remerge-diff-only is much\n> >> >> > more likely to be used with `git show` than with `git log`.)  Anyway,\n> >> >> > your changes seem to suggest that anything relating to how diffs for\n> >> >> > merges are handled should be documented in the same section, but\n> >> >> > --remerge-diff-only doesn't fit.  And it'd seem odd to have\n> >> >> > --remerge-diff and --remerge-diff-only not show up in adjacently but\n> >> >> > be split into separate sections.  Any ideas?\n> >> >>\n> >> >> Sounds like commits limiting option to me. I think it could be named by\n> >> >> its limiting behavior only, say, --remerges. Then it will imply\n> >> >> --diff-merges=remerge, that'd allow user to re-define diff format if she\n> >> >> needs to.\n> >> >\n> >> > It is commit limiting, but the focus is more on the behavioral change\n> >> > in how diffs are shown:\n> >> >   * for 2-parent merges\n> >> >   * for single-parent commits with cherry-pick or revert information\n> >> > and acknowledging that since it has _altered_ the normal way of\n> >> > showing diffs for a number of single-parent commits, that it'd be\n> >> > confusing to show normal diffs of unaffected commits (how would you be\n> >> > able to tell what type of diff you're looking at if both appear in the\n> >> > log?).  Thus, it does commit limiting to only select commits which\n> >> > will make use of the new diff type.\n> >>\n> >> That's how you currently look at it.\n> >>\n> >> For me it looks like pure commit limiting with these criteria might be\n> >> useful by itself, and with my suggestion one could then achieve it\n> >> using, say:\n> >>\n> >> --remerge-diff-only --diff-merges=off\n> >\n> > I see what you're saying, and I think there's some value in it.  But I\n> > think there's something still missing.  For example, you suggest\n> > getting the commit limiting I mention with\n> >\n> >     --remerge-diff-only --diff-merges=off\n> >\n> > But --diff-merges is only supposed to control _merge_ commits, which I\n> > flagged as the big impedance mismatch for my new option.  Why would it\n> > turn off diffs for non-merge commits like cherry-picks and rebases?\n> >\n> >> >\n> >> > (I suspect it will be more common for folks to use the\n> >> > --remerge-diff-only option, or whatever we end up calling it, with\n> >> > `git show` where the commit limiting doesn't matter -- but I have used\n> >> > it with log to go looking for \"evil\" reverts/cherry-picks that might\n> >> > have occurred in history.)\n> >>\n> >> What you describe is complex enough to doubt it could be entirely\n> >> described by option name, so shorter --evils might be better choice\n> >> in this case.\n> >>\n> >> Overall, if you add --diff-merges=remerge as a new diff format, and then\n> >> --evils that implies the former, then it seems like all possible\n> >> use-cases will be covered, and you have short option name for the most\n> >> useful case.\n> >\n> > Since you want things to have orthogonal subcomponents that can be\n> > built up, let's assume we did make --remerge-diff-only be solely about\n> > commit limiting.  In that case, --evils could be gotten by specifying\n> > a combination of flags, and --evils would just be a shorthand.  What\n> > are the flags that you would need to specify, though?  In particular,\n> > you've only named two options above and they don't cover the necessary\n> > behavior; a third is needed:\n> >\n> >    --remerge-diff-only --diff-merges=remerge\n> > --${DIFF_OPTION_NAME_FOR_CHERRY_PICKS_AND_REVERTS}=remerge\n> >\n> > The first two aren't enough because --diff_merges only changes how\n> > diffs for _merge_ commits are shown, and we need a flag for changing\n> > how the single-parent cherry-pick and reverts are shown.\n>\n> Yeah, I see your point. I didn't get it from the beginning that you want\n> yet another representation format for regular commits as well. However,\n> as far as I can tell, if --evils flag is active, you do consider\n> cherry-picks and reverts as kind of merges, that makes sense as they\n> actually /are/ expected to be results of specific /merge operation/,\n> even though they are not /merge commits/, so semantically they do have\n> second parent reference (to the original commit), even if a virtual one.\n>\n> To further illustrate my point, reverts and cherry-picks could have been\n> implemented, for example, as merge commits with, say, 3-rd parent\n> pointing back to the original commit (not 2-nd parent, both to\n> differentiate from regular merges and to support cherry-picking of merge\n> commits.)\n>\n> As a side-note, people rarely differentiate between\n> \"merge-the-operation\" and \"merge-the-result\" anyway, even when it leads\n> to confusion.\n>\n> Overall, if we take the above into account, it seems to be fine if\n> --diff-merges does affect the representation or such \"quasi-merge\"\n> commits, for the purposes of --evils option.\n\nYeah, that could make sense.  We'd still need some additional flag.\nOne flag, perhaps --diff-merges=remerge, would be the one that would\n_only_ affect actual two-parent merges (which I use as the default\ninstead of --cc with `git show`, and which I make implied by default\nwith `git log --patch` at $DAYJOB), and we'd need another name for\nwhatever turned those special diffs on for cherry-picks and reverts.\nFurther, the extra flag that turns on special diffs for cherry-picks\nand reverts should turn off diffs entirely for any other single-parent\ncommits.  (I think it's just too confusing for any command to show\nmultiple single-parent commits with a mixture of different types of\ndiffs.)\n"},{"id":"411565","messageId":"87360i6g8b.fsf@osv.gnss.ru","threadId":"54550","inReplyTo":"CABPp-BFWsdb3ECcvQjN7_v2krsKAqhqv3CDWvQ9d20Oy521Vag@mail.gmail.com","subject":"Re: [PATCH v1 00/27] git-log: implement new --diff-merge options","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-06T16:39:48Z","receivedAt":"2020-12-06T16:40:35Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Elijah Newren <newren@gmail.com> writes:\n\n> On Sat, Dec 5, 2020 at 11:44 AM Sergey Organov <sorganov@gmail.com> wrote:\n>>\n>> Elijah Newren <newren@gmail.com> writes:\n>>\n>> > On Fri, Dec 4, 2020 at 11:23 AM Sergey Organov <sorganov@gmail.com> wrote:\n>> >>\n>> >> Elijah Newren <newren@gmail.com> writes:\n>> >>\n>> >> > On Thu, Dec 3, 2020 at 11:48 AM Sergey Organov\n>> >> > <sorganov@gmail.com> wrote:\n>> >> >>\n>> >> >> Elijah Newren <newren@gmail.com> writes:\n>> >> >>\n>> >> >> > On Sun, Nov 8, 2020 at 1:43 PM Sergey Organov\n>> >> >> > <sorganov@gmail.com> wrote:\n>> >> >> >>\n>> >> >> >> These patch series implement new set of options governing the\n>> >> >> >> diff output\n>> >> >> >> of merge commits, all under the umbrella of the single\n>> >> >> >> --diff-merges=<mode>\n>> >> >> >> option. Most of the new options being synonyms for\n>> >> >> >> -m/-c/--cc options,\n>> >> >> >> there is also additional functionality provided, allowing to get\n>> >> >> >> the format\n>> >> >> >> of \"-p --first-parent\" without change in history traversal that\n>> >> >> >> --first-parent option causes.\n>> >> >> >>\n>> >> >> >> The net result of these series are the following new options:\n>> >> >> >>\n>> >> >> >> --diff-merges=   |  old equivalent\n>> >> >> >> -----------------+----------------\n>> >> >> >> first-parent     | --first-parent (only format implications)\n>> >> >> >> separate         | -m\n>> >> >> >> combined         | -c\n>> >> >> >> dense-combined   | --cc\n>> >> >> >\n>> >> >> > Interesting.  I have some local patches implementing another choice,\n>> >> >> > with the new flag --remerge-diff.  This flag will cause `git show` or\n>> >> >> > `git log` to automatically remerge the two parents in a\n>> >> >> > 2-parent merge\n>> >> >> > commit, and then diff the merge commit against that automatic merge,\n>> >> >> > showing the result. Thus, the diff for a merge commit is\n>> >> >> > likely to be\n>> >> >> > empty if the merge was clean, and is likely to show the removal of\n>> >> >> > conflict markers if the merge was not clean.\n>> >> >> >\n>> >> >> > I'm curious how it'd interact with this new option. Would it\n>> >> >> > also get\n>> >> >> > a name, e.g. --diff-merges=remerge-diff? Feels like a\n>> >> >> > mouthful, but I\n>> >> >> > can't come up with anything better.\n>> >> >>\n>> >> >> Maybe, --diff-merges=remerge?\n>> >> >>\n>> >> >> >\n>> >> >> > Also, I'm curious how it'd interact with another option I\n>> >> >> > added, named\n>> >> >> > --remerge-diff-only.  This latter option modifies revision traversal\n>> >> >> > in that it skips octopus merges, root commits, and single parent\n>> >> >> > commits IF no cherry-pick or revert information can be found.  If it\n>> >> >> > finds a 2-parent merge commit, it behaves like --remerge-diff.  If it\n>> >> >> > finds a 1-parent commit with cherry-pick or revert information, it'll\n>> >> >> > do an in memory repeat of that cherry-pick (or revert) and then diff\n>> >> >> > the actual commit against what the automatic cherry-pick would\n>> >> >> > perform.  Again, that likely means an empty diff if the automatic\n>> >> >> > cherry-pick was clean, and showing any changes made by the user to\n>> >> >> > complete the original cherry-pick (such as deleting conflict markers\n>> >> >> > and picking which chunks from which side to keep) if the automatic\n>> >> >> > cherry-pick was not clean.  (I suspect --remerge-diff-only is much\n>> >> >> > more likely to be used with `git show` than with `git log`.)  Anyway,\n>> >> >> > your changes seem to suggest that anything relating to how diffs for\n>> >> >> > merges are handled should be documented in the same section, but\n>> >> >> > --remerge-diff-only doesn't fit.  And it'd seem odd to have\n>> >> >> > --remerge-diff and --remerge-diff-only not show up in adjacently but\n>> >> >> > be split into separate sections.  Any ideas?\n>> >> >>\n>> >> >> Sounds like commits limiting option to me. I think it could be named by\n>> >> >> its limiting behavior only, say, --remerges. Then it will imply\n>> >> >> --diff-merges=remerge, that'd allow user to re-define diff\n>> >> >> format if she\n>> >> >> needs to.\n>> >> >\n>> >> > It is commit limiting, but the focus is more on the behavioral change\n>> >> > in how diffs are shown:\n>> >> >   * for 2-parent merges\n>> >> >   * for single-parent commits with cherry-pick or revert information\n>> >> > and acknowledging that since it has _altered_ the normal way of\n>> >> > showing diffs for a number of single-parent commits, that it'd be\n>> >> > confusing to show normal diffs of unaffected commits (how would you be\n>> >> > able to tell what type of diff you're looking at if both appear in the\n>> >> > log?).  Thus, it does commit limiting to only select commits which\n>> >> > will make use of the new diff type.\n>> >>\n>> >> That's how you currently look at it.\n>> >>\n>> >> For me it looks like pure commit limiting with these criteria might be\n>> >> useful by itself, and with my suggestion one could then achieve it\n>> >> using, say:\n>> >>\n>> >> --remerge-diff-only --diff-merges=off\n>> >\n>> > I see what you're saying, and I think there's some value in it.  But I\n>> > think there's something still missing.  For example, you suggest\n>> > getting the commit limiting I mention with\n>> >\n>> >     --remerge-diff-only --diff-merges=off\n>> >\n>> > But --diff-merges is only supposed to control _merge_ commits, which I\n>> > flagged as the big impedance mismatch for my new option.  Why would it\n>> > turn off diffs for non-merge commits like cherry-picks and rebases?\n>> >\n>> >> >\n>> >> > (I suspect it will be more common for folks to use the\n>> >> > --remerge-diff-only option, or whatever we end up calling it, with\n>> >> > `git show` where the commit limiting doesn't matter -- but I have used\n>> >> > it with log to go looking for \"evil\" reverts/cherry-picks that might\n>> >> > have occurred in history.)\n>> >>\n>> >> What you describe is complex enough to doubt it could be entirely\n>> >> described by option name, so shorter --evils might be better choice\n>> >> in this case.\n>> >>\n>> >> Overall, if you add --diff-merges=remerge as a new diff format, and then\n>> >> --evils that implies the former, then it seems like all possible\n>> >> use-cases will be covered, and you have short option name for the most\n>> >> useful case.\n>> >\n>> > Since you want things to have orthogonal subcomponents that can be\n>> > built up, let's assume we did make --remerge-diff-only be solely about\n>> > commit limiting.  In that case, --evils could be gotten by specifying\n>> > a combination of flags, and --evils would just be a shorthand.  What\n>> > are the flags that you would need to specify, though?  In particular,\n>> > you've only named two options above and they don't cover the necessary\n>> > behavior; a third is needed:\n>> >\n>> >    --remerge-diff-only --diff-merges=remerge\n>> > --${DIFF_OPTION_NAME_FOR_CHERRY_PICKS_AND_REVERTS}=remerge\n>> >\n>> > The first two aren't enough because --diff_merges only changes how\n>> > diffs for _merge_ commits are shown, and we need a flag for changing\n>> > how the single-parent cherry-pick and reverts are shown.\n>>\n>> Yeah, I see your point. I didn't get it from the beginning that you want\n>> yet another representation format for regular commits as well. However,\n>> as far as I can tell, if --evils flag is active, you do consider\n>> cherry-picks and reverts as kind of merges, that makes sense as they\n>> actually /are/ expected to be results of specific /merge operation/,\n>> even though they are not /merge commits/, so semantically they do have\n>> second parent reference (to the original commit), even if a virtual one.\n>>\n>> To further illustrate my point, reverts and cherry-picks could have been\n>> implemented, for example, as merge commits with, say, 3-rd parent\n>> pointing back to the original commit (not 2-nd parent, both to\n>> differentiate from regular merges and to support cherry-picking of merge\n>> commits.)\n>>\n>> As a side-note, people rarely differentiate between\n>> \"merge-the-operation\" and \"merge-the-result\" anyway, even when it leads\n>> to confusion.\n>>\n>> Overall, if we take the above into account, it seems to be fine if\n>> --diff-merges does affect the representation or such \"quasi-merge\"\n>> commits, for the purposes of --evils option.\n>\n> Yeah, that could make sense.  We'd still need some additional flag.\n> One flag, perhaps --diff-merges=remerge, would be the one that would\n> _only_ affect actual two-parent merges (which I use as the default\n> instead of --cc with `git show`, and which I make implied by default\n> with `git log --patch` at $DAYJOB), and we'd need another name for\n> whatever turned those special diffs on for cherry-picks and reverts.\n> Further, the extra flag that turns on special diffs for cherry-picks\n> and reverts should turn off diffs entirely for any other single-parent\n> commits.  (I think it's just too confusing for any command to show\n> multiple single-parent commits with a mixture of different types of\n> diffs.)\n\nI think you may safely pretend this special diff always produces empty\ndiff for regular commits, so there will be no need to \"disable\"\nanything.\n\n-- Sergey Organov\n\n\n"},{"id":"411731","messageId":"87y2i8dptj.fsf@osv.gnss.ru","threadId":"54550","inReplyTo":"20201101193330.24775-1-sorganov@gmail.com","subject":"Re: [PATCH 00/26] git-log: implement new --diff-merge options","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-08T20:07:36Z","receivedAt":"2020-12-08T20:20:49Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Sergey Organov <sorganov@gmail.com> writes:\n\n\n[...]\n\n> The series also cleanup logic of handling of diff merges options and\n> fix an issue found in the original implementation where logically\n> mutually exclusive options -m/-c/--cc failed to actually override each\n> other.\n\nWorking further on this, I've noticed very irregular interactions\nbetween -m/-c/--cc and --oneline:\n\n1. --oneline disables -m output for 'git log', and leaves -m output enabled\nfor 'git show':\n\n$ /usr/bin/git show -n1 -m --oneline 2e673356aef | wc -l\n80\n$ /usr/bin/git log -n1 -m --oneline 2e673356aef | wc -l\n1\n\n2. For 'git log', --oneline disables -m output, and leaves -c/--cc output\nenabled:\n\n$ /usr/bin/git log -n1 -m --oneline 2e673356aef | wc -l\n1\n$ /usr/bin/git log -n1 -c --oneline 2e673356aef | wc -l\n16\n$ /usr/bin/git log -n1 --cc --oneline 2e673356aef | wc -l\n16\n\nThe question is: what's the right interaction between --oneline and\n-m/-c/--cc?\n\nI tend to think they should be independent, so that --oneline doesn't\naffect diff output, and then the only offender is -m.\n\nWhat do you think?\n\n$ /usr/bin/git --version\ngit version 2.25.1\n\nThanks,\n-- Sergey Organov\n"},{"id":"411739","messageId":"CABPp-BGuLX8Msghbo6L7vB2Wqys=Xg_uvV2Aui-1q4-+ijuNEw@mail.gmail.com","threadId":"54550","inReplyTo":"87y2i8dptj.fsf@osv.gnss.ru","subject":"Re: [PATCH 00/26] git-log: implement new --diff-merge options","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2020-12-08T20:52:52Z","receivedAt":"2020-12-08T20:54:01Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"Hi Sergey,\n\nOn Tue, Dec 8, 2020 at 12:07 PM Sergey Organov <sorganov@gmail.com> wrote:\n>\n> Sergey Organov <sorganov@gmail.com> writes:\n>\n>\n> [...]\n>\n> > The series also cleanup logic of handling of diff merges options and\n> > fix an issue found in the original implementation where logically\n> > mutually exclusive options -m/-c/--cc failed to actually override each\n> > other.\n>\n> Working further on this, I've noticed very irregular interactions\n> between -m/-c/--cc and --oneline:\n>\n> 1. --oneline disables -m output for 'git log', and leaves -m output enabled\n> for 'git show':\n>\n> $ /usr/bin/git show -n1 -m --oneline 2e673356aef | wc -l\n> 80\n> $ /usr/bin/git log -n1 -m --oneline 2e673356aef | wc -l\n> 1\n\nIf you leave off --oneline, you'll note that git show produces a diff\nand git log does not (regardless of whether 2e673356aef is a merge\ncommit or a regular commit).  So, I don't think this is related to\n--oneline.\n\n> 2. For 'git log', --oneline disables -m output, and leaves -c/--cc output\n> enabled:\n>\n> $ /usr/bin/git log -n1 -m --oneline 2e673356aef | wc -l\n> 1\n> $ /usr/bin/git log -n1 -c --oneline 2e673356aef | wc -l\n> 16\n> $ /usr/bin/git log -n1 --cc --oneline 2e673356aef | wc -l\n> 16\n>\n> The question is: what's the right interaction between --oneline and\n> -m/-c/--cc?\n\nI believe the right question is: Should -m be a no-op unless -p is\nalso specified?  In the past, --cc and -c were no-ops except when -p\nwas also specified.  It was somewhat unfriendly and surprising, and\nthus was changed so that --cc and -c implied -p (and thus would cause\noutput for non-merge commits to be shown differently, namely shown\nwith a diff, in addition to affecting the type of diff shown for merge\ncommits).  I think -m was overlooked at the time.\n\n> I tend to think they should be independent, so that --oneline doesn't\n> affect diff output, and then the only offender is -m.\n\nI agree that they should be independent, but I believe they are\nalready independent unless you have more evidence of weirdness\nsomewhere.  The differences you are seeing are due to -m, -c, and --cc\nbeing handled differently, and I think we should probably just give -m\nthe same treatment that we give to -c and --cc (namely, make all three\nimply -p).\n\nHope that helps,\nElijah\n"},{"id":"411788","messageId":"87y2i8c4mr.fsf@osv.gnss.ru","threadId":"54550","inReplyTo":"CABPp-BGuLX8Msghbo6L7vB2Wqys=Xg_uvV2Aui-1q4-+ijuNEw@mail.gmail.com","subject":"Re: [PATCH 00/26] git-log: implement new --diff-merge options","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-08T22:30:36Z","receivedAt":"2020-12-08T22:31:55Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Elijah Newren <newren@gmail.com> writes:\n\n> Hi Sergey,\n\nHi Elijah,\n\n>\n> On Tue, Dec 8, 2020 at 12:07 PM Sergey Organov <sorganov@gmail.com> wrote:\n>>\n>> Sergey Organov <sorganov@gmail.com> writes:\n>>\n>>\n>> [...]\n>>\n>> > The series also cleanup logic of handling of diff merges options and\n>> > fix an issue found in the original implementation where logically\n>> > mutually exclusive options -m/-c/--cc failed to actually override each\n>> > other.\n>>\n>> Working further on this, I've noticed very irregular interactions\n>> between -m/-c/--cc and --oneline:\n>>\n>> 1. --oneline disables -m output for 'git log', and leaves -m output enabled\n>> for 'git show':\n>>\n>> $ /usr/bin/git show -n1 -m --oneline 2e673356aef | wc -l\n>> 80\n>> $ /usr/bin/git log -n1 -m --oneline 2e673356aef | wc -l\n>> 1\n>\n> If you leave off --oneline, you'll note that git show produces a diff\n> and git log does not (regardless of whether 2e673356aef is a merge\n> commit or a regular commit).  So, I don't think this is related to\n> --oneline.\n\nYeah, looks exactly like this, thanks for correcting!\n\n>\n>> 2. For 'git log', --oneline disables -m output, and leaves -c/--cc output\n>> enabled:\n>>\n>> $ /usr/bin/git log -n1 -m --oneline 2e673356aef | wc -l\n>> 1\n>> $ /usr/bin/git log -n1 -c --oneline 2e673356aef | wc -l\n>> 16\n>> $ /usr/bin/git log -n1 --cc --oneline 2e673356aef | wc -l\n>> 16\n>>\n>> The question is: what's the right interaction between --oneline and\n>> -m/-c/--cc?\n>\n> I believe the right question is: Should -m be a no-op unless -p is\n> also specified?\n\nRight.\n\n> In the past, --cc and -c were no-ops except when -p\n> was also specified.  It was somewhat unfriendly and surprising, and\n> thus was changed so that --cc and -c implied -p (and thus would cause\n> output for non-merge commits to be shown differently, namely shown\n> with a diff, in addition to affecting the type of diff shown for merge\n> commits).\n\nWell, so one surprise has been replaced with another, supposedly more\nfriendly, right?\n\nI mean, obviously, with --cc I don't ask for diffs for non-merge\ncommits, so it is still a surprise they are thrown at me.\n\n> I think -m was overlooked at the time.\n\nLooks like it was, but maybe there was rather an actual reason for not\nimplying -p by -m? Maybe Junio will tell?\n\n>\n>> I tend to think they should be independent, so that --oneline doesn't\n>> affect diff output, and then the only offender is -m.\n>\n> I agree that they should be independent, but I believe they are\n> already independent unless you have more evidence of weirdness\n> somewhere.  The differences you are seeing are due to -m, -c, and --cc\n> being handled differently, and I think we should probably just give -m\n> the same treatment that we give to -c and --cc (namely, make all three\n> imply -p).\n\nI think that either all diff-merge options should imply -p, or none,\nfrom the POV of least surprise.\n\nHowever, it'd give us yet another challenge: for some time already,\n--first-parent implies -m, that once it starts to imply -p, will result in\n\n  git log --first-parent\n\nsuddenly producing diff output for everything.\n\nOne way out I see is to specify that implied -m/-c/--cc don't imply\n-p, only explicit do.\n\nEntirely different approach is to get rid of -m/-c/--cc implying -p, and\njust produce diff output for merges independently on -p being provided\nor not. This will give us additional functionality (ability to get diff\nfor merges, but not for regulars), and will get rid of all the related\nsurprises.\n\nThoughts?\n\nThanks,\n-- Sergey Organov\n"},{"id":"411796","messageId":"CABPp-BE3D7ifQx6MZCT_ntRnG0QZm1Ga10SJ=DN+6bpF6mX2GQ@mail.gmail.com","threadId":"54550","inReplyTo":"87y2i8c4mr.fsf@osv.gnss.ru","subject":"Re: [PATCH 00/26] git-log: implement new --diff-merge options","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2020-12-08T23:11:36Z","receivedAt":"2020-12-08T23:12:43Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Tue, Dec 8, 2020 at 2:30 PM Sergey Organov <sorganov@gmail.com> wrote:\n>\n> Elijah Newren <newren@gmail.com> writes:\n>\n> > Hi Sergey,\n>\n> Hi Elijah,\n>\n> >\n> > On Tue, Dec 8, 2020 at 12:07 PM Sergey Organov <sorganov@gmail.com> wrote:\n> >>\n> >> Sergey Organov <sorganov@gmail.com> writes:\n> >>\n> >>\n> >> [...]\n> >>\n> >> > The series also cleanup logic of handling of diff merges options and\n> >> > fix an issue found in the original implementation where logically\n> >> > mutually exclusive options -m/-c/--cc failed to actually override each\n> >> > other.\n> >>\n> >> Working further on this, I've noticed very irregular interactions\n> >> between -m/-c/--cc and --oneline:\n> >>\n> >> 1. --oneline disables -m output for 'git log', and leaves -m output enabled\n> >> for 'git show':\n> >>\n> >> $ /usr/bin/git show -n1 -m --oneline 2e673356aef | wc -l\n> >> 80\n> >> $ /usr/bin/git log -n1 -m --oneline 2e673356aef | wc -l\n> >> 1\n> >\n> > If you leave off --oneline, you'll note that git show produces a diff\n> > and git log does not (regardless of whether 2e673356aef is a merge\n> > commit or a regular commit).  So, I don't think this is related to\n> > --oneline.\n>\n> Yeah, looks exactly like this, thanks for correcting!\n>\n> >\n> >> 2. For 'git log', --oneline disables -m output, and leaves -c/--cc output\n> >> enabled:\n> >>\n> >> $ /usr/bin/git log -n1 -m --oneline 2e673356aef | wc -l\n> >> 1\n> >> $ /usr/bin/git log -n1 -c --oneline 2e673356aef | wc -l\n> >> 16\n> >> $ /usr/bin/git log -n1 --cc --oneline 2e673356aef | wc -l\n> >> 16\n> >>\n> >> The question is: what's the right interaction between --oneline and\n> >> -m/-c/--cc?\n> >\n> > I believe the right question is: Should -m be a no-op unless -p is\n> > also specified?\n>\n> Right.\n>\n> > In the past, --cc and -c were no-ops except when -p\n> > was also specified.  It was somewhat unfriendly and surprising, and\n> > thus was changed so that --cc and -c implied -p (and thus would cause\n> > output for non-merge commits to be shown differently, namely shown\n> > with a diff, in addition to affecting the type of diff shown for merge\n> > commits).\n>\n> Well, so one surprise has been replaced with another, supposedly more\n> friendly, right?\n>\n> I mean, obviously, with --cc I don't ask for diffs for non-merge\n> commits, so it is still a surprise they are thrown at me.\n\nActually, that wasn't a side-effect but part of the intended change --\nsee https://lore.kernel.org/git/1440110591-12941-1-git-send-email-gitster@pobox.com/.\n\n> > I think -m was overlooked at the time.\n>\n> Looks like it was, but maybe there was rather an actual reason for not\n> implying -p by -m? Maybe Junio will tell?\n>\n> >\n> >> I tend to think they should be independent, so that --oneline doesn't\n> >> affect diff output, and then the only offender is -m.\n> >\n> > I agree that they should be independent, but I believe they are\n> > already independent unless you have more evidence of weirdness\n> > somewhere.  The differences you are seeing are due to -m, -c, and --cc\n> > being handled differently, and I think we should probably just give -m\n> > the same treatment that we give to -c and --cc (namely, make all three\n> > imply -p).\n>\n> I think that either all diff-merge options should imply -p, or none,\n> from the POV of least surprise.\n>\n> However, it'd give us yet another challenge: for some time already,\n> --first-parent implies -m, that once it starts to imply -p, will result in\n>\n>   git log --first-parent\n>\n> suddenly producing diff output for everything.\n\nThat is definitely a pickle.\n\n> One way out I see is to specify that implied -m/-c/--cc don't imply\n> -p, only explicit do.\n>\n> Entirely different approach is to get rid of -m/-c/--cc implying -p, and\n> just produce diff output for merges independently on -p being provided\n> or not. This will give us additional functionality (ability to get diff\n> for merges, but not for regulars), and will get rid of all the related\n> surprises.\n>\n> Thoughts?\n\nI was happy when I found out that --cc had changed to imply -p; I\nguess I felt the same as Junio did with his rationale in the link I\nposted above.  I've made --remerge-diff behave like --cc (i.e. it\nimplies -p), and I like it there too.  I use it both to turn on diffs\nfor merges, and to turn on diffs for regular commits without having to\nspecify the extra -p flag.  I guess I'm not sure why one would ever\nwant to see diffs for merges and not for normal commits.  Even in the\nunusual case someone did, couldn't they just pass --merges (to strip\nout the normal commits entirely)?\n\nI may not have the best vantage point on this, though, because I\npersonally don't see enough utility in diffing a merge to just one of\nits parents that it'd merit having an option to git-log, and yet we\nclearly have two such options already (-m and --first-parent when\ncombined with -p).\n\nBut, there is at least one more way to get out of this pickle besides\nthe two options you listed above: we could make --first-parent be just\nabout commit limiting and not imply anything about diff behavior.\nHonestly, I find it a little surprising that despite the fact that log\n-p shows nothing for merge commits, that when I add --first-parent to\nsee a subset of commits I suddenly get weird, huge diffs shown for the\nmerges (yeah, yeah, I learned recently that it's documented behavior,\nso it's not surprising anymore, just weird).  So, this wouldn't just\nget rid of this new nasty pickle, but would remove another negative\nsurprise too.  If we're going to make a behavioral change, I'd rather\nwe fixed this side rather than the (IMO) nicely working --cc/-c side.\n\n\nHope that helps,\nElijah\n"},{"id":"411801","messageId":"xmqqtusv4w2g.fsf@gitster.c.googlers.com","threadId":"54550","inReplyTo":"CABPp-BE3D7ifQx6MZCT_ntRnG0QZm1Ga10SJ=DN+6bpF6mX2GQ@mail.gmail.com","subject":"Re: [PATCH 00/26] git-log: implement new --diff-merge options","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2020-12-09T01:17:27Z","receivedAt":"2020-12-09T01:18:12Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Elijah Newren <newren@gmail.com> writes:\n\n> ... I guess I'm not sure why one would ever\n> want to see diffs for merges and not for normal commits.  Even in the\n> unusual case someone did, couldn't they just pass --merges (to strip\n> out the normal commits entirely)?\n\nGiving \"--merges\" would skip the single-strand-of-pearls commits\nentirely, not even showing their log messages, so it won't be an\nequivalent substitute.\n\n> Honestly, I find it a little surprising that despite the fact that log\n> -p shows nothing for merge commits, that when I add --first-parent to\n> see a subset of commits I suddenly get weird, huge diffs shown for the\n> merges (yeah, yeah, I learned recently that it's documented behavior,\n> so it's not surprising anymore, just weird).\n\nI view \"--first-parent\" as telling \"git log\" to pretend all merges\nare single-parent commits (as if you did squash merges), and it is a\nnatural consequence if \"log --first-parent -p\" showed each commit\nwith its first parent, whether it is a merge or a single-parent\ncommit.\n"},{"id":"411809","messageId":"CABPp-BHCtrKAWR1v3OrUgX8iSfxvDwN8p+yiJy=G1BFfnSopjw@mail.gmail.com","threadId":"54550","inReplyTo":"xmqqtusv4w2g.fsf@gitster.c.googlers.com","subject":"Re: [PATCH 00/26] git-log: implement new --diff-merge options","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2020-12-09T03:06:43Z","receivedAt":"2020-12-09T03:07:48Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"Hi Junio,\n\nOn Tue, Dec 8, 2020 at 5:17 PM Junio C Hamano <gitster@pobox.com> wrote:\n>\n> Elijah Newren <newren@gmail.com> writes:\n>\n> > ... I guess I'm not sure why one would ever\n> > want to see diffs for merges and not for normal commits.  Even in the\n> > unusual case someone did, couldn't they just pass --merges (to strip\n> > out the normal commits entirely)?\n>\n> Giving \"--merges\" would skip the single-strand-of-pearls commits\n> entirely, not even showing their log messages, so it won't be an\n> equivalent substitute.\n\nRight, I said that too in my parenthetical comment; --merges would\nstrip out the normal commits entirely.  As I said, I'm not sure why\nanyone would ever want to see diffs for merges and not for normal\ncommits, the closest useful thing I can imagine is commit messages +\ndiffs for just merges, stripping the normal commits.  Is there a\nusecase here (other than the motivating example of trying to remove an\ninconsistency between -m and --cc output)?\n\nI'd personally dislike needing to specify --cc and -p together when\ntoday I can specify just --cc.  You said as much too at [1].  Have you\nsince changed your mind?\n\n[1] https://lore.kernel.org/git/1440110591-12941-1-git-send-email-gitster@pobox.com/\n\n> > Honestly, I find it a little surprising that despite the fact that log\n> > -p shows nothing for merge commits, that when I add --first-parent to\n> > see a subset of commits I suddenly get weird, huge diffs shown for the\n> > merges (yeah, yeah, I learned recently that it's documented behavior,\n> > so it's not surprising anymore, just weird).\n>\n> I view \"--first-parent\" as telling \"git log\" to pretend all merges\n> are single-parent commits (as if you did squash merges), and it is a\n> natural consequence if \"log --first-parent -p\" showed each commit\n> with its first parent, whether it is a merge or a single-parent\n> commit.\n\nAlright, fair enough.  I had always viewed it as commit limiting only\n(and thus why it looked weird to me), but I really don't use\n--first-parent or -m much.\n\nBut that leaves Sergey's question unanswered: should the inconsistency\nbetween --cc and -m (namely that only the former implies -p) be\nremoved?  If so, since --first-parent implies -m, what's the right way\nto avoid --first-parent becoming weird?  (Allow explicit -m to imply\n-p, but not an implicit -m that came from --first-parent?)\n"},{"id":"411811","messageId":"xmqq7dpr4qa0.fsf@gitster.c.googlers.com","threadId":"54550","inReplyTo":"CABPp-BHCtrKAWR1v3OrUgX8iSfxvDwN8p+yiJy=G1BFfnSopjw@mail.gmail.com","subject":"Re: [PATCH 00/26] git-log: implement new --diff-merge options","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2020-12-09T03:22:31Z","receivedAt":"2020-12-09T03:23:20Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Elijah Newren <newren@gmail.com> writes:\n\n> ...  As I said, I'm not sure why\n> anyone would ever want to see diffs for merges and not for normal\n> commits, the closest useful thing I can imagine is commit messages +\n> diffs for just merges, stripping the normal commits.\n\nIf I can run \"git log --some-options master..next\" (or more\nrealistically, over the range ko/next..next) to get individual\ncommits (without patch) and merges (only when --cc gives some\ninteresting nearby-changes), I would be very happy.  But is there a\nset of options that lets me do so?\n\n"},{"id":"411812","messageId":"CABPp-BHWhiUZ=wCSz1f0oxtHiRzAKCPVmoUYDf+mvvm63ykCEw@mail.gmail.com","threadId":"54550","inReplyTo":"xmqq7dpr4qa0.fsf@gitster.c.googlers.com","subject":"Re: [PATCH 00/26] git-log: implement new --diff-merge options","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2020-12-09T03:31:04Z","receivedAt":"2020-12-09T03:32:03Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Tue, Dec 8, 2020 at 7:22 PM Junio C Hamano <gitster@pobox.com> wrote:\n>\n> Elijah Newren <newren@gmail.com> writes:\n>\n> > ...  As I said, I'm not sure why\n> > anyone would ever want to see diffs for merges and not for normal\n> > commits, the closest useful thing I can imagine is commit messages +\n> > diffs for just merges, stripping the normal commits.\n>\n> If I can run \"git log --some-options master..next\" (or more\n> realistically, over the range ko/next..next) to get individual\n> commits (without patch) and merges (only when --cc gives some\n> interesting nearby-changes), I would be very happy.  But is there a\n> set of options that lets me do so?\n\nSo, you're saying you changed your mind since five years ago?[1]  Or\nthat what you said five years ago is still valid, but you'd appreciate\nmore/different options that allow this new thing?\n\n[1] https://lore.kernel.org/git/1440110591-12941-1-git-send-email-gitster@pobox.com/\n\nWe got to this point in this thread because Sergey suggested reverting\nthe above change (as one option) in order to bring more consistency\nbetween -m and -c/--cc.\n"},{"id":"411813","messageId":"xmqq360f4npg.fsf@gitster.c.googlers.com","threadId":"54550","inReplyTo":"CABPp-BHWhiUZ=wCSz1f0oxtHiRzAKCPVmoUYDf+mvvm63ykCEw@mail.gmail.com","subject":"Re: [PATCH 00/26] git-log: implement new --diff-merge options","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2020-12-09T04:18:03Z","receivedAt":"2020-12-09T04:19:02Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Elijah Newren <newren@gmail.com> writes:\n\n>> If I can run \"git log --some-options master..next\" (or more\n>> realistically, over the range ko/next..next) to get individual\n>> commits (without patch) and merges (only when --cc gives some\n>> interesting nearby-changes), I would be very happy.  But is there a\n>> set of options that lets me do so?\n>\n> So, you're saying you changed your mind since five years ago?[1]  Or\n> that what you said five years ago is still valid, but you'd appreciate\n> more/different options that allow this new thing?\n>\n> [1] https://lore.kernel.org/git/1440110591-12941-1-git-send-email-gitster@pobox.com/\n\nSorry, but I am not seeing in [1] anything that relates to the above\n\"want to see --cc patch for merge but just log message for single\nparent commit\". 5 years is a long time even in Git timescale, so I\nwould not be surprised if I changed my mind over time, but I am not\nsure what opinion on the matter you think I expressed back then.\n\n\"git log --cc master..next\" shows all commits' log messages, patch\nfor each single-parent commit, and combined-dense patch for each\nmerge.  There is no option to squelch the patch for only single\nparent commits.  It may not be such a bad thing to have as an extra\noption.\n\nSo, I think what I am saying is that ...\n\n> > ...  As I said, I'm not sure why\n> > anyone would ever want to see diffs for merges and not for normal\n> > commits, the closest useful thing I can imagine is commit messages +\n> > diffs for just merges, stripping the normal commits.\n\n... I see use for such a feature (assuming that you didn't mean by\n\"diffs for merges\" a regular \"--first-parent -p\" patch, but meant to\nsay \"--cc\" patch) in my workflow.  I'd review \"log ko/next..next\"\nbefore deciding to push out the day's integration of 'next', and at\nthat point, I trust individual commits that came from contributors\nwell enough (otherwise I wouldn't be merging them to 'next'), but I\nwould appreciate the last chance to re-examine conflict resolutions\nin merges.\n\nIt does not mean that I do not like the current behaviour that\n\"--cc\" always implies \"-p\"; it is convenient.  It's just I find the\nlack of feature slightly less than ideal, but I do not care deeply\nenough to design how to express such a feature from the command\nline.\n"},{"id":"411815","messageId":"CABPp-BEAmB9DA7RXrf6vJGbHfGU37V4sE0d1CW+2vRwp_uAudw@mail.gmail.com","threadId":"54550","inReplyTo":"xmqq360f4npg.fsf@gitster.c.googlers.com","subject":"Re: [PATCH 00/26] git-log: implement new --diff-merge options","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2020-12-09T04:54:31Z","receivedAt":"2020-12-09T04:55:24Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Tue, Dec 8, 2020 at 8:18 PM Junio C Hamano <gitster@pobox.com> wrote:\n>\n> Elijah Newren <newren@gmail.com> writes:\n>\n> >> If I can run \"git log --some-options master..next\" (or more\n> >> realistically, over the range ko/next..next) to get individual\n> >> commits (without patch) and merges (only when --cc gives some\n> >> interesting nearby-changes), I would be very happy.  But is there a\n> >> set of options that lets me do so?\n> >\n> > So, you're saying you changed your mind since five years ago?[1]  Or\n> > that what you said five years ago is still valid, but you'd appreciate\n> > more/different options that allow this new thing?\n> >\n> > [1] https://lore.kernel.org/git/1440110591-12941-1-git-send-email-gitster@pobox.com/\n>\n> Sorry, but I am not seeing in [1] anything that relates to the above\n> \"want to see --cc patch for merge but just log message for single\n> parent commit\". 5 years is a long time even in Git timescale, so I\n> would not be surprised if I changed my mind over time, but I am not\n> sure what opinion on the matter you think I expressed back then.\n>\n> \"git log --cc master..next\" shows all commits' log messages, patch\n> for each single-parent commit, and combined-dense patch for each\n> merge.  There is no option to squelch the patch for only single\n> parent commits.  It may not be such a bad thing to have as an extra\n> option.\n>\n> So, I think what I am saying is that ...\n>\n> > > ...  As I said, I'm not sure why\n> > > anyone would ever want to see diffs for merges and not for normal\n> > > commits, the closest useful thing I can imagine is commit messages +\n> > > diffs for just merges, stripping the normal commits.\n>\n> ... I see use for such a feature (assuming that you didn't mean by\n> \"diffs for merges\" a regular \"--first-parent -p\" patch, but meant to\n> say \"--cc\" patch) in my workflow.  I'd review \"log ko/next..next\"\n> before deciding to push out the day's integration of 'next', and at\n> that point, I trust individual commits that came from contributors\n> well enough (otherwise I wouldn't be merging them to 'next'), but I\n> would appreciate the last chance to re-examine conflict resolutions\n> in merges.\n>\n> It does not mean that I do not like the current behaviour that\n> \"--cc\" always implies \"-p\"; it is convenient.  It's just I find the\n> lack of feature slightly less than ideal, but I do not care deeply\n> enough to design how to express such a feature from the command\n> line.\n\nOkay, thanks for clarifying.  It sounds like you were focusing on the\ntangentially related comment I made (diffs for merges and not for\nnormal commits) while I was focusing on Sergey's question (should we\nrevert --cc implies -p).  I was having a hard time understanding if\nyou were answering his question or not.  This last paragraph of yours\nacknowledges the question, though you still avoid answering it.  :-)\n\nHowever, even my focus was on a secondary question.  His real original\nquestion is: -m and --cc are inconsistent -- one requires -p, while\nthe other doesn't.  Should that be fixed...and which option(s) should\nchange?  He gave two possibilities I didn't like.  I added a third\nthat you didn't like.  So...\n"},{"id":"411816","messageId":"xmqqtusv362t.fsf@gitster.c.googlers.com","threadId":"54550","inReplyTo":"CABPp-BEAmB9DA7RXrf6vJGbHfGU37V4sE0d1CW+2vRwp_uAudw@mail.gmail.com","subject":"Re: [PATCH 00/26] git-log: implement new --diff-merge options","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2020-12-09T05:24:10Z","receivedAt":"2020-12-09T05:24:59Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Elijah Newren <newren@gmail.com> writes:\n\n>> It does not mean that I do not like the current behaviour that\n>> \"--cc\" always implies \"-p\"; it is convenient.  It's just I find the\n>> lack of feature slightly less than ideal, but I do not care deeply\n>> enough to design how to express such a feature from the command\n>> line.\n>\n> Okay, thanks for clarifying.  It sounds like you were focusing on the\n> tangentially related comment I made (diffs for merges and not for\n> normal commits) while I was focusing on Sergey's question (should we\n> revert --cc implies -p).  I was having a hard time understanding if\n> you were answering his question or not.  This last paragraph of yours\n> acknowledges the question, though you still avoid answering it.  :-)\n\nI do like the current behaviour that \"--cc\" always implies \"-p\"; it\nis convenient.  I just wish there were a way to say \"enable -p only\nfor merges\" while taking advantage of the convenience.\n\nSo, no we should not stop \"--cc\" or \"-c\" implying \"-p\".\n\nWhen the end-user gives \"-m\" on the command line of either \"show\" or\n\"log\", it cleanly means the user is interested in \"individual\"\npatches shown for each parent when showing a merge commit, so \"-p\"\nimplied by \"-m\" would make sense just as much as \"-p\" implied by\n\"--cc\".  The same comment about the lack of \"want -p to be implied\nbut only for merges\" as an add-on feature applies here, though.\n\nI suspect that the real reason why \"-m\" does not imply \"-p\" was\nmerely a historical implementation detail (e.g. imagine that we\nwanted *not* to show things by default in a subcommand in \"log\"\nfamily, but when \"-p\" is used, wanted it to mean \"-m -p\", or\nsomething like that.  Setting \"-m\" on by default without explicitly\ngiven from the command line, and making sure that m-bit does not\nimply \"-p\", would be an easy-to-implement such a \"when '-p' is\ngiven, take it to mean as '-m -p'\" _feature_).\n\nIf I were to decide now with hindsight, perhaps I'd make \"--cc\" and\n\"-m\" imply \"-p\" only for merge commits, and the user can explicitly\ngive \"--cc -p\" and \"-m -p\" to ask patches for single-parent commits\nto be shown as well.\n\n"},{"id":"411820","messageId":"xmqqpn3j32ka.fsf@gitster.c.googlers.com","threadId":"54550","inReplyTo":"xmqqtusv362t.fsf@gitster.c.googlers.com","subject":"Re: [PATCH 00/26] git-log: implement new --diff-merge options","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2020-12-09T06:40:05Z","receivedAt":"2020-12-09T06:41:23Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\nA clarification and a correction.\n\n> I suspect that the real reason why \"-m\" does not imply \"-p\" was\n> merely a historical implementation detail...\n\nNow I remember better.  The reason was pure oversight.\n\nIn the beginning, there was no patch output for merges.  As most\nmerges just resolve cleanly, and back then the first-parent chains\nwere treated as much much less special than we treat them today,\n\"git log -p\" showed only patches for single-parent commits and\neverybody was happy.  It could have been a possible alternative\ndesign to show first-parent diff for a merge instead of showing no\npatch, but because the traversal went to side branches, the changes\nmade by the merge to the mainline as a single big patch would have\nbeen redundant---we would be seeing individual patches from the side\nbranch anyway.\n\nThen later we introduced \"-m -p\"; since the first-parent chain was\nnot considered all that special, we treated each parent equally.\nNobody, not even Linus and I, thought it was useful by itself even\nback then, but we didn't have anything better.\n\nI think it was Paul Mackerras's \"gitk\" that invented the concept of\ncombined merges.  We liked it quite a lot, and added \"-c\" and \"--cc\"\nsoon after that, to the core git and kept polishing, until \"gitk\"\nstopped combining the patches with each parent in tcl/tk script and\ninstead started telling \"git\" to show with \"--cc\".\n\nBy the time the change to make \"--cc\" imply \"-p\" was introduced, it\nwas pretty much given that \"-m -p\" was useful to anybody, unless you\nare consuming these individual patches in a script or something like\nthat.  So simply I didn't even think of making \"-m\" imply \"-p\".  It\nwould be logical to make it so, but it would not add much practical\nvalue, I would have to say.\n\n> If I were to decide now with hindsight, perhaps I'd make \"--cc\" and\n> \"-m\" imply \"-p\" only for merge commits, and the user can explicitly\n> give \"--cc -p\" and \"-m -p\" to ask patches for single-parent commits\n> to be shown as well.\n\nAfter \"now with hindsight\", I need to add \"and without having to\nworry about backward compatibility issues\" here.  IOW, the above is\nnot my recommendation.  It would be the other way around: \"--cc\"\nimplies \"-p\" for both merges and non-merges, \"-m\" implies \"-p\" for\nboth merges and non-merges.  It is acceptable to add a new option\n\"--no-patch-for-non-merge\" so that the user can ask to see only the\ncombined diff for merges and no patches for individual commits.\n\nBoth \"--no-patch-for-non-merge\" option, and making \"-m\" imply \"-p\"\nare very low priority from my point of view, though, since our users\n(including me) lived without the former and have been happily using\n\"log --cc\" for a long time, and we've written off the latter as\npretty much useless combination unless you are a script.\n"},{"id":"411848","messageId":"87360fgl22.fsf@osv.gnss.ru","threadId":"54550","inReplyTo":"CABPp-BEAmB9DA7RXrf6vJGbHfGU37V4sE0d1CW+2vRwp_uAudw@mail.gmail.com","subject":"Re: [PATCH 00/26] git-log: implement new --diff-merge options","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-09T13:34:29Z","receivedAt":"2020-12-09T13:35:49Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Elijah Newren <newren@gmail.com> writes:\n\n> On Tue, Dec 8, 2020 at 8:18 PM Junio C Hamano <gitster@pobox.com> wrote:\n>>\n>> Elijah Newren <newren@gmail.com> writes:\n>>\n>> >> If I can run \"git log --some-options master..next\" (or more\n>> >> realistically, over the range ko/next..next) to get individual\n>> >> commits (without patch) and merges (only when --cc gives some\n>> >> interesting nearby-changes), I would be very happy.  But is there a\n>> >> set of options that lets me do so?\n>> >\n>> > So, you're saying you changed your mind since five years ago?[1]  Or\n>> > that what you said five years ago is still valid, but you'd appreciate\n>> > more/different options that allow this new thing?\n>> >\n>> > [1]\n>> > https://lore.kernel.org/git/1440110591-12941-1-git-send-email-gitster@pobox.com/\n>>\n>> Sorry, but I am not seeing in [1] anything that relates to the above\n>> \"want to see --cc patch for merge but just log message for single\n>> parent commit\". 5 years is a long time even in Git timescale, so I\n>> would not be surprised if I changed my mind over time, but I am not\n>> sure what opinion on the matter you think I expressed back then.\n>>\n>> \"git log --cc master..next\" shows all commits' log messages, patch\n>> for each single-parent commit, and combined-dense patch for each\n>> merge.  There is no option to squelch the patch for only single\n>> parent commits.  It may not be such a bad thing to have as an extra\n>> option.\n>>\n>> So, I think what I am saying is that ...\n>>\n>> > > ...  As I said, I'm not sure why\n>> > > anyone would ever want to see diffs for merges and not for normal\n>> > > commits, the closest useful thing I can imagine is commit messages +\n>> > > diffs for just merges, stripping the normal commits.\n>>\n>> ... I see use for such a feature (assuming that you didn't mean by\n>> \"diffs for merges\" a regular \"--first-parent -p\" patch, but meant to\n>> say \"--cc\" patch) in my workflow.  I'd review \"log ko/next..next\"\n>> before deciding to push out the day's integration of 'next', and at\n>> that point, I trust individual commits that came from contributors\n>> well enough (otherwise I wouldn't be merging them to 'next'), but I\n>> would appreciate the last chance to re-examine conflict resolutions\n>> in merges.\n>>\n>> It does not mean that I do not like the current behaviour that\n>> \"--cc\" always implies \"-p\"; it is convenient.  It's just I find the\n>> lack of feature slightly less than ideal, but I do not care deeply\n>> enough to design how to express such a feature from the command\n>> line.\n>\n> Okay, thanks for clarifying.  It sounds like you were focusing on the\n> tangentially related comment I made (diffs for merges and not for\n> normal commits) while I was focusing on Sergey's question (should we\n> revert --cc implies -p).  I was having a hard time understanding if\n> you were answering his question or not.  This last paragraph of yours\n> acknowledges the question, though you still avoid answering it.  :-)\n>\n> However, even my focus was on a secondary question.  His real original\n> question is: -m and --cc are inconsistent -- one requires -p, while\n> the other doesn't.  Should that be fixed...and which option(s) should\n> change?  He gave two possibilities I didn't like.  I added a third\n> that you didn't like.  So...\n\nI believe you've misunderstood me slightly.\n\nI didn't suggest bare reverting of the \"-c/-cc imply -p\" commit. I\nrather suggested to modify current behavior to \"-c/--cc enable diff\noutput for merge commits\", then add \"-m\" to the mix, so that we finally\nget:\n\n  \"-m/-c/--c enable diff output for merge commits\".\n\nAnd I should emphasize that what I mean differs from \"-m/-c/--cc imply -p\nfor merge commits only\" as Junio has put it in this discussion, even if\nslightly, -- it won't imply -p, to avoid messing with --first-parent\nthat would imply -p through -m and enable diff for merges, that is not\nwhat we want.\n\nThis is what I'd like to see, as it finally makes -m/-c/--cc (as well as\nother --diff-merges options) focus on merge commits only and never\naffect regular commits, -- the way it should be.\n\nMy alternative suggestion was to rather add \"-m implies -p\" to the\ncurrent state, resulting in:\n\n  \"-m/-c/--c imply -p\".\n\nHowever, the latter one has additional complication in handling of\n\"--first-parent\" that currently implies -m that'd then imply -p and\nsuddenly give lengthy output on bare \"git log --first-parent\".\n\nFixing the latter is still possible by complicating of options handling\nby specifying that implied options don't imply other options, only\nexplicit options do, but somehow I don't like this, -- too complex for\nthe job at hand. I'm still on position that option management in Git\ncould rather be done in much simpler manner, without need for such\ncomplexities.\n\nThanks,\n-- Sergey\n\n"},{"id":"411866","messageId":"87v9dbf4xd.fsf@osv.gnss.ru","threadId":"54550","inReplyTo":"xmqqpn3j32ka.fsf@gitster.c.googlers.com","subject":"Re: [PATCH 00/26] git-log: implement new --diff-merge options","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-09T14:08:14Z","receivedAt":"2020-12-09T14:09:14Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Junio C Hamano <gitster@pobox.com> writes:\n>\n> A clarification and a correction.\n>\n>> I suspect that the real reason why \"-m\" does not imply \"-p\" was\n>> merely a historical implementation detail...\n>\n> Now I remember better.  The reason was pure oversight.\n>\n> In the beginning, there was no patch output for merges.  As most\n> merges just resolve cleanly, and back then the first-parent chains\n> were treated as much much less special than we treat them today,\n> \"git log -p\" showed only patches for single-parent commits and\n> everybody was happy.  It could have been a possible alternative\n> design to show first-parent diff for a merge instead of showing no\n> patch, but because the traversal went to side branches, the changes\n> made by the merge to the mainline as a single big patch would have\n> been redundant---we would be seeing individual patches from the side\n> branch anyway.\n>\n> Then later we introduced \"-m -p\"; since the first-parent chain was\n> not considered all that special, we treated each parent equally.\n> Nobody, not even Linus and I, thought it was useful by itself even\n> back then, but we didn't have anything better.\n>\n> I think it was Paul Mackerras's \"gitk\" that invented the concept of\n> combined merges.  We liked it quite a lot, and added \"-c\" and \"--cc\"\n> soon after that, to the core git and kept polishing, until \"gitk\"\n> stopped combining the patches with each parent in tcl/tk script and\n> instead started telling \"git\" to show with \"--cc\".\n>\n> By the time the change to make \"--cc\" imply \"-p\" was introduced, it\n> was pretty much given that \"-m -p\" was useful to anybody, unless you\n> are consuming these individual patches in a script or something like\n> that.  So simply I didn't even think of making \"-m\" imply \"-p\".  It\n> would be logical to make it so, but it would not add much practical\n> value, I would have to say.\n\n... and then later the \"--first-parent implies -m\" change has been made,\nthat would't work as expected if -m implied -p in the fist place, as\nit'd break \"git log --first-parent\".\n\n>\n>> If I were to decide now with hindsight, perhaps I'd make \"--cc\" and\n>> \"-m\" imply \"-p\" only for merge commits, and the user can explicitly\n>> give \"--cc -p\" and \"-m -p\" to ask patches for single-parent commits\n>> to be shown as well.\n>\n> After \"now with hindsight\", I need to add \"and without having to\n> worry about backward compatibility issues\" here.  IOW, the above is\n> not my recommendation.  It would be the other way around: \"--cc\"\n> implies \"-p\" for both merges and non-merges, \"-m\" implies \"-p\" for\n> both merges and non-merges.  It is acceptable to add a new option\n> \"--no-patch-for-non-merge\" so that the user can ask to see only the\n> combined diff for merges and no patches for individual commits.\n\nOK, so, do we decide that -c/--cc must continue to imply -p and thus\nrequest diffs for everything?\n\nIf so, I can rather change --diff-merges=combined/dense-combined\nbehavior to /not/ imply -p, thus effectively making --cc a synonym for\n\"--diff-merges=dense-combined --patch\", that will have zero backward\ncompatibility issues.\n\nLooks like it'd have everything covered. Old options won't change their\nbehavior at all, and the new set of options will behave differently,\nexactly if designed from scratch, providing new functionality.\n\n>\n> Both \"--no-patch-for-non-merge\" option, and making \"-m\" imply \"-p\"\n> are very low priority from my point of view, though, since our users\n> (including me) lived without the former and have been happily using\n> \"log --cc\" for a long time, and we've written off the latter as\n> pretty much useless combination unless you are a script.\n\nI think my above suggestion covers all the worries without need for this\nnasty \"--no-patch-for-non-merge\" option.\n\nThat said, -m is useless, period. It'd likely have some merit in\nplumbing, but definitely not in porcelain. So I'm inclined to let it\nrest in peace indeed, dying.\n\nThanks,\n-- Sergey\n\n\n"},{"id":"411906","messageId":"87k0tqdasa.fsf@osv.gnss.ru","threadId":"54550","inReplyTo":"xmqqpn3j32ka.fsf@gitster.c.googlers.com","subject":"Re: [PATCH 00/26] git-log: implement new --diff-merge options","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-09T19:44:37Z","receivedAt":"2020-12-09T19:46:00Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n[...]\n\n> By the time the change to make \"--cc\" imply \"-p\" was introduced, it\n> was pretty much given that \"-m -p\" was useful to anybody, unless you\n> are consuming these individual patches in a script or something like\n> that.  So simply I didn't even think of making \"-m\" imply \"-p\".  It\n> would be logical to make it so, but it would not add much practical\n> value, I would have to say.\n\nI need some help here.\n\nLooking at the code and trying to follow the flow, I can't figure what\nrev->diff flag is for? Why rev->diffopt.output_format, that actually\naffects the output, is not enough?\n\nMy confusion originates from the fact that the code in revision.c sets\nrev->diff to 1 for -c/--cc , while it doesn't set it for -m, and this\nwas the case *before* -c/--cc started to imply -p and -m.\n\nIt seems that the only place where rev->diff is tested is at the start\nof log_tree_diff(), and even there its absence could be ignored when\nrev->diffopt.flags.exit_with_status is set.\n\nIs rev->diff an optimization, does it play another significant role, or\nis it a remnant?\n\nThanks,\n-- Sergey\n"},{"id":"411932","messageId":"xmqqo8j21z1n.fsf@gitster.c.googlers.com","threadId":"54550","inReplyTo":"87v9dbf4xd.fsf@osv.gnss.ru","subject":"Re: [PATCH 00/26] git-log: implement new --diff-merge options","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2020-12-09T20:53:40Z","receivedAt":"2020-12-09T20:54:27Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Sergey Organov <sorganov@gmail.com> writes:\n\n>>> If I were to decide now with hindsight, perhaps I'd make \"--cc\" and\n>>> \"-m\" imply \"-p\" only for merge commits, and the user can explicitly\n>>> give \"--cc -p\" and \"-m -p\" to ask patches for single-parent commits\n>>> to be shown as well.\n>>\n>> After \"now with hindsight\", I need to add \"and without having to\n>> worry about backward compatibility issues\" here.  IOW, the above is\n>> not my recommendation.  It would be the other way around: \"--cc\"\n>> implies \"-p\" for both merges and non-merges, \"-m\" implies \"-p\" for\n>> both merges and non-merges.  It is acceptable to add a new option\n>> \"--no-patch-for-non-merge\" so that the user can ask to see only the\n>> combined diff for merges and no patches for individual commits.\n>\n> OK, so, do we decide that -c/--cc must continue to imply -p and thus\n> request diffs for everything?\n\nMy vote goes to keep the above behaviour as-is for compatibility,\nand probably match what happens when -m is given instead of -c/--cc,\nif somebody cares enough about \"-c/--cc/-m discrepancy\".\n\n> That said, -m is useless, period. It'd likely have some merit in\n> plumbing, but definitely not in porcelain. So I'm inclined to let it\n> rest in peace indeed, dying.\n\nThat is fine by me as well.\n\nI do not speak for others, though ;-)\n"},{"id":"411980","messageId":"xmqq5z5axk85.fsf@gitster.c.googlers.com","threadId":"54550","inReplyTo":"87k0tqdasa.fsf@osv.gnss.ru","subject":"Re: [PATCH 00/26] git-log: implement new --diff-merge options","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2020-12-10T06:12:42Z","receivedAt":"2020-12-10T06:14:08Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Sergey Organov <sorganov@gmail.com> writes:\n\n> My confusion originates from the fact that the code in revision.c sets\n> rev->diff to 1 for -c/--cc , while it doesn't set it for -m, and this\n> was the case *before* -c/--cc started to imply -p and -m.\n\nYes, all of this was from cd2bdc53 (Common option parsing for \"git\nlog --diff\" and friends, 2006-04-14).  We can see that \"-m\" is not\ntreated among the first class citizen in the output of \"git show\" on\nthe commit.  Namely, \"-m\" alone is merely a modifier for \"-p\" and\ndoes not cause a diff to be generated (in other words, it only\naffects the output if used together with \"-p\").\n\n\"git show cd2bdc53:git.c\" would give you how \"git log\" looked like\nback then, and how rev.diff field is used.\n\n    static int cmd_log(int argc, const char **argv, char **envp)\n    {\n    ...\n\n\tprepare_revision_walk(&rev);\n\tsetup_pager();\n\twhile ((commit = get_revision(&rev)) != NULL) {\n\t\tif (shown && rev.diff && rev.commit_format != CMIT_FMT_ONELINE)\n\t\t\tputchar('\\n');\n\nWe grab the next commit to show, and if we have already shown\nsomething in the previous iteration, and if we are told to produce\npatch output, we put an extra blank line after the patch for the\nprevious commit.  We omit that extra blank when showing the log\nmessage in oneline format.  And then ...\n\n\t\tfputs(commit_prefix, stdout);\n\t\tif (rev.abbrev_commit && rev.abbrev)\n\t\t\tfputs(find_unique_abbrev(commit->object.sha1, rev.abbrev),\n\t\t\t      stdout);\n\t\telse\n\t\t\tfputs(sha1_to_hex(commit->object.sha1), stdout);\n\t\tif (rev.parents) {\n    ...\n\t\t}\n\t\tif (rev.commit_format == CMIT_FMT_ONELINE)\n\t\t\tputchar(' ');\n\t\telse\n\t\t\tputchar('\\n');\n\t\tpretty_print_commit(rev.commit_format, commit, ~0, buf,\n\t\t\t\t    LOGSIZE, rev.abbrev);\n\t\tprintf(\"%s\\n\", buf);\n\n... after showing the log message, if we were told to produce diff,\n\n\t\tif (rev.diff)\n\t\t\tlog_tree_commit(&rev, commit);\n\nwe ask log_tree_commit() to show the patch.\n\n\t\tshown = 1;\n\t\tfree(commit->buffer);\n\t\tcommit->buffer = NULL;\n\t}\n    ...\n\nI think the code these days have most of the per-commit logic moved\nto log_tree_commit() compared to the code we see above, but the\ncheck at the beginning of log_tree_diff() we have, i.e.\n\n    static int log_tree_diff(struct rev_info *opt, struct commit *...\n    {\n\tint showed_log;\n\tstruct commit_list *parents;\n\tstruct object_id *oid;\n\n\tif (!opt->diff && !opt->diffopt.flags.exit_with_status)\n\t\treturn 0;\n\ndirectly corresponds to the \"if rev.diff is true, then call\nlog_tree_commit()\" in the 2006 code.\n"},{"id":"411984","messageId":"CABPp-BE7r4iUc6VD60Bdi+fF2bBn6_ZwVPrz_niFpY=LTZMXzw@mail.gmail.com","threadId":"54550","inReplyTo":"87k0tqdasa.fsf@osv.gnss.ru","subject":"Re: [PATCH 00/26] git-log: implement new --diff-merge options","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2020-12-10T07:26:44Z","receivedAt":"2020-12-10T07:28:04Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Wed, Dec 9, 2020 at 11:44 AM Sergey Organov <sorganov@gmail.com> wrote:\n>\n> Junio C Hamano <gitster@pobox.com> writes:\n>\n> [...]\n>\n> > By the time the change to make \"--cc\" imply \"-p\" was introduced, it\n> > was pretty much given that \"-m -p\" was useful to anybody, unless you\n> > are consuming these individual patches in a script or something like\n> > that.  So simply I didn't even think of making \"-m\" imply \"-p\".  It\n> > would be logical to make it so, but it would not add much practical\n> > value, I would have to say.\n>\n> I need some help here.\n>\n> Looking at the code and trying to follow the flow, I can't figure what\n> rev->diff flag is for? Why rev->diffopt.output_format, that actually\n> affects the output, is not enough?\n\nI'm not a revision walking expert, but to the best of my understanding...\n\nShowing a diff is not the only reason you might need to compute one.\nYou may also need to compute them if you are filtering commits by\npathspec (-- $filename), using the pickaxe (-S foo), checking if\ncommits are cherry-picks (--cherry-mark), checking for commits with\ncertain type of file changes (--diff-filter=A), selecting commits that\nmodified a certain function (-L :funcname:filename --no-patch), or\nothers I've overlooked.  None of these cause a diff to be shown.  I\ndon't know if all these set rev->diff to 1 or if they special case\nsome other way, but I suspect that rev->diff exists as a shorthand for\n\"need a diff\", so that the code can check for it without having to\ncheck a half dozen special conditions.\n\n>> My confusion originates from the fact that the code in revision.c sets\n> rev->diff to 1 for -c/--cc , while it doesn't set it for -m, and this\n> was the case *before* -c/--cc started to imply -p and -m.\n>\n> It seems that the only place where rev->diff is tested is at the start\n> of log_tree_diff(), and even there its absence could be ignored when\n> rev->diffopt.flags.exit_with_status is set.\n\nrev->diffopt.flags.exit_with_status seems quite unlikely to be set,\nthough.  That setting was added with the --exit-code flag to git log\nin 2008 (in the pm/log-exit-code topic), but was never documented\n(other than to say it's incompatible with --check), the commit message\nadding it doesn't say what behavior was intended, and the commit\nmessage which added it added no regression tests either.  I know what\ndiff --exit-code does, but I'm really not sure what git-log's\n--exit-code does (random guess: sets the exit code to an OR of what\ngit diff would have shown for any one of the commits shown?).  Since I\ndon't know and can't even figure it out looking at the commits in\nquestion, I suspect there aren't too many users out there using it.\nAs such, I suspect rev->diffopt.flags.exit_with_status will be 0 most\nof the time and that the relevant check at the top of log_tree_diff()\nreally is the \"if (!opt->diff)\" part of it.\n\n> Is rev->diff an optimization, does it play another significant role, or\n> is it a remnant?\n"},{"id":"412011","messageId":"87tust777o.fsf@osv.gnss.ru","threadId":"54550","inReplyTo":"CABPp-BE7r4iUc6VD60Bdi+fF2bBn6_ZwVPrz_niFpY=LTZMXzw@mail.gmail.com","subject":"Re: [PATCH 00/26] git-log: implement new --diff-merge options","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-10T20:10:35Z","receivedAt":"2020-12-10T20:11:49Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Elijah Newren <newren@gmail.com> writes:\n\n\n[...]\n\n> As such, I suspect rev->diffopt.flags.exit_with_status will be 0 most\n> of the time and that the relevant check at the top of log_tree_diff()\n> really is the \"if (!opt->diff)\" part of it.\n\nRight, but *why* is it needed? If I do set opt->diff to 1 but don't set\nopt->diffopt.output_format I get no diff, so the question essentially\nis: which caller of log_tree_diff() would need to set\nopt->diffopt.output_format but leave opt->diff to be 0, and why?\n\nEven if such caller exists, it will get no diff, so it seems to be\nentirely pointless.\n\n>\n>> Is rev->diff an optimization, does it play another significant role, or\n>> is it a remnant?\n\nI still don't see what's the correct answer to this question, sorry.\n\nWell, I did a crush-test: commented-out entire if() at the beginning of\nthe log_tree_diff() and ran all the tests. The result was entirely\nsurprising: all the tests pass except one:\n\nTest Summary Report\n-------------------\n./t1410-reflog.sh                                  (Wstat: 256 Tests: 22 Failed: 1)\n  Failed test:  4\n  Non-zero exit status: 1\nFiles=912, Tests=23039, 278 wallclock secs (10.48 usr  2.12 sys + 1034.98 cusr 650.30 csys = 1697.88 CPU)\nResult: FAIL\n\nAnd now I wonder how comes none of specific test are able to notice the\ndifference, yet seemingly unrelated test fails?\n\nThanks,\n-- Sergey\n"},{"id":"412015","messageId":"xmqq4kktuzvc.fsf@gitster.c.googlers.com","threadId":"54550","inReplyTo":"87tust777o.fsf@osv.gnss.ru","subject":"Re: [PATCH 00/26] git-log: implement new --diff-merge options","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2020-12-10T21:15:19Z","receivedAt":"2020-12-10T21:16:33Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Sergey Organov <sorganov@gmail.com> writes:\n\n> Well, I did a crush-test: commented-out entire if() at the beginning of\n> the log_tree_diff() and ran all the tests.\n\nMeaning \"if we are not told to show diff and if we are not told to\nindicate with the exit code whether there was any difference, we do\nnot have to do any of the following\" was skipped?  \n\nFor most cases we do use the absense of \"diff\" as an optimization,\nbut I wouldn't be surprised if a caller of log_tree_commit() that\ndoes not set \"we want diff\" bit leaves the other members of rev_info\nthat need to be set correctly for the body of the function, which is\nessentially a repeated call into diff_tree machinerly, in order to\nwork correctly.\n\n"},{"id":"412016","messageId":"xmqqwnxptks0.fsf@gitster.c.googlers.com","threadId":"54550","inReplyTo":"CABPp-BE7r4iUc6VD60Bdi+fF2bBn6_ZwVPrz_niFpY=LTZMXzw@mail.gmail.com","subject":"Re: [PATCH 00/26] git-log: implement new --diff-merge options","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2020-12-10T21:26:39Z","receivedAt":"2020-12-10T21:27:55Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Elijah Newren <newren@gmail.com> writes:\n\n> ....  I know what\n> diff --exit-code does, but I'm really not sure what git-log's\n> --exit-code does (random guess: sets the exit code to an OR of what\n> git diff would have shown for any one of the commits shown?).\n\nThe end of cmd_log_walk() does try to return diff_result_code(), but\ndiff_flush() can reset .has_changes to 0 or set it to 1 each\niteration, so I do not think it is \"set .has_changes to 0, and never\nreset to 0, but flip it to 1 if any change is found\", which would\nhave had some chance of giving us \"OR'ed together\" semantics.\n\n"},{"id":"412385","messageId":"20201216184929.3924-1-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201101193330.24775-1-sorganov@gmail.com","subject":"[PATCH v2 00/33] git-log: implement new --diff-merge options","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-16T18:48:56Z","receivedAt":"2020-12-16T18:51:06Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"These patch series implement new set of options governing diff output\nof merge commits, all under the umbrella of single\n--diff-merges=<mode> option.\n\nUnlike original -c/--cc options, these new options do not imply -p,\nthus allowing for getting diffs for merge commits without provoking of\ndiff output for regular, non-merge commits. E.g.:\n\n  git log --diff-merges=cc\n\nwill output diffs (in dense-combined format) only for merge commits,\nwhereas:\n\n  git log --cc\n\nenables diffs for all the commits being output, either merges or\nsimple ones.\n\nThere is also another additional functionality provided, allowing to\nget the format of \"-p --first-parent\" without change in history\ntraversal that --first-parent option causes, like this:\n\n  git log --diff-merges=first-parent\n\nThe net result of these series are the following new options:\n\n--diff-merges=\t  |  rough original equivalent\n------------------+----------------\n1|first-parent    | --first-parent (only diff format implications)\nm|separate        | -m and enable diff for merges\nc|combined        | -c and enable diff for merges, but not for regulars\ncc|dense-combined | --cc and enable diff for merges, but not for\n\t\t  |      regulars\n\nThe series also cleanup logic of handling of diff merges options and\nfix an issue found in the original implementation where logically\nmutually exclusive options -m/-c/--cc failed to actually override each\nother. Neither semantics of these old options nor their interactions\nwith other options, such as --first-parent and -p, is supposed to be\nchanged.\n\nThe series start with the set of pure refactoring commits that are expected\nto introduce no functional changes. These are all commits up to and\nincluding:\n\n\"diff-merges: revise revs->diff flag handling\"\n\nThe aim of these commits is to isolate options handling for diff merges so\nthat it could be easily understood and tweaked to ease introduction of the\nnew options.\n\nThen the fix of -m/-c/-cc overriding issue follows, starting with a failing\ntest and followed by the fix.\n\nThen follows a little bit of additional refactoring in order to\nprepare for introduction of the new options, and finally the series\nare finished by the implementation, documentation updates, and\nsome testing for the new options.\n\nUpdates in v2:\n\n  * Move logic of \"-c/--cc imply -p\" to this module and do not imply\n    -p by new --diff-merges options. Instead enable corresponding diff\n    output without affecting non-merge commits. This is the most\n    significant change with respect to v1 and it starts at 24/33.\n\n  * Add support for old mnemonics: --diff-merges=(m|c|cc) to help\n    those who are used to them, and add --diff-merges=1 to cover all\n    variants with short mnemonics.\n\n  * Fixed functions definitions style to have open curly brace on its\n    own line, pointed to by Junio C Hamano.\n\n  * Tweak --diff-merges=first-parent description, requested by Elijah\n    Newren.\n\n  * Fixed git-show documentation not to include description chunk\n    relevant to git-log only, noticed by Elijah Newren.\n\n  * Fixed documentation mistake claiming that -p is needed for\n    diff-merges options to take effect, noticed by Elijah Newren.\n\n  * Fixed a case where a change was put into wrong commit. The change\n    moved to 11/27 form 10/27. Didn't affect end-result in any way.\n\n  * Added short module description to diff-merges.h, as suggested by\n    Junio C Hamano.\n\n  * Fixed not returning \"argcount\" from\tdiff_merges_parse_opts(),\n    noticed by Junio C Hamano.\n\nUpdates in v1:\n\n  * Added documentation fix for git-show to include --diff-merges.\n\n  * Fixed typos in commit messages noticed by Philip Oakley.\n\nSergey Organov (33):\n  revision: factor out parsing of diff-merge related options\n  revision: factor out setup of diff-merge related settings\n  revision: factor out initialization of diff-merge related settings\n  revision: provide implementation for diff merges tweaks\n  revision: move diff merges functions to its own diff-merges.c\n  diff-merges: rename all functions to have common prefix\n  diff-merges: move checks for first_parent_only out of the module\n  diff-merges: rename diff_merges_default_to_enable() to match semantics\n  diff-merges: re-arrange functions to match the order they are called\n    in\n  diff-merges: new function diff_merges_suppress()\n  diff-merges: new function diff_merges_set_dense_combined_if_unset()\n  diff-merges: introduce revs->first_parent_merges flag\n  diff-merges: revise revs->diff flag handling\n  t4013: support test_expect_failure through ':failure' magic\n  t4013: add tests for -m failing to override -c/--cc\n  diff-merges: fix -m to properly override -c/--cc\n  diff-merges: split 'ignore_merges' field\n  diff-merges: group diff-merge flags next to each other inside\n    'rev_info'\n  diff-merges: get rid of now empty diff_merges_init_revs()\n  diff-merges: refactor opt settings into separate functions\n  diff-merges: make -m/-c/--cc explicitly mutually exclusive\n  diff-merges: implement new values for --diff-merges\n  diff-merges: fix style of functions definitions\n  diff-merges: handle imply -p on -c/--cc logic for log.c\n  diff-merges: do not imply -p for new options\n  diff-merges: let new options enable diff without -p\n  diff-merges: add old mnemonic counterparts to --diff-merges\n  diff-merges: add '--diff-merges=1' as synonym for 'first-parent'\n  doc/git-log: describe new --diff-merges options\n  doc/diff-generate-patch: mention new --diff-merges option\n  doc/rev-list-options: document --first-parent changes merges format\n  doc/git-show: include --diff-merges description\n  t4013: add tests for --diff-merges=first-parent\n\n Documentation/diff-generate-patch.txt         |   6 +-\n Documentation/diff-options.txt                |  53 +++++\n Documentation/git-log.txt                     |  46 +---\n Documentation/git-show.txt                    |   7 +-\n Documentation/rev-list-options.txt            |   5 +\n Makefile                                      |   1 +\n builtin/diff-files.c                          |   5 +-\n builtin/diff.c                                |   9 +-\n builtin/log.c                                 |  22 +-\n builtin/merge.c                               |   3 +-\n diff-merges.c                                 | 151 +++++++++++++\n diff-merges.h                                 |  24 +++\n fmt-merge-msg.c                               |   3 +-\n log-tree.c                                    |  30 +--\n revision.c                                    |  38 +---\n revision.h                                    |   9 +-\n t/t4013-diff-various.sh                       |  11 +-\n t/t4013/diff.log_--cc_-m_-p_master            | 200 ++++++++++++++++++\n ...diff.log_--diff-merges=first-parent_master |  56 +++++\n t/t4013/diff.log_-c_-m_-p_master              | 200 ++++++++++++++++++\n ...f.log_-p_--diff-merges=first-parent_master | 137 ++++++++++++\n 21 files changed, 900 insertions(+), 116 deletions(-)\n create mode 100644 diff-merges.c\n create mode 100644 diff-merges.h\n create mode 100644 t/t4013/diff.log_--cc_-m_-p_master\n create mode 100644 t/t4013/diff.log_--diff-merges=first-parent_master\n create mode 100644 t/t4013/diff.log_-c_-m_-p_master\n create mode 100644 t/t4013/diff.log_-p_--diff-merges=first-parent_master\n\n-- \n2.25.1\n\n"},{"id":"412386","messageId":"20201216184929.3924-2-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201216184929.3924-1-sorganov@gmail.com","subject":"[PATCH v2 01/33] revision: factor out parsing of diff-merge related options","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-16T18:48:57Z","receivedAt":"2020-12-16T18:51:07Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Move all the parsing code related to diffing merges into new\nparse_diff_merge_opts() function.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n revision.c | 66 ++++++++++++++++++++++++++++++++----------------------\n 1 file changed, 39 insertions(+), 27 deletions(-)\n\ndiff --git a/revision.c b/revision.c\nindex aa6221204081..917b14e6ad5b 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -2153,6 +2153,44 @@ static void add_message_grep(struct rev_info *revs, const char *pattern)\n \tadd_grep(revs, pattern, GREP_PATTERN_BODY);\n }\n \n+static int parse_diff_merge_opts(struct rev_info *revs, const char **argv) {\n+\tint argcount = 1;\n+\tconst char *optarg;\n+\tconst char *arg = argv[0];\n+\n+\tif (!strcmp(arg, \"-m\")) {\n+\t\t/*\n+\t\t * To \"diff-index\", \"-m\" means \"match missing\", and to the \"log\"\n+\t\t * family of commands, it means \"show full diff for merges\". Set\n+\t\t * both fields appropriately.\n+\t\t */\n+\t\trevs->ignore_merges = 0;\n+\t\trevs->match_missing = 1;\n+\t} else if (!strcmp(arg, \"-c\")) {\n+\t\trevs->diff = 1;\n+\t\trevs->dense_combined_merges = 0;\n+\t\trevs->combine_merges = 1;\n+\t} else if (!strcmp(arg, \"--cc\")) {\n+\t\trevs->diff = 1;\n+\t\trevs->dense_combined_merges = 1;\n+\t\trevs->combine_merges = 1;\n+\t} else if (!strcmp(arg, \"--no-diff-merges\")) {\n+\t\trevs->ignore_merges = 1;\n+\t} else if (!strcmp(arg, \"--combined-all-paths\")) {\n+\t\trevs->diff = 1;\n+\t\trevs->combined_all_paths = 1;\n+\t} else if ((argcount = parse_long_opt(\"diff-merges\", argv, &optarg))) {\n+\t\tif (!strcmp(optarg, \"off\")) {\n+\t\t\trevs->ignore_merges = 1;\n+\t\t} else {\n+\t\t\tdie(_(\"unknown value for --diff-merges: %s\"), optarg);\n+\t\t}\n+\t} else\n+\t\targcount = 0;\n+\n+\treturn argcount;\n+}\n+\n static int handle_revision_opt(struct rev_info *revs, int argc, const char **argv,\n \t\t\t       int *unkc, const char **unkv,\n \t\t\t       const struct setup_revision_opt* opt)\n@@ -2349,34 +2387,8 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg\n \t\trevs->diff = 1;\n \t\trevs->diffopt.flags.recursive = 1;\n \t\trevs->diffopt.flags.tree_in_recursive = 1;\n-\t} else if (!strcmp(arg, \"-m\")) {\n-\t\t/*\n-\t\t * To \"diff-index\", \"-m\" means \"match missing\", and to the \"log\"\n-\t\t * family of commands, it means \"show full diff for merges\". Set\n-\t\t * both fields appropriately.\n-\t\t */\n-\t\trevs->ignore_merges = 0;\n-\t\trevs->match_missing = 1;\n-\t} else if ((argcount = parse_long_opt(\"diff-merges\", argv, &optarg))) {\n-\t\tif (!strcmp(optarg, \"off\")) {\n-\t\t\trevs->ignore_merges = 1;\n-\t\t} else {\n-\t\t\tdie(_(\"unknown value for --diff-merges: %s\"), optarg);\n-\t\t}\n+\t} else if ((argcount = parse_diff_merge_opts(revs, argv))) {\n \t\treturn argcount;\n-\t} else if (!strcmp(arg, \"--no-diff-merges\")) {\n-\t\trevs->ignore_merges = 1;\n-\t} else if (!strcmp(arg, \"-c\")) {\n-\t\trevs->diff = 1;\n-\t\trevs->dense_combined_merges = 0;\n-\t\trevs->combine_merges = 1;\n-\t} else if (!strcmp(arg, \"--combined-all-paths\")) {\n-\t\trevs->diff = 1;\n-\t\trevs->combined_all_paths = 1;\n-\t} else if (!strcmp(arg, \"--cc\")) {\n-\t\trevs->diff = 1;\n-\t\trevs->dense_combined_merges = 1;\n-\t\trevs->combine_merges = 1;\n \t} else if (!strcmp(arg, \"-v\")) {\n \t\trevs->verbose_header = 1;\n \t} else if (!strcmp(arg, \"--pretty\")) {\n-- \n2.25.1\n\n"},{"id":"412387","messageId":"20201216184929.3924-3-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201216184929.3924-1-sorganov@gmail.com","subject":"[PATCH v2 02/33] revision: factor out setup of diff-merge related settings","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-16T18:48:58Z","receivedAt":"2020-12-16T18:51:09Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Move all the setting code related to diffing merges into new\nsetup_diff_merge_revs() function.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n revision.c | 18 ++++++++++++------\n 1 file changed, 12 insertions(+), 6 deletions(-)\n\ndiff --git a/revision.c b/revision.c\nindex 917b14e6ad5b..e4c75d9278c4 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -2191,6 +2191,16 @@ static int parse_diff_merge_opts(struct rev_info *revs, const char **argv) {\n \treturn argcount;\n }\n \n+static void setup_diff_merges_revs(struct rev_info *revs)\n+{\n+\tif (revs->combine_merges && revs->ignore_merges < 0)\n+\t\trevs->ignore_merges = 0;\n+\tif (revs->ignore_merges < 0)\n+\t\trevs->ignore_merges = 1;\n+\tif (revs->combined_all_paths && !revs->combine_merges)\n+\t\tdie(\"--combined-all-paths makes no sense without -c or --cc\");\n+}\n+\n static int handle_revision_opt(struct rev_info *revs, int argc, const char **argv,\n \t\t\t       int *unkc, const char **unkv,\n \t\t\t       const struct setup_revision_opt* opt)\n@@ -2885,12 +2895,8 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s\n \t\t\tcopy_pathspec(&revs->diffopt.pathspec,\n \t\t\t\t      &revs->prune_data);\n \t}\n-\tif (revs->combine_merges && revs->ignore_merges < 0)\n-\t\trevs->ignore_merges = 0;\n-\tif (revs->ignore_merges < 0)\n-\t\trevs->ignore_merges = 1;\n-\tif (revs->combined_all_paths && !revs->combine_merges)\n-\t\tdie(\"--combined-all-paths makes no sense without -c or --cc\");\n+\n+\tsetup_diff_merges_revs(revs);\n \n \trevs->diffopt.abbrev = revs->abbrev;\n \n-- \n2.25.1\n\n"},{"id":"412388","messageId":"20201216184929.3924-5-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201216184929.3924-1-sorganov@gmail.com","subject":"[PATCH v2 04/33] revision: provide implementation for diff merges tweaks","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-16T18:49:00Z","receivedAt":"2020-12-16T18:51:12Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Use these implementations from show_setup_revisions_tweak() and\nlog_setup_revisions_tweak() in builtin/log.c.\n\nThis completes moving of management of diff merges parameters to a\nsingle place, where we can finally observe them simultaneously.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n builtin/log.c | 13 ++-----------\n revision.c    | 17 +++++++++++++++++\n revision.h    |  3 +++\n 3 files changed, 22 insertions(+), 11 deletions(-)\n\ndiff --git a/builtin/log.c b/builtin/log.c\nindex 0a7ed4bef92b..717855a49e90 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -598,15 +598,7 @@ static int show_tree_object(const struct object_id *oid,\n static void show_setup_revisions_tweak(struct rev_info *rev,\n \t\t\t\t       struct setup_revision_opt *opt)\n {\n-\tif (rev->ignore_merges < 0) {\n-\t\t/* There was no \"-m\" variant on the command line */\n-\t\trev->ignore_merges = 0;\n-\t\tif (!rev->first_parent_only && !rev->combine_merges) {\n-\t\t\t/* No \"--first-parent\", \"-c\", or \"--cc\" */\n-\t\t\trev->combine_merges = 1;\n-\t\t\trev->dense_combined_merges = 1;\n-\t\t}\n-\t}\n+\trev_diff_merges_default_to_dense_combined(rev);\n \tif (!rev->diffopt.output_format)\n \t\trev->diffopt.output_format = DIFF_FORMAT_PATCH;\n }\n@@ -731,8 +723,7 @@ static void log_setup_revisions_tweak(struct rev_info *rev,\n \tif (!rev->diffopt.output_format && rev->combine_merges)\n \t\trev->diffopt.output_format = DIFF_FORMAT_PATCH;\n \n-\tif (rev->first_parent_only && rev->ignore_merges < 0)\n-\t\trev->ignore_merges = 0;\n+\trev_diff_merges_first_parent_defaults_to_enable(rev);\n }\n \n int cmd_log(int argc, const char **argv, const char *prefix)\ndiff --git a/revision.c b/revision.c\nindex da82663c8ce1..7b5b59a3c848 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -2207,6 +2207,23 @@ static void setup_diff_merges_revs(struct rev_info *revs)\n \t\tdie(\"--combined-all-paths makes no sense without -c or --cc\");\n }\n \n+void rev_diff_merges_first_parent_defaults_to_enable(struct rev_info *revs) {\n+\tif (revs->first_parent_only && revs->ignore_merges < 0)\n+\t\trevs->ignore_merges = 0;\n+}\n+\n+void rev_diff_merges_default_to_dense_combined(struct rev_info *revs) {\n+\tif (revs->ignore_merges < 0) {\n+\t\t/* There was no \"-m\" variant on the command line */\n+\t\trevs->ignore_merges = 0;\n+\t\tif (!revs->first_parent_only && !revs->combine_merges) {\n+\t\t\t/* No \"--first-parent\", \"-c\", or \"--cc\" */\n+\t\t\trevs->combine_merges = 1;\n+\t\t\trevs->dense_combined_merges = 1;\n+\t\t}\n+\t}\n+}\n+\n static int handle_revision_opt(struct rev_info *revs, int argc, const char **argv,\n \t\t\t       int *unkc, const char **unkv,\n \t\t\t       const struct setup_revision_opt* opt)\ndiff --git a/revision.h b/revision.h\nindex f6bf860d19e5..3dd0229f4edc 100644\n--- a/revision.h\n+++ b/revision.h\n@@ -456,4 +456,7 @@ int rewrite_parents(struct rev_info *revs,\n  */\n struct commit_list *get_saved_parents(struct rev_info *revs, const struct commit *commit);\n \n+void rev_diff_merges_default_to_dense_combined(struct rev_info *revs);\n+void rev_diff_merges_first_parent_defaults_to_enable(struct rev_info *revs);\n+\n #endif\n-- \n2.25.1\n\n"},{"id":"412389","messageId":"20201216184929.3924-4-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201216184929.3924-1-sorganov@gmail.com","subject":"[PATCH v2 03/33] revision: factor out initialization of diff-merge related settings","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-16T18:48:59Z","receivedAt":"2020-12-16T18:51:12Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Move initialization code related to diffing merges into new\ninit_diff_merge_revs() function.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n revision.c | 8 +++++++-\n 1 file changed, 7 insertions(+), 1 deletion(-)\n\ndiff --git a/revision.c b/revision.c\nindex e4c75d9278c4..da82663c8ce1 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -1805,6 +1805,8 @@ static int add_parents_only(struct rev_info *revs, const char *arg_, int flags,\n \treturn 1;\n }\n \n+static void init_diff_merge_revs(struct rev_info *revs);\n+\n void repo_init_revisions(struct repository *r,\n \t\t\t struct rev_info *revs,\n \t\t\t const char *prefix)\n@@ -1813,7 +1815,7 @@ void repo_init_revisions(struct repository *r,\n \n \trevs->repo = r;\n \trevs->abbrev = DEFAULT_ABBREV;\n-\trevs->ignore_merges = -1;\n+\tinit_diff_merge_revs(revs);\n \trevs->simplify_history = 1;\n \trevs->pruning.repo = r;\n \trevs->pruning.flags.recursive = 1;\n@@ -2153,6 +2155,10 @@ static void add_message_grep(struct rev_info *revs, const char *pattern)\n \tadd_grep(revs, pattern, GREP_PATTERN_BODY);\n }\n \n+static void init_diff_merge_revs(struct rev_info *revs) {\n+\trevs->ignore_merges = -1;\n+}\n+\n static int parse_diff_merge_opts(struct rev_info *revs, const char **argv) {\n \tint argcount = 1;\n \tconst char *optarg;\n-- \n2.25.1\n\n"},{"id":"412390","messageId":"20201216184929.3924-6-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201216184929.3924-1-sorganov@gmail.com","subject":"[PATCH v2 05/33] revision: move diff merges functions to its own diff-merges.c","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-16T18:49:01Z","receivedAt":"2020-12-16T18:51:46Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Create separate diff-merges.c and diff-merges.h files, and move all\nthe code related to handling of diff merges there.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n Makefile      |  1 +\n builtin/log.c |  1 +\n diff-merges.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++\n diff-merges.h | 18 +++++++++++++\n revision.c    | 72 +--------------------------------------------------\n revision.h    |  3 ---\n 6 files changed, 93 insertions(+), 74 deletions(-)\n create mode 100644 diff-merges.c\n create mode 100644 diff-merges.h\n\ndiff --git a/Makefile b/Makefile\nindex 1fb0ec17059a..d1347ef262cf 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -872,6 +872,7 @@ LIB_OBJS += date.o\n LIB_OBJS += decorate.o\n LIB_OBJS += delta-islands.o\n LIB_OBJS += diff-delta.o\n+LIB_OBJS += diff-merges.o\n LIB_OBJS += diff-lib.o\n LIB_OBJS += diff-no-index.o\n LIB_OBJS += diff.o\ndiff --git a/builtin/log.c b/builtin/log.c\nindex 717855a49e90..ad3092fdd854 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -12,6 +12,7 @@\n #include \"color.h\"\n #include \"commit.h\"\n #include \"diff.h\"\n+#include \"diff-merges.h\"\n #include \"revision.h\"\n #include \"log-tree.h\"\n #include \"builtin.h\"\ndiff --git a/diff-merges.c b/diff-merges.c\nnew file mode 100644\nindex 000000000000..eb25bcca2494\n--- /dev/null\n+++ b/diff-merges.c\n@@ -0,0 +1,72 @@\n+#include \"diff-merges.h\"\n+\n+#include \"revision.h\"\n+\n+void init_diff_merge_revs(struct rev_info *revs) {\n+\trevs->ignore_merges = -1;\n+}\n+\n+int parse_diff_merge_opts(struct rev_info *revs, const char **argv) {\n+\tint argcount = 1;\n+\tconst char *optarg;\n+\tconst char *arg = argv[0];\n+\n+\tif (!strcmp(arg, \"-m\")) {\n+\t\t/*\n+\t\t * To \"diff-index\", \"-m\" means \"match missing\", and to the \"log\"\n+\t\t * family of commands, it means \"show full diff for merges\". Set\n+\t\t * both fields appropriately.\n+\t\t */\n+\t\trevs->ignore_merges = 0;\n+\t\trevs->match_missing = 1;\n+\t} else if (!strcmp(arg, \"-c\")) {\n+\t\trevs->diff = 1;\n+\t\trevs->dense_combined_merges = 0;\n+\t\trevs->combine_merges = 1;\n+\t} else if (!strcmp(arg, \"--cc\")) {\n+\t\trevs->diff = 1;\n+\t\trevs->dense_combined_merges = 1;\n+\t\trevs->combine_merges = 1;\n+\t} else if (!strcmp(arg, \"--no-diff-merges\")) {\n+\t\trevs->ignore_merges = 1;\n+\t} else if (!strcmp(arg, \"--combined-all-paths\")) {\n+\t\trevs->diff = 1;\n+\t\trevs->combined_all_paths = 1;\n+\t} else if ((argcount = parse_long_opt(\"diff-merges\", argv, &optarg))) {\n+\t\tif (!strcmp(optarg, \"off\")) {\n+\t\t\trevs->ignore_merges = 1;\n+\t\t} else {\n+\t\t\tdie(_(\"unknown value for --diff-merges: %s\"), optarg);\n+\t\t}\n+\t} else\n+\t\targcount = 0;\n+\n+\treturn argcount;\n+}\n+\n+void setup_diff_merges_revs(struct rev_info *revs)\n+{\n+\tif (revs->combine_merges && revs->ignore_merges < 0)\n+\t\trevs->ignore_merges = 0;\n+\tif (revs->ignore_merges < 0)\n+\t\trevs->ignore_merges = 1;\n+\tif (revs->combined_all_paths && !revs->combine_merges)\n+\t\tdie(\"--combined-all-paths makes no sense without -c or --cc\");\n+}\n+\n+void rev_diff_merges_first_parent_defaults_to_enable(struct rev_info *revs) {\n+\tif (revs->first_parent_only && revs->ignore_merges < 0)\n+\t\trevs->ignore_merges = 0;\n+}\n+\n+void rev_diff_merges_default_to_dense_combined(struct rev_info *revs) {\n+\tif (revs->ignore_merges < 0) {\n+\t\t/* There was no \"-m\" variant on the command line */\n+\t\trevs->ignore_merges = 0;\n+\t\tif (!revs->first_parent_only && !revs->combine_merges) {\n+\t\t\t/* No \"--first-parent\", \"-c\", or \"--cc\" */\n+\t\t\trevs->combine_merges = 1;\n+\t\t\trevs->dense_combined_merges = 1;\n+\t\t}\n+\t}\n+}\ndiff --git a/diff-merges.h b/diff-merges.h\nnew file mode 100644\nindex 000000000000..7e970b266cf5\n--- /dev/null\n+++ b/diff-merges.h\n@@ -0,0 +1,18 @@\n+#ifndef DIFF_MERGES_H\n+#define DIFF_MERGES_H\n+\n+/*\n+ * diff-merges - utility module to handle command-line options for\n+ * selection of particular diff format of merge commits\n+ * representation.\n+ */\n+\n+struct rev_info;\n+\n+void init_diff_merge_revs(struct rev_info *revs);\n+int parse_diff_merge_opts(struct rev_info *revs, const char **argv);\n+void setup_diff_merges_revs(struct rev_info *revs);\n+void rev_diff_merges_default_to_dense_combined(struct rev_info *revs);\n+void rev_diff_merges_first_parent_defaults_to_enable(struct rev_info *revs);\n+\n+#endif\ndiff --git a/revision.c b/revision.c\nindex 7b5b59a3c848..4bc14a08a624 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -5,6 +5,7 @@\n #include \"tree.h\"\n #include \"commit.h\"\n #include \"diff.h\"\n+#include \"diff-merges.h\"\n #include \"refs.h\"\n #include \"revision.h\"\n #include \"repository.h\"\n@@ -1805,8 +1806,6 @@ static int add_parents_only(struct rev_info *revs, const char *arg_, int flags,\n \treturn 1;\n }\n \n-static void init_diff_merge_revs(struct rev_info *revs);\n-\n void repo_init_revisions(struct repository *r,\n \t\t\t struct rev_info *revs,\n \t\t\t const char *prefix)\n@@ -2155,75 +2154,6 @@ static void add_message_grep(struct rev_info *revs, const char *pattern)\n \tadd_grep(revs, pattern, GREP_PATTERN_BODY);\n }\n \n-static void init_diff_merge_revs(struct rev_info *revs) {\n-\trevs->ignore_merges = -1;\n-}\n-\n-static int parse_diff_merge_opts(struct rev_info *revs, const char **argv) {\n-\tint argcount = 1;\n-\tconst char *optarg;\n-\tconst char *arg = argv[0];\n-\n-\tif (!strcmp(arg, \"-m\")) {\n-\t\t/*\n-\t\t * To \"diff-index\", \"-m\" means \"match missing\", and to the \"log\"\n-\t\t * family of commands, it means \"show full diff for merges\". Set\n-\t\t * both fields appropriately.\n-\t\t */\n-\t\trevs->ignore_merges = 0;\n-\t\trevs->match_missing = 1;\n-\t} else if (!strcmp(arg, \"-c\")) {\n-\t\trevs->diff = 1;\n-\t\trevs->dense_combined_merges = 0;\n-\t\trevs->combine_merges = 1;\n-\t} else if (!strcmp(arg, \"--cc\")) {\n-\t\trevs->diff = 1;\n-\t\trevs->dense_combined_merges = 1;\n-\t\trevs->combine_merges = 1;\n-\t} else if (!strcmp(arg, \"--no-diff-merges\")) {\n-\t\trevs->ignore_merges = 1;\n-\t} else if (!strcmp(arg, \"--combined-all-paths\")) {\n-\t\trevs->diff = 1;\n-\t\trevs->combined_all_paths = 1;\n-\t} else if ((argcount = parse_long_opt(\"diff-merges\", argv, &optarg))) {\n-\t\tif (!strcmp(optarg, \"off\")) {\n-\t\t\trevs->ignore_merges = 1;\n-\t\t} else {\n-\t\t\tdie(_(\"unknown value for --diff-merges: %s\"), optarg);\n-\t\t}\n-\t} else\n-\t\targcount = 0;\n-\n-\treturn argcount;\n-}\n-\n-static void setup_diff_merges_revs(struct rev_info *revs)\n-{\n-\tif (revs->combine_merges && revs->ignore_merges < 0)\n-\t\trevs->ignore_merges = 0;\n-\tif (revs->ignore_merges < 0)\n-\t\trevs->ignore_merges = 1;\n-\tif (revs->combined_all_paths && !revs->combine_merges)\n-\t\tdie(\"--combined-all-paths makes no sense without -c or --cc\");\n-}\n-\n-void rev_diff_merges_first_parent_defaults_to_enable(struct rev_info *revs) {\n-\tif (revs->first_parent_only && revs->ignore_merges < 0)\n-\t\trevs->ignore_merges = 0;\n-}\n-\n-void rev_diff_merges_default_to_dense_combined(struct rev_info *revs) {\n-\tif (revs->ignore_merges < 0) {\n-\t\t/* There was no \"-m\" variant on the command line */\n-\t\trevs->ignore_merges = 0;\n-\t\tif (!revs->first_parent_only && !revs->combine_merges) {\n-\t\t\t/* No \"--first-parent\", \"-c\", or \"--cc\" */\n-\t\t\trevs->combine_merges = 1;\n-\t\t\trevs->dense_combined_merges = 1;\n-\t\t}\n-\t}\n-}\n-\n static int handle_revision_opt(struct rev_info *revs, int argc, const char **argv,\n \t\t\t       int *unkc, const char **unkv,\n \t\t\t       const struct setup_revision_opt* opt)\ndiff --git a/revision.h b/revision.h\nindex 3dd0229f4edc..f6bf860d19e5 100644\n--- a/revision.h\n+++ b/revision.h\n@@ -456,7 +456,4 @@ int rewrite_parents(struct rev_info *revs,\n  */\n struct commit_list *get_saved_parents(struct rev_info *revs, const struct commit *commit);\n \n-void rev_diff_merges_default_to_dense_combined(struct rev_info *revs);\n-void rev_diff_merges_first_parent_defaults_to_enable(struct rev_info *revs);\n-\n #endif\n-- \n2.25.1\n\n"},{"id":"412391","messageId":"20201216184929.3924-7-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201216184929.3924-1-sorganov@gmail.com","subject":"[PATCH v2 06/33] diff-merges: rename all functions to have common prefix","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-16T18:49:02Z","receivedAt":"2020-12-16T18:51:46Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Use the same \"diff_merges\" prefix for all the diff merges function\nnames.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n builtin/log.c |  4 ++--\n diff-merges.c | 10 +++++-----\n diff-merges.h | 15 ++++++++++-----\n revision.c    |  6 +++---\n 4 files changed, 20 insertions(+), 15 deletions(-)\n\ndiff --git a/builtin/log.c b/builtin/log.c\nindex ad3092fdd854..77a7bba543ad 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -599,7 +599,7 @@ static int show_tree_object(const struct object_id *oid,\n static void show_setup_revisions_tweak(struct rev_info *rev,\n \t\t\t\t       struct setup_revision_opt *opt)\n {\n-\trev_diff_merges_default_to_dense_combined(rev);\n+\tdiff_merges_default_to_dense_combined(rev);\n \tif (!rev->diffopt.output_format)\n \t\trev->diffopt.output_format = DIFF_FORMAT_PATCH;\n }\n@@ -724,7 +724,7 @@ static void log_setup_revisions_tweak(struct rev_info *rev,\n \tif (!rev->diffopt.output_format && rev->combine_merges)\n \t\trev->diffopt.output_format = DIFF_FORMAT_PATCH;\n \n-\trev_diff_merges_first_parent_defaults_to_enable(rev);\n+\tdiff_merges_first_parent_defaults_to_enable(rev);\n }\n \n int cmd_log(int argc, const char **argv, const char *prefix)\ndiff --git a/diff-merges.c b/diff-merges.c\nindex eb25bcca2494..b647920bdb22 100644\n--- a/diff-merges.c\n+++ b/diff-merges.c\n@@ -2,11 +2,11 @@\n \n #include \"revision.h\"\n \n-void init_diff_merge_revs(struct rev_info *revs) {\n+void diff_merges_init_revs(struct rev_info *revs) {\n \trevs->ignore_merges = -1;\n }\n \n-int parse_diff_merge_opts(struct rev_info *revs, const char **argv) {\n+int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {\n \tint argcount = 1;\n \tconst char *optarg;\n \tconst char *arg = argv[0];\n@@ -44,7 +44,7 @@ int parse_diff_merge_opts(struct rev_info *revs, const char **argv) {\n \treturn argcount;\n }\n \n-void setup_diff_merges_revs(struct rev_info *revs)\n+void diff_merges_setup_revs(struct rev_info *revs)\n {\n \tif (revs->combine_merges && revs->ignore_merges < 0)\n \t\trevs->ignore_merges = 0;\n@@ -54,12 +54,12 @@ void setup_diff_merges_revs(struct rev_info *revs)\n \t\tdie(\"--combined-all-paths makes no sense without -c or --cc\");\n }\n \n-void rev_diff_merges_first_parent_defaults_to_enable(struct rev_info *revs) {\n+void diff_merges_first_parent_defaults_to_enable(struct rev_info *revs) {\n \tif (revs->first_parent_only && revs->ignore_merges < 0)\n \t\trevs->ignore_merges = 0;\n }\n \n-void rev_diff_merges_default_to_dense_combined(struct rev_info *revs) {\n+void diff_merges_default_to_dense_combined(struct rev_info *revs) {\n \tif (revs->ignore_merges < 0) {\n \t\t/* There was no \"-m\" variant on the command line */\n \t\trevs->ignore_merges = 0;\ndiff --git a/diff-merges.h b/diff-merges.h\nindex 7e970b266cf5..4ced909b795e 100644\n--- a/diff-merges.h\n+++ b/diff-merges.h\n@@ -9,10 +9,15 @@\n \n struct rev_info;\n \n-void init_diff_merge_revs(struct rev_info *revs);\n-int parse_diff_merge_opts(struct rev_info *revs, const char **argv);\n-void setup_diff_merges_revs(struct rev_info *revs);\n-void rev_diff_merges_default_to_dense_combined(struct rev_info *revs);\n-void rev_diff_merges_first_parent_defaults_to_enable(struct rev_info *revs);\n+void diff_merges_init_revs(struct rev_info *revs);\n+\n+int diff_merges_parse_opts(struct rev_info *revs, const char **argv);\n+\n+void diff_merges_setup_revs(struct rev_info *revs);\n+\n+void diff_merges_default_to_dense_combined(struct rev_info *revs);\n+\n+void diff_merges_first_parent_defaults_to_enable(struct rev_info *revs);\n+\n \n #endif\ndiff --git a/revision.c b/revision.c\nindex 4bc14a08a624..5a0e3d6ad542 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -1814,7 +1814,7 @@ void repo_init_revisions(struct repository *r,\n \n \trevs->repo = r;\n \trevs->abbrev = DEFAULT_ABBREV;\n-\tinit_diff_merge_revs(revs);\n+\tdiff_merges_init_revs(revs);\n \trevs->simplify_history = 1;\n \trevs->pruning.repo = r;\n \trevs->pruning.flags.recursive = 1;\n@@ -2350,7 +2350,7 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg\n \t\trevs->diff = 1;\n \t\trevs->diffopt.flags.recursive = 1;\n \t\trevs->diffopt.flags.tree_in_recursive = 1;\n-\t} else if ((argcount = parse_diff_merge_opts(revs, argv))) {\n+\t} else if ((argcount = diff_merges_parse_opts(revs, argv))) {\n \t\treturn argcount;\n \t} else if (!strcmp(arg, \"-v\")) {\n \t\trevs->verbose_header = 1;\n@@ -2849,7 +2849,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s\n \t\t\t\t      &revs->prune_data);\n \t}\n \n-\tsetup_diff_merges_revs(revs);\n+\tdiff_merges_setup_revs(revs);\n \n \trevs->diffopt.abbrev = revs->abbrev;\n \n-- \n2.25.1\n\n"},{"id":"412392","messageId":"20201216184929.3924-9-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201216184929.3924-1-sorganov@gmail.com","subject":"[PATCH v2 08/33] diff-merges: rename diff_merges_default_to_enable() to match semantics","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-16T18:49:04Z","receivedAt":"2020-12-16T18:51:48Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Rename diff_merges_default_to_enable() to\ndiff_merges_default_to_first_parent() to match its semantics.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n builtin/log.c | 4 ++--\n diff-merges.c | 2 +-\n diff-merges.h | 2 +-\n 3 files changed, 4 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/log.c b/builtin/log.c\nindex a7791c003c91..63875c3aeec9 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -600,7 +600,7 @@ static void show_setup_revisions_tweak(struct rev_info *rev,\n \t\t\t\t       struct setup_revision_opt *opt)\n {\n \tif (rev->first_parent_only)\n-\t\tdiff_merges_default_to_enable(rev);\n+\t\tdiff_merges_default_to_first_parent(rev);\n \telse\n \t\tdiff_merges_default_to_dense_combined(rev);\n \tif (!rev->diffopt.output_format)\n@@ -728,7 +728,7 @@ static void log_setup_revisions_tweak(struct rev_info *rev,\n \t\trev->diffopt.output_format = DIFF_FORMAT_PATCH;\n \n \tif (rev->first_parent_only)\n-\t\tdiff_merges_default_to_enable(rev);\n+\t\tdiff_merges_default_to_first_parent(rev);\n }\n \n int cmd_log(int argc, const char **argv, const char *prefix)\ndiff --git a/diff-merges.c b/diff-merges.c\nindex f0d0ae208213..19b85bfdba6f 100644\n--- a/diff-merges.c\n+++ b/diff-merges.c\n@@ -54,7 +54,7 @@ void diff_merges_setup_revs(struct rev_info *revs)\n \t\tdie(\"--combined-all-paths makes no sense without -c or --cc\");\n }\n \n-void diff_merges_default_to_enable(struct rev_info *revs) {\n+void diff_merges_default_to_first_parent(struct rev_info *revs) {\n \tif (revs->ignore_merges < 0)\t\t/* No -m */\n \t\trevs->ignore_merges = 0;\n }\ndiff --git a/diff-merges.h b/diff-merges.h\nindex 6937d46219f1..18861dc5480e 100644\n--- a/diff-merges.h\n+++ b/diff-merges.h\n@@ -17,7 +17,7 @@ void diff_merges_setup_revs(struct rev_info *revs);\n \n void diff_merges_default_to_dense_combined(struct rev_info *revs);\n \n-void diff_merges_default_to_enable(struct rev_info *revs);\n+void diff_merges_default_to_first_parent(struct rev_info *revs);\n \n \n #endif\n-- \n2.25.1\n\n"},{"id":"412393","messageId":"20201216184929.3924-8-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201216184929.3924-1-sorganov@gmail.com","subject":"[PATCH v2 07/33] diff-merges: move checks for first_parent_only out of the module","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-16T18:49:03Z","receivedAt":"2020-12-16T18:51:48Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"The checks for first_parent_only don't in fact belong to this module,\nas the primary purpose of this flag is history traversal limiting, so\nget it out of this module and rename the\n\ndiff_merges_first_parent_defaults_to_enable()\n\nto\n\ndiff_merges_default_to_enable()\n\nto match new semantics.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n builtin/log.c |  8 ++++++--\n diff-merges.c | 10 ++++------\n diff-merges.h |  2 +-\n 3 files changed, 11 insertions(+), 9 deletions(-)\n\ndiff --git a/builtin/log.c b/builtin/log.c\nindex 77a7bba543ad..a7791c003c91 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -599,7 +599,10 @@ static int show_tree_object(const struct object_id *oid,\n static void show_setup_revisions_tweak(struct rev_info *rev,\n \t\t\t\t       struct setup_revision_opt *opt)\n {\n-\tdiff_merges_default_to_dense_combined(rev);\n+\tif (rev->first_parent_only)\n+\t\tdiff_merges_default_to_enable(rev);\n+\telse\n+\t\tdiff_merges_default_to_dense_combined(rev);\n \tif (!rev->diffopt.output_format)\n \t\trev->diffopt.output_format = DIFF_FORMAT_PATCH;\n }\n@@ -724,7 +727,8 @@ static void log_setup_revisions_tweak(struct rev_info *rev,\n \tif (!rev->diffopt.output_format && rev->combine_merges)\n \t\trev->diffopt.output_format = DIFF_FORMAT_PATCH;\n \n-\tdiff_merges_first_parent_defaults_to_enable(rev);\n+\tif (rev->first_parent_only)\n+\t\tdiff_merges_default_to_enable(rev);\n }\n \n int cmd_log(int argc, const char **argv, const char *prefix)\ndiff --git a/diff-merges.c b/diff-merges.c\nindex b647920bdb22..f0d0ae208213 100644\n--- a/diff-merges.c\n+++ b/diff-merges.c\n@@ -54,17 +54,15 @@ void diff_merges_setup_revs(struct rev_info *revs)\n \t\tdie(\"--combined-all-paths makes no sense without -c or --cc\");\n }\n \n-void diff_merges_first_parent_defaults_to_enable(struct rev_info *revs) {\n-\tif (revs->first_parent_only && revs->ignore_merges < 0)\n+void diff_merges_default_to_enable(struct rev_info *revs) {\n+\tif (revs->ignore_merges < 0)\t\t/* No -m */\n \t\trevs->ignore_merges = 0;\n }\n \n void diff_merges_default_to_dense_combined(struct rev_info *revs) {\n-\tif (revs->ignore_merges < 0) {\n-\t\t/* There was no \"-m\" variant on the command line */\n+\tif (revs->ignore_merges < 0) {\t\t/* No -m */\n \t\trevs->ignore_merges = 0;\n-\t\tif (!revs->first_parent_only && !revs->combine_merges) {\n-\t\t\t/* No \"--first-parent\", \"-c\", or \"--cc\" */\n+\t\tif (!revs->combine_merges) {\t/* No -c/--cc\" */\n \t\t\trevs->combine_merges = 1;\n \t\t\trevs->dense_combined_merges = 1;\n \t\t}\ndiff --git a/diff-merges.h b/diff-merges.h\nindex 4ced909b795e..6937d46219f1 100644\n--- a/diff-merges.h\n+++ b/diff-merges.h\n@@ -17,7 +17,7 @@ void diff_merges_setup_revs(struct rev_info *revs);\n \n void diff_merges_default_to_dense_combined(struct rev_info *revs);\n \n-void diff_merges_first_parent_defaults_to_enable(struct rev_info *revs);\n+void diff_merges_default_to_enable(struct rev_info *revs);\n \n \n #endif\n-- \n2.25.1\n\n"},{"id":"412394","messageId":"20201216184929.3924-11-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201216184929.3924-1-sorganov@gmail.com","subject":"[PATCH v2 10/33] diff-merges: new function diff_merges_suppress()","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-16T18:49:06Z","receivedAt":"2020-12-16T18:51:49Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"This function sets all the relevant flags to disabled state, so that\nno code that checks only one of them get it wrong.\n\nThen we call this new function everywhere where diff merges output\nsuppression is needed.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n builtin/merge.c |  3 ++-\n diff-merges.c   | 15 +++++++++++++--\n diff-merges.h   |  2 ++\n fmt-merge-msg.c |  3 ++-\n 4 files changed, 19 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/merge.c b/builtin/merge.c\nindex 9d5359edc2f7..1f7b69982b40 100644\n--- a/builtin/merge.c\n+++ b/builtin/merge.c\n@@ -14,6 +14,7 @@\n #include \"lockfile.h\"\n #include \"run-command.h\"\n #include \"diff.h\"\n+#include \"diff-merges.h\"\n #include \"refs.h\"\n #include \"refspec.h\"\n #include \"commit.h\"\n@@ -400,7 +401,7 @@ static void squash_message(struct commit *commit, struct commit_list *remotehead\n \tprintf(_(\"Squash commit -- not updating HEAD\\n\"));\n \n \trepo_init_revisions(the_repository, &rev, NULL);\n-\trev.ignore_merges = 1;\n+\tdiff_merges_suppress(&rev);\n \trev.commit_format = CMIT_FMT_MEDIUM;\n \n \tcommit->object.flags |= UNINTERESTING;\ndiff --git a/diff-merges.c b/diff-merges.c\nindex a3b732c34717..b150c0490b1d 100644\n--- a/diff-merges.c\n+++ b/diff-merges.c\n@@ -2,6 +2,13 @@\n \n #include \"revision.h\"\n \n+static void suppress(struct rev_info *revs) {\n+\trevs->ignore_merges = 1;\n+\trevs->first_parent_merges = 0;\n+\trevs->combine_merges = 0;\n+\trevs->dense_combined_merges = 0;\n+}\n+\n /*\n  * Public functions. They are in the order they are called.\n  */\n@@ -32,13 +39,13 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {\n \t\trevs->dense_combined_merges = 1;\n \t\trevs->combine_merges = 1;\n \t} else if (!strcmp(arg, \"--no-diff-merges\")) {\n-\t\trevs->ignore_merges = 1;\n+\t\tsuppress(revs);\n \t} else if (!strcmp(arg, \"--combined-all-paths\")) {\n \t\trevs->diff = 1;\n \t\trevs->combined_all_paths = 1;\n \t} else if ((argcount = parse_long_opt(\"diff-merges\", argv, &optarg))) {\n \t\tif (!strcmp(optarg, \"off\")) {\n-\t\t\trevs->ignore_merges = 1;\n+\t\t\tsuppress(revs);\n \t\t} else {\n \t\t\tdie(_(\"unknown value for --diff-merges: %s\"), optarg);\n \t\t}\n@@ -48,6 +55,10 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {\n \treturn argcount;\n }\n \n+void diff_merges_suppress(struct rev_info *revs) {\n+\tsuppress(revs);\n+}\n+\n void diff_merges_default_to_first_parent(struct rev_info *revs) {\n \tif (revs->ignore_merges < 0)\t\t/* No -m */\n \t\trevs->ignore_merges = 0;\ndiff --git a/diff-merges.h b/diff-merges.h\nindex 243ef915c4cd..a031240576f7 100644\n--- a/diff-merges.h\n+++ b/diff-merges.h\n@@ -13,6 +13,8 @@ void diff_merges_init_revs(struct rev_info *revs);\n \n int diff_merges_parse_opts(struct rev_info *revs, const char **argv);\n \n+void diff_merges_suppress(struct rev_info *revs);\n+\n void diff_merges_default_to_first_parent(struct rev_info *revs);\n \n void diff_merges_default_to_dense_combined(struct rev_info *revs);\ndiff --git a/fmt-merge-msg.c b/fmt-merge-msg.c\nindex bd22e1ea8865..abc3403fb820 100644\n--- a/fmt-merge-msg.c\n+++ b/fmt-merge-msg.c\n@@ -2,6 +2,7 @@\n #include \"refs.h\"\n #include \"object-store.h\"\n #include \"diff.h\"\n+#include \"diff-merges.h\"\n #include \"revision.h\"\n #include \"tag.h\"\n #include \"string-list.h\"\n@@ -668,7 +669,7 @@ int fmt_merge_msg(struct strbuf *in, struct strbuf *out,\n \t\thead = lookup_commit_or_die(&head_oid, \"HEAD\");\n \t\trepo_init_revisions(the_repository, &rev, NULL);\n \t\trev.commit_format = CMIT_FMT_ONELINE;\n-\t\trev.ignore_merges = 1;\n+\t\tdiff_merges_suppress(&rev);\n \t\trev.limited = 1;\n \n \t\tstrbuf_complete_line(out);\n-- \n2.25.1\n\n"},{"id":"412395","messageId":"20201216184929.3924-10-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201216184929.3924-1-sorganov@gmail.com","subject":"[PATCH v2 09/33] diff-merges: re-arrange functions to match the order they are called in","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-16T18:49:05Z","receivedAt":"2020-12-16T18:51:50Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"For clarity, define public functions in the order they are called, to\nmake logic inter-dependencies easier to grok.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n diff-merges.c | 24 ++++++++++++++----------\n diff-merges.h |  7 +++----\n 2 files changed, 17 insertions(+), 14 deletions(-)\n\ndiff --git a/diff-merges.c b/diff-merges.c\nindex 19b85bfdba6f..a3b732c34717 100644\n--- a/diff-merges.c\n+++ b/diff-merges.c\n@@ -2,6 +2,10 @@\n \n #include \"revision.h\"\n \n+/*\n+ * Public functions. They are in the order they are called.\n+ */\n+\n void diff_merges_init_revs(struct rev_info *revs) {\n \trevs->ignore_merges = -1;\n }\n@@ -44,16 +48,6 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {\n \treturn argcount;\n }\n \n-void diff_merges_setup_revs(struct rev_info *revs)\n-{\n-\tif (revs->combine_merges && revs->ignore_merges < 0)\n-\t\trevs->ignore_merges = 0;\n-\tif (revs->ignore_merges < 0)\n-\t\trevs->ignore_merges = 1;\n-\tif (revs->combined_all_paths && !revs->combine_merges)\n-\t\tdie(\"--combined-all-paths makes no sense without -c or --cc\");\n-}\n-\n void diff_merges_default_to_first_parent(struct rev_info *revs) {\n \tif (revs->ignore_merges < 0)\t\t/* No -m */\n \t\trevs->ignore_merges = 0;\n@@ -68,3 +62,13 @@ void diff_merges_default_to_dense_combined(struct rev_info *revs) {\n \t\t}\n \t}\n }\n+\n+void diff_merges_setup_revs(struct rev_info *revs)\n+{\n+\tif (revs->combine_merges && revs->ignore_merges < 0)\n+\t\trevs->ignore_merges = 0;\n+\tif (revs->ignore_merges < 0)\n+\t\trevs->ignore_merges = 1;\n+\tif (revs->combined_all_paths && !revs->combine_merges)\n+\t\tdie(\"--combined-all-paths makes no sense without -c or --cc\");\n+}\ndiff --git a/diff-merges.h b/diff-merges.h\nindex 18861dc5480e..243ef915c4cd 100644\n--- a/diff-merges.h\n+++ b/diff-merges.h\n@@ -13,11 +13,10 @@ void diff_merges_init_revs(struct rev_info *revs);\n \n int diff_merges_parse_opts(struct rev_info *revs, const char **argv);\n \n-void diff_merges_setup_revs(struct rev_info *revs);\n-\n-void diff_merges_default_to_dense_combined(struct rev_info *revs);\n-\n void diff_merges_default_to_first_parent(struct rev_info *revs);\n \n+void diff_merges_default_to_dense_combined(struct rev_info *revs);\n+\n+void diff_merges_setup_revs(struct rev_info *revs);\n \n #endif\n-- \n2.25.1\n\n"},{"id":"412396","messageId":"20201216184929.3924-12-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201216184929.3924-1-sorganov@gmail.com","subject":"[PATCH v2 11/33] diff-merges: new function diff_merges_set_dense_combined_if_unset()","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-16T18:49:07Z","receivedAt":"2020-12-16T18:51:52Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Call it where given functionality is needed instead of direct\nchecking/tweaking of diff merges related fields.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n builtin/diff-files.c |  5 +++--\n builtin/diff.c       |  9 +++++----\n diff-merges.c        | 14 ++++++++++++--\n diff-merges.h        |  2 ++\n 4 files changed, 22 insertions(+), 8 deletions(-)\n\ndiff --git a/builtin/diff-files.c b/builtin/diff-files.c\nindex 1e352dd8f77c..4742a4559b21 100644\n--- a/builtin/diff-files.c\n+++ b/builtin/diff-files.c\n@@ -7,6 +7,7 @@\n #include \"cache.h\"\n #include \"config.h\"\n #include \"diff.h\"\n+#include \"diff-merges.h\"\n #include \"commit.h\"\n #include \"revision.h\"\n #include \"builtin.h\"\n@@ -69,9 +70,9 @@ int cmd_diff_files(int argc, const char **argv, const char *prefix)\n \t * was not asked to.  \"diff-files -c -p\" should not densify\n \t * (the user should ask with \"diff-files --cc\" explicitly).\n \t */\n-\tif (rev.max_count == -1 && !rev.combine_merges &&\n+\tif (rev.max_count == -1 &&\n \t    (rev.diffopt.output_format & DIFF_FORMAT_PATCH))\n-\t\trev.combine_merges = rev.dense_combined_merges = 1;\n+\t\tdiff_merges_set_dense_combined_if_unset(&rev);\n \n \tif (read_cache_preload(&rev.diffopt.pathspec) < 0) {\n \t\tperror(\"read_cache_preload\");\ndiff --git a/builtin/diff.c b/builtin/diff.c\nindex cd4083fed96e..2f570a3131cb 100644\n--- a/builtin/diff.c\n+++ b/builtin/diff.c\n@@ -13,6 +13,7 @@\n #include \"blob.h\"\n #include \"tag.h\"\n #include \"diff.h\"\n+#include \"diff-merges.h\"\n #include \"diffcore.h\"\n #include \"revision.h\"\n #include \"log-tree.h\"\n@@ -199,8 +200,8 @@ static int builtin_diff_combined(struct rev_info *revs,\n \tif (argc > 1)\n \t\tusage(builtin_diff_usage);\n \n-\tif (!revs->dense_combined_merges && !revs->combine_merges)\n-\t\trevs->dense_combined_merges = revs->combine_merges = 1;\n+\tdiff_merges_set_dense_combined_if_unset(revs);\n+\n \tfor (i = 1; i < ents; i++)\n \t\toid_array_append(&parents, &ent[i].item->oid);\n \tdiff_tree_combined(&ent[0].item->oid, &parents, revs);\n@@ -248,9 +249,9 @@ static int builtin_diff_files(struct rev_info *revs, int argc, const char **argv\n \t * dense one, --cc can be explicitly asked for, or just rely\n \t * on the default).\n \t */\n-\tif (revs->max_count == -1 && !revs->combine_merges &&\n+\tif (revs->max_count == -1 &&\n \t    (revs->diffopt.output_format & DIFF_FORMAT_PATCH))\n-\t\trevs->combine_merges = revs->dense_combined_merges = 1;\n+\t\tdiff_merges_set_dense_combined_if_unset(revs);\n \n \tsetup_work_tree();\n \tif (read_cache_preload(&revs->diffopt.pathspec) < 0) {\ndiff --git a/diff-merges.c b/diff-merges.c\nindex b150c0490b1d..899f9e905d3c 100644\n--- a/diff-merges.c\n+++ b/diff-merges.c\n@@ -9,6 +9,12 @@ static void suppress(struct rev_info *revs) {\n \trevs->dense_combined_merges = 0;\n }\n \n+static void set_dense_combined(struct rev_info *revs) {\n+\trevs->combine_merges = 1;\n+\trevs->dense_combined_merges = 1;\n+}\n+\n+\n /*\n  * Public functions. They are in the order they are called.\n  */\n@@ -36,8 +42,7 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {\n \t\trevs->combine_merges = 1;\n \t} else if (!strcmp(arg, \"--cc\")) {\n \t\trevs->diff = 1;\n-\t\trevs->dense_combined_merges = 1;\n-\t\trevs->combine_merges = 1;\n+\t\tset_dense_combined(revs);\n \t} else if (!strcmp(arg, \"--no-diff-merges\")) {\n \t\tsuppress(revs);\n \t} else if (!strcmp(arg, \"--combined-all-paths\")) {\n@@ -74,6 +79,11 @@ void diff_merges_default_to_dense_combined(struct rev_info *revs) {\n \t}\n }\n \n+void diff_merges_set_dense_combined_if_unset(struct rev_info *revs) {\n+\tif (!revs->combine_merges)\n+\t\tset_dense_combined(revs);\n+}\n+\n void diff_merges_setup_revs(struct rev_info *revs)\n {\n \tif (revs->combine_merges && revs->ignore_merges < 0)\ndiff --git a/diff-merges.h b/diff-merges.h\nindex a031240576f7..f92de137d3a0 100644\n--- a/diff-merges.h\n+++ b/diff-merges.h\n@@ -19,6 +19,8 @@ void diff_merges_default_to_first_parent(struct rev_info *revs);\n \n void diff_merges_default_to_dense_combined(struct rev_info *revs);\n \n+void diff_merges_set_dense_combined_if_unset(struct rev_info *revs);\n+\n void diff_merges_setup_revs(struct rev_info *revs);\n \n #endif\n-- \n2.25.1\n\n"},{"id":"412397","messageId":"20201216184929.3924-14-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201216184929.3924-1-sorganov@gmail.com","subject":"[PATCH v2 13/33] diff-merges: revise revs->diff flag handling","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-16T18:49:09Z","receivedAt":"2020-12-16T18:51:53Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Do not set revs->diff when we encounter an option that needs it, as\nit'd be impossible to undo later. Besides, some other options than\nwhat we handle here set this flag as well, and we'd interfere with\nthem trying to clear this flag later.\n\nRather set revs->diff, if finally needed, in diff_merges_setup_revs().\n\nAs an additional bonus, this also makes our code shorter.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n diff-merges.c | 5 ++---\n 1 file changed, 2 insertions(+), 3 deletions(-)\n\ndiff --git a/diff-merges.c b/diff-merges.c\nindex c99d77a318dc..76ddbc37bd59 100644\n--- a/diff-merges.c\n+++ b/diff-merges.c\n@@ -37,16 +37,13 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {\n \t\trevs->ignore_merges = 0;\n \t\trevs->match_missing = 1;\n \t} else if (!strcmp(arg, \"-c\")) {\n-\t\trevs->diff = 1;\n \t\trevs->dense_combined_merges = 0;\n \t\trevs->combine_merges = 1;\n \t} else if (!strcmp(arg, \"--cc\")) {\n-\t\trevs->diff = 1;\n \t\tset_dense_combined(revs);\n \t} else if (!strcmp(arg, \"--no-diff-merges\")) {\n \t\tsuppress(revs);\n \t} else if (!strcmp(arg, \"--combined-all-paths\")) {\n-\t\trevs->diff = 1;\n \t\trevs->combined_all_paths = 1;\n \t} else if ((argcount = parse_long_opt(\"diff-merges\", argv, &optarg))) {\n \t\tif (!strcmp(optarg, \"off\")) {\n@@ -94,4 +91,6 @@ void diff_merges_setup_revs(struct rev_info *revs)\n \t\trevs->ignore_merges = 1;\n \tif (revs->combined_all_paths && !revs->combine_merges)\n \t\tdie(\"--combined-all-paths makes no sense without -c or --cc\");\n+\tif (revs->combine_merges)\n+\t\trevs->diff = 1;\n }\n-- \n2.25.1\n\n"},{"id":"412398","messageId":"20201216184929.3924-13-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201216184929.3924-1-sorganov@gmail.com","subject":"[PATCH v2 12/33] diff-merges: introduce revs->first_parent_merges flag","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-16T18:49:08Z","receivedAt":"2020-12-16T18:51:54Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"This new field allows us to separate format of diff for merges from\n'first_parent_only' flag which primary purpose is limiting history\ntraversal.\n\nThis change further localizes diff format selection logic into the\ndiff-merges.c file.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n diff-merges.c | 2 ++\n log-tree.c    | 4 ++--\n revision.h    | 1 +\n 3 files changed, 5 insertions(+), 2 deletions(-)\n\ndiff --git a/diff-merges.c b/diff-merges.c\nindex 899f9e905d3c..c99d77a318dc 100644\n--- a/diff-merges.c\n+++ b/diff-merges.c\n@@ -67,6 +67,8 @@ void diff_merges_suppress(struct rev_info *revs) {\n void diff_merges_default_to_first_parent(struct rev_info *revs) {\n \tif (revs->ignore_merges < 0)\t\t/* No -m */\n \t\trevs->ignore_merges = 0;\n+\tif (!revs->combine_merges)\t\t/* No -c/--cc\" */\n+\t\trevs->first_parent_merges = 1;\n }\n \n void diff_merges_default_to_dense_combined(struct rev_info *revs) {\ndiff --git a/log-tree.c b/log-tree.c\nindex 1927f917ce94..3fdc0fc64bfb 100644\n--- a/log-tree.c\n+++ b/log-tree.c\n@@ -922,7 +922,7 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log\n \t\t\treturn 0;\n \t\telse if (opt->combine_merges)\n \t\t\treturn do_diff_combined(opt, commit);\n-\t\telse if (!opt->first_parent_only) {\n+\t\telse if (!opt->first_parent_merges) {\n \t\t\t/* If we show multiple diffs, show the parent info */\n \t\t\tlog->parent = parents->item;\n \t\t}\n@@ -941,7 +941,7 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log\n \n \t\t/* Set up the log info for the next parent, if any.. */\n \t\tparents = parents->next;\n-\t\tif (!parents || opt->first_parent_only)\n+\t\tif (!parents || opt->first_parent_merges)\n \t\t\tbreak;\n \t\tlog->parent = parents->item;\n \t\topt->loginfo = log;\ndiff --git a/revision.h b/revision.h\nindex f6bf860d19e5..ba2aef79215e 100644\n--- a/revision.h\n+++ b/revision.h\n@@ -194,6 +194,7 @@ struct rev_info {\n \t\t\tcombine_merges:1,\n \t\t\tcombined_all_paths:1,\n \t\t\tdense_combined_merges:1,\n+\t\t\tfirst_parent_merges:1,\n \t\t\talways_show_header:1;\n \tint             ignore_merges:2;\n \n-- \n2.25.1\n\n"},{"id":"412399","messageId":"20201216184929.3924-15-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201216184929.3924-1-sorganov@gmail.com","subject":"[PATCH v2 14/33] t4013: support test_expect_failure through ':failure' magic","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-16T18:49:10Z","receivedAt":"2020-12-16T18:51:55Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Add support to be able to specify expected failure, through :failure\nmagic, like this:\n\n:failure cmd args\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n t/t4013-diff-various.sh | 7 ++++++-\n 1 file changed, 6 insertions(+), 1 deletion(-)\n\ndiff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh\nindex 5c7b0122b4f1..935d10ac0572 100755\n--- a/t/t4013-diff-various.sh\n+++ b/t/t4013-diff-various.sh\n@@ -174,6 +174,7 @@ process_diffs () {\n V=$(git version | sed -e 's/^git version //' -e 's/\\./\\\\./g')\n while read magic cmd\n do\n+\tstatus=success\n \tcase \"$magic\" in\n \t'' | '#'*)\n \t\tcontinue ;;\n@@ -182,6 +183,10 @@ do\n \t\tlabel=\"$magic-$cmd\"\n \t\tcase \"$magic\" in\n \t\tnoellipses) ;;\n+\t\tfailure)\n+\t\t\tstatus=failure\n+\t\t\tmagic=\n+\t\t\tlabel=\"$cmd\" ;;\n \t\t*)\n \t\t\tBUG \"unknown magic $magic\" ;;\n \t\tesac ;;\n@@ -194,7 +199,7 @@ do\n \texpect=\"$TEST_DIRECTORY/t4013/diff.$test\"\n \tactual=\"$pfx-diff.$test\"\n \n-\ttest_expect_success \"git $cmd # magic is ${magic:-(not used)}\" '\n+\ttest_expect_$status \"git $cmd # magic is ${magic:-(not used)}\" '\n \t\t{\n \t\t\techo \"$ git $cmd\"\n \t\t\tcase \"$magic\" in\n-- \n2.25.1\n\n"},{"id":"412400","messageId":"20201216184929.3924-16-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201216184929.3924-1-sorganov@gmail.com","subject":"[PATCH v2 15/33] t4013: add tests for -m failing to override -c/--cc","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-16T18:49:11Z","receivedAt":"2020-12-16T18:52:01Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Logically, -m, -c, --cc specify 3 different formats for representing\nmerge commits, yet -m doesn't in fact override -c or --cc, that makes\nno sense.\n\nAdd 2 expected to fail tests that demonstrate the problem.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n t/t4013-diff-various.sh            |   2 +\n t/t4013/diff.log_--cc_-m_-p_master | 200 +++++++++++++++++++++++++++++\n t/t4013/diff.log_-c_-m_-p_master   | 200 +++++++++++++++++++++++++++++\n 3 files changed, 402 insertions(+)\n create mode 100644 t/t4013/diff.log_--cc_-m_-p_master\n create mode 100644 t/t4013/diff.log_-c_-m_-p_master\n\ndiff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh\nindex 935d10ac0572..64d9fce44614 100755\n--- a/t/t4013-diff-various.sh\n+++ b/t/t4013-diff-various.sh\n@@ -329,6 +329,8 @@ log --first-parent --diff-merges=off -p master\n log -p --first-parent master\n log -m -p --first-parent master\n log -m -p master\n+:failure log --cc -m -p master\n+:failure log -c -m -p master\n log -SF master\n log -S F master\n log -SF -p master\ndiff --git a/t/t4013/diff.log_--cc_-m_-p_master b/t/t4013/diff.log_--cc_-m_-p_master\nnew file mode 100644\nindex 000000000000..7c217cf348c7\n--- /dev/null\n+++ b/t/t4013/diff.log_--cc_-m_-p_master\n@@ -0,0 +1,200 @@\n+$ git log --cc -m -p master\n+commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (from 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0)\n+Merge: 9a6d494 c7a2ab9\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:04:00 2006 +0000\n+\n+    Merge branch 'side'\n+\n+diff --git a/dir/sub b/dir/sub\n+index cead32e..992913c 100644\n+--- a/dir/sub\n++++ b/dir/sub\n+@@ -4,3 +4,5 @@ C\n+ D\n+ E\n+ F\n++1\n++2\n+diff --git a/file0 b/file0\n+index b414108..10a8a9f 100644\n+--- a/file0\n++++ b/file0\n+@@ -4,3 +4,6 @@\n+ 4\n+ 5\n+ 6\n++A\n++B\n++C\n+\n+commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (from c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a)\n+Merge: 9a6d494 c7a2ab9\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:04:00 2006 +0000\n+\n+    Merge branch 'side'\n+\n+diff --git a/dir/sub b/dir/sub\n+index 7289e35..992913c 100644\n+--- a/dir/sub\n++++ b/dir/sub\n+@@ -1,4 +1,8 @@\n+ A\n+ B\n++C\n++D\n++E\n++F\n+ 1\n+ 2\n+diff --git a/file0 b/file0\n+index f4615da..10a8a9f 100644\n+--- a/file0\n++++ b/file0\n+@@ -1,6 +1,9 @@\n+ 1\n+ 2\n+ 3\n++4\n++5\n++6\n+ A\n+ B\n+ C\n+diff --git a/file1 b/file1\n+new file mode 100644\n+index 0000000..b1e6722\n+--- /dev/null\n++++ b/file1\n+@@ -0,0 +1,3 @@\n++A\n++B\n++C\n+diff --git a/file2 b/file2\n+deleted file mode 100644\n+index 01e79c3..0000000\n+--- a/file2\n++++ /dev/null\n+@@ -1,3 +0,0 @@\n+-1\n+-2\n+-3\n+diff --git a/file3 b/file3\n+deleted file mode 100644\n+index 7289e35..0000000\n+--- a/file3\n++++ /dev/null\n+@@ -1,4 +0,0 @@\n+-A\n+-B\n+-1\n+-2\n+\n+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:03:00 2006 +0000\n+\n+    Side\n+\n+diff --git a/dir/sub b/dir/sub\n+index 35d242b..7289e35 100644\n+--- a/dir/sub\n++++ b/dir/sub\n+@@ -1,2 +1,4 @@\n+ A\n+ B\n++1\n++2\n+diff --git a/file0 b/file0\n+index 01e79c3..f4615da 100644\n+--- a/file0\n++++ b/file0\n+@@ -1,3 +1,6 @@\n+ 1\n+ 2\n+ 3\n++A\n++B\n++C\n+diff --git a/file3 b/file3\n+new file mode 100644\n+index 0000000..7289e35\n+--- /dev/null\n++++ b/file3\n+@@ -0,0 +1,4 @@\n++A\n++B\n++1\n++2\n+\n+commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:02:00 2006 +0000\n+\n+    Third\n+\n+diff --git a/dir/sub b/dir/sub\n+index 8422d40..cead32e 100644\n+--- a/dir/sub\n++++ b/dir/sub\n+@@ -2,3 +2,5 @@ A\n+ B\n+ C\n+ D\n++E\n++F\n+diff --git a/file1 b/file1\n+new file mode 100644\n+index 0000000..b1e6722\n+--- /dev/null\n++++ b/file1\n+@@ -0,0 +1,3 @@\n++A\n++B\n++C\n+\n+commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:01:00 2006 +0000\n+\n+    Second\n+    \n+    This is the second commit.\n+\n+diff --git a/dir/sub b/dir/sub\n+index 35d242b..8422d40 100644\n+--- a/dir/sub\n++++ b/dir/sub\n+@@ -1,2 +1,4 @@\n+ A\n+ B\n++C\n++D\n+diff --git a/file0 b/file0\n+index 01e79c3..b414108 100644\n+--- a/file0\n++++ b/file0\n+@@ -1,3 +1,6 @@\n+ 1\n+ 2\n+ 3\n++4\n++5\n++6\n+diff --git a/file2 b/file2\n+deleted file mode 100644\n+index 01e79c3..0000000\n+--- a/file2\n++++ /dev/null\n+@@ -1,3 +0,0 @@\n+-1\n+-2\n+-3\n+\n+commit 444ac553ac7612cc88969031b02b3767fb8a353a\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:00:00 2006 +0000\n+\n+    Initial\n+$\ndiff --git a/t/t4013/diff.log_-c_-m_-p_master b/t/t4013/diff.log_-c_-m_-p_master\nnew file mode 100644\nindex 000000000000..b660f3d5f28e\n--- /dev/null\n+++ b/t/t4013/diff.log_-c_-m_-p_master\n@@ -0,0 +1,200 @@\n+$ git log -c -m -p master\n+commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (from 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0)\n+Merge: 9a6d494 c7a2ab9\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:04:00 2006 +0000\n+\n+    Merge branch 'side'\n+\n+diff --git a/dir/sub b/dir/sub\n+index cead32e..992913c 100644\n+--- a/dir/sub\n++++ b/dir/sub\n+@@ -4,3 +4,5 @@ C\n+ D\n+ E\n+ F\n++1\n++2\n+diff --git a/file0 b/file0\n+index b414108..10a8a9f 100644\n+--- a/file0\n++++ b/file0\n+@@ -4,3 +4,6 @@\n+ 4\n+ 5\n+ 6\n++A\n++B\n++C\n+\n+commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (from c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a)\n+Merge: 9a6d494 c7a2ab9\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:04:00 2006 +0000\n+\n+    Merge branch 'side'\n+\n+diff --git a/dir/sub b/dir/sub\n+index 7289e35..992913c 100644\n+--- a/dir/sub\n++++ b/dir/sub\n+@@ -1,4 +1,8 @@\n+ A\n+ B\n++C\n++D\n++E\n++F\n+ 1\n+ 2\n+diff --git a/file0 b/file0\n+index f4615da..10a8a9f 100644\n+--- a/file0\n++++ b/file0\n+@@ -1,6 +1,9 @@\n+ 1\n+ 2\n+ 3\n++4\n++5\n++6\n+ A\n+ B\n+ C\n+diff --git a/file1 b/file1\n+new file mode 100644\n+index 0000000..b1e6722\n+--- /dev/null\n++++ b/file1\n+@@ -0,0 +1,3 @@\n++A\n++B\n++C\n+diff --git a/file2 b/file2\n+deleted file mode 100644\n+index 01e79c3..0000000\n+--- a/file2\n++++ /dev/null\n+@@ -1,3 +0,0 @@\n+-1\n+-2\n+-3\n+diff --git a/file3 b/file3\n+deleted file mode 100644\n+index 7289e35..0000000\n+--- a/file3\n++++ /dev/null\n+@@ -1,4 +0,0 @@\n+-A\n+-B\n+-1\n+-2\n+\n+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:03:00 2006 +0000\n+\n+    Side\n+\n+diff --git a/dir/sub b/dir/sub\n+index 35d242b..7289e35 100644\n+--- a/dir/sub\n++++ b/dir/sub\n+@@ -1,2 +1,4 @@\n+ A\n+ B\n++1\n++2\n+diff --git a/file0 b/file0\n+index 01e79c3..f4615da 100644\n+--- a/file0\n++++ b/file0\n+@@ -1,3 +1,6 @@\n+ 1\n+ 2\n+ 3\n++A\n++B\n++C\n+diff --git a/file3 b/file3\n+new file mode 100644\n+index 0000000..7289e35\n+--- /dev/null\n++++ b/file3\n+@@ -0,0 +1,4 @@\n++A\n++B\n++1\n++2\n+\n+commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:02:00 2006 +0000\n+\n+    Third\n+\n+diff --git a/dir/sub b/dir/sub\n+index 8422d40..cead32e 100644\n+--- a/dir/sub\n++++ b/dir/sub\n+@@ -2,3 +2,5 @@ A\n+ B\n+ C\n+ D\n++E\n++F\n+diff --git a/file1 b/file1\n+new file mode 100644\n+index 0000000..b1e6722\n+--- /dev/null\n++++ b/file1\n+@@ -0,0 +1,3 @@\n++A\n++B\n++C\n+\n+commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:01:00 2006 +0000\n+\n+    Second\n+    \n+    This is the second commit.\n+\n+diff --git a/dir/sub b/dir/sub\n+index 35d242b..8422d40 100644\n+--- a/dir/sub\n++++ b/dir/sub\n+@@ -1,2 +1,4 @@\n+ A\n+ B\n++C\n++D\n+diff --git a/file0 b/file0\n+index 01e79c3..b414108 100644\n+--- a/file0\n++++ b/file0\n+@@ -1,3 +1,6 @@\n+ 1\n+ 2\n+ 3\n++4\n++5\n++6\n+diff --git a/file2 b/file2\n+deleted file mode 100644\n+index 01e79c3..0000000\n+--- a/file2\n++++ /dev/null\n+@@ -1,3 +0,0 @@\n+-1\n+-2\n+-3\n+\n+commit 444ac553ac7612cc88969031b02b3767fb8a353a\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:00:00 2006 +0000\n+\n+    Initial\n+$\n-- \n2.25.1\n\n"},{"id":"412401","messageId":"20201216184929.3924-17-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201216184929.3924-1-sorganov@gmail.com","subject":"[PATCH v2 16/33] diff-merges: fix -m to properly override -c/--cc","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-16T18:49:12Z","receivedAt":"2020-12-16T18:52:02Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Logically, -m, -c, --cc specify 3 different formats for representing\nmerge commits, yet -m doesn't in fact override -c or --cc, that makes\nno sense.\n\nFix -m to properly override -c/--cc, and change the tests accordingly.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n diff-merges.c           | 1 +\n t/t4013-diff-various.sh | 4 ++--\n 2 files changed, 3 insertions(+), 2 deletions(-)\n\ndiff --git a/diff-merges.c b/diff-merges.c\nindex 76ddbc37bd59..5d20e329a661 100644\n--- a/diff-merges.c\n+++ b/diff-merges.c\n@@ -29,6 +29,7 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {\n \tconst char *arg = argv[0];\n \n \tif (!strcmp(arg, \"-m\")) {\n+\t\tsuppress(revs);\n \t\t/*\n \t\t * To \"diff-index\", \"-m\" means \"match missing\", and to the \"log\"\n \t\t * family of commands, it means \"show full diff for merges\". Set\ndiff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh\nindex 64d9fce44614..8d8178a8a616 100755\n--- a/t/t4013-diff-various.sh\n+++ b/t/t4013-diff-various.sh\n@@ -329,8 +329,8 @@ log --first-parent --diff-merges=off -p master\n log -p --first-parent master\n log -m -p --first-parent master\n log -m -p master\n-:failure log --cc -m -p master\n-:failure log -c -m -p master\n+log --cc -m -p master\n+log -c -m -p master\n log -SF master\n log -S F master\n log -SF -p master\n-- \n2.25.1\n\n"},{"id":"412402","messageId":"20201216184929.3924-21-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201216184929.3924-1-sorganov@gmail.com","subject":"[PATCH v2 20/33] diff-merges: refactor opt settings into separate functions","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-16T18:49:16Z","receivedAt":"2020-12-16T18:52:03Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"To prepare introduction of new options some of which will be synonyms\nto existing options, let every option handling code just call\ncorresponding function.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n diff-merges.c | 59 ++++++++++++++++++++++++++++++++-------------------\n 1 file changed, 37 insertions(+), 22 deletions(-)\n\ndiff --git a/diff-merges.c b/diff-merges.c\nindex 9ff6ea02edb8..4c434e914c8d 100644\n--- a/diff-merges.c\n+++ b/diff-merges.c\n@@ -9,11 +9,38 @@ static void suppress(struct rev_info *revs) {\n \trevs->dense_combined_merges = 0;\n }\n \n+static void set_separate(struct rev_info *revs) {\n+\tsuppress(revs);\n+\trevs->separate_merges = 1;\n+}\n+\n+static void set_m(struct rev_info *revs) {\n+\t/*\n+\t * To \"diff-index\", \"-m\" means \"match missing\", and to the \"log\"\n+\t * family of commands, it means \"show full diff for merges\". Set\n+\t * both fields appropriately.\n+\t */\n+\tset_separate(revs);\n+\trevs->match_missing = 1;\n+}\n+\n+static void set_combined(struct rev_info *revs) {\n+\trevs->combine_merges = 1;\n+\trevs->dense_combined_merges = 0;\n+}\n+\n static void set_dense_combined(struct rev_info *revs) {\n \trevs->combine_merges = 1;\n \trevs->dense_combined_merges = 1;\n }\n \n+static void set_diff_merges(struct rev_info *revs, const char *optarg) {\n+\tif (!strcmp(optarg, \"off\")) {\n+\t\tsuppress(revs);\n+\t} else {\n+\t\tdie(_(\"unknown value for --diff-merges: %s\"), optarg);\n+\t}\n+}\n \n /*\n  * Public functions. They are in the order they are called.\n@@ -24,31 +51,19 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {\n \tconst char *optarg;\n \tconst char *arg = argv[0];\n \n-\tif (!strcmp(arg, \"-m\")) {\n-\t\tsuppress(revs);\n-\t\t/*\n-\t\t * To \"diff-index\", \"-m\" means \"match missing\", and to the \"log\"\n-\t\t * family of commands, it means \"show full diff for merges\". Set\n-\t\t * both fields appropriately.\n-\t\t */\n-\t\trevs->separate_merges = 1;\n-\t\trevs->match_missing = 1;\n-\t} else if (!strcmp(arg, \"-c\")) {\n-\t\trevs->dense_combined_merges = 0;\n-\t\trevs->combine_merges = 1;\n-\t} else if (!strcmp(arg, \"--cc\")) {\n+\tif (!strcmp(arg, \"-m\"))\n+\t\tset_m(revs);\n+\telse if (!strcmp(arg, \"-c\"))\n+\t\tset_combined(revs);\n+\telse if (!strcmp(arg, \"--cc\"))\n \t\tset_dense_combined(revs);\n-\t} else if (!strcmp(arg, \"--no-diff-merges\")) {\n+\telse if (!strcmp(arg, \"--no-diff-merges\"))\n \t\tsuppress(revs);\n-\t} else if (!strcmp(arg, \"--combined-all-paths\")) {\n+\telse if (!strcmp(arg, \"--combined-all-paths\"))\n \t\trevs->combined_all_paths = 1;\n-\t} else if ((argcount = parse_long_opt(\"diff-merges\", argv, &optarg))) {\n-\t\tif (!strcmp(optarg, \"off\")) {\n-\t\t\tsuppress(revs);\n-\t\t} else {\n-\t\t\tdie(_(\"unknown value for --diff-merges: %s\"), optarg);\n-\t\t}\n-\t} else\n+\telse if ((argcount = parse_long_opt(\"diff-merges\", argv, &optarg)))\n+\t\tset_diff_merges(revs, optarg);\n+\telse\n \t\treturn 0;\n \n \trevs->explicit_diff_merges = 1;\n-- \n2.25.1\n\n"},{"id":"412403","messageId":"20201216184929.3924-20-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201216184929.3924-1-sorganov@gmail.com","subject":"[PATCH v2 19/33] diff-merges: get rid of now empty diff_merges_init_revs()","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-16T18:49:15Z","receivedAt":"2020-12-16T18:52:04Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"After getting rid of 'ignore_merges' field, the diff_merges_init_revs()\nfunction became empty. Get rid of it.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n diff-merges.c | 3 ---\n diff-merges.h | 2 --\n revision.c    | 1 -\n 3 files changed, 6 deletions(-)\n\ndiff --git a/diff-merges.c b/diff-merges.c\nindex 711df9975dd5..9ff6ea02edb8 100644\n--- a/diff-merges.c\n+++ b/diff-merges.c\n@@ -19,9 +19,6 @@ static void set_dense_combined(struct rev_info *revs) {\n  * Public functions. They are in the order they are called.\n  */\n \n-void diff_merges_init_revs(struct rev_info *revs) {\n-}\n-\n int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {\n \tint argcount = 1;\n \tconst char *optarg;\ndiff --git a/diff-merges.h b/diff-merges.h\nindex f92de137d3a0..659467c99a4f 100644\n--- a/diff-merges.h\n+++ b/diff-merges.h\n@@ -9,8 +9,6 @@\n \n struct rev_info;\n \n-void diff_merges_init_revs(struct rev_info *revs);\n-\n int diff_merges_parse_opts(struct rev_info *revs, const char **argv);\n \n void diff_merges_suppress(struct rev_info *revs);\ndiff --git a/revision.c b/revision.c\nindex 5a0e3d6ad542..46645ca0b6df 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -1814,7 +1814,6 @@ void repo_init_revisions(struct repository *r,\n \n \trevs->repo = r;\n \trevs->abbrev = DEFAULT_ABBREV;\n-\tdiff_merges_init_revs(revs);\n \trevs->simplify_history = 1;\n \trevs->pruning.repo = r;\n \trevs->pruning.flags.recursive = 1;\n-- \n2.25.1\n\n"},{"id":"412404","messageId":"20201216184929.3924-24-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201216184929.3924-1-sorganov@gmail.com","subject":"[PATCH v2 23/33] diff-merges: fix style of functions definitions","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-16T18:49:19Z","receivedAt":"2020-12-16T18:52:05Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Put open curly brace on its own line\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n diff-merges.c | 36 ++++++++++++++++++++++++------------\n 1 file changed, 24 insertions(+), 12 deletions(-)\n\ndiff --git a/diff-merges.c b/diff-merges.c\nindex cba391604ac7..0165fa22fcd1 100644\n--- a/diff-merges.c\n+++ b/diff-merges.c\n@@ -2,7 +2,8 @@\n \n #include \"revision.h\"\n \n-static void suppress(struct rev_info *revs) {\n+static void suppress(struct rev_info *revs)\n+{\n \trevs->separate_merges = 0;\n \trevs->first_parent_merges = 0;\n \trevs->combine_merges = 0;\n@@ -10,17 +11,20 @@ static void suppress(struct rev_info *revs) {\n \trevs->combined_all_paths = 0;\n }\n \n-static void set_separate(struct rev_info *revs) {\n+static void set_separate(struct rev_info *revs)\n+{\n \tsuppress(revs);\n \trevs->separate_merges = 1;\n }\n \n-static void set_first_parent(struct rev_info *revs) {\n+static void set_first_parent(struct rev_info *revs)\n+{\n \tset_separate(revs);\n \trevs->first_parent_merges = 1;\n }\n \n-static void set_m(struct rev_info *revs) {\n+static void set_m(struct rev_info *revs)\n+{\n \t/*\n \t * To \"diff-index\", \"-m\" means \"match missing\", and to the \"log\"\n \t * family of commands, it means \"show full diff for merges\". Set\n@@ -30,19 +34,22 @@ static void set_m(struct rev_info *revs) {\n \trevs->match_missing = 1;\n }\n \n-static void set_combined(struct rev_info *revs) {\n+static void set_combined(struct rev_info *revs)\n+{\n \tsuppress(revs);\n \trevs->combine_merges = 1;\n \trevs->dense_combined_merges = 0;\n }\n \n-static void set_dense_combined(struct rev_info *revs) {\n+static void set_dense_combined(struct rev_info *revs)\n+{\n \tsuppress(revs);\n \trevs->combine_merges = 1;\n \trevs->dense_combined_merges = 1;\n }\n \n-static void set_diff_merges(struct rev_info *revs, const char *optarg) {\n+static void set_diff_merges(struct rev_info *revs, const char *optarg)\n+{\n \tif (0) ;\n \telse if (!strcmp(optarg, \"off\")   || !strcmp(optarg, \"none\"))\n \t\tsuppress(revs);\n@@ -62,7 +69,8 @@ static void set_diff_merges(struct rev_info *revs, const char *optarg) {\n  * Public functions. They are in the order they are called.\n  */\n \n-int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {\n+int diff_merges_parse_opts(struct rev_info *revs, const char **argv)\n+{\n \tint argcount = 1;\n \tconst char *optarg;\n \tconst char *arg = argv[0];\n@@ -86,23 +94,27 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {\n \treturn argcount;\n }\n \n-void diff_merges_suppress(struct rev_info *revs) {\n+void diff_merges_suppress(struct rev_info *revs)\n+{\n \tsuppress(revs);\n }\n \n-void diff_merges_default_to_first_parent(struct rev_info *revs) {\n+void diff_merges_default_to_first_parent(struct rev_info *revs)\n+{\n \tif (!revs->explicit_diff_merges)\n \t\trevs->separate_merges = 1;\n \tif (revs->separate_merges)\n \t\trevs->first_parent_merges = 1;\n }\n \n-void diff_merges_default_to_dense_combined(struct rev_info *revs) {\n+void diff_merges_default_to_dense_combined(struct rev_info *revs)\n+{\n \tif (!revs->explicit_diff_merges)\n \t\tset_dense_combined(revs);\n }\n \n-void diff_merges_set_dense_combined_if_unset(struct rev_info *revs) {\n+void diff_merges_set_dense_combined_if_unset(struct rev_info *revs)\n+{\n \tif (!revs->combine_merges)\n \t\tset_dense_combined(revs);\n }\n-- \n2.25.1\n\n"},{"id":"412405","messageId":"20201216184929.3924-25-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201216184929.3924-1-sorganov@gmail.com","subject":"[PATCH v2 24/33] diff-merges: handle imply -p on -c/--cc logic for log.c","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-16T18:49:20Z","receivedAt":"2020-12-16T18:52:06Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Move logic that handles implying -p on -c/--cc from\nlog_setup_revisions_tweak() to diff_merges_setup_revs(), where it\nbelongs.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n builtin/log.c | 4 ----\n diff-merges.c | 7 ++++++-\n 2 files changed, 6 insertions(+), 5 deletions(-)\n\ndiff --git a/builtin/log.c b/builtin/log.c\nindex 63875c3aeec9..c3caf0955b2b 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -723,10 +723,6 @@ static void log_setup_revisions_tweak(struct rev_info *rev,\n \t    rev->prune_data.nr == 1)\n \t\trev->diffopt.flags.follow_renames = 1;\n \n-\t/* Turn --cc/-c into -p --cc/-c when -p was not given */\n-\tif (!rev->diffopt.output_format && rev->combine_merges)\n-\t\trev->diffopt.output_format = DIFF_FORMAT_PATCH;\n-\n \tif (rev->first_parent_only)\n \t\tdiff_merges_default_to_first_parent(rev);\n }\ndiff --git a/diff-merges.c b/diff-merges.c\nindex 0165fa22fcd1..2ac25488d53e 100644\n--- a/diff-merges.c\n+++ b/diff-merges.c\n@@ -127,6 +127,11 @@ void diff_merges_setup_revs(struct rev_info *revs)\n \t\trevs->first_parent_merges = 0;\n \tif (revs->combined_all_paths && !revs->combine_merges)\n \t\tdie(\"--combined-all-paths makes no sense without -c or --cc\");\n-\tif (revs->combine_merges)\n+\tif (revs->combine_merges) {\n \t\trevs->diff = 1;\n+\t\t/* Turn --cc/-c into -p --cc/-c when -p was not given */\n+\t\tif (!revs->diffopt.output_format)\n+\t\t\trevs->diffopt.output_format = DIFF_FORMAT_PATCH;\n+\t}\n+\n }\n-- \n2.25.1\n\n"},{"id":"412406","messageId":"20201216184929.3924-29-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201216184929.3924-1-sorganov@gmail.com","subject":"[PATCH v2 28/33] diff-merges: add '--diff-merges=1' as synonym for 'first-parent'","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-16T18:49:24Z","receivedAt":"2020-12-16T18:52:09Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"As we now have --diff-merges={m|c|cc}, add --diff-merges=1 as synonym\nfor --diff-merges=first-parent, to have shorter mnemonics for it as\nwell.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n diff-merges.c | 3 ++-\n 1 file changed, 2 insertions(+), 1 deletion(-)\n\ndiff --git a/diff-merges.c b/diff-merges.c\nindex 9492cd2b871d..63a0d78b7730 100644\n--- a/diff-merges.c\n+++ b/diff-merges.c\n@@ -57,7 +57,8 @@ static void set_diff_merges(struct rev_info *revs, const char *optarg)\n \t\treturn;\n \t}\n \tif (0) ;\n-\telse if (!strcmp(optarg, \"first\") || !strcmp(optarg, \"first-parent\"))\n+\telse if (!strcmp(optarg, \"first\") || !strcmp(optarg, \"first-parent\") ||\n+\t\t !strcmp(optarg, \"1\"))\n \t\tset_first_parent(revs);\n \telse if (!strcmp(optarg, \"sep\")   || !strcmp(optarg, \"separate\") ||\n \t\t !strcmp(optarg, \"m\"))\n-- \n2.25.1\n\n"},{"id":"412407","messageId":"20201216184929.3924-28-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201216184929.3924-1-sorganov@gmail.com","subject":"[PATCH v2 27/33] diff-merges: add old mnemonic counterparts to --diff-merges","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-16T18:49:23Z","receivedAt":"2020-12-16T18:52:10Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"This adds --diff-merges={m|c|cc} values that match mnemonics of old\noptions, for those who are used to them.\n\nNote that, say, --diff-meres=cc behaves differently than --cc, as the\nlatter implies -p and therefore enables diffs for all the commits,\nwhile the former enables output of diffs for merge commits only.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n diff-merges.c | 9 ++++++---\n 1 file changed, 6 insertions(+), 3 deletions(-)\n\ndiff --git a/diff-merges.c b/diff-merges.c\nindex ffe20d8daa4a..9492cd2b871d 100644\n--- a/diff-merges.c\n+++ b/diff-merges.c\n@@ -59,11 +59,14 @@ static void set_diff_merges(struct rev_info *revs, const char *optarg)\n \tif (0) ;\n \telse if (!strcmp(optarg, \"first\") || !strcmp(optarg, \"first-parent\"))\n \t\tset_first_parent(revs);\n-\telse if (!strcmp(optarg, \"sep\")   || !strcmp(optarg, \"separate\"))\n+\telse if (!strcmp(optarg, \"sep\")   || !strcmp(optarg, \"separate\") ||\n+\t\t !strcmp(optarg, \"m\"))\n \t\tset_separate(revs);\n-\telse if (!strcmp(optarg, \"comb\")  || !strcmp(optarg, \"combined\"))\n+\telse if (!strcmp(optarg, \"comb\")  || !strcmp(optarg, \"combined\") ||\n+\t\t !strcmp(optarg, \"c\"))\n \t\tset_combined(revs);\n-\telse if (!strcmp(optarg, \"dense\") || !strcmp(optarg, \"dense-combined\"))\n+\telse if (!strcmp(optarg, \"dense\") || !strcmp(optarg, \"dense-combined\") ||\n+\t\t !strcmp(optarg, \"cc\"))\n \t\tset_dense_combined(revs);\n \telse\n \t\tdie(_(\"unknown value for --diff-merges: %s\"), optarg);\n-- \n2.25.1\n\n"},{"id":"412408","messageId":"20201216184929.3924-32-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201216184929.3924-1-sorganov@gmail.com","subject":"[PATCH v2 31/33] doc/rev-list-options: document --first-parent changes merges format","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-16T18:49:27Z","receivedAt":"2020-12-16T18:52:10Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"After introduction of the --diff-merges=first-parent, the\n--first-parent sets the default format for merges to the same value as\nthis new option. Document this behavior and add corresponding\nreference to --diff-merges.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n Documentation/rev-list-options.txt | 5 +++++\n 1 file changed, 5 insertions(+)\n\ndiff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt\nindex 002379056a07..96cc89d157d2 100644\n--- a/Documentation/rev-list-options.txt\n+++ b/Documentation/rev-list-options.txt\n@@ -130,6 +130,11 @@ parents) and `--max-parents=-1` (negative numbers denote no upper limit).\n \tthis option allows you to ignore the individual commits\n \tbrought in to your history by such a merge.\n \n+ifdef::git-log[]\n+\tThis option also changes default diff format for merge commits\n+\tto `first-parent`, see `--diff-merges=first-parent` for details.\n+endif::git-log[]\n+\n --not::\n \tReverses the meaning of the '{caret}' prefix (or lack thereof)\n \tfor all following revision specifiers, up to the next `--not`.\n-- \n2.25.1\n\n"},{"id":"412409","messageId":"20201216184929.3924-31-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201216184929.3924-1-sorganov@gmail.com","subject":"[PATCH v2 30/33] doc/diff-generate-patch: mention new --diff-merges option","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-16T18:49:26Z","receivedAt":"2020-12-16T18:52:11Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Mention --diff-merges instead of -m in a note to merge formats to aid\ndiscoverability, as -m is now described among --diff-merges options\nanyway.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n Documentation/diff-generate-patch.txt | 6 +++---\n 1 file changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/Documentation/diff-generate-patch.txt b/Documentation/diff-generate-patch.txt\nindex b10ff4caa6c5..2db8eacc3ec7 100644\n--- a/Documentation/diff-generate-patch.txt\n+++ b/Documentation/diff-generate-patch.txt\n@@ -81,9 +81,9 @@ Combined diff format\n Any diff-generating command can take the `-c` or `--cc` option to\n produce a 'combined diff' when showing a merge. This is the default\n format when showing merges with linkgit:git-diff[1] or\n-linkgit:git-show[1]. Note also that you can give the `-m` option to any\n-of these commands to force generation of diffs with individual parents\n-of a merge.\n+linkgit:git-show[1]. Note also that you can give suitable\n+`--diff-merges` option to any of these commands to force generation of\n+diffs in specific format.\n \n A \"combined diff\" format looks like this:\n \n-- \n2.25.1\n\n"},{"id":"412410","messageId":"20201216184929.3924-19-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201216184929.3924-1-sorganov@gmail.com","subject":"[PATCH v2 18/33] diff-merges: group diff-merge flags next to each other inside 'rev_info'","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-16T18:49:14Z","receivedAt":"2020-12-16T18:52:26Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"The relevant flags were somewhat scattered over definition of 'struct\nrev_info'. Rearrange them to group them together.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n revision.h | 5 +++--\n 1 file changed, 3 insertions(+), 2 deletions(-)\n\ndiff --git a/revision.h b/revision.h\nindex fcc532c873d1..dcfa14454a55 100644\n--- a/revision.h\n+++ b/revision.h\n@@ -191,13 +191,14 @@ struct rev_info {\n \t\t\tmatch_missing:1,\n \t\t\tno_commit_id:1,\n \t\t\tverbose_header:1,\n+\t\t\talways_show_header:1,\n+\t\t\t/* Diff-merge flags */\n \t\t\texplicit_diff_merges: 1,\n \t\t\tseparate_merges: 1,\n \t\t\tcombine_merges:1,\n \t\t\tcombined_all_paths:1,\n \t\t\tdense_combined_merges:1,\n-\t\t\tfirst_parent_merges:1,\n-\t\t\talways_show_header:1;\n+\t\t\tfirst_parent_merges:1;\n \n \t/* Format info */\n \tint\t\tshow_notes;\n-- \n2.25.1\n\n"},{"id":"412411","messageId":"20201216184929.3924-18-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201216184929.3924-1-sorganov@gmail.com","subject":"[PATCH v2 17/33] diff-merges: split 'ignore_merges' field","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-16T18:49:13Z","receivedAt":"2020-12-16T18:52:27Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"'ignore_merges' was 3-way field that served two distinct purposes that\nwe now assign to 2 new independent flags: 'separate_merges', and\n'explicit_diff_merges'.\n\n'separate_merges' tells that we need to output diff format containing\nseparate diff for every parent (as opposed to 'combine_merges').\n\n'explicit_diff_merges' tells that at least one of diff-merges options\nhas been explicitly specified on the command line, so no defaults\nshould apply.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n diff-merges.c | 31 +++++++++++++------------------\n log-tree.c    | 15 ++++++++-------\n revision.h    |  3 ++-\n 3 files changed, 23 insertions(+), 26 deletions(-)\n\ndiff --git a/diff-merges.c b/diff-merges.c\nindex 5d20e329a661..711df9975dd5 100644\n--- a/diff-merges.c\n+++ b/diff-merges.c\n@@ -3,7 +3,7 @@\n #include \"revision.h\"\n \n static void suppress(struct rev_info *revs) {\n-\trevs->ignore_merges = 1;\n+\trevs->separate_merges = 0;\n \trevs->first_parent_merges = 0;\n \trevs->combine_merges = 0;\n \trevs->dense_combined_merges = 0;\n@@ -20,7 +20,6 @@ static void set_dense_combined(struct rev_info *revs) {\n  */\n \n void diff_merges_init_revs(struct rev_info *revs) {\n-\trevs->ignore_merges = -1;\n }\n \n int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {\n@@ -35,7 +34,7 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {\n \t\t * family of commands, it means \"show full diff for merges\". Set\n \t\t * both fields appropriately.\n \t\t */\n-\t\trevs->ignore_merges = 0;\n+\t\trevs->separate_merges = 1;\n \t\trevs->match_missing = 1;\n \t} else if (!strcmp(arg, \"-c\")) {\n \t\trevs->dense_combined_merges = 0;\n@@ -53,8 +52,9 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {\n \t\t\tdie(_(\"unknown value for --diff-merges: %s\"), optarg);\n \t\t}\n \t} else\n-\t\targcount = 0;\n+\t\treturn 0;\n \n+\trevs->explicit_diff_merges = 1;\n \treturn argcount;\n }\n \n@@ -63,20 +63,15 @@ void diff_merges_suppress(struct rev_info *revs) {\n }\n \n void diff_merges_default_to_first_parent(struct rev_info *revs) {\n-\tif (revs->ignore_merges < 0)\t\t/* No -m */\n-\t\trevs->ignore_merges = 0;\n-\tif (!revs->combine_merges)\t\t/* No -c/--cc\" */\n+\tif (!revs->explicit_diff_merges)\n+\t\trevs->separate_merges = 1;\n+\tif (revs->separate_merges)\n \t\trevs->first_parent_merges = 1;\n }\n \n void diff_merges_default_to_dense_combined(struct rev_info *revs) {\n-\tif (revs->ignore_merges < 0) {\t\t/* No -m */\n-\t\trevs->ignore_merges = 0;\n-\t\tif (!revs->combine_merges) {\t/* No -c/--cc\" */\n-\t\t\trevs->combine_merges = 1;\n-\t\t\trevs->dense_combined_merges = 1;\n-\t\t}\n-\t}\n+\tif (!revs->explicit_diff_merges)\n+\t\tset_dense_combined(revs);\n }\n \n void diff_merges_set_dense_combined_if_unset(struct rev_info *revs) {\n@@ -86,10 +81,10 @@ void diff_merges_set_dense_combined_if_unset(struct rev_info *revs) {\n \n void diff_merges_setup_revs(struct rev_info *revs)\n {\n-\tif (revs->combine_merges && revs->ignore_merges < 0)\n-\t\trevs->ignore_merges = 0;\n-\tif (revs->ignore_merges < 0)\n-\t\trevs->ignore_merges = 1;\n+\tif (revs->combine_merges == 0)\n+\t\trevs->dense_combined_merges = 0;\n+\tif (revs->separate_merges == 0)\n+\t\trevs->first_parent_merges = 0;\n \tif (revs->combined_all_paths && !revs->combine_merges)\n \t\tdie(\"--combined-all-paths makes no sense without -c or --cc\");\n \tif (revs->combine_merges)\ndiff --git a/log-tree.c b/log-tree.c\nindex 3fdc0fc64bfb..f9385b1dae6f 100644\n--- a/log-tree.c\n+++ b/log-tree.c\n@@ -918,14 +918,15 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log\n \n \t/* More than one parent? */\n \tif (parents->next) {\n-\t\tif (opt->ignore_merges)\n-\t\t\treturn 0;\n-\t\telse if (opt->combine_merges)\n+\t\tif (opt->combine_merges)\n \t\t\treturn do_diff_combined(opt, commit);\n-\t\telse if (!opt->first_parent_merges) {\n-\t\t\t/* If we show multiple diffs, show the parent info */\n-\t\t\tlog->parent = parents->item;\n-\t\t}\n+\t\tif (opt->separate_merges) {\n+\t\t\tif (!opt->first_parent_merges) {\n+\t\t\t\t/* Show parent info for multiple diffs */\n+\t\t\t\tlog->parent = parents->item;\n+\t\t\t}\n+\t\t} else\n+\t\t\treturn 0;\n \t}\n \n \tshowed_log = 0;\ndiff --git a/revision.h b/revision.h\nindex ba2aef79215e..fcc532c873d1 100644\n--- a/revision.h\n+++ b/revision.h\n@@ -191,12 +191,13 @@ struct rev_info {\n \t\t\tmatch_missing:1,\n \t\t\tno_commit_id:1,\n \t\t\tverbose_header:1,\n+\t\t\texplicit_diff_merges: 1,\n+\t\t\tseparate_merges: 1,\n \t\t\tcombine_merges:1,\n \t\t\tcombined_all_paths:1,\n \t\t\tdense_combined_merges:1,\n \t\t\tfirst_parent_merges:1,\n \t\t\talways_show_header:1;\n-\tint             ignore_merges:2;\n \n \t/* Format info */\n \tint\t\tshow_notes;\n-- \n2.25.1\n\n"},{"id":"412412","messageId":"20201216184929.3924-22-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201216184929.3924-1-sorganov@gmail.com","subject":"[PATCH v2 21/33] diff-merges: make -m/-c/--cc explicitly mutually exclusive","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-16T18:49:17Z","receivedAt":"2020-12-16T18:52:31Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"-c/--cc got precedence over -m only because of external logic where\ncorresponding flags are checked before that for -m. This is too\nerror-prone, so add code that explicitly makes these 3 options\nmutually exclusive, so that the last option specified on the\ncommand-line gets precedence.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n diff-merges.c | 3 +++\n 1 file changed, 3 insertions(+)\n\ndiff --git a/diff-merges.c b/diff-merges.c\nindex 4c434e914c8d..6446e2093661 100644\n--- a/diff-merges.c\n+++ b/diff-merges.c\n@@ -7,6 +7,7 @@ static void suppress(struct rev_info *revs) {\n \trevs->first_parent_merges = 0;\n \trevs->combine_merges = 0;\n \trevs->dense_combined_merges = 0;\n+\trevs->combined_all_paths = 0;\n }\n \n static void set_separate(struct rev_info *revs) {\n@@ -25,11 +26,13 @@ static void set_m(struct rev_info *revs) {\n }\n \n static void set_combined(struct rev_info *revs) {\n+\tsuppress(revs);\n \trevs->combine_merges = 1;\n \trevs->dense_combined_merges = 0;\n }\n \n static void set_dense_combined(struct rev_info *revs) {\n+\tsuppress(revs);\n \trevs->combine_merges = 1;\n \trevs->dense_combined_merges = 1;\n }\n-- \n2.25.1\n\n"},{"id":"412413","messageId":"20201216184929.3924-27-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201216184929.3924-1-sorganov@gmail.com","subject":"[PATCH v2 26/33] diff-merges: let new options enable diff without -p","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-16T18:49:22Z","receivedAt":"2020-12-16T18:52:32Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"New options don't have any visible effect unless -p is either given or\nimplied, as unlike -c/-cc we don't imply -p with --diff-merges. To fix\nthis, this patch adds new functionality by letting new options enable\noutput of diffs for merge commits only.\n\nAdd 'merges_need_diff' field and set it whenever diff output for merges is\nenabled by any of the new options.\n\nExtend diff output logic accordingly, to output diffs for merges when\n'merges_need_diff' is set even when no -p has been provided.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n diff-merges.c | 16 ++++++++++------\n log-tree.c    | 13 +++++++++----\n revision.h    |  1 +\n 3 files changed, 20 insertions(+), 10 deletions(-)\n\ndiff --git a/diff-merges.c b/diff-merges.c\nindex 725db2312074..ffe20d8daa4a 100644\n--- a/diff-merges.c\n+++ b/diff-merges.c\n@@ -10,6 +10,7 @@ static void suppress(struct rev_info *revs)\n \trevs->dense_combined_merges = 0;\n \trevs->combined_all_paths = 0;\n \trevs->combined_imply_patch = 0;\n+\trevs->merges_need_diff = 0;\n }\n \n static void set_separate(struct rev_info *revs)\n@@ -51,9 +52,11 @@ static void set_dense_combined(struct rev_info *revs)\n \n static void set_diff_merges(struct rev_info *revs, const char *optarg)\n {\n+\tif (!strcmp(optarg, \"off\") || !strcmp(optarg, \"none\")) {\n+\t\tsuppress(revs);\n+\t\treturn;\n+\t}\n \tif (0) ;\n-\telse if (!strcmp(optarg, \"off\")   || !strcmp(optarg, \"none\"))\n-\t\tsuppress(revs);\n \telse if (!strcmp(optarg, \"first\") || !strcmp(optarg, \"first-parent\"))\n \t\tset_first_parent(revs);\n \telse if (!strcmp(optarg, \"sep\")   || !strcmp(optarg, \"separate\"))\n@@ -64,6 +67,7 @@ static void set_diff_merges(struct rev_info *revs, const char *optarg)\n \t\tset_dense_combined(revs);\n \telse\n \t\tdie(_(\"unknown value for --diff-merges: %s\"), optarg);\n+\trevs->merges_need_diff = 1;\n }\n \n /*\n@@ -132,12 +136,12 @@ void diff_merges_setup_revs(struct rev_info *revs)\n \t\trevs->first_parent_merges = 0;\n \tif (revs->combined_all_paths && !revs->combine_merges)\n \t\tdie(\"--combined-all-paths makes no sense without -c or --cc\");\n-\tif (revs->combine_merges)\n+\n+\tif (revs->combined_imply_patch)\n \t\trevs->diff = 1;\n-\tif (revs->combined_imply_patch) {\n-\t\t/* Turn --cc/-c into -p --cc/-c when -p was not given */\n+\n+\tif (revs->combined_imply_patch || revs->merges_need_diff) {\n \t\tif (!revs->diffopt.output_format)\n \t\t\trevs->diffopt.output_format = DIFF_FORMAT_PATCH;\n \t}\n-\n }\ndiff --git a/log-tree.c b/log-tree.c\nindex f9385b1dae6f..67060492ca0a 100644\n--- a/log-tree.c\n+++ b/log-tree.c\n@@ -899,15 +899,21 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log\n \tint showed_log;\n \tstruct commit_list *parents;\n \tstruct object_id *oid;\n+\tint is_merge;\n+\tint regulars_need_diff = opt->diff || opt->diffopt.flags.exit_with_status;\n \n-\tif (!opt->diff && !opt->diffopt.flags.exit_with_status)\n+\tif (!regulars_need_diff && !opt->merges_need_diff)\n \t\treturn 0;\n \n \tparse_commit_or_die(commit);\n \toid = get_commit_tree_oid(commit);\n \n-\t/* Root commit? */\n \tparents = get_saved_parents(opt, commit);\n+\tis_merge = parents && parents->next;\n+\tif(!is_merge && !regulars_need_diff)\n+\t\treturn 0;\n+\n+\t/* Root commit? */\n \tif (!parents) {\n \t\tif (opt->show_root_diff) {\n \t\t\tdiff_root_tree_oid(oid, \"\", &opt->diffopt);\n@@ -916,8 +922,7 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log\n \t\treturn !opt->loginfo;\n \t}\n \n-\t/* More than one parent? */\n-\tif (parents->next) {\n+\tif (is_merge) {\n \t\tif (opt->combine_merges)\n \t\t\treturn do_diff_combined(opt, commit);\n \t\tif (opt->separate_merges) {\ndiff --git a/revision.h b/revision.h\nindex bfbae526ad6e..494d86142454 100644\n--- a/revision.h\n+++ b/revision.h\n@@ -194,6 +194,7 @@ struct rev_info {\n \t\t\talways_show_header:1,\n \t\t\t/* Diff-merge flags */\n \t\t\texplicit_diff_merges: 1,\n+\t\t\tmerges_need_diff: 1,\n \t\t\tseparate_merges: 1,\n \t\t\tcombine_merges:1,\n \t\t\tcombined_all_paths:1,\n-- \n2.25.1\n\n"},{"id":"412414","messageId":"20201216184929.3924-26-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201216184929.3924-1-sorganov@gmail.com","subject":"[PATCH v2 25/33] diff-merges: do not imply -p for new options","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-16T18:49:21Z","receivedAt":"2020-12-16T18:52:33Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Add 'combined_imply_patch' field and set it only for old --cc/-c\noptions, then imply -p if this flag is set instead of implying -p\nwhenever 'combined_merge' flag is set.\n\nWe don't want new --diff-merge options to imply -p, to make it\npossible to enable output of diffs for merges independently from\nnon-merge commits. At the same time we want to preserve behavior of\nold --c/-c/-m options and their interactions with --first-parent, to\nstay backward-compatible.\n\nThis patch is first step in this direction: it separates old \"--cc/-c\nimply -p\" logic from the rest of the options.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n diff-merges.c | 12 +++++++++---\n revision.h    |  1 +\n 2 files changed, 10 insertions(+), 3 deletions(-)\n\ndiff --git a/diff-merges.c b/diff-merges.c\nindex 2ac25488d53e..725db2312074 100644\n--- a/diff-merges.c\n+++ b/diff-merges.c\n@@ -9,6 +9,7 @@ static void suppress(struct rev_info *revs)\n \trevs->combine_merges = 0;\n \trevs->dense_combined_merges = 0;\n \trevs->combined_all_paths = 0;\n+\trevs->combined_imply_patch = 0;\n }\n \n static void set_separate(struct rev_info *revs)\n@@ -77,10 +78,14 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv)\n \n \tif (!strcmp(arg, \"-m\"))\n \t\tset_m(revs);\n-\telse if (!strcmp(arg, \"-c\"))\n+\telse if (!strcmp(arg, \"-c\")) {\n \t\tset_combined(revs);\n-\telse if (!strcmp(arg, \"--cc\"))\n+\t\trevs->combined_imply_patch = 1;\n+\t}\n+\telse if (!strcmp(arg, \"--cc\")) {\n \t\tset_dense_combined(revs);\n+\t\trevs->combined_imply_patch = 1;\n+\t}\n \telse if (!strcmp(arg, \"--no-diff-merges\"))\n \t\tsuppress(revs);\n \telse if (!strcmp(arg, \"--combined-all-paths\"))\n@@ -127,8 +132,9 @@ void diff_merges_setup_revs(struct rev_info *revs)\n \t\trevs->first_parent_merges = 0;\n \tif (revs->combined_all_paths && !revs->combine_merges)\n \t\tdie(\"--combined-all-paths makes no sense without -c or --cc\");\n-\tif (revs->combine_merges) {\n+\tif (revs->combine_merges)\n \t\trevs->diff = 1;\n+\tif (revs->combined_imply_patch) {\n \t\t/* Turn --cc/-c into -p --cc/-c when -p was not given */\n \t\tif (!revs->diffopt.output_format)\n \t\t\trevs->diffopt.output_format = DIFF_FORMAT_PATCH;\ndiff --git a/revision.h b/revision.h\nindex dcfa14454a55..bfbae526ad6e 100644\n--- a/revision.h\n+++ b/revision.h\n@@ -197,6 +197,7 @@ struct rev_info {\n \t\t\tseparate_merges: 1,\n \t\t\tcombine_merges:1,\n \t\t\tcombined_all_paths:1,\n+\t\t\tcombined_imply_patch:1,\n \t\t\tdense_combined_merges:1,\n \t\t\tfirst_parent_merges:1;\n \n-- \n2.25.1\n\n"},{"id":"412415","messageId":"20201216184929.3924-30-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201216184929.3924-1-sorganov@gmail.com","subject":"[PATCH v2 29/33] doc/git-log: describe new --diff-merges options","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-16T18:49:25Z","receivedAt":"2020-12-16T18:52:33Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Describe all the new --diff-merges options in the git-log.txt and\nadopt description of originals accordingly.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n Documentation/git-log.txt | 85 ++++++++++++++++++++++++---------------\n 1 file changed, 52 insertions(+), 33 deletions(-)\n\ndiff --git a/Documentation/git-log.txt b/Documentation/git-log.txt\nindex 2b8ac5ff882a..27bc619490c6 100644\n--- a/Documentation/git-log.txt\n+++ b/Documentation/git-log.txt\n@@ -120,45 +120,64 @@ DIFF FORMATTING\n By default, `git log` does not generate any diff output. The options\n below can be used to show the changes made by each commit.\n \n-Note that unless one of `-c`, `--cc`, or `-m` is given, merge commits\n-will never show a diff, even if a diff format like `--patch` is\n-selected, nor will they match search options like `-S`. The exception is\n-when `--first-parent` is in use, in which merges are treated like normal\n-single-parent commits (this can be overridden by providing a\n-combined-diff option or with `--no-diff-merges`).\n+Note that unless one of `--diff-merges` variants (including short\n+`-m`, `-c`, and `--cc` options) is explicitly given, merge commits\n+will not show a diff, even if a diff format like `--patch` is\n+selected, nor will they match search options like `-S`. The exception\n+is when `--first-parent` is in use, in which case `first-parent` is\n+the default format.\n \n--c::\n-\tWith this option, diff output for a merge commit\n-\tshows the differences from each of the parents to the merge result\n-\tsimultaneously instead of showing pairwise diff between a parent\n-\tand the result one at a time. Furthermore, it lists only files\n-\twhich were modified from all parents.\n-\n---cc::\n-\tThis flag implies the `-c` option and further compresses the\n-\tpatch output by omitting uninteresting hunks whose contents in\n-\tthe parents have only two variants and the merge result picks\n-\tone of them without modification.\n+--diff-merges=(off|none|first-parent|1|separate|m|combined|c|dense-combined|cc)::\n+--no-diff-merges::\n+\tSpecify diff format to be used for merge commits. Default is\n+\t`off` unless `--first-parent` is in use, in which case\n+\t`first-parent` is the default.\n++\n+--diff-merges=(off|none):::\n+--no-diff-merges:::\n+\tDisable output of diffs for merge commits. Useful to override\n+\timplied value.\n++\n+--diff-merges=first-parent:::\n+--diff-merges=1:::\n+\tThis option makes merge commits show the full diff with\n+\trespect to the first parent only.\n++\n+--diff-merges=separate:::\n+--diff-merges=m:::\n+-m:::\n+\tThis makes merge commits show the full diff with respect to\n+\teach of the parents. Separate log entry and diff is generated\n+\tfor each parent. `-m` is different in that it doesn't produce\n+\tany output without `-p`.\n++\n+--diff-merges=combined:::\n+--diff-merges=c:::\n+-c:::\n+\tWith this option, diff output for a merge commit shows the\n+\tdifferences from each of the parents to the merge result\n+\tsimultaneously instead of showing pairwise diff between a\n+\tparent and the result one at a time. Furthermore, it lists\n+\tonly files which were modified from all parents. Historically,\n+\t`-c` enables diff output for non-merge commits as well.\n++\n+--diff-merges=dense-combined:::\n+--diff-merges=cc:::\n+--cc:::\n+\tWith this option the output produced by\n+\t`--diff-merges=combined` is further compressed by omitting\n+\tuninteresting hunks whose contents in the parents have only\n+\ttwo variants and the merge result picks one of them without\n+\tmodification.  Historically, `--c` enables diff output for\n+\tnon-merge commits as well.\n \n --combined-all-paths::\n \tThis flag causes combined diffs (used for merge commits) to\n \tlist the name of the file from all parents.  It thus only has\n-\teffect when -c or --cc are specified, and is likely only\n-\tuseful if filename changes are detected (i.e. when either\n-\trename or copy detection have been requested).\n+\teffect when `--diff-merges=[dense-]combined` is in use, and\n+\tis likely only useful if filename changes are detected (i.e.\n+\twhen either rename or copy detection have been requested).\n \n--m::\n-\tThis flag makes the merge commits show the full diff like\n-\tregular commits; for each merge parent, a separate log entry\n-\tand diff is generated. An exception is that only diff against\n-\tthe first parent is shown when `--first-parent` option is given;\n-\tin that case, the output represents the changes the merge\n-\tbrought _into_ the then-current branch.\n-\n---diff-merges=off::\n---no-diff-merges::\n-\tDisable output of diffs for merge commits (default). Useful to\n-\toverride `-m`, `-c`, or `--cc`.\n \n :git-log: 1\n include::diff-options.txt[]\n-- \n2.25.1\n\n"},{"id":"412416","messageId":"20201216184929.3924-33-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201216184929.3924-1-sorganov@gmail.com","subject":"[PATCH v2 32/33] doc/git-show: include --diff-merges description","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-16T18:49:28Z","receivedAt":"2020-12-16T18:52:36Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Move description of --diff-merges option from git-log.txt to\ndiff-options.txt so that it is included in the git-show help.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n Documentation/diff-options.txt | 53 ++++++++++++++++++++++++++++++++++\n Documentation/git-log.txt      | 53 +---------------------------------\n Documentation/git-show.txt     |  7 +++--\n 3 files changed, 59 insertions(+), 54 deletions(-)\n\ndiff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt\nindex 573fb9bb71e2..98db2be423dc 100644\n--- a/Documentation/diff-options.txt\n+++ b/Documentation/diff-options.txt\n@@ -33,6 +33,59 @@ endif::git-diff[]\n \tshow the patch by default, or to cancel the effect of `--patch`.\n endif::git-format-patch[]\n \n+ifdef::git-log[]\n+--diff-merges=(off|none|first-parent|1|separate|m|combined|c|dense-combined|cc)::\n+--no-diff-merges::\n+\tSpecify diff format to be used for merge commits. Default is\n+\t{diff-merges-default} unless `--first-parent` is in use, in which case\n+\t`first-parent` is the default.\n++\n+--diff-merges=(off|none):::\n+--no-diff-merges:::\n+\tDisable output of diffs for merge commits. Useful to override\n+\timplied value.\n++\n+--diff-merges=first-parent:::\n+--diff-merges=1:::\n+\tThis option makes merge commits show the full diff with\n+\trespect to the first parent only.\n++\n+--diff-merges=separate:::\n+--diff-merges=m:::\n+-m:::\n+\tThis makes merge commits show the full diff with respect to\n+\teach of the parents. Separate log entry and diff is generated\n+\tfor each parent. `-m` is different in that it doesn't produce\n+\tany output without `-p`.\n++\n+--diff-merges=combined:::\n+--diff-merges=c:::\n+-c:::\n+\tWith this option, diff output for a merge commit shows the\n+\tdifferences from each of the parents to the merge result\n+\tsimultaneously instead of showing pairwise diff between a\n+\tparent and the result one at a time. Furthermore, it lists\n+\tonly files which were modified from all parents. Historically,\n+\t`-c` enables diff output for non-merge commits as well.\n++\n+--diff-merges=dense-combined:::\n+--diff-merges=cc:::\n+--cc:::\n+\tWith this option the output produced by\n+\t`--diff-merges=combined` is further compressed by omitting\n+\tuninteresting hunks whose contents in the parents have only\n+\ttwo variants and the merge result picks one of them without\n+\tmodification.  Historically, `--c` enables diff output for\n+\tnon-merge commits as well.\n+\n+--combined-all-paths::\n+\tThis flag causes combined diffs (used for merge commits) to\n+\tlist the name of the file from all parents.  It thus only has\n+\teffect when `--diff-merges=[dense-]combined` is in use, and\n+\tis likely only useful if filename changes are detected (i.e.\n+\twhen either rename or copy detection have been requested).\n+endif::git-log[]\n+\n -U<n>::\n --unified=<n>::\n \tGenerate diffs with <n> lines of context instead of\ndiff --git a/Documentation/git-log.txt b/Documentation/git-log.txt\nindex 27bc619490c6..727d20e1a2ab 100644\n--- a/Documentation/git-log.txt\n+++ b/Documentation/git-log.txt\n@@ -127,59 +127,8 @@ selected, nor will they match search options like `-S`. The exception\n is when `--first-parent` is in use, in which case `first-parent` is\n the default format.\n \n---diff-merges=(off|none|first-parent|1|separate|m|combined|c|dense-combined|cc)::\n---no-diff-merges::\n-\tSpecify diff format to be used for merge commits. Default is\n-\t`off` unless `--first-parent` is in use, in which case\n-\t`first-parent` is the default.\n-+\n---diff-merges=(off|none):::\n---no-diff-merges:::\n-\tDisable output of diffs for merge commits. Useful to override\n-\timplied value.\n-+\n---diff-merges=first-parent:::\n---diff-merges=1:::\n-\tThis option makes merge commits show the full diff with\n-\trespect to the first parent only.\n-+\n---diff-merges=separate:::\n---diff-merges=m:::\n--m:::\n-\tThis makes merge commits show the full diff with respect to\n-\teach of the parents. Separate log entry and diff is generated\n-\tfor each parent. `-m` is different in that it doesn't produce\n-\tany output without `-p`.\n-+\n---diff-merges=combined:::\n---diff-merges=c:::\n--c:::\n-\tWith this option, diff output for a merge commit shows the\n-\tdifferences from each of the parents to the merge result\n-\tsimultaneously instead of showing pairwise diff between a\n-\tparent and the result one at a time. Furthermore, it lists\n-\tonly files which were modified from all parents. Historically,\n-\t`-c` enables diff output for non-merge commits as well.\n-+\n---diff-merges=dense-combined:::\n---diff-merges=cc:::\n---cc:::\n-\tWith this option the output produced by\n-\t`--diff-merges=combined` is further compressed by omitting\n-\tuninteresting hunks whose contents in the parents have only\n-\ttwo variants and the merge result picks one of them without\n-\tmodification.  Historically, `--c` enables diff output for\n-\tnon-merge commits as well.\n-\n---combined-all-paths::\n-\tThis flag causes combined diffs (used for merge commits) to\n-\tlist the name of the file from all parents.  It thus only has\n-\teffect when `--diff-merges=[dense-]combined` is in use, and\n-\tis likely only useful if filename changes are detected (i.e.\n-\twhen either rename or copy detection have been requested).\n-\n-\n :git-log: 1\n+:diff-merges-default: `off`\n include::diff-options.txt[]\n \n include::diff-generate-patch.txt[]\ndiff --git a/Documentation/git-show.txt b/Documentation/git-show.txt\nindex fcf528c1b30d..2b1bc7288d5f 100644\n--- a/Documentation/git-show.txt\n+++ b/Documentation/git-show.txt\n@@ -45,10 +45,13 @@ include::pretty-options.txt[]\n include::pretty-formats.txt[]\n \n \n-COMMON DIFF OPTIONS\n--------------------\n+DIFF FORMATTING\n+---------------\n+The options below can be used to change the way `git show` generates\n+diff output.\n \n :git-log: 1\n+:diff-merges-default: `dense-combined`\n include::diff-options.txt[]\n \n include::diff-generate-patch.txt[]\n-- \n2.25.1\n\n"},{"id":"412417","messageId":"20201216184929.3924-34-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201216184929.3924-1-sorganov@gmail.com","subject":"[PATCH v2 33/33] t4013: add tests for --diff-merges=first-parent","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-16T18:49:29Z","receivedAt":"2020-12-16T18:52:36Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"This new option provides essential new functionality, changing diff\noutput to first parent only, without changing history traversal mode,\nso it deserves its own test.\n\nAs we do it, add additional test that --diff-merges=first-parent by\nitself doesn't imply -p and only outputs diffs for merge commits.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n t/t4013-diff-various.sh                       |   2 +\n ...diff.log_--diff-merges=first-parent_master |  56 +++++++\n ...f.log_-p_--diff-merges=first-parent_master | 137 ++++++++++++++++++\n 3 files changed, 195 insertions(+)\n create mode 100644 t/t4013/diff.log_--diff-merges=first-parent_master\n create mode 100644 t/t4013/diff.log_-p_--diff-merges=first-parent_master\n\ndiff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh\nindex 8d8178a8a616..fa82b5a8eed4 100755\n--- a/t/t4013-diff-various.sh\n+++ b/t/t4013-diff-various.sh\n@@ -327,6 +327,8 @@ log --no-diff-merges -p --first-parent master\n log --diff-merges=off -p --first-parent master\n log --first-parent --diff-merges=off -p master\n log -p --first-parent master\n+log -p --diff-merges=first-parent master\n+log --diff-merges=first-parent master\n log -m -p --first-parent master\n log -m -p master\n log --cc -m -p master\ndiff --git a/t/t4013/diff.log_--diff-merges=first-parent_master b/t/t4013/diff.log_--diff-merges=first-parent_master\nnew file mode 100644\nindex 000000000000..fa63a557dd18\n--- /dev/null\n+++ b/t/t4013/diff.log_--diff-merges=first-parent_master\n@@ -0,0 +1,56 @@\n+$ git log --diff-merges=first-parent master\n+commit 59d314ad6f356dd08601a4cd5e530381da3e3c64\n+Merge: 9a6d494 c7a2ab9\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:04:00 2006 +0000\n+\n+    Merge branch 'side'\n+\n+diff --git a/dir/sub b/dir/sub\n+index cead32e..992913c 100644\n+--- a/dir/sub\n++++ b/dir/sub\n+@@ -4,3 +4,5 @@ C\n+ D\n+ E\n+ F\n++1\n++2\n+diff --git a/file0 b/file0\n+index b414108..10a8a9f 100644\n+--- a/file0\n++++ b/file0\n+@@ -4,3 +4,6 @@\n+ 4\n+ 5\n+ 6\n++A\n++B\n++C\n+\n+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:03:00 2006 +0000\n+\n+    Side\n+\n+commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:02:00 2006 +0000\n+\n+    Third\n+\n+commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:01:00 2006 +0000\n+\n+    Second\n+    \n+    This is the second commit.\n+\n+commit 444ac553ac7612cc88969031b02b3767fb8a353a\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:00:00 2006 +0000\n+\n+    Initial\n+$\ndiff --git a/t/t4013/diff.log_-p_--diff-merges=first-parent_master b/t/t4013/diff.log_-p_--diff-merges=first-parent_master\nnew file mode 100644\nindex 000000000000..9538a2751123\n--- /dev/null\n+++ b/t/t4013/diff.log_-p_--diff-merges=first-parent_master\n@@ -0,0 +1,137 @@\n+$ git log -p --diff-merges=first-parent master\n+commit 59d314ad6f356dd08601a4cd5e530381da3e3c64\n+Merge: 9a6d494 c7a2ab9\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:04:00 2006 +0000\n+\n+    Merge branch 'side'\n+\n+diff --git a/dir/sub b/dir/sub\n+index cead32e..992913c 100644\n+--- a/dir/sub\n++++ b/dir/sub\n+@@ -4,3 +4,5 @@ C\n+ D\n+ E\n+ F\n++1\n++2\n+diff --git a/file0 b/file0\n+index b414108..10a8a9f 100644\n+--- a/file0\n++++ b/file0\n+@@ -4,3 +4,6 @@\n+ 4\n+ 5\n+ 6\n++A\n++B\n++C\n+\n+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:03:00 2006 +0000\n+\n+    Side\n+\n+diff --git a/dir/sub b/dir/sub\n+index 35d242b..7289e35 100644\n+--- a/dir/sub\n++++ b/dir/sub\n+@@ -1,2 +1,4 @@\n+ A\n+ B\n++1\n++2\n+diff --git a/file0 b/file0\n+index 01e79c3..f4615da 100644\n+--- a/file0\n++++ b/file0\n+@@ -1,3 +1,6 @@\n+ 1\n+ 2\n+ 3\n++A\n++B\n++C\n+diff --git a/file3 b/file3\n+new file mode 100644\n+index 0000000..7289e35\n+--- /dev/null\n++++ b/file3\n+@@ -0,0 +1,4 @@\n++A\n++B\n++1\n++2\n+\n+commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:02:00 2006 +0000\n+\n+    Third\n+\n+diff --git a/dir/sub b/dir/sub\n+index 8422d40..cead32e 100644\n+--- a/dir/sub\n++++ b/dir/sub\n+@@ -2,3 +2,5 @@ A\n+ B\n+ C\n+ D\n++E\n++F\n+diff --git a/file1 b/file1\n+new file mode 100644\n+index 0000000..b1e6722\n+--- /dev/null\n++++ b/file1\n+@@ -0,0 +1,3 @@\n++A\n++B\n++C\n+\n+commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:01:00 2006 +0000\n+\n+    Second\n+    \n+    This is the second commit.\n+\n+diff --git a/dir/sub b/dir/sub\n+index 35d242b..8422d40 100644\n+--- a/dir/sub\n++++ b/dir/sub\n+@@ -1,2 +1,4 @@\n+ A\n+ B\n++C\n++D\n+diff --git a/file0 b/file0\n+index 01e79c3..b414108 100644\n+--- a/file0\n++++ b/file0\n+@@ -1,3 +1,6 @@\n+ 1\n+ 2\n+ 3\n++4\n++5\n++6\n+diff --git a/file2 b/file2\n+deleted file mode 100644\n+index 01e79c3..0000000\n+--- a/file2\n++++ /dev/null\n+@@ -1,3 +0,0 @@\n+-1\n+-2\n+-3\n+\n+commit 444ac553ac7612cc88969031b02b3767fb8a353a\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:00:00 2006 +0000\n+\n+    Initial\n+$\n-- \n2.25.1\n\n"},{"id":"412418","messageId":"20201216184929.3924-23-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201216184929.3924-1-sorganov@gmail.com","subject":"[PATCH v2 22/33] diff-merges: implement new values for --diff-merges","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-16T18:49:18Z","receivedAt":"2020-12-16T18:53:17Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"We first implement new options as exact synonyms for their original\ncounterparts, to get all the infrastructure right, and keep functional\nimprovements for later commits.\n\nThe following values are implemented:\n\n--diff-merges=\t        old equivalent\nfirst|first-parent    = --first-parent (only format implications)\nsep|separate          = -m\ncomb|combined         = -c\ndense| dense-combined = --cc\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n diff-merges.c | 19 ++++++++++++++++---\n 1 file changed, 16 insertions(+), 3 deletions(-)\n\ndiff --git a/diff-merges.c b/diff-merges.c\nindex 6446e2093661..cba391604ac7 100644\n--- a/diff-merges.c\n+++ b/diff-merges.c\n@@ -15,6 +15,11 @@ static void set_separate(struct rev_info *revs) {\n \trevs->separate_merges = 1;\n }\n \n+static void set_first_parent(struct rev_info *revs) {\n+\tset_separate(revs);\n+\trevs->first_parent_merges = 1;\n+}\n+\n static void set_m(struct rev_info *revs) {\n \t/*\n \t * To \"diff-index\", \"-m\" means \"match missing\", and to the \"log\"\n@@ -38,11 +43,19 @@ static void set_dense_combined(struct rev_info *revs) {\n }\n \n static void set_diff_merges(struct rev_info *revs, const char *optarg) {\n-\tif (!strcmp(optarg, \"off\")) {\n+\tif (0) ;\n+\telse if (!strcmp(optarg, \"off\")   || !strcmp(optarg, \"none\"))\n \t\tsuppress(revs);\n-\t} else {\n+\telse if (!strcmp(optarg, \"first\") || !strcmp(optarg, \"first-parent\"))\n+\t\tset_first_parent(revs);\n+\telse if (!strcmp(optarg, \"sep\")   || !strcmp(optarg, \"separate\"))\n+\t\tset_separate(revs);\n+\telse if (!strcmp(optarg, \"comb\")  || !strcmp(optarg, \"combined\"))\n+\t\tset_combined(revs);\n+\telse if (!strcmp(optarg, \"dense\") || !strcmp(optarg, \"dense-combined\"))\n+\t\tset_dense_combined(revs);\n+\telse\n \t\tdie(_(\"unknown value for --diff-merges: %s\"), optarg);\n-\t}\n }\n \n /*\n-- \n2.25.1\n\n"},{"id":"412519","messageId":"CABPp-BG1S83EUbqtqqjeLT4=Je44BpRMrf0MB+DNQK2wjRDbqQ@mail.gmail.com","threadId":"54550","inReplyTo":"20201216184929.3924-23-sorganov@gmail.com","subject":"Re: [PATCH v2 22/33] diff-merges: implement new values for --diff-merges","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2020-12-18T05:39:13Z","receivedAt":"2020-12-18T05:40:06Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Wed, Dec 16, 2020 at 10:50 AM Sergey Organov <sorganov@gmail.com> wrote:\n>\n> We first implement new options as exact synonyms for their original\n> counterparts, to get all the infrastructure right, and keep functional\n> improvements for later commits.\n>\n> The following values are implemented:\n>\n> --diff-merges=          old equivalent\n> first|first-parent    = --first-parent (only format implications)\n> sep|separate          = -m\n> comb|combined         = -c\n> dense| dense-combined = --cc\n>\n> Signed-off-by: Sergey Organov <sorganov@gmail.com>\n> ---\n>  diff-merges.c | 19 ++++++++++++++++---\n>  1 file changed, 16 insertions(+), 3 deletions(-)\n>\n> diff --git a/diff-merges.c b/diff-merges.c\n> index 6446e2093661..cba391604ac7 100644\n> --- a/diff-merges.c\n> +++ b/diff-merges.c\n> @@ -15,6 +15,11 @@ static void set_separate(struct rev_info *revs) {\n>         revs->separate_merges = 1;\n>  }\n>\n> +static void set_first_parent(struct rev_info *revs) {\n> +       set_separate(revs);\n> +       revs->first_parent_merges = 1;\n> +}\n> +\n>  static void set_m(struct rev_info *revs) {\n>         /*\n>          * To \"diff-index\", \"-m\" means \"match missing\", and to the \"log\"\n> @@ -38,11 +43,19 @@ static void set_dense_combined(struct rev_info *revs) {\n>  }\n>\n>  static void set_diff_merges(struct rev_info *revs, const char *optarg) {\n> -       if (!strcmp(optarg, \"off\")) {\n> +       if (0) ;\n\nLeftover cruft from some intermediate changes or something?\n\n> +       else if (!strcmp(optarg, \"off\")   || !strcmp(optarg, \"none\"))\n>                 suppress(revs);\n> -       } else {\n> +       else if (!strcmp(optarg, \"first\") || !strcmp(optarg, \"first-parent\"))\n> +               set_first_parent(revs);\n> +       else if (!strcmp(optarg, \"sep\")   || !strcmp(optarg, \"separate\"))\n> +               set_separate(revs);\n> +       else if (!strcmp(optarg, \"comb\")  || !strcmp(optarg, \"combined\"))\n> +               set_combined(revs);\n> +       else if (!strcmp(optarg, \"dense\") || !strcmp(optarg, \"dense-combined\"))\n> +               set_dense_combined(revs);\n> +       else\n\nNot sure I like the special-casing for \"sep\" and \"comb\".  \"dense\"\nseems okay since it's a real word.  Since you're adding short versions\nof m, c, and cc later in the series, do we need these other\nspecial-case forms?\n\n>                 die(_(\"unknown value for --diff-merges: %s\"), optarg);\n> -       }\n>  }\n>\n>  /*\n> --\n> 2.25.1\n>\n"},{"id":"412520","messageId":"CABPp-BEf2nbahjzR6aLLNy0YsHYcHqCozCe6veoZOH3LAM892g@mail.gmail.com","threadId":"54550","inReplyTo":"20201216184929.3924-24-sorganov@gmail.com","subject":"Re: [PATCH v2 23/33] diff-merges: fix style of functions definitions","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2020-12-18T05:42:03Z","receivedAt":"2020-12-18T05:43:12Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Wed, Dec 16, 2020 at 10:50 AM Sergey Organov <sorganov@gmail.com> wrote:\n>\n> Put open curly brace on its own line\n>\n> Signed-off-by: Sergey Organov <sorganov@gmail.com>\n> ---\n>  diff-merges.c | 36 ++++++++++++++++++++++++------------\n>  1 file changed, 24 insertions(+), 12 deletions(-)\n>\n> diff --git a/diff-merges.c b/diff-merges.c\n> index cba391604ac7..0165fa22fcd1 100644\n> --- a/diff-merges.c\n> +++ b/diff-merges.c\n> @@ -2,7 +2,8 @@\n>\n>  #include \"revision.h\"\n>\n> -static void suppress(struct rev_info *revs) {\n> +static void suppress(struct rev_info *revs)\n> +{\n>         revs->separate_merges = 0;\n>         revs->first_parent_merges = 0;\n>         revs->combine_merges = 0;\n> @@ -10,17 +11,20 @@ static void suppress(struct rev_info *revs) {\n>         revs->combined_all_paths = 0;\n>  }\n>\n> -static void set_separate(struct rev_info *revs) {\n> +static void set_separate(struct rev_info *revs)\n> +{\n>         suppress(revs);\n>         revs->separate_merges = 1;\n>  }\n>\n> -static void set_first_parent(struct rev_info *revs) {\n> +static void set_first_parent(struct rev_info *revs)\n> +{\n>         set_separate(revs);\n>         revs->first_parent_merges = 1;\n>  }\n>\n> -static void set_m(struct rev_info *revs) {\n> +static void set_m(struct rev_info *revs)\n> +{\n>         /*\n>          * To \"diff-index\", \"-m\" means \"match missing\", and to the \"log\"\n>          * family of commands, it means \"show full diff for merges\". Set\n> @@ -30,19 +34,22 @@ static void set_m(struct rev_info *revs) {\n>         revs->match_missing = 1;\n>  }\n>\n> -static void set_combined(struct rev_info *revs) {\n> +static void set_combined(struct rev_info *revs)\n> +{\n>         suppress(revs);\n>         revs->combine_merges = 1;\n>         revs->dense_combined_merges = 0;\n>  }\n>\n> -static void set_dense_combined(struct rev_info *revs) {\n> +static void set_dense_combined(struct rev_info *revs)\n> +{\n>         suppress(revs);\n>         revs->combine_merges = 1;\n>         revs->dense_combined_merges = 1;\n>  }\n>\n> -static void set_diff_merges(struct rev_info *revs, const char *optarg) {\n> +static void set_diff_merges(struct rev_info *revs, const char *optarg)\n> +{\n>         if (0) ;\n>         else if (!strcmp(optarg, \"off\")   || !strcmp(optarg, \"none\"))\n>                 suppress(revs);\n> @@ -62,7 +69,8 @@ static void set_diff_merges(struct rev_info *revs, const char *optarg) {\n>   * Public functions. They are in the order they are called.\n>   */\n>\n> -int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {\n> +int diff_merges_parse_opts(struct rev_info *revs, const char **argv)\n> +{\n>         int argcount = 1;\n>         const char *optarg;\n>         const char *arg = argv[0];\n> @@ -86,23 +94,27 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) {\n>         return argcount;\n>  }\n>\n> -void diff_merges_suppress(struct rev_info *revs) {\n> +void diff_merges_suppress(struct rev_info *revs)\n> +{\n>         suppress(revs);\n>  }\n>\n> -void diff_merges_default_to_first_parent(struct rev_info *revs) {\n> +void diff_merges_default_to_first_parent(struct rev_info *revs)\n> +{\n>         if (!revs->explicit_diff_merges)\n>                 revs->separate_merges = 1;\n>         if (revs->separate_merges)\n>                 revs->first_parent_merges = 1;\n>  }\n>\n> -void diff_merges_default_to_dense_combined(struct rev_info *revs) {\n> +void diff_merges_default_to_dense_combined(struct rev_info *revs)\n> +{\n>         if (!revs->explicit_diff_merges)\n>                 set_dense_combined(revs);\n>  }\n>\n> -void diff_merges_set_dense_combined_if_unset(struct rev_info *revs) {\n> +void diff_merges_set_dense_combined_if_unset(struct rev_info *revs)\n> +{\n>         if (!revs->combine_merges)\n>                 set_dense_combined(revs);\n>  }\n> --\n> 2.25.1\n>\n\nBut...didn't you add all these functions yourself earlier in the\nseries?  Why didn't you split this patch up and squash it into the\nrelevant previous patches?\n"},{"id":"412534","messageId":"CABPp-BFRPFxm=SuJFwfG+QYCivMKp2VRpnHGwxNL+extK7UdtA@mail.gmail.com","threadId":"54550","inReplyTo":"20201216184929.3924-30-sorganov@gmail.com","subject":"Re: [PATCH v2 29/33] doc/git-log: describe new --diff-merges options","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2020-12-18T05:53:51Z","receivedAt":"2020-12-18T05:54:44Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Wed, Dec 16, 2020 at 10:50 AM Sergey Organov <sorganov@gmail.com> wrote:\n>\n> Describe all the new --diff-merges options in the git-log.txt and\n> adopt description of originals accordingly.\n\nYou also took care to explain interactions of options with -p that\nwere previously undocumented, which is a nice bonus.  That wording\ncould still be improved a bit, though, as noted below.\n\n> Signed-off-by: Sergey Organov <sorganov@gmail.com>\n> ---\n>  Documentation/git-log.txt | 85 ++++++++++++++++++++++++---------------\n>  1 file changed, 52 insertions(+), 33 deletions(-)\n>\n> diff --git a/Documentation/git-log.txt b/Documentation/git-log.txt\n> index 2b8ac5ff882a..27bc619490c6 100644\n> --- a/Documentation/git-log.txt\n> +++ b/Documentation/git-log.txt\n> @@ -120,45 +120,64 @@ DIFF FORMATTING\n>  By default, `git log` does not generate any diff output. The options\n>  below can be used to show the changes made by each commit.\n>\n> -Note that unless one of `-c`, `--cc`, or `-m` is given, merge commits\n> -will never show a diff, even if a diff format like `--patch` is\n> -selected, nor will they match search options like `-S`. The exception is\n> -when `--first-parent` is in use, in which merges are treated like normal\n> -single-parent commits (this can be overridden by providing a\n> -combined-diff option or with `--no-diff-merges`).\n> +Note that unless one of `--diff-merges` variants (including short\n> +`-m`, `-c`, and `--cc` options) is explicitly given, merge commits\n> +will not show a diff, even if a diff format like `--patch` is\n> +selected, nor will they match search options like `-S`. The exception\n> +is when `--first-parent` is in use, in which case `first-parent` is\n> +the default format.\n\nThanks for fixing this up.  :-)\n\n>\n> --c::\n> -       With this option, diff output for a merge commit\n> -       shows the differences from each of the parents to the merge result\n> -       simultaneously instead of showing pairwise diff between a parent\n> -       and the result one at a time. Furthermore, it lists only files\n> -       which were modified from all parents.\n> -\n> ---cc::\n> -       This flag implies the `-c` option and further compresses the\n> -       patch output by omitting uninteresting hunks whose contents in\n> -       the parents have only two variants and the merge result picks\n> -       one of them without modification.\n> +--diff-merges=(off|none|first-parent|1|separate|m|combined|c|dense-combined|cc)::\n> +--no-diff-merges::\n> +       Specify diff format to be used for merge commits. Default is\n> +       `off` unless `--first-parent` is in use, in which case\n> +       `first-parent` is the default.\n> ++\n> +--diff-merges=(off|none):::\n> +--no-diff-merges:::\n> +       Disable output of diffs for merge commits. Useful to override\n> +       implied value.\n> ++\n> +--diff-merges=first-parent:::\n> +--diff-merges=1:::\n> +       This option makes merge commits show the full diff with\n> +       respect to the first parent only.\n\nDoes it imply -p?\n\n> ++\n> +--diff-merges=separate:::\n> +--diff-merges=m:::\n> +-m:::\n> +       This makes merge commits show the full diff with respect to\n> +       each of the parents. Separate log entry and diff is generated\n> +       for each parent. `-m` is different in that it doesn't produce\n> +       any output without `-p`.\n\nDifferent from what?  From --first-parent?  From flags that haven't\nbeen covered yet?  (-c and --cc show up below)\n\n> ++\n> +--diff-merges=combined:::\n> +--diff-merges=c:::\n> +-c:::\n> +       With this option, diff output for a merge commit shows the\n> +       differences from each of the parents to the merge result\n> +       simultaneously instead of showing pairwise diff between a\n> +       parent and the result one at a time. Furthermore, it lists\n> +       only files which were modified from all parents. Historically,\n> +       `-c` enables diff output for non-merge commits as well.\n\n\"Historically\"?  Does that mean it doesn't anymore?  (Maybe, \"The\nshort form, `-c`, also enables diff output for non-merge commits as\nwell.\" or something like that?)\n\n> ++\n> +--diff-merges=dense-combined:::\n> +--diff-merges=cc:::\n> +--cc:::\n> +       With this option the output produced by\n> +       `--diff-merges=combined` is further compressed by omitting\n> +       uninteresting hunks whose contents in the parents have only\n> +       two variants and the merge result picks one of them without\n> +       modification.  Historically, `--c` enables diff output for\n> +       non-merge commits as well.\n\nSame note as above.\n\n>  --combined-all-paths::\n>         This flag causes combined diffs (used for merge commits) to\n>         list the name of the file from all parents.  It thus only has\n> -       effect when -c or --cc are specified, and is likely only\n> -       useful if filename changes are detected (i.e. when either\n> -       rename or copy detection have been requested).\n> +       effect when `--diff-merges=[dense-]combined` is in use, and\n> +       is likely only useful if filename changes are detected (i.e.\n> +       when either rename or copy detection have been requested).\n>\n> --m::\n> -       This flag makes the merge commits show the full diff like\n> -       regular commits; for each merge parent, a separate log entry\n> -       and diff is generated. An exception is that only diff against\n> -       the first parent is shown when `--first-parent` option is given;\n> -       in that case, the output represents the changes the merge\n> -       brought _into_ the then-current branch.\n> -\n> ---diff-merges=off::\n> ---no-diff-merges::\n> -       Disable output of diffs for merge commits (default). Useful to\n> -       override `-m`, `-c`, or `--cc`.\n>\n>  :git-log: 1\n>  include::diff-options.txt[]\n> --\n> 2.25.1\n\nThe rest looks good.\n"},{"id":"412536","messageId":"CABPp-BHh4VSTQ=VOzik5H34OcJaQ63wSgPgrZqJ5-_XvBSow+g@mail.gmail.com","threadId":"54550","inReplyTo":"20201216184929.3924-25-sorganov@gmail.com","subject":"Re: [PATCH v2 24/33] diff-merges: handle imply -p on -c/--cc logic for log.c","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2020-12-18T06:00:54Z","receivedAt":"2020-12-18T06:02:03Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Wed, Dec 16, 2020 at 10:50 AM Sergey Organov <sorganov@gmail.com> wrote:\n>\n> Move logic that handles implying -p on -c/--cc from\n> log_setup_revisions_tweak() to diff_merges_setup_revs(), where it\n> belongs.\n\nA very minor point, but I'd probably drop the \"where it belongs\";\nwhile I think the new place makes sense for it, it reads to me like\nyou're either relying on a consensus to move it or implying there was\na mistake to not put it here previously, neither of which makes sense.\n\nMuch more importantly, this patch doesn't do what you said in\ndiscussions on the previous round.  It'd be helpful if the commit\nmessage called out that you are just moving the logic for now and that\na subsequent patch will tweak the logic to only trigger this for\n-c/--cc and not for --diff-merges=.* flags.\n\n\n> Signed-off-by: Sergey Organov <sorganov@gmail.com>\n> ---\n>  builtin/log.c | 4 ----\n>  diff-merges.c | 7 ++++++-\n>  2 files changed, 6 insertions(+), 5 deletions(-)\n>\n> diff --git a/builtin/log.c b/builtin/log.c\n> index 63875c3aeec9..c3caf0955b2b 100644\n> --- a/builtin/log.c\n> +++ b/builtin/log.c\n> @@ -723,10 +723,6 @@ static void log_setup_revisions_tweak(struct rev_info *rev,\n>             rev->prune_data.nr == 1)\n>                 rev->diffopt.flags.follow_renames = 1;\n>\n> -       /* Turn --cc/-c into -p --cc/-c when -p was not given */\n> -       if (!rev->diffopt.output_format && rev->combine_merges)\n> -               rev->diffopt.output_format = DIFF_FORMAT_PATCH;\n> -\n>         if (rev->first_parent_only)\n>                 diff_merges_default_to_first_parent(rev);\n>  }\n> diff --git a/diff-merges.c b/diff-merges.c\n> index 0165fa22fcd1..2ac25488d53e 100644\n> --- a/diff-merges.c\n> +++ b/diff-merges.c\n> @@ -127,6 +127,11 @@ void diff_merges_setup_revs(struct rev_info *revs)\n>                 revs->first_parent_merges = 0;\n>         if (revs->combined_all_paths && !revs->combine_merges)\n>                 die(\"--combined-all-paths makes no sense without -c or --cc\");\n> -       if (revs->combine_merges)\n> +       if (revs->combine_merges) {\n>                 revs->diff = 1;\n> +               /* Turn --cc/-c into -p --cc/-c when -p was not given */\n> +               if (!revs->diffopt.output_format)\n> +                       revs->diffopt.output_format = DIFF_FORMAT_PATCH;\n> +       }\n> +\n>  }\n> --\n> 2.25.1\n>\n"},{"id":"412537","messageId":"CABPp-BHu2xLZLfwBg+hzNEKQ0K=EyT1HLqJO9=pNzBFf4MqR=A@mail.gmail.com","threadId":"54550","inReplyTo":"20201216184929.3924-27-sorganov@gmail.com","subject":"Re: [PATCH v2 26/33] diff-merges: let new options enable diff without -p","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2020-12-18T06:12:11Z","receivedAt":"2020-12-18T06:13:20Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Wed, Dec 16, 2020 at 10:50 AM Sergey Organov <sorganov@gmail.com> wrote:\n>\n> New options don't have any visible effect unless -p is either given or\n> implied, as unlike -c/-cc we don't imply -p with --diff-merges. To fix\n> this, this patch adds new functionality by letting new options enable\n> output of diffs for merge commits only.\n>\n> Add 'merges_need_diff' field and set it whenever diff output for merges is\n> enabled by any of the new options.\n>\n> Extend diff output logic accordingly, to output diffs for merges when\n> 'merges_need_diff' is set even when no -p has been provided.\n>\n> Signed-off-by: Sergey Organov <sorganov@gmail.com>\n> ---\n>  diff-merges.c | 16 ++++++++++------\n>  log-tree.c    | 13 +++++++++----\n>  revision.h    |  1 +\n>  3 files changed, 20 insertions(+), 10 deletions(-)\n>\n> diff --git a/diff-merges.c b/diff-merges.c\n> index 725db2312074..ffe20d8daa4a 100644\n> --- a/diff-merges.c\n> +++ b/diff-merges.c\n> @@ -10,6 +10,7 @@ static void suppress(struct rev_info *revs)\n>         revs->dense_combined_merges = 0;\n>         revs->combined_all_paths = 0;\n>         revs->combined_imply_patch = 0;\n> +       revs->merges_need_diff = 0;\n>  }\n>\n>  static void set_separate(struct rev_info *revs)\n> @@ -51,9 +52,11 @@ static void set_dense_combined(struct rev_info *revs)\n>\n>  static void set_diff_merges(struct rev_info *revs, const char *optarg)\n>  {\n\n> +       if (!strcmp(optarg, \"off\") || !strcmp(optarg, \"none\")) {\n> +               suppress(revs);\n> +               return;\n> +       }\n>         if (0) ;\n> -       else if (!strcmp(optarg, \"off\")   || !strcmp(optarg, \"none\"))\n> -               suppress(revs);\n\nThe \"if (0) ;\" is still really weird.\n\n>         else if (!strcmp(optarg, \"first\") || !strcmp(optarg, \"first-parent\"))\n>                 set_first_parent(revs);\n>         else if (!strcmp(optarg, \"sep\")   || !strcmp(optarg, \"separate\"))\n> @@ -64,6 +67,7 @@ static void set_diff_merges(struct rev_info *revs, const char *optarg)\n>                 set_dense_combined(revs);\n>         else\n>                 die(_(\"unknown value for --diff-merges: %s\"), optarg);\n> +       revs->merges_need_diff = 1;\n\nI'd put this above the if-else-else block, to make it clearer why you\nare returning early for the \"off\"/\"none\" case.\n\n>  }\n>\n>  /*\n> @@ -132,12 +136,12 @@ void diff_merges_setup_revs(struct rev_info *revs)\n>                 revs->first_parent_merges = 0;\n>         if (revs->combined_all_paths && !revs->combine_merges)\n>                 die(\"--combined-all-paths makes no sense without -c or --cc\");\n> -       if (revs->combine_merges)\n> +\n> +       if (revs->combined_imply_patch)\n>                 revs->diff = 1;\n> -       if (revs->combined_imply_patch) {\n> -               /* Turn --cc/-c into -p --cc/-c when -p was not given */\n> +\n> +       if (revs->combined_imply_patch || revs->merges_need_diff) {\n>                 if (!revs->diffopt.output_format)\n>                         revs->diffopt.output_format = DIFF_FORMAT_PATCH;\n>         }\n> -\n\nThe random space changes squashed in here instead of being combined\nwith the earlier patches that introduced the relevant areas break up\nthe reading.  Would be nice to clean this up.\n\n>  }\n> diff --git a/log-tree.c b/log-tree.c\n> index f9385b1dae6f..67060492ca0a 100644\n> --- a/log-tree.c\n> +++ b/log-tree.c\n> @@ -899,15 +899,21 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log\n>         int showed_log;\n>         struct commit_list *parents;\n>         struct object_id *oid;\n> +       int is_merge;\n> +       int regulars_need_diff = opt->diff || opt->diffopt.flags.exit_with_status;\n\nSo rev_info.diff has changed in meaning from\ncommits-need-to-show-a-diff, to non-merge-commits-need-to-show-a-diff.\nThat's a somewhat subtle semantic shift.  Perhaps it's worth adding a\ncomment to the declaration of rev_info.diff to highlight this?  (And\nperhaps even rename the flag?)\n\n> -       if (!opt->diff && !opt->diffopt.flags.exit_with_status)\n> +       if (!regulars_need_diff && !opt->merges_need_diff)\n>                 return 0;\n>\n>         parse_commit_or_die(commit);\n>         oid = get_commit_tree_oid(commit);\n>\n> -       /* Root commit? */\n>         parents = get_saved_parents(opt, commit);\n> +       is_merge = parents && parents->next;\n> +       if(!is_merge && !regulars_need_diff)\n> +               return 0;\n> +\n> +       /* Root commit? */\n>         if (!parents) {\n>                 if (opt->show_root_diff) {\n>                         diff_root_tree_oid(oid, \"\", &opt->diffopt);\n> @@ -916,8 +922,7 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log\n>                 return !opt->loginfo;\n>         }\n>\n> -       /* More than one parent? */\n> -       if (parents->next) {\n> +       if (is_merge) {\n>                 if (opt->combine_merges)\n>                         return do_diff_combined(opt, commit);\n>                 if (opt->separate_merges) {\n> diff --git a/revision.h b/revision.h\n> index bfbae526ad6e..494d86142454 100644\n> --- a/revision.h\n> +++ b/revision.h\n> @@ -194,6 +194,7 @@ struct rev_info {\n>                         always_show_header:1,\n>                         /* Diff-merge flags */\n>                         explicit_diff_merges: 1,\n> +                       merges_need_diff: 1,\n>                         separate_merges: 1,\n>                         combine_merges:1,\n>                         combined_all_paths:1,\n> --\n> 2.25.1\n\nThe rest makes sense.\n"},{"id":"412541","messageId":"CABPp-BExc7rBCVEvLLs1u_hXurDTtWxTKg0ZN0+PA-21u_ShkA@mail.gmail.com","threadId":"54550","inReplyTo":"20201216184929.3924-29-sorganov@gmail.com","subject":"Re: [PATCH v2 28/33] diff-merges: add '--diff-merges=1' as synonym for 'first-parent'","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2020-12-18T06:19:40Z","receivedAt":"2020-12-18T06:20:33Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Wed, Dec 16, 2020 at 10:50 AM Sergey Organov <sorganov@gmail.com> wrote:\n>\n> As we now have --diff-merges={m|c|cc}, add --diff-merges=1 as synonym\n> for --diff-merges=first-parent, to have shorter mnemonics for it as\n> well.\n\nIn all the other cases, --diff-merges=<short> is equivalent to\n-<short>.  Here, --diff-merges=1 and -1 do _very_ different things.\nIs there any concern that might cause confusion?  (My gut reaction is\nthis is probably fine and people won't try to make such a connection,\nbut it made me worry just enough that I thought I'd flag it for you\nand other reviewers to at least mull over and maybe comment on.)\n\n> Signed-off-by: Sergey Organov <sorganov@gmail.com>\n> ---\n>  diff-merges.c | 3 ++-\n>  1 file changed, 2 insertions(+), 1 deletion(-)\n>\n> diff --git a/diff-merges.c b/diff-merges.c\n> index 9492cd2b871d..63a0d78b7730 100644\n> --- a/diff-merges.c\n> +++ b/diff-merges.c\n> @@ -57,7 +57,8 @@ static void set_diff_merges(struct rev_info *revs, const char *optarg)\n>                 return;\n>         }\n>         if (0) ;\n> -       else if (!strcmp(optarg, \"first\") || !strcmp(optarg, \"first-parent\"))\n> +       else if (!strcmp(optarg, \"first\") || !strcmp(optarg, \"first-parent\") ||\n> +                !strcmp(optarg, \"1\"))\n>                 set_first_parent(revs);\n>         else if (!strcmp(optarg, \"sep\")   || !strcmp(optarg, \"separate\") ||\n>                  !strcmp(optarg, \"m\"))\n> --\n> 2.25.1\n>\n"},{"id":"412544","messageId":"CABPp-BH_p50rNgpirpvPSK4ZnPTm4c62iothOF1Qa_7E1_EfFQ@mail.gmail.com","threadId":"54550","inReplyTo":"20201216184929.3924-1-sorganov@gmail.com","subject":"Re: [PATCH v2 00/33] git-log: implement new --diff-merge options","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2020-12-18T06:54:12Z","receivedAt":"2020-12-18T06:55:06Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Wed, Dec 16, 2020 at 10:50 AM Sergey Organov <sorganov@gmail.com> wrote:\n>\n> These patch series implement new set of options governing diff output\n> of merge commits, all under the umbrella of single\n> --diff-merges=<mode> option.\n\nWith this round, I was hoping to get a range-diff (using the\n--range-diff option to format-patch), so I could more easily see what\nwas new.  Since I've been updating frequently enough, I was able to\ngenerate this locally using Junio's published so/log-diff-merge topic,\nbut it'd be helpful if you could include it in any future rounds.\n\nWith your previous patch series, I scanned most the patches somewhat\nbriefly but looked at the final patches more closely (the series is\nkind of long, and I noticed Junio had started reviewing the early part\nof the series, so I figured it might be most helpful to jump in and\ncover the end in case he didn't get that far).  With this round, I\nread through the range-diff, and then looked at all the new patches\nand have left a number of comments.  I think Junio reviewed the first\n8 or so patches of an earlier round, so patches 9-21 probably could\nbenefit from someone reviewing more closely.\n\nOverall, I like the direction of the series.  I think it'll make it\neasier to add --remerge-diff later since it simplifies getting the\ninteraction between it and -m/-c/--cc/--first-parent right.  It also\nadds some new capabilities you want (--diff-merges=first-parent, to\nshow merges as diff against first parent without only traversing first\nparents), and that Junio wants (--diff-merges=dense-combined, to only\nshow merges for diffs without showing diffs for non-merge commits).\n\n> Unlike original -c/--cc options, these new options do not imply -p,\n> thus allowing for getting diffs for merge commits without provoking of\n> diff output for regular, non-merge commits. E.g.:\n>\n>   git log --diff-merges=cc\n>\n> will output diffs (in dense-combined format) only for merge commits,\n> whereas:\n>\n>   git log --cc\n>\n> enables diffs for all the commits being output, either merges or\n> simple ones.\n>\n> There is also another additional functionality provided, allowing to\n> get the format of \"-p --first-parent\" without change in history\n> traversal that --first-parent option causes, like this:\n>\n>   git log --diff-merges=first-parent\n>\n> The net result of these series are the following new options:\n>\n> --diff-merges=    |  rough original equivalent\n> ------------------+----------------\n> 1|first-parent    | --first-parent (only diff format implications)\n> m|separate        | -m and enable diff for merges\n> c|combined        | -c and enable diff for merges, but not for regulars\n> cc|dense-combined | --cc and enable diff for merges, but not for\n>                   |      regulars\n>\n> The series also cleanup logic of handling of diff merges options and\n> fix an issue found in the original implementation where logically\n> mutually exclusive options -m/-c/--cc failed to actually override each\n> other. Neither semantics of these old options nor their interactions\n> with other options, such as --first-parent and -p, is supposed to be\n> changed.\n>\n> The series start with the set of pure refactoring commits that are expected\n> to introduce no functional changes. These are all commits up to and\n> including:\n>\n> \"diff-merges: revise revs->diff flag handling\"\n>\n> The aim of these commits is to isolate options handling for diff merges so\n> that it could be easily understood and tweaked to ease introduction of the\n> new options.\n>\n> Then the fix of -m/-c/-cc overriding issue follows, starting with a failing\n> test and followed by the fix.\n>\n> Then follows a little bit of additional refactoring in order to\n> prepare for introduction of the new options, and finally the series\n> are finished by the implementation, documentation updates, and\n> some testing for the new options.\n>\n> Updates in v2:\n>\n>   * Move logic of \"-c/--cc imply -p\" to this module and do not imply\n>     -p by new --diff-merges options. Instead enable corresponding diff\n>     output without affecting non-merge commits. This is the most\n>     significant change with respect to v1 and it starts at 24/33.\n>\n>   * Add support for old mnemonics: --diff-merges=(m|c|cc) to help\n>     those who are used to them, and add --diff-merges=1 to cover all\n>     variants with short mnemonics.\n>\n>   * Fixed functions definitions style to have open curly brace on its\n>     own line, pointed to by Junio C Hamano.\n>\n>   * Tweak --diff-merges=first-parent description, requested by Elijah\n>     Newren.\n>\n>   * Fixed git-show documentation not to include description chunk\n>     relevant to git-log only, noticed by Elijah Newren.\n>\n>   * Fixed documentation mistake claiming that -p is needed for\n>     diff-merges options to take effect, noticed by Elijah Newren.\n>\n>   * Fixed a case where a change was put into wrong commit. The change\n>     moved to 11/27 form 10/27. Didn't affect end-result in any way.\n>\n>   * Added short module description to diff-merges.h, as suggested by\n>     Junio C Hamano.\n>\n>   * Fixed not returning \"argcount\" from diff_merges_parse_opts(),\n>     noticed by Junio C Hamano.\n>\n> Updates in v1:\n>\n>   * Added documentation fix for git-show to include --diff-merges.\n>\n>   * Fixed typos in commit messages noticed by Philip Oakley.\n>\n> Sergey Organov (33):\n>   revision: factor out parsing of diff-merge related options\n>   revision: factor out setup of diff-merge related settings\n>   revision: factor out initialization of diff-merge related settings\n>   revision: provide implementation for diff merges tweaks\n>   revision: move diff merges functions to its own diff-merges.c\n>   diff-merges: rename all functions to have common prefix\n>   diff-merges: move checks for first_parent_only out of the module\n>   diff-merges: rename diff_merges_default_to_enable() to match semantics\n>   diff-merges: re-arrange functions to match the order they are called\n>     in\n>   diff-merges: new function diff_merges_suppress()\n>   diff-merges: new function diff_merges_set_dense_combined_if_unset()\n>   diff-merges: introduce revs->first_parent_merges flag\n>   diff-merges: revise revs->diff flag handling\n>   t4013: support test_expect_failure through ':failure' magic\n>   t4013: add tests for -m failing to override -c/--cc\n>   diff-merges: fix -m to properly override -c/--cc\n>   diff-merges: split 'ignore_merges' field\n>   diff-merges: group diff-merge flags next to each other inside\n>     'rev_info'\n>   diff-merges: get rid of now empty diff_merges_init_revs()\n>   diff-merges: refactor opt settings into separate functions\n>   diff-merges: make -m/-c/--cc explicitly mutually exclusive\n>   diff-merges: implement new values for --diff-merges\n>   diff-merges: fix style of functions definitions\n>   diff-merges: handle imply -p on -c/--cc logic for log.c\n>   diff-merges: do not imply -p for new options\n>   diff-merges: let new options enable diff without -p\n>   diff-merges: add old mnemonic counterparts to --diff-merges\n>   diff-merges: add '--diff-merges=1' as synonym for 'first-parent'\n>   doc/git-log: describe new --diff-merges options\n>   doc/diff-generate-patch: mention new --diff-merges option\n>   doc/rev-list-options: document --first-parent changes merges format\n>   doc/git-show: include --diff-merges description\n>   t4013: add tests for --diff-merges=first-parent\n>\n>  Documentation/diff-generate-patch.txt         |   6 +-\n>  Documentation/diff-options.txt                |  53 +++++\n>  Documentation/git-log.txt                     |  46 +---\n>  Documentation/git-show.txt                    |   7 +-\n>  Documentation/rev-list-options.txt            |   5 +\n>  Makefile                                      |   1 +\n>  builtin/diff-files.c                          |   5 +-\n>  builtin/diff.c                                |   9 +-\n>  builtin/log.c                                 |  22 +-\n>  builtin/merge.c                               |   3 +-\n>  diff-merges.c                                 | 151 +++++++++++++\n>  diff-merges.h                                 |  24 +++\n>  fmt-merge-msg.c                               |   3 +-\n>  log-tree.c                                    |  30 +--\n>  revision.c                                    |  38 +---\n>  revision.h                                    |   9 +-\n>  t/t4013-diff-various.sh                       |  11 +-\n>  t/t4013/diff.log_--cc_-m_-p_master            | 200 ++++++++++++++++++\n>  ...diff.log_--diff-merges=first-parent_master |  56 +++++\n>  t/t4013/diff.log_-c_-m_-p_master              | 200 ++++++++++++++++++\n>  ...f.log_-p_--diff-merges=first-parent_master | 137 ++++++++++++\n>  21 files changed, 900 insertions(+), 116 deletions(-)\n>  create mode 100644 diff-merges.c\n>  create mode 100644 diff-merges.h\n>  create mode 100644 t/t4013/diff.log_--cc_-m_-p_master\n>  create mode 100644 t/t4013/diff.log_--diff-merges=first-parent_master\n>  create mode 100644 t/t4013/diff.log_-c_-m_-p_master\n>  create mode 100644 t/t4013/diff.log_-p_--diff-merges=first-parent_master\n>\n> --\n> 2.25.1\n>\n"},{"id":"412560","messageId":"87czz7cjxu.fsf@osv.gnss.ru","threadId":"54550","inReplyTo":"CABPp-BH_p50rNgpirpvPSK4ZnPTm4c62iothOF1Qa_7E1_EfFQ@mail.gmail.com","subject":"Re: [PATCH v2 00/33] git-log: implement new --diff-merge options","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-18T13:39:25Z","receivedAt":"2020-12-18T13:40:26Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Hi Elijah,\n\nThanks a lot for reviewing the series!\n\nElijah Newren <newren@gmail.com> writes:\n\n> On Wed, Dec 16, 2020 at 10:50 AM Sergey Organov <sorganov@gmail.com> wrote:\n>>\n>> These patch series implement new set of options governing diff output\n>> of merge commits, all under the umbrella of single\n>> --diff-merges=<mode> option.\n>\n> With this round, I was hoping to get a range-diff (using the\n> --range-diff option to format-patch), so I could more easily see what\n> was new.  Since I've been updating frequently enough, I was able to\n> generate this locally using Junio's published so/log-diff-merge topic,\n> but it'd be helpful if you could include it in any future rounds.\n\nWell, documentation on contributing doesn't seem to mention this. I'll\ntry to learn it for the future though, thanks!\n\n>\n> With your previous patch series, I scanned most the patches somewhat\n> briefly but looked at the final patches more closely (the series is\n> kind of long, and I noticed Junio had started reviewing the early part\n> of the series, so I figured it might be most helpful to jump in and\n> cover the end in case he didn't get that far).  With this round, I\n> read through the range-diff, and then looked at all the new patches\n> and have left a number of comments.  I think Junio reviewed the first\n> 8 or so patches of an earlier round, so patches 9-21 probably could\n> benefit from someone reviewing more closely.\n>\n> Overall, I like the direction of the series.  I think it'll make it\n> easier to add --remerge-diff later since it simplifies getting the\n> interaction between it and -m/-c/--cc/--first-parent right.  It also\n> adds some new capabilities you want (--diff-merges=first-parent, to\n> show merges as diff against first parent without only traversing first\n> parents), and that Junio wants (--diff-merges=dense-combined, to only\n> show merges for diffs without showing diffs for non-merge commits).\n\nYeah, I hoped to address everything that has been discussed.\n\n[...]\n\nThanks,\n-- Sergey\n"},{"id":"412561","messageId":"87blercju2.fsf@osv.gnss.ru","threadId":"54550","inReplyTo":"CABPp-BEf2nbahjzR6aLLNy0YsHYcHqCozCe6veoZOH3LAM892g@mail.gmail.com","subject":"Re: [PATCH v2 23/33] diff-merges: fix style of functions definitions","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-18T13:41:41Z","receivedAt":"2020-12-18T13:42:27Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Elijah Newren <newren@gmail.com> writes:\n\n> On Wed, Dec 16, 2020 at 10:50 AM Sergey Organov <sorganov@gmail.com> wrote:\n>>\n>> Put open curly brace on its own line\n>>\n>> Signed-off-by: Sergey Organov <sorganov@gmail.com>\n>> ---\n>>  diff-merges.c | 36 ++++++++++++++++++++++++------------\n>>  1 file changed, 24 insertions(+), 12 deletions(-)\n>>\n>> diff --git a/diff-merges.c b/diff-merges.c\n>> index cba391604ac7..0165fa22fcd1 100644\n>> --- a/diff-merges.c\n>> +++ b/diff-merges.c\n>> @@ -2,7 +2,8 @@\n>>\n\n[...]\n\n>>\n>> -void diff_merges_set_dense_combined_if_unset(struct rev_info *revs) {\n>> +void diff_merges_set_dense_combined_if_unset(struct rev_info *revs)\n>> +{\n>>         if (!revs->combine_merges)\n>>                 set_dense_combined(revs);\n>>  }\n>> --\n>> 2.25.1\n>>\n>\n> But...didn't you add all these functions yourself earlier in the\n> series?\n\nYes, I did indeed and somehow picked wrong style from one of the\noccurrences of this style in the existing Git codebase.\n\n> Why didn't you split this patch up and squash it into the\n> relevant previous patches?\n\nWhen Junio noticed and pointed to this deficiency, I asked him if I\nshould fix all the series from the start, or it'd be OK to use fixup\ncommit. As he didn't answer and nobody else commented either, I opted\nfor the latter.\n\nI can still do it if it's that essential, but I'd prefer not to, to\navoid both the hand-work and causing entire series to change. The\nproblem is that there were code movements in the series, so such a fix\nto earlier patches would cause conflicts down the commits chain, to be\nresolved by hand.\n\nThanks,\n-- Sergey\n"},{"id":"412562","messageId":"875z4zciwd.fsf@osv.gnss.ru","threadId":"54550","inReplyTo":"CABPp-BHh4VSTQ=VOzik5H34OcJaQ63wSgPgrZqJ5-_XvBSow+g@mail.gmail.com","subject":"Re: [PATCH v2 24/33] diff-merges: handle imply -p on -c/--cc logic for log.c","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-18T14:01:54Z","receivedAt":"2020-12-18T14:02:40Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Elijah Newren <newren@gmail.com> writes:\n\n> On Wed, Dec 16, 2020 at 10:50 AM Sergey Organov <sorganov@gmail.com> wrote:\n>>\n>> Move logic that handles implying -p on -c/--cc from\n>> log_setup_revisions_tweak() to diff_merges_setup_revs(), where it\n>> belongs.\n>\n> A very minor point, but I'd probably drop the \"where it belongs\";\n> while I think the new place makes sense for it, it reads to me like\n> you're either relying on a consensus to move it or implying there was\n> a mistake to not put it here previously, neither of which makes sense.\n\nWell, it was meant to be an excuse for not moving it there earlier in\nthe patch series indeed. I just overlooked this piece of code that\nlogically belongs to the diff-merges module. I think you need to\nconsider the state of the sources right before this patch to see the\npoint of phrasing it like this.\n\nThat said, I'm fine removing this either.\n\n> Much more importantly, this patch doesn't do what you said in\n> discussions on the previous round.  It'd be helpful if the commit\n> message called out that you are just moving the logic for now and that\n> a subsequent patch will tweak the logic to only trigger this for\n> -c/--cc and not for --diff-merges=.* flags.\n\nI believe this patch is useful by itself, even without any future\nimprovements (that we actually discussed), if any, so I don't see the\npoint in describing what this patch doesn't do.\n\nOTOH, the commit message seems to be clear enough to expect this patch\nto be pure refactoring, without any functional changes, no?\n\nThanks,\n-- Sergey\n\n>\n>\n>> Signed-off-by: Sergey Organov <sorganov@gmail.com>\n>> ---\n>>  builtin/log.c | 4 ----\n>>  diff-merges.c | 7 ++++++-\n>>  2 files changed, 6 insertions(+), 5 deletions(-)\n>>\n>> diff --git a/builtin/log.c b/builtin/log.c\n>> index 63875c3aeec9..c3caf0955b2b 100644\n>> --- a/builtin/log.c\n>> +++ b/builtin/log.c\n>> @@ -723,10 +723,6 @@ static void log_setup_revisions_tweak(struct rev_info *rev,\n>>             rev->prune_data.nr == 1)\n>>                 rev->diffopt.flags.follow_renames = 1;\n>>\n>> -       /* Turn --cc/-c into -p --cc/-c when -p was not given */\n>> -       if (!rev->diffopt.output_format && rev->combine_merges)\n>> -               rev->diffopt.output_format = DIFF_FORMAT_PATCH;\n>> -\n>>         if (rev->first_parent_only)\n>>                 diff_merges_default_to_first_parent(rev);\n>>  }\n>> diff --git a/diff-merges.c b/diff-merges.c\n>> index 0165fa22fcd1..2ac25488d53e 100644\n>> --- a/diff-merges.c\n>> +++ b/diff-merges.c\n>> @@ -127,6 +127,11 @@ void diff_merges_setup_revs(struct rev_info *revs)\n>>                 revs->first_parent_merges = 0;\n>>         if (revs->combined_all_paths && !revs->combine_merges)\n>>                 die(\"--combined-all-paths makes no sense without -c or --cc\");\n>> -       if (revs->combine_merges)\n>> +       if (revs->combine_merges) {\n>>                 revs->diff = 1;\n>> +               /* Turn --cc/-c into -p --cc/-c when -p was not given */\n>> +               if (!revs->diffopt.output_format)\n>> +                       revs->diffopt.output_format = DIFF_FORMAT_PATCH;\n>> +       }\n>> +\n>>  }\n>> --\n>> 2.25.1\n>>\n\n"},{"id":"412563","messageId":"871rfncie5.fsf@osv.gnss.ru","threadId":"54550","inReplyTo":"CABPp-BG1S83EUbqtqqjeLT4=Je44BpRMrf0MB+DNQK2wjRDbqQ@mail.gmail.com","subject":"Re: [PATCH v2 22/33] diff-merges: implement new values for --diff-merges","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-18T14:12:50Z","receivedAt":"2020-12-18T14:13:51Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Elijah Newren <newren@gmail.com> writes:\n\n> On Wed, Dec 16, 2020 at 10:50 AM Sergey Organov <sorganov@gmail.com> wrote:\n>>\n>> We first implement new options as exact synonyms for their original\n>> counterparts, to get all the infrastructure right, and keep functional\n>> improvements for later commits.\n>>\n>> The following values are implemented:\n>>\n>> --diff-merges=          old equivalent\n>> first|first-parent    = --first-parent (only format implications)\n>> sep|separate          = -m\n>> comb|combined         = -c\n>> dense| dense-combined = --cc\n>>\n>> Signed-off-by: Sergey Organov <sorganov@gmail.com>\n>> ---\n>>  diff-merges.c | 19 ++++++++++++++++---\n>>  1 file changed, 16 insertions(+), 3 deletions(-)\n>>\n>> diff --git a/diff-merges.c b/diff-merges.c\n>> index 6446e2093661..cba391604ac7 100644\n>> --- a/diff-merges.c\n>> +++ b/diff-merges.c\n>> @@ -15,6 +15,11 @@ static void set_separate(struct rev_info *revs) {\n>>         revs->separate_merges = 1;\n>>  }\n>>\n>> +static void set_first_parent(struct rev_info *revs) {\n>> +       set_separate(revs);\n>> +       revs->first_parent_merges = 1;\n>> +}\n>> +\n>>  static void set_m(struct rev_info *revs) {\n>>         /*\n>>          * To \"diff-index\", \"-m\" means \"match missing\", and to the \"log\"\n>> @@ -38,11 +43,19 @@ static void set_dense_combined(struct rev_info *revs) {\n>>  }\n>>\n>>  static void set_diff_merges(struct rev_info *revs, const char *optarg) {\n>> -       if (!strcmp(optarg, \"off\")) {\n>> +       if (0) ;\n>\n> Leftover cruft from some intermediate changes or something?\n\nNo. It's just an idiom for if-switch, making all the actual cases look\nthe same. Without this the first one looks special when in fact it\nisn't. I won't die for it though.\n\n>\n>> +       else if (!strcmp(optarg, \"off\")   || !strcmp(optarg, \"none\"))\n>>                 suppress(revs);\n>> -       } else {\n>> +       else if (!strcmp(optarg, \"first\") || !strcmp(optarg, \"first-parent\"))\n>> +               set_first_parent(revs);\n>> +       else if (!strcmp(optarg, \"sep\")   || !strcmp(optarg, \"separate\"))\n>> +               set_separate(revs);\n>> +       else if (!strcmp(optarg, \"comb\")  || !strcmp(optarg, \"combined\"))\n>> +               set_combined(revs);\n>> + else if (!strcmp(optarg, \"dense\") || !strcmp(optarg,\n>> \"dense-combined\"))\n>> +               set_dense_combined(revs);\n>> +       else\n>\n> Not sure I like the special-casing for \"sep\" and \"comb\".  \"dense\"\n> seems okay since it's a real word.\n\nThat was a poor-man attempt at unique shortcuts made by hand, as well as\na reminder to consider to re-write this using generic options framework\nthat will do it automagically. They are just a few first letters,\nnothing more. That's why I didn't even document them.\n\n> Since you're adding short versions of m, c, and cc later in the\n> series, do we need these other special-case forms?\n\nNo, I don't think we do necessarily need them, but then they do no harm\neither, so I didn't remove them when I added m, c, and cc. Neither was I\nsure we do need these m, c, and cc in the first place.\n\nThanks,\n-- Sergey\n"},{"id":"412564","messageId":"87wnxfb2gt.fsf@osv.gnss.ru","threadId":"54550","inReplyTo":"CABPp-BHu2xLZLfwBg+hzNEKQ0K=EyT1HLqJO9=pNzBFf4MqR=A@mail.gmail.com","subject":"Re: [PATCH v2 26/33] diff-merges: let new options enable diff without -p","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-18T14:42:10Z","receivedAt":"2020-12-18T14:42:56Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Elijah Newren <newren@gmail.com> writes:\n\n> On Wed, Dec 16, 2020 at 10:50 AM Sergey Organov <sorganov@gmail.com> wrote:\n>>\n>> New options don't have any visible effect unless -p is either given or\n>> implied, as unlike -c/-cc we don't imply -p with --diff-merges. To fix\n>> this, this patch adds new functionality by letting new options enable\n>> output of diffs for merge commits only.\n>>\n>> Add 'merges_need_diff' field and set it whenever diff output for merges is\n>> enabled by any of the new options.\n>>\n>> Extend diff output logic accordingly, to output diffs for merges when\n>> 'merges_need_diff' is set even when no -p has been provided.\n>>\n>> Signed-off-by: Sergey Organov <sorganov@gmail.com>\n>> ---\n>>  diff-merges.c | 16 ++++++++++------\n>>  log-tree.c    | 13 +++++++++----\n>>  revision.h    |  1 +\n>>  3 files changed, 20 insertions(+), 10 deletions(-)\n>>\n>> diff --git a/diff-merges.c b/diff-merges.c\n>> index 725db2312074..ffe20d8daa4a 100644\n>> --- a/diff-merges.c\n>> +++ b/diff-merges.c\n>> @@ -10,6 +10,7 @@ static void suppress(struct rev_info *revs)\n>>         revs->dense_combined_merges = 0;\n>>         revs->combined_all_paths = 0;\n>>         revs->combined_imply_patch = 0;\n>> +       revs->merges_need_diff = 0;\n>>  }\n>>\n>>  static void set_separate(struct rev_info *revs)\n>> @@ -51,9 +52,11 @@ static void set_dense_combined(struct rev_info *revs)\n>>\n>>  static void set_diff_merges(struct rev_info *revs, const char *optarg)\n>>  {\n>\n>> +       if (!strcmp(optarg, \"off\") || !strcmp(optarg, \"none\")) {\n>> +               suppress(revs);\n>> +               return;\n>> +       }\n>>         if (0) ;\n>> -       else if (!strcmp(optarg, \"off\")   || !strcmp(optarg, \"none\"))\n>> -               suppress(revs);\n>\n> The \"if (0) ;\" is still really weird.\n\nAn idiom (see my previous answer). I'm fine getting rid of it if you\nguys find it weird (that I'm not).\n\n>\n>>         else if (!strcmp(optarg, \"first\") || !strcmp(optarg, \"first-parent\"))\n>>                 set_first_parent(revs);\n>>         else if (!strcmp(optarg, \"sep\")   || !strcmp(optarg, \"separate\"))\n>> @@ -64,6 +67,7 @@ static void set_diff_merges(struct rev_info *revs, const char *optarg)\n>>                 set_dense_combined(revs);\n>>         else\n>>                 die(_(\"unknown value for --diff-merges: %s\"), optarg);\n>> +       revs->merges_need_diff = 1;\n>\n> I'd put this above the if-else-else block, to make it clearer why you\n> are returning early for the \"off\"/\"none\" case.\n\nYeah, makes sense, thanks!\n\n>\n>>  }\n>>\n>>  /*\n>> @@ -132,12 +136,12 @@ void diff_merges_setup_revs(struct rev_info *revs)\n>>                 revs->first_parent_merges = 0;\n>>         if (revs->combined_all_paths && !revs->combine_merges)\n>>                 die(\"--combined-all-paths makes no sense without -c or --cc\");\n>> -       if (revs->combine_merges)\n>> +\n>> +       if (revs->combined_imply_patch)\n>>                 revs->diff = 1;\n>> -       if (revs->combined_imply_patch) {\n>> -               /* Turn --cc/-c into -p --cc/-c when -p was not given */\n>> +\n>> +       if (revs->combined_imply_patch || revs->merges_need_diff) {\n>>                 if (!revs->diffopt.output_format)\n>>                         revs->diffopt.output_format = DIFF_FORMAT_PATCH;\n>>         }\n>> -\n>\n> The random space changes squashed in here instead of being combined\n> with the earlier patches that introduced the relevant areas break up\n> the reading.  Would be nice to clean this up.\n>\n>>  }\n>> diff --git a/log-tree.c b/log-tree.c\n>> index f9385b1dae6f..67060492ca0a 100644\n>> --- a/log-tree.c\n>> +++ b/log-tree.c\n>> @@ -899,15 +899,21 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log\n>>         int showed_log;\n>>         struct commit_list *parents;\n>>         struct object_id *oid;\n>> +       int is_merge;\n>> +       int regulars_need_diff = opt->diff || opt->diffopt.flags.exit_with_status;\n>\n> So rev_info.diff has changed in meaning from\n> commits-need-to-show-a-diff, to non-merge-commits-need-to-show-a-diff.\n> That's a somewhat subtle semantic shift.  Perhaps it's worth adding a\n> comment to the declaration of rev_info.diff to highlight this?  (And\n> perhaps even rename the flag?)\n\nNo, the meaning of rev_info.diff hopefully didn't change. rev_info.diff\nstill enables all the commits to pass further once set. It is still\nexactly the same old condition, just assigned to a variable for reuse.\nMy aim was to avoid touching existing logic of this function and only\nadd a new functionality when opt->merges_need_diff is set.\n\nIt looks like I rather choose confusing name for the variable, and it'd\nbe more clear if I'd call this, say:\n\n  int need_diff = opt->diff || opt->diffopt.flags.exit_with_status;\n\n?\n\nWhat do you think?\n\n>\n>> -       if (!opt->diff && !opt->diffopt.flags.exit_with_status)\n>> +       if (!regulars_need_diff && !opt->merges_need_diff)\n>>                 return 0;\n>>\n>>         parse_commit_or_die(commit);\n>>         oid = get_commit_tree_oid(commit);\n>>\n>> -       /* Root commit? */\n>>         parents = get_saved_parents(opt, commit);\n>> +       is_merge = parents && parents->next;\n>> +       if(!is_merge && !regulars_need_diff)\n>> +               return 0;\n>> +\n>> +       /* Root commit? */\n>>         if (!parents) {\n>>                 if (opt->show_root_diff) {\n>>                         diff_root_tree_oid(oid, \"\", &opt->diffopt);\n>> @@ -916,8 +922,7 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log\n>>                 return !opt->loginfo;\n>>         }\n>>\n>> -       /* More than one parent? */\n>> -       if (parents->next) {\n>> +       if (is_merge) {\n>>                 if (opt->combine_merges)\n>>                         return do_diff_combined(opt, commit);\n>>                 if (opt->separate_merges) {\n>> diff --git a/revision.h b/revision.h\n>> index bfbae526ad6e..494d86142454 100644\n>> --- a/revision.h\n>> +++ b/revision.h\n>> @@ -194,6 +194,7 @@ struct rev_info {\n>>                         always_show_header:1,\n>>                         /* Diff-merge flags */\n>>                         explicit_diff_merges: 1,\n>> +                       merges_need_diff: 1,\n>>                         separate_merges: 1,\n>>                         combine_merges:1,\n>>                         combined_all_paths:1,\n>> --\n>> 2.25.1\n>\n> The rest makes sense.\n\nThanks,\n-- Sergey\n\n"},{"id":"412565","messageId":"87r1nnb2aq.fsf@osv.gnss.ru","threadId":"54550","inReplyTo":"CABPp-BExc7rBCVEvLLs1u_hXurDTtWxTKg0ZN0+PA-21u_ShkA@mail.gmail.com","subject":"Re: [PATCH v2 28/33] diff-merges: add '--diff-merges=1' as synonym for 'first-parent'","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-18T14:45:49Z","receivedAt":"2020-12-18T14:46:34Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Elijah Newren <newren@gmail.com> writes:\n\n> On Wed, Dec 16, 2020 at 10:50 AM Sergey Organov <sorganov@gmail.com> wrote:\n>>\n>> As we now have --diff-merges={m|c|cc}, add --diff-merges=1 as synonym\n>> for --diff-merges=first-parent, to have shorter mnemonics for it as\n>> well.\n>\n> In all the other cases, --diff-merges=<short> is equivalent to\n> -<short>.  Here, --diff-merges=1 and -1 do _very_ different things.\n> Is there any concern that might cause confusion?  (My gut reaction is\n> this is probably fine and people won't try to make such a connection,\n> but it made me worry just enough that I thought I'd flag it for you\n> and other reviewers to at least mull over and maybe comment on.)\n\nI wasn't sure about this myself, and that was one reason to make this\nseparate commit.\n\nI think this one also came from the idea that one might want to have,\nsay, --diff-merges=2 in the future and get diff with respect to the\nsecond parent.\n\nThanks,\n-- Sergey\n"},{"id":"412570","messageId":"87lfdvaymn.fsf@osv.gnss.ru","threadId":"54550","inReplyTo":"CABPp-BFRPFxm=SuJFwfG+QYCivMKp2VRpnHGwxNL+extK7UdtA@mail.gmail.com","subject":"Re: [PATCH v2 29/33] doc/git-log: describe new --diff-merges options","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-18T16:05:04Z","receivedAt":"2020-12-18T16:06:08Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Elijah Newren <newren@gmail.com> writes:\n\n> On Wed, Dec 16, 2020 at 10:50 AM Sergey Organov <sorganov@gmail.com> wrote:\n>>\n>> Describe all the new --diff-merges options in the git-log.txt and\n>> adopt description of originals accordingly.\n>\n> You also took care to explain interactions of options with -p that\n> were previously undocumented, which is a nice bonus.  That wording\n> could still be improved a bit, though, as noted below.\n>\n>> Signed-off-by: Sergey Organov <sorganov@gmail.com>\n>> ---\n>>  Documentation/git-log.txt | 85 ++++++++++++++++++++++++---------------\n>>  1 file changed, 52 insertions(+), 33 deletions(-)\n>>\n>> diff --git a/Documentation/git-log.txt b/Documentation/git-log.txt\n>> index 2b8ac5ff882a..27bc619490c6 100644\n>> --- a/Documentation/git-log.txt\n>> +++ b/Documentation/git-log.txt\n>> @@ -120,45 +120,64 @@ DIFF FORMATTING\n>>  By default, `git log` does not generate any diff output. The options\n>>  below can be used to show the changes made by each commit.\n>>\n>> -Note that unless one of `-c`, `--cc`, or `-m` is given, merge commits\n>> -will never show a diff, even if a diff format like `--patch` is\n>> -selected, nor will they match search options like `-S`. The exception is\n>> -when `--first-parent` is in use, in which merges are treated like normal\n>> -single-parent commits (this can be overridden by providing a\n>> -combined-diff option or with `--no-diff-merges`).\n>> +Note that unless one of `--diff-merges` variants (including short\n>> +`-m`, `-c`, and `--cc` options) is explicitly given, merge commits\n>> +will not show a diff, even if a diff format like `--patch` is\n>> +selected, nor will they match search options like `-S`. The exception\n>> +is when `--first-parent` is in use, in which case `first-parent` is\n>> +the default format.\n>\n> Thanks for fixing this up.  :-)\n\nDon't mention it :-)\n\n>\n>>\n>> --c::\n>> -       With this option, diff output for a merge commit\n>> -       shows the differences from each of the parents to the merge result\n>> -       simultaneously instead of showing pairwise diff between a parent\n>> -       and the result one at a time. Furthermore, it lists only files\n>> -       which were modified from all parents.\n>> -\n>> ---cc::\n>> -       This flag implies the `-c` option and further compresses the\n>> -       patch output by omitting uninteresting hunks whose contents in\n>> -       the parents have only two variants and the merge result picks\n>> -       one of them without modification.\n>> +--diff-merges=(off|none|first-parent|1|separate|m|combined|c|dense-combined|cc)::\n>> +--no-diff-merges::\n>> +       Specify diff format to be used for merge commits. Default is\n>> +       `off` unless `--first-parent` is in use, in which case\n>> +       `first-parent` is the default.\n>> ++\n>> +--diff-merges=(off|none):::\n>> +--no-diff-merges:::\n>> +       Disable output of diffs for merge commits. Useful to override\n>> +       implied value.\n>> ++\n>> +--diff-merges=first-parent:::\n>> +--diff-merges=1:::\n>> +       This option makes merge commits show the full diff with\n>> +       respect to the first parent only.\n>\n> Does it imply -p?\n\nNo, none of --diff-merges options do. This one is not any special. Why\nthe question?\n\n>> ++\n>> +--diff-merges=separate:::\n>> +--diff-merges=m:::\n>> +-m:::\n>> +       This makes merge commits show the full diff with respect to\n>> +       each of the parents. Separate log entry and diff is generated\n>> +       for each parent. `-m` is different in that it doesn't produce\n>> +       any output without `-p`.\n>\n> Different from what?  From --first-parent?  From flags that haven't\n> been covered yet?  (-c and --cc show up below)\n\nWell, from --diff-merges=m and --diff-merges=separate, that, as any\nother --diff-merge option, do produce output (for merge commits) even\nwithout -p.\n\n>\n>> ++\n>> +--diff-merges=combined:::\n>> +--diff-merges=c:::\n>> +-c:::\n>> +       With this option, diff output for a merge commit shows the\n>> +       differences from each of the parents to the merge result\n>> +       simultaneously instead of showing pairwise diff between a\n>> +       parent and the result one at a time. Furthermore, it lists\n>> +       only files which were modified from all parents. Historically,\n>> +       `-c` enables diff output for non-merge commits as well.\n>\n> \"Historically\"?  Does that mean it doesn't anymore?\n\nEh, I don't think \"historically\" means that, but I'm not sure, being\nnon-native English speaker.\n\n> (Maybe, \"The short form, `-c`, also enables diff output for non-merge\n> commits as well.\" or something like that?)\n\n... and then try to explain why this otherwise illogical behavior is\nthere? I thought \"historically\" would cover that.\n\n>\n>> ++\n>> +--diff-merges=dense-combined:::\n>> +--diff-merges=cc:::\n>> +--cc:::\n>> +       With this option the output produced by\n>> +       `--diff-merges=combined` is further compressed by omitting\n>> +       uninteresting hunks whose contents in the parents have only\n>> +       two variants and the merge result picks one of them without\n>> +       modification.  Historically, `--c` enables diff output for\n>> +       non-merge commits as well.\n>\n> Same note as above.\n\nYep.\n\n>\n>>  --combined-all-paths::\n>>         This flag causes combined diffs (used for merge commits) to\n>>         list the name of the file from all parents.  It thus only has\n>> -       effect when -c or --cc are specified, and is likely only\n>> -       useful if filename changes are detected (i.e. when either\n>> -       rename or copy detection have been requested).\n>> +       effect when `--diff-merges=[dense-]combined` is in use, and\n>> +       is likely only useful if filename changes are detected (i.e.\n>> +       when either rename or copy detection have been requested).\n>>\n>> --m::\n>> -       This flag makes the merge commits show the full diff like\n>> -       regular commits; for each merge parent, a separate log entry\n>> -       and diff is generated. An exception is that only diff against\n>> -       the first parent is shown when `--first-parent` option is given;\n>> -       in that case, the output represents the changes the merge\n>> -       brought _into_ the then-current branch.\n>> -\n>> ---diff-merges=off::\n>> ---no-diff-merges::\n>> -       Disable output of diffs for merge commits (default). Useful to\n>> -       override `-m`, `-c`, or `--cc`.\n>>\n>>  :git-log: 1\n>>  include::diff-options.txt[]\n>> --\n>> 2.25.1\n>\n> The rest looks good.\n\nThanks,\n-- Sergey\n"},{"id":"412571","messageId":"CABPp-BGPZiwjSzZw5PLwkctW7hnG2S6UGHmkTGCh1BqgXJ+vEQ@mail.gmail.com","threadId":"54550","inReplyTo":"87blercju2.fsf@osv.gnss.ru","subject":"Re: [PATCH v2 23/33] diff-merges: fix style of functions definitions","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2020-12-18T16:12:45Z","receivedAt":"2020-12-18T16:13:38Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Fri, Dec 18, 2020 at 5:41 AM Sergey Organov <sorganov@gmail.com> wrote:\n>\n> Elijah Newren <newren@gmail.com> writes:\n>\n> > On Wed, Dec 16, 2020 at 10:50 AM Sergey Organov <sorganov@gmail.com> wrote:\n> >>\n> >> Put open curly brace on its own line\n> >>\n> >> Signed-off-by: Sergey Organov <sorganov@gmail.com>\n> >> ---\n> >>  diff-merges.c | 36 ++++++++++++++++++++++++------------\n> >>  1 file changed, 24 insertions(+), 12 deletions(-)\n> >>\n> >> diff --git a/diff-merges.c b/diff-merges.c\n> >> index cba391604ac7..0165fa22fcd1 100644\n> >> --- a/diff-merges.c\n> >> +++ b/diff-merges.c\n> >> @@ -2,7 +2,8 @@\n> >>\n>\n> [...]\n>\n> >>\n> >> -void diff_merges_set_dense_combined_if_unset(struct rev_info *revs) {\n> >> +void diff_merges_set_dense_combined_if_unset(struct rev_info *revs)\n> >> +{\n> >>         if (!revs->combine_merges)\n> >>                 set_dense_combined(revs);\n> >>  }\n> >> --\n> >> 2.25.1\n> >>\n> >\n> > But...didn't you add all these functions yourself earlier in the\n> > series?\n>\n> Yes, I did indeed and somehow picked wrong style from one of the\n> occurrences of this style in the existing Git codebase.\n>\n> > Why didn't you split this patch up and squash it into the\n> > relevant previous patches?\n>\n> When Junio noticed and pointed to this deficiency, I asked him if I\n> should fix all the series from the start, or it'd be OK to use fixup\n> commit. As he didn't answer and nobody else commented either, I opted\n> for the latter.\n>\n> I can still do it if it's that essential, but I'd prefer not to, to\n> avoid both the hand-work and causing entire series to change. The\n> problem is that there were code movements in the series, so such a fix\n> to earlier patches would cause conflicts down the commits chain, to be\n> resolved by hand.\n\nThat's what add -p and interactive rebase is for.  :-)  Code is read\nmore than it is written, so it's important to get things clean.  And\nnot just for immediate reviewers, but for people who look at it later.\n"},{"id":"412573","messageId":"CABPp-BGg9oBkG3ZaWztKMnQE4sREOK_L3so5fer5hbiAKxMaHg@mail.gmail.com","threadId":"54550","inReplyTo":"875z4zciwd.fsf@osv.gnss.ru","subject":"Re: [PATCH v2 24/33] diff-merges: handle imply -p on -c/--cc logic for log.c","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2020-12-18T16:37:01Z","receivedAt":"2020-12-18T16:38:10Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Fri, Dec 18, 2020 at 6:01 AM Sergey Organov <sorganov@gmail.com> wrote:\n>\n> Elijah Newren <newren@gmail.com> writes:\n>\n> > On Wed, Dec 16, 2020 at 10:50 AM Sergey Organov <sorganov@gmail.com> wrote:\n> >>\n> >> Move logic that handles implying -p on -c/--cc from\n> >> log_setup_revisions_tweak() to diff_merges_setup_revs(), where it\n> >> belongs.\n> >\n> > A very minor point, but I'd probably drop the \"where it belongs\";\n> > while I think the new place makes sense for it, it reads to me like\n> > you're either relying on a consensus to move it or implying there was\n> > a mistake to not put it here previously, neither of which makes sense.\n>\n> Well, it was meant to be an excuse for not moving it there earlier in\n> the patch series indeed. I just overlooked this piece of code that\n> logically belongs to the diff-merges module. I think you need to\n> consider the state of the sources right before this patch to see the\n> point of phrasing it like this.\n>\n> That said, I'm fine removing this either.\n\nIf it should have been moved there earlier, then you should amend the\nrelevant previous commit instead of making a new one.  rebase -i is\nyour friend and should be used, especially with long patch series.\n:-)\n\n> > Much more importantly, this patch doesn't do what you said in\n> > discussions on the previous round.  It'd be helpful if the commit\n> > message called out that you are just moving the logic for now and that\n> > a subsequent patch will tweak the logic to only trigger this for\n> > -c/--cc and not for --diff-merges=.* flags.\n>\n> I believe this patch is useful by itself, even without any future\n> improvements (that we actually discussed), if any, so I don't see the\n> point in describing what this patch doesn't do.\n>\n> OTOH, the commit message seems to be clear enough to expect this patch\n> to be pure refactoring, without any functional changes, no?\n\nI'm just pointing out that reading the patch triggers a \"wait, you\nsaid you wanted to enable diffs for merges without diffs for regular\ncommits\" reaction and makes reviewers start diving into the code to\ncheck if they missed where that happened.  Sometimes they'll even\nrespond to the commit asking about it...and then read a later patch\nand find the answer.  Perhaps I'm more attuned to this, because I've\ndone this to reviewers a number of times and they have asked me to add\na note in the earlier commit message to make it easier for other\nreviewers to follow and read the series.  You don't need to describe\nin full detail the subsequent changes that will come, just highlight\nthat they are coming to give reviewers an aid.  For example, this\ncould be as simple as:\n\n\"\"\"\nMove logic that handles implying -p on -c/--cc from\nlog_setup_revisions_tweak() to diff_merges_setup_revs().  A\nsubsequent commit will tweak this logic further.\n\"\"\"\n\n(Note that 'git log --grep=subsequent' in git.git will find you\nseveral examples of where people have done this kind of thing.)\n"},{"id":"412574","messageId":"CABPp-BFtJ_LE2RhKoOQQ7h_Nspa=12Chwtp8kBq0PCKA6j2BPA@mail.gmail.com","threadId":"54550","inReplyTo":"871rfncie5.fsf@osv.gnss.ru","subject":"Re: [PATCH v2 22/33] diff-merges: implement new values for --diff-merges","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2020-12-18T16:42:11Z","receivedAt":"2020-12-18T16:43:04Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Fri, Dec 18, 2020 at 6:12 AM Sergey Organov <sorganov@gmail.com> wrote:\n>\n> Elijah Newren <newren@gmail.com> writes:\n>\n> > On Wed, Dec 16, 2020 at 10:50 AM Sergey Organov <sorganov@gmail.com> wrote:\n> >>\n> >> We first implement new options as exact synonyms for their original\n> >> counterparts, to get all the infrastructure right, and keep functional\n> >> improvements for later commits.\n> >>\n> >> The following values are implemented:\n> >>\n> >> --diff-merges=          old equivalent\n> >> first|first-parent    = --first-parent (only format implications)\n> >> sep|separate          = -m\n> >> comb|combined         = -c\n> >> dense| dense-combined = --cc\n> >>\n> >> Signed-off-by: Sergey Organov <sorganov@gmail.com>\n> >> ---\n> >>  diff-merges.c | 19 ++++++++++++++++---\n> >>  1 file changed, 16 insertions(+), 3 deletions(-)\n> >>\n> >> diff --git a/diff-merges.c b/diff-merges.c\n> >> index 6446e2093661..cba391604ac7 100644\n> >> --- a/diff-merges.c\n> >> +++ b/diff-merges.c\n> >> @@ -15,6 +15,11 @@ static void set_separate(struct rev_info *revs) {\n> >>         revs->separate_merges = 1;\n> >>  }\n> >>\n> >> +static void set_first_parent(struct rev_info *revs) {\n> >> +       set_separate(revs);\n> >> +       revs->first_parent_merges = 1;\n> >> +}\n> >> +\n> >>  static void set_m(struct rev_info *revs) {\n> >>         /*\n> >>          * To \"diff-index\", \"-m\" means \"match missing\", and to the \"log\"\n> >> @@ -38,11 +43,19 @@ static void set_dense_combined(struct rev_info *revs) {\n> >>  }\n> >>\n> >>  static void set_diff_merges(struct rev_info *revs, const char *optarg) {\n> >> -       if (!strcmp(optarg, \"off\")) {\n> >> +       if (0) ;\n> >\n> > Leftover cruft from some intermediate changes or something?\n>\n> No. It's just an idiom for if-switch, making all the actual cases look\n> the same. Without this the first one looks special when in fact it\n> isn't. I won't die for it though.\n>\n> >\n> >> +       else if (!strcmp(optarg, \"off\")   || !strcmp(optarg, \"none\"))\n> >>                 suppress(revs);\n> >> -       } else {\n> >> +       else if (!strcmp(optarg, \"first\") || !strcmp(optarg, \"first-parent\"))\n> >> +               set_first_parent(revs);\n> >> +       else if (!strcmp(optarg, \"sep\")   || !strcmp(optarg, \"separate\"))\n> >> +               set_separate(revs);\n> >> +       else if (!strcmp(optarg, \"comb\")  || !strcmp(optarg, \"combined\"))\n> >> +               set_combined(revs);\n> >> + else if (!strcmp(optarg, \"dense\") || !strcmp(optarg,\n> >> \"dense-combined\"))\n> >> +               set_dense_combined(revs);\n> >> +       else\n> >\n> > Not sure I like the special-casing for \"sep\" and \"comb\".  \"dense\"\n> > seems okay since it's a real word.\n>\n> That was a poor-man attempt at unique shortcuts made by hand, as well as\n> a reminder to consider to re-write this using generic options framework\n> that will do it automagically. They are just a few first letters,\n> nothing more. That's why I didn't even document them.\n\nSeems like a\n   /* TODO: use generic options framework to allow abbreviations */\nwould make that intent much more clear.\n\n> > Since you're adding short versions of m, c, and cc later in the\n> > series, do we need these other special-case forms?\n>\n> No, I don't think we do necessarily need them, but then they do no harm\n> either, so I didn't remove them when I added m, c, and cc. Neither was I\n> sure we do need these m, c, and cc in the first place.\n\nWell, I'd say it certainly adds clutter for reviewers, so there is at\nleast a little harm.  ;-)  It was on the patch that added m, c, and cc\nthat it particularly stood out to me, so I looked up the relevant\ncommit so that I could add the comment at the right place to make it\neasier for you to rip out.\n"},{"id":"412575","messageId":"CABPp-BG4GEmv20YK39M51nzTYVZtcLgD-UbmQLfgynjUhBKx9w@mail.gmail.com","threadId":"54550","inReplyTo":"87wnxfb2gt.fsf@osv.gnss.ru","subject":"Re: [PATCH v2 26/33] diff-merges: let new options enable diff without -p","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2020-12-18T17:01:36Z","receivedAt":"2020-12-18T17:02:29Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Fri, Dec 18, 2020 at 6:42 AM Sergey Organov <sorganov@gmail.com> wrote:\n>\n> Elijah Newren <newren@gmail.com> writes:\n>\n> > On Wed, Dec 16, 2020 at 10:50 AM Sergey Organov <sorganov@gmail.com> wrote:\n> >>\n> >> New options don't have any visible effect unless -p is either given or\n> >> implied, as unlike -c/-cc we don't imply -p with --diff-merges. To fix\n> >> this, this patch adds new functionality by letting new options enable\n> >> output of diffs for merge commits only.\n> >>\n> >> Add 'merges_need_diff' field and set it whenever diff output for merges is\n> >> enabled by any of the new options.\n> >>\n> >> Extend diff output logic accordingly, to output diffs for merges when\n> >> 'merges_need_diff' is set even when no -p has been provided.\n> >>\n> >> Signed-off-by: Sergey Organov <sorganov@gmail.com>\n> >> ---\n> >>  diff-merges.c | 16 ++++++++++------\n> >>  log-tree.c    | 13 +++++++++----\n> >>  revision.h    |  1 +\n> >>  3 files changed, 20 insertions(+), 10 deletions(-)\n> >>\n> >> diff --git a/diff-merges.c b/diff-merges.c\n> >> index 725db2312074..ffe20d8daa4a 100644\n> >> --- a/diff-merges.c\n> >> +++ b/diff-merges.c\n> >> @@ -10,6 +10,7 @@ static void suppress(struct rev_info *revs)\n> >>         revs->dense_combined_merges = 0;\n> >>         revs->combined_all_paths = 0;\n> >>         revs->combined_imply_patch = 0;\n> >> +       revs->merges_need_diff = 0;\n> >>  }\n> >>\n> >>  static void set_separate(struct rev_info *revs)\n> >> @@ -51,9 +52,11 @@ static void set_dense_combined(struct rev_info *revs)\n> >>\n> >>  static void set_diff_merges(struct rev_info *revs, const char *optarg)\n> >>  {\n> >\n> >> +       if (!strcmp(optarg, \"off\") || !strcmp(optarg, \"none\")) {\n> >> +               suppress(revs);\n> >> +               return;\n> >> +       }\n> >>         if (0) ;\n> >> -       else if (!strcmp(optarg, \"off\")   || !strcmp(optarg, \"none\"))\n> >> -               suppress(revs);\n> >\n> > The \"if (0) ;\" is still really weird.\n>\n> An idiom (see my previous answer). I'm fine getting rid of it if you\n> guys find it weird (that I'm not).\n\nI've never seen this idiom, and we apparently have no uses of it in\nthe code.  If it were near any code I was editing, I think I'd rip it\nout as a preliminary cleanup patch...but maybe others have other\nopinions.\n\n> >\n> >>         else if (!strcmp(optarg, \"first\") || !strcmp(optarg, \"first-parent\"))\n> >>                 set_first_parent(revs);\n> >>         else if (!strcmp(optarg, \"sep\")   || !strcmp(optarg, \"separate\"))\n> >> @@ -64,6 +67,7 @@ static void set_diff_merges(struct rev_info *revs, const char *optarg)\n> >>                 set_dense_combined(revs);\n> >>         else\n> >>                 die(_(\"unknown value for --diff-merges: %s\"), optarg);\n> >> +       revs->merges_need_diff = 1;\n> >\n> > I'd put this above the if-else-else block, to make it clearer why you\n> > are returning early for the \"off\"/\"none\" case.\n>\n> Yeah, makes sense, thanks!\n>\n> >\n> >>  }\n> >>\n> >>  /*\n> >> @@ -132,12 +136,12 @@ void diff_merges_setup_revs(struct rev_info *revs)\n> >>                 revs->first_parent_merges = 0;\n> >>         if (revs->combined_all_paths && !revs->combine_merges)\n> >>                 die(\"--combined-all-paths makes no sense without -c or --cc\");\n> >> -       if (revs->combine_merges)\n> >> +\n> >> +       if (revs->combined_imply_patch)\n> >>                 revs->diff = 1;\n> >> -       if (revs->combined_imply_patch) {\n> >> -               /* Turn --cc/-c into -p --cc/-c when -p was not given */\n> >> +\n> >> +       if (revs->combined_imply_patch || revs->merges_need_diff) {\n> >>                 if (!revs->diffopt.output_format)\n> >>                         revs->diffopt.output_format = DIFF_FORMAT_PATCH;\n> >>         }\n> >> -\n> >\n> > The random space changes squashed in here instead of being combined\n> > with the earlier patches that introduced the relevant areas break up\n> > the reading.  Would be nice to clean this up.\n> >\n> >>  }\n> >> diff --git a/log-tree.c b/log-tree.c\n> >> index f9385b1dae6f..67060492ca0a 100644\n> >> --- a/log-tree.c\n> >> +++ b/log-tree.c\n> >> @@ -899,15 +899,21 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log\n> >>         int showed_log;\n> >>         struct commit_list *parents;\n> >>         struct object_id *oid;\n> >> +       int is_merge;\n> >> +       int regulars_need_diff = opt->diff || opt->diffopt.flags.exit_with_status;\n> >\n> > So rev_info.diff has changed in meaning from\n> > commits-need-to-show-a-diff, to non-merge-commits-need-to-show-a-diff.\n> > That's a somewhat subtle semantic shift.  Perhaps it's worth adding a\n> > comment to the declaration of rev_info.diff to highlight this?  (And\n> > perhaps even rename the flag?)\n>\n> No, the meaning of rev_info.diff hopefully didn't change. rev_info.diff\n> still enables all the commits to pass further once set. It is still\n> exactly the same old condition, just assigned to a variable for reuse.\n> My aim was to avoid touching existing logic of this function and only\n> add a new functionality when opt->merges_need_diff is set.\n>\n> It looks like I rather choose confusing name for the variable, and it'd\n> be more clear if I'd call this, say:\n>\n>   int need_diff = opt->diff || opt->diffopt.flags.exit_with_status;\n>\n> ?\n>\n> What do you think?\n\nI think need_diff would actually be confusing.  It can be false when\nyou need diffs (e.g. --diff-merges=cc with no -p, because then you'd\nneed diffs for merge commits and not for non-merge commits).  I'd\nstick with your original local variable name.\n\nPerhaps opt->diff hasn't changed meaning and I just had a wrong mental\nmodel in my head for what it meant, but even then what seems like its\nobvious purpose given its name is mismatched with what it actually\ndoes.  Since you are already changing struct rev_info in this series,\nthis was more a note that a name change or at least a comment for\nopt->diff might be useful.  I mean, you asked a couple times on the\nprevious series for help trying to understand it, and I could only\noffer some flailing guesses and Junio responded with a couple bits of\nhistory.  Clearly, it isn't very clear and this patch reminded me of\nthat and made me wonder if we're possibly making it a little harder\nfor others further down the road to figure out.\n\n> >> -       if (!opt->diff && !opt->diffopt.flags.exit_with_status)\n> >> +       if (!regulars_need_diff && !opt->merges_need_diff)\n> >>                 return 0;\n> >>\n> >>         parse_commit_or_die(commit);\n> >>         oid = get_commit_tree_oid(commit);\n> >>\n> >> -       /* Root commit? */\n> >>         parents = get_saved_parents(opt, commit);\n> >> +       is_merge = parents && parents->next;\n> >> +       if(!is_merge && !regulars_need_diff)\n> >> +               return 0;\n> >> +\n> >> +       /* Root commit? */\n> >>         if (!parents) {\n> >>                 if (opt->show_root_diff) {\n> >>                         diff_root_tree_oid(oid, \"\", &opt->diffopt);\n> >> @@ -916,8 +922,7 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log\n> >>                 return !opt->loginfo;\n> >>         }\n> >>\n> >> -       /* More than one parent? */\n> >> -       if (parents->next) {\n> >> +       if (is_merge) {\n> >>                 if (opt->combine_merges)\n> >>                         return do_diff_combined(opt, commit);\n> >>                 if (opt->separate_merges) {\n> >> diff --git a/revision.h b/revision.h\n> >> index bfbae526ad6e..494d86142454 100644\n> >> --- a/revision.h\n> >> +++ b/revision.h\n> >> @@ -194,6 +194,7 @@ struct rev_info {\n> >>                         always_show_header:1,\n> >>                         /* Diff-merge flags */\n> >>                         explicit_diff_merges: 1,\n> >> +                       merges_need_diff: 1,\n> >>                         separate_merges: 1,\n> >>                         combine_merges:1,\n> >>                         combined_all_paths:1,\n> >> --\n> >> 2.25.1\n> >\n> > The rest makes sense.\n>\n> Thanks,\n> -- Sergey\n"},{"id":"412577","messageId":"CABPp-BGAHFLZDWaK5q+ZHOShUOZnRqUQd+T-X6mXxkg5cp7QpQ@mail.gmail.com","threadId":"54550","inReplyTo":"87lfdvaymn.fsf@osv.gnss.ru","subject":"Re: [PATCH v2 29/33] doc/git-log: describe new --diff-merges options","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2020-12-18T17:25:30Z","receivedAt":"2020-12-18T17:26:25Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Fri, Dec 18, 2020 at 8:05 AM Sergey Organov <sorganov@gmail.com> wrote:\n>\n> Elijah Newren <newren@gmail.com> writes:\n>\n> > On Wed, Dec 16, 2020 at 10:50 AM Sergey Organov <sorganov@gmail.com> wrote:\n> >>\n> >> Describe all the new --diff-merges options in the git-log.txt and\n> >> adopt description of originals accordingly.\n> >\n> > You also took care to explain interactions of options with -p that\n> > were previously undocumented, which is a nice bonus.  That wording\n> > could still be improved a bit, though, as noted below.\n> >\n> >> Signed-off-by: Sergey Organov <sorganov@gmail.com>\n> >> ---\n> >>  Documentation/git-log.txt | 85 ++++++++++++++++++++++++---------------\n> >>  1 file changed, 52 insertions(+), 33 deletions(-)\n> >>\n> >> diff --git a/Documentation/git-log.txt b/Documentation/git-log.txt\n> >> index 2b8ac5ff882a..27bc619490c6 100644\n> >> --- a/Documentation/git-log.txt\n> >> +++ b/Documentation/git-log.txt\n> >> @@ -120,45 +120,64 @@ DIFF FORMATTING\n> >>  By default, `git log` does not generate any diff output. The options\n> >>  below can be used to show the changes made by each commit.\n> >>\n> >> -Note that unless one of `-c`, `--cc`, or `-m` is given, merge commits\n> >> -will never show a diff, even if a diff format like `--patch` is\n> >> -selected, nor will they match search options like `-S`. The exception is\n> >> -when `--first-parent` is in use, in which merges are treated like normal\n> >> -single-parent commits (this can be overridden by providing a\n> >> -combined-diff option or with `--no-diff-merges`).\n> >> +Note that unless one of `--diff-merges` variants (including short\n> >> +`-m`, `-c`, and `--cc` options) is explicitly given, merge commits\n> >> +will not show a diff, even if a diff format like `--patch` is\n> >> +selected, nor will they match search options like `-S`. The exception\n> >> +is when `--first-parent` is in use, in which case `first-parent` is\n> >> +the default format.\n> >\n> > Thanks for fixing this up.  :-)\n>\n> Don't mention it :-)\n>\n> >\n> >>\n> >> --c::\n> >> -       With this option, diff output for a merge commit\n> >> -       shows the differences from each of the parents to the merge result\n> >> -       simultaneously instead of showing pairwise diff between a parent\n> >> -       and the result one at a time. Furthermore, it lists only files\n> >> -       which were modified from all parents.\n> >> -\n> >> ---cc::\n> >> -       This flag implies the `-c` option and further compresses the\n> >> -       patch output by omitting uninteresting hunks whose contents in\n> >> -       the parents have only two variants and the merge result picks\n> >> -       one of them without modification.\n> >> +--diff-merges=(off|none|first-parent|1|separate|m|combined|c|dense-combined|cc)::\n> >> +--no-diff-merges::\n> >> +       Specify diff format to be used for merge commits. Default is\n> >> +       `off` unless `--first-parent` is in use, in which case\n> >> +       `first-parent` is the default.\n> >> ++\n> >> +--diff-merges=(off|none):::\n> >> +--no-diff-merges:::\n> >> +       Disable output of diffs for merge commits. Useful to override\n> >> +       implied value.\n> >> ++\n> >> +--diff-merges=first-parent:::\n> >> +--diff-merges=1:::\n> >> +       This option makes merge commits show the full diff with\n> >> +       respect to the first parent only.\n> >\n> > Does it imply -p?\n>\n> No, none of --diff-merges options do. This one is not any special. Why\n> the question?\n\nThe documentation on -m was vague enough that it made me wonder.\nFixing it would probably prevent me from having asked this question.\n\n> >> ++\n> >> +--diff-merges=separate:::\n> >> +--diff-merges=m:::\n> >> +-m:::\n> >> +       This makes merge commits show the full diff with respect to\n> >> +       each of the parents. Separate log entry and diff is generated\n> >> +       for each parent. `-m` is different in that it doesn't produce\n> >> +       any output without `-p`.\n> >\n> > Different from what?  From --first-parent?  From flags that haven't\n> > been covered yet?  (-c and --cc show up below)\n>\n> Well, from --diff-merges=m and --diff-merges=separate, that, as any\n> other --diff-merge option, do produce output (for merge commits) even\n> without -p.\n\nThat wasn't at all clear to me as the intent of the last sentence.\n\n> >> ++\n> >> +--diff-merges=combined:::\n> >> +--diff-merges=c:::\n> >> +-c:::\n> >> +       With this option, diff output for a merge commit shows the\n> >> +       differences from each of the parents to the merge result\n> >> +       simultaneously instead of showing pairwise diff between a\n> >> +       parent and the result one at a time. Furthermore, it lists\n> >> +       only files which were modified from all parents. Historically,\n> >> +       `-c` enables diff output for non-merge commits as well.\n> >\n> > \"Historically\"?  Does that mean it doesn't anymore?\n>\n> Eh, I don't think \"historically\" means that, but I'm not sure, being\n> non-native English speaker.\n\nSometimes non-native speakers use the language more accurately.  This\nmight be such a case, but that sentence did make me think you might be\nattempting to document past behavior as a way of helping people adjust\nto current/new behavior.\n\n> > (Maybe, \"The short form, `-c`, also enables diff output for non-merge\n> > commits as well.\" or something like that?)\n>\n> ... and then try to explain why this otherwise illogical behavior is\n> there? I thought \"historically\" would cover that.\n\nIt doesn't seem like illogical behavior to me.   Perhaps the view of\n-c as a diff-merges option, reinforced by placing -c right next to\n--diff-merges in the documentation, is what causes you to think so?\nIf so, maybe we should document -c (and --cc) separately after all the\n--diff-merges options, using something like the following:\n\n-c:::\n    Implies both --patch and --diff-merges=combined, i.e. turn on\npatches for normal commits and show a combined diff format for merges.\n\n> >\n> >> ++\n> >> +--diff-merges=dense-combined:::\n> >> +--diff-merges=cc:::\n> >> +--cc:::\n> >> +       With this option the output produced by\n> >> +       `--diff-merges=combined` is further compressed by omitting\n> >> +       uninteresting hunks whose contents in the parents have only\n> >> +       two variants and the merge result picks one of them without\n> >> +       modification.  Historically, `--c` enables diff output for\n> >> +       non-merge commits as well.\n> >\n> > Same note as above.\n>\n> Yep.\n>\n> >\n> >>  --combined-all-paths::\n> >>         This flag causes combined diffs (used for merge commits) to\n> >>         list the name of the file from all parents.  It thus only has\n> >> -       effect when -c or --cc are specified, and is likely only\n> >> -       useful if filename changes are detected (i.e. when either\n> >> -       rename or copy detection have been requested).\n> >> +       effect when `--diff-merges=[dense-]combined` is in use, and\n> >> +       is likely only useful if filename changes are detected (i.e.\n> >> +       when either rename or copy detection have been requested).\n> >>\n> >> --m::\n> >> -       This flag makes the merge commits show the full diff like\n> >> -       regular commits; for each merge parent, a separate log entry\n> >> -       and diff is generated. An exception is that only diff against\n> >> -       the first parent is shown when `--first-parent` option is given;\n> >> -       in that case, the output represents the changes the merge\n> >> -       brought _into_ the then-current branch.\n> >> -\n> >> ---diff-merges=off::\n> >> ---no-diff-merges::\n> >> -       Disable output of diffs for merge commits (default). Useful to\n> >> -       override `-m`, `-c`, or `--cc`.\n> >>\n> >>  :git-log: 1\n> >>  include::diff-options.txt[]\n> >> --\n> >> 2.25.1\n> >\n> > The rest looks good.\n>\n> Thanks,\n> -- Sergey\n"},{"id":"412581","messageId":"87o8iq97o2.fsf@osv.gnss.ru","threadId":"54550","inReplyTo":"CABPp-BG4GEmv20YK39M51nzTYVZtcLgD-UbmQLfgynjUhBKx9w@mail.gmail.com","subject":"Re: [PATCH v2 26/33] diff-merges: let new options enable diff without -p","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-18T20:32:45Z","receivedAt":"2020-12-18T20:33:34Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Elijah Newren <newren@gmail.com> writes:\n\n> On Fri, Dec 18, 2020 at 6:42 AM Sergey Organov <sorganov@gmail.com> wrote:\n>>\n>> Elijah Newren <newren@gmail.com> writes:\n>>\n>> > On Wed, Dec 16, 2020 at 10:50 AM Sergey Organov <sorganov@gmail.com> wrote:\n\n[...]\n\n>> >> diff --git a/log-tree.c b/log-tree.c\n>> >> index f9385b1dae6f..67060492ca0a 100644\n>> >> --- a/log-tree.c\n>> >> +++ b/log-tree.c\n>> >> @@ -899,15 +899,21 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log\n>> >>         int showed_log;\n>> >>         struct commit_list *parents;\n>> >>         struct object_id *oid;\n>> >> +       int is_merge;\n>> >> +       int regulars_need_diff = opt->diff || opt->diffopt.flags.exit_with_status;\n>> >\n>> > So rev_info.diff has changed in meaning from\n>> > commits-need-to-show-a-diff, to non-merge-commits-need-to-show-a-diff.\n>> > That's a somewhat subtle semantic shift.  Perhaps it's worth adding a\n>> > comment to the declaration of rev_info.diff to highlight this?  (And\n>> > perhaps even rename the flag?)\n>>\n>> No, the meaning of rev_info.diff hopefully didn't change. rev_info.diff\n>> still enables all the commits to pass further once set. It is still\n>> exactly the same old condition, just assigned to a variable for reuse.\n>> My aim was to avoid touching existing logic of this function and only\n>> add a new functionality when opt->merges_need_diff is set.\n>>\n>> It looks like I rather choose confusing name for the variable, and it'd\n>> be more clear if I'd call this, say:\n>>\n>>   int need_diff = opt->diff || opt->diffopt.flags.exit_with_status;\n>>\n>> ?\n>>\n>> What do you think?\n>\n> I think need_diff would actually be confusing.  It can be false when\n> you need diffs (e.g. --diff-merges=cc with no -p, because then you'd\n> need diffs for merge commits and not for non-merge commits).  I'd\n> stick with your original local variable name.\n>\n> Perhaps opt->diff hasn't changed meaning and I just had a wrong mental\n> model in my head for what it meant, but even then what seems like its\n> obvious purpose given its name is mismatched with what it actually\n> does.  Since you are already changing struct rev_info in this series,\n> this was more a note that a name change or at least a comment for\n> opt->diff might be useful.  I mean, you asked a couple times on the\n> previous series for help trying to understand it, and I could only\n> offer some flailing guesses and Junio responded with a couple bits of\n> history.  Clearly, it isn't very clear and this patch reminded me of\n> that and made me wonder if we're possibly making it a little harder\n> for others further down the road to figure out.\n\nI still don't see why opt->diff is needed in the first place, and\nsecond, why opt->diffopt.flags.exit_with_status check is here? Why\nwhoever sets opt->diffopt.flags.exit_with_status doesn't just set\nopt->diff as well (provided opt->diff is needed in the first place)?\n\nFrom the aforementioned discussion it looks like opt->diff is an\noptimization (maybe a remnant from the times when diff was a separate\nscript), and that apparently there is some code instance somewhere that\nactually relies on the fact that clearing opt->diff is enough to disable\ndiff machinery (as followed from my experiment of removing the check\naltogether and then getting only single seemingly unrelated test\nfailing.)\n\nOverall, neither have I any idea how to clarify this, nor do I want to\nbother in this patch series. It'd be nice though if somebody who really\ndoes understand diff machinery in Git does the job.\n\nThanks,\n-- Sergey\n"},{"id":"412583","messageId":"87czz696pb.fsf@osv.gnss.ru","threadId":"54550","inReplyTo":"CABPp-BG4GEmv20YK39M51nzTYVZtcLgD-UbmQLfgynjUhBKx9w@mail.gmail.com","subject":"Re: [PATCH v2 26/33] diff-merges: let new options enable diff without -p","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-18T20:53:36Z","receivedAt":"2020-12-18T20:54:36Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Elijah Newren <newren@gmail.com> writes:\n\n> On Fri, Dec 18, 2020 at 6:42 AM Sergey Organov <sorganov@gmail.com> wrote:\n>>\n>> Elijah Newren <newren@gmail.com> writes:\n>>\n>> > On Wed, Dec 16, 2020 at 10:50 AM Sergey Organov <sorganov@gmail.com> wrote:\n>> >>\n>> >> New options don't have any visible effect unless -p is either given or\n>> >> implied, as unlike -c/-cc we don't imply -p with --diff-merges. To fix\n>> >> this, this patch adds new functionality by letting new options enable\n>> >> output of diffs for merge commits only.\n>> >>\n>> >> Add 'merges_need_diff' field and set it whenever diff output for merges is\n>> >> enabled by any of the new options.\n>> >>\n>> >> Extend diff output logic accordingly, to output diffs for merges when\n>> >> 'merges_need_diff' is set even when no -p has been provided.\n>> >>\n>> >> Signed-off-by: Sergey Organov <sorganov@gmail.com>\n>> >> ---\n>> >>  diff-merges.c | 16 ++++++++++------\n>> >>  log-tree.c    | 13 +++++++++----\n>> >>  revision.h    |  1 +\n>> >>  3 files changed, 20 insertions(+), 10 deletions(-)\n>> >>\n>> >> diff --git a/diff-merges.c b/diff-merges.c\n>> >> index 725db2312074..ffe20d8daa4a 100644\n>> >> --- a/diff-merges.c\n>> >> +++ b/diff-merges.c\n>> >> @@ -10,6 +10,7 @@ static void suppress(struct rev_info *revs)\n>> >>         revs->dense_combined_merges = 0;\n>> >>         revs->combined_all_paths = 0;\n>> >>         revs->combined_imply_patch = 0;\n>> >> +       revs->merges_need_diff = 0;\n>> >>  }\n>> >>\n>> >>  static void set_separate(struct rev_info *revs)\n>> >> @@ -51,9 +52,11 @@ static void set_dense_combined(struct rev_info *revs)\n>> >>\n>> >>  static void set_diff_merges(struct rev_info *revs, const char *optarg)\n>> >>  {\n>> >\n>> >> +       if (!strcmp(optarg, \"off\") || !strcmp(optarg, \"none\")) {\n>> >> +               suppress(revs);\n>> >> +               return;\n>> >> +       }\n>> >>         if (0) ;\n>> >> -       else if (!strcmp(optarg, \"off\")   || !strcmp(optarg, \"none\"))\n>> >> -               suppress(revs);\n>> >\n>> > The \"if (0) ;\" is still really weird.\n>>\n>> An idiom (see my previous answer). I'm fine getting rid of it if you\n>> guys find it weird (that I'm not).\n>\n> I've never seen this idiom, and we apparently have no uses of it in\n> the code.  If it were near any code I was editing, I think I'd rip it\n> out as a preliminary cleanup patch...but maybe others have other\n> opinions.\n\nEssentially, this is poor man replacement for non-existent:\n\n    switch(s) {\n      case \"str11\": case \"str12\":\n         do_things1(); break;\n      case \"str21\": case \"str22\":\n         do_things2(); break;\n      case \"str31\": case \"str32\":\n         do_things3(); break;\n      default:\n         default(); break\n    }\n\nNotice that all the case statements, except the last one, look the same,\nwhile with bare \"if() else\" constructs you get the first one looking\nspecial:\n\n    if (!strcmp(s, \"str11\") || !strcmp(s, \"str12\"))\n       do_things1();\n    else if (!strcmp(s, \"str21\") || !strcmp(s, \"str22\"))\n       do_things2();\n    else if (!strcmp(s, \"str31\") || !strcmp(s, \"str32\"))\n       do_things3();\n    else\n       default();\n\nNow, fixing it is as easy as:\n\n    if (0);\n    else if (!strcmp(s, \"str11\") || !strcmp(s, \"str12\"))\n       do_things1();\n    else if (!strcmp(s, \"str21\") || !strcmp(s, \"str22\"))\n       do_things2();\n    else if (!strcmp(s, \"str31\") || !strcmp(s, \"str32\"))\n       do_things3();\n    else\n       default();\n\nand it makes reordering and #ifdefing slightly less painful as well.\n\nJust saying rather, than insisting on adopting or even accepting it for\nthe Git codebase.\n\nThanks,\n-- Sergey\n"},{"id":"412584","messageId":"878s9u96d7.fsf@osv.gnss.ru","threadId":"54550","inReplyTo":"CABPp-BFtJ_LE2RhKoOQQ7h_Nspa=12Chwtp8kBq0PCKA6j2BPA@mail.gmail.com","subject":"Re: [PATCH v2 22/33] diff-merges: implement new values for --diff-merges","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-18T21:00:52Z","receivedAt":"2020-12-18T21:01:53Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Elijah Newren <newren@gmail.com> writes:\n\n> On Fri, Dec 18, 2020 at 6:12 AM Sergey Organov <sorganov@gmail.com> wrote:\n>>\n>> Elijah Newren <newren@gmail.com> writes:\n>>\n>> > On Wed, Dec 16, 2020 at 10:50 AM Sergey Organov <sorganov@gmail.com> wrote:\n>> >>\n>> >> We first implement new options as exact synonyms for their original\n>> >> counterparts, to get all the infrastructure right, and keep functional\n>> >> improvements for later commits.\n>> >>\n>> >> The following values are implemented:\n>> >>\n>> >> --diff-merges=          old equivalent\n>> >> first|first-parent    = --first-parent (only format implications)\n>> >> sep|separate          = -m\n>> >> comb|combined         = -c\n>> >> dense| dense-combined = --cc\n>> >>\n>> >> Signed-off-by: Sergey Organov <sorganov@gmail.com>\n>> >> ---\n>> >>  diff-merges.c | 19 ++++++++++++++++---\n>> >>  1 file changed, 16 insertions(+), 3 deletions(-)\n>> >>\n>> >> diff --git a/diff-merges.c b/diff-merges.c\n>> >> index 6446e2093661..cba391604ac7 100644\n>> >> --- a/diff-merges.c\n>> >> +++ b/diff-merges.c\n>> >> @@ -15,6 +15,11 @@ static void set_separate(struct rev_info *revs) {\n>> >>         revs->separate_merges = 1;\n>> >>  }\n>> >>\n>> >> +static void set_first_parent(struct rev_info *revs) {\n>> >> +       set_separate(revs);\n>> >> +       revs->first_parent_merges = 1;\n>> >> +}\n>> >> +\n>> >>  static void set_m(struct rev_info *revs) {\n>> >>         /*\n>> >>          * To \"diff-index\", \"-m\" means \"match missing\", and to the \"log\"\n>> >> @@ -38,11 +43,19 @@ static void set_dense_combined(struct rev_info *revs) {\n>> >>  }\n>> >>\n>> >>  static void set_diff_merges(struct rev_info *revs, const char *optarg) {\n>> >> -       if (!strcmp(optarg, \"off\")) {\n>> >> +       if (0) ;\n>> >\n>> > Leftover cruft from some intermediate changes or something?\n>>\n>> No. It's just an idiom for if-switch, making all the actual cases look\n>> the same. Without this the first one looks special when in fact it\n>> isn't. I won't die for it though.\n>>\n>> >\n>> >> +       else if (!strcmp(optarg, \"off\")   || !strcmp(optarg, \"none\"))\n>> >>                 suppress(revs);\n>> >> -       } else {\n>> >> + else if (!strcmp(optarg, \"first\") || !strcmp(optarg,\n>> >> \"first-parent\"))\n>> >> +               set_first_parent(revs);\n>> >> +       else if (!strcmp(optarg, \"sep\")   || !strcmp(optarg, \"separate\"))\n>> >> +               set_separate(revs);\n>> >> +       else if (!strcmp(optarg, \"comb\")  || !strcmp(optarg, \"combined\"))\n>> >> +               set_combined(revs);\n>> >> + else if (!strcmp(optarg, \"dense\") || !strcmp(optarg,\n>> >> \"dense-combined\"))\n>> >> +               set_dense_combined(revs);\n>> >> +       else\n>> >\n>> > Not sure I like the special-casing for \"sep\" and \"comb\".  \"dense\"\n>> > seems okay since it's a real word.\n>>\n>> That was a poor-man attempt at unique shortcuts made by hand, as well as\n>> a reminder to consider to re-write this using generic options framework\n>> that will do it automagically. They are just a few first letters,\n>> nothing more. That's why I didn't even document them.\n>\n> Seems like a\n>    /* TODO: use generic options framework to allow abbreviations */\n> would make that intent much more clear.\n>\n>> > Since you're adding short versions of m, c, and cc later in the\n>> > series, do we need these other special-case forms?\n>>\n>> No, I don't think we do necessarily need them, but then they do no harm\n>> either, so I didn't remove them when I added m, c, and cc. Neither was I\n>> sure we do need these m, c, and cc in the first place.\n>\n> Well, I'd say it certainly adds clutter for reviewers, so there is at\n> least a little harm.  ;-)  It was on the patch that added m, c, and cc\n> that it particularly stood out to me, so I looked up the relevant\n> commit so that I could add the comment at the right place to make it\n> easier for you to rip out.\n\nMay that's because they did make sense before the patch that added m, c,\nand cc, where they stood out for you.\n\nOverall, if we do agree m, c, and cc mnemonics are good to have, I'd opt\nfor removing these hand-made abbrevs indeed.\n\nThanks,\n-- Sergey\n"},{"id":"412599","messageId":"871rfm95b9.fsf@osv.gnss.ru","threadId":"54550","inReplyTo":"CABPp-BGPZiwjSzZw5PLwkctW7hnG2S6UGHmkTGCh1BqgXJ+vEQ@mail.gmail.com","subject":"Re: [PATCH v2 23/33] diff-merges: fix style of functions definitions","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-18T21:23:38Z","receivedAt":"2020-12-18T21:24:39Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Elijah Newren <newren@gmail.com> writes:\n\n> On Fri, Dec 18, 2020 at 5:41 AM Sergey Organov <sorganov@gmail.com> wrote:\n>>\n>> Elijah Newren <newren@gmail.com> writes:\n>>\n>> > On Wed, Dec 16, 2020 at 10:50 AM Sergey Organov <sorganov@gmail.com> wrote:\n>> >>\n>> >> Put open curly brace on its own line\n>> >>\n>> >> Signed-off-by: Sergey Organov <sorganov@gmail.com>\n>> >> ---\n>> >>  diff-merges.c | 36 ++++++++++++++++++++++++------------\n>> >>  1 file changed, 24 insertions(+), 12 deletions(-)\n>> >>\n>> >> diff --git a/diff-merges.c b/diff-merges.c\n>> >> index cba391604ac7..0165fa22fcd1 100644\n>> >> --- a/diff-merges.c\n>> >> +++ b/diff-merges.c\n>> >> @@ -2,7 +2,8 @@\n>> >>\n>>\n>> [...]\n>>\n>> >>\n>> >> -void diff_merges_set_dense_combined_if_unset(struct rev_info *revs) {\n>> >> +void diff_merges_set_dense_combined_if_unset(struct rev_info *revs)\n>> >> +{\n>> >>         if (!revs->combine_merges)\n>> >>                 set_dense_combined(revs);\n>> >>  }\n>> >> --\n>> >> 2.25.1\n>> >>\n>> >\n>> > But...didn't you add all these functions yourself earlier in the\n>> > series?\n>>\n>> Yes, I did indeed and somehow picked wrong style from one of the\n>> occurrences of this style in the existing Git codebase.\n>>\n>> > Why didn't you split this patch up and squash it into the\n>> > relevant previous patches?\n>>\n>> When Junio noticed and pointed to this deficiency, I asked him if I\n>> should fix all the series from the start, or it'd be OK to use fixup\n>> commit. As he didn't answer and nobody else commented either, I opted\n>> for the latter.\n>>\n>> I can still do it if it's that essential, but I'd prefer not to, to\n>> avoid both the hand-work and causing entire series to change. The\n>> problem is that there were code movements in the series, so such a fix\n>> to earlier patches would cause conflicts down the commits chain, to be\n>> resolved by hand.\n>\n> That's what add -p and interactive rebase is for.  :-)  Code is read\n> more than it is written, so it's important to get things clean.  And\n> not just for immediate reviewers, but for people who look at it later.\n\nI do know how to do it, but I'd still prefer it to be accepted in its\ncurrent form, as I don't see this particular case being that important\nto justify rewriting of all the series. I'll go through the pain if\nit's a show-stopper though.\n\nThanks,\n-- Sergey\n"},{"id":"412600","messageId":"87tusi7pq4.fsf@osv.gnss.ru","threadId":"54550","inReplyTo":"CABPp-BGg9oBkG3ZaWztKMnQE4sREOK_L3so5fer5hbiAKxMaHg@mail.gmail.com","subject":"Re: [PATCH v2 24/33] diff-merges: handle imply -p on -c/--cc logic for log.c","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-18T21:45:39Z","receivedAt":"2020-12-18T21:46:24Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Elijah Newren <newren@gmail.com> writes:\n\n> On Fri, Dec 18, 2020 at 6:01 AM Sergey Organov <sorganov@gmail.com> wrote:\n>>\n>> Elijah Newren <newren@gmail.com> writes:\n>>\n>> > On Wed, Dec 16, 2020 at 10:50 AM Sergey Organov <sorganov@gmail.com> wrote:\n>> >>\n>> >> Move logic that handles implying -p on -c/--cc from\n>> >> log_setup_revisions_tweak() to diff_merges_setup_revs(), where it\n>> >> belongs.\n>> >\n>> > A very minor point, but I'd probably drop the \"where it belongs\";\n>> > while I think the new place makes sense for it, it reads to me like\n>> > you're either relying on a consensus to move it or implying there was\n>> > a mistake to not put it here previously, neither of which makes sense.\n>>\n>> Well, it was meant to be an excuse for not moving it there earlier in\n>> the patch series indeed. I just overlooked this piece of code that\n>> logically belongs to the diff-merges module. I think you need to\n>> consider the state of the sources right before this patch to see the\n>> point of phrasing it like this.\n>>\n>> That said, I'm fine removing this either.\n>\n> If it should have been moved there earlier, then you should amend the\n> relevant previous commit instead of making a new one.  rebase -i is\n> your friend and should be used, especially with long patch series.\n> :-)\n\nThis is to be a separate commit anyway. I can move the commit itself\nmore closer to the beginning, but I don't see how it'd make things\nany better.\n\nBy \"earlier\" above I mostly meant that I should have noticed and moved\nit in the first issue or the patch series.\n\n>\n>> > Much more importantly, this patch doesn't do what you said in\n>> > discussions on the previous round.  It'd be helpful if the commit\n>> > message called out that you are just moving the logic for now and that\n>> > a subsequent patch will tweak the logic to only trigger this for\n>> > -c/--cc and not for --diff-merges=.* flags.\n>>\n>> I believe this patch is useful by itself, even without any future\n>> improvements (that we actually discussed), if any, so I don't see the\n>> point in describing what this patch doesn't do.\n>>\n>> OTOH, the commit message seems to be clear enough to expect this patch\n>> to be pure refactoring, without any functional changes, no?\n>\n> I'm just pointing out that reading the patch triggers a \"wait, you\n> said you wanted to enable diffs for merges without diffs for regular\n> commits\" reaction and makes reviewers start diving into the code to\n> check if they missed where that happened.  Sometimes they'll even\n> respond to the commit asking about it...and then read a later patch\n> and find the answer.  Perhaps I'm more attuned to this, because I've\n> done this to reviewers a number of times and they have asked me to add\n> a note in the earlier commit message to make it easier for other\n> reviewers to follow and read the series.  You don't need to describe\n> in full detail the subsequent changes that will come, just highlight\n> that they are coming to give reviewers an aid.  For example, this\n> could be as simple as:\n>\n> \"\"\"\n> Move logic that handles implying -p on -c/--cc from\n> log_setup_revisions_tweak() to diff_merges_setup_revs().  A\n> subsequent commit will tweak this logic further.\n> \"\"\"\n\nI think I see what you mean, but I still don't like this, sorry, as:\n\nFirst, this commit doesn't tweak the logic at all, so \"further\" doesn't\nsound right.\n\nSecond, the purpose of this move is not to have subsequent commits that\nwill tweak this logic further in any particular way. One of the aims of\nthis commit is rather to make it more simple to have /any/ further\ntweaks to the logic.\n\nThird, if the \"tweak\" you mention is not accepted, I'd need not to only\nget rid of the tweaking commit, but not to forget to edit the\ndescription of this one, that is basically unrelated?\n\n>\n> (Note that 'git log --grep=subsequent' in git.git will find you\n> several examples of where people have done this kind of thing.)\n\nYeah, I agree it's useful when commits are tightly coupled and thus the\npurpose of single commit is unclear. I just don't think this one is such\na case.\n\nThanks,\n-- Sergey\n"},{"id":"412601","messageId":"CABPp-BF6YyNNYT1i_56=89TjtKEj09bs6TOXJWYKXsC6yAZ0Rw@mail.gmail.com","threadId":"54550","inReplyTo":"87o8iq97o2.fsf@osv.gnss.ru","subject":"Re: [PATCH v2 26/33] diff-merges: let new options enable diff without -p","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2020-12-18T22:06:20Z","receivedAt":"2020-12-18T22:07:13Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Fri, Dec 18, 2020 at 12:32 PM Sergey Organov <sorganov@gmail.com> wrote:\n>\n> Elijah Newren <newren@gmail.com> writes:\n>\n> > On Fri, Dec 18, 2020 at 6:42 AM Sergey Organov <sorganov@gmail.com> wrote:\n> >>\n> >> Elijah Newren <newren@gmail.com> writes:\n> >>\n> >> > On Wed, Dec 16, 2020 at 10:50 AM Sergey Organov <sorganov@gmail.com> wrote:\n>\n> [...]\n>\n> >> >> diff --git a/log-tree.c b/log-tree.c\n> >> >> index f9385b1dae6f..67060492ca0a 100644\n> >> >> --- a/log-tree.c\n> >> >> +++ b/log-tree.c\n> >> >> @@ -899,15 +899,21 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log\n> >> >>         int showed_log;\n> >> >>         struct commit_list *parents;\n> >> >>         struct object_id *oid;\n> >> >> +       int is_merge;\n> >> >> +       int regulars_need_diff = opt->diff || opt->diffopt.flags.exit_with_status;\n> >> >\n> >> > So rev_info.diff has changed in meaning from\n> >> > commits-need-to-show-a-diff, to non-merge-commits-need-to-show-a-diff.\n> >> > That's a somewhat subtle semantic shift.  Perhaps it's worth adding a\n> >> > comment to the declaration of rev_info.diff to highlight this?  (And\n> >> > perhaps even rename the flag?)\n> >>\n> >> No, the meaning of rev_info.diff hopefully didn't change. rev_info.diff\n> >> still enables all the commits to pass further once set. It is still\n> >> exactly the same old condition, just assigned to a variable for reuse.\n> >> My aim was to avoid touching existing logic of this function and only\n> >> add a new functionality when opt->merges_need_diff is set.\n> >>\n> >> It looks like I rather choose confusing name for the variable, and it'd\n> >> be more clear if I'd call this, say:\n> >>\n> >>   int need_diff = opt->diff || opt->diffopt.flags.exit_with_status;\n> >>\n> >> ?\n> >>\n> >> What do you think?\n> >\n> > I think need_diff would actually be confusing.  It can be false when\n> > you need diffs (e.g. --diff-merges=cc with no -p, because then you'd\n> > need diffs for merge commits and not for non-merge commits).  I'd\n> > stick with your original local variable name.\n> >\n> > Perhaps opt->diff hasn't changed meaning and I just had a wrong mental\n> > model in my head for what it meant, but even then what seems like its\n> > obvious purpose given its name is mismatched with what it actually\n> > does.  Since you are already changing struct rev_info in this series,\n> > this was more a note that a name change or at least a comment for\n> > opt->diff might be useful.  I mean, you asked a couple times on the\n> > previous series for help trying to understand it, and I could only\n> > offer some flailing guesses and Junio responded with a couple bits of\n> > history.  Clearly, it isn't very clear and this patch reminded me of\n> > that and made me wonder if we're possibly making it a little harder\n> > for others further down the road to figure out.\n>\n> I still don't see why opt->diff is needed in the first place, and\n> second, why opt->diffopt.flags.exit_with_status check is here? Why\n> whoever sets opt->diffopt.flags.exit_with_status doesn't just set\n> opt->diff as well (provided opt->diff is needed in the first place)?\n>\n> From the aforementioned discussion it looks like opt->diff is an\n> optimization (maybe a remnant from the times when diff was a separate\n> script), and that apparently there is some code instance somewhere that\n> actually relies on the fact that clearing opt->diff is enough to disable\n> diff machinery (as followed from my experiment of removing the check\n> altogether and then getting only single seemingly unrelated test\n> failing.)\n>\n> Overall, neither have I any idea how to clarify this, nor do I want to\n> bother in this patch series. It'd be nice though if somebody who really\n> does understand diff machinery in Git does the job.\n\nDoh, I was hoping you had it all figured out.  If not, then that's a\nfair enough argument not to attempt to clarify.\n"},{"id":"412602","messageId":"87o8iq7oj3.fsf@osv.gnss.ru","threadId":"54550","inReplyTo":"CABPp-BGAHFLZDWaK5q+ZHOShUOZnRqUQd+T-X6mXxkg5cp7QpQ@mail.gmail.com","subject":"Re: [PATCH v2 29/33] doc/git-log: describe new --diff-merges options","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-18T22:11:28Z","receivedAt":"2020-12-18T22:12:29Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Elijah Newren <newren@gmail.com> writes:\n\n> On Fri, Dec 18, 2020 at 8:05 AM Sergey Organov <sorganov@gmail.com> wrote:\n>>\n>> Elijah Newren <newren@gmail.com> writes:\n>>\n>> > On Wed, Dec 16, 2020 at 10:50 AM Sergey Organov <sorganov@gmail.com> wrote:\n>> >>\n>> >> Describe all the new --diff-merges options in the git-log.txt and\n>> >> adopt description of originals accordingly.\n>> >\n>> > You also took care to explain interactions of options with -p that\n>> > were previously undocumented, which is a nice bonus.  That wording\n>> > could still be improved a bit, though, as noted below.\n>> >\n>> >> Signed-off-by: Sergey Organov <sorganov@gmail.com>\n>> >> ---\n>> >>  Documentation/git-log.txt | 85 ++++++++++++++++++++++++---------------\n>> >>  1 file changed, 52 insertions(+), 33 deletions(-)\n>> >>\n>> >> diff --git a/Documentation/git-log.txt b/Documentation/git-log.txt\n>> >> index 2b8ac5ff882a..27bc619490c6 100644\n>> >> --- a/Documentation/git-log.txt\n>> >> +++ b/Documentation/git-log.txt\n>> >> @@ -120,45 +120,64 @@ DIFF FORMATTING\n>> >>  By default, `git log` does not generate any diff output. The options\n>> >>  below can be used to show the changes made by each commit.\n>> >>\n>> >> -Note that unless one of `-c`, `--cc`, or `-m` is given, merge commits\n>> >> -will never show a diff, even if a diff format like `--patch` is\n>> >> -selected, nor will they match search options like `-S`. The exception is\n>> >> -when `--first-parent` is in use, in which merges are treated like normal\n>> >> -single-parent commits (this can be overridden by providing a\n>> >> -combined-diff option or with `--no-diff-merges`).\n>> >> +Note that unless one of `--diff-merges` variants (including short\n>> >> +`-m`, `-c`, and `--cc` options) is explicitly given, merge commits\n>> >> +will not show a diff, even if a diff format like `--patch` is\n>> >> +selected, nor will they match search options like `-S`. The exception\n>> >> +is when `--first-parent` is in use, in which case `first-parent` is\n>> >> +the default format.\n>> >\n>> > Thanks for fixing this up.  :-)\n>>\n>> Don't mention it :-)\n>>\n>> >\n>> >>\n>> >> --c::\n>> >> -       With this option, diff output for a merge commit\n>> >> -       shows the differences from each of the parents to the merge result\n>> >> -       simultaneously instead of showing pairwise diff between a parent\n>> >> -       and the result one at a time. Furthermore, it lists only files\n>> >> -       which were modified from all parents.\n>> >> -\n>> >> ---cc::\n>> >> -       This flag implies the `-c` option and further compresses the\n>> >> -       patch output by omitting uninteresting hunks whose contents in\n>> >> -       the parents have only two variants and the merge result picks\n>> >> -       one of them without modification.\n>> >> +--diff-merges=(off|none|first-parent|1|separate|m|combined|c|dense-combined|cc)::\n>> >> +--no-diff-merges::\n>> >> +       Specify diff format to be used for merge commits. Default is\n>> >> +       `off` unless `--first-parent` is in use, in which case\n>> >> +       `first-parent` is the default.\n>> >> ++\n>> >> +--diff-merges=(off|none):::\n>> >> +--no-diff-merges:::\n>> >> +       Disable output of diffs for merge commits. Useful to override\n>> >> +       implied value.\n>> >> ++\n>> >> +--diff-merges=first-parent:::\n>> >> +--diff-merges=1:::\n>> >> +       This option makes merge commits show the full diff with\n>> >> +       respect to the first parent only.\n>> >\n>> > Does it imply -p?\n>>\n>> No, none of --diff-merges options do. This one is not any special. Why\n>> the question?\n>\n> The documentation on -m was vague enough that it made me wonder.\n> Fixing it would probably prevent me from having asked this question.\n\nOK, I see, so let's try to fix the cause, please see below.\n\n>\n>> >> ++\n>> >> +--diff-merges=separate:::\n>> >> +--diff-merges=m:::\n>> >> +-m:::\n>> >> +       This makes merge commits show the full diff with respect to\n>> >> +       each of the parents. Separate log entry and diff is generated\n>> >> +       for each parent. `-m` is different in that it doesn't produce\n>> >> +       any output without `-p`.\n>> >\n>> > Different from what?  From --first-parent?  From flags that haven't\n>> > been covered yet?  (-c and --cc show up below)\n>>\n>> Well, from --diff-merges=m and --diff-merges=separate, that, as any\n>> other --diff-merge option, do produce output (for merge commits) even\n>> without -p.\n>\n> That wasn't at all clear to me as the intent of the last sentence.\n\nWell, actually, the right answer to your question is: -m is different\nfrom *everything* ;-)\n\nMaybe the confusion you got is not caused by the documentation, but\nrather by some of your expectations? In particular, I wonder, how comes\n--first-parent appeared in your question, that is entirely unrelated?\n\nI mean I'm still unsure how to make this description more clear, maybe\nthis will do:\n\n--diff-merges=separate:::\n--diff-merges=m:::\n-m:::\n       This makes merge commits show the full diff with respect to\n       each of the parents. Separate log entry and diff is generated\n       for each parent. `-m` doesn't produce any output without `-p`.\n\n>\n>> >> ++\n>> >> +--diff-merges=combined:::\n>> >> +--diff-merges=c:::\n>> >> +-c:::\n>> >> +       With this option, diff output for a merge commit shows the\n>> >> +       differences from each of the parents to the merge result\n>> >> +       simultaneously instead of showing pairwise diff between a\n>> >> +       parent and the result one at a time. Furthermore, it lists\n>> >> +       only files which were modified from all parents. Historically,\n>> >> +       `-c` enables diff output for non-merge commits as well.\n>> >\n>> > \"Historically\"?  Does that mean it doesn't anymore?\n>>\n>> Eh, I don't think \"historically\" means that, but I'm not sure, being\n>> non-native English speaker.\n>\n> Sometimes non-native speakers use the language more accurately.  This\n> might be such a case, but that sentence did make me think you might be\n> attempting to document past behavior as a way of helping people adjust\n> to current/new behavior.\n>\n>> > (Maybe, \"The short form, `-c`, also enables diff output for non-merge\n>> > commits as well.\" or something like that?)\n>>\n>> ... and then try to explain why this otherwise illogical behavior is\n>> there? I thought \"historically\" would cover that.\n>\n> It doesn't seem like illogical behavior to me.   Perhaps the view of\n> -c as a diff-merges option, reinforced by placing -c right next to\n> --diff-merges in the documentation, is what causes you to think so?\n\n-c, described as selecting specific format of representation of merge\ncommits, suddenly enabling diff output of non-merge commits, is logical?\nNo. Useful? Maybe. Logical? Not to me. Just saying, see below.\n\n> If so, maybe we should document -c (and --cc) separately after all the\n> --diff-merges options, using something like the following:\n>\n> -c:::\n>     Implies both --patch and --diff-merges=combined, i.e. turn on\n> patches for normal commits and show a combined diff format for merges.\n\nThe problem with this is that it'd then be preferable to describe -m\nseparately as well, and that's not that simple.\n\nOverall, I'd rather change that in place, like this:\n\n--diff-merges=combined:::\n--diff-merges=c:::\n-c:::\n       With this option, diff output for a merge commit shows the\n       differences from each of the parents to the merge result\n       simultaneously instead of showing pairwise diff between a\n       parent and the result one at a time. Furthermore, it lists\n       only files which were modified from all parents. `-c` implies\n       `--patch`.\n\n\nThanks,\n-- Sergey\n"},{"id":"412603","messageId":"CABPp-BG-Nv=pzwTO3J0OK20gFVV67_qFL+m-cL7d9xrMvTjH-Q@mail.gmail.com","threadId":"54550","inReplyTo":"87tusi7pq4.fsf@osv.gnss.ru","subject":"Re: [PATCH v2 24/33] diff-merges: handle imply -p on -c/--cc logic for log.c","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2020-12-18T22:12:46Z","receivedAt":"2020-12-18T22:13:55Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Fri, Dec 18, 2020 at 1:45 PM Sergey Organov <sorganov@gmail.com> wrote:\n>\n> Elijah Newren <newren@gmail.com> writes:\n>\n> > On Fri, Dec 18, 2020 at 6:01 AM Sergey Organov <sorganov@gmail.com> wrote:\n> >>\n> >> Elijah Newren <newren@gmail.com> writes:\n> >>\n> >> > On Wed, Dec 16, 2020 at 10:50 AM Sergey Organov <sorganov@gmail.com> wrote:\n> >> >>\n> >> >> Move logic that handles implying -p on -c/--cc from\n> >> >> log_setup_revisions_tweak() to diff_merges_setup_revs(), where it\n> >> >> belongs.\n> >> >\n> >> > A very minor point, but I'd probably drop the \"where it belongs\";\n> >> > while I think the new place makes sense for it, it reads to me like\n> >> > you're either relying on a consensus to move it or implying there was\n> >> > a mistake to not put it here previously, neither of which makes sense.\n> >>\n> >> Well, it was meant to be an excuse for not moving it there earlier in\n> >> the patch series indeed. I just overlooked this piece of code that\n> >> logically belongs to the diff-merges module. I think you need to\n> >> consider the state of the sources right before this patch to see the\n> >> point of phrasing it like this.\n> >>\n> >> That said, I'm fine removing this either.\n> >\n> > If it should have been moved there earlier, then you should amend the\n> > relevant previous commit instead of making a new one.  rebase -i is\n> > your friend and should be used, especially with long patch series.\n> > :-)\n>\n> This is to be a separate commit anyway. I can move the commit itself\n> more closer to the beginning, but I don't see how it'd make things\n> any better.\n>\n> By \"earlier\" above I mostly meant that I should have noticed and moved\n> it in the first issue or the patch series.\n\nEven if keeping the commit as-is, moving it earlier would have one benefit...\n\n> >\n> >> > Much more importantly, this patch doesn't do what you said in\n> >> > discussions on the previous round.  It'd be helpful if the commit\n> >> > message called out that you are just moving the logic for now and that\n> >> > a subsequent patch will tweak the logic to only trigger this for\n> >> > -c/--cc and not for --diff-merges=.* flags.\n> >>\n> >> I believe this patch is useful by itself, even without any future\n> >> improvements (that we actually discussed), if any, so I don't see the\n> >> point in describing what this patch doesn't do.\n> >>\n> >> OTOH, the commit message seems to be clear enough to expect this patch\n> >> to be pure refactoring, without any functional changes, no?\n> >\n> > I'm just pointing out that reading the patch triggers a \"wait, you\n> > said you wanted to enable diffs for merges without diffs for regular\n> > commits\" reaction and makes reviewers start diving into the code to\n> > check if they missed where that happened.  Sometimes they'll even\n> > respond to the commit asking about it...and then read a later patch\n> > and find the answer.  Perhaps I'm more attuned to this, because I've\n> > done this to reviewers a number of times and they have asked me to add\n> > a note in the earlier commit message to make it easier for other\n> > reviewers to follow and read the series.  You don't need to describe\n> > in full detail the subsequent changes that will come, just highlight\n> > that they are coming to give reviewers an aid.  For example, this\n> > could be as simple as:\n> >\n> > \"\"\"\n> > Move logic that handles implying -p on -c/--cc from\n> > log_setup_revisions_tweak() to diff_merges_setup_revs().  A\n> > subsequent commit will tweak this logic further.\n> > \"\"\"\n>\n> I think I see what you mean, but I still don't like this, sorry, as:\n>\n> First, this commit doesn't tweak the logic at all, so \"further\" doesn't\n> sound right.\n\nGood point, I should have left off \"further\".\n\n> Second, the purpose of this move is not to have subsequent commits that\n> will tweak this logic further in any particular way. One of the aims of\n> this commit is rather to make it more simple to have /any/ further\n> tweaks to the logic.\n>\n> Third, if the \"tweak\" you mention is not accepted, I'd need not to only\n> get rid of the tweaking commit, but not to forget to edit the\n> description of this one, that is basically unrelated?\n\n...so, one advantage of moving this commit earlier in the series is\nthat if it appears before the introduction of --diff-merges, then it\ndoesn't trigger the \"What?  I thought we weren't making the\ndiff-merges flags trigger patches for non-merge commits\" reaction, and\nthus makes it clearer that the patch is just pure refactoring.\n\n> >\n> > (Note that 'git log --grep=subsequent' in git.git will find you\n> > several examples of where people have done this kind of thing.)\n>\n> Yeah, I agree it's useful when commits are tightly coupled and thus the\n> purpose of single commit is unclear. I just don't think this one is such\n> a case.\n\nI think where it appears in the series makes its purpose unclear.\n"},{"id":"412604","messageId":"87k0te7o9s.fsf@osv.gnss.ru","threadId":"54550","inReplyTo":"CABPp-BG-Nv=pzwTO3J0OK20gFVV67_qFL+m-cL7d9xrMvTjH-Q@mail.gmail.com","subject":"Re: [PATCH v2 24/33] diff-merges: handle imply -p on -c/--cc logic for log.c","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-18T22:17:03Z","receivedAt":"2020-12-18T22:17:48Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Elijah Newren <newren@gmail.com> writes:\n\n> On Fri, Dec 18, 2020 at 1:45 PM Sergey Organov <sorganov@gmail.com> wrote:\n>>\n>> Elijah Newren <newren@gmail.com> writes:\n>>\n>> > On Fri, Dec 18, 2020 at 6:01 AM Sergey Organov <sorganov@gmail.com> wrote:\n>> >>\n>> >> Elijah Newren <newren@gmail.com> writes:\n>> >>\n>> >> > On Wed, Dec 16, 2020 at 10:50 AM Sergey Organov\n>> >> > <sorganov@gmail.com> wrote:\n>> >> >>\n>> >> >> Move logic that handles implying -p on -c/--cc from\n>> >> >> log_setup_revisions_tweak() to diff_merges_setup_revs(), where it\n>> >> >> belongs.\n>> >> >\n>> >> > A very minor point, but I'd probably drop the \"where it belongs\";\n>> >> > while I think the new place makes sense for it, it reads to me like\n>> >> > you're either relying on a consensus to move it or implying there was\n>> >> > a mistake to not put it here previously, neither of which makes sense.\n>> >>\n>> >> Well, it was meant to be an excuse for not moving it there earlier in\n>> >> the patch series indeed. I just overlooked this piece of code that\n>> >> logically belongs to the diff-merges module. I think you need to\n>> >> consider the state of the sources right before this patch to see the\n>> >> point of phrasing it like this.\n>> >>\n>> >> That said, I'm fine removing this either.\n>> >\n>> > If it should have been moved there earlier, then you should amend the\n>> > relevant previous commit instead of making a new one.  rebase -i is\n>> > your friend and should be used, especially with long patch series.\n>> > :-)\n>>\n>> This is to be a separate commit anyway. I can move the commit itself\n>> more closer to the beginning, but I don't see how it'd make things\n>> any better.\n>>\n>> By \"earlier\" above I mostly meant that I should have noticed and moved\n>> it in the first issue or the patch series.\n>\n> Even if keeping the commit as-is, moving it earlier would have one benefit...\n>\n>> >\n>> >> > Much more importantly, this patch doesn't do what you said in\n>> >> > discussions on the previous round.  It'd be helpful if the commit\n>> >> > message called out that you are just moving the logic for now and that\n>> >> > a subsequent patch will tweak the logic to only trigger this for\n>> >> > -c/--cc and not for --diff-merges=.* flags.\n>> >>\n>> >> I believe this patch is useful by itself, even without any future\n>> >> improvements (that we actually discussed), if any, so I don't see the\n>> >> point in describing what this patch doesn't do.\n>> >>\n>> >> OTOH, the commit message seems to be clear enough to expect this patch\n>> >> to be pure refactoring, without any functional changes, no?\n>> >\n>> > I'm just pointing out that reading the patch triggers a \"wait, you\n>> > said you wanted to enable diffs for merges without diffs for regular\n>> > commits\" reaction and makes reviewers start diving into the code to\n>> > check if they missed where that happened.  Sometimes they'll even\n>> > respond to the commit asking about it...and then read a later patch\n>> > and find the answer.  Perhaps I'm more attuned to this, because I've\n>> > done this to reviewers a number of times and they have asked me to add\n>> > a note in the earlier commit message to make it easier for other\n>> > reviewers to follow and read the series.  You don't need to describe\n>> > in full detail the subsequent changes that will come, just highlight\n>> > that they are coming to give reviewers an aid.  For example, this\n>> > could be as simple as:\n>> >\n>> > \"\"\"\n>> > Move logic that handles implying -p on -c/--cc from\n>> > log_setup_revisions_tweak() to diff_merges_setup_revs().  A\n>> > subsequent commit will tweak this logic further.\n>> > \"\"\"\n>>\n>> I think I see what you mean, but I still don't like this, sorry, as:\n>>\n>> First, this commit doesn't tweak the logic at all, so \"further\" doesn't\n>> sound right.\n>\n> Good point, I should have left off \"further\".\n>\n>> Second, the purpose of this move is not to have subsequent commits that\n>> will tweak this logic further in any particular way. One of the aims of\n>> this commit is rather to make it more simple to have /any/ further\n>> tweaks to the logic.\n>>\n>> Third, if the \"tweak\" you mention is not accepted, I'd need not to only\n>> get rid of the tweaking commit, but not to forget to edit the\n>> description of this one, that is basically unrelated?\n>\n> ...so, one advantage of moving this commit earlier in the series is\n> that if it appears before the introduction of --diff-merges, then it\n> doesn't trigger the \"What?  I thought we weren't making the\n> diff-merges flags trigger patches for non-merge commits\" reaction, and\n> thus makes it clearer that the patch is just pure refactoring.\n>\n>> >\n>> > (Note that 'git log --grep=subsequent' in git.git will find you\n>> > several examples of where people have done this kind of thing.)\n>>\n>> Yeah, I agree it's useful when commits are tightly coupled and thus the\n>> purpose of single commit is unclear. I just don't think this one is such\n>> a case.\n>\n> I think where it appears in the series makes its purpose unclear.\n\nFine, I'll move it earlier in the series then.\n\nThanks,\n-- Sergey\n"},{"id":"412605","messageId":"87ft427o69.fsf@osv.gnss.ru","threadId":"54550","inReplyTo":"CABPp-BF6YyNNYT1i_56=89TjtKEj09bs6TOXJWYKXsC6yAZ0Rw@mail.gmail.com","subject":"Re: [PATCH v2 26/33] diff-merges: let new options enable diff without -p","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-18T22:19:10Z","receivedAt":"2020-12-18T22:20:09Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Elijah Newren <newren@gmail.com> writes:\n\n> On Fri, Dec 18, 2020 at 12:32 PM Sergey Organov <sorganov@gmail.com> wrote:\n>>\n>> Elijah Newren <newren@gmail.com> writes:\n>>\n>> > On Fri, Dec 18, 2020 at 6:42 AM Sergey Organov <sorganov@gmail.com> wrote:\n>> >>\n>> >> Elijah Newren <newren@gmail.com> writes:\n>> >>\n>> >> > On Wed, Dec 16, 2020 at 10:50 AM Sergey Organov\n>> >> > <sorganov@gmail.com> wrote:\n>>\n>> [...]\n>>\n>> >> >> diff --git a/log-tree.c b/log-tree.c\n>> >> >> index f9385b1dae6f..67060492ca0a 100644\n>> >> >> --- a/log-tree.c\n>> >> >> +++ b/log-tree.c\n>> >> >> @@ -899,15 +899,21 @@ static int log_tree_diff(struct rev_info\n>> >> >> *opt, struct commit *commit, struct log\n>> >> >>         int showed_log;\n>> >> >>         struct commit_list *parents;\n>> >> >>         struct object_id *oid;\n>> >> >> +       int is_merge;\n>> >> >> + int regulars_need_diff = opt->diff ||\n>> >> >> opt->diffopt.flags.exit_with_status;\n>> >> >\n>> >> > So rev_info.diff has changed in meaning from\n>> >> > commits-need-to-show-a-diff, to non-merge-commits-need-to-show-a-diff.\n>> >> > That's a somewhat subtle semantic shift.  Perhaps it's worth adding a\n>> >> > comment to the declaration of rev_info.diff to highlight this?  (And\n>> >> > perhaps even rename the flag?)\n>> >>\n>> >> No, the meaning of rev_info.diff hopefully didn't change. rev_info.diff\n>> >> still enables all the commits to pass further once set. It is still\n>> >> exactly the same old condition, just assigned to a variable for reuse.\n>> >> My aim was to avoid touching existing logic of this function and only\n>> >> add a new functionality when opt->merges_need_diff is set.\n>> >>\n>> >> It looks like I rather choose confusing name for the variable, and it'd\n>> >> be more clear if I'd call this, say:\n>> >>\n>> >>   int need_diff = opt->diff || opt->diffopt.flags.exit_with_status;\n>> >>\n>> >> ?\n>> >>\n>> >> What do you think?\n>> >\n>> > I think need_diff would actually be confusing.  It can be false when\n>> > you need diffs (e.g. --diff-merges=cc with no -p, because then you'd\n>> > need diffs for merge commits and not for non-merge commits).  I'd\n>> > stick with your original local variable name.\n>> >\n>> > Perhaps opt->diff hasn't changed meaning and I just had a wrong mental\n>> > model in my head for what it meant, but even then what seems like its\n>> > obvious purpose given its name is mismatched with what it actually\n>> > does.  Since you are already changing struct rev_info in this series,\n>> > this was more a note that a name change or at least a comment for\n>> > opt->diff might be useful.  I mean, you asked a couple times on the\n>> > previous series for help trying to understand it, and I could only\n>> > offer some flailing guesses and Junio responded with a couple bits of\n>> > history.  Clearly, it isn't very clear and this patch reminded me of\n>> > that and made me wonder if we're possibly making it a little harder\n>> > for others further down the road to figure out.\n>>\n>> I still don't see why opt->diff is needed in the first place, and\n>> second, why opt->diffopt.flags.exit_with_status check is here? Why\n>> whoever sets opt->diffopt.flags.exit_with_status doesn't just set\n>> opt->diff as well (provided opt->diff is needed in the first place)?\n>>\n>> From the aforementioned discussion it looks like opt->diff is an\n>> optimization (maybe a remnant from the times when diff was a separate\n>> script), and that apparently there is some code instance somewhere that\n>> actually relies on the fact that clearing opt->diff is enough to disable\n>> diff machinery (as followed from my experiment of removing the check\n>> altogether and then getting only single seemingly unrelated test\n>> failing.)\n>>\n>> Overall, neither have I any idea how to clarify this, nor do I want to\n>> bother in this patch series. It'd be nice though if somebody who really\n>> does understand diff machinery in Git does the job.\n>\n> Doh, I was hoping you had it all figured out.\n\nI tried. I failed. :-)\n\n> If not, then that's a fair enough argument not to attempt to clarify.\n\nThis.\n\nThanks,\n-- Sergey\n"},{"id":"412606","messageId":"CABPp-BFFKVBtOSLbxbrSg+seG5zVftfuo=H35V5GKo+3iimLng@mail.gmail.com","threadId":"54550","inReplyTo":"87o8iq7oj3.fsf@osv.gnss.ru","subject":"Re: [PATCH v2 29/33] doc/git-log: describe new --diff-merges options","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2020-12-18T22:28:19Z","receivedAt":"2020-12-18T22:29:13Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Fri, Dec 18, 2020 at 2:11 PM Sergey Organov <sorganov@gmail.com> wrote:\n>\n> Elijah Newren <newren@gmail.com> writes:\n>\n> > On Fri, Dec 18, 2020 at 8:05 AM Sergey Organov <sorganov@gmail.com> wrote:\n> >>\n> >> Elijah Newren <newren@gmail.com> writes:\n> >>\n> >> > On Wed, Dec 16, 2020 at 10:50 AM Sergey Organov <sorganov@gmail.com> wrote:\n> >> >>\n> >> >> Describe all the new --diff-merges options in the git-log.txt and\n> >> >> adopt description of originals accordingly.\n> >> >\n> >> > You also took care to explain interactions of options with -p that\n> >> > were previously undocumented, which is a nice bonus.  That wording\n> >> > could still be improved a bit, though, as noted below.\n> >> >\n> >> >> Signed-off-by: Sergey Organov <sorganov@gmail.com>\n> >> >> ---\n> >> >>  Documentation/git-log.txt | 85 ++++++++++++++++++++++++---------------\n> >> >>  1 file changed, 52 insertions(+), 33 deletions(-)\n> >> >>\n> >> >> diff --git a/Documentation/git-log.txt b/Documentation/git-log.txt\n> >> >> index 2b8ac5ff882a..27bc619490c6 100644\n> >> >> --- a/Documentation/git-log.txt\n> >> >> +++ b/Documentation/git-log.txt\n> >> >> @@ -120,45 +120,64 @@ DIFF FORMATTING\n> >> >>  By default, `git log` does not generate any diff output. The options\n> >> >>  below can be used to show the changes made by each commit.\n> >> >>\n> >> >> -Note that unless one of `-c`, `--cc`, or `-m` is given, merge commits\n> >> >> -will never show a diff, even if a diff format like `--patch` is\n> >> >> -selected, nor will they match search options like `-S`. The exception is\n> >> >> -when `--first-parent` is in use, in which merges are treated like normal\n> >> >> -single-parent commits (this can be overridden by providing a\n> >> >> -combined-diff option or with `--no-diff-merges`).\n> >> >> +Note that unless one of `--diff-merges` variants (including short\n> >> >> +`-m`, `-c`, and `--cc` options) is explicitly given, merge commits\n> >> >> +will not show a diff, even if a diff format like `--patch` is\n> >> >> +selected, nor will they match search options like `-S`. The exception\n> >> >> +is when `--first-parent` is in use, in which case `first-parent` is\n> >> >> +the default format.\n> >> >\n> >> > Thanks for fixing this up.  :-)\n> >>\n> >> Don't mention it :-)\n> >>\n> >> >\n> >> >>\n> >> >> --c::\n> >> >> -       With this option, diff output for a merge commit\n> >> >> -       shows the differences from each of the parents to the merge result\n> >> >> -       simultaneously instead of showing pairwise diff between a parent\n> >> >> -       and the result one at a time. Furthermore, it lists only files\n> >> >> -       which were modified from all parents.\n> >> >> -\n> >> >> ---cc::\n> >> >> -       This flag implies the `-c` option and further compresses the\n> >> >> -       patch output by omitting uninteresting hunks whose contents in\n> >> >> -       the parents have only two variants and the merge result picks\n> >> >> -       one of them without modification.\n> >> >> +--diff-merges=(off|none|first-parent|1|separate|m|combined|c|dense-combined|cc)::\n> >> >> +--no-diff-merges::\n> >> >> +       Specify diff format to be used for merge commits. Default is\n> >> >> +       `off` unless `--first-parent` is in use, in which case\n> >> >> +       `first-parent` is the default.\n> >> >> ++\n> >> >> +--diff-merges=(off|none):::\n> >> >> +--no-diff-merges:::\n> >> >> +       Disable output of diffs for merge commits. Useful to override\n> >> >> +       implied value.\n> >> >> ++\n> >> >> +--diff-merges=first-parent:::\n> >> >> +--diff-merges=1:::\n> >> >> +       This option makes merge commits show the full diff with\n> >> >> +       respect to the first parent only.\n> >> >\n> >> > Does it imply -p?\n> >>\n> >> No, none of --diff-merges options do. This one is not any special. Why\n> >> the question?\n> >\n> > The documentation on -m was vague enough that it made me wonder.\n> > Fixing it would probably prevent me from having asked this question.\n>\n> OK, I see, so let's try to fix the cause, please see below.\n\nSounds good.\n\n> >\n> >> >> ++\n> >> >> +--diff-merges=separate:::\n> >> >> +--diff-merges=m:::\n> >> >> +-m:::\n> >> >> +       This makes merge commits show the full diff with respect to\n> >> >> +       each of the parents. Separate log entry and diff is generated\n> >> >> +       for each parent. `-m` is different in that it doesn't produce\n> >> >> +       any output without `-p`.\n> >> >\n> >> > Different from what?  From --first-parent?  From flags that haven't\n> >> > been covered yet?  (-c and --cc show up below)\n> >>\n> >> Well, from --diff-merges=m and --diff-merges=separate, that, as any\n> >> other --diff-merge option, do produce output (for merge commits) even\n> >> without -p.\n> >\n> > That wasn't at all clear to me as the intent of the last sentence.\n>\n> Well, actually, the right answer to your question is: -m is different\n> from *everything* ;-)\n>\n> Maybe the confusion you got is not caused by the documentation, but\n> rather by some of your expectations? In particular, I wonder, how comes\n> --first-parent appeared in your question, that is entirely unrelated?\n\nWhen you said \"`-m` is different\" it was not clear what you were\ncontrasting to.  The fact that you were contrasting to the other\nvalues in the set of three being described by this paragraph may seem\nobvious to you, and I suspect many other readers may catch on to that,\nbut that really honestly did not occur to me while reading it.  Maybe\nI'm weird.  Maybe some subset of users will be like me and we should\ntighten up the wording.  Hard to say.\n\n> I mean I'm still unsure how to make this description more clear, maybe\n> this will do:\n>\n> --diff-merges=separate:::\n> --diff-merges=m:::\n> -m:::\n>        This makes merge commits show the full diff with respect to\n>        each of the parents. Separate log entry and diff is generated\n>        for each parent. `-m` doesn't produce any output without `-p`.\n\nWorks for me.  :-)\n\n> >\n> >> >> ++\n> >> >> +--diff-merges=combined:::\n> >> >> +--diff-merges=c:::\n> >> >> +-c:::\n> >> >> +       With this option, diff output for a merge commit shows the\n> >> >> +       differences from each of the parents to the merge result\n> >> >> +       simultaneously instead of showing pairwise diff between a\n> >> >> +       parent and the result one at a time. Furthermore, it lists\n> >> >> +       only files which were modified from all parents. Historically,\n> >> >> +       `-c` enables diff output for non-merge commits as well.\n> >> >\n> >> > \"Historically\"?  Does that mean it doesn't anymore?\n> >>\n> >> Eh, I don't think \"historically\" means that, but I'm not sure, being\n> >> non-native English speaker.\n> >\n> > Sometimes non-native speakers use the language more accurately.  This\n> > might be such a case, but that sentence did make me think you might be\n> > attempting to document past behavior as a way of helping people adjust\n> > to current/new behavior.\n> >\n> >> > (Maybe, \"The short form, `-c`, also enables diff output for non-merge\n> >> > commits as well.\" or something like that?)\n> >>\n> >> ... and then try to explain why this otherwise illogical behavior is\n> >> there? I thought \"historically\" would cover that.\n> >\n> > It doesn't seem like illogical behavior to me.   Perhaps the view of\n> > -c as a diff-merges option, reinforced by placing -c right next to\n> > --diff-merges in the documentation, is what causes you to think so?\n>\n> -c, described as selecting specific format of representation of merge\n> commits, suddenly enabling diff output of non-merge commits, is logical?\n> No. Useful? Maybe. Logical? Not to me. Just saying, see below.\n\n:-)\n\nI didn't say the former documentation was correct, or that the\nbehavior logically flowed from the documentation's claims.  And you do\nbring up good points that the past documentation should have been\nupdated when -c and --cc were made to imply -p.  I only claimed that\n-c and --cc provide logical behaviors (I want diffs for everything,\nfor merges do it this way...all expressed in a nice compact bundle).\n\n> > If so, maybe we should document -c (and --cc) separately after all the\n> > --diff-merges options, using something like the following:\n> >\n> > -c:::\n> >     Implies both --patch and --diff-merges=combined, i.e. turn on\n> > patches for normal commits and show a combined diff format for merges.\n>\n> The problem with this is that it'd then be preferable to describe -m\n> separately as well, and that's not that simple.\n>\n> Overall, I'd rather change that in place, like this:\n>\n> --diff-merges=combined:::\n> --diff-merges=c:::\n> -c:::\n>        With this option, diff output for a merge commit shows the\n>        differences from each of the parents to the merge result\n>        simultaneously instead of showing pairwise diff between a\n>        parent and the result one at a time. Furthermore, it lists\n>        only files which were modified from all parents. `-c` implies\n>        `--patch`.\n\nWorks for me.  --cc needs a similar change, obviously.\n"},{"id":"412607","messageId":"CABPp-BEZ6VqyTah7QCzkuUm-p7tA_6cnpGPWpgpQbHp_c3Wc5Q@mail.gmail.com","threadId":"54550","inReplyTo":"871rfm95b9.fsf@osv.gnss.ru","subject":"Re: [PATCH v2 23/33] diff-merges: fix style of functions definitions","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2020-12-18T22:56:04Z","receivedAt":"2020-12-18T22:57:12Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Fri, Dec 18, 2020 at 1:23 PM Sergey Organov <sorganov@gmail.com> wrote:\n>\n> Elijah Newren <newren@gmail.com> writes:\n>\n> > On Fri, Dec 18, 2020 at 5:41 AM Sergey Organov <sorganov@gmail.com> wrote:\n> >>\n> >> Elijah Newren <newren@gmail.com> writes:\n> >>\n> >> > On Wed, Dec 16, 2020 at 10:50 AM Sergey Organov <sorganov@gmail.com> wrote:\n> >> >>\n> >> >> Put open curly brace on its own line\n> >> >>\n> >> >> Signed-off-by: Sergey Organov <sorganov@gmail.com>\n> >> >> ---\n> >> >>  diff-merges.c | 36 ++++++++++++++++++++++++------------\n> >> >>  1 file changed, 24 insertions(+), 12 deletions(-)\n> >> >>\n> >> >> diff --git a/diff-merges.c b/diff-merges.c\n> >> >> index cba391604ac7..0165fa22fcd1 100644\n> >> >> --- a/diff-merges.c\n> >> >> +++ b/diff-merges.c\n> >> >> @@ -2,7 +2,8 @@\n> >> >>\n> >>\n> >> [...]\n> >>\n> >> >>\n> >> >> -void diff_merges_set_dense_combined_if_unset(struct rev_info *revs) {\n> >> >> +void diff_merges_set_dense_combined_if_unset(struct rev_info *revs)\n> >> >> +{\n> >> >>         if (!revs->combine_merges)\n> >> >>                 set_dense_combined(revs);\n> >> >>  }\n> >> >> --\n> >> >> 2.25.1\n> >> >>\n> >> >\n> >> > But...didn't you add all these functions yourself earlier in the\n> >> > series?\n> >>\n> >> Yes, I did indeed and somehow picked wrong style from one of the\n> >> occurrences of this style in the existing Git codebase.\n> >>\n> >> > Why didn't you split this patch up and squash it into the\n> >> > relevant previous patches?\n> >>\n> >> When Junio noticed and pointed to this deficiency, I asked him if I\n> >> should fix all the series from the start, or it'd be OK to use fixup\n> >> commit. As he didn't answer and nobody else commented either, I opted\n> >> for the latter.\n> >>\n> >> I can still do it if it's that essential, but I'd prefer not to, to\n> >> avoid both the hand-work and causing entire series to change. The\n> >> problem is that there were code movements in the series, so such a fix\n> >> to earlier patches would cause conflicts down the commits chain, to be\n> >> resolved by hand.\n> >\n> > That's what add -p and interactive rebase is for.  :-)  Code is read\n> > more than it is written, so it's important to get things clean.  And\n> > not just for immediate reviewers, but for people who look at it later.\n>\n> I do know how to do it, but I'd still prefer it to be accepted in its\n> current form, as I don't see this particular case being that important\n> to justify rewriting of all the series. I'll go through the pain if\n> it's a show-stopper though.\n\nPersonally, I think that a really important point to keep in mind when\nsubmitting patch series is trying to figure out the easiest way to\nmove the code from point A to point B, not the route you took to get\nfrom point A to point B.  This is especially true for longer patch\nseries.  It's common after you've finished a series to discover there\nwas an easier or cleaner route to follow that would have arrived at\nthe same end-point.  It's not uncommon for me to spend a significant\nchunk of time rebasing and restructuring a patch series to try to\nhighlight such a better path.  This includes not just style fixups,\nbut different patch orderings, alternate ways to break up functions,\nusing different data structures, etc.\n\nAll that said, I don't get to choose what's accepted or not, so I\ncan't say if it'll be required.  What I can say is I like your series\nand I think it provides obvious improvements, but I'd still recommend\nagainst its inclusion as it stands for as long as this patch is still\npresent.  (I have a feeling that there are other things in this series\nthat possibly should be squashed, restructured, or refactored, e.g.\n[1]).  This is just my opinion, of course.  You are free to disagree\nwith me, and wait to see what others say and what Junio does.\n\n\n[1] https://lore.kernel.org/git/CABPp-BESWpqska++EsfxfbncyV0kNo1RGLjF+1BiV=D6zLx2LQ@mail.gmail.com/\n"},{"id":"412614","messageId":"5fdd50b444ea9_1d9522208a0@natae.notmuch","threadId":"54550","inReplyTo":"CABPp-BEZ6VqyTah7QCzkuUm-p7tA_6cnpGPWpgpQbHp_c3Wc5Q@mail.gmail.com","subject":"Re: [PATCH v2 23/33] diff-merges: fix style of functions definitions","fromName":"Felipe Contreras","fromEmail":"felipe.contreras@gmail.com","sentAt":"2020-12-19T01:00:36Z","receivedAt":"2020-12-19T01:01:35Z","isPatch":true,"sender":{"key":"felipe.contreras@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8358?v=4"},"body":"Elijah Newren wrote:\n> Personally, I think that a really important point to keep in mind when\n> submitting patch series is trying to figure out the easiest way to\n> move the code from point A to point B, not the route you took to get\n> from point A to point B.  This is especially true for longer patch\n> series.  It's common after you've finished a series to discover there\n> was an easier or cleaner route to follow that would have arrived at\n> the same end-point.  It's not uncommon for me to spend a significant\n> chunk of time rebasing and restructuring a patch series to try to\n> highlight such a better path.  This includes not just style fixups,\n> but different patch orderings, alternate ways to break up functions,\n> using different data structures, etc.\n\nMe as well.\n\nIt's extra work for one person, but everyone else benefits, including\nthat one person in the future (who usually forgets why he/she did things\nin that particular way).\n\nCheers.\n\n-- \nFelipe Contreras\n"},{"id":"412615","messageId":"xmqqft42shcc.fsf@gitster.c.googlers.com","threadId":"54550","inReplyTo":"87blercju2.fsf@osv.gnss.ru","subject":"Re: [PATCH v2 23/33] diff-merges: fix style of functions definitions","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2020-12-19T01:41:07Z","receivedAt":"2020-12-19T01:42:08Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Sergey Organov <sorganov@gmail.com> writes:\n\n> When Junio noticed and pointed to this deficiency, I asked him if I\n> should fix all the series from the start, or it'd be OK to use fixup\n> commit. As he didn't answer and nobody else commented either, I opted\n> for the latter.\n\nSorry if it slipped through the cracks---I get too many discussion\nthreads to pay attention to.\n\nYes, we strongly prefer *not* to keep the honest history that\nrecords all the mistakes we made along the way.  Rather, we take the\ntime a topic is still in flight and not yet cast in stone by merged\nto 'next' as an opportunity to pretend that the topic came to\nexistence in the perfect shape, thanks to collective brain effort.\n\nIt is our basic courtesy to future developers who has to read our\ncode (i.e. \"log -p\") to understand what we've been thinking, when\nthey want to fix some stupid bugs we will inevitably leave in our\ncodebase.  It is distracting to read from the beginning of a topic,\nnotice something funny going on and keep moveing to later patches,\nwhile harboring puzzlement in our minds, then later discover that\nthe funny thing we noticed earlier was a simple mistake that gets\nfixed, not some clever trick the reader needs to think deeply to\nunderstand.\n\nThanks.\n\n\n"},{"id":"412629","messageId":"87sg82m2f6.fsf@osv.gnss.ru","threadId":"54550","inReplyTo":"CABPp-BEZ6VqyTah7QCzkuUm-p7tA_6cnpGPWpgpQbHp_c3Wc5Q@mail.gmail.com","subject":"Re: [PATCH v2 23/33] diff-merges: fix style of functions definitions","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-19T11:59:57Z","receivedAt":"2020-12-19T12:00:59Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"\n[...]\n\nFelipe Contreras <felipe.contreras@gmail.com> writes:\n\n> Elijah Newren wrote:\n>> Personally, I think that a really important point to keep in mind when\n>> submitting patch series is trying to figure out the easiest way to\n>> move the code from point A to point B, not the route you took to get\n>> from point A to point B.  This is especially true for longer patch\n>> series.  It's common after you've finished a series to discover there\n>> was an easier or cleaner route to follow that would have arrived at\n>> the same end-point.  It's not uncommon for me to spend a significant\n>> chunk of time rebasing and restructuring a patch series to try to\n>> highlight such a better path.  This includes not just style fixups,\n>> but different patch orderings, alternate ways to break up functions,\n>> using different data structures, etc.\n>\n> Me as well.\n>\n> It's extra work for one person, but everyone else benefits, including\n> that one person in the future (who usually forgets why he/she did things\n> in that particular way).\n>\n> Cheers.\n\nJunio C Hamano <gitster@pobox.com> writes:\n\n> Sergey Organov <sorganov@gmail.com> writes:\n>\n>> When Junio noticed and pointed to this deficiency, I asked him if I\n>> should fix all the series from the start, or it'd be OK to use fixup\n>> commit. As he didn't answer and nobody else commented either, I opted\n>> for the latter.\n>\n> Sorry if it slipped through the cracks---I get too many discussion\n> threads to pay attention to.\n>\n> Yes, we strongly prefer *not* to keep the honest history that\n> records all the mistakes we made along the way.  Rather, we take the\n> time a topic is still in flight and not yet cast in stone by merged\n> to 'next' as an opportunity to pretend that the topic came to\n> existence in the perfect shape, thanks to collective brain effort.\n>\n> It is our basic courtesy to future developers who has to read our\n> code (i.e. \"log -p\") to understand what we've been thinking, when\n> they want to fix some stupid bugs we will inevitably leave in our\n> codebase.  It is distracting to read from the beginning of a topic,\n> notice something funny going on and keep moveing to later patches,\n> while harboring puzzlement in our minds, then later discover that\n> the funny thing we noticed earlier was a simple mistake that gets\n> fixed, not some clever trick the reader needs to think deeply to\n> understand.\n\nOK, so I'll do it.\n\nI'd like to have some agreement on the final shape of the topic though\nbefore I cleanup the series, if possible.\n\nThanks,\n-- Sergey\n"},{"id":"412632","messageId":"87o8iqm1wq.fsf@osv.gnss.ru","threadId":"54550","inReplyTo":"CABPp-BG4GEmv20YK39M51nzTYVZtcLgD-UbmQLfgynjUhBKx9w@mail.gmail.com","subject":"Re: [PATCH v2 26/33] diff-merges: let new options enable diff without -p","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-19T12:11:01Z","receivedAt":"2020-12-19T12:12:02Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Elijah Newren <newren@gmail.com> writes:\n\n> On Fri, Dec 18, 2020 at 6:42 AM Sergey Organov <sorganov@gmail.com> wrote:\n>>\n>> Elijah Newren <newren@gmail.com> writes:\n>>\n>> > On Wed, Dec 16, 2020 at 10:50 AM Sergey Organov <sorganov@gmail.com> wrote:\n>> >>\n>> >> New options don't have any visible effect unless -p is either given or\n>> >> implied, as unlike -c/-cc we don't imply -p with --diff-merges. To fix\n>> >> this, this patch adds new functionality by letting new options enable\n>> >> output of diffs for merge commits only.\n>> >>\n>> >> Add 'merges_need_diff' field and set it whenever diff output for merges is\n>> >> enabled by any of the new options.\n>> >>\n>> >> Extend diff output logic accordingly, to output diffs for merges when\n>> >> 'merges_need_diff' is set even when no -p has been provided.\n>> >>\n>> >> Signed-off-by: Sergey Organov <sorganov@gmail.com>\n>> >> ---\n>> >>  diff-merges.c | 16 ++++++++++------\n>> >>  log-tree.c    | 13 +++++++++----\n>> >>  revision.h    |  1 +\n>> >>  3 files changed, 20 insertions(+), 10 deletions(-)\n\n[...]\n\n>> >> diff --git a/log-tree.c b/log-tree.c\n>> >> index f9385b1dae6f..67060492ca0a 100644\n>> >> --- a/log-tree.c\n>> >> +++ b/log-tree.c\n>> >> @@ -899,15 +899,21 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log\n>> >>         int showed_log;\n>> >>         struct commit_list *parents;\n>> >>         struct object_id *oid;\n>> >> +       int is_merge;\n>> >> +       int regulars_need_diff = opt->diff || opt->diffopt.flags.exit_with_status;\n>> >\n>> > So rev_info.diff has changed in meaning from\n>> > commits-need-to-show-a-diff, to non-merge-commits-need-to-show-a-diff.\n>> > That's a somewhat subtle semantic shift.  Perhaps it's worth adding a\n>> > comment to the declaration of rev_info.diff to highlight this?  (And\n>> > perhaps even rename the flag?)\n>>\n>> No, the meaning of rev_info.diff hopefully didn't change. rev_info.diff\n>> still enables all the commits to pass further once set. It is still\n>> exactly the same old condition, just assigned to a variable for reuse.\n>> My aim was to avoid touching existing logic of this function and only\n>> add a new functionality when opt->merges_need_diff is set.\n>>\n>> It looks like I rather choose confusing name for the variable, and it'd\n>> be more clear if I'd call this, say:\n>>\n>>   int need_diff = opt->diff || opt->diffopt.flags.exit_with_status;\n>>\n>> ?\n>>\n>> What do you think?\n>\n> I think need_diff would actually be confusing.  It can be false when\n> you need diffs (e.g. --diff-merges=cc with no -p, because then you'd\n> need diffs for merge commits and not for non-merge commits).  I'd\n> stick with your original local variable name.\n\nThe problem is that original name I've used lies to the reader, or, more\nprecisely, tells half-truth. True meaning of the variable is \"do run\ndiff for any commit, no matter if it's merge or not\". So \"need_diff\" is\nalready better than \"regulars_need_diff\".\n\nMaybe \"diff_all_commits\" will do?\n\nThanks,\n-- Sergey\n"},{"id":"412634","messageId":"5fde01924f744_1de0de208ea@natae.notmuch","threadId":"54550","inReplyTo":"87o8iqm1wq.fsf@osv.gnss.ru","subject":"Re: [PATCH v2 26/33] diff-merges: let new options enable diff without -p","fromName":"Felipe Contreras","fromEmail":"felipe.contreras@gmail.com","sentAt":"2020-12-19T13:35:14Z","receivedAt":"2020-12-19T13:36:14Z","isPatch":true,"sender":{"key":"felipe.contreras@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8358?v=4"},"body":"Sergey Organov wrote:\n> The problem is that original name I've used lies to the reader, or, more\n> precisely, tells half-truth. True meaning of the variable is \"do run\n> diff for any commit, no matter if it's merge or not\". So \"need_diff\" is\n> already better than \"regulars_need_diff\".\n> \n> Maybe \"diff_all_commits\" will do?\n\nall_need_diff\n\n-- \nFelipe Contreras\n"},{"id":"412635","messageId":"5fde01e133b93_1de0de20818@natae.notmuch","threadId":"54550","inReplyTo":"20201216184929.3924-27-sorganov@gmail.com","subject":"RE: [PATCH v2 26/33] diff-merges: let new options enable diff without -p","fromName":"Felipe Contreras","fromEmail":"felipe.contreras@gmail.com","sentAt":"2020-12-19T13:36:33Z","receivedAt":"2020-12-19T13:37:29Z","isPatch":true,"sender":{"key":"felipe.contreras@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8358?v=4"},"body":"Sergey Organov wrote:\n> diff --git a/log-tree.c b/log-tree.c\n> index f9385b1dae6f..67060492ca0a 100644\n> --- a/log-tree.c\n> +++ b/log-tree.c\n> @@ -899,15 +899,21 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log\n>  \tint showed_log;\n>  \tstruct commit_list *parents;\n>  \tstruct object_id *oid;\n> +\tint is_merge;\n> +\tint regulars_need_diff = opt->diff || opt->diffopt.flags.exit_with_status;\n>  \n> -\tif (!opt->diff && !opt->diffopt.flags.exit_with_status)\n> +\tif (!regulars_need_diff && !opt->merges_need_diff)\n>  \t\treturn 0;\n>  \n>  \tparse_commit_or_die(commit);\n>  \toid = get_commit_tree_oid(commit);\n>  \n> -\t/* Root commit? */\n>  \tparents = get_saved_parents(opt, commit);\n> +\tis_merge = parents && parents->next;\n> +\tif(!is_merge && !regulars_need_diff)\n> +\t\treturn 0;\n\nMissed a space:\n\n        if (!is_merge && !regulars_need_diff)\n\n-- \nFelipe Contreras\n"},{"id":"412648","messageId":"87mty9lqen.fsf@osv.gnss.ru","threadId":"54550","inReplyTo":"5fde01e133b93_1de0de20818@natae.notmuch","subject":"Re: [PATCH v2 26/33] diff-merges: let new options enable diff without -p","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-19T16:19:28Z","receivedAt":"2020-12-19T16:20:14Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Felipe Contreras <felipe.contreras@gmail.com> writes:\n\n> Sergey Organov wrote:\n>> diff --git a/log-tree.c b/log-tree.c\n>> index f9385b1dae6f..67060492ca0a 100644\n>> --- a/log-tree.c\n>> +++ b/log-tree.c\n>> @@ -899,15 +899,21 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log\n>>  \tint showed_log;\n>>  \tstruct commit_list *parents;\n>>  \tstruct object_id *oid;\n>> +\tint is_merge;\n>> +\tint regulars_need_diff = opt->diff || opt->diffopt.flags.exit_with_status;\n>>  \n>> -\tif (!opt->diff && !opt->diffopt.flags.exit_with_status)\n>> +\tif (!regulars_need_diff && !opt->merges_need_diff)\n>>  \t\treturn 0;\n>>  \n>>  \tparse_commit_or_die(commit);\n>>  \toid = get_commit_tree_oid(commit);\n>>  \n>> -\t/* Root commit? */\n>>  \tparents = get_saved_parents(opt, commit);\n>> +\tis_merge = parents && parents->next;\n>> +\tif(!is_merge && !regulars_need_diff)\n>> +\t\treturn 0;\n>\n> Missed a space:\n>\n>         if (!is_merge && !regulars_need_diff)\n\nOops, thanks!\n\n-- Sergey\n"},{"id":"412649","messageId":"87im8xlq7t.fsf@osv.gnss.ru","threadId":"54550","inReplyTo":"5fde01924f744_1de0de208ea@natae.notmuch","subject":"Re: [PATCH v2 26/33] diff-merges: let new options enable diff without -p","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-19T16:23:34Z","receivedAt":"2020-12-19T16:24:34Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Felipe Contreras <felipe.contreras@gmail.com> writes:\n\n> Sergey Organov wrote:\n>> The problem is that original name I've used lies to the reader, or, more\n>> precisely, tells half-truth. True meaning of the variable is \"do run\n>> diff for any commit, no matter if it's merge or not\". So \"need_diff\" is\n>> already better than \"regulars_need_diff\".\n>> \n>> Maybe \"diff_all_commits\" will do?\n>\n> all_need_diff\n\nFine with me.\n\nThanks,\n-- Sergey\n"},{"id":"412691","messageId":"5fe011e0a155_89f1208d3@natae.notmuch","threadId":"54550","inReplyTo":"87czz4thk4.fsf@osv.gnss.ru","subject":"Re: [PATCH v2 23/33] diff-merges: fix style of functions definitions","fromName":"Felipe Contreras","fromEmail":"felipe.contreras@gmail.com","sentAt":"2020-12-21T03:09:20Z","receivedAt":"2020-12-21T04:58:14Z","isPatch":true,"sender":{"key":"felipe.contreras@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8358?v=4"},"body":"Sergey Organov wrote:\n> While we are at it, Linux kernel developers care enough about style to\n> provide script that checks patch series for issues and to insist it is\n> run before submitting.\n> \n> I've used this script to cleanup these series for the next re-roll and I\n> think that having semi-automated test makes a lot of sense, so you may\n> wish to consider to adopt it for Git as well (it seems to have some\n> requirements that are not enforced for Git sources, but not many).\n> \n> The script is called scripts/checkpatch.pl in the Linux kernel sources.\n\nYeah, this has been suggested before.\n\nIt would make the job of newcomers that haven't learned the style yet\nmuch easier. And also it would make suggestions about the style of\npatches a bit less subjective.\n\nCheers.\n\n-- \nFelipe Contreras\n"},{"id":"412693","messageId":"87k0tcthy5.fsf@osv.gnss.ru","threadId":"54550","inReplyTo":"87wnxfb2gt.fsf@osv.gnss.ru","subject":"Re: [PATCH v2 26/33] diff-merges: let new options enable diff without -p","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-20T19:07:14Z","receivedAt":"2020-12-21T05:07:45Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Sergey Organov <sorganov@gmail.com> writes:\n\n> Elijah Newren <newren@gmail.com> writes:\n>\n>> On Wed, Dec 16, 2020 at 10:50 AM Sergey Organov <sorganov@gmail.com> wrote:\n>>>\n\n[...]\n\n>>\n>>>         else if (!strcmp(optarg, \"first\") || !strcmp(optarg, \"first-parent\"))\n>>>                 set_first_parent(revs);\n>>>         else if (!strcmp(optarg, \"sep\")   || !strcmp(optarg, \"separate\"))\n>>> @@ -64,6 +67,7 @@ static void set_diff_merges(struct rev_info *revs, const char *optarg)\n>>>                 set_dense_combined(revs);\n>>>         else\n>>>                 die(_(\"unknown value for --diff-merges: %s\"), optarg);\n>>> +       revs->merges_need_diff = 1;\n>>\n>> I'd put this above the if-else-else block, to make it clearer why you\n>> are returning early for the \"off\"/\"none\" case.\n>\n> Yeah, makes sense, thanks!\n\nIn fact this can't be done as it changes the outcome, as set_xxx()\nfunctions clear the flag.\n\nI rather added clarification comments to the code.\n\nThanks,\n-- Sergey\n"},{"id":"412702","messageId":"87czz4thk4.fsf@osv.gnss.ru","threadId":"54550","inReplyTo":"87sg82m2f6.fsf@osv.gnss.ru","subject":"Re: [PATCH v2 23/33] diff-merges: fix style of functions definitions","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-20T19:15:39Z","receivedAt":"2020-12-21T06:16:41Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Sergey Organov <sorganov@gmail.com> writes:\n\n> [...]\n>\n> Felipe Contreras <felipe.contreras@gmail.com> writes:\n>\n>> Elijah Newren wrote:\n>>> Personally, I think that a really important point to keep in mind when\n>>> submitting patch series is trying to figure out the easiest way to\n>>> move the code from point A to point B, not the route you took to get\n>>> from point A to point B.  This is especially true for longer patch\n>>> series.  It's common after you've finished a series to discover there\n>>> was an easier or cleaner route to follow that would have arrived at\n>>> the same end-point.  It's not uncommon for me to spend a significant\n>>> chunk of time rebasing and restructuring a patch series to try to\n>>> highlight such a better path.  This includes not just style fixups,\n>>> but different patch orderings, alternate ways to break up functions,\n>>> using different data structures, etc.\n>>\n>> Me as well.\n>>\n>> It's extra work for one person, but everyone else benefits, including\n>> that one person in the future (who usually forgets why he/she did things\n>> in that particular way).\n>>\n>> Cheers.\n>\n> Junio C Hamano <gitster@pobox.com> writes:\n>\n>> Sergey Organov <sorganov@gmail.com> writes:\n>>\n>>> When Junio noticed and pointed to this deficiency, I asked him if I\n>>> should fix all the series from the start, or it'd be OK to use fixup\n>>> commit. As he didn't answer and nobody else commented either, I opted\n>>> for the latter.\n>>\n>> Sorry if it slipped through the cracks---I get too many discussion\n>> threads to pay attention to.\n>>\n>> Yes, we strongly prefer *not* to keep the honest history that\n>> records all the mistakes we made along the way.  Rather, we take the\n>> time a topic is still in flight and not yet cast in stone by merged\n>> to 'next' as an opportunity to pretend that the topic came to\n>> existence in the perfect shape, thanks to collective brain effort.\n>>\n>> It is our basic courtesy to future developers who has to read our\n>> code (i.e. \"log -p\") to understand what we've been thinking, when\n>> they want to fix some stupid bugs we will inevitably leave in our\n>> codebase.  It is distracting to read from the beginning of a topic,\n>> notice something funny going on and keep moveing to later patches,\n>> while harboring puzzlement in our minds, then later discover that\n>> the funny thing we noticed earlier was a simple mistake that gets\n>> fixed, not some clever trick the reader needs to think deeply to\n>> understand.\n>\n> OK, so I'll do it.\n>\n\nWhile we are at it, Linux kernel developers care enough about style to\nprovide script that checks patch series for issues and to insist it is\nrun before submitting.\n\nI've used this script to cleanup these series for the next re-roll and I\nthink that having semi-automated test makes a lot of sense, so you may\nwish to consider to adopt it for Git as well (it seems to have some\nrequirements that are not enforced for Git sources, but not many).\n\nThe script is called scripts/checkpatch.pl in the Linux kernel sources.\n\nThanks,\n-- Sergey\n"},{"id":"412718","messageId":"20201221152000.13134-33-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201221152000.13134-1-sorganov@gmail.com","subject":"[PATCH v3 32/32] t4013: add tests for --diff-merges=first-parent","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-21T15:20:00Z","receivedAt":"2020-12-21T18:01:28Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"This new option provides essential new functionality, changing diff\noutput to first parent only, without changing history traversal mode,\nso it deserves its own test.\n\nAs we do it, add additional test that --diff-merges=first-parent by\nitself doesn't imply -p and only outputs diffs for merge commits.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n t/t4013-diff-various.sh                       |   2 +\n ...diff.log_--diff-merges=first-parent_master |  56 +++++++\n ...f.log_-p_--diff-merges=first-parent_master | 137 ++++++++++++++++++\n 3 files changed, 195 insertions(+)\n create mode 100644 t/t4013/diff.log_--diff-merges=first-parent_master\n create mode 100644 t/t4013/diff.log_-p_--diff-merges=first-parent_master\n\ndiff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh\nindex 8d8178a8a616..fa82b5a8eed4 100755\n--- a/t/t4013-diff-various.sh\n+++ b/t/t4013-diff-various.sh\n@@ -327,6 +327,8 @@ log --no-diff-merges -p --first-parent master\n log --diff-merges=off -p --first-parent master\n log --first-parent --diff-merges=off -p master\n log -p --first-parent master\n+log -p --diff-merges=first-parent master\n+log --diff-merges=first-parent master\n log -m -p --first-parent master\n log -m -p master\n log --cc -m -p master\ndiff --git a/t/t4013/diff.log_--diff-merges=first-parent_master b/t/t4013/diff.log_--diff-merges=first-parent_master\nnew file mode 100644\nindex 000000000000..fa63a557dd18\n--- /dev/null\n+++ b/t/t4013/diff.log_--diff-merges=first-parent_master\n@@ -0,0 +1,56 @@\n+$ git log --diff-merges=first-parent master\n+commit 59d314ad6f356dd08601a4cd5e530381da3e3c64\n+Merge: 9a6d494 c7a2ab9\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:04:00 2006 +0000\n+\n+    Merge branch 'side'\n+\n+diff --git a/dir/sub b/dir/sub\n+index cead32e..992913c 100644\n+--- a/dir/sub\n++++ b/dir/sub\n+@@ -4,3 +4,5 @@ C\n+ D\n+ E\n+ F\n++1\n++2\n+diff --git a/file0 b/file0\n+index b414108..10a8a9f 100644\n+--- a/file0\n++++ b/file0\n+@@ -4,3 +4,6 @@\n+ 4\n+ 5\n+ 6\n++A\n++B\n++C\n+\n+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:03:00 2006 +0000\n+\n+    Side\n+\n+commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:02:00 2006 +0000\n+\n+    Third\n+\n+commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:01:00 2006 +0000\n+\n+    Second\n+    \n+    This is the second commit.\n+\n+commit 444ac553ac7612cc88969031b02b3767fb8a353a\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:00:00 2006 +0000\n+\n+    Initial\n+$\ndiff --git a/t/t4013/diff.log_-p_--diff-merges=first-parent_master b/t/t4013/diff.log_-p_--diff-merges=first-parent_master\nnew file mode 100644\nindex 000000000000..9538a2751123\n--- /dev/null\n+++ b/t/t4013/diff.log_-p_--diff-merges=first-parent_master\n@@ -0,0 +1,137 @@\n+$ git log -p --diff-merges=first-parent master\n+commit 59d314ad6f356dd08601a4cd5e530381da3e3c64\n+Merge: 9a6d494 c7a2ab9\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:04:00 2006 +0000\n+\n+    Merge branch 'side'\n+\n+diff --git a/dir/sub b/dir/sub\n+index cead32e..992913c 100644\n+--- a/dir/sub\n++++ b/dir/sub\n+@@ -4,3 +4,5 @@ C\n+ D\n+ E\n+ F\n++1\n++2\n+diff --git a/file0 b/file0\n+index b414108..10a8a9f 100644\n+--- a/file0\n++++ b/file0\n+@@ -4,3 +4,6 @@\n+ 4\n+ 5\n+ 6\n++A\n++B\n++C\n+\n+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:03:00 2006 +0000\n+\n+    Side\n+\n+diff --git a/dir/sub b/dir/sub\n+index 35d242b..7289e35 100644\n+--- a/dir/sub\n++++ b/dir/sub\n+@@ -1,2 +1,4 @@\n+ A\n+ B\n++1\n++2\n+diff --git a/file0 b/file0\n+index 01e79c3..f4615da 100644\n+--- a/file0\n++++ b/file0\n+@@ -1,3 +1,6 @@\n+ 1\n+ 2\n+ 3\n++A\n++B\n++C\n+diff --git a/file3 b/file3\n+new file mode 100644\n+index 0000000..7289e35\n+--- /dev/null\n++++ b/file3\n+@@ -0,0 +1,4 @@\n++A\n++B\n++1\n++2\n+\n+commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:02:00 2006 +0000\n+\n+    Third\n+\n+diff --git a/dir/sub b/dir/sub\n+index 8422d40..cead32e 100644\n+--- a/dir/sub\n++++ b/dir/sub\n+@@ -2,3 +2,5 @@ A\n+ B\n+ C\n+ D\n++E\n++F\n+diff --git a/file1 b/file1\n+new file mode 100644\n+index 0000000..b1e6722\n+--- /dev/null\n++++ b/file1\n+@@ -0,0 +1,3 @@\n++A\n++B\n++C\n+\n+commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:01:00 2006 +0000\n+\n+    Second\n+    \n+    This is the second commit.\n+\n+diff --git a/dir/sub b/dir/sub\n+index 35d242b..8422d40 100644\n+--- a/dir/sub\n++++ b/dir/sub\n+@@ -1,2 +1,4 @@\n+ A\n+ B\n++C\n++D\n+diff --git a/file0 b/file0\n+index 01e79c3..b414108 100644\n+--- a/file0\n++++ b/file0\n+@@ -1,3 +1,6 @@\n+ 1\n+ 2\n+ 3\n++4\n++5\n++6\n+diff --git a/file2 b/file2\n+deleted file mode 100644\n+index 01e79c3..0000000\n+--- a/file2\n++++ /dev/null\n+@@ -1,3 +0,0 @@\n+-1\n+-2\n+-3\n+\n+commit 444ac553ac7612cc88969031b02b3767fb8a353a\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:00:00 2006 +0000\n+\n+    Initial\n+$\n-- \n2.25.1\n\n"},{"id":"412719","messageId":"20201221152000.13134-10-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201221152000.13134-1-sorganov@gmail.com","subject":"[PATCH v3 09/32] diff-merges: re-arrange functions to match the order they are called in","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-21T15:19:37Z","receivedAt":"2020-12-21T18:01:29Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"For clarity, define public functions in the order they are called, to\nmake logic inter-dependencies easier to grok.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n diff-merges.c | 24 ++++++++++++++----------\n diff-merges.h |  7 +++----\n 2 files changed, 17 insertions(+), 14 deletions(-)\n\ndiff --git a/diff-merges.c b/diff-merges.c\nindex 76c804579758..8325ab880166 100644\n--- a/diff-merges.c\n+++ b/diff-merges.c\n@@ -2,6 +2,10 @@\n \n #include \"revision.h\"\n \n+/*\n+ * Public functions. They are in the order they are called.\n+ */\n+\n void diff_merges_init_revs(struct rev_info *revs)\n {\n \trevs->ignore_merges = -1;\n@@ -46,16 +50,6 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv)\n \treturn argcount;\n }\n \n-void diff_merges_setup_revs(struct rev_info *revs)\n-{\n-\tif (revs->combine_merges && revs->ignore_merges < 0)\n-\t\trevs->ignore_merges = 0;\n-\tif (revs->ignore_merges < 0)\n-\t\trevs->ignore_merges = 1;\n-\tif (revs->combined_all_paths && !revs->combine_merges)\n-\t\tdie(\"--combined-all-paths makes no sense without -c or --cc\");\n-}\n-\n void diff_merges_default_to_first_parent(struct rev_info *revs)\n {\n \tif (revs->ignore_merges < 0)\t\t/* No -m */\n@@ -72,3 +66,13 @@ void diff_merges_default_to_dense_combined(struct rev_info *revs)\n \t\t}\n \t}\n }\n+\n+void diff_merges_setup_revs(struct rev_info *revs)\n+{\n+\tif (revs->combine_merges && revs->ignore_merges < 0)\n+\t\trevs->ignore_merges = 0;\n+\tif (revs->ignore_merges < 0)\n+\t\trevs->ignore_merges = 1;\n+\tif (revs->combined_all_paths && !revs->combine_merges)\n+\t\tdie(\"--combined-all-paths makes no sense without -c or --cc\");\n+}\ndiff --git a/diff-merges.h b/diff-merges.h\nindex 18861dc5480e..243ef915c4cd 100644\n--- a/diff-merges.h\n+++ b/diff-merges.h\n@@ -13,11 +13,10 @@ void diff_merges_init_revs(struct rev_info *revs);\n \n int diff_merges_parse_opts(struct rev_info *revs, const char **argv);\n \n-void diff_merges_setup_revs(struct rev_info *revs);\n-\n-void diff_merges_default_to_dense_combined(struct rev_info *revs);\n-\n void diff_merges_default_to_first_parent(struct rev_info *revs);\n \n+void diff_merges_default_to_dense_combined(struct rev_info *revs);\n+\n+void diff_merges_setup_revs(struct rev_info *revs);\n \n #endif\n-- \n2.25.1\n\n"},{"id":"412721","messageId":"20201221152000.13134-4-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201221152000.13134-1-sorganov@gmail.com","subject":"[PATCH v3 03/32] revision: factor out initialization of diff-merge related settings","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-21T15:19:31Z","receivedAt":"2020-12-21T18:03:51Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Move initialization code related to diffing merges into new\ninit_diff_merge_revs() function.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n revision.c | 9 ++++++++-\n 1 file changed, 8 insertions(+), 1 deletion(-)\n\ndiff --git a/revision.c b/revision.c\nindex d818e0b18bbc..3250b2d7e112 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -1805,6 +1805,8 @@ static int add_parents_only(struct rev_info *revs, const char *arg_, int flags,\n \treturn 1;\n }\n \n+static void init_diff_merge_revs(struct rev_info *revs);\n+\n void repo_init_revisions(struct repository *r,\n \t\t\t struct rev_info *revs,\n \t\t\t const char *prefix)\n@@ -1813,7 +1815,7 @@ void repo_init_revisions(struct repository *r,\n \n \trevs->repo = r;\n \trevs->abbrev = DEFAULT_ABBREV;\n-\trevs->ignore_merges = -1;\n+\tinit_diff_merge_revs(revs);\n \trevs->simplify_history = 1;\n \trevs->pruning.repo = r;\n \trevs->pruning.flags.recursive = 1;\n@@ -2153,6 +2155,11 @@ static void add_message_grep(struct rev_info *revs, const char *pattern)\n \tadd_grep(revs, pattern, GREP_PATTERN_BODY);\n }\n \n+static void init_diff_merge_revs(struct rev_info *revs)\n+{\n+\trevs->ignore_merges = -1;\n+}\n+\n static int parse_diff_merge_opts(struct rev_info *revs, const char **argv)\n {\n \tint argcount = 1;\n-- \n2.25.1\n\n"},{"id":"412722","messageId":"20201221152000.13134-12-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201221152000.13134-1-sorganov@gmail.com","subject":"[PATCH v3 11/32] diff-merges: new function diff_merges_set_dense_combined_if_unset()","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-21T15:19:39Z","receivedAt":"2020-12-21T18:03:52Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Call it where given functionality is needed instead of direct\nchecking/tweaking of diff merges related fields.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n builtin/diff-files.c |  5 +++--\n builtin/diff.c       |  9 +++++----\n diff-merges.c        | 16 ++++++++++++++--\n diff-merges.h        |  2 ++\n 4 files changed, 24 insertions(+), 8 deletions(-)\n\ndiff --git a/builtin/diff-files.c b/builtin/diff-files.c\nindex 1e352dd8f77c..4742a4559b21 100644\n--- a/builtin/diff-files.c\n+++ b/builtin/diff-files.c\n@@ -7,6 +7,7 @@\n #include \"cache.h\"\n #include \"config.h\"\n #include \"diff.h\"\n+#include \"diff-merges.h\"\n #include \"commit.h\"\n #include \"revision.h\"\n #include \"builtin.h\"\n@@ -69,9 +70,9 @@ int cmd_diff_files(int argc, const char **argv, const char *prefix)\n \t * was not asked to.  \"diff-files -c -p\" should not densify\n \t * (the user should ask with \"diff-files --cc\" explicitly).\n \t */\n-\tif (rev.max_count == -1 && !rev.combine_merges &&\n+\tif (rev.max_count == -1 &&\n \t    (rev.diffopt.output_format & DIFF_FORMAT_PATCH))\n-\t\trev.combine_merges = rev.dense_combined_merges = 1;\n+\t\tdiff_merges_set_dense_combined_if_unset(&rev);\n \n \tif (read_cache_preload(&rev.diffopt.pathspec) < 0) {\n \t\tperror(\"read_cache_preload\");\ndiff --git a/builtin/diff.c b/builtin/diff.c\nindex cd4083fed96e..2f570a3131cb 100644\n--- a/builtin/diff.c\n+++ b/builtin/diff.c\n@@ -13,6 +13,7 @@\n #include \"blob.h\"\n #include \"tag.h\"\n #include \"diff.h\"\n+#include \"diff-merges.h\"\n #include \"diffcore.h\"\n #include \"revision.h\"\n #include \"log-tree.h\"\n@@ -199,8 +200,8 @@ static int builtin_diff_combined(struct rev_info *revs,\n \tif (argc > 1)\n \t\tusage(builtin_diff_usage);\n \n-\tif (!revs->dense_combined_merges && !revs->combine_merges)\n-\t\trevs->dense_combined_merges = revs->combine_merges = 1;\n+\tdiff_merges_set_dense_combined_if_unset(revs);\n+\n \tfor (i = 1; i < ents; i++)\n \t\toid_array_append(&parents, &ent[i].item->oid);\n \tdiff_tree_combined(&ent[0].item->oid, &parents, revs);\n@@ -248,9 +249,9 @@ static int builtin_diff_files(struct rev_info *revs, int argc, const char **argv\n \t * dense one, --cc can be explicitly asked for, or just rely\n \t * on the default).\n \t */\n-\tif (revs->max_count == -1 && !revs->combine_merges &&\n+\tif (revs->max_count == -1 &&\n \t    (revs->diffopt.output_format & DIFF_FORMAT_PATCH))\n-\t\trevs->combine_merges = revs->dense_combined_merges = 1;\n+\t\tdiff_merges_set_dense_combined_if_unset(revs);\n \n \tsetup_work_tree();\n \tif (read_cache_preload(&revs->diffopt.pathspec) < 0) {\ndiff --git a/diff-merges.c b/diff-merges.c\nindex 23e6cb11d1ad..24f922cf8a0f 100644\n--- a/diff-merges.c\n+++ b/diff-merges.c\n@@ -10,6 +10,13 @@ static void suppress(struct rev_info *revs)\n \trevs->dense_combined_merges = 0;\n }\n \n+static void set_dense_combined(struct rev_info *revs)\n+{\n+\trevs->combine_merges = 1;\n+\trevs->dense_combined_merges = 1;\n+}\n+\n+\n /*\n  * Public functions. They are in the order they are called.\n  */\n@@ -39,8 +46,7 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv)\n \t\trevs->combine_merges = 1;\n \t} else if (!strcmp(arg, \"--cc\")) {\n \t\trevs->diff = 1;\n-\t\trevs->dense_combined_merges = 1;\n-\t\trevs->combine_merges = 1;\n+\t\tset_dense_combined(revs);\n \t} else if (!strcmp(arg, \"--no-diff-merges\")) {\n \t\tsuppress(revs);\n \t} else if (!strcmp(arg, \"--combined-all-paths\")) {\n@@ -80,6 +86,12 @@ void diff_merges_default_to_dense_combined(struct rev_info *revs)\n \t}\n }\n \n+void diff_merges_set_dense_combined_if_unset(struct rev_info *revs)\n+{\n+\tif (!revs->combine_merges)\n+\t\tset_dense_combined(revs);\n+}\n+\n void diff_merges_setup_revs(struct rev_info *revs)\n {\n \tif (revs->combine_merges && revs->ignore_merges < 0)\ndiff --git a/diff-merges.h b/diff-merges.h\nindex a031240576f7..f92de137d3a0 100644\n--- a/diff-merges.h\n+++ b/diff-merges.h\n@@ -19,6 +19,8 @@ void diff_merges_default_to_first_parent(struct rev_info *revs);\n \n void diff_merges_default_to_dense_combined(struct rev_info *revs);\n \n+void diff_merges_set_dense_combined_if_unset(struct rev_info *revs);\n+\n void diff_merges_setup_revs(struct rev_info *revs);\n \n #endif\n-- \n2.25.1\n\n"},{"id":"412725","messageId":"20201221152000.13134-24-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201221152000.13134-1-sorganov@gmail.com","subject":"[PATCH v3 23/32] diff-merges: implement new values for --diff-merges","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-21T15:19:51Z","receivedAt":"2020-12-21T18:05:56Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"We first implement new options as exact synonyms for their original\ncounterparts, to get all the infrastructure right, and keep functional\nimprovements for later commits.\n\nThe following values are implemented:\n\n--diff-merges=\t        old equivalent\nfirst|first-parent    = --first-parent (only format implications)\nsep|separate          = -m\ncomb|combined         = -c\ndense| dense-combined = --cc\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n diff-merges.c | 19 ++++++++++++++++---\n 1 file changed, 16 insertions(+), 3 deletions(-)\n\ndiff --git a/diff-merges.c b/diff-merges.c\nindex e3c0190ebd95..4d22da179577 100644\n--- a/diff-merges.c\n+++ b/diff-merges.c\n@@ -17,6 +17,12 @@ static void set_separate(struct rev_info *revs)\n \trevs->separate_merges = 1;\n }\n \n+static void set_first_parent(struct rev_info *revs)\n+{\n+\tset_separate(revs);\n+\trevs->first_parent_merges = 1;\n+}\n+\n static void set_m(struct rev_info *revs)\n {\n \t/*\n@@ -44,11 +50,18 @@ static void set_dense_combined(struct rev_info *revs)\n \n static void set_diff_merges(struct rev_info *revs, const char *optarg)\n {\n-\tif (!strcmp(optarg, \"off\")) {\n+\tif (!strcmp(optarg, \"off\") || !strcmp(optarg, \"none\"))\n \t\tsuppress(revs);\n-\t} else {\n+\telse if (!strcmp(optarg, \"first-parent\"))\n+\t\tset_first_parent(revs);\n+\telse if (!strcmp(optarg, \"separate\"))\n+\t\tset_separate(revs);\n+\telse if (!strcmp(optarg, \"combined\"))\n+\t\tset_combined(revs);\n+\telse if (!strcmp(optarg, \"dense-combined\"))\n+\t\tset_dense_combined(revs);\n+\telse\n \t\tdie(_(\"unknown value for --diff-merges: %s\"), optarg);\n-\t}\n }\n \n /*\n-- \n2.25.1\n\n"},{"id":"412726","messageId":"20201221152000.13134-23-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201221152000.13134-1-sorganov@gmail.com","subject":"[PATCH v3 22/32] diff-merges: make -m/-c/--cc explicitly mutually exclusive","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-21T15:19:50Z","receivedAt":"2020-12-21T18:06:38Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"-c/--cc got precedence over -m only because of external logic where\ncorresponding flags are checked before that for -m. This is too\nerror-prone, so add code that explicitly makes these 3 options\nmutually exclusive, so that the last option specified on the\ncommand-line gets precedence.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n diff-merges.c | 3 +++\n 1 file changed, 3 insertions(+)\n\ndiff --git a/diff-merges.c b/diff-merges.c\nindex b8fd92adcf16..e3c0190ebd95 100644\n--- a/diff-merges.c\n+++ b/diff-merges.c\n@@ -8,6 +8,7 @@ static void suppress(struct rev_info *revs)\n \trevs->first_parent_merges = 0;\n \trevs->combine_merges = 0;\n \trevs->dense_combined_merges = 0;\n+\trevs->combined_all_paths = 0;\n }\n \n static void set_separate(struct rev_info *revs)\n@@ -29,12 +30,14 @@ static void set_m(struct rev_info *revs)\n \n static void set_combined(struct rev_info *revs)\n {\n+\tsuppress(revs);\n \trevs->combine_merges = 1;\n \trevs->dense_combined_merges = 0;\n }\n \n static void set_dense_combined(struct rev_info *revs)\n {\n+\tsuppress(revs);\n \trevs->combine_merges = 1;\n \trevs->dense_combined_merges = 1;\n }\n-- \n2.25.1\n\n"},{"id":"412727","messageId":"20201221152000.13134-1-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201101193330.24775-1-sorganov@gmail.com","subject":"[PATCH v3 00/32] git-log: implement new --diff-merge options","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-21T15:19:28Z","receivedAt":"2020-12-21T18:07:39Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"These patch series implement new set of options governing diff output\nof merge commits, all under the umbrella of single\n--diff-merges=<mode> option.\n\nUnlike original -c/--cc options, these new options do not imply -p,\nthus allowing for getting diffs for merge commits without provoking of\ndiff output for regular, non-merge commits. E.g.:\n\n  git log --diff-merges=cc\n\nwill output diffs (in dense-combined format) only for merge commits,\nwhereas:\n\n  git log --cc\n\nenables diffs for all the commits being output, either merges or\nsimple ones.\n\nThere is also another additional functionality provided, allowing to\nget the format of \"-p --first-parent\" without change in history\ntraversal that --first-parent option causes, like this:\n\n  git log --diff-merges=first-parent\n\nThe net result of these series are the following new options:\n\n--diff-merges=\t  |  rough original equivalent\n------------------+----------------\n1|first-parent    | --first-parent (only diff format implications)\nm|separate        | -m and enable diff for merges\nc|combined        | -c and enable diff for merges, but not for regulars\ncc|dense-combined | --cc and enable diff for merges, but not for\n\t\t  |      regulars\n\nThe series also cleanup logic of handling of diff merges options and\nfix an issue found in the original implementation where logically\nmutually exclusive options -m/-c/--cc failed to actually override each\nother. Neither semantics of these old options nor their interactions\nwith other options, such as --first-parent and -p, is supposed to be\nchanged.\n\nThe series start with the set of pure refactoring commits that are expected\nto introduce no functional changes. These are all commits up to and\nincluding:\n\n\"diff-merges: revise revs->diff flag handling\"\n\nThe aim of these commits is to isolate options handling for diff merges so\nthat it could be easily understood and tweaked to ease introduction of the\nnew options.\n\nThen the fix of -m/-c/-cc overriding issue follows, starting with a failing\ntest and followed by the fix.\n\nThen follows a little bit of additional refactoring in order to\nprepare for introduction of the new options, and finally the series\nare finished by the implementation, documentation updates, and\nsome testing for the new options.\n\nUpdates in v3:\n\n  * Fixed all the known style issues\n\n  * Revised -m, -c, and -cc description as suggested by Elijah Newren\n\n  * Removed manual abbrevs for diff-merge options\n\n  * Got rid of if(0) ; idiom\n\n  * Renamed regulars_need_diff to all_need_diff to better reflect\n    the meaning of the variable.\n\n  * Moved \"diff-merges: handle imply -p on -c/--cc logic for log.c\"\n    closer to the beginning of the series, where it belongs as being\n    pure refactoring of the old code.\n\n  * Added code clarification comments to set_diff_merges()\n\nUpdates in v2:\n\n  * Move logic of \"-c/--cc imply -p\" to this module and do not imply\n    -p by new --diff-merges options. Instead enable corresponding diff\n    output without affecting non-merge commits. This is the most\n    significant change with respect to v1 and it starts at 24/33.\n\n  * Add support for old mnemonics: --diff-merges=(m|c|cc) to help\n    those who are used to them, and add --diff-merges=1 to cover all\n    variants with short mnemonics.\n\n  * Fixed functions definitions style to have open curly brace on its\n    own line, pointed to by Junio C Hamano.\n\n  * Tweak --diff-merges=first-parent description, requested by Elijah\n    Newren.\n\n  * Fixed git-show documentation not to include description chunk\n    relevant to git-log only, noticed by Elijah Newren.\n\n  * Fixed documentation mistake claiming that -p is needed for\n    diff-merges options to take effect, noticed by Elijah Newren.\n\n  * Fixed a case where a change was put into wrong commit. The change\n    moved to 11/27 form 10/27. Didn't affect end-result in any way.\n\n  * Added short module description to diff-merges.h, as suggested by\n    Junio C Hamano.\n\n  * Fixed not returning \"argcount\" from\tdiff_merges_parse_opts(),\n    noticed by Junio C Hamano.\n\nUpdates in v1:\n\n  * Added documentation fix for git-show to include --diff-merges.\n\n  * Fixed typos in commit messages noticed by Philip Oakley.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n\nSergey Organov (32):\n  revision: factor out parsing of diff-merge related options\n  revision: factor out setup of diff-merge related settings\n  revision: factor out initialization of diff-merge related settings\n  revision: provide implementation for diff merges tweaks\n  revision: move diff merges functions to its own diff-merges.c\n  diff-merges: rename all functions to have common prefix\n  diff-merges: move checks for first_parent_only out of the module\n  diff-merges: rename diff_merges_default_to_enable() to match semantics\n  diff-merges: re-arrange functions to match the order they are called\n    in\n  diff-merges: new function diff_merges_suppress()\n  diff-merges: new function diff_merges_set_dense_combined_if_unset()\n  diff-merges: introduce revs->first_parent_merges flag\n  diff-merges: handle imply -p on -c/--cc logic for log.c\n  diff-merges: revise revs->diff flag handling\n  t4013: support test_expect_failure through ':failure' magic\n  t4013: add tests for -m failing to override -c/--cc\n  diff-merges: fix -m to properly override -c/--cc\n  diff-merges: split 'ignore_merges' field\n  diff-merges: group diff-merge flags next to each other inside\n    'rev_info'\n  diff-merges: get rid of now empty diff_merges_init_revs()\n  diff-merges: refactor opt settings into separate functions\n  diff-merges: make -m/-c/--cc explicitly mutually exclusive\n  diff-merges: implement new values for --diff-merges\n  diff-merges: do not imply -p for new options\n  diff-merges: let new options enable diff without -p\n  diff-merges: add old mnemonic counterparts to --diff-merges\n  diff-merges: add '--diff-merges=1' as synonym for 'first-parent'\n  doc/git-log: describe new --diff-merges options\n  doc/diff-generate-patch: mention new --diff-merges option\n  doc/rev-list-options: document --first-parent changes merges format\n  doc/git-show: include --diff-merges description\n  t4013: add tests for --diff-merges=first-parent\n\n Documentation/diff-generate-patch.txt         |   6 +-\n Documentation/diff-options.txt                |  51 +++++\n Documentation/git-log.txt                     |  46 +---\n Documentation/git-show.txt                    |   7 +-\n Documentation/rev-list-options.txt            |   5 +\n Makefile                                      |   1 +\n builtin/diff-files.c                          |   5 +-\n builtin/diff.c                                |   9 +-\n builtin/log.c                                 |  22 +-\n builtin/merge.c                               |   3 +-\n diff-merges.c                                 | 146 +++++++++++++\n diff-merges.h                                 |  24 +++\n fmt-merge-msg.c                               |   3 +-\n log-tree.c                                    |  30 +--\n revision.c                                    |  38 +---\n revision.h                                    |   9 +-\n t/t4013-diff-various.sh                       |  11 +-\n t/t4013/diff.log_--cc_-m_-p_master            | 200 ++++++++++++++++++\n ...diff.log_--diff-merges=first-parent_master |  56 +++++\n t/t4013/diff.log_-c_-m_-p_master              | 200 ++++++++++++++++++\n ...f.log_-p_--diff-merges=first-parent_master | 137 ++++++++++++\n 21 files changed, 893 insertions(+), 116 deletions(-)\n create mode 100644 diff-merges.c\n create mode 100644 diff-merges.h\n create mode 100644 t/t4013/diff.log_--cc_-m_-p_master\n create mode 100644 t/t4013/diff.log_--diff-merges=first-parent_master\n create mode 100644 t/t4013/diff.log_-c_-m_-p_master\n create mode 100644 t/t4013/diff.log_-p_--diff-merges=first-parent_master\n\nInterdiff against v2:\ndiff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt\nindex 98db2be423dc..c995e82584f3 100644\n--- a/Documentation/diff-options.txt\n+++ b/Documentation/diff-options.txt\n@@ -55,8 +55,7 @@ ifdef::git-log[]\n -m:::\n \tThis makes merge commits show the full diff with respect to\n \teach of the parents. Separate log entry and diff is generated\n-\tfor each parent. `-m` is different in that it doesn't produce\n-\tany output without `-p`.\n+\tfor each parent. `-m` doesn't produce any output without `-p`.\n +\n --diff-merges=combined:::\n --diff-merges=c:::\n@@ -65,8 +64,8 @@ ifdef::git-log[]\n \tdifferences from each of the parents to the merge result\n \tsimultaneously instead of showing pairwise diff between a\n \tparent and the result one at a time. Furthermore, it lists\n-\tonly files which were modified from all parents. Historically,\n-\t`-c` enables diff output for non-merge commits as well.\n+\tonly files which were modified from all parents. `-c` implies\n+\t`-p`.\n +\n --diff-merges=dense-combined:::\n --diff-merges=cc:::\n@@ -75,8 +74,7 @@ ifdef::git-log[]\n \t`--diff-merges=combined` is further compressed by omitting\n \tuninteresting hunks whose contents in the parents have only\n \ttwo variants and the merge result picks one of them without\n-\tmodification.  Historically, `--c` enables diff output for\n-\tnon-merge commits as well.\n+\tmodification.  `--cc` implies `-p`.\n \n --combined-all-paths::\n \tThis flag causes combined diffs (used for merge commits) to\ndiff --git a/diff-merges.c b/diff-merges.c\nindex 63a0d78b7730..146bb50316a6 100644\n--- a/diff-merges.c\n+++ b/diff-merges.c\n@@ -54,23 +54,22 @@ static void set_diff_merges(struct rev_info *revs, const char *optarg)\n {\n \tif (!strcmp(optarg, \"off\") || !strcmp(optarg, \"none\")) {\n \t\tsuppress(revs);\n+\t\t/* Return early to leave revs->merges_need_diff unset */\n \t\treturn;\n \t}\n-\tif (0) ;\n-\telse if (!strcmp(optarg, \"first\") || !strcmp(optarg, \"first-parent\") ||\n-\t\t !strcmp(optarg, \"1\"))\n+\n+\tif (!strcmp(optarg, \"1\") || !strcmp(optarg, \"first-parent\"))\n \t\tset_first_parent(revs);\n-\telse if (!strcmp(optarg, \"sep\")   || !strcmp(optarg, \"separate\") ||\n-\t\t !strcmp(optarg, \"m\"))\n+\telse if (!strcmp(optarg, \"m\") || !strcmp(optarg, \"separate\"))\n \t\tset_separate(revs);\n-\telse if (!strcmp(optarg, \"comb\")  || !strcmp(optarg, \"combined\") ||\n-\t\t !strcmp(optarg, \"c\"))\n+\telse if (!strcmp(optarg, \"c\") || !strcmp(optarg, \"combined\"))\n \t\tset_combined(revs);\n-\telse if (!strcmp(optarg, \"dense\") || !strcmp(optarg, \"dense-combined\") ||\n-\t\t !strcmp(optarg, \"cc\"))\n+\telse if (!strcmp(optarg, \"cc\") || !strcmp(optarg, \"dense-combined\"))\n \t\tset_dense_combined(revs);\n \telse\n \t\tdie(_(\"unknown value for --diff-merges: %s\"), optarg);\n+\n+\t/* The flag is cleared by set_xxx() functions, so don't move this up */\n \trevs->merges_need_diff = 1;\n }\n \n@@ -84,23 +83,21 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv)\n \tconst char *optarg;\n \tconst char *arg = argv[0];\n \n-\tif (!strcmp(arg, \"-m\"))\n+\tif (!strcmp(arg, \"-m\")) {\n \t\tset_m(revs);\n-\telse if (!strcmp(arg, \"-c\")) {\n+\t} else if (!strcmp(arg, \"-c\")) {\n \t\tset_combined(revs);\n \t\trevs->combined_imply_patch = 1;\n-\t}\n-\telse if (!strcmp(arg, \"--cc\")) {\n+\t} else if (!strcmp(arg, \"--cc\")) {\n \t\tset_dense_combined(revs);\n \t\trevs->combined_imply_patch = 1;\n-\t}\n-\telse if (!strcmp(arg, \"--no-diff-merges\"))\n+\t} else if (!strcmp(arg, \"--no-diff-merges\")) {\n \t\tsuppress(revs);\n-\telse if (!strcmp(arg, \"--combined-all-paths\"))\n+\t} else if (!strcmp(arg, \"--combined-all-paths\")) {\n \t\trevs->combined_all_paths = 1;\n-\telse if ((argcount = parse_long_opt(\"diff-merges\", argv, &optarg)))\n+\t} else if ((argcount = parse_long_opt(\"diff-merges\", argv, &optarg))) {\n \t\tset_diff_merges(revs, optarg);\n-\telse\n+\t} else\n \t\treturn 0;\n \n \trevs->explicit_diff_merges = 1;\n@@ -140,10 +137,8 @@ void diff_merges_setup_revs(struct rev_info *revs)\n \t\trevs->first_parent_merges = 0;\n \tif (revs->combined_all_paths && !revs->combine_merges)\n \t\tdie(\"--combined-all-paths makes no sense without -c or --cc\");\n-\n \tif (revs->combined_imply_patch)\n \t\trevs->diff = 1;\n-\n \tif (revs->combined_imply_patch || revs->merges_need_diff) {\n \t\tif (!revs->diffopt.output_format)\n \t\t\trevs->diffopt.output_format = DIFF_FORMAT_PATCH;\ndiff --git a/log-tree.c b/log-tree.c\nindex 67060492ca0a..9f50a81e537e 100644\n--- a/log-tree.c\n+++ b/log-tree.c\n@@ -900,9 +900,9 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log\n \tstruct commit_list *parents;\n \tstruct object_id *oid;\n \tint is_merge;\n-\tint regulars_need_diff = opt->diff || opt->diffopt.flags.exit_with_status;\n+\tint all_need_diff = opt->diff || opt->diffopt.flags.exit_with_status;\n \n-\tif (!regulars_need_diff && !opt->merges_need_diff)\n+\tif (!all_need_diff && !opt->merges_need_diff)\n \t\treturn 0;\n \n \tparse_commit_or_die(commit);\n@@ -910,7 +910,7 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log\n \n \tparents = get_saved_parents(opt, commit);\n \tis_merge = parents && parents->next;\n-\tif(!is_merge && !regulars_need_diff)\n+\tif (!is_merge && !all_need_diff)\n \t\treturn 0;\n \n \t/* Root commit? */\n-- \n2.25.1\n\n"},{"id":"412728","messageId":"20201221152000.13134-19-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201221152000.13134-1-sorganov@gmail.com","subject":"[PATCH v3 18/32] diff-merges: split 'ignore_merges' field","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-21T15:19:46Z","receivedAt":"2020-12-21T18:09:49Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"'ignore_merges' was 3-way field that served two distinct purposes that\nwe now assign to 2 new independent flags: 'separate_merges', and\n'explicit_diff_merges'.\n\n'separate_merges' tells that we need to output diff format containing\nseparate diff for every parent (as opposed to 'combine_merges').\n\n'explicit_diff_merges' tells that at least one of diff-merges options\nhas been explicitly specified on the command line, so no defaults\nshould apply.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n diff-merges.c | 31 +++++++++++++------------------\n log-tree.c    | 15 ++++++++-------\n revision.h    |  3 ++-\n 3 files changed, 23 insertions(+), 26 deletions(-)\n\ndiff --git a/diff-merges.c b/diff-merges.c\nindex 047bf81e6777..eff54cca8287 100644\n--- a/diff-merges.c\n+++ b/diff-merges.c\n@@ -4,7 +4,7 @@\n \n static void suppress(struct rev_info *revs)\n {\n-\trevs->ignore_merges = 1;\n+\trevs->separate_merges = 0;\n \trevs->first_parent_merges = 0;\n \trevs->combine_merges = 0;\n \trevs->dense_combined_merges = 0;\n@@ -23,7 +23,6 @@ static void set_dense_combined(struct rev_info *revs)\n \n void diff_merges_init_revs(struct rev_info *revs)\n {\n-\trevs->ignore_merges = -1;\n }\n \n int diff_merges_parse_opts(struct rev_info *revs, const char **argv)\n@@ -39,7 +38,7 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv)\n \t\t * family of commands, it means \"show full diff for merges\". Set\n \t\t * both fields appropriately.\n \t\t */\n-\t\trevs->ignore_merges = 0;\n+\t\trevs->separate_merges = 1;\n \t\trevs->match_missing = 1;\n \t} else if (!strcmp(arg, \"-c\")) {\n \t\trevs->dense_combined_merges = 0;\n@@ -57,8 +56,9 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv)\n \t\t\tdie(_(\"unknown value for --diff-merges: %s\"), optarg);\n \t\t}\n \t} else\n-\t\targcount = 0;\n+\t\treturn 0;\n \n+\trevs->explicit_diff_merges = 1;\n \treturn argcount;\n }\n \n@@ -69,21 +69,16 @@ void diff_merges_suppress(struct rev_info *revs)\n \n void diff_merges_default_to_first_parent(struct rev_info *revs)\n {\n-\tif (revs->ignore_merges < 0)\t\t/* No -m */\n-\t\trevs->ignore_merges = 0;\n-\tif (!revs->combine_merges)\t\t/* No -c/--cc\" */\n+\tif (!revs->explicit_diff_merges)\n+\t\trevs->separate_merges = 1;\n+\tif (revs->separate_merges)\n \t\trevs->first_parent_merges = 1;\n }\n \n void diff_merges_default_to_dense_combined(struct rev_info *revs)\n {\n-\tif (revs->ignore_merges < 0) {\t\t/* No -m */\n-\t\trevs->ignore_merges = 0;\n-\t\tif (!revs->combine_merges) {\t/* No -c/--cc\" */\n-\t\t\trevs->combine_merges = 1;\n-\t\t\trevs->dense_combined_merges = 1;\n-\t\t}\n-\t}\n+\tif (!revs->explicit_diff_merges)\n+\t\tset_dense_combined(revs);\n }\n \n void diff_merges_set_dense_combined_if_unset(struct rev_info *revs)\n@@ -94,10 +89,10 @@ void diff_merges_set_dense_combined_if_unset(struct rev_info *revs)\n \n void diff_merges_setup_revs(struct rev_info *revs)\n {\n-\tif (revs->combine_merges && revs->ignore_merges < 0)\n-\t\trevs->ignore_merges = 0;\n-\tif (revs->ignore_merges < 0)\n-\t\trevs->ignore_merges = 1;\n+\tif (revs->combine_merges == 0)\n+\t\trevs->dense_combined_merges = 0;\n+\tif (revs->separate_merges == 0)\n+\t\trevs->first_parent_merges = 0;\n \tif (revs->combined_all_paths && !revs->combine_merges)\n \t\tdie(\"--combined-all-paths makes no sense without -c or --cc\");\n \tif (revs->combine_merges) {\ndiff --git a/log-tree.c b/log-tree.c\nindex 3fdc0fc64bfb..f9385b1dae6f 100644\n--- a/log-tree.c\n+++ b/log-tree.c\n@@ -918,14 +918,15 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log\n \n \t/* More than one parent? */\n \tif (parents->next) {\n-\t\tif (opt->ignore_merges)\n-\t\t\treturn 0;\n-\t\telse if (opt->combine_merges)\n+\t\tif (opt->combine_merges)\n \t\t\treturn do_diff_combined(opt, commit);\n-\t\telse if (!opt->first_parent_merges) {\n-\t\t\t/* If we show multiple diffs, show the parent info */\n-\t\t\tlog->parent = parents->item;\n-\t\t}\n+\t\tif (opt->separate_merges) {\n+\t\t\tif (!opt->first_parent_merges) {\n+\t\t\t\t/* Show parent info for multiple diffs */\n+\t\t\t\tlog->parent = parents->item;\n+\t\t\t}\n+\t\t} else\n+\t\t\treturn 0;\n \t}\n \n \tshowed_log = 0;\ndiff --git a/revision.h b/revision.h\nindex ba2aef79215e..fcc532c873d1 100644\n--- a/revision.h\n+++ b/revision.h\n@@ -191,12 +191,13 @@ struct rev_info {\n \t\t\tmatch_missing:1,\n \t\t\tno_commit_id:1,\n \t\t\tverbose_header:1,\n+\t\t\texplicit_diff_merges: 1,\n+\t\t\tseparate_merges: 1,\n \t\t\tcombine_merges:1,\n \t\t\tcombined_all_paths:1,\n \t\t\tdense_combined_merges:1,\n \t\t\tfirst_parent_merges:1,\n \t\t\talways_show_header:1;\n-\tint             ignore_merges:2;\n \n \t/* Format info */\n \tint\t\tshow_notes;\n-- \n2.25.1\n\n"},{"id":"412729","messageId":"20201221152000.13134-25-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201221152000.13134-1-sorganov@gmail.com","subject":"[PATCH v3 24/32] diff-merges: do not imply -p for new options","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-21T15:19:52Z","receivedAt":"2020-12-21T18:10:09Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Add 'combined_imply_patch' field and set it only for old --cc/-c\noptions, then imply -p if this flag is set instead of implying -p\nwhenever 'combined_merge' flag is set.\n\nWe don't want new --diff-merge options to imply -p, to make it\npossible to enable output of diffs for merges independently from\nnon-merge commits. At the same time we want to preserve behavior of\nold --c/-c/-m options and their interactions with --first-parent, to\nstay backward-compatible.\n\nThis patch is first step in this direction: it separates old \"--cc/-c\nimply -p\" logic from the rest of the options.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n diff-merges.c | 20 ++++++++++++--------\n revision.h    |  1 +\n 2 files changed, 13 insertions(+), 8 deletions(-)\n\ndiff --git a/diff-merges.c b/diff-merges.c\nindex 4d22da179577..6d48ac5ab93d 100644\n--- a/diff-merges.c\n+++ b/diff-merges.c\n@@ -9,6 +9,7 @@ static void suppress(struct rev_info *revs)\n \trevs->combine_merges = 0;\n \trevs->dense_combined_merges = 0;\n \trevs->combined_all_paths = 0;\n+\trevs->combined_imply_patch = 0;\n }\n \n static void set_separate(struct rev_info *revs)\n@@ -74,19 +75,21 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv)\n \tconst char *optarg;\n \tconst char *arg = argv[0];\n \n-\tif (!strcmp(arg, \"-m\"))\n+\tif (!strcmp(arg, \"-m\")) {\n \t\tset_m(revs);\n-\telse if (!strcmp(arg, \"-c\"))\n+\t} else if (!strcmp(arg, \"-c\")) {\n \t\tset_combined(revs);\n-\telse if (!strcmp(arg, \"--cc\"))\n+\t\trevs->combined_imply_patch = 1;\n+\t} else if (!strcmp(arg, \"--cc\")) {\n \t\tset_dense_combined(revs);\n-\telse if (!strcmp(arg, \"--no-diff-merges\"))\n+\t\trevs->combined_imply_patch = 1;\n+\t} else if (!strcmp(arg, \"--no-diff-merges\")) {\n \t\tsuppress(revs);\n-\telse if (!strcmp(arg, \"--combined-all-paths\"))\n+\t} else if (!strcmp(arg, \"--combined-all-paths\")) {\n \t\trevs->combined_all_paths = 1;\n-\telse if ((argcount = parse_long_opt(\"diff-merges\", argv, &optarg)))\n+\t} else if ((argcount = parse_long_opt(\"diff-merges\", argv, &optarg))) {\n \t\tset_diff_merges(revs, optarg);\n-\telse\n+\t} else\n \t\treturn 0;\n \n \trevs->explicit_diff_merges = 1;\n@@ -126,8 +129,9 @@ void diff_merges_setup_revs(struct rev_info *revs)\n \t\trevs->first_parent_merges = 0;\n \tif (revs->combined_all_paths && !revs->combine_merges)\n \t\tdie(\"--combined-all-paths makes no sense without -c or --cc\");\n-\tif (revs->combine_merges) {\n+\tif (revs->combine_merges)\n \t\trevs->diff = 1;\n+\tif (revs->combined_imply_patch) {\n \t\t/* Turn --cc/-c into -p --cc/-c when -p was not given */\n \t\tif (!revs->diffopt.output_format)\n \t\t\trevs->diffopt.output_format = DIFF_FORMAT_PATCH;\ndiff --git a/revision.h b/revision.h\nindex dcfa14454a55..bfbae526ad6e 100644\n--- a/revision.h\n+++ b/revision.h\n@@ -197,6 +197,7 @@ struct rev_info {\n \t\t\tseparate_merges: 1,\n \t\t\tcombine_merges:1,\n \t\t\tcombined_all_paths:1,\n+\t\t\tcombined_imply_patch:1,\n \t\t\tdense_combined_merges:1,\n \t\t\tfirst_parent_merges:1;\n \n-- \n2.25.1\n\n"},{"id":"412730","messageId":"20201221152000.13134-18-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201221152000.13134-1-sorganov@gmail.com","subject":"[PATCH v3 17/32] diff-merges: fix -m to properly override -c/--cc","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-21T15:19:45Z","receivedAt":"2020-12-21T18:11:43Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Logically, -m, -c, --cc specify 3 different formats for representing\nmerge commits, yet -m doesn't in fact override -c or --cc, that makes\nno sense.\n\nFix -m to properly override -c/--cc, and change the tests accordingly.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n diff-merges.c           | 1 +\n t/t4013-diff-various.sh | 4 ++--\n 2 files changed, 3 insertions(+), 2 deletions(-)\n\ndiff --git a/diff-merges.c b/diff-merges.c\nindex 225edd293b43..047bf81e6777 100644\n--- a/diff-merges.c\n+++ b/diff-merges.c\n@@ -33,6 +33,7 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv)\n \tconst char *arg = argv[0];\n \n \tif (!strcmp(arg, \"-m\")) {\n+\t\tsuppress(revs);\n \t\t/*\n \t\t * To \"diff-index\", \"-m\" means \"match missing\", and to the \"log\"\n \t\t * family of commands, it means \"show full diff for merges\". Set\ndiff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh\nindex 64d9fce44614..8d8178a8a616 100755\n--- a/t/t4013-diff-various.sh\n+++ b/t/t4013-diff-various.sh\n@@ -329,8 +329,8 @@ log --first-parent --diff-merges=off -p master\n log -p --first-parent master\n log -m -p --first-parent master\n log -m -p master\n-:failure log --cc -m -p master\n-:failure log -c -m -p master\n+log --cc -m -p master\n+log -c -m -p master\n log -SF master\n log -S F master\n log -SF -p master\n-- \n2.25.1\n\n"},{"id":"412731","messageId":"20201221152000.13134-16-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201221152000.13134-1-sorganov@gmail.com","subject":"[PATCH v3 15/32] t4013: support test_expect_failure through ':failure' magic","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-21T15:19:43Z","receivedAt":"2020-12-21T18:12:42Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Add support to be able to specify expected failure, through :failure\nmagic, like this:\n\n:failure cmd args\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n t/t4013-diff-various.sh | 7 ++++++-\n 1 file changed, 6 insertions(+), 1 deletion(-)\n\ndiff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh\nindex 5c7b0122b4f1..935d10ac0572 100755\n--- a/t/t4013-diff-various.sh\n+++ b/t/t4013-diff-various.sh\n@@ -174,6 +174,7 @@ process_diffs () {\n V=$(git version | sed -e 's/^git version //' -e 's/\\./\\\\./g')\n while read magic cmd\n do\n+\tstatus=success\n \tcase \"$magic\" in\n \t'' | '#'*)\n \t\tcontinue ;;\n@@ -182,6 +183,10 @@ do\n \t\tlabel=\"$magic-$cmd\"\n \t\tcase \"$magic\" in\n \t\tnoellipses) ;;\n+\t\tfailure)\n+\t\t\tstatus=failure\n+\t\t\tmagic=\n+\t\t\tlabel=\"$cmd\" ;;\n \t\t*)\n \t\t\tBUG \"unknown magic $magic\" ;;\n \t\tesac ;;\n@@ -194,7 +199,7 @@ do\n \texpect=\"$TEST_DIRECTORY/t4013/diff.$test\"\n \tactual=\"$pfx-diff.$test\"\n \n-\ttest_expect_success \"git $cmd # magic is ${magic:-(not used)}\" '\n+\ttest_expect_$status \"git $cmd # magic is ${magic:-(not used)}\" '\n \t\t{\n \t\t\techo \"$ git $cmd\"\n \t\t\tcase \"$magic\" in\n-- \n2.25.1\n\n"},{"id":"412732","messageId":"20201221152000.13134-27-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201221152000.13134-1-sorganov@gmail.com","subject":"[PATCH v3 26/32] diff-merges: add old mnemonic counterparts to --diff-merges","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-21T15:19:54Z","receivedAt":"2020-12-21T18:13:38Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"This adds --diff-merges={m|c|cc} values that match mnemonics of old\noptions, for those who are used to them.\n\nNote that, say, --diff-meres=cc behaves differently than --cc, as the\nlatter implies -p and therefore enables diffs for all the commits,\nwhile the former enables output of diffs for merge commits only.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n diff-merges.c | 6 +++---\n 1 file changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/diff-merges.c b/diff-merges.c\nindex ee91ed0db409..011bfff1f135 100644\n--- a/diff-merges.c\n+++ b/diff-merges.c\n@@ -60,11 +60,11 @@ static void set_diff_merges(struct rev_info *revs, const char *optarg)\n \n \tif (!strcmp(optarg, \"first-parent\"))\n \t\tset_first_parent(revs);\n-\telse if (!strcmp(optarg, \"separate\"))\n+\telse if (!strcmp(optarg, \"m\") || !strcmp(optarg, \"separate\"))\n \t\tset_separate(revs);\n-\telse if (!strcmp(optarg, \"combined\"))\n+\telse if (!strcmp(optarg, \"c\") || !strcmp(optarg, \"combined\"))\n \t\tset_combined(revs);\n-\telse if (!strcmp(optarg, \"dense-combined\"))\n+\telse if (!strcmp(optarg, \"cc\") || !strcmp(optarg, \"dense-combined\"))\n \t\tset_dense_combined(revs);\n \telse\n \t\tdie(_(\"unknown value for --diff-merges: %s\"), optarg);\n-- \n2.25.1\n\n"},{"id":"412733","messageId":"20201221152000.13134-20-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201221152000.13134-1-sorganov@gmail.com","subject":"[PATCH v3 19/32] diff-merges: group diff-merge flags next to each other inside 'rev_info'","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-21T15:19:47Z","receivedAt":"2020-12-21T18:13:39Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"The relevant flags were somewhat scattered over definition of 'struct\nrev_info'. Rearrange them to group them together.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n revision.h | 5 +++--\n 1 file changed, 3 insertions(+), 2 deletions(-)\n\ndiff --git a/revision.h b/revision.h\nindex fcc532c873d1..dcfa14454a55 100644\n--- a/revision.h\n+++ b/revision.h\n@@ -191,13 +191,14 @@ struct rev_info {\n \t\t\tmatch_missing:1,\n \t\t\tno_commit_id:1,\n \t\t\tverbose_header:1,\n+\t\t\talways_show_header:1,\n+\t\t\t/* Diff-merge flags */\n \t\t\texplicit_diff_merges: 1,\n \t\t\tseparate_merges: 1,\n \t\t\tcombine_merges:1,\n \t\t\tcombined_all_paths:1,\n \t\t\tdense_combined_merges:1,\n-\t\t\tfirst_parent_merges:1,\n-\t\t\talways_show_header:1;\n+\t\t\tfirst_parent_merges:1;\n \n \t/* Format info */\n \tint\t\tshow_notes;\n-- \n2.25.1\n\n"},{"id":"412734","messageId":"20201221152000.13134-21-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201221152000.13134-1-sorganov@gmail.com","subject":"[PATCH v3 20/32] diff-merges: get rid of now empty diff_merges_init_revs()","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-21T15:19:48Z","receivedAt":"2020-12-21T18:13:39Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"After getting rid of 'ignore_merges' field, the diff_merges_init_revs()\nfunction became empty. Get rid of it.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n diff-merges.c | 4 ----\n diff-merges.h | 2 --\n revision.c    | 1 -\n 3 files changed, 7 deletions(-)\n\ndiff --git a/diff-merges.c b/diff-merges.c\nindex eff54cca8287..34d7ed7c70b7 100644\n--- a/diff-merges.c\n+++ b/diff-merges.c\n@@ -21,10 +21,6 @@ static void set_dense_combined(struct rev_info *revs)\n  * Public functions. They are in the order they are called.\n  */\n \n-void diff_merges_init_revs(struct rev_info *revs)\n-{\n-}\n-\n int diff_merges_parse_opts(struct rev_info *revs, const char **argv)\n {\n \tint argcount = 1;\ndiff --git a/diff-merges.h b/diff-merges.h\nindex f92de137d3a0..659467c99a4f 100644\n--- a/diff-merges.h\n+++ b/diff-merges.h\n@@ -9,8 +9,6 @@\n \n struct rev_info;\n \n-void diff_merges_init_revs(struct rev_info *revs);\n-\n int diff_merges_parse_opts(struct rev_info *revs, const char **argv);\n \n void diff_merges_suppress(struct rev_info *revs);\ndiff --git a/revision.c b/revision.c\nindex 5a0e3d6ad542..46645ca0b6df 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -1814,7 +1814,6 @@ void repo_init_revisions(struct repository *r,\n \n \trevs->repo = r;\n \trevs->abbrev = DEFAULT_ABBREV;\n-\tdiff_merges_init_revs(revs);\n \trevs->simplify_history = 1;\n \trevs->pruning.repo = r;\n \trevs->pruning.flags.recursive = 1;\n-- \n2.25.1\n\n"},{"id":"412737","messageId":"20201221152000.13134-26-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201221152000.13134-1-sorganov@gmail.com","subject":"[PATCH v3 25/32] diff-merges: let new options enable diff without -p","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-21T15:19:53Z","receivedAt":"2020-12-21T18:15:38Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"New options don't have any visible effect unless -p is either given or\nimplied, as unlike -c/-cc we don't imply -p with --diff-merges. To fix\nthis, this patch adds new functionality by letting new options enable\noutput of diffs for merge commits only.\n\nAdd 'merges_need_diff' field and set it whenever diff output for merges is\nenabled by any of the new options.\n\nExtend diff output logic accordingly, to output diffs for merges when\n'merges_need_diff' is set even when no -p has been provided.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n diff-merges.c | 17 ++++++++++++-----\n log-tree.c    | 13 +++++++++----\n revision.h    |  1 +\n 3 files changed, 22 insertions(+), 9 deletions(-)\n\ndiff --git a/diff-merges.c b/diff-merges.c\nindex 6d48ac5ab93d..ee91ed0db409 100644\n--- a/diff-merges.c\n+++ b/diff-merges.c\n@@ -10,6 +10,7 @@ static void suppress(struct rev_info *revs)\n \trevs->dense_combined_merges = 0;\n \trevs->combined_all_paths = 0;\n \trevs->combined_imply_patch = 0;\n+\trevs->merges_need_diff = 0;\n }\n \n static void set_separate(struct rev_info *revs)\n@@ -51,9 +52,13 @@ static void set_dense_combined(struct rev_info *revs)\n \n static void set_diff_merges(struct rev_info *revs, const char *optarg)\n {\n-\tif (!strcmp(optarg, \"off\") || !strcmp(optarg, \"none\"))\n+\tif (!strcmp(optarg, \"off\") || !strcmp(optarg, \"none\")) {\n \t\tsuppress(revs);\n-\telse if (!strcmp(optarg, \"first-parent\"))\n+\t\t/* Return early to leave revs->merges_need_diff unset */\n+\t\treturn;\n+\t}\n+\n+\tif (!strcmp(optarg, \"first-parent\"))\n \t\tset_first_parent(revs);\n \telse if (!strcmp(optarg, \"separate\"))\n \t\tset_separate(revs);\n@@ -63,6 +68,9 @@ static void set_diff_merges(struct rev_info *revs, const char *optarg)\n \t\tset_dense_combined(revs);\n \telse\n \t\tdie(_(\"unknown value for --diff-merges: %s\"), optarg);\n+\n+\t/* The flag is cleared by set_xxx() functions, so don't move this up */\n+\trevs->merges_need_diff = 1;\n }\n \n /*\n@@ -129,10 +137,9 @@ void diff_merges_setup_revs(struct rev_info *revs)\n \t\trevs->first_parent_merges = 0;\n \tif (revs->combined_all_paths && !revs->combine_merges)\n \t\tdie(\"--combined-all-paths makes no sense without -c or --cc\");\n-\tif (revs->combine_merges)\n+\tif (revs->combined_imply_patch)\n \t\trevs->diff = 1;\n-\tif (revs->combined_imply_patch) {\n-\t\t/* Turn --cc/-c into -p --cc/-c when -p was not given */\n+\tif (revs->combined_imply_patch || revs->merges_need_diff) {\n \t\tif (!revs->diffopt.output_format)\n \t\t\trevs->diffopt.output_format = DIFF_FORMAT_PATCH;\n \t}\ndiff --git a/log-tree.c b/log-tree.c\nindex f9385b1dae6f..9f50a81e537e 100644\n--- a/log-tree.c\n+++ b/log-tree.c\n@@ -899,15 +899,21 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log\n \tint showed_log;\n \tstruct commit_list *parents;\n \tstruct object_id *oid;\n+\tint is_merge;\n+\tint all_need_diff = opt->diff || opt->diffopt.flags.exit_with_status;\n \n-\tif (!opt->diff && !opt->diffopt.flags.exit_with_status)\n+\tif (!all_need_diff && !opt->merges_need_diff)\n \t\treturn 0;\n \n \tparse_commit_or_die(commit);\n \toid = get_commit_tree_oid(commit);\n \n-\t/* Root commit? */\n \tparents = get_saved_parents(opt, commit);\n+\tis_merge = parents && parents->next;\n+\tif (!is_merge && !all_need_diff)\n+\t\treturn 0;\n+\n+\t/* Root commit? */\n \tif (!parents) {\n \t\tif (opt->show_root_diff) {\n \t\t\tdiff_root_tree_oid(oid, \"\", &opt->diffopt);\n@@ -916,8 +922,7 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log\n \t\treturn !opt->loginfo;\n \t}\n \n-\t/* More than one parent? */\n-\tif (parents->next) {\n+\tif (is_merge) {\n \t\tif (opt->combine_merges)\n \t\t\treturn do_diff_combined(opt, commit);\n \t\tif (opt->separate_merges) {\ndiff --git a/revision.h b/revision.h\nindex bfbae526ad6e..494d86142454 100644\n--- a/revision.h\n+++ b/revision.h\n@@ -194,6 +194,7 @@ struct rev_info {\n \t\t\talways_show_header:1,\n \t\t\t/* Diff-merge flags */\n \t\t\texplicit_diff_merges: 1,\n+\t\t\tmerges_need_diff: 1,\n \t\t\tseparate_merges: 1,\n \t\t\tcombine_merges:1,\n \t\t\tcombined_all_paths:1,\n-- \n2.25.1\n\n"},{"id":"412738","messageId":"20201221152000.13134-7-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201221152000.13134-1-sorganov@gmail.com","subject":"[PATCH v3 06/32] diff-merges: rename all functions to have common prefix","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-21T15:19:34Z","receivedAt":"2020-12-21T18:16:12Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Use the same \"diff_merges\" prefix for all the diff merges function\nnames.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n builtin/log.c |  4 ++--\n diff-merges.c | 10 +++++-----\n diff-merges.h | 15 ++++++++++-----\n revision.c    |  6 +++---\n 4 files changed, 20 insertions(+), 15 deletions(-)\n\ndiff --git a/builtin/log.c b/builtin/log.c\nindex ad3092fdd854..77a7bba543ad 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -599,7 +599,7 @@ static int show_tree_object(const struct object_id *oid,\n static void show_setup_revisions_tweak(struct rev_info *rev,\n \t\t\t\t       struct setup_revision_opt *opt)\n {\n-\trev_diff_merges_default_to_dense_combined(rev);\n+\tdiff_merges_default_to_dense_combined(rev);\n \tif (!rev->diffopt.output_format)\n \t\trev->diffopt.output_format = DIFF_FORMAT_PATCH;\n }\n@@ -724,7 +724,7 @@ static void log_setup_revisions_tweak(struct rev_info *rev,\n \tif (!rev->diffopt.output_format && rev->combine_merges)\n \t\trev->diffopt.output_format = DIFF_FORMAT_PATCH;\n \n-\trev_diff_merges_first_parent_defaults_to_enable(rev);\n+\tdiff_merges_first_parent_defaults_to_enable(rev);\n }\n \n int cmd_log(int argc, const char **argv, const char *prefix)\ndiff --git a/diff-merges.c b/diff-merges.c\nindex 0204292aa9bb..9286dbbd4dfd 100644\n--- a/diff-merges.c\n+++ b/diff-merges.c\n@@ -2,12 +2,12 @@\n \n #include \"revision.h\"\n \n-void init_diff_merge_revs(struct rev_info *revs)\n+void diff_merges_init_revs(struct rev_info *revs)\n {\n \trevs->ignore_merges = -1;\n }\n \n-int parse_diff_merge_opts(struct rev_info *revs, const char **argv)\n+int diff_merges_parse_opts(struct rev_info *revs, const char **argv)\n {\n \tint argcount = 1;\n \tconst char *optarg;\n@@ -46,7 +46,7 @@ int parse_diff_merge_opts(struct rev_info *revs, const char **argv)\n \treturn argcount;\n }\n \n-void setup_diff_merges_revs(struct rev_info *revs)\n+void diff_merges_setup_revs(struct rev_info *revs)\n {\n \tif (revs->combine_merges && revs->ignore_merges < 0)\n \t\trevs->ignore_merges = 0;\n@@ -56,13 +56,13 @@ void setup_diff_merges_revs(struct rev_info *revs)\n \t\tdie(\"--combined-all-paths makes no sense without -c or --cc\");\n }\n \n-void rev_diff_merges_first_parent_defaults_to_enable(struct rev_info *revs)\n+void diff_merges_first_parent_defaults_to_enable(struct rev_info *revs)\n {\n \tif (revs->first_parent_only && revs->ignore_merges < 0)\n \t\trevs->ignore_merges = 0;\n }\n \n-void rev_diff_merges_default_to_dense_combined(struct rev_info *revs)\n+void diff_merges_default_to_dense_combined(struct rev_info *revs)\n {\n \tif (revs->ignore_merges < 0) {\n \t\t/* There was no \"-m\" variant on the command line */\ndiff --git a/diff-merges.h b/diff-merges.h\nindex 7e970b266cf5..4ced909b795e 100644\n--- a/diff-merges.h\n+++ b/diff-merges.h\n@@ -9,10 +9,15 @@\n \n struct rev_info;\n \n-void init_diff_merge_revs(struct rev_info *revs);\n-int parse_diff_merge_opts(struct rev_info *revs, const char **argv);\n-void setup_diff_merges_revs(struct rev_info *revs);\n-void rev_diff_merges_default_to_dense_combined(struct rev_info *revs);\n-void rev_diff_merges_first_parent_defaults_to_enable(struct rev_info *revs);\n+void diff_merges_init_revs(struct rev_info *revs);\n+\n+int diff_merges_parse_opts(struct rev_info *revs, const char **argv);\n+\n+void diff_merges_setup_revs(struct rev_info *revs);\n+\n+void diff_merges_default_to_dense_combined(struct rev_info *revs);\n+\n+void diff_merges_first_parent_defaults_to_enable(struct rev_info *revs);\n+\n \n #endif\ndiff --git a/revision.c b/revision.c\nindex 4bc14a08a624..5a0e3d6ad542 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -1814,7 +1814,7 @@ void repo_init_revisions(struct repository *r,\n \n \trevs->repo = r;\n \trevs->abbrev = DEFAULT_ABBREV;\n-\tinit_diff_merge_revs(revs);\n+\tdiff_merges_init_revs(revs);\n \trevs->simplify_history = 1;\n \trevs->pruning.repo = r;\n \trevs->pruning.flags.recursive = 1;\n@@ -2350,7 +2350,7 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg\n \t\trevs->diff = 1;\n \t\trevs->diffopt.flags.recursive = 1;\n \t\trevs->diffopt.flags.tree_in_recursive = 1;\n-\t} else if ((argcount = parse_diff_merge_opts(revs, argv))) {\n+\t} else if ((argcount = diff_merges_parse_opts(revs, argv))) {\n \t\treturn argcount;\n \t} else if (!strcmp(arg, \"-v\")) {\n \t\trevs->verbose_header = 1;\n@@ -2849,7 +2849,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s\n \t\t\t\t      &revs->prune_data);\n \t}\n \n-\tsetup_diff_merges_revs(revs);\n+\tdiff_merges_setup_revs(revs);\n \n \trevs->diffopt.abbrev = revs->abbrev;\n \n-- \n2.25.1\n\n"},{"id":"412739","messageId":"20201221152000.13134-8-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201221152000.13134-1-sorganov@gmail.com","subject":"[PATCH v3 07/32] diff-merges: move checks for first_parent_only out of the module","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-21T15:19:35Z","receivedAt":"2020-12-21T18:16:13Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"The checks for first_parent_only don't in fact belong to this module,\nas the primary purpose of this flag is history traversal limiting, so\nget it out of this module and rename the\n\ndiff_merges_first_parent_defaults_to_enable()\n\nto\n\ndiff_merges_default_to_enable()\n\nto match new semantics.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n builtin/log.c |  8 ++++++--\n diff-merges.c | 10 ++++------\n diff-merges.h |  2 +-\n 3 files changed, 11 insertions(+), 9 deletions(-)\n\ndiff --git a/builtin/log.c b/builtin/log.c\nindex 77a7bba543ad..a7791c003c91 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -599,7 +599,10 @@ static int show_tree_object(const struct object_id *oid,\n static void show_setup_revisions_tweak(struct rev_info *rev,\n \t\t\t\t       struct setup_revision_opt *opt)\n {\n-\tdiff_merges_default_to_dense_combined(rev);\n+\tif (rev->first_parent_only)\n+\t\tdiff_merges_default_to_enable(rev);\n+\telse\n+\t\tdiff_merges_default_to_dense_combined(rev);\n \tif (!rev->diffopt.output_format)\n \t\trev->diffopt.output_format = DIFF_FORMAT_PATCH;\n }\n@@ -724,7 +727,8 @@ static void log_setup_revisions_tweak(struct rev_info *rev,\n \tif (!rev->diffopt.output_format && rev->combine_merges)\n \t\trev->diffopt.output_format = DIFF_FORMAT_PATCH;\n \n-\tdiff_merges_first_parent_defaults_to_enable(rev);\n+\tif (rev->first_parent_only)\n+\t\tdiff_merges_default_to_enable(rev);\n }\n \n int cmd_log(int argc, const char **argv, const char *prefix)\ndiff --git a/diff-merges.c b/diff-merges.c\nindex 9286dbbd4dfd..a3bafa92f3e1 100644\n--- a/diff-merges.c\n+++ b/diff-merges.c\n@@ -56,19 +56,17 @@ void diff_merges_setup_revs(struct rev_info *revs)\n \t\tdie(\"--combined-all-paths makes no sense without -c or --cc\");\n }\n \n-void diff_merges_first_parent_defaults_to_enable(struct rev_info *revs)\n+void diff_merges_default_to_enable(struct rev_info *revs)\n {\n-\tif (revs->first_parent_only && revs->ignore_merges < 0)\n+\tif (revs->ignore_merges < 0)\t\t/* No -m */\n \t\trevs->ignore_merges = 0;\n }\n \n void diff_merges_default_to_dense_combined(struct rev_info *revs)\n {\n-\tif (revs->ignore_merges < 0) {\n-\t\t/* There was no \"-m\" variant on the command line */\n+\tif (revs->ignore_merges < 0) {\t\t/* No -m */\n \t\trevs->ignore_merges = 0;\n-\t\tif (!revs->first_parent_only && !revs->combine_merges) {\n-\t\t\t/* No \"--first-parent\", \"-c\", or \"--cc\" */\n+\t\tif (!revs->combine_merges) {\t/* No -c/--cc\" */\n \t\t\trevs->combine_merges = 1;\n \t\t\trevs->dense_combined_merges = 1;\n \t\t}\ndiff --git a/diff-merges.h b/diff-merges.h\nindex 4ced909b795e..6937d46219f1 100644\n--- a/diff-merges.h\n+++ b/diff-merges.h\n@@ -17,7 +17,7 @@ void diff_merges_setup_revs(struct rev_info *revs);\n \n void diff_merges_default_to_dense_combined(struct rev_info *revs);\n \n-void diff_merges_first_parent_defaults_to_enable(struct rev_info *revs);\n+void diff_merges_default_to_enable(struct rev_info *revs);\n \n \n #endif\n-- \n2.25.1\n\n"},{"id":"412740","messageId":"20201221152000.13134-32-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201221152000.13134-1-sorganov@gmail.com","subject":"[PATCH v3 31/32] doc/git-show: include --diff-merges description","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-21T15:19:59Z","receivedAt":"2020-12-21T18:16:15Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Move description of --diff-merges option from git-log.txt to\ndiff-options.txt so that it is included in the git-show help.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n Documentation/diff-options.txt | 51 ++++++++++++++++++++++++++++++++++\n Documentation/git-log.txt      | 51 +---------------------------------\n Documentation/git-show.txt     |  7 +++--\n 3 files changed, 57 insertions(+), 52 deletions(-)\n\ndiff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt\nindex 573fb9bb71e2..c995e82584f3 100644\n--- a/Documentation/diff-options.txt\n+++ b/Documentation/diff-options.txt\n@@ -33,6 +33,57 @@ endif::git-diff[]\n \tshow the patch by default, or to cancel the effect of `--patch`.\n endif::git-format-patch[]\n \n+ifdef::git-log[]\n+--diff-merges=(off|none|first-parent|1|separate|m|combined|c|dense-combined|cc)::\n+--no-diff-merges::\n+\tSpecify diff format to be used for merge commits. Default is\n+\t{diff-merges-default} unless `--first-parent` is in use, in which case\n+\t`first-parent` is the default.\n++\n+--diff-merges=(off|none):::\n+--no-diff-merges:::\n+\tDisable output of diffs for merge commits. Useful to override\n+\timplied value.\n++\n+--diff-merges=first-parent:::\n+--diff-merges=1:::\n+\tThis option makes merge commits show the full diff with\n+\trespect to the first parent only.\n++\n+--diff-merges=separate:::\n+--diff-merges=m:::\n+-m:::\n+\tThis makes merge commits show the full diff with respect to\n+\teach of the parents. Separate log entry and diff is generated\n+\tfor each parent. `-m` doesn't produce any output without `-p`.\n++\n+--diff-merges=combined:::\n+--diff-merges=c:::\n+-c:::\n+\tWith this option, diff output for a merge commit shows the\n+\tdifferences from each of the parents to the merge result\n+\tsimultaneously instead of showing pairwise diff between a\n+\tparent and the result one at a time. Furthermore, it lists\n+\tonly files which were modified from all parents. `-c` implies\n+\t`-p`.\n++\n+--diff-merges=dense-combined:::\n+--diff-merges=cc:::\n+--cc:::\n+\tWith this option the output produced by\n+\t`--diff-merges=combined` is further compressed by omitting\n+\tuninteresting hunks whose contents in the parents have only\n+\ttwo variants and the merge result picks one of them without\n+\tmodification.  `--cc` implies `-p`.\n+\n+--combined-all-paths::\n+\tThis flag causes combined diffs (used for merge commits) to\n+\tlist the name of the file from all parents.  It thus only has\n+\teffect when `--diff-merges=[dense-]combined` is in use, and\n+\tis likely only useful if filename changes are detected (i.e.\n+\twhen either rename or copy detection have been requested).\n+endif::git-log[]\n+\n -U<n>::\n --unified=<n>::\n \tGenerate diffs with <n> lines of context instead of\ndiff --git a/Documentation/git-log.txt b/Documentation/git-log.txt\nindex ff83dff14dd6..727d20e1a2ab 100644\n--- a/Documentation/git-log.txt\n+++ b/Documentation/git-log.txt\n@@ -127,57 +127,8 @@ selected, nor will they match search options like `-S`. The exception\n is when `--first-parent` is in use, in which case `first-parent` is\n the default format.\n \n---diff-merges=(off|none|first-parent|1|separate|m|combined|c|dense-combined|cc)::\n---no-diff-merges::\n-\tSpecify diff format to be used for merge commits. Default is\n-\t`off` unless `--first-parent` is in use, in which case\n-\t`first-parent` is the default.\n-+\n---diff-merges=(off|none):::\n---no-diff-merges:::\n-\tDisable output of diffs for merge commits. Useful to override\n-\timplied value.\n-+\n---diff-merges=first-parent:::\n---diff-merges=1:::\n-\tThis option makes merge commits show the full diff with\n-\trespect to the first parent only.\n-+\n---diff-merges=separate:::\n---diff-merges=m:::\n--m:::\n-\tThis makes merge commits show the full diff with respect to\n-\teach of the parents. Separate log entry and diff is generated\n-\tfor each parent. `-m` doesn't produce any output without `-p`.\n-+\n---diff-merges=combined:::\n---diff-merges=c:::\n--c:::\n-\tWith this option, diff output for a merge commit shows the\n-\tdifferences from each of the parents to the merge result\n-\tsimultaneously instead of showing pairwise diff between a\n-\tparent and the result one at a time. Furthermore, it lists\n-\tonly files which were modified from all parents. `-c` implies\n-\t`-p`.\n-+\n---diff-merges=dense-combined:::\n---diff-merges=cc:::\n---cc:::\n-\tWith this option the output produced by\n-\t`--diff-merges=combined` is further compressed by omitting\n-\tuninteresting hunks whose contents in the parents have only\n-\ttwo variants and the merge result picks one of them without\n-\tmodification.  `--cc` implies `-p`.\n-\n---combined-all-paths::\n-\tThis flag causes combined diffs (used for merge commits) to\n-\tlist the name of the file from all parents.  It thus only has\n-\teffect when `--diff-merges=[dense-]combined` is in use, and\n-\tis likely only useful if filename changes are detected (i.e.\n-\twhen either rename or copy detection have been requested).\n-\n-\n :git-log: 1\n+:diff-merges-default: `off`\n include::diff-options.txt[]\n \n include::diff-generate-patch.txt[]\ndiff --git a/Documentation/git-show.txt b/Documentation/git-show.txt\nindex fcf528c1b30d..2b1bc7288d5f 100644\n--- a/Documentation/git-show.txt\n+++ b/Documentation/git-show.txt\n@@ -45,10 +45,13 @@ include::pretty-options.txt[]\n include::pretty-formats.txt[]\n \n \n-COMMON DIFF OPTIONS\n--------------------\n+DIFF FORMATTING\n+---------------\n+The options below can be used to change the way `git show` generates\n+diff output.\n \n :git-log: 1\n+:diff-merges-default: `dense-combined`\n include::diff-options.txt[]\n \n include::diff-generate-patch.txt[]\n-- \n2.25.1\n\n"},{"id":"412743","messageId":"20201221152000.13134-31-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201221152000.13134-1-sorganov@gmail.com","subject":"[PATCH v3 30/32] doc/rev-list-options: document --first-parent changes merges format","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-21T15:19:58Z","receivedAt":"2020-12-21T18:25:52Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"After introduction of the --diff-merges=first-parent, the\n--first-parent sets the default format for merges to the same value as\nthis new option. Document this behavior and add corresponding\nreference to --diff-merges.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n Documentation/rev-list-options.txt | 5 +++++\n 1 file changed, 5 insertions(+)\n\ndiff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt\nindex 002379056a07..96cc89d157d2 100644\n--- a/Documentation/rev-list-options.txt\n+++ b/Documentation/rev-list-options.txt\n@@ -130,6 +130,11 @@ parents) and `--max-parents=-1` (negative numbers denote no upper limit).\n \tthis option allows you to ignore the individual commits\n \tbrought in to your history by such a merge.\n \n+ifdef::git-log[]\n+\tThis option also changes default diff format for merge commits\n+\tto `first-parent`, see `--diff-merges=first-parent` for details.\n+endif::git-log[]\n+\n --not::\n \tReverses the meaning of the '{caret}' prefix (or lack thereof)\n \tfor all following revision specifiers, up to the next `--not`.\n-- \n2.25.1\n\n"},{"id":"412747","messageId":"20201221152000.13134-13-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201221152000.13134-1-sorganov@gmail.com","subject":"[PATCH v3 12/32] diff-merges: introduce revs->first_parent_merges flag","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-21T15:19:40Z","receivedAt":"2020-12-21T18:31:41Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"This new field allows us to separate format of diff for merges from\n'first_parent_only' flag which primary purpose is limiting history\ntraversal.\n\nThis change further localizes diff format selection logic into the\ndiff-merges.c file.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n diff-merges.c | 2 ++\n log-tree.c    | 4 ++--\n revision.h    | 1 +\n 3 files changed, 5 insertions(+), 2 deletions(-)\n\ndiff --git a/diff-merges.c b/diff-merges.c\nindex 24f922cf8a0f..fb591a933959 100644\n--- a/diff-merges.c\n+++ b/diff-merges.c\n@@ -73,6 +73,8 @@ void diff_merges_default_to_first_parent(struct rev_info *revs)\n {\n \tif (revs->ignore_merges < 0)\t\t/* No -m */\n \t\trevs->ignore_merges = 0;\n+\tif (!revs->combine_merges)\t\t/* No -c/--cc\" */\n+\t\trevs->first_parent_merges = 1;\n }\n \n void diff_merges_default_to_dense_combined(struct rev_info *revs)\ndiff --git a/log-tree.c b/log-tree.c\nindex 1927f917ce94..3fdc0fc64bfb 100644\n--- a/log-tree.c\n+++ b/log-tree.c\n@@ -922,7 +922,7 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log\n \t\t\treturn 0;\n \t\telse if (opt->combine_merges)\n \t\t\treturn do_diff_combined(opt, commit);\n-\t\telse if (!opt->first_parent_only) {\n+\t\telse if (!opt->first_parent_merges) {\n \t\t\t/* If we show multiple diffs, show the parent info */\n \t\t\tlog->parent = parents->item;\n \t\t}\n@@ -941,7 +941,7 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log\n \n \t\t/* Set up the log info for the next parent, if any.. */\n \t\tparents = parents->next;\n-\t\tif (!parents || opt->first_parent_only)\n+\t\tif (!parents || opt->first_parent_merges)\n \t\t\tbreak;\n \t\tlog->parent = parents->item;\n \t\topt->loginfo = log;\ndiff --git a/revision.h b/revision.h\nindex f6bf860d19e5..ba2aef79215e 100644\n--- a/revision.h\n+++ b/revision.h\n@@ -194,6 +194,7 @@ struct rev_info {\n \t\t\tcombine_merges:1,\n \t\t\tcombined_all_paths:1,\n \t\t\tdense_combined_merges:1,\n+\t\t\tfirst_parent_merges:1,\n \t\t\talways_show_header:1;\n \tint             ignore_merges:2;\n \n-- \n2.25.1\n\n"},{"id":"412748","messageId":"20201221152000.13134-22-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201221152000.13134-1-sorganov@gmail.com","subject":"[PATCH v3 21/32] diff-merges: refactor opt settings into separate functions","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-21T15:19:49Z","receivedAt":"2020-12-21T18:33:20Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"To prepare introduction of new options some of which will be synonyms\nto existing options, let every option handling code just call\ncorresponding function.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n diff-merges.c | 63 +++++++++++++++++++++++++++++++++------------------\n 1 file changed, 41 insertions(+), 22 deletions(-)\n\ndiff --git a/diff-merges.c b/diff-merges.c\nindex 34d7ed7c70b7..b8fd92adcf16 100644\n--- a/diff-merges.c\n+++ b/diff-merges.c\n@@ -10,12 +10,43 @@ static void suppress(struct rev_info *revs)\n \trevs->dense_combined_merges = 0;\n }\n \n+static void set_separate(struct rev_info *revs)\n+{\n+\tsuppress(revs);\n+\trevs->separate_merges = 1;\n+}\n+\n+static void set_m(struct rev_info *revs)\n+{\n+\t/*\n+\t * To \"diff-index\", \"-m\" means \"match missing\", and to the \"log\"\n+\t * family of commands, it means \"show full diff for merges\". Set\n+\t * both fields appropriately.\n+\t */\n+\tset_separate(revs);\n+\trevs->match_missing = 1;\n+}\n+\n+static void set_combined(struct rev_info *revs)\n+{\n+\trevs->combine_merges = 1;\n+\trevs->dense_combined_merges = 0;\n+}\n+\n static void set_dense_combined(struct rev_info *revs)\n {\n \trevs->combine_merges = 1;\n \trevs->dense_combined_merges = 1;\n }\n \n+static void set_diff_merges(struct rev_info *revs, const char *optarg)\n+{\n+\tif (!strcmp(optarg, \"off\")) {\n+\t\tsuppress(revs);\n+\t} else {\n+\t\tdie(_(\"unknown value for --diff-merges: %s\"), optarg);\n+\t}\n+}\n \n /*\n  * Public functions. They are in the order they are called.\n@@ -27,31 +58,19 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv)\n \tconst char *optarg;\n \tconst char *arg = argv[0];\n \n-\tif (!strcmp(arg, \"-m\")) {\n-\t\tsuppress(revs);\n-\t\t/*\n-\t\t * To \"diff-index\", \"-m\" means \"match missing\", and to the \"log\"\n-\t\t * family of commands, it means \"show full diff for merges\". Set\n-\t\t * both fields appropriately.\n-\t\t */\n-\t\trevs->separate_merges = 1;\n-\t\trevs->match_missing = 1;\n-\t} else if (!strcmp(arg, \"-c\")) {\n-\t\trevs->dense_combined_merges = 0;\n-\t\trevs->combine_merges = 1;\n-\t} else if (!strcmp(arg, \"--cc\")) {\n+\tif (!strcmp(arg, \"-m\"))\n+\t\tset_m(revs);\n+\telse if (!strcmp(arg, \"-c\"))\n+\t\tset_combined(revs);\n+\telse if (!strcmp(arg, \"--cc\"))\n \t\tset_dense_combined(revs);\n-\t} else if (!strcmp(arg, \"--no-diff-merges\")) {\n+\telse if (!strcmp(arg, \"--no-diff-merges\"))\n \t\tsuppress(revs);\n-\t} else if (!strcmp(arg, \"--combined-all-paths\")) {\n+\telse if (!strcmp(arg, \"--combined-all-paths\"))\n \t\trevs->combined_all_paths = 1;\n-\t} else if ((argcount = parse_long_opt(\"diff-merges\", argv, &optarg))) {\n-\t\tif (!strcmp(optarg, \"off\")) {\n-\t\t\tsuppress(revs);\n-\t\t} else {\n-\t\t\tdie(_(\"unknown value for --diff-merges: %s\"), optarg);\n-\t\t}\n-\t} else\n+\telse if ((argcount = parse_long_opt(\"diff-merges\", argv, &optarg)))\n+\t\tset_diff_merges(revs, optarg);\n+\telse\n \t\treturn 0;\n \n \trevs->explicit_diff_merges = 1;\n-- \n2.25.1\n\n"},{"id":"412750","messageId":"20201221152000.13134-28-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201221152000.13134-1-sorganov@gmail.com","subject":"[PATCH v3 27/32] diff-merges: add '--diff-merges=1' as synonym for 'first-parent'","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-21T15:19:55Z","receivedAt":"2020-12-21T18:39:48Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"As we now have --diff-merges={m|c|cc}, add --diff-merges=1 as synonym\nfor --diff-merges=first-parent, to have shorter mnemonics for it as\nwell.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n diff-merges.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/diff-merges.c b/diff-merges.c\nindex 011bfff1f135..146bb50316a6 100644\n--- a/diff-merges.c\n+++ b/diff-merges.c\n@@ -58,7 +58,7 @@ static void set_diff_merges(struct rev_info *revs, const char *optarg)\n \t\treturn;\n \t}\n \n-\tif (!strcmp(optarg, \"first-parent\"))\n+\tif (!strcmp(optarg, \"1\") || !strcmp(optarg, \"first-parent\"))\n \t\tset_first_parent(revs);\n \telse if (!strcmp(optarg, \"m\") || !strcmp(optarg, \"separate\"))\n \t\tset_separate(revs);\n-- \n2.25.1\n\n"},{"id":"412751","messageId":"5fe0ec103ad4f_e6ff208f5@natae.notmuch","threadId":"54550","inReplyTo":"20201221152000.13134-26-sorganov@gmail.com","subject":"RE: [PATCH v3 25/32] diff-merges: let new options enable diff without -p","fromName":"Felipe Contreras","fromEmail":"felipe.contreras@gmail.com","sentAt":"2020-12-21T18:40:16Z","receivedAt":"2020-12-21T18:41:53Z","isPatch":true,"sender":{"key":"felipe.contreras@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8358?v=4"},"body":"Sergey Organov wrote:\n> diff --git a/log-tree.c b/log-tree.c\n> index f9385b1dae6f..9f50a81e537e 100644\n> --- a/log-tree.c\n> +++ b/log-tree.c\n> @@ -899,15 +899,21 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log\n>  \tint showed_log;\n>  \tstruct commit_list *parents;\n>  \tstruct object_id *oid;\n> +\tint is_merge;\n> +\tint all_need_diff = opt->diff || opt->diffopt.flags.exit_with_status;\n>  \n> -\tif (!opt->diff && !opt->diffopt.flags.exit_with_status)\n> +\tif (!all_need_diff && !opt->merges_need_diff)\n>  \t\treturn 0;\n>  \n>  \tparse_commit_or_die(commit);\n>  \toid = get_commit_tree_oid(commit);\n>  \n> -\t/* Root commit? */\n>  \tparents = get_saved_parents(opt, commit);\n> +\tis_merge = parents && parents->next;\n> +\tif (!is_merge && !all_need_diff)\n> +\t\treturn 0;\n> +\n> +\t/* Root commit? */\n>  \tif (!parents) {\n>  \t\tif (opt->show_root_diff) {\n>  \t\t\tdiff_root_tree_oid(oid, \"\", &opt->diffopt);\n\nFWIW this logic does make sense to me.\n\n-- \nFelipe Contreras\n"},{"id":"412752","messageId":"20201221152000.13134-3-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201221152000.13134-1-sorganov@gmail.com","subject":"[PATCH v3 02/32] revision: factor out setup of diff-merge related settings","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-21T15:19:30Z","receivedAt":"2020-12-21T18:46:47Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Move all the setting code related to diffing merges into new\nsetup_diff_merge_revs() function.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n revision.c | 18 ++++++++++++------\n 1 file changed, 12 insertions(+), 6 deletions(-)\n\ndiff --git a/revision.c b/revision.c\nindex 8b17cfd754fe..d818e0b18bbc 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -2192,6 +2192,16 @@ static int parse_diff_merge_opts(struct rev_info *revs, const char **argv)\n \treturn argcount;\n }\n \n+static void setup_diff_merges_revs(struct rev_info *revs)\n+{\n+\tif (revs->combine_merges && revs->ignore_merges < 0)\n+\t\trevs->ignore_merges = 0;\n+\tif (revs->ignore_merges < 0)\n+\t\trevs->ignore_merges = 1;\n+\tif (revs->combined_all_paths && !revs->combine_merges)\n+\t\tdie(\"--combined-all-paths makes no sense without -c or --cc\");\n+}\n+\n static int handle_revision_opt(struct rev_info *revs, int argc, const char **argv,\n \t\t\t       int *unkc, const char **unkv,\n \t\t\t       const struct setup_revision_opt* opt)\n@@ -2886,12 +2896,8 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s\n \t\t\tcopy_pathspec(&revs->diffopt.pathspec,\n \t\t\t\t      &revs->prune_data);\n \t}\n-\tif (revs->combine_merges && revs->ignore_merges < 0)\n-\t\trevs->ignore_merges = 0;\n-\tif (revs->ignore_merges < 0)\n-\t\trevs->ignore_merges = 1;\n-\tif (revs->combined_all_paths && !revs->combine_merges)\n-\t\tdie(\"--combined-all-paths makes no sense without -c or --cc\");\n+\n+\tsetup_diff_merges_revs(revs);\n \n \trevs->diffopt.abbrev = revs->abbrev;\n \n-- \n2.25.1\n\n"},{"id":"412753","messageId":"20201221152000.13134-6-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201221152000.13134-1-sorganov@gmail.com","subject":"[PATCH v3 05/32] revision: move diff merges functions to its own diff-merges.c","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-21T15:19:33Z","receivedAt":"2020-12-21T18:53:44Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Create separate diff-merges.c and diff-merges.h files, and move all\nthe code related to handling of diff merges there.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n Makefile      |  1 +\n builtin/log.c |  1 +\n diff-merges.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++\n diff-merges.h | 18 ++++++++++++\n revision.c    | 76 +--------------------------------------------------\n revision.h    |  3 --\n 6 files changed, 97 insertions(+), 78 deletions(-)\n create mode 100644 diff-merges.c\n create mode 100644 diff-merges.h\n\ndiff --git a/Makefile b/Makefile\nindex 1fb0ec17059a..d1347ef262cf 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -872,6 +872,7 @@ LIB_OBJS += date.o\n LIB_OBJS += decorate.o\n LIB_OBJS += delta-islands.o\n LIB_OBJS += diff-delta.o\n+LIB_OBJS += diff-merges.o\n LIB_OBJS += diff-lib.o\n LIB_OBJS += diff-no-index.o\n LIB_OBJS += diff.o\ndiff --git a/builtin/log.c b/builtin/log.c\nindex 717855a49e90..ad3092fdd854 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -12,6 +12,7 @@\n #include \"color.h\"\n #include \"commit.h\"\n #include \"diff.h\"\n+#include \"diff-merges.h\"\n #include \"revision.h\"\n #include \"log-tree.h\"\n #include \"builtin.h\"\ndiff --git a/diff-merges.c b/diff-merges.c\nnew file mode 100644\nindex 000000000000..0204292aa9bb\n--- /dev/null\n+++ b/diff-merges.c\n@@ -0,0 +1,76 @@\n+#include \"diff-merges.h\"\n+\n+#include \"revision.h\"\n+\n+void init_diff_merge_revs(struct rev_info *revs)\n+{\n+\trevs->ignore_merges = -1;\n+}\n+\n+int parse_diff_merge_opts(struct rev_info *revs, const char **argv)\n+{\n+\tint argcount = 1;\n+\tconst char *optarg;\n+\tconst char *arg = argv[0];\n+\n+\tif (!strcmp(arg, \"-m\")) {\n+\t\t/*\n+\t\t * To \"diff-index\", \"-m\" means \"match missing\", and to the \"log\"\n+\t\t * family of commands, it means \"show full diff for merges\". Set\n+\t\t * both fields appropriately.\n+\t\t */\n+\t\trevs->ignore_merges = 0;\n+\t\trevs->match_missing = 1;\n+\t} else if (!strcmp(arg, \"-c\")) {\n+\t\trevs->diff = 1;\n+\t\trevs->dense_combined_merges = 0;\n+\t\trevs->combine_merges = 1;\n+\t} else if (!strcmp(arg, \"--cc\")) {\n+\t\trevs->diff = 1;\n+\t\trevs->dense_combined_merges = 1;\n+\t\trevs->combine_merges = 1;\n+\t} else if (!strcmp(arg, \"--no-diff-merges\")) {\n+\t\trevs->ignore_merges = 1;\n+\t} else if (!strcmp(arg, \"--combined-all-paths\")) {\n+\t\trevs->diff = 1;\n+\t\trevs->combined_all_paths = 1;\n+\t} else if ((argcount = parse_long_opt(\"diff-merges\", argv, &optarg))) {\n+\t\tif (!strcmp(optarg, \"off\")) {\n+\t\t\trevs->ignore_merges = 1;\n+\t\t} else {\n+\t\t\tdie(_(\"unknown value for --diff-merges: %s\"), optarg);\n+\t\t}\n+\t} else\n+\t\targcount = 0;\n+\n+\treturn argcount;\n+}\n+\n+void setup_diff_merges_revs(struct rev_info *revs)\n+{\n+\tif (revs->combine_merges && revs->ignore_merges < 0)\n+\t\trevs->ignore_merges = 0;\n+\tif (revs->ignore_merges < 0)\n+\t\trevs->ignore_merges = 1;\n+\tif (revs->combined_all_paths && !revs->combine_merges)\n+\t\tdie(\"--combined-all-paths makes no sense without -c or --cc\");\n+}\n+\n+void rev_diff_merges_first_parent_defaults_to_enable(struct rev_info *revs)\n+{\n+\tif (revs->first_parent_only && revs->ignore_merges < 0)\n+\t\trevs->ignore_merges = 0;\n+}\n+\n+void rev_diff_merges_default_to_dense_combined(struct rev_info *revs)\n+{\n+\tif (revs->ignore_merges < 0) {\n+\t\t/* There was no \"-m\" variant on the command line */\n+\t\trevs->ignore_merges = 0;\n+\t\tif (!revs->first_parent_only && !revs->combine_merges) {\n+\t\t\t/* No \"--first-parent\", \"-c\", or \"--cc\" */\n+\t\t\trevs->combine_merges = 1;\n+\t\t\trevs->dense_combined_merges = 1;\n+\t\t}\n+\t}\n+}\ndiff --git a/diff-merges.h b/diff-merges.h\nnew file mode 100644\nindex 000000000000..7e970b266cf5\n--- /dev/null\n+++ b/diff-merges.h\n@@ -0,0 +1,18 @@\n+#ifndef DIFF_MERGES_H\n+#define DIFF_MERGES_H\n+\n+/*\n+ * diff-merges - utility module to handle command-line options for\n+ * selection of particular diff format of merge commits\n+ * representation.\n+ */\n+\n+struct rev_info;\n+\n+void init_diff_merge_revs(struct rev_info *revs);\n+int parse_diff_merge_opts(struct rev_info *revs, const char **argv);\n+void setup_diff_merges_revs(struct rev_info *revs);\n+void rev_diff_merges_default_to_dense_combined(struct rev_info *revs);\n+void rev_diff_merges_first_parent_defaults_to_enable(struct rev_info *revs);\n+\n+#endif\ndiff --git a/revision.c b/revision.c\nindex 1c224d276474..4bc14a08a624 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -5,6 +5,7 @@\n #include \"tree.h\"\n #include \"commit.h\"\n #include \"diff.h\"\n+#include \"diff-merges.h\"\n #include \"refs.h\"\n #include \"revision.h\"\n #include \"repository.h\"\n@@ -1805,8 +1806,6 @@ static int add_parents_only(struct rev_info *revs, const char *arg_, int flags,\n \treturn 1;\n }\n \n-static void init_diff_merge_revs(struct rev_info *revs);\n-\n void repo_init_revisions(struct repository *r,\n \t\t\t struct rev_info *revs,\n \t\t\t const char *prefix)\n@@ -2155,79 +2154,6 @@ static void add_message_grep(struct rev_info *revs, const char *pattern)\n \tadd_grep(revs, pattern, GREP_PATTERN_BODY);\n }\n \n-static void init_diff_merge_revs(struct rev_info *revs)\n-{\n-\trevs->ignore_merges = -1;\n-}\n-\n-static int parse_diff_merge_opts(struct rev_info *revs, const char **argv)\n-{\n-\tint argcount = 1;\n-\tconst char *optarg;\n-\tconst char *arg = argv[0];\n-\n-\tif (!strcmp(arg, \"-m\")) {\n-\t\t/*\n-\t\t * To \"diff-index\", \"-m\" means \"match missing\", and to the \"log\"\n-\t\t * family of commands, it means \"show full diff for merges\". Set\n-\t\t * both fields appropriately.\n-\t\t */\n-\t\trevs->ignore_merges = 0;\n-\t\trevs->match_missing = 1;\n-\t} else if (!strcmp(arg, \"-c\")) {\n-\t\trevs->diff = 1;\n-\t\trevs->dense_combined_merges = 0;\n-\t\trevs->combine_merges = 1;\n-\t} else if (!strcmp(arg, \"--cc\")) {\n-\t\trevs->diff = 1;\n-\t\trevs->dense_combined_merges = 1;\n-\t\trevs->combine_merges = 1;\n-\t} else if (!strcmp(arg, \"--no-diff-merges\")) {\n-\t\trevs->ignore_merges = 1;\n-\t} else if (!strcmp(arg, \"--combined-all-paths\")) {\n-\t\trevs->diff = 1;\n-\t\trevs->combined_all_paths = 1;\n-\t} else if ((argcount = parse_long_opt(\"diff-merges\", argv, &optarg))) {\n-\t\tif (!strcmp(optarg, \"off\")) {\n-\t\t\trevs->ignore_merges = 1;\n-\t\t} else {\n-\t\t\tdie(_(\"unknown value for --diff-merges: %s\"), optarg);\n-\t\t}\n-\t} else\n-\t\targcount = 0;\n-\n-\treturn argcount;\n-}\n-\n-static void setup_diff_merges_revs(struct rev_info *revs)\n-{\n-\tif (revs->combine_merges && revs->ignore_merges < 0)\n-\t\trevs->ignore_merges = 0;\n-\tif (revs->ignore_merges < 0)\n-\t\trevs->ignore_merges = 1;\n-\tif (revs->combined_all_paths && !revs->combine_merges)\n-\t\tdie(\"--combined-all-paths makes no sense without -c or --cc\");\n-}\n-\n-void rev_diff_merges_first_parent_defaults_to_enable(struct rev_info *revs)\n-{\n-\tif (revs->first_parent_only && revs->ignore_merges < 0)\n-\t\trevs->ignore_merges = 0;\n-}\n-\n-void rev_diff_merges_default_to_dense_combined(struct rev_info *revs)\n-{\n-\tif (revs->ignore_merges < 0) {\n-\t\t/* There was no \"-m\" variant on the command line */\n-\t\trevs->ignore_merges = 0;\n-\t\tif (!revs->first_parent_only && !revs->combine_merges) {\n-\t\t\t/* No \"--first-parent\", \"-c\", or \"--cc\" */\n-\t\t\trevs->combine_merges = 1;\n-\t\t\trevs->dense_combined_merges = 1;\n-\t\t}\n-\t}\n-}\n-\n static int handle_revision_opt(struct rev_info *revs, int argc, const char **argv,\n \t\t\t       int *unkc, const char **unkv,\n \t\t\t       const struct setup_revision_opt* opt)\ndiff --git a/revision.h b/revision.h\nindex 3dd0229f4edc..f6bf860d19e5 100644\n--- a/revision.h\n+++ b/revision.h\n@@ -456,7 +456,4 @@ int rewrite_parents(struct rev_info *revs,\n  */\n struct commit_list *get_saved_parents(struct rev_info *revs, const struct commit *commit);\n \n-void rev_diff_merges_default_to_dense_combined(struct rev_info *revs);\n-void rev_diff_merges_first_parent_defaults_to_enable(struct rev_info *revs);\n-\n #endif\n-- \n2.25.1\n\n"},{"id":"412754","messageId":"20201221152000.13134-9-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201221152000.13134-1-sorganov@gmail.com","subject":"[PATCH v3 08/32] diff-merges: rename diff_merges_default_to_enable() to match semantics","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-21T15:19:36Z","receivedAt":"2020-12-21T18:56:34Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Rename diff_merges_default_to_enable() to\ndiff_merges_default_to_first_parent() to match its semantics.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n builtin/log.c | 4 ++--\n diff-merges.c | 2 +-\n diff-merges.h | 2 +-\n 3 files changed, 4 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/log.c b/builtin/log.c\nindex a7791c003c91..63875c3aeec9 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -600,7 +600,7 @@ static void show_setup_revisions_tweak(struct rev_info *rev,\n \t\t\t\t       struct setup_revision_opt *opt)\n {\n \tif (rev->first_parent_only)\n-\t\tdiff_merges_default_to_enable(rev);\n+\t\tdiff_merges_default_to_first_parent(rev);\n \telse\n \t\tdiff_merges_default_to_dense_combined(rev);\n \tif (!rev->diffopt.output_format)\n@@ -728,7 +728,7 @@ static void log_setup_revisions_tweak(struct rev_info *rev,\n \t\trev->diffopt.output_format = DIFF_FORMAT_PATCH;\n \n \tif (rev->first_parent_only)\n-\t\tdiff_merges_default_to_enable(rev);\n+\t\tdiff_merges_default_to_first_parent(rev);\n }\n \n int cmd_log(int argc, const char **argv, const char *prefix)\ndiff --git a/diff-merges.c b/diff-merges.c\nindex a3bafa92f3e1..76c804579758 100644\n--- a/diff-merges.c\n+++ b/diff-merges.c\n@@ -56,7 +56,7 @@ void diff_merges_setup_revs(struct rev_info *revs)\n \t\tdie(\"--combined-all-paths makes no sense without -c or --cc\");\n }\n \n-void diff_merges_default_to_enable(struct rev_info *revs)\n+void diff_merges_default_to_first_parent(struct rev_info *revs)\n {\n \tif (revs->ignore_merges < 0)\t\t/* No -m */\n \t\trevs->ignore_merges = 0;\ndiff --git a/diff-merges.h b/diff-merges.h\nindex 6937d46219f1..18861dc5480e 100644\n--- a/diff-merges.h\n+++ b/diff-merges.h\n@@ -17,7 +17,7 @@ void diff_merges_setup_revs(struct rev_info *revs);\n \n void diff_merges_default_to_dense_combined(struct rev_info *revs);\n \n-void diff_merges_default_to_enable(struct rev_info *revs);\n+void diff_merges_default_to_first_parent(struct rev_info *revs);\n \n \n #endif\n-- \n2.25.1\n\n"},{"id":"412756","messageId":"20201221152000.13134-29-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201221152000.13134-1-sorganov@gmail.com","subject":"[PATCH v3 28/32] doc/git-log: describe new --diff-merges options","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-21T15:19:56Z","receivedAt":"2020-12-21T19:02:56Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Describe all the new --diff-merges options in the git-log.txt and\nadopt description of originals accordingly.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n Documentation/git-log.txt | 83 +++++++++++++++++++++++----------------\n 1 file changed, 50 insertions(+), 33 deletions(-)\n\ndiff --git a/Documentation/git-log.txt b/Documentation/git-log.txt\nindex 2b8ac5ff882a..ff83dff14dd6 100644\n--- a/Documentation/git-log.txt\n+++ b/Documentation/git-log.txt\n@@ -120,45 +120,62 @@ DIFF FORMATTING\n By default, `git log` does not generate any diff output. The options\n below can be used to show the changes made by each commit.\n \n-Note that unless one of `-c`, `--cc`, or `-m` is given, merge commits\n-will never show a diff, even if a diff format like `--patch` is\n-selected, nor will they match search options like `-S`. The exception is\n-when `--first-parent` is in use, in which merges are treated like normal\n-single-parent commits (this can be overridden by providing a\n-combined-diff option or with `--no-diff-merges`).\n+Note that unless one of `--diff-merges` variants (including short\n+`-m`, `-c`, and `--cc` options) is explicitly given, merge commits\n+will not show a diff, even if a diff format like `--patch` is\n+selected, nor will they match search options like `-S`. The exception\n+is when `--first-parent` is in use, in which case `first-parent` is\n+the default format.\n \n--c::\n-\tWith this option, diff output for a merge commit\n-\tshows the differences from each of the parents to the merge result\n-\tsimultaneously instead of showing pairwise diff between a parent\n-\tand the result one at a time. Furthermore, it lists only files\n-\twhich were modified from all parents.\n-\n---cc::\n-\tThis flag implies the `-c` option and further compresses the\n-\tpatch output by omitting uninteresting hunks whose contents in\n-\tthe parents have only two variants and the merge result picks\n-\tone of them without modification.\n+--diff-merges=(off|none|first-parent|1|separate|m|combined|c|dense-combined|cc)::\n+--no-diff-merges::\n+\tSpecify diff format to be used for merge commits. Default is\n+\t`off` unless `--first-parent` is in use, in which case\n+\t`first-parent` is the default.\n++\n+--diff-merges=(off|none):::\n+--no-diff-merges:::\n+\tDisable output of diffs for merge commits. Useful to override\n+\timplied value.\n++\n+--diff-merges=first-parent:::\n+--diff-merges=1:::\n+\tThis option makes merge commits show the full diff with\n+\trespect to the first parent only.\n++\n+--diff-merges=separate:::\n+--diff-merges=m:::\n+-m:::\n+\tThis makes merge commits show the full diff with respect to\n+\teach of the parents. Separate log entry and diff is generated\n+\tfor each parent. `-m` doesn't produce any output without `-p`.\n++\n+--diff-merges=combined:::\n+--diff-merges=c:::\n+-c:::\n+\tWith this option, diff output for a merge commit shows the\n+\tdifferences from each of the parents to the merge result\n+\tsimultaneously instead of showing pairwise diff between a\n+\tparent and the result one at a time. Furthermore, it lists\n+\tonly files which were modified from all parents. `-c` implies\n+\t`-p`.\n++\n+--diff-merges=dense-combined:::\n+--diff-merges=cc:::\n+--cc:::\n+\tWith this option the output produced by\n+\t`--diff-merges=combined` is further compressed by omitting\n+\tuninteresting hunks whose contents in the parents have only\n+\ttwo variants and the merge result picks one of them without\n+\tmodification.  `--cc` implies `-p`.\n \n --combined-all-paths::\n \tThis flag causes combined diffs (used for merge commits) to\n \tlist the name of the file from all parents.  It thus only has\n-\teffect when -c or --cc are specified, and is likely only\n-\tuseful if filename changes are detected (i.e. when either\n-\trename or copy detection have been requested).\n+\teffect when `--diff-merges=[dense-]combined` is in use, and\n+\tis likely only useful if filename changes are detected (i.e.\n+\twhen either rename or copy detection have been requested).\n \n--m::\n-\tThis flag makes the merge commits show the full diff like\n-\tregular commits; for each merge parent, a separate log entry\n-\tand diff is generated. An exception is that only diff against\n-\tthe first parent is shown when `--first-parent` option is given;\n-\tin that case, the output represents the changes the merge\n-\tbrought _into_ the then-current branch.\n-\n---diff-merges=off::\n---no-diff-merges::\n-\tDisable output of diffs for merge commits (default). Useful to\n-\toverride `-m`, `-c`, or `--cc`.\n \n :git-log: 1\n include::diff-options.txt[]\n-- \n2.25.1\n\n"},{"id":"412758","messageId":"20201221152000.13134-30-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201221152000.13134-1-sorganov@gmail.com","subject":"[PATCH v3 29/32] doc/diff-generate-patch: mention new --diff-merges option","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-21T15:19:57Z","receivedAt":"2020-12-21T19:12:11Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Mention --diff-merges instead of -m in a note to merge formats to aid\ndiscoverability, as -m is now described among --diff-merges options\nanyway.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n Documentation/diff-generate-patch.txt | 6 +++---\n 1 file changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/Documentation/diff-generate-patch.txt b/Documentation/diff-generate-patch.txt\nindex b10ff4caa6c5..2db8eacc3ec7 100644\n--- a/Documentation/diff-generate-patch.txt\n+++ b/Documentation/diff-generate-patch.txt\n@@ -81,9 +81,9 @@ Combined diff format\n Any diff-generating command can take the `-c` or `--cc` option to\n produce a 'combined diff' when showing a merge. This is the default\n format when showing merges with linkgit:git-diff[1] or\n-linkgit:git-show[1]. Note also that you can give the `-m` option to any\n-of these commands to force generation of diffs with individual parents\n-of a merge.\n+linkgit:git-show[1]. Note also that you can give suitable\n+`--diff-merges` option to any of these commands to force generation of\n+diffs in specific format.\n \n A \"combined diff\" format looks like this:\n \n-- \n2.25.1\n\n"},{"id":"412759","messageId":"20201221152000.13134-2-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201221152000.13134-1-sorganov@gmail.com","subject":"[PATCH v3 01/32] revision: factor out parsing of diff-merge related options","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-21T15:19:29Z","receivedAt":"2020-12-21T19:13:00Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Move all the parsing code related to diffing merges into new\nparse_diff_merge_opts() function.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n revision.c | 67 ++++++++++++++++++++++++++++++++----------------------\n 1 file changed, 40 insertions(+), 27 deletions(-)\n\ndiff --git a/revision.c b/revision.c\nindex aa6221204081..8b17cfd754fe 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -2153,6 +2153,45 @@ static void add_message_grep(struct rev_info *revs, const char *pattern)\n \tadd_grep(revs, pattern, GREP_PATTERN_BODY);\n }\n \n+static int parse_diff_merge_opts(struct rev_info *revs, const char **argv)\n+{\n+\tint argcount = 1;\n+\tconst char *optarg;\n+\tconst char *arg = argv[0];\n+\n+\tif (!strcmp(arg, \"-m\")) {\n+\t\t/*\n+\t\t * To \"diff-index\", \"-m\" means \"match missing\", and to the \"log\"\n+\t\t * family of commands, it means \"show full diff for merges\". Set\n+\t\t * both fields appropriately.\n+\t\t */\n+\t\trevs->ignore_merges = 0;\n+\t\trevs->match_missing = 1;\n+\t} else if (!strcmp(arg, \"-c\")) {\n+\t\trevs->diff = 1;\n+\t\trevs->dense_combined_merges = 0;\n+\t\trevs->combine_merges = 1;\n+\t} else if (!strcmp(arg, \"--cc\")) {\n+\t\trevs->diff = 1;\n+\t\trevs->dense_combined_merges = 1;\n+\t\trevs->combine_merges = 1;\n+\t} else if (!strcmp(arg, \"--no-diff-merges\")) {\n+\t\trevs->ignore_merges = 1;\n+\t} else if (!strcmp(arg, \"--combined-all-paths\")) {\n+\t\trevs->diff = 1;\n+\t\trevs->combined_all_paths = 1;\n+\t} else if ((argcount = parse_long_opt(\"diff-merges\", argv, &optarg))) {\n+\t\tif (!strcmp(optarg, \"off\")) {\n+\t\t\trevs->ignore_merges = 1;\n+\t\t} else {\n+\t\t\tdie(_(\"unknown value for --diff-merges: %s\"), optarg);\n+\t\t}\n+\t} else\n+\t\targcount = 0;\n+\n+\treturn argcount;\n+}\n+\n static int handle_revision_opt(struct rev_info *revs, int argc, const char **argv,\n \t\t\t       int *unkc, const char **unkv,\n \t\t\t       const struct setup_revision_opt* opt)\n@@ -2349,34 +2388,8 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg\n \t\trevs->diff = 1;\n \t\trevs->diffopt.flags.recursive = 1;\n \t\trevs->diffopt.flags.tree_in_recursive = 1;\n-\t} else if (!strcmp(arg, \"-m\")) {\n-\t\t/*\n-\t\t * To \"diff-index\", \"-m\" means \"match missing\", and to the \"log\"\n-\t\t * family of commands, it means \"show full diff for merges\". Set\n-\t\t * both fields appropriately.\n-\t\t */\n-\t\trevs->ignore_merges = 0;\n-\t\trevs->match_missing = 1;\n-\t} else if ((argcount = parse_long_opt(\"diff-merges\", argv, &optarg))) {\n-\t\tif (!strcmp(optarg, \"off\")) {\n-\t\t\trevs->ignore_merges = 1;\n-\t\t} else {\n-\t\t\tdie(_(\"unknown value for --diff-merges: %s\"), optarg);\n-\t\t}\n+\t} else if ((argcount = parse_diff_merge_opts(revs, argv))) {\n \t\treturn argcount;\n-\t} else if (!strcmp(arg, \"--no-diff-merges\")) {\n-\t\trevs->ignore_merges = 1;\n-\t} else if (!strcmp(arg, \"-c\")) {\n-\t\trevs->diff = 1;\n-\t\trevs->dense_combined_merges = 0;\n-\t\trevs->combine_merges = 1;\n-\t} else if (!strcmp(arg, \"--combined-all-paths\")) {\n-\t\trevs->diff = 1;\n-\t\trevs->combined_all_paths = 1;\n-\t} else if (!strcmp(arg, \"--cc\")) {\n-\t\trevs->diff = 1;\n-\t\trevs->dense_combined_merges = 1;\n-\t\trevs->combine_merges = 1;\n \t} else if (!strcmp(arg, \"-v\")) {\n \t\trevs->verbose_header = 1;\n \t} else if (!strcmp(arg, \"--pretty\")) {\n-- \n2.25.1\n\n"},{"id":"412760","messageId":"20201221152000.13134-17-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201221152000.13134-1-sorganov@gmail.com","subject":"[PATCH v3 16/32] t4013: add tests for -m failing to override -c/--cc","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-21T15:19:44Z","receivedAt":"2020-12-21T19:13:01Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Logically, -m, -c, --cc specify 3 different formats for representing\nmerge commits, yet -m doesn't in fact override -c or --cc, that makes\nno sense.\n\nAdd 2 expected to fail tests that demonstrate the problem.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n t/t4013-diff-various.sh            |   2 +\n t/t4013/diff.log_--cc_-m_-p_master | 200 +++++++++++++++++++++++++++++\n t/t4013/diff.log_-c_-m_-p_master   | 200 +++++++++++++++++++++++++++++\n 3 files changed, 402 insertions(+)\n create mode 100644 t/t4013/diff.log_--cc_-m_-p_master\n create mode 100644 t/t4013/diff.log_-c_-m_-p_master\n\ndiff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh\nindex 935d10ac0572..64d9fce44614 100755\n--- a/t/t4013-diff-various.sh\n+++ b/t/t4013-diff-various.sh\n@@ -329,6 +329,8 @@ log --first-parent --diff-merges=off -p master\n log -p --first-parent master\n log -m -p --first-parent master\n log -m -p master\n+:failure log --cc -m -p master\n+:failure log -c -m -p master\n log -SF master\n log -S F master\n log -SF -p master\ndiff --git a/t/t4013/diff.log_--cc_-m_-p_master b/t/t4013/diff.log_--cc_-m_-p_master\nnew file mode 100644\nindex 000000000000..7c217cf348c7\n--- /dev/null\n+++ b/t/t4013/diff.log_--cc_-m_-p_master\n@@ -0,0 +1,200 @@\n+$ git log --cc -m -p master\n+commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (from 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0)\n+Merge: 9a6d494 c7a2ab9\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:04:00 2006 +0000\n+\n+    Merge branch 'side'\n+\n+diff --git a/dir/sub b/dir/sub\n+index cead32e..992913c 100644\n+--- a/dir/sub\n++++ b/dir/sub\n+@@ -4,3 +4,5 @@ C\n+ D\n+ E\n+ F\n++1\n++2\n+diff --git a/file0 b/file0\n+index b414108..10a8a9f 100644\n+--- a/file0\n++++ b/file0\n+@@ -4,3 +4,6 @@\n+ 4\n+ 5\n+ 6\n++A\n++B\n++C\n+\n+commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (from c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a)\n+Merge: 9a6d494 c7a2ab9\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:04:00 2006 +0000\n+\n+    Merge branch 'side'\n+\n+diff --git a/dir/sub b/dir/sub\n+index 7289e35..992913c 100644\n+--- a/dir/sub\n++++ b/dir/sub\n+@@ -1,4 +1,8 @@\n+ A\n+ B\n++C\n++D\n++E\n++F\n+ 1\n+ 2\n+diff --git a/file0 b/file0\n+index f4615da..10a8a9f 100644\n+--- a/file0\n++++ b/file0\n+@@ -1,6 +1,9 @@\n+ 1\n+ 2\n+ 3\n++4\n++5\n++6\n+ A\n+ B\n+ C\n+diff --git a/file1 b/file1\n+new file mode 100644\n+index 0000000..b1e6722\n+--- /dev/null\n++++ b/file1\n+@@ -0,0 +1,3 @@\n++A\n++B\n++C\n+diff --git a/file2 b/file2\n+deleted file mode 100644\n+index 01e79c3..0000000\n+--- a/file2\n++++ /dev/null\n+@@ -1,3 +0,0 @@\n+-1\n+-2\n+-3\n+diff --git a/file3 b/file3\n+deleted file mode 100644\n+index 7289e35..0000000\n+--- a/file3\n++++ /dev/null\n+@@ -1,4 +0,0 @@\n+-A\n+-B\n+-1\n+-2\n+\n+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:03:00 2006 +0000\n+\n+    Side\n+\n+diff --git a/dir/sub b/dir/sub\n+index 35d242b..7289e35 100644\n+--- a/dir/sub\n++++ b/dir/sub\n+@@ -1,2 +1,4 @@\n+ A\n+ B\n++1\n++2\n+diff --git a/file0 b/file0\n+index 01e79c3..f4615da 100644\n+--- a/file0\n++++ b/file0\n+@@ -1,3 +1,6 @@\n+ 1\n+ 2\n+ 3\n++A\n++B\n++C\n+diff --git a/file3 b/file3\n+new file mode 100644\n+index 0000000..7289e35\n+--- /dev/null\n++++ b/file3\n+@@ -0,0 +1,4 @@\n++A\n++B\n++1\n++2\n+\n+commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:02:00 2006 +0000\n+\n+    Third\n+\n+diff --git a/dir/sub b/dir/sub\n+index 8422d40..cead32e 100644\n+--- a/dir/sub\n++++ b/dir/sub\n+@@ -2,3 +2,5 @@ A\n+ B\n+ C\n+ D\n++E\n++F\n+diff --git a/file1 b/file1\n+new file mode 100644\n+index 0000000..b1e6722\n+--- /dev/null\n++++ b/file1\n+@@ -0,0 +1,3 @@\n++A\n++B\n++C\n+\n+commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:01:00 2006 +0000\n+\n+    Second\n+    \n+    This is the second commit.\n+\n+diff --git a/dir/sub b/dir/sub\n+index 35d242b..8422d40 100644\n+--- a/dir/sub\n++++ b/dir/sub\n+@@ -1,2 +1,4 @@\n+ A\n+ B\n++C\n++D\n+diff --git a/file0 b/file0\n+index 01e79c3..b414108 100644\n+--- a/file0\n++++ b/file0\n+@@ -1,3 +1,6 @@\n+ 1\n+ 2\n+ 3\n++4\n++5\n++6\n+diff --git a/file2 b/file2\n+deleted file mode 100644\n+index 01e79c3..0000000\n+--- a/file2\n++++ /dev/null\n+@@ -1,3 +0,0 @@\n+-1\n+-2\n+-3\n+\n+commit 444ac553ac7612cc88969031b02b3767fb8a353a\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:00:00 2006 +0000\n+\n+    Initial\n+$\ndiff --git a/t/t4013/diff.log_-c_-m_-p_master b/t/t4013/diff.log_-c_-m_-p_master\nnew file mode 100644\nindex 000000000000..b660f3d5f28e\n--- /dev/null\n+++ b/t/t4013/diff.log_-c_-m_-p_master\n@@ -0,0 +1,200 @@\n+$ git log -c -m -p master\n+commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (from 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0)\n+Merge: 9a6d494 c7a2ab9\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:04:00 2006 +0000\n+\n+    Merge branch 'side'\n+\n+diff --git a/dir/sub b/dir/sub\n+index cead32e..992913c 100644\n+--- a/dir/sub\n++++ b/dir/sub\n+@@ -4,3 +4,5 @@ C\n+ D\n+ E\n+ F\n++1\n++2\n+diff --git a/file0 b/file0\n+index b414108..10a8a9f 100644\n+--- a/file0\n++++ b/file0\n+@@ -4,3 +4,6 @@\n+ 4\n+ 5\n+ 6\n++A\n++B\n++C\n+\n+commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (from c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a)\n+Merge: 9a6d494 c7a2ab9\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:04:00 2006 +0000\n+\n+    Merge branch 'side'\n+\n+diff --git a/dir/sub b/dir/sub\n+index 7289e35..992913c 100644\n+--- a/dir/sub\n++++ b/dir/sub\n+@@ -1,4 +1,8 @@\n+ A\n+ B\n++C\n++D\n++E\n++F\n+ 1\n+ 2\n+diff --git a/file0 b/file0\n+index f4615da..10a8a9f 100644\n+--- a/file0\n++++ b/file0\n+@@ -1,6 +1,9 @@\n+ 1\n+ 2\n+ 3\n++4\n++5\n++6\n+ A\n+ B\n+ C\n+diff --git a/file1 b/file1\n+new file mode 100644\n+index 0000000..b1e6722\n+--- /dev/null\n++++ b/file1\n+@@ -0,0 +1,3 @@\n++A\n++B\n++C\n+diff --git a/file2 b/file2\n+deleted file mode 100644\n+index 01e79c3..0000000\n+--- a/file2\n++++ /dev/null\n+@@ -1,3 +0,0 @@\n+-1\n+-2\n+-3\n+diff --git a/file3 b/file3\n+deleted file mode 100644\n+index 7289e35..0000000\n+--- a/file3\n++++ /dev/null\n+@@ -1,4 +0,0 @@\n+-A\n+-B\n+-1\n+-2\n+\n+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:03:00 2006 +0000\n+\n+    Side\n+\n+diff --git a/dir/sub b/dir/sub\n+index 35d242b..7289e35 100644\n+--- a/dir/sub\n++++ b/dir/sub\n+@@ -1,2 +1,4 @@\n+ A\n+ B\n++1\n++2\n+diff --git a/file0 b/file0\n+index 01e79c3..f4615da 100644\n+--- a/file0\n++++ b/file0\n+@@ -1,3 +1,6 @@\n+ 1\n+ 2\n+ 3\n++A\n++B\n++C\n+diff --git a/file3 b/file3\n+new file mode 100644\n+index 0000000..7289e35\n+--- /dev/null\n++++ b/file3\n+@@ -0,0 +1,4 @@\n++A\n++B\n++1\n++2\n+\n+commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:02:00 2006 +0000\n+\n+    Third\n+\n+diff --git a/dir/sub b/dir/sub\n+index 8422d40..cead32e 100644\n+--- a/dir/sub\n++++ b/dir/sub\n+@@ -2,3 +2,5 @@ A\n+ B\n+ C\n+ D\n++E\n++F\n+diff --git a/file1 b/file1\n+new file mode 100644\n+index 0000000..b1e6722\n+--- /dev/null\n++++ b/file1\n+@@ -0,0 +1,3 @@\n++A\n++B\n++C\n+\n+commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:01:00 2006 +0000\n+\n+    Second\n+    \n+    This is the second commit.\n+\n+diff --git a/dir/sub b/dir/sub\n+index 35d242b..8422d40 100644\n+--- a/dir/sub\n++++ b/dir/sub\n+@@ -1,2 +1,4 @@\n+ A\n+ B\n++C\n++D\n+diff --git a/file0 b/file0\n+index 01e79c3..b414108 100644\n+--- a/file0\n++++ b/file0\n+@@ -1,3 +1,6 @@\n+ 1\n+ 2\n+ 3\n++4\n++5\n++6\n+diff --git a/file2 b/file2\n+deleted file mode 100644\n+index 01e79c3..0000000\n+--- a/file2\n++++ /dev/null\n+@@ -1,3 +0,0 @@\n+-1\n+-2\n+-3\n+\n+commit 444ac553ac7612cc88969031b02b3767fb8a353a\n+Author: A U Thor <author@example.com>\n+Date:   Mon Jun 26 00:00:00 2006 +0000\n+\n+    Initial\n+$\n-- \n2.25.1\n\n"},{"id":"412761","messageId":"20201221152000.13134-15-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201221152000.13134-1-sorganov@gmail.com","subject":"[PATCH v3 14/32] diff-merges: revise revs->diff flag handling","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-21T15:19:42Z","receivedAt":"2020-12-21T19:16:38Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Do not set revs->diff when we encounter an option that needs it, as\nit'd be impossible to undo later. Besides, some other options than\nwhat we handle here set this flag as well, and we'd interfere with\nthem trying to clear this flag later.\n\nRather set revs->diff, if finally needed, in diff_merges_setup_revs().\n\nAs an additional bonus, this also makes our code shorter.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n diff-merges.c | 4 +---\n 1 file changed, 1 insertion(+), 3 deletions(-)\n\ndiff --git a/diff-merges.c b/diff-merges.c\nindex c48a65f8de64..225edd293b43 100644\n--- a/diff-merges.c\n+++ b/diff-merges.c\n@@ -41,16 +41,13 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv)\n \t\trevs->ignore_merges = 0;\n \t\trevs->match_missing = 1;\n \t} else if (!strcmp(arg, \"-c\")) {\n-\t\trevs->diff = 1;\n \t\trevs->dense_combined_merges = 0;\n \t\trevs->combine_merges = 1;\n \t} else if (!strcmp(arg, \"--cc\")) {\n-\t\trevs->diff = 1;\n \t\tset_dense_combined(revs);\n \t} else if (!strcmp(arg, \"--no-diff-merges\")) {\n \t\tsuppress(revs);\n \t} else if (!strcmp(arg, \"--combined-all-paths\")) {\n-\t\trevs->diff = 1;\n \t\trevs->combined_all_paths = 1;\n \t} else if ((argcount = parse_long_opt(\"diff-merges\", argv, &optarg))) {\n \t\tif (!strcmp(optarg, \"off\")) {\n@@ -103,6 +100,7 @@ void diff_merges_setup_revs(struct rev_info *revs)\n \tif (revs->combined_all_paths && !revs->combine_merges)\n \t\tdie(\"--combined-all-paths makes no sense without -c or --cc\");\n \tif (revs->combine_merges) {\n+\t\trevs->diff = 1;\n \t\t/* Turn --cc/-c into -p --cc/-c when -p was not given */\n \t\tif (!revs->diffopt.output_format)\n \t\t\trevs->diffopt.output_format = DIFF_FORMAT_PATCH;\n-- \n2.25.1\n\n"},{"id":"412762","messageId":"20201221152000.13134-5-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201221152000.13134-1-sorganov@gmail.com","subject":"[PATCH v3 04/32] revision: provide implementation for diff merges tweaks","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-21T15:19:32Z","receivedAt":"2020-12-21T19:18:35Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Use these implementations from show_setup_revisions_tweak() and\nlog_setup_revisions_tweak() in builtin/log.c.\n\nThis completes moving of management of diff merges parameters to a\nsingle place, where we can finally observe them simultaneously.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n builtin/log.c | 13 ++-----------\n revision.c    | 19 +++++++++++++++++++\n revision.h    |  3 +++\n 3 files changed, 24 insertions(+), 11 deletions(-)\n\ndiff --git a/builtin/log.c b/builtin/log.c\nindex 0a7ed4bef92b..717855a49e90 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -598,15 +598,7 @@ static int show_tree_object(const struct object_id *oid,\n static void show_setup_revisions_tweak(struct rev_info *rev,\n \t\t\t\t       struct setup_revision_opt *opt)\n {\n-\tif (rev->ignore_merges < 0) {\n-\t\t/* There was no \"-m\" variant on the command line */\n-\t\trev->ignore_merges = 0;\n-\t\tif (!rev->first_parent_only && !rev->combine_merges) {\n-\t\t\t/* No \"--first-parent\", \"-c\", or \"--cc\" */\n-\t\t\trev->combine_merges = 1;\n-\t\t\trev->dense_combined_merges = 1;\n-\t\t}\n-\t}\n+\trev_diff_merges_default_to_dense_combined(rev);\n \tif (!rev->diffopt.output_format)\n \t\trev->diffopt.output_format = DIFF_FORMAT_PATCH;\n }\n@@ -731,8 +723,7 @@ static void log_setup_revisions_tweak(struct rev_info *rev,\n \tif (!rev->diffopt.output_format && rev->combine_merges)\n \t\trev->diffopt.output_format = DIFF_FORMAT_PATCH;\n \n-\tif (rev->first_parent_only && rev->ignore_merges < 0)\n-\t\trev->ignore_merges = 0;\n+\trev_diff_merges_first_parent_defaults_to_enable(rev);\n }\n \n int cmd_log(int argc, const char **argv, const char *prefix)\ndiff --git a/revision.c b/revision.c\nindex 3250b2d7e112..1c224d276474 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -2209,6 +2209,25 @@ static void setup_diff_merges_revs(struct rev_info *revs)\n \t\tdie(\"--combined-all-paths makes no sense without -c or --cc\");\n }\n \n+void rev_diff_merges_first_parent_defaults_to_enable(struct rev_info *revs)\n+{\n+\tif (revs->first_parent_only && revs->ignore_merges < 0)\n+\t\trevs->ignore_merges = 0;\n+}\n+\n+void rev_diff_merges_default_to_dense_combined(struct rev_info *revs)\n+{\n+\tif (revs->ignore_merges < 0) {\n+\t\t/* There was no \"-m\" variant on the command line */\n+\t\trevs->ignore_merges = 0;\n+\t\tif (!revs->first_parent_only && !revs->combine_merges) {\n+\t\t\t/* No \"--first-parent\", \"-c\", or \"--cc\" */\n+\t\t\trevs->combine_merges = 1;\n+\t\t\trevs->dense_combined_merges = 1;\n+\t\t}\n+\t}\n+}\n+\n static int handle_revision_opt(struct rev_info *revs, int argc, const char **argv,\n \t\t\t       int *unkc, const char **unkv,\n \t\t\t       const struct setup_revision_opt* opt)\ndiff --git a/revision.h b/revision.h\nindex f6bf860d19e5..3dd0229f4edc 100644\n--- a/revision.h\n+++ b/revision.h\n@@ -456,4 +456,7 @@ int rewrite_parents(struct rev_info *revs,\n  */\n struct commit_list *get_saved_parents(struct rev_info *revs, const struct commit *commit);\n \n+void rev_diff_merges_default_to_dense_combined(struct rev_info *revs);\n+void rev_diff_merges_first_parent_defaults_to_enable(struct rev_info *revs);\n+\n #endif\n-- \n2.25.1\n\n"},{"id":"412763","messageId":"20201221152000.13134-11-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201221152000.13134-1-sorganov@gmail.com","subject":"[PATCH v3 10/32] diff-merges: new function diff_merges_suppress()","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-21T15:19:38Z","receivedAt":"2020-12-21T19:19:15Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"This function sets all the relevant flags to disabled state, so that\nno code that checks only one of them get it wrong.\n\nThen we call this new function everywhere where diff merges output\nsuppression is needed.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n builtin/merge.c |  3 ++-\n diff-merges.c   | 17 +++++++++++++++--\n diff-merges.h   |  2 ++\n fmt-merge-msg.c |  3 ++-\n 4 files changed, 21 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/merge.c b/builtin/merge.c\nindex 9d5359edc2f7..1f7b69982b40 100644\n--- a/builtin/merge.c\n+++ b/builtin/merge.c\n@@ -14,6 +14,7 @@\n #include \"lockfile.h\"\n #include \"run-command.h\"\n #include \"diff.h\"\n+#include \"diff-merges.h\"\n #include \"refs.h\"\n #include \"refspec.h\"\n #include \"commit.h\"\n@@ -400,7 +401,7 @@ static void squash_message(struct commit *commit, struct commit_list *remotehead\n \tprintf(_(\"Squash commit -- not updating HEAD\\n\"));\n \n \trepo_init_revisions(the_repository, &rev, NULL);\n-\trev.ignore_merges = 1;\n+\tdiff_merges_suppress(&rev);\n \trev.commit_format = CMIT_FMT_MEDIUM;\n \n \tcommit->object.flags |= UNINTERESTING;\ndiff --git a/diff-merges.c b/diff-merges.c\nindex 8325ab880166..23e6cb11d1ad 100644\n--- a/diff-merges.c\n+++ b/diff-merges.c\n@@ -2,6 +2,14 @@\n \n #include \"revision.h\"\n \n+static void suppress(struct rev_info *revs)\n+{\n+\trevs->ignore_merges = 1;\n+\trevs->first_parent_merges = 0;\n+\trevs->combine_merges = 0;\n+\trevs->dense_combined_merges = 0;\n+}\n+\n /*\n  * Public functions. They are in the order they are called.\n  */\n@@ -34,13 +42,13 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv)\n \t\trevs->dense_combined_merges = 1;\n \t\trevs->combine_merges = 1;\n \t} else if (!strcmp(arg, \"--no-diff-merges\")) {\n-\t\trevs->ignore_merges = 1;\n+\t\tsuppress(revs);\n \t} else if (!strcmp(arg, \"--combined-all-paths\")) {\n \t\trevs->diff = 1;\n \t\trevs->combined_all_paths = 1;\n \t} else if ((argcount = parse_long_opt(\"diff-merges\", argv, &optarg))) {\n \t\tif (!strcmp(optarg, \"off\")) {\n-\t\t\trevs->ignore_merges = 1;\n+\t\t\tsuppress(revs);\n \t\t} else {\n \t\t\tdie(_(\"unknown value for --diff-merges: %s\"), optarg);\n \t\t}\n@@ -50,6 +58,11 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv)\n \treturn argcount;\n }\n \n+void diff_merges_suppress(struct rev_info *revs)\n+{\n+\tsuppress(revs);\n+}\n+\n void diff_merges_default_to_first_parent(struct rev_info *revs)\n {\n \tif (revs->ignore_merges < 0)\t\t/* No -m */\ndiff --git a/diff-merges.h b/diff-merges.h\nindex 243ef915c4cd..a031240576f7 100644\n--- a/diff-merges.h\n+++ b/diff-merges.h\n@@ -13,6 +13,8 @@ void diff_merges_init_revs(struct rev_info *revs);\n \n int diff_merges_parse_opts(struct rev_info *revs, const char **argv);\n \n+void diff_merges_suppress(struct rev_info *revs);\n+\n void diff_merges_default_to_first_parent(struct rev_info *revs);\n \n void diff_merges_default_to_dense_combined(struct rev_info *revs);\ndiff --git a/fmt-merge-msg.c b/fmt-merge-msg.c\nindex bd22e1ea8865..abc3403fb820 100644\n--- a/fmt-merge-msg.c\n+++ b/fmt-merge-msg.c\n@@ -2,6 +2,7 @@\n #include \"refs.h\"\n #include \"object-store.h\"\n #include \"diff.h\"\n+#include \"diff-merges.h\"\n #include \"revision.h\"\n #include \"tag.h\"\n #include \"string-list.h\"\n@@ -668,7 +669,7 @@ int fmt_merge_msg(struct strbuf *in, struct strbuf *out,\n \t\thead = lookup_commit_or_die(&head_oid, \"HEAD\");\n \t\trepo_init_revisions(the_repository, &rev, NULL);\n \t\trev.commit_format = CMIT_FMT_ONELINE;\n-\t\trev.ignore_merges = 1;\n+\t\tdiff_merges_suppress(&rev);\n \t\trev.limited = 1;\n \n \t\tstrbuf_complete_line(out);\n-- \n2.25.1\n\n"},{"id":"412764","messageId":"20201221152000.13134-14-sorganov@gmail.com","threadId":"54550","inReplyTo":"20201221152000.13134-1-sorganov@gmail.com","subject":"[PATCH v3 13/32] diff-merges: handle imply -p on -c/--cc logic for log.c","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-21T15:19:41Z","receivedAt":"2020-12-21T19:19:41Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Move logic that handles implying -p on -c/--cc from\nlog_setup_revisions_tweak() to diff_merges_setup_revs(), where it\nbelongs.\n\nSigned-off-by: Sergey Organov <sorganov@gmail.com>\n---\n builtin/log.c | 4 ----\n diff-merges.c | 5 +++++\n 2 files changed, 5 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/log.c b/builtin/log.c\nindex 63875c3aeec9..c3caf0955b2b 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -723,10 +723,6 @@ static void log_setup_revisions_tweak(struct rev_info *rev,\n \t    rev->prune_data.nr == 1)\n \t\trev->diffopt.flags.follow_renames = 1;\n \n-\t/* Turn --cc/-c into -p --cc/-c when -p was not given */\n-\tif (!rev->diffopt.output_format && rev->combine_merges)\n-\t\trev->diffopt.output_format = DIFF_FORMAT_PATCH;\n-\n \tif (rev->first_parent_only)\n \t\tdiff_merges_default_to_first_parent(rev);\n }\ndiff --git a/diff-merges.c b/diff-merges.c\nindex fb591a933959..c48a65f8de64 100644\n--- a/diff-merges.c\n+++ b/diff-merges.c\n@@ -102,4 +102,9 @@ void diff_merges_setup_revs(struct rev_info *revs)\n \t\trevs->ignore_merges = 1;\n \tif (revs->combined_all_paths && !revs->combine_merges)\n \t\tdie(\"--combined-all-paths makes no sense without -c or --cc\");\n+\tif (revs->combine_merges) {\n+\t\t/* Turn --cc/-c into -p --cc/-c when -p was not given */\n+\t\tif (!revs->diffopt.output_format)\n+\t\t\trevs->diffopt.output_format = DIFF_FORMAT_PATCH;\n+\t}\n }\n-- \n2.25.1\n\n"},{"id":"412768","messageId":"87sg7yrkib.fsf@osv.gnss.ru","threadId":"54550","inReplyTo":"5fe0ec103ad4f_e6ff208f5@natae.notmuch","subject":"Re: [PATCH v3 25/32] diff-merges: let new options enable diff without -p","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2020-12-21T20:07:08Z","receivedAt":"2020-12-21T20:07:53Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Felipe Contreras <felipe.contreras@gmail.com> writes:\n\n> Sergey Organov wrote:\n>> diff --git a/log-tree.c b/log-tree.c\n>> index f9385b1dae6f..9f50a81e537e 100644\n>> --- a/log-tree.c\n>> +++ b/log-tree.c\n>> @@ -899,15 +899,21 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log\n>>  \tint showed_log;\n>>  \tstruct commit_list *parents;\n>>  \tstruct object_id *oid;\n>> +\tint is_merge;\n>> +\tint all_need_diff = opt->diff || opt->diffopt.flags.exit_with_status;\n>>  \n>> -\tif (!opt->diff && !opt->diffopt.flags.exit_with_status)\n>> +\tif (!all_need_diff && !opt->merges_need_diff)\n>>  \t\treturn 0;\n>>  \n>>  \tparse_commit_or_die(commit);\n>>  \toid = get_commit_tree_oid(commit);\n>>  \n>> -\t/* Root commit? */\n>>  \tparents = get_saved_parents(opt, commit);\n>> +\tis_merge = parents && parents->next;\n>> +\tif (!is_merge && !all_need_diff)\n>> +\t\treturn 0;\n>> +\n>> +\t/* Root commit? */\n>>  \tif (!parents) {\n>>  \t\tif (opt->show_root_diff) {\n>>  \t\t\tdiff_root_tree_oid(oid, \"\", &opt->diffopt);\n>\n> FWIW this logic does make sense to me.\n\nThanks for reviewing!\n\n-- Sergey\n"},{"id":"414491","messageId":"xmqqmtx9pdqa.fsf@gitster.c.googlers.com","threadId":"54550","inReplyTo":"20201221152000.13134-1-sorganov@gmail.com","subject":"Re: [PATCH v3 00/32] git-log: implement new --diff-merge options","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-01-16T07:01:17Z","receivedAt":"2021-01-16T07:02:18Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Sergey Organov <sorganov@gmail.com> writes:\n\n> These patch series implement new set of options governing diff output\n> of merge commits, all under the umbrella of single\n> --diff-merges=<mode> option.\n\nThis latest round hasn't seen much review reactions, so I gave it a\nread-thru with fresh eyes.  I didn't spot anything objectionable, so\nlet's start merging it down to 'next'.\n\nThanks.\n\n"},{"id":"414494","messageId":"871rels0ka.fsf@osv.gnss.ru","threadId":"54550","inReplyTo":"xmqqmtx9pdqa.fsf@gitster.c.googlers.com","subject":"Re: [PATCH v3 00/32] git-log: implement new --diff-merge options","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2021-01-16T09:17:25Z","receivedAt":"2021-01-16T09:18:12Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Sergey Organov <sorganov@gmail.com> writes:\n>\n>> These patch series implement new set of options governing diff output\n>> of merge commits, all under the umbrella of single\n>> --diff-merges=<mode> option.\n>\n> This latest round hasn't seen much review reactions, so I gave it a\n> read-thru with fresh eyes.  I didn't spot anything objectionable, so\n> let's start merging it down to 'next'.\n\nThanks, Junio!\n\nIn fact I'm planning to propose a few further improvements on top of\nthis, and wanted to wait till these patches are settled.\n\n-- Sergey Organov\n"}]}