Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RevDiff: compare any two files #8193

Merged

Conversation

gerhardol
Copy link
Member

@gerhardol gerhardol commented Jun 6, 2020

Fixes #8048

Proposed changes

  • If two items in the RevDiff list are selected, add menu item to compare them
  • If one item is selected, menu item to remember the file
  • If one item is selected and one item remembered, menu item to compare them

This allows to compare refactored files, between commits, currently you have to save temporary files and compare them
The primary use is refactoring, when files are renamed and changed without Git detecting the change or when the change is done over several commits. It also allows seeing the difference for images (like in p4merge) when files are renamed.

Viewing files requires that the file exist in the commit, the first item must not be work tree.
To simplify usage, the compared file is automatically selecting the first revision if the second revision does cannot be used for the diff.

See #8193 (comment) for some use cases.

The first and second revisions are not named, just First and Second as the revisions are explained in the top of the menu.

Refactoring:

  • DiffTool should always detect rename and copy
    Hard to track that "-M -C" is always used, the parameters are passed around in some situations, in the Git command for others

  • RevDiff: Allow difftool menu for untracked
    Working in some difftools, comparing to NUL

  • [New] Use Second instead of Selected in the Difftool submenu (should have been changed when the naming for the groups were changed).

  • [New] Keep Second above First in the difftool submenu (already this order in Reset submenu)

Possible enhancement:
Add Remember file and Diff with in FileTree

Screenshots

Before

image

After

image

image

image

(Change from Selected to Second, same as in Diff submenu)
image

Test methodology

Added tests


✒️ I contribute this code under The Developer Certificate of Origin.

@ghost ghost assigned gerhardol Jun 6, 2020
@gerhardol gerhardol changed the title Feature/i8048 compare two files RevDiff: compare any two files Jun 6, 2020
@gerhardol gerhardol force-pushed the feature/i8048-compare-two-files branch from b0f96ff to e8a9085 Compare June 6, 2020 22:46
@codecov
Copy link

codecov bot commented Jun 6, 2020

Codecov Report

Merging #8193 into master will increase coverage by 0.05%.
The diff coverage is 64.68%.

@@            Coverage Diff             @@
##           master    #8193      +/-   ##
==========================================
+ Coverage   52.75%   52.81%   +0.05%     
==========================================
  Files         855      857       +2     
  Lines       62092    62305     +213     
  Branches    11154    11190      +36     
==========================================
+ Hits        32758    32905     +147     
- Misses      26737    26799      +62     
- Partials     2597     2601       +4     
Flag Coverage Δ
#production 40.78% <18.96%> (-0.04%) ⬇️
#tests 94.46% <99.34%> (+0.05%) ⬆️

@gerhardol gerhardol force-pushed the feature/i8048-compare-two-files branch from e8a9085 to 19a3d21 Compare June 8, 2020 04:53
@mstv
Copy link
Member

mstv commented Jun 9, 2020

👍 Works well. I'll review the code later (edit: has already been rebased).

I'd like to add a separator above the new menu items.
Save selected file to later should be rephrased to e.g. Save selected file for later comparison.
The filename should be quoted in Compare selected file to "file".
Perhaps this menu item should be suppressed if the identical file and revision is selected. Git does not open the difftool in this case.

I think it would be useful to have these context menu items in the file tree, too. E.g. if an unchanged file was cloned to a new one.

Slightly off-topic for this PR: I still quarrel over the new position of the submenu Open with difftool.
It even does not have a fixed position because
Cherry pick changes is hidden for multi-selections. It should rather be disabled if it is too difficult to implement it.

@gerhardol
Copy link
Member Author

gerhardol commented Jun 9, 2020

Works well. I'll review the code later (edit: has already been rebased).

I will rebase at least when there are conflicts, more often if I want to sync to other PRs.

I'd like to add a separator above the new menu items.
Save selected file to later should be rephrased to e.g. Save selected file for later comparison.
The filename should be quoted in Compare selected file to "file".
Perhaps this menu item should be suppressed if the identical file and revision is selected. Git does not open the difftool in this case.

Agree. I have to leave something for you too

I think it would be useful to have these context menu items in the file tree, too. E.g. if an unchanged file was cloned to a new one.

Can this be separate or do we need a separate resolver that is common?

I probably want to have an alternative for Save parent to selected for later comparison (nice and short? Should have the revision too). With a divider it may be OK to see these separate

Slightly off-topic for this PR: I still quarrel over the new position of the submenu Open with difftool.
It even does not have a fixed position because
Cherry pick changes is hidden for multi-selections. It should rather be disabled if it is too difficult to implement it.

(I do not like the position either, but found it better than an implementation that was inconsistent.)
Implementation right now is to get the diff from the diff viewer. It would be better to get the diff (patch) separately anyway and apply that (whitespaces etc).

A bigger problem is to implement the fish-needs-bicycle tests for the controller.

Edit: I have pushed an update for the comments to a private branch. Will update the PR later

@RussKie
Copy link
Member

RussKie commented Jun 11, 2020

What does "Save selected file to later" mean?

@gerhardol
Copy link
Member Author

What does "Save selected file to later" mean?

Save the file+commit so it can be compared later. Really similar to comparing the two commits, then compare, but it may be easier to find the files/commits to compare.
Similar to the explorer context menus for difftools like BeyondCompare, DiffMerge and TortoiseGit.

@RussKie
Copy link
Member

RussKie commented Jun 12, 2020

Similar to the explorer context menus for difftools like BeyondCompare, DiffMerge and TortoiseGit.

Do they have the same wording?
May be it should be for - "Save selected file for later"?

...and even then it looks/sounds awkward.

Comment on lines 792 to 796
compareToExistingDifftoolToolStripMenuItem.Visible = diffFiles.Count == 1 && _savedCompareFileItem != null;
compareToExistingDifftoolToolStripMenuItem.Enabled = diffFiles.Count == 1 && _revisionDiffContextMenuController.ShouldEnableSecondSpecialCompare(diffFiles?[0]);
compareToExistingDifftoolToolStripMenuItem.Text = _savedCompareFileItem != null ? string.Format(_compareSelectedFile.Text, _savedCompareFileItem.Item.Name) : string.Empty;
saveForLaterDifftoolToolStripMenuItem.Visible = diffFiles.Count == 1;
saveForLaterDifftoolToolStripMenuItem.Enabled = diffFiles.Count == 1 && _revisionDiffContextMenuController.ShouldEnableFirstSpecialCompare(diffFiles?[0]);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the idea of being able to compare arbitrary files across revisions, but I'm finding the visual presentation of the feature confusing. I had to look at the code to understand the screenshots showed...

Few Qs that immediately popped up:

  1. how do I know which files from which revisions I marked?
  2. how do I unmark selected/all files?
  3. how do I change the order of files?

Copy link
Member

@mstv mstv Jun 12, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how do I know which files from which revisions I marked?

The file name is shown in the menu item Compare selected file to "file".
Its revision is something for your short-term memory :)

how do I change the order of files?

Click grafik
Or replace the selection using Save selected file for later comparison and then choose Compare selected file to "file" after selecting the first one again.

how do I unmark selected/all files?

It's all about comparing exactly two files.
No need to unmark, just start over with Save selected file for later comparison.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I want to have the previous selectable too
Diff the selected files (when two selected)
Diff with "file" (one selected, revision not included in text)
Save b/12345678 for later (one selected, filename not included)
Save a/12345678 for later

Screenshots for other apps. No consistent description. The proposals are considerably longer...

  • No selection
  • Select the same file again
  • Another selected
  • Two selected
  • more than two selected
    image

DiffMerge can save several files, as well as clear them
image

Tortoise supports both git-diff and file system from the context menu
image

image

Copy link
Member

@RussKie RussKie Jun 25, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, it's starting to make sense.
Now to pick and agree on the wording :) I think if I saw BC and TG menus I'd conceivably guess their intent.
Would "Remember file for compare" work? And then "Compare with <the remembered file>"?
Is "first" and "second" placement material?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(I missed this comment, waiting with a merge)
The menu and Git uses diff rather than compare, so I prefer diff.
"Compare selected..." should be "Diff with " (dropping "selected file".

But "Remember Second for later" or "Remember Second" (similar to First) is possible. The shorter, the better is my preference (I constantly fail though.)

@mstv ?

@gerhardol
Copy link
Member Author

gerhardol commented Jun 14, 2020

I have pushed changes to private branches in my repo only (will test some more)
9d89892 contains the differences, will squash that, see 18e14f654472655d3611992c4e9d7c1b28bc14ba
Description and screenshots will be updated

This cleans up the the handling of assuming first rev when second rev cannot be used, including addig "Save first revision" to the context menu.
(Prepared for mstv's suggestion to add to the context menu there, not done though, awaiting review first.)

Use case 1:
File is renamed but Git do not detect the change
5dae302
Use P4Merge or some tool that display images
Diff IconAbout.co and information.ico

Use case 2:
Compare similar files
dc89d30

Use case 3:
(My primary use, but also the most complicated)
Refactoring splitting a file (there are better examples that I do not find now)

3a
f056b71
Save First for ScriptInfo.cs then ScriptEvent.cs
(to see that the enum is unchanged)

3b
19129fb
Select FormBrowse.cs, First, then RevisionDiff.cs, Diff with.

@gerhardol gerhardol force-pushed the feature/i8048-compare-two-files branch from 19a3d21 to 4068565 Compare June 15, 2020 20:21
@gerhardol gerhardol requested review from mstv and RussKie June 15, 2020 20:46
Copy link
Member

@mstv mstv left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Found an edge case: No matter whether the first or second of a renamed file is saved for later, the new name appears in the menu:
grafik

And: Should it be First -> Second instead of First -> Selected?

Should Second b/... rather be the top item in order to match the order in the RevisionGrid and in the Reset file(s) to menu?

grafik

/// <param name="firstGitCommit">commitish</param>
/// <param name="secondGitCommit">commitish</param>
/// <returns>empty string</returns>
public string OpenFilesWithDifftool(string firstGitCommit, string secondGitCommit)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not make it return void?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It follows the pattern for OpenWithDifftool()
See the TODO there
As an empty string is always returned anyway, few callers try to use the data
This should be handled the same

GitCommands/Git/GitModule.cs Show resolved Hide resolved
GitUI/CommandsDialogs/RevisionDiffControl.cs Outdated Show resolved Hide resolved
GitUI/CommandsDialogs/RevisionDiffControl.cs Outdated Show resolved Hide resolved
GitUI/CommandsDialogs/RevisionDiffControl.cs Outdated Show resolved Hide resolved
GitUI/CommandsDialogs/RevisionDiffControl.cs Outdated Show resolved Hide resolved
GitUI/CommandsDialogs/RevisionDiffControl.cs Outdated Show resolved Hide resolved
GitUI/CommandsDialogs/RevisionDiffControl.cs Outdated Show resolved Hide resolved
@gerhardol
Copy link
Member Author

Found an edge case: No matter whether the first or second of a renamed file is saved for later, the new name appears in the menu:

I had ignored that, but since you are commenting on it I will change that
Sidenote: Save for later is intentionally not disabling the menuitem if already selected, intentional

And: Should it be First -> Second instead of First -> Selected?

Yes

Should Second b/... rather be the top item in order to match the order in the RevisionGrid and in the Reset file(s) to menu?

It should be the same as in Reset at least. That Selected was before First was natural, but First before Second may not be.
But if the natural selection should be first, the order should be Send, First also in Reset.

@mstv
Copy link
Member

mstv commented Jun 16, 2020

Sidenote: Save for later is intentionally not disabling the menuitem if already selected

👍 else I would have complained 😉

GitUI/CommandsDialogs/RevisionDiffControl.cs Outdated Show resolved Hide resolved
@gerhardol
Copy link
Member Author

Should Second b/... rather be the top item in order to match the order in the RevisionGrid and in the Reset file(s) to menu?

It should be the same as in Reset at least. That Selected was before First was natural, but First before Second may not be.
But if the natural selection should be first, the order should be Send, First also in Reset.

Added a commit to align diff submenu with reset submenu, updated description and screenshot, also removed WIP

Copy link
Member

@mstv mstv left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@RussKie
Copy link
Member

RussKie commented Jun 25, 2020

I had a brief looked at the code, it looks good, I have no objections.

@gerhardol gerhardol force-pushed the feature/i8048-compare-two-files branch from 0cd1ffc to fe5fbeb Compare June 25, 2020 21:57
@gerhardol
Copy link
Member Author

@msftbot merge in 24 hours

@RussKie
Copy link
Member

RussKie commented Jun 26, 2020

For the ease of navigation, continuation of the discussion in #8193 (comment)

Something like this?

  • "Diff the selected files" (when two selected)
  • "Diff with <remembered file>" (visible, if there is a 'remembered' file)
  • separator
  • "Remember b/12345678 for diff` (one selected, filename not included)
  • "Remember a/12345678 for diff`
  • "Forget <remembered file>" (visible, if there is a 'remembered' file)

@gerhardol
Copy link
Member Author

Adapted the proposal.

separator

(No need to have a separator further down "Diff the selected" is only shown with two selected, the other only with one

"Diff the selected files" (when two selected)
"Diff with " (when one file selected) (visible, if there is a 'remembered' file)
"Remember Second for diff (one selected, filename not included) "Remember First for diff

Second and First is explained in the top of the menu, no need to do it again

"Forget " (visible, if there is a 'remembered' file)

No need for this one, forgotten if swiching repos.
I consider this as junk in the menu actions, more confusing than helping

...And the references to "saveForLater" in the code should be changed to remember file...

@RussKie
Copy link
Member

RussKie commented Jun 26, 2020

👍
So then, just "Save" -> "Remember"

Thank you

@mstv
Copy link
Member

mstv commented Jun 26, 2020

I agree.
Though I noticed today: Compared to the menu items above the separator, Compare selected file to "remembered file" could / should be simplified to Second -> "remembered file". If you find this too reduced, then I suggest to avoid the term "Compare to" and rather use "Diff with", which seems to be preferred by git and GE.

Is "first" and "second" placement material?

It has been made consistent with the other submenus, and matches the order in the RevisionGrid.
Sorry this comes really late: Unfortunately, it is opposite to the display of patches. Which should take precedence: DiffView or RevisionGrid? Which is nearer?

@gerhardol
Copy link
Member Author

gerhardol commented Jun 26, 2020

It has been made consistent with the other submenus, and matches the order in the RevisionGrid.
Sorry this comes really late: Unfortunately, it is opposite to the display of patches. Which should take precedence: DiffView or RevisionGrid? Which is nearer?

At this point, I say follow RevisionGrid "one selected" order
The order in the grid can vary though, but the Second is normally the Selected commit, so it is natural to keep it first in the list and First as second

Will squash latest commit in a day or so (no changes other than naming in the latest commit)
(The first four commits should remain)
If no further comments, I will set a merge a day after that

#8239 will follow, then likely #8254 before #7825 can be resumed

@RussKie
Copy link
Member

RussKie commented Jun 26, 2020 via email

 * If two items in the RevDiff list are selected, add menu item to diff them
 * If one item is selected, menu item to remember the file
 * If one item is selected and one item remembered, menu item to diff them

This allows to compare refactored files, between commits
@gerhardol gerhardol force-pushed the feature/i8048-compare-two-files branch 2 times, most recently from 477c86f to b8f68cb Compare June 27, 2020 21:40
/// </summary>
public FileStatusItem RememberedDiffFileItem { get; set; }

// Note that the methods in this class are without side effects (static)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's [Pure] attribute for that.

@RussKie RussKie merged commit 7ab900b into gitextensions:master Jun 28, 2020
@ghost ghost added this to the 4.0 milestone Jun 28, 2020
@gerhardol gerhardol deleted the feature/i8048-compare-two-files branch November 14, 2021 13:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Diff: Compare to any file
3 participants