{"thread":{"id":"58336","subject":"`git range-diff` lists chunks with uninteresting changes","startedAt":"2022-08-20T14:52:06Z","lastAt":"2022-08-22T18:48:17Z","messageCount":3,"participants":["squirrel","Johannes Schindelin"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"461659","messageId":"CAAsFbAtu0vYhwa-Kb6dfpNBZ7jSLriVODi1s7H=-Deq9J6L0ww@mail.gmail.com","threadId":"58336","inReplyTo":null,"subject":"`git range-diff` lists chunks with uninteresting changes","fromName":"squirrel","fromEmail":"jatjasjem@gmail.com","sentAt":"2022-08-20T14:51:38Z","receivedAt":"2022-08-20T14:52:06Z","isPatch":false,"sender":{"key":"jatjasjem@gmail.com","avatar":null},"body":"When someone makes a PR, they may be asked to rebase their feature branch onto\nmain to resolve conflicts. It may be useful to quickly see what changed during\nthe rebase, that is how the new version of PR is different to the old one.\n\nIf the PR branch has not been reparented, you may get away with `git diff`.\nBut if it has, `git diff` may contain a lot of changes from upstream. Instead,\n`git range-diff` can be used.\n\nThe problem with this is that in this case `git range-diff` can show chunks\nwith changes that have nothing to do with changes in the PR. Consider this\nrepository (commands are runnable):\n\n    git init\n    git branch -m main\n    echo -e \"a\\nb\\nc\\nd\\ne\\n1\\n2\\n3\\nf\" > file\n    git add file\n    git commit -am \"a b c d e f\"\n\n    git checkout -b foo\n    echo -e \"a\\nb\\nc\\nd\\ne\\n1\\n2\\n3\\nfoo\" > file\n    git commit -am \"f -> foo\"\n\n    git checkout main\n    git checkout -b cat\n    echo -e \"a\\nb\\ncat\\nd\\ne\\n1\\n2\\n3\\nf\" > file\n    git commit -am \"c -> cat\"\n\nWe got a few letters of alphabet on separate lines on main, and in branch\nfoo `f` is changed to `foo`, and in branch cat `c` is changed to `cat`.\n\n    $ git log --all --graph --pretty=oneline\n    * 90e873e3 (HEAD -> cat) c -> cat\n    | * 3d8c1baf (foo) f -> foo\n    |/\n    * 4d2337dd (main) a b c d e f\n\nNow, still on cat, let's combine the two changes.\n\n    $ git rebase foo\n    Successfully rebased and updated refs/heads/cat\n\n    $ git log --all --graph --pretty=oneline\n    * 98e554a0 (HEAD -> cat) c -> cat\n    * 3d8c1baf (foo) f -> foo\n    * 4d2337dd (main) a b c d e f\n\nNow, `git rebase foo` worked automatically, so *the change* of the last commit\non `cat` is the same as it was without rebase, which is changing `c` to `cat`.\nBut if we run `git range-diff`, we will see this:\n\n    $ git range-diff 90e873e3...cat\n    -:  ------- > 1:  3d8c1ba f -> foo\n    1:  90e873e ! 2:  98e554a c -> cat\n        @@ file\n         +cat\n          d\n          e\n        - f\n        + foo\n\nIt seems that this chunk is included for the sole reason that the change from\n`foo` is sort of close. If we try the same code, but put the lines `c` and `f`\nfurther apart, for example by replacing `e\\n` with `e\\n1\\n2\\n3\\n` in the\ncommands above, the output would be, as expected,\n\n    $ git range-diff f1e0a6cc3...cat\n    -:  ------- > 1:  4db06be f -> foo\n    1:  f1e0a6c = 2:  cc56db7 c -> cat\n\nI suggest not showing uninteresting chunks like that, or perhaps having a\ncommand line option that controls how close together the changes must be in\norder to be included in the output.\n"},{"id":"461771","messageId":"252qppor-o3pp-s13o-q59r-9166478no04r@tzk.qr","threadId":"58336","inReplyTo":"CAAsFbAtu0vYhwa-Kb6dfpNBZ7jSLriVODi1s7H=-Deq9J6L0ww@mail.gmail.com","subject":"Re: `git range-diff` lists chunks with uninteresting changes","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2022-08-22T16:02:35Z","receivedAt":"2022-08-22T16:02:47Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi squirrel,\n\nOn Sat, 20 Aug 2022, squirrel wrote:\n\n> When someone makes a PR, they may be asked to rebase their feature branch onto\n> main to resolve conflicts. It may be useful to quickly see what changed during\n> the rebase, that is how the new version of PR is different to the old one.\n>\n> If the PR branch has not been reparented, you may get away with `git diff`.\n> But if it has, `git diff` may contain a lot of changes from upstream. Instead,\n> `git range-diff` can be used.\n>\n> The problem with this is that in this case `git range-diff` can show chunks\n> with changes that have nothing to do with changes in the PR. Consider this\n> repository (commands are runnable):\n>\n>     git init\n>     git branch -m main\n>     echo -e \"a\\nb\\nc\\nd\\ne\\n1\\n2\\n3\\nf\" > file\n>     git add file\n>     git commit -am \"a b c d e f\"\n>\n>     git checkout -b foo\n>     echo -e \"a\\nb\\nc\\nd\\ne\\n1\\n2\\n3\\nfoo\" > file\n>     git commit -am \"f -> foo\"\n>\n>     git checkout main\n>     git checkout -b cat\n>     echo -e \"a\\nb\\ncat\\nd\\ne\\n1\\n2\\n3\\nf\" > file\n>     git commit -am \"c -> cat\"\n>\n> We got a few letters of alphabet on separate lines on main, and in branch\n> foo `f` is changed to `foo`, and in branch cat `c` is changed to `cat`.\n>\n>     $ git log --all --graph --pretty=oneline\n>     * 90e873e3 (HEAD -> cat) c -> cat\n>     | * 3d8c1baf (foo) f -> foo\n>     |/\n>     * 4d2337dd (main) a b c d e f\n>\n> Now, still on cat, let's combine the two changes.\n>\n>     $ git rebase foo\n>     Successfully rebased and updated refs/heads/cat\n>\n>     $ git log --all --graph --pretty=oneline\n>     * 98e554a0 (HEAD -> cat) c -> cat\n>     * 3d8c1baf (foo) f -> foo\n>     * 4d2337dd (main) a b c d e f\n>\n> Now, `git rebase foo` worked automatically, so *the change* of the last commit\n> on `cat` is the same as it was without rebase, which is changing `c` to `cat`.\n> But if we run `git range-diff`, we will see this:\n>\n>     $ git range-diff 90e873e3...cat\n>     -:  ------- > 1:  3d8c1ba f -> foo\n>     1:  90e873e ! 2:  98e554a c -> cat\n>         @@ file\n>          +cat\n>           d\n>           e\n>         - f\n>         + foo\n>\n> It seems that this chunk is included for the sole reason that the change from\n> `foo` is sort of close. If we try the same code, but put the lines `c` and `f`\n> further apart, for example by replacing `e\\n` with `e\\n1\\n2\\n3\\n` in the\n> commands above, the output would be, as expected,\n>\n>     $ git range-diff f1e0a6cc3...cat\n>     -:  ------- > 1:  4db06be f -> foo\n>     1:  f1e0a6c = 2:  cc56db7 c -> cat\n>\n> I suggest not showing uninteresting chunks like that, or perhaps having a\n> command line option that controls how close together the changes must be in\n> order to be included in the output.\n\nIn a generic tool like `range-diff`, it is virtually guaranteed that the\ndefault operation does not satisfy all use cases. This example\ndemonstrates that ;-)\n\nIn general, the `A...B` form does what users want, namely show you pairs\nbetween the \"left\" and the \"right\" commits in that symmetric range.\n\nHowever, you _can_ use `range-diff` in a way that it produces what you\nwant. In the example you provided above, `git range-diff foo cat@{1} cat`\nshould do it. That would be the `<upstream> <before> <after>` form.\n\nIn general, you might need to play with `git merge-base --fork-point` (see\n*1* for more information). I could imagine that the following command\nmight give you what you want in even more cases:\n\n\tgit range-diff \\\n\t\t$(git merge-base --fork-point @{u} @{1})..@{1} \\\n\t\t$(git merge-base --fork-point @{u} HEAD)..HEAD\n\nCiao,\nJohannes\n\nFootnote *1*: https://git-scm.com/docs/git-merge-base#_discussion_on_fork_point_mode\n"},{"id":"461792","messageId":"CAAsFbAsD_AwyO1KM2G10Gs8fWzErsXQUx2My2RdfmN6WefU4EA@mail.gmail.com","threadId":"58336","inReplyTo":"252qppor-o3pp-s13o-q59r-9166478no04r@tzk.qr","subject":"Re: `git range-diff` lists chunks with uninteresting changes","fromName":"squirrel","fromEmail":"jatjasjem@gmail.com","sentAt":"2022-08-22T18:47:02Z","receivedAt":"2022-08-22T18:48:17Z","isPatch":false,"sender":{"key":"jatjasjem@gmail.com","avatar":null},"body":"Oh boy I messed up. There's a mistake in my reproduction example. Sorry!\n\nI was saying that the uninteresting chunks pop if the changes from upstream\nappear close to changes in feature branch. To demonstrate the case when they\nare not close, I said to add a few lines, `1\\n2\\n3\\n`, to the initial file.\nSomehow I managed to include this `1\\n2\\n3\\n` in the main example that was\nsupposed to demonstrate the issue. The correct, copy-pasteable, example:\n\n    git init\n    git branch -m main\n    echo -e \"a\\nb\\nc\\nd\\ne\\nf\" > file\n    git add file\n    git commit -am \"a b c d e f\"\n    git checkout -b foo\n    echo -e \"a\\nb\\nc\\nd\\ne\\nfoo\" > file\n    git commit -am \"f -> foo\"\n    git checkout main\n    git checkout -b cat\n    echo -e \"a\\nb\\ncat\\nd\\ne\\nf\" > file\n    git commit -am \"c -> cat\"\n    git rebase foo\n    git range-diff foo cat@{1} cat\n\nNow if I was to use the command that you give:\n\n    $ git range-diff foo cat@{1} cat\n    1:  5b1a2f5 ! 1:  16c4eea c -> cat\n        @@ file\n         +cat\n          d\n          e\n        - f\n        + foo\n\nI think the command and the result are both correct. Indeed the change of\n`f` to `foo` is a difference between the two ranges. However, this change\nis just not interesting! I hope there's a way to not see it.\n\nSorry about the mess up.\n\nOn Mon, 22 Aug 2022 at 17:02, Johannes Schindelin\n<Johannes.Schindelin@gmx.de> wrote:\n>\n> Hi squirrel,\n>\n> On Sat, 20 Aug 2022, squirrel wrote:\n>\n> > When someone makes a PR, they may be asked to rebase their feature branch onto\n> > main to resolve conflicts. It may be useful to quickly see what changed during\n> > the rebase, that is how the new version of PR is different to the old one.\n> >\n> > If the PR branch has not been reparented, you may get away with `git diff`.\n> > But if it has, `git diff` may contain a lot of changes from upstream. Instead,\n> > `git range-diff` can be used.\n> >\n> > The problem with this is that in this case `git range-diff` can show chunks\n> > with changes that have nothing to do with changes in the PR. Consider this\n> > repository (commands are runnable):\n> >\n> >     git init\n> >     git branch -m main\n> >     echo -e \"a\\nb\\nc\\nd\\ne\\n1\\n2\\n3\\nf\" > file\n> >     git add file\n> >     git commit -am \"a b c d e f\"\n> >\n> >     git checkout -b foo\n> >     echo -e \"a\\nb\\nc\\nd\\ne\\n1\\n2\\n3\\nfoo\" > file\n> >     git commit -am \"f -> foo\"\n> >\n> >     git checkout main\n> >     git checkout -b cat\n> >     echo -e \"a\\nb\\ncat\\nd\\ne\\n1\\n2\\n3\\nf\" > file\n> >     git commit -am \"c -> cat\"\n> >\n> > We got a few letters of alphabet on separate lines on main, and in branch\n> > foo `f` is changed to `foo`, and in branch cat `c` is changed to `cat`.\n> >\n> >     $ git log --all --graph --pretty=oneline\n> >     * 90e873e3 (HEAD -> cat) c -> cat\n> >     | * 3d8c1baf (foo) f -> foo\n> >     |/\n> >     * 4d2337dd (main) a b c d e f\n> >\n> > Now, still on cat, let's combine the two changes.\n> >\n> >     $ git rebase foo\n> >     Successfully rebased and updated refs/heads/cat\n> >\n> >     $ git log --all --graph --pretty=oneline\n> >     * 98e554a0 (HEAD -> cat) c -> cat\n> >     * 3d8c1baf (foo) f -> foo\n> >     * 4d2337dd (main) a b c d e f\n> >\n> > Now, `git rebase foo` worked automatically, so *the change* of the last commit\n> > on `cat` is the same as it was without rebase, which is changing `c` to `cat`.\n> > But if we run `git range-diff`, we will see this:\n> >\n> >     $ git range-diff 90e873e3...cat\n> >     -:  ------- > 1:  3d8c1ba f -> foo\n> >     1:  90e873e ! 2:  98e554a c -> cat\n> >         @@ file\n> >          +cat\n> >           d\n> >           e\n> >         - f\n> >         + foo\n> >\n> > It seems that this chunk is included for the sole reason that the change from\n> > `foo` is sort of close. If we try the same code, but put the lines `c` and `f`\n> > further apart, for example by replacing `e\\n` with `e\\n1\\n2\\n3\\n` in the\n> > commands above, the output would be, as expected,\n> >\n> >     $ git range-diff f1e0a6cc3...cat\n> >     -:  ------- > 1:  4db06be f -> foo\n> >     1:  f1e0a6c = 2:  cc56db7 c -> cat\n> >\n> > I suggest not showing uninteresting chunks like that, or perhaps having a\n> > command line option that controls how close together the changes must be in\n> > order to be included in the output.\n>\n> In a generic tool like `range-diff`, it is virtually guaranteed that the\n> default operation does not satisfy all use cases. This example\n> demonstrates that ;-)\n>\n> In general, the `A...B` form does what users want, namely show you pairs\n> between the \"left\" and the \"right\" commits in that symmetric range.\n>\n> However, you _can_ use `range-diff` in a way that it produces what you\n> want. In the example you provided above, `git range-diff foo cat@{1} cat`\n> should do it. That would be the `<upstream> <before> <after>` form.\n>\n> In general, you might need to play with `git merge-base --fork-point` (see\n> *1* for more information). I could imagine that the following command\n> might give you what you want in even more cases:\n>\n>         git range-diff \\\n>                 $(git merge-base --fork-point @{u} @{1})..@{1} \\\n>                 $(git merge-base --fork-point @{u} HEAD)..HEAD\n>\n> Ciao,\n> Johagnnes\n>\n> Footnote *1*: https://git-scm.com/docs/git-merge-base#_discussion_on_fork_point_mode\n"}]}