Skip to contentSkip to conversation

gitk: added external diff file rename detection

PATCH Superseded ToBoMi via GitGitGadget 3 participants 17 messages Aug 22, 2024 – Nov 6, 2025

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 gitk: added external diff file rename detection

From: deboeto <[email protected]>

* If a file was renamed between commits and an external diff is started through gitk on the THE ORIGINAL FILE NAME (not the renamed one), gitk was unable to open the renamed file in the external diff editor.
It failed to fetch the renamed file from git, because it fetched it with the original path in contrast to using the renamed path
* gitk now detects the rename and opens the
external diff with the original and the RENAMED file instead of no file (it is able to fetch the renamed file now from git with the renamed path/filename)
* Since git doesn't destinguish between move or rename this also works for moved files
* External diff detection and usage is optional and has to be enabled in gitk settings
* External rename detection ist marked EXPERIMENTAL in the settings and disabled by default
* Showing the renamed file doesn't work when THE RENAMED FILE is selected in gitk and an external diff ist started on that file, because the selected file is not renamed in that commit. It already IS the renamed file.

---
gitk: added external diff file rename detection

Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-1774%2FToBoMi%2Fdetect_renamed_files_when_opening_diff-v1
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1774/ToBoMi/detect_renamed_files_when_opening_diff-v1
Pull-Request: https://github.com/gitgitgadget/git/pull/1774

 gitk-git/gitk | 54 ++++++++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 47 insertions(+), 7 deletions(-)
gitk-git/gitk +47 -7
index 7a087f123d7..f7427f6d3f2 100755
@@ -3662,11 +3662,33 @@ proc external_diff_get_one_file {diffid filename diffdir} {
                "revision $diffid"]
 }
 
+proc check_for_renames_in_diff {filepath} {
+    global ctext
+
+    set renamed_filenames [list {}]
+    set filename [file tail $filepath]
+    set rename_from_text_length 12
+    set rename_to_text_length 10
+    set reg_expr_rename_from {^rename from (.*$filename)}
+    set reg_expr_rename_from [subst -nobackslashes -nocommands $reg_expr_rename_from]
+    set reg_expr_rename_to {^rename to (.*)}
+    set rename_from_text_index [$ctext search -elide -regexp -- $reg_expr_rename_from 0.0]
+    if { ($rename_from_text_index != {})} {
+        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_length chars" "$rename_from_text_index lineend"]
+            lappend renamed_filenames [$ctext get "$rename_to_text_index + $rename_to_text_length chars" "$rename_to_text_index lineend"]
+        }
+    }
+    return $renamed_filenames
+}
+
 proc external_diff {} {
     global nullid nullid2
     global flist_menu_file
     global diffids
     global extdifftool
+    global file_rename_detection
 
     if {[llength $diffids] == 1} {
         # no reference commit given
@@ -3692,8 +3714,21 @@ 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]
+    if {$file_rename_detection} {
+        set renamed_filenames [check_for_renames_in_diff $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]
+        }
+    } 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]
@@ -11577,7 +11612,7 @@ proc create_prefs_page {w} {
 proc prefspage_general {notebook} {
     global NS maxwidth maxgraphpct showneartags showlocalchanges
     global tabstop limitdiffs autoselect autosellen extdifftool perfile_attrs
-    global hideremotes want_ttk have_ttk maxrefs web_browser
+    global hideremotes want_ttk have_ttk maxrefs web_browser file_rename_detection
 
     set page [create_prefs_page $notebook.general]
 
@@ -11639,12 +11674,16 @@ proc prefspage_general {notebook} {
     grid $page.lgen - -sticky w -pady 10
     ${NS}::checkbutton $page.want_ttk -variable want_ttk \
         -text [mc "Use themed widgets"]
+    ${NS}::checkbutton $page.file_rename_detection -variable file_rename_detection \
+        -text [mc "Use ext diff file rename detection"]
+    ${NS}::label $page.file_rename_detection_note -text [mc "(EXPERIMENTAL\nTries to find the file path of a\nrenamed file in external diff)"]
     if {$have_ttk} {
         ${NS}::label $page.ttk_note -text [mc "(change requires restart)"]
     } else {
         ${NS}::label $page.ttk_note -text [mc "(currently unavailable)"]
     }
     grid x $page.want_ttk $page.ttk_note -sticky w
+    grid x $page.file_rename_detection $page.file_rename_detection_note -sticky w
     return $page
 }
 
@@ -11725,7 +11764,7 @@ proc doprefs {} {
     global oldprefs prefstop showneartags showlocalchanges
     global uicolor bgcolor fgcolor ctext diffcolors selectbgcolor markbgcolor
     global tabstop limitdiffs autoselect autosellen extdifftool perfile_attrs
-    global hideremotes want_ttk have_ttk
+    global hideremotes want_ttk have_ttk file_rename_detection
 
     set top .gitkprefs
     set prefstop $top
@@ -11734,7 +11773,7 @@ proc doprefs {} {
         return
     }
     foreach v {maxwidth maxgraphpct showneartags showlocalchanges \
-                   limitdiffs tabstop perfile_attrs hideremotes want_ttk} {
+                   limitdiffs tabstop perfile_attrs hideremotes want_ttk file_rename_detection} {
         set oldprefs($v) [set $v]
     }
     ttk_toplevel $top
@@ -11860,7 +11899,7 @@ proc prefscan {} {
     global oldprefs prefstop
 
     foreach v {maxwidth maxgraphpct showneartags showlocalchanges \
-                   limitdiffs tabstop perfile_attrs hideremotes want_ttk} {
+                   limitdiffs tabstop perfile_attrs hideremotes want_ttk file_rename_detection} {
         global $v
         set $v $oldprefs($v)
     }
@@ -12404,6 +12443,7 @@ set autoselect 1
 set autosellen 40
 set perfile_attrs 0
 set want_ttk 1
+set file_rename_detection 0
 
 if {[tk windowingsystem] eq "aqua"} {
     set extdifftool "opendiff"
@@ -12498,7 +12538,7 @@ config_check_tmp_exists 50
 set config_variables {
     mainfont textfont uifont tabstop findmergefiles maxgraphpct maxwidth
     cmitmode wrapcomment autoselect autosellen showneartags maxrefs visiblerefs
-    hideremotes showlocalchanges datetimeformat limitdiffs uicolor want_ttk
+    hideremotes showlocalchanges datetimeformat limitdiffs uicolor want_ttk file_rename_detection
     bgcolor fgcolor uifgcolor uifgdisabledcolor colors diffcolors mergecolors
     markbgcolor diffcontext selectbgcolor foundbgcolor currentsearchhitbgcolor
     extdifftool perfile_attrs headbgcolor headfgcolor headoutlinecolor

base-commit: b9849e4f7631d80f146d159bf7b60263b3205632

Signature · 1 line
gitgitgadget
#1 lore raw

PATCH v2 1/1 gitk: added external diff file rename detection

From: Tobias Boesch <[email protected]>

* If a file was renamed between commits and an external diff is started through gitk on the THE ORIGINAL FILE NAME (not the renamed one), gitk was unable to open the renamed file in the external diff editor. It failed to fetch the renamed file from git, because it fetched it with the original path in contrast to using the renamed path
* gitk now detects the rename and opens the external diff with the original and the RENAMED file instead of no file (it is able to fetch the renamed file now from git with the renamed path/filename)
* Since git doesn't destinguish between move or rename this also works for moved files
* External diff detection and usage is optional and has to be enabled in gitk settings
* External rename detection ist marked EXPERIMENTAL in the settings and disabled by default
* Showing the renamed file doesn't work when THE RENAMED FILE is selected in gitk and an external diff ist started on that file, because the selected file is not renamed in that commit. It already IS the renamed file.

---
gitk: added external diff file rename detection

Changes since v1:

* Commit message ident
* Commit message line length

Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-1774%2FToBoMi%2Fdetect_renamed_files_when_opening_diff-v2
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1774/ToBoMi/detect_renamed_files_when_opening_diff-v2
Pull-Request: https://github.com/gitgitgadget/git/pull/1774

Range-diff vs v1:

1: 4ff4aec82fe ! 1: 6209080cad6 gitk: added external diff file rename detection
@@
## Metadata ##
-Author: deboeto <[email protected]>
+Author: Tobias Boesch <[email protected]>

## Commit message ##
gitk: added external diff file rename detection

- * If a file was renamed between commits and
- an external diff is started through gitk
- on the THE ORIGINAL FILE NAME (not the
- renamed one), gitk was unable to open
- the renamed file in the external diff
- editor.
- It failed to fetch the renamed file from
- git, because it fetched it with the original
- path in contrast to using the renamed path
- * gitk now detects the rename and opens the
- external diff with the original and the RENAMED
- file instead of no file (it is able to fetch
- the renamed file now from git with the renamed
- path/filename)
- * Since git doesn't destinguish between move or
- rename this also works for moved files
- * External diff detection and usage is optional
- and has to be enabled in gitk settings
- * External rename detection ist marked
- EXPERIMENTAL in the settings and disabled
- by default
- * Showing the renamed file doesn't work when THE
- RENAMED FILE is selected in gitk and an
- external diff ist started on that file,
- because the selected file is not renamed in
- that commit. It already IS the renamed file.
+ * If a file was renamed between commits and an external diff is started
+ through gitk on the THE ORIGINAL FILE NAME (not the renamed one),
+ gitk was unable to open the renamed file in the external diff editor.
+ It failed to fetch the renamed file from git, because it fetched it
+ with the original path in contrast to using the renamed path
+ * gitk now detects the rename and opens the external diff with the
+ original and the RENAMED file instead of no file (it is able to
+ fetch the renamed file now from git with the renamed path/filename)
+ * Since git doesn't destinguish between move or rename this also works
+ for moved files
+ * External diff detection and usage is optional and has to be enabled in
+ gitk settings
+ * External rename detection ist marked EXPERIMENTAL in the settings
+ and disabled by default
+ * Showing the renamed file doesn't work when THE RENAMED FILE is selected
+ in gitk and an external diff ist started on that file, because the
+ selected file is not renamed in that commit. It already IS the renamed
+ file.

- Signed-off-by: deboeto <[email protected]>
+ Signed-off-by: Tobias Boeesch <[email protected]>

## gitk-git/gitk ##
@@ gitk-git/gitk: proc external_diff_get_one_file {diffid filename diffdir} {

 gitk-git/gitk | 54 ++++++++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 47 insertions(+), 7 deletions(-)
gitk-git/gitk +47 -7
index 7a087f123d7..f7427f6d3f2 100755
@@ -3662,11 +3662,33 @@ proc external_diff_get_one_file {diffid filename diffdir} {
                "revision $diffid"]
 }
 
+proc check_for_renames_in_diff {filepath} {
+    global ctext
+
+    set renamed_filenames [list {}]
+    set filename [file tail $filepath]
+    set rename_from_text_length 12
+    set rename_to_text_length 10
+    set reg_expr_rename_from {^rename from (.*$filename)}
+    set reg_expr_rename_from [subst -nobackslashes -nocommands $reg_expr_rename_from]
+    set reg_expr_rename_to {^rename to (.*)}
+    set rename_from_text_index [$ctext search -elide -regexp -- $reg_expr_rename_from 0.0]
+    if { ($rename_from_text_index != {})} {
+        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_length chars" "$rename_from_text_index lineend"]
+            lappend renamed_filenames [$ctext get "$rename_to_text_index + $rename_to_text_length chars" "$rename_to_text_index lineend"]
+        }
+    }
+    return $renamed_filenames
+}
+
 proc external_diff {} {
     global nullid nullid2
     global flist_menu_file
     global diffids
     global extdifftool
+    global file_rename_detection
 
     if {[llength $diffids] == 1} {
         # no reference commit given
@@ -3692,8 +3714,21 @@ 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]
+    if {$file_rename_detection} {
+        set renamed_filenames [check_for_renames_in_diff $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]
+        }
+    } 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]
@@ -11577,7 +11612,7 @@ proc create_prefs_page {w} {
 proc prefspage_general {notebook} {
     global NS maxwidth maxgraphpct showneartags showlocalchanges
     global tabstop limitdiffs autoselect autosellen extdifftool perfile_attrs
-    global hideremotes want_ttk have_ttk maxrefs web_browser
+    global hideremotes want_ttk have_ttk maxrefs web_browser file_rename_detection
 
     set page [create_prefs_page $notebook.general]
 
@@ -11639,12 +11674,16 @@ proc prefspage_general {notebook} {
     grid $page.lgen - -sticky w -pady 10
     ${NS}::checkbutton $page.want_ttk -variable want_ttk \
         -text [mc "Use themed widgets"]
+    ${NS}::checkbutton $page.file_rename_detection -variable file_rename_detection \
+        -text [mc "Use ext diff file rename detection"]
+    ${NS}::label $page.file_rename_detection_note -text [mc "(EXPERIMENTAL\nTries to find the file path of a\nrenamed file in external diff)"]
     if {$have_ttk} {
         ${NS}::label $page.ttk_note -text [mc "(change requires restart)"]
     } else {
         ${NS}::label $page.ttk_note -text [mc "(currently unavailable)"]
     }
     grid x $page.want_ttk $page.ttk_note -sticky w
+    grid x $page.file_rename_detection $page.file_rename_detection_note -sticky w
     return $page
 }
 
@@ -11725,7 +11764,7 @@ proc doprefs {} {
     global oldprefs prefstop showneartags showlocalchanges
     global uicolor bgcolor fgcolor ctext diffcolors selectbgcolor markbgcolor
     global tabstop limitdiffs autoselect autosellen extdifftool perfile_attrs
-    global hideremotes want_ttk have_ttk
+    global hideremotes want_ttk have_ttk file_rename_detection
 
     set top .gitkprefs
     set prefstop $top
@@ -11734,7 +11773,7 @@ proc doprefs {} {
         return
     }
     foreach v {maxwidth maxgraphpct showneartags showlocalchanges \
-                   limitdiffs tabstop perfile_attrs hideremotes want_ttk} {
+                   limitdiffs tabstop perfile_attrs hideremotes want_ttk file_rename_detection} {
         set oldprefs($v) [set $v]
     }
     ttk_toplevel $top
@@ -11860,7 +11899,7 @@ proc prefscan {} {
     global oldprefs prefstop
 
     foreach v {maxwidth maxgraphpct showneartags showlocalchanges \
-                   limitdiffs tabstop perfile_attrs hideremotes want_ttk} {
+                   limitdiffs tabstop perfile_attrs hideremotes want_ttk file_rename_detection} {
         global $v
         set $v $oldprefs($v)
     }
@@ -12404,6 +12443,7 @@ set autoselect 1
 set autosellen 40
 set perfile_attrs 0
 set want_ttk 1
+set file_rename_detection 0
 
 if {[tk windowingsystem] eq "aqua"} {
     set extdifftool "opendiff"
@@ -12498,7 +12538,7 @@ config_check_tmp_exists 50
 set config_variables {
     mainfont textfont uifont tabstop findmergefiles maxgraphpct maxwidth
     cmitmode wrapcomment autoselect autosellen showneartags maxrefs visiblerefs
-    hideremotes showlocalchanges datetimeformat limitdiffs uicolor want_ttk
+    hideremotes showlocalchanges datetimeformat limitdiffs uicolor want_ttk file_rename_detection
     bgcolor fgcolor uifgcolor uifgdisabledcolor colors diffcolors mergecolors
     markbgcolor diffcontext selectbgcolor foundbgcolor currentsearchhitbgcolor
     extdifftool perfile_attrs headbgcolor headfgcolor headoutlinecolor

base-commit: 2e7b89e038c0c888acf61f1b4ee5a43d4dd5e94c

Signature · 1 line
gitgitgadget
#2 lore raw
Quoted 10 lines

-----Ursprüngliche Nachricht-----
Von: ToBoMi via GitGitGadget <[email protected]>
Gesendet: Freitag, 6. September 2024 09:28
An: [email protected]
Cc: Boesch, Tobias <[email protected]>; Boesch, Tobias <[email protected]>
Betreff: [PATCH v2] gitk: added external diff file rename detection

From: Tobias Boesch <[email protected]>

Quoted 14 lines

* If a file was renamed between commits and an external diff is started through gitk on the THE ORIGINAL FILE NAME (not the renamed one), gitk was unable to open the renamed file in the external diff editor. It failed to fetch the renamed file from git, because it fetched it with the original path in contrast to using the renamed path
* gitk now detects the rename and opens the external diff with the original and the RENAMED file instead of no file (it is able to fetch the renamed file now from git with the renamed path/filename)
* Since git doesn't destinguish between move or rename this also works for moved files
* External diff detection and usage is optional and has to be enabled in gitk settings
* External rename detection ist marked EXPERIMENTAL in the settings and disabled by default

It would be nice to have this without an additional setting. Just enable the feature and remove the option.

Quoted 4 lines

* Showing the renamed file doesn't work when THE RENAMED FILE is selected in gitk and an external diff ist started on that file, because the selected file is not renamed in that commit. It already IS the renamed file.

gitk already shows the exact same diff for both file entries, the file that is renamed and the renamed file.
This is why it would be okay to show the same external diff for both file entries.
It should be possible from the current code change to also gather the file names the other way round, that is to gather the file path of the file to be renamed from the renamed file path. Since gitk doesn't change the diff depending on the file that is selected, the external diff should not switch sides depending on the file being selected.

Quoted 240 lines

---
gitk: added external diff file rename detection

Changes since v1:

* Commit message ident
* Commit message line length

Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-
1774%2FToBoMi%2Fdetect_renamed_files_when_opening_diff-v2
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr- 1774/ToBoMi/detect_renamed_files_when_opening_diff-v2
Pull-Request: https://github.com/gitgitgadget/git/pull/1774

Range-diff vs v1:

1: 4ff4aec82fe ! 1: 6209080cad6 gitk: added external diff file rename
detection
@@
## Metadata ##
-Author: deboeto <[email protected]>
+Author: Tobias Boesch <[email protected]>

## Commit message ##
gitk: added external diff file rename detection

- * If a file was renamed between commits and
- an external diff is started through gitk
- on the THE ORIGINAL FILE NAME (not the
- renamed one), gitk was unable to open
- the renamed file in the external diff
- editor.
- It failed to fetch the renamed file from
- git, because it fetched it with the original
- path in contrast to using the renamed path
- * gitk now detects the rename and opens the
- external diff with the original and the RENAMED
- file instead of no file (it is able to fetch
- the renamed file now from git with the renamed
- path/filename)
- * Since git doesn't destinguish between move or
- rename this also works for moved files
- * External diff detection and usage is optional
- and has to be enabled in gitk settings
- * External rename detection ist marked
- EXPERIMENTAL in the settings and disabled
- by default
- * Showing the renamed file doesn't work when THE
- RENAMED FILE is selected in gitk and an
- external diff ist started on that file,
- because the selected file is not renamed in
- that commit. It already IS the renamed file.
+ * If a file was renamed between commits and an external diff is started
+ through gitk on the THE ORIGINAL FILE NAME (not the renamed one),
+ gitk was unable to open the renamed file in the external diff editor.
+ It failed to fetch the renamed file from git, because it fetched it
+ with the original path in contrast to using the renamed path
+ * gitk now detects the rename and opens the external diff with the
+ original and the RENAMED file instead of no file (it is able to
+ fetch the renamed file now from git with the renamed path/filename)
+ * Since git doesn't destinguish between move or rename this also works
+ for moved files
+ * External diff detection and usage is optional and has to be enabled in
+ gitk settings
+ * External rename detection ist marked EXPERIMENTAL in the settings
+ and disabled by default
+ * Showing the renamed file doesn't work when THE RENAMED FILE is
selected

     +      in gitk and an external diff ist started on that file, because the
     +      selected file is not renamed in that commit. It already IS the renamed
     +      file.

- Signed-off-by: deboeto <[email protected]>
+ Signed-off-by: Tobias Boeesch <[email protected]>

## gitk-git/gitk ##
@@ gitk-git/gitk: proc external_diff_get_one_file {diffid filename diffdir} {

 gitk-git/gitk | 54 ++++++++++++++++++++++++++++++++++++++++++++--
-----
 1 file changed, 47 insertions(+), 7 deletions(-)
gitk-git/gitk index 7a087f123d7..f7427f6d3f2 renamed from gitk-git/gitk +0 -0

100755

gitk-git/gitk +9 -0
@@ -3662,11 +3662,33 @@ proc external_diff_get_one_file {diffid filename
 diffdir} {
                "revision $diffid"]
 }
 
+proc check_for_renames_in_diff {filepath} {
+    global ctext
+
+    set renamed_filenames [list {}]
+    set filename [file tail $filepath]
+    set rename_from_text_length 12
+    set rename_to_text_length 10
+    set reg_expr_rename_from {^rename from (.*$filename)}
+    set reg_expr_rename_from [subst -nobackslashes -nocommands

$reg_expr_rename_from]

gitk-git/gitk +2 -0
+    set reg_expr_rename_to {^rename to (.*)}
+    set rename_from_text_index [$ctext search -elide -regexp --

$reg_expr_rename_from 0.0]

gitk-git/gitk +2 -0
+    if { ($rename_from_text_index != {})} {
+        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_length chars" "$rename_from_text_index lineend"]
+ lappend renamed_filenames [$ctext get "$rename_to_text_index +
$rename_to_text_length chars" "$rename_to_text_index lineend"]

gitk-git/gitk +6 -1
+        }
+    }
+    return $renamed_filenames
+}
+
 proc external_diff {} {
     global nullid nullid2
     global flist_menu_file
     global diffids
     global extdifftool
+    global file_rename_detection
 
     if {[llength $diffids] == 1} {
         # no reference commit given
@@ -3692,8 +3714,21 @@ proc external_diff {} {
     if {$diffdir eq {}} return
 
     # gather files to diff
-    set difffromfile [external_diff_get_one_file $diffidfrom $flist_menu_file

$diffdir]

gitk-git/gitk +6 -1
-    set difftofile [external_diff_get_one_file $diffidto $flist_menu_file $diffdir]
+    if {$file_rename_detection} {
+        set renamed_filenames [check_for_renames_in_diff $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]

gitk-git/gitk +2 -0
+        } 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]

gitk-git/gitk +3 -0
+        }
+    } 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] @@ -
11577,7 +11612,7 @@ proc create_prefs_page {w} { proc prefspage_general {notebook} {
global NS maxwidth maxgraphpct showneartags showlocalchanges global tabstop limitdiffs autoselect autosellen extdifftool perfile_attrs

gitk-git/gitk +14 -4
-    global hideremotes want_ttk have_ttk maxrefs web_browser
+    global hideremotes want_ttk have_ttk maxrefs web_browser
+ file_rename_detection
 
     set page [create_prefs_page $notebook.general]
@@ -11639,12 +11674,16 @@ proc prefspage_general {notebook} {
     grid $page.lgen - -sticky w -pady 10
     ${NS}::checkbutton $page.want_ttk -variable want_ttk \
         -text [mc "Use themed widgets"]
+    ${NS}::checkbutton $page.file_rename_detection -variable
 file_rename_detection \
+        -text [mc "Use ext diff file rename detection"]
+    ${NS}::label $page.file_rename_detection_note -text [mc
+ "(EXPERIMENTAL\nTries to find the file path of a\nrenamed file in
+ external diff)"]
     if {$have_ttk} {
         ${NS}::label $page.ttk_note -text [mc "(change requires restart)"]
     } else {
         ${NS}::label $page.ttk_note -text [mc "(currently unavailable)"]
     }
     grid x $page.want_ttk $page.ttk_note -sticky w
+    grid x $page.file_rename_detection $page.file_rename_detection_note
+ -sticky w
     return $page
 }
@@ -11725,7 +11764,7 @@ proc doprefs {} {
     global oldprefs prefstop showneartags showlocalchanges
     global uicolor bgcolor fgcolor ctext diffcolors selectbgcolor markbgcolor
     global tabstop limitdiffs autoselect autosellen extdifftool perfile_attrs
-    global hideremotes want_ttk have_ttk
+    global hideremotes want_ttk have_ttk file_rename_detection
 
     set top .gitkprefs
     set prefstop $top
@@ -11734,7 +11773,7 @@ proc doprefs {} {
         return
     }
     foreach v {maxwidth maxgraphpct showneartags showlocalchanges \
-                   limitdiffs tabstop perfile_attrs hideremotes want_ttk} {
+                   limitdiffs tabstop perfile_attrs hideremotes
+ want_ttk file_rename_detection} {
         set oldprefs($v) [set $v]
     }
     ttk_toplevel $top
@@ -11860,7 +11899,7 @@ proc prefscan {} {
     global oldprefs prefstop
 
     foreach v {maxwidth maxgraphpct showneartags showlocalchanges \
-                   limitdiffs tabstop perfile_attrs hideremotes want_ttk} {
+                   limitdiffs tabstop perfile_attrs hideremotes
+ want_ttk file_rename_detection} {
         global $v
         set $v $oldprefs($v)
     }
@@ -12404,6 +12443,7 @@ set autoselect 1  set autosellen 40  set

perfile_attrs 0 set want_ttk 1

gitk-git/gitk +1 -0
+set file_rename_detection 0
 
 if {[tk windowingsystem] eq "aqua"} {
     set extdifftool "opendiff"
@@ -12498,7 +12538,7 @@ config_check_tmp_exists 50  set
 config_variables {
     mainfont textfont uifont tabstop findmergefiles maxgraphpct maxwidth
     cmitmode wrapcomment autoselect autosellen showneartags maxrefs

visiblerefs

gitk-git/gitk +2 -1
-    hideremotes showlocalchanges datetimeformat limitdiffs uicolor want_ttk
+    hideremotes showlocalchanges datetimeformat limitdiffs uicolor
+ want_ttk file_rename_detection
     bgcolor fgcolor uifgcolor uifgdisabledcolor colors diffcolors mergecolors
     markbgcolor diffcontext selectbgcolor foundbgcolor

currentsearchhitbgcolor
extdifftool perfile_attrs headbgcolor headfgcolor headoutlinecolor

Quoted 3 lines

base-commit: 2e7b89e038c0c888acf61f1b4ee5a43d4dd5e94c --
gitgitgadget

-------------------------------------------------------------------------------------------------
imperial-Werke oHG, Sitz Bünde, Registergericht Bad Oeynhausen - HRA 4825

#3 lore raw

PATCH v3 1/1 gitk: added external diff file rename detection

In reply to ToBoMi via GitGitGadget

From: Tobias Boesch <[email protected]>

* If a file was renamed between commits and an external diff is started through gitk on the original or the renamed file name, gitk was unable to open the renamed file in the external diff editor. It failed to fetch the renamed file from git, because it fetched it using its original path in contrast to using the renamed path of the file.
* With this change gitk detects the rename and opens the external diff with the original and the renamed file instead of no file (it is able to fetch the renamed file path and name now from git).
* Since git doesn't destinguish between move or rename this also works for moved files.
* Showing the external diff with the original and the renamed file works when either of the files is selected in gitk.

---
gitk: added 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

Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-1774%2FToBoMi%2Fdetect_renamed_files_when_opening_diff-v3
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1774/ToBoMi/detect_renamed_files_when_opening_diff-v3
Pull-Request: https://github.com/gitgitgadget/git/pull/1774

Range-diff vs v2:

1: 6209080cad6 ! 1: 1a64e989713 gitk: added external diff file rename detection
@@ Commit message
gitk: added external diff file rename detection

* If a file was renamed between commits and an external diff is started
- through gitk on the THE ORIGINAL FILE NAME (not the renamed one),
+ through gitk on the original or the renamed file name,
gitk was unable to open the renamed file in the external diff editor. It failed to fetch the renamed file from git, because it fetched it
- with the original path in contrast to using the renamed path
- * gitk now detects the rename and opens the external diff with the
- original and the RENAMED file instead of no file (it is able to
- fetch the renamed file now from git with the renamed path/filename)
- * Since git doesn't destinguish between move or rename this also works
- for moved files
- * External diff detection and usage is optional and has to be enabled in
- gitk settings
- * External rename detection ist marked EXPERIMENTAL in the settings
- and disabled by default
- * Showing the renamed file doesn't work when THE RENAMED FILE is selected
- in gitk and an external diff ist started on that file, because the
- selected file is not renamed in that commit. It already IS the renamed
+ using its original path in contrast to using the renamed path of the
file.
+ * With this change gitk detects the rename and opens the external diff
+ with the original and the renamed file instead of no file (it is able
+ to fetch the renamed file path and name now from git).
+ * Since git doesn't destinguish between move or rename this also works
+ for moved files.
+ * Showing the external diff with the original and the renamed file
+ works when either of the files is selected in gitk.

- Signed-off-by: Tobias Boeesch <[email protected]>
+ Signed-off-by: Tobias Boesch <[email protected]>

## gitk-git/gitk ##
@@ gitk-git/gitk: proc external_diff_get_one_file {diffid filename diffdir} {
@@ gitk-git/gitk: proc external_diff_get_one_file {diffid filename diffdir} {
+
+ set renamed_filenames [list {}]
+ set filename [file tail $filepath]
-+ set rename_from_text_length 12
-+ set rename_to_text_length 10
++ 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 reg_expr_rename_to {^rename to (.*)}
+ 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_length chars" "$rename_from_text_index lineend"]
-+ lappend renamed_filenames [$ctext get "$rename_to_text_index + $rename_to_text_length chars" "$rename_to_text_index lineend"]
++ 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
++ }
++ 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"]
+ }
++ return $renamed_filenames
+ }
-+ return $renamed_filenames
+}
+
proc external_diff {} {
global nullid nullid2
global flist_menu_file
- global diffids
- global extdifftool
-+ global file_rename_detection
-
- if {[llength $diffids] == 1} {
- # no reference commit given
@@ gitk-git/gitk: 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]
-+ if {$file_rename_detection} {
-+ set renamed_filenames [check_for_renames_in_diff $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]
-+ }
++ set renamed_filenames [check_for_renames_in_diff $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]
@@ gitk-git/gitk: proc external_diff {} {

if {$difffromfile ne {} && $difftofile ne {}} {
set cmd [list [shellsplit $extdifftool] $difffromfile $difftofile]
-@@ gitk-git/gitk: proc create_prefs_page {w} {
- proc prefspage_general {notebook} {
- global NS maxwidth maxgraphpct showneartags showlocalchanges
- global tabstop limitdiffs autoselect autosellen extdifftool perfile_attrs
-- global hideremotes want_ttk have_ttk maxrefs web_browser
-+ global hideremotes want_ttk have_ttk maxrefs web_browser file_rename_detection
-
- set page [create_prefs_page $notebook.general]
-
-@@ gitk-git/gitk: proc prefspage_general {notebook} {
- grid $page.lgen - -sticky w -pady 10
- ${NS}::checkbutton $page.want_ttk -variable want_ttk \
- -text [mc "Use themed widgets"]
-+ ${NS}::checkbutton $page.file_rename_detection -variable file_rename_detection \
-+ -text [mc "Use ext diff file rename detection"]
-+ ${NS}::label $page.file_rename_detection_note -text [mc "(EXPERIMENTAL\nTries to find the file path of a\nrenamed file in external diff)"]
- if {$have_ttk} {
- ${NS}::label $page.ttk_note -text [mc "(change requires restart)"]
- } else {
- ${NS}::label $page.ttk_note -text [mc "(currently unavailable)"]
- }
- grid x $page.want_ttk $page.ttk_note -sticky w
-+ grid x $page.file_rename_detection $page.file_rename_detection_note -sticky w
- return $page
- }
-
-@@ gitk-git/gitk: proc doprefs {} {
- global oldprefs prefstop showneartags showlocalchanges
- global uicolor bgcolor fgcolor ctext diffcolors selectbgcolor markbgcolor
- global tabstop limitdiffs autoselect autosellen extdifftool perfile_attrs
-- global hideremotes want_ttk have_ttk
-+ global hideremotes want_ttk have_ttk file_rename_detection
-
- set top .gitkprefs
- set prefstop $top
-@@ gitk-git/gitk: proc doprefs {} {
- return
- }
- foreach v {maxwidth maxgraphpct showneartags showlocalchanges \
-- limitdiffs tabstop perfile_attrs hideremotes want_ttk} {
-+ limitdiffs tabstop perfile_attrs hideremotes want_ttk file_rename_detection} {
- set oldprefs($v) [set $v]
- }
- ttk_toplevel $top
-@@ gitk-git/gitk: proc prefscan {} {
- global oldprefs prefstop
-
- foreach v {maxwidth maxgraphpct showneartags showlocalchanges \
-- limitdiffs tabstop perfile_attrs hideremotes want_ttk} {
-+ limitdiffs tabstop perfile_attrs hideremotes want_ttk file_rename_detection} {
- global $v
- set $v $oldprefs($v)
- }
-@@ gitk-git/gitk: set autoselect 1
- set autosellen 40
- set perfile_attrs 0
- set want_ttk 1
-+set file_rename_detection 0
-
- if {[tk windowingsystem] eq "aqua"} {
- set extdifftool "opendiff"
-@@ gitk-git/gitk: config_check_tmp_exists 50
- set config_variables {
- mainfont textfont uifont tabstop findmergefiles maxgraphpct maxwidth
- cmitmode wrapcomment autoselect autosellen showneartags maxrefs visiblerefs
-- hideremotes showlocalchanges datetimeformat limitdiffs uicolor want_ttk
-+ hideremotes showlocalchanges datetimeformat limitdiffs uicolor want_ttk file_rename_detection
- bgcolor fgcolor uifgcolor uifgdisabledcolor colors diffcolors mergecolors
- markbgcolor diffcontext selectbgcolor foundbgcolor currentsearchhitbgcolor
- extdifftool perfile_attrs headbgcolor headfgcolor headoutlinecolor

 gitk-git/gitk | 45 +++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 43 insertions(+), 2 deletions(-)
gitk-git/gitk +43 -2
index bc9efa18566..ddbe60398f2 100755
@@ -3806,6 +3806,39 @@ proc external_diff_get_one_file {diffid filename diffdir} {
                "revision $diffid"]
 }
 
+proc check_for_renames_in_diff {filepath} {
+    global ctext
+
+    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
+    }
+    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"]
+        }
+        return $renamed_filenames
+    }
+}
+
 proc external_diff {} {
     global nullid nullid2
     global flist_menu_file
@@ -3836,8 +3869,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 $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: db91954e18654eeebc54c900f44c704002e1866d

Signature · 1 line
gitgitgadget
#4 lore raw

Am 04.03.25 um 14:01 schrieb ToBoMi via GitGitGadget:

Quoted 16 lines

From: Tobias Boesch <[email protected]>

* If a file was renamed between commits and an external diff is started through gitk on the original or the renamed file name, gitk was unable to open the renamed file in the external diff editor. It failed to fetch the renamed file from git, because it fetched it using its original path in contrast to using the renamed path of the file.
* With this change gitk detects the rename and opens the external diff with the original and the renamed file instead of no file (it is able to fetch the renamed file path and name now from git).
* Since git doesn't destinguish between move or rename this also works for moved files.
* Showing the external diff with the original and the renamed file works when either of the files is selected in gitk.

Quoted 2 lines

---

I've picked up this patch, but haven't found time to look at it in detail. It will take some time. Please bear with me.

The commit message would need to be rewritten to match our usual style:

- We do not use bullet points for normal text paragraphs.
- We describe the status quo in present tense,
- and then the changes in imperative mood. (Like, "code, become so!")
- The subject is not in past tense, but usually also imperative.

-- Hannes

#6 lore raw

PATCH v4 1/1 gitk: add external diff file rename detection

In reply to ToBoMi via GitGitGadget

From: Tobias Boesch <[email protected]>

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.

---
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

Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-1774%2FToBoMi%2Fdetect_renamed_files_when_opening_diff-v4
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1774/ToBoMi/detect_renamed_files_when_opening_diff-v4
Pull-Request: https://github.com/gitgitgadget/git/pull/1774

Range-diff vs v3:

1: 1a64e989713 ! 1: 948b94bef5c gitk: added external diff file rename detection
@@ Metadata
Author: Tobias Boesch <[email protected]>

## Commit message ##
- gitk: added external diff file rename detection
+ gitk: add external diff file rename detection

- * If a file was renamed between commits and an external diff is started
- through gitk on the original or the renamed file name,
- gitk was unable to open the renamed file in the external diff editor.
- It failed to fetch the renamed file from git, because it fetched it
- using its original path in contrast to using the renamed path of the
- file.
- * With this change gitk detects the rename and opens the external diff
- with the original and the renamed file instead of no file (it is able
- to fetch the renamed file path and name now from git).
- * Since git doesn't destinguish between move or rename this also works
- for moved files.
- * Showing the external diff with the original and the renamed file
- works when either of the files is selected in gitk.
+ 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.

 gitk-git/gitk | 45 +++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 43 insertions(+), 2 deletions(-)
gitk-git/gitk +43 -2
index bc9efa18566..ddbe60398f2 100755
@@ -3806,6 +3806,39 @@ proc external_diff_get_one_file {diffid filename diffdir} {
                "revision $diffid"]
 }
 
+proc check_for_renames_in_diff {filepath} {
+    global ctext
+
+    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
+    }
+    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"]
+        }
+        return $renamed_filenames
+    }
+}
+
 proc external_diff {} {
     global nullid nullid2
     global flist_menu_file
@@ -3836,8 +3869,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 $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: 5b97a56fa0e7d580dc8865b73107407c9b3f0eff

Signature · 1 line
gitgitgadget
#5 lore raw
In reply to Johannes Sixt

Thanks for the update.
Take the time you need.
Changes to the message are following.

Quoted 30 lines

-----Ursprüngliche Nachricht-----
Von: Johannes Sixt <[email protected]>
Gesendet: Sonntag, 16. März 2025 17:22
An: Boesch, Tobias <[email protected]>
Cc: [email protected]; ToBoMi via GitGitGadget <[email protected]>
Betreff: Re: [PATCH v3] gitk: added external diff file rename detection

Am 04.03.25 um 14:01 schrieb ToBoMi via GitGitGadget:

Quoted 16 lines

From: Tobias Boesch <[email protected]>

* If a file was renamed between commits and an external diff is started through gitk on the original or the renamed file name, gitk was unable to open the renamed file in the external diff editor. It failed to fetch the renamed file from git, because it fetched it using its original path in contrast to using the renamed path of the file.
* With this change gitk detects the rename and opens the external diff with the original and the renamed file instead of no file (it is able to fetch the renamed file path and name now from git).
* Since git doesn't destinguish between move or rename this also works for moved files.
* Showing the external diff with the original and the renamed file works when either of the files is selected in gitk.

Quoted 2 lines

---

I've picked up this patch, but haven't found time to look at it in detail. It will take some time. Please bear with me.

Quoted 8 lines

The commit message would need to be rewritten to match our usual style:

- We do not use bullet points for normal text paragraphs.
- We describe the status quo in present tense,
- and then the changes in imperative mood. (Like, "code, become so!")
- The subject is not in past tense, but usually also imperative.

-- Hannes

-------------------------------------------------------------------------------------------------
imperial-Werke oHG, Sitz Bünde, Registergericht Bad Oeynhausen - HRA 4825

#7 lore raw

Re: [PATCH v4] gitk: add external diff file rename detection

In reply to ToBoMi via GitGitGadget

Am 28.04.25 um 10:47 schrieb ToBoMi via GitGitGadget:

Quoted 15 lines

From: Tobias Boesch <[email protected]>

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.

Quoted 1 line

Thank you. Sorry for taking so long to respond.

In general, I like the goal of this patch.

I am not familar, yet, how renamed files are represented in Gitk.

I wonder whether it is necessary to parse diff text to find renamed file names. When you click on a renamed file in the file list, the diff panel jumps to the corresponding text for both the original file name and the renamed file name. Is the information about those two names not already available?

Would it make sense to support also copied files?

Quoted 9 lines
 gitk-git/gitk | 45 +++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 43 insertions(+), 2 deletions(-)
gitk-git/gitk +0 -0
index bc9efa18566..ddbe60398f2 100755
@@ -3806,6 +3806,39 @@ proc external_diff_get_one_file {diffid filename diffdir} {
                "revision $diffid"]

gitk-git/gitk proc external_diff_get_one_file {diffid filename diffdir} { · line 3816

Quoted 10 lines
gitk-git/gitk +8 -0
 }
 
+proc check_for_renames_in_diff {filepath} {
+    global ctext
+
+    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)}

$filename can certainly have characters that are special for a regular expression, such as the fullstop, right? They need to be escaped or this will find the wrong file if one at all.

If this search wants to find one side of the rename, why does it ignore the directories?

gitk-git/gitk proc external_diff_get_one_file {diffid filename diffdir} { · line 3819

Quoted 3 lines
gitk-git/gitk +3 -0
+    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 != {})} {

Here and elsewhere in this patch we have a string comparison that uses '!='. It should use 'ne'.

Please avoid the extra set of parentheses, even around && (below). Also, in this code base, we do not have spaces around the condition inside {}.

Quoted 12 lines
gitk-git/gitk +12 -0
+        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
+    }
+    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 != {})} {

gitk-git/gitk proc external_diff_get_one_file {diffid filename diffdir} { · line 3841

Quoted 10 lines
gitk-git/gitk +10 -0
+        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"]
+        }
+        return $renamed_filenames
+    }
+}
+

Can we please have shorter variable names? They are all local variables. I have to spend so mucht time to find the end of the variable names before I can understand what the lines do...

Quoted 23 lines
gitk-git/gitk +10 -2
 proc external_diff {} {
     global nullid nullid2
     global flist_menu_file
@@ -3836,8 +3869,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 $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]
Quoted 1 line

base-commit: 5b97a56fa0e7d580dc8865b73107407c9b3f0eff

-- Hannes

#8 lore raw

AW: [PATCH v4] gitk: add external diff file rename detection

Quoted 27 lines

-----Ursprüngliche Nachricht-----
Von: Johannes Sixt <[email protected]>
Gesendet: Dienstag, 6. Mai 2025 21:39
An: ToBoMi via GitGitGadget <[email protected]>; [email protected]
Cc: Boesch, Tobias <[email protected]>
Betreff: Re: [PATCH v4] gitk: add external diff file rename detection

Am 28.04.25 um 10:47 schrieb ToBoMi via GitGitGadget:

Quoted 15 lines

From: Tobias Boesch <[email protected]>

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.

Quoted 1 line

Thank you. Sorry for taking so long to respond.

Quoted 8 lines

In general, I like the goal of this patch.

I am not familar, yet, how renamed files are represented in Gitk.

I wonder whether it is necessary to parse diff text to find renamed file names. When you click on a renamed file in the file list, the diff panel jumps to the corresponding text for both the original file name and the renamed file name. Is the information about those two names not already available?

I believe this could go wrong, because I think one can scroll after selecting the file and then right click on it or even another file to execute the external diff. Then the filenames are no longer at the top top of the text field.

I got around this by finding a git command that delivers the full paths of the original and the renamed file. Since git commands are executed in the codebase already I hope this is okay and maybe this is even more efficient than parsing the ctext.

Quoted 2 lines

Would it make sense to support also copied files?

I don't know how why this is a benefit and I believe that git currently does not handle copied files the way it does with renamed or moved files. That's why I would like to skip this.

Quoted 26 lines

gitk-git/gitk proc external_diff_get_one_file {diffid filename

Quoted 9 lines
 gitk-git/gitk | 45 +++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 43 insertions(+), 2 deletions(-)
gitk-git/gitk index renamed from gitk-git/gitk +0 -0

bc9efa18566..ddbe60398f2 100755

gitk-git/gitk +0 -0
@@ -3806,6 +3806,39 @@ proc external_diff_get_one_file {diffid filename

diffdir} {

gitk-git/gitk proc external_diff_get_one_file {diffid filename diffdir} { · line 3816

Quoted 11 lines
gitk-git/gitk +8 -0
                "revision $diffid"]
 }
 
+proc check_for_renames_in_diff {filepath} {
+    global ctext
+
+    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)}

$filename can certainly have characters that are special for a regular expression, such as the fullstop, right? They need to be escaped or this will find the wrong file if one at all.

Quoted 2 lines

If this search wants to find one side of the rename, why does it ignore the directories?

True. Now that a git command is used that emits the full path of the files This regex is no longer necessary and is removed.

Quoted 9 lines

gitk-git/gitk proc external_diff_get_one_file {diffid filename · line 3817

Quoted 2 lines
gitk-git/gitk +1 -0
+    set reg_expr_rename_from [subst -nobackslashes -nocommands

$reg_expr_rename_from]

gitk-git/gitk proc external_diff_get_one_file {diffid filename · line 3818

Quoted 1 line
gitk-git/gitk +1 -0
+    set rename_from_text_index [$ctext search -elide -regexp --

$reg_expr_rename_from 0.0]

gitk-git/gitk proc external_diff_get_one_file {diffid filename diffdir} { · line 3819

Quoted 1 line
gitk-git/gitk +1 -0
+    if { ($rename_from_text_index != {})} {

Here and elsewhere in this patch we have a string comparison that uses '!='. It should use 'ne'.

done

Quoted 3 lines

Please avoid the extra set of parentheses, even around && (below). Also, in this code base, we do not have spaces around the condition inside {}.

done

Quoted 30 lines

gitk-git/gitk proc external_diff_get_one_file {diffid filename · line 3821

Quoted 3 lines
gitk-git/gitk +2 -0
+        set reg_expr_rename_to {^rename to (.*)}
+        set rename_to_text_index [$ctext search -elide -regexp --

$reg_expr_rename_to $rename_from_text_index]

gitk-git/gitk proc external_diff_get_one_file {diffid filename · line 3822

Quoted 1 line
gitk-git/gitk +1 -0
+        if { ($rename_from_text_index != {}) && ($rename_to_text_index != {})

} {

gitk-git/gitk proc external_diff_get_one_file {diffid filename · line 3823

Quoted 1 line
gitk-git/gitk +1 -0
+            lappend renamed_filenames [$ctext get "$rename_from_text_index

+ $rename_from_text_identifier_length chars" "$rename_from_text_index lineend"]

gitk-git/gitk proc external_diff_get_one_file {diffid filename · line 3824

Quoted 1 line
gitk-git/gitk +1 -0
+            lappend renamed_filenames [$ctext get "$rename_to_text_index +

$rename_to_text_identifier_length chars" "$rename_to_text_index lineend"]

gitk-git/gitk proc external_diff_get_one_file {diffid filename diffdir} {

Quoted 5 lines
gitk-git/gitk +5 -0
+        }
+        return $renamed_filenames
+    }
+    set reg_expr_rename_to {^rename to (.*$filename)}
+    set reg_expr_rename_to [subst -nobackslashes -nocommands

$reg_expr_rename_to]

gitk-git/gitk proc external_diff_get_one_file {diffid filename · line 3830

Quoted 1 line
gitk-git/gitk +1 -0
+    set rename_to_text_index [$ctext search -elide -regexp --

$reg_expr_rename_to 0.0]

gitk-git/gitk proc external_diff_get_one_file {diffid filename diffdir} {

Quoted 3 lines
gitk-git/gitk +3 -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]

gitk-git/gitk proc external_diff_get_one_file {diffid filename · line 3834

Quoted 1 line
gitk-git/gitk +1 -0
+        if { ($rename_to_text_index != {}) && ($rename_from_text_index != {})

} {

gitk-git/gitk proc external_diff_get_one_file {diffid filename · line 3835

Quoted 1 line
gitk-git/gitk +1 -0
+            lappend renamed_filenames [$ctext get "$rename_from_text_index

+ $rename_from_text_identifier_length chars" "$rename_from_text_index lineend"]

gitk-git/gitk proc external_diff_get_one_file {diffid filename · line 3836

Quoted 1 line
gitk-git/gitk +1 -0
+            lappend renamed_filenames [$ctext get "$rename_to_text_index +

$rename_to_text_identifier_length chars" "$rename_to_text_index lineend"]

Quoted 9 lines

gitk-git/gitk proc external_diff_get_one_file {diffid filename diffdir} { · line 3841

Quoted 5 lines
gitk-git/gitk +5 -0
+        }
+        return $renamed_filenames
+    }
+}
+

Can we please have shorter variable names? They are all local variables. I have to spend so mucht time to find the end of the variable names before I can understand what the lines do...

done

Quoted 26 lines

gitk-git/gitk proc external_diff {} { · line 3839

Quoted 9 lines
gitk-git/gitk +0 -1
 proc external_diff {} {
     global nullid nullid2
     global flist_menu_file
@@ -3836,8 +3869,16 @@ proc external_diff {} {
     if {$diffdir eq {}} return
 
     # gather files to diff
-    set difffromfile [external_diff_get_one_file $diffidfrom $flist_menu_file

$diffdir]

gitk-git/gitk proc external_diff {} {

Quoted 6 lines
gitk-git/gitk +5 -1
-    set difftofile [external_diff_get_one_file $diffidto $flist_menu_file $diffdir]
+    set renamed_filenames [check_for_renames_in_diff $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]

gitk-git/gitk proc external_diff {} { · line 3877

Quoted 1 line
gitk-git/gitk +1 -0
+        set difftofile [external_diff_get_one_file $diffidto $rename_to_filename

$diffdir]

gitk-git/gitk proc external_diff {} { · line 3879

Quoted 2 lines
gitk-git/gitk +2 -0
+    } else {
+        set difffromfile [external_diff_get_one_file $diffidfrom $flist_menu_file

$diffdir]

gitk-git/gitk proc external_diff {} { · line 3880

Quoted 1 line
gitk-git/gitk +1 -0
+        set difftofile [external_diff_get_one_file $diffidto $flist_menu_file

$diffdir]

Quoted 2 lines
gitk-git/gitk +1 -0
+    }
 
Quoted 7 lines
Quoted 5 lines
gitk-git/gitk +0 -0
     if {$difffromfile ne {} && $difftofile ne {}} {
         set cmd [list [shellsplit $extdifftool] $difffromfile

$difftofile]

base-commit: 5b97a56fa0e7d580dc8865b73107407c9b3f0eff

-- Hannes

-------------------------------------------------------------------------------------------------
imperial-Werke oHG, Sitz Bünde, Registergericht Bad Oeynhausen - HRA 4825

#9 lore raw

PATCH v5 1/1 gitk: add external diff file rename detection

In reply to ToBoMi via GitGitGadget

From: Tobias Boesch <[email protected]>

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.

---
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(-)
gitk-git/gitk +42 -2
index 19689765cde..f97904f5fa2 100755
@@ -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

Signature · 1 line
gitgitgadget
#10 lore raw

AW: [PATCH v5] gitk: add external diff file rename detection

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

Quoted 232 lines

-----Ursprüngliche Nachricht-----
Von: ToBoMi via GitGitGadget <[email protected]>
Gesendet: Dienstag, 10. Juni 2025 10:30
An: [email protected]
Cc: Johannes Sixt <[email protected]>; Boesch, Tobias <[email protected]>; Boesch, Tobias <[email protected]>; Boesch, Tobias <[email protected]>
Betreff: [PATCH v5] gitk: add external diff file rename detection

From: Tobias Boesch <[email protected]>

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.

---
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(-)
gitk-git/gitk index 19689765cde..f97904f5fa2 renamed from gitk-git/gitk +0 -0

100755

gitk-git/gitk +24 -0
@@ -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]}

{

gitk-git/gitk +8 -1
+        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]

gitk-git/gitk +1 -1
-    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]

gitk-git/gitk +4 -0
+    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]

gitk-git/gitk +2 -0
+    } 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]
+ }

Quoted 6 lines

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

#11 lore raw

PATCH v6 1/1 gitk: add external diff file rename detection

In reply to ToBoMi via GitGitGadget

From: Tobias Boesch <[email protected]>

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.

---
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

Changes sine v5:

* Include filename in rename check. Find only the file and its renamed version that is selected in the GUI.
* Escape special characters in the filename to prevent that they are intepreted as part of a regular expression

Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-1774%2FToBoMi%2Fdetect_renamed_files_when_opening_diff-v6
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1774/ToBoMi/detect_renamed_files_when_opening_diff-v6
Pull-Request: https://github.com/gitgitgadget/git/pull/1774

Range-diff vs v5:

1: 0d28f189dc3 ! 1: f1c71e56324 gitk: add external diff file rename detection
@@ gitk-git/gitk: proc external_diff_get_one_file {diffid filename diffdir} {
+ $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]} {
++ set esc_chars {\\ | ? ^ * . $ \[ \] + \( \) \{ \}}
++ foreach char $esc_chars {
++ set filename [string map [list $char \\$char] $filename]
++ }
++ set regex_base {\d+\s\d+\s\S+\s\S+\s\S+\s+}
++ set regex_ren_from $regex_base[subst -nobackslashes -nocommands {(\S+$filename)\s+(\S+)}]
++ set regex_ren_to $regex_base[subst -nobackslashes -nocommands {(\S+)\s+(\S+$filename)}]
++ if {[regexp -line -- $regex_ren_from $cmd_result whole_match ren_from ren_to]} {
++ if {$ren_from ne {} && $ren_to ne {}} {
++ lappend renames $ren_from
++ lappend renames $ren_to
++ }
++ } elseif {[regexp -line -- $regex_ren_to $cmd_result whole_match ren_from ren_to]} {
+ if {$ren_from ne {} && $ren_to ne {}} {
+ lappend renames $ren_from
+ lappend renames $ren_to

 gitk-git/gitk | 54 +++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 52 insertions(+), 2 deletions(-)
gitk-git/gitk +52 -2
index 19689765cde..5d4b0fd3a68 100755
@@ -3775,6 +3775,48 @@ 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 esc_chars {\\ | ? ^ * . $ \[ \] + \( \) \{ \}}
+    foreach char $esc_chars {
+        set filename [string map [list $char \\$char] $filename]
+    }
+    set regex_base {\d+\s\d+\s\S+\s\S+\s\S+\s+}
+    set regex_ren_from $regex_base[subst -nobackslashes -nocommands {(\S+$filename)\s+(\S+)}]
+    set regex_ren_to $regex_base[subst -nobackslashes -nocommands {(\S+)\s+(\S+$filename)}]
+    if {[regexp -line -- $regex_ren_from $cmd_result whole_match ren_from ren_to]} {
+        if {$ren_from ne {} && $ren_to ne {}} {
+            lappend renames $ren_from
+            lappend renames $ren_to
+        }
+    } elseif {[regexp -line -- $regex_ren_to $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 +3847,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

Signature · 1 line
gitgitgadget
#12 lore raw

Re: [PATCH v6] gitk: add external diff file rename detection

Am 24.06.25 um 11:05 schrieb ToBoMi via GitGitGadget:

Quoted 14 lines

From: Tobias Boesch <[email protected]>

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.

In Git parlance, when we talk about "renamed" files, we always mean files that have any part of the path name changed (and not just the last path component). Therefore, this last sentence is redundant.

Quoted 5 lines

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.

An earlier round parsed the rename information from the patch text panel. I argued that it should not be necessary, because the file list already knows how to scroll the diff text panel to the correct section and should already what was renamed. It turns out it's not that simple.

But I still think that this information can be leveraged for this new purpose and that it is not necessary to invoke an external process. At a minimum, it should be possible to parse off the rename information from a smaller section of the patch text, because we know where the section pertaining to the file of interest starts. Look for uses of the variable 'difffilestart'.

I think that the goal of this patch can be achieved easier by parsing the patch text panel rather than parsing the output of another git command. I'll still comment on the presented solution just in case it turns out we must invoke git anyway.

Quoted 1 line

+ set renames [list {}]

This constructs a list with one element that is the empty string. I assume you meant one of these:

set renames [list]
set renames {}

Quoted 1 line

+ if {[catch {eval exec git diff $rev --find-renames --stat --raw --diff-filter=R} cmd_result]} {

A few things I have to note here:

- Don't use porcelain commands, use plumbing commands, i.e., git diff-tree, git diff-index, and git diff-files instead of git diff.
- Place non-option arguments after all options.
- Why use --stat?
- --numstat may be easier to parse than --raw, but see below.

gitk-git/gitk proc external_diff_get_one_file {diffid filename diffdir} { · line 3804

Quoted 10 lines
gitk-git/gitk +10 -0
+        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 esc_chars {\\ | ? ^ * . $ \[ \] + \( \) \{ \}}
+    foreach char $esc_chars {
+        set filename [string map [list $char \\$char] $filename]
+    }
+    set regex_base {\d+\s\d+\s\S+\s\S+\s\S+\s+}
+    set regex_ren_from $regex_base[subst -nobackslashes -nocommands {(\S+$filename)\s+(\S+)}]

This regular expression wants to parse the first of the two file names that are on the output line. But it assumes that the second of the two names cannot contain spaces: '(\S+)'. This is not a valid assumption.

Note that the output format of --raw is very restricted. In particular, the file names are separated from the rest not by space of any kind, but by TAB. A much stricter regular expression can be used. But still, TAB is a character that is permitted in file names, and the regular expression could match still match incorrectly. You can use -z to separate the parts with a zero byte in an unambiguous way and split the parts without a regular expression.

Quoted 1 line

+ set regex_ren_to $regex_base[subst -nobackslashes -nocommands {(\S+)\s+(\S+$filename)}]

I don't understand the purpose of 'subst' here. Is this not just

    set regex_ren_to $regex_base{(\S+)\s+(\S+}$filename{)}

gitk-git/gitk proc external_diff {} { · line 3853

Quoted 10 lines
gitk-git/gitk +4 -2
@@ -3805,8 +3847,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 != {}) } {

This expression doesn't follow the pattern that we see elsewhere, e.g., in the context below.

Please lose the redundant "_filename" in the variable names. In this context, it's clear that these are names, not indices or somehthing else. Also, when you look around, you notice that we normally don't use the underscore in variable names.

gitk-git/gitk proc external_diff {} { · line 3862

Quoted 9 lines
gitk-git/gitk +6 -0
+        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]

-- Hannes

#13 lore raw

PATCH v7 1/1 gitk: add external diff file rename detection

In reply to ToBoMi via GitGitGadget

From: Tobias Boesch <[email protected]>

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.

---
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

Changes sine v5:

* Include filename in rename check. Find only the file and its renamed version that is selected in the GUI.
* Escape special characters in the filename to prevent that they are intepreted as part of a regular expression

Changes since v6:

* Don't extra mention moved files in commit message
* Create empty list properly (avoid creting a list containing an empty string)
* Avoid snake case in variable names
* Change logic that checks the renames and gathers the file paths to use the difffilestart variable for efficient file path extraction
* Removed underscores in file names

Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-1774%2FToBoMi%2Fdetect_renamed_files_when_opening_diff-v7
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1774/ToBoMi/detect_renamed_files_when_opening_diff-v7
Pull-Request: https://github.com/gitgitgadget/git/pull/1774

Range-diff vs v6:

1: f1c71e5632 ! 1: 7c09a28951 gitk: add external diff file rename detection
@@ Commit message
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.

@@ gitk-git/gitk: proc external_diff_get_one_file {diffid filename diffdir} {
"revision $diffid"]
}

-+proc check_for_renames_in_diff {diffidfrom diffidto filepath} {
-+ global nullid nullid2
++proc check_for_renames_in_diff {filepath} { # renames
++ global difffilestart ctext
+
-+ 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 esc_chars {\\ | ? ^ * . $ \[ \] + \( \) \{ \}}
-+ foreach char $esc_chars {
-+ set filename [string map [list $char \\$char] $filename]
-+ }
-+ set regex_base {\d+\s\d+\s\S+\s\S+\s\S+\s+}
-+ set regex_ren_from $regex_base[subst -nobackslashes -nocommands {(\S+$filename)\s+(\S+)}]
-+ set regex_ren_to $regex_base[subst -nobackslashes -nocommands {(\S+)\s+(\S+$filename)}]
-+ if {[regexp -line -- $regex_ren_from $cmd_result whole_match ren_from ren_to]} {
-+ if {$ren_from ne {} && $ren_to ne {}} {
-+ lappend renames $ren_from
-+ lappend renames $ren_to
-+ }
-+ } elseif {[regexp -line -- $regex_ren_to $cmd_result whole_match ren_from ren_to]} {
-+ if {$ren_from ne {} && $ren_to ne {}} {
-+ lappend renames $ren_from
-+ lappend renames $ren_to
++ set renames {}
++
++ foreach loc $difffilestart {
++ set loclineend [string map {.0 .end} $loc]
++ set ctextline [$ctext get $loc $loclineend]
++ if {[string first $filename $ctextline] != -1} {
++ set fromlineloc "$loc + 2 lines"
++ set tolineloc "$loc + 3 lines"
++ set renfromline [$ctext get $fromlineloc [string map {.0 .end} $fromlineloc]]
++ set rentoline [$ctext get $tolineloc [string map {.0 .end} $tolineloc]]
++ if {[string match "rename from *" $renfromline]
++ && [string match "rename to *" $rentoline]} {
++ set renfrom [string range $renfromline 12 end]
++ set rento [string range $rentoline 10 end]
++ lappend renames $renfrom
++ lappend renames $rento
++ break
++ }
+ }
+ }
++
+ return $renames
+}
+
@@ 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 $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]
++ set renames [check_for_renames_in_diff $flist_menu_file]
++ set renamefrom [lindex $renames 0]
++ set renameto [lindex $renames 1]
++ if { ($renamefrom != {}) && ($renameto != {}) } {
++ set difffromfile [external_diff_get_one_file $diffidfrom $renamefrom $diffdir]
++ set difftofile [external_diff_get_one_file $diffidto $renameto $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]

 gitk-git/gitk | 40 ++++++++++++++++++++++++++++++++++++++--
 1 file changed, 38 insertions(+), 2 deletions(-)
gitk-git/gitk +38 -2
index c02db0194d..8f8f1cb9ab 100755
@@ -3788,6 +3788,34 @@ proc external_diff_get_one_file {diffid filename diffdir} {
                "revision $diffid"]
 }
 
+proc check_for_renames_in_diff {filepath} { # renames
+    global difffilestart ctext
+
+    set filename [file tail $filepath]
+    set renames {}
+    
+    foreach loc $difffilestart {
+        set loclineend [string map {.0 .end} $loc]
+        set ctextline [$ctext get $loc $loclineend]
+        if {[string first $filename $ctextline] != -1} {
+            set fromlineloc "$loc + 2 lines"
+            set tolineloc "$loc + 3 lines"
+            set renfromline [$ctext get $fromlineloc [string map {.0 .end} $fromlineloc]]
+            set rentoline [$ctext get $tolineloc [string map {.0 .end} $tolineloc]]
+            if {[string match "rename from *" $renfromline]
+                && [string match "rename to *" $rentoline]} {
+                set renfrom [string range $renfromline 12 end]
+                set rento [string range $rentoline 10 end]
+                lappend renames $renfrom
+                lappend renames $rento
+                break
+            }
+        }
+    }
+    
+    return $renames
+}
+
 proc external_diff {} {
     global nullid nullid2
     global flist_menu_file
@@ -3818,8 +3846,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 renames [check_for_renames_in_diff $flist_menu_file]
+    set renamefrom [lindex $renames 0]
+    set renameto [lindex $renames 1]
+    if { ($renamefrom != {}) && ($renameto != {}) } {
+        set difffromfile [external_diff_get_one_file $diffidfrom $renamefrom $diffdir]
+        set difftofile [external_diff_get_one_file $diffidto $renameto $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: 57da342c786f59eaeb436c18635cc1c7597733d9

Signature · 1 line
gitgitgadget
#14 lore raw

Re: [PATCH v7] gitk: add external diff file rename detection

Am 31.10.25 um 11:09 schrieb ToBoMi via GitGitGadget:

Quoted 12 lines

From: Tobias Boesch <[email protected]>

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.

Make a mental note of this sentence.

Quoted 7 lines

---

Changes since v6:
* Change logic that checks the renames and gathers the file paths to use the difffilestart variable for efficient file path extraction

Nice to see this change!

Quoted 11 lines
 gitk-git/gitk | 40 ++++++++++++++++++++++++++++++++++++++--
 1 file changed, 38 insertions(+), 2 deletions(-)
gitk-git/gitk +0 -0
index c02db0194d..8f8f1cb9ab 100755
@@ -3788,6 +3788,34 @@ proc external_diff_get_one_file {diffid filename diffdir} {
                "revision $diffid"]
 }
 

gitk-git/gitk proc external_diff_get_one_file {diffid filename diffdir} { · line 3800

Quoted 10 lines
gitk-git/gitk +10 -0
+proc check_for_renames_in_diff {filepath} { # renames
+    global difffilestart ctext
+
+    set filename [file tail $filepath]
+    set renames {}
+    
+    foreach loc $difffilestart {
+        set loclineend [string map {.0 .end} $loc]
+        set ctextline [$ctext get $loc $loclineend]
+        if {[string first $filename $ctextline] != -1} {

At this point, we are looking at the separator line, which contains the renamed-to file name. This means that we skip the following if the renamed-from file name was selected in the file list. The consequence is that the external diff shows differences between renamed files only when the renamed-to file name was selected, in contrast to what the commit message announces.

I suggest to check the file names extracted from the "renamed from" and "renamed to" lines instead.

gitk-git/gitk proc external_diff_get_one_file {diffid filename diffdir} { · line 3806

Quoted 6 lines
gitk-git/gitk +6 -0
+            set fromlineloc "$loc + 2 lines"
+            set tolineloc "$loc + 3 lines"
+            set renfromline [$ctext get $fromlineloc [string map {.0 .end} $fromlineloc]]
+            set rentoline [$ctext get $tolineloc [string map {.0 .end} $tolineloc]]
+            if {[string match "rename from *" $renfromline]
+                && [string match "rename to *" $rentoline]} {

These could be [string equal ...] with -length 12 and 10, respectively.

gitk-git/gitk proc external_diff_get_one_file {diffid filename diffdir} { · line 3808

Quoted 2 lines
gitk-git/gitk +2 -0
+                set renfrom [string range $renfromline 12 end]
+                set rento [string range $rentoline 10 end]

Here we now have a problem if the file names are not plain ASCII. Then we see escaped file names here. I consider this an independent bug in Gitk, and we can ignore the problem for now in this patch.

Quoted 14 lines
gitk-git/gitk +10 -0
+                lappend renames $renfrom
+                lappend renames $rento
+                break
+            }
+        }
+    }
+    
+    return $renames
+}
+
 proc external_diff {} {
     global nullid nullid2
     global flist_menu_file

gitk-git/gitk proc external_diff {} { · line 3852

Quoted 9 lines
gitk-git/gitk +4 -2
@@ -3818,8 +3846,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 renames [check_for_renames_in_diff $flist_menu_file]
+    set renamefrom [lindex $renames 0]
+    set renameto [lindex $renames 1]
+    if { ($renamefrom != {}) && ($renameto != {}) } {

Please let's write this as

    if {$renamefrom ne {} && $renameto ne {}} {
Quoted 11 lines
gitk-git/gitk +6 -0
+        set difffromfile [external_diff_get_one_file $diffidfrom $renamefrom $diffdir]
+        set difftofile [external_diff_get_one_file $diffidto $renameto $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: 57da342c786f59eaeb436c18635cc1c7597733d9

-- Hannes

#15 lore raw

PATCH v8 1/1 gitk: add external diff file rename detection

In reply to ToBoMi via GitGitGadget

From: Tobias Boesch <[email protected]>

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.

---
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

Changes sine v5:

* Include filename in rename check. Find only the file and its renamed version that is selected in the GUI.
* Escape special characters in the filename to prevent that they are intepreted as part of a regular expression

Changes since v6:

* Don't extra mention moved files in commit message
* Create empty list properly (avoid creting a list containing an empty string)
* Avoid snake case in variable names
* Change logic that checks the renames and gathers the file paths to use the difffilestart variable for efficient file path extraction
* Removed underscores in file names

Changes since v7:

* Find renames by checking the file names extracted from the "renamed from" and "renamed to" diff lines instead of the separator line (make rename detection also work when the original file was selected) (I checked this, but only in a repo where a file move occurred - that worked since the filename didn't change)
* Change "string match" and wildcard to "string equal" with length parameter
* Change empty list detection to use "ne" instead of "!=" and reduce parenthesis

Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-1774%2FToBoMi%2Fdetect_renamed_files_when_opening_diff-v8
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1774/ToBoMi/detect_renamed_files_when_opening_diff-v8
Pull-Request: https://github.com/gitgitgadget/git/pull/1774

Range-diff vs v7:

1: 7c09a28951 ! 1: 6fe99eb5a3 gitk: add external diff file rename detection
@@ gitk-git/gitk: proc external_diff_get_one_file {diffid filename diffdir} {
+
+ foreach loc $difffilestart {
+ set loclineend [string map {.0 .end} $loc]
-+ set ctextline [$ctext get $loc $loclineend]
-+ if {[string first $filename $ctextline] != -1} {
-+ set fromlineloc "$loc + 2 lines"
-+ set tolineloc "$loc + 3 lines"
-+ set renfromline [$ctext get $fromlineloc [string map {.0 .end} $fromlineloc]]
-+ set rentoline [$ctext get $tolineloc [string map {.0 .end} $tolineloc]]
-+ if {[string match "rename from *" $renfromline]
-+ && [string match "rename to *" $rentoline]} {
-+ set renfrom [string range $renfromline 12 end]
-+ set rento [string range $rentoline 10 end]
-+ lappend renames $renfrom
-+ lappend renames $rento
++ set fromlineloc "$loc + 2 lines"
++ set tolineloc "$loc + 3 lines"
++ set renfromline [$ctext get $fromlineloc [string map {.0 .end} $fromlineloc]]
++ set rentoline [$ctext get $tolineloc [string map {.0 .end} $tolineloc]]
++ if {[string equal -length 12 "rename from " $renfromline]
++ && [string equal -length 10 "rename to " $rentoline]} {
++ set renfrom [string range $renfromline 12 end]
++ set rento [string range $rentoline 10 end]
++ if {[string first $filename $renfrom] != -1
++ || [string first $filename $rento] != -1} {
++ lappend renames $renfrom
++ lappend renames $rento
+ break
+ }
+ }
@@ gitk-git/gitk: proc external_diff {} {
+ set renames [check_for_renames_in_diff $flist_menu_file]
+ set renamefrom [lindex $renames 0]
+ set renameto [lindex $renames 1]
-+ if { ($renamefrom != {}) && ($renameto != {}) } {
++ if {$renamefrom ne {} && $renameto ne {}} {
+ set difffromfile [external_diff_get_one_file $diffidfrom $renamefrom $diffdir]
+ set difftofile [external_diff_get_one_file $diffidto $renameto $diffdir]
+ } else {

 gitk-git/gitk | 40 ++++++++++++++++++++++++++++++++++++++--
 1 file changed, 38 insertions(+), 2 deletions(-)
gitk-git/gitk +38 -2
index c02db0194d..90cbfd4ec1 100755
@@ -3788,6 +3788,34 @@ proc external_diff_get_one_file {diffid filename diffdir} {
                "revision $diffid"]
 }
 
+proc check_for_renames_in_diff {filepath} { # renames
+    global difffilestart ctext
+
+    set filename [file tail $filepath]
+    set renames {}
+    
+    foreach loc $difffilestart {
+        set loclineend [string map {.0 .end} $loc]
+        set fromlineloc "$loc + 2 lines"
+        set tolineloc "$loc + 3 lines"
+        set renfromline [$ctext get $fromlineloc [string map {.0 .end} $fromlineloc]]
+        set rentoline [$ctext get $tolineloc [string map {.0 .end} $tolineloc]]
+        if {[string equal -length 12 "rename from " $renfromline]
+            && [string equal -length 10 "rename to " $rentoline]} {
+            set renfrom [string range $renfromline 12 end]
+            set rento [string range $rentoline 10 end]
+                if {[string first $filename $renfrom] != -1
+                    || [string first $filename $rento] != -1} {
+                    lappend renames $renfrom
+                    lappend renames $rento
+                break
+            }
+        }
+    }
+    
+    return $renames
+}
+
 proc external_diff {} {
     global nullid nullid2
     global flist_menu_file
@@ -3818,8 +3846,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 renames [check_for_renames_in_diff $flist_menu_file]
+    set renamefrom [lindex $renames 0]
+    set renameto [lindex $renames 1]
+    if {$renamefrom ne {} && $renameto ne {}} {
+        set difffromfile [external_diff_get_one_file $diffidfrom $renamefrom $diffdir]
+        set difftofile [external_diff_get_one_file $diffidto $renameto $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: 57da342c786f59eaeb436c18635cc1c7597733d9

Signature · 1 line
gitgitgadget
#16 lore raw

Re: [PATCH v8] gitk: add external diff file rename detection

Am 06.11.25 um 15:42 schrieb ToBoMi via GitGitGadget:

Quoted 13 lines

From: Tobias Boesch <[email protected]>

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.

Quoted 2 lines

---

Thanks, this is looking good now. I applied these whitespace fixes while queuing:

gitk +6 -6
index caaee16..9659466 100755
@@ -3811,7 +3811,7 @@ proc check_for_renames_in_diff {filepath} { # renames
 
     set filename [file tail $filepath]
     set renames {}
-    
+
     foreach loc $difffilestart {
         set loclineend [string map {.0 .end} $loc]
         set fromlineloc "$loc + 2 lines"
@@ -3822,15 +3822,15 @@ proc check_for_renames_in_diff {filepath} { # renames
             && [string equal -length 10 "rename to " $rentoline]} {
             set renfrom [string range $renfromline 12 end]
             set rento [string range $rentoline 10 end]
-                if {[string first $filename $renfrom] != -1
-                    || [string first $filename $rento] != -1} {
-                    lappend renames $renfrom
-                    lappend renames $rento
+            if {[string first $filename $renfrom] != -1
+                || [string first $filename $rento] != -1} {
+                lappend renames $renfrom
+                lappend renames $rento
                 break
             }
         }
     }
-    
+
     return $renames
 }
 

-- Hannes