From cb07fc2a29c86d1bc11f5415368f778d25d3d20a Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Mon, 6 Nov 2006 14:20:27 -0500 Subject: git-gui: Initial revision. This is based on Paul Mackerras' gitool prototype which he offered up to the community earlier in 2006. Its mostly however a rewrite from scratch of a Tcl/Tk based graphical interface for Git and the most common commands users might need to perform. Currently it can display the status of the current repository, and not much else. Signed-off-by: Shawn O. Pearce --- git-gui | 764 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 764 insertions(+) create mode 100755 git-gui (limited to 'git-gui') diff --git a/git-gui b/git-gui new file mode 100755 index 000000000..dfa300026 --- /dev/null +++ b/git-gui @@ -0,0 +1,764 @@ +#!/bin/sh +# Tcl ignores the next line -*- tcl -*- \ +exec wish "$0" -- "$@" + +# Copyright (C) 2006 Shawn Pearce, Paul Mackerras. All rights reserved. +# This program is free software; it may be used, copied, modified +# and distributed under the terms of the GNU General Public Licence, +# either version 2, or (at your option) any later version. + + +###################################################################### +## +## status + +set status_active 0 + +proc update_status {} { + global gitdir HEAD commit_type + global ui_index ui_other ui_status_value + global status_active file_states + + if {$status_active > 0} return + + array unset file_states + set ui_status_value {Refreshing file status...} + foreach w [list $ui_index $ui_other] { + $w conf -state normal + $w delete 0.0 end + $w conf -state disabled + } + + if {[catch {set HEAD [exec git rev-parse --verify HEAD]}]} { + set commit_type initial + } else { + set commit_type normal + } + + set ls_others [list | git ls-files --others -z \ + --exclude-per-directory=.gitignore] + set info_exclude [file join $gitdir info exclude] + if {[file readable $info_exclude]} { + lappend ls_others "--exclude-from=$info_exclude" + } + + set fd_di [open "| git diff-index --cached -z $HEAD" r] + set fd_df [open "| git diff-files -z" r] + set fd_lo [open $ls_others r] + set status_active 3 + + fconfigure $fd_di -blocking 0 -translation binary + fconfigure $fd_df -blocking 0 -translation binary + fconfigure $fd_lo -blocking 0 -translation binary + fileevent $fd_di readable [list read_diff_index $fd_di] + fileevent $fd_df readable [list read_diff_files $fd_df] + fileevent $fd_lo readable [list read_ls_others $fd_lo] +} + +proc read_diff_index {fd} { + global buf_rdi + + append buf_rdi [read $fd] + set pck [split $buf_rdi "\0"] + set buf_rdi [lindex $pck end] + foreach {m p} [lrange $pck 0 end-1] { + if {$m != {} && $p != {}} { + display_file $p [string index $m end]_ + } + } + status_eof $fd buf_rdi +} + +proc read_diff_files {fd} { + global buf_rdf + + append buf_rdf [read $fd] + set pck [split $buf_rdf "\0"] + set buf_rdf [lindex $pck end] + foreach {m p} [lrange $pck 0 end-1] { + if {$m != {} && $p != {}} { + display_file $p _[string index $m end] + } + } + status_eof $fd buf_rdf +} + +proc read_ls_others {fd} { + global buf_rlo + + append buf_rlo [read $fd] + set pck [split $buf_rlo "\0"] + set buf_rlo [lindex $pck end] + foreach p [lrange $pck 0 end-1] { + display_file $p _O + } + status_eof $fd buf_rlo +} + +proc status_eof {fd buf} { + global status_active $buf + global ui_fname_value ui_status_value + + if {[eof $fd]} { + set $buf {} + close $fd + if {[incr status_active -1] == 0} { + set ui_status_value {Ready.} + if {$ui_fname_value != {}} { + show_diff $ui_fname_value + } + } + } +} + +###################################################################### +## +## diff + +set diff_active 0 + +proc clear_diff {} { + global ui_diff ui_fname_value ui_fstatus_value + + $ui_diff conf -state normal + $ui_diff delete 0.0 end + $ui_diff conf -state disabled + set ui_fname_value {} + set ui_fstatus_value {} +} + +proc show_diff {path} { + global file_states HEAD status_active diff_3way diff_active + global ui_diff ui_fname_value ui_fstatus_value ui_status_value + + if {$status_active > 0} return + if {$diff_active} return + + clear_diff + set s $file_states($path) + set m [lindex $s 0] + set diff_3way 0 + set diff_active 1 + set ui_fname_value $path + set ui_fstatus_value [mapdesc $m $path] + set ui_status_value "Loading diff of $path..." + + set cmd [list | git diff-index -p $HEAD -- $path] + switch $m { + AM { + } + MM { + set cmd [list | git diff-index -p -c $HEAD $path] + } + _O { + if {[catch { + set fd [open $path r] + set content [read $fd] + close $fd + } err ]} { + set ui_status_value "Unable to display $path" + error_popup "Error loading file:\n$err" + return + } + $ui_diff conf -state normal + $ui_diff insert end $content + $ui_diff conf -state disabled + return + } + } + + if {[catch {set fd [open $cmd r]} err]} { + set ui_status_value "Unable to display $path" + error_popup "Error loading diff:\n$err" + return + } + + fconfigure $fd -blocking 0 + fileevent $fd readable [list read_diff $fd] +} + +proc read_diff {fd} { + global ui_diff ui_status_value diff_3way diff_active + + while {[gets $fd line] >= 0} { + if {[string match index* $line]} { + if {[string first , $line] >= 0} { + set diff_3way 1 + } + } + + $ui_diff conf -state normal + if {!$diff_3way} { + set x [string index $line 0] + switch -- $x { + "@" {set tags da} + "+" {set tags dp} + "-" {set tags dm} + default {set tags {}} + } + } else { + set x [string range $line 0 1] + switch -- $x { + default {set tags {}} + "@@" {set tags da} + "++" {set tags dp; set x " +"} + " +" {set tags {di bold}; set x "++"} + "+ " {set tags dni; set x "-+"} + "--" {set tags dm; set x " -"} + " -" {set tags {dm bold}; set x "--"} + "- " {set tags di; set x "+-"} + default {set tags {}} + } + set line [string replace $line 0 1 $x] + } + $ui_diff insert end $line $tags + $ui_diff insert end "\n" + $ui_diff conf -state disabled + } + + if {[eof $fd]} { + close $fd + set diff_active 0 + set ui_status_value {Ready.} + } +} + +###################################################################### +## +## ui helpers + +proc mapcol {state path} { + global all_cols + + if {[catch {set r $all_cols($state)}]} { + puts "error: no column for state={$state} $path" + return o + } + return $r +} + +proc mapicon {state path} { + global all_icons + + if {[catch {set r $all_icons($state)}]} { + puts "error: no icon for state={$state} $path" + return file_plain + } + return $r +} + +proc mapdesc {state path} { + global all_descs + + if {[catch {set r $all_descs($state)}]} { + puts "error: no desc for state={$state} $path" + return $state + } + return $r +} + +proc bsearch {w path} { + set hi [expr [lindex [split [$w index end] .] 0] - 2] + if {$hi == 0} { + return -1 + } + set lo 0 + while {$lo < $hi} { + set mi [expr [expr $lo + $hi] / 2] + set ti [expr $mi + 1] + set cmp [string compare [$w get $ti.1 $ti.end] $path] + if {$cmp < 0} { + set lo $ti + } elseif {$cmp == 0} { + return $mi + } else { + set hi $mi + } + } + return -[expr $lo + 1] +} + +proc merge_state {path state} { + global file_states + + if {[array names file_states -exact $path] == {}} { + set o __ + set s [list $o none none] + } else { + set s $file_states($path) + set o [lindex $s 0] + } + + set m [lindex $s 0] + if {[string index $state 0] == "_"} { + set state [string index $m 0][string index $state 1] + } elseif {[string index $state 0] == "*"} { + set state _[string index $state 1] + } + + if {[string index $state 1] == "_"} { + set state [string index $state 0][string index $m 1] + } elseif {[string index $state 1] == "*"} { + set state [string index $state 0]_ + } + + set file_states($path) [lreplace $s 0 0 $state] + return $o +} + +proc display_file {path state} { + global ui_index ui_other file_states + + set old_m [merge_state $path $state] + set s $file_states($path) + set m [lindex $s 0] + + if {[mapcol $m $path] == "o"} { + set ii 1 + set ai 2 + set iw $ui_index + set aw $ui_other + } else { + set ii 2 + set ai 1 + set iw $ui_other + set aw $ui_index + } + + set d [lindex $s $ii] + if {$d != "none"} { + set lno [bsearch $iw $path] + if {$lno >= 0} { + incr lno + $iw conf -state normal + $iw delete $lno.0 [expr $lno + 1].0 + $iw conf -state disabled + set s [lreplace $s $ii $ii none] + } + } + + set d [lindex $s $ai] + if {$d == "none"} { + set lno [expr abs([bsearch $aw $path] + 1) + 1] + $aw conf -state normal + set ico [$aw image create $lno.0 \ + -align center -padx 5 -pady 1 \ + -image [mapicon $m $path]] + $aw insert $lno.1 "$path\n" + $aw conf -state disabled + set file_states($path) [lreplace $s $ai $ai [list $ico]] + } elseif {[mapicon $m $path] != [mapicon $old_m $path]} { + set ico [lindex $d 0] + $aw image conf $ico -image [mapicon $m $path] + } +} + +proc toggle_mode {path} { + global file_states + + set s $file_states($path) + set m [lindex $s 0] + + switch -- $m { + AM - + _O { + set new A* + set cmd [list exec git update-index --add $path] + } + MM { + set new M* + set cmd [list exec git update-index $path] + } + _D { + set new D* + set cmd [list exec git update-index --remove $path] + } + default { + return + } + } + + if {[catch {eval $cmd} err]} { + error_popup "Error processing file:\n$err" + return + } + display_file $path $new +} + +###################################################################### +## +## icons + +set filemask { +#define mask_width 14 +#define mask_height 15 +static unsigned char mask_bits[] = { + 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, + 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, + 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f}; +} + +image create bitmap file_plain -background white -foreground black -data { +#define plain_width 14 +#define plain_height 15 +static unsigned char plain_bits[] = { + 0xfe, 0x01, 0x02, 0x03, 0x02, 0x05, 0x02, 0x09, 0x02, 0x1f, 0x02, 0x10, + 0x02, 0x10, 0x02, 0x10, 0x02, 0x10, 0x02, 0x10, 0x02, 0x10, 0x02, 0x10, + 0x02, 0x10, 0x02, 0x10, 0xfe, 0x1f}; +} -maskdata $filemask + +image create bitmap file_mod -background white -foreground blue -data { +#define mod_width 14 +#define mod_height 15 +static unsigned char mod_bits[] = { + 0xfe, 0x01, 0x02, 0x03, 0x7a, 0x05, 0x02, 0x09, 0x7a, 0x1f, 0x02, 0x10, + 0xfa, 0x17, 0x02, 0x10, 0xfa, 0x17, 0x02, 0x10, 0xfa, 0x17, 0x02, 0x10, + 0xfa, 0x17, 0x02, 0x10, 0xfe, 0x1f}; +} -maskdata $filemask + +image create bitmap file_tick -background white -foreground "#007000" -data { +#define file_tick_width 14 +#define file_tick_height 15 +static unsigned char file_tick_bits[] = { + 0xfe, 0x01, 0x02, 0x1a, 0x02, 0x0c, 0x02, 0x0c, 0x02, 0x16, 0x02, 0x16, + 0x02, 0x13, 0x00, 0x13, 0x86, 0x11, 0x8c, 0x11, 0xd8, 0x10, 0xf2, 0x10, + 0x62, 0x10, 0x02, 0x10, 0xfe, 0x1f}; +} -maskdata $filemask + +image create bitmap file_parttick -background white -foreground "#005050" -data { +#define parttick_width 14 +#define parttick_height 15 +static unsigned char parttick_bits[] = { + 0xfe, 0x01, 0x02, 0x03, 0x7a, 0x05, 0x02, 0x09, 0x7a, 0x1f, 0x02, 0x10, + 0x7a, 0x14, 0x02, 0x16, 0x02, 0x13, 0x8a, 0x11, 0xda, 0x10, 0x72, 0x10, + 0x22, 0x10, 0x02, 0x10, 0xfe, 0x1f}; +} -maskdata $filemask + +image create bitmap file_question -background white -foreground black -data { +#define file_question_width 14 +#define file_question_height 15 +static unsigned char file_question_bits[] = { + 0xfe, 0x01, 0x02, 0x02, 0xe2, 0x04, 0xf2, 0x09, 0x1a, 0x1b, 0x0a, 0x13, + 0x82, 0x11, 0xc2, 0x10, 0x62, 0x10, 0x62, 0x10, 0x02, 0x10, 0x62, 0x10, + 0x62, 0x10, 0x02, 0x10, 0xfe, 0x1f}; +} -maskdata $filemask + +image create bitmap file_removed -background white -foreground red -data { +#define file_removed_width 14 +#define file_removed_height 15 +static unsigned char file_removed_bits[] = { + 0xfe, 0x01, 0x02, 0x03, 0x02, 0x05, 0x02, 0x09, 0x02, 0x1f, 0x02, 0x10, + 0x1a, 0x16, 0x32, 0x13, 0xe2, 0x11, 0xc2, 0x10, 0xe2, 0x11, 0x32, 0x13, + 0x1a, 0x16, 0x02, 0x10, 0xfe, 0x1f}; +} -maskdata $filemask + +image create bitmap file_merge -background white -foreground blue -data { +#define file_merge_width 14 +#define file_merge_height 15 +static unsigned char file_merge_bits[] = { + 0xfe, 0x01, 0x02, 0x03, 0x62, 0x05, 0x62, 0x09, 0x62, 0x1f, 0x62, 0x10, + 0xfa, 0x11, 0xf2, 0x10, 0x62, 0x10, 0x02, 0x10, 0xfa, 0x17, 0x02, 0x10, + 0xfa, 0x17, 0x02, 0x10, 0xfe, 0x1f}; +} -maskdata $filemask + +foreach i { + {__ i "Unmodified" plain} + {_M i "Modified" mod} + {M_ i "Checked in" tick} + {MM i "Partially checked in" parttick} + + {_O o "Untracked" plain} + {A_ o "Added" tick} + {AM o "Partially added" parttick} + + {_D i "Missing" question} + {D_ i "Removed" removed} + {DD i "Removed" removed} + {DO i "Partially removed" removed} + + {UM i "Merge conflicts" merge} + {U_ i "Merge conflicts" merge} + } { + set all_cols([lindex $i 0]) [lindex $i 1] + set all_descs([lindex $i 0]) [lindex $i 2] + set all_icons([lindex $i 0]) file_[lindex $i 3] +} +unset filemask i + +###################################################################### +## +## util + +proc error_popup {msg} { + set w .error + toplevel $w + wm transient $w . + show_msg $w $w $msg +} + +proc show_msg {w top msg} { + message $w.m -text $msg -justify center -aspect 400 + pack $w.m -side top -fill x -padx 20 -pady 20 + button $w.ok -text OK -command "destroy $top" + pack $w.ok -side bottom -fill x + bind $top "grab $top; focus $top" + bind $top "destroy $top" + tkwait window $top +} + +###################################################################### +## +## ui commands + +proc do_gitk {} { + global tcl_platform + + if {$tcl_platform(platform) == "windows"} { + exec sh -c gitk & + } else { + exec gitk & + } +} + +proc do_quit {} { + destroy . +} + +proc do_rescan {} { + update_status +} + +# shift == 1: left click +# 3: right click +proc click {w x y shift wx wy} { + set pos [split [$w index @$x,$y] .] + set lno [lindex $pos 0] + set col [lindex $pos 1] + set path [$w get $lno.1 $lno.end] + if {$path == {}} return + + if {$col > 0 && $shift == 1} { + show_diff $path + } +} + +proc unclick {w x y} { + set pos [split [$w index @$x,$y] .] + set lno [lindex $pos 0] + set col [lindex $pos 1] + set path [$w get $lno.1 $lno.end] + if {$path == {}} return + + if {$col == 0} { + toggle_mode $path + } +} + +###################################################################### +## +## ui init + +set mainfont {Helvetica 10} +set difffont {Courier 10} +set maincursor [. cget -cursor] + +# -- Menu Bar +menu .mbar -tearoff 0 +.mbar add cascade -label Project -menu .mbar.project +.mbar add cascade -label Commit -menu .mbar.commit +.mbar add cascade -label Fetch -menu .mbar.fetch +.mbar add cascade -label Pull -menu .mbar.pull +. configure -menu .mbar + +# -- Project Menu +menu .mbar.project +.mbar.project add command -label Visulize \ + -command do_gitk \ + -font $mainfont +.mbar.project add command -label Quit \ + -command do_quit \ + -font $mainfont + +# -- Commit Menu +menu .mbar.commit +.mbar.commit add command -label Rescan \ + -command do_rescan \ + -font $mainfont + +# -- Fetch Menu +menu .mbar.fetch + +# -- Pull Menu +menu .mbar.pull + +# -- Main Window Layout +panedwindow .vpane -orient vertical +panedwindow .vpane.files -orient horizontal +.vpane add .vpane.files -sticky nsew +pack .vpane -anchor n -side top -fill both -expand 1 + +# -- Index File List +set ui_index .vpane.files.index.list +frame .vpane.files.index -height 100 -width 400 +label .vpane.files.index.title -text {Modified Files} \ + -background green \ + -font $mainfont +text $ui_index -background white -borderwidth 0 \ + -width 40 -height 10 \ + -font $mainfont \ + -yscrollcommand {.vpane.files.index.sb set} \ + -cursor $maincursor \ + -state disabled +scrollbar .vpane.files.index.sb -command [list $ui_index yview] +pack .vpane.files.index.title -side top -fill x +pack .vpane.files.index.sb -side right -fill y +pack $ui_index -side left -fill both -expand 1 +.vpane.files add .vpane.files.index -sticky nsew + +# -- Other (Add) File List +set ui_other .vpane.files.other.list +frame .vpane.files.other -height 100 -width 100 +label .vpane.files.other.title -text {Untracked Files} \ + -background red \ + -font $mainfont +text $ui_other -background white -borderwidth 0 \ + -width 40 -height 10 \ + -font $mainfont \ + -yscrollcommand {.vpane.files.other.sb set} \ + -cursor $maincursor \ + -state disabled +scrollbar .vpane.files.other.sb -command [list $ui_other yview] +pack .vpane.files.other.title -side top -fill x +pack .vpane.files.other.sb -side right -fill y +pack $ui_other -side left -fill both -expand 1 +.vpane.files add .vpane.files.other -sticky nsew + +# -- Diff Header +set ui_fname_value {} +set ui_fstatus_value {} +frame .vpane.diff -height 100 -width 100 +frame .vpane.diff.header +label .vpane.diff.header.l1 -text {File:} -font $mainfont +label .vpane.diff.header.l2 -textvariable ui_fname_value \ + -anchor w \ + -justify left \ + -font $mainfont +label .vpane.diff.header.l3 -text {Status:} -font $mainfont +label .vpane.diff.header.l4 -textvariable ui_fstatus_value \ + -width 20 \ + -anchor w \ + -justify left \ + -font $mainfont +pack .vpane.diff.header.l1 -side left +pack .vpane.diff.header.l2 -side left -fill x +pack .vpane.diff.header.l4 -side right +pack .vpane.diff.header.l3 -side right + +# -- Diff Body +frame .vpane.diff.body +set ui_diff .vpane.diff.body.t +text $ui_diff -background white -borderwidth 0 \ + -width 40 -height 20 \ + -font $difffont \ + -xscrollcommand {.vpane.diff.body.sbx set} \ + -yscrollcommand {.vpane.diff.body.sby set} \ + -cursor $maincursor \ + -state disabled +scrollbar .vpane.diff.body.sbx -orient horizontal \ + -command [list $ui_diff xview] +scrollbar .vpane.diff.body.sby -orient vertical \ + -command [list $ui_diff yview] +pack .vpane.diff.body.sbx -side bottom -fill x +pack .vpane.diff.body.sby -side right -fill y +pack $ui_diff -side left -fill both -expand 1 +pack .vpane.diff.header -side top -fill x +pack .vpane.diff.body -side bottom -fill both -expand 1 +.vpane add .vpane.diff -stick nsew + +$ui_diff tag conf dm -foreground red +$ui_diff tag conf dp -foreground blue +$ui_diff tag conf da -font [concat $difffont bold] +$ui_diff tag conf di -foreground "#00a000" +$ui_diff tag conf dni -foreground "#a000a0" +$ui_diff tag conf bold -font [concat $difffont bold] + +# -- Commit Area +frame .vpane.commarea -height 50 +.vpane add .vpane.commarea -stick nsew + +# -- Commit Area Buttons +frame .vpane.commarea.buttons +label .vpane.commarea.buttons.l -text {} \ + -anchor w \ + -justify left \ + -font $mainfont +pack .vpane.commarea.buttons.l -side top -fill x +button .vpane.commarea.buttons.rescan -text {Rescan} \ + -command do_rescan \ + -font $mainfont +pack .vpane.commarea.buttons.rescan -side top -fill x +button .vpane.commarea.buttons.ciall -text {Check-in All} \ + -command do_checkin_all \ + -font $mainfont +pack .vpane.commarea.buttons.ciall -side top -fill x +button .vpane.commarea.buttons.commit -text {Commit} \ + -command do_commit \ + -font $mainfont +pack .vpane.commarea.buttons.commit -side top -fill x +pack .vpane.commarea.buttons -side left -fill y + +# -- Commit Message Buffer +frame .vpane.commarea.buffer +set ui_comm .vpane.commarea.buffer.t +label .vpane.commarea.buffer.l -text {Commit Message:} \ + -anchor w \ + -justify left \ + -font $mainfont +text $ui_comm -background white -borderwidth 1 \ + -relief sunken \ + -width 75 -height 10 -wrap none \ + -font $difffont \ + -yscrollcommand {.vpane.commarea.buffer.sby set} \ + -cursor $maincursor +scrollbar .vpane.commarea.buffer.sby -command [list $ui_comm yview] +pack .vpane.commarea.buffer.l -side top -fill x +pack .vpane.commarea.buffer.sby -side right -fill y +pack $ui_comm -side left -fill y +pack .vpane.commarea.buffer -side left -fill y + +# -- Status Bar +set ui_status_value {Initializing...} +label .status -textvariable ui_status_value \ + -anchor w \ + -justify left \ + -borderwidth 1 \ + -relief sunken \ + -font $mainfont +pack .status -anchor w -side bottom -fill x + +# -- Key Bindings +bind . do_quit +bind . do_rescan +bind . do_rescan +bind . do_rescan +bind . do_quit +bind . do_quit +foreach i [list $ui_index $ui_other] { + bind $i {click %W %x %y 1 %X %Y; break} + bind $i {click %W %x %y 3 %X %Y; break} + bind $i {unclick %W %x %y; break} +} +unset i + +###################################################################### +## +## main + +if {[catch {set gitdir [exec git rev-parse --git-dir]} err]} { + show_msg {} . "Cannot find the git directory: $err" + exit 1 +} + +wm title . "git-ui ([file normalize [file dirname $gitdir]])" +focus -force $ui_comm +update_status -- cgit v1.2.1 From 131f503b7262b001eae434182feb08cb5e6fa4be Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Mon, 6 Nov 2006 16:07:32 -0500 Subject: git-gui: Additional early feature development. * Run refresh before diff-index. * Load saved commit message during rescan. * Save current commit message (if any) during quit. * Add Signed-off-by line to commit buffer. * Batch update-index invocations through --stdin. * Better highlight which file is in the diff viewer. * Key bindings for signoff, check-in all and commit. * Improved formatting of status table within source. Signed-off-by: Shawn O. Pearce --- git-gui | 270 ++++++++++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 214 insertions(+), 56 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index dfa300026..d74509a20 100755 --- a/git-gui +++ b/git-gui @@ -13,16 +13,30 @@ exec wish "$0" -- "$@" ## status set status_active 0 +set diff_active 0 +set checkin_active 0 +set update_index_fd {} + +proc is_busy {} { + global status_active diff_active checkin_active update_index_fd + + if {$status_active > 0 + || $diff_active + || $checkin_active + || $update_index_fd != {}} { + return 1 + } + return 0 +} proc update_status {} { global gitdir HEAD commit_type - global ui_index ui_other ui_status_value + global ui_index ui_other ui_status_value ui_comm global status_active file_states - if {$status_active > 0} return + if {[is_busy]} return array unset file_states - set ui_status_value {Refreshing file status...} foreach w [list $ui_index $ui_other] { $w conf -state normal $w delete 0.0 end @@ -35,6 +49,31 @@ proc update_status {} { set commit_type normal } + if {![$ui_comm edit modified] + || [string trim [$ui_comm get 0.0 end]] == {}} { + if {[load_message GITGUI_MSG]} { + } elseif {[load_message MERGE_MSG]} { + } elseif {[load_message SQUASH_MSG]} { + } + $ui_comm edit modified false + } + + set status_active 1 + set ui_status_value {Refreshing file status...} + set fd_rf [open "| git update-index -q --unmerged --refresh" r] + fconfigure $fd_rf -blocking 0 -translation binary + fileevent $fd_rf readable [list read_refresh $fd_rf] +} + +proc read_refresh {fd} { + global gitdir HEAD commit_type + global ui_index ui_other ui_status_value ui_comm + global status_active file_states + + read $fd + if {![eof $fd]} return + close $fd + set ls_others [list | git ls-files --others -z \ --exclude-per-directory=.gitignore] set info_exclude [file join $gitdir info exclude] @@ -42,10 +81,11 @@ proc update_status {} { lappend ls_others "--exclude-from=$info_exclude" } + set status_active 3 + set ui_status_value {Scanning for modified files ...} set fd_di [open "| git diff-index --cached -z $HEAD" r] set fd_df [open "| git diff-files -z" r] set fd_lo [open $ls_others r] - set status_active 3 fconfigure $fd_di -blocking 0 -translation binary fconfigure $fd_df -blocking 0 -translation binary @@ -55,6 +95,23 @@ proc update_status {} { fileevent $fd_lo readable [list read_ls_others $fd_lo] } +proc load_message {file} { + global gitdir ui_comm + + set f [file join $gitdir $file] + if {[file exists $f]} { + if {[catch {set fd [open $f r]}]} { + return 0 + } + set content [read $fd] + close $fd + $ui_comm delete 0.0 end + $ui_comm insert end $content + return 1 + } + return 0 +} + proc read_diff_index {fd} { global buf_rdi @@ -115,8 +172,6 @@ proc status_eof {fd buf} { ## ## diff -set diff_active 0 - proc clear_diff {} { global ui_diff ui_fname_value ui_fstatus_value @@ -128,11 +183,10 @@ proc clear_diff {} { } proc show_diff {path} { - global file_states HEAD status_active diff_3way diff_active + global file_states HEAD diff_3way diff_active global ui_diff ui_fname_value ui_fstatus_value ui_status_value - if {$status_active > 0} return - if {$diff_active} return + if {[is_busy]} return clear_diff set s $file_states($path) @@ -156,6 +210,7 @@ proc show_diff {path} { set content [read $fd] close $fd } err ]} { + set diff_active 0 set ui_status_value "Unable to display $path" error_popup "Error loading file:\n$err" return @@ -168,12 +223,13 @@ proc show_diff {path} { } if {[catch {set fd [open $cmd r]} err]} { + set diff_active 0 set ui_status_value "Unable to display $path" error_popup "Error loading diff:\n$err" return } - fconfigure $fd -blocking 0 + fconfigure $fd -blocking 0 -translation binary fileevent $fd readable [list read_diff $fd] } @@ -353,6 +409,32 @@ proc display_file {path state} { } } +proc with_update_index {body} { + global update_index_fd + + if {$update_index_fd == {}} { + set update_index_fd [open \ + "| git update-index --add --remove -z --stdin" \ + w] + fconfigure $update_index_fd -translation binary + uplevel 1 $body + close $update_index_fd + set update_index_fd {} + } else { + uplevel 1 $body + } +} + +proc update_index {path} { + global update_index_fd + + if {$update_index_fd == {}} { + error {not in with_update_index} + } else { + puts -nonewline $update_index_fd "$path\0" + } +} + proc toggle_mode {path} { global file_states @@ -361,27 +443,14 @@ proc toggle_mode {path} { switch -- $m { AM - - _O { - set new A* - set cmd [list exec git update-index --add $path] - } - MM { - set new M* - set cmd [list exec git update-index $path] - } - _D { - set new D* - set cmd [list exec git update-index --remove $path] - } - default { - return - } + _O {set new A*} + _M - + MM {set new M*} + _D {set new D*} + default {return} } - if {[catch {eval $cmd} err]} { - error_popup "Error processing file:\n$err" - return - } + with_update_index {update_index $path} display_file $path $new } @@ -416,10 +485,10 @@ static unsigned char mod_bits[] = { 0xfa, 0x17, 0x02, 0x10, 0xfe, 0x1f}; } -maskdata $filemask -image create bitmap file_tick -background white -foreground "#007000" -data { -#define file_tick_width 14 -#define file_tick_height 15 -static unsigned char file_tick_bits[] = { +image create bitmap file_fulltick -background white -foreground "#007000" -data { +#define file_fulltick_width 14 +#define file_fulltick_height 15 +static unsigned char file_fulltick_bits[] = { 0xfe, 0x01, 0x02, 0x1a, 0x02, 0x0c, 0x02, 0x0c, 0x02, 0x16, 0x02, 0x16, 0x02, 0x13, 0x00, 0x13, 0x86, 0x11, 0x8c, 0x11, 0xd8, 0x10, 0xf2, 0x10, 0x62, 0x10, 0x02, 0x10, 0xfe, 0x1f}; @@ -461,27 +530,31 @@ static unsigned char file_merge_bits[] = { 0xfa, 0x17, 0x02, 0x10, 0xfe, 0x1f}; } -maskdata $filemask +set max_status_desc 0 foreach i { - {__ i "Unmodified" plain} - {_M i "Modified" mod} - {M_ i "Checked in" tick} - {MM i "Partially checked in" parttick} - - {_O o "Untracked" plain} - {A_ o "Added" tick} - {AM o "Partially added" parttick} - - {_D i "Missing" question} - {D_ i "Removed" removed} - {DD i "Removed" removed} - {DO i "Partially removed" removed} - - {UM i "Merge conflicts" merge} - {U_ i "Merge conflicts" merge} + {__ i plain "Unmodified"} + {_M i mod "Modified"} + {M_ i fulltick "Checked in"} + {MM i parttick "Partially checked in"} + + {_O o plain "Untracked"} + {A_ o fulltick "Added"} + {AM o parttick "Partially added"} + + {_D i question "Missing"} + {D_ i removed "Removed"} + {DD i removed "Removed"} + {DO i removed "Removed (still exists)"} + + {UM i merge "Merge conflicts"} + {U_ i merge "Merge conflicts"} } { + if {$max_status_desc < [string length [lindex $i 3]]} { + set max_status_desc [string length [lindex $i 3]] + } set all_cols([lindex $i 0]) [lindex $i 1] - set all_descs([lindex $i 0]) [lindex $i 2] - set all_icons([lindex $i 0]) file_[lindex $i 3] + set all_icons([lindex $i 0]) file_[lindex $i 2] + set all_descs([lindex $i 0]) [lindex $i 3] } unset filemask i @@ -521,6 +594,20 @@ proc do_gitk {} { } proc do_quit {} { + global gitdir ui_comm + + set save [file join $gitdir GITGUI_MSG] + if {[$ui_comm edit modified] + && [string trim [$ui_comm get 0.0 end]] != {}} { + catch { + set fd [open $save w] + puts $fd [string trim [$ui_comm get 0.0 end]] + close $fd + } + } elseif {[file exists $save]} { + file delete $save + } + destroy . } @@ -528,9 +615,52 @@ proc do_rescan {} { update_status } +proc do_checkin_all {} { + global checkin_active ui_status_value + + if {[is_busy]} return + + set checkin_active 1 + set ui_status_value {Checking in all files...} + after 1 { + with_update_index { + foreach path [array names file_states] { + set s $file_states($path) + set m [lindex $s 0] + switch -- $m { + AM - + MM - + _M - + _D {toggle_mode $path} + } + } + } + set checkin_active 0 + set ui_status_value {Ready.} + } +} + +proc do_signoff {} { + global ui_comm + + catch { + set me [exec git var GIT_COMMITTER_IDENT] + if {[regexp {(.*) [0-9]+ [-+0-9]+$} $me me name]} { + set str "Signed-off-by: $name" + if {[$ui_comm get {end -1c linestart} {end -1c}] != $str} { + $ui_comm insert end "\n" + $ui_comm insert end $str + $ui_comm see end + } + } + } +} + # shift == 1: left click # 3: right click proc click {w x y shift wx wy} { + global ui_index ui_other + set pos [split [$w index @$x,$y] .] set lno [lindex $pos 0] set col [lindex $pos 1] @@ -538,6 +668,9 @@ proc click {w x y shift wx wy} { if {$path == {}} return if {$col > 0 && $shift == 1} { + $ui_index tag remove in_diff 0.0 end + $ui_other tag remove in_diff 0.0 end + $w tag add in_diff $lno.0 [expr $lno + 1].0 show_diff $path } } @@ -549,7 +682,7 @@ proc unclick {w x y} { set path [$w get $lno.1 $lno.end] if {$path == {}} return - if {$col == 0} { + if {$col == 0 && ![is_busy]} { toggle_mode $path } } @@ -584,6 +717,15 @@ menu .mbar.commit .mbar.commit add command -label Rescan \ -command do_rescan \ -font $mainfont +.mbar.commit add command -label {Check-in All Files} \ + -command do_checkin_all \ + -font $mainfont +.mbar.commit add command -label {Sign Off} \ + -command do_signoff \ + -font $mainfont +.mbar.commit add command -label Commit \ + -command do_commit \ + -font $mainfont # -- Fetch Menu menu .mbar.fetch @@ -633,10 +775,13 @@ pack .vpane.files.other.sb -side right -fill y pack $ui_other -side left -fill both -expand 1 .vpane.files add .vpane.files.other -sticky nsew +$ui_index tag conf in_diff -font [concat $mainfont bold] +$ui_other tag conf in_diff -font [concat $mainfont bold] + # -- Diff Header set ui_fname_value {} set ui_fstatus_value {} -frame .vpane.diff -height 100 -width 100 +frame .vpane.diff -height 50 -width 400 frame .vpane.diff.header label .vpane.diff.header.l1 -text {File:} -font $mainfont label .vpane.diff.header.l2 -textvariable ui_fname_value \ @@ -645,7 +790,7 @@ label .vpane.diff.header.l2 -textvariable ui_fname_value \ -font $mainfont label .vpane.diff.header.l3 -text {Status:} -font $mainfont label .vpane.diff.header.l4 -textvariable ui_fstatus_value \ - -width 20 \ + -width $max_status_desc \ -anchor w \ -justify left \ -font $mainfont @@ -658,7 +803,7 @@ pack .vpane.diff.header.l3 -side right frame .vpane.diff.body set ui_diff .vpane.diff.body.t text $ui_diff -background white -borderwidth 0 \ - -width 40 -height 20 \ + -width 80 -height 15 \ -font $difffont \ -xscrollcommand {.vpane.diff.body.sbx set} \ -yscrollcommand {.vpane.diff.body.sby set} \ @@ -693,19 +838,27 @@ label .vpane.commarea.buttons.l -text {} \ -justify left \ -font $mainfont pack .vpane.commarea.buttons.l -side top -fill x +pack .vpane.commarea.buttons -side left -fill y + button .vpane.commarea.buttons.rescan -text {Rescan} \ -command do_rescan \ -font $mainfont pack .vpane.commarea.buttons.rescan -side top -fill x + button .vpane.commarea.buttons.ciall -text {Check-in All} \ -command do_checkin_all \ -font $mainfont pack .vpane.commarea.buttons.ciall -side top -fill x + +button .vpane.commarea.buttons.signoff -text {Sign Off} \ + -command do_signoff \ + -font $mainfont +pack .vpane.commarea.buttons.signoff -side top -fill x + button .vpane.commarea.buttons.commit -text {Commit} \ -command do_commit \ -font $mainfont pack .vpane.commarea.buttons.commit -side top -fill x -pack .vpane.commarea.buttons -side left -fill y # -- Commit Message Buffer frame .vpane.commarea.buffer @@ -741,6 +894,11 @@ bind . do_quit bind . do_rescan bind . do_rescan bind . do_rescan +bind . do_signoff +bind . do_signoff +bind . do_checkin_all +bind . do_checkin_all +bind . do_commit bind . do_quit bind . do_quit foreach i [list $ui_index $ui_other] { -- cgit v1.2.1 From 6f6eed286f6a056fab1f887871ba5287f609e1f1 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Mon, 6 Nov 2006 18:22:19 -0500 Subject: git-gui: Fixed UI layout problems on Windows. Signed-off-by: Shawn O. Pearce --- git-gui | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index d74509a20..3ee32e105 100755 --- a/git-gui +++ b/git-gui @@ -229,7 +229,7 @@ proc show_diff {path} { return } - fconfigure $fd -blocking 0 -translation binary + fconfigure $fd -blocking 0 -translation auto fileevent $fd readable [list read_diff $fd] } @@ -237,6 +237,10 @@ proc read_diff {fd} { global ui_diff ui_status_value diff_3way diff_active while {[gets $fd line] >= 0} { + if {[string match {diff --git *} $line]} continue + if {[string match {diff --combined *} $line]} continue + if {[string match {--- *} $line]} continue + if {[string match {+++ *} $line]} continue if {[string match index* $line]} { if {[string first , $line] >= 0} { set diff_3way 1 @@ -584,8 +588,9 @@ proc show_msg {w top msg} { ## ui commands proc do_gitk {} { - global tcl_platform + global tcl_platform ui_status_value + set ui_status_value "Please wait... Starting gitk..." if {$tcl_platform(platform) == "windows"} { exec sh -c gitk & } else { @@ -705,7 +710,7 @@ menu .mbar -tearoff 0 # -- Project Menu menu .mbar.project -.mbar.project add command -label Visulize \ +.mbar.project add command -label Visualize \ -command do_gitk \ -font $mainfont .mbar.project add command -label Quit \ @@ -736,7 +741,7 @@ menu .mbar.pull # -- Main Window Layout panedwindow .vpane -orient vertical panedwindow .vpane.files -orient horizontal -.vpane add .vpane.files -sticky nsew +.vpane add .vpane.files -sticky nsew -height 100 -width 400 pack .vpane -anchor n -side top -fill both -expand 1 # -- Index File List @@ -781,7 +786,7 @@ $ui_other tag conf in_diff -font [concat $mainfont bold] # -- Diff Header set ui_fname_value {} set ui_fstatus_value {} -frame .vpane.diff -height 50 -width 400 +frame .vpane.diff -height 200 -width 400 frame .vpane.diff.header label .vpane.diff.header.l1 -text {File:} -font $mainfont label .vpane.diff.header.l2 -textvariable ui_fname_value \ @@ -803,7 +808,7 @@ pack .vpane.diff.header.l3 -side right frame .vpane.diff.body set ui_diff .vpane.diff.body.t text $ui_diff -background white -borderwidth 0 \ - -width 80 -height 15 \ + -width 80 -height 15 -wrap none \ -font $difffont \ -xscrollcommand {.vpane.diff.body.sbx set} \ -yscrollcommand {.vpane.diff.body.sby set} \ @@ -828,7 +833,7 @@ $ui_diff tag conf dni -foreground "#a000a0" $ui_diff tag conf bold -font [concat $difffont bold] # -- Commit Area -frame .vpane.commarea -height 50 +frame .vpane.commarea -height 150 .vpane add .vpane.commarea -stick nsew # -- Commit Area Buttons -- cgit v1.2.1 From e210e67451f22f97c1476d6b78b6fa7fdd5817f9 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Mon, 6 Nov 2006 19:12:58 -0500 Subject: git-gui: Corrected keyboard bindings on Windows, improved state management. When we are refreshing from the index or updating the index we shouldn't let the user cause other index based operations to occur as these would likely conflict with the currently running operations possibly causing some index changes to be lost. Signed-off-by: Shawn O. Pearce --- git-gui | 99 +++++++++++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 75 insertions(+), 24 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 3ee32e105..168062e67 100755 --- a/git-gui +++ b/git-gui @@ -7,34 +7,53 @@ exec wish "$0" -- "$@" # and distributed under the terms of the GNU General Public Licence, # either version 2, or (at your option) any later version. - ###################################################################### ## -## status +## task management set status_active 0 set diff_active 0 set checkin_active 0 set update_index_fd {} -proc is_busy {} { - global status_active diff_active checkin_active update_index_fd +set disable_on_lock [list] +set index_lock_type none + +proc lock_index {type} { + global index_lock_type disable_on_lock - if {$status_active > 0 - || $diff_active - || $checkin_active - || $update_index_fd != {}} { + if {$index_lock_type == {none}} { + set index_lock_type $type + foreach w $disable_on_lock { + uplevel #0 $w disabled + } + return 1 + } elseif {$index_lock_type == {begin-update} && $type == {update}} { + set index_lock_type $type return 1 } return 0 } +proc unlock_index {} { + global index_lock_type disable_on_lock + + set index_lock_type none + foreach w $disable_on_lock { + uplevel #0 $w normal + } +} + +###################################################################### +## +## status + proc update_status {} { global gitdir HEAD commit_type global ui_index ui_other ui_status_value ui_comm global status_active file_states - if {[is_busy]} return + if {$status_active || ![lock_index read]} return array unset file_states foreach w [list $ui_index $ui_other] { @@ -160,6 +179,7 @@ proc status_eof {fd buf} { set $buf {} close $fd if {[incr status_active -1] == 0} { + unlock_index set ui_status_value {Ready.} if {$ui_fname_value != {}} { show_diff $ui_fname_value @@ -186,7 +206,7 @@ proc show_diff {path} { global file_states HEAD diff_3way diff_active global ui_diff ui_fname_value ui_fstatus_value ui_status_value - if {[is_busy]} return + if {$diff_active || ![lock_index read]} return clear_diff set s $file_states($path) @@ -211,6 +231,7 @@ proc show_diff {path} { close $fd } err ]} { set diff_active 0 + unlock_index set ui_status_value "Unable to display $path" error_popup "Error loading file:\n$err" return @@ -224,6 +245,7 @@ proc show_diff {path} { if {[catch {set fd [open $cmd r]} err]} { set diff_active 0 + unlock_index set ui_status_value "Unable to display $path" error_popup "Error loading diff:\n$err" return @@ -279,6 +301,7 @@ proc read_diff {fd} { if {[eof $fd]} { close $fd set diff_active 0 + unlock_index set ui_status_value {Ready.} } } @@ -417,6 +440,7 @@ proc with_update_index {body} { global update_index_fd if {$update_index_fd == {}} { + if {![lock_index update]} return set update_index_fd [open \ "| git update-index --add --remove -z --stdin" \ w] @@ -424,6 +448,7 @@ proc with_update_index {body} { uplevel 1 $body close $update_index_fd set update_index_fd {} + unlock_index } else { uplevel 1 $body } @@ -587,10 +612,17 @@ proc show_msg {w top msg} { ## ## ui commands +set starting_gitk_msg {Please wait... Starting gitk...} proc do_gitk {} { - global tcl_platform ui_status_value + global tcl_platform ui_status_value starting_gitk_msg + + set ui_status_value $starting_gitk_msg + after 5000 { + if {$ui_status_value == $starting_gitk_msg} { + set ui_status_value {Ready.} + } + } - set ui_status_value "Please wait... Starting gitk..." if {$tcl_platform(platform) == "windows"} { exec sh -c gitk & } else { @@ -623,7 +655,7 @@ proc do_rescan {} { proc do_checkin_all {} { global checkin_active ui_status_value - if {[is_busy]} return + if {$checkin_active || ![lock_index begin-update]} return set checkin_active 1 set ui_status_value {Checking in all files...} @@ -687,7 +719,7 @@ proc unclick {w x y} { set path [$w get $lno.1 $lno.end] if {$path == {}} return - if {$col == 0 && ![is_busy]} { + if {$col == 0} { toggle_mode $path } } @@ -700,6 +732,11 @@ set mainfont {Helvetica 10} set difffont {Courier 10} set maincursor [. cget -cursor] +switch -- $tcl_platform(platform) { +windows {set M1B Control; set M1T Ctrl} +default {set M1B M1; set M1T M1} +} + # -- Menu Bar menu .mbar -tearoff 0 .mbar add cascade -label Project -menu .mbar.project @@ -715,22 +752,33 @@ menu .mbar.project -font $mainfont .mbar.project add command -label Quit \ -command do_quit \ + -accelerator $M1T-Q \ -font $mainfont # -- Commit Menu menu .mbar.commit .mbar.commit add command -label Rescan \ -command do_rescan \ + -accelerator F5 \ -font $mainfont +lappend disable_on_lock \ + [list .mbar.commit entryconf [.mbar.commit index last] -state] .mbar.commit add command -label {Check-in All Files} \ -command do_checkin_all \ + -accelerator $M1T-U \ -font $mainfont +lappend disable_on_lock \ + [list .mbar.commit entryconf [.mbar.commit index last] -state] .mbar.commit add command -label {Sign Off} \ -command do_signoff \ + -accelerator $M1T-S \ -font $mainfont .mbar.commit add command -label Commit \ -command do_commit \ + -accelerator $M1T-Return \ -font $mainfont +lappend disable_on_lock \ + [list .mbar.commit entryconf [.mbar.commit index last] -state] # -- Fetch Menu menu .mbar.fetch @@ -849,11 +897,13 @@ button .vpane.commarea.buttons.rescan -text {Rescan} \ -command do_rescan \ -font $mainfont pack .vpane.commarea.buttons.rescan -side top -fill x +lappend disable_on_lock {.vpane.commarea.buttons.rescan conf -state} button .vpane.commarea.buttons.ciall -text {Check-in All} \ -command do_checkin_all \ -font $mainfont pack .vpane.commarea.buttons.ciall -side top -fill x +lappend disable_on_lock {.vpane.commarea.buttons.ciall conf -state} button .vpane.commarea.buttons.signoff -text {Sign Off} \ -command do_signoff \ @@ -864,6 +914,7 @@ button .vpane.commarea.buttons.commit -text {Commit} \ -command do_commit \ -font $mainfont pack .vpane.commarea.buttons.commit -side top -fill x +lappend disable_on_lock {.vpane.commarea.buttons.commit conf -state} # -- Commit Message Buffer frame .vpane.commarea.buffer @@ -897,21 +948,21 @@ pack .status -anchor w -side bottom -fill x # -- Key Bindings bind . do_quit bind . do_rescan -bind . do_rescan -bind . do_rescan -bind . do_signoff -bind . do_signoff -bind . do_checkin_all -bind . do_checkin_all -bind . do_commit -bind . do_quit -bind . do_quit +bind . <$M1B-Key-r> do_rescan +bind . <$M1B-Key-R> do_rescan +bind . <$M1B-Key-s> do_signoff +bind . <$M1B-Key-S> do_signoff +bind . <$M1B-Key-u> do_checkin_all +bind . <$M1B-Key-U> do_checkin_all +bind . <$M1B-Key-Return> do_commit +bind . <$M1B-Key-q> do_quit +bind . <$M1B-Key-Q> do_quit foreach i [list $ui_index $ui_other] { bind $i {click %W %x %y 1 %X %Y; break} bind $i {click %W %x %y 3 %X %Y; break} bind $i {unclick %W %x %y; break} } -unset i +unset i M1B M1T ###################################################################### ## -- cgit v1.2.1 From 6e27d826c807153a4773f197e5056d66a6a809c0 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Mon, 6 Nov 2006 20:03:36 -0500 Subject: git-gui: Verify we should actually perform a commit when asked to do so. A user shouldn't perform a commit if any of the following are true: * The repository state has changed since the last rescan. * There are no files updated in the index to commit. * There are unmerged stages still in the index. * The commit message has not been provided. * The pre-commit hook is executable and declined. Signed-off-by: Shawn O. Pearce --- git-gui | 139 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 137 insertions(+), 2 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 168062e67..0b941c3ff 100755 --- a/git-gui +++ b/git-gui @@ -599,15 +599,62 @@ proc error_popup {msg} { } proc show_msg {w top msg} { - message $w.m -text $msg -justify center -aspect 400 + global gitdir + + message $w.m -text $msg -justify left -aspect 400 pack $w.m -side top -fill x -padx 20 -pady 20 button $w.ok -text OK -command "destroy $top" - pack $w.ok -side bottom -fill x + pack $w.ok -side bottom bind $top "grab $top; focus $top" bind $top "destroy $top" + wm title $top "error: git-ui ([file normalize [file dirname $gitdir]])" tkwait window $top } +proc hook_failed_popup {hook msg} { + global gitdir mainfont difffont + + set w .hookfail + toplevel $w + wm transient $w . + + frame $w.m + label $w.m.l1 -text "$hook hook failed:" \ + -anchor w \ + -justify left \ + -font [concat $mainfont bold] + text $w.m.t \ + -background white -borderwidth 1 \ + -relief sunken \ + -width 80 -height 10 \ + -font $difffont \ + -yscrollcommand [list $w.m.sby set] + label $w.m.l2 \ + -text {You must correct the above errors before committing.} \ + -anchor w \ + -justify left \ + -font [concat $mainfont bold] + scrollbar $w.m.sby -command [list $w.m.t yview] + pack $w.m.l1 -side top -fill x + pack $w.m.l2 -side bottom -fill x + pack $w.m.sby -side right -fill y + pack $w.m.t -side left -fill both -expand 1 + pack $w.m -side top -fill both -expand 1 -padx 5 -pady 10 + + $w.m.t insert 1.0 $msg + $w.m.t conf -state disabled + + button $w.ok -text OK \ + -width 15 \ + -command "destroy $w" + pack $w.ok -side bottom + + bind $w "grab $w; focus $w" + bind $w "destroy $w" + wm title $w "error: git-ui ([file normalize [file dirname $gitdir]])" + tkwait window $w +} + ###################################################################### ## ## ui commands @@ -693,6 +740,94 @@ proc do_signoff {} { } } +proc do_commit {} { + global tcl_platform HEAD gitdir commit_type file_states + global ui_comm + + # -- Our in memory state should match the repository. + # + if {[catch {set curHEAD [exec git rev-parse --verify HEAD]}]} { + set cur_type initial + } else { + set cur_type normal + } + if {$commit_type != $commit_type || $HEAD != $curHEAD} { + error_popup {Last scanned state does not match repository state. + +Its highly likely that another Git program modified the +repository since our last scan. A rescan is required +before committing. +} + update_status + return + } + + # -- At least one file should differ in the index. + # + set files_ready 0 + foreach path [array names file_states] { + set s $file_states($path) + switch -glob -- [lindex $s 0] { + _* {continue} + A* - + D* - + M* {set files_ready 1; break} + U* { + error_popup "Unmerged files cannot be committed. + +File $path has merge conflicts. +You must resolve them and check the file in before committing. +" + return + } + default { + error_popup "Unknown file state [lindex $s 0] detected. + +File $path cannot be committed by this program. +" + } + } + } + if {!$files_ready} { + error_popup {No checked-in files to commit. + +You must check-in at least 1 file before you can commit. +} + return + } + + # -- A message is required. + # + set msg [string trim [$ui_comm get 1.0 end]] + if {$msg == {}} { + error_popup {Please supply a commit message. + +A good commit message has the following format: + +- First line: Describe in one sentance what you did. +- Second line: Blank +- Remaining lines: Describe why this change is good. +} + return + } + + # -- Ask the pre-commit hook for the go-ahead. + # + set pchook [file join $gitdir hooks pre-commit] + if {$tcl_platform(platform) == {windows} && [file exists $pchook]} { + set pchook [list sh -c \ + "if test -x \"$pchook\"; then exec \"$pchook\"; fi"] + } elseif {[file executable $pchook]} { + set pchook [list $pchook] + } else { + set pchook {} + } + if {$pchook != {} && [catch {eval exec $pchook} err]} { + hook_failed_popup pre-commit $err + return + } +} + # shift == 1: left click # 3: right click proc click {w x y shift wx wy} { -- cgit v1.2.1 From ec6b424abb8d0a5c6399bcffdfde19aa47f16d18 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Mon, 6 Nov 2006 20:50:59 -0500 Subject: git-gui: Finished commit implementation. We can now commit any type of commit (initial, normal or merge) using the same techniques as git-commit.sh does for these types of things. If invoked as git-citool we run exit immediately after the commit was finished. If invoked as git-gui then we stay running. Also fixed a bug which caused the commit message buffer to be lost when the application shutdown and restarted. Signed-off-by: Shawn O. Pearce --- git-gui | 339 +++++++++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 237 insertions(+), 102 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 0b941c3ff..0e9e51963 100755 --- a/git-gui +++ b/git-gui @@ -11,9 +11,11 @@ exec wish "$0" -- "$@" ## ## task management +set single_commit 0 set status_active 0 set diff_active 0 set checkin_active 0 +set commit_active 0 set update_index_fd {} set disable_on_lock [list] @@ -48,13 +50,27 @@ proc unlock_index {} { ## ## status +proc repository_state {hdvar ctvar} { + global gitdir + upvar $hdvar hd $ctvar ct + + if {[catch {set hd [exec git rev-parse --verify HEAD]}]} { + set ct initial + } elseif {[file exists [file join $gitdir MERGE_HEAD]]} { + set ct merge + } else { + set ct normal + } +} + proc update_status {} { - global gitdir HEAD commit_type + global HEAD commit_type global ui_index ui_other ui_status_value ui_comm global status_active file_states if {$status_active || ![lock_index read]} return + repository_state HEAD commit_type array unset file_states foreach w [list $ui_index $ui_other] { $w conf -state normal @@ -62,12 +78,6 @@ proc update_status {} { $w conf -state disabled } - if {[catch {set HEAD [exec git rev-parse --verify HEAD]}]} { - set commit_type initial - } else { - set commit_type normal - } - if {![$ui_comm edit modified] || [string trim [$ui_comm get 0.0 end]] == {}} { if {[load_message GITGUI_MSG]} { @@ -306,6 +316,207 @@ proc read_diff {fd} { } } +###################################################################### +## +## commit + +proc commit_tree {} { + global tcl_platform HEAD gitdir commit_type file_states + global commit_active ui_status_value + global ui_comm + + if {$commit_active || ![lock_index update]} return + + # -- Our in memory state should match the repository. + # + repository_state curHEAD cur_type + if {$commit_type != $cur_type || $HEAD != $curHEAD} { + error_popup {Last scanned state does not match repository state. + +Its highly likely that another Git program modified the +repository since our last scan. A rescan is required +before committing. +} + unlock_index + update_status + return + } + + # -- At least one file should differ in the index. + # + set files_ready 0 + foreach path [array names file_states] { + set s $file_states($path) + switch -glob -- [lindex $s 0] { + _* {continue} + A* - + D* - + M* {set files_ready 1; break} + U* { + error_popup "Unmerged files cannot be committed. + +File $path has merge conflicts. +You must resolve them and check the file in before committing. +" + unlock_index + return + } + default { + error_popup "Unknown file state [lindex $s 0] detected. + +File $path cannot be committed by this program. +" + } + } + } + if {!$files_ready} { + error_popup {No checked-in files to commit. + +You must check-in at least 1 file before you can commit. +} + unlock_index + return + } + + # -- A message is required. + # + set msg [string trim [$ui_comm get 1.0 end]] + if {$msg == {}} { + error_popup {Please supply a commit message. + +A good commit message has the following format: + +- First line: Describe in one sentance what you did. +- Second line: Blank +- Remaining lines: Describe why this change is good. +} + unlock_index + return + } + + # -- Ask the pre-commit hook for the go-ahead. + # + set pchook [file join $gitdir hooks pre-commit] + if {$tcl_platform(platform) == {windows} && [file exists $pchook]} { + set pchook [list sh -c \ + "if test -x \"$pchook\"; then exec \"$pchook\"; fi"] + } elseif {[file executable $pchook]} { + set pchook [list $pchook] + } else { + set pchook {} + } + if {$pchook != {} && [catch {eval exec $pchook} err]} { + hook_failed_popup pre-commit $err + unlock_index + return + } + + # -- Write the tree in the background. + # + set commit_active 1 + set ui_status_value {Committing changes...} + + set fd_wt [open "| git write-tree" r] + fileevent $fd_wt readable \ + [list commit_stage2 $fd_wt $curHEAD $msg] +} + +proc commit_stage2 {fd_wt curHEAD msg} { + global single_commit gitdir HEAD commit_type + global commit_active ui_status_value comm_ui + + gets $fd_wt tree_id + close $fd_wt + + if {$tree_id == {}} { + error_popup "write-tree failed" + set commit_active 0 + set ui_status_value {Commit failed.} + unlock_index + return + } + + # -- Create the commit. + # + set cmd [list git commit-tree $tree_id] + if {$commit_type != {initial}} { + lappend cmd -p $HEAD + } + if {$commit_type == {merge}} { + if {[catch { + set fd_mh [open [file join $gitdir MERGE_HEAD] r] + while {[gets $fd_mh merge_head] > 0} { + lappend -p $merge_head + } + close $fd_mh + } err]} { + error_popup "Loading MERGE_HEADs failed:\n$err" + set commit_active 0 + set ui_status_value {Commit failed.} + unlock_index + return + } + } + if {$commit_type == {initial}} { + # git commit-tree writes to stderr during initial commit. + lappend cmd 2>/dev/null + } + lappend cmd << $msg + if {[catch {set cmt_id [eval exec $cmd]} err]} { + error_popup "commit-tree failed:\n$err" + set commit_active 0 + set ui_status_value {Commit failed.} + unlock_index + return + } + + # -- Update the HEAD ref. + # + set reflogm commit + if {$commit_type != {normal}} { + append reflogm " ($commit_type)" + } + set i [string first "\n" $msg] + if {$i >= 0} { + append reflogm {: } [string range $msg 0 [expr $i - 1]] + } else { + append reflogm {: } $msg + } + set cmd [list git update-ref \ + -m $reflogm \ + HEAD $cmt_id $curHEAD] + if {[catch {eval exec $cmd} err]} { + error_popup "update-ref failed:\n$err" + set commit_active 0 + set ui_status_value {Commit failed.} + unlock_index + return + } + + # -- Cleanup after ourselves. + # + catch {file delete [file join $gitdir MERGE_HEAD]} + catch {file delete [file join $gitdir MERGE_MSG]} + catch {file delete [file join $gitdir SQUASH_MSG]} + catch {file delete [file join $gitdir GITGUI_MSG]} + + # -- Let rerere do its thing. + # + if {[file isdirectory [file join $gitdir rr-cache]]} { + catch {exec git rerere} + } + + $comm_ui delete 0.0 end + $comm_ui edit modified false + + if {$single_commit} do_quit + + set commit_active 0 + set ui_status_value "Changes committed as $cmt_id." + unlock_index + update_status +} + ###################################################################### ## ## ui helpers @@ -599,20 +810,22 @@ proc error_popup {msg} { } proc show_msg {w top msg} { - global gitdir + global gitdir appname message $w.m -text $msg -justify left -aspect 400 - pack $w.m -side top -fill x -padx 20 -pady 20 - button $w.ok -text OK -command "destroy $top" + pack $w.m -side top -fill x -padx 5 -pady 10 + button $w.ok -text OK \ + -width 15 \ + -command "destroy $top" pack $w.ok -side bottom bind $top "grab $top; focus $top" bind $top "destroy $top" - wm title $top "error: git-ui ([file normalize [file dirname $gitdir]])" + wm title $top "error: $appname ([file normalize [file dirname $gitdir]])" tkwait window $top } proc hook_failed_popup {hook msg} { - global gitdir mainfont difffont + global gitdir mainfont difffont appname set w .hookfail toplevel $w @@ -651,7 +864,7 @@ proc hook_failed_popup {hook msg} { bind $w "grab $w; focus $w" bind $w "destroy $w" - wm title $w "error: git-ui ([file normalize [file dirname $gitdir]])" + wm title $w "error: $appname ([file normalize [file dirname $gitdir]])" tkwait window $w } @@ -681,14 +894,14 @@ proc do_quit {} { global gitdir ui_comm set save [file join $gitdir GITGUI_MSG] - if {[$ui_comm edit modified] - && [string trim [$ui_comm get 0.0 end]] != {}} { + set msg [string trim [$ui_comm get 0.0 end]] + if {[$ui_comm edit modified] && $msg != {}} { catch { set fd [open $save w] puts $fd [string trim [$ui_comm get 0.0 end]] close $fd } - } elseif {[file exists $save]} { + } elseif {$msg == {} && [file exists $save]} { file delete $save } @@ -741,91 +954,7 @@ proc do_signoff {} { } proc do_commit {} { - global tcl_platform HEAD gitdir commit_type file_states - global ui_comm - - # -- Our in memory state should match the repository. - # - if {[catch {set curHEAD [exec git rev-parse --verify HEAD]}]} { - set cur_type initial - } else { - set cur_type normal - } - if {$commit_type != $commit_type || $HEAD != $curHEAD} { - error_popup {Last scanned state does not match repository state. - -Its highly likely that another Git program modified the -repository since our last scan. A rescan is required -before committing. -} - update_status - return - } - - # -- At least one file should differ in the index. - # - set files_ready 0 - foreach path [array names file_states] { - set s $file_states($path) - switch -glob -- [lindex $s 0] { - _* {continue} - A* - - D* - - M* {set files_ready 1; break} - U* { - error_popup "Unmerged files cannot be committed. - -File $path has merge conflicts. -You must resolve them and check the file in before committing. -" - return - } - default { - error_popup "Unknown file state [lindex $s 0] detected. - -File $path cannot be committed by this program. -" - } - } - } - if {!$files_ready} { - error_popup {No checked-in files to commit. - -You must check-in at least 1 file before you can commit. -} - return - } - - # -- A message is required. - # - set msg [string trim [$ui_comm get 1.0 end]] - if {$msg == {}} { - error_popup {Please supply a commit message. - -A good commit message has the following format: - -- First line: Describe in one sentance what you did. -- Second line: Blank -- Remaining lines: Describe why this change is good. -} - return - } - - # -- Ask the pre-commit hook for the go-ahead. - # - set pchook [file join $gitdir hooks pre-commit] - if {$tcl_platform(platform) == {windows} && [file exists $pchook]} { - set pchook [list sh -c \ - "if test -x \"$pchook\"; then exec \"$pchook\"; fi"] - } elseif {[file executable $pchook]} { - set pchook [list $pchook] - } else { - set pchook {} - } - if {$pchook != {} && [catch {eval exec $pchook} err]} { - hook_failed_popup pre-commit $err - return - } + commit_tree } # shift == 1: left click @@ -1081,6 +1210,7 @@ label .status -textvariable ui_status_value \ pack .status -anchor w -side bottom -fill x # -- Key Bindings +bind $ui_comm <$M1B-Key-Return> {do_commit;break} bind . do_quit bind . do_rescan bind . <$M1B-Key-r> do_rescan @@ -1108,6 +1238,11 @@ if {[catch {set gitdir [exec git rev-parse --git-dir]} err]} { exit 1 } -wm title . "git-ui ([file normalize [file dirname $gitdir]])" +set appname [lindex [file split $argv0] end] +if {$appname == {git-citool}} { + set single_commit 1 +} + +wm title . "$appname ([file normalize [file dirname $gitdir]])" focus -force $ui_comm update_status -- cgit v1.2.1 From e57ca85e113437649ec908ce48fc43a659d650f8 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Mon, 6 Nov 2006 21:34:10 -0500 Subject: git-gui: Implemented amended commits. Also fixed a bug related that caused a crash if the file currently in the diff viewer is no longer modified after the commit. Signed-off-by: Shawn O. Pearce --- git-gui | 160 +++++++++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 119 insertions(+), 41 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 0e9e51963..bb89da433 100755 --- a/git-gui +++ b/git-gui @@ -21,6 +21,10 @@ set update_index_fd {} set disable_on_lock [list] set index_lock_type none +set HEAD {} +set PARENT {} +set commit_type {} + proc lock_index {type} { global index_lock_type disable_on_lock @@ -63,14 +67,23 @@ proc repository_state {hdvar ctvar} { } } -proc update_status {} { - global HEAD commit_type +proc update_status {{final Ready.}} { + global HEAD PARENT commit_type global ui_index ui_other ui_status_value ui_comm global status_active file_states if {$status_active || ![lock_index read]} return - repository_state HEAD commit_type + repository_state new_HEAD new_type + if {$commit_type == {amend} + && $new_type == {normal} + && $new_HEAD == $HEAD} { + } else { + set HEAD $new_HEAD + set PARENT $new_HEAD + set commit_type $new_type + } + array unset file_states foreach w [list $ui_index $ui_other] { $w conf -state normal @@ -91,11 +104,11 @@ proc update_status {} { set ui_status_value {Refreshing file status...} set fd_rf [open "| git update-index -q --unmerged --refresh" r] fconfigure $fd_rf -blocking 0 -translation binary - fileevent $fd_rf readable [list read_refresh $fd_rf] + fileevent $fd_rf readable [list read_refresh $fd_rf $final] } -proc read_refresh {fd} { - global gitdir HEAD commit_type +proc read_refresh {fd final} { + global gitdir PARENT commit_type global ui_index ui_other ui_status_value ui_comm global status_active file_states @@ -112,27 +125,27 @@ proc read_refresh {fd} { set status_active 3 set ui_status_value {Scanning for modified files ...} - set fd_di [open "| git diff-index --cached -z $HEAD" r] + set fd_di [open "| git diff-index --cached -z $PARENT" r] set fd_df [open "| git diff-files -z" r] set fd_lo [open $ls_others r] fconfigure $fd_di -blocking 0 -translation binary fconfigure $fd_df -blocking 0 -translation binary fconfigure $fd_lo -blocking 0 -translation binary - fileevent $fd_di readable [list read_diff_index $fd_di] - fileevent $fd_df readable [list read_diff_files $fd_df] - fileevent $fd_lo readable [list read_ls_others $fd_lo] + fileevent $fd_di readable [list read_diff_index $fd_di $final] + fileevent $fd_df readable [list read_diff_files $fd_df $final] + fileevent $fd_lo readable [list read_ls_others $fd_lo $final] } proc load_message {file} { global gitdir ui_comm set f [file join $gitdir $file] - if {[file exists $f]} { + if {[file isfile $f]} { if {[catch {set fd [open $f r]}]} { return 0 } - set content [read $fd] + set content [string trim [read $fd]] close $fd $ui_comm delete 0.0 end $ui_comm insert end $content @@ -141,7 +154,7 @@ proc load_message {file} { return 0 } -proc read_diff_index {fd} { +proc read_diff_index {fd final} { global buf_rdi append buf_rdi [read $fd] @@ -152,10 +165,10 @@ proc read_diff_index {fd} { display_file $p [string index $m end]_ } } - status_eof $fd buf_rdi + status_eof $fd buf_rdi $final } -proc read_diff_files {fd} { +proc read_diff_files {fd final} { global buf_rdf append buf_rdf [read $fd] @@ -166,10 +179,10 @@ proc read_diff_files {fd} { display_file $p _[string index $m end] } } - status_eof $fd buf_rdf + status_eof $fd buf_rdf $final } -proc read_ls_others {fd} { +proc read_ls_others {fd final} { global buf_rlo append buf_rlo [read $fd] @@ -178,21 +191,25 @@ proc read_ls_others {fd} { foreach p [lrange $pck 0 end-1] { display_file $p _O } - status_eof $fd buf_rlo + status_eof $fd buf_rlo $final } -proc status_eof {fd buf} { +proc status_eof {fd buf final} { global status_active $buf - global ui_fname_value ui_status_value + global ui_fname_value ui_status_value file_states if {[eof $fd]} { set $buf {} close $fd if {[incr status_active -1] == 0} { unlock_index - set ui_status_value {Ready.} - if {$ui_fname_value != {}} { + + set ui_status_value $final + if {$ui_fname_value != {} && [array names file_states \ + -exact $ui_fname_value] != {}} { show_diff $ui_fname_value + } else { + clear_diff } } } @@ -213,7 +230,7 @@ proc clear_diff {} { } proc show_diff {path} { - global file_states HEAD diff_3way diff_active + global file_states PARENT diff_3way diff_active global ui_diff ui_fname_value ui_fstatus_value ui_status_value if {$diff_active || ![lock_index read]} return @@ -227,12 +244,12 @@ proc show_diff {path} { set ui_fstatus_value [mapdesc $m $path] set ui_status_value "Loading diff of $path..." - set cmd [list | git diff-index -p $HEAD -- $path] + set cmd [list | git diff-index -p $PARENT -- $path] switch $m { AM { } MM { - set cmd [list | git diff-index -p -c $HEAD $path] + set cmd [list | git diff-index -p -c $PARENT $path] } _O { if {[catch { @@ -320,6 +337,51 @@ proc read_diff {fd} { ## ## commit +proc load_last_commit {} { + global HEAD PARENT commit_type ui_comm + + if {$commit_type == {amend}} return + if {$commit_type != {normal}} { + error_popup "Can't amend a $commit_type commit." + return + } + + set msg {} + set parent {} + set parent_count 0 + if {[catch { + set fd [open "| git cat-file commit $HEAD" r] + while {[gets $fd line] > 0} { + if {[string match {parent *} $line]} { + set parent [string range $line 7 end] + incr parent_count + } + } + set msg [string trim [read $fd]] + close $fd + } err]} { + error_popup "Error loading commit data for amend:\n$err" + return + } + + if {$parent_count == 0} { + set commit_type amend + set HEAD {} + set PARENT {} + update_status + } elseif {$parent_count == 1} { + set commit_type amend + set PARENT $parent + $ui_comm delete 0.0 end + $ui_comm insert end $msg + $ui_comm edit modified false + update_status + } else { + error_popup {You can't amend a merge commit.} + return + } +} + proc commit_tree {} { global tcl_platform HEAD gitdir commit_type file_states global commit_active ui_status_value @@ -330,7 +392,10 @@ proc commit_tree {} { # -- Our in memory state should match the repository. # repository_state curHEAD cur_type - if {$commit_type != $cur_type || $HEAD != $curHEAD} { + if {$commit_type == {amend} + && $cur_type == {normal} + && $curHEAD == $HEAD} { + } elseif {$commit_type != $cur_type || $HEAD != $curHEAD} { error_popup {Last scanned state does not match repository state. Its highly likely that another Git program modified the @@ -397,7 +462,7 @@ A good commit message has the following format: # -- Ask the pre-commit hook for the go-ahead. # set pchook [file join $gitdir hooks pre-commit] - if {$tcl_platform(platform) == {windows} && [file exists $pchook]} { + if {$tcl_platform(platform) == {windows} && [file isfile $pchook]} { set pchook [list sh -c \ "if test -x \"$pchook\"; then exec \"$pchook\"; fi"] } elseif {[file executable $pchook]} { @@ -422,8 +487,8 @@ A good commit message has the following format: } proc commit_stage2 {fd_wt curHEAD msg} { - global single_commit gitdir HEAD commit_type - global commit_active ui_status_value comm_ui + global single_commit gitdir PARENT commit_type + global commit_active ui_status_value ui_comm gets $fd_wt tree_id close $fd_wt @@ -439,8 +504,8 @@ proc commit_stage2 {fd_wt curHEAD msg} { # -- Create the commit. # set cmd [list git commit-tree $tree_id] - if {$commit_type != {initial}} { - lappend cmd -p $HEAD + if {$PARENT != {}} { + lappend cmd -p $PARENT } if {$commit_type == {merge}} { if {[catch { @@ -457,7 +522,7 @@ proc commit_stage2 {fd_wt curHEAD msg} { return } } - if {$commit_type == {initial}} { + if {$PARENT == {}} { # git commit-tree writes to stderr during initial commit. lappend cmd 2>/dev/null } @@ -482,9 +547,7 @@ proc commit_stage2 {fd_wt curHEAD msg} { } else { append reflogm {: } $msg } - set cmd [list git update-ref \ - -m $reflogm \ - HEAD $cmt_id $curHEAD] + set cmd [list git update-ref -m $reflogm HEAD $cmt_id $curHEAD] if {[catch {eval exec $cmd} err]} { error_popup "update-ref failed:\n$err" set commit_active 0 @@ -506,15 +569,15 @@ proc commit_stage2 {fd_wt curHEAD msg} { catch {exec git rerere} } - $comm_ui delete 0.0 end - $comm_ui edit modified false + $ui_comm delete 0.0 end + $ui_comm edit modified false if {$single_commit} do_quit + set commit_type {} set commit_active 0 - set ui_status_value "Changes committed as $cmt_id." unlock_index - update_status + update_status "Changes committed as $cmt_id." } ###################################################################### @@ -877,7 +940,7 @@ proc do_gitk {} { global tcl_platform ui_status_value starting_gitk_msg set ui_status_value $starting_gitk_msg - after 5000 { + after 10000 { if {$ui_status_value == $starting_gitk_msg} { set ui_status_value {Ready.} } @@ -953,6 +1016,10 @@ proc do_signoff {} { } } +proc do_amend_last {} { + load_last_commit +} + proc do_commit {} { commit_tree } @@ -1027,6 +1094,11 @@ menu .mbar.commit -font $mainfont lappend disable_on_lock \ [list .mbar.commit entryconf [.mbar.commit index last] -state] +.mbar.commit add command -label {Amend Last Commit} \ + -command do_amend_last \ + -font $mainfont +lappend disable_on_lock \ + [list .mbar.commit entryconf [.mbar.commit index last] -state] .mbar.commit add command -label {Check-in All Files} \ -command do_checkin_all \ -accelerator $M1T-U \ @@ -1145,7 +1217,7 @@ $ui_diff tag conf dni -foreground "#a000a0" $ui_diff tag conf bold -font [concat $difffont bold] # -- Commit Area -frame .vpane.commarea -height 150 +frame .vpane.commarea -height 170 .vpane add .vpane.commarea -stick nsew # -- Commit Area Buttons @@ -1163,6 +1235,12 @@ button .vpane.commarea.buttons.rescan -text {Rescan} \ pack .vpane.commarea.buttons.rescan -side top -fill x lappend disable_on_lock {.vpane.commarea.buttons.rescan conf -state} +button .vpane.commarea.buttons.amend -text {Amend Last} \ + -command do_amend_last \ + -font $mainfont +pack .vpane.commarea.buttons.amend -side top -fill x +lappend disable_on_lock {.vpane.commarea.buttons.amend conf -state} + button .vpane.commarea.buttons.ciall -text {Check-in All} \ -command do_checkin_all \ -font $mainfont -- cgit v1.2.1 From bd1e2b4028e183f7b4d564aad69c3eae8bdb661a Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Mon, 6 Nov 2006 22:03:05 -0500 Subject: git-gui: Misc. nit type of bug fixes. * Make sure we are in the top level working directory. This way we can access files using their repository path. * Reload the diff viewer if the current file's status has changed; as the diff may now be different. * Correctly handle the 'AD' file state: added but now gone from the working directory. Signed-off-by: Shawn O. Pearce --- git-gui | 36 +++++++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 7 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index bb89da433..8ad3f2d03 100755 --- a/git-gui +++ b/git-gui @@ -266,6 +266,9 @@ proc show_diff {path} { $ui_diff conf -state normal $ui_diff insert end $content $ui_diff conf -state disabled + set diff_active 0 + unlock_index + set ui_status_value {Ready.} return } } @@ -482,8 +485,7 @@ A good commit message has the following format: set ui_status_value {Committing changes...} set fd_wt [open "| git write-tree" r] - fileevent $fd_wt readable \ - [list commit_stage2 $fd_wt $curHEAD $msg] + fileevent $fd_wt readable [list commit_stage2 $fd_wt $curHEAD $msg] } proc commit_stage2 {fd_wt curHEAD msg} { @@ -510,8 +512,8 @@ proc commit_stage2 {fd_wt curHEAD msg} { if {$commit_type == {merge}} { if {[catch { set fd_mh [open [file join $gitdir MERGE_HEAD] r] - while {[gets $fd_mh merge_head] > 0} { - lappend -p $merge_head + while {[gets $fd_mh merge_head] >= 0} { + lappend cmd -p $merge_head } close $fd_mh } err]} { @@ -576,6 +578,8 @@ proc commit_stage2 {fd_wt curHEAD msg} { set commit_type {} set commit_active 0 + set HEAD $cmt_id + set PARENT $cmt_id unlock_index update_status "Changes committed as $cmt_id." } @@ -739,7 +743,7 @@ proc update_index {path} { } proc toggle_mode {path} { - global file_states + global file_states ui_fname_value set s $file_states($path) set m [lindex $s 0] @@ -749,12 +753,16 @@ proc toggle_mode {path} { _O {set new A*} _M - MM {set new M*} + AD - _D {set new D*} default {return} } with_update_index {update_index $path} display_file $path $new + if {$ui_fname_value == $path} { + show_diff $path + } } ###################################################################### @@ -843,6 +851,7 @@ foreach i { {_O o plain "Untracked"} {A_ o fulltick "Added"} {AM o parttick "Partially added"} + {AD o question "Added (but now gone)"} {_D i question "Missing"} {D_ i removed "Removed"} @@ -1261,10 +1270,18 @@ lappend disable_on_lock {.vpane.commarea.buttons.commit conf -state} # -- Commit Message Buffer frame .vpane.commarea.buffer set ui_comm .vpane.commarea.buffer.t -label .vpane.commarea.buffer.l -text {Commit Message:} \ +set ui_coml .vpane.commarea.buffer.l +label $ui_coml -text {Commit Message:} \ -anchor w \ -justify left \ -font $mainfont +trace add variable commit_type write {uplevel #0 { + switch -glob $commit_type \ + initial {$ui_coml conf -text {Initial Commit Message:}} \ + amend {$ui_coml conf -text {Amended Commit Message:}} \ + merge {$ui_coml conf -text {Merge Commit Message:}} \ + * {$ui_coml conf -text {Commit Message:}} +}} text $ui_comm -background white -borderwidth 1 \ -relief sunken \ -width 75 -height 10 -wrap none \ @@ -1272,7 +1289,7 @@ text $ui_comm -background white -borderwidth 1 \ -yscrollcommand {.vpane.commarea.buffer.sby set} \ -cursor $maincursor scrollbar .vpane.commarea.buffer.sby -command [list $ui_comm yview] -pack .vpane.commarea.buffer.l -side top -fill x +pack $ui_coml -side top -fill x pack .vpane.commarea.buffer.sby -side right -fill y pack $ui_comm -side left -fill y pack .vpane.commarea.buffer -side left -fill y @@ -1315,6 +1332,11 @@ if {[catch {set gitdir [exec git rev-parse --git-dir]} err]} { show_msg {} . "Cannot find the git directory: $err" exit 1 } +set cdup [exec git rev-parse --show-cdup] +if {$cdup != ""} { + cd $cdup +} +unset cdup set appname [lindex [file split $argv0] end] if {$appname == {git-citool}} { -- cgit v1.2.1 From 8c0ce436826f01e17cba90ebcaf6483ad3b8c984 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Mon, 6 Nov 2006 23:13:23 -0500 Subject: git-gui: Started construction of fetch and push operations. Signed-off-by: Shawn O. Pearce --- git-gui | 124 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 8ad3f2d03..a43fb2f66 100755 --- a/git-gui +++ b/git-gui @@ -584,6 +584,34 @@ proc commit_stage2 {fd_wt curHEAD msg} { update_status "Changes committed as $cmt_id." } +###################################################################### +## +## fetch pull push + +proc fetch_from {remote} { + set w [new_console "fetch $remote" \ + "Fetching new changes from $remote"] + set cmd [list | git fetch] + lappend -v + lappend cmd $remote + lappend cmd |& cat + set fd_f [open $cmd r] + fconfigure $fd_f -blocking 0 -translation auto + fileevent $fd_f readable [list console_read $w $fd_f] +} + +proc push_to {remote} { + set w [new_console "push $remote" \ + "Pushing changes to $remote"] + set cmd [list | git push] + lappend -v + lappend cmd $remote + lappend cmd |& cat + set fd_f [open $cmd r] + fconfigure $fd_f -blocking 0 -translation auto + fileevent $fd_f readable [list console_read $w $fd_f] +} + ###################################################################### ## ## ui helpers @@ -765,6 +793,41 @@ proc toggle_mode {path} { } } +###################################################################### +## +## config (fetch push pull) + +proc load_all_remotes {} { + global gitdir all_remotes + + set all_remotes [list] + set rm_dir [file join $gitdir remotes] + if {[file isdirectory $rm_dir]} { + set all_remotes [concat $all_remotes \ + [glob -types f -tails -directory $rm_dir * *]] + } + + set fd_rc [open "| git repo-config --list" r] + while {[gets $fd_rc line] >= 0} { + if {[regexp ^remote\.(.*)\.url= $line line name]} { + lappend all_remotes $name + } + } + close $fd_rc + + set all_remotes [lsort -unique $all_remotes] +} + +proc populate_remote_menu {m pfx op} { + global gitdir all_remotes mainfont + + foreach remote $all_remotes { + $m add command -label "$pfx $remote..." \ + -command [list $op $remote] \ + -font $mainfont + } +} + ###################################################################### ## ## icons @@ -888,6 +951,7 @@ proc show_msg {w top msg} { pack $w.m -side top -fill x -padx 5 -pady 10 button $w.ok -text OK \ -width 15 \ + -font $mainfont \ -command "destroy $top" pack $w.ok -side bottom bind $top "grab $top; focus $top" @@ -931,6 +995,7 @@ proc hook_failed_popup {hook msg} { button $w.ok -text OK \ -width 15 \ + -font $mainfont \ -command "destroy $w" pack $w.ok -side bottom @@ -940,6 +1005,58 @@ proc hook_failed_popup {hook msg} { tkwait window $w } +set next_console_id 0 + +proc new_console {short_title long_title} { + global next_console_id gitdir appname mainfont difffont + + set w .console[incr next_console_id] + toplevel $w + frame $w.m + label $w.m.l1 -text "$long_title:" \ + -anchor w \ + -justify left \ + -font [concat $mainfont bold] + text $w.m.t \ + -background white -borderwidth 1 \ + -relief sunken \ + -width 80 -height 10 \ + -font $difffont \ + -state disabled \ + -yscrollcommand [list $w.m.sby set] + scrollbar $w.m.sby -command [list $w.m.t yview] + pack $w.m.l1 -side top -fill x + pack $w.m.sby -side right -fill y + pack $w.m.t -side left -fill both -expand 1 + pack $w.m -side top -fill both -expand 1 -padx 5 -pady 10 + + button $w.ok -text {OK} \ + -width 15 \ + -font $mainfont \ + -state disabled \ + -command "destroy $w" + pack $w.ok -side bottom + + bind $w "focus $w" + bind $w break + wm title $w "$appname ([file dirname [file normalize [file dirname $gitdir]]]): $short_title" + return $w +} + +proc console_read {w fd} { + $w.m.t conf -state normal + while {[gets $fd line] >= 0} { + $w.m.t insert end $line + $w.m.t insert end "\n" + } + $w.m.t conf -state disabled + + if {[eof $fd]} { + close $fd + $w.ok conf -state normal + } +} + ###################################################################### ## ## ui commands @@ -1083,6 +1200,7 @@ menu .mbar -tearoff 0 .mbar add cascade -label Commit -menu .mbar.commit .mbar add cascade -label Fetch -menu .mbar.fetch .mbar add cascade -label Pull -menu .mbar.pull +.mbar add cascade -label Push -menu .mbar.push . configure -menu .mbar # -- Project Menu @@ -1131,6 +1249,9 @@ menu .mbar.fetch # -- Pull Menu menu .mbar.pull +# -- Push Menu +menu .mbar.push + # -- Main Window Layout panedwindow .vpane -orient vertical panedwindow .vpane.files -orient horizontal @@ -1345,4 +1466,7 @@ if {$appname == {git-citool}} { wm title . "$appname ([file normalize [file dirname $gitdir]])" focus -force $ui_comm +load_all_remotes +populate_remote_menu .mbar.fetch From fetch_from +populate_remote_menu .mbar.push To push_to update_status -- cgit v1.2.1 From cc4b1c0213ad2d99121135125b8c2ea630bebe3d Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Mon, 6 Nov 2006 23:47:05 -0500 Subject: git-gui: Worked around environment variable problems on Windows. Apparently the Cygwin tclsh/wish executables don't pass the environment that they inherited onto any children that they invoke. This causes a problem for some users during 'git fetch' or 'git push' as critical environment variables like GIT_SSH and SSH_AUTH_SOCK aren't available to the git processes. So we work around this by forcing sh to start a login shell, thus reloading the user's environment, then cd to the current directory, and finally start the requested process. Of course this won't correctly handle any transient environment variables that were inherited but were not supplied by the user's login shell. Signed-off-by: Shawn O. Pearce --- git-gui | 42 +++++++++++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 13 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index a43fb2f66..be361dec1 100755 --- a/git-gui +++ b/git-gui @@ -92,7 +92,7 @@ proc update_status {{final Ready.}} { } if {![$ui_comm edit modified] - || [string trim [$ui_comm get 0.0 end]] == {}} { + || [string trim [$ui_comm get 0.0 end]] == {}} { if {[load_message GITGUI_MSG]} { } elseif {[load_message MERGE_MSG]} { } elseif {[load_message SQUASH_MSG]} { @@ -591,25 +591,19 @@ proc commit_stage2 {fd_wt curHEAD msg} { proc fetch_from {remote} { set w [new_console "fetch $remote" \ "Fetching new changes from $remote"] - set cmd [list | git fetch] - lappend -v + set cmd [list git fetch] + lappend cmd -v lappend cmd $remote - lappend cmd |& cat - set fd_f [open $cmd r] - fconfigure $fd_f -blocking 0 -translation auto - fileevent $fd_f readable [list console_read $w $fd_f] + console_exec $w $cmd } proc push_to {remote} { set w [new_console "push $remote" \ "Pushing changes to $remote"] - set cmd [list | git push] + set cmd [list git push] lappend -v lappend cmd $remote - lappend cmd |& cat - set fd_f [open $cmd r] - fconfigure $fd_f -blocking 0 -translation auto - fileevent $fd_f readable [list console_read $w $fd_f] + console_exec $w $cmd } ###################################################################### @@ -1043,6 +1037,26 @@ proc new_console {short_title long_title} { return $w } +proc console_exec {w cmd} { + global tcl_platform + + # -- Windows tosses the enviroment when we exec our child. + # But most users need that so we have to relogin. :-( + # + if {$tcl_platform(platform) == {windows}} { + set cmd [list sh --login -c "cd \"[pwd]\" && [join $cmd { }]"] + } + + # -- Tcl won't let us redirect both stdout and stderr to + # the same pipe. So pass it through cat... + # + set cmd [concat | $cmd |& cat] + + set fd_f [open $cmd r] + fconfigure $fd_f -blocking 0 -translation auto + fileevent $fd_f readable [list console_read $w $fd_f] +} + proc console_read {w fd} { $w.m.t conf -state normal while {[gets $fd line] >= 0} { @@ -1050,6 +1064,7 @@ proc console_read {w fd} { $w.m.t insert end "\n" } $w.m.t conf -state disabled + $w.m.t see end if {[eof $fd]} { close $fd @@ -1062,6 +1077,7 @@ proc console_read {w fd} { ## ui commands set starting_gitk_msg {Please wait... Starting gitk...} + proc do_gitk {} { global tcl_platform ui_status_value starting_gitk_msg @@ -1072,7 +1088,7 @@ proc do_gitk {} { } } - if {$tcl_platform(platform) == "windows"} { + if {$tcl_platform(platform) == {windows}} { exec sh -c gitk & } else { exec gitk & -- cgit v1.2.1 From b8ce6f0ec8a275bf9e32ff7666d00a88154fd50b Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Tue, 7 Nov 2006 00:20:56 -0500 Subject: git-gui: Reorganized startup procedure to ensure gitdir is right. Because we cd after getting the cdup value from Git we can't try to get the gitdir until after we perform the cd, as usually the gitdir is relative to the current working directory. Signed-off-by: Shawn O. Pearce --- git-gui | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index be361dec1..87dcbaef4 100755 --- a/git-gui +++ b/git-gui @@ -939,7 +939,7 @@ proc error_popup {msg} { } proc show_msg {w top msg} { - global gitdir appname + global gitdir appname mainfont message $w.m -text $msg -justify left -aspect 400 pack $w.m -side top -fill x -padx 5 -pady 10 @@ -1465,17 +1465,23 @@ unset i M1B M1T ## ## main -if {[catch {set gitdir [exec git rev-parse --git-dir]} err]} { +set appname [lindex [file split $argv0] end] +set gitdir {} + +if {[catch {set cdup [exec git rev-parse --show-cdup]} err]} { show_msg {} . "Cannot find the git directory: $err" exit 1 } -set cdup [exec git rev-parse --show-cdup] if {$cdup != ""} { cd $cdup } unset cdup -set appname [lindex [file split $argv0] end] +if {[catch {set gitdir [exec git rev-parse --git-dir]} err]} { + show_msg {} . "Cannot find the git directory: $err" + exit 1 +} + if {$appname == {git-citool}} { set single_commit 1 } -- cgit v1.2.1 From 661448922fd55b907449962d35d3fdb92397ce9d Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Tue, 7 Nov 2006 00:53:39 -0500 Subject: git-gui: Fix menu item accelerator display on Mac OS X. Apparently accelerators really only work correctly for function keys (F1-F12) and "Cmd-q". Apparently wish on Mac OS X reports itself as unix and the OS is Darwin, this makes it a little difficult to be sure we are running under Aqua. Signed-off-by: Shawn O. Pearce --- git-gui | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 87dcbaef4..0bbb0064f 100755 --- a/git-gui +++ b/git-gui @@ -1205,9 +1205,10 @@ set mainfont {Helvetica 10} set difffont {Courier 10} set maincursor [. cget -cursor] -switch -- $tcl_platform(platform) { -windows {set M1B Control; set M1T Ctrl} -default {set M1B M1; set M1T M1} +switch -glob -- "$tcl_platform(platform),$tcl_platform(os)" { +windows,* {set M1B Control; set M1T Ctrl} +unix,Darwin {set M1B M1; set M1T Cmd} +default {set M1B M1; set M1T M1} } # -- Menu Bar -- cgit v1.2.1 From ee3dc9354d23b1262fb9c71c648435e0ccf01d7e Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Tue, 7 Nov 2006 02:18:18 -0500 Subject: git-gui: Correctly handle CR vs. LF within the console of fetch. Because the remote end is likely to send us progress meters by resetting each line with a CR (and no LF) we should display those meters by replacing the last line of text with the next line, just like a normal xterm would do. This makes the output of fetch look about the same as if we ran it from within an xterm. Signed-off-by: Shawn O. Pearce --- git-gui | 36 ++++++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 0bbb0064f..2645cd5d1 100755 --- a/git-gui +++ b/git-gui @@ -1002,9 +1002,11 @@ proc hook_failed_popup {hook msg} { set next_console_id 0 proc new_console {short_title long_title} { - global next_console_id gitdir appname mainfont difffont + global next_console_id console_cr + global gitdir appname mainfont difffont set w .console[incr next_console_id] + set console_cr($w) 1.0 toplevel $w frame $w.m label $w.m.l1 -text "$long_title:" \ @@ -1024,7 +1026,7 @@ proc new_console {short_title long_title} { pack $w.m.t -side left -fill both -expand 1 pack $w.m -side top -fill both -expand 1 -padx 5 -pady 10 - button $w.ok -text {OK} \ + button $w.ok -text {Running...} \ -width 15 \ -font $mainfont \ -state disabled \ @@ -1053,22 +1055,44 @@ proc console_exec {w cmd} { set cmd [concat | $cmd |& cat] set fd_f [open $cmd r] - fconfigure $fd_f -blocking 0 -translation auto + fconfigure $fd_f -blocking 0 -translation binary fileevent $fd_f readable [list console_read $w $fd_f] } proc console_read {w fd} { + global console_cr + $w.m.t conf -state normal - while {[gets $fd line] >= 0} { - $w.m.t insert end $line - $w.m.t insert end "\n" + set buf [read $fd] + set c 0 + set n [string length $buf] + while {$c < $n} { + set cr [string first "\r" $buf $c] + set lf [string first "\n" $buf $c] + if {$cr < 0} {set cr [expr $n + 1]} + if {$lf < 0} {set lf [expr $n + 1]} + + if {$lf < $cr} { + $w.m.t insert end [string range $buf $c $lf] + set console_cr($w) [$w.m.t index {end -1c}] + set c $lf + incr c + } else { + $w.m.t delete $console_cr($w) end + $w.m.t insert end "\n" + $w.m.t insert end [string range $buf $c $cr] + set c $cr + incr c + } } $w.m.t conf -state disabled $w.m.t see end if {[eof $fd]} { close $fd + $w.ok conf -text Close $w.ok conf -state normal + array unset console_cr $w } } -- cgit v1.2.1 From 07123f4002efdb881f6ce08c5c4411e17e34e141 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Tue, 7 Nov 2006 02:57:46 -0500 Subject: git-gui: Check for fetch or push command failure and denote it. Signed-off-by: Shawn O. Pearce --- git-gui | 37 +++++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 12 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 2645cd5d1..0cd85e3c9 100755 --- a/git-gui +++ b/git-gui @@ -1020,8 +1020,12 @@ proc new_console {short_title long_title} { -font $difffont \ -state disabled \ -yscrollcommand [list $w.m.sby set] + label $w.m.s -anchor w \ + -justify left \ + -font [concat $mainfont bold] scrollbar $w.m.sby -command [list $w.m.t yview] pack $w.m.l1 -side top -fill x + pack $w.m.s -side bottom -fill x pack $w.m.sby -side right -fill y pack $w.m.t -side left -fill both -expand 1 pack $w.m -side top -fill both -expand 1 -padx 5 -pady 10 @@ -1088,12 +1092,19 @@ proc console_read {w fd} { $w.m.t conf -state disabled $w.m.t see end + fconfigure $fd -blocking 1 if {[eof $fd]} { - close $fd + if {[catch {close $fd}]} { + $w.m.s conf -background red -text {Error: Command Failed} + } else { + $w.m.s conf -background green -text {Success} + } $w.ok conf -text Close $w.ok conf -state normal array unset console_cr $w + return } + fconfigure $fd -blocking 0 } ###################################################################### @@ -1468,17 +1479,19 @@ pack .status -anchor w -side bottom -fill x # -- Key Bindings bind $ui_comm <$M1B-Key-Return> {do_commit;break} -bind . do_quit -bind . do_rescan -bind . <$M1B-Key-r> do_rescan -bind . <$M1B-Key-R> do_rescan -bind . <$M1B-Key-s> do_signoff -bind . <$M1B-Key-S> do_signoff -bind . <$M1B-Key-u> do_checkin_all -bind . <$M1B-Key-U> do_checkin_all -bind . <$M1B-Key-Return> do_commit -bind . <$M1B-Key-q> do_quit -bind . <$M1B-Key-Q> do_quit +bind . do_quit +bind all do_rescan +bind all <$M1B-Key-r> do_rescan +bind all <$M1B-Key-R> do_rescan +bind . <$M1B-Key-s> do_signoff +bind . <$M1B-Key-S> do_signoff +bind . <$M1B-Key-u> do_checkin_all +bind . <$M1B-Key-U> do_checkin_all +bind . <$M1B-Key-Return> do_commit +bind all <$M1B-Key-q> do_quit +bind all <$M1B-Key-Q> do_quit +bind all <$M1B-Key-w> {destroy [winfo toplevel %W]} +bind all <$M1B-Key-W> {destroy [winfo toplevel %W]} foreach i [list $ui_index $ui_other] { bind $i {click %W %x %y 1 %X %Y; break} bind $i {click %W %x %y 3 %X %Y; break} -- cgit v1.2.1 From d47ae541cef50f5fbfaec195597cf1cebc2840f5 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Tue, 7 Nov 2006 03:00:20 -0500 Subject: git-gui: Don't complain if no .git/remotes exist. The user might be using the new style config syntax remote.name.url rather than the older standalone remote file. Signed-off-by: Shawn O. Pearce --- git-gui | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 0cd85e3c9..b8e7c8958 100755 --- a/git-gui +++ b/git-gui @@ -797,8 +797,11 @@ proc load_all_remotes {} { set all_remotes [list] set rm_dir [file join $gitdir remotes] if {[file isdirectory $rm_dir]} { - set all_remotes [concat $all_remotes \ - [glob -types f -tails -directory $rm_dir * *]] + set all_remotes [concat $all_remotes [glob \ + -types f \ + -tails \ + -nocomplain \ + -directory $rm_dir *]] } set fd_rc [open "| git repo-config --list" r] -- cgit v1.2.1 From 37af79d10d980418eaeca953c4ba1c08a85d37e9 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Tue, 7 Nov 2006 04:19:49 -0500 Subject: git-gui: Automatically reopen any console closed by the user. If the user closes a console and we get more ouptut for it then we will get a Tcl error in the readable event handle for the file channel. Since this loses the actual output and is quite unfriendly to the end user instead reopen any console which the user closed prior to the additional output arriving. Signed-off-by: Shawn O. Pearce --- git-gui | 74 ++++++++++++++++++++++++++++++++++++++--------------------------- 1 file changed, 43 insertions(+), 31 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index b8e7c8958..adc89474a 100755 --- a/git-gui +++ b/git-gui @@ -1005,14 +1005,20 @@ proc hook_failed_popup {hook msg} { set next_console_id 0 proc new_console {short_title long_title} { - global next_console_id console_cr + global next_console_id console_data + set w .console[incr next_console_id] + set console_data($w) [list $short_title $long_title] + return [console_init $w] +} + +proc console_init {w} { + global console_cr console_data global gitdir appname mainfont difffont - set w .console[incr next_console_id] set console_cr($w) 1.0 toplevel $w frame $w.m - label $w.m.l1 -text "$long_title:" \ + label $w.m.l1 -text "[lindex $console_data($w) 1]:" \ -anchor w \ -justify left \ -font [concat $mainfont bold] @@ -1041,8 +1047,7 @@ proc new_console {short_title long_title} { pack $w.ok -side bottom bind $w "focus $w" - bind $w break - wm title $w "$appname ([file dirname [file normalize [file dirname $gitdir]]]): $short_title" + wm title $w "$appname ([file dirname [file normalize [file dirname $gitdir]]]): [lindex $console_data($w) 0]" return $w } @@ -1067,44 +1072,51 @@ proc console_exec {w cmd} { } proc console_read {w fd} { - global console_cr + global console_cr console_data - $w.m.t conf -state normal set buf [read $fd] - set c 0 - set n [string length $buf] - while {$c < $n} { - set cr [string first "\r" $buf $c] - set lf [string first "\n" $buf $c] - if {$cr < 0} {set cr [expr $n + 1]} - if {$lf < 0} {set lf [expr $n + 1]} - - if {$lf < $cr} { - $w.m.t insert end [string range $buf $c $lf] - set console_cr($w) [$w.m.t index {end -1c}] - set c $lf - incr c - } else { - $w.m.t delete $console_cr($w) end - $w.m.t insert end "\n" - $w.m.t insert end [string range $buf $c $cr] - set c $cr - incr c + if {$buf != {}} { + if {![winfo exists $w]} {console_init $w} + $w.m.t conf -state normal + set c 0 + set n [string length $buf] + while {$c < $n} { + set cr [string first "\r" $buf $c] + set lf [string first "\n" $buf $c] + if {$cr < 0} {set cr [expr $n + 1]} + if {$lf < 0} {set lf [expr $n + 1]} + + if {$lf < $cr} { + $w.m.t insert end [string range $buf $c $lf] + set console_cr($w) [$w.m.t index {end -1c}] + set c $lf + incr c + } else { + $w.m.t delete $console_cr($w) end + $w.m.t insert end "\n" + $w.m.t insert end [string range $buf $c $cr] + set c $cr + incr c + } } + $w.m.t conf -state disabled + $w.m.t see end } - $w.m.t conf -state disabled - $w.m.t see end fconfigure $fd -blocking 1 if {[eof $fd]} { if {[catch {close $fd}]} { + if {![winfo exists $w]} {console_init $w} $w.m.s conf -background red -text {Error: Command Failed} - } else { + $w.ok conf -text Close + $w.ok conf -state normal + } elseif {[winfo exists $w]} { $w.m.s conf -background green -text {Success} + $w.ok conf -text Close + $w.ok conf -state normal } - $w.ok conf -text Close - $w.ok conf -state normal array unset console_cr $w + array unset console_data $w return } fconfigure $fd -blocking 0 -- cgit v1.2.1 From 0d4f3eb5f330a53300e630c1ffe4ea1fa61f5dd9 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Tue, 7 Nov 2006 04:26:02 -0500 Subject: git-gui: Cache all repo-config data in an array. We're likely going to need key/value pairs from the repo-config beyond just remote.*.url, so cache them all up front into a Tcl array where we have fast access to them without needing to refork a repo-config --list process. Signed-off-by: Shawn O. Pearce --- git-gui | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index adc89474a..de67aa2a6 100755 --- a/git-gui +++ b/git-gui @@ -791,8 +791,23 @@ proc toggle_mode {path} { ## ## config (fetch push pull) +proc load_repo_config {} { + global repo_config + + array unset repo_config + catch { + set fd_rc [open "| git repo-config --list" r] + while {[gets $fd_rc line] >= 0} { + if {[regexp {^([^=]+)=(.*)$} $line line name value]} { + lappend repo_config($name) $value + } + } + close $fd_rc + } +} + proc load_all_remotes {} { - global gitdir all_remotes + global gitdir all_remotes repo_config set all_remotes [list] set rm_dir [file join $gitdir remotes] @@ -804,13 +819,11 @@ proc load_all_remotes {} { -directory $rm_dir *]] } - set fd_rc [open "| git repo-config --list" r] - while {[gets $fd_rc line] >= 0} { - if {[regexp ^remote\.(.*)\.url= $line line name]} { + foreach line [array names repo_config remote.*.url] { + if {[regexp ^remote\.(.*)\.url\$ $line line name]} { lappend all_remotes $name } } - close $fd_rc set all_remotes [lsort -unique $all_remotes] } @@ -1541,6 +1554,7 @@ if {$appname == {git-citool}} { wm title . "$appname ([file normalize [file dirname $gitdir]])" focus -force $ui_comm +load_repo_config load_all_remotes populate_remote_menu .mbar.fetch From fetch_from populate_remote_menu .mbar.push To push_to -- cgit v1.2.1 From d33ba5fa809be1714c7f31f128a7a72461a96d96 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Tue, 7 Nov 2006 05:02:15 -0500 Subject: git-gui: Added support for pulling from default branch of a remote. We now create one menu entry per remote listing the first Pull: or fetch entry associated with that remote as the branch to pull into the current branch. This is actually quite incorrect as we should be using the default remote branch name listed in branch..merge for a new-style remote described in the config file. But its a good default to get started with. Signed-off-by: Shawn O. Pearce --- git-gui | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 70 insertions(+), 9 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index de67aa2a6..4aa035a6c 100755 --- a/git-gui +++ b/git-gui @@ -592,16 +592,31 @@ proc fetch_from {remote} { set w [new_console "fetch $remote" \ "Fetching new changes from $remote"] set cmd [list git fetch] - lappend cmd -v lappend cmd $remote console_exec $w $cmd } +proc pull_remote {remote branch} { + set w [new_console "pull $remote $branch" \ + "Pulling new changes from branch $branch in $remote"] + set cmd [list git pull] + lappend cmd $remote + lappend cmd $branch + console_exec $w $cmd [list post_pull_remote $remote $branch] +} + +proc post_pull_remote {remote branch success} { + if {$success} { + update_status "Successfully pulled $branch from $remote." + } else { + update_status "Conflicts detected while pulling $branch from $remote." + } +} + proc push_to {remote} { set w [new_console "push $remote" \ "Pushing changes to $remote"] set cmd [list git push] - lappend -v lappend cmd $remote console_exec $w $cmd } @@ -829,7 +844,7 @@ proc load_all_remotes {} { } proc populate_remote_menu {m pfx op} { - global gitdir all_remotes mainfont + global all_remotes mainfont foreach remote $all_remotes { $m add command -label "$pfx $remote..." \ @@ -838,6 +853,40 @@ proc populate_remote_menu {m pfx op} { } } +proc populate_pull_menu {m} { + global gitdir repo_config all_remotes mainfont + + foreach remote $all_remotes { + set rb {} + if {[array get repo_config remote.$remote.url] != {}} { + if {[array get repo_config remote.$remote.fetch] != {}} { + regexp {^([^:]+):} \ + [lindex $repo_config(remote.$remote.fetch) 0] \ + line rb + } + } else { + catch { + set fd [open [file join $gitdir remotes $remote] r] + while {[gets $fd line] >= 0} { + if {[regexp {^Pull:[ \t]*([^:]+):} $line line rb]} { + break + } + } + close $fd + } + } + + set rb_short $rb + regsub ^refs/heads/ $rb {} rb_short + if {$rb_short != {}} { + $m add command \ + -label "Branch $rb_short from $remote..." \ + -command [list pull_remote $remote $rb] \ + -font $mainfont + } + } +} + ###################################################################### ## ## icons @@ -966,7 +1015,9 @@ proc show_msg {w top msg} { pack $w.ok -side bottom bind $top "grab $top; focus $top" bind $top "destroy $top" - wm title $top "error: $appname ([file normalize [file dirname $gitdir]])" + wm title $w "$appname ([lindex [file split \ + [file normalize [file dirname $gitdir]]] \ + end]): error" tkwait window $top } @@ -1011,7 +1062,9 @@ proc hook_failed_popup {hook msg} { bind $w "grab $w; focus $w" bind $w "destroy $w" - wm title $w "error: $appname ([file normalize [file dirname $gitdir]])" + wm title $w "$appname ([lindex [file split \ + [file normalize [file dirname $gitdir]]] \ + end]): error" tkwait window $w } @@ -1060,11 +1113,13 @@ proc console_init {w} { pack $w.ok -side bottom bind $w "focus $w" - wm title $w "$appname ([file dirname [file normalize [file dirname $gitdir]]]): [lindex $console_data($w) 0]" + wm title $w "$appname ([lindex [file split \ + [file normalize [file dirname $gitdir]]] \ + end]): [lindex $console_data($w) 0]" return $w } -proc console_exec {w cmd} { +proc console_exec {w cmd {after {}}} { global tcl_platform # -- Windows tosses the enviroment when we exec our child. @@ -1081,10 +1136,10 @@ proc console_exec {w cmd} { set fd_f [open $cmd r] fconfigure $fd_f -blocking 0 -translation binary - fileevent $fd_f readable [list console_read $w $fd_f] + fileevent $fd_f readable [list console_read $w $fd_f $after] } -proc console_read {w fd} { +proc console_read {w fd after} { global console_cr console_data set buf [read $fd] @@ -1123,13 +1178,18 @@ proc console_read {w fd} { $w.m.s conf -background red -text {Error: Command Failed} $w.ok conf -text Close $w.ok conf -state normal + set ok 0 } elseif {[winfo exists $w]} { $w.m.s conf -background green -text {Success} $w.ok conf -text Close $w.ok conf -state normal + set ok 1 } array unset console_cr $w array unset console_data $w + if {$after != {}} { + uplevel #0 $after $ok + } return } fconfigure $fd -blocking 0 @@ -1558,4 +1618,5 @@ load_repo_config load_all_remotes populate_remote_menu .mbar.fetch From fetch_from populate_remote_menu .mbar.push To push_to +populate_pull_menu .mbar.pull update_status -- cgit v1.2.1 From 868c8752451c0b75502a0134068f0cfe055eb7ad Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Tue, 7 Nov 2006 18:34:09 -0500 Subject: git-gui: Corrected diff-index/diff-files protocol parsing errors. When we were receiving a lot of output from diff-index we split records at the wrong locations and started using the file status information (mode and SHA1s) as path names, and then proceeded to try to use part of the path names as status data. This caused all sorts of havoc. So I rewrote the parsing implementation to scan for the pair of null bytes along the buffer and stop scanning (waiting for more data) if both can't be found during this event. This seems to work well under high load (like when processing 6,983 added files). Signed-off-by: Shawn O. Pearce --- git-gui | 59 +++++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 47 insertions(+), 12 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 4aa035a6c..48e1c5601 100755 --- a/git-gui +++ b/git-gui @@ -111,6 +111,7 @@ proc read_refresh {fd final} { global gitdir PARENT commit_type global ui_index ui_other ui_status_value ui_comm global status_active file_states + global buf_rdi buf_rdf buf_rlo read $fd if {![eof $fd]} return @@ -123,6 +124,10 @@ proc read_refresh {fd final} { lappend ls_others "--exclude-from=$info_exclude" } + set buf_rdi {} + set buf_rdf {} + set buf_rlo {} + set status_active 3 set ui_status_value {Scanning for modified files ...} set fd_di [open "| git diff-index --cached -z $PARENT" r] @@ -158,13 +163,28 @@ proc read_diff_index {fd final} { global buf_rdi append buf_rdi [read $fd] - set pck [split $buf_rdi "\0"] - set buf_rdi [lindex $pck end] - foreach {m p} [lrange $pck 0 end-1] { - if {$m != {} && $p != {}} { - display_file $p [string index $m end]_ - } + set c 0 + set n [string length $buf_rdi] + while {$c < $n} { + set z1 [string first "\0" $buf_rdi $c] + if {$z1 == -1} break + incr z1 + set z2 [string first "\0" $buf_rdi $z1] + if {$z2 == -1} break + + set c $z2 + incr z2 -1 + display_file \ + [string range $buf_rdi $z1 $z2] \ + [string index $buf_rdi [expr $z1 - 2]]_ + incr c + } + if {$c < $n} { + set buf_rdi [string range $buf_rdi $c end] + } else { + set buf_rdi {} } + status_eof $fd buf_rdi $final } @@ -172,13 +192,28 @@ proc read_diff_files {fd final} { global buf_rdf append buf_rdf [read $fd] - set pck [split $buf_rdf "\0"] - set buf_rdf [lindex $pck end] - foreach {m p} [lrange $pck 0 end-1] { - if {$m != {} && $p != {}} { - display_file $p _[string index $m end] - } + set c 0 + set n [string length $buf_rdf] + while {$c < $n} { + set z1 [string first "\0" $buf_rdf $c] + if {$z1 == -1} break + incr z1 + set z2 [string first "\0" $buf_rdf $z1] + if {$z2 == -1} break + + set c $z2 + incr z2 -1 + display_file \ + [string range $buf_rdf $z1 $z2] \ + _[string index $buf_rdf [expr $z1 - 2]] + incr c + } + if {$c < $n} { + set buf_rdf [string range $buf_rdf $c end] + } else { + set buf_rdf {} } + status_eof $fd buf_rdf $final } -- cgit v1.2.1 From 93f654df7ec9a509e9362e06821c2af0b2bacc82 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Tue, 7 Nov 2006 19:30:54 -0500 Subject: git-gui: Performance improvements for large file sets. Loading 6900 newly added files required about 90 seconds on one system. This is just far too long to perform a "status" type of operation. git-status on the same system completes in just 8.2 seconds if it is redirected to /dev/null. Most of our performance improvement comes from moving all of the UI updating out of the main fileevent handlers for the status process. Instead we are only updating the file_states array and then only doing the UI update when all states are known and have been finally determined. The rescan execution is now down to almost 30 seconds for the same case, a good (but not really all that impressive) improvement. Signed-off-by: Shawn O. Pearce --- git-gui | 107 ++++++++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 67 insertions(+), 40 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 48e1c5601..ed745ee52 100755 --- a/git-gui +++ b/git-gui @@ -236,10 +236,13 @@ proc status_eof {fd buf final} { if {[eof $fd]} { set $buf {} close $fd + if {[incr status_active -1] == 0} { unlock_index set ui_status_value $final + display_all_files + if {$ui_fname_value != {} && [array names file_states \ -exact $ui_fname_value] != {}} { show_diff $ui_fname_value @@ -711,79 +714,103 @@ proc bsearch {w path} { return -[expr $lo + 1] } +set next_icon_id 0 + proc merge_state {path state} { - global file_states + global file_states next_icon_id if {[array names file_states -exact $path] == {}} { - set o __ - set s [list $o none none] + set m __ + set s [list $m icon[incr next_icon_id]] } else { set s $file_states($path) - set o [lindex $s 0] + set m [lindex $s 0] } - set m [lindex $s 0] - if {[string index $state 0] == "_"} { + if {[string index $state 0] == {_}} { set state [string index $m 0][string index $state 1] - } elseif {[string index $state 0] == "*"} { + } elseif {[string index $state 0] == {*}} { set state _[string index $state 1] } - if {[string index $state 1] == "_"} { + if {[string index $state 1] == {_}} { set state [string index $state 0][string index $m 1] - } elseif {[string index $state 1] == "*"} { + } elseif {[string index $state 1] == {*}} { set state [string index $state 0]_ } set file_states($path) [lreplace $s 0 0 $state] - return $o + return $m } proc display_file {path state} { - global ui_index ui_other file_states + global ui_index ui_other file_states status_active set old_m [merge_state $path $state] + if {$status_active} return + set s $file_states($path) - set m [lindex $s 0] + set new_m [lindex $s 0] + set new_col [mapcol $new_m $path] + set new_ico [mapicon $new_m $path] - if {[mapcol $m $path] == "o"} { - set ii 1 - set ai 2 - set iw $ui_index - set aw $ui_other + if {$new_col == {o}} { + set old_w $ui_index + set new_w $ui_other } else { - set ii 2 - set ai 1 - set iw $ui_other - set aw $ui_index + set old_w $ui_other + set new_w $ui_index } - set d [lindex $s $ii] - if {$d != "none"} { - set lno [bsearch $iw $path] + if {$new_col != [mapcol $old_m $path]} { + set lno [bsearch $old_w $path] if {$lno >= 0} { incr lno - $iw conf -state normal - $iw delete $lno.0 [expr $lno + 1].0 - $iw conf -state disabled - set s [lreplace $s $ii $ii none] + $old_w conf -state normal + $old_w delete $lno.0 [expr $lno + 1].0 + $old_w conf -state disabled } + + set lno [expr abs([bsearch $new_w $path] + 1) + 1] + $new_w conf -state normal + $new_w image create $lno.0 \ + -align center -padx 5 -pady 1 \ + -name [lindex $s 1] \ + -image [mapicon $m $path] + $new_w insert $lno.1 "$path\n" + $new_w conf -state disabled + } elseif {$new_icon != [mapicon $old_m $path]} { + $new_w conf -state normal + $new_w image conf [lindex $s 1] -image $new_icon + $new_w conf -state disabled } +} - set d [lindex $s $ai] - if {$d == "none"} { - set lno [expr abs([bsearch $aw $path] + 1) + 1] - $aw conf -state normal - set ico [$aw image create $lno.0 \ +proc display_all_files {} { + global ui_index ui_other file_states + + $ui_index conf -state normal + $ui_other conf -state normal + + foreach path [lsort [array names file_states]] { + set s $file_states($path) + set m [lindex $s 0] + + if {[mapcol $m $path] == {o}} { + set aw $ui_other + } else { + set aw $ui_index + } + + $aw image create end \ -align center -padx 5 -pady 1 \ - -image [mapicon $m $path]] - $aw insert $lno.1 "$path\n" - $aw conf -state disabled - set file_states($path) [lreplace $s $ai $ai [list $ico]] - } elseif {[mapicon $m $path] != [mapicon $old_m $path]} { - set ico [lindex $d 0] - $aw image conf $ico -image [mapicon $m $path] + -name [lindex $s 1] \ + -image [mapicon $m $path] + $aw insert end "$path\n" } + + $ui_index conf -state disabled + $ui_other conf -state disabled } proc with_update_index {body} { -- cgit v1.2.1 From 6b29267542546b443fd885b2ed6dc896680b09ed Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Tue, 7 Nov 2006 19:58:37 -0500 Subject: git-gui: More performance improvements to rescan logic. Removed as much as possible from the merge_state proc, which is where we spent most of our time before UI update. This change makes our running time match that of git status, except that we then need about 7 additional seconds to draw 6900 files on screen. Apparently the [array names a -exact $v] operator in Tcl is O(n) rather than O(1), which is really quite disappointing given that each array can only have one entry for a given value. Switching to a lookup with a catch (whose error we ignore) runs in O(1) time and bought us most of that improvement. Signed-off-by: Shawn O. Pearce --- git-gui | 87 ++++++++++++++++++++++++++++++++--------------------------------- 1 file changed, 43 insertions(+), 44 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index ed745ee52..1833fa86c 100755 --- a/git-gui +++ b/git-gui @@ -70,7 +70,7 @@ proc repository_state {hdvar ctvar} { proc update_status {{final Ready.}} { global HEAD PARENT commit_type global ui_index ui_other ui_status_value ui_comm - global status_active file_states + global status_active file_states status_start if {$status_active || ![lock_index read]} return @@ -84,6 +84,7 @@ proc update_status {{final Ready.}} { set commit_type $new_type } + set status_start [clock seconds] array unset file_states foreach w [list $ui_index $ui_other] { $w conf -state normal @@ -230,7 +231,7 @@ proc read_ls_others {fd final} { } proc status_eof {fd buf final} { - global status_active $buf + global status_active status_start $buf global ui_fname_value ui_status_value file_states if {[eof $fd]} { @@ -240,8 +241,12 @@ proc status_eof {fd buf final} { if {[incr status_active -1] == 0} { unlock_index - set ui_status_value $final + set e1 [clock seconds] display_all_files + set e2 [clock seconds] +puts "TIME [expr $e1 - $status_start] + [expr $e2 - $e1] = [expr $e2 - $status_start]" + + set ui_status_value $final if {$ui_fname_value != {} && [array names file_states \ -exact $ui_fname_value] != {}} { @@ -664,11 +669,11 @@ proc push_to {remote} { ## ui helpers proc mapcol {state path} { - global all_cols + global all_cols ui_other if {[catch {set r $all_cols($state)}]} { puts "error: no column for state={$state} $path" - return o + return $ui_other } return $r } @@ -716,31 +721,34 @@ proc bsearch {w path} { set next_icon_id 0 -proc merge_state {path state} { +proc merge_state {path new_state} { global file_states next_icon_id - if {[array names file_states -exact $path] == {}} { - set m __ - set s [list $m icon[incr next_icon_id]] + set s0 [string index $new_state 0] + set s1 [string index $new_state 1] + + if {[catch {set info $file_states($path)}]} { + set state __ + set icon n[incr next_icon_id] } else { - set s $file_states($path) - set m [lindex $s 0] + set state [lindex $info 0] + set icon [lindex $info 1] } - if {[string index $state 0] == {_}} { - set state [string index $m 0][string index $state 1] - } elseif {[string index $state 0] == {*}} { - set state _[string index $state 1] + if {$s0 == {_}} { + set s0 [string index $state 0] + } elseif {$s0 == {*}} { + set s0 _ } - if {[string index $state 1] == {_}} { - set state [string index $state 0][string index $m 1] - } elseif {[string index $state 1] == {*}} { - set state [string index $state 0]_ + if {$s1 == {_}} { + set s1 [string index $state 1] + } elseif {$s1 == {*}} { + set s1 _ } - set file_states($path) [lreplace $s 0 0 $state] - return $m + set file_states($path) [list $s0$s1 $icon] + return $state } proc display_file {path state} { @@ -750,19 +758,12 @@ proc display_file {path state} { if {$status_active} return set s $file_states($path) + set old_w [mapcol $old_m $path] + set new_w [mapcol $new_m $path] set new_m [lindex $s 0] - set new_col [mapcol $new_m $path] set new_ico [mapicon $new_m $path] - if {$new_col == {o}} { - set old_w $ui_index - set new_w $ui_other - } else { - set old_w $ui_other - set new_w $ui_index - } - - if {$new_col != [mapcol $old_m $path]} { + if {$new_w != $old_w} { set lno [bsearch $old_w $path] if {$lno >= 0} { incr lno @@ -795,18 +796,12 @@ proc display_all_files {} { foreach path [lsort [array names file_states]] { set s $file_states($path) set m [lindex $s 0] - - if {[mapcol $m $path] == {o}} { - set aw $ui_other - } else { - set aw $ui_index - } - - $aw image create end \ + set w [mapcol $m $path] + $w image create end \ -align center -padx 5 -pady 1 \ -name [lindex $s 1] \ -image [mapicon $m $path] - $aw insert end "$path\n" + $w insert end "$path\n" } $ui_index conf -state disabled @@ -1025,6 +1020,8 @@ static unsigned char file_merge_bits[] = { 0xfa, 0x17, 0x02, 0x10, 0xfe, 0x1f}; } -maskdata $filemask +set ui_index .vpane.files.index.list +set ui_other .vpane.files.other.list set max_status_desc 0 foreach i { {__ i plain "Unmodified"} @@ -1035,7 +1032,7 @@ foreach i { {_O o plain "Untracked"} {A_ o fulltick "Added"} {AM o parttick "Partially added"} - {AD o question "Added (but now gone)"} + {AD o question "Added (but now gone)"} {_D i question "Missing"} {D_ i removed "Removed"} @@ -1048,7 +1045,11 @@ foreach i { if {$max_status_desc < [string length [lindex $i 3]]} { set max_status_desc [string length [lindex $i 3]] } - set all_cols([lindex $i 0]) [lindex $i 1] + if {[lindex $i 1] == {i}} { + set all_cols([lindex $i 0]) $ui_index + } else { + set all_cols([lindex $i 0]) $ui_other + } set all_icons([lindex $i 0]) file_[lindex $i 2] set all_descs([lindex $i 0]) [lindex $i 3] } @@ -1461,7 +1462,6 @@ panedwindow .vpane.files -orient horizontal pack .vpane -anchor n -side top -fill both -expand 1 # -- Index File List -set ui_index .vpane.files.index.list frame .vpane.files.index -height 100 -width 400 label .vpane.files.index.title -text {Modified Files} \ -background green \ @@ -1479,7 +1479,6 @@ pack $ui_index -side left -fill both -expand 1 .vpane.files add .vpane.files.index -sticky nsew # -- Other (Add) File List -set ui_other .vpane.files.other.list frame .vpane.files.other -height 100 -width 100 label .vpane.files.other.title -text {Untracked Files} \ -background red \ -- cgit v1.2.1 From 0fb8f9ce05bf65cc9c22f078c4a6dc7dec3ec27a Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Tue, 7 Nov 2006 20:27:46 -0500 Subject: git-gui: Flip commit message buffer and diff area. Since Tk will only supply new space gained from growing the top level to the bottom/right most widget within a panedwindow and most users will be growing a git-gui main window for the purposes of seeing more of the currently shown diff, flipping the order around makes Tk do what the user wants by default. Of course because we also removed the paned window from the commit buffer area it is now impossible to increase the visible space for the commit message. But I don't see this as a huge concern right now as its actually very awkward to try and balance three paned window dividers within the same top level window. We could always add it back if users really want to expand the commit buffer and see more. I also corrected a number of bugs that I accidentally introduced in the last commit. Signed-off-by: Shawn O. Pearce --- git-gui | 179 +++++++++++++++++++++++++++++++++------------------------------- 1 file changed, 91 insertions(+), 88 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 1833fa86c..83f713535 100755 --- a/git-gui +++ b/git-gui @@ -70,7 +70,7 @@ proc repository_state {hdvar ctvar} { proc update_status {{final Ready.}} { global HEAD PARENT commit_type global ui_index ui_other ui_status_value ui_comm - global status_active file_states status_start + global status_active file_states if {$status_active || ![lock_index read]} return @@ -84,7 +84,6 @@ proc update_status {{final Ready.}} { set commit_type $new_type } - set status_start [clock seconds] array unset file_states foreach w [list $ui_index $ui_other] { $w conf -state normal @@ -231,7 +230,7 @@ proc read_ls_others {fd final} { } proc status_eof {fd buf final} { - global status_active status_start $buf + global status_active $buf global ui_fname_value ui_status_value file_states if {[eof $fd]} { @@ -241,11 +240,7 @@ proc status_eof {fd buf final} { if {[incr status_active -1] == 0} { unlock_index - set e1 [clock seconds] display_all_files - set e2 [clock seconds] -puts "TIME [expr $e1 - $status_start] + [expr $e2 - $e1] = [expr $e2 - $status_start]" - set ui_status_value $final if {$ui_fname_value != {} && [array names file_states \ @@ -758,10 +753,10 @@ proc display_file {path state} { if {$status_active} return set s $file_states($path) - set old_w [mapcol $old_m $path] - set new_w [mapcol $new_m $path] set new_m [lindex $s 0] - set new_ico [mapicon $new_m $path] + set new_w [mapcol $new_m $path] + set old_w [mapcol $old_m $path] + set new_icon [mapicon $new_m $path] if {$new_w != $old_w} { set lno [bsearch $old_w $path] @@ -1498,101 +1493,56 @@ pack $ui_other -side left -fill both -expand 1 $ui_index tag conf in_diff -font [concat $mainfont bold] $ui_other tag conf in_diff -font [concat $mainfont bold] -# -- Diff Header -set ui_fname_value {} -set ui_fstatus_value {} -frame .vpane.diff -height 200 -width 400 -frame .vpane.diff.header -label .vpane.diff.header.l1 -text {File:} -font $mainfont -label .vpane.diff.header.l2 -textvariable ui_fname_value \ - -anchor w \ - -justify left \ - -font $mainfont -label .vpane.diff.header.l3 -text {Status:} -font $mainfont -label .vpane.diff.header.l4 -textvariable ui_fstatus_value \ - -width $max_status_desc \ - -anchor w \ - -justify left \ - -font $mainfont -pack .vpane.diff.header.l1 -side left -pack .vpane.diff.header.l2 -side left -fill x -pack .vpane.diff.header.l4 -side right -pack .vpane.diff.header.l3 -side right - -# -- Diff Body -frame .vpane.diff.body -set ui_diff .vpane.diff.body.t -text $ui_diff -background white -borderwidth 0 \ - -width 80 -height 15 -wrap none \ - -font $difffont \ - -xscrollcommand {.vpane.diff.body.sbx set} \ - -yscrollcommand {.vpane.diff.body.sby set} \ - -cursor $maincursor \ - -state disabled -scrollbar .vpane.diff.body.sbx -orient horizontal \ - -command [list $ui_diff xview] -scrollbar .vpane.diff.body.sby -orient vertical \ - -command [list $ui_diff yview] -pack .vpane.diff.body.sbx -side bottom -fill x -pack .vpane.diff.body.sby -side right -fill y -pack $ui_diff -side left -fill both -expand 1 -pack .vpane.diff.header -side top -fill x -pack .vpane.diff.body -side bottom -fill both -expand 1 -.vpane add .vpane.diff -stick nsew - -$ui_diff tag conf dm -foreground red -$ui_diff tag conf dp -foreground blue -$ui_diff tag conf da -font [concat $difffont bold] -$ui_diff tag conf di -foreground "#00a000" -$ui_diff tag conf dni -foreground "#a000a0" -$ui_diff tag conf bold -font [concat $difffont bold] - -# -- Commit Area -frame .vpane.commarea -height 170 -.vpane add .vpane.commarea -stick nsew +# -- Diff and Commit Area +frame .vpane.lower -height 400 -width 400 +frame .vpane.lower.commarea +frame .vpane.lower.diff -relief sunken -borderwidth 1 +pack .vpane.lower.commarea -side top -fill x +pack .vpane.lower.diff -side bottom -fill both -expand 1 +.vpane add .vpane.lower -stick nsew # -- Commit Area Buttons -frame .vpane.commarea.buttons -label .vpane.commarea.buttons.l -text {} \ +frame .vpane.lower.commarea.buttons +label .vpane.lower.commarea.buttons.l -text {} \ -anchor w \ -justify left \ -font $mainfont -pack .vpane.commarea.buttons.l -side top -fill x -pack .vpane.commarea.buttons -side left -fill y +pack .vpane.lower.commarea.buttons.l -side top -fill x +pack .vpane.lower.commarea.buttons -side left -fill y -button .vpane.commarea.buttons.rescan -text {Rescan} \ +button .vpane.lower.commarea.buttons.rescan -text {Rescan} \ -command do_rescan \ -font $mainfont -pack .vpane.commarea.buttons.rescan -side top -fill x -lappend disable_on_lock {.vpane.commarea.buttons.rescan conf -state} +pack .vpane.lower.commarea.buttons.rescan -side top -fill x +lappend disable_on_lock {.vpane.lower.commarea.buttons.rescan conf -state} -button .vpane.commarea.buttons.amend -text {Amend Last} \ +button .vpane.lower.commarea.buttons.amend -text {Amend Last} \ -command do_amend_last \ -font $mainfont -pack .vpane.commarea.buttons.amend -side top -fill x -lappend disable_on_lock {.vpane.commarea.buttons.amend conf -state} +pack .vpane.lower.commarea.buttons.amend -side top -fill x +lappend disable_on_lock {.vpane.lower.commarea.buttons.amend conf -state} -button .vpane.commarea.buttons.ciall -text {Check-in All} \ +button .vpane.lower.commarea.buttons.ciall -text {Check-in All} \ -command do_checkin_all \ -font $mainfont -pack .vpane.commarea.buttons.ciall -side top -fill x -lappend disable_on_lock {.vpane.commarea.buttons.ciall conf -state} +pack .vpane.lower.commarea.buttons.ciall -side top -fill x +lappend disable_on_lock {.vpane.lower.commarea.buttons.ciall conf -state} -button .vpane.commarea.buttons.signoff -text {Sign Off} \ +button .vpane.lower.commarea.buttons.signoff -text {Sign Off} \ -command do_signoff \ -font $mainfont -pack .vpane.commarea.buttons.signoff -side top -fill x +pack .vpane.lower.commarea.buttons.signoff -side top -fill x -button .vpane.commarea.buttons.commit -text {Commit} \ +button .vpane.lower.commarea.buttons.commit -text {Commit} \ -command do_commit \ -font $mainfont -pack .vpane.commarea.buttons.commit -side top -fill x -lappend disable_on_lock {.vpane.commarea.buttons.commit conf -state} +pack .vpane.lower.commarea.buttons.commit -side top -fill x +lappend disable_on_lock {.vpane.lower.commarea.buttons.commit conf -state} # -- Commit Message Buffer -frame .vpane.commarea.buffer -set ui_comm .vpane.commarea.buffer.t -set ui_coml .vpane.commarea.buffer.l +frame .vpane.lower.commarea.buffer +set ui_comm .vpane.lower.commarea.buffer.t +set ui_coml .vpane.lower.commarea.buffer.l label $ui_coml -text {Commit Message:} \ -anchor w \ -justify left \ @@ -1606,15 +1556,68 @@ trace add variable commit_type write {uplevel #0 { }} text $ui_comm -background white -borderwidth 1 \ -relief sunken \ - -width 75 -height 10 -wrap none \ + -width 75 -height 9 -wrap none \ -font $difffont \ - -yscrollcommand {.vpane.commarea.buffer.sby set} \ + -yscrollcommand {.vpane.lower.commarea.buffer.sby set} \ -cursor $maincursor -scrollbar .vpane.commarea.buffer.sby -command [list $ui_comm yview] +scrollbar .vpane.lower.commarea.buffer.sby -command [list $ui_comm yview] pack $ui_coml -side top -fill x -pack .vpane.commarea.buffer.sby -side right -fill y +pack .vpane.lower.commarea.buffer.sby -side right -fill y pack $ui_comm -side left -fill y -pack .vpane.commarea.buffer -side left -fill y +pack .vpane.lower.commarea.buffer -side left -fill y + +# -- Diff Header +set ui_fname_value {} +set ui_fstatus_value {} +frame .vpane.lower.diff.header -background orange +label .vpane.lower.diff.header.l1 -text {File:} \ + -background orange \ + -font $mainfont +label .vpane.lower.diff.header.l2 -textvariable ui_fname_value \ + -background orange \ + -anchor w \ + -justify left \ + -font $mainfont +label .vpane.lower.diff.header.l3 -text {Status:} \ + -background orange \ + -font $mainfont +label .vpane.lower.diff.header.l4 -textvariable ui_fstatus_value \ + -background orange \ + -width $max_status_desc \ + -anchor w \ + -justify left \ + -font $mainfont +pack .vpane.lower.diff.header.l1 -side left +pack .vpane.lower.diff.header.l2 -side left -fill x +pack .vpane.lower.diff.header.l4 -side right +pack .vpane.lower.diff.header.l3 -side right + +# -- Diff Body +frame .vpane.lower.diff.body +set ui_diff .vpane.lower.diff.body.t +text $ui_diff -background white -borderwidth 0 \ + -width 80 -height 15 -wrap none \ + -font $difffont \ + -xscrollcommand {.vpane.lower.diff.body.sbx set} \ + -yscrollcommand {.vpane.lower.diff.body.sby set} \ + -cursor $maincursor \ + -state disabled +scrollbar .vpane.lower.diff.body.sbx -orient horizontal \ + -command [list $ui_diff xview] +scrollbar .vpane.lower.diff.body.sby -orient vertical \ + -command [list $ui_diff yview] +pack .vpane.lower.diff.body.sbx -side bottom -fill x +pack .vpane.lower.diff.body.sby -side right -fill y +pack $ui_diff -side left -fill both -expand 1 +pack .vpane.lower.diff.header -side top -fill x +pack .vpane.lower.diff.body -side bottom -fill both -expand 1 + +$ui_diff tag conf dm -foreground red +$ui_diff tag conf dp -foreground blue +$ui_diff tag conf da -font [concat $difffont bold] +$ui_diff tag conf di -foreground "#00a000" +$ui_diff tag conf dni -foreground "#a000a0" +$ui_diff tag conf bold -font [concat $difffont bold] # -- Status Bar set ui_status_value {Initializing...} -- cgit v1.2.1 From d1536c488e2f410c9f622356e29d9a5870d2403f Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Tue, 7 Nov 2006 20:40:35 -0500 Subject: git-gui: Added repack database menu option, to invoke git repack. Most users of git-gui probably shouldn't be invoking git repack directly; instead we should be looking at how many loose objects they have and how many active packs they have and making the decision for them. But that's more work to code, and there's always going to be discussion about what is the right default threshold and how do we know that the user is willing to do the repack when we decide its time, etc. So instead we'll just keep it simple and offer up the menu option. Unfortunately right now we get now progress indication back from git-pack-objects as its being invoked not through a tty, which makes it disable progress output and the git-repack.sh wrapper won't let us pass through --progress. Signed-off-by: Shawn O. Pearce --- git-gui | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 83f713535..eb7329c21 100755 --- a/git-gui +++ b/git-gui @@ -1276,6 +1276,14 @@ proc do_gitk {} { } } +proc do_repack {} { + set w [new_console "repack" "Repacking the object database"] + set cmd [list git repack] + lappend cmd -a + lappend cmd -d + console_exec $w $cmd +} + proc do_quit {} { global gitdir ui_comm @@ -1406,6 +1414,9 @@ menu .mbar.project .mbar.project add command -label Visualize \ -command do_gitk \ -font $mainfont +.mbar.project add command -label {Repack Database} \ + -command do_repack \ + -font $mainfont .mbar.project add command -label Quit \ -command do_quit \ -accelerator $M1T-Q \ -- cgit v1.2.1 From e534f3a88676fe0a08eb20359e1a43c6aa7dfe84 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Tue, 7 Nov 2006 21:27:29 -0500 Subject: git-gui: Allow the user to disable update-index --refresh during rescan. On very large projects (~1000 files) on Windows systems the update-index --refresh stage of the rescan process takes a nontrival amount of time. If the user is generally very careful with their file modification such that the modification timestamp of the file differs only when the content also differs then we can skip this somewhat expensive step and go right to the diff-index and diff-files processes. We save the user's prefernce in the current repository if they modify the setting during a git-gui session, but we also load it through our dump of repo-config --list so the user could move it to their ~/.gitconfig file if they wanted it globally disabled. We still keep update-index --refresh enabled by default however, as most users will probably want it. Signed-off-by: Shawn O. Pearce --- git-gui | 51 ++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 42 insertions(+), 9 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index eb7329c21..8562983d3 100755 --- a/git-gui +++ b/git-gui @@ -71,6 +71,7 @@ proc update_status {{final Ready.}} { global HEAD PARENT commit_type global ui_index ui_other ui_status_value ui_comm global status_active file_states + global cfg_trust_mtime if {$status_active || ![lock_index read]} return @@ -100,22 +101,28 @@ proc update_status {{final Ready.}} { $ui_comm edit modified false } - set status_active 1 - set ui_status_value {Refreshing file status...} - set fd_rf [open "| git update-index -q --unmerged --refresh" r] - fconfigure $fd_rf -blocking 0 -translation binary - fileevent $fd_rf readable [list read_refresh $fd_rf $final] + if {$cfg_trust_mtime == {true}} { + update_status_stage2 {} $final + } else { + set status_active 1 + set ui_status_value {Refreshing file status...} + set fd_rf [open "| git update-index -q --unmerged --refresh" r] + fconfigure $fd_rf -blocking 0 -translation binary + fileevent $fd_rf readable [list update_status_stage2 $fd_rf $final] + } } -proc read_refresh {fd final} { +proc update_status_stage2 {fd final} { global gitdir PARENT commit_type global ui_index ui_other ui_status_value ui_comm global status_active file_states global buf_rdi buf_rdf buf_rlo - read $fd - if {![eof $fd]} return - close $fd + if {$fd != {}} { + read $fd + if {![eof $fd]} return + close $fd + } set ls_others [list | git ls-files --others -z \ --exclude-per-directory=.gitignore] @@ -860,6 +867,7 @@ proc toggle_mode {path} { proc load_repo_config {} { global repo_config + global cfg_trust_mtime array unset repo_config catch { @@ -871,6 +879,22 @@ proc load_repo_config {} { } close $fd_rc } + + if {[catch {set cfg_trust_mtime $repo_config(gui.trustmtime)}]} { + set cfg_trust_mtime false + } +} + +proc save_my_config {} { + global repo_config + global cfg_trust_mtime + + if {[catch {set rc_trustMTime $repo_config(gui.trustmtime)}]} { + set rc_trustMTime false + } + if {$cfg_trust_mtime != $rc_trustMTime} { + exec git repo-config gui.trustMTime $cfg_trust_mtime + } } proc load_all_remotes {} { @@ -1299,6 +1323,7 @@ proc do_quit {} { file delete $save } + save_my_config destroy . } @@ -1407,6 +1432,7 @@ menu .mbar -tearoff 0 .mbar add cascade -label Fetch -menu .mbar.fetch .mbar add cascade -label Pull -menu .mbar.pull .mbar add cascade -label Push -menu .mbar.push +.mbar add cascade -label Options -menu .mbar.options . configure -menu .mbar # -- Project Menu @@ -1461,6 +1487,13 @@ menu .mbar.pull # -- Push Menu menu .mbar.push +# -- Options Menu +menu .mbar.options +.mbar.options add checkbutton -label {Trust File Modification Timestamp} \ + -offvalue false \ + -onvalue true \ + -variable cfg_trust_mtime + # -- Main Window Layout panedwindow .vpane -orient vertical panedwindow .vpane.files -orient horizontal -- cgit v1.2.1 From 988b8a7d63ff52f252bb4c517d9f05c3952aa728 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Tue, 7 Nov 2006 21:30:46 -0500 Subject: git-gui: Grab the index lock while running pull. The user must not modify the index while a git pull operation is running, doing so might cause problems for the merge driver and specific strategy being used. Normally on the command line people are just really good and don't try to run index altering operations while they are also running a pull. But in a slick GUI like git-gui we can't trust the user quite as much. Signed-off-by: Shawn O. Pearce --- git-gui | 2 ++ 1 file changed, 2 insertions(+) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 8562983d3..2d82152b3 100755 --- a/git-gui +++ b/git-gui @@ -642,6 +642,7 @@ proc fetch_from {remote} { } proc pull_remote {remote branch} { + if {![lock_index update]} return set w [new_console "pull $remote $branch" \ "Pulling new changes from branch $branch in $remote"] set cmd [list git pull] @@ -651,6 +652,7 @@ proc pull_remote {remote branch} { } proc post_pull_remote {remote branch success} { + unlock_index if {$success} { update_status "Successfully pulled $branch from $remote." } else { -- cgit v1.2.1 From 2bc5b3487e47dc6caa8d543fc50a944e80651c59 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Tue, 7 Nov 2006 21:38:22 -0500 Subject: git-gui: Pluralize timestamps within the options menu. Signed-off-by: Shawn O. Pearce --- git-gui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 2d82152b3..465c2f388 100755 --- a/git-gui +++ b/git-gui @@ -1491,7 +1491,7 @@ menu .mbar.push # -- Options Menu menu .mbar.options -.mbar.options add checkbutton -label {Trust File Modification Timestamp} \ +.mbar.options add checkbutton -label {Trust File Modification Timestamps} \ -offvalue false \ -onvalue true \ -variable cfg_trust_mtime -- cgit v1.2.1 From 0a462d67761b8178f09e23ef85a9298d1e19a2eb Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Tue, 7 Nov 2006 21:43:16 -0500 Subject: git-gui: Disable pull menu items when the index is locked. If we have the index locked then no pull command is allowed to proceed (as it would fail to get the index lock itself). So disable the pull menu items when we are doing any index based operations. Signed-off-by: Shawn O. Pearce --- git-gui | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 465c2f388..4041aaacd 100755 --- a/git-gui +++ b/git-gui @@ -932,7 +932,7 @@ proc populate_remote_menu {m pfx op} { } proc populate_pull_menu {m} { - global gitdir repo_config all_remotes mainfont + global gitdir repo_config all_remotes mainfont disable_on_lock foreach remote $all_remotes { set rb {} @@ -961,6 +961,8 @@ proc populate_pull_menu {m} { -label "Branch $rb_short from $remote..." \ -command [list pull_remote $remote $rb] \ -font $mainfont + lappend disable_on_lock \ + [list $m entryconf [$m index last] -state] } } } -- cgit v1.2.1 From ec39d83a55124660d03a744e0e7f67072a833950 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Tue, 7 Nov 2006 22:00:38 -0500 Subject: git-gui: Don't let the user pull into an uncommitted working directory. If there are modified files present in the working directory then we should not let the user perform a pull as it may fail due to the modified files being uncommitted but needing to be merged at the file level. Yes there are many cases where a merge will complete successfully even though there are modified or untracked files sitting in the working directory. But users generally shouldn't be attempting merges like that, and if they are they probably are advanced enough to just use the command line and bypass this little safety check. We also no longer run a rescan after a successful pull has completed. Usually this is unnecessary as a successful pull won't leave modified files laying around. Instead we just update our HEAD and PARENT values with the new commit, if there is one. Unfortunately this does let the user get into an insane state as there are bugs in core Git's git-pull and git-merge programs where the exit status is sent back as a 0 rather than non-0 when a failure is detected. Signed-off-by: Shawn O. Pearce --- git-gui | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 4041aaacd..d405008d2 100755 --- a/git-gui +++ b/git-gui @@ -642,7 +642,40 @@ proc fetch_from {remote} { } proc pull_remote {remote branch} { + global HEAD commit_type + global file_states + if {![lock_index update]} return + + # -- Our in memory state should match the repository. + # + repository_state curHEAD cur_type + if {$commit_type != $cur_type || $HEAD != $curHEAD} { + error_popup {Last scanned state does not match repository state. + +Its highly likely that another Git program modified the +repository since our last scan. A rescan is required +before a pull can be started. +} + unlock_index + update_status + return + } + + # -- No differences should exist before a pull. + # + if {[array size file_states] != 0} { + error_popup {Uncommitted but modified files are present. + +You should not perform a pull with unmodified files in your working +directory as Git would be unable to recover from an incorrect merge. + +Commit or throw away all changes before starting a pull operation. +} + unlock_index + return + } + set w [new_console "pull $remote $branch" \ "Pulling new changes from branch $branch in $remote"] set cmd [list git pull] @@ -652,9 +685,14 @@ proc pull_remote {remote branch} { } proc post_pull_remote {remote branch success} { + global HEAD PARENT commit_type + global ui_status_value + unlock_index if {$success} { - update_status "Successfully pulled $branch from $remote." + repository_state HEAD commit_type + set PARENT $HEAD + set $ui_status_value {Ready.} } else { update_status "Conflicts detected while pulling $branch from $remote." } -- cgit v1.2.1 From e4ee9af4946557370cfe18efdfa46c265a10639f Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Tue, 7 Nov 2006 22:09:55 -0500 Subject: git-gui: Bug fix for bad variable reference in display_file. When a file jumps between the file lists due to its state changing we crashed thanks to a stale variable reference within the procedure as we tried to setup the new icon. Signed-off-by: Shawn O. Pearce --- git-gui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index d405008d2..515cbb9df 100755 --- a/git-gui +++ b/git-gui @@ -819,7 +819,7 @@ proc display_file {path state} { $new_w image create $lno.0 \ -align center -padx 5 -pady 1 \ -name [lindex $s 1] \ - -image [mapicon $m $path] + -image $new_icon $new_w insert $lno.1 "$path\n" $new_w conf -state disabled } elseif {$new_icon != [mapicon $old_m $path]} { -- cgit v1.2.1 From 7fe7e733fafbab0373ee0d8fc35b9e284a598ee4 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Wed, 8 Nov 2006 22:48:34 -0500 Subject: git-gui: Changed term 'check-in' to 'include'. At least one user was confused by the term 'check-in'; he thought that clicking that button would commit just that one file, but he wanted to include all modified files into his next commit. Since git doesn't really have a check-in concept this really was poor language to use. Git does have an update-index concept but that is a little too low level to show to the user. So instead we now talk about including files in a commit. Signed-off-by: Shawn O. Pearce --- git-gui | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 515cbb9df..c57d71314 100755 --- a/git-gui +++ b/git-gui @@ -14,7 +14,7 @@ exec wish "$0" -- "$@" set single_commit 0 set status_active 0 set diff_active 0 -set checkin_active 0 +set update_active 0 set commit_active 0 set update_index_fd {} @@ -469,7 +469,7 @@ before committing. error_popup "Unmerged files cannot be committed. File $path has merge conflicts. -You must resolve them and check the file in before committing. +You must resolve them and include the file before committing. " unlock_index return @@ -483,9 +483,9 @@ File $path cannot be committed by this program. } } if {!$files_ready} { - error_popup {No checked-in files to commit. + error_popup {No included files to commit. -You must check-in at least 1 file before you can commit. +You must include at least 1 file before you can commit. } unlock_index return @@ -1088,7 +1088,7 @@ foreach i { {__ i plain "Unmodified"} {_M i mod "Modified"} {M_ i fulltick "Checked in"} - {MM i parttick "Partially checked in"} + {MM i parttick "Partially included"} {_O o plain "Untracked"} {A_ o fulltick "Added"} @@ -1373,13 +1373,13 @@ proc do_rescan {} { update_status } -proc do_checkin_all {} { - global checkin_active ui_status_value +proc do_include_all {} { + global update_active ui_status_value - if {$checkin_active || ![lock_index begin-update]} return + if {$update_active || ![lock_index begin-update]} return - set checkin_active 1 - set ui_status_value {Checking in all files...} + set update_active 1 + set ui_status_value {Including all modified files...} after 1 { with_update_index { foreach path [array names file_states] { @@ -1393,7 +1393,7 @@ proc do_checkin_all {} { } } } - set checkin_active 0 + set update_active 0 set ui_status_value {Ready.} } } @@ -1503,8 +1503,8 @@ lappend disable_on_lock \ -font $mainfont lappend disable_on_lock \ [list .mbar.commit entryconf [.mbar.commit index last] -state] -.mbar.commit add command -label {Check-in All Files} \ - -command do_checkin_all \ +.mbar.commit add command -label {Include All Files} \ + -command do_include_all \ -accelerator $M1T-U \ -font $mainfont lappend disable_on_lock \ @@ -1608,11 +1608,11 @@ button .vpane.lower.commarea.buttons.amend -text {Amend Last} \ pack .vpane.lower.commarea.buttons.amend -side top -fill x lappend disable_on_lock {.vpane.lower.commarea.buttons.amend conf -state} -button .vpane.lower.commarea.buttons.ciall -text {Check-in All} \ - -command do_checkin_all \ +button .vpane.lower.commarea.buttons.incall -text {Include All} \ + -command do_include_all \ -font $mainfont -pack .vpane.lower.commarea.buttons.ciall -side top -fill x -lappend disable_on_lock {.vpane.lower.commarea.buttons.ciall conf -state} +pack .vpane.lower.commarea.buttons.incall -side top -fill x +lappend disable_on_lock {.vpane.lower.commarea.buttons.incall conf -state} button .vpane.lower.commarea.buttons.signoff -text {Sign Off} \ -command do_signoff \ @@ -1723,8 +1723,8 @@ bind all <$M1B-Key-r> do_rescan bind all <$M1B-Key-R> do_rescan bind . <$M1B-Key-s> do_signoff bind . <$M1B-Key-S> do_signoff -bind . <$M1B-Key-u> do_checkin_all -bind . <$M1B-Key-U> do_checkin_all +bind . <$M1B-Key-u> do_include_all +bind . <$M1B-Key-U> do_include_all bind . <$M1B-Key-Return> do_commit bind all <$M1B-Key-q> do_quit bind all <$M1B-Key-Q> do_quit -- cgit v1.2.1 From d4ab2035ca64ccb380c42a73f1ce0aefe1669a39 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Wed, 8 Nov 2006 22:51:09 -0500 Subject: git-gui: Show only the abbreviated SHA1 after committing. There's really no great reason to show the entire commit object id within the GUI, especially if the user is unable to copy and paste it into another interface such as gitk or a terminal window. So we'll just show them the first 8 digits and hope that is unique within their repository. Signed-off-by: Shawn O. Pearce --- git-gui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index c57d71314..1b1ffee5e 100755 --- a/git-gui +++ b/git-gui @@ -626,7 +626,7 @@ proc commit_stage2 {fd_wt curHEAD msg} { set HEAD $cmt_id set PARENT $cmt_id unlock_index - update_status "Changes committed as $cmt_id." + update_status "Changes committed as [string range $cmt_id 0 7]." } ###################################################################### -- cgit v1.2.1 From 97bf01c46526a680fb04ac88cb0ecaefbd3b4d7f Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Wed, 8 Nov 2006 23:05:46 -0500 Subject: git-gui: Cache the GIT_COMMITTER_IDENT value on first sign-off. Caching the Signed-Off-By line isn't very important (as its not performance critical). The major improvement here is that we now report an error to the user if we can't obtain their name from git-var. Signed-off-by: Shawn O. Pearce --- git-gui | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 1b1ffee5e..ad3aa0727 100755 --- a/git-gui +++ b/git-gui @@ -1398,19 +1398,28 @@ proc do_include_all {} { } } +set GIT_COMMITTER_IDENT {} + proc do_signoff {} { - global ui_comm + global ui_comm GIT_COMMITTER_IDENT - catch { - set me [exec git var GIT_COMMITTER_IDENT] - if {[regexp {(.*) [0-9]+ [-+0-9]+$} $me me name]} { - set str "Signed-off-by: $name" - if {[$ui_comm get {end -1c linestart} {end -1c}] != $str} { - $ui_comm insert end "\n" - $ui_comm insert end $str - $ui_comm see end - } + if {$GIT_COMMITTER_IDENT == {}} { + if {[catch {set me [exec git var GIT_COMMITTER_IDENT]} err]} { + error_popup "Unable to obtain your identity:\n$err" + return } + if {![regexp {^(.*) [0-9]+ [-+0-9]+$} \ + $me me GIT_COMMITTER_IDENT]} { + error_popup "Invalid GIT_COMMITTER_IDENT:\n$me" + return + } + } + + set str "Signed-off-by: $GIT_COMMITTER_IDENT" + if {[$ui_comm get {end -1c linestart} {end -1c}] != $str} { + $ui_comm insert end "\n" + $ui_comm insert end $str + $ui_comm see end } } -- cgit v1.2.1 From 2d19516db4a6807e817879e6d30fd3137a4a7817 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Wed, 8 Nov 2006 23:42:51 -0500 Subject: git-gui: Save window geometry to .git/config during exit. I started to find it very annoying that my test application kept opening at the wrong location on my desktop, so now we save the basic window geometry and sash positions into the config file as gui.geometry. Signed-off-by: Shawn O. Pearce --- git-gui | 149 ++++++++++++++++++++++++++++++++++++++-------------------------- 1 file changed, 88 insertions(+), 61 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index ad3aa0727..aa73aa3de 100755 --- a/git-gui +++ b/git-gui @@ -7,6 +7,86 @@ exec wish "$0" -- "$@" # and distributed under the terms of the GNU General Public Licence, # either version 2, or (at your option) any later version. +###################################################################### +## +## config + +proc load_repo_config {} { + global repo_config + global cfg_trust_mtime + + array unset repo_config + catch { + set fd_rc [open "| git repo-config --list" r] + while {[gets $fd_rc line] >= 0} { + if {[regexp {^([^=]+)=(.*)$} $line line name value]} { + lappend repo_config($name) $value + } + } + close $fd_rc + } + + if {[catch {set cfg_trust_mtime \ + [lindex $repo_config(gui.trustmtime) 0] + }]} { + set cfg_trust_mtime false + } +} + +proc save_my_config {} { + global repo_config + global cfg_trust_mtime + + if {[catch {set rc_trustMTime $repo_config(gui.trustmtime)}]} { + set rc_trustMTime [list false] + } + if {$cfg_trust_mtime != [lindex $rc_trustMTime 0]} { + exec git repo-config gui.trustMTime $cfg_trust_mtime + set repo_config(gui.trustmtime) [list $cfg_trust_mtime] + } + + set cfg_geometry [list \ + [wm geometry .] \ + [.vpane sash coord 0] \ + [.vpane.files sash coord 0] \ + ] + if {[catch {set rc_geometry $repo_config(gui.geometry)}]} { + set rc_geometry [list [list]] + } + if {$cfg_geometry != [lindex $rc_geometry 0]} { + exec git repo-config gui.geometry $cfg_geometry + set repo_config(gui.geometry) [list $cfg_geometry] + } +} + +###################################################################### +## +## repository setup + +set appname [lindex [file split $argv0] end] +set gitdir {} +set GIT_COMMITTER_IDENT {} + +if {[catch {set cdup [exec git rev-parse --show-cdup]} err]} { + show_msg {} . "Cannot find the git directory: $err" + exit 1 +} +if {$cdup != ""} { + cd $cdup +} +unset cdup + +if {[catch {set gitdir [exec git rev-parse --git-dir]} err]} { + show_msg {} . "Cannot find the git directory: $err" + exit 1 +} + +if {$appname == {git-citool}} { + set single_commit 1 +} + +load_repo_config + ###################################################################### ## ## task management @@ -903,39 +983,7 @@ proc toggle_mode {path} { ###################################################################### ## -## config (fetch push pull) - -proc load_repo_config {} { - global repo_config - global cfg_trust_mtime - - array unset repo_config - catch { - set fd_rc [open "| git repo-config --list" r] - while {[gets $fd_rc line] >= 0} { - if {[regexp {^([^=]+)=(.*)$} $line line name value]} { - lappend repo_config($name) $value - } - } - close $fd_rc - } - - if {[catch {set cfg_trust_mtime $repo_config(gui.trustmtime)}]} { - set cfg_trust_mtime false - } -} - -proc save_my_config {} { - global repo_config - global cfg_trust_mtime - - if {[catch {set rc_trustMTime $repo_config(gui.trustmtime)}]} { - set rc_trustMTime false - } - if {$cfg_trust_mtime != $rc_trustMTime} { - exec git repo-config gui.trustMTime $cfg_trust_mtime - } -} +## remote management proc load_all_remotes {} { global gitdir all_remotes repo_config @@ -1398,8 +1446,6 @@ proc do_include_all {} { } } -set GIT_COMMITTER_IDENT {} - proc do_signoff {} { global ui_comm GIT_COMMITTER_IDENT @@ -1724,6 +1770,13 @@ label .status -textvariable ui_status_value \ -font $mainfont pack .status -anchor w -side bottom -fill x +# -- Load geometry +catch { +wm geometry . [lindex $repo_config(gui.geometry) 0 0] +eval .vpane sash place 0 [lindex $repo_config(gui.geometry) 0 1] +eval .vpane.files sash place 0 [lindex $repo_config(gui.geometry) 0 2] +} + # -- Key Bindings bind $ui_comm <$M1B-Key-Return> {do_commit;break} bind . do_quit @@ -1746,34 +1799,8 @@ foreach i [list $ui_index $ui_other] { } unset i M1B M1T -###################################################################### -## -## main - -set appname [lindex [file split $argv0] end] -set gitdir {} - -if {[catch {set cdup [exec git rev-parse --show-cdup]} err]} { - show_msg {} . "Cannot find the git directory: $err" - exit 1 -} -if {$cdup != ""} { - cd $cdup -} -unset cdup - -if {[catch {set gitdir [exec git rev-parse --git-dir]} err]} { - show_msg {} . "Cannot find the git directory: $err" - exit 1 -} - -if {$appname == {git-citool}} { - set single_commit 1 -} - wm title . "$appname ([file normalize [file dirname $gitdir]])" focus -force $ui_comm -load_repo_config load_all_remotes populate_remote_menu .mbar.fetch From fetch_from populate_remote_menu .mbar.push To push_to -- cgit v1.2.1 From 49b86f010c3f2d6576a8fba45c5c6b9a23f76fa0 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 11 Nov 2006 15:16:01 -0500 Subject: git-gui: Change accelerator for "Include All" to M1-I. Now that we call the update-index all files action "Include All" it makes more sense to make this M1-I (so Control-I or Command-I depending on platform) than M1-U, which stood for update but is somewhat confusing to users. Signed-off-by: Shawn O. Pearce --- git-gui | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index aa73aa3de..20c36c2d2 100755 --- a/git-gui +++ b/git-gui @@ -1560,7 +1560,7 @@ lappend disable_on_lock \ [list .mbar.commit entryconf [.mbar.commit index last] -state] .mbar.commit add command -label {Include All Files} \ -command do_include_all \ - -accelerator $M1T-U \ + -accelerator $M1T-I \ -font $mainfont lappend disable_on_lock \ [list .mbar.commit entryconf [.mbar.commit index last] -state] @@ -1779,14 +1779,17 @@ eval .vpane.files sash place 0 [lindex $repo_config(gui.geometry) 0 2] # -- Key Bindings bind $ui_comm <$M1B-Key-Return> {do_commit;break} +bind $ui_comm <$M1B-Key-i> {do_include_all;break} +bind $ui_comm <$M1B-Key-I> {do_include_all;break} + bind . do_quit bind all do_rescan bind all <$M1B-Key-r> do_rescan bind all <$M1B-Key-R> do_rescan bind . <$M1B-Key-s> do_signoff bind . <$M1B-Key-S> do_signoff -bind . <$M1B-Key-u> do_include_all -bind . <$M1B-Key-U> do_include_all +bind . <$M1B-Key-i> do_include_all +bind . <$M1B-Key-I> do_include_all bind . <$M1B-Key-Return> do_commit bind all <$M1B-Key-q> do_quit bind all <$M1B-Key-Q> do_quit -- cgit v1.2.1 From 9861671de26bf7cd41f591bd2099ac299349f284 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 11 Nov 2006 15:51:41 -0500 Subject: git-gui: Created edit menu and basic editing bindings. Users have come to expect basic editing features within their applications, such as cut/copy/paste/undo/redo/select-all. I found these features to be lacking in git-gui so now we have them. I also added basic keyboard bindings for the diff viewing area so that the arrow keys move around single units (lines or columns) and the M1-X/C keys will copy the selected text and the M1-A key will select the entire diff. Signed-off-by: Shawn O. Pearce --- git-gui | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 20c36c2d2..640519c20 100755 --- a/git-gui +++ b/git-gui @@ -1525,6 +1525,7 @@ default {set M1B M1; set M1T M1} # -- Menu Bar menu .mbar -tearoff 0 .mbar add cascade -label Project -menu .mbar.project +.mbar add cascade -label Edit -menu .mbar.edit .mbar add cascade -label Commit -menu .mbar.commit .mbar add cascade -label Fetch -menu .mbar.fetch .mbar add cascade -label Pull -menu .mbar.pull @@ -1545,6 +1546,40 @@ menu .mbar.project -accelerator $M1T-Q \ -font $mainfont +# -- Edit Menu +# +menu .mbar.edit +.mbar.edit add command -label Undo \ + -command {catch {[focus] edit undo}} \ + -accelerator $M1T-Z \ + -font $mainfont +.mbar.edit add command -label Redo \ + -command {catch {[focus] edit redo}} \ + -accelerator $M1T-Y \ + -font $mainfont +.mbar.edit add separator +.mbar.edit add command -label Cut \ + -command {catch {tk_textCut [focus]}} \ + -accelerator $M1T-X \ + -font $mainfont +.mbar.edit add command -label Copy \ + -command {catch {tk_textCopy [focus]}} \ + -accelerator $M1T-C \ + -font $mainfont +.mbar.edit add command -label Paste \ + -command {catch {tk_textPaste [focus]; [focus] see insert}} \ + -accelerator $M1T-V \ + -font $mainfont +.mbar.edit add command -label Delete \ + -command {catch {[focus] delete sel.first sel.last}} \ + -accelerator Del \ + -font $mainfont +.mbar.edit add separator +.mbar.edit add command -label {Select All} \ + -command {catch {[focus] tag add sel 0.0 end}} \ + -accelerator $M1T-A \ + -font $mainfont + # -- Commit Menu menu .mbar.commit .mbar.commit add command -label Rescan \ @@ -1586,7 +1621,8 @@ menu .mbar.push # -- Options Menu menu .mbar.options -.mbar.options add checkbutton -label {Trust File Modification Timestamps} \ +.mbar.options add checkbutton \ + -label {Trust File Modification Timestamps} \ -offvalue false \ -onvalue true \ -variable cfg_trust_mtime @@ -1696,6 +1732,8 @@ trace add variable commit_type write {uplevel #0 { * {$ui_coml conf -text {Commit Message:}} }} text $ui_comm -background white -borderwidth 1 \ + -undo true \ + -autoseparators true \ -relief sunken \ -width 75 -height 9 -wrap none \ -font $difffont \ @@ -1781,6 +1819,27 @@ eval .vpane.files sash place 0 [lindex $repo_config(gui.geometry) 0 2] bind $ui_comm <$M1B-Key-Return> {do_commit;break} bind $ui_comm <$M1B-Key-i> {do_include_all;break} bind $ui_comm <$M1B-Key-I> {do_include_all;break} +bind $ui_comm <$M1B-Key-x> {tk_textCut %W;break} +bind $ui_comm <$M1B-Key-X> {tk_textCut %W;break} +bind $ui_comm <$M1B-Key-c> {tk_textCopy %W;break} +bind $ui_comm <$M1B-Key-C> {tk_textCopy %W;break} +bind $ui_comm <$M1B-Key-v> {tk_textPaste %W; %W see insert; break} +bind $ui_comm <$M1B-Key-V> {tk_textPaste %W; %W see insert; break} +bind $ui_comm <$M1B-Key-a> {%W tag add sel 0.0 end;break} +bind $ui_comm <$M1B-Key-A> {%W tag add sel 0.0 end;break} + +bind $ui_diff <$M1B-Key-x> {tk_textCopy %W;break} +bind $ui_diff <$M1B-Key-X> {tk_textCopy %W;break} +bind $ui_diff <$M1B-Key-c> {tk_textCopy %W;break} +bind $ui_diff <$M1B-Key-C> {tk_textCopy %W;break} +bind $ui_diff <$M1B-Key-v> {break} +bind $ui_diff <$M1B-Key-V> {break} +bind $ui_diff <$M1B-Key-a> {%W tag add sel 0.0 end;break} +bind $ui_diff <$M1B-Key-A> {%W tag add sel 0.0 end;break} +bind $ui_diff {%W yview scroll -1 units} +bind $ui_diff {%W yview scroll 1 units} +bind $ui_diff {%W xview scroll -1 units} +bind $ui_diff {%W xview scroll 1 units} bind . do_quit bind all do_rescan -- cgit v1.2.1 From b2c6fcf197fd09a6fedb39e4d8d13e6fdc2df4d4 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 11 Nov 2006 16:16:25 -0500 Subject: git-gui: Clear undo/redo stack when loading a message file from disk. If we load a message file (e.g. MERGE_MSG) or we have just finished making a commit and are clearing out the commit buffer we should also clear out the undo/redo stack associated with that buffer. The prior undo/redo stack has no associated with the new content and therefore is not useful to the user. Also modified the sign-off operation to perform the entire update in a single undo/redo operation, allowing the user to undo the signoff in case they didn't actually want to do that. I also noticed what may be a crash on Windows related to the up and down arrow keys navigating within the diff viewer. Since I got back no stack trace (just an application exit with a loss of the commit message) I suspect that the binding to scroll the text widget crashed with an error and the wish process just terminated. So now we catch (and ignore) any sort of error related to the arrow keys in the diff viewer. Signed-off-by: Shawn O. Pearce --- git-gui | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 640519c20..540d56397 100755 --- a/git-gui +++ b/git-gui @@ -179,6 +179,7 @@ proc update_status {{final Ready.}} { } elseif {[load_message SQUASH_MSG]} { } $ui_comm edit modified false + $ui_comm edit reset } if {$cfg_trust_mtime == {true}} { @@ -503,6 +504,7 @@ proc load_last_commit {} { $ui_comm delete 0.0 end $ui_comm insert end $msg $ui_comm edit modified false + $ui_comm edit reset update_status } else { error_popup {You can't amend a merge commit.} @@ -698,6 +700,7 @@ proc commit_stage2 {fd_wt curHEAD msg} { $ui_comm delete 0.0 end $ui_comm edit modified false + $ui_comm edit reset if {$single_commit} do_quit @@ -1463,8 +1466,9 @@ proc do_signoff {} { set str "Signed-off-by: $GIT_COMMITTER_IDENT" if {[$ui_comm get {end -1c linestart} {end -1c}] != $str} { - $ui_comm insert end "\n" - $ui_comm insert end $str + $ui_comm edit separator + $ui_comm insert end "\n$str" + $ui_comm edit separator $ui_comm see end } } @@ -1733,6 +1737,7 @@ trace add variable commit_type write {uplevel #0 { }} text $ui_comm -background white -borderwidth 1 \ -undo true \ + -maxundo 20 \ -autoseparators true \ -relief sunken \ -width 75 -height 9 -wrap none \ @@ -1836,10 +1841,10 @@ bind $ui_diff <$M1B-Key-v> {break} bind $ui_diff <$M1B-Key-V> {break} bind $ui_diff <$M1B-Key-a> {%W tag add sel 0.0 end;break} bind $ui_diff <$M1B-Key-A> {%W tag add sel 0.0 end;break} -bind $ui_diff {%W yview scroll -1 units} -bind $ui_diff {%W yview scroll 1 units} -bind $ui_diff {%W xview scroll -1 units} -bind $ui_diff {%W xview scroll 1 units} +bind $ui_diff {catch {%W yview scroll -1 units};break} +bind $ui_diff {catch {%W yview scroll 1 units};break} +bind $ui_diff {catch {%W xview scroll -1 units};break} +bind $ui_diff {catch {%W xview scroll 1 units};break} bind . do_quit bind all do_rescan -- cgit v1.2.1 From 03e4ec5364f955f5e1af0775166c679ed60f7fb4 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 11 Nov 2006 17:52:16 -0500 Subject: git-gui: Always indicate the file in the diff viewer. When we did a rescan to update the file lists we lost the tag which indicated which file was currently in the diff viewer. This occurs because we delete every line from the two file list boxes (thus removing the tag) and then redisplay the diff in the diff viewer but then fail to restore the tag in the file list. Now we restore that tag by searching for the file in the file lists and adding the tag back when the diff viewer displays something. We also no longer obtain the file path directly from the file list text box. Instead we now keep two Tcl lists, one for each file list, holding the file names in sorted order. These lists can be searched with the native [lsearch -sorted] operation (which should be faster than our crude bsearch) or can be quickly accessed by index to return the file path. This should help make things safer should we ever be given a file name which contains an LF within it (as that would span two lines in the file list, not one). Signed-off-by: Shawn O. Pearce --- git-gui | 72 ++++++++++++++++++++++++++++++++--------------------------------- 1 file changed, 36 insertions(+), 36 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 540d56397..f36594eea 100755 --- a/git-gui +++ b/git-gui @@ -150,7 +150,7 @@ proc repository_state {hdvar ctvar} { proc update_status {{final Ready.}} { global HEAD PARENT commit_type global ui_index ui_other ui_status_value ui_comm - global status_active file_states + global status_active file_states file_lists global cfg_trust_mtime if {$status_active || ![lock_index read]} return @@ -166,6 +166,7 @@ proc update_status {{final Ready.}} { } array unset file_states + array unset file_lists foreach w [list $ui_index $ui_other] { $w conf -state normal $w delete 0.0 end @@ -196,7 +197,7 @@ proc update_status {{final Ready.}} { proc update_status_stage2 {fd final} { global gitdir PARENT commit_type global ui_index ui_other ui_status_value ui_comm - global status_active file_states + global status_active global buf_rdi buf_rdf buf_rlo if {$fd != {}} { @@ -346,22 +347,40 @@ proc status_eof {fd buf final} { ## diff proc clear_diff {} { - global ui_diff ui_fname_value ui_fstatus_value + global ui_diff ui_fname_value ui_fstatus_value ui_index ui_other $ui_diff conf -state normal $ui_diff delete 0.0 end $ui_diff conf -state disabled + set ui_fname_value {} set ui_fstatus_value {} + + $ui_index tag remove in_diff 0.0 end + $ui_other tag remove in_diff 0.0 end } -proc show_diff {path} { - global file_states PARENT diff_3way diff_active +proc show_diff {path {w {}} {lno {}}} { + global file_states file_lists + global PARENT diff_3way diff_active global ui_diff ui_fname_value ui_fstatus_value ui_status_value if {$diff_active || ![lock_index read]} return clear_diff + if {$w == {} || $lno == {}} { + foreach w [array names file_lists] { + set lno [lsearch -sorted $file_lists($w) $path] + if {$lno >= 0} { + incr lno + break + } + } + } + if {$w != {} && $lno >= 1} { + $w tag add in_diff $lno.0 [expr $lno + 1].0 + } + set s $file_states($path) set m [lindex $s 0] set diff_3way 0 @@ -823,27 +842,6 @@ proc mapdesc {state path} { return $r } -proc bsearch {w path} { - set hi [expr [lindex [split [$w index end] .] 0] - 2] - if {$hi == 0} { - return -1 - } - set lo 0 - while {$lo < $hi} { - set mi [expr [expr $lo + $hi] / 2] - set ti [expr $mi + 1] - set cmp [string compare [$w get $ti.1 $ti.end] $path] - if {$cmp < 0} { - set lo $ti - } elseif {$cmp == 0} { - return $mi - } else { - set hi $mi - } - } - return -[expr $lo + 1] -} - set next_icon_id 0 proc merge_state {path new_state} { @@ -877,7 +875,8 @@ proc merge_state {path new_state} { } proc display_file {path state} { - global ui_index ui_other file_states status_active + global ui_index ui_other + global file_states file_lists status_active set old_m [merge_state $path $state] if {$status_active} return @@ -889,7 +888,7 @@ proc display_file {path state} { set new_icon [mapicon $new_m $path] if {$new_w != $old_w} { - set lno [bsearch $old_w $path] + set lno [lsearch -sorted $file_lists($old_w) $path] if {$lno >= 0} { incr lno $old_w conf -state normal @@ -897,7 +896,10 @@ proc display_file {path state} { $old_w conf -state disabled } - set lno [expr abs([bsearch $new_w $path] + 1) + 1] + lappend file_lists($new_w) $path + set file_lists($new_w) [lsort $file_lists($new_w)] + set lno [lsearch -sorted $file_lists($new_w) $path] + incr lno $new_w conf -state normal $new_w image create $lno.0 \ -align center -padx 5 -pady 1 \ @@ -913,7 +915,7 @@ proc display_file {path state} { } proc display_all_files {} { - global ui_index ui_other file_states + global ui_index ui_other file_states file_lists $ui_index conf -state normal $ui_other conf -state normal @@ -922,6 +924,7 @@ proc display_all_files {} { set s $file_states($path) set m [lindex $s 0] set w [mapcol $m $path] + lappend file_lists($w) $path $w image create end \ -align center -padx 5 -pady 1 \ -name [lindex $s 1] \ @@ -1484,19 +1487,16 @@ proc do_commit {} { # shift == 1: left click # 3: right click proc click {w x y shift wx wy} { - global ui_index ui_other + global ui_index ui_other file_lists set pos [split [$w index @$x,$y] .] set lno [lindex $pos 0] set col [lindex $pos 1] - set path [$w get $lno.1 $lno.end] + set path [lindex $file_lists($w) [expr $lno - 1]] if {$path == {}} return if {$col > 0 && $shift == 1} { - $ui_index tag remove in_diff 0.0 end - $ui_other tag remove in_diff 0.0 end - $w tag add in_diff $lno.0 [expr $lno + 1].0 - show_diff $path + show_diff $path $w $lno } } -- cgit v1.2.1 From 68e009dec44a023efd6f6fcd61c1583b23b04f32 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 11 Nov 2006 17:59:34 -0500 Subject: git-gui: Correctly handle files containing LF in their name. If we are given a file whose path name contains an LF (\n) we now escape it by inserting the common escape string \n instead of the LF character whenever we display the name in the UI. This way the text fields don't start to span multiple lines just to display one file, and it keeps the line numbers correct within the file lists. Signed-off-by: Shawn O. Pearce --- git-gui | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index f36594eea..ab64684c9 100755 --- a/git-gui +++ b/git-gui @@ -385,9 +385,9 @@ proc show_diff {path {w {}} {lno {}}} { set m [lindex $s 0] set diff_3way 0 set diff_active 1 - set ui_fname_value $path + set ui_fname_value [escape_path $path] set ui_fstatus_value [mapdesc $m $path] - set ui_status_value "Loading diff of $path..." + set ui_status_value "Loading diff of [escape_path $path]..." set cmd [list | git diff-index -p $PARENT -- $path] switch $m { @@ -404,7 +404,7 @@ proc show_diff {path {w {}} {lno {}}} { } err ]} { set diff_active 0 unlock_index - set ui_status_value "Unable to display $path" + set ui_status_value "Unable to display [escape_path $path]" error_popup "Error loading file:\n$err" return } @@ -421,7 +421,7 @@ proc show_diff {path {w {}} {lno {}}} { if {[catch {set fd [open $cmd r]} err]} { set diff_active 0 unlock_index - set ui_status_value "Unable to display $path" + set ui_status_value "Unable to display [escape_path $path]" error_popup "Error loading diff:\n$err" return } @@ -569,7 +569,7 @@ before committing. U* { error_popup "Unmerged files cannot be committed. -File $path has merge conflicts. +File [escape_path $path] has merge conflicts. You must resolve them and include the file before committing. " unlock_index @@ -578,7 +578,7 @@ You must resolve them and include the file before committing. default { error_popup "Unknown file state [lindex $s 0] detected. -File $path cannot be committed by this program. +File [escape_path $path] cannot be committed by this program. " } } @@ -842,6 +842,11 @@ proc mapdesc {state path} { return $r } +proc escape_path {path} { + regsub -all "\n" $path "\\n" path + return $path +} + set next_icon_id 0 proc merge_state {path new_state} { @@ -905,7 +910,7 @@ proc display_file {path state} { -align center -padx 5 -pady 1 \ -name [lindex $s 1] \ -image $new_icon - $new_w insert $lno.1 "$path\n" + $new_w insert $lno.1 "[escape_path $path]\n" $new_w conf -state disabled } elseif {$new_icon != [mapicon $old_m $path]} { $new_w conf -state normal @@ -929,7 +934,7 @@ proc display_all_files {} { -align center -padx 5 -pady 1 \ -name [lindex $s 1] \ -image [mapicon $m $path] - $w insert end "$path\n" + $w insert end "[escape_path $path]\n" } $ui_index conf -state disabled -- cgit v1.2.1 From 7f1df79bb7bad696d1d8965da3937edeb1cfe9f6 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 11 Nov 2006 18:38:00 -0500 Subject: git-gui: Efficiently update the UI after committing. When we commit we know that whatever was in the index went as part of the commit. Since we generally assume that the user does not update the index except through our user interface we can be reasonably certain that any file which was marked as A/M/D in the index will have had that A/M/D state changed to an _ (not different) by the commit. We can use this knowledge to update the user interface post commit by simply updating the index part of the file state of all files whose index state was A/M/D to _ and then removing any file memory any which wound up with a final state of __ (not different anywhere). Finally we redraw the file lists and update the diff view. Signed-off-by: Shawn O. Pearce --- git-gui | 85 +++++++++++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 56 insertions(+), 29 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index ab64684c9..2c4e97236 100755 --- a/git-gui +++ b/git-gui @@ -150,7 +150,7 @@ proc repository_state {hdvar ctvar} { proc update_status {{final Ready.}} { global HEAD PARENT commit_type global ui_index ui_other ui_status_value ui_comm - global status_active file_states file_lists + global status_active file_states global cfg_trust_mtime if {$status_active || ![lock_index read]} return @@ -166,12 +166,6 @@ proc update_status {{final Ready.}} { } array unset file_states - array unset file_lists - foreach w [list $ui_index $ui_other] { - $w conf -state normal - $w delete 0.0 end - $w conf -state disabled - } if {![$ui_comm edit modified] || [string trim [$ui_comm get 0.0 end]] == {}} { @@ -319,25 +313,18 @@ proc read_ls_others {fd final} { } proc status_eof {fd buf final} { - global status_active $buf - global ui_fname_value ui_status_value file_states + global status_active ui_status_value + upvar $buf to_clear if {[eof $fd]} { - set $buf {} + set to_clear {} close $fd if {[incr status_active -1] == 0} { - unlock_index - display_all_files + unlock_index + reshow_diff set ui_status_value $final - - if {$ui_fname_value != {} && [array names file_states \ - -exact $ui_fname_value] != {}} { - show_diff $ui_fname_value - } else { - clear_diff - } } } } @@ -360,6 +347,17 @@ proc clear_diff {} { $ui_other tag remove in_diff 0.0 end } +proc reshow_diff {} { + global ui_fname_value ui_status_value file_states + + if {$ui_fname_value != {} && [array names file_states \ + -exact $ui_fname_value] != {}} { + show_diff $ui_fname_value + } else { + clear_diff + } +} + proc show_diff {path {w {}} {lno {}}} { global file_states file_lists global PARENT diff_3way diff_active @@ -562,11 +560,11 @@ before committing. foreach path [array names file_states] { set s $file_states($path) switch -glob -- [lindex $s 0] { - _* {continue} - A* - - D* - - M* {set files_ready 1; break} - U* { + _? {continue} + A? - + D? - + M? {set files_ready 1; break} + U? { error_popup "Unmerged files cannot be committed. File [escape_path $path] has merge conflicts. @@ -635,8 +633,9 @@ A good commit message has the following format: } proc commit_stage2 {fd_wt curHEAD msg} { - global single_commit gitdir PARENT commit_type + global single_commit gitdir HEAD PARENT commit_type global commit_active ui_status_value ui_comm + global file_states gets $fd_wt tree_id close $fd_wt @@ -663,7 +662,7 @@ proc commit_stage2 {fd_wt curHEAD msg} { } close $fd_mh } err]} { - error_popup "Loading MERGE_HEADs failed:\n$err" + error_popup "Loading MERGE_HEAD failed:\n$err" set commit_active 0 set ui_status_value {Commit failed.} unlock_index @@ -723,12 +722,34 @@ proc commit_stage2 {fd_wt curHEAD msg} { if {$single_commit} do_quit - set commit_type {} + # -- Update status without invoking any git commands. + # set commit_active 0 + set commit_type normal set HEAD $cmt_id set PARENT $cmt_id + + foreach path [array names file_states] { + set s $file_states($path) + set m [lindex $s 0] + switch -glob -- $m { + A? - + M? - + D? {set m _[string index $m 1]} + } + + if {$m == {__}} { + unset file_states($path) + } else { + lset file_states($path) 0 $m + } + } + + display_all_files unlock_index - update_status "Changes committed as [string range $cmt_id 0 7]." + reshow_diff + set ui_status_value \ + "Changes committed as [string range $cmt_id 0 7]." } ###################################################################### @@ -925,6 +946,10 @@ proc display_all_files {} { $ui_index conf -state normal $ui_other conf -state normal + $ui_index delete 0.0 end + $ui_other delete 0.0 end + + array unset file_lists foreach path [lsort [array names file_states]] { set s $file_states($path) set m [lindex $s 0] @@ -1506,10 +1531,12 @@ proc click {w x y shift wx wy} { } proc unclick {w x y} { + global file_lists + set pos [split [$w index @$x,$y] .] set lno [lindex $pos 0] set col [lindex $pos 1] - set path [$w get $lno.1 $lno.end] + set path [lindex $file_lists($w) [expr $lno - 1]] if {$path == {}} return if {$col == 0} { -- cgit v1.2.1 From 73ad179bbbba56c053045c555b7e5f1882380533 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 11 Nov 2006 18:42:42 -0500 Subject: git-gui: Use catch rather than array names to check file. When we reshow the current diff file it can be faster to just fetch the value from the file_states array than it is to ask for all paths whose name exactly matches the one we want to show. This is because [array names -exact] is O(n) in the number of files. Signed-off-by: Shawn O. Pearce --- git-gui | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 2c4e97236..e16fcf734 100755 --- a/git-gui +++ b/git-gui @@ -350,11 +350,11 @@ proc clear_diff {} { proc reshow_diff {} { global ui_fname_value ui_status_value file_states - if {$ui_fname_value != {} && [array names file_states \ - -exact $ui_fname_value] != {}} { - show_diff $ui_fname_value - } else { + if {$ui_fname_value == {} + || [catch {set s $file_states($ui_fname_value)}]} { clear_diff + } else { + show_diff $ui_fname_value } } -- cgit v1.2.1 From 3963678da9e78e87fa9b57f2f3ad75ba1c70e589 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 11 Nov 2006 18:46:52 -0500 Subject: git-gui: Rename difffont/mainfont variables. I found difffont to be a very awkward varible name, due to the use of three f's in a row. So use easier to read variable names. Signed-off-by: Shawn O. Pearce --- git-gui | 110 ++++++++++++++++++++++++++++++++-------------------------------- 1 file changed, 55 insertions(+), 55 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index e16fcf734..e30a11443 100755 --- a/git-gui +++ b/git-gui @@ -1044,17 +1044,17 @@ proc load_all_remotes {} { } proc populate_remote_menu {m pfx op} { - global all_remotes mainfont + global all_remotes font_ui foreach remote $all_remotes { $m add command -label "$pfx $remote..." \ -command [list $op $remote] \ - -font $mainfont + -font $font_ui } } proc populate_pull_menu {m} { - global gitdir repo_config all_remotes mainfont disable_on_lock + global gitdir repo_config all_remotes font_ui disable_on_lock foreach remote $all_remotes { set rb {} @@ -1082,7 +1082,7 @@ proc populate_pull_menu {m} { $m add command \ -label "Branch $rb_short from $remote..." \ -command [list pull_remote $remote $rb] \ - -font $mainfont + -font $font_ui lappend disable_on_lock \ [list $m entryconf [$m index last] -state] } @@ -1212,13 +1212,13 @@ proc error_popup {msg} { } proc show_msg {w top msg} { - global gitdir appname mainfont + global gitdir appname font_ui message $w.m -text $msg -justify left -aspect 400 pack $w.m -side top -fill x -padx 5 -pady 10 button $w.ok -text OK \ -width 15 \ - -font $mainfont \ + -font $font_ui \ -command "destroy $top" pack $w.ok -side bottom bind $top "grab $top; focus $top" @@ -1230,7 +1230,7 @@ proc show_msg {w top msg} { } proc hook_failed_popup {hook msg} { - global gitdir mainfont difffont appname + global gitdir font_ui font_diff appname set w .hookfail toplevel $w @@ -1240,18 +1240,18 @@ proc hook_failed_popup {hook msg} { label $w.m.l1 -text "$hook hook failed:" \ -anchor w \ -justify left \ - -font [concat $mainfont bold] + -font [concat $font_ui bold] text $w.m.t \ -background white -borderwidth 1 \ -relief sunken \ -width 80 -height 10 \ - -font $difffont \ + -font $font_diff \ -yscrollcommand [list $w.m.sby set] label $w.m.l2 \ -text {You must correct the above errors before committing.} \ -anchor w \ -justify left \ - -font [concat $mainfont bold] + -font [concat $font_ui bold] scrollbar $w.m.sby -command [list $w.m.t yview] pack $w.m.l1 -side top -fill x pack $w.m.l2 -side bottom -fill x @@ -1264,7 +1264,7 @@ proc hook_failed_popup {hook msg} { button $w.ok -text OK \ -width 15 \ - -font $mainfont \ + -font $font_ui \ -command "destroy $w" pack $w.ok -side bottom @@ -1287,7 +1287,7 @@ proc new_console {short_title long_title} { proc console_init {w} { global console_cr console_data - global gitdir appname mainfont difffont + global gitdir appname font_ui font_diff set console_cr($w) 1.0 toplevel $w @@ -1295,17 +1295,17 @@ proc console_init {w} { label $w.m.l1 -text "[lindex $console_data($w) 1]:" \ -anchor w \ -justify left \ - -font [concat $mainfont bold] + -font [concat $font_ui bold] text $w.m.t \ -background white -borderwidth 1 \ -relief sunken \ -width 80 -height 10 \ - -font $difffont \ + -font $font_diff \ -state disabled \ -yscrollcommand [list $w.m.sby set] label $w.m.s -anchor w \ -justify left \ - -font [concat $mainfont bold] + -font [concat $font_ui bold] scrollbar $w.m.sby -command [list $w.m.t yview] pack $w.m.l1 -side top -fill x pack $w.m.s -side bottom -fill x @@ -1315,7 +1315,7 @@ proc console_init {w} { button $w.ok -text {Running...} \ -width 15 \ - -font $mainfont \ + -font $font_ui \ -state disabled \ -command "destroy $w" pack $w.ok -side bottom @@ -1548,8 +1548,8 @@ proc unclick {w x y} { ## ## ui init -set mainfont {Helvetica 10} -set difffont {Courier 10} +set font_ui {Helvetica 10} +set font_diff {Courier 10} set maincursor [. cget -cursor] switch -glob -- "$tcl_platform(platform),$tcl_platform(os)" { @@ -1573,14 +1573,14 @@ menu .mbar -tearoff 0 menu .mbar.project .mbar.project add command -label Visualize \ -command do_gitk \ - -font $mainfont + -font $font_ui .mbar.project add command -label {Repack Database} \ -command do_repack \ - -font $mainfont + -font $font_ui .mbar.project add command -label Quit \ -command do_quit \ -accelerator $M1T-Q \ - -font $mainfont + -font $font_ui # -- Edit Menu # @@ -1588,61 +1588,61 @@ menu .mbar.edit .mbar.edit add command -label Undo \ -command {catch {[focus] edit undo}} \ -accelerator $M1T-Z \ - -font $mainfont + -font $font_ui .mbar.edit add command -label Redo \ -command {catch {[focus] edit redo}} \ -accelerator $M1T-Y \ - -font $mainfont + -font $font_ui .mbar.edit add separator .mbar.edit add command -label Cut \ -command {catch {tk_textCut [focus]}} \ -accelerator $M1T-X \ - -font $mainfont + -font $font_ui .mbar.edit add command -label Copy \ -command {catch {tk_textCopy [focus]}} \ -accelerator $M1T-C \ - -font $mainfont + -font $font_ui .mbar.edit add command -label Paste \ -command {catch {tk_textPaste [focus]; [focus] see insert}} \ -accelerator $M1T-V \ - -font $mainfont + -font $font_ui .mbar.edit add command -label Delete \ -command {catch {[focus] delete sel.first sel.last}} \ -accelerator Del \ - -font $mainfont + -font $font_ui .mbar.edit add separator .mbar.edit add command -label {Select All} \ -command {catch {[focus] tag add sel 0.0 end}} \ -accelerator $M1T-A \ - -font $mainfont + -font $font_ui # -- Commit Menu menu .mbar.commit .mbar.commit add command -label Rescan \ -command do_rescan \ -accelerator F5 \ - -font $mainfont + -font $font_ui lappend disable_on_lock \ [list .mbar.commit entryconf [.mbar.commit index last] -state] .mbar.commit add command -label {Amend Last Commit} \ -command do_amend_last \ - -font $mainfont + -font $font_ui lappend disable_on_lock \ [list .mbar.commit entryconf [.mbar.commit index last] -state] .mbar.commit add command -label {Include All Files} \ -command do_include_all \ -accelerator $M1T-I \ - -font $mainfont + -font $font_ui lappend disable_on_lock \ [list .mbar.commit entryconf [.mbar.commit index last] -state] .mbar.commit add command -label {Sign Off} \ -command do_signoff \ -accelerator $M1T-S \ - -font $mainfont + -font $font_ui .mbar.commit add command -label Commit \ -command do_commit \ -accelerator $M1T-Return \ - -font $mainfont + -font $font_ui lappend disable_on_lock \ [list .mbar.commit entryconf [.mbar.commit index last] -state] @@ -1673,10 +1673,10 @@ pack .vpane -anchor n -side top -fill both -expand 1 frame .vpane.files.index -height 100 -width 400 label .vpane.files.index.title -text {Modified Files} \ -background green \ - -font $mainfont + -font $font_ui text $ui_index -background white -borderwidth 0 \ -width 40 -height 10 \ - -font $mainfont \ + -font $font_ui \ -yscrollcommand {.vpane.files.index.sb set} \ -cursor $maincursor \ -state disabled @@ -1690,10 +1690,10 @@ pack $ui_index -side left -fill both -expand 1 frame .vpane.files.other -height 100 -width 100 label .vpane.files.other.title -text {Untracked Files} \ -background red \ - -font $mainfont + -font $font_ui text $ui_other -background white -borderwidth 0 \ -width 40 -height 10 \ - -font $mainfont \ + -font $font_ui \ -yscrollcommand {.vpane.files.other.sb set} \ -cursor $maincursor \ -state disabled @@ -1703,8 +1703,8 @@ pack .vpane.files.other.sb -side right -fill y pack $ui_other -side left -fill both -expand 1 .vpane.files add .vpane.files.other -sticky nsew -$ui_index tag conf in_diff -font [concat $mainfont bold] -$ui_other tag conf in_diff -font [concat $mainfont bold] +$ui_index tag conf in_diff -font [concat $font_ui bold] +$ui_other tag conf in_diff -font [concat $font_ui bold] # -- Diff and Commit Area frame .vpane.lower -height 400 -width 400 @@ -1719,36 +1719,36 @@ frame .vpane.lower.commarea.buttons label .vpane.lower.commarea.buttons.l -text {} \ -anchor w \ -justify left \ - -font $mainfont + -font $font_ui pack .vpane.lower.commarea.buttons.l -side top -fill x pack .vpane.lower.commarea.buttons -side left -fill y button .vpane.lower.commarea.buttons.rescan -text {Rescan} \ -command do_rescan \ - -font $mainfont + -font $font_ui pack .vpane.lower.commarea.buttons.rescan -side top -fill x lappend disable_on_lock {.vpane.lower.commarea.buttons.rescan conf -state} button .vpane.lower.commarea.buttons.amend -text {Amend Last} \ -command do_amend_last \ - -font $mainfont + -font $font_ui pack .vpane.lower.commarea.buttons.amend -side top -fill x lappend disable_on_lock {.vpane.lower.commarea.buttons.amend conf -state} button .vpane.lower.commarea.buttons.incall -text {Include All} \ -command do_include_all \ - -font $mainfont + -font $font_ui pack .vpane.lower.commarea.buttons.incall -side top -fill x lappend disable_on_lock {.vpane.lower.commarea.buttons.incall conf -state} button .vpane.lower.commarea.buttons.signoff -text {Sign Off} \ -command do_signoff \ - -font $mainfont + -font $font_ui pack .vpane.lower.commarea.buttons.signoff -side top -fill x button .vpane.lower.commarea.buttons.commit -text {Commit} \ -command do_commit \ - -font $mainfont + -font $font_ui pack .vpane.lower.commarea.buttons.commit -side top -fill x lappend disable_on_lock {.vpane.lower.commarea.buttons.commit conf -state} @@ -1759,7 +1759,7 @@ set ui_coml .vpane.lower.commarea.buffer.l label $ui_coml -text {Commit Message:} \ -anchor w \ -justify left \ - -font $mainfont + -font $font_ui trace add variable commit_type write {uplevel #0 { switch -glob $commit_type \ initial {$ui_coml conf -text {Initial Commit Message:}} \ @@ -1773,7 +1773,7 @@ text $ui_comm -background white -borderwidth 1 \ -autoseparators true \ -relief sunken \ -width 75 -height 9 -wrap none \ - -font $difffont \ + -font $font_diff \ -yscrollcommand {.vpane.lower.commarea.buffer.sby set} \ -cursor $maincursor scrollbar .vpane.lower.commarea.buffer.sby -command [list $ui_comm yview] @@ -1788,21 +1788,21 @@ set ui_fstatus_value {} frame .vpane.lower.diff.header -background orange label .vpane.lower.diff.header.l1 -text {File:} \ -background orange \ - -font $mainfont + -font $font_ui label .vpane.lower.diff.header.l2 -textvariable ui_fname_value \ -background orange \ -anchor w \ -justify left \ - -font $mainfont + -font $font_ui label .vpane.lower.diff.header.l3 -text {Status:} \ -background orange \ - -font $mainfont + -font $font_ui label .vpane.lower.diff.header.l4 -textvariable ui_fstatus_value \ -background orange \ -width $max_status_desc \ -anchor w \ -justify left \ - -font $mainfont + -font $font_ui pack .vpane.lower.diff.header.l1 -side left pack .vpane.lower.diff.header.l2 -side left -fill x pack .vpane.lower.diff.header.l4 -side right @@ -1813,7 +1813,7 @@ frame .vpane.lower.diff.body set ui_diff .vpane.lower.diff.body.t text $ui_diff -background white -borderwidth 0 \ -width 80 -height 15 -wrap none \ - -font $difffont \ + -font $font_diff \ -xscrollcommand {.vpane.lower.diff.body.sbx set} \ -yscrollcommand {.vpane.lower.diff.body.sby set} \ -cursor $maincursor \ @@ -1830,10 +1830,10 @@ pack .vpane.lower.diff.body -side bottom -fill both -expand 1 $ui_diff tag conf dm -foreground red $ui_diff tag conf dp -foreground blue -$ui_diff tag conf da -font [concat $difffont bold] +$ui_diff tag conf da -font [concat $font_diff bold] $ui_diff tag conf di -foreground "#00a000" $ui_diff tag conf dni -foreground "#a000a0" -$ui_diff tag conf bold -font [concat $difffont bold] +$ui_diff tag conf bold -font [concat $font_diff bold] # -- Status Bar set ui_status_value {Initializing...} @@ -1842,7 +1842,7 @@ label .status -textvariable ui_status_value \ -justify left \ -borderwidth 1 \ -relief sunken \ - -font $mainfont + -font $font_ui pack .status -anchor w -side bottom -fill x # -- Load geometry -- cgit v1.2.1 From da5239dcab0e8f899a4e6bfb34b574f6286b9dbb Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 11 Nov 2006 19:03:06 -0500 Subject: git-gui: Use native tk_messageBox for errors. Rather than drawing our own toplevel for error messages we really should just use the the native tk_messageBox command to display any error messages. Major benefits for doing so are: - automatically centers over main window; - less code required on our part in git-gui; - includes a nifty error icon on most systems; - better fits the look-and-feel of the operating system. Signed-off-by: Shawn O. Pearce --- git-gui | 56 +++++++++++++++++++++++++------------------------------- 1 file changed, 25 insertions(+), 31 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index e30a11443..81fe38f00 100755 --- a/git-gui +++ b/git-gui @@ -7,6 +7,9 @@ exec wish "$0" -- "$@" # and distributed under the terms of the GNU General Public Licence, # either version 2, or (at your option) any later version. +set appname [lindex [file split $argv0] end] +set gitdir {} + ###################################################################### ## ## config @@ -59,16 +62,30 @@ proc save_my_config {} { } } +proc error_popup {msg} { + global gitdir appname + + set title $appname + if {$gitdir != {}} { + append title { (} + append title [lindex \ + [file split [file normalize [file dirname $gitdir]]] \ + end] + append title {)} + } + tk_messageBox -parent . \ + -icon error \ + -type ok \ + -title "$title: error" \ + -message $msg +} + ###################################################################### ## ## repository setup -set appname [lindex [file split $argv0] end] -set gitdir {} -set GIT_COMMITTER_IDENT {} - if {[catch {set cdup [exec git rev-parse --show-cdup]} err]} { - show_msg {} . "Cannot find the git directory: $err" + error_popup "Cannot find the git directory:\n$err" exit 1 } if {$cdup != ""} { @@ -77,7 +94,7 @@ if {$cdup != ""} { unset cdup if {[catch {set gitdir [exec git rev-parse --git-dir]} err]} { - show_msg {} . "Cannot find the git directory: $err" + error_popup "Cannot find the git directory:\n$err" exit 1 } @@ -1204,31 +1221,6 @@ unset filemask i ## ## util -proc error_popup {msg} { - set w .error - toplevel $w - wm transient $w . - show_msg $w $w $msg -} - -proc show_msg {w top msg} { - global gitdir appname font_ui - - message $w.m -text $msg -justify left -aspect 400 - pack $w.m -side top -fill x -padx 5 -pady 10 - button $w.ok -text OK \ - -width 15 \ - -font $font_ui \ - -command "destroy $top" - pack $w.ok -side bottom - bind $top "grab $top; focus $top" - bind $top "destroy $top" - wm title $w "$appname ([lindex [file split \ - [file normalize [file dirname $gitdir]]] \ - end]): error" - tkwait window $top -} - proc hook_failed_popup {hook msg} { global gitdir font_ui font_diff appname @@ -1482,6 +1474,8 @@ proc do_include_all {} { } } +set GIT_COMMITTER_IDENT {} + proc do_signoff {} { global ui_comm GIT_COMMITTER_IDENT -- cgit v1.2.1 From 44be340e4d8d39475e86d3e00cec31fec0d0f6c1 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 11 Nov 2006 19:10:10 -0500 Subject: git-gui: Cleaned up error message formatting. Added an extra blank line between the first line of each error message and the rest of the message, as usually the rest of the message is coming from Tcl or is the stderr output of a git command we tried to invoke. This makes it easier to read the output (if any). Signed-off-by: Shawn O. Pearce --- git-gui | 36 ++++++++++++++++-------------------- 1 file changed, 16 insertions(+), 20 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 81fe38f00..4449c7d67 100755 --- a/git-gui +++ b/git-gui @@ -73,7 +73,8 @@ proc error_popup {msg} { end] append title {)} } - tk_messageBox -parent . \ + tk_messageBox \ + -parent . \ -icon error \ -type ok \ -title "$title: error" \ @@ -84,8 +85,10 @@ proc error_popup {msg} { ## ## repository setup -if {[catch {set cdup [exec git rev-parse --show-cdup]} err]} { - error_popup "Cannot find the git directory:\n$err" +if { [catch {set cdup [exec git rev-parse --show-cdup]} err] + || [catch {set gitdir [exec git rev-parse --git-dir]} err]} { + catch {wm withdraw .} + error_popup "Cannot find the git directory:\n\n$err" exit 1 } if {$cdup != ""} { @@ -93,11 +96,6 @@ if {$cdup != ""} { } unset cdup -if {[catch {set gitdir [exec git rev-parse --git-dir]} err]} { - error_popup "Cannot find the git directory:\n$err" - exit 1 -} - if {$appname == {git-citool}} { set single_commit 1 } @@ -420,7 +418,7 @@ proc show_diff {path {w {}} {lno {}}} { set diff_active 0 unlock_index set ui_status_value "Unable to display [escape_path $path]" - error_popup "Error loading file:\n$err" + error_popup "Error loading file:\n\n$err" return } $ui_diff conf -state normal @@ -437,7 +435,7 @@ proc show_diff {path {w {}} {lno {}}} { set diff_active 0 unlock_index set ui_status_value "Unable to display [escape_path $path]" - error_popup "Error loading diff:\n$err" + error_popup "Error loading diff:\n\n$err" return } @@ -523,7 +521,7 @@ proc load_last_commit {} { set msg [string trim [read $fd]] close $fd } err]} { - error_popup "Error loading commit data for amend:\n$err" + error_popup "Error loading commit data for amend:\n\n$err" return } @@ -655,10 +653,8 @@ proc commit_stage2 {fd_wt curHEAD msg} { global file_states gets $fd_wt tree_id - close $fd_wt - - if {$tree_id == {}} { - error_popup "write-tree failed" + if {$tree_id == {} || [catch {close $fd_wt} err]} { + error_popup "write-tree failed:\n\n$err" set commit_active 0 set ui_status_value {Commit failed.} unlock_index @@ -679,7 +675,7 @@ proc commit_stage2 {fd_wt curHEAD msg} { } close $fd_mh } err]} { - error_popup "Loading MERGE_HEAD failed:\n$err" + error_popup "Loading MERGE_HEAD failed:\n\n$err" set commit_active 0 set ui_status_value {Commit failed.} unlock_index @@ -692,7 +688,7 @@ proc commit_stage2 {fd_wt curHEAD msg} { } lappend cmd << $msg if {[catch {set cmt_id [eval exec $cmd]} err]} { - error_popup "commit-tree failed:\n$err" + error_popup "commit-tree failed:\n\n$err" set commit_active 0 set ui_status_value {Commit failed.} unlock_index @@ -713,7 +709,7 @@ proc commit_stage2 {fd_wt curHEAD msg} { } set cmd [list git update-ref -m $reflogm HEAD $cmt_id $curHEAD] if {[catch {eval exec $cmd} err]} { - error_popup "update-ref failed:\n$err" + error_popup "update-ref failed:\n\n$err" set commit_active 0 set ui_status_value {Commit failed.} unlock_index @@ -1481,12 +1477,12 @@ proc do_signoff {} { if {$GIT_COMMITTER_IDENT == {}} { if {[catch {set me [exec git var GIT_COMMITTER_IDENT]} err]} { - error_popup "Unable to obtain your identity:\n$err" + error_popup "Unable to obtain your identity:\n\n$err" return } if {![regexp {^(.*) [0-9]+ [-+0-9]+$} \ $me me GIT_COMMITTER_IDENT]} { - error_popup "Invalid GIT_COMMITTER_IDENT:\n$me" + error_popup "Invalid GIT_COMMITTER_IDENT:\n\n$me" return } } -- cgit v1.2.1 From c4fe7728529fd9f3dc2c413ce889d359732cd3a4 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 11 Nov 2006 19:32:24 -0500 Subject: git-gui: Simplified format of geometry configuration. The gui.geometry config value was starting to contain the odd string \\{ as part of its value due to the way the Tcl lists were being supplied to git repo-config. Now we write out only three values: the overall window geomtry, the y position of the horizontal sash, and the x position of the vertical sash. All other data is skipped, which makes the gui.geometry value simpler. While debugging this I noticed that the save_my_config procedure was being invoked multiple times during exit due to do_quit getting invoked over and over again. So now we set a flag in do_quit and don't perform any of our "at exit" type of logic if we've already been through the do_quit procedure once. Signed-off-by: Shawn O. Pearce --- git-gui | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 4449c7d67..ce49c3898 100755 --- a/git-gui +++ b/git-gui @@ -48,11 +48,9 @@ proc save_my_config {} { set repo_config(gui.trustmtime) [list $cfg_trust_mtime] } - set cfg_geometry [list \ - [wm geometry .] \ - [.vpane sash coord 0] \ - [.vpane.files sash coord 0] \ - ] + set cfg_geometry [wm geometry .] + append cfg_geometry " [lindex [.vpane sash coord 0] 1]" + append cfg_geometry " [lindex [.vpane.files sash coord 0] 0]" if {[catch {set rc_geometry $repo_config(gui.geometry)}]} { set rc_geometry [list [list]] } @@ -1422,8 +1420,13 @@ proc do_repack {} { console_exec $w $cmd } +set quitting 0 + proc do_quit {} { - global gitdir ui_comm + global gitdir ui_comm quitting + + if {$quitting} return + set quitting 1 set save [file join $gitdir GITGUI_MSG] set msg [string trim [$ui_comm get 0.0 end]] @@ -1837,10 +1840,16 @@ pack .status -anchor w -side bottom -fill x # -- Load geometry catch { -wm geometry . [lindex $repo_config(gui.geometry) 0 0] -eval .vpane sash place 0 [lindex $repo_config(gui.geometry) 0 1] -eval .vpane.files sash place 0 [lindex $repo_config(gui.geometry) 0 2] -} +set gm [lindex $repo_config(gui.geometry) 0] +wm geometry . [lindex $gm 0] +.vpane sash place 0 \ + [lindex [.vpane sash coord 0] 0] \ + [lindex $gm 1] +.vpane.files sash place 0 \ + [lindex $gm 2] \ + [lindex [.vpane.files sash coord 0] 1] +} +unset gm # -- Key Bindings bind $ui_comm <$M1B-Key-Return> {do_commit;break} -- cgit v1.2.1 From 390adaeafbefc49a88d06c3a2ad68bc00fe0c614 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 11 Nov 2006 19:40:33 -0500 Subject: git-gui: Misc. formatting cleanups. A number of lines were line wrapping in a rather ugly way when opened in vim with line numbers enabled, so I split most of these lines over two lines using a sensible wrapping policy. Signed-off-by: Shawn O. Pearce --- git-gui | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index ce49c3898..f8c51590b 100755 --- a/git-gui +++ b/git-gui @@ -197,7 +197,8 @@ proc update_status {{final Ready.}} { set ui_status_value {Refreshing file status...} set fd_rf [open "| git update-index -q --unmerged --refresh" r] fconfigure $fd_rf -blocking 0 -translation binary - fileevent $fd_rf readable [list update_status_stage2 $fd_rf $final] + fileevent $fd_rf readable \ + [list update_status_stage2 $fd_rf $final] } } @@ -402,8 +403,6 @@ proc show_diff {path {w {}} {lno {}}} { set cmd [list | git diff-index -p $PARENT -- $path] switch $m { - AM { - } MM { set cmd [list | git diff-index -p -c $PARENT $path] } @@ -828,7 +827,8 @@ proc post_pull_remote {remote branch success} { set PARENT $HEAD set $ui_status_value {Ready.} } else { - update_status "Conflicts detected while pulling $branch from $remote." + update_status \ + "Conflicts detected while pulling $branch from $remote." } } @@ -1548,7 +1548,7 @@ set maincursor [. cget -cursor] switch -glob -- "$tcl_platform(platform),$tcl_platform(os)" { windows,* {set M1B Control; set M1T Ctrl} unix,Darwin {set M1B M1; set M1T Cmd} -default {set M1B M1; set M1T M1} +* {set M1B M1; set M1T M1} } # -- Menu Bar @@ -1720,19 +1720,22 @@ button .vpane.lower.commarea.buttons.rescan -text {Rescan} \ -command do_rescan \ -font $font_ui pack .vpane.lower.commarea.buttons.rescan -side top -fill x -lappend disable_on_lock {.vpane.lower.commarea.buttons.rescan conf -state} +lappend disable_on_lock \ + {.vpane.lower.commarea.buttons.rescan conf -state} button .vpane.lower.commarea.buttons.amend -text {Amend Last} \ -command do_amend_last \ -font $font_ui pack .vpane.lower.commarea.buttons.amend -side top -fill x -lappend disable_on_lock {.vpane.lower.commarea.buttons.amend conf -state} +lappend disable_on_lock \ + {.vpane.lower.commarea.buttons.amend conf -state} button .vpane.lower.commarea.buttons.incall -text {Include All} \ -command do_include_all \ -font $font_ui pack .vpane.lower.commarea.buttons.incall -side top -fill x -lappend disable_on_lock {.vpane.lower.commarea.buttons.incall conf -state} +lappend disable_on_lock \ + {.vpane.lower.commarea.buttons.incall conf -state} button .vpane.lower.commarea.buttons.signoff -text {Sign Off} \ -command do_signoff \ @@ -1743,7 +1746,8 @@ button .vpane.lower.commarea.buttons.commit -text {Commit} \ -command do_commit \ -font $font_ui pack .vpane.lower.commarea.buttons.commit -side top -fill x -lappend disable_on_lock {.vpane.lower.commarea.buttons.commit conf -state} +lappend disable_on_lock \ + {.vpane.lower.commarea.buttons.commit conf -state} # -- Commit Message Buffer frame .vpane.lower.commarea.buffer @@ -1769,7 +1773,8 @@ text $ui_comm -background white -borderwidth 1 \ -font $font_diff \ -yscrollcommand {.vpane.lower.commarea.buffer.sby set} \ -cursor $maincursor -scrollbar .vpane.lower.commarea.buffer.sby -command [list $ui_comm yview] +scrollbar .vpane.lower.commarea.buffer.sby \ + -command [list $ui_comm yview] pack $ui_coml -side top -fill x pack .vpane.lower.commarea.buffer.sby -side right -fill y pack $ui_comm -side left -fill y @@ -1848,8 +1853,8 @@ wm geometry . [lindex $gm 0] .vpane.files sash place 0 \ [lindex $gm 2] \ [lindex [.vpane.files sash coord 0] 1] -} unset gm +} # -- Key Bindings bind $ui_comm <$M1B-Key-Return> {do_commit;break} -- cgit v1.2.1 From 62aac80b133de4fa004d90d27a97f574aec9d02d Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 11 Nov 2006 20:00:35 -0500 Subject: git-gui: Misc. bug fixes for mouse click crashes. Make sure the file_lists array has both elements set at all times, otherwise we get Tcl errors during mouse clicks in the file list areas due to the list not being defined. Also added M1-A as a keyboard binding within the console window text area. This lets users select all text easily and copy it to the clipboard. Signed-off-by: Shawn O. Pearce --- git-gui | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index f8c51590b..b82e6e629 100755 --- a/git-gui +++ b/git-gui @@ -960,7 +960,9 @@ proc display_all_files {} { $ui_index delete 0.0 end $ui_other delete 0.0 end - array unset file_lists + set file_lists($ui_index) [list] + set file_lists($ui_other) [list] + foreach path [lsort [array names file_states]] { set s $file_states($path) set m [lindex $s 0] @@ -1273,7 +1275,7 @@ proc new_console {short_title long_title} { proc console_init {w} { global console_cr console_data - global gitdir appname font_ui font_diff + global gitdir appname font_ui font_diff M1B set console_cr($w) 1.0 toplevel $w @@ -1306,6 +1308,8 @@ proc console_init {w} { -command "destroy $w" pack $w.ok -side bottom + bind $w.m.t <$M1B-Key-a> "$w.m.t tag add sel 0.0 end;break" + bind $w.m.t <$M1B-Key-A> "$w.m.t tag add sel 0.0 end;break" bind $w "focus $w" wm title $w "$appname ([lindex [file split \ [file normalize [file dirname $gitdir]]] \ @@ -1900,7 +1904,10 @@ foreach i [list $ui_index $ui_other] { bind $i {click %W %x %y 3 %X %Y; break} bind $i {unclick %W %x %y; break} } -unset i M1B M1T +unset i + +set file_lists($ui_index) [list] +set file_lists($ui_other) [list] wm title . "$appname ([file normalize [file dirname $gitdir]])" focus -force $ui_comm -- cgit v1.2.1 From 0e794311833fd4d6f0c3204a5449372284318bda Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 11 Nov 2006 20:24:23 -0500 Subject: git-gui: Added context menus for consoles and commit message buffer. This change adds a context menu to the commit message buffer providing fast access to the contents of the Edit menu, and to the console text buffer, providing easy ways to copy selections of the buffer or the entire buffer. Signed-off-by: Shawn O. Pearce --- git-gui | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) (limited to 'git-gui') diff --git a/git-gui b/git-gui index b82e6e629..c2b5e5683 100755 --- a/git-gui +++ b/git-gui @@ -1301,6 +1301,21 @@ proc console_init {w} { pack $w.m.t -side left -fill both -expand 1 pack $w.m -side top -fill both -expand 1 -padx 5 -pady 10 + menu $w.ctxm -tearoff 0 + $w.ctxm add command -label "Copy" \ + -font $font_ui \ + -command "tk_textCopy $w.m.t" + $w.ctxm add command -label "Select All" \ + -font $font_ui \ + -command "$w.m.t tag add sel 0.0 end" + $w.ctxm add command -label "Copy All" \ + -font $font_ui \ + -command " + $w.m.t tag add sel 0.0 end + tk_textCopy $w.m.t + $w.m.t tag remove sel 0.0 end + " + button $w.ok -text {Running...} \ -width 15 \ -font $font_ui \ @@ -1308,6 +1323,7 @@ proc console_init {w} { -command "destroy $w" pack $w.ok -side bottom + bind $w.m.t "tk_popup $w.ctxm %X %Y" bind $w.m.t <$M1B-Key-a> "$w.m.t tag add sel 0.0 end;break" bind $w.m.t <$M1B-Key-A> "$w.m.t tag add sel 0.0 end;break" bind $w "focus $w" @@ -1784,6 +1800,38 @@ pack .vpane.lower.commarea.buffer.sby -side right -fill y pack $ui_comm -side left -fill y pack .vpane.lower.commarea.buffer -side left -fill y +# -- Commit Message Buffer Context Menu +# +menu $ui_comm.ctxm -tearoff 0 +$ui_comm.ctxm add command -label "Cut" \ + -font $font_ui \ + -command "tk_textCut $ui_comm" +$ui_comm.ctxm add command -label "Copy" \ + -font $font_ui \ + -command "tk_textCopy $ui_comm" +$ui_comm.ctxm add command -label "Paste" \ + -font $font_ui \ + -command "tk_textPaste $ui_comm" +$ui_comm.ctxm add command -label "Delete" \ + -font $font_ui \ + -command "$ui_comm delete sel.first sel.last" +$ui_comm.ctxm add separator +$ui_comm.ctxm add command -label "Select All" \ + -font $font_ui \ + -command "$ui_comm tag add sel 0.0 end" +$ui_comm.ctxm add command -label "Copy All" \ + -font $font_ui \ + -command " + $ui_comm tag add sel 0.0 end + tk_textCopy $ui_comm + $ui_comm tag remove sel 0.0 end + " +$ui_comm.ctxm add separator +$ui_comm.ctxm add command -label "Sign Off" \ + -font $font_ui \ + -command do_signoff +bind $ui_comm "tk_popup $ui_comm.ctxm %X %Y" + # -- Diff Header set ui_fname_value {} set ui_fstatus_value {} @@ -1837,6 +1885,24 @@ $ui_diff tag conf di -foreground "#00a000" $ui_diff tag conf dni -foreground "#a000a0" $ui_diff tag conf bold -font [concat $font_diff bold] +# -- Diff Body Context Menu +# +menu $ui_diff.ctxm -tearoff 0 +$ui_diff.ctxm add command -label "Copy" \ + -font $font_ui \ + -command "tk_textCopy $ui_diff" +$ui_diff.ctxm add command -label "Select All" \ + -font $font_ui \ + -command "$ui_diff tag add sel 0.0 end" +$ui_diff.ctxm add command -label "Copy All" \ + -font $font_ui \ + -command " + $ui_diff tag add sel 0.0 end + tk_textCopy $ui_diff + $ui_diff tag remove sel 0.0 end + " +bind $ui_diff "tk_popup $ui_diff.ctxm %X %Y" + # -- Status Bar set ui_status_value {Initializing...} label .status -textvariable ui_status_value \ -- cgit v1.2.1 From 6c6dd01a041e628ce6efb583ea865d1a694ff7b2 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 11 Nov 2006 20:33:30 -0500 Subject: git-gui: Fix mouse cursor behavior when in widgets. The mouse cursor (at least on Windows) seemed to be picking up the cursor from the sash controls and then never resetting itself back to the standard text cursor (the I-beam) when it was over a text area that the user can edit (like the commit buffer) or over a text area the user can copy from (like the diff viewer). So now we always set the cursor to left_ptr (which according to the Tk documentation should be available everywhere) and only for the two text areas which we use to list file names, as the user clicks in these but is not permitted to select text. Signed-off-by: Shawn O. Pearce --- git-gui | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index c2b5e5683..9a259c0dc 100755 --- a/git-gui +++ b/git-gui @@ -1563,7 +1563,7 @@ proc unclick {w x y} { set font_ui {Helvetica 10} set font_diff {Courier 10} -set maincursor [. cget -cursor] +set cursor_ptr left_ptr switch -glob -- "$tcl_platform(platform),$tcl_platform(os)" { windows,* {set M1B Control; set M1T Ctrl} @@ -1690,8 +1690,8 @@ label .vpane.files.index.title -text {Modified Files} \ text $ui_index -background white -borderwidth 0 \ -width 40 -height 10 \ -font $font_ui \ + -cursor $cursor_ptr \ -yscrollcommand {.vpane.files.index.sb set} \ - -cursor $maincursor \ -state disabled scrollbar .vpane.files.index.sb -command [list $ui_index yview] pack .vpane.files.index.title -side top -fill x @@ -1707,8 +1707,8 @@ label .vpane.files.other.title -text {Untracked Files} \ text $ui_other -background white -borderwidth 0 \ -width 40 -height 10 \ -font $font_ui \ + -cursor $cursor_ptr \ -yscrollcommand {.vpane.files.other.sb set} \ - -cursor $maincursor \ -state disabled scrollbar .vpane.files.other.sb -command [list $ui_other yview] pack .vpane.files.other.title -side top -fill x @@ -1791,8 +1791,7 @@ text $ui_comm -background white -borderwidth 1 \ -relief sunken \ -width 75 -height 9 -wrap none \ -font $font_diff \ - -yscrollcommand {.vpane.lower.commarea.buffer.sby set} \ - -cursor $maincursor + -yscrollcommand {.vpane.lower.commarea.buffer.sby set} scrollbar .vpane.lower.commarea.buffer.sby \ -command [list $ui_comm yview] pack $ui_coml -side top -fill x @@ -1866,7 +1865,6 @@ text $ui_diff -background white -borderwidth 0 \ -font $font_diff \ -xscrollcommand {.vpane.lower.diff.body.sbx set} \ -yscrollcommand {.vpane.lower.diff.body.sby set} \ - -cursor $maincursor \ -state disabled scrollbar .vpane.lower.diff.body.sbx -orient horizontal \ -command [list $ui_diff xview] -- cgit v1.2.1 From 1daf1d0c81c7c2623867f7884c8cbc5ff0a10d30 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 11 Nov 2006 20:44:03 -0500 Subject: git-gui: Teach sign off to be more intelligent. When we sign off on a commit we want to add a blank line between whatever is in the commit buffer and the new Signed-off-by line, unless there already is a Signed-off-by (or Acked-by) tag at the end of the buffer already. This change makes us do the right thing more often. Signed-off-by: Shawn O. Pearce --- git-gui | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 9a259c0dc..8a42c97cb 100755 --- a/git-gui +++ b/git-gui @@ -1510,10 +1510,15 @@ proc do_signoff {} { } } - set str "Signed-off-by: $GIT_COMMITTER_IDENT" - if {[$ui_comm get {end -1c linestart} {end -1c}] != $str} { + set sob "Signed-off-by: $GIT_COMMITTER_IDENT" + set last [$ui_comm get {end -1c linestart} {end -1c}] + if {$last != $sob} { $ui_comm edit separator - $ui_comm insert end "\n$str" + if {$last != {} + && ![regexp {^[A-Z][A-Za-z]*-[A-Za-z-]+: *} $last]} { + $ui_comm insert end "\n" + } + $ui_comm insert end "\n$sob" $ui_comm edit separator $ui_comm see end } -- cgit v1.2.1 From 058803f400d8bbd72aa8b8584e9a6e93dbd17d54 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 11 Nov 2006 20:45:52 -0500 Subject: git-gui: Corrected font used for options menu items. Signed-off-by: Shawn O. Pearce --- git-gui | 1 + 1 file changed, 1 insertion(+) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 8a42c97cb..008eeb446 100755 --- a/git-gui +++ b/git-gui @@ -1677,6 +1677,7 @@ menu .mbar.push menu .mbar.options .mbar.options add checkbutton \ -label {Trust File Modification Timestamps} \ + -font $font_ui \ -offvalue false \ -onvalue true \ -variable cfg_trust_mtime -- cgit v1.2.1 From f019c96add051aa9265c3dba8940c29f307aae81 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 11 Nov 2006 21:02:37 -0500 Subject: git-gui: Honor system font and let user configure fonts. Rather than hardcoding our fonts to something that I thought was reasonable, guess font_ui off the font used by the system in the menu bar. This way the application conforms by default to whatever the user's desktop is setup to. We also now let the user supply font configuration through their repository configuration as gui.fontui (the overall UI font) and gui.fontdiff (the font used for the diff viewer). Signed-off-by: Shawn O. Pearce --- git-gui | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 008eeb446..26df169c1 100755 --- a/git-gui +++ b/git-gui @@ -1566,9 +1566,16 @@ proc unclick {w x y} { ## ## ui init -set font_ui {Helvetica 10} -set font_diff {Courier 10} -set cursor_ptr left_ptr +set font_ui {} +set font_diff {} +set cursor_ptr {} +menu .mbar -tearoff 0 +catch {set font_ui [lindex $repo_config(gui.fontui) 0]} +catch {set font_diff [lindex $repo_config(gui.fontdiff) 0]} +if {$font_ui == {}} {catch {set font_ui [.mbar cget -font]}} +if {$font_ui == {}} {set font_ui {Helvetica 10}} +if {$font_diff == {}} {set font_diff {Courier 10}} +if {$cursor_ptr == {}} {set cursor_ptr left_ptr} switch -glob -- "$tcl_platform(platform),$tcl_platform(os)" { windows,* {set M1B Control; set M1T Ctrl} @@ -1577,7 +1584,6 @@ unix,Darwin {set M1B M1; set M1T Cmd} } # -- Menu Bar -menu .mbar -tearoff 0 .mbar add cascade -label Project -menu .mbar.project .mbar add cascade -label Edit -menu .mbar.edit .mbar add cascade -label Commit -menu .mbar.commit -- cgit v1.2.1 From 2c26e6f5279286aa844a54363d877acffb4a4310 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 11 Nov 2006 21:14:28 -0500 Subject: git-gui: Allow the user to change the diff viewer font size. Because the diff area is one of the most important areas to be able to read users should be able to increase or decrease the size of the font used within that area. Currently we save that back to the global configuration, even if it may have originated from the local repository configuration. This is probably going to be considered to be a bug by at least one user who wants some sort of different font within a given repository, but I'm just going to ignore the problem for now. Signed-off-by: Shawn O. Pearce --- git-gui | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 26df169c1..fdb1dce88 100755 --- a/git-gui +++ b/git-gui @@ -39,6 +39,7 @@ proc load_repo_config {} { proc save_my_config {} { global repo_config global cfg_trust_mtime + global font_diff if {[catch {set rc_trustMTime $repo_config(gui.trustmtime)}]} { set rc_trustMTime [list false] @@ -48,6 +49,14 @@ proc save_my_config {} { set repo_config(gui.trustmtime) [list $cfg_trust_mtime] } + if {[catch {set rc_fontdiff $repo_config(gui.fontdiff)}]} { + set rc_fontdiff [list {Courier 10}] + } + if {$font_diff != [lindex $rc_fontdiff 0]} { + exec git repo-config --global gui.fontDiff $font_diff + set repo_config(gui.fontdiff) [list $font_diff] + } + set cfg_geometry [wm geometry .] append cfg_geometry " [lindex [.vpane sash coord 0] 1]" append cfg_geometry " [lindex [.vpane.files sash coord 0] 0]" @@ -1890,9 +1899,9 @@ pack .vpane.lower.diff.body -side bottom -fill both -expand 1 $ui_diff tag conf dm -foreground red $ui_diff tag conf dp -foreground blue -$ui_diff tag conf da -font [concat $font_diff bold] $ui_diff tag conf di -foreground "#00a000" $ui_diff tag conf dni -foreground "#a000a0" +$ui_diff tag conf da -font [concat $font_diff bold] $ui_diff tag conf bold -font [concat $font_diff bold] # -- Diff Body Context Menu @@ -1911,6 +1920,23 @@ $ui_diff.ctxm add command -label "Copy All" \ tk_textCopy $ui_diff $ui_diff tag remove sel 0.0 end " +$ui_diff.ctxm add separator +$ui_diff.ctxm add command -label "Decrease Font Size" \ + -font $font_ui \ + -command { + lset font_diff 1 [expr [lindex $font_diff 1] - 1] + $ui_diff configure -font $font_diff + $ui_diff tag conf da -font [concat $font_diff bold] + $ui_diff tag conf bold -font [concat $font_diff bold] + } +$ui_diff.ctxm add command -label "Increase Font Size" \ + -font $font_ui \ + -command { + lset font_diff 1 [expr [lindex $font_diff 1] + 1] + $ui_diff configure -font $font_diff + $ui_diff tag conf da -font [concat $font_diff bold] + $ui_diff tag conf bold -font [concat $font_diff bold] + } bind $ui_diff "tk_popup $ui_diff.ctxm %X %Y" # -- Status Bar -- cgit v1.2.1 From 16403d0b1f9d17bec6bce488356ec8bf84cace48 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 11 Nov 2006 21:52:06 -0500 Subject: git-gui: Refresh a file if it has an empty diff. When the user has enabled the Trust File Modification Timestamp option then we may display a file as being modified yet that file may not have a difference. When the user clicks on that file we wind up displaying an empty diff viewer, which makes no sense to the user. So instead if we get an empty diff and the user has this option enabled and the file's current state is _M (no change in index but the working file appears modified) then run a quick update-index on just that file and remove it from the list of modified files. We also give the user a quick dialog stating we are removing it, and why. Usually I don't run into this situation when I have the Trust File Modification Timestamp option enabled, so its not that annoying to have a dialog pop open to remind me why there are no differences. Signed-off-by: Shawn O. Pearce --- git-gui | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 72 insertions(+), 4 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index fdb1dce88..ae87879bb 100755 --- a/git-gui +++ b/git-gui @@ -88,6 +88,25 @@ proc error_popup {msg} { -message $msg } +proc info_popup {msg} { + global gitdir appname + + set title $appname + if {$gitdir != {}} { + append title { (} + append title [lindex \ + [file split [file normalize [file dirname $gitdir]]] \ + end] + append title {)} + } + tk_messageBox \ + -parent . \ + -icon error \ + -type ok \ + -title $title \ + -message $msg +} + ###################################################################### ## ## repository setup @@ -204,7 +223,12 @@ proc update_status {{final Ready.}} { } else { set status_active 1 set ui_status_value {Refreshing file status...} - set fd_rf [open "| git update-index -q --unmerged --refresh" r] + set cmd [list git update-index] + lappend cmd -q + lappend cmd --unmerged + lappend cmd --ignore-missing + lappend cmd --refresh + set fd_rf [open "| $cmd" r] fconfigure $fd_rf -blocking 0 -translation binary fileevent $fd_rf readable \ [list update_status_stage2 $fd_rf $final] @@ -381,6 +405,42 @@ proc reshow_diff {} { } } +proc handle_empty_diff {} { + global ui_fname_value file_states file_lists + + set path $ui_fname_value + set s $file_states($path) + if {[lindex $s 0] != {_M}} return + + info_popup "No differences detected. + +[short_path $path] has no changes. + +The modification date of this file was updated by another +application and you currently have the Trust File Modification +Timestamps feature enabled, so Git did not automatically detect +that there are no content differences in this file. + +This file will now be removed from the modified files list, to +prevent possible confusion. +" + if {[catch {exec git update-index -- $path} err]} { + error_popup "Failed to refresh index:\n\n$err" + } + + clear_diff + set old_w [mapcol [lindex $file_states($path) 0] $path] + set lno [lsearch -sorted $file_lists($old_w) $path] + if {$lno >= 0} { + set file_lists($old_w) \ + [lreplace $file_lists($old_w) $lno $lno] + incr lno + $old_w conf -state normal + $old_w delete $lno.0 [expr $lno + 1].0 + $old_w conf -state disabled + } +} + proc show_diff {path {w {}} {lno {}}} { global file_states file_lists global PARENT diff_3way diff_active @@ -451,6 +511,7 @@ proc show_diff {path {w {}} {lno {}}} { proc read_diff {fd} { global ui_diff ui_status_value diff_3way diff_active + global cfg_trust_mtime while {[gets $fd line] >= 0} { if {[string match {diff --git *} $line]} continue @@ -497,6 +558,10 @@ proc read_diff {fd} { set diff_active 0 unlock_index set ui_status_value {Ready.} + + if {$cfg_trust_mtime && [$ui_diff index end] == {2.0}} { + handle_empty_diff + } } } @@ -588,7 +653,7 @@ before committing. U? { error_popup "Unmerged files cannot be committed. -File [escape_path $path] has merge conflicts. +File [short_path $path] has merge conflicts. You must resolve them and include the file before committing. " unlock_index @@ -597,7 +662,7 @@ You must resolve them and include the file before committing. default { error_popup "Unknown file state [lindex $s 0] detected. -File [escape_path $path] cannot be committed by this program. +File [short_path $path] cannot be committed by this program. " } } @@ -888,6 +953,10 @@ proc escape_path {path} { return $path } +proc short_path {path} { + return [escape_path [lindex [file split $path] end]] +} + set next_icon_id 0 proc merge_state {path new_state} { @@ -921,7 +990,6 @@ proc merge_state {path new_state} { } proc display_file {path state} { - global ui_index ui_other global file_states file_lists status_active set old_m [merge_state $path $state] -- cgit v1.2.1 From b4946930fa0f7aa538e33f1d799beffb7e10e7a9 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sun, 12 Nov 2006 00:40:38 -0500 Subject: git-gui: Make use of the Tk font system rather than faking it. The native Tk font system is actually quite powerful and has the nice property that modifications to a named font are immediately reflected throughout all widgets currently displayed. This really saves us from needing to write all of the reconfigure code as part of our font display. I also fixed the way we detect and apply the system font on the main UI widgets as although it worked on a Windows 2000 system it does not work at all on my Mac OS 10.4 system. Signed-off-by: Shawn O. Pearce --- git-gui | 192 +++++++++++++++++++++++++++++++--------------------------------- 1 file changed, 92 insertions(+), 100 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index ae87879bb..3cbe3e7f7 100755 --- a/git-gui +++ b/git-gui @@ -39,7 +39,6 @@ proc load_repo_config {} { proc save_my_config {} { global repo_config global cfg_trust_mtime - global font_diff if {[catch {set rc_trustMTime $repo_config(gui.trustmtime)}]} { set rc_trustMTime [list false] @@ -49,14 +48,6 @@ proc save_my_config {} { set repo_config(gui.trustmtime) [list $cfg_trust_mtime] } - if {[catch {set rc_fontdiff $repo_config(gui.fontdiff)}]} { - set rc_fontdiff [list {Courier 10}] - } - if {$font_diff != [lindex $rc_fontdiff 0]} { - exec git repo-config --global gui.fontDiff $font_diff - set repo_config(gui.fontdiff) [list $font_diff] - } - set cfg_geometry [wm geometry .] append cfg_geometry " [lindex [.vpane sash coord 0] 1]" append cfg_geometry " [lindex [.vpane.files sash coord 0] 0]" @@ -1134,17 +1125,17 @@ proc load_all_remotes {} { } proc populate_remote_menu {m pfx op} { - global all_remotes font_ui + global all_remotes foreach remote $all_remotes { $m add command -label "$pfx $remote..." \ -command [list $op $remote] \ - -font $font_ui + -font font_ui } } proc populate_pull_menu {m} { - global gitdir repo_config all_remotes font_ui disable_on_lock + global gitdir repo_config all_remotes disable_on_lock foreach remote $all_remotes { set rb {} @@ -1172,7 +1163,7 @@ proc populate_pull_menu {m} { $m add command \ -label "Branch $rb_short from $remote..." \ -command [list pull_remote $remote $rb] \ - -font $font_ui + -font font_ui lappend disable_on_lock \ [list $m entryconf [$m index last] -state] } @@ -1294,8 +1285,15 @@ unset filemask i ## ## util +proc incr_font_size {font {amt 1}} { + set sz [font configure $font -size] + incr sz $amt + font configure $font -size $sz + font configure ${font}bold -size $sz +} + proc hook_failed_popup {hook msg} { - global gitdir font_ui font_diff appname + global gitdir appname set w .hookfail toplevel $w @@ -1305,18 +1303,18 @@ proc hook_failed_popup {hook msg} { label $w.m.l1 -text "$hook hook failed:" \ -anchor w \ -justify left \ - -font [concat $font_ui bold] + -font font_uibold text $w.m.t \ -background white -borderwidth 1 \ -relief sunken \ -width 80 -height 10 \ - -font $font_diff \ + -font font_diff \ -yscrollcommand [list $w.m.sby set] label $w.m.l2 \ -text {You must correct the above errors before committing.} \ -anchor w \ -justify left \ - -font [concat $font_ui bold] + -font font_uibold scrollbar $w.m.sby -command [list $w.m.t yview] pack $w.m.l1 -side top -fill x pack $w.m.l2 -side bottom -fill x @@ -1329,7 +1327,7 @@ proc hook_failed_popup {hook msg} { button $w.ok -text OK \ -width 15 \ - -font $font_ui \ + -font font_ui \ -command "destroy $w" pack $w.ok -side bottom @@ -1352,7 +1350,7 @@ proc new_console {short_title long_title} { proc console_init {w} { global console_cr console_data - global gitdir appname font_ui font_diff M1B + global gitdir appname M1B set console_cr($w) 1.0 toplevel $w @@ -1360,17 +1358,17 @@ proc console_init {w} { label $w.m.l1 -text "[lindex $console_data($w) 1]:" \ -anchor w \ -justify left \ - -font [concat $font_ui bold] + -font font_uibold text $w.m.t \ -background white -borderwidth 1 \ -relief sunken \ -width 80 -height 10 \ - -font $font_diff \ + -font font_diff \ -state disabled \ -yscrollcommand [list $w.m.sby set] label $w.m.s -anchor w \ -justify left \ - -font [concat $font_ui bold] + -font font_uibold scrollbar $w.m.sby -command [list $w.m.t yview] pack $w.m.l1 -side top -fill x pack $w.m.s -side bottom -fill x @@ -1380,13 +1378,13 @@ proc console_init {w} { menu $w.ctxm -tearoff 0 $w.ctxm add command -label "Copy" \ - -font $font_ui \ + -font font_ui \ -command "tk_textCopy $w.m.t" $w.ctxm add command -label "Select All" \ - -font $font_ui \ + -font font_ui \ -command "$w.m.t tag add sel 0.0 end" $w.ctxm add command -label "Copy All" \ - -font $font_ui \ + -font font_ui \ -command " $w.m.t tag add sel 0.0 end tk_textCopy $w.m.t @@ -1395,7 +1393,7 @@ proc console_init {w} { button $w.ok -text {Running...} \ -width 15 \ - -font $font_ui \ + -font font_ui \ -state disabled \ -command "destroy $w" pack $w.ok -side bottom @@ -1643,16 +1641,19 @@ proc unclick {w x y} { ## ## ui init -set font_ui {} -set font_diff {} -set cursor_ptr {} -menu .mbar -tearoff 0 -catch {set font_ui [lindex $repo_config(gui.fontui) 0]} -catch {set font_diff [lindex $repo_config(gui.fontdiff) 0]} -if {$font_ui == {}} {catch {set font_ui [.mbar cget -font]}} -if {$font_ui == {}} {set font_ui {Helvetica 10}} -if {$font_diff == {}} {set font_diff {Courier 10}} -if {$cursor_ptr == {}} {set cursor_ptr left_ptr} +set cursor_ptr left_ptr +font create font_diff -family Courier -size 10 +font create font_ui +catch { + label .dummy + eval font configure font_ui [font actual [.dummy cget -font]] + destroy .dummy +} + +eval font create font_uibold [font configure font_ui] +font configure font_uibold -weight bold +eval font create font_diffbold [font configure font_diff] +font configure font_diffbold -weight bold switch -glob -- "$tcl_platform(platform),$tcl_platform(os)" { windows,* {set M1B Control; set M1T Ctrl} @@ -1661,6 +1662,7 @@ unix,Darwin {set M1B M1; set M1T Cmd} } # -- Menu Bar +menu .mbar -tearoff 0 .mbar add cascade -label Project -menu .mbar.project .mbar add cascade -label Edit -menu .mbar.edit .mbar add cascade -label Commit -menu .mbar.commit @@ -1674,14 +1676,14 @@ unix,Darwin {set M1B M1; set M1T Cmd} menu .mbar.project .mbar.project add command -label Visualize \ -command do_gitk \ - -font $font_ui + -font font_ui .mbar.project add command -label {Repack Database} \ -command do_repack \ - -font $font_ui + -font font_ui .mbar.project add command -label Quit \ -command do_quit \ -accelerator $M1T-Q \ - -font $font_ui + -font font_ui # -- Edit Menu # @@ -1689,61 +1691,61 @@ menu .mbar.edit .mbar.edit add command -label Undo \ -command {catch {[focus] edit undo}} \ -accelerator $M1T-Z \ - -font $font_ui + -font font_ui .mbar.edit add command -label Redo \ -command {catch {[focus] edit redo}} \ -accelerator $M1T-Y \ - -font $font_ui + -font font_ui .mbar.edit add separator .mbar.edit add command -label Cut \ -command {catch {tk_textCut [focus]}} \ -accelerator $M1T-X \ - -font $font_ui + -font font_ui .mbar.edit add command -label Copy \ -command {catch {tk_textCopy [focus]}} \ -accelerator $M1T-C \ - -font $font_ui + -font font_ui .mbar.edit add command -label Paste \ -command {catch {tk_textPaste [focus]; [focus] see insert}} \ -accelerator $M1T-V \ - -font $font_ui + -font font_ui .mbar.edit add command -label Delete \ -command {catch {[focus] delete sel.first sel.last}} \ -accelerator Del \ - -font $font_ui + -font font_ui .mbar.edit add separator .mbar.edit add command -label {Select All} \ -command {catch {[focus] tag add sel 0.0 end}} \ -accelerator $M1T-A \ - -font $font_ui + -font font_ui # -- Commit Menu menu .mbar.commit .mbar.commit add command -label Rescan \ -command do_rescan \ -accelerator F5 \ - -font $font_ui + -font font_ui lappend disable_on_lock \ [list .mbar.commit entryconf [.mbar.commit index last] -state] .mbar.commit add command -label {Amend Last Commit} \ -command do_amend_last \ - -font $font_ui + -font font_ui lappend disable_on_lock \ [list .mbar.commit entryconf [.mbar.commit index last] -state] .mbar.commit add command -label {Include All Files} \ -command do_include_all \ -accelerator $M1T-I \ - -font $font_ui + -font font_ui lappend disable_on_lock \ [list .mbar.commit entryconf [.mbar.commit index last] -state] .mbar.commit add command -label {Sign Off} \ -command do_signoff \ -accelerator $M1T-S \ - -font $font_ui + -font font_ui .mbar.commit add command -label Commit \ -command do_commit \ -accelerator $M1T-Return \ - -font $font_ui + -font font_ui lappend disable_on_lock \ [list .mbar.commit entryconf [.mbar.commit index last] -state] @@ -1760,7 +1762,7 @@ menu .mbar.push menu .mbar.options .mbar.options add checkbutton \ -label {Trust File Modification Timestamps} \ - -font $font_ui \ + -font font_ui \ -offvalue false \ -onvalue true \ -variable cfg_trust_mtime @@ -1775,10 +1777,10 @@ pack .vpane -anchor n -side top -fill both -expand 1 frame .vpane.files.index -height 100 -width 400 label .vpane.files.index.title -text {Modified Files} \ -background green \ - -font $font_ui + -font font_ui text $ui_index -background white -borderwidth 0 \ -width 40 -height 10 \ - -font $font_ui \ + -font font_ui \ -cursor $cursor_ptr \ -yscrollcommand {.vpane.files.index.sb set} \ -state disabled @@ -1792,10 +1794,10 @@ pack $ui_index -side left -fill both -expand 1 frame .vpane.files.other -height 100 -width 100 label .vpane.files.other.title -text {Untracked Files} \ -background red \ - -font $font_ui + -font font_ui text $ui_other -background white -borderwidth 0 \ -width 40 -height 10 \ - -font $font_ui \ + -font font_ui \ -cursor $cursor_ptr \ -yscrollcommand {.vpane.files.other.sb set} \ -state disabled @@ -1805,8 +1807,8 @@ pack .vpane.files.other.sb -side right -fill y pack $ui_other -side left -fill both -expand 1 .vpane.files add .vpane.files.other -sticky nsew -$ui_index tag conf in_diff -font [concat $font_ui bold] -$ui_other tag conf in_diff -font [concat $font_ui bold] +$ui_index tag conf in_diff -font font_uibold +$ui_other tag conf in_diff -font font_uibold # -- Diff and Commit Area frame .vpane.lower -height 400 -width 400 @@ -1821,39 +1823,39 @@ frame .vpane.lower.commarea.buttons label .vpane.lower.commarea.buttons.l -text {} \ -anchor w \ -justify left \ - -font $font_ui + -font font_ui pack .vpane.lower.commarea.buttons.l -side top -fill x pack .vpane.lower.commarea.buttons -side left -fill y button .vpane.lower.commarea.buttons.rescan -text {Rescan} \ -command do_rescan \ - -font $font_ui + -font font_ui pack .vpane.lower.commarea.buttons.rescan -side top -fill x lappend disable_on_lock \ {.vpane.lower.commarea.buttons.rescan conf -state} button .vpane.lower.commarea.buttons.amend -text {Amend Last} \ -command do_amend_last \ - -font $font_ui + -font font_ui pack .vpane.lower.commarea.buttons.amend -side top -fill x lappend disable_on_lock \ {.vpane.lower.commarea.buttons.amend conf -state} button .vpane.lower.commarea.buttons.incall -text {Include All} \ -command do_include_all \ - -font $font_ui + -font font_ui pack .vpane.lower.commarea.buttons.incall -side top -fill x lappend disable_on_lock \ {.vpane.lower.commarea.buttons.incall conf -state} button .vpane.lower.commarea.buttons.signoff -text {Sign Off} \ -command do_signoff \ - -font $font_ui + -font font_ui pack .vpane.lower.commarea.buttons.signoff -side top -fill x button .vpane.lower.commarea.buttons.commit -text {Commit} \ -command do_commit \ - -font $font_ui + -font font_ui pack .vpane.lower.commarea.buttons.commit -side top -fill x lappend disable_on_lock \ {.vpane.lower.commarea.buttons.commit conf -state} @@ -1865,7 +1867,7 @@ set ui_coml .vpane.lower.commarea.buffer.l label $ui_coml -text {Commit Message:} \ -anchor w \ -justify left \ - -font $font_ui + -font font_ui trace add variable commit_type write {uplevel #0 { switch -glob $commit_type \ initial {$ui_coml conf -text {Initial Commit Message:}} \ @@ -1879,7 +1881,7 @@ text $ui_comm -background white -borderwidth 1 \ -autoseparators true \ -relief sunken \ -width 75 -height 9 -wrap none \ - -font $font_diff \ + -font font_diff \ -yscrollcommand {.vpane.lower.commarea.buffer.sby set} scrollbar .vpane.lower.commarea.buffer.sby \ -command [list $ui_comm yview] @@ -1892,23 +1894,23 @@ pack .vpane.lower.commarea.buffer -side left -fill y # menu $ui_comm.ctxm -tearoff 0 $ui_comm.ctxm add command -label "Cut" \ - -font $font_ui \ + -font font_ui \ -command "tk_textCut $ui_comm" $ui_comm.ctxm add command -label "Copy" \ - -font $font_ui \ + -font font_ui \ -command "tk_textCopy $ui_comm" $ui_comm.ctxm add command -label "Paste" \ - -font $font_ui \ + -font font_ui \ -command "tk_textPaste $ui_comm" $ui_comm.ctxm add command -label "Delete" \ - -font $font_ui \ + -font font_ui \ -command "$ui_comm delete sel.first sel.last" $ui_comm.ctxm add separator $ui_comm.ctxm add command -label "Select All" \ - -font $font_ui \ + -font font_ui \ -command "$ui_comm tag add sel 0.0 end" $ui_comm.ctxm add command -label "Copy All" \ - -font $font_ui \ + -font font_ui \ -command " $ui_comm tag add sel 0.0 end tk_textCopy $ui_comm @@ -1916,7 +1918,7 @@ $ui_comm.ctxm add command -label "Copy All" \ " $ui_comm.ctxm add separator $ui_comm.ctxm add command -label "Sign Off" \ - -font $font_ui \ + -font font_ui \ -command do_signoff bind $ui_comm "tk_popup $ui_comm.ctxm %X %Y" @@ -1926,21 +1928,21 @@ set ui_fstatus_value {} frame .vpane.lower.diff.header -background orange label .vpane.lower.diff.header.l1 -text {File:} \ -background orange \ - -font $font_ui + -font font_ui label .vpane.lower.diff.header.l2 -textvariable ui_fname_value \ -background orange \ -anchor w \ -justify left \ - -font $font_ui + -font font_ui label .vpane.lower.diff.header.l3 -text {Status:} \ -background orange \ - -font $font_ui + -font font_ui label .vpane.lower.diff.header.l4 -textvariable ui_fstatus_value \ -background orange \ -width $max_status_desc \ -anchor w \ -justify left \ - -font $font_ui + -font font_ui pack .vpane.lower.diff.header.l1 -side left pack .vpane.lower.diff.header.l2 -side left -fill x pack .vpane.lower.diff.header.l4 -side right @@ -1951,7 +1953,7 @@ frame .vpane.lower.diff.body set ui_diff .vpane.lower.diff.body.t text $ui_diff -background white -borderwidth 0 \ -width 80 -height 15 -wrap none \ - -font $font_diff \ + -font font_diff \ -xscrollcommand {.vpane.lower.diff.body.sbx set} \ -yscrollcommand {.vpane.lower.diff.body.sby set} \ -state disabled @@ -1967,22 +1969,22 @@ pack .vpane.lower.diff.body -side bottom -fill both -expand 1 $ui_diff tag conf dm -foreground red $ui_diff tag conf dp -foreground blue -$ui_diff tag conf di -foreground "#00a000" -$ui_diff tag conf dni -foreground "#a000a0" -$ui_diff tag conf da -font [concat $font_diff bold] -$ui_diff tag conf bold -font [concat $font_diff bold] +$ui_diff tag conf di -foreground {#00a000} +$ui_diff tag conf dni -foreground {#a000a0} +$ui_diff tag conf da -font font_diffbold +$ui_diff tag conf bold -font font_diffbold # -- Diff Body Context Menu # menu $ui_diff.ctxm -tearoff 0 $ui_diff.ctxm add command -label "Copy" \ - -font $font_ui \ + -font font_ui \ -command "tk_textCopy $ui_diff" $ui_diff.ctxm add command -label "Select All" \ - -font $font_ui \ + -font font_ui \ -command "$ui_diff tag add sel 0.0 end" $ui_diff.ctxm add command -label "Copy All" \ - -font $font_ui \ + -font font_ui \ -command " $ui_diff tag add sel 0.0 end tk_textCopy $ui_diff @@ -1990,21 +1992,11 @@ $ui_diff.ctxm add command -label "Copy All" \ " $ui_diff.ctxm add separator $ui_diff.ctxm add command -label "Decrease Font Size" \ - -font $font_ui \ - -command { - lset font_diff 1 [expr [lindex $font_diff 1] - 1] - $ui_diff configure -font $font_diff - $ui_diff tag conf da -font [concat $font_diff bold] - $ui_diff tag conf bold -font [concat $font_diff bold] - } + -font font_ui \ + -command {incr_font_size font_diff -1} $ui_diff.ctxm add command -label "Increase Font Size" \ - -font $font_ui \ - -command { - lset font_diff 1 [expr [lindex $font_diff 1] + 1] - $ui_diff configure -font $font_diff - $ui_diff tag conf da -font [concat $font_diff bold] - $ui_diff tag conf bold -font [concat $font_diff bold] - } + -font font_ui \ + -command {incr_font_size font_diff 1} bind $ui_diff "tk_popup $ui_diff.ctxm %X %Y" # -- Status Bar @@ -2014,7 +2006,7 @@ label .status -textvariable ui_status_value \ -justify left \ -borderwidth 1 \ -relief sunken \ - -font $font_ui + -font font_ui pack .status -anchor w -side bottom -fill x # -- Load geometry -- cgit v1.2.1 From 16fccd7a1111c1fca6ce973ddaff690188e742d0 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sun, 12 Nov 2006 02:22:21 -0500 Subject: git-gui: Improve right click context menu binding on all platforms. Apparently doesn't work on my single button PowerBook mouse under Mac OS X. I'm guessing this is because Tk is stealing every event and doesn't realize that Control-Button-1 is actually supposed to invoke the context menu on this platform. So now we have a utility procedure is_MacOSX to guess if we are running on a Mac OS X system, and if so setup Control-Button-1 to also activate what Button-3 should have. This does mean that I need to stay away from using Control-Button-1 as a binding in any other context. Of course we should use $M1B for that, which is M1 (aka Command) on Mac OS X so that shouldn't prove to be a problem. Signed-off-by: Shawn O. Pearce --- git-gui | 37 +++++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 3cbe3e7f7..040581e82 100755 --- a/git-gui +++ b/git-gui @@ -1285,6 +1285,23 @@ unset filemask i ## ## util +proc is_MacOSX {} { + global tcl_platform tk_library + if {$tcl_platform(platform) == {unix} + && $tcl_platform(os) == {Darwin} + && [string match /Library/Frameworks/* $tk_library]} { + return 1 + } + return 0 +} + +proc bind_button3 {w cmd} { + bind $w $cmd + if {[is_MacOSX]} { + bind $w $cmd + } +} + proc incr_font_size {font {amt 1}} { set sz [font configure $font -size] incr sz $amt @@ -1398,7 +1415,7 @@ proc console_init {w} { -command "destroy $w" pack $w.ok -side bottom - bind $w.m.t "tk_popup $w.ctxm %X %Y" + bind_button3 $w.m.t "tk_popup $w.ctxm %X %Y" bind $w.m.t <$M1B-Key-a> "$w.m.t tag add sel 0.0 end;break" bind $w.m.t <$M1B-Key-A> "$w.m.t tag add sel 0.0 end;break" bind $w "focus $w" @@ -1655,10 +1672,14 @@ font configure font_uibold -weight bold eval font create font_diffbold [font configure font_diff] font configure font_diffbold -weight bold -switch -glob -- "$tcl_platform(platform),$tcl_platform(os)" { -windows,* {set M1B Control; set M1T Ctrl} -unix,Darwin {set M1B M1; set M1T Cmd} -* {set M1B M1; set M1T M1} +set M1B M1 +set M1T M1 +if {$tcl_platform(platform) == {windows}} { + set M1B Control + set M1T Ctrl +} elseif {[is_MacOSX]} { + set M1B M1 + set M1T Cmd } # -- Menu Bar @@ -1920,7 +1941,7 @@ $ui_comm.ctxm add separator $ui_comm.ctxm add command -label "Sign Off" \ -font font_ui \ -command do_signoff -bind $ui_comm "tk_popup $ui_comm.ctxm %X %Y" +bind_button3 $ui_comm "tk_popup $ui_comm.ctxm %X %Y" # -- Diff Header set ui_fname_value {} @@ -1997,7 +2018,7 @@ $ui_diff.ctxm add command -label "Decrease Font Size" \ $ui_diff.ctxm add command -label "Increase Font Size" \ -font font_ui \ -command {incr_font_size font_diff 1} -bind $ui_diff "tk_popup $ui_diff.ctxm %X %Y" +bind_button3 $ui_diff "tk_popup $ui_diff.ctxm %X %Y" # -- Status Bar set ui_status_value {Initializing...} @@ -2063,8 +2084,8 @@ bind all <$M1B-Key-w> {destroy [winfo toplevel %W]} bind all <$M1B-Key-W> {destroy [winfo toplevel %W]} foreach i [list $ui_index $ui_other] { bind $i {click %W %x %y 1 %X %Y; break} - bind $i {click %W %x %y 3 %X %Y; break} bind $i {unclick %W %x %y; break} + bind_button3 $i {click %W %x %y 3 %X %Y; break} } unset i -- cgit v1.2.1 From b5834d70fe970ccf955378d4f6e60a51a94bbaaf Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sun, 12 Nov 2006 02:27:28 -0500 Subject: git-gui: Rename quitting global to is_quitting. This is a boolean value; naming it as such is a good thing. Signed-off-by: Shawn O. Pearce --- git-gui | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 040581e82..73227d594 100755 --- a/git-gui +++ b/git-gui @@ -1532,13 +1532,13 @@ proc do_repack {} { console_exec $w $cmd } -set quitting 0 +set is_quitting 0 proc do_quit {} { - global gitdir ui_comm quitting + global gitdir ui_comm is_quitting - if {$quitting} return - set quitting 1 + if {$is_quitting} return + set is_quitting 1 set save [file join $gitdir GITGUI_MSG] set msg [string trim [$ui_comm get 0.0 end]] -- cgit v1.2.1 From 00f949fbd831bda29dc909baf4a21d00a7c2c119 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sun, 12 Nov 2006 02:30:02 -0500 Subject: git-gui: Use arrow cursor rather than left_ptr. Arrow is available on all Tk platforms and is mapped to the native system cursor on Windows and Mac OS X. Consequently its the better cursor choice as it should match whatever the system has configured for the standard pointing thingy. Signed-off-by: Shawn O. Pearce --- git-gui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 73227d594..29877e415 100755 --- a/git-gui +++ b/git-gui @@ -1658,7 +1658,7 @@ proc unclick {w x y} { ## ## ui init -set cursor_ptr left_ptr +set cursor_ptr arrow font create font_diff -family Courier -size 10 font create font_ui catch { -- cgit v1.2.1 From 51f4d16b1d8e2e709f28a4e52b951236950cb1d5 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sun, 12 Nov 2006 03:47:00 -0500 Subject: git-gui: Refactor options menu into an options dialog. I decided that the options menu was going to turn into a mess after a while as I start to add additional features to git-gui. The better approach would be to create a dialog that lets the user edit the options, including their --global options. We also wisely let the user press Cancel (or destroy the window) to abort any sort of option editing session, without the options being changed. Signed-off-by: Shawn O. Pearce --- git-gui | 204 +++++++++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 158 insertions(+), 46 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 29877e415..520ec1eff 100755 --- a/git-gui +++ b/git-gui @@ -14,49 +14,90 @@ set gitdir {} ## ## config -proc load_repo_config {} { - global repo_config - global cfg_trust_mtime +set default_config(gui.trustmtime) false + +proc is_many_config {name} { + switch -glob -- $name { + remote.*.fetch - + remote.*.push + {return 1} + * + {return 0} + } +} +proc load_config {} { + global repo_config global_config default_config + + array unset global_config array unset repo_config + catch { + set fd_rc [open "| git repo-config --global --list" r] + while {[gets $fd_rc line] >= 0} { + if {[regexp {^([^=]+)=(.*)$} $line line name value]} { + if {[is_many_config $name]} { + lappend global_config($name) $value + } else { + set global_config($name) $value + } + } + } + close $fd_rc + } catch { set fd_rc [open "| git repo-config --list" r] while {[gets $fd_rc line] >= 0} { if {[regexp {^([^=]+)=(.*)$} $line line name value]} { - lappend repo_config($name) $value + if {[is_many_config $name]} { + lappend repo_config($name) $value + } else { + set repo_config($name) $value + } } } close $fd_rc } - if {[catch {set cfg_trust_mtime \ - [lindex $repo_config(gui.trustmtime) 0] - }]} { - set cfg_trust_mtime false + foreach name [array names default_config] { + if {[catch {set v $global_config($name)}]} { + set global_config($name) $default_config($name) + } + if {[catch {set v $repo_config($name)}]} { + set repo_config($name) $default_config($name) + } } } -proc save_my_config {} { - global repo_config - global cfg_trust_mtime +proc save_config {} { + global repo_config global_config default_config + global repo_config_new global_config_new - if {[catch {set rc_trustMTime $repo_config(gui.trustmtime)}]} { - set rc_trustMTime [list false] - } - if {$cfg_trust_mtime != [lindex $rc_trustMTime 0]} { - exec git repo-config gui.trustMTime $cfg_trust_mtime - set repo_config(gui.trustmtime) [list $cfg_trust_mtime] + foreach name [array names global_config_new] { + set value $global_config_new($name) + if {$value != $global_config($name)} { + if {$value == $default_config($name)} { + catch {exec git repo-config --global --unset $name} + } else { + catch {exec git repo-config --global $name $value} + } + set global_config($name) $value + if {$value == $repo_config($name)} { + catch {exec git repo-config --unset $name} + set repo_config($name) $value + } + } } - set cfg_geometry [wm geometry .] - append cfg_geometry " [lindex [.vpane sash coord 0] 1]" - append cfg_geometry " [lindex [.vpane.files sash coord 0] 0]" - if {[catch {set rc_geometry $repo_config(gui.geometry)}]} { - set rc_geometry [list [list]] - } - if {$cfg_geometry != [lindex $rc_geometry 0]} { - exec git repo-config gui.geometry $cfg_geometry - set repo_config(gui.geometry) [list $cfg_geometry] + foreach name [array names repo_config_new] { + set value $repo_config_new($name) + if {$value != $repo_config($name)} { + if {$value == $global_config($name)} { + catch {exec git repo-config --unset $name} + } else { + catch {exec git repo-config $name $value} + } + set repo_config($name) $value + } } } @@ -117,7 +158,7 @@ if {$appname == {git-citool}} { set single_commit 1 } -load_repo_config +load_config ###################################################################### ## @@ -183,7 +224,7 @@ proc update_status {{final Ready.}} { global HEAD PARENT commit_type global ui_index ui_other ui_status_value ui_comm global status_active file_states - global cfg_trust_mtime + global repo_config if {$status_active || ![lock_index read]} return @@ -209,7 +250,7 @@ proc update_status {{final Ready.}} { $ui_comm edit reset } - if {$cfg_trust_mtime == {true}} { + if {$repo_config(gui.trustmtime) == {true}} { update_status_stage2 {} $final } else { set status_active 1 @@ -409,7 +450,7 @@ proc handle_empty_diff {} { The modification date of this file was updated by another application and you currently have the Trust File Modification -Timestamps feature enabled, so Git did not automatically detect +Timestamps option enabled, so Git did not automatically detect that there are no content differences in this file. This file will now be removed from the modified files list, to @@ -502,7 +543,7 @@ proc show_diff {path {w {}} {lno {}}} { proc read_diff {fd} { global ui_diff ui_status_value diff_3way diff_active - global cfg_trust_mtime + global repo_config while {[gets $fd line] >= 0} { if {[string match {diff --git *} $line]} continue @@ -550,7 +591,8 @@ proc read_diff {fd} { unlock_index set ui_status_value {Ready.} - if {$cfg_trust_mtime && [$ui_diff index end] == {2.0}} { + if {$repo_config(gui.trustmtime) == {true} + && [$ui_diff index end] == {2.0}} { handle_empty_diff } } @@ -1314,7 +1356,6 @@ proc hook_failed_popup {hook msg} { set w .hookfail toplevel $w - wm transient $w . frame $w.m label $w.m.l1 -text "$hook hook failed:" \ @@ -1535,11 +1576,13 @@ proc do_repack {} { set is_quitting 0 proc do_quit {} { - global gitdir ui_comm is_quitting + global gitdir ui_comm is_quitting repo_config if {$is_quitting} return set is_quitting 1 + # -- Stash our current commit buffer. + # set save [file join $gitdir GITGUI_MSG] set msg [string trim [$ui_comm get 0.0 end]] if {[$ui_comm edit modified] && $msg != {}} { @@ -1552,7 +1595,19 @@ proc do_quit {} { file delete $save } - save_my_config + # -- Stash our current window geometry into this repository. + # + set cfg_geometry [list] + lappend cfg_geometry [wm geometry .] + lappend cfg_geometry [lindex [.vpane sash coord 0] 1] + lappend cfg_geometry [lindex [.vpane.files sash coord 0] 0] + if {[catch {set rc_geometry $repo_config(gui.geometry)}]} { + set rc_geometry {} + } + if {$cfg_geometry != $rc_geometry} { + catch {exec git repo-config gui.geometry $cfg_geometry} + } + destroy . } @@ -1624,6 +1679,69 @@ proc do_commit {} { commit_tree } +proc do_options {} { + global appname gitdir + global repo_config global_config + global repo_config_new global_config_new + + load_config + array unset repo_config_new + array unset global_config_new + foreach name [array names repo_config] { + set repo_config_new($name) $repo_config($name) + } + foreach name [array names global_config] { + set global_config_new($name) $global_config($name) + } + + set w .options_editor + toplevel $w + + label $w.header -text "$appname Options" \ + -font font_uibold + pack $w.header -side top -fill x + + frame $w.buttons + button $w.buttons.save -text Save \ + -font font_ui \ + -command "save_config; destroy $w" + pack $w.buttons.save -side right + button $w.buttons.cancel -text {Cancel} \ + -font font_ui \ + -command "destroy $w" + pack $w.buttons.cancel -side right + pack $w.buttons -side bottom -anchor e -pady 10 -padx 10 + + labelframe $w.repo -text {This Repository} \ + -relief raised -borderwidth 2 + labelframe $w.global -text {Global (All Repositories)} \ + -relief raised -borderwidth 2 + pack $w.repo -side left -fill both -expand 1 -pady 5 -padx 5 + pack $w.global -side right -fill both -expand 1 -pady 5 -padx 5 + + foreach option { + {trustmtime {Trust File Modification Timestamps}} + } { + set name [lindex $option 0] + set text [lindex $option 1] + foreach f {repo global} { + checkbutton $w.$f.$name -text $text \ + -variable ${f}_config_new(gui.$name) \ + -onvalue true \ + -offvalue false \ + -font font_ui + pack $w.$f.$name -side top -anchor w + } + } + + bind $w "grab $w; focus $w" + bind $w "destroy $w" + wm title $w "$appname ([lindex [file split \ + [file normalize [file dirname $gitdir]]] \ + end]): Options" + tkwait window $w +} + # shift == 1: left click # 3: right click proc click {w x y shift wx wy} { @@ -1690,7 +1808,6 @@ menu .mbar -tearoff 0 .mbar add cascade -label Fetch -menu .mbar.fetch .mbar add cascade -label Pull -menu .mbar.pull .mbar add cascade -label Push -menu .mbar.push -.mbar add cascade -label Options -menu .mbar.options . configure -menu .mbar # -- Project Menu @@ -1739,6 +1856,10 @@ menu .mbar.edit -command {catch {[focus] tag add sel 0.0 end}} \ -accelerator $M1T-A \ -font font_ui +.mbar.edit add separator +.mbar.edit add command -label {Options...} \ + -command do_options \ + -font font_ui # -- Commit Menu menu .mbar.commit @@ -1779,15 +1900,6 @@ menu .mbar.pull # -- Push Menu menu .mbar.push -# -- Options Menu -menu .mbar.options -.mbar.options add checkbutton \ - -label {Trust File Modification Timestamps} \ - -font font_ui \ - -offvalue false \ - -onvalue true \ - -variable cfg_trust_mtime - # -- Main Window Layout panedwindow .vpane -orient vertical panedwindow .vpane.files -orient horizontal @@ -2032,7 +2144,7 @@ pack .status -anchor w -side bottom -fill x # -- Load geometry catch { -set gm [lindex $repo_config(gui.geometry) 0] +set gm $repo_config(gui.geometry) wm geometry . [lindex $gm 0] .vpane sash place 0 \ [lindex [.vpane sash coord 0] 0] \ -- cgit v1.2.1 From 92148d8091d148e219b88e4d555a386ffa78f575 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sun, 12 Nov 2006 05:27:00 -0500 Subject: git-gui: Allow the user to manipulate the fonts from the options panel. This turned out to take a lot more time than I thought it would take; but now users can edit the main UI font and the diff/fixed with font by changing both the family name and/or the point size of the text. We save the complete Tk font specification to the user's ~/.gitconfig file upon saving options. This is probably more verbose than it needs to be as there are many useless options recorded (e.g. -overstrike 0) that a user won't really want to use in this application. Signed-off-by: Shawn O. Pearce --- git-gui | 140 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 124 insertions(+), 16 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 520ec1eff..931a95930 100755 --- a/git-gui +++ b/git-gui @@ -14,8 +14,6 @@ set gitdir {} ## ## config -set default_config(gui.trustmtime) false - proc is_many_config {name} { switch -glob -- $name { remote.*.fetch - @@ -69,10 +67,25 @@ proc load_config {} { } proc save_config {} { - global repo_config global_config default_config + global default_config font_descs + global repo_config global_config global repo_config_new global_config_new - foreach name [array names global_config_new] { + foreach option $font_descs { + set name [lindex $option 0] + set font [lindex $option 1] + font configure $font \ + -family $global_config_new(gui.$font^^family) \ + -size $global_config_new(gui.$font^^size) + font configure ${font}bold \ + -family $global_config_new(gui.$font^^family) \ + -size $global_config_new(gui.$font^^size) + set global_config_new(gui.$name) [font configure $font] + unset global_config_new(gui.$font^^family) + unset global_config_new(gui.$font^^size) + } + + foreach name [array names default_config] { set value $global_config_new($name) if {$value != $global_config($name)} { if {$value == $default_config($name)} { @@ -88,7 +101,7 @@ proc save_config {} { } } - foreach name [array names repo_config_new] { + foreach name [array names default_config] { set value $repo_config_new($name) if {$value != $repo_config($name)} { if {$value == $global_config($name)} { @@ -158,8 +171,6 @@ if {$appname == {git-citool}} { set single_commit 1 } -load_config - ###################################################################### ## ## task management @@ -1680,7 +1691,7 @@ proc do_commit {} { } proc do_options {} { - global appname gitdir + global appname gitdir font_descs global repo_config global_config global repo_config_new global_config_new @@ -1702,19 +1713,25 @@ proc do_options {} { pack $w.header -side top -fill x frame $w.buttons + button $w.buttons.restore -text {Restore Defaults} \ + -font font_ui \ + -command do_restore_defaults + pack $w.buttons.restore -side left button $w.buttons.save -text Save \ -font font_ui \ - -command "save_config; destroy $w" + -command [list do_save_config $w] pack $w.buttons.save -side right button $w.buttons.cancel -text {Cancel} \ -font font_ui \ - -command "destroy $w" + -command [list destroy $w] pack $w.buttons.cancel -side right - pack $w.buttons -side bottom -anchor e -pady 10 -padx 10 + pack $w.buttons -side bottom -fill x -pady 10 -padx 10 labelframe $w.repo -text {This Repository} \ + -font font_ui \ -relief raised -borderwidth 2 labelframe $w.global -text {Global (All Repositories)} \ + -font font_ui \ -relief raised -borderwidth 2 pack $w.repo -side left -fill both -expand 1 -pady 5 -padx 5 pack $w.global -side right -fill both -expand 1 -pady 5 -padx 5 @@ -1734,6 +1751,33 @@ proc do_options {} { } } + set all_fonts [lsort [font families]] + foreach option $font_descs { + set name [lindex $option 0] + set font [lindex $option 1] + set text [lindex $option 2] + + set global_config_new(gui.$font^^family) \ + [font configure $font -family] + set global_config_new(gui.$font^^size) \ + [font configure $font -size] + + frame $w.global.$name + label $w.global.$name.l -text "$text:" -font font_ui + pack $w.global.$name.l -side left -anchor w -fill x + eval tk_optionMenu $w.global.$name.family \ + global_config_new(gui.$font^^family) \ + $all_fonts + spinbox $w.global.$name.size \ + -textvariable global_config_new(gui.$font^^size) \ + -from 2 -to 80 -increment 1 \ + -width 3 \ + -font font_ui + pack $w.global.$name.size -side right -anchor e + pack $w.global.$name.family -side right -anchor e + pack $w.global.$name -side top -anchor w -fill x + } + bind $w "grab $w; focus $w" bind $w "destroy $w" wm title $w "$appname ([lindex [file split \ @@ -1742,6 +1786,38 @@ proc do_options {} { tkwait window $w } +proc do_restore_defaults {} { + global font_descs default_config + global repo_config_new global_config_new + + foreach name [array names default_config] { + set repo_config_new($name) $default_config($name) + set global_config_new($name) $default_config($name) + } + + foreach option $font_descs { + set name [lindex $option 0] + set repo_config($name) $default_config(gui.$name) + } + apply_config + + foreach option $font_descs { + set name [lindex $option 0] + set font [lindex $option 1] + set global_config_new(gui.$font^^family) \ + [font configure $font -family] + set global_config_new(gui.$font^^size) \ + [font configure $font -size] + } +} + +proc do_save_config {w} { + if {[catch {save_config} err]} { + error_popup "Failed to completely save options:\n\n$err" + } + destroy $w +} + # shift == 1: left click # 3: right click proc click {w x y shift wx wy} { @@ -1774,7 +1850,7 @@ proc unclick {w x y} { ###################################################################### ## -## ui init +## config defaults set cursor_ptr arrow font create font_diff -family Courier -size 10 @@ -1785,10 +1861,8 @@ catch { destroy .dummy } -eval font create font_uibold [font configure font_ui] -font configure font_uibold -weight bold -eval font create font_diffbold [font configure font_diff] -font configure font_diffbold -weight bold +font create font_uibold +font create font_diffbold set M1B M1 set M1T M1 @@ -1800,6 +1874,40 @@ if {$tcl_platform(platform) == {windows}} { set M1T Cmd } +proc apply_config {} { + global repo_config font_descs + + foreach option $font_descs { + set name [lindex $option 0] + set font [lindex $option 1] + if {[catch { + foreach {cn cv} $repo_config(gui.$name) { + font configure $font $cn $cv + } + } err]} { + error_popup "Invalid font specified in gui.$name:\n\n$err" + } + foreach {cn cv} [font configure $font] { + font configure ${font}bold $cn $cv + } + font configure ${font}bold -weight bold + } +} + +set default_config(gui.trustmtime) false +set default_config(gui.fontui) [font configure font_ui] +set default_config(gui.fontdiff) [font configure font_diff] +set font_descs { + {fontui font_ui {Main Font}} + {fontdiff font_diff {Diff/Console Font}} +} +load_config +apply_config + +###################################################################### +## +## ui construction + # -- Menu Bar menu .mbar -tearoff 0 .mbar add cascade -label Project -menu .mbar.project -- cgit v1.2.1 From 74e6b12f5831a8c93a5d3c90118a73e908d0680a Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sun, 12 Nov 2006 06:35:14 -0500 Subject: git-gui: Supply progress feedback when running update-index. The git-update-index process can take a while to process a large number of files; for example my laptop would probably need almost an hour to chug through 20,000 modified files. In these incredibly large cases the user should be given at least some feedback to let them know the application is still working on their behalf, even if it won't them do anything else (as the index is locked). Signed-off-by: Shawn O. Pearce --- git-gui | 143 +++++++++++++++++++++++++++++++++++----------------------------- 1 file changed, 79 insertions(+), 64 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 931a95930..456f53fdc 100755 --- a/git-gui +++ b/git-gui @@ -178,9 +178,7 @@ if {$appname == {git-citool}} { set single_commit 0 set status_active 0 set diff_active 0 -set update_active 0 set commit_active 0 -set update_index_fd {} set disable_on_lock [list] set index_lock_type none @@ -1100,55 +1098,73 @@ proc display_all_files {} { $ui_other conf -state disabled } -proc with_update_index {body} { - global update_index_fd +proc update_index {pathList} { + global update_index_cp ui_status_value - if {$update_index_fd == {}} { - if {![lock_index update]} return - set update_index_fd [open \ - "| git update-index --add --remove -z --stdin" \ - w] - fconfigure $update_index_fd -translation binary - uplevel 1 $body - close $update_index_fd - set update_index_fd {} - unlock_index - } else { - uplevel 1 $body - } -} + if {![lock_index update]} return -proc update_index {path} { - global update_index_fd + set update_index_cp 0 + set totalCnt [llength $pathList] + set batch [expr {int($totalCnt * .01) + 1}] + if {$batch > 25} {set batch 25} + + set ui_status_value "Including files ... 0/$totalCnt 0%" + set ui_status_value [format \ + "Including files ... %i/%i files (%.2f%%)" \ + $update_index_cp \ + $totalCnt \ + 0.0] + set fd [open "| git update-index --add --remove -z --stdin" w] + fconfigure $fd -blocking 0 -translation binary + fileevent $fd writable [list \ + write_update_index \ + $fd \ + $pathList \ + $totalCnt \ + $batch \ + ] +} + +proc write_update_index {fd pathList totalCnt batch} { + global update_index_cp ui_status_value + global file_states ui_fname_value - if {$update_index_fd == {}} { - error {not in with_update_index} - } else { - puts -nonewline $update_index_fd "$path\0" + if {$update_index_cp >= $totalCnt} { + close $fd + unlock_index + set ui_status_value {Ready.} + return } -} -proc toggle_mode {path} { - global file_states ui_fname_value - - set s $file_states($path) - set m [lindex $s 0] + for {set i $batch} \ + {$update_index_cp < $totalCnt && $i > 0} \ + {incr i -1} { + set path [lindex $pathList $update_index_cp] + incr update_index_cp + + switch -- [lindex $file_states($path) 0] { + AM - + _O {set new A*} + _M - + MM {set new M*} + AD - + _D {set new D*} + default {continue} + } - switch -- $m { - AM - - _O {set new A*} - _M - - MM {set new M*} - AD - - _D {set new D*} - default {return} + puts -nonewline $fd $path + puts -nonewline $fd "\0" + display_file $path $new + if {$ui_fname_value == $path} { + show_diff $path + } } - with_update_index {update_index $path} - display_file $path $new - if {$ui_fname_value == $path} { - show_diff $path - } + set ui_status_value [format \ + "Including files ... %i/%i files (%.2f%%)" \ + $update_index_cp \ + $totalCnt \ + [expr {100.0 * $update_index_cp / $totalCnt}]] } ###################################################################### @@ -1627,27 +1643,25 @@ proc do_rescan {} { } proc do_include_all {} { - global update_active ui_status_value - - if {$update_active || ![lock_index begin-update]} return - - set update_active 1 - set ui_status_value {Including all modified files...} - after 1 { - with_update_index { - foreach path [array names file_states] { - set s $file_states($path) - set m [lindex $s 0] - switch -- $m { - AM - - MM - - _M - - _D {toggle_mode $path} - } - } + global file_states + + if {![lock_index begin-update]} return + + set pathList [list] + foreach path [array names file_states] { + set s $file_states($path) + set m [lindex $s 0] + switch -- $m { + AM - + MM - + _M - + _D {lappend pathList $path} } - set update_active 0 - set ui_status_value {Ready.} + } + if {$pathList == {}} { + unlock_index + } else { + update_index $pathList } } @@ -1844,7 +1858,7 @@ proc unclick {w x y} { if {$path == {}} return if {$col == 0} { - toggle_mode $path + update_index [list $path] } } @@ -2318,4 +2332,5 @@ load_all_remotes populate_remote_menu .mbar.fetch From fetch_from populate_remote_menu .mbar.push To push_to populate_pull_menu .mbar.pull +tkwait visibility . update_status -- cgit v1.2.1 From e01b42211cad31b1262d152b7e2561cb8bf218ed Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sun, 12 Nov 2006 06:46:26 -0500 Subject: git-gui: Minor options dialog UI cleanups. Display the name of "this" repository rather than the quite ambiguous string "This". The idea is that seeing the name of the directory the repository is stored in should help jog the user's memory about what they are setting options for. Also place the options dialog immediately over the git-gui main window when it gets opened. This way the user isn't scrolling very far away to gain access to the window. At least on my Mac OS X system not doing this makes the options dialog open rather far away, thus requiring lots of mouse activity to reach it. Signed-off-by: Shawn O. Pearce --- git-gui | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 456f53fdc..580110e62 100755 --- a/git-gui +++ b/git-gui @@ -1718,9 +1718,13 @@ proc do_options {} { foreach name [array names global_config] { set global_config_new($name) $global_config($name) } + set reponame [lindex [file split \ + [file normalize [file dirname $gitdir]]] \ + end] set w .options_editor toplevel $w + wm geometry $w "+[winfo rootx .]+[winfo rooty .]" label $w.header -text "$appname Options" \ -font font_uibold @@ -1741,7 +1745,7 @@ proc do_options {} { pack $w.buttons.cancel -side right pack $w.buttons -side bottom -fill x -pady 10 -padx 10 - labelframe $w.repo -text {This Repository} \ + labelframe $w.repo -text "$reponame Repository" \ -font font_ui \ -relief raised -borderwidth 2 labelframe $w.global -text {Global (All Repositories)} \ @@ -1794,9 +1798,7 @@ proc do_options {} { bind $w "grab $w; focus $w" bind $w "destroy $w" - wm title $w "$appname ([lindex [file split \ - [file normalize [file dirname $gitdir]]] \ - end]): Options" + wm title $w "$appname ($reponame): Options" tkwait window $w } -- cgit v1.2.1 From 8009dcdc8d9bee0b5aab1f6e860a834ffbb0b08f Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sun, 12 Nov 2006 06:53:56 -0500 Subject: git-gui: Added Options... menu item to end of diff context menu. Since the font name can only be chosen from within the options dialog giving the user fast access to this dialog from within a context menu that already talks about increasing and decreasing the font size may help users to locate the font name setting as well. Signed-off-by: Shawn O. Pearce --- git-gui | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 580110e62..f959cb670 100755 --- a/git-gui +++ b/git-gui @@ -2068,7 +2068,7 @@ $ui_index tag conf in_diff -font font_uibold $ui_other tag conf in_diff -font font_uibold # -- Diff and Commit Area -frame .vpane.lower -height 400 -width 400 +frame .vpane.lower -height 300 -width 400 frame .vpane.lower.commarea frame .vpane.lower.diff -relief sunken -borderwidth 1 pack .vpane.lower.commarea -side top -fill x @@ -2254,6 +2254,9 @@ $ui_diff.ctxm add command -label "Decrease Font Size" \ $ui_diff.ctxm add command -label "Increase Font Size" \ -font font_ui \ -command {incr_font_size font_diff 1} +$ui_diff.ctxm add command -label {Options...} \ + -font font_ui \ + -command do_options bind_button3 $ui_diff "tk_popup $ui_diff.ctxm %X %Y" # -- Status Bar -- cgit v1.2.1 From 4af2c384eaae62300765e205c705c7741dd7dd31 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sun, 12 Nov 2006 15:04:15 -0500 Subject: git-gui: Use 'after 1' to post UI rather than tkwait. The tkwait visibility command and Windows doesn't seem to realize the window is visible, consequently we are never finishing our initialization by calling update_status. Signed-off-by: Shawn O. Pearce --- git-gui | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index f959cb670..2138d2d2e 100755 --- a/git-gui +++ b/git-gui @@ -2337,5 +2337,4 @@ load_all_remotes populate_remote_menu .mbar.fetch From fetch_from populate_remote_menu .mbar.push To push_to populate_pull_menu .mbar.pull -tkwait visibility . -update_status +after 1 update_status -- cgit v1.2.1 From 7b64d0b7d62ec0eb6e8b37f0be2e62f2a719de16 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sun, 12 Nov 2006 15:45:35 -0500 Subject: git-gui: Correct bugs in font config handling. Apparently Tcl is being helpful on Windows during exec and is throwing a \ in front of every { it finds in the string. I'm guessing they think the value might be read by another Tcl program? Anyway, Git faithfully stores the \{ sequence and sends it back that way to Tcl, at which point Tcl parses the list wrong and starts to break it in the middle of any element which contains spaces. Therefore a list such as: -family {Times New Roman} gets broken up into the pairs: {-family \{Times} {New Roman} which is very incorrect. So now we replace all { and } with "", at which point Tcl doesn't throw \ in front of the " on the way out to Git yet it reads it correctly as a list on the way back in. I also found and fixed a bug in the way we restored the fonts when the user presses Restore Defaults in the options dialog. Signed-off-by: Shawn O. Pearce --- git-gui | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 2138d2d2e..e59d225cb 100755 --- a/git-gui +++ b/git-gui @@ -91,7 +91,8 @@ proc save_config {} { if {$value == $default_config($name)} { catch {exec git repo-config --global --unset $name} } else { - catch {exec git repo-config --global $name $value} + regsub -all "\[{}\]" $value {"} value + exec git repo-config --global $name $value } set global_config($name) $value if {$value == $repo_config($name)} { @@ -107,7 +108,8 @@ proc save_config {} { if {$value == $global_config($name)} { catch {exec git repo-config --unset $name} } else { - catch {exec git repo-config $name $value} + regsub -all "\[{}\]" $value {"} value + exec git repo-config $name $value } set repo_config($name) $value } @@ -1803,7 +1805,7 @@ proc do_options {} { } proc do_restore_defaults {} { - global font_descs default_config + global font_descs default_config repo_config global repo_config_new global_config_new foreach name [array names default_config] { @@ -1813,7 +1815,7 @@ proc do_restore_defaults {} { foreach option $font_descs { set name [lindex $option 0] - set repo_config($name) $default_config(gui.$name) + set repo_config(gui.$name) $default_config(gui.$name) } apply_config -- cgit v1.2.1 From 4ccdab028263dfdeb0adf9764466bb3a43265395 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sun, 12 Nov 2006 16:20:36 -0500 Subject: git-gui: Hide non-commit related commands when invoked as git-citool. If the user is invoking us as git-citool then they want to perform a single commit and exit quickly. Since we are about to be a very short lived process we should do what we can to avoid spending CPU time setting up menus which the user will never use, like the fetch/push/pull menus. Signed-off-by: Shawn O. Pearce --- git-gui | 42 +++++++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 17 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index e59d225cb..249b2c894 100755 --- a/git-gui +++ b/git-gui @@ -169,6 +169,7 @@ if {$cdup != ""} { } unset cdup +set single_commit 0 if {$appname == {git-citool}} { set single_commit 1 } @@ -177,7 +178,6 @@ if {$appname == {git-citool}} { ## ## task management -set single_commit 0 set status_active 0 set diff_active 0 set commit_active 0 @@ -1931,9 +1931,11 @@ menu .mbar -tearoff 0 .mbar add cascade -label Project -menu .mbar.project .mbar add cascade -label Edit -menu .mbar.edit .mbar add cascade -label Commit -menu .mbar.commit -.mbar add cascade -label Fetch -menu .mbar.fetch -.mbar add cascade -label Pull -menu .mbar.pull -.mbar add cascade -label Push -menu .mbar.push +if {!$single_commit} { + .mbar add cascade -label Fetch -menu .mbar.fetch + .mbar add cascade -label Pull -menu .mbar.pull + .mbar add cascade -label Push -menu .mbar.push +} . configure -menu .mbar # -- Project Menu @@ -1941,9 +1943,11 @@ menu .mbar.project .mbar.project add command -label Visualize \ -command do_gitk \ -font font_ui -.mbar.project add command -label {Repack Database} \ - -command do_repack \ - -font font_ui +if {!$single_commit} { + .mbar.project add command -label {Repack Database} \ + -command do_repack \ + -font font_ui +} .mbar.project add command -label Quit \ -command do_quit \ -accelerator $M1T-Q \ @@ -2017,14 +2021,16 @@ lappend disable_on_lock \ lappend disable_on_lock \ [list .mbar.commit entryconf [.mbar.commit index last] -state] -# -- Fetch Menu -menu .mbar.fetch +if {!$single_commit} { + # -- Fetch Menu + menu .mbar.fetch -# -- Pull Menu -menu .mbar.pull + # -- Pull Menu + menu .mbar.pull -# -- Push Menu -menu .mbar.push + # -- Push Menu + menu .mbar.push +} # -- Main Window Layout panedwindow .vpane -orient vertical @@ -2335,8 +2341,10 @@ set file_lists($ui_other) [list] wm title . "$appname ([file normalize [file dirname $gitdir]])" focus -force $ui_comm -load_all_remotes -populate_remote_menu .mbar.fetch From fetch_from -populate_remote_menu .mbar.push To push_to -populate_pull_menu .mbar.pull +if {!$single_commit} { + load_all_remotes + populate_remote_menu .mbar.fetch From fetch_from + populate_remote_menu .mbar.push To push_to + populate_pull_menu .mbar.pull +} after 1 update_status -- cgit v1.2.1 From 6bbd1cb95aede2991d0748d2a54088f2c1291602 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sun, 12 Nov 2006 16:24:52 -0500 Subject: git-gui: Don't load the global options unless necessary. Since git-repo-config will supply us a union of both the global and the local repository configuration data when we invoke it during startup there is no reason to go get the global configuration with an extra call to repo-config unless the user is trying to view & edit all options in the options dialog. Since skipping this extra repo-config invocation save us a little bit of time its nice to be able to avoid it when we are invoked as git-citool and won't be running very long. Signed-off-by: Shawn O. Pearce --- git-gui | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 249b2c894..fbb3090ed 100755 --- a/git-gui +++ b/git-gui @@ -24,24 +24,27 @@ proc is_many_config {name} { } } -proc load_config {} { +proc load_config {include_global} { global repo_config global_config default_config array unset global_config - array unset repo_config - catch { - set fd_rc [open "| git repo-config --global --list" r] - while {[gets $fd_rc line] >= 0} { - if {[regexp {^([^=]+)=(.*)$} $line line name value]} { - if {[is_many_config $name]} { - lappend global_config($name) $value - } else { - set global_config($name) $value + if {$include_global} { + catch { + set fd_rc [open "| git repo-config --global --list" r] + while {[gets $fd_rc line] >= 0} { + if {[regexp {^([^=]+)=(.*)$} $line line name value]} { + if {[is_many_config $name]} { + lappend global_config($name) $value + } else { + set global_config($name) $value + } } } + close $fd_rc } - close $fd_rc } + + array unset repo_config catch { set fd_rc [open "| git repo-config --list" r] while {[gets $fd_rc line] >= 0} { @@ -1711,7 +1714,7 @@ proc do_options {} { global repo_config global_config global repo_config_new global_config_new - load_config + load_config 1 array unset repo_config_new array unset global_config_new foreach name [array names repo_config] { @@ -1919,7 +1922,7 @@ set font_descs { {fontui font_ui {Main Font}} {fontdiff font_diff {Diff/Console Font}} } -load_config +load_config 0 apply_config ###################################################################### -- cgit v1.2.1 From ebf336b9422302ec89bce14b83017060d7ccd3e6 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sun, 12 Nov 2006 16:53:19 -0500 Subject: git-gui: Allow the user to disable diff stat summary during pull. Because the pull diffstat summary can take as long as the pull itself some users may just choose to disable the summary and save themselves an extra few seconds during each pull. This is especially true if the user really doesn't care about the other files being modified, as due to their project organizational structure they aren't really responsible for their content. This adds an option to the options panel which lets the user disable the diffstat summary (and thus we pass --no-summary to git-pull) but there does appear to be a bug in the config saving code where we did not set the local repo config differently from the global config. Signed-off-by: Shawn O. Pearce --- git-gui | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index fbb3090ed..761ce7551 100755 --- a/git-gui +++ b/git-gui @@ -896,8 +896,7 @@ proc fetch_from {remote} { } proc pull_remote {remote branch} { - global HEAD commit_type - global file_states + global HEAD commit_type file_states repo_config if {![lock_index update]} return @@ -933,6 +932,9 @@ Commit or throw away all changes before starting a pull operation. set w [new_console "pull $remote $branch" \ "Pulling new changes from branch $branch in $remote"] set cmd [list git pull] + if {$repo_config(gui.pullsummary) == {false}} { + lappend cmd --no-summary + } lappend cmd $remote lappend cmd $branch console_exec $w $cmd [list post_pull_remote $remote $branch] @@ -1760,6 +1762,7 @@ proc do_options {} { pack $w.global -side right -fill both -expand 1 -pady 5 -padx 5 foreach option { + {pullsummary {Show Pull Summary}} {trustmtime {Trust File Modification Timestamps}} } { set name [lindex $option 0] @@ -1916,6 +1919,7 @@ proc apply_config {} { } set default_config(gui.trustmtime) false +set default_config(gui.pullsummary) true set default_config(gui.fontui) [font configure font_ui] set default_config(gui.fontdiff) [font configure font_diff] set font_descs { -- cgit v1.2.1 From 4658b56fce4e8b7c4489ae7b0fe9ecf1e236b70b Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sun, 12 Nov 2006 17:58:08 -0500 Subject: git-gui: Run the pre-commit hook in the background. I started to notice on Windows that commits took a lot longer to get going than on my Mac OS X system. The real reason is the repositories that I'm testing with on Windows all enabled the standard pre-commit hook while my test repository on Mac OS X doesn't have it executable (so its not running). So the Windows repositories are spending this lag time running that hook. Now we run the pre-commit hook in the background, allowing the UI to update and tell the user we are busy doing things. Signed-off-by: Shawn O. Pearce --- git-gui | 55 +++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 43 insertions(+), 12 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 761ce7551..bee17de4d 100755 --- a/git-gui +++ b/git-gui @@ -664,8 +664,8 @@ proc load_last_commit {} { proc commit_tree {} { global tcl_platform HEAD gitdir commit_type file_states - global commit_active ui_status_value - global ui_comm + global commit_active pch_error + global ui_status_value ui_comm if {$commit_active || ![lock_index update]} return @@ -739,33 +739,64 @@ A good commit message has the following format: return } + set commit_active 1 + # -- Ask the pre-commit hook for the go-ahead. # set pchook [file join $gitdir hooks pre-commit] if {$tcl_platform(platform) == {windows} && [file isfile $pchook]} { - set pchook [list sh -c \ - "if test -x \"$pchook\"; then exec \"$pchook\"; fi"] + set pchook [list sh -c [concat \ + "if test -x \"$pchook\";" \ + "then exec \"$pchook\" 2>&1;" \ + "fi"]] } elseif {[file executable $pchook]} { - set pchook [list $pchook] + set pchook [list $pchook |& cat] } else { set pchook {} } - if {$pchook != {} && [catch {eval exec $pchook} err]} { - hook_failed_popup pre-commit $err - unlock_index + if {$pchook != {}} { + set ui_status_value {Calling pre-commit hook...} + set pch_error {} + set fd_ph [open "| $pchook" r] + fconfigure $fd_ph -blocking 0 -translation binary + fileevent $fd_ph readable \ + [list commit_stage1 $fd_ph $curHEAD $msg] + } else { + commit_stage2 $curHEAD $msg + } +} + +proc commit_stage1 {fd_ph curHEAD msg} { + global commit_active pch_error ui_status_value + + append pch_error [read $fd_ph] + fconfigure $fd_ph -blocking 1 + if {[eof $fd_ph]} { + if {[catch {close $fd_ph}]} { + set ui_status_value {Commit declined by pre-commit hook.} + hook_failed_popup pre-commit $pch_error + unlock_index + set commit_active 0 + set pch_error {} + return + } + commit_stage2 $curHEAD $msg return } + fconfigure $fd_ph -blocking 0 +} + +proc commit_stage2 {curHEAD msg} { + global ui_status_value # -- Write the tree in the background. # - set commit_active 1 set ui_status_value {Committing changes...} - set fd_wt [open "| git write-tree" r] - fileevent $fd_wt readable [list commit_stage2 $fd_wt $curHEAD $msg] + fileevent $fd_wt readable [list commit_stage3 $fd_wt $curHEAD $msg] } -proc commit_stage2 {fd_wt curHEAD msg} { +proc commit_stage3 {fd_wt curHEAD msg} { global single_commit gitdir HEAD PARENT commit_type global commit_active ui_status_value ui_comm global file_states -- cgit v1.2.1 From 333b0c74b33fe54f0489813950345edbeb62c0b5 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sun, 12 Nov 2006 18:03:19 -0500 Subject: git-gui: Remove the commit_active global variable. We were originally trying to use $commit_active to tell us if there was a commit currently in progress, just so we didn't attempt to start a second (parallel) one by mistake. But really the index lock handles this for us as it won't let us lock the index if it is already locked for update. So this can't happen. Signed-off-by: Shawn O. Pearce --- git-gui | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index bee17de4d..3ccf0a41d 100755 --- a/git-gui +++ b/git-gui @@ -183,7 +183,6 @@ if {$appname == {git-citool}} { set status_active 0 set diff_active 0 -set commit_active 0 set disable_on_lock [list] set index_lock_type none @@ -664,10 +663,10 @@ proc load_last_commit {} { proc commit_tree {} { global tcl_platform HEAD gitdir commit_type file_states - global commit_active pch_error + global pch_error global ui_status_value ui_comm - if {$commit_active || ![lock_index update]} return + if {![lock_index update]} return # -- Our in memory state should match the repository. # @@ -739,8 +738,6 @@ A good commit message has the following format: return } - set commit_active 1 - # -- Ask the pre-commit hook for the go-ahead. # set pchook [file join $gitdir hooks pre-commit] @@ -767,7 +764,7 @@ A good commit message has the following format: } proc commit_stage1 {fd_ph curHEAD msg} { - global commit_active pch_error ui_status_value + global pch_error ui_status_value append pch_error [read $fd_ph] fconfigure $fd_ph -blocking 1 @@ -776,14 +773,13 @@ proc commit_stage1 {fd_ph curHEAD msg} { set ui_status_value {Commit declined by pre-commit hook.} hook_failed_popup pre-commit $pch_error unlock_index - set commit_active 0 - set pch_error {} - return + } else { + commit_stage2 $curHEAD $msg } - commit_stage2 $curHEAD $msg - return + set pch_error {} + } else { + fconfigure $fd_ph -blocking 0 } - fconfigure $fd_ph -blocking 0 } proc commit_stage2 {curHEAD msg} { @@ -798,13 +794,12 @@ proc commit_stage2 {curHEAD msg} { proc commit_stage3 {fd_wt curHEAD msg} { global single_commit gitdir HEAD PARENT commit_type - global commit_active ui_status_value ui_comm + global ui_status_value ui_comm global file_states gets $fd_wt tree_id if {$tree_id == {} || [catch {close $fd_wt} err]} { error_popup "write-tree failed:\n\n$err" - set commit_active 0 set ui_status_value {Commit failed.} unlock_index return @@ -825,7 +820,6 @@ proc commit_stage3 {fd_wt curHEAD msg} { close $fd_mh } err]} { error_popup "Loading MERGE_HEAD failed:\n\n$err" - set commit_active 0 set ui_status_value {Commit failed.} unlock_index return @@ -838,7 +832,6 @@ proc commit_stage3 {fd_wt curHEAD msg} { lappend cmd << $msg if {[catch {set cmt_id [eval exec $cmd]} err]} { error_popup "commit-tree failed:\n\n$err" - set commit_active 0 set ui_status_value {Commit failed.} unlock_index return @@ -859,7 +852,6 @@ proc commit_stage3 {fd_wt curHEAD msg} { set cmd [list git update-ref -m $reflogm HEAD $cmt_id $curHEAD] if {[catch {eval exec $cmd} err]} { error_popup "update-ref failed:\n\n$err" - set commit_active 0 set ui_status_value {Commit failed.} unlock_index return @@ -886,7 +878,6 @@ proc commit_stage3 {fd_wt curHEAD msg} { # -- Update status without invoking any git commands. # - set commit_active 0 set commit_type normal set HEAD $cmt_id set PARENT $cmt_id -- cgit v1.2.1 From c8ebafd84537473bb8a53880a6a6740d723b83bc Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sun, 12 Nov 2006 18:08:10 -0500 Subject: git-gui: Added post-commit invocation after the commit is done. Since git-commit.sh invokes hooks/post-commit after running git rerere we should do the same if its available and executable. Signed-off-by: Shawn O. Pearce --- git-gui | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 3ccf0a41d..7eeff9061 100755 --- a/git-gui +++ b/git-gui @@ -793,7 +793,7 @@ proc commit_stage2 {curHEAD msg} { } proc commit_stage3 {fd_wt curHEAD msg} { - global single_commit gitdir HEAD PARENT commit_type + global single_commit gitdir HEAD PARENT commit_type tcl_platform global ui_status_value ui_comm global file_states @@ -870,6 +870,21 @@ proc commit_stage3 {fd_wt curHEAD msg} { catch {exec git rerere} } + # -- Run the post-commit hook. + # + set pchook [file join $gitdir hooks post-commit] + if {$tcl_platform(platform) == {windows} && [file isfile $pchook]} { + set pchook [list sh -c [concat \ + "if test -x \"$pchook\";" \ + "then exec \"$pchook\";" \ + "fi"]] + } elseif {![file executable $pchook]} { + set pchook {} + } + if {$pchook != {}} { + catch {exec $pchook &} + } + $ui_comm delete 0.0 end $ui_comm edit modified false $ui_comm edit reset -- cgit v1.2.1 From 043f701116c30067c2a7096135b6e419dd1f7b47 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sun, 12 Nov 2006 18:16:45 -0500 Subject: git-gui: Always use eq/ne for string comparsions. This is one of those stupid Tcl mistakes that an experienced Tcl programmer just wouldn't make. We should always use eq and ne to compare string values (and never == or !=) as when we use ==/!= Tcl will attempt to convert either side to numeric if one of the two sides looks like a numeric. This could cause some trouble if a file named "1" exists and a different file named "1.0" also exists; their paths are equal according to == but not according to eq. Signed-off-by: Shawn O. Pearce --- git-gui | 140 ++++++++++++++++++++++++++++++++-------------------------------- 1 file changed, 70 insertions(+), 70 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 7eeff9061..05ef8e2e3 100755 --- a/git-gui +++ b/git-gui @@ -90,15 +90,15 @@ proc save_config {} { foreach name [array names default_config] { set value $global_config_new($name) - if {$value != $global_config($name)} { - if {$value == $default_config($name)} { + if {$value ne $global_config($name)} { + if {$value eq $default_config($name)} { catch {exec git repo-config --global --unset $name} } else { regsub -all "\[{}\]" $value {"} value exec git repo-config --global $name $value } set global_config($name) $value - if {$value == $repo_config($name)} { + if {$value eq $repo_config($name)} { catch {exec git repo-config --unset $name} set repo_config($name) $value } @@ -107,8 +107,8 @@ proc save_config {} { foreach name [array names default_config] { set value $repo_config_new($name) - if {$value != $repo_config($name)} { - if {$value == $global_config($name)} { + if {$value ne $repo_config($name)} { + if {$value eq $global_config($name)} { catch {exec git repo-config --unset $name} } else { regsub -all "\[{}\]" $value {"} value @@ -123,7 +123,7 @@ proc error_popup {msg} { global gitdir appname set title $appname - if {$gitdir != {}} { + if {$gitdir ne {}} { append title { (} append title [lindex \ [file split [file normalize [file dirname $gitdir]]] \ @@ -142,7 +142,7 @@ proc info_popup {msg} { global gitdir appname set title $appname - if {$gitdir != {}} { + if {$gitdir ne {}} { append title { (} append title [lindex \ [file split [file normalize [file dirname $gitdir]]] \ @@ -167,13 +167,13 @@ if { [catch {set cdup [exec git rev-parse --show-cdup]} err] error_popup "Cannot find the git directory:\n\n$err" exit 1 } -if {$cdup != ""} { +if {$cdup ne ""} { cd $cdup } unset cdup set single_commit 0 -if {$appname == {git-citool}} { +if {$appname eq {git-citool}} { set single_commit 1 } @@ -194,13 +194,13 @@ set commit_type {} proc lock_index {type} { global index_lock_type disable_on_lock - if {$index_lock_type == {none}} { + if {$index_lock_type eq {none}} { set index_lock_type $type foreach w $disable_on_lock { uplevel #0 $w disabled } return 1 - } elseif {$index_lock_type == {begin-update} && $type == {update}} { + } elseif {$index_lock_type eq {begin-update} && $type eq {update}} { set index_lock_type $type return 1 } @@ -242,9 +242,9 @@ proc update_status {{final Ready.}} { if {$status_active || ![lock_index read]} return repository_state new_HEAD new_type - if {$commit_type == {amend} - && $new_type == {normal} - && $new_HEAD == $HEAD} { + if {$commit_type eq {amend} + && $new_type eq {normal} + && $new_HEAD eq $HEAD} { } else { set HEAD $new_HEAD set PARENT $new_HEAD @@ -254,7 +254,7 @@ proc update_status {{final Ready.}} { array unset file_states if {![$ui_comm edit modified] - || [string trim [$ui_comm get 0.0 end]] == {}} { + || [string trim [$ui_comm get 0.0 end]] eq {}} { if {[load_message GITGUI_MSG]} { } elseif {[load_message MERGE_MSG]} { } elseif {[load_message SQUASH_MSG]} { @@ -263,7 +263,7 @@ proc update_status {{final Ready.}} { $ui_comm edit reset } - if {$repo_config(gui.trustmtime) == {true}} { + if {$repo_config(gui.trustmtime) eq {true}} { update_status_stage2 {} $final } else { set status_active 1 @@ -286,7 +286,7 @@ proc update_status_stage2 {fd final} { global status_active global buf_rdi buf_rdf buf_rlo - if {$fd != {}} { + if {$fd ne {}} { read $fd if {![eof $fd]} return close $fd @@ -442,7 +442,7 @@ proc clear_diff {} { proc reshow_diff {} { global ui_fname_value ui_status_value file_states - if {$ui_fname_value == {} + if {$ui_fname_value eq {} || [catch {set s $file_states($ui_fname_value)}]} { clear_diff } else { @@ -455,7 +455,7 @@ proc handle_empty_diff {} { set path $ui_fname_value set s $file_states($path) - if {[lindex $s 0] != {_M}} return + if {[lindex $s 0] ne {_M}} return info_popup "No differences detected. @@ -494,7 +494,7 @@ proc show_diff {path {w {}} {lno {}}} { if {$diff_active || ![lock_index read]} return clear_diff - if {$w == {} || $lno == {}} { + if {$w eq {} || $lno == {}} { foreach w [array names file_lists] { set lno [lsearch -sorted $file_lists($w) $path] if {$lno >= 0} { @@ -503,7 +503,7 @@ proc show_diff {path {w {}} {lno {}}} { } } } - if {$w != {} && $lno >= 1} { + if {$w ne {} && $lno >= 1} { $w tag add in_diff $lno.0 [expr $lno + 1].0 } @@ -604,8 +604,8 @@ proc read_diff {fd} { unlock_index set ui_status_value {Ready.} - if {$repo_config(gui.trustmtime) == {true} - && [$ui_diff index end] == {2.0}} { + if {$repo_config(gui.trustmtime) eq {true} + && [$ui_diff index end] eq {2.0}} { handle_empty_diff } } @@ -618,8 +618,8 @@ proc read_diff {fd} { proc load_last_commit {} { global HEAD PARENT commit_type ui_comm - if {$commit_type == {amend}} return - if {$commit_type != {normal}} { + if {$commit_type eq {amend}} return + if {$commit_type ne {normal}} { error_popup "Can't amend a $commit_type commit." return } @@ -671,10 +671,10 @@ proc commit_tree {} { # -- Our in memory state should match the repository. # repository_state curHEAD cur_type - if {$commit_type == {amend} - && $cur_type == {normal} - && $curHEAD == $HEAD} { - } elseif {$commit_type != $cur_type || $HEAD != $curHEAD} { + if {$commit_type eq {amend} + && $cur_type eq {normal} + && $curHEAD eq $HEAD} { + } elseif {$commit_type ne $cur_type || $HEAD ne $curHEAD} { error_popup {Last scanned state does not match repository state. Its highly likely that another Git program modified the @@ -725,7 +725,7 @@ You must include at least 1 file before you can commit. # -- A message is required. # set msg [string trim [$ui_comm get 1.0 end]] - if {$msg == {}} { + if {$msg eq {}} { error_popup {Please supply a commit message. A good commit message has the following format: @@ -741,7 +741,7 @@ A good commit message has the following format: # -- Ask the pre-commit hook for the go-ahead. # set pchook [file join $gitdir hooks pre-commit] - if {$tcl_platform(platform) == {windows} && [file isfile $pchook]} { + if {$tcl_platform(platform) eq {windows} && [file isfile $pchook]} { set pchook [list sh -c [concat \ "if test -x \"$pchook\";" \ "then exec \"$pchook\" 2>&1;" \ @@ -751,7 +751,7 @@ A good commit message has the following format: } else { set pchook {} } - if {$pchook != {}} { + if {$pchook ne {}} { set ui_status_value {Calling pre-commit hook...} set pch_error {} set fd_ph [open "| $pchook" r] @@ -798,7 +798,7 @@ proc commit_stage3 {fd_wt curHEAD msg} { global file_states gets $fd_wt tree_id - if {$tree_id == {} || [catch {close $fd_wt} err]} { + if {$tree_id eq {} || [catch {close $fd_wt} err]} { error_popup "write-tree failed:\n\n$err" set ui_status_value {Commit failed.} unlock_index @@ -808,10 +808,10 @@ proc commit_stage3 {fd_wt curHEAD msg} { # -- Create the commit. # set cmd [list git commit-tree $tree_id] - if {$PARENT != {}} { + if {$PARENT ne {}} { lappend cmd -p $PARENT } - if {$commit_type == {merge}} { + if {$commit_type eq {merge}} { if {[catch { set fd_mh [open [file join $gitdir MERGE_HEAD] r] while {[gets $fd_mh merge_head] >= 0} { @@ -825,7 +825,7 @@ proc commit_stage3 {fd_wt curHEAD msg} { return } } - if {$PARENT == {}} { + if {$PARENT eq {}} { # git commit-tree writes to stderr during initial commit. lappend cmd 2>/dev/null } @@ -840,7 +840,7 @@ proc commit_stage3 {fd_wt curHEAD msg} { # -- Update the HEAD ref. # set reflogm commit - if {$commit_type != {normal}} { + if {$commit_type ne {normal}} { append reflogm " ($commit_type)" } set i [string first "\n" $msg] @@ -873,7 +873,7 @@ proc commit_stage3 {fd_wt curHEAD msg} { # -- Run the post-commit hook. # set pchook [file join $gitdir hooks post-commit] - if {$tcl_platform(platform) == {windows} && [file isfile $pchook]} { + if {$tcl_platform(platform) eq {windows} && [file isfile $pchook]} { set pchook [list sh -c [concat \ "if test -x \"$pchook\";" \ "then exec \"$pchook\";" \ @@ -881,7 +881,7 @@ proc commit_stage3 {fd_wt curHEAD msg} { } elseif {![file executable $pchook]} { set pchook {} } - if {$pchook != {}} { + if {$pchook ne {}} { catch {exec $pchook &} } @@ -906,7 +906,7 @@ proc commit_stage3 {fd_wt curHEAD msg} { D? {set m _[string index $m 1]} } - if {$m == {__}} { + if {$m eq {__}} { unset file_states($path) } else { lset file_states($path) 0 $m @@ -940,7 +940,7 @@ proc pull_remote {remote branch} { # -- Our in memory state should match the repository. # repository_state curHEAD cur_type - if {$commit_type != $cur_type || $HEAD != $curHEAD} { + if {$commit_type ne $cur_type || $HEAD ne $curHEAD} { error_popup {Last scanned state does not match repository state. Its highly likely that another Git program modified the @@ -969,7 +969,7 @@ Commit or throw away all changes before starting a pull operation. set w [new_console "pull $remote $branch" \ "Pulling new changes from branch $branch in $remote"] set cmd [list git pull] - if {$repo_config(gui.pullsummary) == {false}} { + if {$repo_config(gui.pullsummary) eq {false}} { lappend cmd --no-summary } lappend cmd $remote @@ -1059,15 +1059,15 @@ proc merge_state {path new_state} { set icon [lindex $info 1] } - if {$s0 == {_}} { + if {$s0 eq {_}} { set s0 [string index $state 0] - } elseif {$s0 == {*}} { + } elseif {$s0 eq {*}} { set s0 _ } - if {$s1 == {_}} { + if {$s1 eq {_}} { set s1 [string index $state 1] - } elseif {$s1 == {*}} { + } elseif {$s1 eq {*}} { set s1 _ } @@ -1087,7 +1087,7 @@ proc display_file {path state} { set old_w [mapcol $old_m $path] set new_icon [mapicon $new_m $path] - if {$new_w != $old_w} { + if {$new_w ne $old_w} { set lno [lsearch -sorted $file_lists($old_w) $path] if {$lno >= 0} { incr lno @@ -1107,7 +1107,7 @@ proc display_file {path state} { -image $new_icon $new_w insert $lno.1 "[escape_path $path]\n" $new_w conf -state disabled - } elseif {$new_icon != [mapicon $old_m $path]} { + } elseif {$new_icon ne [mapicon $old_m $path]} { $new_w conf -state normal $new_w image conf [lindex $s 1] -image $new_icon $new_w conf -state disabled @@ -1199,7 +1199,7 @@ proc write_update_index {fd pathList totalCnt batch} { puts -nonewline $fd $path puts -nonewline $fd "\0" display_file $path $new - if {$ui_fname_value == $path} { + if {$ui_fname_value eq $path} { show_diff $path } } @@ -1252,8 +1252,8 @@ proc populate_pull_menu {m} { foreach remote $all_remotes { set rb {} - if {[array get repo_config remote.$remote.url] != {}} { - if {[array get repo_config remote.$remote.fetch] != {}} { + if {[array get repo_config remote.$remote.url] ne {}} { + if {[array get repo_config remote.$remote.fetch] ne {}} { regexp {^([^:]+):} \ [lindex $repo_config(remote.$remote.fetch) 0] \ line rb @@ -1272,7 +1272,7 @@ proc populate_pull_menu {m} { set rb_short $rb regsub ^refs/heads/ $rb {} rb_short - if {$rb_short != {}} { + if {$rb_short ne {}} { $m add command \ -label "Branch $rb_short from $remote..." \ -command [list pull_remote $remote $rb] \ @@ -1384,7 +1384,7 @@ foreach i { if {$max_status_desc < [string length [lindex $i 3]]} { set max_status_desc [string length [lindex $i 3]] } - if {[lindex $i 1] == {i}} { + if {[lindex $i 1] eq {i}} { set all_cols([lindex $i 0]) $ui_index } else { set all_cols([lindex $i 0]) $ui_other @@ -1400,8 +1400,8 @@ unset filemask i proc is_MacOSX {} { global tcl_platform tk_library - if {$tcl_platform(platform) == {unix} - && $tcl_platform(os) == {Darwin} + if {$tcl_platform(platform) eq {unix} + && $tcl_platform(os) eq {Darwin} && [string match /Library/Frameworks/* $tk_library]} { return 1 } @@ -1543,7 +1543,7 @@ proc console_exec {w cmd {after {}}} { # -- Windows tosses the enviroment when we exec our child. # But most users need that so we have to relogin. :-( # - if {$tcl_platform(platform) == {windows}} { + if {$tcl_platform(platform) eq {windows}} { set cmd [list sh --login -c "cd \"[pwd]\" && [join $cmd { }]"] } @@ -1561,7 +1561,7 @@ proc console_read {w fd after} { global console_cr console_data set buf [read $fd] - if {$buf != {}} { + if {$buf ne {}} { if {![winfo exists $w]} {console_init $w} $w.m.t conf -state normal set c 0 @@ -1605,7 +1605,7 @@ proc console_read {w fd after} { } array unset console_cr $w array unset console_data $w - if {$after != {}} { + if {$after ne {}} { uplevel #0 $after $ok } return @@ -1624,12 +1624,12 @@ proc do_gitk {} { set ui_status_value $starting_gitk_msg after 10000 { - if {$ui_status_value == $starting_gitk_msg} { + if {$ui_status_value eq $starting_gitk_msg} { set ui_status_value {Ready.} } } - if {$tcl_platform(platform) == {windows}} { + if {$tcl_platform(platform) eq {windows}} { exec sh -c gitk & } else { exec gitk & @@ -1656,13 +1656,13 @@ proc do_quit {} { # set save [file join $gitdir GITGUI_MSG] set msg [string trim [$ui_comm get 0.0 end]] - if {[$ui_comm edit modified] && $msg != {}} { + if {[$ui_comm edit modified] && $msg ne {}} { catch { set fd [open $save w] puts $fd [string trim [$ui_comm get 0.0 end]] close $fd } - } elseif {$msg == {} && [file exists $save]} { + } elseif {$msg eq {} && [file exists $save]} { file delete $save } @@ -1675,7 +1675,7 @@ proc do_quit {} { if {[catch {set rc_geometry $repo_config(gui.geometry)}]} { set rc_geometry {} } - if {$cfg_geometry != $rc_geometry} { + if {$cfg_geometry ne $rc_geometry} { catch {exec git repo-config gui.geometry $cfg_geometry} } @@ -1702,7 +1702,7 @@ proc do_include_all {} { _D {lappend pathList $path} } } - if {$pathList == {}} { + if {$pathList eq {}} { unlock_index } else { update_index $pathList @@ -1714,7 +1714,7 @@ set GIT_COMMITTER_IDENT {} proc do_signoff {} { global ui_comm GIT_COMMITTER_IDENT - if {$GIT_COMMITTER_IDENT == {}} { + if {$GIT_COMMITTER_IDENT eq {}} { if {[catch {set me [exec git var GIT_COMMITTER_IDENT]} err]} { error_popup "Unable to obtain your identity:\n\n$err" return @@ -1728,9 +1728,9 @@ proc do_signoff {} { set sob "Signed-off-by: $GIT_COMMITTER_IDENT" set last [$ui_comm get {end -1c linestart} {end -1c}] - if {$last != $sob} { + if {$last ne $sob} { $ui_comm edit separator - if {$last != {} + if {$last ne {} && ![regexp {^[A-Z][A-Za-z]*-[A-Za-z-]+: *} $last]} { $ui_comm insert end "\n" } @@ -1888,7 +1888,7 @@ proc click {w x y shift wx wy} { set lno [lindex $pos 0] set col [lindex $pos 1] set path [lindex $file_lists($w) [expr $lno - 1]] - if {$path == {}} return + if {$path eq {}} return if {$col > 0 && $shift == 1} { show_diff $path $w $lno @@ -1902,7 +1902,7 @@ proc unclick {w x y} { set lno [lindex $pos 0] set col [lindex $pos 1] set path [lindex $file_lists($w) [expr $lno - 1]] - if {$path == {}} return + if {$path eq {}} return if {$col == 0} { update_index [list $path] @@ -1927,7 +1927,7 @@ font create font_diffbold set M1B M1 set M1T M1 -if {$tcl_platform(platform) == {windows}} { +if {$tcl_platform(platform) eq {windows}} { set M1B Control set M1T Ctrl } elseif {[is_MacOSX]} { -- cgit v1.2.1 From 2cbe5577a0e83ae7368eb2202ffe62c1d607b0bb Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sun, 12 Nov 2006 18:22:59 -0500 Subject: git-gui: Reshow diff if we sent the file to update-index. We can't ask the diff viewer to recompute the diff until after our update-index child process terminates, as the diff programs need to be able to read the updated index in order to generate the correct diff. This is actually why we prevent diffs from being generated while there is an update lock on the index, which is why we ignored our own show_diff invocation in the middle of the write_update_index event handler. So now we mark a flag if we identify that the file currently in the diff viewer was also sent to update-index; then later when the update-index process has terminated we update the diff viewer if the flag is true. Signed-off-by: Shawn O. Pearce --- git-gui | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 05ef8e2e3..fdb82812b 100755 --- a/git-gui +++ b/git-gui @@ -1143,11 +1143,12 @@ proc display_all_files {} { } proc update_index {pathList} { - global update_index_cp ui_status_value + global update_index_cp update_index_rsd ui_status_value if {![lock_index update]} return set update_index_cp 0 + set update_index_rsd 0 set totalCnt [llength $pathList] set batch [expr {int($totalCnt * .01) + 1}] if {$batch > 25} {set batch 25} @@ -1170,13 +1171,17 @@ proc update_index {pathList} { } proc write_update_index {fd pathList totalCnt batch} { - global update_index_cp ui_status_value + global update_index_cp update_index_rsd ui_status_value global file_states ui_fname_value if {$update_index_cp >= $totalCnt} { close $fd unlock_index - set ui_status_value {Ready.} + if {$update_index_rsd} { + show_diff $ui_fname_value + } else { + set ui_status_value {Ready.} + } return } @@ -1200,7 +1205,7 @@ proc write_update_index {fd pathList totalCnt batch} { puts -nonewline $fd "\0" display_file $path $new if {$ui_fname_value eq $path} { - show_diff $path + set update_index_rsd 1 } } -- cgit v1.2.1 From fd2656fdfe575b55424b672f8bc274bf86526b9e Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sun, 12 Nov 2006 18:51:38 -0500 Subject: git-gui: Cleanup diff construction code to prepare for more options. I'd like to allow the user to have more control over how we format the diff in the diff viewer; to that end we need to add additional options to the diff-index command line as we construct the command for execution. So cleanup the command handling code now to use lappend so we can come back and add in our additional options. Signed-off-by: Shawn O. Pearce --- git-gui | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index fdb82812b..ea71526e6 100755 --- a/git-gui +++ b/git-gui @@ -488,7 +488,7 @@ prevent possible confusion. proc show_diff {path {w {}} {lno {}}} { global file_states file_lists - global PARENT diff_3way diff_active + global PARENT diff_3way diff_active repo_config global ui_diff ui_fname_value ui_fstatus_value ui_status_value if {$diff_active || ![lock_index read]} return @@ -515,10 +515,13 @@ proc show_diff {path {w {}} {lno {}}} { set ui_fstatus_value [mapdesc $m $path] set ui_status_value "Loading diff of [escape_path $path]..." - set cmd [list | git diff-index -p $PARENT -- $path] + set cmd [list | git diff-index] + lappend cmd --no-color + lappend cmd -p + switch $m { MM { - set cmd [list | git diff-index -p -c $PARENT $path] + lappend cmd -c } _O { if {[catch { @@ -542,6 +545,10 @@ proc show_diff {path {w {}} {lno {}}} { } } + lappend cmd $PARENT + lappend cmd -- + lappend cmd $path + if {[catch {set fd [open $cmd r]} err]} { set diff_active 0 unlock_index @@ -1178,7 +1185,7 @@ proc write_update_index {fd pathList totalCnt batch} { close $fd unlock_index if {$update_index_rsd} { - show_diff $ui_fname_value + reshow_diff } else { set ui_status_value {Ready.} } -- cgit v1.2.1 From 358d8de8f3b9d09c9c4d7d43c03d33a4f60ba1da Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sun, 12 Nov 2006 19:20:02 -0500 Subject: git-gui: Allow the user to control the number of context lines in a diff. When displaying a diff the Git default of 3 line of context may not be enough for a user to see what has actually changed. Consequently we set our own program default to 5 lines of context and then allow the user to adjust this on a per-repository and global level through our options dialog. Signed-off-by: Shawn O. Pearce --- git-gui | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 55 insertions(+), 11 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index ea71526e6..3f74fbb07 100755 --- a/git-gui +++ b/git-gui @@ -517,6 +517,9 @@ proc show_diff {path {w {}} {lno {}}} { set cmd [list | git diff-index] lappend cmd --no-color + if {$repo_config(gui.diffcontext) > 0} { + lappend cmd "-U$repo_config(gui.diffcontext)" + } lappend cmd -p switch $m { @@ -1765,12 +1768,18 @@ proc do_options {} { global repo_config global_config global repo_config_new global_config_new - load_config 1 array unset repo_config_new array unset global_config_new foreach name [array names repo_config] { set repo_config_new($name) $repo_config($name) } + load_config 1 + foreach name [array names repo_config] { + switch -- $name { + gui.diffcontext {continue} + } + set repo_config_new($name) $repo_config($name) + } foreach name [array names global_config] { set global_config_new($name) $global_config($name) } @@ -1811,18 +1820,36 @@ proc do_options {} { pack $w.global -side right -fill both -expand 1 -pady 5 -padx 5 foreach option { - {pullsummary {Show Pull Summary}} - {trustmtime {Trust File Modification Timestamps}} + {b pullsummary {Show Pull Summary}} + {b trustmtime {Trust File Modification Timestamps}} + {i diffcontext {Number of Diff Context Lines}} } { - set name [lindex $option 0] - set text [lindex $option 1] + set type [lindex $option 0] + set name [lindex $option 1] + set text [lindex $option 2] foreach f {repo global} { - checkbutton $w.$f.$name -text $text \ - -variable ${f}_config_new(gui.$name) \ - -onvalue true \ - -offvalue false \ - -font font_ui - pack $w.$f.$name -side top -anchor w + switch $type { + b { + checkbutton $w.$f.$name -text $text \ + -variable ${f}_config_new(gui.$name) \ + -onvalue true \ + -offvalue false \ + -font font_ui + pack $w.$f.$name -side top -anchor w + } + i { + frame $w.$f.$name + label $w.$f.$name.l -text "$text:" -font font_ui + pack $w.$f.$name.l -side left -anchor w -fill x + spinbox $w.$f.$name.v \ + -textvariable ${f}_config_new(gui.$name) \ + -from 1 -to 99 -increment 1 \ + -width 3 \ + -font font_ui + pack $w.$f.$name.v -side right -anchor e + pack $w.$f.$name -side top -anchor w -fill x + } + } } } @@ -1888,6 +1915,7 @@ proc do_save_config {w} { if {[catch {save_config} err]} { error_popup "Failed to completely save options:\n\n$err" } + reshow_diff destroy $w } @@ -1969,6 +1997,7 @@ proc apply_config {} { set default_config(gui.trustmtime) false set default_config(gui.pullsummary) true +set default_config(gui.diffcontext) 5 set default_config(gui.fontui) [font configure font_ui] set default_config(gui.fontdiff) [font configure font_diff] set font_descs { @@ -2318,6 +2347,21 @@ $ui_diff.ctxm add command -label "Decrease Font Size" \ $ui_diff.ctxm add command -label "Increase Font Size" \ -font font_ui \ -command {incr_font_size font_diff 1} +$ui_diff.ctxm add separator +$ui_diff.ctxm add command -label "Show Less Context" \ + -font font_ui \ + -command {if {$ui_fname_value ne {} + && $repo_config(gui.diffcontext) >= 2} { + incr repo_config(gui.diffcontext) -1 + reshow_diff + }} +$ui_diff.ctxm add command -label "Show More Context" \ + -font font_ui \ + -command {if {$ui_fname_value ne {}} { + incr repo_config(gui.diffcontext) + reshow_diff + }} +$ui_diff.ctxm add separator $ui_diff.ctxm add command -label {Options...} \ -font font_ui \ -command do_options -- cgit v1.2.1 From aaf1085a03a53eacff1b26459d0281a133f573d5 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sun, 12 Nov 2006 19:29:04 -0500 Subject: git-gui: Sort the list of paths being updated in the index. Its a little surprising to see the UI update the icons for files in random order, due to the fact that the files are updating in the order they appear within the array (which is based on a hash function and not order). So sort the list of files before we send any to update-index so the order of operation is means something to the user. Signed-off-by: Shawn O. Pearce --- git-gui | 1 + 1 file changed, 1 insertion(+) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 3f74fbb07..b1a90e666 100755 --- a/git-gui +++ b/git-gui @@ -1159,6 +1159,7 @@ proc update_index {pathList} { set update_index_cp 0 set update_index_rsd 0 + set pathList [lsort $pathList] set totalCnt [llength $pathList] set batch [expr {int($totalCnt * .01) + 1}] if {$batch > 25} {set batch 25} -- cgit v1.2.1 From 7f09cfafa8acf507f3a1358e05002e566f41783f Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sun, 12 Nov 2006 19:33:33 -0500 Subject: git-gui: Use a smaller pipe buffer for update-index. When we shove a large number of files at update-index and they have very short path names we are likely going to fit a large number of them into the pipe buffer very early; thereby seeing a huge progress update followed by lots of waiting between progress updates due to the latency of update-index. Using a smaller buffer should help smooth out the progress updates as we are better able to keep tabs on the update-index process' progress through our list of paths. Signed-off-by: Shawn O. Pearce --- git-gui | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index b1a90e666..7e28328cf 100755 --- a/git-gui +++ b/git-gui @@ -1171,7 +1171,11 @@ proc update_index {pathList} { $totalCnt \ 0.0] set fd [open "| git update-index --add --remove -z --stdin" w] - fconfigure $fd -blocking 0 -translation binary + fconfigure $fd \ + -blocking 0 \ + -buffering full \ + -buffersize 512 \ + -translation binary fileevent $fd writable [list \ write_update_index \ $fd \ -- cgit v1.2.1 From c11b5f20d3bc2e8bc4fcd965b16e1575b87c0d5f Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sun, 12 Nov 2006 21:11:12 -0500 Subject: git-gui: Allow the user to copy name of the file in the diff viewer. There's a lot of reasons why the user might need to obtain the complete (or just part of) path of a file which they are currently viewing in the diff viewer pane. So now we allow selection on this widget by using a text widget instead of a label. We also offer a context menu which has actions for copying the selection or the entire value onto the clipboard. Signed-off-by: Shawn O. Pearce --- git-gui | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 7e28328cf..1e5b0d049 100755 --- a/git-gui +++ b/git-gui @@ -511,7 +511,7 @@ proc show_diff {path {w {}} {lno {}}} { set m [lindex $s 0] set diff_3way 0 set diff_active 1 - set ui_fname_value [escape_path $path] + set ui_fname_value $path set ui_fstatus_value [mapdesc $m $path] set ui_status_value "Loading diff of [escape_path $path]..." @@ -2284,11 +2284,33 @@ frame .vpane.lower.diff.header -background orange label .vpane.lower.diff.header.l1 -text {File:} \ -background orange \ -font font_ui -label .vpane.lower.diff.header.l2 -textvariable ui_fname_value \ +set ui_fname .vpane.lower.diff.header.l2 +text $ui_fname \ -background orange \ - -anchor w \ - -justify left \ + -height 1 \ + -relief flat \ + -state disabled \ -font font_ui +menu $ui_fname.ctxm -tearoff 0 +$ui_fname.ctxm add command -label "Copy Only Selection" \ + -font font_ui \ + -command "tk_textCopy $ui_fname" +$ui_fname.ctxm add command -label "Copy Complete Name" \ + -font font_ui \ + -command " + $ui_fname tag add sel 0.0 {end -1c} + tk_textCopy $ui_fname + $ui_fname tag remove sel 0.0 end + " +bind_button3 $ui_fname "tk_popup $ui_fname.ctxm %X %Y" +trace add variable ui_fname_value write $ui_fname.update +proc $ui_fname.update {varname args} { + global ui_fname ui_fname_value + $ui_fname configure -state normal + $ui_fname delete 0.0 end + $ui_fname insert end [escape_path $ui_fname_value] + $ui_fname configure -state disabled +} label .vpane.lower.diff.header.l3 -text {Status:} \ -background orange \ -font font_ui -- cgit v1.2.1 From 135f76ed996b6a0478831c561e1cddd249b7e19d Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sun, 12 Nov 2006 21:49:49 -0500 Subject: git-gui: Correct language for M_/A_ status codes. When I changed from 'check in' to 'include' I missed the human friendly status displayed in the right side of the diff viewer heading. It was still reporting 'Checked in' for a fully included file, which is not what we wanted it to say. Signed-off-by: Shawn O. Pearce --- git-gui | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 1e5b0d049..907db0e9d 100755 --- a/git-gui +++ b/git-gui @@ -1385,17 +1385,17 @@ set max_status_desc 0 foreach i { {__ i plain "Unmodified"} {_M i mod "Modified"} - {M_ i fulltick "Checked in"} + {M_ i fulltick "Included in commit"} {MM i parttick "Partially included"} {_O o plain "Untracked"} - {A_ o fulltick "Added"} + {A_ o fulltick "Added by commit"} {AM o parttick "Partially added"} {AD o question "Added (but now gone)"} {_D i question "Missing"} - {D_ i removed "Removed"} - {DD i removed "Removed"} + {D_ i removed "Removed by commit"} + {DD i removed "Removed by commit"} {DO i removed "Removed (still exists)"} {UM i merge "Merge conflicts"} -- cgit v1.2.1 From 3e7b0e1d0ae509a54ca61c2b4c4990c8e6f0b2c0 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sun, 12 Nov 2006 22:06:37 -0500 Subject: git-gui: Display status on left in diff header. Because the Tk pack layout manager gives all space to the right/bottom most widget during expand/contract of the frame we were adding and removing all space from the status area of the bar and not from the file name, which is what we actually wanted. A simple enough fix is to just put the status of the given file on the left side of the diff viewer header rather than on the right. Signed-off-by: Shawn O. Pearce --- git-gui | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 907db0e9d..00b6cdf28 100755 --- a/git-gui +++ b/git-gui @@ -2281,6 +2281,13 @@ bind_button3 $ui_comm "tk_popup $ui_comm.ctxm %X %Y" set ui_fname_value {} set ui_fstatus_value {} frame .vpane.lower.diff.header -background orange +label .vpane.lower.diff.header.l4 \ + -textvariable ui_fstatus_value \ + -background orange \ + -width $max_status_desc \ + -anchor w \ + -justify left \ + -font font_ui label .vpane.lower.diff.header.l1 -text {File:} \ -background orange \ -font font_ui @@ -2288,6 +2295,7 @@ set ui_fname .vpane.lower.diff.header.l2 text $ui_fname \ -background orange \ -height 1 \ + -wrap none \ -relief flat \ -state disabled \ -font font_ui @@ -2311,19 +2319,9 @@ proc $ui_fname.update {varname args} { $ui_fname insert end [escape_path $ui_fname_value] $ui_fname configure -state disabled } -label .vpane.lower.diff.header.l3 -text {Status:} \ - -background orange \ - -font font_ui -label .vpane.lower.diff.header.l4 -textvariable ui_fstatus_value \ - -background orange \ - -width $max_status_desc \ - -anchor w \ - -justify left \ - -font font_ui +pack .vpane.lower.diff.header.l4 -side left pack .vpane.lower.diff.header.l1 -side left -pack .vpane.lower.diff.header.l2 -side left -fill x -pack .vpane.lower.diff.header.l4 -side right -pack .vpane.lower.diff.header.l3 -side right +pack $ui_fname -fill x # -- Diff Body frame .vpane.lower.diff.body -- cgit v1.2.1 From 1e5c18fb431c2d2493996e24ea68408e59ef6c16 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sun, 12 Nov 2006 22:41:34 -0500 Subject: git-gui: Minor UI layout improvements for console windows. Moved the Close button over to the lower right corner where our Cancel/Save buttons are in the options dialog. This should fit better with our own look and feel as well as that of most apps on Mac OS X and Windows. Also set the lower status bar in a console window to indicate the process is working and that the user should wait for it to finish. Signed-off-by: Shawn O. Pearce --- git-gui | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 00b6cdf28..fbbc0caaa 100755 --- a/git-gui +++ b/git-gui @@ -1478,7 +1478,7 @@ proc hook_failed_popup {hook msg} { -width 15 \ -font font_ui \ -command "destroy $w" - pack $w.ok -side bottom + pack $w.ok -side bottom -anchor e -pady 10 -padx 10 bind $w "grab $w; focus $w" bind $w "destroy $w" @@ -1515,7 +1515,8 @@ proc console_init {w} { -font font_diff \ -state disabled \ -yscrollcommand [list $w.m.sby set] - label $w.m.s -anchor w \ + label $w.m.s -text {Working... please wait...} \ + -anchor w \ -justify left \ -font font_uibold scrollbar $w.m.sby -command [list $w.m.t yview] @@ -1540,12 +1541,11 @@ proc console_init {w} { $w.m.t tag remove sel 0.0 end " - button $w.ok -text {Running...} \ - -width 15 \ + button $w.ok -text {Close} \ -font font_ui \ -state disabled \ -command "destroy $w" - pack $w.ok -side bottom + pack $w.ok -side bottom -anchor e -pady 10 -padx 10 bind_button3 $w.m.t "tk_popup $w.ctxm %X %Y" bind $w.m.t <$M1B-Key-a> "$w.m.t tag add sel 0.0 end;break" @@ -1614,12 +1614,10 @@ proc console_read {w fd after} { if {[catch {close $fd}]} { if {![winfo exists $w]} {console_init $w} $w.m.s conf -background red -text {Error: Command Failed} - $w.ok conf -text Close $w.ok conf -state normal set ok 0 } elseif {[winfo exists $w]} { $w.m.s conf -background green -text {Success} - $w.ok conf -text Close $w.ok conf -state normal set ok 1 } -- cgit v1.2.1 From fce89e466ae75961018ab88fec7000568f981d46 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Mon, 13 Nov 2006 00:48:44 -0500 Subject: git-gui: Reverted file name text field to a label. So although a text field with a flat relief looks like a label on Windows it doesn't on Mac OS X. The Aqua version of Tk is still drawing a border around the text field and that makes the diff pane header look pretty ugly. Earlier I had made the file name area into a text widget so the user could highlight parts of it and copy them onto the clipboard; but with the context menu being present this isn't quite as necessary as the user can copy the file name to the clipboard using that instead. So although this is a small loss in functionality for non-Mac OS X systems I think it is still reasonable. Signed-off-by: Shawn O. Pearce --- git-gui | 34 ++++++++++++---------------------- 1 file changed, 12 insertions(+), 22 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index fbbc0caaa..ca7f8dbc4 100755 --- a/git-gui +++ b/git-gui @@ -2290,33 +2290,23 @@ label .vpane.lower.diff.header.l1 -text {File:} \ -background orange \ -font font_ui set ui_fname .vpane.lower.diff.header.l2 -text $ui_fname \ +label $ui_fname \ + -textvariable ui_fname_value \ -background orange \ - -height 1 \ - -wrap none \ - -relief flat \ - -state disabled \ + -anchor w \ + -justify left \ -font font_ui menu $ui_fname.ctxm -tearoff 0 -$ui_fname.ctxm add command -label "Copy Only Selection" \ +$ui_fname.ctxm add command -label "Copy" \ -font font_ui \ - -command "tk_textCopy $ui_fname" -$ui_fname.ctxm add command -label "Copy Complete Name" \ - -font font_ui \ - -command " - $ui_fname tag add sel 0.0 {end -1c} - tk_textCopy $ui_fname - $ui_fname tag remove sel 0.0 end - " + -command { + clipboard clear + clipboard append \ + -format STRING \ + -type STRING \ + -- $ui_fname_value + } bind_button3 $ui_fname "tk_popup $ui_fname.ctxm %X %Y" -trace add variable ui_fname_value write $ui_fname.update -proc $ui_fname.update {varname args} { - global ui_fname ui_fname_value - $ui_fname configure -state normal - $ui_fname delete 0.0 end - $ui_fname insert end [escape_path $ui_fname_value] - $ui_fname configure -state disabled -} pack .vpane.lower.diff.header.l4 -side left pack .vpane.lower.diff.header.l1 -side left pack $ui_fname -fill x -- cgit v1.2.1 From f7f8d32226595c22cb4f28f8e9e139cf42e1e640 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Mon, 13 Nov 2006 04:22:42 -0500 Subject: git-gui: By default don't allow partially included files. The concept of the Git index is confusing for many users, especially those who are newer to Git. Since git-gui is (at least partially) intended to be used by newer users who don't need the complexity of the index to be put in front of them early on, we should hide it by making any partially included file fully included as soon as we identify it. To do this we just run a quick update_index pass on any file which differs both in the index and the working directory, as these files have already been at least partially included by the user. A new option has been added in the options dialog (gui.partialinclude) which lets the user enable accessing the index from git-gui. This just disables the automatic update_index pass on partially included files. Signed-off-by: Shawn O. Pearce --- git-gui | 36 +++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index ca7f8dbc4..3e3a53532 100755 --- a/git-gui +++ b/git-gui @@ -406,19 +406,33 @@ proc read_ls_others {fd final} { proc status_eof {fd buf final} { global status_active ui_status_value + global file_states repo_config upvar $buf to_clear - if {[eof $fd]} { - set to_clear {} - close $fd + if {![eof $fd]} return + set to_clear {} + close $fd + if {[incr status_active -1] > 0} return - if {[incr status_active -1] == 0} { - display_all_files - unlock_index - reshow_diff - set ui_status_value $final + unlock_index + display_all_files + + if {$repo_config(gui.partialinclude) ne {true}} { + set pathList [list] + foreach path [array names file_states] { + switch -- [lindex $file_states($path) 0] { + AM - + MM {lappend pathList $path} + } + } + if {$pathList ne {}} { + update_index $pathList + return } } + + reshow_diff + set ui_status_value $final } ###################################################################### @@ -1164,7 +1178,6 @@ proc update_index {pathList} { set batch [expr {int($totalCnt * .01) + 1}] if {$batch > 25} {set batch 25} - set ui_status_value "Including files ... 0/$totalCnt 0%" set ui_status_value [format \ "Including files ... %i/%i files (%.2f%%)" \ $update_index_cp \ @@ -1192,10 +1205,9 @@ proc write_update_index {fd pathList totalCnt batch} { if {$update_index_cp >= $totalCnt} { close $fd unlock_index + set ui_status_value {Ready.} if {$update_index_rsd} { reshow_diff - } else { - set ui_status_value {Ready.} } return } @@ -1823,6 +1835,7 @@ proc do_options {} { pack $w.global -side right -fill both -expand 1 -pady 5 -padx 5 foreach option { + {b partialinclude {Allow Partially Included Files}} {b pullsummary {Show Pull Summary}} {b trustmtime {Trust File Modification Timestamps}} {i diffcontext {Number of Diff Context Lines}} @@ -2000,6 +2013,7 @@ proc apply_config {} { set default_config(gui.trustmtime) false set default_config(gui.pullsummary) true +set default_config(gui.partialinclude) false set default_config(gui.diffcontext) 5 set default_config(gui.fontui) [font configure font_ui] set default_config(gui.fontdiff) [font configure font_diff] -- cgit v1.2.1 From 7d0d289e457eb643b8638b6385a0ce056f1f5a97 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Mon, 13 Nov 2006 14:25:53 -0500 Subject: git-gui: Refactor mouse clicking on file names/icons. I'm not a huge fan of putting the left and right mouse actions into the same procedure. Originally this is how Paul had implemented the logic in gitool and I had carried some of that over into git-gui, but now that I'm getting ready to implement right mouse click features to act on files I really should split this apart. Signed-off-by: Shawn O. Pearce --- git-gui | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 3e3a53532..b8ebe3177 100755 --- a/git-gui +++ b/git-gui @@ -1935,10 +1935,8 @@ proc do_save_config {w} { destroy $w } -# shift == 1: left click -# 3: right click -proc click {w x y shift wx wy} { - global ui_index ui_other file_lists +proc file_left_click {w x y} { + global file_lists set pos [split [$w index @$x,$y] .] set lno [lindex $pos 0] @@ -1946,12 +1944,12 @@ proc click {w x y shift wx wy} { set path [lindex $file_lists($w) [expr $lno - 1]] if {$path eq {}} return - if {$col > 0 && $shift == 1} { + if {$col > 0} { show_diff $path $w $lno } } -proc unclick {w x y} { +proc file_left_unclick {w x y} { global file_lists set pos [split [$w index @$x,$y] .] @@ -2457,9 +2455,8 @@ bind all <$M1B-Key-Q> do_quit bind all <$M1B-Key-w> {destroy [winfo toplevel %W]} bind all <$M1B-Key-W> {destroy [winfo toplevel %W]} foreach i [list $ui_index $ui_other] { - bind $i {click %W %x %y 1 %X %Y; break} - bind $i {unclick %W %x %y; break} - bind_button3 $i {click %W %x %y 3 %X %Y; break} + bind $i {file_left_click %W %x %y; break} + bind $i {file_left_unclick %W %x %y; break} } unset i -- cgit v1.2.1 From a37eee4406ff965fda4d234759aa58526657cbe3 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Mon, 13 Nov 2006 14:37:41 -0500 Subject: git-gui: Narrow the no differences information message. On Mac OS X the no differences informational message was linewrapped at the wrong points due to the limited width of the system dialog, yet the LFs embedded in the message (where I linewrapped it manually) were also being honored. This resulted in a very difficult to read paragraph of text. So this narrows the text down by another 10 columns or so, making it more readable. Signed-off-by: Shawn O. Pearce --- git-gui | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index b8ebe3177..6b8d25e9a 100755 --- a/git-gui +++ b/git-gui @@ -475,13 +475,15 @@ proc handle_empty_diff {} { [short_path $path] has no changes. -The modification date of this file was updated by another -application and you currently have the Trust File Modification -Timestamps option enabled, so Git did not automatically detect -that there are no content differences in this file. - -This file will now be removed from the modified files list, to -prevent possible confusion. +The modification date of this file was updated +by another application and you currently have +the Trust File Modification Timestamps option +enabled, so Git did not automatically detect +that there are no content differences in this +file. + +This file will now be removed from the modified +files list, to prevent possible confusion. " if {[catch {exec git update-index -- $path} err]} { error_popup "Failed to refresh index:\n\n$err" -- cgit v1.2.1 From 24263b77165edfd438045ed3c25ec6669b3e76d4 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Mon, 13 Nov 2006 16:06:38 -0500 Subject: git-gui: Implemented multiple selection in file lists. Because I want to let users apply actions to more than one file at a time we really needed a concept of "the current selection" from the two file lists. Since I'm abusing a Tk text widget for the file displays I can't really use the Tk selection to track which files are picked and which aren't. So instead we keep this in an array to tell us which paths are currently selected and we use an inverse fg/bg for the selected file display. This is common most operating systems as a selection indicator. The selection works like most users would expect; single click will clear the selection and pick only that file, M1-click (aka Ctrl-click or Cmd-click) will toggle the one file in/out of the selection, and Shift-click will select the range between the last clicked file and the currently clicked file. Signed-off-by: Shawn O. Pearce --- git-gui | 136 ++++++++++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 111 insertions(+), 25 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 6b8d25e9a..a60bf1c8a 100755 --- a/git-gui +++ b/git-gui @@ -183,6 +183,7 @@ if {$appname eq {git-citool}} { set status_active 0 set diff_active 0 +set last_clicked {} set disable_on_lock [list] set index_lock_type none @@ -351,7 +352,7 @@ proc read_diff_index {fd final} { incr z2 -1 display_file \ [string range $buf_rdi $z1 $z2] \ - [string index $buf_rdi [expr $z1 - 2]]_ + [string index $buf_rdi [expr {$z1 - 2}]]_ incr c } if {$c < $n} { @@ -380,7 +381,7 @@ proc read_diff_files {fd final} { incr z2 -1 display_file \ [string range $buf_rdf $z1 $z2] \ - _[string index $buf_rdf [expr $z1 - 2]] + _[string index $buf_rdf [expr {$z1 - 2}]] incr c } if {$c < $n} { @@ -414,6 +415,7 @@ proc status_eof {fd buf final} { close $fd if {[incr status_active -1] > 0} return + prune_selection unlock_index display_all_files @@ -435,6 +437,16 @@ proc status_eof {fd buf final} { set ui_status_value $final } +proc prune_selection {} { + global file_states selected_paths + + foreach path [array names selected_paths] { + if {[catch {set still_here $file_states($path)}]} { + unset selected_paths($path) + } + } +} + ###################################################################### ## ## diff @@ -497,7 +509,7 @@ files list, to prevent possible confusion. [lreplace $file_lists($old_w) $lno $lno] incr lno $old_w conf -state normal - $old_w delete $lno.0 [expr $lno + 1].0 + $old_w delete $lno.0 [expr {$lno + 1}].0 $old_w conf -state disabled } } @@ -520,7 +532,7 @@ proc show_diff {path {w {}} {lno {}}} { } } if {$w ne {} && $lno >= 1} { - $w tag add in_diff $lno.0 [expr $lno + 1].0 + $w tag add in_diff $lno.0 [expr {$lno + 1}].0 } set s $file_states($path) @@ -821,7 +833,7 @@ proc commit_stage2 {curHEAD msg} { proc commit_stage3 {fd_wt curHEAD msg} { global single_commit gitdir HEAD PARENT commit_type tcl_platform global ui_status_value ui_comm - global file_states + global file_states selected_paths gets $fd_wt tree_id if {$tree_id eq {} || [catch {close $fd_wt} err]} { @@ -871,7 +883,7 @@ proc commit_stage3 {fd_wt curHEAD msg} { } set i [string first "\n" $msg] if {$i >= 0} { - append reflogm {: } [string range $msg 0 [expr $i - 1]] + append reflogm {: } [string range $msg 0 [expr {$i - 1}]] } else { append reflogm {: } $msg } @@ -934,6 +946,7 @@ proc commit_stage3 {fd_wt curHEAD msg} { if {$m eq {__}} { unset file_states($path) + catch {unset selected_paths($path)} } else { lset file_states($path) 0 $m } @@ -1102,7 +1115,7 @@ proc merge_state {path new_state} { } proc display_file {path state} { - global file_states file_lists status_active + global file_states file_lists selected_paths status_active set old_m [merge_state $path $state] if {$status_active} return @@ -1118,7 +1131,7 @@ proc display_file {path state} { if {$lno >= 0} { incr lno $old_w conf -state normal - $old_w delete $lno.0 [expr $lno + 1].0 + $old_w delete $lno.0 [expr {$lno + 1}].0 $old_w conf -state disabled } @@ -1132,6 +1145,12 @@ proc display_file {path state} { -name [lindex $s 1] \ -image $new_icon $new_w insert $lno.1 "[escape_path $path]\n" + if {[catch {set in_sel $selected_paths($path)}]} { + set in_sel 0 + } + if {$in_sel} { + $new_w tag add in_sel $lno.0 [expr {$lno + 1}].0 + } $new_w conf -state disabled } elseif {$new_icon ne [mapicon $old_m $path]} { $new_w conf -state normal @@ -1141,13 +1160,16 @@ proc display_file {path state} { } proc display_all_files {} { - global ui_index ui_other file_states file_lists + global ui_index ui_other + global file_states file_lists + global last_clicked selected_paths $ui_index conf -state normal $ui_other conf -state normal $ui_index delete 0.0 end $ui_other delete 0.0 end + set last_clicked {} set file_lists($ui_index) [list] set file_lists($ui_other) [list] @@ -1157,11 +1179,18 @@ proc display_all_files {} { set m [lindex $s 0] set w [mapcol $m $path] lappend file_lists($w) $path + set lno [expr {[lindex [split [$w index end] .] 0] - 1}] $w image create end \ -align center -padx 5 -pady 1 \ -name [lindex $s 1] \ -image [mapicon $m $path] $w insert end "[escape_path $path]\n" + if {[catch {set in_sel $selected_paths($path)}]} { + set in_sel 0 + } + if {$in_sel} { + $w tag add in_sel $lno.0 [expr {$lno + 1}].0 + } } $ui_index conf -state disabled @@ -1603,8 +1632,8 @@ proc console_read {w fd after} { while {$c < $n} { set cr [string first "\r" $buf $c] set lf [string first "\n" $buf $c] - if {$cr < 0} {set cr [expr $n + 1]} - if {$lf < 0} {set lf [expr $n + 1]} + if {$cr < 0} {set cr [expr {$n + 1}]} + if {$lf < 0} {set lf [expr {$n + 1}]} if {$lf < $cr} { $w.m.t insert end [string range $buf $c $lf] @@ -1937,32 +1966,83 @@ proc do_save_config {w} { destroy $w } -proc file_left_click {w x y} { - global file_lists +proc toggle_or_diff {w x y} { + global file_lists ui_index ui_other + global last_clicked selected_paths set pos [split [$w index @$x,$y] .] set lno [lindex $pos 0] set col [lindex $pos 1] - set path [lindex $file_lists($w) [expr $lno - 1]] - if {$path eq {}} return + set path [lindex $file_lists($w) [expr {$lno - 1}]] + if {$path eq {}} { + set last_clicked {} + return + } + + set last_clicked [list $w $lno] + array unset selected_paths + $ui_index tag remove in_sel 0.0 end + $ui_other tag remove in_sel 0.0 end - if {$col > 0} { + if {$col == 0} { + update_index [list $path] + } else { show_diff $path $w $lno } } -proc file_left_unclick {w x y} { +proc add_one_to_selection {w x y} { global file_lists + global last_clicked selected_paths set pos [split [$w index @$x,$y] .] set lno [lindex $pos 0] set col [lindex $pos 1] - set path [lindex $file_lists($w) [expr $lno - 1]] - if {$path eq {}} return + set path [lindex $file_lists($w) [expr {$lno - 1}]] + if {$path eq {}} { + set last_clicked {} + return + } - if {$col == 0} { - update_index [list $path] + set last_clicked [list $w $lno] + if {[catch {set in_sel $selected_paths($path)}]} { + set in_sel 0 + } + if {$in_sel} { + unset selected_paths($path) + $w tag remove in_sel $lno.0 [expr {$lno + 1}].0 + } else { + set selected_paths($path) 1 + $w tag add in_sel $lno.0 [expr {$lno + 1}].0 + } +} + +proc add_range_to_selection {w x y} { + global file_lists + global last_clicked selected_paths + + if {[lindex $last_clicked 0] ne $w} { + toggle_or_diff $w $x $y + return } + + set pos [split [$w index @$x,$y] .] + set lno [lindex $pos 0] + set lc [lindex $last_clicked 1] + if {$lc < $lno} { + set begin $lc + set end $lno + } else { + set begin $lno + set end $lc + } + + foreach path [lrange $file_lists($w) \ + [expr {$begin - 1}] \ + [expr {$end - 1}]] { + set selected_paths($path) 1 + } + $w tag add in_sel $begin.0 [expr {$end + 1}].0 } ###################################################################### @@ -2174,8 +2254,13 @@ pack .vpane.files.other.sb -side right -fill y pack $ui_other -side left -fill both -expand 1 .vpane.files add .vpane.files.other -sticky nsew -$ui_index tag conf in_diff -font font_uibold -$ui_other tag conf in_diff -font font_uibold +foreach i [list $ui_index $ui_other] { + $i tag conf in_diff -font font_uibold + $i tag conf in_sel \ + -background [$i cget -foreground] \ + -foreground [$i cget -background] +} +unset i # -- Diff and Commit Area frame .vpane.lower -height 300 -width 400 @@ -2457,8 +2542,9 @@ bind all <$M1B-Key-Q> do_quit bind all <$M1B-Key-w> {destroy [winfo toplevel %W]} bind all <$M1B-Key-W> {destroy [winfo toplevel %W]} foreach i [list $ui_index $ui_other] { - bind $i {file_left_click %W %x %y; break} - bind $i {file_left_unclick %W %x %y; break} + bind $i "toggle_or_diff $i %x %y; break" + bind $i <$M1B-Button-1> "add_one_to_selection $i %x %y; break" + bind $i "add_range_to_selection $i %x %y; break" } unset i -- cgit v1.2.1 From 99058720df7981aaaaf64e9a0d2c658d90b82340 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Tue, 14 Nov 2006 01:19:03 -0500 Subject: git-gui: Refactor update_status -> rescan. Since we refer to the act of updating our memory structures with index and working directory differences as a rescan in the UI its probably a good idea to make the related procedures have the same name. Signed-off-by: Shawn O. Pearce --- git-gui | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index a60bf1c8a..a1266fe7a 100755 --- a/git-gui +++ b/git-gui @@ -234,7 +234,7 @@ proc repository_state {hdvar ctvar} { } } -proc update_status {{final Ready.}} { +proc rescan {{final Ready.}} { global HEAD PARENT commit_type global ui_index ui_other ui_status_value ui_comm global status_active file_states @@ -265,7 +265,7 @@ proc update_status {{final Ready.}} { } if {$repo_config(gui.trustmtime) eq {true}} { - update_status_stage2 {} $final + rescan_stage2 {} $final } else { set status_active 1 set ui_status_value {Refreshing file status...} @@ -277,11 +277,11 @@ proc update_status {{final Ready.}} { set fd_rf [open "| $cmd" r] fconfigure $fd_rf -blocking 0 -translation binary fileevent $fd_rf readable \ - [list update_status_stage2 $fd_rf $final] + [list rescan_stage2 $fd_rf $final] } } -proc update_status_stage2 {fd final} { +proc rescan_stage2 {fd final} { global gitdir PARENT commit_type global ui_index ui_other ui_status_value ui_comm global status_active @@ -684,7 +684,7 @@ proc load_last_commit {} { set commit_type amend set HEAD {} set PARENT {} - update_status + rescan } elseif {$parent_count == 1} { set commit_type amend set PARENT $parent @@ -692,7 +692,7 @@ proc load_last_commit {} { $ui_comm insert end $msg $ui_comm edit modified false $ui_comm edit reset - update_status + rescan } else { error_popup {You can't amend a merge commit.} return @@ -720,7 +720,7 @@ repository since our last scan. A rescan is required before committing. } unlock_index - update_status + rescan return } @@ -987,7 +987,7 @@ repository since our last scan. A rescan is required before a pull can be started. } unlock_index - update_status + rescan return } @@ -1026,7 +1026,7 @@ proc post_pull_remote {remote branch success} { set PARENT $HEAD set $ui_status_value {Ready.} } else { - update_status \ + rescan \ "Conflicts detected while pulling $branch from $remote." } } @@ -1744,7 +1744,7 @@ proc do_quit {} { } proc do_rescan {} { - update_status + rescan } proc do_include_all {} { @@ -2559,4 +2559,4 @@ if {!$single_commit} { populate_remote_menu .mbar.push To push_to populate_pull_menu .mbar.pull } -after 1 update_status +after 1 rescan -- cgit v1.2.1 From 8f52548a9ed078d581379ad526a4259920f80a88 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Tue, 14 Nov 2006 01:29:32 -0500 Subject: git-gui: Provide an after-rescan script to rescan. There are some situations where we need to run rescan and have it do more than just updating the status in the UI when its complete. To help with that this changes the rescan procedure to take a script which it will run at the global level as soon as the rescan is done and the UI has finished updating with the results. This is useful for example if we performed a rescan as part of a commit operation; we can go back to the commit where we left off when the rescan got initiated. Signed-off-by: Shawn O. Pearce --- git-gui | 68 ++++++++++++++++++++++++++++++++--------------------------------- 1 file changed, 34 insertions(+), 34 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index a1266fe7a..2c8501eeb 100755 --- a/git-gui +++ b/git-gui @@ -181,7 +181,7 @@ if {$appname eq {git-citool}} { ## ## task management -set status_active 0 +set rescan_active 0 set diff_active 0 set last_clicked {} @@ -234,13 +234,13 @@ proc repository_state {hdvar ctvar} { } } -proc rescan {{final Ready.}} { +proc rescan {after} { global HEAD PARENT commit_type global ui_index ui_other ui_status_value ui_comm - global status_active file_states + global rescan_active file_states global repo_config - if {$status_active || ![lock_index read]} return + if {$rescan_active > 0 || ![lock_index read]} return repository_state new_HEAD new_type if {$commit_type eq {amend} @@ -265,9 +265,9 @@ proc rescan {{final Ready.}} { } if {$repo_config(gui.trustmtime) eq {true}} { - rescan_stage2 {} $final + rescan_stage2 {} $after } else { - set status_active 1 + set rescan_active 1 set ui_status_value {Refreshing file status...} set cmd [list git update-index] lappend cmd -q @@ -277,14 +277,14 @@ proc rescan {{final Ready.}} { set fd_rf [open "| $cmd" r] fconfigure $fd_rf -blocking 0 -translation binary fileevent $fd_rf readable \ - [list rescan_stage2 $fd_rf $final] + [list rescan_stage2 $fd_rf $after] } } -proc rescan_stage2 {fd final} { +proc rescan_stage2 {fd after} { global gitdir PARENT commit_type global ui_index ui_other ui_status_value ui_comm - global status_active + global rescan_active global buf_rdi buf_rdf buf_rlo if {$fd ne {}} { @@ -304,7 +304,7 @@ proc rescan_stage2 {fd final} { set buf_rdf {} set buf_rlo {} - set status_active 3 + set rescan_active 3 set ui_status_value {Scanning for modified files ...} set fd_di [open "| git diff-index --cached -z $PARENT" r] set fd_df [open "| git diff-files -z" r] @@ -313,9 +313,9 @@ proc rescan_stage2 {fd final} { fconfigure $fd_di -blocking 0 -translation binary fconfigure $fd_df -blocking 0 -translation binary fconfigure $fd_lo -blocking 0 -translation binary - fileevent $fd_di readable [list read_diff_index $fd_di $final] - fileevent $fd_df readable [list read_diff_files $fd_df $final] - fileevent $fd_lo readable [list read_ls_others $fd_lo $final] + fileevent $fd_di readable [list read_diff_index $fd_di $after] + fileevent $fd_df readable [list read_diff_files $fd_df $after] + fileevent $fd_lo readable [list read_ls_others $fd_lo $after] } proc load_message {file} { @@ -335,7 +335,7 @@ proc load_message {file} { return 0 } -proc read_diff_index {fd final} { +proc read_diff_index {fd after} { global buf_rdi append buf_rdi [read $fd] @@ -361,10 +361,10 @@ proc read_diff_index {fd final} { set buf_rdi {} } - status_eof $fd buf_rdi $final + rescan_done $fd buf_rdi $after } -proc read_diff_files {fd final} { +proc read_diff_files {fd after} { global buf_rdf append buf_rdf [read $fd] @@ -390,10 +390,10 @@ proc read_diff_files {fd final} { set buf_rdf {} } - status_eof $fd buf_rdf $final + rescan_done $fd buf_rdf $after } -proc read_ls_others {fd final} { +proc read_ls_others {fd after} { global buf_rlo append buf_rlo [read $fd] @@ -402,18 +402,18 @@ proc read_ls_others {fd final} { foreach p [lrange $pck 0 end-1] { display_file $p _O } - status_eof $fd buf_rlo $final + rescan_done $fd buf_rlo $after } -proc status_eof {fd buf final} { - global status_active ui_status_value +proc rescan_done {fd buf after} { + global rescan_active global file_states repo_config upvar $buf to_clear if {![eof $fd]} return set to_clear {} close $fd - if {[incr status_active -1] > 0} return + if {[incr rescan_active -1] > 0} return prune_selection unlock_index @@ -434,7 +434,7 @@ proc status_eof {fd buf final} { } reshow_diff - set ui_status_value $final + uplevel #0 $after } proc prune_selection {} { @@ -684,7 +684,7 @@ proc load_last_commit {} { set commit_type amend set HEAD {} set PARENT {} - rescan + rescan {set ui_status_value {Ready.}} } elseif {$parent_count == 1} { set commit_type amend set PARENT $parent @@ -692,7 +692,7 @@ proc load_last_commit {} { $ui_comm insert end $msg $ui_comm edit modified false $ui_comm edit reset - rescan + rescan {set ui_status_value {Ready.}} } else { error_popup {You can't amend a merge commit.} return @@ -720,7 +720,7 @@ repository since our last scan. A rescan is required before committing. } unlock_index - rescan + rescan {set ui_status_value {Ready.}} return } @@ -987,7 +987,7 @@ repository since our last scan. A rescan is required before a pull can be started. } unlock_index - rescan + rescan {set ui_status_value {Ready.}} return } @@ -1024,10 +1024,10 @@ proc post_pull_remote {remote branch success} { if {$success} { repository_state HEAD commit_type set PARENT $HEAD - set $ui_status_value {Ready.} + set $ui_status_value "Pulling $branch from $remote complete." } else { - rescan \ - "Conflicts detected while pulling $branch from $remote." + set m "Conflicts detected while pulling $branch from $remote." + rescan "set ui_status_value {$m}" } } @@ -1115,10 +1115,10 @@ proc merge_state {path new_state} { } proc display_file {path state} { - global file_states file_lists selected_paths status_active + global file_states file_lists selected_paths rescan_active set old_m [merge_state $path $state] - if {$status_active} return + if {$rescan_active > 0} return set s $file_states($path) set new_m [lindex $s 0] @@ -1744,7 +1744,7 @@ proc do_quit {} { } proc do_rescan {} { - rescan + rescan {set ui_status_value {Ready.}} } proc do_include_all {} { @@ -2559,4 +2559,4 @@ if {!$single_commit} { populate_remote_menu .mbar.push To push_to populate_pull_menu .mbar.pull } -after 1 rescan +after 1 do_rescan -- cgit v1.2.1 From 04b393824ff57b5fcb881a00466e513cd4ad2a7f Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Tue, 14 Nov 2006 01:42:32 -0500 Subject: git-gui: Allow update_index to also run a script when it completes. Like rescan we also have cases where we need to perform a script after we have finished updating a number of files in the index. By changing the parameter structure of update_index we can easily pass through any script we need to run afterwards, such as picking up in the middle of a commit, or finishing what is left of a rescan. Signed-off-by: Shawn O. Pearce --- git-gui | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 2c8501eeb..be42b9106 100755 --- a/git-gui +++ b/git-gui @@ -428,7 +428,10 @@ proc rescan_done {fd buf after} { } } if {$pathList ne {}} { - update_index $pathList + update_index \ + "Updating included files" \ + $pathList \ + [concat {reshow_diff;} $after] return } } @@ -1197,7 +1200,7 @@ proc display_all_files {} { $ui_other conf -state disabled } -proc update_index {pathList} { +proc update_index {msg pathList after} { global update_index_cp update_index_rsd ui_status_value if {![lock_index update]} return @@ -1210,7 +1213,7 @@ proc update_index {pathList} { if {$batch > 25} {set batch 25} set ui_status_value [format \ - "Including files ... %i/%i files (%.2f%%)" \ + "$msg... %i/%i files (%.2f%%)" \ $update_index_cp \ $totalCnt \ 0.0] @@ -1226,20 +1229,20 @@ proc update_index {pathList} { $pathList \ $totalCnt \ $batch \ + $msg \ + $after \ ] } -proc write_update_index {fd pathList totalCnt batch} { +proc write_update_index {fd pathList totalCnt batch msg after} { global update_index_cp update_index_rsd ui_status_value global file_states ui_fname_value if {$update_index_cp >= $totalCnt} { close $fd unlock_index - set ui_status_value {Ready.} - if {$update_index_rsd} { - reshow_diff - } + if {$update_index_rsd} reshow_diff + uplevel #0 $after return } @@ -1268,7 +1271,7 @@ proc write_update_index {fd pathList totalCnt batch} { } set ui_status_value [format \ - "Including files ... %i/%i files (%.2f%%)" \ + "$msg... %i/%i files (%.2f%%)" \ $update_index_cp \ $totalCnt \ [expr {100.0 * $update_index_cp / $totalCnt}]] @@ -1766,7 +1769,10 @@ proc do_include_all {} { if {$pathList eq {}} { unlock_index } else { - update_index $pathList + update_index \ + "Including all modified files" \ + $pathList \ + {set ui_status_value {Ready to commit.}} } } @@ -1985,7 +1991,10 @@ proc toggle_or_diff {w x y} { $ui_other tag remove in_sel 0.0 end if {$col == 0} { - update_index [list $path] + update_index \ + "Including [short_path $path]" \ + [list $path] \ + {set ui_status_value {Ready.}} } else { show_diff $path $w $lno } -- cgit v1.2.1 From bbe3b3b9b93763ff4eff4fbb638b1c6a4bed8c95 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Wed, 15 Nov 2006 18:06:29 -0500 Subject: git-gui: Automatically update-index all included files before commit. If the user has "Allow Partially Included Files" disabled (and most probably will as its the default setting) we should run update-index on every included file before commit to make sure that any changes made by the user since the last rescan will still be part of this commit. If we don't update-index every modified file the user will likely become confused when part of their changes were committed and other parts weren't; and those other parts won't show up until a later rescan occurs. Since we don't rescan immediately after a commit this may be a while. Signed-off-by: Shawn O. Pearce --- git-gui | 101 ++++++++++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 66 insertions(+), 35 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index be42b9106..9a6953e97 100755 --- a/git-gui +++ b/git-gui @@ -420,7 +420,7 @@ proc rescan_done {fd buf after} { display_all_files if {$repo_config(gui.partialinclude) ne {true}} { - set pathList [list] + set pathList [list] foreach path [array names file_states] { switch -- [lindex $file_states($path) 0] { AM - @@ -703,9 +703,7 @@ proc load_last_commit {} { } proc commit_tree {} { - global tcl_platform HEAD gitdir commit_type file_states - global pch_error - global ui_status_value ui_comm + global HEAD commit_type file_states ui_comm repo_config if {![lock_index update]} return @@ -719,8 +717,10 @@ proc commit_tree {} { error_popup {Last scanned state does not match repository state. Its highly likely that another Git program modified the -repository since our last scan. A rescan is required +repository since the last scan. A rescan is required before committing. + +A rescan will be automatically started now. } unlock_index rescan {set ui_status_value {Ready.}} @@ -731,8 +731,7 @@ before committing. # set files_ready 0 foreach path [array names file_states] { - set s $file_states($path) - switch -glob -- [lindex $s 0] { + switch -glob -- [lindex $file_states($path) 0] { _? {continue} A? - D? - @@ -779,10 +778,39 @@ A good commit message has the following format: return } - # -- Ask the pre-commit hook for the go-ahead. + # -- Update included files if partialincludes are off. # + if {$repo_config(gui.partialinclude) ne {true}} { + set pathList [list] + foreach path [array names file_states] { + switch -glob -- [lindex $file_states($path) 0] { + A? - + M? {lappend pathList $path} + } + } + if {$pathList ne {}} { + unlock_index + update_index \ + "Updating included files" \ + $pathList \ + [concat {lock_index update;} \ + [list commit_prehook $curHEAD $msg]] + return + } + } + + commit_prehook $curHEAD $msg +} + +proc commit_prehook {curHEAD msg} { + global tcl_platform gitdir ui_status_value pch_error + + # On Cygwin [file executable] might lie so we need to ask + # the shell if the hook is executable. Yes that's annoying. + set pchook [file join $gitdir hooks pre-commit] - if {$tcl_platform(platform) eq {windows} && [file isfile $pchook]} { + if {$tcl_platform(platform) eq {windows} + && [file isfile $pchook]} { set pchook [list sh -c [concat \ "if test -x \"$pchook\";" \ "then exec \"$pchook\" 2>&1;" \ @@ -790,21 +818,19 @@ A good commit message has the following format: } elseif {[file executable $pchook]} { set pchook [list $pchook |& cat] } else { - set pchook {} - } - if {$pchook ne {}} { - set ui_status_value {Calling pre-commit hook...} - set pch_error {} - set fd_ph [open "| $pchook" r] - fconfigure $fd_ph -blocking 0 -translation binary - fileevent $fd_ph readable \ - [list commit_stage1 $fd_ph $curHEAD $msg] - } else { - commit_stage2 $curHEAD $msg + commit_writetree $curHEAD $msg + return } + + set ui_status_value {Calling pre-commit hook...} + set pch_error {} + set fd_ph [open "| $pchook" r] + fconfigure $fd_ph -blocking 0 -translation binary + fileevent $fd_ph readable \ + [list commit_prehook_wait $fd_ph $curHEAD $msg] } -proc commit_stage1 {fd_ph curHEAD msg} { +proc commit_prehook_wait {fd_ph curHEAD msg} { global pch_error ui_status_value append pch_error [read $fd_ph] @@ -815,25 +841,24 @@ proc commit_stage1 {fd_ph curHEAD msg} { hook_failed_popup pre-commit $pch_error unlock_index } else { - commit_stage2 $curHEAD $msg + commit_writetree $curHEAD $msg } set pch_error {} - } else { - fconfigure $fd_ph -blocking 0 + return } + fconfigure $fd_ph -blocking 0 } -proc commit_stage2 {curHEAD msg} { +proc commit_writetree {curHEAD msg} { global ui_status_value - # -- Write the tree in the background. - # set ui_status_value {Committing changes...} set fd_wt [open "| git write-tree" r] - fileevent $fd_wt readable [list commit_stage3 $fd_wt $curHEAD $msg] + fileevent $fd_wt readable \ + [list commit_committree $fd_wt $curHEAD $msg] } -proc commit_stage3 {fd_wt curHEAD msg} { +proc commit_committree {fd_wt curHEAD msg} { global single_commit gitdir HEAD PARENT commit_type tcl_platform global ui_status_value ui_comm global file_states selected_paths @@ -1252,14 +1277,20 @@ proc write_update_index {fd pathList totalCnt batch msg after} { set path [lindex $pathList $update_index_cp] incr update_index_cp - switch -- [lindex $file_states($path) 0] { - AM - - _O {set new A*} - _M - - MM {set new M*} + switch -glob -- [lindex $file_states($path) 0] { AD - + MD - _D {set new D*} - default {continue} + + _M - + MM - + M_ {set new M*} + + _O - + AM - + A_ {set new A*} + + ?? {continue} } puts -nonewline $fd $path -- cgit v1.2.1 From e8ab64461968392f126b0a0e2fef4ce8bdcca623 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Wed, 15 Nov 2006 18:55:05 -0500 Subject: git-gui: Disable diff actions when no diff is active. There is no reason why the user should be able to operate on the diff buffer if there is no currently selected diff; likewise the "File:" label text appears rather silly looking all by itself when no diff is being shown in the diff buffer. So now we only enable widgets (like menu items) if there is a diff currently showing, and we disable them when a diff isn't showing. Signed-off-by: Shawn O. Pearce --- git-gui | 186 ++++++++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 118 insertions(+), 68 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 9a6953e97..844966453 100755 --- a/git-gui +++ b/git-gui @@ -455,34 +455,33 @@ proc prune_selection {} { ## diff proc clear_diff {} { - global ui_diff ui_fname_value ui_fstatus_value ui_index ui_other + global ui_diff current_diff ui_index ui_other $ui_diff conf -state normal $ui_diff delete 0.0 end $ui_diff conf -state disabled - set ui_fname_value {} - set ui_fstatus_value {} + set current_diff {} $ui_index tag remove in_diff 0.0 end $ui_other tag remove in_diff 0.0 end } proc reshow_diff {} { - global ui_fname_value ui_status_value file_states + global current_diff ui_status_value file_states - if {$ui_fname_value eq {} - || [catch {set s $file_states($ui_fname_value)}]} { + if {$current_diff eq {} + || [catch {set s $file_states($current_diff)}]} { clear_diff } else { - show_diff $ui_fname_value + show_diff $current_diff } } proc handle_empty_diff {} { - global ui_fname_value file_states file_lists + global current_diff file_states file_lists - set path $ui_fname_value + set path $current_diff set s $file_states($path) if {[lindex $s 0] ne {_M}} return @@ -520,7 +519,7 @@ files list, to prevent possible confusion. proc show_diff {path {w {}} {lno {}}} { global file_states file_lists global PARENT diff_3way diff_active repo_config - global ui_diff ui_fname_value ui_fstatus_value ui_status_value + global ui_diff current_diff ui_status_value if {$diff_active || ![lock_index read]} return @@ -542,8 +541,7 @@ proc show_diff {path {w {}} {lno {}}} { set m [lindex $s 0] set diff_3way 0 set diff_active 1 - set ui_fname_value $path - set ui_fstatus_value [mapdesc $m $path] + set current_diff $path set ui_status_value "Loading diff of [escape_path $path]..." set cmd [list | git diff-index] @@ -1261,7 +1259,7 @@ proc update_index {msg pathList after} { proc write_update_index {fd pathList totalCnt batch msg after} { global update_index_cp update_index_rsd ui_status_value - global file_states ui_fname_value + global file_states current_diff if {$update_index_cp >= $totalCnt} { close $fd @@ -1296,7 +1294,7 @@ proc write_update_index {fd pathList totalCnt batch msg after} { puts -nonewline $fd $path puts -nonewline $fd "\0" display_file $path $new - if {$ui_fname_value eq $path} { + if {$current_diff eq $path} { set update_index_rsd 1 } } @@ -2384,71 +2382,105 @@ pack .vpane.lower.commarea.buffer -side left -fill y # -- Commit Message Buffer Context Menu # -menu $ui_comm.ctxm -tearoff 0 -$ui_comm.ctxm add command -label "Cut" \ +set ctxm .vpane.lower.commarea.buffer.ctxm +menu $ctxm -tearoff 0 +$ctxm add command \ + -label {Cut} \ -font font_ui \ - -command "tk_textCut $ui_comm" -$ui_comm.ctxm add command -label "Copy" \ + -command {tk_textCut $ui_comm} +$ctxm add command \ + -label {Copy} \ -font font_ui \ - -command "tk_textCopy $ui_comm" -$ui_comm.ctxm add command -label "Paste" \ + -command {tk_textCopy $ui_comm} +$ctxm add command \ + -label {Paste} \ -font font_ui \ - -command "tk_textPaste $ui_comm" -$ui_comm.ctxm add command -label "Delete" \ + -command {tk_textPaste $ui_comm} +$ctxm add command \ + -label {Delete} \ -font font_ui \ - -command "$ui_comm delete sel.first sel.last" -$ui_comm.ctxm add separator -$ui_comm.ctxm add command -label "Select All" \ + -command {$ui_comm delete sel.first sel.last} +$ctxm add separator +$ctxm add command \ + -label {Select All} \ -font font_ui \ - -command "$ui_comm tag add sel 0.0 end" -$ui_comm.ctxm add command -label "Copy All" \ + -command {$ui_comm tag add sel 0.0 end} +$ctxm add command \ + -label {Copy All} \ -font font_ui \ - -command " + -command { $ui_comm tag add sel 0.0 end tk_textCopy $ui_comm $ui_comm tag remove sel 0.0 end - " -$ui_comm.ctxm add separator -$ui_comm.ctxm add command -label "Sign Off" \ + } +$ctxm add separator +$ctxm add command \ + -label {Sign Off} \ -font font_ui \ -command do_signoff -bind_button3 $ui_comm "tk_popup $ui_comm.ctxm %X %Y" +bind_button3 $ui_comm "tk_popup $ctxm %X %Y" # -- Diff Header -set ui_fname_value {} -set ui_fstatus_value {} +set current_diff {} +set diff_actions [list] +proc current_diff_trace {varname args} { + global current_diff diff_actions file_states + if {$current_diff eq {}} { + set s {} + set f {} + set p {} + set o disabled + } else { + set p $current_diff + set s [mapdesc [lindex $file_states($p) 0] $p] + set f {File:} + set p [escape_path $p] + set o normal + } + + .vpane.lower.diff.header.status configure -text $s + .vpane.lower.diff.header.file configure -text $f + .vpane.lower.diff.header.path configure -text $p + foreach w $diff_actions { + uplevel #0 $w $o + } +} +trace add variable current_diff write current_diff_trace + frame .vpane.lower.diff.header -background orange -label .vpane.lower.diff.header.l4 \ - -textvariable ui_fstatus_value \ +label .vpane.lower.diff.header.status \ -background orange \ -width $max_status_desc \ -anchor w \ -justify left \ -font font_ui -label .vpane.lower.diff.header.l1 -text {File:} \ +label .vpane.lower.diff.header.file \ -background orange \ + -anchor w \ + -justify left \ -font font_ui -set ui_fname .vpane.lower.diff.header.l2 -label $ui_fname \ - -textvariable ui_fname_value \ +label .vpane.lower.diff.header.path \ -background orange \ -anchor w \ -justify left \ -font font_ui -menu $ui_fname.ctxm -tearoff 0 -$ui_fname.ctxm add command -label "Copy" \ +pack .vpane.lower.diff.header.status -side left +pack .vpane.lower.diff.header.file -side left +pack .vpane.lower.diff.header.path -fill x +set ctxm .vpane.lower.diff.header.ctxm +menu $ctxm -tearoff 0 +$ctxm add command \ + -label {Copy} \ -font font_ui \ -command { clipboard clear clipboard append \ -format STRING \ -type STRING \ - -- $ui_fname_value + -- $current_diff } -bind_button3 $ui_fname "tk_popup $ui_fname.ctxm %X %Y" -pack .vpane.lower.diff.header.l4 -side left -pack .vpane.lower.diff.header.l1 -side left -pack $ui_fname -fill x +lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state] +bind_button3 .vpane.lower.diff.header.path "tk_popup $ctxm %X %Y" # -- Diff Body frame .vpane.lower.diff.body @@ -2478,48 +2510,63 @@ $ui_diff tag conf bold -font font_diffbold # -- Diff Body Context Menu # -menu $ui_diff.ctxm -tearoff 0 -$ui_diff.ctxm add command -label "Copy" \ +set ctxm .vpane.lower.diff.body.ctxm +menu $ctxm -tearoff 0 +$ctxm add command \ + -label {Copy} \ -font font_ui \ - -command "tk_textCopy $ui_diff" -$ui_diff.ctxm add command -label "Select All" \ + -command {tk_textCopy $ui_diff} +lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state] +$ctxm add command \ + -label {Select All} \ -font font_ui \ - -command "$ui_diff tag add sel 0.0 end" -$ui_diff.ctxm add command -label "Copy All" \ + -command {$ui_diff tag add sel 0.0 end} +lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state] +$ctxm add command \ + -label {Copy All} \ -font font_ui \ - -command " + -command { $ui_diff tag add sel 0.0 end tk_textCopy $ui_diff $ui_diff tag remove sel 0.0 end - " -$ui_diff.ctxm add separator -$ui_diff.ctxm add command -label "Decrease Font Size" \ + } +lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state] +$ctxm add separator +$ctxm add command \ + -label {Decrease Font Size} \ -font font_ui \ -command {incr_font_size font_diff -1} -$ui_diff.ctxm add command -label "Increase Font Size" \ +lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state] +$ctxm add command \ + -label {Increase Font Size} \ -font font_ui \ -command {incr_font_size font_diff 1} -$ui_diff.ctxm add separator -$ui_diff.ctxm add command -label "Show Less Context" \ +lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state] +$ctxm add separator +$ctxm add command \ + -label {Show Less Context} \ -font font_ui \ - -command {if {$ui_fname_value ne {} - && $repo_config(gui.diffcontext) >= 2} { + -command {if {$repo_config(gui.diffcontext) >= 2} { incr repo_config(gui.diffcontext) -1 reshow_diff }} -$ui_diff.ctxm add command -label "Show More Context" \ +lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state] +$ctxm add command \ + -label {Show More Context} \ -font font_ui \ - -command {if {$ui_fname_value ne {}} { + -command { incr repo_config(gui.diffcontext) reshow_diff - }} -$ui_diff.ctxm add separator -$ui_diff.ctxm add command -label {Options...} \ + } +lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state] +$ctxm add separator +$ctxm add command -label {Options...} \ -font font_ui \ -command do_options -bind_button3 $ui_diff "tk_popup $ui_diff.ctxm %X %Y" +bind_button3 $ui_diff "tk_popup $ctxm %X %Y" # -- Status Bar +# set ui_status_value {Initializing...} label .status -textvariable ui_status_value \ -anchor w \ @@ -2530,6 +2577,7 @@ label .status -textvariable ui_status_value \ pack .status -anchor w -side bottom -fill x # -- Load geometry +# catch { set gm $repo_config(gui.geometry) wm geometry . [lindex $gm 0] @@ -2543,6 +2591,7 @@ unset gm } # -- Key Bindings +# bind $ui_comm <$M1B-Key-Return> {do_commit;break} bind $ui_comm <$M1B-Key-i> {do_include_all;break} bind $ui_comm <$M1B-Key-I> {do_include_all;break} @@ -2590,6 +2639,7 @@ unset i set file_lists($ui_index) [list] set file_lists($ui_other) [list] +set current_diff {} wm title . "$appname ([file normalize [file dirname $gitdir]])" focus -force $ui_comm -- cgit v1.2.1 From fbee8500a5b64a1c0c6103232879bcecc30f64b4 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Wed, 15 Nov 2006 22:13:45 -0500 Subject: git-gui: Correctly handle GIT_DIR environment variable. Some users may want to start us by running "git --git-dir=... gui" rather than trying to cd into the directory first. This is especially true if they want to just make a shortcut to our executable on Windows and always have that associated with a certain repository. Since Tcl on Windows throws away our environment and doesn't pass it down to the child process correctly we cannot call git-rev-parse to get the GIT_DIR environment variable. So instead we ask for it specifically ourselves; if its not defined then we ask rev-parse. This should actually reduce startup by 1 fork/exec if we were started as "git gui" as GIT_DIR will be set for us. Signed-off-by: Shawn O. Pearce --- git-gui | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 844966453..7c2f803fe 100755 --- a/git-gui +++ b/git-gui @@ -161,16 +161,17 @@ proc info_popup {msg} { ## ## repository setup -if { [catch {set cdup [exec git rev-parse --show-cdup]} err] - || [catch {set gitdir [exec git rev-parse --git-dir]} err]} { +if { [catch {set gitdir $env(GIT_DIR)}] + && [catch {set gitdir [exec git rev-parse --git-dir]} err]} { catch {wm withdraw .} error_popup "Cannot find the git directory:\n\n$err" exit 1 } -if {$cdup ne ""} { - cd $cdup +if {[catch {cd [file dirname $gitdir]} err]} { + catch {wm withdraw .} + error_popup "No working directory [file dirname $gitdir]:\n\n$err" + exit 1 } -unset cdup set single_commit 0 if {$appname eq {git-citool}} { -- cgit v1.2.1 From 4aca740b3915b35d7fa1707be79b268b0cc94123 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Wed, 15 Nov 2006 22:35:26 -0500 Subject: git-gui: Create Windows shortcut icons for git-gui. If we are running on Windows we now offer a 'Create Desktop Icon' menu item under the Project menu. This pops up a save dialog box letting the user create a .bat file on their desktop (or somewhere else). The .bat script will startup Cygwin with a login shell then launch git-gui in the current working directory. This is very useful for Windows users who have little to no desire to start a command window just to run a git-gui session. Signed-off-by: Shawn O. Pearce --- git-gui | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 7c2f803fe..def6a5e07 100755 --- a/git-gui +++ b/git-gui @@ -2002,6 +2002,54 @@ proc do_save_config {w} { destroy $w } +proc do_windows_shortcut {} { + global gitdir appname argv0 + + set reponame [lindex [file split \ + [file normalize [file dirname $gitdir]]] \ + end] + + if {[catch { + set desktop [exec cygpath \ + --windows \ + --absolute \ + --long-name \ + --desktop] + }]} { + set desktop . + } + set fn [tk_getSaveFile \ + -parent . \ + -title "$appname ($reponame): Create Desktop Icon" \ + -initialdir $desktop \ + -initialfile "Git $reponame.bat"] + if {$fn != {}} { + if {[catch { + set fd [open $fn w] + set sh [exec cygpath \ + --windows \ + --absolute \ + --long-name \ + /bin/sh] + set me [exec cygpath \ + --unix \ + --absolute \ + $argv0] + set gd [exec cygpath \ + --unix \ + --absolute \ + $gitdir] + puts -nonewline $fd "\"$sh\" --login -c \"" + puts -nonewline $fd "GIT_DIR=\\\"$gd\\\"" + puts -nonewline $fd " \\\"$me\\\"" + puts $fd "&\"" + close $fd + } err]} { + error_popup "Cannot write script:\n\n$err" + } + } +} + proc toggle_or_diff {w x y} { global file_lists ui_index ui_other global last_clicked selected_paths @@ -2168,6 +2216,13 @@ if {!$single_commit} { .mbar.project add command -label {Repack Database} \ -command do_repack \ -font font_ui + + if {$tcl_platform(platform) eq {windows}} { + .mbar.project add command \ + -label {Create Desktop Icon} \ + -command do_windows_shortcut \ + -font font_ui + } } .mbar.project add command -label Quit \ -command do_quit \ -- cgit v1.2.1 From dbccbbda4f4c049552495a87b1747b1b2a1e2823 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Wed, 15 Nov 2006 22:45:33 -0500 Subject: git-gui: Protect ourselves from funny GIT_DIR/working directory setups. Since we have some serious problems with the GIT_DIR environment variable on Windows we cannot let the user use a non-standard GIT_DIR with their working directory. So require that the GIT_DIR name is actually ".git", that it exists, and that its parent directory is our working directory. Signed-off-by: Shawn O. Pearce --- git-gui | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index def6a5e07..c35c73c8c 100755 --- a/git-gui +++ b/git-gui @@ -167,6 +167,16 @@ if { [catch {set gitdir $env(GIT_DIR)}] error_popup "Cannot find the git directory:\n\n$err" exit 1 } +if {![file isdirectory $gitdir]} { + catch {wm withdraw .} + error_popup "Git directory not found:\n\n$gitdir" + exit 1 +} +if {[lindex [file split $gitdir] end] ne {.git}} { + catch {wm withdraw .} + error_popup "Cannot use funny .git directory:\n\n$gitdir" + exit 1 +} if {[catch {cd [file dirname $gitdir]} err]} { catch {wm withdraw .} error_popup "No working directory [file dirname $gitdir]:\n\n$err" @@ -2040,8 +2050,8 @@ proc do_windows_shortcut {} { --absolute \ $gitdir] puts -nonewline $fd "\"$sh\" --login -c \"" - puts -nonewline $fd "GIT_DIR=\\\"$gd\\\"" - puts -nonewline $fd " \\\"$me\\\"" + puts -nonewline $fd "GIT_DIR='$gd'" + puts -nonewline $fd " '$me'" puts $fd "&\"" close $fd } err]} { -- cgit v1.2.1 From 306500fc09e7d8be042e8b9abbd9011b80b3300d Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Wed, 15 Nov 2006 22:53:53 -0500 Subject: git-gui: Handle ' within paths when creating Windows shortcuts. Signed-off-by: Shawn O. Pearce --- git-gui | 2 ++ 1 file changed, 2 insertions(+) (limited to 'git-gui') diff --git a/git-gui b/git-gui index c35c73c8c..013f21b2e 100755 --- a/git-gui +++ b/git-gui @@ -2049,6 +2049,8 @@ proc do_windows_shortcut {} { --unix \ --absolute \ $gitdir] + regsub -all ' $me "'\\''" me + regsub -all ' $gd "'\\''" gd puts -nonewline $fd "\"$sh\" --login -c \"" puts -nonewline $fd "GIT_DIR='$gd'" puts -nonewline $fd " '$me'" -- cgit v1.2.1 From c1237ae288aae7e45a18f3d5097b49451293acfe Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Wed, 15 Nov 2006 23:52:20 -0500 Subject: git-gui: Only populate a fetch or push if we have an action. Don't offer to fetch from a remote unless we have at least one Pull: line in its .git/remotes/ file or at least one configuration value for remote..fetch. Ditto for push. Users shouldn't be fetching or pushing branch groups unless they have them configured; anything else is just crazy. Signed-off-by: Shawn O. Pearce --- git-gui | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 60 insertions(+), 8 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 013f21b2e..ea60e327e 100755 --- a/git-gui +++ b/git-gui @@ -1343,13 +1343,65 @@ proc load_all_remotes {} { set all_remotes [lsort -unique $all_remotes] } -proc populate_remote_menu {m pfx op} { - global all_remotes +proc populate_fetch_menu {m} { + global gitdir all_remotes repo_config - foreach remote $all_remotes { - $m add command -label "$pfx $remote..." \ - -command [list $op $remote] \ - -font font_ui + foreach r $all_remotes { + set enable 0 + if {![catch {set a $repo_config(remote.$r.url)}]} { + if {![catch {set a $repo_config(remote.$r.fetch)}]} { + set enable 1 + } + } else { + catch { + set fd [open [file join $gitdir remotes $r] r] + while {[gets $fd n] >= 0} { + if {[regexp {^Pull:[ \t]*([^:]+):} $n]} { + set enable 1 + break + } + } + close $fd + } + } + + if {$enable} { + $m add command \ + -label "Fetch from $r..." \ + -command [list fetch_from $r] \ + -font font_ui + } + } +} + +proc populate_push_menu {m} { + global gitdir all_remotes repo_config + + foreach r $all_remotes { + set enable 0 + if {![catch {set a $repo_config(remote.$r.url)}]} { + if {![catch {set a $repo_config(remote.$r.push)}]} { + set enable 1 + } + } else { + catch { + set fd [open [file join $gitdir remotes $r] r] + while {[gets $fd n] >= 0} { + if {[regexp {^Push:[ \t]*([^:]+):} $n]} { + set enable 1 + break + } + } + close $fd + } + } + + if {$enable} { + $m add command \ + -label "Push to $r..." \ + -command [list push_to $r] \ + -font font_ui + } } } @@ -2713,8 +2765,8 @@ wm title . "$appname ([file normalize [file dirname $gitdir]])" focus -force $ui_comm if {!$single_commit} { load_all_remotes - populate_remote_menu .mbar.fetch From fetch_from - populate_remote_menu .mbar.push To push_to + populate_fetch_menu .mbar.fetch populate_pull_menu .mbar.pull + populate_push_menu .mbar.push } after 1 do_rescan -- cgit v1.2.1 From 06c311157a045c2189acc5496fdc71a806c28f8c Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 18 Nov 2006 00:31:00 -0500 Subject: git-gui: Create a .app file on MacOS X if requested. If a user works with a repository frequently they may want to just create an icon they can use to launch git-gui against that repository. Since we already support this concept on Windows we can do the same on Mac OS X by creating a .app file with a tiny shell script in it that sets up the necessary environment then invokes our script. Signed-off-by: Shawn O. Pearce --- git-gui | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) (limited to 'git-gui') diff --git a/git-gui b/git-gui index ea60e327e..472bcb7e3 100755 --- a/git-gui +++ b/git-gui @@ -2114,6 +2114,79 @@ proc do_windows_shortcut {} { } } +proc do_macosx_app {} { + global gitdir appname argv0 env + + set reponame [lindex [file split \ + [file normalize [file dirname $gitdir]]] \ + end] + + set fn [tk_getSaveFile \ + -parent . \ + -title "$appname ($reponame): Create Desktop Icon" \ + -initialdir [file join $env(HOME) Desktop] \ + -initialfile "Git $reponame.app"] + if {$fn != {}} { + if {[catch { + set Contents [file join $fn Contents] + set MacOS [file join $Contents MacOS] + set exe [file join $MacOS git-gui] + + file mkdir $MacOS + + set fd [open [file join $Contents PkgInfo] w] + puts -nonewline $fd {APPL????} + close $fd + + set fd [open [file join $Contents Info.plist] w] + puts $fd { + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + git-gui + CFBundleIdentifier + org.spearce.git-gui + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + APPL + CFBundleSignature + ???? + CFBundleVersion + 1.0 + NSPrincipalClass + NSApplication + +} + close $fd + + set fd [open $exe w] + set gd [file normalize $gitdir] + set ep [file normalize [exec git --exec-path]] + regsub -all ' $gd "'\\''" gd + regsub -all ' $ep "'\\''" ep + puts $fd "#!/bin/sh" + foreach name [array names env] { + if {[string match GIT_* $name]} { + regsub -all ' $env($name) "'\\''" v + puts $fd "export $name='$v'" + } + } + puts $fd "export PATH='$ep':\$PATH" + puts $fd "export GIT_DIR='$gd'" + puts $fd "exec [file normalize $argv0]" + close $fd + + file attributes $exe -permissions u+x,g+x,o+x + } err]} { + error_popup "Cannot write icon:\n\n$err" + } + } +} + proc toggle_or_diff {w x y} { global file_lists ui_index ui_other global last_clicked selected_paths @@ -2286,6 +2359,11 @@ if {!$single_commit} { -label {Create Desktop Icon} \ -command do_windows_shortcut \ -font font_ui + } elseif {[is_MacOSX]} { + .mbar.project add command \ + -label {Create Desktop Icon} \ + -command do_macosx_app \ + -font font_ui } } .mbar.project add command -label Quit \ -- cgit v1.2.1 From cbbaa28bc0a2b607b0f5e2e23f910d1619b52b0f Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 18 Nov 2006 01:20:37 -0500 Subject: git-gui: Display error dialog on Mac OS X when no .git found. If we can't locate a .git directory for the given directory we need to show a message to the user to let them know the directory wasn't found. But since this is before we have shown our main application window we cannot use that as the parent for the error popup; on Mac OS X this causes an error and prevents the dialog from showing. Instead only add -parent . to the popup call if we have mapped (shown) the main window. Signed-off-by: Shawn O. Pearce --- git-gui | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 472bcb7e3..12a46e976 100755 --- a/git-gui +++ b/git-gui @@ -130,12 +130,15 @@ proc error_popup {msg} { end] append title {)} } - tk_messageBox \ - -parent . \ + set cmd [list tk_messageBox \ -icon error \ -type ok \ -title "$title: error" \ - -message $msg + -message $msg] + if {[winfo ismapped .]} { + lappend cmd -parent . + } + eval $cmd } proc info_popup {msg} { -- cgit v1.2.1 From 4539eacd6dde87b4e73c859e946bb0a2c89d71f4 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 18 Nov 2006 02:50:58 -0500 Subject: git-gui: Make initial commits work properly. Apparently I never really tested the logic for making or amending an initial commit, so although most of the code was here in git-gui it didn't quite work as it was intended to. So this is all just bug fixes to make initial commits correctly generate the list of files going into the initial commit, or to show a newly added file's diff, and to amend an initial commit. Because we really want to diff the index against a tree-ish and there is no such tree-ish on an initial commit we create an empty tree through git-mktree and diff against that. This unfortunately creates a dangling tree, which may confuse a new user who uses git-gui to make a new commit and then immediately afterwards runs git fsck-objects to see if their object database is corrupt or not. Signed-off-by: Shawn O. Pearce --- git-gui | 74 ++++++++++++++++++++++++++++++++++++++++------------------------- 1 file changed, 46 insertions(+), 28 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 12a46e976..e2e0beae9 100755 --- a/git-gui +++ b/git-gui @@ -205,6 +205,7 @@ set index_lock_type none set HEAD {} set PARENT {} set commit_type {} +set empty_tree {} proc lock_index {type} { global index_lock_type disable_on_lock @@ -240,6 +241,7 @@ proc repository_state {hdvar ctvar} { upvar $hdvar hd $ctvar ct if {[catch {set hd [exec git rev-parse --verify HEAD]}]} { + set hd {} set ct initial } elseif {[file exists [file join $gitdir MERGE_HEAD]]} { set ct merge @@ -248,6 +250,18 @@ proc repository_state {hdvar ctvar} { } } +proc PARENT {} { + global PARENT empty_tree + + if {$PARENT ne {}} { + return $PARENT + } + if {$empty_tree eq {}} { + set empty_tree [exec git mktree << {}] + } + return $empty_tree +} + proc rescan {after} { global HEAD PARENT commit_type global ui_index ui_other ui_status_value ui_comm @@ -257,7 +271,7 @@ proc rescan {after} { if {$rescan_active > 0 || ![lock_index read]} return repository_state new_HEAD new_type - if {$commit_type eq {amend} + if {[string match amend* $commit_type] && $new_type eq {normal} && $new_HEAD eq $HEAD} { } else { @@ -296,10 +310,8 @@ proc rescan {after} { } proc rescan_stage2 {fd after} { - global gitdir PARENT commit_type - global ui_index ui_other ui_status_value ui_comm - global rescan_active - global buf_rdi buf_rdf buf_rlo + global gitdir ui_status_value + global rescan_active buf_rdi buf_rdf buf_rlo if {$fd ne {}} { read $fd @@ -320,7 +332,7 @@ proc rescan_stage2 {fd after} { set rescan_active 3 set ui_status_value {Scanning for modified files ...} - set fd_di [open "| git diff-index --cached -z $PARENT" r] + set fd_di [open "| git diff-index --cached -z [PARENT]" r] set fd_df [open "| git diff-files -z" r] set fd_lo [open $ls_others r] @@ -532,7 +544,7 @@ files list, to prevent possible confusion. proc show_diff {path {w {}} {lno {}}} { global file_states file_lists - global PARENT diff_3way diff_active repo_config + global diff_3way diff_active repo_config global ui_diff current_diff ui_status_value if {$diff_active || ![lock_index read]} return @@ -591,7 +603,7 @@ proc show_diff {path {w {}} {lno {}}} { } } - lappend cmd $PARENT + lappend cmd [PARENT] lappend cmd -- lappend cmd $path @@ -671,7 +683,7 @@ proc read_diff {fd} { proc load_last_commit {} { global HEAD PARENT commit_type ui_comm - if {$commit_type eq {amend}} return + if {[string match amend* $commit_type]} return if {$commit_type ne {normal}} { error_popup "Can't amend a $commit_type commit." return @@ -695,23 +707,24 @@ proc load_last_commit {} { return } + if {$parent_count > 1} { + error_popup {Can't amend a merge commit.} + return + } + if {$parent_count == 0} { - set commit_type amend - set HEAD {} + set commit_type amend-initial set PARENT {} - rescan {set ui_status_value {Ready.}} } elseif {$parent_count == 1} { set commit_type amend set PARENT $parent - $ui_comm delete 0.0 end - $ui_comm insert end $msg - $ui_comm edit modified false - $ui_comm edit reset - rescan {set ui_status_value {Ready.}} - } else { - error_popup {You can't amend a merge commit.} - return } + + $ui_comm delete 0.0 end + $ui_comm insert end $msg + $ui_comm edit modified false + $ui_comm edit reset + rescan {set ui_status_value {Ready.}} } proc commit_tree {} { @@ -722,7 +735,7 @@ proc commit_tree {} { # -- Our in memory state should match the repository. # repository_state curHEAD cur_type - if {$commit_type eq {amend} + if {[string match amend* $commit_type] && $cur_type eq {normal} && $curHEAD eq $HEAD} { } elseif {$commit_type ne $cur_type || $HEAD ne $curHEAD} { @@ -2559,13 +2572,18 @@ label $ui_coml -text {Commit Message:} \ -anchor w \ -justify left \ -font font_ui -trace add variable commit_type write {uplevel #0 { - switch -glob $commit_type \ - initial {$ui_coml conf -text {Initial Commit Message:}} \ - amend {$ui_coml conf -text {Amended Commit Message:}} \ - merge {$ui_coml conf -text {Merge Commit Message:}} \ - * {$ui_coml conf -text {Commit Message:}} -}} +proc trace_commit_type {varname args} { + global ui_coml commit_type + switch -glob -- $commit_type { + initial {set txt {Initial Commit Message:}} + amend {set txt {Amended Commit Message:}} + amend-initial {set txt {Amended Initial Commit Message:}} + merge {set txt {Merge Commit Message:}} + * {set txt {Commit Message:}} + } + $ui_coml conf -text $txt +} +trace add variable commit_type write trace_commit_type text $ui_comm -background white -borderwidth 1 \ -undo true \ -maxundo 20 \ -- cgit v1.2.1 From 32e0bcab59334ed8f1955c8afa830de22362c1ec Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 18 Nov 2006 03:03:16 -0500 Subject: git-gui: Only reshow diff when really necessary. I noticed that we were reshowing the current diff during a commit; this occurs because we feed every added and modified file through update-index just before commit. During the update-index process we reshow the current diff if the current file in the diff pane was one of those added or modified files we reprocessed. This just slows down the UI more than is necessary. So refactoring update_index so that we don't call reshow_diff from within that code; instead we do it at a higher level. Signed-off-by: Shawn O. Pearce --- git-gui | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index e2e0beae9..62545b709 100755 --- a/git-gui +++ b/git-gui @@ -1251,12 +1251,11 @@ proc display_all_files {} { } proc update_index {msg pathList after} { - global update_index_cp update_index_rsd ui_status_value + global update_index_cp ui_status_value if {![lock_index update]} return set update_index_cp 0 - set update_index_rsd 0 set pathList [lsort $pathList] set totalCnt [llength $pathList] set batch [expr {int($totalCnt * .01) + 1}] @@ -1285,13 +1284,12 @@ proc update_index {msg pathList after} { } proc write_update_index {fd pathList totalCnt batch msg after} { - global update_index_cp update_index_rsd ui_status_value + global update_index_cp ui_status_value global file_states current_diff if {$update_index_cp >= $totalCnt} { close $fd unlock_index - if {$update_index_rsd} reshow_diff uplevel #0 $after return } @@ -1321,9 +1319,6 @@ proc write_update_index {fd pathList totalCnt batch msg after} { puts -nonewline $fd $path puts -nonewline $fd "\0" display_file $path $new - if {$current_diff eq $path} { - set update_index_rsd 1 - } } set ui_status_value [format \ @@ -1859,19 +1854,23 @@ proc do_rescan {} { } proc do_include_all {} { - global file_states + global file_states current_diff if {![lock_index begin-update]} return set pathList [list] + set after {} foreach path [array names file_states] { - set s $file_states($path) - set m [lindex $s 0] - switch -- $m { + switch -- [lindex $file_states($path) 0] { AM - MM - _M - - _D {lappend pathList $path} + _D { + lappend pathList $path + if {$path eq $current_diff} { + set after {reshow_diff;} + } + } } } if {$pathList eq {}} { @@ -1880,7 +1879,7 @@ proc do_include_all {} { update_index \ "Including all modified files" \ $pathList \ - {set ui_status_value {Ready to commit.}} + [concat $after {set ui_status_value {Ready to commit.}}] } } @@ -2204,7 +2203,7 @@ proc do_macosx_app {} { } proc toggle_or_diff {w x y} { - global file_lists ui_index ui_other + global file_lists current_diff ui_index ui_other global last_clicked selected_paths set pos [split [$w index @$x,$y] .] @@ -2222,10 +2221,15 @@ proc toggle_or_diff {w x y} { $ui_other tag remove in_sel 0.0 end if {$col == 0} { + if {$current_diff eq $path} { + set after {reshow_diff;} + } else { + set after {} + } update_index \ "Including [short_path $path]" \ [list $path] \ - {set ui_status_value {Ready.}} + [concat $after {set ui_status_value {Ready.}}] } else { show_diff $path $w $lno } @@ -2642,7 +2646,7 @@ bind_button3 $ui_comm "tk_popup $ctxm %X %Y" # -- Diff Header set current_diff {} set diff_actions [list] -proc current_diff_trace {varname args} { +proc trace_current_diff {varname args} { global current_diff diff_actions file_states if {$current_diff eq {}} { set s {} @@ -2664,7 +2668,7 @@ proc current_diff_trace {varname args} { uplevel #0 $w $o } } -trace add variable current_diff write current_diff_trace +trace add variable current_diff write trace_current_diff frame .vpane.lower.diff.header -background orange label .vpane.lower.diff.header.status \ -- cgit v1.2.1 From b67651129897738496a9dcd3c01129a42acd11db Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 18 Nov 2006 03:08:51 -0500 Subject: git-gui: Refactor file state representations. It just felt wrong to me that I was using _ as part of the mode argument to display_file to mean "don't care/use existing" and * as part of the mode argument to mean "force to _". So instead use ? to mean "don't care/use existing" and _ to mean "force to _". The code is a lot clearer this way and hopefully it won't drive another developer insane, as it did me. Signed-off-by: Shawn O. Pearce --- git-gui | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 62545b709..901d93236 100755 --- a/git-gui +++ b/git-gui @@ -378,7 +378,7 @@ proc read_diff_index {fd after} { incr z2 -1 display_file \ [string range $buf_rdi $z1 $z2] \ - [string index $buf_rdi [expr {$z1 - 2}]]_ + [string index $buf_rdi [expr {$z1 - 2}]]? incr c } if {$c < $n} { @@ -407,7 +407,7 @@ proc read_diff_files {fd after} { incr z2 -1 display_file \ [string range $buf_rdf $z1 $z2] \ - _[string index $buf_rdf [expr {$z1 - 2}]] + ?[string index $buf_rdf [expr {$z1 - 2}]] incr c } if {$c < $n} { @@ -426,7 +426,7 @@ proc read_ls_others {fd after} { set pck [split $buf_rlo "\0"] set buf_rlo [lindex $pck end] foreach p [lrange $pck 0 end-1] { - display_file $p _O + display_file $p ?O } rescan_done $fd buf_rlo $after } @@ -1151,15 +1151,15 @@ proc merge_state {path new_state} { set icon [lindex $info 1] } - if {$s0 eq {_}} { + if {$s0 eq {?}} { set s0 [string index $state 0] - } elseif {$s0 eq {*}} { + } elseif {$s0 eq {_}} { set s0 _ } - if {$s1 eq {_}} { + if {$s1 eq {?}} { set s1 [string index $state 1] - } elseif {$s1 eq {*}} { + } elseif {$s1 eq {_}} { set s1 _ } @@ -1303,15 +1303,15 @@ proc write_update_index {fd pathList totalCnt batch msg after} { switch -glob -- [lindex $file_states($path) 0] { AD - MD - - _D {set new D*} + _D {set new D_} _M - MM - - M_ {set new M*} + M_ {set new M_} _O - AM - - A_ {set new A*} + A_ {set new A_} ?? {continue} } -- cgit v1.2.1 From c4ed879fc2b64b6c6f8a42bd156b2e4bd18e9420 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 18 Nov 2006 03:24:20 -0500 Subject: git-gui: Add menu option to include only selected files. When the user selects a number of files they would typically expect to be able to act on that selection, such as by including those files into the next commit. So we now have a menu option under the Commit menu that lets the user include only the selection, rather than everything. If there is no selection but there is a file in the diff viewer than we consider that to be the selection (a selection of 1). Unfortunately we don't disable this option yet when there's nothing selected to include, but this is probably not a big deal as there are very few situations where there are no selected files. Signed-off-by: Shawn O. Pearce --- git-gui | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 901d93236..a02089502 100755 --- a/git-gui +++ b/git-gui @@ -1853,14 +1853,14 @@ proc do_rescan {} { rescan {set ui_status_value {Ready.}} } -proc do_include_all {} { +proc include_helper {txt paths} { global file_states current_diff if {![lock_index begin-update]} return set pathList [list] set after {} - foreach path [array names file_states] { + foreach path $paths { switch -- [lindex $file_states($path) 0] { AM - MM - @@ -1877,12 +1877,33 @@ proc do_include_all {} { unlock_index } else { update_index \ - "Including all modified files" \ + $txt \ $pathList \ [concat $after {set ui_status_value {Ready to commit.}}] } } +proc do_include_selection {} { + global current_diff selected_paths + + if {[array size selected_paths] > 0} { + include_helper \ + {Including selected files} \ + [array names selected_paths] + } elseif {$current_diff ne {}} { + include_helper \ + "Including [short_path $current_diff]" \ + [list $current_diff] + } +} + +proc do_include_all {} { + global file_states + include_helper \ + {Including all modified files} \ + [array names file_states] +} + set GIT_COMMITTER_IDENT {} proc do_signoff {} { @@ -2442,6 +2463,11 @@ lappend disable_on_lock \ -font font_ui lappend disable_on_lock \ [list .mbar.commit entryconf [.mbar.commit index last] -state] +.mbar.commit add command -label {Include Selected Files} \ + -command do_include_selection \ + -font font_ui +lappend disable_on_lock \ + [list .mbar.commit entryconf [.mbar.commit index last] -state] .mbar.commit add command -label {Include All Files} \ -command do_include_all \ -accelerator $M1T-I \ -- cgit v1.2.1 From a49c67d1ff9861d80bae57642d891016ea5debd5 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 18 Nov 2006 03:27:23 -0500 Subject: git-gui: Misc. comment formatting cleanups. Signed-off-by: Shawn O. Pearce --- git-gui | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index a02089502..c2b4dd706 100755 --- a/git-gui +++ b/git-gui @@ -202,11 +202,6 @@ set last_clicked {} set disable_on_lock [list] set index_lock_type none -set HEAD {} -set PARENT {} -set commit_type {} -set empty_tree {} - proc lock_index {type} { global index_lock_type disable_on_lock @@ -2374,6 +2369,7 @@ apply_config ## ui construction # -- Menu Bar +# menu .mbar -tearoff 0 .mbar add cascade -label Project -menu .mbar.project .mbar add cascade -label Edit -menu .mbar.edit @@ -2386,6 +2382,7 @@ if {!$single_commit} { . configure -menu .mbar # -- Project Menu +# menu .mbar.project .mbar.project add command -label Visualize \ -command do_gitk \ @@ -2451,6 +2448,7 @@ menu .mbar.edit -font font_ui # -- Commit Menu +# menu .mbar.commit .mbar.commit add command -label Rescan \ -command do_rescan \ @@ -2485,24 +2483,23 @@ lappend disable_on_lock \ lappend disable_on_lock \ [list .mbar.commit entryconf [.mbar.commit index last] -state] +# -- Transport menus +# if {!$single_commit} { - # -- Fetch Menu menu .mbar.fetch - - # -- Pull Menu menu .mbar.pull - - # -- Push Menu menu .mbar.push } # -- Main Window Layout +# panedwindow .vpane -orient vertical panedwindow .vpane.files -orient horizontal .vpane add .vpane.files -sticky nsew -height 100 -width 400 pack .vpane -anchor n -side top -fill both -expand 1 # -- Index File List +# frame .vpane.files.index -height 100 -width 400 label .vpane.files.index.title -text {Modified Files} \ -background green \ @@ -2520,6 +2517,7 @@ pack $ui_index -side left -fill both -expand 1 .vpane.files add .vpane.files.index -sticky nsew # -- Other (Add) File List +# frame .vpane.files.other -height 100 -width 100 label .vpane.files.other.title -text {Untracked Files} \ -background red \ @@ -2545,6 +2543,7 @@ foreach i [list $ui_index $ui_other] { unset i # -- Diff and Commit Area +# frame .vpane.lower -height 300 -width 400 frame .vpane.lower.commarea frame .vpane.lower.diff -relief sunken -borderwidth 1 @@ -2553,6 +2552,7 @@ pack .vpane.lower.diff -side bottom -fill both -expand 1 .vpane add .vpane.lower -stick nsew # -- Commit Area Buttons +# frame .vpane.lower.commarea.buttons label .vpane.lower.commarea.buttons.l -text {} \ -anchor w \ @@ -2595,10 +2595,11 @@ lappend disable_on_lock \ {.vpane.lower.commarea.buttons.commit conf -state} # -- Commit Message Buffer +# frame .vpane.lower.commarea.buffer set ui_comm .vpane.lower.commarea.buffer.t set ui_coml .vpane.lower.commarea.buffer.l -label $ui_coml -text {Commit Message:} \ +label $ui_coml \ -anchor w \ -justify left \ -font font_ui @@ -2670,6 +2671,7 @@ $ctxm add command \ bind_button3 $ui_comm "tk_popup $ctxm %X %Y" # -- Diff Header +# set current_diff {} set diff_actions [list] proc trace_current_diff {varname args} { @@ -2732,6 +2734,7 @@ lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state] bind_button3 .vpane.lower.diff.header.path "tk_popup $ctxm %X %Y" # -- Diff Body +# frame .vpane.lower.diff.body set ui_diff .vpane.lower.diff.body.t text $ui_diff -background white -borderwidth 0 \ @@ -2888,6 +2891,11 @@ unset i set file_lists($ui_index) [list] set file_lists($ui_other) [list] + +set HEAD {} +set PARENT {} +set commit_type {} +set empty_tree {} set current_diff {} wm title . "$appname ([file normalize [file dirname $gitdir]])" -- cgit v1.2.1 From 53716a7bc94497cd6d2dfd53b1e4f7669d677b01 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 18 Nov 2006 03:31:25 -0500 Subject: git-gui: Start UI with the index locked. Because we immediately start a rescan operation, but do so slightly delayed (by 1 ms, to let the UI show before we start forking off git processes), we can't let the user try to activate any of the restricted GUI commands before the 1 ms timer expires and we kick off the rescan. So now we lock the index before we enter the Tk event loop, ensuring that it is impossible for the user to inject a conflicting UI event before our rescan can begin. Signed-off-by: Shawn O. Pearce --- git-gui | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index c2b4dd706..4850e78ab 100755 --- a/git-gui +++ b/git-gui @@ -211,7 +211,7 @@ proc lock_index {type} { uplevel #0 $w disabled } return 1 - } elseif {$index_lock_type eq {begin-update} && $type eq {update}} { + } elseif {$index_lock_type eq "begin-$type"} { set index_lock_type $type return 1 } @@ -2906,4 +2906,5 @@ if {!$single_commit} { populate_pull_menu .mbar.pull populate_push_menu .mbar.push } +lock_index begin-read after 1 do_rescan -- cgit v1.2.1 From 24ac9b752d6df7ab309826d487fbeaae53806025 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 18 Nov 2006 20:59:49 -0500 Subject: git-gui: Toggle between new commit and amend commit modes. I was starting to find it annoying that once you entered the 'Amend Last' mode there was no way to go back to the 'New Commit' mode without quitting and restarting git-gui. Its just confusing for the end-user. Now we can flip back and forth between a new commit and an amend commit through a pair of radio buttons on the header of the commit buffer area and through a pair of radio menu buttons in the Commit menu. Signed-off-by: Shawn O. Pearce --- git-gui | 97 +++++++++++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 79 insertions(+), 18 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 4850e78ab..5c6af8940 100755 --- a/git-gui +++ b/git-gui @@ -722,6 +722,16 @@ proc load_last_commit {} { rescan {set ui_status_value {Ready.}} } +proc create_new_commit {} { + global commit_type ui_comm + + set commit_type normal + $ui_comm delete 0.0 end + $ui_comm edit modified false + $ui_comm edit reset + rescan {set ui_status_value {Ready.}} +} + proc commit_tree {} { global HEAD commit_type file_states ui_comm repo_config @@ -880,7 +890,7 @@ proc commit_writetree {curHEAD msg} { proc commit_committree {fd_wt curHEAD msg} { global single_commit gitdir HEAD PARENT commit_type tcl_platform - global ui_status_value ui_comm + global ui_status_value ui_comm selected_commit_type global file_states selected_paths gets $fd_wt tree_id @@ -980,6 +990,7 @@ proc commit_committree {fd_wt curHEAD msg} { # -- Update status without invoking any git commands. # set commit_type normal + set selected_commit_type new set HEAD $cmt_id set PARENT $cmt_id @@ -1065,13 +1076,14 @@ Commit or throw away all changes before starting a pull operation. } proc post_pull_remote {remote branch success} { - global HEAD PARENT commit_type + global HEAD PARENT commit_type selected_commit_type global ui_status_value unlock_index if {$success} { repository_state HEAD commit_type set PARENT $HEAD + set selected_commit_type new set $ui_status_value "Pulling $branch from $remote complete." } else { set m "Conflicts detected while pulling $branch from $remote." @@ -1930,8 +1942,22 @@ proc do_signoff {} { } } -proc do_amend_last {} { - load_last_commit +proc do_select_commit_type {} { + global commit_type selected_commit_type + + if {$selected_commit_type eq {new} + && [string match amend* $commit_type]} { + create_new_commit + } elseif {$selected_commit_type eq {amend} + && ![string match amend* $commit_type]} { + load_last_commit + + # The amend request was rejected... + # + if {![string match amend* $commit_type]} { + set commit_type new + } + } } proc do_commit {} { @@ -2450,32 +2476,52 @@ menu .mbar.edit # -- Commit Menu # menu .mbar.commit -.mbar.commit add command -label Rescan \ - -command do_rescan \ - -accelerator F5 \ + +.mbar.commit add radiobutton \ + -label {New Commit} \ + -command do_select_commit_type \ + -variable selected_commit_type \ + -value new \ + -font font_ui +lappend disable_on_lock \ + [list .mbar.commit entryconf [.mbar.commit index last] -state] + +.mbar.commit add radiobutton \ + -label {Amend Last Commit} \ + -command do_select_commit_type \ + -variable selected_commit_type \ + -value amend \ -font font_ui lappend disable_on_lock \ [list .mbar.commit entryconf [.mbar.commit index last] -state] -.mbar.commit add command -label {Amend Last Commit} \ - -command do_amend_last \ + +.mbar.commit add separator + +.mbar.commit add command -label Rescan \ + -command do_rescan \ + -accelerator F5 \ -font font_ui lappend disable_on_lock \ [list .mbar.commit entryconf [.mbar.commit index last] -state] + .mbar.commit add command -label {Include Selected Files} \ -command do_include_selection \ -font font_ui lappend disable_on_lock \ [list .mbar.commit entryconf [.mbar.commit index last] -state] + .mbar.commit add command -label {Include All Files} \ -command do_include_all \ -accelerator $M1T-I \ -font font_ui lappend disable_on_lock \ [list .mbar.commit entryconf [.mbar.commit index last] -state] + .mbar.commit add command -label {Sign Off} \ -command do_signoff \ -accelerator $M1T-S \ -font font_ui + .mbar.commit add command -label Commit \ -command do_commit \ -accelerator $M1T-Return \ @@ -2568,13 +2614,6 @@ pack .vpane.lower.commarea.buttons.rescan -side top -fill x lappend disable_on_lock \ {.vpane.lower.commarea.buttons.rescan conf -state} -button .vpane.lower.commarea.buttons.amend -text {Amend Last} \ - -command do_amend_last \ - -font font_ui -pack .vpane.lower.commarea.buttons.amend -side top -fill x -lappend disable_on_lock \ - {.vpane.lower.commarea.buttons.amend conf -state} - button .vpane.lower.commarea.buttons.incall -text {Include All} \ -command do_include_all \ -font font_ui @@ -2597,8 +2636,25 @@ lappend disable_on_lock \ # -- Commit Message Buffer # frame .vpane.lower.commarea.buffer +frame .vpane.lower.commarea.buffer.header set ui_comm .vpane.lower.commarea.buffer.t -set ui_coml .vpane.lower.commarea.buffer.l +set ui_coml .vpane.lower.commarea.buffer.header.l +radiobutton .vpane.lower.commarea.buffer.header.new \ + -text {New Commit} \ + -command do_select_commit_type \ + -variable selected_commit_type \ + -value new \ + -font font_ui +lappend disable_on_lock \ + [list .vpane.lower.commarea.buffer.header.new conf -state] +radiobutton .vpane.lower.commarea.buffer.header.amend \ + -text {Amend Last Commit} \ + -command do_select_commit_type \ + -variable selected_commit_type \ + -value amend \ + -font font_ui +lappend disable_on_lock \ + [list .vpane.lower.commarea.buffer.header.amend conf -state] label $ui_coml \ -anchor w \ -justify left \ @@ -2615,6 +2671,10 @@ proc trace_commit_type {varname args} { $ui_coml conf -text $txt } trace add variable commit_type write trace_commit_type +pack $ui_coml -side left -fill x +pack .vpane.lower.commarea.buffer.header.amend -side right +pack .vpane.lower.commarea.buffer.header.new -side right + text $ui_comm -background white -borderwidth 1 \ -undo true \ -maxundo 20 \ @@ -2625,7 +2685,7 @@ text $ui_comm -background white -borderwidth 1 \ -yscrollcommand {.vpane.lower.commarea.buffer.sby set} scrollbar .vpane.lower.commarea.buffer.sby \ -command [list $ui_comm yview] -pack $ui_coml -side top -fill x +pack .vpane.lower.commarea.buffer.header -side top -fill x pack .vpane.lower.commarea.buffer.sby -side right -fill y pack $ui_comm -side left -fill y pack .vpane.lower.commarea.buffer -side left -fill y @@ -2897,6 +2957,7 @@ set PARENT {} set commit_type {} set empty_tree {} set current_diff {} +set selected_commit_type new wm title . "$appname ([file normalize [file dirname $gitdir]])" focus -force $ui_comm -- cgit v1.2.1 From d63efae2816a277e40a379eb5c5f23f2a656fddc Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 18 Nov 2006 21:07:05 -0500 Subject: git-gui: Verify the user has GIT_COMMITTER_IDENT before comitting. Since git-commit also checks that the user has a GIT_COMMITTER_IDENT value before it lets the user make a commit we should do the same check here in git-gui. We cache the result and assume that the user won't do something which would change the status of GIT_COMMITTER_IDENT while we are running. Signed-off-by: Shawn O. Pearce --- git-gui | 40 +++++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 15 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 5c6af8940..7630a2d2e 100755 --- a/git-gui +++ b/git-gui @@ -732,10 +732,31 @@ proc create_new_commit {} { rescan {set ui_status_value {Ready.}} } +set GIT_COMMITTER_IDENT {} + +proc committer_ident {} { + global GIT_COMMITTER_IDENT + + if {$GIT_COMMITTER_IDENT eq {}} { + if {[catch {set me [exec git var GIT_COMMITTER_IDENT]} err]} { + error_popup "Unable to obtain your identity:\n\n$err" + return {} + } + if {![regexp {^(.*) [0-9]+ [-+0-9]+$} \ + $me me GIT_COMMITTER_IDENT]} { + error_popup "Invalid GIT_COMMITTER_IDENT:\n\n$me" + return {} + } + } + + return $GIT_COMMITTER_IDENT +} + proc commit_tree {} { global HEAD commit_type file_states ui_comm repo_config if {![lock_index update]} return + if {[committer_ident] eq {}} return # -- Our in memory state should match the repository. # @@ -1911,24 +1932,13 @@ proc do_include_all {} { [array names file_states] } -set GIT_COMMITTER_IDENT {} - proc do_signoff {} { - global ui_comm GIT_COMMITTER_IDENT + global ui_comm - if {$GIT_COMMITTER_IDENT eq {}} { - if {[catch {set me [exec git var GIT_COMMITTER_IDENT]} err]} { - error_popup "Unable to obtain your identity:\n\n$err" - return - } - if {![regexp {^(.*) [0-9]+ [-+0-9]+$} \ - $me me GIT_COMMITTER_IDENT]} { - error_popup "Invalid GIT_COMMITTER_IDENT:\n\n$me" - return - } - } + set me [committer_ident] + if {$me eq {}} return - set sob "Signed-off-by: $GIT_COMMITTER_IDENT" + set sob "Signed-off-by: $me" set last [$ui_comm get {end -1c linestart} {end -1c}] if {$last ne $sob} { $ui_comm edit separator -- cgit v1.2.1 From bca680b054ffa736e876075fad358bee1caa898a Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 18 Nov 2006 21:13:16 -0500 Subject: git-gui: Rephrase rescan before commit informational message. Its not an error that a rescan is required before commit; its just something we do as a safety feature to try and ensure the user knows what is going into this commit. So the dialog should use the info icon (if one is used by the host OS) rather than the error icon. Its also not "highly likely" that another Git program modified the repository, its completely the case. There is no reason why the repository would not match our last scanned state unless another Git program modified the repository (or someone else did so by hand). So don't be vague about it, own up to the issue and go on with our business. Signed-off-by: Shawn O. Pearce --- git-gui | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 7630a2d2e..23efe4742 100755 --- a/git-gui +++ b/git-gui @@ -765,13 +765,13 @@ proc commit_tree {} { && $cur_type eq {normal} && $curHEAD eq $HEAD} { } elseif {$commit_type ne $cur_type || $HEAD ne $curHEAD} { - error_popup {Last scanned state does not match repository state. + info_popup {Last scanned state does not match repository state. -Its highly likely that another Git program modified the -repository since the last scan. A rescan is required -before committing. +Another Git program has modified this repository +since the last scan. A rescan must be performed +before another commit can be created. -A rescan will be automatically started now. +The rescan will be automatically started now. } unlock_index rescan {set ui_status_value {Ready.}} -- cgit v1.2.1 From 54896cf7c150038bd286b909897673f85c691abc Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 18 Nov 2006 21:33:04 -0500 Subject: git-gui: Allow adding untracked files in selection. The previous implementation of do_include_selection did not actually add files in state _O (untracked, not added) into the repository when they were in the selection and Commit->Include Selected Files was used. This was due to the file state filtering logic being the same as that of Commit->Include All Files, which only considers existing files. Also fixed a minor issue with rejected attempts to amend an initial commit. Signed-off-by: Shawn O. Pearce --- git-gui | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 23efe4742..d1054f663 100755 --- a/git-gui +++ b/git-gui @@ -1891,9 +1891,13 @@ proc include_helper {txt paths} { foreach path $paths { switch -- [lindex $file_states($path) 0] { AM - + AD - MM - + UM - + U_ - _M - - _D { + _D - + _O { lappend pathList $path if {$path eq $current_diff} { set after {reshow_diff;} @@ -1927,9 +1931,20 @@ proc do_include_selection {} { proc do_include_all {} { global file_states + + set paths [list] + foreach path [array names file_states] { + switch -- [lindex $file_states($path) 0] { + AM - + AD - + MM - + _M - + _D {lappend paths $path} + } + } include_helper \ {Including all modified files} \ - [array names file_states] + $paths } proc do_signoff {} { @@ -1965,7 +1980,7 @@ proc do_select_commit_type {} { # The amend request was rejected... # if {![string match amend* $commit_type]} { - set commit_type new + set selected_commit_type new } } } -- cgit v1.2.1 From d7c0d7c86191925dcd0dfff353823f9f7e473de5 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 18 Nov 2006 23:17:41 -0500 Subject: git-gui: Don't create PkgInfo on Mac OS X "desktop icons". Turns out that we really don't need the Contents/PkgInfo file on Mac OS 10.4. The Finder will still launch the application properly without one. Signed-off-by: Shawn O. Pearce --- git-gui | 4 ---- 1 file changed, 4 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index d1054f663..063d83c12 100755 --- a/git-gui +++ b/git-gui @@ -2216,10 +2216,6 @@ proc do_macosx_app {} { file mkdir $MacOS - set fd [open [file join $Contents PkgInfo] w] - puts -nonewline $fd {APPL????} - close $fd - set fd [open [file join $Contents Info.plist] w] puts $fd { -- cgit v1.2.1 From 1461c5f3d0634f6fad0013eba1ef1087a38cc748 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sun, 19 Nov 2006 00:29:55 -0500 Subject: git-gui: Teach the gui how to uninclude a file. Sometimes the user may want to keep their working directory file to be the same content but they don't want it to be part of the current commit anymore. In this case we need to undo any changes made to the index for that file (by reloading the info from HEAD or removing the file from the index) but leave the working directory alone. Signed-off-by: Shawn O. Pearce --- git-gui | 185 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 157 insertions(+), 28 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 063d83c12..6b886c64c 100755 --- a/git-gui +++ b/git-gui @@ -1,4 +1,3 @@ -#!/bin/sh # Tcl ignores the next line -*- tcl -*- \ exec wish "$0" -- "$@" @@ -369,12 +368,14 @@ proc read_diff_index {fd after} { set z2 [string first "\0" $buf_rdi $z1] if {$z2 == -1} break - set c $z2 - incr z2 -1 - display_file \ - [string range $buf_rdi $z1 $z2] \ - [string index $buf_rdi [expr {$z1 - 2}]]? incr c + set n [split [string range $buf_rdi $c [expr {$z1 - 2}]] { }] + merge_state \ + [string range $buf_rdi $z1 [expr {$z2 - 1}]] \ + [lindex $n 4]? \ + [list [lindex $n 0] [lindex $n 2]] \ + [list] + set c $z2 } if {$c < $n} { set buf_rdi [string range $buf_rdi $c end] @@ -398,12 +399,14 @@ proc read_diff_files {fd after} { set z2 [string first "\0" $buf_rdf $z1] if {$z2 == -1} break - set c $z2 - incr z2 -1 - display_file \ - [string range $buf_rdf $z1 $z2] \ - ?[string index $buf_rdf [expr {$z1 - 2}]] incr c + set n [split [string range $buf_rdf $c [expr {$z1 - 2}]] { }] + merge_state \ + [string range $buf_rdf $z1 [expr {$z2 - 1}]] \ + ?[lindex $n 4] \ + [list] \ + [list [lindex $n 0] [lindex $n 2]] + set c $z2 } if {$c < $n} { set buf_rdf [string range $buf_rdf $c end] @@ -421,7 +424,7 @@ proc read_ls_others {fd after} { set pck [split $buf_rlo "\0"] set buf_rlo [lindex $pck end] foreach p [lrange $pck 0 end-1] { - display_file $p ?O + merge_state $p ?O } rescan_done $fd buf_rlo $after } @@ -1165,7 +1168,7 @@ proc short_path {path} { set next_icon_id 0 -proc merge_state {path new_state} { +proc merge_state {path new_state {head_info {}} {index_info {}}} { global file_states next_icon_id set s0 [string index $new_state 0] @@ -1177,30 +1180,31 @@ proc merge_state {path new_state} { } else { set state [lindex $info 0] set icon [lindex $info 1] + if {$head_info eq {}} {set head_info [lindex $info 2]} + if {$index_info eq {}} {set index_info [lindex $info 3]} } - if {$s0 eq {?}} { - set s0 [string index $state 0] - } elseif {$s0 eq {_}} { - set s0 _ - } + if {$s0 eq {?}} {set s0 [string index $state 0]} \ + elseif {$s0 eq {_}} {set s0 _} + + if {$s1 eq {?}} {set s1 [string index $state 1]} \ + elseif {$s1 eq {_}} {set s1 _} - if {$s1 eq {?}} { - set s1 [string index $state 1] - } elseif {$s1 eq {_}} { - set s1 _ + if {$s0 ne {_} && [string index $state 0] eq {_} + && $head_info eq {}} { + set head_info $index_info } - set file_states($path) [list $s0$s1 $icon] + set file_states($path) [list $s0$s1 $icon \ + $head_info $index_info \ + ] return $state } proc display_file {path state} { - global file_states file_lists selected_paths rescan_active + global file_states file_lists selected_paths set old_m [merge_state $path $state] - if {$rescan_active > 0} return - set s $file_states($path) set new_m [lindex $s 0] set new_w [mapcol $new_m $path] @@ -1278,6 +1282,80 @@ proc display_all_files {} { $ui_other conf -state disabled } +proc update_indexinfo {msg pathList after} { + global update_index_cp ui_status_value + + if {![lock_index update]} return + + set update_index_cp 0 + set pathList [lsort $pathList] + set totalCnt [llength $pathList] + set batch [expr {int($totalCnt * .01) + 1}] + if {$batch > 25} {set batch 25} + + set ui_status_value [format \ + "$msg... %i/%i files (%.2f%%)" \ + $update_index_cp \ + $totalCnt \ + 0.0] + set fd [open "| git update-index -z --index-info" w] + fconfigure $fd \ + -blocking 0 \ + -buffering full \ + -buffersize 512 \ + -translation binary + fileevent $fd writable [list \ + write_update_indexinfo \ + $fd \ + $pathList \ + $totalCnt \ + $batch \ + $msg \ + $after \ + ] +} + +proc write_update_indexinfo {fd pathList totalCnt batch msg after} { + global update_index_cp ui_status_value + global file_states current_diff + + if {$update_index_cp >= $totalCnt} { + close $fd + unlock_index + uplevel #0 $after + return + } + + for {set i $batch} \ + {$update_index_cp < $totalCnt && $i > 0} \ + {incr i -1} { + set path [lindex $pathList $update_index_cp] + incr update_index_cp + + set s $file_states($path) + switch -glob -- [lindex $s 0] { + A? {set new _O} + M? {set new _M} + D? {set new _?} + ?? {continue} + } + set info [lindex $s 2] + if {$info eq {}} continue + + puts -nonewline $fd $info + puts -nonewline $fd "\t" + puts -nonewline $fd $path + puts -nonewline $fd "\0" + display_file $path $new + } + + set ui_status_value [format \ + "$msg... %i/%i files (%.2f%%)" \ + $update_index_cp \ + $totalCnt \ + [expr {100.0 * $update_index_cp / $totalCnt}]] +} + proc update_index {msg pathList after} { global update_index_cp ui_status_value @@ -1881,6 +1959,49 @@ proc do_rescan {} { rescan {set ui_status_value {Ready.}} } +proc remove_helper {txt paths} { + global file_states current_diff + + if {![lock_index begin-update]} return + + set pathList [list] + set after {} + foreach path $paths { + switch -glob -- [lindex $file_states($path) 0] { + A? - + M? - + D? { + lappend pathList $path + if {$path eq $current_diff} { + set after {reshow_diff;} + } + } + } + } + if {$pathList eq {}} { + unlock_index + } else { + update_indexinfo \ + $txt \ + $pathList \ + [concat $after {set ui_status_value {Ready.}}] + } +} + +proc do_remove_selection {} { + global current_diff selected_paths + + if {[array size selected_paths] > 0} { + remove_helper \ + {Removing selected files from commit} \ + [array names selected_paths] + } elseif {$current_diff ne {}} { + remove_helper \ + "Removing [short_path $current_diff] from commit" \ + [list $current_diff] + } +} + proc include_helper {txt paths} { global file_states current_diff @@ -2525,19 +2646,27 @@ lappend disable_on_lock \ lappend disable_on_lock \ [list .mbar.commit entryconf [.mbar.commit index last] -state] -.mbar.commit add command -label {Include Selected Files} \ +.mbar.commit add command -label {Remove From Commit} \ + -command do_remove_selection \ + -font font_ui +lappend disable_on_lock \ + [list .mbar.commit entryconf [.mbar.commit index last] -state] + +.mbar.commit add command -label {Include In Commit} \ -command do_include_selection \ -font font_ui lappend disable_on_lock \ [list .mbar.commit entryconf [.mbar.commit index last] -state] -.mbar.commit add command -label {Include All Files} \ +.mbar.commit add command -label {Include All} \ -command do_include_all \ -accelerator $M1T-I \ -font font_ui lappend disable_on_lock \ [list .mbar.commit entryconf [.mbar.commit index last] -state] +.mbar.commit add separator + .mbar.commit add command -label {Sign Off} \ -command do_signoff \ -accelerator $M1T-S \ -- cgit v1.2.1 From 74d18d2edfc84d35b20e1b4520e496aadc14c365 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sun, 19 Nov 2006 00:37:49 -0500 Subject: git-gui: Make consecutive icon clicks toggle included status of a file. If the user clicks on the icon associated with a file we now flip to the inverse status. Partially included files first fully include, then fully uninclude, as we don't keep track of intermediate partial inclusions. Signed-off-by: Shawn O. Pearce --- git-gui | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 6b886c64c..7126f8d89 100755 --- a/git-gui +++ b/git-gui @@ -2387,7 +2387,7 @@ proc do_macosx_app {} { } proc toggle_or_diff {w x y} { - global file_lists current_diff ui_index ui_other + global file_states file_lists current_diff ui_index ui_other global last_clicked selected_paths set pos [split [$w index @$x,$y] .] @@ -2410,10 +2410,23 @@ proc toggle_or_diff {w x y} { } else { set after {} } - update_index \ - "Including [short_path $path]" \ - [list $path] \ - [concat $after {set ui_status_value {Ready.}}] + switch -glob -- [lindex $file_states($path) 0] { + A_ - + AO - + M_ - + D_ { + update_indexinfo \ + "Removing [short_path $path] from commit" \ + [list $path] \ + [concat $after {set ui_status_value {Ready.}}] + } + ?? { + update_index \ + "Including [short_path $path]" \ + [list $path] \ + [concat $after {set ui_status_value {Ready.}}] + } + } } else { show_diff $path $w $lno } -- cgit v1.2.1 From dde5974ef109ed3aadfbac4d233899fb04d1c9ff Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sun, 19 Nov 2006 00:46:08 -0500 Subject: git-gui: Correct toggling of deleted file status. There was a bug with the way we handled deleted file status. A file really shouldn't be in D_ state when it has been deleted, instead it is really DD. Therefore we should have toggled _D to DD, not D_, thereby letting us toggle back to _D. Signed-off-by: Shawn O. Pearce --- git-gui | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 7126f8d89..7ea31e508 100755 --- a/git-gui +++ b/git-gui @@ -1022,6 +1022,8 @@ proc commit_committree {fd_wt curHEAD msg} { set s $file_states($path) set m [lindex $s 0] switch -glob -- $m { + DD - + AO {set m __} A? - M? - D? {set m _[string index $m 1]} @@ -1409,7 +1411,7 @@ proc write_update_index {fd pathList totalCnt batch msg after} { switch -glob -- [lindex $file_states($path) 0] { AD - MD - - _D {set new D_} + _D {set new DD} _M - MM - @@ -2414,6 +2416,7 @@ proc toggle_or_diff {w x y} { A_ - AO - M_ - + DD - D_ { update_indexinfo \ "Removing [short_path $path] from commit" \ -- cgit v1.2.1 From 86291555c94300b057a156d87239a6cab09511b3 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sun, 19 Nov 2006 01:00:48 -0500 Subject: git-gui: Fix list loading corruption introduced by 1461c5f3. Tcl let me assign two different types of values to the variable $n. Prior to 1461c5f3 $n was the total number of bytes in the string; but in that commit it also became the current info list for the current file. This caused $c < $n to fail as $n was now treated as 0 and we only loaded the first file in each buffer. So use a different variable, like $i, instead. Signed-off-by: Shawn O. Pearce --- git-gui | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 7ea31e508..bd22125e5 100755 --- a/git-gui +++ b/git-gui @@ -369,13 +369,14 @@ proc read_diff_index {fd after} { if {$z2 == -1} break incr c - set n [split [string range $buf_rdi $c [expr {$z1 - 2}]] { }] + set i [split [string range $buf_rdi $c [expr {$z1 - 2}]] { }] merge_state \ [string range $buf_rdi $z1 [expr {$z2 - 1}]] \ - [lindex $n 4]? \ - [list [lindex $n 0] [lindex $n 2]] \ + [lindex $i 4]? \ + [list [lindex $i 0] [lindex $i 2]] \ [list] set c $z2 + incr c } if {$c < $n} { set buf_rdi [string range $buf_rdi $c end] @@ -400,13 +401,14 @@ proc read_diff_files {fd after} { if {$z2 == -1} break incr c - set n [split [string range $buf_rdf $c [expr {$z1 - 2}]] { }] + set i [split [string range $buf_rdf $c [expr {$z1 - 2}]] { }] merge_state \ [string range $buf_rdf $z1 [expr {$z2 - 1}]] \ - ?[lindex $n 4] \ + ?[lindex $i 4] \ [list] \ - [list [lindex $n 0] [lindex $n 2]] + [list [lindex $i 0] [lindex $i 2]] set c $z2 + incr c } if {$c < $n} { set buf_rdf [string range $buf_rdf $c end] -- cgit v1.2.1 From 0d5709cf88e9f242e0e31ccbda42a1c827c90a22 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sun, 19 Nov 2006 01:06:42 -0500 Subject: git-gui: Describe deleted symlinks in a more friendly way. Currently core-git's diff utilities report a deleted symlink as a deleted file with a mode of 120000. This is not nearly as user friendly as one might like, as the user must remember that 120000 is the UNIX mode bits for a symlink. So instead we transform the not-so-friendly message from core-git into a slightly more user friendly "deleted symlink" message. Signed-off-by: Shawn O. Pearce --- git-gui | 3 +++ 1 file changed, 3 insertions(+) (limited to 'git-gui') diff --git a/git-gui b/git-gui index bd22125e5..3f7e40835 100755 --- a/git-gui +++ b/git-gui @@ -628,6 +628,9 @@ proc read_diff {fd} { if {[string match {diff --combined *} $line]} continue if {[string match {--- *} $line]} continue if {[string match {+++ *} $line]} continue + if {$line eq {deleted file mode 120000}} { + set line "deleted symlink" + } if {[string match index* $line]} { if {[string first , $line] >= 0} { set diff_3way 1 -- cgit v1.2.1 From 51cc47fedaaea46a556aac7d4e32683abca1b57b Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sun, 19 Nov 2006 01:20:42 -0500 Subject: git-gui: Correct toggling of added/untracked status for new files. New files also lack index data from diff-files therefore we cannot use their diff-files index data when we update-index. Instead we can use the fact that Git has them hardcoded as "0 0{40}" and do the same thing ourselves. This way you can toggle an untracked file into added status and back out to untracked. Signed-off-by: Shawn O. Pearce --- git-gui | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 3f7e40835..75d1640c0 100755 --- a/git-gui +++ b/git-gui @@ -1174,9 +1174,10 @@ proc short_path {path} { } set next_icon_id 0 +set null_sha1 [string repeat 0 40] proc merge_state {path new_state {head_info {}} {index_info {}}} { - global file_states next_icon_id + global file_states next_icon_id null_sha1 set s0 [string index $new_state 0] set s1 [string index $new_state 1] @@ -1197,7 +1198,9 @@ proc merge_state {path new_state {head_info {}} {index_info {}}} { if {$s1 eq {?}} {set s1 [string index $state 1]} \ elseif {$s1 eq {_}} {set s1 _} - if {$s0 ne {_} && [string index $state 0] eq {_} + if {$s0 eq {A} && $s1 eq {_} && $head_info eq {}} { + set head_info [list 0 $null_sha1] + } elseif {$s0 ne {_} && [string index $state 0] eq {_} && $head_info eq {}} { set head_info $index_info } -- cgit v1.2.1 From 38dbe273ffb86d8dc5c90403c27c561e683ade4a Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sun, 19 Nov 2006 02:46:52 -0500 Subject: git-gui: Refactored diff line display formatting logic. The tags used for diff formatting (which I inherited from gitool) just didn't make a whole lot of sense, especially if you wanted to try to match them to the diff output you were seeing on screen. It did not help that the diff-index -c output's first two columns are also munged to make the diff output more user friendly. So this is a large refactoring of the tags used for diff display. Now our tag names match what we put in the left column of each line, which makes it easier to correlate presentation and implementation. I removed bold font usage from everything except the hunk headers as I really did not like the way bold font caused column alignments to become out of whack within the diff viewer. It also drew attention to the parts of the file which were identically changed in both the index and in the working directory, yet these are usually the parts I find myself caring the least about. So its very counter-intuitive. Lines which are changed differently by both the index and the working directory are now shown with background colors which span the entire line, making these lines easier to pick out of the diff. In general these are the lines that appear to be more interesting to me when looking at the 3-way diff as they are the ones which contain recent and quite different changes. Signed-off-by: Shawn O. Pearce --- git-gui | 80 +++++++++++++++++++++++++++++++++++------------------------------ 1 file changed, 43 insertions(+), 37 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 75d1640c0..a2a76c11d 100755 --- a/git-gui +++ b/git-gui @@ -544,7 +544,7 @@ files list, to prevent possible confusion. proc show_diff {path {w {}} {lno {}}} { global file_states file_lists - global diff_3way diff_active repo_config + global is_3way_diff diff_active repo_config global ui_diff current_diff ui_status_value if {$diff_active || ![lock_index read]} return @@ -565,7 +565,7 @@ proc show_diff {path {w {}} {lno {}}} { set s $file_states($path) set m [lindex $s 0] - set diff_3way 0 + set is_3way_diff 0 set diff_active 1 set current_diff $path set ui_status_value "Loading diff of [escape_path $path]..." @@ -620,51 +620,52 @@ proc show_diff {path {w {}} {lno {}}} { } proc read_diff {fd} { - global ui_diff ui_status_value diff_3way diff_active + global ui_diff ui_status_value is_3way_diff diff_active global repo_config + $ui_diff conf -state normal while {[gets $fd line] >= 0} { - if {[string match {diff --git *} $line]} continue + # -- Cleanup uninteresting diff header lines. + # + if {[string match {diff --git *} $line]} continue if {[string match {diff --combined *} $line]} continue - if {[string match {--- *} $line]} continue - if {[string match {+++ *} $line]} continue + if {[string match {--- *} $line]} continue + if {[string match {+++ *} $line]} continue if {$line eq {deleted file mode 120000}} { set line "deleted symlink" } - if {[string match index* $line]} { - if {[string first , $line] >= 0} { - set diff_3way 1 - } - } - $ui_diff conf -state normal - if {!$diff_3way} { - set x [string index $line 0] - switch -- $x { - "@" {set tags da} - "+" {set tags dp} - "-" {set tags dm} + # -- Automatically detect if this is a 3 way diff. + # + if {[string match {@@@ *} $line]} {set is_3way_diff 1} + + # -- Reformat a 3 way diff, 'cause its too weird. + # + if {$is_3way_diff} { + set op [string range $line 0 1] + switch -- $op { + {@@} {set tags d_@} + {++} {set tags d_+ ; set op { +}} + {--} {set tags d_- ; set op { -}} + { +} {set tags d_++; set op {++}} + { -} {set tags d_--; set op {--}} + {+ } {set tags d_-+; set op {-+}} + {- } {set tags d_+-; set op {+-}} default {set tags {}} } + set line [string replace $line 0 1 $op] } else { - set x [string range $line 0 1] - switch -- $x { - default {set tags {}} - "@@" {set tags da} - "++" {set tags dp; set x " +"} - " +" {set tags {di bold}; set x "++"} - "+ " {set tags dni; set x "-+"} - "--" {set tags dm; set x " -"} - " -" {set tags {dm bold}; set x "--"} - "- " {set tags di; set x "+-"} + switch -- [string index $line 0] { + @ {set tags d_@} + + {set tags d_+} + - {set tags d_-} default {set tags {}} } - set line [string replace $line 0 1 $x] } $ui_diff insert end $line $tags - $ui_diff insert end "\n" - $ui_diff conf -state disabled + $ui_diff insert end "\n" $tags } + $ui_diff conf -state disabled if {[eof $fd]} { close $fd @@ -2987,12 +2988,17 @@ pack $ui_diff -side left -fill both -expand 1 pack .vpane.lower.diff.header -side top -fill x pack .vpane.lower.diff.body -side bottom -fill both -expand 1 -$ui_diff tag conf dm -foreground red -$ui_diff tag conf dp -foreground blue -$ui_diff tag conf di -foreground {#00a000} -$ui_diff tag conf dni -foreground {#a000a0} -$ui_diff tag conf da -font font_diffbold -$ui_diff tag conf bold -font font_diffbold +$ui_diff tag conf d_@ -font font_diffbold +$ui_diff tag conf d_+ -foreground blue +$ui_diff tag conf d_- -foreground red +$ui_diff tag conf d_++ -foreground {#00a000} +$ui_diff tag conf d_-- -foreground {#a000a0} +$ui_diff tag conf d_+- \ + -foreground red \ + -background {light goldenrod yellow} +$ui_diff tag conf d_-+ \ + -foreground blue \ + -background azure2 # -- Diff Body Context Menu # -- cgit v1.2.1 From bd11b82db88049fc4822d52764c009cc55b55afd Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sun, 19 Nov 2006 02:57:58 -0500 Subject: git-gui: Restore the all important shebang line. Accidentally removed by an unnoticed fat finger accident in vi during commit 1461c5f3. Signed-off-by: Shawn O. Pearce --- git-gui | 1 + 1 file changed, 1 insertion(+) (limited to 'git-gui') diff --git a/git-gui b/git-gui index a2a76c11d..3f0424a33 100755 --- a/git-gui +++ b/git-gui @@ -1,3 +1,4 @@ +#!/bin/sh # Tcl ignores the next line -*- tcl -*- \ exec wish "$0" -- "$@" -- cgit v1.2.1 From a29481e2123c2fd14fbcb2531be9de16adf21779 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sun, 19 Nov 2006 03:38:48 -0500 Subject: git-gui: Update in memory states after commit. In order to allow the user to toggle include/exclude from next commit for files which were partially included in the last commit we need the current index mode+sha1 data stored in our file_states array. For any partially included file we have this information from diff-files, so we just have to copy it over to the diff-index portion of our state array. Signed-off-by: Shawn O. Pearce --- git-gui | 38 ++++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 3f0424a33..dcb25c8d6 100755 --- a/git-gui +++ b/git-gui @@ -922,7 +922,7 @@ proc commit_writetree {curHEAD msg} { proc commit_committree {fd_wt curHEAD msg} { global single_commit gitdir HEAD PARENT commit_type tcl_platform global ui_status_value ui_comm selected_commit_type - global file_states selected_paths + global file_states selected_paths rescan_active gets $fd_wt tree_id if {$tree_id eq {} || [catch {close $fd_wt} err]} { @@ -1018,7 +1018,7 @@ proc commit_committree {fd_wt curHEAD msg} { if {$single_commit} do_quit - # -- Update status without invoking any git commands. + # -- Update in memory status # set commit_type normal set selected_commit_type new @@ -1029,18 +1029,29 @@ proc commit_committree {fd_wt curHEAD msg} { set s $file_states($path) set m [lindex $s 0] switch -glob -- $m { - DD - - AO {set m __} - A? - - M? - - D? {set m _[string index $m 1]} - } - - if {$m eq {__}} { + _O - + _M - + _D {continue} + __ - + A_ - + M_ - + DD { unset file_states($path) catch {unset selected_paths($path)} - } else { - lset file_states($path) 0 $m + } + DO { + set file_states($path) [list _O [lindex $s 1] {} {}] + } + AM - + AD - + MM - + DM { + set file_states($path) [list \ + _[string index $m 1] \ + [lindex $s 1] \ + [lindex $s 3] \ + {}] + } } } @@ -1661,9 +1672,9 @@ foreach i { {AD o question "Added (but now gone)"} {_D i question "Missing"} - {D_ i removed "Removed by commit"} {DD i removed "Removed by commit"} {DO i removed "Removed (still exists)"} + {DM i removed "Removed (but modified)"} {UM i merge "Merge conflicts"} {U_ i merge "Merge conflicts"} @@ -2424,7 +2435,6 @@ proc toggle_or_diff {w x y} { } switch -glob -- [lindex $file_states($path) 0] { A_ - - AO - M_ - DD - D_ { -- cgit v1.2.1 From 375f38828e9c50ad79b6582e768db410216c2c41 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sun, 19 Nov 2006 03:46:29 -0500 Subject: git-gui: Correct some state matchings for include/remove. Signed-off-by: Shawn O. Pearce --- git-gui | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index dcb25c8d6..dcbb100fe 100755 --- a/git-gui +++ b/git-gui @@ -1676,6 +1676,7 @@ foreach i { {DO i removed "Removed (still exists)"} {DM i removed "Removed (but modified)"} + {UD i merge "Merge conflicts"} {UM i merge "Merge conflicts"} {U_ i merge "Merge conflicts"} } { @@ -2033,12 +2034,11 @@ proc include_helper {txt paths} { set pathList [list] set after {} foreach path $paths { - switch -- [lindex $file_states($path) 0] { + switch -glob -- [lindex $file_states($path) 0] { AM - AD - MM - - UM - - U_ - + U? - _M - _D - _O { @@ -2437,7 +2437,8 @@ proc toggle_or_diff {w x y} { A_ - M_ - DD - - D_ { + DO - + DM { update_indexinfo \ "Removing [short_path $path] from commit" \ [list $path] \ -- cgit v1.2.1 From f18e40a1a60d506065b6cc0e45704ce29ea0a035 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Mon, 20 Nov 2006 21:27:22 -0500 Subject: git-gui: Improve handling of merge commits. Its useful to be able to amend the last commit even if it was a merge commit, so we really should support that in the gui. We now do so by making PARENT a list. We always diff against the first parent but we create a commit consisting of the parent(s) listed in this list, in order. We also should recheck the repository state during an amend. Earlier I was bitten by this exact bug when I switched branches through a command prompt and then did not do a rescan in git-gui. When I hit "Amend Last Commit" I was surprised to see information from the prior branch appear. This was due to git-gui caching the data from the last rescan and using that data form the amend data load request, rather than the data of the current branch. Improved error text in the dialogs used to tell the user why an amend is being refused by git-gui. In general this is only during an initial commit (nothing prior to amend) and during a merge commit (it is simply too confusing to amend the last commit while also trying to complete a merge). Fixed a couple of minor bugs in the pull logic. Since this code isn't really useful nobody has recently tested it and noticed the breakage. It really needs to be rewritten anyway. Signed-off-by: Shawn O. Pearce --- git-gui | 141 +++++++++++++++++++++++++++++++++++----------------------------- 1 file changed, 78 insertions(+), 63 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index dcbb100fe..d5738baf1 100755 --- a/git-gui +++ b/git-gui @@ -231,25 +231,38 @@ proc unlock_index {} { ## ## status -proc repository_state {hdvar ctvar} { +proc repository_state {ctvar hdvar mhvar} { global gitdir - upvar $hdvar hd $ctvar ct + upvar $ctvar ct $hdvar hd $mhvar mh + + set mh [list] if {[catch {set hd [exec git rev-parse --verify HEAD]}]} { set hd {} set ct initial - } elseif {[file exists [file join $gitdir MERGE_HEAD]]} { + return + } + + set merge_head [file join $gitdir MERGE_HEAD] + if {[file exists $merge_head]} { set ct merge - } else { - set ct normal + set fd_mh [open $merge_head r] + while {[gets $fd_mh line] >= 0} { + lappend mh $line + } + close $fd_mh + return } + + set ct normal } proc PARENT {} { global PARENT empty_tree - if {$PARENT ne {}} { - return $PARENT + set p [lindex $PARENT 0] + if {$p ne {}} { + return $p } if {$empty_tree eq {}} { set empty_tree [exec git mktree << {}] @@ -258,21 +271,22 @@ proc PARENT {} { } proc rescan {after} { - global HEAD PARENT commit_type + global HEAD PARENT MERGE_HEAD commit_type global ui_index ui_other ui_status_value ui_comm global rescan_active file_states global repo_config if {$rescan_active > 0 || ![lock_index read]} return - repository_state new_HEAD new_type + repository_state newType newHEAD newMERGE_HEAD if {[string match amend* $commit_type] - && $new_type eq {normal} - && $new_HEAD eq $HEAD} { + && $newType eq {normal} + && $newHEAD eq $HEAD} { } else { - set HEAD $new_HEAD - set PARENT $new_HEAD - set commit_type $new_type + set HEAD $newHEAD + set PARENT $newHEAD + set MERGE_HEAD $newMERGE_HEAD + set commit_type $newType } array unset file_states @@ -686,23 +700,36 @@ proc read_diff {fd} { ## commit proc load_last_commit {} { - global HEAD PARENT commit_type ui_comm + global HEAD PARENT MERGE_HEAD commit_type ui_comm - if {[string match amend* $commit_type]} return - if {$commit_type ne {normal}} { - error_popup "Can't amend a $commit_type commit." + if {[llength $PARENT] == 0} { + error_popup {There is nothing to amend. + +You are about to create the initial commit. +There is no commit before this to amend. +} + return + } + + repository_state curType curHEAD curMERGE_HEAD + if {$curType eq {merge}} { + error_popup {Cannot amend while merging. + +You are currently in the middle of a merge that +has not been fully completed. You cannot amend +the prior commit unless you first abort the +current merge activity. +} return } set msg {} - set parent {} - set parent_count 0 + set parents [list] if {[catch { - set fd [open "| git cat-file commit $HEAD" r] + set fd [open "| git cat-file commit $curHEAD" r] while {[gets $fd line] > 0} { if {[string match {parent *} $line]} { - set parent [string range $line 7 end] - incr parent_count + lappend parents [string range $line 7 end] } } set msg [string trim [read $fd]] @@ -712,17 +739,13 @@ proc load_last_commit {} { return } - if {$parent_count > 1} { - error_popup {Can't amend a merge commit.} - return - } - - if {$parent_count == 0} { - set commit_type amend-initial - set PARENT {} - } elseif {$parent_count == 1} { - set commit_type amend - set PARENT $parent + set HEAD $curHEAD + set PARENT $parents + set MERGE_HEAD [list] + switch -- [llength $parents] { + 0 {set commit_type amend-initial} + 1 {set commit_type amend} + default {set commit_type amend-merge} } $ui_comm delete 0.0 end @@ -770,11 +793,11 @@ proc commit_tree {} { # -- Our in memory state should match the repository. # - repository_state curHEAD cur_type + repository_state curType curHEAD curMERGE_HEAD if {[string match amend* $commit_type] - && $cur_type eq {normal} + && $curType eq {normal} && $curHEAD eq $HEAD} { - } elseif {$commit_type ne $cur_type || $HEAD ne $curHEAD} { + } elseif {$commit_type ne $curType || $HEAD ne $curHEAD} { info_popup {Last scanned state does not match repository state. Another Git program has modified this repository @@ -920,7 +943,8 @@ proc commit_writetree {curHEAD msg} { } proc commit_committree {fd_wt curHEAD msg} { - global single_commit gitdir HEAD PARENT commit_type tcl_platform + global HEAD PARENT MERGE_HEAD commit_type + global single_commit gitdir tcl_platform global ui_status_value ui_comm selected_commit_type global file_states selected_paths rescan_active @@ -935,24 +959,12 @@ proc commit_committree {fd_wt curHEAD msg} { # -- Create the commit. # set cmd [list git commit-tree $tree_id] - if {$PARENT ne {}} { - lappend cmd -p $PARENT - } - if {$commit_type eq {merge}} { - if {[catch { - set fd_mh [open [file join $gitdir MERGE_HEAD] r] - while {[gets $fd_mh merge_head] >= 0} { - lappend cmd -p $merge_head - } - close $fd_mh - } err]} { - error_popup "Loading MERGE_HEAD failed:\n\n$err" - set ui_status_value {Commit failed.} - unlock_index - return + set parents [concat $PARENT $MERGE_HEAD] + if {[llength $parents] > 0} { + foreach p $parents { + lappend cmd -p $p } - } - if {$PARENT eq {}} { + } else { # git commit-tree writes to stderr during initial commit. lappend cmd 2>/dev/null } @@ -1020,10 +1032,11 @@ proc commit_committree {fd_wt curHEAD msg} { # -- Update in memory status # - set commit_type normal set selected_commit_type new + set commit_type normal set HEAD $cmt_id set PARENT $cmt_id + set MERGE_HEAD [list] foreach path [array names file_states] { set s $file_states($path) @@ -1081,8 +1094,8 @@ proc pull_remote {remote branch} { # -- Our in memory state should match the repository. # - repository_state curHEAD cur_type - if {$commit_type ne $cur_type || $HEAD ne $curHEAD} { + repository_state curType curHEAD curMERGE_HEAD + if {$commit_type ne $curType || $HEAD ne $curHEAD} { error_popup {Last scanned state does not match repository state. Its highly likely that another Git program modified the @@ -1120,18 +1133,18 @@ Commit or throw away all changes before starting a pull operation. } proc post_pull_remote {remote branch success} { - global HEAD PARENT commit_type selected_commit_type + global HEAD PARENT MERGE_HEAD commit_type selected_commit_type global ui_status_value unlock_index if {$success} { - repository_state HEAD commit_type + repository_state commit_type HEAD MERGE_HEAD set PARENT $HEAD set selected_commit_type new - set $ui_status_value "Pulling $branch from $remote complete." + set ui_status_value "Pulling $branch from $remote complete." } else { - set m "Conflicts detected while pulling $branch from $remote." - rescan "set ui_status_value {$m}" + rescan [list set ui_status_value \ + "Conflicts detected while pulling $branch from $remote."] } } @@ -2852,6 +2865,7 @@ proc trace_commit_type {varname args} { initial {set txt {Initial Commit Message:}} amend {set txt {Amended Commit Message:}} amend-initial {set txt {Amended Initial Commit Message:}} + amend-merge {set txt {Amended Merge Commit Message:}} merge {set txt {Merge Commit Message:}} * {set txt {Commit Message:}} } @@ -3146,6 +3160,7 @@ set file_lists($ui_other) [list] set HEAD {} set PARENT {} +set MERGE_HEAD [list] set commit_type {} set empty_tree {} set current_diff {} -- cgit v1.2.1 From 444f92d097425e8d1043a14571ebfd82c1c3b0a5 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Mon, 20 Nov 2006 21:43:41 -0500 Subject: git-gui: Allow users to run fsck-objects from the gui. I recently found a need to run fsck-objects in a number of repositories that I also use git-gui against. Tossing in a menu option to invoke fsck-objects and have its output show up in a console window is simple enough to do. We probably need to enhance the console window used by fsck-objects, like to open up the Git fsck-objects manual page and let the user see what each message means (such as "dangling commit") and to also let the user invoke prune, to cleanup any such dangling objects. But right now I'm going to ignore that problem in favor of getting other more important features implemented. Signed-off-by: Shawn O. Pearce --- git-gui | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'git-gui') diff --git a/git-gui b/git-gui index d5738baf1..2aa82781e 100755 --- a/git-gui +++ b/git-gui @@ -1954,6 +1954,15 @@ proc do_repack {} { console_exec $w $cmd } +proc do_fsck_objects {} { + set w [new_console "verify" "Verifying the object database"] + set cmd [list git fsck-objects] + lappend cmd --full + lappend cmd --cache + lappend cmd --strict + console_exec $w $cmd +} + set is_quitting 0 proc do_quit {} { @@ -2610,6 +2619,10 @@ if {!$single_commit} { -command do_repack \ -font font_ui + .mbar.project add command -label {Verify Database} \ + -command do_fsck_objects \ + -font font_ui + if {$tcl_platform(platform) eq {windows}} { .mbar.project add command \ -label {Create Desktop Icon} \ -- cgit v1.2.1 From 21d7744fbc98b526bc00138fce287565df2c0075 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Mon, 20 Nov 2006 21:59:19 -0500 Subject: git-gui: Don't save amended commit message buffer. Because we don't automatically restart in amend mode when we quit while in amend mode the commit message buffer shouldn't be saved to GITGUI_MSG as it would be misleading when the user restarts the application. Signed-off-by: Shawn O. Pearce --- git-gui | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 2aa82781e..d0176aca7 100755 --- a/git-gui +++ b/git-gui @@ -297,8 +297,8 @@ proc rescan {after} { } elseif {[load_message MERGE_MSG]} { } elseif {[load_message SQUASH_MSG]} { } - $ui_comm edit modified false $ui_comm edit reset + $ui_comm edit modified false } if {$repo_config(gui.trustmtime) eq {true}} { @@ -750,8 +750,8 @@ current merge activity. $ui_comm delete 0.0 end $ui_comm insert end $msg - $ui_comm edit modified false $ui_comm edit reset + $ui_comm edit modified false rescan {set ui_status_value {Ready.}} } @@ -760,8 +760,8 @@ proc create_new_commit {} { set commit_type normal $ui_comm delete 0.0 end - $ui_comm edit modified false $ui_comm edit reset + $ui_comm edit modified false rescan {set ui_status_value {Ready.}} } @@ -1025,8 +1025,8 @@ proc commit_committree {fd_wt curHEAD msg} { } $ui_comm delete 0.0 end - $ui_comm edit modified false $ui_comm edit reset + $ui_comm edit modified false if {$single_commit} do_quit @@ -1966,7 +1966,7 @@ proc do_fsck_objects {} { set is_quitting 0 proc do_quit {} { - global gitdir ui_comm is_quitting repo_config + global gitdir ui_comm is_quitting repo_config commit_type if {$is_quitting} return set is_quitting 1 @@ -1975,14 +1975,16 @@ proc do_quit {} { # set save [file join $gitdir GITGUI_MSG] set msg [string trim [$ui_comm get 0.0 end]] - if {[$ui_comm edit modified] && $msg ne {}} { + if {![string match amend* $commit_type] + && [$ui_comm edit modified] + && $msg ne {}} { catch { set fd [open $save w] puts $fd [string trim [$ui_comm get 0.0 end]] close $fd } - } elseif {$msg eq {} && [file exists $save]} { - file delete $save + } else { + catch {file delete $save} } # -- Stash our current window geometry into this repository. -- cgit v1.2.1 From 93a79912055dfc0cbdc974e98c705bc75950862a Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Mon, 20 Nov 2006 22:17:15 -0500 Subject: git-gui: Reworded verify console title. It would be something of a disservice to our users if we refer to fsck-objects as "verify". So instead we call it fsck-objects in the console title, and indicate that's how we are verifying the object database. We probably should call our menu option "fsck-objects" or similar but I really do think that "Verify Database" more accurately describes the action then "fsck-objects" does, especially to users who aren't file system developers. Signed-off-by: Shawn O. Pearce --- git-gui | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index d0176aca7..7f75ffeaa 100755 --- a/git-gui +++ b/git-gui @@ -1947,7 +1947,8 @@ proc do_gitk {} { } proc do_repack {} { - set w [new_console "repack" "Repacking the object database"] + set w [new_console {repack} \ + {Repacking the object database}] set cmd [list git repack] lappend cmd -a lappend cmd -d @@ -1955,7 +1956,8 @@ proc do_repack {} { } proc do_fsck_objects {} { - set w [new_console "verify" "Verifying the object database"] + set w [new_console {fsck-objects} \ + {Verifying the object database with fsck-objects}] set cmd [list git fsck-objects] lappend cmd --full lappend cmd --cache -- cgit v1.2.1 From 75e355d6bec2796ea0e69f4f4421670141ac77a2 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Mon, 20 Nov 2006 22:22:10 -0500 Subject: git-gui: Seperate out the database operations in project menu. The project menu is just too cluttered without using separator entries to split out the database operations (such as repack and verify) from the other options in the same menu. Signed-off-by: Shawn O. Pearce --- git-gui | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 7f75ffeaa..83ff5100a 100755 --- a/git-gui +++ b/git-gui @@ -2619,6 +2619,8 @@ menu .mbar.project -command do_gitk \ -font font_ui if {!$single_commit} { + .mbar.project add separator + .mbar.project add command -label {Repack Database} \ -command do_repack \ -font font_ui @@ -2627,6 +2629,8 @@ if {!$single_commit} { -command do_fsck_objects \ -font font_ui + .mbar.project add separator + if {$tcl_platform(platform) eq {windows}} { .mbar.project add command \ -label {Create Desktop Icon} \ -- cgit v1.2.1 From a4abfa62d69ff92e3159ca0fd41184f5b72e16a4 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Mon, 20 Nov 2006 23:01:47 -0500 Subject: git-gui: Rename Project menu to Repository. Since all of the actions in our Project menu actually apply to the Git concept of a repository, it is a disservice to our users to call it "project". This is especially true if Git ever gets any sort of subproject support, as the term would then most definately conflict. Signed-off-by: Shawn O. Pearce --- git-gui | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 83ff5100a..e770717b4 100755 --- a/git-gui +++ b/git-gui @@ -2602,7 +2602,7 @@ apply_config # -- Menu Bar # menu .mbar -tearoff 0 -.mbar add cascade -label Project -menu .mbar.project +.mbar add cascade -label Repository -menu .mbar.repository .mbar add cascade -label Edit -menu .mbar.edit .mbar add cascade -label Commit -menu .mbar.commit if {!$single_commit} { @@ -2612,38 +2612,38 @@ if {!$single_commit} { } . configure -menu .mbar -# -- Project Menu +# -- Repository Menu # -menu .mbar.project -.mbar.project add command -label Visualize \ +menu .mbar.repository +.mbar.repository add command -label Visualize \ -command do_gitk \ -font font_ui if {!$single_commit} { - .mbar.project add separator + .mbar.repository add separator - .mbar.project add command -label {Repack Database} \ + .mbar.repository add command -label {Repack Database} \ -command do_repack \ -font font_ui - .mbar.project add command -label {Verify Database} \ + .mbar.repository add command -label {Verify Database} \ -command do_fsck_objects \ -font font_ui - .mbar.project add separator + .mbar.repository add separator if {$tcl_platform(platform) eq {windows}} { - .mbar.project add command \ + .mbar.repository add command \ -label {Create Desktop Icon} \ -command do_windows_shortcut \ -font font_ui } elseif {[is_MacOSX]} { - .mbar.project add command \ + .mbar.repository add command \ -label {Create Desktop Icon} \ -command do_macosx_app \ -font font_ui } } -.mbar.project add command -label Quit \ +.mbar.repository add command -label Quit \ -command do_quit \ -accelerator $M1T-Q \ -font font_ui @@ -2729,7 +2729,7 @@ lappend disable_on_lock \ lappend disable_on_lock \ [list .mbar.commit entryconf [.mbar.commit index last] -state] -.mbar.commit add command -label {Include All} \ +.mbar.commit add command -label {Include All In Commit} \ -command do_include_all \ -accelerator $M1T-I \ -font font_ui -- cgit v1.2.1 From 82aa23545f84f01e83fb2164b5751b41fd449b62 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Mon, 20 Nov 2006 23:55:51 -0500 Subject: git-gui: Added about dialog box. Created a help menu with an about dialog box. This about dialog shows the copyright notice for the application, the fact that it is covered by the GPL v2.0 or later, the authors, and the current version of Git it is invoking when users perform actions within it. Signed-off-by: Shawn O. Pearce --- git-gui | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) (limited to 'git-gui') diff --git a/git-gui b/git-gui index e770717b4..57120bd2b 100755 --- a/git-gui +++ b/git-gui @@ -2159,6 +2159,55 @@ proc do_commit {} { commit_tree } +proc do_about {} { + global appname + + set w .about_dialog + toplevel $w + wm geometry $w "+[winfo rootx .]+[winfo rooty .]" + + label $w.header -text "About $appname" \ + -font font_uibold + pack $w.header -side top -fill x + + frame $w.buttons + button $w.buttons.close -text {Close} \ + -font font_ui \ + -command [list destroy $w] + pack $w.buttons.close -side right + pack $w.buttons -side bottom -fill x -pady 10 -padx 10 + + label $w.desc \ + -text "$appname - a commit creation tool for Git. + +Copyright © 2006 Shawn Pearce, Paul Mackerras + +Use and redistribute under the terms of the +GNU General Public License, v. 2.0 or later." \ + -padx 5 -pady 5 \ + -justify left \ + -anchor w \ + -borderwidth 1 \ + -relief solid \ + -font font_ui + pack $w.desc -side top -fill x -padx 5 -pady 5 + + label $w.vers \ + -text [exec git --version] \ + -padx 5 -pady 5 \ + -justify left \ + -anchor w \ + -borderwidth 1 \ + -relief solid \ + -font font_ui + pack $w.vers -side top -fill x -padx 5 -pady 5 + + bind $w "grab $w; focus $w" + bind $w "destroy $w" + wm title $w "About $appname" + tkwait window $w +} + proc do_options {} { global appname gitdir font_descs global repo_config global_config @@ -2610,6 +2659,7 @@ if {!$single_commit} { .mbar add cascade -label Pull -menu .mbar.pull .mbar add cascade -label Push -menu .mbar.push } +.mbar add cascade -label Help -menu .mbar.help . configure -menu .mbar # -- Repository Menu @@ -2758,6 +2808,14 @@ if {!$single_commit} { menu .mbar.push } +# -- Help Menm +# +menu .mbar.help + +.mbar.help add command -label "About $appname" \ + -command do_about \ + -font font_ui + # -- Main Window Layout # panedwindow .vpane -orient vertical -- cgit v1.2.1 From 0c8d7839c9dafcfd33dae2bd35b9bf4a98ffa07a Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Tue, 21 Nov 2006 02:33:56 -0500 Subject: git-gui: Be more Macintosh like. It is tradition for applications to store their about and preferences menu options within the application menu. This is the first menu in the menu bar, just after the apple menu. Apparently the way to access this menu from Tk on Mac OS X systems is to create a special menu whose name ends in ".apple" and place it into the menu bar. So now if we are on Mac OS X we move our about menu and our options menu into the application menu, like other Mac OS X applications. Signed-off-by: Shawn O. Pearce --- git-gui | 40 +++++++++++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 11 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 57120bd2b..4b07612f5 100755 --- a/git-gui +++ b/git-gui @@ -2659,7 +2659,6 @@ if {!$single_commit} { .mbar add cascade -label Pull -menu .mbar.pull .mbar add cascade -label Push -menu .mbar.push } -.mbar add cascade -label Help -menu .mbar.help . configure -menu .mbar # -- Repository Menu @@ -2731,10 +2730,6 @@ menu .mbar.edit -command {catch {[focus] tag add sel 0.0 end}} \ -accelerator $M1T-A \ -font font_ui -.mbar.edit add separator -.mbar.edit add command -label {Options...} \ - -command do_options \ - -font font_ui # -- Commit Menu # @@ -2808,13 +2803,36 @@ if {!$single_commit} { menu .mbar.push } -# -- Help Menm -# -menu .mbar.help +if {[is_MacOSX]} { + # -- Apple Menu (Mac OS X only) + # + .mbar add cascade -label Apple -menu .mbar.apple + menu .mbar.apple + + .mbar.apple add command -label "About $appname" \ + -command do_about \ + -font font_ui + .mbar.apple add command -label "$appname Options..." \ + -command do_options \ + -font font_ui +} else { + # -- Edit Menu + # + .mbar.edit add separator + .mbar.edit add command -label {Options...} \ + -command do_options \ + -font font_ui + + # -- Help Menu + # + .mbar add cascade -label Help -menu .mbar.help + menu .mbar.help + + .mbar.help add command -label "About $appname" \ + -command do_about \ + -font font_ui +} -.mbar.help add command -label "About $appname" \ - -command do_about \ - -font font_ui # -- Main Window Layout # -- cgit v1.2.1 From bdc9ea202407114737d1d58f7bef00b9579df9b7 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Tue, 21 Nov 2006 02:36:55 -0500 Subject: git-gui: Make the copyright notice serve double duty. The copyright notice we display in the about dialog should be the same as the one at the top of our source code. By putting the copyright notice that appears at the top of our source code into a global variable rather than a comment we can trivially make them the same at all times. Signed-off-by: Shawn O. Pearce --- git-gui | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 4b07612f5..b28786657 100755 --- a/git-gui +++ b/git-gui @@ -2,10 +2,15 @@ # Tcl ignores the next line -*- tcl -*- \ exec wish "$0" -- "$@" -# Copyright (C) 2006 Shawn Pearce, Paul Mackerras. All rights reserved. -# This program is free software; it may be used, copied, modified -# and distributed under the terms of the GNU General Public Licence, -# either version 2, or (at your option) any later version. +set copyright { +Copyright © 2006 Shawn Pearce, Paul Mackerras. + +All rights reserved. + +This program is free software; it may be used, copied, modified +and distributed under the terms of the GNU General Public Licence, +either version 2, or (at your option) any later version. +} set appname [lindex [file split $argv0] end] set gitdir {} @@ -2160,7 +2165,7 @@ proc do_commit {} { } proc do_about {} { - global appname + global appname copyright set w .about_dialog toplevel $w @@ -2179,11 +2184,7 @@ proc do_about {} { label $w.desc \ -text "$appname - a commit creation tool for Git. - -Copyright © 2006 Shawn Pearce, Paul Mackerras - -Use and redistribute under the terms of the -GNU General Public License, v. 2.0 or later." \ +$copyright" \ -padx 5 -pady 5 \ -justify left \ -anchor w \ -- cgit v1.2.1 From 53f7a33bdc89a6ec870fdce5221c05a2759974d3 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Tue, 21 Nov 2006 02:46:51 -0500 Subject: git-gui: Include the Tcl/Tk version in the about dialog. Users may need to know what version of Tcl they are running git-gui under, in case there is an interesting interface quirk or other compatability problem we don't know about right now that we may need to explore (and maybe fix). Since its simple enough to show a line with this version data we should do so. We also try to reduce the amount of text shown as often the Tcl and Tk version numbers will be identical; when this happens we should only show the one version number. Signed-off-by: Shawn O. Pearce --- git-gui | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index b28786657..dfdce94cf 100755 --- a/git-gui +++ b/git-gui @@ -9,8 +9,7 @@ All rights reserved. This program is free software; it may be used, copied, modified and distributed under the terms of the GNU General Public Licence, -either version 2, or (at your option) any later version. -} +either version 2, or (at your option) any later version.} set appname [lindex [file split $argv0] end] set gitdir {} @@ -2166,6 +2165,7 @@ proc do_commit {} { proc do_about {} { global appname copyright + global tcl_patchLevel tk_patchLevel set w .about_dialog toplevel $w @@ -2193,8 +2193,17 @@ $copyright" \ -font font_ui pack $w.desc -side top -fill x -padx 5 -pady 5 + set v [exec git --version] + append v "\n\n" + if {$tcl_patchLevel eq $tk_patchLevel} { + append v "Tcl/Tk version $tcl_patchLevel" + } else { + append v "Tcl version $tcl_patchLevel" + append v ", Tk version $tk_patchLevel" + } + label $w.vers \ - -text [exec git --version] \ + -text $v \ -padx 5 -pady 5 \ -justify left \ -anchor w \ -- cgit v1.2.1 From 7b85a17b86062c87ceebbf70acfbd62e00cd4bac Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Tue, 21 Nov 2006 11:57:41 -0500 Subject: git-gui: Abstract out windows platform test to is_Windows proc. Like the is_MacOSX proc we shouldn't keep repeating the platform test for Windows. Instead abstract the code out into a procedure and use the procedure whenever we need to do something special. Signed-off-by: Shawn O. Pearce --- git-gui | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index dfdce94cf..3e53fbd62 100755 --- a/git-gui +++ b/git-gui @@ -891,14 +891,14 @@ A good commit message has the following format: } proc commit_prehook {curHEAD msg} { - global tcl_platform gitdir ui_status_value pch_error + global gitdir ui_status_value pch_error + + set pchook [file join $gitdir hooks pre-commit] # On Cygwin [file executable] might lie so we need to ask # the shell if the hook is executable. Yes that's annoying. - - set pchook [file join $gitdir hooks pre-commit] - if {$tcl_platform(platform) eq {windows} - && [file isfile $pchook]} { + # + if {[is_Windows] && [file isfile $pchook]} { set pchook [list sh -c [concat \ "if test -x \"$pchook\";" \ "then exec \"$pchook\" 2>&1;" \ @@ -948,7 +948,7 @@ proc commit_writetree {curHEAD msg} { proc commit_committree {fd_wt curHEAD msg} { global HEAD PARENT MERGE_HEAD commit_type - global single_commit gitdir tcl_platform + global single_commit gitdir global ui_status_value ui_comm selected_commit_type global file_states selected_paths rescan_active @@ -1016,7 +1016,7 @@ proc commit_committree {fd_wt curHEAD msg} { # -- Run the post-commit hook. # set pchook [file join $gitdir hooks post-commit] - if {$tcl_platform(platform) eq {windows} && [file isfile $pchook]} { + if {[is_Windows] && [file isfile $pchook]} { set pchook [list sh -c [concat \ "if test -x \"$pchook\";" \ "then exec \"$pchook\";" \ @@ -1724,6 +1724,14 @@ proc is_MacOSX {} { return 0 } +proc is_Windows {} { + global tcl_platform + if {$tcl_platform(platform) eq {windows}} { + return 1 + } + return 0 +} + proc bind_button3 {w cmd} { bind $w $cmd if {[is_MacOSX]} { @@ -1854,12 +1862,10 @@ proc console_init {w} { } proc console_exec {w cmd {after {}}} { - global tcl_platform - # -- Windows tosses the enviroment when we exec our child. # But most users need that so we have to relogin. :-( # - if {$tcl_platform(platform) eq {windows}} { + if {[is_Windows]} { set cmd [list sh --login -c "cd \"[pwd]\" && [join $cmd { }]"] } @@ -1934,7 +1940,7 @@ proc console_read {w fd after} { set starting_gitk_msg {Please wait... Starting gitk...} proc do_gitk {} { - global tcl_platform ui_status_value starting_gitk_msg + global ui_status_value starting_gitk_msg set ui_status_value $starting_gitk_msg after 10000 { @@ -1943,7 +1949,7 @@ proc do_gitk {} { } } - if {$tcl_platform(platform) eq {windows}} { + if {[is_Windows]} { exec sh -c gitk & } else { exec gitk & @@ -2613,7 +2619,7 @@ font create font_diffbold set M1B M1 set M1T M1 -if {$tcl_platform(platform) eq {windows}} { +if {[is_Windows]} { set M1B Control set M1T Ctrl } elseif {[is_MacOSX]} { @@ -2690,7 +2696,7 @@ if {!$single_commit} { .mbar.repository add separator - if {$tcl_platform(platform) eq {windows}} { + if {[is_Windows]} { .mbar.repository add command \ -label {Create Desktop Icon} \ -command do_windows_shortcut \ -- cgit v1.2.1 From 3add5d3517972f6407da450fcd7dff08187cca34 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Tue, 21 Nov 2006 12:00:50 -0500 Subject: git-gui: Correct is_MacOSX platform test. Darwn based UNIX systems are not necessarily Mac OS X. However the only windowing system used by Tk that is Mac OS X is 'aqua', and only 'aqua' exists on Mac OS X. Therefore this is a more reliable test for the Macintosh platform. Signed-off-by: Shawn O. Pearce --- git-gui | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 3e53fbd62..afd9ac026 100755 --- a/git-gui +++ b/git-gui @@ -1716,9 +1716,7 @@ unset filemask i proc is_MacOSX {} { global tcl_platform tk_library - if {$tcl_platform(platform) eq {unix} - && $tcl_platform(os) eq {Darwin} - && [string match /Library/Frameworks/* $tk_library]} { + if {[tk windowingsystem] eq {aqua}} { return 1 } return 0 -- cgit v1.2.1 From 1d8b3cbf2841612791178853efbfe9ba60b48f2b Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Tue, 21 Nov 2006 15:28:14 -0500 Subject: git-gui: Warn Cygwin users about possible environment issues. Because the Tcl binary distributed with Cygwin tends to not pass along its own environment (the env array) to its children, its unlikely that any Git commands spawned by git-gui will receive the same environment variables that git-gui itself received from the shell which started it. If the user is counting on environment variables to pass down, like say GIT_INDEX_FILE, they may not, so we warn them during git-gui startup that things may not work out as the user intended. Perhaps one day when git-gui and git are running on native Windows (rather than through the Cygwin emulation layers) things will work better. Signed-off-by: Shawn O. Pearce --- git-gui | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 81 insertions(+), 1 deletion(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index afd9ac026..525314187 100755 --- a/git-gui +++ b/git-gui @@ -145,6 +145,28 @@ proc error_popup {msg} { eval $cmd } +proc warn_popup {msg} { + global gitdir appname + + set title $appname + if {$gitdir ne {}} { + append title { (} + append title [lindex \ + [file split [file normalize [file dirname $gitdir]]] \ + end] + append title {)} + } + set cmd [list tk_messageBox \ + -icon warning \ + -type ok \ + -title "$title: warning" \ + -message $msg] + if {[winfo ismapped .]} { + lappend cmd -parent . + } + eval $cmd +} + proc info_popup {msg} { global gitdir appname @@ -158,7 +180,7 @@ proc info_popup {msg} { } tk_messageBox \ -parent . \ - -icon error \ + -icon info \ -type ok \ -title $title \ -message $msg @@ -3279,6 +3301,64 @@ set selected_commit_type new wm title . "$appname ([file normalize [file dirname $gitdir]])" focus -force $ui_comm + +# -- Warn the user about environmental problems. +# Cygwin's Tcl does *not* pass its env array +# onto any processes it spawns. This means +# that the git processes get none of our +# environment. That may not work... +# +if {[is_Windows]} { + set ignored_env 0 + set suggest_user {} + set msg "Possible environment issues exist. + +The following environment variables are probably +going to be ignored by any Git subprocess run +by $appname: + +" + foreach name [array names env] { + switch -regexp -- $name { + {^GIT_INDEX_FILE$} - + {^GIT_OBJECT_DIRECTORY$} - + {^GIT_ALTERNATE_OBJECT_DIRECTORIES$} - + {^GIT_DIFF_OPTS$} - + {^GIT_EXTERNAL_DIFF$} - + {^GIT_PAGER$} - + {^GIT_TRACE$} - + {^GIT_CONFIG$} - + {^GIT_CONFIG_LOCAL$} - + {^GIT_(AUTHOR|COMMITTER)_DATE$} { + append msg " - $name\n" + incr ignored_env + } + {^GIT_(AUTHOR|COMMITTER)_(NAME|EMAIL)$} { + append msg " - $name\n" + incr ignored_env + set suggest_user $name + } + } + } + if {$ignored_env > 0} { + append msg " +This is due to a known issue with the +Tcl binary distributed by Cygwin." + + if {$suggest_user ne {}} { + append msg " + +A good replacement for $suggest_user +is placing values for the user.name and +user.email settings into your personal +~/.gitconfig file. +" + } + warn_popup $msg + } + unset ignored_env msg suggest_user name +} + if {!$single_commit} { load_all_remotes populate_fetch_menu .mbar.fetch -- cgit v1.2.1 From b673bbc59cf6950808d12b0d4020ae606019a8cd Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Tue, 21 Nov 2006 20:21:11 -0500 Subject: git-gui: Refactor M1 binding selection. Signed-off-by: Shawn O. Pearce --- git-gui | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 525314187..13b40823e 100755 --- a/git-gui +++ b/git-gui @@ -2637,14 +2637,15 @@ catch { font create font_uibold font create font_diffbold -set M1B M1 -set M1T M1 if {[is_Windows]} { set M1B Control set M1T Ctrl } elseif {[is_MacOSX]} { set M1B M1 set M1T Cmd +} else { + set M1B M1 + set M1T M1 } proc apply_config {} { -- cgit v1.2.1 From d075242923691e5f3c671f240945b0bdf26a7cd0 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Tue, 21 Nov 2006 20:33:09 -0500 Subject: git-gui: Added menu command to visualize all branches. Sometimes its useful to start gitk with the --all option, to view all of the known branches and tags within this repository. Rather than making the user startup gitk and then edit the view we can pass the option along for them. This also makes it slightly more explicit, that when gitk starts up by default its showing the current branch and not everything. Yes gitk isn't showing that to the user, but the fact that the user had to make a decision between seeing this current branch or all branches will hopefully make them study gitk's display before jumping to a conclusion. Signed-off-by: Shawn O. Pearce --- git-gui | 39 ++++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 13 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 13b40823e..ef8c7cf06 100755 --- a/git-gui +++ b/git-gui @@ -1959,20 +1959,28 @@ proc console_read {w fd after} { set starting_gitk_msg {Please wait... Starting gitk...} -proc do_gitk {} { +proc do_gitk {revs} { global ui_status_value starting_gitk_msg - set ui_status_value $starting_gitk_msg - after 10000 { - if {$ui_status_value eq $starting_gitk_msg} { - set ui_status_value {Ready.} - } + set cmd gitk + if {$revs ne {}} { + append cmd { } + append cmd $revs } - if {[is_Windows]} { - exec sh -c gitk & + set cmd "sh -c \"exec $cmd\"" + } + append cmd { &} + + if {[catch {eval exec $cmd} err]} { + error_popup "Failed to start gitk:\n\n$err" } else { - exec gitk & + set ui_status_value $starting_gitk_msg + after 10000 { + if {$ui_status_value eq $starting_gitk_msg} { + set ui_status_value {Ready.} + } + } } } @@ -2701,12 +2709,17 @@ if {!$single_commit} { # -- Repository Menu # menu .mbar.repository -.mbar.repository add command -label Visualize \ - -command do_gitk \ +.mbar.repository add command \ + -label {Visualize Current Branch} \ + -command {do_gitk {}} \ -font font_ui -if {!$single_commit} { - .mbar.repository add separator +.mbar.repository add command \ + -label {Visualize All Branches} \ + -command {do_gitk {--all}} \ + -font font_ui +.mbar.repository add separator +if {!$single_commit} { .mbar.repository add command -label {Repack Database} \ -command do_repack \ -font font_ui -- cgit v1.2.1 From 5040f926f9b06946b6b6144eb358db1850dce505 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Tue, 21 Nov 2006 22:58:28 -0500 Subject: git-gui: Don't start 'gitk --all' on Mac OS X. Since gitk is currently broken on Mac OS X and is unable to start itself when given command line parameters just don't offer the "Visual All Branches" menu option on Mac OS X. Once this feature of gitk is fixed we should change this section of code to make sure a working version of gitk will be executed before we offer the option up to the user. Signed-off-by: Shawn O. Pearce --- git-gui | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index ef8c7cf06..d1cc0ec24 100755 --- a/git-gui +++ b/git-gui @@ -2713,10 +2713,12 @@ menu .mbar.repository -label {Visualize Current Branch} \ -command {do_gitk {}} \ -font font_ui -.mbar.repository add command \ - -label {Visualize All Branches} \ - -command {do_gitk {--all}} \ - -font font_ui +if {![is_MacOSX]} { + .mbar.repository add command \ + -label {Visualize All Branches} \ + -command {do_gitk {--all}} \ + -font font_ui +} .mbar.repository add separator if {!$single_commit} { -- cgit v1.2.1 From 4c2035d55e0a5c013677a8e83193e37d51000793 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Wed, 22 Nov 2006 19:24:41 -0500 Subject: git-gui: Improve pull error dialogs. Just like prior to a commit its only an informational message that we refuse to perform a pull on a dirty working directory. Therefore we should not use an error icon. Signed-off-by: Shawn O. Pearce --- git-gui | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index d1cc0ec24..8246037fa 100755 --- a/git-gui +++ b/git-gui @@ -1122,11 +1122,13 @@ proc pull_remote {remote branch} { # repository_state curType curHEAD curMERGE_HEAD if {$commit_type ne $curType || $HEAD ne $curHEAD} { - error_popup {Last scanned state does not match repository state. + info_popup {Last scanned state does not match repository state. -Its highly likely that another Git program modified the -repository since our last scan. A rescan is required -before a pull can be started. +Another Git program has modified this repository +since the last scan. A rescan must be performed +before a pull operation can be started. + +The rescan will be automatically started now. } unlock_index rescan {set ui_status_value {Ready.}} @@ -1138,10 +1140,12 @@ before a pull can be started. if {[array size file_states] != 0} { error_popup {Uncommitted but modified files are present. -You should not perform a pull with unmodified files in your working -directory as Git would be unable to recover from an incorrect merge. +You should not perform a pull with unmodified +files in your working directory as Git will be +unable to recover from an incorrect merge. -Commit or throw away all changes before starting a pull operation. +You should commit or revert all changes before +starting a pull operation. } unlock_index return -- cgit v1.2.1 From e734817db0af028f2aea356b44c74b7ac51023cd Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Thu, 23 Nov 2006 21:40:45 -0500 Subject: git-gui: Added revert changes command. Users sometimes need to be able to throw away locally modified files in order to go back to the last committed version of that file. To perform a revert the user must first uninclude each file from the new commit as the working file must at least partially match the index, and we use git-checkout-index to update the working directory. Signed-off-by: Shawn O. Pearce --- git-gui | 184 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 177 insertions(+), 7 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 8246037fa..34a1daa44 100755 --- a/git-gui +++ b/git-gui @@ -1277,9 +1277,26 @@ proc display_file {path state} { set old_w [mapcol $old_m $path] set new_icon [mapicon $new_m $path] + if {$new_m eq {__}} { + set lno [lsearch -sorted $file_lists($old_w) $path] + if {$lno >= 0} { + set file_lists($old_w) \ + [lreplace $file_lists($old_w) $lno $lno] + incr lno + $old_w conf -state normal + $old_w delete $lno.0 [expr {$lno + 1}].0 + $old_w conf -state disabled + } + unset file_states($path) + catch {unset selected_paths($path)} + return + } + if {$new_w ne $old_w} { set lno [lsearch -sorted $file_lists($old_w) $path] if {$lno >= 0} { + set file_lists($old_w) \ + [lreplace $file_lists($old_w) $lno $lno] incr lno $old_w conf -state normal $old_w delete $lno.0 [expr {$lno + 1}].0 @@ -1500,6 +1517,84 @@ proc write_update_index {fd pathList totalCnt batch msg after} { [expr {100.0 * $update_index_cp / $totalCnt}]] } +proc checkout_index {msg pathList after} { + global update_index_cp ui_status_value + + if {![lock_index update]} return + + set update_index_cp 0 + set pathList [lsort $pathList] + set totalCnt [llength $pathList] + set batch [expr {int($totalCnt * .01) + 1}] + if {$batch > 25} {set batch 25} + + set ui_status_value [format \ + "$msg... %i/%i files (%.2f%%)" \ + $update_index_cp \ + $totalCnt \ + 0.0] + set cmd [list git checkout-index] + lappend cmd --index + lappend cmd --quiet + lappend cmd --force + lappend cmd -z + lappend cmd --stdin + set fd [open "| $cmd " w] + fconfigure $fd \ + -blocking 0 \ + -buffering full \ + -buffersize 512 \ + -translation binary + fileevent $fd writable [list \ + write_checkout_index \ + $fd \ + $pathList \ + $totalCnt \ + $batch \ + $msg \ + $after \ + ] +} + +proc write_checkout_index {fd pathList totalCnt batch msg after} { + global update_index_cp ui_status_value + global file_states current_diff + + if {$update_index_cp >= $totalCnt} { + close $fd + unlock_index + uplevel #0 $after + return + } + + for {set i $batch} \ + {$update_index_cp < $totalCnt && $i > 0} \ + {incr i -1} { + set path [lindex $pathList $update_index_cp] + incr update_index_cp + + switch -glob -- [lindex $file_states($path) 0] { + AM - + AD {set new A_} + MM - + MD {set new M_} + _M - + _D {set new __} + ?? {continue} + } + + puts -nonewline $fd $path + puts -nonewline $fd "\0" + display_file $path $new + } + + set ui_status_value [format \ + "$msg... %i/%i files (%.2f%%)" \ + $update_index_cp \ + $totalCnt \ + [expr {100.0 * $update_index_cp / $totalCnt}]] +} + ###################################################################### ## ## remote management @@ -1708,11 +1803,12 @@ foreach i { {_M i mod "Modified"} {M_ i fulltick "Included in commit"} {MM i parttick "Partially included"} + {MD i question "Included (but gone)"} {_O o plain "Untracked"} {A_ o fulltick "Added by commit"} {AM o parttick "Partially added"} - {AD o question "Added (but now gone)"} + {AD o question "Added (but gone)"} {_D i question "Missing"} {DD i removed "Removed by commit"} @@ -2159,6 +2255,74 @@ proc do_include_all {} { $paths } +proc revert_helper {txt paths} { + global file_states current_diff + + if {![lock_index begin-update]} return + + set pathList [list] + set after {} + foreach path $paths { + switch -glob -- [lindex $file_states($path) 0] { + AM - + AD - + MM - + MD - + _M - + _D { + lappend pathList $path + if {$path eq $current_diff} { + set after {reshow_diff;} + } + } + } + } + + set n [llength $pathList] + if {$n == 0} { + unlock_index + return + } elseif {$n == 1} { + set s "[short_path [lindex $pathList]]" + } else { + set s "these $n files" + } + + set reply [tk_dialog \ + .confirm_revert \ + "title" \ + "Revert unincluded changes in $s? + +Any unincluded changes will be permanently lost by the revert." \ + questhead \ + 1 \ + {Do Nothing} \ + {Revert Changes} \ + ] + if {$reply == 1} { + checkout_index \ + $txt \ + $pathList \ + [concat $after {set ui_status_value {Ready.}}] + } else { + unlock_index + } +} + +proc do_revert_selection {} { + global current_diff selected_paths + + if {[array size selected_paths] > 0} { + revert_helper \ + {Reverting selected files} \ + [array names selected_paths] + } elseif {$current_diff ne {}} { + revert_helper \ + "Reverting [short_path $current_diff]" \ + [list $current_diff] + } +} + proc do_signoff {} { global ui_comm @@ -2818,12 +2982,6 @@ lappend disable_on_lock \ lappend disable_on_lock \ [list .mbar.commit entryconf [.mbar.commit index last] -state] -.mbar.commit add command -label {Remove From Commit} \ - -command do_remove_selection \ - -font font_ui -lappend disable_on_lock \ - [list .mbar.commit entryconf [.mbar.commit index last] -state] - .mbar.commit add command -label {Include In Commit} \ -command do_include_selection \ -font font_ui @@ -2837,6 +2995,18 @@ lappend disable_on_lock \ lappend disable_on_lock \ [list .mbar.commit entryconf [.mbar.commit index last] -state] +.mbar.commit add command -label {Remove From Commit} \ + -command do_remove_selection \ + -font font_ui +lappend disable_on_lock \ + [list .mbar.commit entryconf [.mbar.commit index last] -state] + +.mbar.commit add command -label {Revert Changes} \ + -command do_revert_selection \ + -font font_ui +lappend disable_on_lock \ + [list .mbar.commit entryconf [.mbar.commit index last] -state] + .mbar.commit add separator .mbar.commit add command -label {Sign Off} \ -- cgit v1.2.1 From 8553b772d7aeebe8c83710233877483dd409b846 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Fri, 24 Nov 2006 15:38:18 -0500 Subject: git-gui: Display the current branch. Users want to know what branch they are sitting on before making a commit, as they may need to switch to a different branch first. Signed-off-by: Shawn O. Pearce --- git-gui | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 34a1daa44..dd2d750ab 100755 --- a/git-gui +++ b/git-gui @@ -258,11 +258,20 @@ proc unlock_index {} { ## status proc repository_state {ctvar hdvar mhvar} { - global gitdir + global gitdir current_branch upvar $ctvar ct $hdvar hd $mhvar mh set mh [list] + if {[catch {set current_branch [exec git symbolic-ref HEAD]}]} { + set current_branch {} + } else { + regsub ^refs/(heads|tags)/ \ + $current_branch \ + {} \ + current_branch + } + if {[catch {set hd [exec git rev-parse --verify HEAD]}]} { set hd {} set ct initial @@ -3060,6 +3069,25 @@ if {[is_MacOSX]} { } +# -- Branch Control +# +frame .branch \ + -borderwidth 1 \ + -relief sunken +label .branch.l1 \ + -text {Current Branch:} \ + -anchor w \ + -justify left \ + -font font_ui +label .branch.cb \ + -textvariable current_branch \ + -anchor w \ + -justify left \ + -font font_ui +pack .branch.l1 -side left +pack .branch.cb -side left -fill x +pack .branch -side top -fill x + # -- Main Window Layout # panedwindow .vpane -orient vertical @@ -3486,6 +3514,7 @@ set PARENT {} set MERGE_HEAD [list] set commit_type {} set empty_tree {} +set current_branch {} set current_diff {} set selected_commit_type new -- cgit v1.2.1 From 9342e26d3a832dd24878725b42444b8efe4fa1c4 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Fri, 24 Nov 2006 15:59:34 -0500 Subject: git-gui: Support file state MD (modified/deleted). Apparently I missed the file state MD, which is a file modified and updated in the index but then removed from the working directory. This should be treated just like AD, an added file which has been deleted from the working directory. Signed-off-by: Shawn O. Pearce --- git-gui | 3 +++ 1 file changed, 3 insertions(+) (limited to 'git-gui') diff --git a/git-gui b/git-gui index dd2d750ab..e9d4600a2 100755 --- a/git-gui +++ b/git-gui @@ -1093,6 +1093,7 @@ proc commit_committree {fd_wt curHEAD msg} { AM - AD - MM - + MD - DM { set file_states($path) [list \ _[string index $m 1] \ @@ -2211,6 +2212,7 @@ proc include_helper {txt paths} { AM - AD - MM - + MD - U? - _M - _D - @@ -2255,6 +2257,7 @@ proc do_include_all {} { AM - AD - MM - + MD - _M - _D {lappend paths $path} } -- cgit v1.2.1 From 700a65ce380f29a5083bcc230aa1ef5c28e66f2c Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Fri, 24 Nov 2006 17:30:12 -0500 Subject: git-gui: Created Branch menu. This is an early start at branch management from within git-gui. The branch menu has create/delete command entries to create and delete branches as well as a list of radiobutton entries for each branch found in the repository through for-each-ref. Signed-off-by: Shawn O. Pearce --- git-gui | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) (limited to 'git-gui') diff --git a/git-gui b/git-gui index e9d4600a2..69ebd9095 100755 --- a/git-gui +++ b/git-gui @@ -1605,6 +1605,44 @@ proc write_checkout_index {fd pathList totalCnt batch msg after} { [expr {100.0 * $update_index_cp / $totalCnt}]] } +###################################################################### +## +## branch management + +proc load_all_branches {} { + global all_branches + + set all_branches [list] + set cmd [list git for-each-ref] + lappend cmd --format=%(refname) + lappend cmd refs/heads + set fd [open "| $cmd" r] + while {[gets $fd line] > 0} { + if {[regsub ^refs/heads/ $line {} line]} { + lappend all_branches $line + } + } + close $fd + + set all_branches [lsort $all_branches] +} + +proc populate_branch_menu {m} { + global all_branches disable_on_lock + + $m add separator + foreach b $all_branches { + $m add radiobutton \ + -label $b \ + -command [list do_switch_branch $b] \ + -variable current_branch \ + -value $b \ + -font font_ui + lappend disable_on_lock \ + [list $m entryconf [$m index last] -state] + } +} + ###################################################################### ## ## remote management @@ -2878,6 +2916,9 @@ apply_config menu .mbar -tearoff 0 .mbar add cascade -label Repository -menu .mbar.repository .mbar add cascade -label Edit -menu .mbar.edit +if {!$single_commit} { + .mbar add cascade -label Branch -menu .mbar.branch +} .mbar add cascade -label Commit -menu .mbar.commit if {!$single_commit} { .mbar add cascade -label Fetch -menu .mbar.fetch @@ -2963,6 +3004,24 @@ menu .mbar.edit -accelerator $M1T-A \ -font font_ui +if {!$single_commit} { + # -- Branch Menu + # + menu .mbar.branch + + .mbar.branch add command -label {Create...} \ + -command do_create_branch \ + -font font_ui + lappend disable_on_lock [list .mbar.branch entryconf \ + [.mbar.branch index last] -state] + + .mbar.branch add command -label {Delete...} \ + -command do_delete_branch \ + -font font_ui + lappend disable_on_lock [list .mbar.branch entryconf \ + [.mbar.branch index last] -state] +} + # -- Commit Menu # menu .mbar.commit @@ -3583,6 +3642,8 @@ user.email settings into your personal if {!$single_commit} { load_all_remotes + load_all_branches + populate_branch_menu .mbar.branch populate_fetch_menu .mbar.fetch populate_pull_menu .mbar.pull populate_push_menu .mbar.push -- cgit v1.2.1 From d90d83a3a95e5fb4672906589ac0a19c19f1187b Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 25 Nov 2006 02:45:19 -0500 Subject: git-gui: Parse off refs/remotes when showing current branch. Even though the user shouldn't have a remote branch checked out, if they do we should still show as short of the branch name as possible. Signed-off-by: Shawn O. Pearce --- git-gui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 69ebd9095..48e781dd3 100755 --- a/git-gui +++ b/git-gui @@ -266,7 +266,7 @@ proc repository_state {ctvar hdvar mhvar} { if {[catch {set current_branch [exec git symbolic-ref HEAD]}]} { set current_branch {} } else { - regsub ^refs/(heads|tags)/ \ + regsub ^refs/((heads|tags|remotes)/)? \ $current_branch \ {} \ current_branch -- cgit v1.2.1 From 2171bf4b44884fd75bc5c1c412a39c2d4e645453 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 25 Nov 2006 02:47:18 -0500 Subject: git-gui: Abort on not implemented branch switching. I'm not currently ready to implement branch switching, so I'm just going to punt on it for now. :-) Signed-off-by: Shawn O. Pearce --- git-gui | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 48e781dd3..9bfed1f6a 100755 --- a/git-gui +++ b/git-gui @@ -1634,7 +1634,7 @@ proc populate_branch_menu {m} { foreach b $all_branches { $m add radiobutton \ -label $b \ - -command [list do_switch_branch $b] \ + -command [list switch_branch $b] \ -variable current_branch \ -value $b \ -font font_ui @@ -1643,6 +1643,10 @@ proc populate_branch_menu {m} { } } +proc switch_branch {b} { + error "NOT IMPLEMENTED" +} + ###################################################################### ## ## remote management -- cgit v1.2.1 From 359ca42a4b9288421d2f0409652f76e9a365b801 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 25 Nov 2006 03:33:03 -0500 Subject: git-gui: Automatically skip tracking branches in branch menu. Since the user should not work on a tracking branch we automatically hide any branch which is used as a tracking branch by either a remote..fetch config entry or by a Pull: line in a remotes file. Signed-off-by: Shawn O. Pearce --- git-gui | 46 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 37 insertions(+), 9 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 9bfed1f6a..7406238c9 100755 --- a/git-gui +++ b/git-gui @@ -1610,7 +1610,7 @@ proc write_checkout_index {fd pathList totalCnt batch msg after} { ## branch management proc load_all_branches {} { - global all_branches + global all_branches tracking_branches set all_branches [list] set cmd [list git for-each-ref] @@ -1618,9 +1618,9 @@ proc load_all_branches {} { lappend cmd refs/heads set fd [open "| $cmd" r] while {[gets $fd line] > 0} { - if {[regsub ^refs/heads/ $line {} line]} { - lappend all_branches $line - } + if {![catch {set info $tracking_branches($line)}]} continue + if {![regsub ^refs/heads/ $line {} name]} continue + lappend all_branches $name } close $fd @@ -1652,21 +1652,49 @@ proc switch_branch {b} { ## remote management proc load_all_remotes {} { - global gitdir all_remotes repo_config + global gitdir repo_config + global all_remotes tracking_branches set all_remotes [list] + array unset tracking_branches + set rm_dir [file join $gitdir remotes] if {[file isdirectory $rm_dir]} { - set all_remotes [concat $all_remotes [glob \ + set all_remotes [glob \ -types f \ -tails \ -nocomplain \ - -directory $rm_dir *]] + -directory $rm_dir *] + + foreach name $all_remotes { + catch { + set fd [open [file join $rm_dir $name] r] + while {[gets $fd line] >= 0} { + if {![regexp {^Pull:[ ]*([^:]+):(.+)$} \ + $line line src dst]} continue + if {![regexp ^refs/ $dst]} { + set dst "refs/heads/$dst" + } + set tracking_branches($dst) [list $name $src] + } + close $fd + } + } } foreach line [array names repo_config remote.*.url] { - if {[regexp ^remote\.(.*)\.url\$ $line line name]} { - lappend all_remotes $name + if {![regexp ^remote\.(.*)\.url\$ $line line name]} continue + lappend all_remotes $name + + if {[catch {set fl $repo_config(remote.$name.fetch)}]} { + set fl {} + } + foreach line $fl { + if {![regexp {^([^:]+):(.+)$} $line line src dst]} continue + if {![regexp ^refs/ $dst]} { + set dst "refs/heads/$dst" + } + set tracking_branches($dst) [list $name $src] } } -- cgit v1.2.1 From bb1ad51a5365cbe48d5dcee7e00a8d9f90d89171 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 25 Nov 2006 03:35:33 -0500 Subject: git-gui: Rename all_branches -> all_heads. Since this list is really the set of refs which match "refs/heads/*" it really is the set of heads and not necessarily the set of all branches, as the remote tracking branches are not listed in this set, even if it appears in the "refs/heads/*" namespace (e.g. an old style repository). Signed-off-by: Shawn O. Pearce --- git-gui | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 7406238c9..6035105f8 100755 --- a/git-gui +++ b/git-gui @@ -1609,10 +1609,10 @@ proc write_checkout_index {fd pathList totalCnt batch msg after} { ## ## branch management -proc load_all_branches {} { - global all_branches tracking_branches +proc load_all_heads {} { + global all_heads tracking_branches - set all_branches [list] + set all_heads [list] set cmd [list git for-each-ref] lappend cmd --format=%(refname) lappend cmd refs/heads @@ -1620,18 +1620,18 @@ proc load_all_branches {} { while {[gets $fd line] > 0} { if {![catch {set info $tracking_branches($line)}]} continue if {![regsub ^refs/heads/ $line {} name]} continue - lappend all_branches $name + lappend all_heads $name } close $fd - set all_branches [lsort $all_branches] + set all_heads [lsort $all_heads] } proc populate_branch_menu {m} { - global all_branches disable_on_lock + global all_heads disable_on_lock $m add separator - foreach b $all_branches { + foreach b $all_heads { $m add radiobutton \ -label $b \ -command [list switch_branch $b] \ @@ -3674,7 +3674,7 @@ user.email settings into your personal if {!$single_commit} { load_all_remotes - load_all_branches + load_all_heads populate_branch_menu .mbar.branch populate_fetch_menu .mbar.fetch populate_pull_menu .mbar.pull -- cgit v1.2.1 From 85ab313ed3dc9a951ec3859fcc3a32a6c5c3ee19 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 25 Nov 2006 03:38:39 -0500 Subject: git-gui: Misc. comment and formatting cleanups. Signed-off-by: Shawn O. Pearce --- git-gui | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 6035105f8..f52dd522c 100755 --- a/git-gui +++ b/git-gui @@ -2997,6 +2997,7 @@ if {!$single_commit} { -font font_ui } } + .mbar.repository add command -label Quit \ -command do_quit \ -accelerator $M1T-Q \ @@ -3036,9 +3037,9 @@ menu .mbar.edit -accelerator $M1T-A \ -font font_ui +# -- Branch Menu +# if {!$single_commit} { - # -- Branch Menu - # menu .mbar.branch .mbar.branch add command -label {Create...} \ @@ -3615,11 +3616,9 @@ set selected_commit_type new wm title . "$appname ([file normalize [file dirname $gitdir]])" focus -force $ui_comm -# -- Warn the user about environmental problems. -# Cygwin's Tcl does *not* pass its env array -# onto any processes it spawns. This means -# that the git processes get none of our -# environment. That may not work... +# -- Warn the user about environmental problems. Cygwin's Tcl +# does *not* pass its env array onto any processes it spawns. +# This means that git processes get none of our environment. # if {[is_Windows]} { set ignored_env 0 @@ -3672,13 +3671,17 @@ user.email settings into your personal unset ignored_env msg suggest_user name } +# -- Only initialize complex UI if we are going to stay running. +# if {!$single_commit} { load_all_remotes load_all_heads + populate_branch_menu .mbar.branch populate_fetch_menu .mbar.fetch populate_pull_menu .mbar.pull populate_push_menu .mbar.push } + lock_index begin-read after 1 do_rescan -- cgit v1.2.1 From 84e0bf1de4fcdada4698e2bd53bafaeaea6b5cbd Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 25 Nov 2006 04:04:24 -0500 Subject: git-gui: Started implementation of switch_branch. This implementation of switch_branch is not yet finished, and thus it throws a "NOT FINISHED" error rather than completing the switch. But its a rough sketch of the procedure required. Signed-off-by: Shawn O. Pearce --- git-gui | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index f52dd522c..3845cf716 100755 --- a/git-gui +++ b/git-gui @@ -1643,10 +1643,59 @@ proc populate_branch_menu {m} { } } -proc switch_branch {b} { +proc do_create_branch {} { error "NOT IMPLEMENTED" } +proc do_delete_branch {} { + error "NOT IMPLEMENTED" +} + +proc switch_branch {b} { + global HEAD commit_type file_states current_branch + global selected_commit_type ui_comm + + if {![lock_index switch]} return + + # -- Backup the selected branch (repository_state resets it) + # + set new_branch $current_branch + + # -- Our in memory state should match the repository. + # + repository_state curType curHEAD curMERGE_HEAD + if {[string match amend* $commit_type] + && $curType eq {normal} + && $curHEAD eq $HEAD} { + } elseif {$commit_type ne $curType || $HEAD ne $curHEAD} { + info_popup {Last scanned state does not match repository state. + +Another Git program has modified this repository +since the last scan. A rescan must be performed +before the current branch can be changed. + +The rescan will be automatically started now. +} + unlock_index + rescan {set ui_status_value {Ready.}} + return + } + + # -- Toss the message buffer if we are in amend mode. + # + if {[string match amend* $curType]} { + $ui_comm delete 0.0 end + $ui_comm edit reset + $ui_comm edit modified false + } + + set selected_commit_type new + set current_branch $new_branch + + unlock_index + error "NOT FINISHED" +} + ###################################################################### ## ## remote management -- cgit v1.2.1 From 9208487b34706887fcc10ce6423099134f301f5e Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 25 Nov 2006 12:40:29 -0500 Subject: git-gui: Set a proper title on our revert confirm dialog box. Signed-off-by: Shawn O. Pearce --- git-gui | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 3845cf716..09fc40aaf 100755 --- a/git-gui +++ b/git-gui @@ -2387,6 +2387,7 @@ proc do_include_all {} { } proc revert_helper {txt paths} { + global gitdir appname global file_states current_diff if {![lock_index begin-update]} return @@ -2419,13 +2420,17 @@ proc revert_helper {txt paths} { set s "these $n files" } + set reponame [lindex [file split \ + [file normalize [file dirname $gitdir]]] \ + end] + set reply [tk_dialog \ .confirm_revert \ - "title" \ + "$appname ($reponame)" \ "Revert unincluded changes in $s? Any unincluded changes will be permanently lost by the revert." \ - questhead \ + question \ 1 \ {Do Nothing} \ {Revert Changes} \ -- cgit v1.2.1 From f70c3a2caccf4f0f5abfd3d0db4120e8659dd0d7 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sun, 26 Nov 2006 19:45:39 -0500 Subject: git-gui: Enable resolution of merge conflicts. If a file has a merge conflict (index state = U) the user will need to run update-index on that file to resolve all stages down to stage 0, by including the file in the working directory. Like core Git we'll just trust the user that their resolution is correct, and that they didn't just include the file into the commit while merge conflicts still exist within the file. Signed-off-by: Shawn O. Pearce --- git-gui | 3 +++ 1 file changed, 3 insertions(+) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 09fc40aaf..0b0f1e3e7 100755 --- a/git-gui +++ b/git-gui @@ -1502,10 +1502,13 @@ proc write_update_index {fd pathList totalCnt batch msg after} { switch -glob -- [lindex $file_states($path) 0] { AD - MD - + UD - _D {set new DD} _M - MM - + UM - + U_ - M_ {set new M_} _O - -- cgit v1.2.1 From c15ad650c77ef3213d723efec4e1dca89efba6cd Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sun, 26 Nov 2006 19:46:45 -0500 Subject: git-gui: Auto-update any A? or M? files during rescan. If the user has partial includes disabled then it doesn't matter what state the working directory is in; if the file has been included in the next commit its index state is A or M and we should immediately run update-index on the working directory file to bring the index in sync with the working directory. Signed-off-by: Shawn O. Pearce --- git-gui | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 0b0f1e3e7..899fa35a6 100755 --- a/git-gui +++ b/git-gui @@ -499,8 +499,8 @@ proc rescan_done {fd buf after} { set pathList [list] foreach path [array names file_states] { switch -- [lindex $file_states($path) 0] { - AM - - MM {lappend pathList $path} + A? - + M? {lappend pathList $path} } } if {$pathList ne {}} { -- cgit v1.2.1 From eae2ce619277903e73550663e6826f0299191bf3 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Thu, 7 Dec 2006 19:59:46 -0500 Subject: git-gui: Reworded 'Include' to 'Add' to match core Git. Now that git-add is a first class citizen in core Git (Nico's 366bfcb6) users may start to expect the term 'add' to refer to the act of including a file's changes into a commit. So I'm replacing all uses of the term 'Include' in the UI with 'Add'. Signed-off-by: Shawn O. Pearce --- git-gui | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 899fa35a6..1891215a6 100755 --- a/git-gui +++ b/git-gui @@ -3143,13 +3143,13 @@ lappend disable_on_lock \ lappend disable_on_lock \ [list .mbar.commit entryconf [.mbar.commit index last] -state] -.mbar.commit add command -label {Include In Commit} \ +.mbar.commit add command -label {Add To Commit} \ -command do_include_selection \ -font font_ui lappend disable_on_lock \ [list .mbar.commit entryconf [.mbar.commit index last] -state] -.mbar.commit add command -label {Include All In Commit} \ +.mbar.commit add command -label {Add All To Commit} \ -command do_include_all \ -accelerator $M1T-I \ -font font_ui @@ -3317,7 +3317,7 @@ pack .vpane.lower.commarea.buttons.rescan -side top -fill x lappend disable_on_lock \ {.vpane.lower.commarea.buttons.rescan conf -state} -button .vpane.lower.commarea.buttons.incall -text {Include All} \ +button .vpane.lower.commarea.buttons.incall -text {Add All} \ -command do_include_all \ -font font_ui pack .vpane.lower.commarea.buttons.incall -side top -fill x -- cgit v1.2.1 From 557afe820baccb21206c974fbd4afa65bd7f1e03 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Thu, 7 Dec 2006 22:07:38 -0500 Subject: git-gui: Created very crude Tools menu, to support miga. In one particular case I have a tool called 'miga' which users may need to invoke on their repository. This is a homegrown tool which is not (and should be) part of git-gui, but I still want to be able to run it from within the gui. Right now I'm taking a shortcut and adding it to the Tools menu if we are not on Mac OS X and the support script used to launch the tool exists in the local filesystem. This is nothing but a complete and utter hack. Signed-off-by: Shawn O. Pearce --- git-gui | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 1891215a6..36979afd7 100755 --- a/git-gui +++ b/git-gui @@ -3210,6 +3210,35 @@ if {[is_MacOSX]} { -command do_options \ -font font_ui + # -- Tools Menu + # + if {[file exists /usr/local/miga/lib/gui-miga]} { + proc do_miga {} { + global gitdir ui_status_value + if {![lock_index update]} return + set cmd [list sh --login -c "/usr/local/miga/lib/gui-miga \"[pwd]\""] + set miga_fd [open "|$cmd" r] + fconfigure $miga_fd -blocking 0 + fileevent $miga_fd readable [list miga_done $miga_fd] + set ui_status_value {Running miga...} + } + proc miga_done {fd} { + read $fd 512 + if {[eof $fd]} { + close $fd + unlock_index + rescan [list set ui_status_value {Ready.}] + } + } + .mbar add cascade -label Tools -menu .mbar.tools + menu .mbar.tools + .mbar.tools add command -label "Migrate" \ + -command do_miga \ + -font font_ui + lappend disable_on_lock \ + [list .mbar.tools entryconf [.mbar.tools index last] -state] + } + # -- Help Menu # .mbar add cascade -label Help -menu .mbar.help -- cgit v1.2.1 From 51e7e568c0a7854b2f93b86d6085695ce80053cc Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Tue, 12 Dec 2006 22:44:38 -0500 Subject: git-gui: Show all fetched branches for remote pulls. Loop through every remote..fetch entry and add it as a valid option in the Pull menu. This way users can pull any remote branch that they track, without needing to leave the gui. Its a rather crude work around for not having a full merge interface. Signed-off-by: Shawn O. Pearce --- git-gui | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 36979afd7..0c88e4c7c 100755 --- a/git-gui +++ b/git-gui @@ -1819,28 +1819,29 @@ proc populate_pull_menu {m} { global gitdir repo_config all_remotes disable_on_lock foreach remote $all_remotes { - set rb {} + set rb_list [list] if {[array get repo_config remote.$remote.url] ne {}} { if {[array get repo_config remote.$remote.fetch] ne {}} { - regexp {^([^:]+):} \ - [lindex $repo_config(remote.$remote.fetch) 0] \ - line rb + foreach line $repo_config(remote.$remote.fetch) { + if {[regexp {^([^:]+):} $line line rb]} { + lappend rb_list $rb + } + } } } else { catch { set fd [open [file join $gitdir remotes $remote] r] while {[gets $fd line] >= 0} { if {[regexp {^Pull:[ \t]*([^:]+):} $line line rb]} { - break + lappend rb_list $rb } } close $fd } } - set rb_short $rb - regsub ^refs/heads/ $rb {} rb_short - if {$rb_short ne {}} { + foreach rb $rb_list { + regsub ^refs/heads/ $rb {} rb_short $m add command \ -label "Branch $rb_short from $remote..." \ -command [list pull_remote $remote $rb] \ -- cgit v1.2.1 From 81c0f29a5633f6a9ab01e0e9ded5e1c6d715b70b Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 20 Jan 2007 18:38:12 -0500 Subject: git-gui: Run git-gc rather than git-repack. Now that git 1.5.0-rc1 and later has a 'git gc' command which performs all important repository management activites (including reflog pruning, repacking local objects, unnecessary loose object pruning and rerere cache expiration) we should run 'gc' when the user wants us to cleanup their object database for them. I think the name 'gc' is horrible for a GUI application like git-gui, so I'm labeling the menu action 'Compress Database' instead. Hopefully this will provide some clue to the user about what the action does. Signed-off-by: Shawn O. Pearce --- git-gui | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 0c88e4c7c..95c922b21 100755 --- a/git-gui +++ b/git-gui @@ -2217,13 +2217,9 @@ proc do_gitk {revs} { } } -proc do_repack {} { - set w [new_console {repack} \ - {Repacking the object database}] - set cmd [list git repack] - lappend cmd -a - lappend cmd -d - console_exec $w $cmd +proc do_gc {} { + set w [new_console {gc} {Compressing the object database}] + console_exec $w {git gc} } proc do_fsck_objects {} { @@ -3033,8 +3029,8 @@ if {![is_MacOSX]} { .mbar.repository add separator if {!$single_commit} { - .mbar.repository add command -label {Repack Database} \ - -command do_repack \ + .mbar.repository add command -label {Compress Database} \ + -command do_gc \ -font font_ui .mbar.repository add command -label {Verify Database} \ -- cgit v1.2.1 From 6b0f3f46293e2f718054e9947e209c0344721a69 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 20 Jan 2007 18:50:14 -0500 Subject: git-gui: Corrected behavior of deleted (but existing in HEAD) files. Apparently I did not account for the D_ file state. This can occur when a file has been marked for deletion by deleting it from the index, and the file also does not exist in the working directory. Typically this happens when the user deletes the file, hits Rescan, then includes the missing file in the commit, then hits Rescan again. We don't find the file in the working directory but its been removed in the index, so the state becomes D_. This state should be identical with DD. I'm not entirely sure why DD occurs sometimes and D_ others, it would seem like D_ is the state that should be happening instead of DD, leading me to believe there is a quirk in git-gui's state manipulation code. Signed-off-by: Shawn O. Pearce --- git-gui | 2 ++ 1 file changed, 2 insertions(+) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 95c922b21..04fdb0c1e 100755 --- a/git-gui +++ b/git-gui @@ -1429,6 +1429,7 @@ proc write_update_indexinfo {fd pathList totalCnt batch msg after} { switch -glob -- [lindex $s 0] { A? {set new _O} M? {set new _M} + D_ {set new _D} D? {set new _?} ?? {continue} } @@ -1945,6 +1946,7 @@ foreach i { {_D i question "Missing"} {DD i removed "Removed by commit"} + {D_ i removed "Removed by commit"} {DO i removed "Removed (still exists)"} {DM i removed "Removed (but modified)"} -- cgit v1.2.1 From 68cbfb13919132cb2ddc591a765f4f20f9294657 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 20 Jan 2007 18:54:56 -0500 Subject: git-gui: Correct wording of the revert confirmation dialog. We no longer describe updating the index as including changes, as we now use the add notation used by core Git's command line tools. So its confusing to be talking about unincluded changes within the revert dialog. Instead we should used language like 'unadded changes'. Signed-off-by: Shawn O. Pearce --- git-gui | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 04fdb0c1e..ade64dcd1 100755 --- a/git-gui +++ b/git-gui @@ -2429,9 +2429,9 @@ proc revert_helper {txt paths} { set reply [tk_dialog \ .confirm_revert \ "$appname ($reponame)" \ - "Revert unincluded changes in $s? + "Revert changes in $s? -Any unincluded changes will be permanently lost by the revert." \ +Any unadded changes will be permanently lost by the revert." \ question \ 1 \ {Do Nothing} \ -- cgit v1.2.1 From bdadecbae5b9f7317994bf2f521bb15068823a1d Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 20 Jan 2007 19:03:26 -0500 Subject: git-gui: Work around odd cygpath bug on Windows. There appears to be a bug on one of my test systems where cygpath with the --long-name option is generating a corrupt string that does not actually refer to sh.exe. This breaks any desktop icon created by git-gui as the executable we are trying to invoke does not exist. Since Cygwin is typically installed as C:\cygwin long path names is probably not actually necessary to link to the shell. I also added a small echo to the start of the icon script, as it can take one of my test systems several seconds to startup git-gui. This way the user knows we're starting git-gui, and was politely asked to wait for the action to complete. Signed-off-by: Shawn O. Pearce --- git-gui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index ade64dcd1..c5120cc1a 100755 --- a/git-gui +++ b/git-gui @@ -2742,7 +2742,6 @@ proc do_windows_shortcut {} { set sh [exec cygpath \ --windows \ --absolute \ - --long-name \ /bin/sh] set me [exec cygpath \ --unix \ @@ -2754,6 +2753,7 @@ proc do_windows_shortcut {} { $gitdir] regsub -all ' $me "'\\''" me regsub -all ' $gd "'\\''" gd + puts $fd "@ECHO Starting git-gui... Please wait..." puts -nonewline $fd "\"$sh\" --login -c \"" puts -nonewline $fd "GIT_DIR='$gd'" puts -nonewline $fd " '$me'" -- cgit v1.2.1 From 4d583c86ec52f8b2937a0b9dc02667b54c4a28a2 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 20 Jan 2007 19:07:46 -0500 Subject: git-gui: Change more 'include' language to 'add'. I just found a whole slew of places where we still were using the term 'include' rather than 'add' to refer to the act of updating the index with modifications from the working directory. To be consistent with all Git documentation and command line tools, these should be 'add'. Signed-off-by: Shawn O. Pearce --- git-gui | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index c5120cc1a..11ba41f74 100755 --- a/git-gui +++ b/git-gui @@ -1935,9 +1935,9 @@ set max_status_desc 0 foreach i { {__ i plain "Unmodified"} {_M i mod "Modified"} - {M_ i fulltick "Included in commit"} + {M_ i fulltick "Added to commit"} {MM i parttick "Partially included"} - {MD i question "Included (but gone)"} + {MD i question "Added (but gone)"} {_O o plain "Untracked"} {A_ o fulltick "Added by commit"} @@ -2360,11 +2360,11 @@ proc do_include_selection {} { if {[array size selected_paths] > 0} { include_helper \ - {Including selected files} \ + {Adding selected files} \ [array names selected_paths] } elseif {$current_diff ne {}} { include_helper \ - "Including [short_path $current_diff]" \ + "Adding [short_path $current_diff]" \ [list $current_diff] } } @@ -2384,7 +2384,7 @@ proc do_include_all {} { } } include_helper \ - {Including all modified files} \ + {Adding all modified files} \ $paths } @@ -2615,7 +2615,7 @@ proc do_options {} { pack $w.global -side right -fill both -expand 1 -pady 5 -padx 5 foreach option { - {b partialinclude {Allow Partially Included Files}} + {b partialinclude {Allow Partially Added Files}} {b pullsummary {Show Pull Summary}} {b trustmtime {Trust File Modification Timestamps}} {i diffcontext {Number of Diff Context Lines}} @@ -2871,7 +2871,7 @@ proc toggle_or_diff {w x y} { } ?? { update_index \ - "Including [short_path $path]" \ + "Adding [short_path $path]" \ [list $path] \ [concat $after {set ui_status_value {Ready.}}] } -- cgit v1.2.1 From c25623321d52642fe8fb80c64904a53363f91b12 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 20 Jan 2007 19:45:26 -0500 Subject: git-gui: Hide the ugly bash command line from the windows desktop icon. The user really doesn't need to see the technical details of how we launch git-gui from within their "desktop icon". Instead we should hide the command line from being displayed when the icon launches by putting @ at the start of the line. If they really need to see the command we are running they can edit the batch file. Signed-off-by: Shawn O. Pearce --- git-gui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'git-gui') diff --git a/git-gui b/git-gui index 11ba41f74..b79eb451d 100755 --- a/git-gui +++ b/git-gui @@ -2754,7 +2754,7 @@ proc do_windows_shortcut {} { regsub -all ' $me "'\\''" me regsub -all ' $gd "'\\''" gd puts $fd "@ECHO Starting git-gui... Please wait..." - puts -nonewline $fd "\"$sh\" --login -c \"" + puts -nonewline $fd "@\"$sh\" --login -c \"" puts -nonewline $fd "GIT_DIR='$gd'" puts -nonewline $fd " '$me'" puts $fd "&\"" -- cgit v1.2.1 From 41bdcda37376a5faa63028f01260890723c3fcfa Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 20 Jan 2007 20:00:07 -0500 Subject: git-gui: Modified makefile to embed version into git-gui script. We want to embed the version of git-gui directly into the script file, so that we can display it properly in the about dialog. Consequently I've refactored the Makefile process to act like the one in core git.git with regards to shell scripts, allowing git-gui to be constructed by a sed replacement performed on git-gui.sh. Signed-off-by: Shawn O. Pearce --- git-gui | 3772 --------------------------------------------------------------- 1 file changed, 3772 deletions(-) delete mode 100755 git-gui (limited to 'git-gui') diff --git a/git-gui b/git-gui deleted file mode 100755 index b79eb451d..000000000 --- a/git-gui +++ /dev/null @@ -1,3772 +0,0 @@ -#!/bin/sh -# Tcl ignores the next line -*- tcl -*- \ -exec wish "$0" -- "$@" - -set copyright { -Copyright © 2006 Shawn Pearce, Paul Mackerras. - -All rights reserved. - -This program is free software; it may be used, copied, modified -and distributed under the terms of the GNU General Public Licence, -either version 2, or (at your option) any later version.} - -set appname [lindex [file split $argv0] end] -set gitdir {} - -###################################################################### -## -## config - -proc is_many_config {name} { - switch -glob -- $name { - remote.*.fetch - - remote.*.push - {return 1} - * - {return 0} - } -} - -proc load_config {include_global} { - global repo_config global_config default_config - - array unset global_config - if {$include_global} { - catch { - set fd_rc [open "| git repo-config --global --list" r] - while {[gets $fd_rc line] >= 0} { - if {[regexp {^([^=]+)=(.*)$} $line line name value]} { - if {[is_many_config $name]} { - lappend global_config($name) $value - } else { - set global_config($name) $value - } - } - } - close $fd_rc - } - } - - array unset repo_config - catch { - set fd_rc [open "| git repo-config --list" r] - while {[gets $fd_rc line] >= 0} { - if {[regexp {^([^=]+)=(.*)$} $line line name value]} { - if {[is_many_config $name]} { - lappend repo_config($name) $value - } else { - set repo_config($name) $value - } - } - } - close $fd_rc - } - - foreach name [array names default_config] { - if {[catch {set v $global_config($name)}]} { - set global_config($name) $default_config($name) - } - if {[catch {set v $repo_config($name)}]} { - set repo_config($name) $default_config($name) - } - } -} - -proc save_config {} { - global default_config font_descs - global repo_config global_config - global repo_config_new global_config_new - - foreach option $font_descs { - set name [lindex $option 0] - set font [lindex $option 1] - font configure $font \ - -family $global_config_new(gui.$font^^family) \ - -size $global_config_new(gui.$font^^size) - font configure ${font}bold \ - -family $global_config_new(gui.$font^^family) \ - -size $global_config_new(gui.$font^^size) - set global_config_new(gui.$name) [font configure $font] - unset global_config_new(gui.$font^^family) - unset global_config_new(gui.$font^^size) - } - - foreach name [array names default_config] { - set value $global_config_new($name) - if {$value ne $global_config($name)} { - if {$value eq $default_config($name)} { - catch {exec git repo-config --global --unset $name} - } else { - regsub -all "\[{}\]" $value {"} value - exec git repo-config --global $name $value - } - set global_config($name) $value - if {$value eq $repo_config($name)} { - catch {exec git repo-config --unset $name} - set repo_config($name) $value - } - } - } - - foreach name [array names default_config] { - set value $repo_config_new($name) - if {$value ne $repo_config($name)} { - if {$value eq $global_config($name)} { - catch {exec git repo-config --unset $name} - } else { - regsub -all "\[{}\]" $value {"} value - exec git repo-config $name $value - } - set repo_config($name) $value - } - } -} - -proc error_popup {msg} { - global gitdir appname - - set title $appname - if {$gitdir ne {}} { - append title { (} - append title [lindex \ - [file split [file normalize [file dirname $gitdir]]] \ - end] - append title {)} - } - set cmd [list tk_messageBox \ - -icon error \ - -type ok \ - -title "$title: error" \ - -message $msg] - if {[winfo ismapped .]} { - lappend cmd -parent . - } - eval $cmd -} - -proc warn_popup {msg} { - global gitdir appname - - set title $appname - if {$gitdir ne {}} { - append title { (} - append title [lindex \ - [file split [file normalize [file dirname $gitdir]]] \ - end] - append title {)} - } - set cmd [list tk_messageBox \ - -icon warning \ - -type ok \ - -title "$title: warning" \ - -message $msg] - if {[winfo ismapped .]} { - lappend cmd -parent . - } - eval $cmd -} - -proc info_popup {msg} { - global gitdir appname - - set title $appname - if {$gitdir ne {}} { - append title { (} - append title [lindex \ - [file split [file normalize [file dirname $gitdir]]] \ - end] - append title {)} - } - tk_messageBox \ - -parent . \ - -icon info \ - -type ok \ - -title $title \ - -message $msg -} - -###################################################################### -## -## repository setup - -if { [catch {set gitdir $env(GIT_DIR)}] - && [catch {set gitdir [exec git rev-parse --git-dir]} err]} { - catch {wm withdraw .} - error_popup "Cannot find the git directory:\n\n$err" - exit 1 -} -if {![file isdirectory $gitdir]} { - catch {wm withdraw .} - error_popup "Git directory not found:\n\n$gitdir" - exit 1 -} -if {[lindex [file split $gitdir] end] ne {.git}} { - catch {wm withdraw .} - error_popup "Cannot use funny .git directory:\n\n$gitdir" - exit 1 -} -if {[catch {cd [file dirname $gitdir]} err]} { - catch {wm withdraw .} - error_popup "No working directory [file dirname $gitdir]:\n\n$err" - exit 1 -} - -set single_commit 0 -if {$appname eq {git-citool}} { - set single_commit 1 -} - -###################################################################### -## -## task management - -set rescan_active 0 -set diff_active 0 -set last_clicked {} - -set disable_on_lock [list] -set index_lock_type none - -proc lock_index {type} { - global index_lock_type disable_on_lock - - if {$index_lock_type eq {none}} { - set index_lock_type $type - foreach w $disable_on_lock { - uplevel #0 $w disabled - } - return 1 - } elseif {$index_lock_type eq "begin-$type"} { - set index_lock_type $type - return 1 - } - return 0 -} - -proc unlock_index {} { - global index_lock_type disable_on_lock - - set index_lock_type none - foreach w $disable_on_lock { - uplevel #0 $w normal - } -} - -###################################################################### -## -## status - -proc repository_state {ctvar hdvar mhvar} { - global gitdir current_branch - upvar $ctvar ct $hdvar hd $mhvar mh - - set mh [list] - - if {[catch {set current_branch [exec git symbolic-ref HEAD]}]} { - set current_branch {} - } else { - regsub ^refs/((heads|tags|remotes)/)? \ - $current_branch \ - {} \ - current_branch - } - - if {[catch {set hd [exec git rev-parse --verify HEAD]}]} { - set hd {} - set ct initial - return - } - - set merge_head [file join $gitdir MERGE_HEAD] - if {[file exists $merge_head]} { - set ct merge - set fd_mh [open $merge_head r] - while {[gets $fd_mh line] >= 0} { - lappend mh $line - } - close $fd_mh - return - } - - set ct normal -} - -proc PARENT {} { - global PARENT empty_tree - - set p [lindex $PARENT 0] - if {$p ne {}} { - return $p - } - if {$empty_tree eq {}} { - set empty_tree [exec git mktree << {}] - } - return $empty_tree -} - -proc rescan {after} { - global HEAD PARENT MERGE_HEAD commit_type - global ui_index ui_other ui_status_value ui_comm - global rescan_active file_states - global repo_config - - if {$rescan_active > 0 || ![lock_index read]} return - - repository_state newType newHEAD newMERGE_HEAD - if {[string match amend* $commit_type] - && $newType eq {normal} - && $newHEAD eq $HEAD} { - } else { - set HEAD $newHEAD - set PARENT $newHEAD - set MERGE_HEAD $newMERGE_HEAD - set commit_type $newType - } - - array unset file_states - - if {![$ui_comm edit modified] - || [string trim [$ui_comm get 0.0 end]] eq {}} { - if {[load_message GITGUI_MSG]} { - } elseif {[load_message MERGE_MSG]} { - } elseif {[load_message SQUASH_MSG]} { - } - $ui_comm edit reset - $ui_comm edit modified false - } - - if {$repo_config(gui.trustmtime) eq {true}} { - rescan_stage2 {} $after - } else { - set rescan_active 1 - set ui_status_value {Refreshing file status...} - set cmd [list git update-index] - lappend cmd -q - lappend cmd --unmerged - lappend cmd --ignore-missing - lappend cmd --refresh - set fd_rf [open "| $cmd" r] - fconfigure $fd_rf -blocking 0 -translation binary - fileevent $fd_rf readable \ - [list rescan_stage2 $fd_rf $after] - } -} - -proc rescan_stage2 {fd after} { - global gitdir ui_status_value - global rescan_active buf_rdi buf_rdf buf_rlo - - if {$fd ne {}} { - read $fd - if {![eof $fd]} return - close $fd - } - - set ls_others [list | git ls-files --others -z \ - --exclude-per-directory=.gitignore] - set info_exclude [file join $gitdir info exclude] - if {[file readable $info_exclude]} { - lappend ls_others "--exclude-from=$info_exclude" - } - - set buf_rdi {} - set buf_rdf {} - set buf_rlo {} - - set rescan_active 3 - set ui_status_value {Scanning for modified files ...} - set fd_di [open "| git diff-index --cached -z [PARENT]" r] - set fd_df [open "| git diff-files -z" r] - set fd_lo [open $ls_others r] - - fconfigure $fd_di -blocking 0 -translation binary - fconfigure $fd_df -blocking 0 -translation binary - fconfigure $fd_lo -blocking 0 -translation binary - fileevent $fd_di readable [list read_diff_index $fd_di $after] - fileevent $fd_df readable [list read_diff_files $fd_df $after] - fileevent $fd_lo readable [list read_ls_others $fd_lo $after] -} - -proc load_message {file} { - global gitdir ui_comm - - set f [file join $gitdir $file] - if {[file isfile $f]} { - if {[catch {set fd [open $f r]}]} { - return 0 - } - set content [string trim [read $fd]] - close $fd - $ui_comm delete 0.0 end - $ui_comm insert end $content - return 1 - } - return 0 -} - -proc read_diff_index {fd after} { - global buf_rdi - - append buf_rdi [read $fd] - set c 0 - set n [string length $buf_rdi] - while {$c < $n} { - set z1 [string first "\0" $buf_rdi $c] - if {$z1 == -1} break - incr z1 - set z2 [string first "\0" $buf_rdi $z1] - if {$z2 == -1} break - - incr c - set i [split [string range $buf_rdi $c [expr {$z1 - 2}]] { }] - merge_state \ - [string range $buf_rdi $z1 [expr {$z2 - 1}]] \ - [lindex $i 4]? \ - [list [lindex $i 0] [lindex $i 2]] \ - [list] - set c $z2 - incr c - } - if {$c < $n} { - set buf_rdi [string range $buf_rdi $c end] - } else { - set buf_rdi {} - } - - rescan_done $fd buf_rdi $after -} - -proc read_diff_files {fd after} { - global buf_rdf - - append buf_rdf [read $fd] - set c 0 - set n [string length $buf_rdf] - while {$c < $n} { - set z1 [string first "\0" $buf_rdf $c] - if {$z1 == -1} break - incr z1 - set z2 [string first "\0" $buf_rdf $z1] - if {$z2 == -1} break - - incr c - set i [split [string range $buf_rdf $c [expr {$z1 - 2}]] { }] - merge_state \ - [string range $buf_rdf $z1 [expr {$z2 - 1}]] \ - ?[lindex $i 4] \ - [list] \ - [list [lindex $i 0] [lindex $i 2]] - set c $z2 - incr c - } - if {$c < $n} { - set buf_rdf [string range $buf_rdf $c end] - } else { - set buf_rdf {} - } - - rescan_done $fd buf_rdf $after -} - -proc read_ls_others {fd after} { - global buf_rlo - - append buf_rlo [read $fd] - set pck [split $buf_rlo "\0"] - set buf_rlo [lindex $pck end] - foreach p [lrange $pck 0 end-1] { - merge_state $p ?O - } - rescan_done $fd buf_rlo $after -} - -proc rescan_done {fd buf after} { - global rescan_active - global file_states repo_config - upvar $buf to_clear - - if {![eof $fd]} return - set to_clear {} - close $fd - if {[incr rescan_active -1] > 0} return - - prune_selection - unlock_index - display_all_files - - if {$repo_config(gui.partialinclude) ne {true}} { - set pathList [list] - foreach path [array names file_states] { - switch -- [lindex $file_states($path) 0] { - A? - - M? {lappend pathList $path} - } - } - if {$pathList ne {}} { - update_index \ - "Updating included files" \ - $pathList \ - [concat {reshow_diff;} $after] - return - } - } - - reshow_diff - uplevel #0 $after -} - -proc prune_selection {} { - global file_states selected_paths - - foreach path [array names selected_paths] { - if {[catch {set still_here $file_states($path)}]} { - unset selected_paths($path) - } - } -} - -###################################################################### -## -## diff - -proc clear_diff {} { - global ui_diff current_diff ui_index ui_other - - $ui_diff conf -state normal - $ui_diff delete 0.0 end - $ui_diff conf -state disabled - - set current_diff {} - - $ui_index tag remove in_diff 0.0 end - $ui_other tag remove in_diff 0.0 end -} - -proc reshow_diff {} { - global current_diff ui_status_value file_states - - if {$current_diff eq {} - || [catch {set s $file_states($current_diff)}]} { - clear_diff - } else { - show_diff $current_diff - } -} - -proc handle_empty_diff {} { - global current_diff file_states file_lists - - set path $current_diff - set s $file_states($path) - if {[lindex $s 0] ne {_M}} return - - info_popup "No differences detected. - -[short_path $path] has no changes. - -The modification date of this file was updated -by another application and you currently have -the Trust File Modification Timestamps option -enabled, so Git did not automatically detect -that there are no content differences in this -file. - -This file will now be removed from the modified -files list, to prevent possible confusion. -" - if {[catch {exec git update-index -- $path} err]} { - error_popup "Failed to refresh index:\n\n$err" - } - - clear_diff - set old_w [mapcol [lindex $file_states($path) 0] $path] - set lno [lsearch -sorted $file_lists($old_w) $path] - if {$lno >= 0} { - set file_lists($old_w) \ - [lreplace $file_lists($old_w) $lno $lno] - incr lno - $old_w conf -state normal - $old_w delete $lno.0 [expr {$lno + 1}].0 - $old_w conf -state disabled - } -} - -proc show_diff {path {w {}} {lno {}}} { - global file_states file_lists - global is_3way_diff diff_active repo_config - global ui_diff current_diff ui_status_value - - if {$diff_active || ![lock_index read]} return - - clear_diff - if {$w eq {} || $lno == {}} { - foreach w [array names file_lists] { - set lno [lsearch -sorted $file_lists($w) $path] - if {$lno >= 0} { - incr lno - break - } - } - } - if {$w ne {} && $lno >= 1} { - $w tag add in_diff $lno.0 [expr {$lno + 1}].0 - } - - set s $file_states($path) - set m [lindex $s 0] - set is_3way_diff 0 - set diff_active 1 - set current_diff $path - set ui_status_value "Loading diff of [escape_path $path]..." - - set cmd [list | git diff-index] - lappend cmd --no-color - if {$repo_config(gui.diffcontext) > 0} { - lappend cmd "-U$repo_config(gui.diffcontext)" - } - lappend cmd -p - - switch $m { - MM { - lappend cmd -c - } - _O { - if {[catch { - set fd [open $path r] - set content [read $fd] - close $fd - } err ]} { - set diff_active 0 - unlock_index - set ui_status_value "Unable to display [escape_path $path]" - error_popup "Error loading file:\n\n$err" - return - } - $ui_diff conf -state normal - $ui_diff insert end $content - $ui_diff conf -state disabled - set diff_active 0 - unlock_index - set ui_status_value {Ready.} - return - } - } - - lappend cmd [PARENT] - lappend cmd -- - lappend cmd $path - - if {[catch {set fd [open $cmd r]} err]} { - set diff_active 0 - unlock_index - set ui_status_value "Unable to display [escape_path $path]" - error_popup "Error loading diff:\n\n$err" - return - } - - fconfigure $fd -blocking 0 -translation auto - fileevent $fd readable [list read_diff $fd] -} - -proc read_diff {fd} { - global ui_diff ui_status_value is_3way_diff diff_active - global repo_config - - $ui_diff conf -state normal - while {[gets $fd line] >= 0} { - # -- Cleanup uninteresting diff header lines. - # - if {[string match {diff --git *} $line]} continue - if {[string match {diff --combined *} $line]} continue - if {[string match {--- *} $line]} continue - if {[string match {+++ *} $line]} continue - if {$line eq {deleted file mode 120000}} { - set line "deleted symlink" - } - - # -- Automatically detect if this is a 3 way diff. - # - if {[string match {@@@ *} $line]} {set is_3way_diff 1} - - # -- Reformat a 3 way diff, 'cause its too weird. - # - if {$is_3way_diff} { - set op [string range $line 0 1] - switch -- $op { - {@@} {set tags d_@} - {++} {set tags d_+ ; set op { +}} - {--} {set tags d_- ; set op { -}} - { +} {set tags d_++; set op {++}} - { -} {set tags d_--; set op {--}} - {+ } {set tags d_-+; set op {-+}} - {- } {set tags d_+-; set op {+-}} - default {set tags {}} - } - set line [string replace $line 0 1 $op] - } else { - switch -- [string index $line 0] { - @ {set tags d_@} - + {set tags d_+} - - {set tags d_-} - default {set tags {}} - } - } - $ui_diff insert end $line $tags - $ui_diff insert end "\n" $tags - } - $ui_diff conf -state disabled - - if {[eof $fd]} { - close $fd - set diff_active 0 - unlock_index - set ui_status_value {Ready.} - - if {$repo_config(gui.trustmtime) eq {true} - && [$ui_diff index end] eq {2.0}} { - handle_empty_diff - } - } -} - -###################################################################### -## -## commit - -proc load_last_commit {} { - global HEAD PARENT MERGE_HEAD commit_type ui_comm - - if {[llength $PARENT] == 0} { - error_popup {There is nothing to amend. - -You are about to create the initial commit. -There is no commit before this to amend. -} - return - } - - repository_state curType curHEAD curMERGE_HEAD - if {$curType eq {merge}} { - error_popup {Cannot amend while merging. - -You are currently in the middle of a merge that -has not been fully completed. You cannot amend -the prior commit unless you first abort the -current merge activity. -} - return - } - - set msg {} - set parents [list] - if {[catch { - set fd [open "| git cat-file commit $curHEAD" r] - while {[gets $fd line] > 0} { - if {[string match {parent *} $line]} { - lappend parents [string range $line 7 end] - } - } - set msg [string trim [read $fd]] - close $fd - } err]} { - error_popup "Error loading commit data for amend:\n\n$err" - return - } - - set HEAD $curHEAD - set PARENT $parents - set MERGE_HEAD [list] - switch -- [llength $parents] { - 0 {set commit_type amend-initial} - 1 {set commit_type amend} - default {set commit_type amend-merge} - } - - $ui_comm delete 0.0 end - $ui_comm insert end $msg - $ui_comm edit reset - $ui_comm edit modified false - rescan {set ui_status_value {Ready.}} -} - -proc create_new_commit {} { - global commit_type ui_comm - - set commit_type normal - $ui_comm delete 0.0 end - $ui_comm edit reset - $ui_comm edit modified false - rescan {set ui_status_value {Ready.}} -} - -set GIT_COMMITTER_IDENT {} - -proc committer_ident {} { - global GIT_COMMITTER_IDENT - - if {$GIT_COMMITTER_IDENT eq {}} { - if {[catch {set me [exec git var GIT_COMMITTER_IDENT]} err]} { - error_popup "Unable to obtain your identity:\n\n$err" - return {} - } - if {![regexp {^(.*) [0-9]+ [-+0-9]+$} \ - $me me GIT_COMMITTER_IDENT]} { - error_popup "Invalid GIT_COMMITTER_IDENT:\n\n$me" - return {} - } - } - - return $GIT_COMMITTER_IDENT -} - -proc commit_tree {} { - global HEAD commit_type file_states ui_comm repo_config - - if {![lock_index update]} return - if {[committer_ident] eq {}} return - - # -- Our in memory state should match the repository. - # - repository_state curType curHEAD curMERGE_HEAD - if {[string match amend* $commit_type] - && $curType eq {normal} - && $curHEAD eq $HEAD} { - } elseif {$commit_type ne $curType || $HEAD ne $curHEAD} { - info_popup {Last scanned state does not match repository state. - -Another Git program has modified this repository -since the last scan. A rescan must be performed -before another commit can be created. - -The rescan will be automatically started now. -} - unlock_index - rescan {set ui_status_value {Ready.}} - return - } - - # -- At least one file should differ in the index. - # - set files_ready 0 - foreach path [array names file_states] { - switch -glob -- [lindex $file_states($path) 0] { - _? {continue} - A? - - D? - - M? {set files_ready 1; break} - U? { - error_popup "Unmerged files cannot be committed. - -File [short_path $path] has merge conflicts. -You must resolve them and include the file before committing. -" - unlock_index - return - } - default { - error_popup "Unknown file state [lindex $s 0] detected. - -File [short_path $path] cannot be committed by this program. -" - } - } - } - if {!$files_ready} { - error_popup {No included files to commit. - -You must include at least 1 file before you can commit. -} - unlock_index - return - } - - # -- A message is required. - # - set msg [string trim [$ui_comm get 1.0 end]] - if {$msg eq {}} { - error_popup {Please supply a commit message. - -A good commit message has the following format: - -- First line: Describe in one sentance what you did. -- Second line: Blank -- Remaining lines: Describe why this change is good. -} - unlock_index - return - } - - # -- Update included files if partialincludes are off. - # - if {$repo_config(gui.partialinclude) ne {true}} { - set pathList [list] - foreach path [array names file_states] { - switch -glob -- [lindex $file_states($path) 0] { - A? - - M? {lappend pathList $path} - } - } - if {$pathList ne {}} { - unlock_index - update_index \ - "Updating included files" \ - $pathList \ - [concat {lock_index update;} \ - [list commit_prehook $curHEAD $msg]] - return - } - } - - commit_prehook $curHEAD $msg -} - -proc commit_prehook {curHEAD msg} { - global gitdir ui_status_value pch_error - - set pchook [file join $gitdir hooks pre-commit] - - # On Cygwin [file executable] might lie so we need to ask - # the shell if the hook is executable. Yes that's annoying. - # - if {[is_Windows] && [file isfile $pchook]} { - set pchook [list sh -c [concat \ - "if test -x \"$pchook\";" \ - "then exec \"$pchook\" 2>&1;" \ - "fi"]] - } elseif {[file executable $pchook]} { - set pchook [list $pchook |& cat] - } else { - commit_writetree $curHEAD $msg - return - } - - set ui_status_value {Calling pre-commit hook...} - set pch_error {} - set fd_ph [open "| $pchook" r] - fconfigure $fd_ph -blocking 0 -translation binary - fileevent $fd_ph readable \ - [list commit_prehook_wait $fd_ph $curHEAD $msg] -} - -proc commit_prehook_wait {fd_ph curHEAD msg} { - global pch_error ui_status_value - - append pch_error [read $fd_ph] - fconfigure $fd_ph -blocking 1 - if {[eof $fd_ph]} { - if {[catch {close $fd_ph}]} { - set ui_status_value {Commit declined by pre-commit hook.} - hook_failed_popup pre-commit $pch_error - unlock_index - } else { - commit_writetree $curHEAD $msg - } - set pch_error {} - return - } - fconfigure $fd_ph -blocking 0 -} - -proc commit_writetree {curHEAD msg} { - global ui_status_value - - set ui_status_value {Committing changes...} - set fd_wt [open "| git write-tree" r] - fileevent $fd_wt readable \ - [list commit_committree $fd_wt $curHEAD $msg] -} - -proc commit_committree {fd_wt curHEAD msg} { - global HEAD PARENT MERGE_HEAD commit_type - global single_commit gitdir - global ui_status_value ui_comm selected_commit_type - global file_states selected_paths rescan_active - - gets $fd_wt tree_id - if {$tree_id eq {} || [catch {close $fd_wt} err]} { - error_popup "write-tree failed:\n\n$err" - set ui_status_value {Commit failed.} - unlock_index - return - } - - # -- Create the commit. - # - set cmd [list git commit-tree $tree_id] - set parents [concat $PARENT $MERGE_HEAD] - if {[llength $parents] > 0} { - foreach p $parents { - lappend cmd -p $p - } - } else { - # git commit-tree writes to stderr during initial commit. - lappend cmd 2>/dev/null - } - lappend cmd << $msg - if {[catch {set cmt_id [eval exec $cmd]} err]} { - error_popup "commit-tree failed:\n\n$err" - set ui_status_value {Commit failed.} - unlock_index - return - } - - # -- Update the HEAD ref. - # - set reflogm commit - if {$commit_type ne {normal}} { - append reflogm " ($commit_type)" - } - set i [string first "\n" $msg] - if {$i >= 0} { - append reflogm {: } [string range $msg 0 [expr {$i - 1}]] - } else { - append reflogm {: } $msg - } - set cmd [list git update-ref -m $reflogm HEAD $cmt_id $curHEAD] - if {[catch {eval exec $cmd} err]} { - error_popup "update-ref failed:\n\n$err" - set ui_status_value {Commit failed.} - unlock_index - return - } - - # -- Cleanup after ourselves. - # - catch {file delete [file join $gitdir MERGE_HEAD]} - catch {file delete [file join $gitdir MERGE_MSG]} - catch {file delete [file join $gitdir SQUASH_MSG]} - catch {file delete [file join $gitdir GITGUI_MSG]} - - # -- Let rerere do its thing. - # - if {[file isdirectory [file join $gitdir rr-cache]]} { - catch {exec git rerere} - } - - # -- Run the post-commit hook. - # - set pchook [file join $gitdir hooks post-commit] - if {[is_Windows] && [file isfile $pchook]} { - set pchook [list sh -c [concat \ - "if test -x \"$pchook\";" \ - "then exec \"$pchook\";" \ - "fi"]] - } elseif {![file executable $pchook]} { - set pchook {} - } - if {$pchook ne {}} { - catch {exec $pchook &} - } - - $ui_comm delete 0.0 end - $ui_comm edit reset - $ui_comm edit modified false - - if {$single_commit} do_quit - - # -- Update in memory status - # - set selected_commit_type new - set commit_type normal - set HEAD $cmt_id - set PARENT $cmt_id - set MERGE_HEAD [list] - - foreach path [array names file_states] { - set s $file_states($path) - set m [lindex $s 0] - switch -glob -- $m { - _O - - _M - - _D {continue} - __ - - A_ - - M_ - - DD { - unset file_states($path) - catch {unset selected_paths($path)} - } - DO { - set file_states($path) [list _O [lindex $s 1] {} {}] - } - AM - - AD - - MM - - MD - - DM { - set file_states($path) [list \ - _[string index $m 1] \ - [lindex $s 1] \ - [lindex $s 3] \ - {}] - } - } - } - - display_all_files - unlock_index - reshow_diff - set ui_status_value \ - "Changes committed as [string range $cmt_id 0 7]." -} - -###################################################################### -## -## fetch pull push - -proc fetch_from {remote} { - set w [new_console "fetch $remote" \ - "Fetching new changes from $remote"] - set cmd [list git fetch] - lappend cmd $remote - console_exec $w $cmd -} - -proc pull_remote {remote branch} { - global HEAD commit_type file_states repo_config - - if {![lock_index update]} return - - # -- Our in memory state should match the repository. - # - repository_state curType curHEAD curMERGE_HEAD - if {$commit_type ne $curType || $HEAD ne $curHEAD} { - info_popup {Last scanned state does not match repository state. - -Another Git program has modified this repository -since the last scan. A rescan must be performed -before a pull operation can be started. - -The rescan will be automatically started now. -} - unlock_index - rescan {set ui_status_value {Ready.}} - return - } - - # -- No differences should exist before a pull. - # - if {[array size file_states] != 0} { - error_popup {Uncommitted but modified files are present. - -You should not perform a pull with unmodified -files in your working directory as Git will be -unable to recover from an incorrect merge. - -You should commit or revert all changes before -starting a pull operation. -} - unlock_index - return - } - - set w [new_console "pull $remote $branch" \ - "Pulling new changes from branch $branch in $remote"] - set cmd [list git pull] - if {$repo_config(gui.pullsummary) eq {false}} { - lappend cmd --no-summary - } - lappend cmd $remote - lappend cmd $branch - console_exec $w $cmd [list post_pull_remote $remote $branch] -} - -proc post_pull_remote {remote branch success} { - global HEAD PARENT MERGE_HEAD commit_type selected_commit_type - global ui_status_value - - unlock_index - if {$success} { - repository_state commit_type HEAD MERGE_HEAD - set PARENT $HEAD - set selected_commit_type new - set ui_status_value "Pulling $branch from $remote complete." - } else { - rescan [list set ui_status_value \ - "Conflicts detected while pulling $branch from $remote."] - } -} - -proc push_to {remote} { - set w [new_console "push $remote" \ - "Pushing changes to $remote"] - set cmd [list git push] - lappend cmd $remote - console_exec $w $cmd -} - -###################################################################### -## -## ui helpers - -proc mapcol {state path} { - global all_cols ui_other - - if {[catch {set r $all_cols($state)}]} { - puts "error: no column for state={$state} $path" - return $ui_other - } - return $r -} - -proc mapicon {state path} { - global all_icons - - if {[catch {set r $all_icons($state)}]} { - puts "error: no icon for state={$state} $path" - return file_plain - } - return $r -} - -proc mapdesc {state path} { - global all_descs - - if {[catch {set r $all_descs($state)}]} { - puts "error: no desc for state={$state} $path" - return $state - } - return $r -} - -proc escape_path {path} { - regsub -all "\n" $path "\\n" path - return $path -} - -proc short_path {path} { - return [escape_path [lindex [file split $path] end]] -} - -set next_icon_id 0 -set null_sha1 [string repeat 0 40] - -proc merge_state {path new_state {head_info {}} {index_info {}}} { - global file_states next_icon_id null_sha1 - - set s0 [string index $new_state 0] - set s1 [string index $new_state 1] - - if {[catch {set info $file_states($path)}]} { - set state __ - set icon n[incr next_icon_id] - } else { - set state [lindex $info 0] - set icon [lindex $info 1] - if {$head_info eq {}} {set head_info [lindex $info 2]} - if {$index_info eq {}} {set index_info [lindex $info 3]} - } - - if {$s0 eq {?}} {set s0 [string index $state 0]} \ - elseif {$s0 eq {_}} {set s0 _} - - if {$s1 eq {?}} {set s1 [string index $state 1]} \ - elseif {$s1 eq {_}} {set s1 _} - - if {$s0 eq {A} && $s1 eq {_} && $head_info eq {}} { - set head_info [list 0 $null_sha1] - } elseif {$s0 ne {_} && [string index $state 0] eq {_} - && $head_info eq {}} { - set head_info $index_info - } - - set file_states($path) [list $s0$s1 $icon \ - $head_info $index_info \ - ] - return $state -} - -proc display_file {path state} { - global file_states file_lists selected_paths - - set old_m [merge_state $path $state] - set s $file_states($path) - set new_m [lindex $s 0] - set new_w [mapcol $new_m $path] - set old_w [mapcol $old_m $path] - set new_icon [mapicon $new_m $path] - - if {$new_m eq {__}} { - set lno [lsearch -sorted $file_lists($old_w) $path] - if {$lno >= 0} { - set file_lists($old_w) \ - [lreplace $file_lists($old_w) $lno $lno] - incr lno - $old_w conf -state normal - $old_w delete $lno.0 [expr {$lno + 1}].0 - $old_w conf -state disabled - } - unset file_states($path) - catch {unset selected_paths($path)} - return - } - - if {$new_w ne $old_w} { - set lno [lsearch -sorted $file_lists($old_w) $path] - if {$lno >= 0} { - set file_lists($old_w) \ - [lreplace $file_lists($old_w) $lno $lno] - incr lno - $old_w conf -state normal - $old_w delete $lno.0 [expr {$lno + 1}].0 - $old_w conf -state disabled - } - - lappend file_lists($new_w) $path - set file_lists($new_w) [lsort $file_lists($new_w)] - set lno [lsearch -sorted $file_lists($new_w) $path] - incr lno - $new_w conf -state normal - $new_w image create $lno.0 \ - -align center -padx 5 -pady 1 \ - -name [lindex $s 1] \ - -image $new_icon - $new_w insert $lno.1 "[escape_path $path]\n" - if {[catch {set in_sel $selected_paths($path)}]} { - set in_sel 0 - } - if {$in_sel} { - $new_w tag add in_sel $lno.0 [expr {$lno + 1}].0 - } - $new_w conf -state disabled - } elseif {$new_icon ne [mapicon $old_m $path]} { - $new_w conf -state normal - $new_w image conf [lindex $s 1] -image $new_icon - $new_w conf -state disabled - } -} - -proc display_all_files {} { - global ui_index ui_other - global file_states file_lists - global last_clicked selected_paths - - $ui_index conf -state normal - $ui_other conf -state normal - - $ui_index delete 0.0 end - $ui_other delete 0.0 end - set last_clicked {} - - set file_lists($ui_index) [list] - set file_lists($ui_other) [list] - - foreach path [lsort [array names file_states]] { - set s $file_states($path) - set m [lindex $s 0] - set w [mapcol $m $path] - lappend file_lists($w) $path - set lno [expr {[lindex [split [$w index end] .] 0] - 1}] - $w image create end \ - -align center -padx 5 -pady 1 \ - -name [lindex $s 1] \ - -image [mapicon $m $path] - $w insert end "[escape_path $path]\n" - if {[catch {set in_sel $selected_paths($path)}]} { - set in_sel 0 - } - if {$in_sel} { - $w tag add in_sel $lno.0 [expr {$lno + 1}].0 - } - } - - $ui_index conf -state disabled - $ui_other conf -state disabled -} - -proc update_indexinfo {msg pathList after} { - global update_index_cp ui_status_value - - if {![lock_index update]} return - - set update_index_cp 0 - set pathList [lsort $pathList] - set totalCnt [llength $pathList] - set batch [expr {int($totalCnt * .01) + 1}] - if {$batch > 25} {set batch 25} - - set ui_status_value [format \ - "$msg... %i/%i files (%.2f%%)" \ - $update_index_cp \ - $totalCnt \ - 0.0] - set fd [open "| git update-index -z --index-info" w] - fconfigure $fd \ - -blocking 0 \ - -buffering full \ - -buffersize 512 \ - -translation binary - fileevent $fd writable [list \ - write_update_indexinfo \ - $fd \ - $pathList \ - $totalCnt \ - $batch \ - $msg \ - $after \ - ] -} - -proc write_update_indexinfo {fd pathList totalCnt batch msg after} { - global update_index_cp ui_status_value - global file_states current_diff - - if {$update_index_cp >= $totalCnt} { - close $fd - unlock_index - uplevel #0 $after - return - } - - for {set i $batch} \ - {$update_index_cp < $totalCnt && $i > 0} \ - {incr i -1} { - set path [lindex $pathList $update_index_cp] - incr update_index_cp - - set s $file_states($path) - switch -glob -- [lindex $s 0] { - A? {set new _O} - M? {set new _M} - D_ {set new _D} - D? {set new _?} - ?? {continue} - } - set info [lindex $s 2] - if {$info eq {}} continue - - puts -nonewline $fd $info - puts -nonewline $fd "\t" - puts -nonewline $fd $path - puts -nonewline $fd "\0" - display_file $path $new - } - - set ui_status_value [format \ - "$msg... %i/%i files (%.2f%%)" \ - $update_index_cp \ - $totalCnt \ - [expr {100.0 * $update_index_cp / $totalCnt}]] -} - -proc update_index {msg pathList after} { - global update_index_cp ui_status_value - - if {![lock_index update]} return - - set update_index_cp 0 - set pathList [lsort $pathList] - set totalCnt [llength $pathList] - set batch [expr {int($totalCnt * .01) + 1}] - if {$batch > 25} {set batch 25} - - set ui_status_value [format \ - "$msg... %i/%i files (%.2f%%)" \ - $update_index_cp \ - $totalCnt \ - 0.0] - set fd [open "| git update-index --add --remove -z --stdin" w] - fconfigure $fd \ - -blocking 0 \ - -buffering full \ - -buffersize 512 \ - -translation binary - fileevent $fd writable [list \ - write_update_index \ - $fd \ - $pathList \ - $totalCnt \ - $batch \ - $msg \ - $after \ - ] -} - -proc write_update_index {fd pathList totalCnt batch msg after} { - global update_index_cp ui_status_value - global file_states current_diff - - if {$update_index_cp >= $totalCnt} { - close $fd - unlock_index - uplevel #0 $after - return - } - - for {set i $batch} \ - {$update_index_cp < $totalCnt && $i > 0} \ - {incr i -1} { - set path [lindex $pathList $update_index_cp] - incr update_index_cp - - switch -glob -- [lindex $file_states($path) 0] { - AD - - MD - - UD - - _D {set new DD} - - _M - - MM - - UM - - U_ - - M_ {set new M_} - - _O - - AM - - A_ {set new A_} - - ?? {continue} - } - - puts -nonewline $fd $path - puts -nonewline $fd "\0" - display_file $path $new - } - - set ui_status_value [format \ - "$msg... %i/%i files (%.2f%%)" \ - $update_index_cp \ - $totalCnt \ - [expr {100.0 * $update_index_cp / $totalCnt}]] -} - -proc checkout_index {msg pathList after} { - global update_index_cp ui_status_value - - if {![lock_index update]} return - - set update_index_cp 0 - set pathList [lsort $pathList] - set totalCnt [llength $pathList] - set batch [expr {int($totalCnt * .01) + 1}] - if {$batch > 25} {set batch 25} - - set ui_status_value [format \ - "$msg... %i/%i files (%.2f%%)" \ - $update_index_cp \ - $totalCnt \ - 0.0] - set cmd [list git checkout-index] - lappend cmd --index - lappend cmd --quiet - lappend cmd --force - lappend cmd -z - lappend cmd --stdin - set fd [open "| $cmd " w] - fconfigure $fd \ - -blocking 0 \ - -buffering full \ - -buffersize 512 \ - -translation binary - fileevent $fd writable [list \ - write_checkout_index \ - $fd \ - $pathList \ - $totalCnt \ - $batch \ - $msg \ - $after \ - ] -} - -proc write_checkout_index {fd pathList totalCnt batch msg after} { - global update_index_cp ui_status_value - global file_states current_diff - - if {$update_index_cp >= $totalCnt} { - close $fd - unlock_index - uplevel #0 $after - return - } - - for {set i $batch} \ - {$update_index_cp < $totalCnt && $i > 0} \ - {incr i -1} { - set path [lindex $pathList $update_index_cp] - incr update_index_cp - - switch -glob -- [lindex $file_states($path) 0] { - AM - - AD {set new A_} - MM - - MD {set new M_} - _M - - _D {set new __} - ?? {continue} - } - - puts -nonewline $fd $path - puts -nonewline $fd "\0" - display_file $path $new - } - - set ui_status_value [format \ - "$msg... %i/%i files (%.2f%%)" \ - $update_index_cp \ - $totalCnt \ - [expr {100.0 * $update_index_cp / $totalCnt}]] -} - -###################################################################### -## -## branch management - -proc load_all_heads {} { - global all_heads tracking_branches - - set all_heads [list] - set cmd [list git for-each-ref] - lappend cmd --format=%(refname) - lappend cmd refs/heads - set fd [open "| $cmd" r] - while {[gets $fd line] > 0} { - if {![catch {set info $tracking_branches($line)}]} continue - if {![regsub ^refs/heads/ $line {} name]} continue - lappend all_heads $name - } - close $fd - - set all_heads [lsort $all_heads] -} - -proc populate_branch_menu {m} { - global all_heads disable_on_lock - - $m add separator - foreach b $all_heads { - $m add radiobutton \ - -label $b \ - -command [list switch_branch $b] \ - -variable current_branch \ - -value $b \ - -font font_ui - lappend disable_on_lock \ - [list $m entryconf [$m index last] -state] - } -} - -proc do_create_branch {} { - error "NOT IMPLEMENTED" -} - -proc do_delete_branch {} { - error "NOT IMPLEMENTED" -} - -proc switch_branch {b} { - global HEAD commit_type file_states current_branch - global selected_commit_type ui_comm - - if {![lock_index switch]} return - - # -- Backup the selected branch (repository_state resets it) - # - set new_branch $current_branch - - # -- Our in memory state should match the repository. - # - repository_state curType curHEAD curMERGE_HEAD - if {[string match amend* $commit_type] - && $curType eq {normal} - && $curHEAD eq $HEAD} { - } elseif {$commit_type ne $curType || $HEAD ne $curHEAD} { - info_popup {Last scanned state does not match repository state. - -Another Git program has modified this repository -since the last scan. A rescan must be performed -before the current branch can be changed. - -The rescan will be automatically started now. -} - unlock_index - rescan {set ui_status_value {Ready.}} - return - } - - # -- Toss the message buffer if we are in amend mode. - # - if {[string match amend* $curType]} { - $ui_comm delete 0.0 end - $ui_comm edit reset - $ui_comm edit modified false - } - - set selected_commit_type new - set current_branch $new_branch - - unlock_index - error "NOT FINISHED" -} - -###################################################################### -## -## remote management - -proc load_all_remotes {} { - global gitdir repo_config - global all_remotes tracking_branches - - set all_remotes [list] - array unset tracking_branches - - set rm_dir [file join $gitdir remotes] - if {[file isdirectory $rm_dir]} { - set all_remotes [glob \ - -types f \ - -tails \ - -nocomplain \ - -directory $rm_dir *] - - foreach name $all_remotes { - catch { - set fd [open [file join $rm_dir $name] r] - while {[gets $fd line] >= 0} { - if {![regexp {^Pull:[ ]*([^:]+):(.+)$} \ - $line line src dst]} continue - if {![regexp ^refs/ $dst]} { - set dst "refs/heads/$dst" - } - set tracking_branches($dst) [list $name $src] - } - close $fd - } - } - } - - foreach line [array names repo_config remote.*.url] { - if {![regexp ^remote\.(.*)\.url\$ $line line name]} continue - lappend all_remotes $name - - if {[catch {set fl $repo_config(remote.$name.fetch)}]} { - set fl {} - } - foreach line $fl { - if {![regexp {^([^:]+):(.+)$} $line line src dst]} continue - if {![regexp ^refs/ $dst]} { - set dst "refs/heads/$dst" - } - set tracking_branches($dst) [list $name $src] - } - } - - set all_remotes [lsort -unique $all_remotes] -} - -proc populate_fetch_menu {m} { - global gitdir all_remotes repo_config - - foreach r $all_remotes { - set enable 0 - if {![catch {set a $repo_config(remote.$r.url)}]} { - if {![catch {set a $repo_config(remote.$r.fetch)}]} { - set enable 1 - } - } else { - catch { - set fd [open [file join $gitdir remotes $r] r] - while {[gets $fd n] >= 0} { - if {[regexp {^Pull:[ \t]*([^:]+):} $n]} { - set enable 1 - break - } - } - close $fd - } - } - - if {$enable} { - $m add command \ - -label "Fetch from $r..." \ - -command [list fetch_from $r] \ - -font font_ui - } - } -} - -proc populate_push_menu {m} { - global gitdir all_remotes repo_config - - foreach r $all_remotes { - set enable 0 - if {![catch {set a $repo_config(remote.$r.url)}]} { - if {![catch {set a $repo_config(remote.$r.push)}]} { - set enable 1 - } - } else { - catch { - set fd [open [file join $gitdir remotes $r] r] - while {[gets $fd n] >= 0} { - if {[regexp {^Push:[ \t]*([^:]+):} $n]} { - set enable 1 - break - } - } - close $fd - } - } - - if {$enable} { - $m add command \ - -label "Push to $r..." \ - -command [list push_to $r] \ - -font font_ui - } - } -} - -proc populate_pull_menu {m} { - global gitdir repo_config all_remotes disable_on_lock - - foreach remote $all_remotes { - set rb_list [list] - if {[array get repo_config remote.$remote.url] ne {}} { - if {[array get repo_config remote.$remote.fetch] ne {}} { - foreach line $repo_config(remote.$remote.fetch) { - if {[regexp {^([^:]+):} $line line rb]} { - lappend rb_list $rb - } - } - } - } else { - catch { - set fd [open [file join $gitdir remotes $remote] r] - while {[gets $fd line] >= 0} { - if {[regexp {^Pull:[ \t]*([^:]+):} $line line rb]} { - lappend rb_list $rb - } - } - close $fd - } - } - - foreach rb $rb_list { - regsub ^refs/heads/ $rb {} rb_short - $m add command \ - -label "Branch $rb_short from $remote..." \ - -command [list pull_remote $remote $rb] \ - -font font_ui - lappend disable_on_lock \ - [list $m entryconf [$m index last] -state] - } - } -} - -###################################################################### -## -## icons - -set filemask { -#define mask_width 14 -#define mask_height 15 -static unsigned char mask_bits[] = { - 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, - 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, - 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f}; -} - -image create bitmap file_plain -background white -foreground black -data { -#define plain_width 14 -#define plain_height 15 -static unsigned char plain_bits[] = { - 0xfe, 0x01, 0x02, 0x03, 0x02, 0x05, 0x02, 0x09, 0x02, 0x1f, 0x02, 0x10, - 0x02, 0x10, 0x02, 0x10, 0x02, 0x10, 0x02, 0x10, 0x02, 0x10, 0x02, 0x10, - 0x02, 0x10, 0x02, 0x10, 0xfe, 0x1f}; -} -maskdata $filemask - -image create bitmap file_mod -background white -foreground blue -data { -#define mod_width 14 -#define mod_height 15 -static unsigned char mod_bits[] = { - 0xfe, 0x01, 0x02, 0x03, 0x7a, 0x05, 0x02, 0x09, 0x7a, 0x1f, 0x02, 0x10, - 0xfa, 0x17, 0x02, 0x10, 0xfa, 0x17, 0x02, 0x10, 0xfa, 0x17, 0x02, 0x10, - 0xfa, 0x17, 0x02, 0x10, 0xfe, 0x1f}; -} -maskdata $filemask - -image create bitmap file_fulltick -background white -foreground "#007000" -data { -#define file_fulltick_width 14 -#define file_fulltick_height 15 -static unsigned char file_fulltick_bits[] = { - 0xfe, 0x01, 0x02, 0x1a, 0x02, 0x0c, 0x02, 0x0c, 0x02, 0x16, 0x02, 0x16, - 0x02, 0x13, 0x00, 0x13, 0x86, 0x11, 0x8c, 0x11, 0xd8, 0x10, 0xf2, 0x10, - 0x62, 0x10, 0x02, 0x10, 0xfe, 0x1f}; -} -maskdata $filemask - -image create bitmap file_parttick -background white -foreground "#005050" -data { -#define parttick_width 14 -#define parttick_height 15 -static unsigned char parttick_bits[] = { - 0xfe, 0x01, 0x02, 0x03, 0x7a, 0x05, 0x02, 0x09, 0x7a, 0x1f, 0x02, 0x10, - 0x7a, 0x14, 0x02, 0x16, 0x02, 0x13, 0x8a, 0x11, 0xda, 0x10, 0x72, 0x10, - 0x22, 0x10, 0x02, 0x10, 0xfe, 0x1f}; -} -maskdata $filemask - -image create bitmap file_question -background white -foreground black -data { -#define file_question_width 14 -#define file_question_height 15 -static unsigned char file_question_bits[] = { - 0xfe, 0x01, 0x02, 0x02, 0xe2, 0x04, 0xf2, 0x09, 0x1a, 0x1b, 0x0a, 0x13, - 0x82, 0x11, 0xc2, 0x10, 0x62, 0x10, 0x62, 0x10, 0x02, 0x10, 0x62, 0x10, - 0x62, 0x10, 0x02, 0x10, 0xfe, 0x1f}; -} -maskdata $filemask - -image create bitmap file_removed -background white -foreground red -data { -#define file_removed_width 14 -#define file_removed_height 15 -static unsigned char file_removed_bits[] = { - 0xfe, 0x01, 0x02, 0x03, 0x02, 0x05, 0x02, 0x09, 0x02, 0x1f, 0x02, 0x10, - 0x1a, 0x16, 0x32, 0x13, 0xe2, 0x11, 0xc2, 0x10, 0xe2, 0x11, 0x32, 0x13, - 0x1a, 0x16, 0x02, 0x10, 0xfe, 0x1f}; -} -maskdata $filemask - -image create bitmap file_merge -background white -foreground blue -data { -#define file_merge_width 14 -#define file_merge_height 15 -static unsigned char file_merge_bits[] = { - 0xfe, 0x01, 0x02, 0x03, 0x62, 0x05, 0x62, 0x09, 0x62, 0x1f, 0x62, 0x10, - 0xfa, 0x11, 0xf2, 0x10, 0x62, 0x10, 0x02, 0x10, 0xfa, 0x17, 0x02, 0x10, - 0xfa, 0x17, 0x02, 0x10, 0xfe, 0x1f}; -} -maskdata $filemask - -set ui_index .vpane.files.index.list -set ui_other .vpane.files.other.list -set max_status_desc 0 -foreach i { - {__ i plain "Unmodified"} - {_M i mod "Modified"} - {M_ i fulltick "Added to commit"} - {MM i parttick "Partially included"} - {MD i question "Added (but gone)"} - - {_O o plain "Untracked"} - {A_ o fulltick "Added by commit"} - {AM o parttick "Partially added"} - {AD o question "Added (but gone)"} - - {_D i question "Missing"} - {DD i removed "Removed by commit"} - {D_ i removed "Removed by commit"} - {DO i removed "Removed (still exists)"} - {DM i removed "Removed (but modified)"} - - {UD i merge "Merge conflicts"} - {UM i merge "Merge conflicts"} - {U_ i merge "Merge conflicts"} - } { - if {$max_status_desc < [string length [lindex $i 3]]} { - set max_status_desc [string length [lindex $i 3]] - } - if {[lindex $i 1] eq {i}} { - set all_cols([lindex $i 0]) $ui_index - } else { - set all_cols([lindex $i 0]) $ui_other - } - set all_icons([lindex $i 0]) file_[lindex $i 2] - set all_descs([lindex $i 0]) [lindex $i 3] -} -unset filemask i - -###################################################################### -## -## util - -proc is_MacOSX {} { - global tcl_platform tk_library - if {[tk windowingsystem] eq {aqua}} { - return 1 - } - return 0 -} - -proc is_Windows {} { - global tcl_platform - if {$tcl_platform(platform) eq {windows}} { - return 1 - } - return 0 -} - -proc bind_button3 {w cmd} { - bind $w $cmd - if {[is_MacOSX]} { - bind $w $cmd - } -} - -proc incr_font_size {font {amt 1}} { - set sz [font configure $font -size] - incr sz $amt - font configure $font -size $sz - font configure ${font}bold -size $sz -} - -proc hook_failed_popup {hook msg} { - global gitdir appname - - set w .hookfail - toplevel $w - - frame $w.m - label $w.m.l1 -text "$hook hook failed:" \ - -anchor w \ - -justify left \ - -font font_uibold - text $w.m.t \ - -background white -borderwidth 1 \ - -relief sunken \ - -width 80 -height 10 \ - -font font_diff \ - -yscrollcommand [list $w.m.sby set] - label $w.m.l2 \ - -text {You must correct the above errors before committing.} \ - -anchor w \ - -justify left \ - -font font_uibold - scrollbar $w.m.sby -command [list $w.m.t yview] - pack $w.m.l1 -side top -fill x - pack $w.m.l2 -side bottom -fill x - pack $w.m.sby -side right -fill y - pack $w.m.t -side left -fill both -expand 1 - pack $w.m -side top -fill both -expand 1 -padx 5 -pady 10 - - $w.m.t insert 1.0 $msg - $w.m.t conf -state disabled - - button $w.ok -text OK \ - -width 15 \ - -font font_ui \ - -command "destroy $w" - pack $w.ok -side bottom -anchor e -pady 10 -padx 10 - - bind $w "grab $w; focus $w" - bind $w "destroy $w" - wm title $w "$appname ([lindex [file split \ - [file normalize [file dirname $gitdir]]] \ - end]): error" - tkwait window $w -} - -set next_console_id 0 - -proc new_console {short_title long_title} { - global next_console_id console_data - set w .console[incr next_console_id] - set console_data($w) [list $short_title $long_title] - return [console_init $w] -} - -proc console_init {w} { - global console_cr console_data - global gitdir appname M1B - - set console_cr($w) 1.0 - toplevel $w - frame $w.m - label $w.m.l1 -text "[lindex $console_data($w) 1]:" \ - -anchor w \ - -justify left \ - -font font_uibold - text $w.m.t \ - -background white -borderwidth 1 \ - -relief sunken \ - -width 80 -height 10 \ - -font font_diff \ - -state disabled \ - -yscrollcommand [list $w.m.sby set] - label $w.m.s -text {Working... please wait...} \ - -anchor w \ - -justify left \ - -font font_uibold - scrollbar $w.m.sby -command [list $w.m.t yview] - pack $w.m.l1 -side top -fill x - pack $w.m.s -side bottom -fill x - pack $w.m.sby -side right -fill y - pack $w.m.t -side left -fill both -expand 1 - pack $w.m -side top -fill both -expand 1 -padx 5 -pady 10 - - menu $w.ctxm -tearoff 0 - $w.ctxm add command -label "Copy" \ - -font font_ui \ - -command "tk_textCopy $w.m.t" - $w.ctxm add command -label "Select All" \ - -font font_ui \ - -command "$w.m.t tag add sel 0.0 end" - $w.ctxm add command -label "Copy All" \ - -font font_ui \ - -command " - $w.m.t tag add sel 0.0 end - tk_textCopy $w.m.t - $w.m.t tag remove sel 0.0 end - " - - button $w.ok -text {Close} \ - -font font_ui \ - -state disabled \ - -command "destroy $w" - pack $w.ok -side bottom -anchor e -pady 10 -padx 10 - - bind_button3 $w.m.t "tk_popup $w.ctxm %X %Y" - bind $w.m.t <$M1B-Key-a> "$w.m.t tag add sel 0.0 end;break" - bind $w.m.t <$M1B-Key-A> "$w.m.t tag add sel 0.0 end;break" - bind $w "focus $w" - wm title $w "$appname ([lindex [file split \ - [file normalize [file dirname $gitdir]]] \ - end]): [lindex $console_data($w) 0]" - return $w -} - -proc console_exec {w cmd {after {}}} { - # -- Windows tosses the enviroment when we exec our child. - # But most users need that so we have to relogin. :-( - # - if {[is_Windows]} { - set cmd [list sh --login -c "cd \"[pwd]\" && [join $cmd { }]"] - } - - # -- Tcl won't let us redirect both stdout and stderr to - # the same pipe. So pass it through cat... - # - set cmd [concat | $cmd |& cat] - - set fd_f [open $cmd r] - fconfigure $fd_f -blocking 0 -translation binary - fileevent $fd_f readable [list console_read $w $fd_f $after] -} - -proc console_read {w fd after} { - global console_cr console_data - - set buf [read $fd] - if {$buf ne {}} { - if {![winfo exists $w]} {console_init $w} - $w.m.t conf -state normal - set c 0 - set n [string length $buf] - while {$c < $n} { - set cr [string first "\r" $buf $c] - set lf [string first "\n" $buf $c] - if {$cr < 0} {set cr [expr {$n + 1}]} - if {$lf < 0} {set lf [expr {$n + 1}]} - - if {$lf < $cr} { - $w.m.t insert end [string range $buf $c $lf] - set console_cr($w) [$w.m.t index {end -1c}] - set c $lf - incr c - } else { - $w.m.t delete $console_cr($w) end - $w.m.t insert end "\n" - $w.m.t insert end [string range $buf $c $cr] - set c $cr - incr c - } - } - $w.m.t conf -state disabled - $w.m.t see end - } - - fconfigure $fd -blocking 1 - if {[eof $fd]} { - if {[catch {close $fd}]} { - if {![winfo exists $w]} {console_init $w} - $w.m.s conf -background red -text {Error: Command Failed} - $w.ok conf -state normal - set ok 0 - } elseif {[winfo exists $w]} { - $w.m.s conf -background green -text {Success} - $w.ok conf -state normal - set ok 1 - } - array unset console_cr $w - array unset console_data $w - if {$after ne {}} { - uplevel #0 $after $ok - } - return - } - fconfigure $fd -blocking 0 -} - -###################################################################### -## -## ui commands - -set starting_gitk_msg {Please wait... Starting gitk...} - -proc do_gitk {revs} { - global ui_status_value starting_gitk_msg - - set cmd gitk - if {$revs ne {}} { - append cmd { } - append cmd $revs - } - if {[is_Windows]} { - set cmd "sh -c \"exec $cmd\"" - } - append cmd { &} - - if {[catch {eval exec $cmd} err]} { - error_popup "Failed to start gitk:\n\n$err" - } else { - set ui_status_value $starting_gitk_msg - after 10000 { - if {$ui_status_value eq $starting_gitk_msg} { - set ui_status_value {Ready.} - } - } - } -} - -proc do_gc {} { - set w [new_console {gc} {Compressing the object database}] - console_exec $w {git gc} -} - -proc do_fsck_objects {} { - set w [new_console {fsck-objects} \ - {Verifying the object database with fsck-objects}] - set cmd [list git fsck-objects] - lappend cmd --full - lappend cmd --cache - lappend cmd --strict - console_exec $w $cmd -} - -set is_quitting 0 - -proc do_quit {} { - global gitdir ui_comm is_quitting repo_config commit_type - - if {$is_quitting} return - set is_quitting 1 - - # -- Stash our current commit buffer. - # - set save [file join $gitdir GITGUI_MSG] - set msg [string trim [$ui_comm get 0.0 end]] - if {![string match amend* $commit_type] - && [$ui_comm edit modified] - && $msg ne {}} { - catch { - set fd [open $save w] - puts $fd [string trim [$ui_comm get 0.0 end]] - close $fd - } - } else { - catch {file delete $save} - } - - # -- Stash our current window geometry into this repository. - # - set cfg_geometry [list] - lappend cfg_geometry [wm geometry .] - lappend cfg_geometry [lindex [.vpane sash coord 0] 1] - lappend cfg_geometry [lindex [.vpane.files sash coord 0] 0] - if {[catch {set rc_geometry $repo_config(gui.geometry)}]} { - set rc_geometry {} - } - if {$cfg_geometry ne $rc_geometry} { - catch {exec git repo-config gui.geometry $cfg_geometry} - } - - destroy . -} - -proc do_rescan {} { - rescan {set ui_status_value {Ready.}} -} - -proc remove_helper {txt paths} { - global file_states current_diff - - if {![lock_index begin-update]} return - - set pathList [list] - set after {} - foreach path $paths { - switch -glob -- [lindex $file_states($path) 0] { - A? - - M? - - D? { - lappend pathList $path - if {$path eq $current_diff} { - set after {reshow_diff;} - } - } - } - } - if {$pathList eq {}} { - unlock_index - } else { - update_indexinfo \ - $txt \ - $pathList \ - [concat $after {set ui_status_value {Ready.}}] - } -} - -proc do_remove_selection {} { - global current_diff selected_paths - - if {[array size selected_paths] > 0} { - remove_helper \ - {Removing selected files from commit} \ - [array names selected_paths] - } elseif {$current_diff ne {}} { - remove_helper \ - "Removing [short_path $current_diff] from commit" \ - [list $current_diff] - } -} - -proc include_helper {txt paths} { - global file_states current_diff - - if {![lock_index begin-update]} return - - set pathList [list] - set after {} - foreach path $paths { - switch -glob -- [lindex $file_states($path) 0] { - AM - - AD - - MM - - MD - - U? - - _M - - _D - - _O { - lappend pathList $path - if {$path eq $current_diff} { - set after {reshow_diff;} - } - } - } - } - if {$pathList eq {}} { - unlock_index - } else { - update_index \ - $txt \ - $pathList \ - [concat $after {set ui_status_value {Ready to commit.}}] - } -} - -proc do_include_selection {} { - global current_diff selected_paths - - if {[array size selected_paths] > 0} { - include_helper \ - {Adding selected files} \ - [array names selected_paths] - } elseif {$current_diff ne {}} { - include_helper \ - "Adding [short_path $current_diff]" \ - [list $current_diff] - } -} - -proc do_include_all {} { - global file_states - - set paths [list] - foreach path [array names file_states] { - switch -- [lindex $file_states($path) 0] { - AM - - AD - - MM - - MD - - _M - - _D {lappend paths $path} - } - } - include_helper \ - {Adding all modified files} \ - $paths -} - -proc revert_helper {txt paths} { - global gitdir appname - global file_states current_diff - - if {![lock_index begin-update]} return - - set pathList [list] - set after {} - foreach path $paths { - switch -glob -- [lindex $file_states($path) 0] { - AM - - AD - - MM - - MD - - _M - - _D { - lappend pathList $path - if {$path eq $current_diff} { - set after {reshow_diff;} - } - } - } - } - - set n [llength $pathList] - if {$n == 0} { - unlock_index - return - } elseif {$n == 1} { - set s "[short_path [lindex $pathList]]" - } else { - set s "these $n files" - } - - set reponame [lindex [file split \ - [file normalize [file dirname $gitdir]]] \ - end] - - set reply [tk_dialog \ - .confirm_revert \ - "$appname ($reponame)" \ - "Revert changes in $s? - -Any unadded changes will be permanently lost by the revert." \ - question \ - 1 \ - {Do Nothing} \ - {Revert Changes} \ - ] - if {$reply == 1} { - checkout_index \ - $txt \ - $pathList \ - [concat $after {set ui_status_value {Ready.}}] - } else { - unlock_index - } -} - -proc do_revert_selection {} { - global current_diff selected_paths - - if {[array size selected_paths] > 0} { - revert_helper \ - {Reverting selected files} \ - [array names selected_paths] - } elseif {$current_diff ne {}} { - revert_helper \ - "Reverting [short_path $current_diff]" \ - [list $current_diff] - } -} - -proc do_signoff {} { - global ui_comm - - set me [committer_ident] - if {$me eq {}} return - - set sob "Signed-off-by: $me" - set last [$ui_comm get {end -1c linestart} {end -1c}] - if {$last ne $sob} { - $ui_comm edit separator - if {$last ne {} - && ![regexp {^[A-Z][A-Za-z]*-[A-Za-z-]+: *} $last]} { - $ui_comm insert end "\n" - } - $ui_comm insert end "\n$sob" - $ui_comm edit separator - $ui_comm see end - } -} - -proc do_select_commit_type {} { - global commit_type selected_commit_type - - if {$selected_commit_type eq {new} - && [string match amend* $commit_type]} { - create_new_commit - } elseif {$selected_commit_type eq {amend} - && ![string match amend* $commit_type]} { - load_last_commit - - # The amend request was rejected... - # - if {![string match amend* $commit_type]} { - set selected_commit_type new - } - } -} - -proc do_commit {} { - commit_tree -} - -proc do_about {} { - global appname copyright - global tcl_patchLevel tk_patchLevel - - set w .about_dialog - toplevel $w - wm geometry $w "+[winfo rootx .]+[winfo rooty .]" - - label $w.header -text "About $appname" \ - -font font_uibold - pack $w.header -side top -fill x - - frame $w.buttons - button $w.buttons.close -text {Close} \ - -font font_ui \ - -command [list destroy $w] - pack $w.buttons.close -side right - pack $w.buttons -side bottom -fill x -pady 10 -padx 10 - - label $w.desc \ - -text "$appname - a commit creation tool for Git. -$copyright" \ - -padx 5 -pady 5 \ - -justify left \ - -anchor w \ - -borderwidth 1 \ - -relief solid \ - -font font_ui - pack $w.desc -side top -fill x -padx 5 -pady 5 - - set v [exec git --version] - append v "\n\n" - if {$tcl_patchLevel eq $tk_patchLevel} { - append v "Tcl/Tk version $tcl_patchLevel" - } else { - append v "Tcl version $tcl_patchLevel" - append v ", Tk version $tk_patchLevel" - } - - label $w.vers \ - -text $v \ - -padx 5 -pady 5 \ - -justify left \ - -anchor w \ - -borderwidth 1 \ - -relief solid \ - -font font_ui - pack $w.vers -side top -fill x -padx 5 -pady 5 - - bind $w "grab $w; focus $w" - bind $w "destroy $w" - wm title $w "About $appname" - tkwait window $w -} - -proc do_options {} { - global appname gitdir font_descs - global repo_config global_config - global repo_config_new global_config_new - - array unset repo_config_new - array unset global_config_new - foreach name [array names repo_config] { - set repo_config_new($name) $repo_config($name) - } - load_config 1 - foreach name [array names repo_config] { - switch -- $name { - gui.diffcontext {continue} - } - set repo_config_new($name) $repo_config($name) - } - foreach name [array names global_config] { - set global_config_new($name) $global_config($name) - } - set reponame [lindex [file split \ - [file normalize [file dirname $gitdir]]] \ - end] - - set w .options_editor - toplevel $w - wm geometry $w "+[winfo rootx .]+[winfo rooty .]" - - label $w.header -text "$appname Options" \ - -font font_uibold - pack $w.header -side top -fill x - - frame $w.buttons - button $w.buttons.restore -text {Restore Defaults} \ - -font font_ui \ - -command do_restore_defaults - pack $w.buttons.restore -side left - button $w.buttons.save -text Save \ - -font font_ui \ - -command [list do_save_config $w] - pack $w.buttons.save -side right - button $w.buttons.cancel -text {Cancel} \ - -font font_ui \ - -command [list destroy $w] - pack $w.buttons.cancel -side right - pack $w.buttons -side bottom -fill x -pady 10 -padx 10 - - labelframe $w.repo -text "$reponame Repository" \ - -font font_ui \ - -relief raised -borderwidth 2 - labelframe $w.global -text {Global (All Repositories)} \ - -font font_ui \ - -relief raised -borderwidth 2 - pack $w.repo -side left -fill both -expand 1 -pady 5 -padx 5 - pack $w.global -side right -fill both -expand 1 -pady 5 -padx 5 - - foreach option { - {b partialinclude {Allow Partially Added Files}} - {b pullsummary {Show Pull Summary}} - {b trustmtime {Trust File Modification Timestamps}} - {i diffcontext {Number of Diff Context Lines}} - } { - set type [lindex $option 0] - set name [lindex $option 1] - set text [lindex $option 2] - foreach f {repo global} { - switch $type { - b { - checkbutton $w.$f.$name -text $text \ - -variable ${f}_config_new(gui.$name) \ - -onvalue true \ - -offvalue false \ - -font font_ui - pack $w.$f.$name -side top -anchor w - } - i { - frame $w.$f.$name - label $w.$f.$name.l -text "$text:" -font font_ui - pack $w.$f.$name.l -side left -anchor w -fill x - spinbox $w.$f.$name.v \ - -textvariable ${f}_config_new(gui.$name) \ - -from 1 -to 99 -increment 1 \ - -width 3 \ - -font font_ui - pack $w.$f.$name.v -side right -anchor e - pack $w.$f.$name -side top -anchor w -fill x - } - } - } - } - - set all_fonts [lsort [font families]] - foreach option $font_descs { - set name [lindex $option 0] - set font [lindex $option 1] - set text [lindex $option 2] - - set global_config_new(gui.$font^^family) \ - [font configure $font -family] - set global_config_new(gui.$font^^size) \ - [font configure $font -size] - - frame $w.global.$name - label $w.global.$name.l -text "$text:" -font font_ui - pack $w.global.$name.l -side left -anchor w -fill x - eval tk_optionMenu $w.global.$name.family \ - global_config_new(gui.$font^^family) \ - $all_fonts - spinbox $w.global.$name.size \ - -textvariable global_config_new(gui.$font^^size) \ - -from 2 -to 80 -increment 1 \ - -width 3 \ - -font font_ui - pack $w.global.$name.size -side right -anchor e - pack $w.global.$name.family -side right -anchor e - pack $w.global.$name -side top -anchor w -fill x - } - - bind $w "grab $w; focus $w" - bind $w "destroy $w" - wm title $w "$appname ($reponame): Options" - tkwait window $w -} - -proc do_restore_defaults {} { - global font_descs default_config repo_config - global repo_config_new global_config_new - - foreach name [array names default_config] { - set repo_config_new($name) $default_config($name) - set global_config_new($name) $default_config($name) - } - - foreach option $font_descs { - set name [lindex $option 0] - set repo_config(gui.$name) $default_config(gui.$name) - } - apply_config - - foreach option $font_descs { - set name [lindex $option 0] - set font [lindex $option 1] - set global_config_new(gui.$font^^family) \ - [font configure $font -family] - set global_config_new(gui.$font^^size) \ - [font configure $font -size] - } -} - -proc do_save_config {w} { - if {[catch {save_config} err]} { - error_popup "Failed to completely save options:\n\n$err" - } - reshow_diff - destroy $w -} - -proc do_windows_shortcut {} { - global gitdir appname argv0 - - set reponame [lindex [file split \ - [file normalize [file dirname $gitdir]]] \ - end] - - if {[catch { - set desktop [exec cygpath \ - --windows \ - --absolute \ - --long-name \ - --desktop] - }]} { - set desktop . - } - set fn [tk_getSaveFile \ - -parent . \ - -title "$appname ($reponame): Create Desktop Icon" \ - -initialdir $desktop \ - -initialfile "Git $reponame.bat"] - if {$fn != {}} { - if {[catch { - set fd [open $fn w] - set sh [exec cygpath \ - --windows \ - --absolute \ - /bin/sh] - set me [exec cygpath \ - --unix \ - --absolute \ - $argv0] - set gd [exec cygpath \ - --unix \ - --absolute \ - $gitdir] - regsub -all ' $me "'\\''" me - regsub -all ' $gd "'\\''" gd - puts $fd "@ECHO Starting git-gui... Please wait..." - puts -nonewline $fd "@\"$sh\" --login -c \"" - puts -nonewline $fd "GIT_DIR='$gd'" - puts -nonewline $fd " '$me'" - puts $fd "&\"" - close $fd - } err]} { - error_popup "Cannot write script:\n\n$err" - } - } -} - -proc do_macosx_app {} { - global gitdir appname argv0 env - - set reponame [lindex [file split \ - [file normalize [file dirname $gitdir]]] \ - end] - - set fn [tk_getSaveFile \ - -parent . \ - -title "$appname ($reponame): Create Desktop Icon" \ - -initialdir [file join $env(HOME) Desktop] \ - -initialfile "Git $reponame.app"] - if {$fn != {}} { - if {[catch { - set Contents [file join $fn Contents] - set MacOS [file join $Contents MacOS] - set exe [file join $MacOS git-gui] - - file mkdir $MacOS - - set fd [open [file join $Contents Info.plist] w] - puts $fd { - - - - CFBundleDevelopmentRegion - English - CFBundleExecutable - git-gui - CFBundleIdentifier - org.spearce.git-gui - CFBundleInfoDictionaryVersion - 6.0 - CFBundlePackageType - APPL - CFBundleSignature - ???? - CFBundleVersion - 1.0 - NSPrincipalClass - NSApplication - -} - close $fd - - set fd [open $exe w] - set gd [file normalize $gitdir] - set ep [file normalize [exec git --exec-path]] - regsub -all ' $gd "'\\''" gd - regsub -all ' $ep "'\\''" ep - puts $fd "#!/bin/sh" - foreach name [array names env] { - if {[string match GIT_* $name]} { - regsub -all ' $env($name) "'\\''" v - puts $fd "export $name='$v'" - } - } - puts $fd "export PATH='$ep':\$PATH" - puts $fd "export GIT_DIR='$gd'" - puts $fd "exec [file normalize $argv0]" - close $fd - - file attributes $exe -permissions u+x,g+x,o+x - } err]} { - error_popup "Cannot write icon:\n\n$err" - } - } -} - -proc toggle_or_diff {w x y} { - global file_states file_lists current_diff ui_index ui_other - global last_clicked selected_paths - - set pos [split [$w index @$x,$y] .] - set lno [lindex $pos 0] - set col [lindex $pos 1] - set path [lindex $file_lists($w) [expr {$lno - 1}]] - if {$path eq {}} { - set last_clicked {} - return - } - - set last_clicked [list $w $lno] - array unset selected_paths - $ui_index tag remove in_sel 0.0 end - $ui_other tag remove in_sel 0.0 end - - if {$col == 0} { - if {$current_diff eq $path} { - set after {reshow_diff;} - } else { - set after {} - } - switch -glob -- [lindex $file_states($path) 0] { - A_ - - M_ - - DD - - DO - - DM { - update_indexinfo \ - "Removing [short_path $path] from commit" \ - [list $path] \ - [concat $after {set ui_status_value {Ready.}}] - } - ?? { - update_index \ - "Adding [short_path $path]" \ - [list $path] \ - [concat $after {set ui_status_value {Ready.}}] - } - } - } else { - show_diff $path $w $lno - } -} - -proc add_one_to_selection {w x y} { - global file_lists - global last_clicked selected_paths - - set pos [split [$w index @$x,$y] .] - set lno [lindex $pos 0] - set col [lindex $pos 1] - set path [lindex $file_lists($w) [expr {$lno - 1}]] - if {$path eq {}} { - set last_clicked {} - return - } - - set last_clicked [list $w $lno] - if {[catch {set in_sel $selected_paths($path)}]} { - set in_sel 0 - } - if {$in_sel} { - unset selected_paths($path) - $w tag remove in_sel $lno.0 [expr {$lno + 1}].0 - } else { - set selected_paths($path) 1 - $w tag add in_sel $lno.0 [expr {$lno + 1}].0 - } -} - -proc add_range_to_selection {w x y} { - global file_lists - global last_clicked selected_paths - - if {[lindex $last_clicked 0] ne $w} { - toggle_or_diff $w $x $y - return - } - - set pos [split [$w index @$x,$y] .] - set lno [lindex $pos 0] - set lc [lindex $last_clicked 1] - if {$lc < $lno} { - set begin $lc - set end $lno - } else { - set begin $lno - set end $lc - } - - foreach path [lrange $file_lists($w) \ - [expr {$begin - 1}] \ - [expr {$end - 1}]] { - set selected_paths($path) 1 - } - $w tag add in_sel $begin.0 [expr {$end + 1}].0 -} - -###################################################################### -## -## config defaults - -set cursor_ptr arrow -font create font_diff -family Courier -size 10 -font create font_ui -catch { - label .dummy - eval font configure font_ui [font actual [.dummy cget -font]] - destroy .dummy -} - -font create font_uibold -font create font_diffbold - -if {[is_Windows]} { - set M1B Control - set M1T Ctrl -} elseif {[is_MacOSX]} { - set M1B M1 - set M1T Cmd -} else { - set M1B M1 - set M1T M1 -} - -proc apply_config {} { - global repo_config font_descs - - foreach option $font_descs { - set name [lindex $option 0] - set font [lindex $option 1] - if {[catch { - foreach {cn cv} $repo_config(gui.$name) { - font configure $font $cn $cv - } - } err]} { - error_popup "Invalid font specified in gui.$name:\n\n$err" - } - foreach {cn cv} [font configure $font] { - font configure ${font}bold $cn $cv - } - font configure ${font}bold -weight bold - } -} - -set default_config(gui.trustmtime) false -set default_config(gui.pullsummary) true -set default_config(gui.partialinclude) false -set default_config(gui.diffcontext) 5 -set default_config(gui.fontui) [font configure font_ui] -set default_config(gui.fontdiff) [font configure font_diff] -set font_descs { - {fontui font_ui {Main Font}} - {fontdiff font_diff {Diff/Console Font}} -} -load_config 0 -apply_config - -###################################################################### -## -## ui construction - -# -- Menu Bar -# -menu .mbar -tearoff 0 -.mbar add cascade -label Repository -menu .mbar.repository -.mbar add cascade -label Edit -menu .mbar.edit -if {!$single_commit} { - .mbar add cascade -label Branch -menu .mbar.branch -} -.mbar add cascade -label Commit -menu .mbar.commit -if {!$single_commit} { - .mbar add cascade -label Fetch -menu .mbar.fetch - .mbar add cascade -label Pull -menu .mbar.pull - .mbar add cascade -label Push -menu .mbar.push -} -. configure -menu .mbar - -# -- Repository Menu -# -menu .mbar.repository -.mbar.repository add command \ - -label {Visualize Current Branch} \ - -command {do_gitk {}} \ - -font font_ui -if {![is_MacOSX]} { - .mbar.repository add command \ - -label {Visualize All Branches} \ - -command {do_gitk {--all}} \ - -font font_ui -} -.mbar.repository add separator - -if {!$single_commit} { - .mbar.repository add command -label {Compress Database} \ - -command do_gc \ - -font font_ui - - .mbar.repository add command -label {Verify Database} \ - -command do_fsck_objects \ - -font font_ui - - .mbar.repository add separator - - if {[is_Windows]} { - .mbar.repository add command \ - -label {Create Desktop Icon} \ - -command do_windows_shortcut \ - -font font_ui - } elseif {[is_MacOSX]} { - .mbar.repository add command \ - -label {Create Desktop Icon} \ - -command do_macosx_app \ - -font font_ui - } -} - -.mbar.repository add command -label Quit \ - -command do_quit \ - -accelerator $M1T-Q \ - -font font_ui - -# -- Edit Menu -# -menu .mbar.edit -.mbar.edit add command -label Undo \ - -command {catch {[focus] edit undo}} \ - -accelerator $M1T-Z \ - -font font_ui -.mbar.edit add command -label Redo \ - -command {catch {[focus] edit redo}} \ - -accelerator $M1T-Y \ - -font font_ui -.mbar.edit add separator -.mbar.edit add command -label Cut \ - -command {catch {tk_textCut [focus]}} \ - -accelerator $M1T-X \ - -font font_ui -.mbar.edit add command -label Copy \ - -command {catch {tk_textCopy [focus]}} \ - -accelerator $M1T-C \ - -font font_ui -.mbar.edit add command -label Paste \ - -command {catch {tk_textPaste [focus]; [focus] see insert}} \ - -accelerator $M1T-V \ - -font font_ui -.mbar.edit add command -label Delete \ - -command {catch {[focus] delete sel.first sel.last}} \ - -accelerator Del \ - -font font_ui -.mbar.edit add separator -.mbar.edit add command -label {Select All} \ - -command {catch {[focus] tag add sel 0.0 end}} \ - -accelerator $M1T-A \ - -font font_ui - -# -- Branch Menu -# -if {!$single_commit} { - menu .mbar.branch - - .mbar.branch add command -label {Create...} \ - -command do_create_branch \ - -font font_ui - lappend disable_on_lock [list .mbar.branch entryconf \ - [.mbar.branch index last] -state] - - .mbar.branch add command -label {Delete...} \ - -command do_delete_branch \ - -font font_ui - lappend disable_on_lock [list .mbar.branch entryconf \ - [.mbar.branch index last] -state] -} - -# -- Commit Menu -# -menu .mbar.commit - -.mbar.commit add radiobutton \ - -label {New Commit} \ - -command do_select_commit_type \ - -variable selected_commit_type \ - -value new \ - -font font_ui -lappend disable_on_lock \ - [list .mbar.commit entryconf [.mbar.commit index last] -state] - -.mbar.commit add radiobutton \ - -label {Amend Last Commit} \ - -command do_select_commit_type \ - -variable selected_commit_type \ - -value amend \ - -font font_ui -lappend disable_on_lock \ - [list .mbar.commit entryconf [.mbar.commit index last] -state] - -.mbar.commit add separator - -.mbar.commit add command -label Rescan \ - -command do_rescan \ - -accelerator F5 \ - -font font_ui -lappend disable_on_lock \ - [list .mbar.commit entryconf [.mbar.commit index last] -state] - -.mbar.commit add command -label {Add To Commit} \ - -command do_include_selection \ - -font font_ui -lappend disable_on_lock \ - [list .mbar.commit entryconf [.mbar.commit index last] -state] - -.mbar.commit add command -label {Add All To Commit} \ - -command do_include_all \ - -accelerator $M1T-I \ - -font font_ui -lappend disable_on_lock \ - [list .mbar.commit entryconf [.mbar.commit index last] -state] - -.mbar.commit add command -label {Remove From Commit} \ - -command do_remove_selection \ - -font font_ui -lappend disable_on_lock \ - [list .mbar.commit entryconf [.mbar.commit index last] -state] - -.mbar.commit add command -label {Revert Changes} \ - -command do_revert_selection \ - -font font_ui -lappend disable_on_lock \ - [list .mbar.commit entryconf [.mbar.commit index last] -state] - -.mbar.commit add separator - -.mbar.commit add command -label {Sign Off} \ - -command do_signoff \ - -accelerator $M1T-S \ - -font font_ui - -.mbar.commit add command -label Commit \ - -command do_commit \ - -accelerator $M1T-Return \ - -font font_ui -lappend disable_on_lock \ - [list .mbar.commit entryconf [.mbar.commit index last] -state] - -# -- Transport menus -# -if {!$single_commit} { - menu .mbar.fetch - menu .mbar.pull - menu .mbar.push -} - -if {[is_MacOSX]} { - # -- Apple Menu (Mac OS X only) - # - .mbar add cascade -label Apple -menu .mbar.apple - menu .mbar.apple - - .mbar.apple add command -label "About $appname" \ - -command do_about \ - -font font_ui - .mbar.apple add command -label "$appname Options..." \ - -command do_options \ - -font font_ui -} else { - # -- Edit Menu - # - .mbar.edit add separator - .mbar.edit add command -label {Options...} \ - -command do_options \ - -font font_ui - - # -- Tools Menu - # - if {[file exists /usr/local/miga/lib/gui-miga]} { - proc do_miga {} { - global gitdir ui_status_value - if {![lock_index update]} return - set cmd [list sh --login -c "/usr/local/miga/lib/gui-miga \"[pwd]\""] - set miga_fd [open "|$cmd" r] - fconfigure $miga_fd -blocking 0 - fileevent $miga_fd readable [list miga_done $miga_fd] - set ui_status_value {Running miga...} - } - proc miga_done {fd} { - read $fd 512 - if {[eof $fd]} { - close $fd - unlock_index - rescan [list set ui_status_value {Ready.}] - } - } - .mbar add cascade -label Tools -menu .mbar.tools - menu .mbar.tools - .mbar.tools add command -label "Migrate" \ - -command do_miga \ - -font font_ui - lappend disable_on_lock \ - [list .mbar.tools entryconf [.mbar.tools index last] -state] - } - - # -- Help Menu - # - .mbar add cascade -label Help -menu .mbar.help - menu .mbar.help - - .mbar.help add command -label "About $appname" \ - -command do_about \ - -font font_ui -} - - -# -- Branch Control -# -frame .branch \ - -borderwidth 1 \ - -relief sunken -label .branch.l1 \ - -text {Current Branch:} \ - -anchor w \ - -justify left \ - -font font_ui -label .branch.cb \ - -textvariable current_branch \ - -anchor w \ - -justify left \ - -font font_ui -pack .branch.l1 -side left -pack .branch.cb -side left -fill x -pack .branch -side top -fill x - -# -- Main Window Layout -# -panedwindow .vpane -orient vertical -panedwindow .vpane.files -orient horizontal -.vpane add .vpane.files -sticky nsew -height 100 -width 400 -pack .vpane -anchor n -side top -fill both -expand 1 - -# -- Index File List -# -frame .vpane.files.index -height 100 -width 400 -label .vpane.files.index.title -text {Modified Files} \ - -background green \ - -font font_ui -text $ui_index -background white -borderwidth 0 \ - -width 40 -height 10 \ - -font font_ui \ - -cursor $cursor_ptr \ - -yscrollcommand {.vpane.files.index.sb set} \ - -state disabled -scrollbar .vpane.files.index.sb -command [list $ui_index yview] -pack .vpane.files.index.title -side top -fill x -pack .vpane.files.index.sb -side right -fill y -pack $ui_index -side left -fill both -expand 1 -.vpane.files add .vpane.files.index -sticky nsew - -# -- Other (Add) File List -# -frame .vpane.files.other -height 100 -width 100 -label .vpane.files.other.title -text {Untracked Files} \ - -background red \ - -font font_ui -text $ui_other -background white -borderwidth 0 \ - -width 40 -height 10 \ - -font font_ui \ - -cursor $cursor_ptr \ - -yscrollcommand {.vpane.files.other.sb set} \ - -state disabled -scrollbar .vpane.files.other.sb -command [list $ui_other yview] -pack .vpane.files.other.title -side top -fill x -pack .vpane.files.other.sb -side right -fill y -pack $ui_other -side left -fill both -expand 1 -.vpane.files add .vpane.files.other -sticky nsew - -foreach i [list $ui_index $ui_other] { - $i tag conf in_diff -font font_uibold - $i tag conf in_sel \ - -background [$i cget -foreground] \ - -foreground [$i cget -background] -} -unset i - -# -- Diff and Commit Area -# -frame .vpane.lower -height 300 -width 400 -frame .vpane.lower.commarea -frame .vpane.lower.diff -relief sunken -borderwidth 1 -pack .vpane.lower.commarea -side top -fill x -pack .vpane.lower.diff -side bottom -fill both -expand 1 -.vpane add .vpane.lower -stick nsew - -# -- Commit Area Buttons -# -frame .vpane.lower.commarea.buttons -label .vpane.lower.commarea.buttons.l -text {} \ - -anchor w \ - -justify left \ - -font font_ui -pack .vpane.lower.commarea.buttons.l -side top -fill x -pack .vpane.lower.commarea.buttons -side left -fill y - -button .vpane.lower.commarea.buttons.rescan -text {Rescan} \ - -command do_rescan \ - -font font_ui -pack .vpane.lower.commarea.buttons.rescan -side top -fill x -lappend disable_on_lock \ - {.vpane.lower.commarea.buttons.rescan conf -state} - -button .vpane.lower.commarea.buttons.incall -text {Add All} \ - -command do_include_all \ - -font font_ui -pack .vpane.lower.commarea.buttons.incall -side top -fill x -lappend disable_on_lock \ - {.vpane.lower.commarea.buttons.incall conf -state} - -button .vpane.lower.commarea.buttons.signoff -text {Sign Off} \ - -command do_signoff \ - -font font_ui -pack .vpane.lower.commarea.buttons.signoff -side top -fill x - -button .vpane.lower.commarea.buttons.commit -text {Commit} \ - -command do_commit \ - -font font_ui -pack .vpane.lower.commarea.buttons.commit -side top -fill x -lappend disable_on_lock \ - {.vpane.lower.commarea.buttons.commit conf -state} - -# -- Commit Message Buffer -# -frame .vpane.lower.commarea.buffer -frame .vpane.lower.commarea.buffer.header -set ui_comm .vpane.lower.commarea.buffer.t -set ui_coml .vpane.lower.commarea.buffer.header.l -radiobutton .vpane.lower.commarea.buffer.header.new \ - -text {New Commit} \ - -command do_select_commit_type \ - -variable selected_commit_type \ - -value new \ - -font font_ui -lappend disable_on_lock \ - [list .vpane.lower.commarea.buffer.header.new conf -state] -radiobutton .vpane.lower.commarea.buffer.header.amend \ - -text {Amend Last Commit} \ - -command do_select_commit_type \ - -variable selected_commit_type \ - -value amend \ - -font font_ui -lappend disable_on_lock \ - [list .vpane.lower.commarea.buffer.header.amend conf -state] -label $ui_coml \ - -anchor w \ - -justify left \ - -font font_ui -proc trace_commit_type {varname args} { - global ui_coml commit_type - switch -glob -- $commit_type { - initial {set txt {Initial Commit Message:}} - amend {set txt {Amended Commit Message:}} - amend-initial {set txt {Amended Initial Commit Message:}} - amend-merge {set txt {Amended Merge Commit Message:}} - merge {set txt {Merge Commit Message:}} - * {set txt {Commit Message:}} - } - $ui_coml conf -text $txt -} -trace add variable commit_type write trace_commit_type -pack $ui_coml -side left -fill x -pack .vpane.lower.commarea.buffer.header.amend -side right -pack .vpane.lower.commarea.buffer.header.new -side right - -text $ui_comm -background white -borderwidth 1 \ - -undo true \ - -maxundo 20 \ - -autoseparators true \ - -relief sunken \ - -width 75 -height 9 -wrap none \ - -font font_diff \ - -yscrollcommand {.vpane.lower.commarea.buffer.sby set} -scrollbar .vpane.lower.commarea.buffer.sby \ - -command [list $ui_comm yview] -pack .vpane.lower.commarea.buffer.header -side top -fill x -pack .vpane.lower.commarea.buffer.sby -side right -fill y -pack $ui_comm -side left -fill y -pack .vpane.lower.commarea.buffer -side left -fill y - -# -- Commit Message Buffer Context Menu -# -set ctxm .vpane.lower.commarea.buffer.ctxm -menu $ctxm -tearoff 0 -$ctxm add command \ - -label {Cut} \ - -font font_ui \ - -command {tk_textCut $ui_comm} -$ctxm add command \ - -label {Copy} \ - -font font_ui \ - -command {tk_textCopy $ui_comm} -$ctxm add command \ - -label {Paste} \ - -font font_ui \ - -command {tk_textPaste $ui_comm} -$ctxm add command \ - -label {Delete} \ - -font font_ui \ - -command {$ui_comm delete sel.first sel.last} -$ctxm add separator -$ctxm add command \ - -label {Select All} \ - -font font_ui \ - -command {$ui_comm tag add sel 0.0 end} -$ctxm add command \ - -label {Copy All} \ - -font font_ui \ - -command { - $ui_comm tag add sel 0.0 end - tk_textCopy $ui_comm - $ui_comm tag remove sel 0.0 end - } -$ctxm add separator -$ctxm add command \ - -label {Sign Off} \ - -font font_ui \ - -command do_signoff -bind_button3 $ui_comm "tk_popup $ctxm %X %Y" - -# -- Diff Header -# -set current_diff {} -set diff_actions [list] -proc trace_current_diff {varname args} { - global current_diff diff_actions file_states - if {$current_diff eq {}} { - set s {} - set f {} - set p {} - set o disabled - } else { - set p $current_diff - set s [mapdesc [lindex $file_states($p) 0] $p] - set f {File:} - set p [escape_path $p] - set o normal - } - - .vpane.lower.diff.header.status configure -text $s - .vpane.lower.diff.header.file configure -text $f - .vpane.lower.diff.header.path configure -text $p - foreach w $diff_actions { - uplevel #0 $w $o - } -} -trace add variable current_diff write trace_current_diff - -frame .vpane.lower.diff.header -background orange -label .vpane.lower.diff.header.status \ - -background orange \ - -width $max_status_desc \ - -anchor w \ - -justify left \ - -font font_ui -label .vpane.lower.diff.header.file \ - -background orange \ - -anchor w \ - -justify left \ - -font font_ui -label .vpane.lower.diff.header.path \ - -background orange \ - -anchor w \ - -justify left \ - -font font_ui -pack .vpane.lower.diff.header.status -side left -pack .vpane.lower.diff.header.file -side left -pack .vpane.lower.diff.header.path -fill x -set ctxm .vpane.lower.diff.header.ctxm -menu $ctxm -tearoff 0 -$ctxm add command \ - -label {Copy} \ - -font font_ui \ - -command { - clipboard clear - clipboard append \ - -format STRING \ - -type STRING \ - -- $current_diff - } -lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state] -bind_button3 .vpane.lower.diff.header.path "tk_popup $ctxm %X %Y" - -# -- Diff Body -# -frame .vpane.lower.diff.body -set ui_diff .vpane.lower.diff.body.t -text $ui_diff -background white -borderwidth 0 \ - -width 80 -height 15 -wrap none \ - -font font_diff \ - -xscrollcommand {.vpane.lower.diff.body.sbx set} \ - -yscrollcommand {.vpane.lower.diff.body.sby set} \ - -state disabled -scrollbar .vpane.lower.diff.body.sbx -orient horizontal \ - -command [list $ui_diff xview] -scrollbar .vpane.lower.diff.body.sby -orient vertical \ - -command [list $ui_diff yview] -pack .vpane.lower.diff.body.sbx -side bottom -fill x -pack .vpane.lower.diff.body.sby -side right -fill y -pack $ui_diff -side left -fill both -expand 1 -pack .vpane.lower.diff.header -side top -fill x -pack .vpane.lower.diff.body -side bottom -fill both -expand 1 - -$ui_diff tag conf d_@ -font font_diffbold -$ui_diff tag conf d_+ -foreground blue -$ui_diff tag conf d_- -foreground red -$ui_diff tag conf d_++ -foreground {#00a000} -$ui_diff tag conf d_-- -foreground {#a000a0} -$ui_diff tag conf d_+- \ - -foreground red \ - -background {light goldenrod yellow} -$ui_diff tag conf d_-+ \ - -foreground blue \ - -background azure2 - -# -- Diff Body Context Menu -# -set ctxm .vpane.lower.diff.body.ctxm -menu $ctxm -tearoff 0 -$ctxm add command \ - -label {Copy} \ - -font font_ui \ - -command {tk_textCopy $ui_diff} -lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state] -$ctxm add command \ - -label {Select All} \ - -font font_ui \ - -command {$ui_diff tag add sel 0.0 end} -lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state] -$ctxm add command \ - -label {Copy All} \ - -font font_ui \ - -command { - $ui_diff tag add sel 0.0 end - tk_textCopy $ui_diff - $ui_diff tag remove sel 0.0 end - } -lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state] -$ctxm add separator -$ctxm add command \ - -label {Decrease Font Size} \ - -font font_ui \ - -command {incr_font_size font_diff -1} -lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state] -$ctxm add command \ - -label {Increase Font Size} \ - -font font_ui \ - -command {incr_font_size font_diff 1} -lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state] -$ctxm add separator -$ctxm add command \ - -label {Show Less Context} \ - -font font_ui \ - -command {if {$repo_config(gui.diffcontext) >= 2} { - incr repo_config(gui.diffcontext) -1 - reshow_diff - }} -lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state] -$ctxm add command \ - -label {Show More Context} \ - -font font_ui \ - -command { - incr repo_config(gui.diffcontext) - reshow_diff - } -lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state] -$ctxm add separator -$ctxm add command -label {Options...} \ - -font font_ui \ - -command do_options -bind_button3 $ui_diff "tk_popup $ctxm %X %Y" - -# -- Status Bar -# -set ui_status_value {Initializing...} -label .status -textvariable ui_status_value \ - -anchor w \ - -justify left \ - -borderwidth 1 \ - -relief sunken \ - -font font_ui -pack .status -anchor w -side bottom -fill x - -# -- Load geometry -# -catch { -set gm $repo_config(gui.geometry) -wm geometry . [lindex $gm 0] -.vpane sash place 0 \ - [lindex [.vpane sash coord 0] 0] \ - [lindex $gm 1] -.vpane.files sash place 0 \ - [lindex $gm 2] \ - [lindex [.vpane.files sash coord 0] 1] -unset gm -} - -# -- Key Bindings -# -bind $ui_comm <$M1B-Key-Return> {do_commit;break} -bind $ui_comm <$M1B-Key-i> {do_include_all;break} -bind $ui_comm <$M1B-Key-I> {do_include_all;break} -bind $ui_comm <$M1B-Key-x> {tk_textCut %W;break} -bind $ui_comm <$M1B-Key-X> {tk_textCut %W;break} -bind $ui_comm <$M1B-Key-c> {tk_textCopy %W;break} -bind $ui_comm <$M1B-Key-C> {tk_textCopy %W;break} -bind $ui_comm <$M1B-Key-v> {tk_textPaste %W; %W see insert; break} -bind $ui_comm <$M1B-Key-V> {tk_textPaste %W; %W see insert; break} -bind $ui_comm <$M1B-Key-a> {%W tag add sel 0.0 end;break} -bind $ui_comm <$M1B-Key-A> {%W tag add sel 0.0 end;break} - -bind $ui_diff <$M1B-Key-x> {tk_textCopy %W;break} -bind $ui_diff <$M1B-Key-X> {tk_textCopy %W;break} -bind $ui_diff <$M1B-Key-c> {tk_textCopy %W;break} -bind $ui_diff <$M1B-Key-C> {tk_textCopy %W;break} -bind $ui_diff <$M1B-Key-v> {break} -bind $ui_diff <$M1B-Key-V> {break} -bind $ui_diff <$M1B-Key-a> {%W tag add sel 0.0 end;break} -bind $ui_diff <$M1B-Key-A> {%W tag add sel 0.0 end;break} -bind $ui_diff {catch {%W yview scroll -1 units};break} -bind $ui_diff {catch {%W yview scroll 1 units};break} -bind $ui_diff {catch {%W xview scroll -1 units};break} -bind $ui_diff {catch {%W xview scroll 1 units};break} - -bind . do_quit -bind all do_rescan -bind all <$M1B-Key-r> do_rescan -bind all <$M1B-Key-R> do_rescan -bind . <$M1B-Key-s> do_signoff -bind . <$M1B-Key-S> do_signoff -bind . <$M1B-Key-i> do_include_all -bind . <$M1B-Key-I> do_include_all -bind . <$M1B-Key-Return> do_commit -bind all <$M1B-Key-q> do_quit -bind all <$M1B-Key-Q> do_quit -bind all <$M1B-Key-w> {destroy [winfo toplevel %W]} -bind all <$M1B-Key-W> {destroy [winfo toplevel %W]} -foreach i [list $ui_index $ui_other] { - bind $i "toggle_or_diff $i %x %y; break" - bind $i <$M1B-Button-1> "add_one_to_selection $i %x %y; break" - bind $i "add_range_to_selection $i %x %y; break" -} -unset i - -set file_lists($ui_index) [list] -set file_lists($ui_other) [list] - -set HEAD {} -set PARENT {} -set MERGE_HEAD [list] -set commit_type {} -set empty_tree {} -set current_branch {} -set current_diff {} -set selected_commit_type new - -wm title . "$appname ([file normalize [file dirname $gitdir]])" -focus -force $ui_comm - -# -- Warn the user about environmental problems. Cygwin's Tcl -# does *not* pass its env array onto any processes it spawns. -# This means that git processes get none of our environment. -# -if {[is_Windows]} { - set ignored_env 0 - set suggest_user {} - set msg "Possible environment issues exist. - -The following environment variables are probably -going to be ignored by any Git subprocess run -by $appname: - -" - foreach name [array names env] { - switch -regexp -- $name { - {^GIT_INDEX_FILE$} - - {^GIT_OBJECT_DIRECTORY$} - - {^GIT_ALTERNATE_OBJECT_DIRECTORIES$} - - {^GIT_DIFF_OPTS$} - - {^GIT_EXTERNAL_DIFF$} - - {^GIT_PAGER$} - - {^GIT_TRACE$} - - {^GIT_CONFIG$} - - {^GIT_CONFIG_LOCAL$} - - {^GIT_(AUTHOR|COMMITTER)_DATE$} { - append msg " - $name\n" - incr ignored_env - } - {^GIT_(AUTHOR|COMMITTER)_(NAME|EMAIL)$} { - append msg " - $name\n" - incr ignored_env - set suggest_user $name - } - } - } - if {$ignored_env > 0} { - append msg " -This is due to a known issue with the -Tcl binary distributed by Cygwin." - - if {$suggest_user ne {}} { - append msg " - -A good replacement for $suggest_user -is placing values for the user.name and -user.email settings into your personal -~/.gitconfig file. -" - } - warn_popup $msg - } - unset ignored_env msg suggest_user name -} - -# -- Only initialize complex UI if we are going to stay running. -# -if {!$single_commit} { - load_all_remotes - load_all_heads - - populate_branch_menu .mbar.branch - populate_fetch_menu .mbar.fetch - populate_pull_menu .mbar.pull - populate_push_menu .mbar.push -} - -lock_index begin-read -after 1 do_rescan -- cgit v1.2.1