diff options
Diffstat (limited to 'git-gui/git-gui.sh')
| -rwxr-xr-x | git-gui/git-gui.sh | 4092 | 
1 files changed, 102 insertions, 3990 deletions
| diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index ae881336da..46358258bb 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -22,6 +22,30 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA}  ######################################################################  ## +## configure our library + +set oguilib {@@GITGUI_LIBDIR@@} +if {[string match @@* $oguilib]} { +	set oguilib [file join [file dirname [file normalize $argv0]] lib] +} +set auto_path [concat [list $oguilib] $auto_path] + +if {![catch {set _verbose $env(GITGUI_VERBOSE)}]} { +	unset _verbose +	rename auto_load real__auto_load +	proc auto_load {name args} { +		puts stderr "auto_load $name" +		return [uplevel 1 real__auto_load $name $args] +	} +	rename source real__source +	proc source {name} { +		puts stderr "source    $name" +		uplevel 1 real__source $name +	} +} + +###################################################################### +##  ## read only globals  set _appname [lindex [file split $argv0] end] @@ -179,56 +203,6 @@ proc load_config {include_global} {  	}  } -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 {git config --global --unset $name} -			} else { -				regsub -all "\[{}\]" $value {"} value -				git config --global $name $value -			} -			set global_config($name) $value -			if {$value eq $repo_config($name)} { -				catch {git 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 {git config --unset $name} -			} else { -				regsub -all "\[{}\]" $value {"} value -				git config $name $value -			} -			set repo_config($name) $value -		} -	} -} -  ######################################################################  ##  ## handy utils @@ -237,62 +211,13 @@ proc git {args} {  	return [eval exec git $args]  } -proc error_popup {msg} { -	set title [appname] -	if {[reponame] ne {}} { -		append title " ([reponame])" -	} -	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} { -	set title [appname] -	if {[reponame] ne {}} { -		append title " ([reponame])" -	} -	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 {parent .}} { -	set title [appname] -	if {[reponame] ne {}} { -		append title " ([reponame])" -	} -	tk_messageBox \ -		-parent $parent \ -		-icon info \ -		-type ok \ -		-title $title \ -		-message $msg -} - -proc ask_popup {msg} { -	set title [appname] -	if {[reponame] ne {}} { -		append title " ([reponame])" -	} -	return [tk_messageBox \ -		-parent . \ -		-icon question \ -		-type yesno \ -		-title $title \ -		-message $msg] +auto_load tk_optionMenu +rename tk_optionMenu real__tkOptionMenu +proc tk_optionMenu {w varName args} { +	set m [eval real__tkOptionMenu $w $varName $args] +	$m configure -font font_ui +	$w configure -font font_ui +	return $m  }  ###################################################################### @@ -655,7 +580,7 @@ proc read_ls_others {fd after} {  }  proc rescan_done {fd buf after} { -	global rescan_active +	global rescan_active current_diff_path  	global file_states repo_config  	upvar $buf to_clear @@ -667,7 +592,7 @@ proc rescan_done {fd buf after} {  	prune_selection  	unlock_index  	display_all_files -	reshow_diff +	if {$current_diff_path ne {}} reshow_diff  	uplevel #0 $after  } @@ -683,768 +608,6 @@ proc prune_selection {} {  ######################################################################  ## -## diff - -proc clear_diff {} { -	global ui_diff current_diff_path current_diff_header -	global ui_index ui_workdir - -	$ui_diff conf -state normal -	$ui_diff delete 0.0 end -	$ui_diff conf -state disabled - -	set current_diff_path {} -	set current_diff_header {} - -	$ui_index tag remove in_diff 0.0 end -	$ui_workdir tag remove in_diff 0.0 end -} - -proc reshow_diff {} { -	global ui_status_value file_states file_lists -	global current_diff_path current_diff_side - -	set p $current_diff_path -	if {$p eq {}} { -		# No diff is being shown. -	} elseif {$current_diff_side eq {} -		|| [catch {set s $file_states($p)}] -		|| [lsearch -sorted -exact $file_lists($current_diff_side) $p] == -1} { -		clear_diff -	} else { -		show_diff $p $current_diff_side -	} -} - -proc handle_empty_diff {} { -	global current_diff_path file_states file_lists - -	set path $current_diff_path -	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, but the content within -the file was not changed. - -A rescan will be automatically started to find -other files which may have the same state." - -	clear_diff -	display_file $path __ -	rescan {set ui_status_value {Ready.}} 0 -} - -proc show_diff {path w {lno {}}} { -	global file_states file_lists -	global is_3way_diff diff_active repo_config -	global ui_diff ui_status_value ui_index ui_workdir -	global current_diff_path current_diff_side current_diff_header - -	if {$diff_active || ![lock_index read]} return - -	clear_diff -	if {$lno == {}} { -		set lno [lsearch -sorted -exact $file_lists($w) $path] -		if {$lno >= 0} { -			incr lno -		} -	} -	if {$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 $path -	set current_diff_side $w -	set current_diff_header {} -	set ui_status_value "Loading diff of [escape_path $path]..." - -	# - Git won't give us the diff, there's nothing to compare to! -	# -	if {$m eq {_O}} { -		set max_sz [expr {128 * 1024}] -		if {[catch { -				set fd [open $path r] -				set content [read $fd $max_sz] -				close $fd -				set sz [file size $path] -			} 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 -		if {![catch {set type [exec file $path]}]} { -			set n [string length $path] -			if {[string equal -length $n $path $type]} { -				set type [string range $type $n end] -				regsub {^:?\s*} $type {} type -			} -			$ui_diff insert end "* $type\n" d_@ -		} -		if {[string first "\0" $content] != -1} { -			$ui_diff insert end \ -				"* Binary file (not showing content)." \ -				d_@ -		} else { -			if {$sz > $max_sz} { -				$ui_diff insert end \ -"* Untracked file is $sz bytes. -* Showing only first $max_sz bytes. -" d_@ -			} -			$ui_diff insert end $content -			if {$sz > $max_sz} { -				$ui_diff insert end " -* Untracked file clipped here by [appname]. -* To see the entire file, use an external editor. -" d_@ -			} -		} -		$ui_diff conf -state disabled -		set diff_active 0 -		unlock_index -		set ui_status_value {Ready.} -		return -	} - -	set cmd [list | git] -	if {$w eq $ui_index} { -		lappend cmd diff-index -		lappend cmd --cached -	} elseif {$w eq $ui_workdir} { -		if {[string index $m 0] eq {U}} { -			lappend cmd diff -		} else { -			lappend cmd diff-files -		} -	} - -	lappend cmd -p -	lappend cmd --no-color -	if {$repo_config(gui.diffcontext) > 0} { -		lappend cmd "-U$repo_config(gui.diffcontext)" -	} -	if {$w eq $ui_index} { -		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 \ -		-encoding binary \ -		-translation binary -	fileevent $fd readable [list read_diff $fd] -} - -proc read_diff {fd} { -	global ui_diff ui_status_value diff_active -	global is_3way_diff current_diff_header - -	$ui_diff conf -state normal -	while {[gets $fd line] >= 0} { -		# -- Cleanup uninteresting diff header lines. -		# -		if {   [string match {diff --git *}      $line] -			|| [string match {diff --cc *}       $line] -			|| [string match {diff --combined *} $line] -			|| [string match {--- *}             $line] -			|| [string match {+++ *}             $line]} { -			append current_diff_header $line "\n" -			continue -		} -		if {[string match {index *} $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} - -		if {[string match {mode *} $line] -			|| [string match {new file *} $line] -			|| [string match {deleted file *} $line] -			|| [string match {Binary files * and * differ} $line] -			|| $line eq {\ No newline at end of file} -			|| [regexp {^\* Unmerged path } $line]} { -			set tags {} -		} elseif {$is_3way_diff} { -			set op [string range $line 0 1] -			switch -- $op { -			{  } {set tags {}} -			{@@} {set tags d_@} -			{ +} {set tags d_s+} -			{ -} {set tags d_s-} -			{+ } {set tags d_+s} -			{- } {set tags d_-s} -			{--} {set tags d_--} -			{++} { -				if {[regexp {^\+\+([<>]{7} |={7})} $line _g op]} { -					set line [string replace $line 0 1 {  }] -					set tags d$op -				} else { -					set tags d_++ -				} -			} -			default { -				puts "error: Unhandled 3 way diff marker: {$op}" -				set tags {} -			} -			} -		} else { -			set op [string index $line 0] -			switch -- $op { -			{ } {set tags {}} -			{@} {set tags d_@} -			{-} {set tags d_-} -			{+} { -				if {[regexp {^\+([<>]{7} |={7})} $line _g op]} { -					set line [string replace $line 0 0 { }] -					set tags d$op -				} else { -					set tags d_+ -				} -			} -			default { -				puts "error: Unhandled 2 way diff marker: {$op}" -				set tags {} -			} -			} -		} -		$ui_diff insert end $line $tags -		if {[string index $line end] eq "\r"} { -			$ui_diff tag add d_cr {end - 2c} -		} -		$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 {[$ui_diff index end] eq {2.0}} { -			handle_empty_diff -		} -	} -} - -proc apply_hunk {x y} { -	global current_diff_path current_diff_header current_diff_side -	global ui_diff ui_index file_states - -	if {$current_diff_path eq {} || $current_diff_header eq {}} return -	if {![lock_index apply_hunk]} return - -	set apply_cmd {git apply --cached --whitespace=nowarn} -	set mi [lindex $file_states($current_diff_path) 0] -	if {$current_diff_side eq $ui_index} { -		set mode unstage -		lappend apply_cmd --reverse -		if {[string index $mi 0] ne {M}} { -			unlock_index -			return -		} -	} else { -		set mode stage -		if {[string index $mi 1] ne {M}} { -			unlock_index -			return -		} -	} - -	set s_lno [lindex [split [$ui_diff index @$x,$y] .] 0] -	set s_lno [$ui_diff search -backwards -regexp ^@@ $s_lno.0 0.0] -	if {$s_lno eq {}} { -		unlock_index -		return -	} - -	set e_lno [$ui_diff search -forwards -regexp ^@@ "$s_lno + 1 lines" end] -	if {$e_lno eq {}} { -		set e_lno end -	} - -	if {[catch { -		set p [open "| $apply_cmd" w] -		fconfigure $p -translation binary -encoding binary -		puts -nonewline $p $current_diff_header -		puts -nonewline $p [$ui_diff get $s_lno $e_lno] -		close $p} err]} { -		error_popup "Failed to $mode selected hunk.\n\n$err" -		unlock_index -		return -	} - -	$ui_diff conf -state normal -	$ui_diff delete $s_lno $e_lno -	$ui_diff conf -state disabled - -	if {[$ui_diff get 1.0 end] eq "\n"} { -		set o _ -	} else { -		set o ? -	} - -	if {$current_diff_side eq $ui_index} { -		set mi ${o}M -	} elseif {[string index $mi 0] eq {_}} { -		set mi M$o -	} else { -		set mi ?$o -	} -	unlock_index -	display_file $current_diff_path $mi -	if {$o eq {_}} { -		clear_diff -	} -} - -###################################################################### -## -## commit - -proc load_last_commit {} { -	global HEAD PARENT MERGE_HEAD commit_type ui_comm -	global repo_config - -	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] -			fconfigure $fd -encoding binary -translation lf -			if {[catch {set enc $repo_config(i18n.commitencoding)}]} { -				set enc utf-8 -			} -			while {[gets $fd line] > 0} { -				if {[string match {parent *} $line]} { -					lappend parents [string range $line 7 end] -				} elseif {[string match {encoding *} $line]} { -					set enc [string tolower [string range $line 9 end]] -				} -			} -			fconfigure $fd -encoding $enc -			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 [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 -	global ui_status_value pch_error - -	if {[committer_ident] eq {}} return -	if {![lock_index update]} 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} -		U? { -			error_popup "Unmerged files cannot be committed. - -File [short_path $path] has merge conflicts. -You must resolve them and add 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 && ![string match *merge $curType]} { -		info_popup {No changes to commit. - -You must add 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]] -	regsub -all -line {[ \t\r]+$} $msg {} msg -	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 -	} - -	# -- Run the pre-commit hook. -	# -	set pchook [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_Cygwin] && [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 all_heads current_branch -	global ui_status_value ui_comm selected_commit_type -	global file_states selected_paths rescan_active -	global repo_config - -	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 -	} - -	# -- Verify this wasn't an empty change. -	# -	if {$commit_type eq {normal}} { -		set old_tree [git rev-parse "$PARENT^{tree}"] -		if {$tree_id eq $old_tree} { -			info_popup {No changes to commit. - -No files were modified by this commit and it -was not a merge commit. - -A rescan will be automatically started now. -} -			unlock_index -			rescan {set ui_status_value {No changes to commit.}} -			return -		} -	} - -	# -- Build the message. -	# -	set msg_p [gitdir COMMIT_EDITMSG] -	set msg_wt [open $msg_p w] -	if {[catch {set enc $repo_config(i18n.commitencoding)}]} { -		set enc utf-8 -	} -	fconfigure $msg_wt -encoding $enc -translation binary -	puts -nonewline $msg_wt $msg -	close $msg_wt - -	# -- Create the commit. -	# -	set cmd [list git commit-tree $tree_id] -	foreach p [concat $PARENT $MERGE_HEAD] { -		lappend cmd -p $p -	} -	lappend cmd <$msg_p -	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 $msg_p} -	catch {file delete [gitdir MERGE_HEAD]} -	catch {file delete [gitdir MERGE_MSG]} -	catch {file delete [gitdir SQUASH_MSG]} -	catch {file delete [gitdir GITGUI_MSG]} - -	# -- Let rerere do its thing. -	# -	if {[file isdirectory [gitdir rr-cache]]} { -		catch {git rerere} -	} - -	# -- Run the post-commit hook. -	# -	set pchook [gitdir hooks post-commit] -	if {[is_Cygwin] && [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 {[is_enabled singlecommit]} do_quit - -	# -- Make sure our current branch exists. -	# -	if {$commit_type eq {initial}} { -		lappend all_heads $current_branch -		set all_heads [lsort -unique $all_heads] -		populate_branch_menu -	} - -	# -- 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_ - -		D_ { -			unset file_states($path) -			catch {unset selected_paths($path)} -		} -		DO { -			set file_states($path) [list _O [lindex $s 1] {} {}] -		} -		AM - -		AD - -		MM - -		MD { -			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 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 console_done -} - -proc push_to {remote} { -	set w [new_console \ -		"push $remote" \ -		"Pushing changes to $remote"] -	set cmd [list git push] -	lappend cmd -v -	lappend cmd $remote -	console_exec $w $cmd console_done -} - -###################################################################### -##  ## ui helpers  proc mapicon {w state path} { @@ -1636,2091 +799,6 @@ proc display_all_files {} {  	$ui_workdir 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 \ -		-encoding binary \ -		-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_path - -	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\t[encoding convertto $path]\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 \ -		-encoding binary \ -		-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_path - -	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 {set new __} -		?D {set new D_} -		_O - -		AM {set new A_} -		U? { -			if {[file exists $path]} { -				set new M_ -			} else { -				set new D_ -			} -		} -		?M {set new M_} -		?? {continue} -		} -		puts -nonewline $fd "[encoding convertto $path]\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 \ -		-encoding binary \ -		-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_path - -	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] { -		U? {continue} -		?M - -		?D { -			puts -nonewline $fd "[encoding convertto $path]\0" -			display_file $path ?_ -		} -		} -	} - -	set ui_status_value [format \ -		"$msg... %i/%i files (%.2f%%)" \ -		$update_index_cp \ -		$totalCnt \ -		[expr {100.0 * $update_index_cp / $totalCnt}]] -} - -###################################################################### -## -## branch management - -proc is_tracking_branch {name} { -	global tracking_branches - -	if {![catch {set info $tracking_branches($name)}]} { -		return 1 -	} -	foreach t [array names tracking_branches] { -		if {[string match {*/\*} $t] && [string match $t $name]} { -			return 1 -		} -	} -	return 0 -} - -proc load_all_heads {} { -	global all_heads - -	set all_heads [list] -	set fd [open "| git for-each-ref --format=%(refname) refs/heads" r] -	while {[gets $fd line] > 0} { -		if {[is_tracking_branch $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 {} { -	global all_heads disable_on_lock - -	set m .mbar.branch -	set last [$m index last] -	for {set i 0} {$i <= $last} {incr i} { -		if {[$m type $i] eq {separator}} { -			$m delete $i last -			set new_dol [list] -			foreach a $disable_on_lock { -				if {[lindex $a 0] ne $m || [lindex $a 2] < $i} { -					lappend new_dol $a -				} -			} -			set disable_on_lock $new_dol -			break -		} -	} - -	if {$all_heads ne {}} { -		$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 all_tracking_branches {} { -	global tracking_branches - -	set all_trackings {} -	set cmd {} -	foreach name [array names tracking_branches] { -		if {[regsub {/\*$} $name {} name]} { -			lappend cmd $name -		} else { -			regsub ^refs/(heads|remotes)/ $name {} name -			lappend all_trackings $name -		} -	} - -	if {$cmd ne {}} { -		set fd [open "| git for-each-ref --format=%(refname) $cmd" r] -		while {[gets $fd name] > 0} { -			regsub ^refs/(heads|remotes)/ $name {} name -			lappend all_trackings $name -		} -		close $fd -	} - -	return [lsort -unique $all_trackings] -} - -proc load_all_tags {} { -	set all_tags [list] -	set fd [open "| git for-each-ref --format=%(refname) refs/tags" r] -	while {[gets $fd line] > 0} { -		if {![regsub ^refs/tags/ $line {} name]} continue -		lappend all_tags $name -	} -	close $fd - -	return [lsort $all_tags] -} - -proc do_create_branch_action {w} { -	global all_heads null_sha1 repo_config -	global create_branch_checkout create_branch_revtype -	global create_branch_head create_branch_trackinghead -	global create_branch_name create_branch_revexp -	global create_branch_tag - -	set newbranch $create_branch_name -	if {$newbranch eq {} -		|| $newbranch eq $repo_config(gui.newbranchtemplate)} { -		tk_messageBox \ -			-icon error \ -			-type ok \ -			-title [wm title $w] \ -			-parent $w \ -			-message "Please supply a branch name." -		focus $w.desc.name_t -		return -	} -	if {![catch {git show-ref --verify -- "refs/heads/$newbranch"}]} { -		tk_messageBox \ -			-icon error \ -			-type ok \ -			-title [wm title $w] \ -			-parent $w \ -			-message "Branch '$newbranch' already exists." -		focus $w.desc.name_t -		return -	} -	if {[catch {git check-ref-format "heads/$newbranch"}]} { -		tk_messageBox \ -			-icon error \ -			-type ok \ -			-title [wm title $w] \ -			-parent $w \ -			-message "We do not like '$newbranch' as a branch name." -		focus $w.desc.name_t -		return -	} - -	set rev {} -	switch -- $create_branch_revtype { -	head {set rev $create_branch_head} -	tracking {set rev $create_branch_trackinghead} -	tag {set rev $create_branch_tag} -	expression {set rev $create_branch_revexp} -	} -	if {[catch {set cmt [git rev-parse --verify "${rev}^0"]}]} { -		tk_messageBox \ -			-icon error \ -			-type ok \ -			-title [wm title $w] \ -			-parent $w \ -			-message "Invalid starting revision: $rev" -		return -	} -	set cmd [list git update-ref] -	lappend cmd -m -	lappend cmd "branch: Created from $rev" -	lappend cmd "refs/heads/$newbranch" -	lappend cmd $cmt -	lappend cmd $null_sha1 -	if {[catch {eval exec $cmd} err]} { -		tk_messageBox \ -			-icon error \ -			-type ok \ -			-title [wm title $w] \ -			-parent $w \ -			-message "Failed to create '$newbranch'.\n\n$err" -		return -	} - -	lappend all_heads $newbranch -	set all_heads [lsort $all_heads] -	populate_branch_menu -	destroy $w -	if {$create_branch_checkout} { -		switch_branch $newbranch -	} -} - -proc radio_selector {varname value args} { -	upvar #0 $varname var -	set var $value -} - -trace add variable create_branch_head write \ -	[list radio_selector create_branch_revtype head] -trace add variable create_branch_trackinghead write \ -	[list radio_selector create_branch_revtype tracking] -trace add variable create_branch_tag write \ -	[list radio_selector create_branch_revtype tag] - -trace add variable delete_branch_head write \ -	[list radio_selector delete_branch_checktype head] -trace add variable delete_branch_trackinghead write \ -	[list radio_selector delete_branch_checktype tracking] - -proc do_create_branch {} { -	global all_heads current_branch repo_config -	global create_branch_checkout create_branch_revtype -	global create_branch_head create_branch_trackinghead -	global create_branch_name create_branch_revexp -	global create_branch_tag - -	set w .branch_editor -	toplevel $w -	wm geometry $w "+[winfo rootx .]+[winfo rooty .]" - -	label $w.header -text {Create New Branch} \ -		-font font_uibold -	pack $w.header -side top -fill x - -	frame $w.buttons -	button $w.buttons.create -text Create \ -		-font font_ui \ -		-default active \ -		-command [list do_create_branch_action $w] -	pack $w.buttons.create -side right -	button $w.buttons.cancel -text {Cancel} \ -		-font font_ui \ -		-command [list destroy $w] -	pack $w.buttons.cancel -side right -padx 5 -	pack $w.buttons -side bottom -fill x -pady 10 -padx 10 - -	labelframe $w.desc \ -		-text {Branch Description} \ -		-font font_ui -	label $w.desc.name_l -text {Name:} -font font_ui -	entry $w.desc.name_t \ -		-borderwidth 1 \ -		-relief sunken \ -		-width 40 \ -		-textvariable create_branch_name \ -		-font font_ui \ -		-validate key \ -		-validatecommand { -			if {%d == 1 && [regexp {[~^:?*\[\0- ]} %S]} {return 0} -			return 1 -		} -	grid $w.desc.name_l $w.desc.name_t -sticky we -padx {0 5} -	grid columnconfigure $w.desc 1 -weight 1 -	pack $w.desc -anchor nw -fill x -pady 5 -padx 5 - -	labelframe $w.from \ -		-text {Starting Revision} \ -		-font font_ui -	radiobutton $w.from.head_r \ -		-text {Local Branch:} \ -		-value head \ -		-variable create_branch_revtype \ -		-font font_ui -	eval tk_optionMenu $w.from.head_m create_branch_head $all_heads -	grid $w.from.head_r $w.from.head_m -sticky w -	set all_trackings [all_tracking_branches] -	if {$all_trackings ne {}} { -		set create_branch_trackinghead [lindex $all_trackings 0] -		radiobutton $w.from.tracking_r \ -			-text {Tracking Branch:} \ -			-value tracking \ -			-variable create_branch_revtype \ -			-font font_ui -		eval tk_optionMenu $w.from.tracking_m \ -			create_branch_trackinghead \ -			$all_trackings -		grid $w.from.tracking_r $w.from.tracking_m -sticky w -	} -	set all_tags [load_all_tags] -	if {$all_tags ne {}} { -		set create_branch_tag [lindex $all_tags 0] -		radiobutton $w.from.tag_r \ -			-text {Tag:} \ -			-value tag \ -			-variable create_branch_revtype \ -			-font font_ui -		eval tk_optionMenu $w.from.tag_m \ -			create_branch_tag \ -			$all_tags -		grid $w.from.tag_r $w.from.tag_m -sticky w -	} -	radiobutton $w.from.exp_r \ -		-text {Revision Expression:} \ -		-value expression \ -		-variable create_branch_revtype \ -		-font font_ui -	entry $w.from.exp_t \ -		-borderwidth 1 \ -		-relief sunken \ -		-width 50 \ -		-textvariable create_branch_revexp \ -		-font font_ui \ -		-validate key \ -		-validatecommand { -			if {%d == 1 && [regexp {\s} %S]} {return 0} -			if {%d == 1 && [string length %S] > 0} { -				set create_branch_revtype expression -			} -			return 1 -		} -	grid $w.from.exp_r $w.from.exp_t -sticky we -padx {0 5} -	grid columnconfigure $w.from 1 -weight 1 -	pack $w.from -anchor nw -fill x -pady 5 -padx 5 - -	labelframe $w.postActions \ -		-text {Post Creation Actions} \ -		-font font_ui -	checkbutton $w.postActions.checkout \ -		-text {Checkout after creation} \ -		-variable create_branch_checkout \ -		-font font_ui -	pack $w.postActions.checkout -anchor nw -	pack $w.postActions -anchor nw -fill x -pady 5 -padx 5 - -	set create_branch_checkout 1 -	set create_branch_head $current_branch -	set create_branch_revtype head -	set create_branch_name $repo_config(gui.newbranchtemplate) -	set create_branch_revexp {} - -	bind $w <Visibility> " -		grab $w -		$w.desc.name_t icursor end -		focus $w.desc.name_t -	" -	bind $w <Key-Escape> "destroy $w" -	bind $w <Key-Return> "do_create_branch_action $w;break" -	wm title $w "[appname] ([reponame]): Create Branch" -	tkwait window $w -} - -proc do_delete_branch_action {w} { -	global all_heads -	global delete_branch_checktype delete_branch_head delete_branch_trackinghead - -	set check_rev {} -	switch -- $delete_branch_checktype { -	head {set check_rev $delete_branch_head} -	tracking {set check_rev $delete_branch_trackinghead} -	always {set check_rev {:none}} -	} -	if {$check_rev eq {:none}} { -		set check_cmt {} -	} elseif {[catch {set check_cmt [git rev-parse --verify "${check_rev}^0"]}]} { -		tk_messageBox \ -			-icon error \ -			-type ok \ -			-title [wm title $w] \ -			-parent $w \ -			-message "Invalid check revision: $check_rev" -		return -	} - -	set to_delete [list] -	set not_merged [list] -	foreach i [$w.list.l curselection] { -		set b [$w.list.l get $i] -		if {[catch {set o [git rev-parse --verify $b]}]} continue -		if {$check_cmt ne {}} { -			if {$b eq $check_rev} continue -			if {[catch {set m [git merge-base $o $check_cmt]}]} continue -			if {$o ne $m} { -				lappend not_merged $b -				continue -			} -		} -		lappend to_delete [list $b $o] -	} -	if {$not_merged ne {}} { -		set msg "The following branches are not completely merged into $check_rev: - - - [join $not_merged "\n - "]" -		tk_messageBox \ -			-icon info \ -			-type ok \ -			-title [wm title $w] \ -			-parent $w \ -			-message $msg -	} -	if {$to_delete eq {}} return -	if {$delete_branch_checktype eq {always}} { -		set msg {Recovering deleted branches is difficult. - -Delete the selected branches?} -		if {[tk_messageBox \ -			-icon warning \ -			-type yesno \ -			-title [wm title $w] \ -			-parent $w \ -			-message $msg] ne yes} { -			return -		} -	} - -	set failed {} -	foreach i $to_delete { -		set b [lindex $i 0] -		set o [lindex $i 1] -		if {[catch {git update-ref -d "refs/heads/$b" $o} err]} { -			append failed " - $b: $err\n" -		} else { -			set x [lsearch -sorted -exact $all_heads $b] -			if {$x >= 0} { -				set all_heads [lreplace $all_heads $x $x] -			} -		} -	} - -	if {$failed ne {}} { -		tk_messageBox \ -			-icon error \ -			-type ok \ -			-title [wm title $w] \ -			-parent $w \ -			-message "Failed to delete branches:\n$failed" -	} - -	set all_heads [lsort $all_heads] -	populate_branch_menu -	destroy $w -} - -proc do_delete_branch {} { -	global all_heads tracking_branches current_branch -	global delete_branch_checktype delete_branch_head delete_branch_trackinghead - -	set w .branch_editor -	toplevel $w -	wm geometry $w "+[winfo rootx .]+[winfo rooty .]" - -	label $w.header -text {Delete Local Branch} \ -		-font font_uibold -	pack $w.header -side top -fill x - -	frame $w.buttons -	button $w.buttons.create -text Delete \ -		-font font_ui \ -		-command [list do_delete_branch_action $w] -	pack $w.buttons.create -side right -	button $w.buttons.cancel -text {Cancel} \ -		-font font_ui \ -		-command [list destroy $w] -	pack $w.buttons.cancel -side right -padx 5 -	pack $w.buttons -side bottom -fill x -pady 10 -padx 10 - -	labelframe $w.list \ -		-text {Local Branches} \ -		-font font_ui -	listbox $w.list.l \ -		-height 10 \ -		-width 70 \ -		-selectmode extended \ -		-yscrollcommand [list $w.list.sby set] \ -		-font font_ui -	foreach h $all_heads { -		if {$h ne $current_branch} { -			$w.list.l insert end $h -		} -	} -	scrollbar $w.list.sby -command [list $w.list.l yview] -	pack $w.list.sby -side right -fill y -	pack $w.list.l -side left -fill both -expand 1 -	pack $w.list -fill both -expand 1 -pady 5 -padx 5 - -	labelframe $w.validate \ -		-text {Delete Only If} \ -		-font font_ui -	radiobutton $w.validate.head_r \ -		-text {Merged Into Local Branch:} \ -		-value head \ -		-variable delete_branch_checktype \ -		-font font_ui -	eval tk_optionMenu $w.validate.head_m delete_branch_head $all_heads -	grid $w.validate.head_r $w.validate.head_m -sticky w -	set all_trackings [all_tracking_branches] -	if {$all_trackings ne {}} { -		set delete_branch_trackinghead [lindex $all_trackings 0] -		radiobutton $w.validate.tracking_r \ -			-text {Merged Into Tracking Branch:} \ -			-value tracking \ -			-variable delete_branch_checktype \ -			-font font_ui -		eval tk_optionMenu $w.validate.tracking_m \ -			delete_branch_trackinghead \ -			$all_trackings -		grid $w.validate.tracking_r $w.validate.tracking_m -sticky w -	} -	radiobutton $w.validate.always_r \ -		-text {Always (Do not perform merge checks)} \ -		-value always \ -		-variable delete_branch_checktype \ -		-font font_ui -	grid $w.validate.always_r -columnspan 2 -sticky w -	grid columnconfigure $w.validate 1 -weight 1 -	pack $w.validate -anchor nw -fill x -pady 5 -padx 5 - -	set delete_branch_head $current_branch -	set delete_branch_checktype head - -	bind $w <Visibility> "grab $w; focus $w" -	bind $w <Key-Escape> "destroy $w" -	wm title $w "[appname] ([reponame]): Delete Branch" -	tkwait window $w -} - -proc switch_branch {new_branch} { -	global HEAD commit_type current_branch repo_config - -	if {![lock_index switch]} 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 the current branch can be changed. - -The rescan will be automatically started now. -} -		unlock_index -		rescan {set ui_status_value {Ready.}} -		return -	} - -	# -- Don't do a pointless switch. -	# -	if {$current_branch eq $new_branch} { -		unlock_index -		return -	} - -	if {$repo_config(gui.trustmtime) eq {true}} { -		switch_branch_stage2 {} $new_branch -	} else { -		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 switch_branch_stage2 $fd_rf $new_branch] -	} -} - -proc switch_branch_stage2 {fd_rf new_branch} { -	global ui_status_value HEAD - -	if {$fd_rf ne {}} { -		read $fd_rf -		if {![eof $fd_rf]} return -		close $fd_rf -	} - -	set ui_status_value "Updating working directory to '$new_branch'..." -	set cmd [list git read-tree] -	lappend cmd -m -	lappend cmd -u -	lappend cmd --exclude-per-directory=.gitignore -	lappend cmd $HEAD -	lappend cmd $new_branch -	set fd_rt [open "| $cmd" r] -	fconfigure $fd_rt -blocking 0 -translation binary -	fileevent $fd_rt readable \ -		[list switch_branch_readtree_wait $fd_rt $new_branch] -} - -proc switch_branch_readtree_wait {fd_rt new_branch} { -	global selected_commit_type commit_type HEAD MERGE_HEAD PARENT -	global current_branch -	global ui_comm ui_status_value - -	# -- We never get interesting output on stdout; only stderr. -	# -	read $fd_rt -	fconfigure $fd_rt -blocking 1 -	if {![eof $fd_rt]} { -		fconfigure $fd_rt -blocking 0 -		return -	} - -	# -- The working directory wasn't in sync with the index and -	#    we'd have to overwrite something to make the switch. A -	#    merge is required. -	# -	if {[catch {close $fd_rt} err]} { -		regsub {^fatal: } $err {} err -		warn_popup "File level merge required. - -$err - -Staying on branch '$current_branch'." -		set ui_status_value "Aborted checkout of '$new_branch' (file level merging is required)." -		unlock_index -		return -	} - -	# -- Update the symbolic ref.  Core git doesn't even check for failure -	#    here, it Just Works(tm).  If it doesn't we are in some really ugly -	#    state that is difficult to recover from within git-gui. -	# -	if {[catch {git symbolic-ref HEAD "refs/heads/$new_branch"} err]} { -		error_popup "Failed to set current branch. - -This working directory is only partially switched. -We successfully updated your files, but failed to -update an internal Git file. - -This should not have occurred.  [appname] will now -close and give up. - -$err" -		do_quit -		return -	} - -	# -- Update our repository state.  If we were previously in amend mode -	#    we need to toss the current buffer and do a full rescan to update -	#    our file lists.  If we weren't in amend mode our file lists are -	#    accurate and we can avoid the rescan. -	# -	unlock_index -	set selected_commit_type new -	if {[string match amend* $commit_type]} { -		$ui_comm delete 0.0 end -		$ui_comm edit reset -		$ui_comm edit modified false -		rescan {set ui_status_value "Checked out branch '$current_branch'."} -	} else { -		repository_state commit_type HEAD MERGE_HEAD -		set PARENT $HEAD -		set ui_status_value "Checked out branch '$current_branch'." -	} -} - -###################################################################### -## -## remote management - -proc load_all_remotes {} { -	global repo_config -	global all_remotes tracking_branches - -	set all_remotes [list] -	array unset tracking_branches - -	set rm_dir [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 {} { -	global all_remotes repo_config - -	set m .mbar.fetch -	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 [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 {} { -	global all_remotes repo_config - -	set m .mbar.push -	set fast_count 0 -	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 [gitdir remotes $r] r] -				while {[gets $fd n] >= 0} { -					if {[regexp {^Push:[ \t]*([^:]+):} $n]} { -						set enable 1 -						break -					} -				} -				close $fd -			} -		} - -		if {$enable} { -			if {!$fast_count} { -				$m add separator -			} -			$m add command \ -				-label "Push to $r..." \ -				-command [list push_to $r] \ -				-font font_ui -			incr fast_count -		} -	} -} - -proc start_push_anywhere_action {w} { -	global push_urltype push_remote push_url push_thin push_tags - -	set r_url {} -	switch -- $push_urltype { -	remote {set r_url $push_remote} -	url {set r_url $push_url} -	} -	if {$r_url eq {}} return - -	set cmd [list git push] -	lappend cmd -v -	if {$push_thin} { -		lappend cmd --thin -	} -	if {$push_tags} { -		lappend cmd --tags -	} -	lappend cmd $r_url -	set cnt 0 -	foreach i [$w.source.l curselection] { -		set b [$w.source.l get $i] -		lappend cmd "refs/heads/$b:refs/heads/$b" -		incr cnt -	} -	if {$cnt == 0} { -		return -	} elseif {$cnt == 1} { -		set unit branch -	} else { -		set unit branches -	} - -	set cons [new_console "push $r_url" "Pushing $cnt $unit to $r_url"] -	console_exec $cons $cmd console_done -	destroy $w -} - -trace add variable push_remote write \ -	[list radio_selector push_urltype remote] - -proc do_push_anywhere {} { -	global all_heads all_remotes current_branch -	global push_urltype push_remote push_url push_thin push_tags - -	set w .push_setup -	toplevel $w -	wm geometry $w "+[winfo rootx .]+[winfo rooty .]" - -	label $w.header -text {Push Branches} -font font_uibold -	pack $w.header -side top -fill x - -	frame $w.buttons -	button $w.buttons.create -text Push \ -		-font font_ui \ -		-command [list start_push_anywhere_action $w] -	pack $w.buttons.create -side right -	button $w.buttons.cancel -text {Cancel} \ -		-font font_ui \ -		-command [list destroy $w] -	pack $w.buttons.cancel -side right -padx 5 -	pack $w.buttons -side bottom -fill x -pady 10 -padx 10 - -	labelframe $w.source \ -		-text {Source Branches} \ -		-font font_ui -	listbox $w.source.l \ -		-height 10 \ -		-width 70 \ -		-selectmode extended \ -		-yscrollcommand [list $w.source.sby set] \ -		-font font_ui -	foreach h $all_heads { -		$w.source.l insert end $h -		if {$h eq $current_branch} { -			$w.source.l select set end -		} -	} -	scrollbar $w.source.sby -command [list $w.source.l yview] -	pack $w.source.sby -side right -fill y -	pack $w.source.l -side left -fill both -expand 1 -	pack $w.source -fill both -expand 1 -pady 5 -padx 5 - -	labelframe $w.dest \ -		-text {Destination Repository} \ -		-font font_ui -	if {$all_remotes ne {}} { -		radiobutton $w.dest.remote_r \ -			-text {Remote:} \ -			-value remote \ -			-variable push_urltype \ -			-font font_ui -		eval tk_optionMenu $w.dest.remote_m push_remote $all_remotes -		grid $w.dest.remote_r $w.dest.remote_m -sticky w -		if {[lsearch -sorted -exact $all_remotes origin] != -1} { -			set push_remote origin -		} else { -			set push_remote [lindex $all_remotes 0] -		} -		set push_urltype remote -	} else { -		set push_urltype url -	} -	radiobutton $w.dest.url_r \ -		-text {Arbitrary URL:} \ -		-value url \ -		-variable push_urltype \ -		-font font_ui -	entry $w.dest.url_t \ -		-borderwidth 1 \ -		-relief sunken \ -		-width 50 \ -		-textvariable push_url \ -		-font font_ui \ -		-validate key \ -		-validatecommand { -			if {%d == 1 && [regexp {\s} %S]} {return 0} -			if {%d == 1 && [string length %S] > 0} { -				set push_urltype url -			} -			return 1 -		} -	grid $w.dest.url_r $w.dest.url_t -sticky we -padx {0 5} -	grid columnconfigure $w.dest 1 -weight 1 -	pack $w.dest -anchor nw -fill x -pady 5 -padx 5 - -	labelframe $w.options \ -		-text {Transfer Options} \ -		-font font_ui -	checkbutton $w.options.thin \ -		-text {Use thin pack (for slow network connections)} \ -		-variable push_thin \ -		-font font_ui -	grid $w.options.thin -columnspan 2 -sticky w -	checkbutton $w.options.tags \ -		-text {Include tags} \ -		-variable push_tags \ -		-font font_ui -	grid $w.options.tags -columnspan 2 -sticky w -	grid columnconfigure $w.options 1 -weight 1 -	pack $w.options -anchor nw -fill x -pady 5 -padx 5 - -	set push_url {} -	set push_thin 0 -	set push_tags 0 - -	bind $w <Visibility> "grab $w" -	bind $w <Key-Escape> "destroy $w" -	wm title $w "[appname] ([reponame]): Push" -	tkwait window $w -} - -###################################################################### -## -## merge - -proc can_merge {} { -	global HEAD commit_type file_states - -	if {[string match amend* $commit_type]} { -		info_popup {Cannot merge while amending. - -You must finish amending this commit before -starting any type of merge. -} -		return 0 -	} - -	if {[committer_ident] eq {}} {return 0} -	if {![lock_index merge]} {return 0} - -	# -- 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 merge can be performed. - -The rescan will be automatically started now. -} -		unlock_index -		rescan {set ui_status_value {Ready.}} -		return 0 -	} - -	foreach path [array names file_states] { -		switch -glob -- [lindex $file_states($path) 0] { -		_O { -			continue; # and pray it works! -		} -		U? { -			error_popup "You are in the middle of a conflicted merge. - -File [short_path $path] has merge conflicts. - -You must resolve them, add the file, and commit to -complete the current merge.  Only then can you -begin another merge. -" -			unlock_index -			return 0 -		} -		?? { -			error_popup "You are in the middle of a change. - -File [short_path $path] is modified. - -You should complete the current commit before -starting a merge.  Doing so will help you abort -a failed merge, should the need arise. -" -			unlock_index -			return 0 -		} -		} -	} - -	return 1 -} - -proc visualize_local_merge {w} { -	set revs {} -	foreach i [$w.source.l curselection] { -		lappend revs [$w.source.l get $i] -	} -	if {$revs eq {}} return -	lappend revs --not HEAD -	do_gitk $revs -} - -proc start_local_merge_action {w} { -	global HEAD ui_status_value current_branch - -	set cmd [list git merge] -	set names {} -	set revcnt 0 -	foreach i [$w.source.l curselection] { -		set b [$w.source.l get $i] -		lappend cmd $b -		lappend names $b -		incr revcnt -	} - -	if {$revcnt == 0} { -		return -	} elseif {$revcnt == 1} { -		set unit branch -	} elseif {$revcnt <= 15} { -		set unit branches -	} else { -		tk_messageBox \ -			-icon error \ -			-type ok \ -			-title [wm title $w] \ -			-parent $w \ -			-message "Too many branches selected. - -You have requested to merge $revcnt branches -in an octopus merge.  This exceeds Git's -internal limit of 15 branches per merge. - -Please select fewer branches.  To merge more -than 15 branches, merge the branches in batches. -" -		return -	} - -	set msg "Merging $current_branch, [join $names {, }]" -	set ui_status_value "$msg..." -	set cons [new_console "Merge" $msg] -	console_exec $cons $cmd [list finish_merge $revcnt] -	bind $w <Destroy> {} -	destroy $w -} - -proc finish_merge {revcnt w ok} { -	console_done $w $ok -	if {$ok} { -		set msg {Merge completed successfully.} -	} else { -		if {$revcnt != 1} { -			info_popup "Octopus merge failed. - -Your merge of $revcnt branches has failed. - -There are file-level conflicts between the -branches which must be resolved manually. - -The working directory will now be reset. - -You can attempt this merge again -by merging only one branch at a time." $w - -			set fd [open "| git read-tree --reset -u HEAD" r] -			fconfigure $fd -blocking 0 -translation binary -			fileevent $fd readable [list reset_hard_wait $fd] -			set ui_status_value {Aborting... please wait...} -			return -		} - -		set msg {Merge failed.  Conflict resolution is required.} -	} -	unlock_index -	rescan [list set ui_status_value $msg] -} - -proc do_local_merge {} { -	global current_branch - -	if {![can_merge]} return - -	set w .merge_setup -	toplevel $w -	wm geometry $w "+[winfo rootx .]+[winfo rooty .]" - -	label $w.header \ -		-text "Merge Into $current_branch" \ -		-font font_uibold -	pack $w.header -side top -fill x - -	frame $w.buttons -	button $w.buttons.visualize -text Visualize \ -		-font font_ui \ -		-command [list visualize_local_merge $w] -	pack $w.buttons.visualize -side left -	button $w.buttons.create -text Merge \ -		-font font_ui \ -		-command [list start_local_merge_action $w] -	pack $w.buttons.create -side right -	button $w.buttons.cancel -text {Cancel} \ -		-font font_ui \ -		-command [list destroy $w] -	pack $w.buttons.cancel -side right -padx 5 -	pack $w.buttons -side bottom -fill x -pady 10 -padx 10 - -	labelframe $w.source \ -		-text {Source Branches} \ -		-font font_ui -	listbox $w.source.l \ -		-height 10 \ -		-width 70 \ -		-selectmode extended \ -		-yscrollcommand [list $w.source.sby set] \ -		-font font_ui -	scrollbar $w.source.sby -command [list $w.source.l yview] -	pack $w.source.sby -side right -fill y -	pack $w.source.l -side left -fill both -expand 1 -	pack $w.source -fill both -expand 1 -pady 5 -padx 5 - -	set cmd [list git for-each-ref] -	lappend cmd {--format=%(objectname) %(*objectname) %(refname)} -	lappend cmd refs/heads -	lappend cmd refs/remotes -	lappend cmd refs/tags -	set fr_fd [open "| $cmd" r] -	fconfigure $fr_fd -translation binary -	while {[gets $fr_fd line] > 0} { -		set line [split $line { }] -		set sha1([lindex $line 0]) [lindex $line 2] -		set sha1([lindex $line 1]) [lindex $line 2] -	} -	close $fr_fd - -	set to_show {} -	set fr_fd [open "| git rev-list --all --not HEAD"] -	while {[gets $fr_fd line] > 0} { -		if {[catch {set ref $sha1($line)}]} continue -		regsub ^refs/(heads|remotes|tags)/ $ref {} ref -		lappend to_show $ref -	} -	close $fr_fd - -	foreach ref [lsort -unique $to_show] { -		$w.source.l insert end $ref -	} - -	bind $w <Visibility> "grab $w" -	bind $w <Key-Escape> "unlock_index;destroy $w" -	bind $w <Destroy> unlock_index -	wm title $w "[appname] ([reponame]): Merge" -	tkwait window $w -} - -proc do_reset_hard {} { -	global HEAD commit_type file_states - -	if {[string match amend* $commit_type]} { -		info_popup {Cannot abort while amending. - -You must finish amending this commit. -} -		return -	} - -	if {![lock_index abort]} return - -	if {[string match *merge* $commit_type]} { -		set op merge -	} else { -		set op commit -	} - -	if {[ask_popup "Abort $op? - -Aborting the current $op will cause -*ALL* uncommitted changes to be lost. - -Continue with aborting the current $op?"] eq {yes}} { -		set fd [open "| git read-tree --reset -u HEAD" r] -		fconfigure $fd -blocking 0 -translation binary -		fileevent $fd readable [list reset_hard_wait $fd] -		set ui_status_value {Aborting... please wait...} -	} else { -		unlock_index -	} -} - -proc reset_hard_wait {fd} { -	global ui_comm - -	read $fd -	if {[eof $fd]} { -		close $fd -		unlock_index - -		$ui_comm delete 0.0 end -		$ui_comm edit modified false - -		catch {file delete [gitdir MERGE_HEAD]} -		catch {file delete [gitdir rr-cache MERGE_RR]} -		catch {file delete [gitdir SQUASH_MSG]} -		catch {file delete [gitdir MERGE_MSG]} -		catch {file delete [gitdir GITGUI_MSG]} - -		rescan {set ui_status_value {Abort completed.  Ready.}} -	} -} - -###################################################################### -## -## browser - -set next_browser_id 0 - -proc new_browser {commit} { -	global next_browser_id cursor_ptr M1B -	global browser_commit browser_status browser_stack browser_path browser_busy - -	if {[winfo ismapped .]} { -		set w .browser[incr next_browser_id] -		set tl $w -		toplevel $w -	} else { -		set w {} -		set tl . -	} -	set w_list $w.list.l -	set browser_commit($w_list) $commit -	set browser_status($w_list) {Starting...} -	set browser_stack($w_list) {} -	set browser_path($w_list) $browser_commit($w_list): -	set browser_busy($w_list) 1 - -	label $w.path -textvariable browser_path($w_list) \ -		-anchor w \ -		-justify left \ -		-borderwidth 1 \ -		-relief sunken \ -		-font font_uibold -	pack $w.path -anchor w -side top -fill x - -	frame $w.list -	text $w_list -background white -borderwidth 0 \ -		-cursor $cursor_ptr \ -		-state disabled \ -		-wrap none \ -		-height 20 \ -		-width 70 \ -		-xscrollcommand [list $w.list.sbx set] \ -		-yscrollcommand [list $w.list.sby set] \ -		-font font_ui -	$w_list tag conf in_sel \ -		-background [$w_list cget -foreground] \ -		-foreground [$w_list cget -background] -	scrollbar $w.list.sbx -orient h -command [list $w_list xview] -	scrollbar $w.list.sby -orient v -command [list $w_list yview] -	pack $w.list.sbx -side bottom -fill x -	pack $w.list.sby -side right -fill y -	pack $w_list -side left -fill both -expand 1 -	pack $w.list -side top -fill both -expand 1 - -	label $w.status -textvariable browser_status($w_list) \ -		-anchor w \ -		-justify left \ -		-borderwidth 1 \ -		-relief sunken \ -		-font font_ui -	pack $w.status -anchor w -side bottom -fill x - -	bind $w_list <Button-1>        "browser_click 0 $w_list @%x,%y;break" -	bind $w_list <Double-Button-1> "browser_click 1 $w_list @%x,%y;break" -	bind $w_list <$M1B-Up>         "browser_parent $w_list;break" -	bind $w_list <$M1B-Left>       "browser_parent $w_list;break" -	bind $w_list <Up>              "browser_move -1 $w_list;break" -	bind $w_list <Down>            "browser_move 1 $w_list;break" -	bind $w_list <$M1B-Right>      "browser_enter $w_list;break" -	bind $w_list <Return>          "browser_enter $w_list;break" -	bind $w_list <Prior>           "browser_page -1 $w_list;break" -	bind $w_list <Next>            "browser_page 1 $w_list;break" -	bind $w_list <Left>            break -	bind $w_list <Right>           break - -	bind $tl <Visibility> "focus $w" -	bind $tl <Destroy> " -		array unset browser_buffer $w_list -		array unset browser_files $w_list -		array unset browser_status $w_list -		array unset browser_stack $w_list -		array unset browser_path $w_list -		array unset browser_commit $w_list -		array unset browser_busy $w_list -	" -	wm title $tl "[appname] ([reponame]): File Browser" -	ls_tree $w_list $browser_commit($w_list) {} -} - -proc browser_move {dir w} { -	global browser_files browser_busy - -	if {$browser_busy($w)} return -	set lno [lindex [split [$w index in_sel.first] .] 0] -	incr lno $dir -	if {[lindex $browser_files($w) [expr {$lno - 1}]] ne {}} { -		$w tag remove in_sel 0.0 end -		$w tag add in_sel $lno.0 [expr {$lno + 1}].0 -		$w see $lno.0 -	} -} - -proc browser_page {dir w} { -	global browser_files browser_busy - -	if {$browser_busy($w)} return -	$w yview scroll $dir pages -	set lno [expr {int( -		  [lindex [$w yview] 0] -		* [llength $browser_files($w)] -		+ 1)}] -	if {[lindex $browser_files($w) [expr {$lno - 1}]] ne {}} { -		$w tag remove in_sel 0.0 end -		$w tag add in_sel $lno.0 [expr {$lno + 1}].0 -		$w see $lno.0 -	} -} - -proc browser_parent {w} { -	global browser_files browser_status browser_path -	global browser_stack browser_busy - -	if {$browser_busy($w)} return -	set info [lindex $browser_files($w) 0] -	if {[lindex $info 0] eq {parent}} { -		set parent [lindex $browser_stack($w) end-1] -		set browser_stack($w) [lrange $browser_stack($w) 0 end-2] -		if {$browser_stack($w) eq {}} { -			regsub {:.*$} $browser_path($w) {:} browser_path($w) -		} else { -			regsub {/[^/]+$} $browser_path($w) {} browser_path($w) -		} -		set browser_status($w) "Loading $browser_path($w)..." -		ls_tree $w [lindex $parent 0] [lindex $parent 1] -	} -} - -proc browser_enter {w} { -	global browser_files browser_status browser_path -	global browser_commit browser_stack browser_busy - -	if {$browser_busy($w)} return -	set lno [lindex [split [$w index in_sel.first] .] 0] -	set info [lindex $browser_files($w) [expr {$lno - 1}]] -	if {$info ne {}} { -		switch -- [lindex $info 0] { -		parent { -			browser_parent $w -		} -		tree { -			set name [lindex $info 2] -			set escn [escape_path $name] -			set browser_status($w) "Loading $escn..." -			append browser_path($w) $escn -			ls_tree $w [lindex $info 1] $name -		} -		blob { -			set name [lindex $info 2] -			set p {} -			foreach n $browser_stack($w) { -				append p [lindex $n 1] -			} -			append p $name -			show_blame $browser_commit($w) $p -		} -		} -	} -} - -proc browser_click {was_double_click w pos} { -	global browser_files browser_busy - -	if {$browser_busy($w)} return -	set lno [lindex [split [$w index $pos] .] 0] -	focus $w - -	if {[lindex $browser_files($w) [expr {$lno - 1}]] ne {}} { -		$w tag remove in_sel 0.0 end -		$w tag add in_sel $lno.0 [expr {$lno + 1}].0 -		if {$was_double_click} { -			browser_enter $w -		} -	} -} - -proc ls_tree {w tree_id name} { -	global browser_buffer browser_files browser_stack browser_busy - -	set browser_buffer($w) {} -	set browser_files($w) {} -	set browser_busy($w) 1 - -	$w conf -state normal -	$w tag remove in_sel 0.0 end -	$w delete 0.0 end -	if {$browser_stack($w) ne {}} { -		$w image create end \ -			-align center -padx 5 -pady 1 \ -			-name icon0 \ -			-image file_uplevel -		$w insert end {[Up To Parent]} -		lappend browser_files($w) parent -	} -	lappend browser_stack($w) [list $tree_id $name] -	$w conf -state disabled - -	set cmd [list git ls-tree -z $tree_id] -	set fd [open "| $cmd" r] -	fconfigure $fd -blocking 0 -translation binary -encoding binary -	fileevent $fd readable [list read_ls_tree $fd $w] -} - -proc read_ls_tree {fd w} { -	global browser_buffer browser_files browser_status browser_busy - -	if {![winfo exists $w]} { -		catch {close $fd} -		return -	} - -	append browser_buffer($w) [read $fd] -	set pck [split $browser_buffer($w) "\0"] -	set browser_buffer($w) [lindex $pck end] - -	set n [llength $browser_files($w)] -	$w conf -state normal -	foreach p [lrange $pck 0 end-1] { -		set info [split $p "\t"] -		set path [lindex $info 1] -		set info [split [lindex $info 0] { }] -		set type [lindex $info 1] -		set object [lindex $info 2] - -		switch -- $type { -		blob { -			set image file_mod -		} -		tree { -			set image file_dir -			append path / -		} -		default { -			set image file_question -		} -		} - -		if {$n > 0} {$w insert end "\n"} -		$w image create end \ -			-align center -padx 5 -pady 1 \ -			-name icon[incr n] \ -			-image $image -		$w insert end [escape_path $path] -		lappend browser_files($w) [list $type $object $path] -	} -	$w conf -state disabled - -	if {[eof $fd]} { -		close $fd -		set browser_status($w) Ready. -		set browser_busy($w) 0 -		array unset browser_buffer $w -		if {$n > 0} { -			$w tag add in_sel 1.0 2.0 -			focus -force $w -		} -	} -} - -proc show_blame {commit path} { -	global next_browser_id blame_status blame_data - -	if {[winfo ismapped .]} { -		set w .browser[incr next_browser_id] -		set tl $w -		toplevel $w -	} else { -		set w {} -		set tl . -	} -	set blame_status($w) {Loading current file content...} - -	label $w.path -text "$commit:$path" \ -		-anchor w \ -		-justify left \ -		-borderwidth 1 \ -		-relief sunken \ -		-font font_uibold -	pack $w.path -side top -fill x - -	frame $w.out -	text $w.out.loaded_t \ -		-background white -borderwidth 0 \ -		-state disabled \ -		-wrap none \ -		-height 40 \ -		-width 1 \ -		-font font_diff -	$w.out.loaded_t tag conf annotated -background grey - -	text $w.out.linenumber_t \ -		-background white -borderwidth 0 \ -		-state disabled \ -		-wrap none \ -		-height 40 \ -		-width 5 \ -		-font font_diff -	$w.out.linenumber_t tag conf linenumber -justify right - -	text $w.out.file_t \ -		-background white -borderwidth 0 \ -		-state disabled \ -		-wrap none \ -		-height 40 \ -		-width 80 \ -		-xscrollcommand [list $w.out.sbx set] \ -		-font font_diff - -	scrollbar $w.out.sbx -orient h -command [list $w.out.file_t xview] -	scrollbar $w.out.sby -orient v \ -		-command [list scrollbar2many [list \ -		$w.out.loaded_t \ -		$w.out.linenumber_t \ -		$w.out.file_t \ -		] yview] -	grid \ -		$w.out.linenumber_t \ -		$w.out.loaded_t \ -		$w.out.file_t \ -		$w.out.sby \ -		-sticky nsew -	grid conf $w.out.sbx -column 2 -sticky we -	grid columnconfigure $w.out 2 -weight 1 -	grid rowconfigure $w.out 0 -weight 1 -	pack $w.out -fill both -expand 1 - -	label $w.status -textvariable blame_status($w) \ -		-anchor w \ -		-justify left \ -		-borderwidth 1 \ -		-relief sunken \ -		-font font_ui -	pack $w.status -side bottom -fill x - -	frame $w.cm -	text $w.cm.t \ -		-background white -borderwidth 0 \ -		-state disabled \ -		-wrap none \ -		-height 10 \ -		-width 80 \ -		-xscrollcommand [list $w.cm.sbx set] \ -		-yscrollcommand [list $w.cm.sby set] \ -		-font font_diff -	scrollbar $w.cm.sbx -orient h -command [list $w.cm.t xview] -	scrollbar $w.cm.sby -orient v -command [list $w.cm.t yview] -	pack $w.cm.sby -side right -fill y -	pack $w.cm.sbx -side bottom -fill x -	pack $w.cm.t -expand 1 -fill both -	pack $w.cm -side bottom -fill x - -	menu $w.ctxm -tearoff 0 -	$w.ctxm add command -label "Copy Commit" \ -		-font font_ui \ -		-command "blame_copycommit $w \$cursorW @\$cursorX,\$cursorY" - -	foreach i [list \ -		$w.out.loaded_t \ -		$w.out.linenumber_t \ -		$w.out.file_t] { -		$i tag conf in_sel \ -			-background [$i cget -foreground] \ -			-foreground [$i cget -background] -		$i conf -yscrollcommand \ -			[list many2scrollbar [list \ -			$w.out.loaded_t \ -			$w.out.linenumber_t \ -			$w.out.file_t \ -			] yview $w.out.sby] -		bind $i <Button-1> " -			blame_click {$w} \\ -				$w.cm.t \\ -				$w.out.linenumber_t \\ -				$w.out.file_t \\ -				$i @%x,%y -			focus $i -		" -		bind_button3 $i " -			set cursorX %x -			set cursorY %y -			set cursorW %W -			tk_popup $w.ctxm %X %Y -		" -	} - -	bind $w.cm.t <Button-1> "focus $w.cm.t" -	bind $tl <Visibility> "focus $tl" -	bind $tl <Destroy> " -		array unset blame_status {$w} -		array unset blame_data $w,* -	" -	wm title $tl "[appname] ([reponame]): File Viewer" - -	set blame_data($w,commit_count) 0 -	set blame_data($w,commit_list) {} -	set blame_data($w,total_lines) 0 -	set blame_data($w,blame_lines) 0 -	set blame_data($w,highlight_commit) {} -	set blame_data($w,highlight_line) -1 - -	set cmd [list git cat-file blob "$commit:$path"] -	set fd [open "| $cmd" r] -	fconfigure $fd -blocking 0 -translation lf -encoding binary -	fileevent $fd readable [list read_blame_catfile \ -		$fd $w $commit $path \ -		$w.cm.t $w.out.loaded_t $w.out.linenumber_t $w.out.file_t] -} - -proc read_blame_catfile {fd w commit path w_cmit w_load w_line w_file} { -	global blame_status blame_data - -	if {![winfo exists $w_file]} { -		catch {close $fd} -		return -	} - -	set n $blame_data($w,total_lines) -	$w_load conf -state normal -	$w_line conf -state normal -	$w_file conf -state normal -	while {[gets $fd line] >= 0} { -		regsub "\r\$" $line {} line -		incr n -		$w_load insert end "\n" -		$w_line insert end "$n\n" linenumber -		$w_file insert end "$line\n" -	} -	$w_load conf -state disabled -	$w_line conf -state disabled -	$w_file conf -state disabled -	set blame_data($w,total_lines) $n - -	if {[eof $fd]} { -		close $fd -		blame_incremental_status $w -		set cmd [list git blame -M -C --incremental] -		lappend cmd $commit -- $path -		set fd [open "| $cmd" r] -		fconfigure $fd -blocking 0 -translation lf -encoding binary -		fileevent $fd readable [list read_blame_incremental $fd $w \ -			$w_load $w_cmit $w_line $w_file] -	} -} - -proc read_blame_incremental {fd w w_load w_cmit w_line w_file} { -	global blame_status blame_data - -	if {![winfo exists $w_file]} { -		catch {close $fd} -		return -	} - -	while {[gets $fd line] >= 0} { -		if {[regexp {^([a-z0-9]{40}) (\d+) (\d+) (\d+)$} $line line \ -			cmit original_line final_line line_count]} { -			set blame_data($w,commit) $cmit -			set blame_data($w,original_line) $original_line -			set blame_data($w,final_line) $final_line -			set blame_data($w,line_count) $line_count - -			if {[catch {set g $blame_data($w,$cmit,order)}]} { -				$w_line tag conf g$cmit -				$w_file tag conf g$cmit -				$w_line tag raise in_sel -				$w_file tag raise in_sel -				$w_file tag raise sel -				set blame_data($w,$cmit,order) $blame_data($w,commit_count) -				incr blame_data($w,commit_count) -				lappend blame_data($w,commit_list) $cmit -			} -		} elseif {[string match {filename *} $line]} { -			set file [string range $line 9 end] -			set n $blame_data($w,line_count) -			set lno $blame_data($w,final_line) -			set cmit $blame_data($w,commit) - -			while {$n > 0} { -				if {[catch {set g g$blame_data($w,line$lno,commit)}]} { -					$w_load tag add annotated $lno.0 "$lno.0 lineend + 1c" -				} else { -					$w_line tag remove g$g $lno.0 "$lno.0 lineend + 1c" -					$w_file tag remove g$g $lno.0 "$lno.0 lineend + 1c" -				} - -				set blame_data($w,line$lno,commit) $cmit -				set blame_data($w,line$lno,file) $file -				$w_line tag add g$cmit $lno.0 "$lno.0 lineend + 1c" -				$w_file tag add g$cmit $lno.0 "$lno.0 lineend + 1c" - -				if {$blame_data($w,highlight_line) == -1} { -					if {[lindex [$w_file yview] 0] == 0} { -						$w_file see $lno.0 -						blame_showcommit $w $w_cmit $w_line $w_file $lno -					} -				} elseif {$blame_data($w,highlight_line) == $lno} { -					blame_showcommit $w $w_cmit $w_line $w_file $lno -				} - -				incr n -1 -				incr lno -				incr blame_data($w,blame_lines) -			} - -			set hc $blame_data($w,highlight_commit) -			if {$hc ne {} -				&& [expr {$blame_data($w,$hc,order) + 1}] -					== $blame_data($w,$cmit,order)} { -				blame_showcommit $w $w_cmit $w_line $w_file \ -					$blame_data($w,highlight_line) -			} -		} elseif {[regexp {^([a-z-]+) (.*)$} $line line header data]} { -			set blame_data($w,$blame_data($w,commit),$header) $data -		} -	} - -	if {[eof $fd]} { -		close $fd -		set blame_status($w) {Annotation complete.} -	} else { -		blame_incremental_status $w -	} -} - -proc blame_incremental_status {w} { -	global blame_status blame_data - -	set have  $blame_data($w,blame_lines) -	set total $blame_data($w,total_lines) -	set pdone 0 -	if {$total} {set pdone [expr {100 * $have / $total}]} - -	set blame_status($w) [format \ -		"Loading annotations... %i of %i lines annotated (%2i%%)" \ -		$have $total $pdone] -} - -proc blame_click {w w_cmit w_line w_file cur_w pos} { -	set lno [lindex [split [$cur_w index $pos] .] 0] -	if {$lno eq {}} return - -	$w_line tag remove in_sel 0.0 end -	$w_file tag remove in_sel 0.0 end -	$w_line tag add in_sel $lno.0 "$lno.0 + 1 line" -	$w_file tag add in_sel $lno.0 "$lno.0 + 1 line" - -	blame_showcommit $w $w_cmit $w_line $w_file $lno -} - -set blame_colors { -	#ff4040 -	#ff40ff -	#4040ff -} - -proc blame_showcommit {w w_cmit w_line w_file lno} { -	global blame_colors blame_data repo_config - -	set cmit $blame_data($w,highlight_commit) -	if {$cmit ne {}} { -		set idx $blame_data($w,$cmit,order) -		set i 0 -		foreach c $blame_colors { -			set h [lindex $blame_data($w,commit_list) [expr {$idx - 1 + $i}]] -			$w_line tag conf g$h -background white -			$w_file tag conf g$h -background white -			incr i -		} -	} - -	$w_cmit conf -state normal -	$w_cmit delete 0.0 end -	if {[catch {set cmit $blame_data($w,line$lno,commit)}]} { -		set cmit {} -		$w_cmit insert end "Loading annotation..." -	} else { -		set idx $blame_data($w,$cmit,order) -		set i 0 -		foreach c $blame_colors { -			set h [lindex $blame_data($w,commit_list) [expr {$idx - 1 + $i}]] -			$w_line tag conf g$h -background $c -			$w_file tag conf g$h -background $c -			incr i -		} - -		if {[catch {set msg $blame_data($w,$cmit,message)}]} { -			set msg {} -			catch { -				set fd [open "| git cat-file commit $cmit" r] -				fconfigure $fd -encoding binary -translation lf -				if {[catch {set enc $repo_config(i18n.commitencoding)}]} { -					set enc utf-8 -				} -				while {[gets $fd line] > 0} { -					if {[string match {encoding *} $line]} { -						set enc [string tolower [string range $line 9 end]] -					} -				} -				fconfigure $fd -encoding $enc -				set msg [string trim [read $fd]] -				close $fd -			} -			set blame_data($w,$cmit,message) $msg -		} - -		set author_name {} -		set author_email {} -		set author_time {} -		catch {set author_name $blame_data($w,$cmit,author)} -		catch {set author_email $blame_data($w,$cmit,author-mail)} -		catch {set author_time [clock format $blame_data($w,$cmit,author-time)]} - -		set committer_name {} -		set committer_email {} -		set committer_time {} -		catch {set committer_name $blame_data($w,$cmit,committer)} -		catch {set committer_email $blame_data($w,$cmit,committer-mail)} -		catch {set committer_time [clock format $blame_data($w,$cmit,committer-time)]} - -		$w_cmit insert end "commit $cmit\n" -		$w_cmit insert end "Author: $author_name $author_email $author_time\n" -		$w_cmit insert end "Committer: $committer_name $committer_email $committer_time\n" -		$w_cmit insert end "Original File: [escape_path $blame_data($w,line$lno,file)]\n" -		$w_cmit insert end "\n" -		$w_cmit insert end $msg -	} -	$w_cmit conf -state disabled - -	set blame_data($w,highlight_line) $lno -	set blame_data($w,highlight_commit) $cmit -} - -proc blame_copycommit {w i pos} { -	global blame_data -	set lno [lindex [split [$i index $pos] .] 0] -	if {![catch {set commit $blame_data($w,line$lno,commit)}]} { -		clipboard clear -		clipboard append \ -			-format STRING \ -			-type STRING \ -			-- $commit -	} -} -  ######################################################################  ##  ## icons @@ -3895,233 +973,6 @@ proc incr_font_size {font {amt 1}} {  	font configure ${font}bold -size $sz  } -proc hook_failed_popup {hook msg} { -	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 <Visibility> "grab $w; focus $w" -	bind $w <Key-Return> "destroy $w" -	wm title $w "[appname] ([reponame]): 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 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 "focus $w.m.t;$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 <Visibility> "focus $w" -	wm title $w "[appname] ([reponame]): [lindex $console_data($w) 0]" -	return $w -} - -proc console_exec {w cmd after} { -	# -- Cygwin's Tcl tosses the enviroment when we exec our child. -	#    But most users need that so we have to relogin. :-( -	# -	if {[is_Cygwin]} { -		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 - -	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}]} { -			set ok 0 -		} else { -			set ok 1 -		} -		uplevel #0 $after $w $ok -		return -	} -	fconfigure $fd -blocking 0 -} - -proc console_chain {cmdlist w {ok 1}} { -	if {$ok} { -		if {[llength $cmdlist] == 0} { -			console_done $w $ok -			return -		} - -		set cmd [lindex $cmdlist 0] -		set cmdlist [lrange $cmdlist 1 end] - -		if {[lindex $cmd 0] eq {console_exec}} { -			console_exec $w \ -				[lindex $cmd 1] \ -				[list console_chain $cmdlist] -		} else { -			uplevel #0 $cmd $cmdlist $w $ok -		} -	} else { -		console_done $w $ok -	} -} - -proc console_done {args} { -	global console_cr console_data - -	switch -- [llength $args] { -	2 { -		set w [lindex $args 0] -		set ok [lindex $args 1] -	} -	3 { -		set w [lindex $args 1] -		set ok [lindex $args 2] -	} -	default { -		error "wrong number of args: console_done ?ignored? w ok" -	} -	} - -	if {$ok} { -		if {[winfo exists $w]} { -			$w.m.s conf -background green -text {Success} -			$w.ok conf -state normal -		} -	} else { -		if {![winfo exists $w]} { -			console_init $w -		} -		$w.m.s conf -background red -text {Error: Command Failed} -		$w.ok conf -state normal -	} - -	array unset console_cr $w -	array unset console_data $w -} -  ######################################################################  ##  ## ui commands @@ -4153,94 +1004,6 @@ proc do_gitk {revs} {  	}  } -proc do_stats {} { -	set fd [open "| git count-objects -v" r] -	while {[gets $fd line] > 0} { -		if {[regexp {^([^:]+): (\d+)$} $line _ name value]} { -			set stats($name) $value -		} -	} -	close $fd - -	set packed_sz 0 -	foreach p [glob -directory [gitdir objects pack] \ -		-type f \ -		-nocomplain -- *] { -		incr packed_sz [file size $p] -	} -	if {$packed_sz > 0} { -		set stats(size-pack) [expr {$packed_sz / 1024}] -	} - -	set w .stats_view -	toplevel $w -	wm geometry $w "+[winfo rootx .]+[winfo rooty .]" - -	label $w.header -text {Database Statistics} \ -		-font font_uibold -	pack $w.header -side top -fill x - -	frame $w.buttons -border 1 -	button $w.buttons.close -text Close \ -		-font font_ui \ -		-command [list destroy $w] -	button $w.buttons.gc -text {Compress Database} \ -		-font font_ui \ -		-command "destroy $w;do_gc" -	pack $w.buttons.close -side right -	pack $w.buttons.gc -side left -	pack $w.buttons -side bottom -fill x -pady 10 -padx 10 - -	frame $w.stat -borderwidth 1 -relief solid -	foreach s { -		{count           {Number of loose objects}} -		{size            {Disk space used by loose objects} { KiB}} -		{in-pack         {Number of packed objects}} -		{packs           {Number of packs}} -		{size-pack       {Disk space used by packed objects} { KiB}} -		{prune-packable  {Packed objects waiting for pruning}} -		{garbage         {Garbage files}} -		} { -		set name [lindex $s 0] -		set label [lindex $s 1] -		if {[catch {set value $stats($name)}]} continue -		if {[llength $s] > 2} { -			set value "$value[lindex $s 2]" -		} - -		label $w.stat.l_$name -text "$label:" -anchor w -font font_ui -		label $w.stat.v_$name -text $value -anchor w -font font_ui -		grid $w.stat.l_$name $w.stat.v_$name -sticky we -padx {0 5} -	} -	pack $w.stat -pady 10 -padx 10 - -	bind $w <Visibility> "grab $w; focus $w" -	bind $w <Key-Escape> [list destroy $w] -	bind $w <Key-Return> [list destroy $w] -	wm title $w "[appname] ([reponame]): Database Statistics" -	tkwait window $w -} - -proc do_gc {} { -	set w [new_console {gc} {Compressing the object database}] -	console_chain { -		{console_exec {git pack-refs --prune}} -		{console_exec {git reflog expire --all}} -		{console_exec {git repack -a -d -l}} -		{console_exec {git rerere gc}} -	} $w -} - -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 console_done -} -  set is_quitting 0  proc do_quit {} { @@ -4288,598 +1051,10 @@ proc do_rescan {} {  	rescan {set ui_status_value {Ready.}}  } -proc unstage_helper {txt paths} { -	global file_states current_diff_path - -	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_path} { -				set after {reshow_diff;} -			} -		} -		} -	} -	if {$pathList eq {}} { -		unlock_index -	} else { -		update_indexinfo \ -			$txt \ -			$pathList \ -			[concat $after {set ui_status_value {Ready.}}] -	} -} - -proc do_unstage_selection {} { -	global current_diff_path selected_paths - -	if {[array size selected_paths] > 0} { -		unstage_helper \ -			{Unstaging selected files from commit} \ -			[array names selected_paths] -	} elseif {$current_diff_path ne {}} { -		unstage_helper \ -			"Unstaging [short_path $current_diff_path] from commit" \ -			[list $current_diff_path] -	} -} - -proc add_helper {txt paths} { -	global file_states current_diff_path - -	if {![lock_index begin-update]} return - -	set pathList [list] -	set after {} -	foreach path $paths { -		switch -glob -- [lindex $file_states($path) 0] { -		_O - -		?M - -		?D - -		U? { -			lappend pathList $path -			if {$path eq $current_diff_path} { -				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_add_selection {} { -	global current_diff_path selected_paths - -	if {[array size selected_paths] > 0} { -		add_helper \ -			{Adding selected files} \ -			[array names selected_paths] -	} elseif {$current_diff_path ne {}} { -		add_helper \ -			"Adding [short_path $current_diff_path]" \ -			[list $current_diff_path] -	} -} - -proc do_add_all {} { -	global file_states - -	set paths [list] -	foreach path [array names file_states] { -		switch -glob -- [lindex $file_states($path) 0] { -		U? {continue} -		?M - -		?D {lappend paths $path} -		} -	} -	add_helper {Adding all changed files} $paths -} - -proc revert_helper {txt paths} { -	global file_states current_diff_path - -	if {![lock_index begin-update]} return - -	set pathList [list] -	set after {} -	foreach path $paths { -		switch -glob -- [lindex $file_states($path) 0] { -		U? {continue} -		?M - -		?D { -			lappend pathList $path -			if {$path eq $current_diff_path} { -				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 \ -		"[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_path selected_paths - -	if {[array size selected_paths] > 0} { -		revert_helper \ -			{Reverting selected files} \ -			[array names selected_paths] -	} elseif {$current_diff_path ne {}} { -		revert_helper \ -			"Reverting [short_path $current_diff_path]" \ -			[list $current_diff_path] -	} -} - -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 appvers 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 "git-gui - a graphical user interface 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 {} -	append v "git-gui version $appvers\n" -	append v "[git version]\n" -	append v "\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 - -	menu $w.ctxm -tearoff 0 -	$w.ctxm add command \ -		-label {Copy} \ -		-font font_ui \ -		-command " -		clipboard clear -		clipboard append -format STRING -type STRING -- \[$w.vers cget -text\] -	" - -	bind $w <Visibility> "grab $w; focus $w" -	bind $w <Key-Escape> "destroy $w" -	bind_button3 $w.vers "tk_popup $w.ctxm %X %Y; grab $w; focus $w" -	wm title $w "About [appname]" -	tkwait window $w -} - -proc do_options {} { -	global repo_config global_config font_descs -	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 w .options_editor -	toplevel $w -	wm geometry $w "+[winfo rootx .]+[winfo rooty .]" - -	label $w.header -text "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 -padx 5 -	pack $w.buttons -side bottom -fill x -pady 10 -padx 10 - -	labelframe $w.repo -text "[reponame] Repository" \ -		-font font_ui -	labelframe $w.global -text {Global (All Repositories)} \ -		-font font_ui -	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 - -	set optid 0 -	foreach option { -		{t user.name {User Name}} -		{t user.email {Email Address}} - -		{b merge.summary {Summarize Merge Commits}} -		{i-1..5 merge.verbosity {Merge Verbosity}} - -		{b gui.trustmtime  {Trust File Modification Timestamps}} -		{i-1..99 gui.diffcontext {Number of Diff Context Lines}} -		{t gui.newbranchtemplate {New Branch Name Template}} -		} { -		set type [lindex $option 0] -		set name [lindex $option 1] -		set text [lindex $option 2] -		incr optid -		foreach f {repo global} { -			switch -glob -- $type { -			b { -				checkbutton $w.$f.$optid -text $text \ -					-variable ${f}_config_new($name) \ -					-onvalue true \ -					-offvalue false \ -					-font font_ui -				pack $w.$f.$optid -side top -anchor w -			} -			i-* { -				regexp -- {-(\d+)\.\.(\d+)$} $type _junk min max -				frame $w.$f.$optid -				label $w.$f.$optid.l -text "$text:" -font font_ui -				pack $w.$f.$optid.l -side left -anchor w -fill x -				spinbox $w.$f.$optid.v \ -					-textvariable ${f}_config_new($name) \ -					-from $min \ -					-to $max \ -					-increment 1 \ -					-width [expr {1 + [string length $max]}] \ -					-font font_ui -				bind $w.$f.$optid.v <FocusIn> {%W selection range 0 end} -				pack $w.$f.$optid.v -side right -anchor e -padx 5 -				pack $w.$f.$optid -side top -anchor w -fill x -			} -			t { -				frame $w.$f.$optid -				label $w.$f.$optid.l -text "$text:" -font font_ui -				entry $w.$f.$optid.v \ -					-borderwidth 1 \ -					-relief sunken \ -					-width 20 \ -					-textvariable ${f}_config_new($name) \ -					-font font_ui -				pack $w.$f.$optid.l -side left -anchor w -				pack $w.$f.$optid.v -side left -anchor w \ -					-fill x -expand 1 \ -					-padx 5 -				pack $w.$f.$optid -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 -		bind $w.global.$name.size <FocusIn> {%W selection range 0 end} -		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 <Visibility> "grab $w; focus $w" -	bind $w <Key-Escape> "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 argv0 - -	set fn [tk_getSaveFile \ -		-parent . \ -		-title "[appname] ([reponame]): Create Desktop Icon" \ -		-initialfile "Git [reponame].bat"] -	if {$fn != {}} { -		if {[catch { -				set fd [open $fn w] -				puts $fd "@ECHO Entering [reponame]" -				puts $fd "@ECHO Starting git-gui... please wait..." -				puts $fd "@SET PATH=[file normalize [gitexec]];%PATH%" -				puts $fd "@SET GIT_DIR=[file normalize [gitdir]]" -				puts -nonewline $fd "@\"[info nameofexecutable]\"" -				puts $fd " \"[file normalize $argv0]\"" -				close $fd -			} err]} { -			error_popup "Cannot write script:\n\n$err" -		} -	} -} - -proc do_cygwin_shortcut {} { -	global argv0 - -	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]] -				set gw [exec cygpath \ -					--windows \ -					--absolute \ -					[file dirname [gitdir]]] -				regsub -all ' $me "'\\''" me -				regsub -all ' $gd "'\\''" gd -				puts $fd "@ECHO Entering $gw" -				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 argv0 env - -	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 {<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> -<plist version="1.0"> -<dict> -	<key>CFBundleDevelopmentRegion</key> -	<string>English</string> -	<key>CFBundleExecutable</key> -	<string>git-gui</string> -	<key>CFBundleIdentifier</key> -	<string>org.spearce.git-gui</string> -	<key>CFBundleInfoDictionaryVersion</key> -	<string>6.0</string> -	<key>CFBundlePackageType</key> -	<string>APPL</string> -	<key>CFBundleSignature</key> -	<string>????</string> -	<key>CFBundleVersion</key> -	<string>1.0</string> -	<key>NSPrincipalClass</key> -	<string>NSApplication</string> -</dict> -</plist>} -				close $fd - -				set fd [open $exe w] -				set gd [file normalize [gitdir]] -				set ep [file normalize [gitexec]] -				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_path ui_index ui_workdir  	global last_clicked selected_paths @@ -4991,6 +1166,13 @@ catch {  font create font_uibold  font create font_diffbold +foreach class {Button Checkbutton Entry Label +		Labelframe Listbox Menu Message +		Radiobutton Text} { +	option add *$class.font font_ui +} +unset class +  if {[is_Windows]} {  	set M1B Control  	set M1T Ctrl @@ -5106,93 +1288,76 @@ menu .mbar.repository  .mbar.repository add command \  	-label {Browse Current Branch} \ -	-command {new_browser $current_branch} \ -	-font font_ui +	-command {new_browser $current_branch}  trace add variable current_branch write ".mbar.repository entryconf [.mbar.repository index last] -label \"Browse \$current_branch\" ;#"  .mbar.repository add separator  .mbar.repository add command \  	-label {Visualize Current Branch} \ -	-command {do_gitk $current_branch} \ -	-font font_ui +	-command {do_gitk $current_branch}  trace add variable current_branch write ".mbar.repository entryconf [.mbar.repository index last] -label \"Visualize \$current_branch\" ;#"  .mbar.repository add command \  	-label {Visualize All Branches} \ -	-command {do_gitk --all} \ -	-font font_ui +	-command {do_gitk --all}  .mbar.repository add separator  if {[is_enabled multicommit]} {  	.mbar.repository add command -label {Database Statistics} \ -		-command do_stats \ -		-font font_ui +		-command do_stats  	.mbar.repository add command -label {Compress Database} \ -		-command do_gc \ -		-font font_ui +		-command do_gc  	.mbar.repository add command -label {Verify Database} \ -		-command do_fsck_objects \ -		-font font_ui +		-command do_fsck_objects  	.mbar.repository add separator  	if {[is_Cygwin]} {  		.mbar.repository add command \  			-label {Create Desktop Icon} \ -			-command do_cygwin_shortcut \ -			-font font_ui +			-command do_cygwin_shortcut  	} elseif {[is_Windows]} {  		.mbar.repository add command \  			-label {Create Desktop Icon} \ -			-command do_windows_shortcut \ -			-font font_ui +			-command do_windows_shortcut  	} elseif {[is_MacOSX]} {  		.mbar.repository add command \  			-label {Create Desktop Icon} \ -			-command do_macosx_app \ -			-font font_ui +			-command do_macosx_app  	}  }  .mbar.repository add command -label Quit \  	-command do_quit \ -	-accelerator $M1T-Q \ -	-font font_ui +	-accelerator $M1T-Q  # -- Edit Menu  #  menu .mbar.edit  .mbar.edit add command -label Undo \  	-command {catch {[focus] edit undo}} \ -	-accelerator $M1T-Z \ -	-font font_ui +	-accelerator $M1T-Z  .mbar.edit add command -label Redo \  	-command {catch {[focus] edit redo}} \ -	-accelerator $M1T-Y \ -	-font font_ui +	-accelerator $M1T-Y  .mbar.edit add separator  .mbar.edit add command -label Cut \  	-command {catch {tk_textCut [focus]}} \ -	-accelerator $M1T-X \ -	-font font_ui +	-accelerator $M1T-X  .mbar.edit add command -label Copy \  	-command {catch {tk_textCopy [focus]}} \ -	-accelerator $M1T-C \ -	-font font_ui +	-accelerator $M1T-C  .mbar.edit add command -label Paste \  	-command {catch {tk_textPaste [focus]; [focus] see insert}} \ -	-accelerator $M1T-V \ -	-font font_ui +	-accelerator $M1T-V  .mbar.edit add command -label Delete \  	-command {catch {[focus] delete sel.first sel.last}} \ -	-accelerator Del \ -	-font font_ui +	-accelerator Del  .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 +	-accelerator $M1T-A  # -- Branch Menu  # @@ -5201,20 +1366,17 @@ if {[is_enabled branch]} {  	.mbar.branch add command -label {Create...} \  		-command do_create_branch \ -		-accelerator $M1T-N \ -		-font font_ui +		-accelerator $M1T-N  	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 +		-command do_delete_branch  	lappend disable_on_lock [list .mbar.branch entryconf \  		[.mbar.branch index last] -state]  	.mbar.branch add command -label {Reset...} \ -		-command do_reset_hard \ -		-font font_ui +		-command merge::reset_hard  	lappend disable_on_lock [list .mbar.branch entryconf \  		[.mbar.branch index last] -state]  } @@ -5228,8 +1390,7 @@ if {[is_enabled multicommit] || [is_enabled singlecommit]} {  		-label {New Commit} \  		-command do_select_commit_type \  		-variable selected_commit_type \ -		-value new \ -		-font font_ui +		-value new  	lappend disable_on_lock \  		[list .mbar.commit entryconf [.mbar.commit index last] -state] @@ -5237,8 +1398,7 @@ if {[is_enabled multicommit] || [is_enabled singlecommit]} {  		-label {Amend Last Commit} \  		-command do_select_commit_type \  		-variable selected_commit_type \ -		-value amend \ -		-font font_ui +		-value amend  	lappend disable_on_lock \  		[list .mbar.commit entryconf [.mbar.commit index last] -state] @@ -5246,33 +1406,28 @@ if {[is_enabled multicommit] || [is_enabled singlecommit]} {  	.mbar.commit add command -label Rescan \  		-command do_rescan \ -		-accelerator F5 \ -		-font font_ui +		-accelerator F5  	lappend disable_on_lock \  		[list .mbar.commit entryconf [.mbar.commit index last] -state]  	.mbar.commit add command -label {Add To Commit} \ -		-command do_add_selection \ -		-font font_ui +		-command do_add_selection  	lappend disable_on_lock \  		[list .mbar.commit entryconf [.mbar.commit index last] -state]  	.mbar.commit add command -label {Add Existing To Commit} \  		-command do_add_all \ -		-accelerator $M1T-I \ -		-font font_ui +		-accelerator $M1T-I  	lappend disable_on_lock \  		[list .mbar.commit entryconf [.mbar.commit index last] -state]  	.mbar.commit add command -label {Unstage From Commit} \ -		-command do_unstage_selection \ -		-font font_ui +		-command do_unstage_selection  	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 +		-command do_revert_selection  	lappend disable_on_lock \  		[list .mbar.commit entryconf [.mbar.commit index last] -state] @@ -5280,13 +1435,11 @@ if {[is_enabled multicommit] || [is_enabled singlecommit]} {  	.mbar.commit add command -label {Sign Off} \  		-command do_signoff \ -		-accelerator $M1T-S \ -		-font font_ui +		-accelerator $M1T-S  	.mbar.commit add command -label Commit \  		-command do_commit \ -		-accelerator $M1T-Return \ -		-font font_ui +		-accelerator $M1T-Return  	lappend disable_on_lock \  		[list .mbar.commit entryconf [.mbar.commit index last] -state]  } @@ -5296,13 +1449,11 @@ if {[is_enabled multicommit] || [is_enabled singlecommit]} {  if {[is_enabled branch]} {  	menu .mbar.merge  	.mbar.merge add command -label {Local Merge...} \ -		-command do_local_merge \ -		-font font_ui +		-command merge::dialog  	lappend disable_on_lock \  		[list .mbar.merge entryconf [.mbar.merge index last] -state]  	.mbar.merge add command -label {Abort Merge...} \ -		-command do_reset_hard \ -		-font font_ui +		-command merge::reset_hard  	lappend disable_on_lock \  		[list .mbar.merge entryconf [.mbar.merge index last] -state] @@ -5315,8 +1466,7 @@ if {[is_enabled transport]} {  	menu .mbar.push  	.mbar.push add command -label {Push...} \ -		-command do_push_anywhere \ -		-font font_ui +		-command do_push_anywhere  }  if {[is_MacOSX]} { @@ -5326,18 +1476,15 @@ if {[is_MacOSX]} {  	menu .mbar.apple  	.mbar.apple add command -label "About [appname]" \ -		-command do_about \ -		-font font_ui +		-command do_about  	.mbar.apple add command -label "Options..." \ -		-command do_options \ -		-font font_ui +		-command do_options  } else {  	# -- Edit Menu  	#  	.mbar.edit add separator  	.mbar.edit add command -label {Options...} \ -		-command do_options \ -		-font font_ui +		-command do_options  	# -- Tools Menu  	# @@ -5363,8 +1510,7 @@ if {[is_MacOSX]} {  	.mbar add cascade -label Tools -menu .mbar.tools  	menu .mbar.tools  	.mbar.tools add command -label "Migrate" \ -		-command do_miga \ -		-font font_ui +		-command do_miga  	lappend disable_on_lock \  		[list .mbar.tools entryconf [.mbar.tools index last] -state]  	} @@ -5377,8 +1523,7 @@ menu .mbar.help  if {![is_MacOSX]} {  	.mbar.help add command -label "About [appname]" \ -		-command do_about \ -		-font font_ui +		-command do_about  }  set browser {} @@ -5415,8 +1560,7 @@ if {[file isfile $doc_path]} {  if {$browser ne {}} {  	.mbar.help add command -label {Online Documentation} \ -		-command [list exec $browser $doc_url &] \ -		-font font_ui +		-command [list exec $browser $doc_url &]  }  unset browser doc_path doc_url @@ -5475,13 +1619,11 @@ frame .branch \  label .branch.l1 \  	-text {Current Branch:} \  	-anchor w \ -	-justify left \ -	-font font_ui +	-justify left  label .branch.cb \  	-textvariable current_branch \  	-anchor w \ -	-justify left \ -	-font font_ui +	-justify left  pack .branch.l1 -side left  pack .branch.cb -side left -fill x  pack .branch -side top -fill x @@ -5497,12 +1639,10 @@ pack .vpane -anchor n -side top -fill both -expand 1  #  frame .vpane.files.index -height 100 -width 200  label .vpane.files.index.title -text {Changes To Be Committed} \ -	-background green \ -	-font font_ui +	-background green  text $ui_index -background white -borderwidth 0 \  	-width 20 -height 10 \  	-wrap none \ -	-font font_ui \  	-cursor $cursor_ptr \  	-xscrollcommand {.vpane.files.index.sx set} \  	-yscrollcommand {.vpane.files.index.sy set} \ @@ -5519,12 +1659,10 @@ pack $ui_index -side left -fill both -expand 1  #  frame .vpane.files.workdir -height 100 -width 200  label .vpane.files.workdir.title -text {Changed But Not Updated} \ -	-background red \ -	-font font_ui +	-background red  text $ui_workdir -background white -borderwidth 0 \  	-width 20 -height 10 \  	-wrap none \ -	-font font_ui \  	-cursor $cursor_ptr \  	-xscrollcommand {.vpane.files.workdir.sx set} \  	-yscrollcommand {.vpane.files.workdir.sy set} \ @@ -5559,33 +1697,28 @@ pack .vpane.lower.diff -side bottom -fill both -expand 1  frame .vpane.lower.commarea.buttons  label .vpane.lower.commarea.buttons.l -text {} \  	-anchor w \ -	-justify left \ -	-font font_ui +	-justify left  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 +	-command do_rescan  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 Existing} \ -	-command do_add_all \ -	-font font_ui +	-command do_add_all  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 +	-command do_signoff  pack .vpane.lower.commarea.buttons.signoff -side top -fill x  button .vpane.lower.commarea.buttons.commit -text {Commit} \ -	-command do_commit \ -	-font font_ui +	-command do_commit  pack .vpane.lower.commarea.buttons.commit -side top -fill x  lappend disable_on_lock \  	{.vpane.lower.commarea.buttons.commit conf -state} @@ -5600,22 +1733,19 @@ radiobutton .vpane.lower.commarea.buffer.header.new \  	-text {New Commit} \  	-command do_select_commit_type \  	-variable selected_commit_type \ -	-value new \ -	-font font_ui +	-value new  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 +	-value amend  lappend disable_on_lock \  	[list .vpane.lower.commarea.buffer.header.amend conf -state]  label $ui_coml \  	-anchor w \ -	-justify left \ -	-font font_ui +	-justify left  proc trace_commit_type {varname args} {  	global ui_coml commit_type  	switch -glob -- $commit_type { @@ -5654,28 +1784,22 @@ 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 {focus $ui_comm;$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 @@ -5684,7 +1808,6 @@ $ctxm add command \  $ctxm add separator  $ctxm add command \  	-label {Sign Off} \ -	-font font_ui \  	-command do_signoff  bind_button3 $ui_comm "tk_popup $ctxm %X %Y" @@ -5719,18 +1842,15 @@ label .vpane.lower.diff.header.status \  	-background orange \  	-width $max_status_desc \  	-anchor w \ -	-justify left \ -	-font font_ui +	-justify left  label .vpane.lower.diff.header.file \  	-background orange \  	-anchor w \ -	-justify left \ -	-font font_ui +	-justify left  label .vpane.lower.diff.header.path \  	-background orange \  	-anchor w \ -	-justify left \ -	-font font_ui +	-justify left  pack .vpane.lower.diff.header.status -side left  pack .vpane.lower.diff.header.file -side left  pack .vpane.lower.diff.header.path -fill x @@ -5738,7 +1858,6 @@ set ctxm .vpane.lower.diff.header.ctxm  menu $ctxm -tearoff 0  $ctxm add command \  	-label {Copy} \ -	-font font_ui \  	-command {  		clipboard clear  		clipboard append \ @@ -5807,22 +1926,18 @@ set ctxm .vpane.lower.diff.body.ctxm  menu $ctxm -tearoff 0  $ctxm add command \  	-label {Refresh} \ -	-font font_ui \  	-command reshow_diff  lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]  $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 {focus $ui_diff;$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 @@ -5832,25 +1947,21 @@ lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]  $ctxm add separator  $ctxm add command \  	-label {Apply/Reverse Hunk} \ -	-font font_ui \  	-command {apply_hunk $cursorX $cursorY}  set ui_diff_applyhunk [$ctxm index last]  lappend diff_actions [list $ctxm entryconf $ui_diff_applyhunk -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 @@ -5858,7 +1969,6 @@ $ctxm add command \  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 @@ -5866,7 +1976,6 @@ $ctxm add command \  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 "  	set cursorX %x @@ -5886,8 +1995,7 @@ label .status -textvariable ui_status_value \  	-anchor w \  	-justify left \  	-borderwidth 1 \ -	-relief sunken \ -	-font font_ui +	-relief sunken  pack .status -anchor w -side bottom -fill x  # -- Load geometry @@ -5930,6 +2038,12 @@ bind $ui_diff <Key-Up>     {catch {%W yview scroll -1 units};break}  bind $ui_diff <Key-Down>   {catch {%W yview scroll  1 units};break}  bind $ui_diff <Key-Left>   {catch {%W xview scroll -1 units};break}  bind $ui_diff <Key-Right>  {catch {%W xview scroll  1 units};break} +bind $ui_diff <Key-k>         {catch {%W yview scroll -1 units};break} +bind $ui_diff <Key-j>         {catch {%W yview scroll  1 units};break} +bind $ui_diff <Key-h>         {catch {%W xview scroll -1 units};break} +bind $ui_diff <Key-l>         {catch {%W xview scroll  1 units};break} +bind $ui_diff <Control-Key-b> {catch {%W yview scroll -1 pages};break} +bind $ui_diff <Control-Key-f> {catch {%W yview scroll  1 pages};break}  bind $ui_diff <Button-1>   {focus %W}  if {[is_enabled branch]} { @@ -5955,7 +2069,7 @@ unset i  set file_lists($ui_index) [list]  set file_lists($ui_workdir) [list] -wm title . "[appname] ([file normalize [file dirname [gitdir]]])" +wm title . "[appname] ([reponame]) [file normalize [file dirname [gitdir]]]"  focus -force $ui_comm  # -- Warn the user about environmental problems.  Cygwin's Tcl @@ -6034,9 +2148,7 @@ if {[is_enabled multicommit]} {  		if {[ask_popup \  			"This repository currently has $objects_current loose objects. -To maintain optimal performance it is strongly -recommended that you compress the database -when more than $object_limit loose objects exist. +To maintain optimal performance it is strongly recommended that you compress the database when more than $object_limit loose objects exist.  Compress the database now?"] eq yes} {  			do_gc | 
