From 8b5636a57ff078ac368f246f813b156552a0726c Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 17 Oct 2025 18:37:52 +0200 Subject: [PATCH 1/5] Revert "gitk: Only restore window size from ~/.gitk, not position" This reverts commit b9bee11526ec (gitk: Only restore window size from ~/.gitk, not position, 2008-03-10). The earlier commit e9937d2a03a4 (Make gitk work reasonably well on Cygwin, 2007-02-01) reworked the window layout considerably. Much of this became irrelevant around 2011 after Cygwin gained an X11 server and switched to a supportable port of the Unix/X11 Tcl/Tk (it is now on the current 8.6 code base). Part of the necessary change was to restore the window size across sessions, but the position was also restored. This raised complaints on the mailing list[*], because Gitk was opened on the wrong monitor. b9bee11526ec was the compromise, because it was only the size that mattered for the Cygwin layout engine to work. I personally, find it annoying when Gitk pops up on a random location on the screen, in particular, since many other applications restore the window positions across sessions, so why not Gitk as well? (I do not operate multi-monitor setups, so I cannot test the case.) [*] https://lore.kernel.org/git/47AAA254.2020008@thorn.ws/ Helped-by: Mark Levedahl Signed-off-by: Johannes Sixt --- gitk | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/gitk b/gitk index 6e4d71d585..275f353811 100755 --- a/gitk +++ b/gitk @@ -2764,17 +2764,9 @@ proc makewindow {} { .pwbottom add .bright .ctop add .pwbottom - # restore window width & height if known + # restore window position if known if {[info exists geometry(main)]} { - if {[scan $geometry(main) "%dx%d" w h] >= 2} { - if {$w > [winfo screenwidth .]} { - set w [winfo screenwidth .] - } - if {$h > [winfo screenheight .]} { - set h [winfo screenheight .] - } - wm geometry . "${w}x$h" - } + wm geometry . "$geometry(main)" } if {[info exists geometry(state)] && $geometry(state) eq "zoomed"} { From bf5a55ac5eaef91e87470d704613e6942500a810 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 17 Oct 2025 18:38:11 +0200 Subject: [PATCH 2/5] gitk: persist position and size of the Tags and Heads window The Tags and Heads window always opens at a default position and size, requiring users to reposition it each time. Remember its geometry between sessions in the config file as `geometry(showrefs)`. Note that the existing configuration is sourced in proc savestuff right before new settings are written. This makes the old settings available as local variables(!) and does not overwrite the current settings. Since we need access to the global geometry(showrefs), it is necessary to unset the local variable. Helped-by: Michael Rappazzo Signed-off-by: Johannes Sixt --- gitk | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/gitk b/gitk index 275f353811..ed616613ae 100755 --- a/gitk +++ b/gitk @@ -2131,12 +2131,14 @@ proc ttk_toplevel {w args} { return $w } -proc make_transient {window origin} { +proc make_transient {window origin {geometry ""}} { wm transient $window $origin - # Windows fails to place transient windows normally, so - # schedule a callback to center them on the parent. - if {[tk windowingsystem] eq {win32}} { + if {$geometry ne ""} { + after idle [list wm geometry $window $geometry] + } elseif {[tk windowingsystem] eq {win32}} { + # Windows fails to place transient windows normally, so + # schedule a callback to center them on the parent. after idle [list tk::PlaceWindow $window widget $origin] } } @@ -3106,6 +3108,11 @@ proc savestuff {w} { puts $f "set geometry(pwsash1) \"[.tf.histframe.pwclist sashpos 1] 1\"" puts $f "set geometry(botwidth) [winfo width .bleft]" puts $f "set geometry(botheight) [winfo height .bleft]" + unset -nocomplain geometry + global geometry + if {[info exists geometry(showrefs)]} { + puts $f "set geometry(showrefs) $geometry(showrefs)" + } array set view_save {} array set views {} @@ -10193,6 +10200,7 @@ proc rmbranch {} { proc showrefs {} { global showrefstop bgcolor fgcolor selectbgcolor global bglist fglist reflistfilter reflist maincursor + global geometry set top .showrefs set showrefstop $top @@ -10203,7 +10211,11 @@ proc showrefs {} { } ttk_toplevel $top wm title $top [mc "Tags and heads: %s" [file tail [pwd]]] - make_transient $top . + if {[info exists geometry(showrefs)]} { + make_transient $top . $geometry(showrefs) + } else { + make_transient $top . + } text $top.list -background $bgcolor -foreground $fgcolor \ -selectbackground $selectbgcolor -font mainfont \ -xscrollcommand "$top.xsb set" -yscrollcommand "$top.ysb set" \ @@ -10239,6 +10251,9 @@ proc showrefs {} { bind $top.list {sel_reflist %W %x %y; break} set reflist {} refill_reflist + # avoid being bound to child windows + bindtags $top [linsert [bindtags $top] 1 bind$top] + bind bind$top {set geometry(showrefs) [wm geometry %W]} } proc sel_reflist {w x y} { From 77e7aab693daee402ef37323715207c5a2daec9f Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 6 Nov 2025 09:20:41 +0100 Subject: [PATCH 3/5] gitk: fix a 'continue' statement outside a loop to 'return' When 5de460a2cfdd (gitk: Refactor per-line part of getblobdiffline and its support) moved the body of a loop into a separate function, several 'continue' statements were changed to 'return'. But one instance was missed. Fix it now. Signed-off-by: Johannes Sixt --- gitk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gitk b/gitk index c02db0194d..eb657aa1e4 100755 --- a/gitk +++ b/gitk @@ -8296,7 +8296,7 @@ proc parseblobdiffline {ids line} { if {![regexp {^diff (--cc|--git) } $line m type]} { set line [convertfrom utf-8 $line] $ctext insert end "$line\n" hunksep - continue + return } # start of a new file set diffinhdr 1 From d445a78873423c55b79f97361a082272acd17f7b Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 6 Nov 2025 10:42:37 +0100 Subject: [PATCH 4/5] gitk: show unescaped file names on 'rename' and 'copy' lines When a file is selected in the file list, the diff window scrolls to the corresponding section. The administrative data needed for this purpose is extracted from the 'rename from', 'rename to', and 'copy to' lines. Escaped file names are unescaped for this purpose. However, the lines shown in the diff window are left in the escaped form. This is not very pleasing. Replace the escaped form by the unescaped form. Add a section to treat the 'copy from' case. Signed-off-by: Johannes Sixt --- gitk | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/gitk b/gitk index eb657aa1e4..9e4f113c9b 100755 --- a/gitk +++ b/gitk @@ -8401,6 +8401,7 @@ proc parseblobdiffline {ids line} { if {$i >= 0} { setinlist difffilestart $i $curdiffstart } + set line "rename from $fname" } elseif {![string compare -length 10 $line "rename to "] || ![string compare -length 8 $line "copy to "]} { set fname [string range $line [expr 4 + [string first " to " $line] ] end] @@ -8408,6 +8409,13 @@ proc parseblobdiffline {ids line} { set fname [lindex $fname 0] } makediffhdr $fname $ids + set line "[lindex $line 0] to $fname" + } elseif {![string compare -length 10 $line "copy from "]} { + set fname [string range $line 10 end] + if {[string index $fname 0] eq "\""} { + set fname [lindex $fname 0] + } + set line "copy from $fname" } elseif {[string compare -length 3 $line "---"] == 0} { # do nothing return From bdb1cf831251b16d174f742178caac181add87f4 Mon Sep 17 00:00:00 2001 From: Tobias Boesch Date: Thu, 6 Nov 2025 14:42:11 +0000 Subject: [PATCH 5/5] gitk: add external diff file rename detection 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. Signed-off-by: Tobias Boesch Signed-off-by: Johannes Sixt --- gitk | 40 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/gitk b/gitk index bc9efa1856..9659466052 100755 --- a/gitk +++ b/gitk @@ -3806,6 +3806,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 @@ -3836,8 +3864,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]