Skip to contentSkip to conversation

Enable ability to visualise the results of git cherry C1 C2

PATCH In review Pierre Dumuid 2 participants 9 messages Dec 15, 2016 – Dec 31, 2016

lore
Share & tools
lore
#0 lore raw

PATCH 1/6 Enable ability to visualise the results of git cherry C1 C2

It's a bit clunky but it works!!

Usage:
- mark commit one (e.g. v45)
- Select commit two.
- Switch the gdttype to the option, "git-cherry between marked commit and:"

---
 gitk | 110 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 107 insertions(+), 3 deletions(-)
gitk +107 -3
index a14d7a1..50d1ef4 100755
@@ -2319,7 +2319,9 @@ proc makewindow {} {
 		[mc "containing:"] \
 		[mc "touching paths:"] \
 		[mc "adding/removing string:"] \
-		[mc "changing lines matching:"]]
+		[mc "changing lines matching:"] \
+		[mc "git-cherry between marked commit and:"] \
+	       ]
     trace add variable gdttype write gdttype_change
     pack .tf.lbar.gdttype -side left -fill y
 
@@ -4707,6 +4709,18 @@ proc gdttype_change {name ix op} {
     global gdttype highlight_files findstring findpattern
 
     stopfinding
+
+    if {$gdttype eq [mc "git-cherry between marked commit and:"]} {
+	if {$highlight_files ne {}} {
+	    set highlight_files {}
+	    hfiles_change
+	}
+	findcom_change
+	update_gitcherrylist
+	drawvisible
+	return
+    }
+
     if {$findstring ne {}} {
 	if {$gdttype eq [mc "containing:"]} {
 	    if {$highlight_files ne {}} {
@@ -4733,6 +4747,9 @@ proc find_change {name ix op} {
     stopfinding
     if {$gdttype eq [mc "containing:"]} {
 	findcom_change
+    } elseif {$gdttype eq [mc "git-cherry between marked commit and:"]} {
+	findcom_change
+	update_gitcherrylist
     } else {
 	if {$highlight_files ne $findstring} {
 	    set highlight_files $findstring
@@ -4742,6 +4759,54 @@ proc find_change {name ix op} {
     drawvisible
 }
 
+proc update_gitcherrylist {} {
+    global gitcherryids
+    global markedid
+    global findstring
+    global fstring
+    global currentid
+    global iddrawn
+
+    unset -nocomplain gitcherryids
+    set fs $findstring
+
+    if {$findstring eq {}} {
+	$fstring delete 0 end
+	$fstring insert 0 $currentid
+    }
+
+    if {![info exists markedid]} {
+	error_popup [mc "Please mark a git commit before using this find method!"]
+	return
+    }
+
+    #puts [join [list "Running cherry between: `" $markedid "` and `" $findstring "`"] ""]
+
+    if {[catch {set cherryOutput [exec git cherry $markedid $findstring]}]} {
+	puts "ERROR: An error occured running git-cherry!"
+	return
+    }
+
+    set cherryLines [split $cherryOutput "\n"]
+    foreach cherryLine $cherryLines {
+	set op [lindex [split $cherryLine " "] 0]
+	set gitSha [lindex [split $cherryLine " "] 1]
+
+	#puts [join [list "line is: `" $cherryLine "`, op:`" $op "`, gitSha:`" $gitSha "`"] ""]
+	if {$op eq "+"} {
+	    set gitcherryids($gitSha) 1
+	    if ([info exists iddrawn($gitSha)]) {
+		bolden $gitSha mainfontbold
+	    }
+
+	}
+    }
+    # puts "list is as follows"
+    #foreach {gitsha setBold} [array get gitcherryids] {
+    # 	puts [concat $gitsha = $setBold]
+    #}
+}
+
 proc findcom_change args {
     global nhighlights boldnameids
     global findpattern findtype findstring gdttype
@@ -4802,6 +4867,9 @@ proc do_file_hl {serial} {
 	set gdtargs [list "-S$highlight_files"]
     } elseif {$gdttype eq [mc "changing lines matching:"]} {
 	set gdtargs [list "-G$highlight_files"]
+    } elseif {$gdttype eq [mc "git-cherry between marked commit and:"]} {
+	# Skipping opening the file handle, filehighlight
+	return
     } else {
 	# must be "containing:", i.e. we're searching commit info
 	return
@@ -4882,6 +4950,17 @@ proc doesmatch {f} {
     }
 }
 
+proc askcherryhighlight {row id} {
+    global nhighlights gitcherryids
+
+    set isbold 0
+    if {[info exists gitcherryids($id)]} {
+	set isbold 1
+    }
+
+    set nhighlights($id) $isbold
+}
+
 proc askfindhighlight {row id} {
     global nhighlights commitinfo iddrawn
     global findloc
@@ -6216,6 +6295,7 @@ proc drawcmitrow {row} {
     global filehighlight fhighlights findpattern nhighlights
     global hlview vhighlights
     global highlight_related rhighlights
+    global gdttype
 
     if {$row >= $numcommits} return
 
@@ -6226,6 +6306,11 @@ proc drawcmitrow {row} {
     if {[info exists filehighlight] && ![info exists fhighlights($id)]} {
 	askfilehighlight $row $id
     }
+
+    if {$gdttype eq [mc "git-cherry between marked commit and:"] && ![info exists nhighlights($id)]} {
+	askcherryhighlight $row $id
+    }
+
     if {$findpattern ne {} && ![info exists nhighlights($id)]} {
 	askfindhighlight $row $id
     }
@@ -6776,7 +6861,9 @@ proc dofind {{dirn 1} {wrap 1}} {
     }
     set findcurline $findstartline
     nowbusy finding [mc "Searching"]
-    if {$gdttype ne [mc "containing:"] && ![info exists filehighlight]} {
+    if {$gdttype eq [mc "git-cherry between marked commit and:"]} {
+	# Don't do anything related to open do_file_hl since we'll just have a list
+    } elseif {$gdttype ne [mc "containing:"] && ![info exists filehighlight]} {
 	after cancel do_file_hl $fh_serial
 	do_file_hl $fh_serial
     }
@@ -6803,6 +6890,7 @@ proc findmore {} {
     global findstartline findcurline findallowwrap
     global find_dirn gdttype fhighlights fprogcoord
     global curview varcorder vrownum varccommits vrowmod
+    global gitcherryids
 
     if {![info exists find_dirn]} {
 	return 0
@@ -6848,7 +6936,23 @@ proc findmore {} {
     set arow [lindex $vrownum($curview) $ai]
     set ids [lindex $varccommits($curview,$a)]
     set arowend [expr {$arow + [llength $ids]}]
-    if {$gdttype eq [mc "containing:"]} {
+
+    if {$gdttype eq [mc "git-cherry between marked commit and:"]} {
+	for {} {$n > 0} {incr n -1; incr l $find_dirn} {
+	    if {$l < $arow || $l >= $arowend} {
+		incr ai $find_dirn
+		set a [lindex $varcorder($curview) $ai]
+		set arow [lindex $vrownum($curview) $ai]
+		set ids [lindex $varccommits($curview,$a)]
+		set arowend [expr {$arow + [llength $ids]}]
+	    }
+	    set id [lindex $ids [expr {$l - $arow}]]
+	    if {[info exists gitcherryids($id)]} {
+		set found 1
+	    }
+	    if {$found} break
+	}
+    } elseif {$gdttype eq [mc "containing:"]} {
 	for {} {$n > 0} {incr n -1; incr l $find_dirn} {
 	    if {$l < $arow || $l >= $arowend} {
 		incr ai $find_dirn
Signature · 1 line
2.10.2
#1 lore raw

PATCH 2/6 Add ability to follow a remote branch with a dialog

A suggested name is provided when creating a new "following" branch.

---
 gitk | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 82 insertions(+), 4 deletions(-)
gitk +82 -4
index 50d1ef4..36cba49 100755
@@ -2673,6 +2673,7 @@ proc makewindow {} {
 	{mc "Rename this branch" command mvbranch}
 	{mc "Remove this branch" command rmbranch}
 	{mc "Copy branch name" command {clipboard clear; clipboard append $headmenuhead}}
+	{mc "Follow this branch"  command follow_remote_branch_dialog}
     }
     $headctxmenu configure -tearoff 0
 
@@ -9947,23 +9948,100 @@ proc headmenu {x y id head} {
     stopfinding
     set headmenuid $id
     set headmenuhead $head
-    array set state {0 normal 1 normal 2 normal}
+    array set state {0 normal 1 normal 2 normal 3 normal}
     if {[string match "remotes/*" $head]} {
 	set localhead [string range $head [expr [string last / $head] + 1] end]
 	if {[info exists headids($localhead)]} {
 	    set state(0) disabled
 	}
-	array set state {1 disabled 2 disabled}
+	array set state {1 disabled 2 disabled 3 normal}
     }
     if {$head eq $mainhead} {
-	array set state {0 disabled 2 disabled}
+	array set state {0 disabled 2 disabled 3 disabled}
+    } else {
+	set state(3) disabled
     }
-    foreach i {0 1 2} {
+    foreach i {0 1 2 3} {
 	$headctxmenu entryconfigure $i -state $state($i)
     }
     tk_popup $headctxmenu $x $y
 }
 
+proc follow_remote_branch_dialog {} {
+    global headmenuhead NS
+
+    # check the tree is clean first??
+    nowbusy createFollowingBranch [mc "Creating following branch"]
+    update
+    dohidelocalchanges
+
+    set top .create_following_branch
+    catch {destroy $top}
+    ttk_toplevel $top
+    make_transient $top .
+
+    ${NS}::label $top.title -text [mc "Create following branch"]
+    grid $top.title - -pady 10
+
+    ${NS}::label $top.remote_branch_name_label -text [mc "Remote Branch:"]
+    ${NS}::entry $top.remote_branch_name -width 40
+    $top.remote_branch_name insert 0 $headmenuhead
+    $top.remote_branch_name conf -state readonly
+    grid $top.remote_branch_name_label $top.remote_branch_name -sticky w
+
+    ${NS}::label $top.new_branch_name_label -text [mc "Name:"]
+    ${NS}::entry $top.new_branch_name -width 40
+    set suggested_name $headmenuhead
+    regsub {^remotes/[^/]*/} $suggested_name {} suggested_name
+    $top.new_branch_name insert 0 $suggested_name
+    grid $top.new_branch_name_label $top.new_branch_name -sticky w
+
+    set actionCreate [list follow_remote_branch_callback $top]
+    set actionCancel "catch {notbusy createFollowingBranch; destroy $top}"
+
+    ${NS}::frame $top.buts
+    ${NS}::button $top.buts.go  -text [mc "Create"] -command $actionCreate
+    ${NS}::button $top.buts.can -text [mc "Cancel"] -command $actionCancel
+    grid $top.buts.go $top.buts.can
+    grid columnconfigure $top.buts 0 -weight 1 -uniform a
+    grid columnconfigure $top.buts 1 -weight 1 -uniform a
+    grid $top.buts - -pady 10 -sticky ew
+
+    bind $top <Key-Return> $actionCreate
+    bind $top <Key-Escape> $actionCancel
+
+    focus $top.new_branch_name
+}
+
+proc follow_remote_branch_callback {top} {
+    global headids idheads NS
+    set new_branch_name    [$top.new_branch_name get]
+    set remote_branch_name [$top.remote_branch_name get]
+    set cmdargs {}
+
+    if {$new_branch_name eq {}} {
+	error_popup [mc "Please specify a name for the new branch"] $top
+	return
+    }
+    if {[info exists headids($new_branch_name)]} {
+	error_popup [mc "The branch name you specified already exists, please specify a new name"] $top
+	return
+    }
+    catch {destroy $top}
+
+    lappend cmdargs $new_branch_name $remote_branch_name
+
+    if {[catch {
+	eval exec git branch --track $cmdargs
+    } err]} {
+	notbusy createFollowingBranch
+	error_popup $err
+    } else {
+	notbusy createFollowingBranch
+	updatecommits
+    }
+}
+
 proc cobranch {} {
     global headmenuid headmenuhead headids
     global showlocalchanges
Signature · 1 line
2.10.2
#2 lore raw

Re: [PATCH 2/6] Add ability to follow a remote branch with a dialog

Quoted 22 lines · Pierre Dumuid

A suggested name is provided when creating a new "following" branch.

---
 gitk | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 82 insertions(+), 4 deletions(-)
gitk +1 -0
index 50d1ef4..36cba49 100755
@@ -2673,6 +2673,7 @@ proc makewindow {} {
 	{mc "Rename this branch" command mvbranch}
 	{mc "Remove this branch" command rmbranch}
 	{mc "Copy branch name" command {clipboard clear; clipboard append $headmenuhead}}
+	{mc "Follow this branch"  command follow_remote_branch_dialog}
     }
     $headctxmenu configure -tearoff 0
 
@@ -9947,23 +9948,100 @@ proc headmenu {x y id head} {
     stopfinding
     set headmenuid $id

gitk proc headmenu {x y id head} { · line 9957

Quoted 10 lines
gitk +2 -2
     set headmenuhead $head
-    array set state {0 normal 1 normal 2 normal}
+    array set state {0 normal 1 normal 2 normal 3 normal}
     if {[string match "remotes/*" $head]} {
 	set localhead [string range $head [expr [string last / $head] + 1] end]
 	if {[info exists headids($localhead)]} {
 	    set state(0) disabled
 	}
-	array set state {1 disabled 2 disabled}
+	array set state {1 disabled 2 disabled 3 normal}

You set array(3) to "normal" just above, no need to do it again.

gitk proc headmenu {x y id head} { · line 9963

Quoted 7 lines
gitk +3 -1
     }
     if {$head eq $mainhead} {
-	array set state {0 disabled 2 disabled}
+	array set state {0 disabled 2 disabled 3 disabled}
+    } else {
+	set state(3) disabled
     }

As far as I can see, this will always end up with state(3) set to "disabled", won't it? Is that really what you want?

Paul.

#3 lore raw

PATCH 3/6 Add a tree view to the local branches, remote branches and tags, where / is treated as a directory seperator.

In reply to Pierre Dumuid
---
 gitk | 117 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 117 insertions(+)
gitk +117 -0
index 36cba49..a894f1d 100755
@@ -2089,6 +2089,10 @@ proc makewindow {} {
 	    {mc "Reread re&ferences" command rereadrefs}
 	    {mc "&List references" command showrefs -accelerator F2}
 	    {xx "" separator}
+	    {mc "List Local Branches"  command {show_tree_of_references_dialog "localBranches"}  -accelerator F6}
+	    {mc "List Remote Branches" command {show_tree_of_references_dialog "remoteBranches"} -accelerator F7}
+	    {mc "List Tags"            command {show_tree_of_references_dialog "tags"}           -accelerator F8}
+	    {xx "" separator}
 	    {mc "Start git &gui" command {exec git gui &}}
 	    {xx "" separator}
 	    {mc "&Quit" command doquit -accelerator Meta1-Q}
@@ -2601,6 +2605,9 @@ proc makewindow {} {
     bind . <F5> updatecommits
     bindmodfunctionkey Shift 5 reloadcommits
     bind . <F2> showrefs
+    bind . <F6> {show_tree_of_references_dialog "localBranches"}
+    bind . <F7> {show_tree_of_references_dialog "remoteBranches"}
+    bind . <F8> {show_tree_of_references_dialog "tags"}
     bindmodfunctionkey Shift 4 {newview 0}
     bind . <F4> edit_or_newview
     bind . <$M1B-q> doquit
@@ -10146,6 +10153,116 @@ proc rmbranch {} {
     run refill_reflist
 }
 
+# Display a tree view of local branches, remote branches, and tags according to view_type.
+#
+# @param string view_type
+#    Must be one of "localBranches", "remoteBranches", or "tags".
+#
+proc show_tree_of_references_dialog {view_type} {
+    global NS
+    global treefilelist
+    global headids tagids
+
+    switch -- $view_type {
+	"localBranches" {
+	    set dialogName "Local Branches"
+	    set top .show_tree_of_local_branches
+	    set listOfReferences [lsort [array names headids -regexp {^(?!remotes/)} ]]
+	    set truncateFrom 0
+	}
+	"remoteBranches" {
+	    set dialogName "Remote Branches"
+	    set top .show_tree_of_remote_branches
+	    set listOfReferences [lsort [array names headids -regexp {^remotes/} ]]
+	    set truncateFrom 8
+	}
+	"tags" {
+	    set dialogName "Tags"
+	    set top .show_tree_of_tags
+	    set listOfReferences [lsort [array names tagids]]
+	    set truncateFrom 0
+	}
+    }
+
+    if {[winfo exists $top]} {
+	raise $top
+	return
+    }
+
+    ttk_toplevel $top
+    wm title $top [mc "$dialogName: %s" [file tail [pwd]]]
+    wm geometry $top "600x900"
+
+    make_transient $top .
+
+    ## See http://www.tkdocs.com/tutorial/tree.html
+    ttk::treeview $top.referenceList -xscrollcommand "$top.horizontalScrollBar set" -yscrollcommand "$top.verticalScrollBar set"
+
+    # Populate the dialog
+    foreach reference $listOfReferences {
+	# The display name omits some leading characters (such as "remotes/")
+	set referenceDisplayName [string range $reference $truncateFrom end]
+
+	# Split the branch/tag by slashes, and incrementally ensure that each leaf in the treeview exists..
+	# otherwise add it.
+	set treeLeaves [split $referenceDisplayName "/"]
+	for {set i 0} {$i < [llength $treeLeaves]} {} {
+	    set leafReferenceId [join [lrange $treeLeaves 0 $i] "/"]
+	    if {![$top.referenceList exists $leafReferenceId]} {
+		if {$i > 0} {
+		    set parentLeafId [join [lrange $treeLeaves 0 $i-1] "/"]
+		} else {
+		    set parentLeafId {}
+		}
+		$top.referenceList insert $parentLeafId end -id $leafReferenceId -text [lindex $treeLeaves $i]
+	    }
+	    incr i
+	}
+    }
+
+    ${NS}::scrollbar $top.verticalScrollBar   -command "$top.referenceList yview" -orient vertical
+    ${NS}::scrollbar $top.horizontalScrollBar -command "$top.referenceList xview" -orient horizontal
+
+    grid $top.referenceList $top.verticalScrollBar -sticky nsew
+    grid $top.horizontalScrollBar x -sticky ew
+
+    bind $top <Key-Escape> [list destroy $top]
+
+    bind $top.referenceList <<TreeviewSelect>> {callback_tree_of_references_item_selected %W; break}
+
+    grid columnconfigure $top 0 -weight 1
+    grid rowconfigure    $top 0 -weight 1
+}
+
+# Call back for selecting a branch / tag in the tree of references
+#
+# @param w
+#
+proc callback_tree_of_references_item_selected {w} {
+    global headids tagids
+
+    set itemId [$w focus]
+    switch -- $w {
+	".show_tree_of_local_branches.referenceList" {
+	    if {[info exists headids($itemId)]} {
+		selbyid $headids($itemId)
+	    }
+	}
+	".show_tree_of_remote_branches.referenceList" {
+	    set itemId "remotes/$itemId"
+	    if {[info exists headids($itemId)]} {
+		selbyid $headids($itemId)
+	    }
+	}
+	".show_tree_of_tags.referenceList" {
+	    if {[info exists tagids($itemId)]} {
+		selbyid $tagids($itemId)
+	    }
+	}
+    }
+}
+
+
 # Display a list of tags and heads
 proc showrefs {} {
     global showrefstop bgcolor fgcolor selectbgcolor NS
Signature · 1 line
2.10.2
#4 lore raw

Re: [PATCH 3/6] Add a tree view to the local branches, remote branches and tags, where / is treated as a directory seperator.

Quoted 4 lines · Pierre Dumuid
---
 gitk | 117 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 117 insertions(+)

Nice idea in general... a few comments below. Also, please don't put the entire commit message in the subject line. :)

Quoted 58 lines
gitk +36 -0
index 36cba49..a894f1d 100755
@@ -2089,6 +2089,10 @@ proc makewindow {} {
 	    {mc "Reread re&ferences" command rereadrefs}
 	    {mc "&List references" command showrefs -accelerator F2}
 	    {xx "" separator}
+	    {mc "List Local Branches"  command {show_tree_of_references_dialog "localBranches"}  -accelerator F6}
+	    {mc "List Remote Branches" command {show_tree_of_references_dialog "remoteBranches"} -accelerator F7}
+	    {mc "List Tags"            command {show_tree_of_references_dialog "tags"}           -accelerator F8}
+	    {xx "" separator}
 	    {mc "Start git &gui" command {exec git gui &}}
 	    {xx "" separator}
 	    {mc "&Quit" command doquit -accelerator Meta1-Q}
@@ -2601,6 +2605,9 @@ proc makewindow {} {
     bind . <F5> updatecommits
     bindmodfunctionkey Shift 5 reloadcommits
     bind . <F2> showrefs
+    bind . <F6> {show_tree_of_references_dialog "localBranches"}
+    bind . <F7> {show_tree_of_references_dialog "remoteBranches"}
+    bind . <F8> {show_tree_of_references_dialog "tags"}
     bindmodfunctionkey Shift 4 {newview 0}
     bind . <F4> edit_or_newview
     bind . <$M1B-q> doquit
@@ -10146,6 +10153,116 @@ proc rmbranch {} {
     run refill_reflist
 }
 
+# Display a tree view of local branches, remote branches, and tags according to view_type.
+#
+# @param string view_type
+#    Must be one of "localBranches", "remoteBranches", or "tags".
+#
+proc show_tree_of_references_dialog {view_type} {
+    global NS
+    global treefilelist
+    global headids tagids
+
+    switch -- $view_type {
+	"localBranches" {
+	    set dialogName "Local Branches"
+	    set top .show_tree_of_local_branches
+	    set listOfReferences [lsort [array names headids -regexp {^(?!remotes/)} ]]
+	    set truncateFrom 0
+	}
+	"remoteBranches" {
+	    set dialogName "Remote Branches"
+	    set top .show_tree_of_remote_branches
+	    set listOfReferences [lsort [array names headids -regexp {^remotes/} ]]
+	    set truncateFrom 8
+	}
+	"tags" {
+	    set dialogName "Tags"
+	    set top .show_tree_of_tags
+	    set listOfReferences [lsort [array names tagids]]
+	    set truncateFrom 0
+	}

gitk proc rmbranch {} { · line 10194

Quoted 10 lines
gitk +10 -0
+    }
+
+    if {[winfo exists $top]} {
+	raise $top
+	return
+    }
+
+    ttk_toplevel $top
+    wm title $top [mc "$dialogName: %s" [file tail [pwd]]]
+    wm geometry $top "600x900"

Do you really need to do this? A fixed size like this is inevitably going to be too big for some users and too small for others.

gitk proc rmbranch {} { · line 10199

Quoted 5 lines
gitk +5 -0
+
+    make_transient $top .
+
+    ## See http://www.tkdocs.com/tutorial/tree.html
+    ttk::treeview $top.referenceList -xscrollcommand "$top.horizontalScrollBar set" -yscrollcommand "$top.verticalScrollBar set"

We still have the option for people to run without ttk, in case someone is still using an old Tcl/Tk version or just doesn't like the ttk widgets. However, there isn't an equivalent of ttk::treeview in the older Tk widget set. It would be OK to omit the new menu entries or to disable them if $use_ttk is false, but I don't want to have menu entries that will always cause gitk to blow up when $use_ttk is false.

We possibly should consider converting the file list view to use a ttk::treeview when $use_ttk is true.

Paul.

#5 lore raw

PATCH 4/6 Add DirDiffTool as additional option

In reply to Pierre Dumuid
---
 gitk | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)
gitk +17 -0
index a894f1d..5f27716 100755
@@ -2661,6 +2661,9 @@ proc makewindow {} {
 	{mc "Diff this -> marked commit" command {diffvsmark 0}}
 	{mc "Diff marked commit -> this" command {diffvsmark 1}}
 	{mc "Revert this commit" command revert}
+
+	{mc "DirDiffTool this -> selected" command {externalDiffToolVsSel 0}}
+	{mc "DirDiffTool selected -> this" command {externalDiffToolVsSel 1}}
     }
     $rowctxmenu configure -tearoff 0
 
@@ -9254,6 +9257,20 @@ proc diffvssel {dirn} {
     doseldiff $oldid $newid
 }
 
+proc externalDiffToolVsSel {diffDirection} {
+    global rowmenuid selectedline
+
+    if {$selectedline eq {}} return
+    if {$diffDirection} {
+	set oldid [commitonrow $selectedline]
+	set newid $rowmenuid
+    } else {
+	set oldid $rowmenuid
+	set newid [commitonrow $selectedline]
+    }
+    [exec git difftool -d $oldid $newid]
+}
+
 proc diffvsmark {dirn} {
     global rowmenuid markedid
 
Signature · 1 line
2.10.2
#6 lore raw

PATCH 5/6 gitk: Add a "Save file as" menu item

In reply to Pierre Dumuid

Previously, there was no easy way to save a particular file from the currently selected revision.

This patch adds a menu item "Save file as" to the file list popup menu, which opens a file selection dialog to determine the name under which a file should be saved. The default filename is of the form "[shortid] basename". If the current revision is the index, the default pattern is of the form "[index] basename". This works for both, the "Patch" and "Tree" view. The menu item is disabled for the "local uncommitted changes" fake revision.

---
 gitk | 36 ++++++++++++++++++++++++++++++++++++
 1 file changed, 36 insertions(+)
gitk +36 -0
index 5f27716..0903d2d 100755
@@ -2693,6 +2693,7 @@ proc makewindow {} {
 	{mc "Highlight this too" command {flist_hl 0}}
 	{mc "Highlight this only" command {flist_hl 1}}
 	{mc "External diff" command {external_diff}}
+	{mc "Save file as" command {save_file_as}}
 	{mc "Blame parent commit" command {external_blame 1}}
 	{mc "Copy path" command {clipboard clear; clipboard append $flist_menu_file}}
     }
@@ -3504,6 +3505,7 @@ proc sel_flist {w x y} {
 proc pop_flist_menu {w X Y x y} {
     global ctext cflist cmitmode flist_menu flist_menu_file
     global treediffs diffids
+    global nullid
 
     stopfinding
     set l [lindex [split [$w index "@$x,$y"] "."] 0]
@@ -3521,6 +3523,12 @@ proc pop_flist_menu {w X Y x y} {
     }
     # Disable "External diff" item in tree mode
     $flist_menu entryconf 2 -state $xdiffstate
+    set savefilestate "normal"
+    if {[lindex $diffids 0] eq $nullid} {
+	set savefilestate "disabled"
+    }
+    # Disable "Save file as" item "local uncommited changes" revision
+    $flist_menu entryconf 3 -state $savefilestate
     tk_popup $flist_menu $X $Y
 }
 
@@ -3632,6 +3640,34 @@ proc external_diff_get_one_file {diffid filename diffdir} {
 	       "revision $diffid"]
 }
 
+proc save_file_as {} {
+    global nullid nullid2
+    global flist_menu_file cmitmode
+    global diffids
+
+    set diffid [lindex $diffids 0]
+    if {$diffid == $nullid} {
+	return
+    } elseif {$diffid == $nullid2} {
+	set diffidtext [mc "index"]
+	set diffid ""
+	set whattext $diffidtext
+    } else {
+	set diffidtext [shortids $diffid]
+	set whattext "[mc "revision"] $diffidtext"
+    }
+    set diffid $diffid:
+    if {$cmitmode eq "tree"} {
+	set diffid $diffid./
+    }
+    set difffile "\[$diffidtext\] [file tail $flist_menu_file]"
+    set difffile [tk_getSaveFile -initialfile $difffile -title [mc "Save file as"] -parent .]
+    if {$difffile eq {}} {
+	return
+    }
+    save_file_from_commit $diffid$flist_menu_file $difffile $whattext
+}
+
 proc external_diff {} {
     global nullid nullid2
     global flist_menu_file
Signature · 1 line
2.10.2
#7 lore raw

PATCH 6/6 Rename 'remotes/' to 'r../' in heads

In reply to Pierre Dumuid
---
 gitk | 19 ++++++++++++++-----
 1 file changed, 14 insertions(+), 5 deletions(-)
gitk +14 -5
index 0903d2d..6f50b06 100755
@@ -6731,22 +6731,28 @@ proc drawtags {id x xt y1} {
     set yb [expr {$yt + $linespc - 1}]
     set xvals {}
     set wvals {}
+    set newTags {}
+
     set i -1
     foreach tag $marks {
 	incr i
+	set newTag $tag
+	regsub {^remotes} $newTag "r.." newTag
+
 	if {$i >= $ntags && $i < $ntags + $nheads && $tag eq $mainhead} {
-	    set wid [font measure mainfontbold $tag]
+	    set wid [font measure mainfontbold $newTag]
 	} else {
-	    set wid [font measure mainfont $tag]
+	    set wid [font measure mainfont $newTag]
 	}
 	lappend xvals $xt
 	lappend wvals $wid
+	lappend newTags $newTag
 	set xt [expr {$xt + $wid + $extra}]
     }
     set t [$canv create line $x $y1 [lindex $xvals end] $y1 \
 	       -width $lthickness -fill $reflinecolor -tags tag.$id]
     $canv lower $t
-    foreach tag $marks x $xvals wid $wvals {
+    foreach tag $marks x $xvals wid $wvals newTag $newTags {
 	set tag_quoted [string map {% %%} $tag]
 	set xl [expr {$x + $delta}]
 	set xr [expr {$x + $delta + $wid + $lthickness}]
@@ -6778,7 +6784,10 @@ proc drawtags {id x xt y1} {
 	    $canv create polygon $x $yt $xr $yt $xr $yb $x $yb \
 		-width 1 -outline black -fill $col -tags tag.$id
 	    if {[regexp {^(remotes/.*/|remotes/)} $tag match remoteprefix]} {
-	        set rwid [font measure mainfont $remoteprefix]
+		set newRemotePrefix $remoteprefix
+		regsub {^remotes} $newRemotePrefix "r.." newRemotePrefix
+
+	        set rwid [font measure mainfont $newRemotePrefix]
 		set xi [expr {$x + 1}]
 		set yti [expr {$yt + 1}]
 		set xri [expr {$x + $rwid}]
@@ -6786,7 +6795,7 @@ proc drawtags {id x xt y1} {
 			-width 0 -fill $remotebgcolor -tags tag.$id
 	    }
 	}
-	set t [$canv create text $xl $y1 -anchor w -text $tag -fill $headfgcolor \
+	set t [$canv create text $xl $y1 -anchor w -text $newTag -fill $headfgcolor \
 		   -font $font -tags [list tag.$id text]]
 	if {$ntags >= 0} {
 	    $canv bind $t <1> $tagclick
Signature · 1 line
2.10.2
#8 lore raw
In reply to Pierre Dumuid
Quoted 6 lines · Pierre Dumuid

It's a bit clunky but it works!!

Usage:
- mark commit one (e.g. v45)
- Select commit two.
- Switch the gdttype to the option, "git-cherry between marked commit and:"

This needs a better description. "Git-cherry between marked commit and" is a description of an implementation not a description of what's being achieved. Having read the git cherry man page, it seems like it's (Find commit) included in marked commit but not in this commit (or the other way around?). We would need a terser description that that, though.

[...]

Quoted 14 lines
gitk +14 -0
+proc update_gitcherrylist {} {
+    global gitcherryids
+    global markedid
+    global findstring
+    global fstring
+    global currentid
+    global iddrawn
+
+    unset -nocomplain gitcherryids
+    set fs $findstring
+
+    if {$findstring eq {}} {
+	$fstring delete 0 end
+	$fstring insert 0 $currentid

gitk proc find_change {name ix op} { · line 4785

Quoted 10 lines
gitk +10 -0
+    }
+
+    if {![info exists markedid]} {
+	error_popup [mc "Please mark a git commit before using this find method!"]
+	return
+    }
+
+    #puts [join [list "Running cherry between: `" $markedid "` and `" $findstring "`"] ""]
+
+    if {[catch {set cherryOutput [exec git cherry $markedid $findstring]}]} {

How long could the git cherry take to run? If it's more than a fraction of a second, then we would need to handle its output asynchronously like we do in [do_file_hl].

Paul.