Can somebody explain the usage of git range-diff?
Asked Answered
D

5

24

Git version 2.19 introduces git range-diff which is supposed to be used in order to compare two commit ranges. I have been reading the documentation, but I cannot get what is the purpose of this new features.

I checked the official Git documentation, and I have trouble understanding its syntax (omitting flags):

git range-diff ( <range1> <range2> | <rev1>...​<rev2> | <base> <rev1> <rev2> )

What is rev1 and rev2?

Could somebody explain when they are useful I mean each case?

Digastric answered 13/9, 2018 at 23:23 Comment(1)
Note: with Git 2.31 (Q1 2021), git range diff comes with the new --(left|right)-only options . See my edited answer below.Picaresque
R
15

I have not actually used them yet, but they are meant as an improvement over the old git cherry* flow for analysing / comparing some upstream or downstream change-set vs what you have now. To make the range-sets useful we want some set of "here are my commits" and "here are theirs", expressed as simply as possible.

A range1 range2 set would be written as, e.g.:

git range-diff theirs~5..theirs ours~4..ours

if you had, e.g.:

          T1--T2--T3--T4--T5   <-- theirs
         /
...--o--*   <-- base
         \
          O1--O2--O3--O4   <-- ours

where the O commits are "ours" and the T commits are "theirs".

Given this exact same configuration, however, we could also write:

git range-diff theirs...ours    # or ours...theirs

(note the three dots). (This is the syntax used with git rev-list --cherry-mark --left-right, for instance.)

Or, again given this same situation, we could write:

git range-diff base theirs ours   # or base ours theirs

Here base is the stop point for both theirs and ours, and avoids having to count back 5.

If the situation is more complicated—as in the graph:

          X1--T1--T2--T3   <-- theirs
         /
...--o--*   <-- base
         \
          Y1--Y2--O1--O2--O3--O4   <-- ours

neither the three-dot nor the base ours theirs kind of syntax quite works, so the two sets of ranges (theirs~3..theirs ours~4..ours) would be best.

Roseboro answered 13/9, 2018 at 23:59 Comment(0)
S
27

Range diff is very useful right after resolving merge conflicts (after rebase, cherry-pick, etc.), especially when you had multiple conflicting commits, and you want to make sure that you haven't accidentally broken something during the process.

Here is a scenario that usually happens in case you are doing multiple commits in a branch.
Let's say we have a branch called "our", and our branch is behind the master branch:

m1-m2-m3-m4  <- "master" branch
  \
   o1-o2-o3  <- "our" current branch

Before rebasing, we do a backup of our branch (just make a copy branch with the name "our_bkp")

git branch our_bkp

Then we initiate rebasing with the master

git rebase master

And solve some of the merge conflicts on the commit "o1"...
Note: If the conflicting files on the "o1" were also used/changed in "o2" or "o3",
then we'll have to re-resolve the same merge conflicts on them as well.

Now, let's say after an exhausting rebase process we have something like this:

             _<- branch "master"
            /
 m1-m2-m3-m4-o1'-o2'-o3'  <- branch "our" (after rebase)
  \
   o1-o2-o3   <- branch "our_bkp"
   

Since there were many merge conflicts, it's not clearly visible whether we've missed something or not.

And this is where the range-diff shines.

To make sure that we haven't missed any change or accidentally damaged anything, we can simply compare our commits from the old version of the branch with the newer version:

git range-diff our_bkp~3..our_bkp our~3..our

or

git range-diff o1..o3 o1'..o3'

If the diffs are only related to the conflicting parts, then we are good, and haven't changed anything other than them.
But if we see some other unexpected diffs, then we or git did something wrong, and we'll need to fix them.

Notes

  • Both of the range-diff commands above are doing exactly the same thing.
  • By saying o1..o3 I mean the numbers of those commits, e.g.: 0277a5883d132bebdb34e35ee228f4382dd2bb7..e415aee3fa53a213dc53ca6a7944301066b72f24
  • The ~3 in our_bkp~3 says git to take the commit that was 3 commits before the last one on our_bkp branch. Replace the number with the amount of the commits you had on your branch and of course don't forget to replace the branch name our_bkp with your backup branch's name.
  • You can consider the range-diff as doing a diff of two diff-s. This way it'll be easier to remember and understand what it's doing.
Sleuth answered 15/4, 2020 at 0:59 Comment(6)
great answer - exactly what i was looking for. i also made a small wrapper script to automate this: github.com/kiprasmel/git-rebase-diffGatehouse
Nice answer. A concrete use-case with enough explanation. The example on the man-page for this command (as of 2.39.0) is a bit too advanced for me.Vav
This is perfect as an extra check before merging very-long-living branches too. Your example and explanation were very easy to understand. Too bad that the official docs for this command aren't that beginner-friendly. You saved my day!Wooldridge
Shouldn't it be git range-diff o1~1..o3 o1'~1..o3' or git range-diff m1..o3 m4..o3'?Dolor
@IulianOnofrei With that command we'd also see the diff between the "parent" commits m1 and m4 which are not about our changes and I guess wouldn't bring some additional value.Sleuth
@JustShadow, But isn't our_bkp~3 the same as m1?Dolor
R
15

I have not actually used them yet, but they are meant as an improvement over the old git cherry* flow for analysing / comparing some upstream or downstream change-set vs what you have now. To make the range-sets useful we want some set of "here are my commits" and "here are theirs", expressed as simply as possible.

A range1 range2 set would be written as, e.g.:

git range-diff theirs~5..theirs ours~4..ours

if you had, e.g.:

          T1--T2--T3--T4--T5   <-- theirs
         /
...--o--*   <-- base
         \
          O1--O2--O3--O4   <-- ours

where the O commits are "ours" and the T commits are "theirs".

Given this exact same configuration, however, we could also write:

git range-diff theirs...ours    # or ours...theirs

(note the three dots). (This is the syntax used with git rev-list --cherry-mark --left-right, for instance.)

Or, again given this same situation, we could write:

git range-diff base theirs ours   # or base ours theirs

Here base is the stop point for both theirs and ours, and avoids having to count back 5.

If the situation is more complicated—as in the graph:

          X1--T1--T2--T3   <-- theirs
         /
...--o--*   <-- base
         \
          Y1--Y2--O1--O2--O3--O4   <-- ours

neither the three-dot nor the base ours theirs kind of syntax quite works, so the two sets of ranges (theirs~3..theirs ours~4..ours) would be best.

Roseboro answered 13/9, 2018 at 23:59 Comment(0)
C
4

A "range" in Git parlance is a pair of revision identifiers (start and end).

The first form of usage for git range-diff is <range1> <range2>. Since we know a range is a pair of revision identifiers, some possible examples are:

abc1234..def5678 9876foo..5432bar
HEAD..def5678 my_release_1_1..my_release_1_2

The other two forms of usage are for convenience when some of the four revision identifiers are the same as each other. Namely:

  1. For a case like abc..def def..abc, you can simply specify def...abc.
  2. For a case like abc..def abc..xyz, you can specify abc def xyz. This seems like a common case to me: you want to compare two ranges which start at the same point.
Cindelyn answered 13/9, 2018 at 23:57 Comment(3)
typo: under 1 you want three dots for the simpler version.Roseboro
@torek: Thanks, fixed. Did you know that since you have 167k rep, you could simply add the missing dot instead of commenting about it?Cindelyn
I prefer to let others edit their own answers, especially for anything potentially technical. For instance maybe you knew something about the range arguments to git range-diff that I don't :)Roseboro
V
3

Just Shadow explained how git-range-diff can be used to check that a rebase went as intended with regards to merge conflicts. torek explained how git-range-diff can be used to compare “ours” and “theirs” pretty generally.

Comparing versions of branches

Say you are working on a feature branch based on main, the main branch. You have two versions of this branch, v1 and v2.

$ git log --oneline v1
a058faf257b6 (v1) WIP Third
2e06d1cb89d0 WIP Second
c38f3355c04f (main) First
$ git log --oneline v2
3d8caecb46fc (HEAD -> v2) Third
b03b2cbb23c9 Second
c38f3355c04f (main) First

Case 1: Only commit messages changed

Compare the two branches:[1]

git range-diff main..v1 main..v2
1:  2e06d1cb89d0 ! 1:  b03b2cbb23c9 WIP Second
    @@ Metadata
     Author: Victor Version Control <[email protected]>

      ## Commit message ##
    -    WIP Second
    +    Second

      ## readme.md ##
     @@
2:  a058faf257b6 ! 2:  3d8caecb46fc WIP Third
    @@ Metadata
     Author: Victor Version Control <[email protected]>

      ## Commit message ##
    -    WIP Third
    +    Third

      ## readme.md ##
     @@

The only thing that changed was that we removed the “WIP” prefix from the commit messages.

Case 2: Email metadata changed

Now the author makes a v3 because he noticed that he used the wrong email in one of the commits.

$ git range-diff main..v2 main..v3
1:  b03b2cbb23c9 = 1:  b03b2cbb23c9 Second
2:  3d8caecb46fc ! 2:  c95c9aee11f5 Third
    @@
      ## Metadata ##
    -Author: Victor Version Control <[email protected]>
    +Author: Victor Version Control <[email protected]>

      ## Commit message ##
         Third

Case 3: The trees (diffs) changed

v4, fixing a bug: commit message said “Third” but change said “Fourth”.

The regular diff between v4 and v3:

$ git diff v4 v3
diff --git a/readme.md b/readme.md
index ab7c514bba87..8ba854c1fe69 100644
--- a/readme.md
+++ b/readme.md
@@ -1,3 +1,3 @@
 First
 Second
-Third
+Fourth

range-diff:

git range-diff main..v4 main..v3
1:  b03b2cbb23c9 = 1:  b03b2cbb23c9 Second
2:  2b91ce078f8a < -:  ------------ Third
-:  ------------ > 2:  c95c9aee11f5 Third

Okay, great. But hold on… where’s the diff for the tree change? Well, as far as I understand it (after googling for two minutes) my change was too “drastic” (due to the triviality of the example); the two commits are completely different, being after all two completely different additions. But we can force a tree diff by using --creation-factor=100:

$ git range-diff --creation-factor=100 main..v4 main..v3
1:  b03b2cbb23c9 = 1:  b03b2cbb23c9 Second
2:  2b91ce078f8a ! 2:  c95c9aee11f5 Third
    @@ readme.md
     @@
      First
      Second
    -+Third
    ++Fourth

But let’s try something slightly more organic:

  1. Create v5 with some lorem-ipsum paragraphs in one commit
  2. Create v6 which is a different commit: amend v6 (not v6 itself but you understand) by changing some words randomly

.

 $ git range-diff main..v5 main..v6
 1:  b03b2cbb23c9 = 1:  b03b2cbb23c9 Second
 2:  2b91ce078f8a = 2:  2b91ce078f8a Third
 3:  d82fd734d258 ! 3:  a0f7f0bf0cee Lorem ipsum
     @@ readme.md
       Third
      +
      +Nullam eu ante vel est convallis dignissim.  Fusce suscipit, wisi nec
     -+facilisis facilisis, est dui fermentum leo, quis tempor ligula erat quis
     ++facilisis facilisis, etc. dui fermentum leo, quis tempor ligula erat quis
      +odio.  Nunc porta vulputate tellus.  Nunc rutrum turpis sed pede.  Sed
      +bibendum.  Aliquam posuere.  Nunc aliquet, augue nec adipiscing
      +interdum, lacus tellus malesuada massa, quis varius mi purus non odio.
     @@ readme.md
      +ornare nulla, non luctus diam neque sit amet urna.  Curabitur vulputate
      +vestibulum lorem.  Fusce sagittis, libero non molestie mollis, magna
      +orci ultrices dolor, at vulputate neque nulla lacinia eros.  Sed id
     -+ligula quis est convallis tempor.  Curabitur lacinia pulvinar nibh.  Nam
     ++ligula quis etc. convallis tempor.  Curabitur lacinia pulvinar nibh.  Nam
      +a sapien.
      +
      +Pellentesque dapibus suscipit ligula.  Donec posuere augue in quam.

Notice the two-level diff (replaced two “est” with “etc.”).

Case 4: One more commit on the newest version

Regular diff:

$ git diff v6 v7
diff --git a/readme.md b/readme.md
index b48a079e18d3..57239ba86643 100644
--- a/readme.md
+++ b/readme.md
@@ -25,3 +25,11 @@ vitae lacus.  Nullam libero mauris, consequat quis, varius et, dictum
 id, arcu.  Mauris mollis tincidunt felis.  Aliquam feugiat tellus ut
 neque.  Nulla facilisis, risus a rhoncus fermentum, tellus tellus
 lacinia purus, et dictum nunc justo sit amet elit.
+
+Lorem ipsum dolor sit amet, consectetuer adipiscing elit.  Donec
+hendrerit tempor tellus.  Donec pretium posuere tellus.  Proin quam
+nisl, tincidunt et, mattis eget, convallis nec, purus.  Cum sociis
+natoque penatibus et magnis dis parturient montes, nascetur ridiculus
+mus.  Nulla posuere.  Donec vitae dolor.  Nullam tristique diam non
+turpis.  Cras placerat accumsan nulla.  Nullam rutrum.  Nam vestibulum
+accumsan nisl.

range-diff:

$ git range-diff main..v6 main..v7
1:  b03b2cbb23c9 = 1:  b03b2cbb23c9 Second
2:  2b91ce078f8a = 2:  2b91ce078f8a Third
3:  a0f7f0bf0cee = 3:  a0f7f0bf0cee Lorem ipsum
-:  ------------ > 4:  568431442120 One more paragraph

Case 5: Different notes (git-notes)

Now we add one more commit to v7 and we add a git-note on the testing namespace:

Bah, couldn’t be bothered. How do you test a readme change?

In v8 we just reword that commit and change the note (the --notes=testing is needed in order to show the notes change):

$ git range-diff --notes=testing main..v7 main..v8
1:  b03b2cbb23c9 = 1:  b03b2cbb23c9 Second
2:  2b91ce078f8a = 2:  2b91ce078f8a Third
3:  a0f7f0bf0cee = 3:  a0f7f0bf0cee Lorem ipsum
4:  568431442120 = 4:  568431442120 One more paragraph
5:  bb816b4f9fbe ! 5:  795df6f46595 Only lorem ipsum + add a paragraph
    @@ Metadata
     Author: Victor Version Control <[email protected]>

      ## Commit message ##
    -    Only lorem ipsum + add a paragraph
    +    Only lorem ipsum


      ## Notes (testing) ##
    -    Bah, couldn’t be bothered. How do you test a readme change?
    +    Ran CI (lorem ipsum linter)!

      ## readme.md ##
     @@

Real-world example from the Git mailing list

Patch series: [PATCH v7 0/9] config API: make "multi" safe, fix segfaults, propagate "ret"

(By Ævar Arnfjörð Bjarmason)

The subject tells us:

  • This is the “cover letter” of the patch series (the email that introduces the series, which consists of the cover letter and one email per patch/commit)
  • This is version 7 of this series

The author notes the differences from version 6:

A larger general overview at v1[1], but note the API changes in
v2[2]. Changes since v6[3]:

 * Glen pointed out that ejecting a commit in v6 orphaned a
   corresponding forward-reference in a commit message, fix that.

And indeed, the provided range-diff output tells us as much:

Range-diff against v6:
 1:  43fdb0cf50c =  1:  9f297a35e14 config tests: cover blind spots in git_die_config() tests
 2:  4b0799090c9 =  2:  45d483066ef config tests: add "NULL" tests for *_get_value_multi()
 3:  62fe2f04e71 !  3:  a977b7b188f config API: add and use a "git_config_get()" family of functions
    @@ Commit message
         "int" instead of "void". Let's leave that for now, and focus on
         the *_get_*() functions.

    -    In a subsequent commit we'll fix the other *_get_*() functions to so
    -    that they'll ferry our underlying "ret" along, rather than normalizing
    -    it to a "return 1". But as an intermediate step to that we'll need to
    -    fix git_configset_get_value_multi() to return "int", and that change
    -    itself is smaller because of this change to migrate some callers away
    -    from the *_value_multi() API.
    -
         1. 3c8687a73ee (add `config_set` API for caching config-like files, 2014-07-28)
         2. https://lore.kernel.org/git/[email protected]/
         3. 1e8697b5c4e (submodule--helper: check repo{_submodule,}_init()
 4:  e36303f4d3d =  4:  3a5a323cd91 versioncmp.c: refactor config reading next commit
 5:  e38523267e7 =  5:  dced12a40d2 config API: have *_multi() return an "int" and take a "dest"
 6:  3a87b35e114 =  6:  d910f7e3a27 for-each-repo: error on bad --config
 7:  66b7060f66f =  7:  57db0fcd91f config API users: test for *_get_value_multi() segfaults
 8:  0da4cdb3f6a =  8:  b374a716555 config API: add "string" version of *_value_multi(), fix segfaults
 9:  627eb15a319 =  9:  6791e1f6f85 for-each-repo: with bad config, don't conflate <path> and <cmd>

† 1: Note that we lose the coloring here, which seems even more important for this kind of diff compared to a regular diff. The experience is better in the terminal with coloring.

Vav answered 5/3, 2023 at 20:3 Comment(0)
P
-5

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.

Picaresque answered 27/7, 2019 at 6:22 Comment(6)
why are you keeping a changelog in this answer?Alcaraz
@Xerus To keep track of the evolution of the git range-diff command.Picaresque
how about a wiki (public through git ^^), emacs org-mode, idk? Is SO your diary? ;)Alcaraz
@Xerus The all idea of Stack Overflow is that it is here to stay. An external wiki can come and go. The goal is to write here permanent information which will always be available. This is the right place to record those evolution, and will help other developers.Picaresque
Make sure to use Git 2.34: fixes a segfault: github.com/git/git/commit/…Picaresque
well yeah, but the changelog does not answer the question and requires me to scroll a lot more just to see other answersAlcaraz

© 2022 - 2024 — McMap. All rights reserved.