Usage of git range-diff
regarding filename in inner diffs header (Git 2.23)
The command git range-diff
, that you can see here comparing two patches, has been revisited in Git 2.23 (Q3 2019), for easier identification of which part of what file the patch shown is about.
See commit 499352c, commit 444e096, commit b66885a, commit 430be36, commit e1db263, commit 44b67cb, commit 1ca6922, commit ef283b3, commit 80e1841 (11 Jul 2019), and commit 877a833, commit 570fe99, commit 85c3713, commit d6c88c4, commit 5af4087 (08 Jul 2019) by Thomas Gummerer (tgummerer
).
(Merged by Junio C Hamano -- gitster
-- in commit 43ba21c, 25 Jul 2019)
range-diff
: add filename to inner diff
In a range-diff it's not always clear which file a certain funcname
of
the inner diff belongs to, because the diff header (or section header as added in a previous commit) is not always visible in the range-diff.
Add the filename to the inner diffs header, so it's always visible to
users.
This also allows us to add the filename + the funcname to the outer
diffs hunk headers using a custom userdiff pattern, which will be done
in the next commit.
And:
range-diff
: add headers to the outer hunk header
Add the section headers/hunk headers we introduced in the previous commits to the outer diff's hunk headers.
This makes it easier to understand which change we are actually looking at. For example an outer hunk header might now look like:
@@ Documentation/config/interactive.txt
while previously it would have only been
@@
which doesn't give a lot of context for the change that follows.
See t3206-range-diff.sh
as an example.
And:
range-diff: add section header instead of diff header
Currently range-diff keeps the diff header of the inner diff intact (apart from stripping lines starting with index).
This diff header is somewhat useful, especially when files get different
names in different ranges.
However there is no real need to keep the whole diff header for that.
The main reason we currently do that is probably because it is easy to do.
Introduce a new range diff hunk header, that's enclosed by "##
", similar to how line numbers in diff hunks are enclosed by "@@
", and give human readable information of what exactly happened to the file, including the file name.
This improves the readability of the range-diff by giving more concise
information to the users.
For example if a file was renamed in one iteration, but not in another, the diff of the headers would be quite noisy.
However the diff of a single line is concise and should be easier to understand.
Again, t3206-range-diff.sh
provides an example:
git range-diff --no-color --submodule=log topic...renamed-file >actual &&
sed s/Z/\ /g >expected <<-EOF &&
1: 4de457d = 1: f258d75 s/5/A/
2: fccce22 ! 2: 017b62d s/4/A/
@@ Metadata
ZAuthor: Thomas Rast <[email protected]>
Z
Z ## Commit message ##
- s/4/A/
+ s/4/A/ + rename file
Z
- ## file ##
+ ## file => renamed-file ##
Z@@
Z 1
Z 2
Usage of git range-diff
with diff.noprefix
(Git 2.24)
But: beware of the diff.noprefix
config setting: A git range-diff
would segfault with Git before 2.24 (Q4 2019)!
"git range-diff
" segfaulted when diff.noprefix
configuration was used, as it blindly expected the patch it internally generates to have the standard a/
and b/
prefixes.
The command now forces the internal patch to be built without any prefix, not to be affected by any end-user configuration.
See commit 937b76e (02 Oct 2019) by Johannes Schindelin (dscho
).
(Merged by Junio C Hamano -- gitster
-- in commit 159cdab, 11 Oct 2019)
range-diff: internally force diff.noprefix=true
When parsing the diffs, range-diff
expects to see the prefixes a/
and b/
in the diff headers.
These prefixes can be forced off via the config setting diff.noprefix=true
.
As range-diff
is not prepared for that situation, this will cause a segmentation fault.
Let's avoid that by passing the --no-prefix
option to the git log
process that generates the diffs that range-diff
wants to parse.
And of course expect the output to have no prefixes, then.
And "git range-diff
" failed to handle mode-only change, which has been
corrected with Git 2.24 (Q4 2019):
See commit 2b6a9b1 (08 Oct 2019) by Thomas Gummerer (tgummerer
).
(Merged by Junio C Hamano -- gitster
-- in commit b6d712f, 15 Oct 2019)
range-diff
: don't segfault with mode-only changes
Reported-by: Uwe Kleine-König
Signed-off-by: Thomas Gummerer
Acked-by: Johannes Schindelin
In ef283b3699 ("apply
: make parse_git_diff_header
public", 2019-07-11, Git v2.23.0-rc0 -- merge listed in batch #7) the 'parse_git_diff_header
' function was made public and useable by callers outside of apply.c
.
However it was missed that its (then) only caller, 'find_header
' did some error handling, and completing 'struct patch
' appropriately.
range-diff
then started using this function, and tried to handle this appropriately itself, but fell short in some cases.
This in turn would lead to range-diff
segfaulting when there are mode-only changes in a range.
Move the error handling and completing of the struct into the 'parse_git_diff_header
' function, so other callers can take advantage of it.
This fixes the segfault in 'git range-diff
'.
Usage of git range-diff --notes=<ref>
(Git 2.25)
With Git 2.25 (Q1 2020), "git range-diff
" learned to take the "--notes=<ref>
" and the "--no-notes
" options to control the commit notes included in the log message that gets compared.
See commit 5b583e6, commit bd36191, commit 9f726e1, commit 3bdbdfb, commit 75c5aa0, commit 79f3950, commit 3a6e48e, commit 26d9485 (20 Nov 2019), and commit 9d45ac4, commit 828e829 (19 Nov 2019) by Denton Liu (Denton-L
).
(Merged by Junio C Hamano -- gitster
-- in commit f3c7bfd, 05 Dec 2019)
range-diff
: output ## Notes ##
header
Signed-off-by: Denton Liu
When notes were included in the output of range-diff
, they were just mashed together with the rest of the commit message. As a result, users wouldn't be able to clearly distinguish where the commit message ended and where the notes started.
Output a ## Notes ##
header when notes are detected so that notes can be compared more clearly.
Note that we handle case of Notes (<ref>): -> ## Notes (<ref>) ##
with this code as well. We can't test this in this patch, however, since there is currently no way to pass along different notes refs to git log
. This will be fixed in a future patch.
And:
See commit abcf857, commit f867534, commit 828765d (06 Dec 2019) by Denton Liu (Denton-L
).
(Merged by Junio C Hamano -- gitster
-- in commit d1c0fe8, 16 Dec 2019)
range-diff
: clear other_arg
at end of function
Signed-off-by: Denton Liu
We were leaking memory by not clearing other_arg
after we were done using it.
Clear it after we've finished using it.
Note that this isn't strictly necessary since the memory will be reclaimed once the command exits.
However, since we are releasing the strbufs
, we should also clear other_arg
for consistency.
Usage of git range-diff
using git log
(Git 2.27)
With Git 2.27 (Q2 2020), "git range-diff
" is more robust.
See commit 8d1675e, commit 8cf5156 (15 Apr 2020) by Vasil Dimov (vasild
).
(Merged by Junio C Hamano -- gitster
-- in commit 93d1f19, 28 Apr 2020)
range-diff
: fix a crash in parsing git-log
output
Signed-off-by: Vasil Dimov
git range-diff
calls git log
internally and tries to parse its output.
But git log
output can be customized by the user in their git config
and for certain configurations either an error will be returned by git range-diff
or it will crash.
To fix this explicitly set the output format of the internally executed git log
with --pretty=medium
.
Because that cancels --notes
, add explicitly --notes
at the end.
Also, make sure we never crash in the same way - trying to dereference util
which was never created and has remained NULL
.
It would happen if the first line of git log
output does not begin with 'commit '.
Alternative considered but discarded - somehow disable all git configs and behave as if no config is present in the internally executed git log
, but that does not seem to be possible.
GIT_CONFIG_NOSYSTEM
is the closest to it, but even with that we would still read .git/config
.
Usage of git range-diff --(left|right)-only
(Git 2.31)
With Git 2.31 (Q1 2021), the "git range-diff
"(man) command learned --(left|right)-only
option to show only one side of the compared range.
See commit 1e79f97, commit 3e6046e, commit f1ce6c1 (05 Feb 2021), and commit 5189bb8, commit a2d474a, commit 8c29b49 (04 Feb 2021) by Johannes Schindelin (dscho
).
(Merged by Junio C Hamano -- gitster
-- in commit dadc91f, 17 Feb 2021)
range-diff
: offer --left-only/--right-only options
Signed-off-by: Johannes Schindelin
When comparing commit ranges, one is frequently interested only in one side, such as asking the question "Has this patch that I submitted to the Git mailing list been applied?": one would only care about the part of the output that corresponds to the commits in a local branch.
To make that possible, imitate the git rev-list
(man) options --left-only
and --right-only
.
This addresses gitgitgadget/git
issue 206: "range-diff
: add support for --left-only
and --right-only
"
git range-diff
now includes in its man page:
--left-only
Suppress commits that are missing from the first specified range
(or the "left range" when using the <rev1>...<rev2>
format).
--right-only
Suppress commits that are missing from the second specified range
(or the "right range" when using the <rev1>...<rev2>
format).
Usage of git range-diff
with unterminated lines (Git 2.34)
Git 2.34 (Q4 2021) deals with a corner case of "git range-diff
"(man), regarding unterminated lines.
See commit c4d5907, commit 7c86d36, commit 47ac23d (09 Aug 2021) by Jeff King (peff
).
(Merged by Junio C Hamano -- gitster
-- in commit fb0b14d, 30 Aug 2021)
range-diff
: handle unterminated lines in read_patches()
Signed-off-by: Jeff King
Acked-by: Derrick Stolee
When parsing our buffer of output from git-log
, we have a find_end_of_line()
helper that finds the next newline, and gives us the number of bytes to move past it, or the size of the whole remaining buffer if there is no newline.
But trying to handle both those cases leads to some oddities:
- we try to overwrite the newline with
NUL
in the caller, by writing over line[len-1]
.
This is at best redundant, since the helper will already have done so if it saw a newline.
- But if it didn't see a newline, it's actively wrong; we'll overwrite the byte at the end of the (unterminated) line.
To solve this, the caller needs to know whether we actually found a newline or not.
We could modify find_end_of_line()
to return that information, but we can further observe that it has only one caller.
So let's just inline it in that caller.
Nobody seems to have noticed this case, probably because 'git-log
'(man) would never produce input that does not end with a newline.
Usage of git range-diff --notes
(Git 2.43)
With Git 2.43 (Q4 2023), "git range-diff --notes=foo
"(man) compared log --notes=foo --notes
of the two ranges, instead of using just the specified notes tree.
See commit 2e0d30d (19 Sep 2023) by Kristoffer Haugsbakk (LemmingAvalanche
).
(Merged by Junio C Hamano -- gitster
-- in commit 5cd3f68, 29 Sep 2023)
range-diff
: treat notes like log
Co-authored-by: Johannes Schindelin
Signed-off-by: Kristoffer Haugsbakk
Currently, range-diff
shows the default notes if no notes-related arguments are given.
This is also how log
behaves.
But unlike range-diff
, log
does not show the default notes if --notes=<custom>
are given.
In other words, this:
git log --notes=custom
is equivalent to this:
git log --no-notes --notes=custom
While:
git range-diff --notes=custom
acts like this:
git log --notes --notes-custom
This can't be how the user expects range-diff
to behave given that the man page for range-diff
under --[no-]notes[=<ref>]
says:
This flag is passed to the git log
(man) program (see git-log(1)) that > generates the patches.
This behavior also affects format-patch
since it uses range-diff
for the cover letter.
Unlike log
, though, format-patch
is not supposed to show the default notes if no notes-related arguments are given.1 But this promise is broken when the range-diff happens to have something to say about the changes to the default notes, since that will be shown in the cover letter.
Remedy this by introducing --show-notes-by-default
that range-diff
can use to tell the log
subprocess what to do.
§ Authors
• Fix by Johannes • Tests by Kristoffer
† 1: See e.g. 66b2ed0 (Fix "log" family not to be too agressive about showing notes, 2010-01-20, Git v1.7.0-rc0 -- merge).
pretty-options
now includes in its man page:
--show-notes-by-default
Show the default notes unless options for displaying specific
notes are given.
git range diff
comes with the new--(left|right)-only
options . See my edited answer below. – Picaresque