Merge branch 'so/log-diff-merge'

"git log" learned a new "--diff-merges=<how>" option.

* so/log-diff-merge: (32 commits)
  t4013: add tests for --diff-merges=first-parent
  doc/git-show: include --diff-merges description
  doc/rev-list-options: document --first-parent changes merges format
  doc/diff-generate-patch: mention new --diff-merges option
  doc/git-log: describe new --diff-merges options
  diff-merges: add '--diff-merges=1' as synonym for 'first-parent'
  diff-merges: add old mnemonic counterparts to --diff-merges
  diff-merges: let new options enable diff without -p
  diff-merges: do not imply -p for new options
  diff-merges: implement new values for --diff-merges
  diff-merges: make -m/-c/--cc explicitly mutually exclusive
  diff-merges: refactor opt settings into separate functions
  diff-merges: get rid of now empty diff_merges_init_revs()
  diff-merges: group diff-merge flags next to each other inside 'rev_info'
  diff-merges: split 'ignore_merges' field
  diff-merges: fix -m to properly override -c/--cc
  t4013: add tests for -m failing to override -c/--cc
  t4013: support test_expect_failure through ':failure' magic
  diff-merges: revise revs->diff flag handling
  diff-merges: handle imply -p on -c/--cc logic for log.c
  ...
This commit is contained in:
Junio C Hamano 2021-02-05 16:40:44 -08:00
commit aac006aa99
21 changed files with 893 additions and 116 deletions

View File

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

View File

@ -33,6 +33,57 @@ endif::git-diff[]
show the patch by default, or to cancel the effect of `--patch`. show the patch by default, or to cancel the effect of `--patch`.
endif::git-format-patch[] endif::git-format-patch[]
ifdef::git-log[]
--diff-merges=(off|none|first-parent|1|separate|m|combined|c|dense-combined|cc)::
--no-diff-merges::
Specify diff format to be used for merge commits. Default is
{diff-merges-default} unless `--first-parent` is in use, in which case
`first-parent` is the default.
+
--diff-merges=(off|none):::
--no-diff-merges:::
Disable output of diffs for merge commits. Useful to override
implied value.
+
--diff-merges=first-parent:::
--diff-merges=1:::
This option makes merge commits show the full diff with
respect to the first parent only.
+
--diff-merges=separate:::
--diff-merges=m:::
-m:::
This makes merge commits show the full diff with respect to
each of the parents. Separate log entry and diff is generated
for each parent. `-m` doesn't produce any output without `-p`.
+
--diff-merges=combined:::
--diff-merges=c:::
-c:::
With this option, diff output for a merge commit shows the
differences from each of the parents to the merge result
simultaneously instead of showing pairwise diff between a
parent and the result one at a time. Furthermore, it lists
only files which were modified from all parents. `-c` implies
`-p`.
+
--diff-merges=dense-combined:::
--diff-merges=cc:::
--cc:::
With this option the output produced by
`--diff-merges=combined` is further compressed by omitting
uninteresting hunks whose contents in the parents have only
two variants and the merge result picks one of them without
modification. `--cc` implies `-p`.
--combined-all-paths::
This flag causes combined diffs (used for merge commits) to
list the name of the file from all parents. It thus only has
effect when `--diff-merges=[dense-]combined` is in use, and
is likely only useful if filename changes are detected (i.e.
when either rename or copy detection have been requested).
endif::git-log[]
-U<n>:: -U<n>::
--unified=<n>:: --unified=<n>::
Generate diffs with <n> lines of context instead of Generate diffs with <n> lines of context instead of

View File

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

View File

@ -45,10 +45,13 @@ include::pretty-options.txt[]
include::pretty-formats.txt[] include::pretty-formats.txt[]
COMMON DIFF OPTIONS DIFF FORMATTING
------------------- ---------------
The options below can be used to change the way `git show` generates
diff output.
:git-log: 1 :git-log: 1
:diff-merges-default: `dense-combined`
include::diff-options.txt[] include::diff-options.txt[]
include::diff-generate-patch.txt[] include::diff-generate-patch.txt[]

View File

@ -130,6 +130,11 @@ parents) and `--max-parents=-1` (negative numbers denote no upper limit).
this option allows you to ignore the individual commits this option allows you to ignore the individual commits
brought in to your history by such a merge. brought in to your history by such a merge.
ifdef::git-log[]
This option also changes default diff format for merge commits
to `first-parent`, see `--diff-merges=first-parent` for details.
endif::git-log[]
--not:: --not::
Reverses the meaning of the '{caret}' prefix (or lack thereof) Reverses the meaning of the '{caret}' prefix (or lack thereof)
for all following revision specifiers, up to the next `--not`. for all following revision specifiers, up to the next `--not`.

View File

@ -860,6 +860,7 @@ LIB_OBJS += date.o
LIB_OBJS += decorate.o LIB_OBJS += decorate.o
LIB_OBJS += delta-islands.o LIB_OBJS += delta-islands.o
LIB_OBJS += diff-delta.o LIB_OBJS += diff-delta.o
LIB_OBJS += diff-merges.o
LIB_OBJS += diff-lib.o LIB_OBJS += diff-lib.o
LIB_OBJS += diff-no-index.o LIB_OBJS += diff-no-index.o
LIB_OBJS += diff.o LIB_OBJS += diff.o

View File

@ -7,6 +7,7 @@
#include "cache.h" #include "cache.h"
#include "config.h" #include "config.h"
#include "diff.h" #include "diff.h"
#include "diff-merges.h"
#include "commit.h" #include "commit.h"
#include "revision.h" #include "revision.h"
#include "builtin.h" #include "builtin.h"
@ -69,9 +70,9 @@ int cmd_diff_files(int argc, const char **argv, const char *prefix)
* was not asked to. "diff-files -c -p" should not densify * was not asked to. "diff-files -c -p" should not densify
* (the user should ask with "diff-files --cc" explicitly). * (the user should ask with "diff-files --cc" explicitly).
*/ */
if (rev.max_count == -1 && !rev.combine_merges && if (rev.max_count == -1 &&
(rev.diffopt.output_format & DIFF_FORMAT_PATCH)) (rev.diffopt.output_format & DIFF_FORMAT_PATCH))
rev.combine_merges = rev.dense_combined_merges = 1; diff_merges_set_dense_combined_if_unset(&rev);
if (read_cache_preload(&rev.diffopt.pathspec) < 0) { if (read_cache_preload(&rev.diffopt.pathspec) < 0) {
perror("read_cache_preload"); perror("read_cache_preload");

View File

@ -13,6 +13,7 @@
#include "blob.h" #include "blob.h"
#include "tag.h" #include "tag.h"
#include "diff.h" #include "diff.h"
#include "diff-merges.h"
#include "diffcore.h" #include "diffcore.h"
#include "revision.h" #include "revision.h"
#include "log-tree.h" #include "log-tree.h"
@ -216,8 +217,8 @@ static int builtin_diff_combined(struct rev_info *revs,
if (argc > 1) if (argc > 1)
usage(builtin_diff_usage); usage(builtin_diff_usage);
if (!revs->dense_combined_merges && !revs->combine_merges) diff_merges_set_dense_combined_if_unset(revs);
revs->dense_combined_merges = revs->combine_merges = 1;
for (i = 1; i < ents; i++) for (i = 1; i < ents; i++)
oid_array_append(&parents, &ent[i].item->oid); oid_array_append(&parents, &ent[i].item->oid);
diff_tree_combined(&ent[0].item->oid, &parents, revs); diff_tree_combined(&ent[0].item->oid, &parents, revs);
@ -265,9 +266,9 @@ static int builtin_diff_files(struct rev_info *revs, int argc, const char **argv
* dense one, --cc can be explicitly asked for, or just rely * dense one, --cc can be explicitly asked for, or just rely
* on the default). * on the default).
*/ */
if (revs->max_count == -1 && !revs->combine_merges && if (revs->max_count == -1 &&
(revs->diffopt.output_format & DIFF_FORMAT_PATCH)) (revs->diffopt.output_format & DIFF_FORMAT_PATCH))
revs->combine_merges = revs->dense_combined_merges = 1; diff_merges_set_dense_combined_if_unset(revs);
setup_work_tree(); setup_work_tree();
if (read_cache_preload(&revs->diffopt.pathspec) < 0) { if (read_cache_preload(&revs->diffopt.pathspec) < 0) {

View File

@ -12,6 +12,7 @@
#include "color.h" #include "color.h"
#include "commit.h" #include "commit.h"
#include "diff.h" #include "diff.h"
#include "diff-merges.h"
#include "revision.h" #include "revision.h"
#include "log-tree.h" #include "log-tree.h"
#include "builtin.h" #include "builtin.h"
@ -607,15 +608,10 @@ static int show_tree_object(const struct object_id *oid,
static void show_setup_revisions_tweak(struct rev_info *rev, static void show_setup_revisions_tweak(struct rev_info *rev,
struct setup_revision_opt *opt) struct setup_revision_opt *opt)
{ {
if (rev->ignore_merges < 0) { if (rev->first_parent_only)
/* There was no "-m" variant on the command line */ diff_merges_default_to_first_parent(rev);
rev->ignore_merges = 0; else
if (!rev->first_parent_only && !rev->combine_merges) { diff_merges_default_to_dense_combined(rev);
/* No "--first-parent", "-c", or "--cc" */
rev->combine_merges = 1;
rev->dense_combined_merges = 1;
}
}
if (!rev->diffopt.output_format) if (!rev->diffopt.output_format)
rev->diffopt.output_format = DIFF_FORMAT_PATCH; rev->diffopt.output_format = DIFF_FORMAT_PATCH;
} }
@ -736,12 +732,8 @@ static void log_setup_revisions_tweak(struct rev_info *rev,
rev->prune_data.nr == 1) rev->prune_data.nr == 1)
rev->diffopt.flags.follow_renames = 1; rev->diffopt.flags.follow_renames = 1;
/* Turn --cc/-c into -p --cc/-c when -p was not given */ if (rev->first_parent_only)
if (!rev->diffopt.output_format && rev->combine_merges) diff_merges_default_to_first_parent(rev);
rev->diffopt.output_format = DIFF_FORMAT_PATCH;
if (rev->first_parent_only && rev->ignore_merges < 0)
rev->ignore_merges = 0;
} }
int cmd_log(int argc, const char **argv, const char *prefix) int cmd_log(int argc, const char **argv, const char *prefix)

View File

@ -14,6 +14,7 @@
#include "lockfile.h" #include "lockfile.h"
#include "run-command.h" #include "run-command.h"
#include "diff.h" #include "diff.h"
#include "diff-merges.h"
#include "refs.h" #include "refs.h"
#include "refspec.h" #include "refspec.h"
#include "commit.h" #include "commit.h"
@ -409,7 +410,7 @@ static void squash_message(struct commit *commit, struct commit_list *remotehead
printf(_("Squash commit -- not updating HEAD\n")); printf(_("Squash commit -- not updating HEAD\n"));
repo_init_revisions(the_repository, &rev, NULL); repo_init_revisions(the_repository, &rev, NULL);
rev.ignore_merges = 1; diff_merges_suppress(&rev);
rev.commit_format = CMIT_FMT_MEDIUM; rev.commit_format = CMIT_FMT_MEDIUM;
commit->object.flags |= UNINTERESTING; commit->object.flags |= UNINTERESTING;

146
diff-merges.c Normal file
View File

@ -0,0 +1,146 @@
#include "diff-merges.h"
#include "revision.h"
static void suppress(struct rev_info *revs)
{
revs->separate_merges = 0;
revs->first_parent_merges = 0;
revs->combine_merges = 0;
revs->dense_combined_merges = 0;
revs->combined_all_paths = 0;
revs->combined_imply_patch = 0;
revs->merges_need_diff = 0;
}
static void set_separate(struct rev_info *revs)
{
suppress(revs);
revs->separate_merges = 1;
}
static void set_first_parent(struct rev_info *revs)
{
set_separate(revs);
revs->first_parent_merges = 1;
}
static void set_m(struct rev_info *revs)
{
/*
* To "diff-index", "-m" means "match missing", and to the "log"
* family of commands, it means "show full diff for merges". Set
* both fields appropriately.
*/
set_separate(revs);
revs->match_missing = 1;
}
static void set_combined(struct rev_info *revs)
{
suppress(revs);
revs->combine_merges = 1;
revs->dense_combined_merges = 0;
}
static void set_dense_combined(struct rev_info *revs)
{
suppress(revs);
revs->combine_merges = 1;
revs->dense_combined_merges = 1;
}
static void set_diff_merges(struct rev_info *revs, const char *optarg)
{
if (!strcmp(optarg, "off") || !strcmp(optarg, "none")) {
suppress(revs);
/* Return early to leave revs->merges_need_diff unset */
return;
}
if (!strcmp(optarg, "1") || !strcmp(optarg, "first-parent"))
set_first_parent(revs);
else if (!strcmp(optarg, "m") || !strcmp(optarg, "separate"))
set_separate(revs);
else if (!strcmp(optarg, "c") || !strcmp(optarg, "combined"))
set_combined(revs);
else if (!strcmp(optarg, "cc") || !strcmp(optarg, "dense-combined"))
set_dense_combined(revs);
else
die(_("unknown value for --diff-merges: %s"), optarg);
/* The flag is cleared by set_xxx() functions, so don't move this up */
revs->merges_need_diff = 1;
}
/*
* Public functions. They are in the order they are called.
*/
int diff_merges_parse_opts(struct rev_info *revs, const char **argv)
{
int argcount = 1;
const char *optarg;
const char *arg = argv[0];
if (!strcmp(arg, "-m")) {
set_m(revs);
} else if (!strcmp(arg, "-c")) {
set_combined(revs);
revs->combined_imply_patch = 1;
} else if (!strcmp(arg, "--cc")) {
set_dense_combined(revs);
revs->combined_imply_patch = 1;
} else if (!strcmp(arg, "--no-diff-merges")) {
suppress(revs);
} else if (!strcmp(arg, "--combined-all-paths")) {
revs->combined_all_paths = 1;
} else if ((argcount = parse_long_opt("diff-merges", argv, &optarg))) {
set_diff_merges(revs, optarg);
} else
return 0;
revs->explicit_diff_merges = 1;
return argcount;
}
void diff_merges_suppress(struct rev_info *revs)
{
suppress(revs);
}
void diff_merges_default_to_first_parent(struct rev_info *revs)
{
if (!revs->explicit_diff_merges)
revs->separate_merges = 1;
if (revs->separate_merges)
revs->first_parent_merges = 1;
}
void diff_merges_default_to_dense_combined(struct rev_info *revs)
{
if (!revs->explicit_diff_merges)
set_dense_combined(revs);
}
void diff_merges_set_dense_combined_if_unset(struct rev_info *revs)
{
if (!revs->combine_merges)
set_dense_combined(revs);
}
void diff_merges_setup_revs(struct rev_info *revs)
{
if (revs->combine_merges == 0)
revs->dense_combined_merges = 0;
if (revs->separate_merges == 0)
revs->first_parent_merges = 0;
if (revs->combined_all_paths && !revs->combine_merges)
die("--combined-all-paths makes no sense without -c or --cc");
if (revs->combined_imply_patch)
revs->diff = 1;
if (revs->combined_imply_patch || revs->merges_need_diff) {
if (!revs->diffopt.output_format)
revs->diffopt.output_format = DIFF_FORMAT_PATCH;
}
}

24
diff-merges.h Normal file
View File

@ -0,0 +1,24 @@
#ifndef DIFF_MERGES_H
#define DIFF_MERGES_H
/*
* diff-merges - utility module to handle command-line options for
* selection of particular diff format of merge commits
* representation.
*/
struct rev_info;
int diff_merges_parse_opts(struct rev_info *revs, const char **argv);
void diff_merges_suppress(struct rev_info *revs);
void diff_merges_default_to_first_parent(struct rev_info *revs);
void diff_merges_default_to_dense_combined(struct rev_info *revs);
void diff_merges_set_dense_combined_if_unset(struct rev_info *revs);
void diff_merges_setup_revs(struct rev_info *revs);
#endif

View File

@ -2,6 +2,7 @@
#include "refs.h" #include "refs.h"
#include "object-store.h" #include "object-store.h"
#include "diff.h" #include "diff.h"
#include "diff-merges.h"
#include "revision.h" #include "revision.h"
#include "tag.h" #include "tag.h"
#include "string-list.h" #include "string-list.h"
@ -670,7 +671,7 @@ int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
head = lookup_commit_or_die(&head_oid, "HEAD"); head = lookup_commit_or_die(&head_oid, "HEAD");
repo_init_revisions(the_repository, &rev, NULL); repo_init_revisions(the_repository, &rev, NULL);
rev.commit_format = CMIT_FMT_ONELINE; rev.commit_format = CMIT_FMT_ONELINE;
rev.ignore_merges = 1; diff_merges_suppress(&rev);
rev.limited = 1; rev.limited = 1;
strbuf_complete_line(out); strbuf_complete_line(out);

View File

@ -899,15 +899,21 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log
int showed_log; int showed_log;
struct commit_list *parents; struct commit_list *parents;
struct object_id *oid; struct object_id *oid;
int is_merge;
int all_need_diff = opt->diff || opt->diffopt.flags.exit_with_status;
if (!opt->diff && !opt->diffopt.flags.exit_with_status) if (!all_need_diff && !opt->merges_need_diff)
return 0; return 0;
parse_commit_or_die(commit); parse_commit_or_die(commit);
oid = get_commit_tree_oid(commit); oid = get_commit_tree_oid(commit);
/* Root commit? */
parents = get_saved_parents(opt, commit); parents = get_saved_parents(opt, commit);
is_merge = parents && parents->next;
if (!is_merge && !all_need_diff)
return 0;
/* Root commit? */
if (!parents) { if (!parents) {
if (opt->show_root_diff) { if (opt->show_root_diff) {
diff_root_tree_oid(oid, "", &opt->diffopt); diff_root_tree_oid(oid, "", &opt->diffopt);
@ -916,16 +922,16 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log
return !opt->loginfo; return !opt->loginfo;
} }
/* More than one parent? */ if (is_merge) {
if (parents->next) { if (opt->combine_merges)
if (opt->ignore_merges)
return 0;
else if (opt->combine_merges)
return do_diff_combined(opt, commit); return do_diff_combined(opt, commit);
else if (!opt->first_parent_only) { if (opt->separate_merges) {
/* If we show multiple diffs, show the parent info */ if (!opt->first_parent_merges) {
log->parent = parents->item; /* Show parent info for multiple diffs */
} log->parent = parents->item;
}
} else
return 0;
} }
showed_log = 0; showed_log = 0;
@ -941,7 +947,7 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log
/* Set up the log info for the next parent, if any.. */ /* Set up the log info for the next parent, if any.. */
parents = parents->next; parents = parents->next;
if (!parents || opt->first_parent_only) if (!parents || opt->first_parent_merges)
break; break;
log->parent = parents->item; log->parent = parents->item;
opt->loginfo = log; opt->loginfo = log;

View File

@ -5,6 +5,7 @@
#include "tree.h" #include "tree.h"
#include "commit.h" #include "commit.h"
#include "diff.h" #include "diff.h"
#include "diff-merges.h"
#include "refs.h" #include "refs.h"
#include "revision.h" #include "revision.h"
#include "repository.h" #include "repository.h"
@ -1808,7 +1809,6 @@ void repo_init_revisions(struct repository *r,
revs->repo = r; revs->repo = r;
revs->abbrev = DEFAULT_ABBREV; revs->abbrev = DEFAULT_ABBREV;
revs->ignore_merges = -1;
revs->simplify_history = 1; revs->simplify_history = 1;
revs->pruning.repo = r; revs->pruning.repo = r;
revs->pruning.flags.recursive = 1; revs->pruning.flags.recursive = 1;
@ -2343,34 +2343,8 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
revs->diff = 1; revs->diff = 1;
revs->diffopt.flags.recursive = 1; revs->diffopt.flags.recursive = 1;
revs->diffopt.flags.tree_in_recursive = 1; revs->diffopt.flags.tree_in_recursive = 1;
} else if (!strcmp(arg, "-m")) { } else if ((argcount = diff_merges_parse_opts(revs, argv))) {
/*
* To "diff-index", "-m" means "match missing", and to the "log"
* family of commands, it means "show full diff for merges". Set
* both fields appropriately.
*/
revs->ignore_merges = 0;
revs->match_missing = 1;
} else if ((argcount = parse_long_opt("diff-merges", argv, &optarg))) {
if (!strcmp(optarg, "off")) {
revs->ignore_merges = 1;
} else {
die(_("unknown value for --diff-merges: %s"), optarg);
}
return argcount; return argcount;
} else if (!strcmp(arg, "--no-diff-merges")) {
revs->ignore_merges = 1;
} else if (!strcmp(arg, "-c")) {
revs->diff = 1;
revs->dense_combined_merges = 0;
revs->combine_merges = 1;
} else if (!strcmp(arg, "--combined-all-paths")) {
revs->diff = 1;
revs->combined_all_paths = 1;
} else if (!strcmp(arg, "--cc")) {
revs->diff = 1;
revs->dense_combined_merges = 1;
revs->combine_merges = 1;
} else if (!strcmp(arg, "-v")) { } else if (!strcmp(arg, "-v")) {
revs->verbose_header = 1; revs->verbose_header = 1;
} else if (!strcmp(arg, "--pretty")) { } else if (!strcmp(arg, "--pretty")) {
@ -2867,12 +2841,8 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
copy_pathspec(&revs->diffopt.pathspec, copy_pathspec(&revs->diffopt.pathspec,
&revs->prune_data); &revs->prune_data);
} }
if (revs->combine_merges && revs->ignore_merges < 0)
revs->ignore_merges = 0; diff_merges_setup_revs(revs);
if (revs->ignore_merges < 0)
revs->ignore_merges = 1;
if (revs->combined_all_paths && !revs->combine_merges)
die("--combined-all-paths makes no sense without -c or --cc");
revs->diffopt.abbrev = revs->abbrev; revs->diffopt.abbrev = revs->abbrev;

View File

@ -191,11 +191,16 @@ struct rev_info {
match_missing:1, match_missing:1,
no_commit_id:1, no_commit_id:1,
verbose_header:1, verbose_header:1,
always_show_header:1,
/* Diff-merge flags */
explicit_diff_merges: 1,
merges_need_diff: 1,
separate_merges: 1,
combine_merges:1, combine_merges:1,
combined_all_paths:1, combined_all_paths:1,
combined_imply_patch:1,
dense_combined_merges:1, dense_combined_merges:1,
always_show_header:1; first_parent_merges:1;
int ignore_merges:2;
/* Format info */ /* Format info */
int show_notes; int show_notes;

View File

@ -178,6 +178,7 @@ process_diffs () {
V=$(git version | sed -e 's/^git version //' -e 's/\./\\./g') V=$(git version | sed -e 's/^git version //' -e 's/\./\\./g')
while read magic cmd while read magic cmd
do do
status=success
case "$magic" in case "$magic" in
'' | '#'*) '' | '#'*)
continue ;; continue ;;
@ -186,6 +187,10 @@ do
label="$magic-$cmd" label="$magic-$cmd"
case "$magic" in case "$magic" in
noellipses) ;; noellipses) ;;
failure)
status=failure
magic=
label="$cmd" ;;
*) *)
BUG "unknown magic $magic" ;; BUG "unknown magic $magic" ;;
esac ;; esac ;;
@ -198,7 +203,7 @@ do
expect="$TEST_DIRECTORY/t4013/diff.$test" expect="$TEST_DIRECTORY/t4013/diff.$test"
actual="$pfx-diff.$test" actual="$pfx-diff.$test"
test_expect_success "git $cmd # magic is ${magic:-(not used)}" ' test_expect_$status "git $cmd # magic is ${magic:-(not used)}" '
{ {
echo "$ git $cmd" echo "$ git $cmd"
case "$magic" in case "$magic" in
@ -326,8 +331,12 @@ log --no-diff-merges -p --first-parent master
log --diff-merges=off -p --first-parent master log --diff-merges=off -p --first-parent master
log --first-parent --diff-merges=off -p master log --first-parent --diff-merges=off -p master
log -p --first-parent master log -p --first-parent master
log -p --diff-merges=first-parent master
log --diff-merges=first-parent master
log -m -p --first-parent master log -m -p --first-parent master
log -m -p master log -m -p master
log --cc -m -p master
log -c -m -p master
log -SF master log -SF master
log -S F master log -S F master
log -SF -p master log -SF -p master

View File

@ -0,0 +1,200 @@
$ git log --cc -m -p master
commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (from 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0)
Merge: 9a6d494 c7a2ab9
Author: A U Thor <author@example.com>
Date: Mon Jun 26 00:04:00 2006 +0000
Merge branch 'side'
diff --git a/dir/sub b/dir/sub
index cead32e..992913c 100644
--- a/dir/sub
+++ b/dir/sub
@@ -4,3 +4,5 @@ C
D
E
F
+1
+2
diff --git a/file0 b/file0
index b414108..10a8a9f 100644
--- a/file0
+++ b/file0
@@ -4,3 +4,6 @@
4
5
6
+A
+B
+C
commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (from c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a)
Merge: 9a6d494 c7a2ab9
Author: A U Thor <author@example.com>
Date: Mon Jun 26 00:04:00 2006 +0000
Merge branch 'side'
diff --git a/dir/sub b/dir/sub
index 7289e35..992913c 100644
--- a/dir/sub
+++ b/dir/sub
@@ -1,4 +1,8 @@
A
B
+C
+D
+E
+F
1
2
diff --git a/file0 b/file0
index f4615da..10a8a9f 100644
--- a/file0
+++ b/file0
@@ -1,6 +1,9 @@
1
2
3
+4
+5
+6
A
B
C
diff --git a/file1 b/file1
new file mode 100644
index 0000000..b1e6722
--- /dev/null
+++ b/file1
@@ -0,0 +1,3 @@
+A
+B
+C
diff --git a/file2 b/file2
deleted file mode 100644
index 01e79c3..0000000
--- a/file2
+++ /dev/null
@@ -1,3 +0,0 @@
-1
-2
-3
diff --git a/file3 b/file3
deleted file mode 100644
index 7289e35..0000000
--- a/file3
+++ /dev/null
@@ -1,4 +0,0 @@
-A
-B
-1
-2
commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a
Author: A U Thor <author@example.com>
Date: Mon Jun 26 00:03:00 2006 +0000
Side
diff --git a/dir/sub b/dir/sub
index 35d242b..7289e35 100644
--- a/dir/sub
+++ b/dir/sub
@@ -1,2 +1,4 @@
A
B
+1
+2
diff --git a/file0 b/file0
index 01e79c3..f4615da 100644
--- a/file0
+++ b/file0
@@ -1,3 +1,6 @@
1
2
3
+A
+B
+C
diff --git a/file3 b/file3
new file mode 100644
index 0000000..7289e35
--- /dev/null
+++ b/file3
@@ -0,0 +1,4 @@
+A
+B
+1
+2
commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0
Author: A U Thor <author@example.com>
Date: Mon Jun 26 00:02:00 2006 +0000
Third
diff --git a/dir/sub b/dir/sub
index 8422d40..cead32e 100644
--- a/dir/sub
+++ b/dir/sub
@@ -2,3 +2,5 @@ A
B
C
D
+E
+F
diff --git a/file1 b/file1
new file mode 100644
index 0000000..b1e6722
--- /dev/null
+++ b/file1
@@ -0,0 +1,3 @@
+A
+B
+C
commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44
Author: A U Thor <author@example.com>
Date: Mon Jun 26 00:01:00 2006 +0000
Second
This is the second commit.
diff --git a/dir/sub b/dir/sub
index 35d242b..8422d40 100644
--- a/dir/sub
+++ b/dir/sub
@@ -1,2 +1,4 @@
A
B
+C
+D
diff --git a/file0 b/file0
index 01e79c3..b414108 100644
--- a/file0
+++ b/file0
@@ -1,3 +1,6 @@
1
2
3
+4
+5
+6
diff --git a/file2 b/file2
deleted file mode 100644
index 01e79c3..0000000
--- a/file2
+++ /dev/null
@@ -1,3 +0,0 @@
-1
-2
-3
commit 444ac553ac7612cc88969031b02b3767fb8a353a
Author: A U Thor <author@example.com>
Date: Mon Jun 26 00:00:00 2006 +0000
Initial
$

View File

@ -0,0 +1,56 @@
$ git log --diff-merges=first-parent master
commit 59d314ad6f356dd08601a4cd5e530381da3e3c64
Merge: 9a6d494 c7a2ab9
Author: A U Thor <author@example.com>
Date: Mon Jun 26 00:04:00 2006 +0000
Merge branch 'side'
diff --git a/dir/sub b/dir/sub
index cead32e..992913c 100644
--- a/dir/sub
+++ b/dir/sub
@@ -4,3 +4,5 @@ C
D
E
F
+1
+2
diff --git a/file0 b/file0
index b414108..10a8a9f 100644
--- a/file0
+++ b/file0
@@ -4,3 +4,6 @@
4
5
6
+A
+B
+C
commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a
Author: A U Thor <author@example.com>
Date: Mon Jun 26 00:03:00 2006 +0000
Side
commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0
Author: A U Thor <author@example.com>
Date: Mon Jun 26 00:02:00 2006 +0000
Third
commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44
Author: A U Thor <author@example.com>
Date: Mon Jun 26 00:01:00 2006 +0000
Second
This is the second commit.
commit 444ac553ac7612cc88969031b02b3767fb8a353a
Author: A U Thor <author@example.com>
Date: Mon Jun 26 00:00:00 2006 +0000
Initial
$

View File

@ -0,0 +1,200 @@
$ git log -c -m -p master
commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (from 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0)
Merge: 9a6d494 c7a2ab9
Author: A U Thor <author@example.com>
Date: Mon Jun 26 00:04:00 2006 +0000
Merge branch 'side'
diff --git a/dir/sub b/dir/sub
index cead32e..992913c 100644
--- a/dir/sub
+++ b/dir/sub
@@ -4,3 +4,5 @@ C
D
E
F
+1
+2
diff --git a/file0 b/file0
index b414108..10a8a9f 100644
--- a/file0
+++ b/file0
@@ -4,3 +4,6 @@
4
5
6
+A
+B
+C
commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (from c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a)
Merge: 9a6d494 c7a2ab9
Author: A U Thor <author@example.com>
Date: Mon Jun 26 00:04:00 2006 +0000
Merge branch 'side'
diff --git a/dir/sub b/dir/sub
index 7289e35..992913c 100644
--- a/dir/sub
+++ b/dir/sub
@@ -1,4 +1,8 @@
A
B
+C
+D
+E
+F
1
2
diff --git a/file0 b/file0
index f4615da..10a8a9f 100644
--- a/file0
+++ b/file0
@@ -1,6 +1,9 @@
1
2
3
+4
+5
+6
A
B
C
diff --git a/file1 b/file1
new file mode 100644
index 0000000..b1e6722
--- /dev/null
+++ b/file1
@@ -0,0 +1,3 @@
+A
+B
+C
diff --git a/file2 b/file2
deleted file mode 100644
index 01e79c3..0000000
--- a/file2
+++ /dev/null
@@ -1,3 +0,0 @@
-1
-2
-3
diff --git a/file3 b/file3
deleted file mode 100644
index 7289e35..0000000
--- a/file3
+++ /dev/null
@@ -1,4 +0,0 @@
-A
-B
-1
-2
commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a
Author: A U Thor <author@example.com>
Date: Mon Jun 26 00:03:00 2006 +0000
Side
diff --git a/dir/sub b/dir/sub
index 35d242b..7289e35 100644
--- a/dir/sub
+++ b/dir/sub
@@ -1,2 +1,4 @@
A
B
+1
+2
diff --git a/file0 b/file0
index 01e79c3..f4615da 100644
--- a/file0
+++ b/file0
@@ -1,3 +1,6 @@
1
2
3
+A
+B
+C
diff --git a/file3 b/file3
new file mode 100644
index 0000000..7289e35
--- /dev/null
+++ b/file3
@@ -0,0 +1,4 @@
+A
+B
+1
+2
commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0
Author: A U Thor <author@example.com>
Date: Mon Jun 26 00:02:00 2006 +0000
Third
diff --git a/dir/sub b/dir/sub
index 8422d40..cead32e 100644
--- a/dir/sub
+++ b/dir/sub
@@ -2,3 +2,5 @@ A
B
C
D
+E
+F
diff --git a/file1 b/file1
new file mode 100644
index 0000000..b1e6722
--- /dev/null
+++ b/file1
@@ -0,0 +1,3 @@
+A
+B
+C
commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44
Author: A U Thor <author@example.com>
Date: Mon Jun 26 00:01:00 2006 +0000
Second
This is the second commit.
diff --git a/dir/sub b/dir/sub
index 35d242b..8422d40 100644
--- a/dir/sub
+++ b/dir/sub
@@ -1,2 +1,4 @@
A
B
+C
+D
diff --git a/file0 b/file0
index 01e79c3..b414108 100644
--- a/file0
+++ b/file0
@@ -1,3 +1,6 @@
1
2
3
+4
+5
+6
diff --git a/file2 b/file2
deleted file mode 100644
index 01e79c3..0000000
--- a/file2
+++ /dev/null
@@ -1,3 +0,0 @@
-1
-2
-3
commit 444ac553ac7612cc88969031b02b3767fb8a353a
Author: A U Thor <author@example.com>
Date: Mon Jun 26 00:00:00 2006 +0000
Initial
$

View File

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