Skip to content

Commit

Permalink
Merge branch 'pb/log-first-parent-p-m'
Browse files Browse the repository at this point in the history
* pb/log-first-parent-p-m:
  show --first-parent/-m: do not default to --cc
  show -c: show patch text
  revision: introduce setup_revision_opt
  t4013: add tests for log -p -m --first-parent
  git log -p -m: document -m and honor --first-parent
  • Loading branch information
Junio C Hamano committed Mar 24, 2010
2 parents 954f7cf + 2bf6587 commit 797d443
Show file tree
Hide file tree
Showing 17 changed files with 653 additions and 30 deletions.
3 changes: 2 additions & 1 deletion Documentation/diff-generate-patch.txt
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ combined diff format

"git-diff-tree", "git-diff-files" and "git-diff" can take '-c' or
'--cc' option to produce 'combined diff'. For showing a merge commit
with "git log -p", this is the default format.
with "git log -p", this is the default format; you can force showing
full diff with the '-m' option.
A 'combined diff' format looks like this:

------------
Expand Down
9 changes: 9 additions & 0 deletions Documentation/git-log.txt
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,15 @@ git log master --not --remotes=*/master::
Shows all commits that are in local master but not in any remote
repository master branches.

git log -p -m --first-parent::

Shows the history including change diffs, but only from the
"main branch" perspective, skipping commits that come from merged
branches, and showing full diffs of changes introduced by the merges.
This makes sense only when following a strict policy of merging all
topic branches when staying on a single integration branch.


Discussion
----------

Expand Down
13 changes: 11 additions & 2 deletions Documentation/rev-list-options.txt
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,8 @@ options may be given. See linkgit:git-diff-files[1] for more options.

-c::

This flag changes the way a merge commit is displayed. It shows
the differences from each of the parents to the merge result
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.
Expand All @@ -121,6 +121,15 @@ options may be given. See linkgit:git-diff-files[1] for more options.
the parents have only two variants and the merge result picks
one of them without modification.

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

-r::

Show recursive diffs.
Expand Down
18 changes: 14 additions & 4 deletions builtin/diff-tree.c
Original file line number Diff line number Diff line change
Expand Up @@ -92,20 +92,33 @@ static const char diff_tree_usage[] =
" --root include the initial commit as diff against /dev/null\n"
COMMON_DIFF_OPTIONS_HELP;

static void diff_tree_tweak_rev(struct rev_info *rev, struct setup_revision_opt *opt)
{
if (!rev->diffopt.output_format) {
if (rev->dense_combined_merges)
rev->diffopt.output_format = DIFF_FORMAT_PATCH;
else
rev->diffopt.output_format = DIFF_FORMAT_RAW;
}
}

int cmd_diff_tree(int argc, const char **argv, const char *prefix)
{
int nr_sha1;
char line[1000];
struct object *tree1, *tree2;
static struct rev_info *opt = &log_tree_opt;
struct setup_revision_opt s_r_opt;
int read_stdin = 0;

init_revisions(opt, prefix);
git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
opt->abbrev = 0;
opt->diff = 1;
opt->disable_stdin = 1;
argc = setup_revisions(argc, argv, opt, NULL);
memset(&s_r_opt, 0, sizeof(s_r_opt));
s_r_opt.tweak = diff_tree_tweak_rev;
argc = setup_revisions(argc, argv, opt, &s_r_opt);

while (--argc > 0) {
const char *arg = *++argv;
Expand All @@ -117,9 +130,6 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix)
usage(diff_tree_usage);
}

if (!opt->diffopt.output_format)
opt->diffopt.output_format = DIFF_FORMAT_RAW;

/*
* NOTE! We expect "a ^b" to be equal to "a..b", so we
* reverse the order of the objects if the second one
Expand Down
49 changes: 38 additions & 11 deletions builtin/log.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ static const char * const builtin_log_usage =
" or: git show [options] <object>...";

static void cmd_log_init(int argc, const char **argv, const char *prefix,
struct rev_info *rev)
struct rev_info *rev, struct setup_revision_opt *opt)
{
int i;
int decoration_style = 0;
Expand All @@ -56,7 +56,7 @@ static void cmd_log_init(int argc, const char **argv, const char *prefix,
*/
if (argc == 2 && !strcmp(argv[1], "-h"))
usage(builtin_log_usage);
argc = setup_revisions(argc, argv, rev, "HEAD");
argc = setup_revisions(argc, argv, rev, opt);

if (!rev->show_notes_given && !rev->pretty_given)
rev->show_notes = 1;
Expand Down Expand Up @@ -262,6 +262,7 @@ static int git_log_config(const char *var, const char *value, void *cb)
int cmd_whatchanged(int argc, const char **argv, const char *prefix)
{
struct rev_info rev;
struct setup_revision_opt opt;

git_config(git_log_config, NULL);

Expand All @@ -271,7 +272,9 @@ int cmd_whatchanged(int argc, const char **argv, const char *prefix)
init_revisions(&rev, prefix);
rev.diff = 1;
rev.simplify_history = 0;
cmd_log_init(argc, argv, prefix, &rev);
memset(&opt, 0, sizeof(opt));
opt.def = "HEAD";
cmd_log_init(argc, argv, prefix, &rev, &opt);
if (!rev.diffopt.output_format)
rev.diffopt.output_format = DIFF_FORMAT_RAW;
return cmd_log_walk(&rev);
Expand Down Expand Up @@ -324,10 +327,26 @@ static int show_tree_object(const unsigned char *sha1,
return 0;
}

static void show_rev_tweak_rev(struct rev_info *rev, struct setup_revision_opt *opt)
{
if (rev->ignore_merges) {
/* There was no "-m" on the command line */
rev->ignore_merges = 0;
if (!rev->first_parent_only && !rev->combine_merges) {
/* No "--first-parent", "-c", nor "--cc" */
rev->combine_merges = 1;
rev->dense_combined_merges = 1;
}
}
if (!rev->diffopt.output_format)
rev->diffopt.output_format = DIFF_FORMAT_PATCH;
}

int cmd_show(int argc, const char **argv, const char *prefix)
{
struct rev_info rev;
struct object_array_entry *objects;
struct setup_revision_opt opt;
int i, count, ret = 0;

git_config(git_log_config, NULL);
Expand All @@ -337,12 +356,12 @@ int cmd_show(int argc, const char **argv, const char *prefix)

init_revisions(&rev, prefix);
rev.diff = 1;
rev.combine_merges = 1;
rev.dense_combined_merges = 1;
rev.always_show_header = 1;
rev.ignore_merges = 0;
rev.no_walk = 1;
cmd_log_init(argc, argv, prefix, &rev);
memset(&opt, 0, sizeof(opt));
opt.def = "HEAD";
opt.tweak = show_rev_tweak_rev;
cmd_log_init(argc, argv, prefix, &rev, &opt);

count = rev.pending.nr;
objects = rev.pending.objects;
Expand Down Expand Up @@ -405,6 +424,7 @@ int cmd_show(int argc, const char **argv, const char *prefix)
int cmd_log_reflog(int argc, const char **argv, const char *prefix)
{
struct rev_info rev;
struct setup_revision_opt opt;

git_config(git_log_config, NULL);

Expand All @@ -415,7 +435,9 @@ int cmd_log_reflog(int argc, const char **argv, const char *prefix)
init_reflog_walk(&rev.reflog_info);
rev.abbrev_commit = 1;
rev.verbose_header = 1;
cmd_log_init(argc, argv, prefix, &rev);
memset(&opt, 0, sizeof(opt));
opt.def = "HEAD";
cmd_log_init(argc, argv, prefix, &rev, &opt);

/*
* This means that we override whatever commit format the user gave
Expand All @@ -438,6 +460,7 @@ int cmd_log_reflog(int argc, const char **argv, const char *prefix)
int cmd_log(int argc, const char **argv, const char *prefix)
{
struct rev_info rev;
struct setup_revision_opt opt;

git_config(git_log_config, NULL);

Expand All @@ -446,7 +469,9 @@ int cmd_log(int argc, const char **argv, const char *prefix)

init_revisions(&rev, prefix);
rev.always_show_header = 1;
cmd_log_init(argc, argv, prefix, &rev);
memset(&opt, 0, sizeof(opt));
opt.def = "HEAD";
cmd_log_init(argc, argv, prefix, &rev, &opt);
return cmd_log_walk(&rev);
}

Expand Down Expand Up @@ -902,6 +927,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
struct commit *commit;
struct commit **list = NULL;
struct rev_info rev;
struct setup_revision_opt s_r_opt;
int nr = 0, total, i;
int use_stdout = 0;
int start_number = -1;
Expand Down Expand Up @@ -983,8 +1009,9 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
rev.combine_merges = 0;
rev.ignore_merges = 1;
DIFF_OPT_SET(&rev.diffopt, RECURSIVE);

rev.subject_prefix = fmt_patch_subject_prefix;
memset(&s_r_opt, 0, sizeof(s_r_opt));
s_r_opt.def = "HEAD";

if (default_attach) {
rev.mime_boundary = default_attach;
Expand Down Expand Up @@ -1056,7 +1083,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
if (keep_subject && subject_prefix)
die ("--subject-prefix and -k are mutually exclusive.");

argc = setup_revisions(argc, argv, &rev, "HEAD");
argc = setup_revisions(argc, argv, &rev, &s_r_opt);
if (argc > 1)
die ("unrecognized argument: %s", argv[1]);

Expand Down
5 changes: 4 additions & 1 deletion diff-lib.c
Original file line number Diff line number Diff line change
Expand Up @@ -510,9 +510,12 @@ int do_diff_cache(const unsigned char *tree_sha1, struct diff_options *opt)
int index_differs_from(const char *def, int diff_flags)
{
struct rev_info rev;
struct setup_revision_opt opt;

init_revisions(&rev, NULL);
setup_revisions(0, NULL, &rev, def);
memset(&opt, 0, sizeof(opt));
opt.def = def;
setup_revisions(0, NULL, &rev, &opt);
DIFF_OPT_SET(&rev.diffopt, QUICK);
DIFF_OPT_SET(&rev.diffopt, EXIT_WITH_STATUS);
rev.diffopt.flags |= diff_flags;
Expand Down
10 changes: 10 additions & 0 deletions log-tree.c
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,16 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log
return 0;
else if (opt->combine_merges)
return do_diff_combined(opt, commit);
else if (opt->first_parent_only) {
/*
* Generate merge log entry only for the first
* parent, showing summary diff of the others
* we merged _in_.
*/
diff_tree_sha1(parents->item->object.sha1, sha1, "", &opt->diffopt);
log_tree_diff_flush(opt);
return !opt->loginfo;
}

/* If we show individual diffs, show the parent info */
log->parent = parents->item;
Expand Down
11 changes: 5 additions & 6 deletions revision.c
Original file line number Diff line number Diff line change
Expand Up @@ -1332,7 +1332,7 @@ static void append_prune_data(const char ***prune_data, const char **av)
* Returns the number of arguments left that weren't recognized
* (which are also moved to the head of the argument list)
*/
int setup_revisions(int argc, const char **argv, struct rev_info *revs, const char *def)
int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct setup_revision_opt *opt)
{
int i, flags, left, seen_dashdash, read_from_stdin, got_rev_arg = 0;
const char **prune_data = NULL;
Expand Down Expand Up @@ -1468,7 +1468,9 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
revs->prune_data = get_pathspec(revs->prefix, prune_data);

if (revs->def == NULL)
revs->def = def;
revs->def = opt ? opt->def : NULL;
if (opt && opt->tweak)
opt->tweak(revs, opt);
if (revs->show_merge)
prepare_show_merge(revs);
if (revs->def && !revs->pending.nr && !got_rev_arg) {
Expand Down Expand Up @@ -1502,11 +1504,8 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
if (!revs->full_diff)
diff_tree_setup_paths(revs->prune_data, &revs->diffopt);
}
if (revs->combine_merges) {
if (revs->combine_merges)
revs->ignore_merges = 0;
if (revs->dense_combined_merges && !revs->diffopt.output_format)
revs->diffopt.output_format = DIFF_FORMAT_PATCH;
}
revs->diffopt.abbrev = revs->abbrev;
if (diff_setup_done(&revs->diffopt) < 0)
die("diff_setup_done failed");
Expand Down
7 changes: 6 additions & 1 deletion revision.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,13 @@ struct rev_info {
typedef void (*show_early_output_fn_t)(struct rev_info *, struct commit_list *);
extern volatile show_early_output_fn_t show_early_output;

struct setup_revision_opt {
const char *def;
void (*tweak)(struct rev_info *, struct setup_revision_opt *);
};

extern void init_revisions(struct rev_info *revs, const char *prefix);
extern int setup_revisions(int argc, const char **argv, struct rev_info *revs, const char *def);
extern int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct setup_revision_opt *);
extern void parse_revision_opt(struct rev_info *revs, struct parse_opt_ctx_t *ctx,
const struct option *options,
const char * const usagestr[]);
Expand Down
6 changes: 6 additions & 0 deletions t/t4013-diff-various.sh
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,9 @@ log --root --patch-with-stat --summary master
log --root -c --patch-with-stat --summary master
# improved by Timo's patch
log --root --cc --patch-with-stat --summary master
log -p --first-parent master
log -m -p --first-parent master
log -m -p master
log -SF master
log -SF -p master
log --decorate --all
Expand Down Expand Up @@ -235,6 +238,9 @@ show initial
show --root initial
show side
show master
show -c master
show -m master
show --first-parent master
show --stat side
show --stat --summary side
show --patch-with-stat side
Expand Down
Loading

0 comments on commit 797d443

Please sign in to comment.