Hi Hannes, please ignore the V5 patch. I totally missed to check for the file of interest when checking for renames. I'll correct that and send an update. Best wishes Tobias > -----Ursprüngliche Nachricht----- > Von: ToBoMi via GitGitGadget <gitgitgadget@xxxxxxxxx> > Gesendet: Dienstag, 10. Juni 2025 10:30 > An: git@xxxxxxxxxxxxxxx > Cc: Johannes Sixt <j6t@xxxxxxxx>; Boesch, Tobias > <tobias.boesch@xxxxxxxxx>; Boesch, Tobias <tobias.boesch@xxxxxxxxx>; > Boesch, Tobias <tobias.boesch@xxxxxxxxx> > Betreff: [PATCH v5] gitk: add external diff file rename detection > > From: Tobias Boesch <tobias.boesch@xxxxxxxxx> > > If a file is renamed between commits and an external diff is started through > gitk on the original or the renamed file name, gitk is unable to open the > renamed file in the external diff editor. > It fails to fetch the renamed file from git, because it fetches it using its original > path in contrast to using the renamed path of the file. > Detect the rename and open the external diff with the original and the > renamed file instead of no file (fetch the renamed file path and name from git) > no matter if the original or the renamed file is selected in gitk. > Since moved or renamed file are handled the same way do this also for moved > files. > > Signed-off-by: Tobias Boesch <tobias.boesch@xxxxxxxxx> > --- > gitk: add external diff file rename detection > > Changes since v1: > > * Commit message ident > * Commit message line length > > Changes since v2: > > * Removed option for rename detection (Adding GUI options seems to be > not desired - which is understandable) > * Rebased on current master of git-for-windows > * Renamed variables for a better understanding > * Made rename detection also work when the renamed file is selected in > gitk > > Changes since v3: > > * Changed message to use present tense, removed bullet points and > described changes in imperative mood > > Changes sine v4: > > * Use a git command to gather the changed file paths rather than > parsing the text from the diff window panel for efficiency and to > avoid regex containing the filename as a variable. > * Change != to ne in string comparison > * removed extra set of parentheses around && > * shorter variable names > > Published-As: https://github.com/gitgitgadget/git/releases/tag/pr- > 1774%2FToBoMi%2Fdetect_renamed_files_when_opening_diff-v5 > Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr- > 1774/ToBoMi/detect_renamed_files_when_opening_diff-v5 > Pull-Request: https://github.com/gitgitgadget/git/pull/1774 > > Range-diff vs v4: > > 1: 948b94bef5c ! 1: 0d28f189dc3 gitk: add external diff file rename > detection > @@ gitk-git/gitk: proc external_diff_get_one_file {diffid filename diffdir} { > "revision $diffid"] > } > > -+proc check_for_renames_in_diff {filepath} { > -+ global ctext > ++proc check_for_renames_in_diff {diffidfrom diffidto filepath} { > ++ global nullid nullid2 > + > -+ set renamed_filenames [list {}] > -+ set filename [file tail $filepath] > -+ set rename_from_text_identifier_length 12 > -+ set rename_to_text_identifier_length 10 > -+ set reg_expr_rename_from {^rename from (.*$filename)} > -+ set reg_expr_rename_from [subst -nobackslashes -nocommands > $reg_expr_rename_from] > -+ set rename_from_text_index [$ctext search -elide -regexp -- > $reg_expr_rename_from 0.0] > -+ if { ($rename_from_text_index != {})} { > -+ set reg_expr_rename_to {^rename to (.*)} > -+ set rename_to_text_index [$ctext search -elide -regexp -- > $reg_expr_rename_to $rename_from_text_index] > -+ if { ($rename_from_text_index != {}) && ($rename_to_text_index != > {}) } { > -+ lappend renamed_filenames [$ctext get > "$rename_from_text_index + $rename_from_text_identifier_length chars" > "$rename_from_text_index lineend"] > -+ lappend renamed_filenames [$ctext get "$rename_to_text_index + > $rename_to_text_identifier_length chars" "$rename_to_text_index lineend"] > -+ } > -+ return $renamed_filenames > ++ if {$diffidfrom eq $nullid} { > ++ set rev [list $diffidto -R] > ++ } elseif {$diffidfrom eq $nullid2} { > ++ set rev [list $diffidto --cached -R] > ++ } elseif {$diffidto eq $nullid} { > ++ set rev [list $diffidfrom] > ++ } elseif {$diffidto eq $nullid2} { > ++ set rev [list $diffidfrom --cached] > ++ } else { > ++ set rev [list $diffidfrom..$diffidto] > + } > -+ set reg_expr_rename_to {^rename to (.*$filename)} > -+ set reg_expr_rename_to [subst -nobackslashes -nocommands > $reg_expr_rename_to] > -+ set rename_to_text_index [$ctext search -elide -regexp -- > $reg_expr_rename_to 0.0] > -+ if { ($rename_to_text_index != {})} { > -+ set reg_expr_rename_from {^rename from (.*)} > -+ set rename_from_text_index [$ctext search -backwards -elide -regexp > -- $reg_expr_rename_from $rename_to_text_index] > -+ if { ($rename_to_text_index != {}) && ($rename_from_text_index != > {}) } { > -+ lappend renamed_filenames [$ctext get > "$rename_from_text_index + $rename_from_text_identifier_length chars" > "$rename_from_text_index lineend"] > -+ lappend renamed_filenames [$ctext get "$rename_to_text_index + > $rename_to_text_identifier_length chars" "$rename_to_text_index lineend"] > ++ > ++ set renames [list {}] > ++ if {[catch {eval exec git diff $rev --find-renames --stat --raw --diff- > filter=R} cmd_result]} { > ++ error_popup "[mc "Error getting file rename info for file \"%s\" from > commit %s to %s." \ > ++ $filepath $diffidfrom $diffidto] $cmd_result.\n\n" > ++ } > ++ set filename [file tail $filepath] > ++ set regex_ren {\d+\s\d+\s\S+\s\S+\s\S+\s+(\S+)\s+(\S+)} > ++ set regex_ren [subst -nobackslashes -nocommands $regex_ren] > ++ if {[regexp -line -- $regex_ren $cmd_result whole_match ren_from > ren_to]} { > ++ if {$ren_from ne {} && $ren_to ne {}} { > ++ lappend renames $ren_from > ++ lappend renames $ren_to > + } > -+ return $renamed_filenames > + } > ++ return $renames > +} > + > proc external_diff {} { > @@ gitk-git/gitk: proc external_diff {} { > # gather files to diff > - set difffromfile [external_diff_get_one_file $diffidfrom $flist_menu_file > $diffdir] > - set difftofile [external_diff_get_one_file $diffidto $flist_menu_file > $diffdir] > -+ set renamed_filenames [check_for_renames_in_diff $flist_menu_file] > ++ set renamed_filenames [check_for_renames_in_diff $diffidfrom > $diffidto $flist_menu_file] > + set rename_from_filename [lindex $renamed_filenames 1] > + set rename_to_filename [lindex $renamed_filenames 2] > + if { ($rename_from_filename != {}) && ($rename_to_filename != {}) } { > > > gitk-git/gitk | 44 ++++++++++++++++++++++++++++++++++++++++++-- > 1 file changed, 42 insertions(+), 2 deletions(-) > > diff --git a/gitk-git/gitk b/gitk-git/gitk index 19689765cde..f97904f5fa2 > 100755 > --- a/gitk-git/gitk > +++ b/gitk-git/gitk > @@ -3775,6 +3775,38 @@ proc external_diff_get_one_file {diffid filename > diffdir} { > "revision $diffid"] > } > > +proc check_for_renames_in_diff {diffidfrom diffidto filepath} { > + global nullid nullid2 > + > + if {$diffidfrom eq $nullid} { > + set rev [list $diffidto -R] > + } elseif {$diffidfrom eq $nullid2} { > + set rev [list $diffidto --cached -R] > + } elseif {$diffidto eq $nullid} { > + set rev [list $diffidfrom] > + } elseif {$diffidto eq $nullid2} { > + set rev [list $diffidfrom --cached] > + } else { > + set rev [list $diffidfrom..$diffidto] > + } > + > + set renames [list {}] > + if {[catch {eval exec git diff $rev --find-renames --stat --raw --diff-filter=R} > cmd_result]} { > + error_popup "[mc "Error getting file rename info for file \"%s\" from > commit %s to %s." \ > + $filepath $diffidfrom $diffidto] $cmd_result.\n\n" > + } > + set filename [file tail $filepath] > + set regex_ren {\d+\s\d+\s\S+\s\S+\s\S+\s+(\S+)\s+(\S+)} > + set regex_ren [subst -nobackslashes -nocommands $regex_ren] > + if {[regexp -line -- $regex_ren $cmd_result whole_match ren_from ren_to]} > { > + if {$ren_from ne {} && $ren_to ne {}} { > + lappend renames $ren_from > + lappend renames $ren_to > + } > + } > + return $renames > +} > + > proc external_diff {} { > global nullid nullid2 > global flist_menu_file > @@ -3805,8 +3837,16 @@ proc external_diff {} { > if {$diffdir eq {}} return > > # gather files to diff > - set difffromfile [external_diff_get_one_file $diffidfrom $flist_menu_file > $diffdir] > - set difftofile [external_diff_get_one_file $diffidto $flist_menu_file $diffdir] > + set renamed_filenames [check_for_renames_in_diff $diffidfrom $diffidto > $flist_menu_file] > + set rename_from_filename [lindex $renamed_filenames 1] > + set rename_to_filename [lindex $renamed_filenames 2] > + if { ($rename_from_filename != {}) && ($rename_to_filename != {}) } { > + set difffromfile [external_diff_get_one_file $diffidfrom > $rename_from_filename $diffdir] > + set difftofile [external_diff_get_one_file $diffidto $rename_to_filename > $diffdir] > + } else { > + set difffromfile [external_diff_get_one_file $diffidfrom $flist_menu_file > $diffdir] > + set difftofile [external_diff_get_one_file $diffidto $flist_menu_file > $diffdir] > + } > > if {$difffromfile ne {} && $difftofile ne {}} { > set cmd [list [shellsplit $extdifftool] $difffromfile $difftofile] > > base-commit: 14de3eb34435db79c6e7edc8082c302a26a8330a > -- > gitgitgadget ------------------------------------------------------------------------------------------------- imperial-Werke oHG, Sitz Bünde, Registergericht Bad Oeynhausen - HRA 4825