diff mbox series

[2/2] diff-merges: introduce '-d' option

Message ID 20230909125446.142715-3-sorganov@gmail.com (mailing list archive)
State New
Headers show
Series diff-merges: introduce '-d' option | expand

Commit Message

Sergey Organov Sept. 9, 2023, 12:54 p.m. UTC
This option provides a shortcut to request diff with respect to first
parent for any kind of commit, universally. It's implemented as pure
synonym for "--diff-merges=first-parent --patch".

Signed-off-by: Sergey Organov <sorganov@gmail.com>
---
 Documentation/diff-options.txt | 4 ++++
 Documentation/git-log.txt      | 2 +-
 diff-merges.c                  | 3 +++
 t/t4013-diff-various.sh        | 8 ++++++++
 4 files changed, 16 insertions(+), 1 deletion(-)

Comments

Junio C Hamano Sept. 11, 2023, 9:01 p.m. UTC | #1
Sergey Organov <sorganov@gmail.com> writes:

> This option provides a shortcut to request diff with respect to first
> parent for any kind of commit, universally. It's implemented as pure
> synonym for "--diff-merges=first-parent --patch".
>
> Signed-off-by: Sergey Organov <sorganov@gmail.com>
> ---

Sounds very straight-forward.

Given that "--first-parent" in "git log --first-parent -p" already
defeats "-m" and shows the diff against the first parent only,
people may find it confusing if "git log -d" does not act as a
shorthand for that.  From the above and also from the documentation
update, it is hard to tell if that is what you implemented, or it
only affects the "diff-merges" part.

Other than that, the patch looks quite small and to the point.

Thanks.

>  Documentation/diff-options.txt | 4 ++++
>  Documentation/git-log.txt      | 2 +-
>  diff-merges.c                  | 3 +++
>  t/t4013-diff-various.sh        | 8 ++++++++
>  4 files changed, 16 insertions(+), 1 deletion(-)
>
> diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt
> index f93aa3e46a52..d773dafcb10a 100644
> --- a/Documentation/diff-options.txt
> +++ b/Documentation/diff-options.txt
> @@ -51,6 +51,10 @@ ifdef::git-log[]
>  Note: This option not implying `-p` is legacy feature that is
>  preserved for the sake of backward compatibility.
>  
> +-d::
> +	Produce diff with respect to first parent.
> +	Shortcut for '--diff-merges=first-parent -p'.
> +
>  -c::
>  	Produce combined diff output for merge commits.
>  	Shortcut for '--diff-merges=combined -p'.
> diff --git a/Documentation/git-log.txt b/Documentation/git-log.txt
> index 9b7ec96e767a..59bd74a1a596 100644
> --- a/Documentation/git-log.txt
> +++ b/Documentation/git-log.txt
> @@ -120,7 +120,7 @@ By default, `git log` does not generate any diff output. The options
>  below can be used to show the changes made by each commit.
>  
>  Note that unless one of `--diff-merges` variants (including short
> -`-m`, `-c`, and `--cc` options) is explicitly given, merge commits
> +`-d`, `-m`, `-c`, and `--cc` options) is explicitly given, merge commits
>  will not show a diff, even if a diff format like `--patch` is
>  selected, nor will they match search options like `-S`. The exception
>  is when `--first-parent` is in use, in which case `first-parent` is
> diff --git a/diff-merges.c b/diff-merges.c
> index ec97616db1df..6eb72e6fc28a 100644
> --- a/diff-merges.c
> +++ b/diff-merges.c
> @@ -125,6 +125,9 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv)
>  	if (!suppress_m_parsing && !strcmp(arg, "-m")) {
>  		set_to_default(revs);
>  		revs->merges_need_diff = 0;
> +	} else if (!strcmp(arg, "-d")) {
> +		set_first_parent(revs);
> +		revs->merges_imply_patch = 1;
>  	} else if (!strcmp(arg, "-c")) {
>  		set_combined(revs);
>  		revs->merges_imply_patch = 1;
> diff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh
> index 5de1d190759f..a07d6eb6dd97 100755
> --- a/t/t4013-diff-various.sh
> +++ b/t/t4013-diff-various.sh
> @@ -473,6 +473,14 @@ test_expect_success 'log --diff-merges=on matches --diff-merges=separate' '
>  	test_cmp expected actual
>  '
>  
> +test_expect_success 'log -d matches --diff-merges=1 -p' '
> +	git log --diff-merges=1 -p master >result &&
> +	process_diffs result >expected &&
> +	git log -d master >result &&
> +	process_diffs result >actual &&
> +	test_cmp expected actual
> +'
> +
>  test_expect_success 'deny wrong log.diffMerges config' '
>  	test_config log.diffMerges wrong-value &&
>  	test_expect_code 128 git log
Sergey Organov Sept. 12, 2023, 7:59 a.m. UTC | #2
Junio C Hamano <gitster@pobox.com> writes:

> Sergey Organov <sorganov@gmail.com> writes:
>
>> This option provides a shortcut to request diff with respect to first
>> parent for any kind of commit, universally. It's implemented as pure
>> synonym for "--diff-merges=first-parent --patch".
>>
>> Signed-off-by: Sergey Organov <sorganov@gmail.com>
>> ---
>
> Sounds very straight-forward.
>
> Given that "--first-parent" in "git log --first-parent -p" already
> defeats "-m" and shows the diff against the first parent only,
> people may find it confusing if "git log -d" does not act as a
> shorthand for that.

It doesn't, and I believe it's a good thing, as primary function of
--first-parent is to change history traversal rules, and if -d did that,
it would be extremely confusing.

Also, --first-parent is correctly documented as implying
--diff-merges=first-parent, not as defeating -m.

> From the above and also from the documentation update, it is hard to
> tell if that is what you implemented, or it only affects the
> "diff-merges" part.

If we read resulting documentation with a fresh eye, -d is similar to
--cc, and -c, just producing yet another kind of output, so I think all
this fits together quite nicely and shouldn't cause confusion.

>
> Other than that, the patch looks quite small and to the point.

Thanks,
-- Sergey Organov
Junio C Hamano Sept. 14, 2023, 10:17 p.m. UTC | #3
Sergey Organov <sorganov@gmail.com> writes:

>> Sounds very straight-forward.
>>
>> Given that "--first-parent" in "git log --first-parent -p" already
>> defeats "-m" and shows the diff against the first parent only,
>> people may find it confusing if "git log -d" does not act as a
>> shorthand for that.
>
> It doesn't, and I believe it's a good thing, as primary function of
> --first-parent is to change history traversal rules, and if -d did that,
> it would be extremely confusing.

I am not sure about that.

> Also, --first-parent is correctly documented as implying
> --diff-merges=first-parent, not as defeating -m.

Yes, exactly.  That makes me even more convinced that the intuitive
behaviour, when we say "we have this great short-hand option that
lets your 'git log' to do the first-parent thing with patch output",
is to do the first-parent traversal _and_ show first-parent patches.

"-d" is documented as a short-hand for "--diff-merges=first-parent
--patch" and not for "--first-parent --patch", so the behaviour may
correctly match documentation, but that does not make the documented
behaviour an intuitive one.  And a behaviour that is not intuitive
is confusing.

> If we read resulting documentation with a fresh eye, -d is similar to
> --cc, and -c, just producing yet another kind of output, so I think all
> this fits together quite nicely and shouldn't cause confusion.

Another thing is that showing first-parent patch for merges while
letting the traversal also visit the second-parent chain is not as
useful an option as it could be, even though it is not so bad as the
original "-m -p" that also showed second-parent patch for merges as
well.  People would have to say "log --first-parent -p" to get the
first-parent traversal with first-parent patch output, and they
would not behefit from having "-d".
Sergey Organov Sept. 14, 2023, 11:56 p.m. UTC | #4
Junio C Hamano <gitster@pobox.com> writes:

> Sergey Organov <sorganov@gmail.com> writes:
>
>>> Sounds very straight-forward.
>>>
>>> Given that "--first-parent" in "git log --first-parent -p" already
>>> defeats "-m" and shows the diff against the first parent only,
>>> people may find it confusing if "git log -d" does not act as a
>>> shorthand for that.
>>
>> It doesn't, and I believe it's a good thing, as primary function of
>> --first-parent is to change history traversal rules, and if -d did that,
>> it would be extremely confusing.
>
> I am not sure about that.
>
>> Also, --first-parent is correctly documented as implying
>> --diff-merges=first-parent, not as defeating -m.
>
> Yes, exactly.  That makes me even more convinced that the intuitive
> behaviour, when we say "we have this great short-hand option that
> lets your 'git log' to do the first-parent thing with patch output",
> is to do the first-parent traversal _and_ show first-parent patches.
>
> "-d" is documented as a short-hand for "--diff-merges=first-parent
> --patch" and not for "--first-parent --patch", so the behaviour may
> correctly match documentation, but that does not make the documented
> behaviour an intuitive one.  And a behaviour that is not intuitive
> is confusing.

I think both behaviors make sense, provided they are correctly
documented. I just prefer the one that is more basic, yet allows to
achieve things that another one does not.

>
>> If we read resulting documentation with a fresh eye, -d is similar to
>> --cc, and -c, just producing yet another kind of output, so I think all
>> this fits together quite nicely and shouldn't cause confusion.
>
> Another thing is that showing first-parent patch for merges while
> letting the traversal also visit the second-parent chain is not as
> useful an option as it could be, even though it is not so bad as the
> original "-m -p" that also showed second-parent patch for merges as
> well.

I don't see why desire to look at diff-to-first-parent on "side"
branches is any different from desire to look at them on "primary"
branch, sorry, so I still don't want "-d" to affect traversal or other
commit filtering rules. We do have --first-parent as well as a few
others for that.

> People would have to say "log --first-parent -p" to get the
> first-parent traversal with first-parent patch output, and they
> would not behefit from having "-d".

Well, at least they can now say "log --first-parent -d" as well ;)

Honestly, the "log --first-parent -p" (without "-m") suddenly producing
diffs for merge commits is already unnatural, needs yet another
special-casing in documentation, and then, finally, this relatively new
behavior was introduced exactly because there were no "-d" at that time,
to save typing "-m". The latter is yet another example of why "-d" in
its current form is a good idea.

That said, if you feel like there is place for a short-cut for this
particular use-case, it'd be fine with me, say:

--fpd:
  short-cut for "--first-parent -d"

would fit quite nicely into the picture, I think.

Thanks,
-- Sergey Organov
Junio C Hamano Sept. 15, 2023, 5:24 p.m. UTC | #5
Sergey Organov <sorganov@gmail.com> writes:

> I don't see why desire to look at diff-to-first-parent on "side"
> branches is any different from desire to look at them on "primary"
> branch

Yeah, but that is not what I meant.  The above argues for why
"--diff-merges=first-parent" should exist independently from the
"--first-parent" traversal *and* display option.  I am not saying
it should not exist.

But I view that the desire to look at any commits and its changes on
the "side" branch at all *is* at odds with the wish to look at
first-parent change for merge commits.  Once you decide to look at
first-parent change for a merge commit, then every change you see
for each commit on the "side" branch, whether it is shown as
first-parent diff or N pairwise diffs, is what you have already seen
in the change in the merge commit, because "git log" goes newer to
older, and the commits on the side branches appear after the merge
that brings them to the mainline.

Making "log -d" mean "log --diff-merges=first-parent --patch" lets
that less useful combination ("show first-parent patches but
traverse side branches as well") squat on the short and sweet "-d"
that could be used for more useful "log --first-parent --patch",
which would also be more common and intuitive to users, and that is
what I suspect will become problematic in the longer run.

Thanks.
Sergey Organov Sept. 16, 2023, 6:37 p.m. UTC | #6
Junio C Hamano <gitster@pobox.com> writes:

> Sergey Organov <sorganov@gmail.com> writes:
>
>> I don't see why desire to look at diff-to-first-parent on "side"
>> branches is any different from desire to look at them on "primary"
>> branch
>
> Yeah, but that is not what I meant.  The above argues for why
> "--diff-merges=first-parent" should exist independently from the
> "--first-parent" traversal *and* display option.  I am not saying
> it should not exist.

I was not assuming you were saying this, as it has been discussed and
agreed upon when --diff-merges=first-parent was introduced, though I
think I now see your point more clearly.

>
> But I view that the desire to look at any commits and its changes on
> the "side" branch at all *is* at odds with the wish to look at
> first-parent change for merge commits.

I think I do now understand what you mean, yet I have alternative view
on the issue.

> Once you decide to look at first-parent change for a merge commit,
> then every change you see for each commit on the "side" branch,
> whether it is shown as first-parent diff or N pairwise diffs, is what
> you have already seen in the change in the merge commit,

Actually, this happens to be exactly one of intended use-cases for "-d".
It's useful to see how some change introduced by the merge looked in the
context of the original commit, or to figure where the change came from.

> because "git log" goes newer to older, and the commits on the side
> branches appear after the merge that brings them to the mainline.

The exact order is orthogonal to the issue at hands, I think.

> Making "log -d" mean "log --diff-merges=first-parent --patch" lets
> that less useful combination ("show first-parent patches but
> traverse side branches as well") squat on the short and sweet "-d"
> that could be used for more useful "log --first-parent --patch",
> which would also be more common and intuitive to users, and that is
> what I suspect will become problematic in the longer run.

Sorry, "-d ≡ --first-parent --patch" you suggest contradicts my view on
the whole scheme of things, for several reasons:

* I still find it problematic if -d, intended to fit nicely among --cc,
-c, -d, -m, -p, --remerge-diff options, suddenly implies --first-parent.
This would bring yet another inconsistency, and I don't want to be the
one who introduced it.

* In its current state -d conveniently means: "gimme simple diff output
for everything", where --first-parent you suggest doesn't fit at all.

* Current -d implementation is semantically as close to -p as possible,
tweaking exactly one thing compared to -p: the format of output for
merge commits, so is simpler than what you suggest from all angles, as
--first-parent tweaks more than one thing.

* To me what you argue for looks mostly like a desire to have a
short-cut for "--first-parent --patch", and my patch in question does
not seem to contradict this desire, as it'd be very surprising if
somebody came up with the name "-d" for such a short-cut. Definitely not
me.

* Finally, if -d becomes "--patch --first-parent", how do I get back
useful "--patch --diff-merges=first-parent" part of it, provided
--first-parent is unreversable? And even if it were reversable, then

   git log -d --no-first-parent =
   git log --patch --first-parent --no-first-parent =
   git log --patch

is definitely not what is needed, nor frequent demand to revert implied
things indicates optimal design. Compare this to

   git log -d --first-parent

that current -d provides for you to get what you need, and that
unambiguously reads: "gimme *d*iff for all commits while following
*first parent* through the history" (while, unlike, -p not requiring
--first-parent to implicitly tweak diff for merges output).

Overall, after considering your concern, I'd still prefer to leave "-d"
semantics as implemented, consistent with the rest of similar options,
and let somebody else define more shortcuts for their frequent use-cases
if they feel like it.

Thanks,
-- Sergey Organov

P.S. I also figure that maybe our divergence comes from the fact that I
consider merge commits to be primarily commits (introducing particular
set of changes, and then having reference to the source of the changes),
whereas you consider them primarily merges (joining two histories, and
then maybe some artificial changes that make merges "evil"). That's why
we often end up agreeing to disagree, as both these points of view seem
pretty valid.
Junio C Hamano Sept. 26, 2023, 2:50 a.m. UTC | #7
Sergey Organov <sorganov@gmail.com> writes:

> P.S. I also figure that maybe our divergence comes from the fact that I
> consider merge commits to be primarily commits (introducing particular
> set of changes, and then having reference to the source of the changes),
> whereas you consider them primarily merges (joining two histories, and
> then maybe some artificial changes that make merges "evil"). That's why
> we often end up agreeing to disagree, as both these points of view seem
> pretty valid.

It rarely is the case that two opposing world views are equally
valid, though.

If there were an option that forbids any comparison output from a
single parent commit (say --ndfnm "no-diff-for-non-merge"), then
those with "merges are the primary thing, single-parent commits on
the merged branches are implementation details" worldview would be
commonly using "--diff-merges=first-parent --patch --ndfnm" and (1)
viewing only the combined effect of merging side branches without
seeing noise from individual commits whose effects are already shown
in these merges, and (2) traversing the side branches as well, so
that merges from side-side branches into the side branches are
viewable the same way as merges into the mainline.

But because no such option exists and nobody asked for such an
option during the whole lifetime of the project, I highly doubt
that it is a valid world view with wide backing from the users.

Even if it were a valid world view with wide backing, the
combination "--diff-merges=first-parent --patch" would be less than
ideal presentation for them (due to lack of "--ndfnm").  And as I
already said, it would not be useful without --first-parent
traversal for the worldview git has supported.

That is why I find it of dubious value to let short-and-sweet '-d'
be squatted by less than ideal "--diff-merges=first-parent --patch"
combination.  Shorthands are scarse resources, and we want to be
careful before handing them out.

Thanks.
Sergey Organov Sept. 26, 2023, 9:04 a.m. UTC | #8
Junio C Hamano <gitster@pobox.com> writes:

> Sergey Organov <sorganov@gmail.com> writes:
>
>> P.S. I also figure that maybe our divergence comes from the fact that I
>> consider merge commits to be primarily commits (introducing particular
>> set of changes, and then having reference to the source of the changes),
>> whereas you consider them primarily merges (joining two histories, and
>> then maybe some artificial changes that make merges "evil"). That's why
>> we often end up agreeing to disagree, as both these points of view seem
>> pretty valid.
>
> It rarely is the case that two opposing world views are equally
> valid, though.

Yes. In this particular case the two are not opposing though, rather
orthogonal, as they reflect the intrinsic dualism of the concept of
"merge commit". Merge commit is both a new state, and history junction,
neither of which is more or less valid or essential, and I use both
views myself, depending on situation.

An electron is both a particle and a wave, and one just uses its side
that is more convenient for explanation of the case in hand.

I promote features that I routinely need in my workflows, yet respecting
the other side of the coin as well, even though I may rarely find this
other side useful. I mean, for me, this -c/--cc (let alone -m) output is
only confusing, yet I won't be saying that it's somehow less valid than
proposed -d.

> If there were an option that forbids any comparison output from a
> single parent commit (say --ndfnm "no-diff-for-non-merge"),
> then those with "merges are the primary thing, single-parent commits
> on the merged branches are implementation details" worldview would be
> commonly using "--diff-merges=first-parent --patch --ndfnm" and (1)
> viewing only the combined effect of merging side branches without
> seeing noise from individual commits whose effects are already shown
> in these merges, and (2) traversing the side branches as well, so that
> merges from side-side branches into the side branches are viewable the
> same way as merges into the mainline.

No need to ask for a new option, as the behavior you describe is already
there, and is spelled "git log --diff-merges=first-parent"
(--diff-merges=1 for short).

> But because no such option exists and nobody asked for such an
> option during the whole lifetime of the project, I highly doubt
> that it is a valid world view with wide backing from the users.

Your concern above seems to be void, so this doesn't hold either.

As a side-note though, something like this has been asked recently, as
what you describe by --ndfnm should in fact have been what --no-patch
does, but surprisingly does not (please recall recent discussion of this
issue).

> Even if it were a valid world view with wide backing,

Apparently it is valid, otherwise there would be no need for diff to
first parent at all, let alone "git log --first-parent -p" have used it
by default.

> the combination "--diff-merges=first-parent --patch" would be less
> than ideal presentation for them (due to lack of "--ndfnm").

First, as we figured above, --ndfnm is not needed, and second, me, being
one of "them", tries hard to convince you it is the best presentation
"them" can get, while "ideal" simply never exists.

> And as I already said, it would not be useful without --first-parent
> traversal for the worldview git has supported.

Yes, you said it earlier in this thread, and as well I already explained
how it is useful without --first-parent.

> That is why I find it of dubious value to let short-and-sweet '-d'
> be squatted by less than ideal "--diff-merges=first-parent --patch"
> combination.

Hopefully I do understand your concerns, yet I believe
"--diff-merges=first-parent --patch" is way better for "-d" shortcut
than "--first-parent --patch", for the reasons I already explained
earlier in this thread.

> Shorthands are scarse resources, and we want to be careful before
> handing them out.

Yep, agreed.

I believe I carefully thought it over though, weighing all pros and
cons, and thus -d fits nicely among -c and --cc, being yet another
frequently desired format for merges, plays nice with -p as well, and is
very mnemonic, giving us convenient, user-friendly, and consistent user
interface overall.

Thanks,
-- Sergey Organov
Junio C Hamano Sept. 26, 2023, 5:08 p.m. UTC | #9
Sergey Organov <sorganov@gmail.com> writes:

> No need to ask for a new option, as the behavior you describe is already
> there, and is spelled "git log --diff-merges=first-parent"
> (--diff-merges=1 for short).

Ah, that changes things.  

Making "--diff-merges=<how>" only about the presentation of merge
commits, requiring a separate "-p" for single-parent commits [*],
does make the life for those in the "merges are the only interesting
things" camp a lot easier, exactly because the lack of "-p" can be
used to say "I am not interested in chanages by single-parent
commits".

	Side note: I personally think it is a design mistake of
	--diff-merges=<how> (e.g., --cc and --diff-merges=cc do not
	behave the same way) but that is a different story, and it
	is way too late now anyway to "fix" or change.

So "-d" that stands for "--diff-merges=first-parent -p" makes the
more useful (to those who think "merges are the only interesting
things", which I do not belong to) "--diff-merges=first-parent"
(without "-p") less useful.  And the combination is not useful for
those of us who find individual patches plus tweaks by merges
(either --cc or --remerge-diff) are the way to look at the history.

I still do not think that we want to give a short-and-sweet single
letter option for such a combination.

Thanks for clarification.
Sergey Organov Sept. 26, 2023, 8:05 p.m. UTC | #10
Junio C Hamano <gitster@pobox.com> writes:

> Sergey Organov <sorganov@gmail.com> writes:
>
>> No need to ask for a new option, as the behavior you describe is already
>> there, and is spelled "git log --diff-merges=first-parent"
>> (--diff-merges=1 for short).
>
> Ah, that changes things.

Only a tiny bit, unfortunately, as I'm still struggling to finally
convince you (((

>
> Making "--diff-merges=<how>" only about the presentation of merge
> commits, requiring a separate "-p" for single-parent commits [*],
> does make the life for those in the "merges are the only interesting
> things" camp a lot easier, exactly because the lack of "-p" can be
> used to say "I am not interested in chanages by single-parent
> commits".
>
> 	Side note: I personally think it is a design mistake of
> 	--diff-merges=<how> (e.g., --cc and --diff-merges=cc do not
> 	behave the same way) but that is a different story, and it
> 	is way too late now anyway to "fix" or change.

        Side note: This has been considered and agreed upon when
        --diff-merges= options were introduced, and as far as I recall,
        at that time you explicitly agreed it might be useful to be able
        to get output only for merge commits.

        --cc is a simple alias for "--diff-merges=cc --patch" nowadays,
        so yes, they do behave differently, and that's by design. Dunno
        see any design mistake here, as we get all useful variations of
        behavior with a straightforward design, more frequent use-cases
        served by shorter options. Looks fine.

>
> So "-d" that stands for "--diff-merges=first-parent -p" makes the
> more useful (to those who think "merges are the only interesting
> things", which I do not belong to) "--diff-merges=first-parent"
> (without "-p") less useful.  And the combination is not useful for
> those of us who find individual patches plus tweaks by merges
> (either --cc or --remerge-diff) are the way to look at the history.

Yes, you have your --cc, -c, and --remerge-diff (that I'd call something
like --rd probably, but anyway). Could I please have my simple,
straightforward, mnemonic, and terribly useful "-d" as well?

In other words, will I finally be faced with "if you need it, do it
yourself" argument? ;)

> I still do not think that we want to give a short-and-sweet single
> letter option for such a combination.

I have very simple desire: convenient way to tell Git to show me diff to
the first parent for merge commits, as that's the thing I need 99% of
times when I do request diff output at all. That's exactly what I'd have
seen as changes when I was about to commit the merge as well, similar to
any other commit. It's so natural that I can't figure why it looks so
damn rare or unusual to you, and that it makes you argue so hard against
-d, especially when -p, -c, --cc, or even -m, are already there?

I do sympathize your desire to be careful about short options, but what
reservation for "-d" do you still have in mind? It seems that it was
just waiting for me to come and finally bring it to life with the best
meaning possible. How long should I wait for it to remain unused to
finally be able to make use of it?

Thanks,
-- Sergey Organov
diff mbox series

Patch

diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt
index f93aa3e46a52..d773dafcb10a 100644
--- a/Documentation/diff-options.txt
+++ b/Documentation/diff-options.txt
@@ -51,6 +51,10 @@  ifdef::git-log[]
 Note: This option not implying `-p` is legacy feature that is
 preserved for the sake of backward compatibility.
 
+-d::
+	Produce diff with respect to first parent.
+	Shortcut for '--diff-merges=first-parent -p'.
+
 -c::
 	Produce combined diff output for merge commits.
 	Shortcut for '--diff-merges=combined -p'.
diff --git a/Documentation/git-log.txt b/Documentation/git-log.txt
index 9b7ec96e767a..59bd74a1a596 100644
--- a/Documentation/git-log.txt
+++ b/Documentation/git-log.txt
@@ -120,7 +120,7 @@  By default, `git log` does not generate any diff output. The options
 below can be used to show the changes made by each commit.
 
 Note that unless one of `--diff-merges` variants (including short
-`-m`, `-c`, and `--cc` options) is explicitly given, merge commits
+`-d`, `-m`, `-c`, and `--cc` options) is explicitly given, merge commits
 will not show a diff, even if a diff format like `--patch` is
 selected, nor will they match search options like `-S`. The exception
 is when `--first-parent` is in use, in which case `first-parent` is
diff --git a/diff-merges.c b/diff-merges.c
index ec97616db1df..6eb72e6fc28a 100644
--- a/diff-merges.c
+++ b/diff-merges.c
@@ -125,6 +125,9 @@  int diff_merges_parse_opts(struct rev_info *revs, const char **argv)
 	if (!suppress_m_parsing && !strcmp(arg, "-m")) {
 		set_to_default(revs);
 		revs->merges_need_diff = 0;
+	} else if (!strcmp(arg, "-d")) {
+		set_first_parent(revs);
+		revs->merges_imply_patch = 1;
 	} else if (!strcmp(arg, "-c")) {
 		set_combined(revs);
 		revs->merges_imply_patch = 1;
diff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh
index 5de1d190759f..a07d6eb6dd97 100755
--- a/t/t4013-diff-various.sh
+++ b/t/t4013-diff-various.sh
@@ -473,6 +473,14 @@  test_expect_success 'log --diff-merges=on matches --diff-merges=separate' '
 	test_cmp expected actual
 '
 
+test_expect_success 'log -d matches --diff-merges=1 -p' '
+	git log --diff-merges=1 -p master >result &&
+	process_diffs result >expected &&
+	git log -d master >result &&
+	process_diffs result >actual &&
+	test_cmp expected actual
+'
+
 test_expect_success 'deny wrong log.diffMerges config' '
 	test_config log.diffMerges wrong-value &&
 	test_expect_code 128 git log