Merge branch 'master' of git://repo.or.cz/git-gui
* 'master' of git://repo.or.cz/git-gui: (50 commits) git-gui: Minor refactoring of merge command line in merge support git-gui: Use more modern looking icons in the tree browser git-gui: Don't offer to stage hunks from untracked files git-gui: Make sure remotes are loaded when picking revisions git-gui: Use progress bar while resetting/aborting files git-gui: Honor core.excludesfile when listing extra files git-gui: Unify wording to say "to stage" instead of "to add" git-gui: Don't kill modified commit message buffer with merge templates git-gui: Remove usernames from absolute SSH urls during merging git-gui: Format tracking branch merges as though they were pulls git-gui: Cleanup bindings within merge dialog git-gui: Replace merge dialog with our revision picker widget git-gui: Show ref last update times in revision chooser tooltips git-gui: Display commit/tag/remote info in tooltip of revision picker git-gui: Save remote urls obtained from config/remotes setup git-gui: Avoid unnecessary symbolic-ref call during checkout git-gui: Refactor current branch menu items to make i18n easier git-gui: Refactor diff popup into a procedure to ease i18n work git-gui: Paper bag fix quitting crash after commit git-gui: Clarify meaning of add tracked menu option ...maint
						commit
						b8de7f764e
					
				|  | @ -154,12 +154,10 @@ proc gitexec {args} { | ||||||
| } | } | ||||||
|  |  | ||||||
| proc reponame {} { | proc reponame {} { | ||||||
| 	global _reponame | 	return $::_reponame | ||||||
| 	return $_reponame |  | ||||||
| } | } | ||||||
|  |  | ||||||
| proc is_MacOSX {} { | proc is_MacOSX {} { | ||||||
| 	global tcl_platform tk_library |  | ||||||
| 	if {[tk windowingsystem] eq {aqua}} { | 	if {[tk windowingsystem] eq {aqua}} { | ||||||
| 		return 1 | 		return 1 | ||||||
| 	} | 	} | ||||||
|  | @ -167,17 +165,16 @@ proc is_MacOSX {} { | ||||||
| } | } | ||||||
|  |  | ||||||
| proc is_Windows {} { | proc is_Windows {} { | ||||||
| 	global tcl_platform | 	if {$::tcl_platform(platform) eq {windows}} { | ||||||
| 	if {$tcl_platform(platform) eq {windows}} { |  | ||||||
| 		return 1 | 		return 1 | ||||||
| 	} | 	} | ||||||
| 	return 0 | 	return 0 | ||||||
| } | } | ||||||
|  |  | ||||||
| proc is_Cygwin {} { | proc is_Cygwin {} { | ||||||
| 	global tcl_platform _iscygwin | 	global _iscygwin | ||||||
| 	if {$_iscygwin eq {}} { | 	if {$_iscygwin eq {}} { | ||||||
| 		if {$tcl_platform(platform) eq {windows}} { | 		if {$::tcl_platform(platform) eq {windows}} { | ||||||
| 			if {[catch {set p [exec cygpath --windir]} err]} { | 			if {[catch {set p [exec cygpath --windir]} err]} { | ||||||
| 				set _iscygwin 0 | 				set _iscygwin 0 | ||||||
| 			} else { | 			} else { | ||||||
|  | @ -367,16 +364,25 @@ proc _which {what} { | ||||||
| 	return {} | 	return {} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | proc _lappend_nice {cmd_var} { | ||||||
|  | 	global _nice | ||||||
|  | 	upvar $cmd_var cmd | ||||||
|  |  | ||||||
|  | 	if {![info exists _nice]} { | ||||||
|  | 		set _nice [_which nice] | ||||||
|  | 	} | ||||||
|  | 	if {$_nice ne {}} { | ||||||
|  | 		lappend cmd $_nice | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
| proc git {args} { | proc git {args} { | ||||||
| 	set opt [list exec] | 	set opt [list exec] | ||||||
|  |  | ||||||
| 	while {1} { | 	while {1} { | ||||||
| 		switch -- [lindex $args 0] { | 		switch -- [lindex $args 0] { | ||||||
| 		--nice { | 		--nice { | ||||||
| 			global _nice | 			_lappend_nice opt | ||||||
| 			if {$_nice ne {}} { |  | ||||||
| 				lappend opt $_nice |  | ||||||
| 			} |  | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		default { | 		default { | ||||||
|  | @ -414,6 +420,7 @@ proc _open_stdout_stderr {cmd} { | ||||||
| 			error $err | 			error $err | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | 	fconfigure $fd -eofchar {} | ||||||
| 	return $fd | 	return $fd | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -423,10 +430,7 @@ proc git_read {args} { | ||||||
| 	while {1} { | 	while {1} { | ||||||
| 		switch -- [lindex $args 0] { | 		switch -- [lindex $args 0] { | ||||||
| 		--nice { | 		--nice { | ||||||
| 			global _nice | 			_lappend_nice opt | ||||||
| 			if {$_nice ne {}} { |  | ||||||
| 				lappend opt $_nice |  | ||||||
| 			} |  | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		--stderr { | 		--stderr { | ||||||
|  | @ -454,10 +458,7 @@ proc git_write {args} { | ||||||
| 	while {1} { | 	while {1} { | ||||||
| 		switch -- [lindex $args 0] { | 		switch -- [lindex $args 0] { | ||||||
| 		--nice { | 		--nice { | ||||||
| 			global _nice | 			_lappend_nice opt | ||||||
| 			if {$_nice ne {}} { |  | ||||||
| 				lappend opt $_nice |  | ||||||
| 			} |  | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		default { | 		default { | ||||||
|  | @ -524,7 +525,6 @@ if {$_git eq {}} { | ||||||
| 	error_popup "Cannot find git in PATH." | 	error_popup "Cannot find git in PATH." | ||||||
| 	exit 1 | 	exit 1 | ||||||
| } | } | ||||||
| set _nice [_which nice] |  | ||||||
|  |  | ||||||
| ###################################################################### | ###################################################################### | ||||||
| ## | ## | ||||||
|  | @ -544,8 +544,34 @@ if {![regsub {^git version } $_git_version {} _git_version]} { | ||||||
| 	error_popup "Cannot parse Git version string:\n\n$_git_version" | 	error_popup "Cannot parse Git version string:\n\n$_git_version" | ||||||
| 	exit 1 | 	exit 1 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | set _real_git_version $_git_version | ||||||
|  | regsub -- {-dirty$} $_git_version {} _git_version | ||||||
| regsub {\.[0-9]+\.g[0-9a-f]+$} $_git_version {} _git_version | regsub {\.[0-9]+\.g[0-9a-f]+$} $_git_version {} _git_version | ||||||
| regsub {\.rc[0-9]+$} $_git_version {} _git_version | regsub {\.rc[0-9]+$} $_git_version {} _git_version | ||||||
|  | regsub {\.GIT$} $_git_version {} _git_version | ||||||
|  |  | ||||||
|  | if {![regexp {^[1-9]+(\.[0-9]+)+$} $_git_version]} { | ||||||
|  | 	catch {wm withdraw .} | ||||||
|  | 	if {[tk_messageBox \ | ||||||
|  | 		-icon warning \ | ||||||
|  | 		-type yesno \ | ||||||
|  | 		-default no \ | ||||||
|  | 		-title "[appname]: warning" \ | ||||||
|  | 		-message "Git version cannot be determined. | ||||||
|  |  | ||||||
|  | $_git claims it is version '$_real_git_version'. | ||||||
|  |  | ||||||
|  | [appname] requires at least Git 1.5.0 or later. | ||||||
|  |  | ||||||
|  | Assume '$_real_git_version' is version 1.5.0? | ||||||
|  | "] eq {yes}} { | ||||||
|  | 		set _git_version 1.5.0 | ||||||
|  | 	} else { | ||||||
|  | 		exit 1 | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | unset _real_git_version | ||||||
|  |  | ||||||
| proc git-version {args} { | proc git-version {args} { | ||||||
| 	global _git_version | 	global _git_version | ||||||
|  | @ -601,6 +627,46 @@ You are using [git-version]: | ||||||
| 	exit 1 | 	exit 1 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | ###################################################################### | ||||||
|  | ## | ||||||
|  | ## feature option selection | ||||||
|  |  | ||||||
|  | if {[regexp {^git-(.+)$} [appname] _junk subcommand]} { | ||||||
|  | 	unset _junk | ||||||
|  | } else { | ||||||
|  | 	set subcommand gui | ||||||
|  | } | ||||||
|  | if {$subcommand eq {gui.sh}} { | ||||||
|  | 	set subcommand gui | ||||||
|  | } | ||||||
|  | if {$subcommand eq {gui} && [llength $argv] > 0} { | ||||||
|  | 	set subcommand [lindex $argv 0] | ||||||
|  | 	set argv [lrange $argv 1 end] | ||||||
|  | } | ||||||
|  |  | ||||||
|  | enable_option multicommit | ||||||
|  | enable_option branch | ||||||
|  | enable_option transport | ||||||
|  | disable_option bare | ||||||
|  |  | ||||||
|  | switch -- $subcommand { | ||||||
|  | browser - | ||||||
|  | blame { | ||||||
|  | 	enable_option bare | ||||||
|  |  | ||||||
|  | 	disable_option multicommit | ||||||
|  | 	disable_option branch | ||||||
|  | 	disable_option transport | ||||||
|  | } | ||||||
|  | citool { | ||||||
|  | 	enable_option singlecommit | ||||||
|  |  | ||||||
|  | 	disable_option multicommit | ||||||
|  | 	disable_option branch | ||||||
|  | 	disable_option transport | ||||||
|  | } | ||||||
|  | } | ||||||
|  |  | ||||||
| ###################################################################### | ###################################################################### | ||||||
| ## | ## | ||||||
| ## repository setup | ## repository setup | ||||||
|  | @ -625,6 +691,7 @@ if {![file isdirectory $_gitdir]} { | ||||||
| 	error_popup "Git directory not found:\n\n$_gitdir" | 	error_popup "Git directory not found:\n\n$_gitdir" | ||||||
| 	exit 1 | 	exit 1 | ||||||
| } | } | ||||||
|  | if {![is_enabled bare]} { | ||||||
| 	if {[lindex [file split $_gitdir] end] ne {.git}} { | 	if {[lindex [file split $_gitdir] end] ne {.git}} { | ||||||
| 		catch {wm withdraw .} | 		catch {wm withdraw .} | ||||||
| 		error_popup "Cannot use funny .git directory:\n\n$_gitdir" | 		error_popup "Cannot use funny .git directory:\n\n$_gitdir" | ||||||
|  | @ -635,9 +702,13 @@ if {[catch {cd [file dirname $_gitdir]} err]} { | ||||||
| 		error_popup "No working directory [file dirname $_gitdir]:\n\n$err" | 		error_popup "No working directory [file dirname $_gitdir]:\n\n$err" | ||||||
| 		exit 1 | 		exit 1 | ||||||
| 	} | 	} | ||||||
| set _reponame [lindex [file split \ | } | ||||||
| 	[file normalize [file dirname $_gitdir]]] \ | set _reponame [file split [file normalize $_gitdir]] | ||||||
| 	end] | if {[lindex $_reponame end] eq {.git}} { | ||||||
|  | 	set _reponame [lindex $_reponame end-1] | ||||||
|  | } else { | ||||||
|  | 	set _reponame [lindex $_reponame end] | ||||||
|  | } | ||||||
|  |  | ||||||
| ###################################################################### | ###################################################################### | ||||||
| ## | ## | ||||||
|  | @ -758,8 +829,9 @@ proc rescan {after {honor_trustmtime 1}} { | ||||||
|  |  | ||||||
| 	array unset file_states | 	array unset file_states | ||||||
|  |  | ||||||
| 	if {![$ui_comm edit modified] | 	if {!$::GITGUI_BCK_exists && | ||||||
| 		|| [string trim [$ui_comm get 0.0 end]] eq {}} { | 		(![$ui_comm edit modified] | ||||||
|  | 		|| [string trim [$ui_comm get 0.0 end]] eq {})} { | ||||||
| 		if {[string match amend* $commit_type]} { | 		if {[string match amend* $commit_type]} { | ||||||
| 		} elseif {[load_message GITGUI_MSG]} { | 		} elseif {[load_message GITGUI_MSG]} { | ||||||
| 		} elseif {[load_message MERGE_MSG]} { | 		} elseif {[load_message MERGE_MSG]} { | ||||||
|  | @ -800,6 +872,10 @@ proc rescan_stage2 {fd after} { | ||||||
| 	if {[file readable $info_exclude]} { | 	if {[file readable $info_exclude]} { | ||||||
| 		lappend ls_others "--exclude-from=$info_exclude" | 		lappend ls_others "--exclude-from=$info_exclude" | ||||||
| 	} | 	} | ||||||
|  | 	set user_exclude [get_config core.excludesfile] | ||||||
|  | 	if {$user_exclude ne {} && [file readable $user_exclude]} { | ||||||
|  | 		lappend ls_others "--exclude-from=$user_exclude" | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	set buf_rdi {} | 	set buf_rdi {} | ||||||
| 	set buf_rdf {} | 	set buf_rdf {} | ||||||
|  | @ -827,6 +903,7 @@ proc load_message {file} { | ||||||
| 		if {[catch {set fd [open $f r]}]} { | 		if {[catch {set fd [open $f r]}]} { | ||||||
| 			return 0 | 			return 0 | ||||||
| 		} | 		} | ||||||
|  | 		fconfigure $fd -eofchar {} | ||||||
| 		set content [string trim [read $fd]] | 		set content [string trim [read $fd]] | ||||||
| 		close $fd | 		close $fd | ||||||
| 		regsub -all -line {[ \r\t]+$} $content {} content | 		regsub -all -line {[ \r\t]+$} $content {} content | ||||||
|  | @ -1219,32 +1296,6 @@ static unsigned char file_merge_bits[] = { | ||||||
|    0xfa, 0x17, 0x02, 0x10, 0xfe, 0x1f}; |    0xfa, 0x17, 0x02, 0x10, 0xfe, 0x1f}; | ||||||
| } -maskdata $filemask | } -maskdata $filemask | ||||||
|  |  | ||||||
| set file_dir_data { |  | ||||||
| #define file_width 18 |  | ||||||
| #define file_height 18 |  | ||||||
| static unsigned char file_bits[] = { |  | ||||||
|   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x03, 0x00, |  | ||||||
|   0x0c, 0x03, 0x00, 0x04, 0xfe, 0x00, 0x06, 0x80, 0x00, 0xff, 0x9f, 0x00, |  | ||||||
|   0x03, 0x98, 0x00, 0x02, 0x90, 0x00, 0x06, 0xb0, 0x00, 0x04, 0xa0, 0x00, |  | ||||||
|   0x0c, 0xe0, 0x00, 0x08, 0xc0, 0x00, 0xf8, 0xff, 0x00, 0x00, 0x00, 0x00, |  | ||||||
|   0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; |  | ||||||
| } |  | ||||||
| image create bitmap file_dir -background white -foreground blue \ |  | ||||||
| 	-data $file_dir_data -maskdata $file_dir_data |  | ||||||
| unset file_dir_data |  | ||||||
|  |  | ||||||
| set file_uplevel_data { |  | ||||||
| #define up_width 15 |  | ||||||
| #define up_height 15 |  | ||||||
| static unsigned char up_bits[] = { |  | ||||||
|   0x80, 0x00, 0xc0, 0x01, 0xe0, 0x03, 0xf0, 0x07, 0xf8, 0x0f, 0xfc, 0x1f, |  | ||||||
|   0xfe, 0x3f, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, |  | ||||||
|   0xc0, 0x01, 0xc0, 0x01, 0x00, 0x00}; |  | ||||||
| } |  | ||||||
| image create bitmap file_uplevel -background white -foreground red \ |  | ||||||
| 	-data $file_uplevel_data -maskdata $file_uplevel_data |  | ||||||
| unset file_uplevel_data |  | ||||||
|  |  | ||||||
| set ui_index .vpane.files.index.list | set ui_index .vpane.files.index.list | ||||||
| set ui_workdir .vpane.files.workdir.list | set ui_workdir .vpane.files.workdir.list | ||||||
|  |  | ||||||
|  | @ -1345,6 +1396,7 @@ set is_quitting 0 | ||||||
|  |  | ||||||
| proc do_quit {} { | proc do_quit {} { | ||||||
| 	global ui_comm is_quitting repo_config commit_type | 	global ui_comm is_quitting repo_config commit_type | ||||||
|  | 	global GITGUI_BCK_exists GITGUI_BCK_i | ||||||
|  |  | ||||||
| 	if {$is_quitting} return | 	if {$is_quitting} return | ||||||
| 	set is_quitting 1 | 	set is_quitting 1 | ||||||
|  | @ -1353,6 +1405,10 @@ proc do_quit {} { | ||||||
| 		# -- Stash our current commit buffer. | 		# -- Stash our current commit buffer. | ||||||
| 		# | 		# | ||||||
| 		set save [gitdir GITGUI_MSG] | 		set save [gitdir GITGUI_MSG] | ||||||
|  | 		if {$GITGUI_BCK_exists && ![$ui_comm edit modified]} { | ||||||
|  | 			file rename -force [gitdir GITGUI_BCK] $save | ||||||
|  | 			set GITGUI_BCK_exists 0 | ||||||
|  | 		} else { | ||||||
| 			set msg [string trim [$ui_comm get 0.0 end]] | 			set msg [string trim [$ui_comm get 0.0 end]] | ||||||
| 			regsub -all -line {[ \r\t]+$} $msg {} msg | 			regsub -all -line {[ \r\t]+$} $msg {} msg | ||||||
| 			if {(![string match amend* $commit_type] | 			if {(![string match amend* $commit_type] | ||||||
|  | @ -1366,6 +1422,14 @@ proc do_quit {} { | ||||||
| 			} else { | 			} else { | ||||||
| 				catch {file delete $save} | 				catch {file delete $save} | ||||||
| 			} | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		# -- Remove our editor backup, its not needed. | ||||||
|  | 		# | ||||||
|  | 		after cancel $GITGUI_BCK_i | ||||||
|  | 		if {$GITGUI_BCK_exists} { | ||||||
|  | 			catch {file delete [gitdir GITGUI_BCK]} | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		# -- Stash our current window geometry into this repository. | 		# -- Stash our current window geometry into this repository. | ||||||
| 		# | 		# | ||||||
|  | @ -1566,43 +1630,6 @@ set font_descs { | ||||||
| load_config 0 | load_config 0 | ||||||
| apply_config | apply_config | ||||||
|  |  | ||||||
| ###################################################################### |  | ||||||
| ## |  | ||||||
| ## feature option selection |  | ||||||
|  |  | ||||||
| if {[regexp {^git-(.+)$} [appname] _junk subcommand]} { |  | ||||||
| 	unset _junk |  | ||||||
| } else { |  | ||||||
| 	set subcommand gui |  | ||||||
| } |  | ||||||
| if {$subcommand eq {gui.sh}} { |  | ||||||
| 	set subcommand gui |  | ||||||
| } |  | ||||||
| if {$subcommand eq {gui} && [llength $argv] > 0} { |  | ||||||
| 	set subcommand [lindex $argv 0] |  | ||||||
| 	set argv [lrange $argv 1 end] |  | ||||||
| } |  | ||||||
|  |  | ||||||
| enable_option multicommit |  | ||||||
| enable_option branch |  | ||||||
| enable_option transport |  | ||||||
|  |  | ||||||
| switch -- $subcommand { |  | ||||||
| browser - |  | ||||||
| blame { |  | ||||||
| 	disable_option multicommit |  | ||||||
| 	disable_option branch |  | ||||||
| 	disable_option transport |  | ||||||
| } |  | ||||||
| citool { |  | ||||||
| 	enable_option singlecommit |  | ||||||
|  |  | ||||||
| 	disable_option multicommit |  | ||||||
| 	disable_option branch |  | ||||||
| 	disable_option transport |  | ||||||
| } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| ###################################################################### | ###################################################################### | ||||||
| ## | ## | ||||||
| ## ui construction | ## ui construction | ||||||
|  | @ -1632,20 +1659,32 @@ if {[is_enabled transport]} { | ||||||
| menu .mbar.repository | menu .mbar.repository | ||||||
|  |  | ||||||
| .mbar.repository add command \ | .mbar.repository add command \ | ||||||
| 	-label {Browse Current Branch} \ | 	-label {Browse Current Branch's Files} \ | ||||||
| 	-command {browser::new $current_branch} | 	-command {browser::new $current_branch} | ||||||
| trace add variable current_branch write ".mbar.repository entryconf [.mbar.repository index last] -label \"Browse \$current_branch\" ;#" | set ui_browse_current [.mbar.repository index last] | ||||||
|  | .mbar.repository add command \ | ||||||
|  | 	-label {Browse Branch Files...} \ | ||||||
|  | 	-command browser_open::dialog | ||||||
| .mbar.repository add separator | .mbar.repository add separator | ||||||
|  |  | ||||||
| .mbar.repository add command \ | .mbar.repository add command \ | ||||||
| 	-label {Visualize Current Branch} \ | 	-label {Visualize Current Branch's History} \ | ||||||
| 	-command {do_gitk $current_branch} | 	-command {do_gitk $current_branch} | ||||||
| trace add variable current_branch write ".mbar.repository entryconf [.mbar.repository index last] -label \"Visualize \$current_branch\" ;#" | set ui_visualize_current [.mbar.repository index last] | ||||||
| .mbar.repository add command \ | .mbar.repository add command \ | ||||||
| 	-label {Visualize All Branches} \ | 	-label {Visualize All Branch History} \ | ||||||
| 	-command {do_gitk --all} | 	-command {do_gitk --all} | ||||||
| .mbar.repository add separator | .mbar.repository add separator | ||||||
|  |  | ||||||
|  | proc current_branch_write {args} { | ||||||
|  | 	global current_branch | ||||||
|  | 	.mbar.repository entryconf $::ui_browse_current \ | ||||||
|  | 		-label "Browse $current_branch's Files" | ||||||
|  | 	.mbar.repository entryconf $::ui_visualize_current \ | ||||||
|  | 		-label "Visualize $current_branch's History" | ||||||
|  | } | ||||||
|  | trace add variable current_branch write current_branch_write | ||||||
|  |  | ||||||
| if {[is_enabled multicommit]} { | if {[is_enabled multicommit]} { | ||||||
| 	.mbar.repository add command -label {Database Statistics} \ | 	.mbar.repository add command -label {Database Statistics} \ | ||||||
| 		-command do_stats | 		-command do_stats | ||||||
|  | @ -1766,12 +1805,12 @@ if {[is_enabled multicommit] || [is_enabled singlecommit]} { | ||||||
| 	lappend disable_on_lock \ | 	lappend disable_on_lock \ | ||||||
| 		[list .mbar.commit entryconf [.mbar.commit index last] -state] | 		[list .mbar.commit entryconf [.mbar.commit index last] -state] | ||||||
|  |  | ||||||
| 	.mbar.commit add command -label {Add To Commit} \ | 	.mbar.commit add command -label {Stage To Commit} \ | ||||||
| 		-command do_add_selection | 		-command do_add_selection | ||||||
| 	lappend disable_on_lock \ | 	lappend disable_on_lock \ | ||||||
| 		[list .mbar.commit entryconf [.mbar.commit index last] -state] | 		[list .mbar.commit entryconf [.mbar.commit index last] -state] | ||||||
|  |  | ||||||
| 	.mbar.commit add command -label {Add Existing To Commit} \ | 	.mbar.commit add command -label {Stage Changed Files To Commit} \ | ||||||
| 		-command do_add_all \ | 		-command do_add_all \ | ||||||
| 		-accelerator $M1T-I | 		-accelerator $M1T-I | ||||||
| 	lappend disable_on_lock \ | 	lappend disable_on_lock \ | ||||||
|  | @ -1805,14 +1844,14 @@ if {[is_enabled multicommit] || [is_enabled singlecommit]} { | ||||||
| if {[is_enabled branch]} { | if {[is_enabled branch]} { | ||||||
| 	menu .mbar.merge | 	menu .mbar.merge | ||||||
| 	.mbar.merge add command -label {Local Merge...} \ | 	.mbar.merge add command -label {Local Merge...} \ | ||||||
| 		-command merge::dialog | 		-command merge::dialog \ | ||||||
|  | 		-accelerator $M1T-M | ||||||
| 	lappend disable_on_lock \ | 	lappend disable_on_lock \ | ||||||
| 		[list .mbar.merge entryconf [.mbar.merge index last] -state] | 		[list .mbar.merge entryconf [.mbar.merge index last] -state] | ||||||
| 	.mbar.merge add command -label {Abort Merge...} \ | 	.mbar.merge add command -label {Abort Merge...} \ | ||||||
| 		-command merge::reset_hard | 		-command merge::reset_hard | ||||||
| 	lappend disable_on_lock \ | 	lappend disable_on_lock \ | ||||||
| 		[list .mbar.merge entryconf [.mbar.merge index last] -state] | 		[list .mbar.merge entryconf [.mbar.merge index last] -state] | ||||||
|  |  | ||||||
| } | } | ||||||
|  |  | ||||||
| # -- Transport Menu | # -- Transport Menu | ||||||
|  | @ -1844,33 +1883,6 @@ if {[is_MacOSX]} { | ||||||
| 	.mbar.edit add separator | 	.mbar.edit add separator | ||||||
| 	.mbar.edit add command -label {Options...} \ | 	.mbar.edit add command -label {Options...} \ | ||||||
| 		-command do_options | 		-command do_options | ||||||
|  |  | ||||||
| 	# -- Tools Menu |  | ||||||
| 	# |  | ||||||
| 	if {[is_Cygwin] && [file exists /usr/local/miga/lib/gui-miga]} { |  | ||||||
| 	proc do_miga {} { |  | ||||||
| 		if {![lock_index update]} return |  | ||||||
| 		set cmd [list sh --login -c "/usr/local/miga/lib/gui-miga \"[pwd]\""] |  | ||||||
| 		set miga_fd [open "|$cmd" r] |  | ||||||
| 		fconfigure $miga_fd -blocking 0 |  | ||||||
| 		fileevent $miga_fd readable [list miga_done $miga_fd] |  | ||||||
| 		ui_status {Running miga...} |  | ||||||
| 	} |  | ||||||
| 	proc miga_done {fd} { |  | ||||||
| 		read $fd 512 |  | ||||||
| 		if {[eof $fd]} { |  | ||||||
| 			close $fd |  | ||||||
| 			unlock_index |  | ||||||
| 			rescan ui_ready |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	.mbar add cascade -label Tools -menu .mbar.tools |  | ||||||
| 	menu .mbar.tools |  | ||||||
| 	.mbar.tools add command -label "Migrate" \ |  | ||||||
| 		-command do_miga |  | ||||||
| 	lappend disable_on_lock \ |  | ||||||
| 		[list .mbar.tools entryconf [.mbar.tools index last] -state] |  | ||||||
| 	} |  | ||||||
| } | } | ||||||
|  |  | ||||||
| # -- Help Menu | # -- Help Menu | ||||||
|  | @ -1938,29 +1950,10 @@ proc usage {} { | ||||||
| # -- Not a normal commit type invocation?  Do that instead! | # -- Not a normal commit type invocation?  Do that instead! | ||||||
| # | # | ||||||
| switch -- $subcommand { | switch -- $subcommand { | ||||||
| browser { | browser - | ||||||
| 	set subcommand_args {rev?} |  | ||||||
| 	switch [llength $argv] { |  | ||||||
| 	0 { load_current_branch } |  | ||||||
| 	1 { |  | ||||||
| 		set current_branch [lindex $argv 0] |  | ||||||
| 		if {[regexp {^[0-9a-f]{1,39}$} $current_branch]} { |  | ||||||
| 			if {[catch { |  | ||||||
| 					set current_branch \ |  | ||||||
| 					[git rev-parse --verify $current_branch] |  | ||||||
| 				} err]} { |  | ||||||
| 				puts stderr $err |  | ||||||
| 				exit 1 |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	default usage |  | ||||||
| 	} |  | ||||||
| 	browser::new $current_branch |  | ||||||
| 	return |  | ||||||
| } |  | ||||||
| blame { | blame { | ||||||
| 	set subcommand_args {rev? path?} | 	set subcommand_args {rev? path} | ||||||
|  | 	if {$argv eq {}} usage | ||||||
| 	set head {} | 	set head {} | ||||||
| 	set path {} | 	set path {} | ||||||
| 	set is_path 0 | 	set is_path 0 | ||||||
|  | @ -1979,12 +1972,18 @@ blame { | ||||||
| 		} elseif {$head eq {}} { | 		} elseif {$head eq {}} { | ||||||
| 			if {$head ne {}} usage | 			if {$head ne {}} usage | ||||||
| 			set head $a | 			set head $a | ||||||
|  | 			set is_path 1 | ||||||
| 		} else { | 		} else { | ||||||
| 			usage | 			usage | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	unset is_path | 	unset is_path | ||||||
|  |  | ||||||
|  | 	if {$head ne {} && $path eq {}} { | ||||||
|  | 		set path $_prefix$head | ||||||
|  | 		set head {} | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	if {$head eq {}} { | 	if {$head eq {}} { | ||||||
| 		load_current_branch | 		load_current_branch | ||||||
| 	} else { | 	} else { | ||||||
|  | @ -1999,8 +1998,26 @@ blame { | ||||||
| 		set current_branch $head | 		set current_branch $head | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if {$path eq {}} usage | 	switch -- $subcommand { | ||||||
|  | 	browser { | ||||||
|  | 		if {$head eq {}} { | ||||||
|  | 			if {$path ne {} && [file isdirectory $path]} { | ||||||
|  | 				set head $current_branch | ||||||
|  | 			} else { | ||||||
|  | 				set head $path | ||||||
|  | 				set path {} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		browser::new $head $path | ||||||
|  | 	} | ||||||
|  | 	blame   { | ||||||
|  | 		if {$head eq {} && ![file exists $path]} { | ||||||
|  | 			puts stderr "fatal: cannot stat path $path: No such file or directory" | ||||||
|  | 			exit 1 | ||||||
|  | 		} | ||||||
| 		blame::new $head $path | 		blame::new $head $path | ||||||
|  | 	} | ||||||
|  | 	} | ||||||
| 	return | 	return | ||||||
| } | } | ||||||
| citool - | citool - | ||||||
|  | @ -2115,7 +2132,7 @@ pack .vpane.lower.commarea.buttons.rescan -side top -fill x | ||||||
| lappend disable_on_lock \ | lappend disable_on_lock \ | ||||||
| 	{.vpane.lower.commarea.buttons.rescan conf -state} | 	{.vpane.lower.commarea.buttons.rescan conf -state} | ||||||
|  |  | ||||||
| button .vpane.lower.commarea.buttons.incall -text {Add Existing} \ | button .vpane.lower.commarea.buttons.incall -text {Stage Changed} \ | ||||||
| 	-command do_add_all | 	-command do_add_all | ||||||
| pack .vpane.lower.commarea.buttons.incall -side top -fill x | pack .vpane.lower.commarea.buttons.incall -side top -fill x | ||||||
| lappend disable_on_lock \ | lappend disable_on_lock \ | ||||||
|  | @ -2389,17 +2406,25 @@ lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state] | ||||||
| $ctxm add separator | $ctxm add separator | ||||||
| $ctxm add command -label {Options...} \ | $ctxm add command -label {Options...} \ | ||||||
| 	-command do_options | 	-command do_options | ||||||
| bind_button3 $ui_diff " | proc popup_diff_menu {ctxm x y X Y} { | ||||||
| 	set cursorX %x | 	set ::cursorX $x | ||||||
| 	set cursorY %y | 	set ::cursorY $y | ||||||
| 	if {\$ui_index eq \$current_diff_side} { | 	if {$::ui_index eq $::current_diff_side} { | ||||||
| 		$ctxm entryconf $ui_diff_applyhunk -label {Unstage Hunk From Commit} | 		$ctxm entryconf $::ui_diff_applyhunk \ | ||||||
|  | 			-state normal \ | ||||||
|  | 			-label {Unstage Hunk From Commit} | ||||||
|  | 	} elseif {{_O} eq [lindex $::file_states($::current_diff_path) 0]} { | ||||||
|  | 		$ctxm entryconf $::ui_diff_applyhunk \ | ||||||
|  | 			-state disabled \ | ||||||
|  | 			-label {Stage Hunk For Commit} | ||||||
| 	} else { | 	} else { | ||||||
| 		$ctxm entryconf $ui_diff_applyhunk -label {Stage Hunk For Commit} | 		$ctxm entryconf $::ui_diff_applyhunk \ | ||||||
|  | 			-state normal \ | ||||||
|  | 			-label {Stage Hunk For Commit} | ||||||
| 	} | 	} | ||||||
| 	tk_popup $ctxm %X %Y | 	tk_popup $ctxm $X $Y | ||||||
| " | } | ||||||
| unset ui_diff_applyhunk | bind_button3 $ui_diff [list popup_diff_menu $ctxm %x %y %X %Y] | ||||||
|  |  | ||||||
| # -- Status Bar | # -- Status Bar | ||||||
| # | # | ||||||
|  | @ -2460,6 +2485,8 @@ if {[is_enabled branch]} { | ||||||
| 	bind . <$M1B-Key-N> branch_create::dialog | 	bind . <$M1B-Key-N> branch_create::dialog | ||||||
| 	bind . <$M1B-Key-o> branch_checkout::dialog | 	bind . <$M1B-Key-o> branch_checkout::dialog | ||||||
| 	bind . <$M1B-Key-O> branch_checkout::dialog | 	bind . <$M1B-Key-O> branch_checkout::dialog | ||||||
|  | 	bind . <$M1B-Key-m> merge::dialog | ||||||
|  | 	bind . <$M1B-Key-M> merge::dialog | ||||||
| } | } | ||||||
| if {[is_enabled transport]} { | if {[is_enabled transport]} { | ||||||
| 	bind . <$M1B-Key-p> do_push_anywhere | 	bind . <$M1B-Key-p> do_push_anywhere | ||||||
|  | @ -2551,24 +2578,64 @@ if {[is_enabled transport]} { | ||||||
| 	populate_push_menu | 	populate_push_menu | ||||||
| } | } | ||||||
|  |  | ||||||
| # -- Only suggest a gc run if we are going to stay running. | if {[winfo exists $ui_comm]} { | ||||||
|  | 	set GITGUI_BCK_exists [load_message GITGUI_BCK] | ||||||
|  |  | ||||||
|  | 	# -- If both our backup and message files exist use the | ||||||
|  | 	#    newer of the two files to initialize the buffer. | ||||||
| 	# | 	# | ||||||
| if {[is_enabled multicommit]} { | 	if {$GITGUI_BCK_exists} { | ||||||
| 	set object_limit 2000 | 		set m [gitdir GITGUI_MSG] | ||||||
| 	if {[is_Windows]} {set object_limit 200} | 		if {[file isfile $m]} { | ||||||
| 	regexp {^([0-9]+) objects,} [git count-objects] _junk objects_current | 			if {[file mtime [gitdir GITGUI_BCK]] > [file mtime $m]} { | ||||||
| 	if {$objects_current >= $object_limit} { | 				catch {file delete [gitdir GITGUI_MSG]} | ||||||
| 		if {[ask_popup \ | 			} else { | ||||||
| 			"This repository currently has $objects_current loose objects. | 				$ui_comm delete 0.0 end | ||||||
|  | 				$ui_comm edit reset | ||||||
| To maintain optimal performance it is strongly recommended that you compress the database when more than $object_limit loose objects exist. | 				$ui_comm edit modified false | ||||||
|  | 				catch {file delete [gitdir GITGUI_BCK]} | ||||||
| Compress the database now?"] eq yes} { | 				set GITGUI_BCK_exists 0 | ||||||
| 			do_gc |  | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	unset object_limit _junk objects_current | 		unset m | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	proc backup_commit_buffer {} { | ||||||
|  | 		global ui_comm GITGUI_BCK_exists | ||||||
|  |  | ||||||
|  | 		set m [$ui_comm edit modified] | ||||||
|  | 		if {$m || $GITGUI_BCK_exists} { | ||||||
|  | 			set msg [string trim [$ui_comm get 0.0 end]] | ||||||
|  | 			regsub -all -line {[ \r\t]+$} $msg {} msg | ||||||
|  |  | ||||||
|  | 			if {$msg eq {}} { | ||||||
|  | 				if {$GITGUI_BCK_exists} { | ||||||
|  | 					catch {file delete [gitdir GITGUI_BCK]} | ||||||
|  | 					set GITGUI_BCK_exists 0 | ||||||
|  | 				} | ||||||
|  | 			} elseif {$m} { | ||||||
|  | 				catch { | ||||||
|  | 					set fd [open [gitdir GITGUI_BCK] w] | ||||||
|  | 					puts -nonewline $fd $msg | ||||||
|  | 					close $fd | ||||||
|  | 					set GITGUI_BCK_exists 1 | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			$ui_comm edit modified false | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		set ::GITGUI_BCK_i [after 2000 backup_commit_buffer] | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	backup_commit_buffer | ||||||
| } | } | ||||||
|  |  | ||||||
| lock_index begin-read | lock_index begin-read | ||||||
|  | if {![winfo ismapped .]} { | ||||||
|  | 	wm deiconify . | ||||||
|  | } | ||||||
| after 1 do_rescan | after 1 do_rescan | ||||||
|  | if {[is_enabled multicommit]} { | ||||||
|  | 	after 1000 hint_gc | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -370,6 +370,7 @@ method _load {jump} { | ||||||
| 	$w_path conf -text [escape_path $path] | 	$w_path conf -text [escape_path $path] | ||||||
| 	if {$commit eq {}} { | 	if {$commit eq {}} { | ||||||
| 		set fd [open $path r] | 		set fd [open $path r] | ||||||
|  | 		fconfigure $fd -eofchar {} | ||||||
| 	} else { | 	} else { | ||||||
| 		set fd [git_read cat-file blob "$commit:$path"] | 		set fd [git_read cat-file blob "$commit:$path"] | ||||||
| 	} | 	} | ||||||
|  | @ -770,15 +771,20 @@ method _showcommit {cur_w lno} { | ||||||
| 						set enc [string tolower [string range $line 9 end]] | 						set enc [string tolower [string range $line 9 end]] | ||||||
| 					} | 					} | ||||||
| 				} | 				} | ||||||
| 				set msg [encoding convertfrom $enc [read $fd]] | 				set msg [read $fd] | ||||||
| 				set msg [string trim $msg] |  | ||||||
| 				close $fd | 				close $fd | ||||||
|  |  | ||||||
|  | 				set enc [tcl_encoding $enc] | ||||||
|  | 				if {$enc ne {}} { | ||||||
|  | 					set msg [encoding convertfrom $enc $msg] | ||||||
| 					set author_name [encoding convertfrom $enc $author_name] | 					set author_name [encoding convertfrom $enc $author_name] | ||||||
| 					set committer_name [encoding convertfrom $enc $committer_name] | 					set committer_name [encoding convertfrom $enc $committer_name] | ||||||
|  |  | ||||||
| 					set header($cmit,author) $author_name | 					set header($cmit,author) $author_name | ||||||
| 					set header($cmit,committer) $committer_name | 					set header($cmit,committer) $committer_name | ||||||
|  | 					set header($cmit,summary) \ | ||||||
|  | 					[encoding convertfrom $enc $header($cmit,summary)] | ||||||
|  | 				} | ||||||
|  | 				set msg [string trim $msg] | ||||||
| 			} | 			} | ||||||
| 			set header($cmit,message) $msg | 			set header($cmit,message) $msg | ||||||
| 		} | 		} | ||||||
|  | @ -873,6 +879,11 @@ method _open_tooltip {cur_w} { | ||||||
| 		set org [lindex $amov_data $lno] | 		set org [lindex $amov_data $lno] | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	if {$dat eq {}} { | ||||||
|  | 		_hide_tooltip $this | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	set cmit [lindex $dat 0] | 	set cmit [lindex $dat 0] | ||||||
| 	set tooltip_commit [list $cmit] | 	set tooltip_commit [list $cmit] | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @ -3,6 +3,13 @@ | ||||||
|  |  | ||||||
| class browser { | class browser { | ||||||
|  |  | ||||||
|  | image create photo ::browser::img_parent  -data {R0lGODlhEAAQAIUAAPwCBBxSHBxOHMTSzNzu3KzCtBRGHCSKFIzCjLzSxBQ2FAxGHDzCLCyeHBQ+FHSmfAwuFBxKLDSCNMzizISyjJzOnDSyLAw+FAQSDAQeDBxWJAwmDAQOBKzWrDymNAQaDAQODAwaDDyKTFSyXFTGTEy6TAQCBAQKDAwiFBQyHAwSFAwmHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAZ1QIBwSCwaj0hiQCBICpcDQsFgGAaIguhhi0gohIsrQEDYMhiNrRfgeAQC5fMCAolIDhD2hFI5WC4YRBkaBxsOE2l/RxsHHA4dHmkfRyAbIQ4iIyQlB5NFGCAACiakpSZEJyinTgAcKSesACorgU4mJ6uxR35BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs=} | ||||||
|  | image create photo ::browser::img_rblob   -data {R0lGODlhEAAQAIUAAPwCBFxaXNze3Ly2rJSWjPz+/Ozq7GxqbJyanPT29HRydMzOzDQyNIyKjERCROTi3Pz69PTy7Pzy7PTu5Ozm3LyqlJyWlJSSjJSOhOzi1LyulPz27PTq3PTm1OzezLyqjIyKhJSKfOzaxPz29OzizLyidIyGdIyCdOTOpLymhOzavOTStMTCtMS+rMS6pMSynMSulLyedAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaQQIAQECgajcNkQMBkDgKEQFK4LFgLhkMBIVUKroWEYlEgMLxbBKLQUBwc52HgAQ4LBo049atWQyIPA3pEdFcQEhMUFYNVagQWFxgZGoxfYRsTHB0eH5UJCJAYICEinUoPIxIcHCQkIiIllQYEGCEhJicoKYwPmiQeKisrKLFKLCwtLi8wHyUlMYwM0tPUDH5BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs=} | ||||||
|  | image create photo ::browser::img_xblob   -data {R0lGODlhEAAQAIYAAPwCBFRWVFxaXNza3OTi3Nze3Ly2tJyanPz+/Ozq7GxubNzSxMzOzMTGxHRybDQyNLy+vHRydHx6fKSipISChIyKjGxqbERCRCwuLLy6vGRiZExKTCQiJAwKDLSytLy2rJSSlHx+fDw6PKyqrBQWFPTu5Ozm3LyulLS2tCQmJAQCBPTq3Ozi1MSynCwqLAQGBOTazOzizOzezLyqjBweHNzSvOzaxKyurHRuZNzOtLymhDw+PIyCdOzWvOTOpLyidNzKtOTStLyifMTCtMS+rLyedAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAfZgACCAAEChYeGg4oCAwQFjgYBBwGKggEECJkICQoIkwADCwwNDY2mDA4Lng8QDhESsLARExQVDhYXGBkWExIaGw8cHR4SCQQfFQ8eFgUgIQEiwiMSBMYfGB4atwEXDyQd0wQlJicPKAHoFyIpJCoeDgMrLC0YKBsX6i4kL+4OMDEyZijr5oLGNxUqUCioEcPGDAwjPNyI6MEDChQjcOSwsUDHgw07RIgI4KCkAgs8cvTw8eOBogAxQtXIASTISiEuBwUYMoRIixYnZggpUgTDywdIkWJIitRPIAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7} | ||||||
|  | image create photo ::browser::img_tree    -data {R0lGODlhEAAQAIYAAPwCBAQCBExKTBwWHMzKzOzq7ERCRExGTCwqLARqnAQ+ZHR2dKyqrNTOzHx2fCQiJMTi9NTu9HzC3AxmnAQ+XPTm7Dy67DymzITC3IzG5AxypHRydKymrMzOzOzu7BweHByy9AyGtFyy1IzG3NTu/ARupFRSVByazBR6rAyGvFyuzJTK3MTm9BR+tAxWhHS61MTi7Pz+/IymvCxulBRelAx2rHS63Pz6/PTy9PTu9Nza3ISitBRupFSixNTS1CxqnDQyNMzGzOTi5MTCxMTGxGxubGxqbLy2vLSutGRiZLy6vLSytKyurDQuNFxaXKSipDw6PAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAfDgACCAAECg4eIAAMEBQYHCImDBgkKCwwNBQIBBw4Bhw8QERITFJYEFQUFnoIPFhcYoRkaFBscHR4Ggh8gIRciEiMQJBkltCa6JyUoKSkXKhIrLCQYuQAPLS4TEyUhKb0qLzDVAjEFMjMuNBMoNcw21QY3ODkFOjs82RM1PfDzFRU3fOggcM7Fj2pAgggRokOHDx9DhhAZUqQaISBGhjwMEvEIkiIHEgUAkgSJkiNLmFSMJChAEydPGBSBwvJQgAc0/QQCACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs=} | ||||||
|  | image create photo ::browser::img_symlink -data {R0lGODlhEAAQAIQAAPwCBCwqLLSytLy+vERGRFRWVDQ2NKSmpAQCBKyurMTGxISChJyanHR2dIyKjGxubHRydGRmZIyOjFxeXHx6fAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAVbICACwWieY1CibCCsrBkMb0zchSEcNYskCtqBBzshFkOGQFk0IRqOxqPBODRHCMhCQKteRc9FI/KQWGOIyFYgkDC+gPR4snCcfRGKOIKIgSMQE31+f4OEYCZ+IQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7} | ||||||
|  | image create photo ::browser::img_unknown -data {R0lGODlhEAAQAIUAAPwCBFxaXIyKjNTW1Nze3LS2tJyanER2RGS+VPz+/PTu5GxqbPz69BQ6BCxeLFSqRPT29HRydMzOzDQyNERmPKSypCRWHIyKhERCRDyGPKz2nESiLBxGHCyCHGxubPz6/PTy7Ozi1Ly2rKSipOzm3LyqlKSWhCRyFOzizLymhNTKtNzOvOzaxOTStPz27OzWvOTOpLSupLyedMS+rMS6pMSulLyqjLymfLyifAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAamQIAQECgajcOkYEBoDgoBQyAJOCCuiENCsWBIh9aGw9F4HCARiXciRDQoBUnlYRlcIgsMG5CxXAgMGhscBRAEBRd7AB0eBBoIgxUfICEiikSPgyMMIAokJZcBkBybJgomIaBJAZoMpyCmqkMBFCcVCrgKKAwpoSorKqchKCwtvasIFBIhLiYvLzDHsxQNMcMKLDAwMqEz3jQ1NTY3ONyrE+jp6hN+QQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7} | ||||||
|  |  | ||||||
| field w | field w | ||||||
| field browser_commit | field browser_commit | ||||||
| field browser_path | field browser_path | ||||||
|  | @ -13,13 +20,13 @@ field browser_busy   1 | ||||||
|  |  | ||||||
| field ls_buf     {}; # Buffered record output from ls-tree | field ls_buf     {}; # Buffered record output from ls-tree | ||||||
|  |  | ||||||
| constructor new {commit} { | constructor new {commit {path {}}} { | ||||||
| 	global cursor_ptr M1B | 	global cursor_ptr M1B | ||||||
| 	make_toplevel top w | 	make_toplevel top w | ||||||
| 	wm title $top "[appname] ([reponame]): File Browser" | 	wm title $top "[appname] ([reponame]): File Browser" | ||||||
|  |  | ||||||
| 	set browser_commit $commit | 	set browser_commit $commit | ||||||
| 	set browser_path $browser_commit: | 	set browser_path $browser_commit:$path | ||||||
|  |  | ||||||
| 	label $w.path \ | 	label $w.path \ | ||||||
| 		-textvariable @browser_path \ | 		-textvariable @browser_path \ | ||||||
|  | @ -73,7 +80,11 @@ constructor new {commit} { | ||||||
|  |  | ||||||
| 	bind $w_list <Visibility> [list focus $w_list] | 	bind $w_list <Visibility> [list focus $w_list] | ||||||
| 	set w $w_list | 	set w $w_list | ||||||
| 	_ls $this $browser_commit | 	if {$path ne {}} { | ||||||
|  | 		_ls $this $browser_commit:$path $path | ||||||
|  | 	} else { | ||||||
|  | 		_ls $this $browser_commit $path | ||||||
|  | 	} | ||||||
| 	return $this | 	return $this | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -173,7 +184,7 @@ method _ls {tree_id {name {}}} { | ||||||
| 		$w image create end \ | 		$w image create end \ | ||||||
| 			-align center -padx 5 -pady 1 \ | 			-align center -padx 5 -pady 1 \ | ||||||
| 			-name icon0 \ | 			-name icon0 \ | ||||||
| 			-image file_uplevel | 			-image ::browser::img_parent | ||||||
| 		$w insert end {[Up To Parent]} | 		$w insert end {[Up To Parent]} | ||||||
| 		lappend browser_files parent | 		lappend browser_files parent | ||||||
| 	} | 	} | ||||||
|  | @ -203,14 +214,21 @@ method _read {fd} { | ||||||
|  |  | ||||||
| 		switch -- $type { | 		switch -- $type { | ||||||
| 		blob { | 		blob { | ||||||
| 			set image file_mod | 			scan [lindex $info 0] %o mode | ||||||
|  | 			if {$mode == 0120000} { | ||||||
|  | 				set image ::browser::img_symlink | ||||||
|  | 			} elseif {($mode & 0100) != 0} { | ||||||
|  | 				set image ::browser::img_xblob | ||||||
|  | 			} else { | ||||||
|  | 				set image ::browser::img_rblob | ||||||
|  | 			} | ||||||
| 		} | 		} | ||||||
| 		tree { | 		tree { | ||||||
| 			set image file_dir | 			set image ::browser::img_tree | ||||||
| 			append path / | 			append path / | ||||||
| 		} | 		} | ||||||
| 		default { | 		default { | ||||||
| 			set image file_question | 			set image ::browser::img_unknown | ||||||
| 		} | 		} | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | @ -239,3 +257,56 @@ method _read {fd} { | ||||||
| } | } | ||||||
|  |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  | class browser_open { | ||||||
|  |  | ||||||
|  | field w              ; # widget path | ||||||
|  | field w_rev          ; # mega-widget to pick the initial revision | ||||||
|  |  | ||||||
|  | constructor dialog {} { | ||||||
|  | 	make_toplevel top w | ||||||
|  | 	wm title $top "[appname] ([reponame]): Browse Branch Files" | ||||||
|  | 	if {$top ne {.}} { | ||||||
|  | 		wm geometry $top "+[winfo rootx .]+[winfo rooty .]" | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	label $w.header \ | ||||||
|  | 		-text {Browse Branch Files} \ | ||||||
|  | 		-font font_uibold | ||||||
|  | 	pack $w.header -side top -fill x | ||||||
|  |  | ||||||
|  | 	frame $w.buttons | ||||||
|  | 	button $w.buttons.browse -text Browse \ | ||||||
|  | 		-default active \ | ||||||
|  | 		-command [cb _open] | ||||||
|  | 	pack $w.buttons.browse -side right | ||||||
|  | 	button $w.buttons.cancel -text {Cancel} \ | ||||||
|  | 		-command [list destroy $w] | ||||||
|  | 	pack $w.buttons.cancel -side right -padx 5 | ||||||
|  | 	pack $w.buttons -side bottom -fill x -pady 10 -padx 10 | ||||||
|  |  | ||||||
|  | 	set w_rev [::choose_rev::new $w.rev {Revision}] | ||||||
|  | 	$w_rev bind_listbox <Double-Button-1> [cb _open] | ||||||
|  | 	pack $w.rev -anchor nw -fill both -expand 1 -pady 5 -padx 5 | ||||||
|  |  | ||||||
|  | 	bind $w <Visibility> [cb _visible] | ||||||
|  | 	bind $w <Key-Escape> [list destroy $w] | ||||||
|  | 	bind $w <Key-Return> [cb _open]\;break | ||||||
|  | 	tkwait window $w | ||||||
|  | } | ||||||
|  |  | ||||||
|  | method _open {} { | ||||||
|  | 	if {[catch {$w_rev commit_or_die} err]} { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	set name [$w_rev get] | ||||||
|  | 	destroy $w | ||||||
|  | 	browser::new $name | ||||||
|  | } | ||||||
|  |  | ||||||
|  | method _visible {} { | ||||||
|  | 	grab $w | ||||||
|  | 	$w_rev focus_filter | ||||||
|  | } | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -12,6 +12,7 @@ field new_ref    ; # ref we are updating/creating | ||||||
|  |  | ||||||
| field parent_w      .; # window that started us | field parent_w      .; # window that started us | ||||||
| field merge_type none; # type of merge to apply to existing branch | field merge_type none; # type of merge to apply to existing branch | ||||||
|  | field merge_base   {}; # merge base if we have another ref involved | ||||||
| field fetch_spec   {}; # refetch tracking branch if used? | field fetch_spec   {}; # refetch tracking branch if used? | ||||||
| field checkout      1; # actually checkout the branch? | field checkout      1; # actually checkout the branch? | ||||||
| field create        0; # create the branch if it doesn't exist? | field create        0; # create the branch if it doesn't exist? | ||||||
|  | @ -65,14 +66,19 @@ method run {} { | ||||||
| 		set r_head [lindex $fetch_spec 2] | 		set r_head [lindex $fetch_spec 2] | ||||||
| 		regsub ^refs/heads/ $r_head {} r_name | 		regsub ^refs/heads/ $r_head {} r_name | ||||||
|  |  | ||||||
|  | 		set cmd [list git fetch $remote] | ||||||
|  | 		if {$l_trck ne {}} { | ||||||
|  | 			lappend cmd +$r_head:$l_trck | ||||||
|  | 		} else { | ||||||
|  | 			lappend cmd $r_head | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		_toplevel $this {Refreshing Tracking Branch} | 		_toplevel $this {Refreshing Tracking Branch} | ||||||
| 		set w_cons [::console::embed \ | 		set w_cons [::console::embed \ | ||||||
| 			$w.console \ | 			$w.console \ | ||||||
| 			"Fetching $r_name from $remote"] | 			"Fetching $r_name from $remote"] | ||||||
| 		pack $w.console -fill both -expand 1 | 		pack $w.console -fill both -expand 1 | ||||||
| 		$w_cons exec \ | 		$w_cons exec $cmd [cb _finish_fetch] | ||||||
| 			[list git fetch $remote +$r_head:$l_trck] \ |  | ||||||
| 			[cb _finish_fetch] |  | ||||||
|  |  | ||||||
| 		bind $w <$M1B-Key-w> break | 		bind $w <$M1B-Key-w> break | ||||||
| 		bind $w <$M1B-Key-W> break | 		bind $w <$M1B-Key-W> break | ||||||
|  | @ -113,6 +119,9 @@ method _noop {} {} | ||||||
| method _finish_fetch {ok} { | method _finish_fetch {ok} { | ||||||
| 	if {$ok} { | 	if {$ok} { | ||||||
| 		set l_trck [lindex $fetch_spec 0] | 		set l_trck [lindex $fetch_spec 0] | ||||||
|  | 		if {$l_trck eq {}} { | ||||||
|  | 			set l_trck FETCH_HEAD | ||||||
|  | 		} | ||||||
| 		if {[catch {set new_hash [git rev-parse --verify "$l_trck^0"]} err]} { | 		if {[catch {set new_hash [git rev-parse --verify "$l_trck^0"]} err]} { | ||||||
| 			set ok 0 | 			set ok 0 | ||||||
| 			$w_cons insert "fatal: Cannot resolve $l_trck" | 			$w_cons insert "fatal: Cannot resolve $l_trck" | ||||||
|  | @ -180,29 +189,25 @@ method _update_ref {} { | ||||||
| 		# No merge would be required, don't compute anything. | 		# No merge would be required, don't compute anything. | ||||||
| 		# | 		# | ||||||
| 	} else { | 	} else { | ||||||
| 		set mrb {} | 		catch {set merge_base [git merge-base $new $cur]} | ||||||
| 		catch {set mrb [git merge-base $new $cur]} | 		if {$merge_base eq $cur} { | ||||||
| 		switch -- $merge_type { |  | ||||||
| 		ff { |  | ||||||
| 			if {$mrb eq $new} { |  | ||||||
| 				# The current branch is actually newer. |  | ||||||
| 				# |  | ||||||
| 				set new $cur |  | ||||||
| 			} elseif {$mrb eq $cur} { |  | ||||||
| 			# The current branch is older. | 			# The current branch is older. | ||||||
| 			# | 			# | ||||||
| 			set reflog_msg "merge $new_expr: Fast-forward" | 			set reflog_msg "merge $new_expr: Fast-forward" | ||||||
|  | 		} else { | ||||||
|  | 			switch -- $merge_type { | ||||||
|  | 			ff { | ||||||
|  | 				if {$merge_base eq $new} { | ||||||
|  | 					# The current branch is actually newer. | ||||||
|  | 					# | ||||||
|  | 					set new $cur | ||||||
|  | 					set new_hash $cur | ||||||
| 				} else { | 				} else { | ||||||
| 					_error $this "Branch '$newbranch' already exists.\n\nIt cannot fast-forward to $new_expr.\nA merge is required." | 					_error $this "Branch '$newbranch' already exists.\n\nIt cannot fast-forward to $new_expr.\nA merge is required." | ||||||
| 					return 0 | 					return 0 | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 			reset { | 			reset { | ||||||
| 			if {$mrb eq $cur} { |  | ||||||
| 				# The current branch is older. |  | ||||||
| 				# |  | ||||||
| 				set reflog_msg "merge $new_expr: Fast-forward" |  | ||||||
| 			} else { |  | ||||||
| 				# The current branch will lose things. | 				# The current branch will lose things. | ||||||
| 				# | 				# | ||||||
| 				if {[_confirm_reset $this $cur]} { | 				if {[_confirm_reset $this $cur]} { | ||||||
|  | @ -211,13 +216,13 @@ method _update_ref {} { | ||||||
| 					return 0 | 					return 0 | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 		} |  | ||||||
| 			default { | 			default { | ||||||
| 			_error $this "Only 'ff' and 'reset' merge is currently supported." | 				_error $this "Merge strategy '$merge_type' not supported." | ||||||
| 				return 0 | 				return 0 | ||||||
| 			} | 			} | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	if {$new ne $cur} { | 	if {$new ne $cur} { | ||||||
| 		if {$is_current} { | 		if {$is_current} { | ||||||
|  | @ -243,7 +248,7 @@ method _checkout {} { | ||||||
| 	if {[lock_index checkout_op]} { | 	if {[lock_index checkout_op]} { | ||||||
| 		after idle [cb _start_checkout] | 		after idle [cb _start_checkout] | ||||||
| 	} else { | 	} else { | ||||||
| 		_error $this "Index is already locked." | 		_error $this "Staging area (index) is already locked." | ||||||
| 		delete_this | 		delete_this | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | @ -270,7 +275,9 @@ The rescan will be automatically started now. | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if {[is_config_true gui.trustmtime]} { | 	if {$curHEAD eq $new_hash} { | ||||||
|  | 		_after_readtree $this | ||||||
|  | 	} elseif {[is_config_true gui.trustmtime]} { | ||||||
| 		_readtree $this | 		_readtree $this | ||||||
| 	} else { | 	} else { | ||||||
| 		ui_status {Refreshing file status...} | 		ui_status {Refreshing file status...} | ||||||
|  | @ -378,8 +385,8 @@ method _after_readtree {} { | ||||||
| 	set rn [string length $rh] | 	set rn [string length $rh] | ||||||
| 	if {[string equal -length $rn $rh $new_ref]} { | 	if {[string equal -length $rn $rh $new_ref]} { | ||||||
| 		set new_branch [string range $new_ref $rn end] | 		set new_branch [string range $new_ref $rn end] | ||||||
|  | 		if {$is_detached || $current_branch ne $new_branch} { | ||||||
| 			append log " to $new_branch" | 			append log " to $new_branch" | ||||||
|  |  | ||||||
| 			if {[catch { | 			if {[catch { | ||||||
| 					git symbolic-ref -m $log HEAD $new_ref | 					git symbolic-ref -m $log HEAD $new_ref | ||||||
| 				} err]} { | 				} err]} { | ||||||
|  | @ -387,14 +394,16 @@ method _after_readtree {} { | ||||||
| 			} | 			} | ||||||
| 			set current_branch $new_branch | 			set current_branch $new_branch | ||||||
| 			set is_detached 0 | 			set is_detached 0 | ||||||
|  | 		} | ||||||
| 	} else { | 	} else { | ||||||
|  | 		if {$new_hash ne $HEAD} { | ||||||
| 			append log " to $new_expr" | 			append log " to $new_expr" | ||||||
|  |  | ||||||
| 			if {[catch { | 			if {[catch { | ||||||
| 					_detach_HEAD $log $new_hash | 					_detach_HEAD $log $new_hash | ||||||
| 				} err]} { | 				} err]} { | ||||||
| 				_fatal $this $err | 				_fatal $this $err | ||||||
| 			} | 			} | ||||||
|  | 		} | ||||||
| 		set current_branch HEAD | 		set current_branch HEAD | ||||||
| 		set is_detached 1 | 		set is_detached 1 | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -16,10 +16,28 @@ field cur_specs [list]; # list of specs for $revtype | ||||||
| field spec_head       ; # list of all head specs | field spec_head       ; # list of all head specs | ||||||
| field spec_trck       ; # list of all tracking branch specs | field spec_trck       ; # list of all tracking branch specs | ||||||
| field spec_tag        ; # list of all tag specs | field spec_tag        ; # list of all tag specs | ||||||
|  | field tip_data        ; # array of tip commit info by refname | ||||||
|  | field log_last        ; # array of reflog date by refname | ||||||
|  |  | ||||||
| constructor new {path {title {}}} { | field tooltip_wm        {} ; # Current tooltip toplevel, if open | ||||||
|  | field tooltip_t         {} ; # Text widget in $tooltip_wm | ||||||
|  | field tooltip_timer     {} ; # Current timer event for our tooltip | ||||||
|  |  | ||||||
|  | proc new {path {title {}}} { | ||||||
|  | 	return [_new $path 0 $title] | ||||||
|  | } | ||||||
|  |  | ||||||
|  | proc new_unmerged {path {title {}}} { | ||||||
|  | 	return [_new $path 1 $title] | ||||||
|  | } | ||||||
|  |  | ||||||
|  | constructor _new {path unmerged_only title} { | ||||||
| 	global current_branch is_detached | 	global current_branch is_detached | ||||||
|  |  | ||||||
|  | 	if {![info exists ::all_remotes]} { | ||||||
|  | 		load_all_remotes | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	set w $path | 	set w $path | ||||||
|  |  | ||||||
| 	if {$title ne {}} { | 	if {$title ne {}} { | ||||||
|  | @ -86,13 +104,17 @@ constructor new {path {title {}}} { | ||||||
| 	listbox $w_list \ | 	listbox $w_list \ | ||||||
| 		-font font_diff \ | 		-font font_diff \ | ||||||
| 		-width 50 \ | 		-width 50 \ | ||||||
| 		-height 5 \ | 		-height 10 \ | ||||||
| 		-selectmode browse \ | 		-selectmode browse \ | ||||||
| 		-exportselection false \ | 		-exportselection false \ | ||||||
| 		-xscrollcommand [cb _sb_set $w.list.sbx h] \ | 		-xscrollcommand [cb _sb_set $w.list.sbx h] \ | ||||||
| 		-yscrollcommand [cb _sb_set $w.list.sby v] | 		-yscrollcommand [cb _sb_set $w.list.sby v] | ||||||
| 	pack $w_list -fill both -expand 1 | 	pack $w_list -fill both -expand 1 | ||||||
| 	grid $w.list -sticky nswe -padx {20 5} -columnspan 2 | 	grid $w.list -sticky nswe -padx {20 5} -columnspan 2 | ||||||
|  | 	bind $w_list <Any-Motion>  [cb _show_tooltip @%x,%y] | ||||||
|  | 	bind $w_list <Any-Enter>   [cb _hide_tooltip] | ||||||
|  | 	bind $w_list <Any-Leave>   [cb _hide_tooltip] | ||||||
|  | 	bind $w_list <Destroy>     [cb _hide_tooltip] | ||||||
|  |  | ||||||
| 	grid columnconfigure $w 1 -weight 1 | 	grid columnconfigure $w 1 -weight 1 | ||||||
| 	if {$is_detached} { | 	if {$is_detached} { | ||||||
|  | @ -105,21 +127,89 @@ constructor new {path {title {}}} { | ||||||
| 	bind $w_filter <Key-Return> [list focus $w_list]\;break | 	bind $w_filter <Key-Return> [list focus $w_list]\;break | ||||||
| 	bind $w_filter <Key-Down>   [list focus $w_list] | 	bind $w_filter <Key-Down>   [list focus $w_list] | ||||||
|  |  | ||||||
|  | 	set fmt list | ||||||
|  | 	append fmt { %(refname)} | ||||||
|  | 	append fmt { [list} | ||||||
|  | 	append fmt { %(objecttype)} | ||||||
|  | 	append fmt { %(objectname)} | ||||||
|  | 	append fmt { [concat %(taggername) %(authorname)]} | ||||||
|  | 	append fmt { [concat %(taggerdate) %(authordate)]} | ||||||
|  | 	append fmt { %(subject)} | ||||||
|  | 	append fmt {] [list} | ||||||
|  | 	append fmt { %(*objecttype)} | ||||||
|  | 	append fmt { %(*objectname)} | ||||||
|  | 	append fmt { %(*authorname)} | ||||||
|  | 	append fmt { %(*authordate)} | ||||||
|  | 	append fmt { %(*subject)} | ||||||
|  | 	append fmt {]} | ||||||
|  | 	set all_refn [list] | ||||||
|  | 	set fr_fd [git_read for-each-ref \ | ||||||
|  | 		--tcl \ | ||||||
|  | 		--sort=-taggerdate \ | ||||||
|  | 		--format=$fmt \ | ||||||
|  | 		refs/heads \ | ||||||
|  | 		refs/remotes \ | ||||||
|  | 		refs/tags \ | ||||||
|  | 		] | ||||||
|  | 	fconfigure $fr_fd -translation lf -encoding utf-8 | ||||||
|  | 	while {[gets $fr_fd line] > 0} { | ||||||
|  | 		set line [eval $line] | ||||||
|  | 		if {[lindex $line 1 0] eq {tag}} { | ||||||
|  | 			if {[lindex $line 2 0] eq {commit}} { | ||||||
|  | 				set sha1 [lindex $line 2 1] | ||||||
|  | 			} else { | ||||||
|  | 				continue | ||||||
|  | 			} | ||||||
|  | 		} elseif {[lindex $line 1 0] eq {commit}} { | ||||||
|  | 			set sha1 [lindex $line 1 1] | ||||||
|  | 		} else { | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 		set refn [lindex $line 0] | ||||||
|  | 		set tip_data($refn) [lrange $line 1 end] | ||||||
|  | 		lappend cmt_refn($sha1) $refn | ||||||
|  | 		lappend all_refn $refn | ||||||
|  | 	} | ||||||
|  | 	close $fr_fd | ||||||
|  |  | ||||||
|  | 	if {$unmerged_only} { | ||||||
|  | 		set fr_fd [git_read rev-list --all ^$::HEAD] | ||||||
|  | 		while {[gets $fr_fd sha1] > 0} { | ||||||
|  | 			if {[catch {set rlst $cmt_refn($sha1)}]} continue | ||||||
|  | 			foreach refn $rlst { | ||||||
|  | 				set inc($refn) 1 | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		close $fr_fd | ||||||
|  | 	} else { | ||||||
|  | 		foreach refn $all_refn { | ||||||
|  | 			set inc($refn) 1 | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	set spec_head [list] | 	set spec_head [list] | ||||||
| 	foreach name [load_all_heads] { | 	foreach name [load_all_heads] { | ||||||
| 		lappend spec_head [list $name refs/heads/$name] | 		set refn refs/heads/$name | ||||||
|  | 		if {[info exists inc($refn)]} { | ||||||
|  | 			lappend spec_head [list $name $refn] | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	set spec_trck [list] | 	set spec_trck [list] | ||||||
| 	foreach spec [all_tracking_branches] { | 	foreach spec [all_tracking_branches] { | ||||||
| 		set name [lindex $spec 0] | 		set refn [lindex $spec 0] | ||||||
| 		regsub ^refs/(heads|remotes)/ $name {} name | 		if {[info exists inc($refn)]} { | ||||||
|  | 			regsub ^refs/(heads|remotes)/ $refn {} name | ||||||
| 			lappend spec_trck [concat $name $spec] | 			lappend spec_trck [concat $name $spec] | ||||||
| 		} | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	set spec_tag [list] | 	set spec_tag [list] | ||||||
| 	foreach name [load_all_tags] { | 	foreach name [load_all_tags] { | ||||||
| 		lappend spec_tag [list $name refs/tags/$name] | 		set refn refs/tags/$name | ||||||
|  | 		if {[info exists inc($refn)]} { | ||||||
|  | 			lappend spec_tag [list $name $refn] | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 		  if {$is_detached}             { set revtype HEAD | 		  if {$is_detached}             { set revtype HEAD | ||||||
|  | @ -364,4 +454,174 @@ method _sb_set {sb orient first last} { | ||||||
| 	$sb set $first $last | 	$sb set $first $last | ||||||
| } | } | ||||||
|  |  | ||||||
|  | method _show_tooltip {pos} { | ||||||
|  | 	if {$tooltip_wm ne {}} { | ||||||
|  | 		_open_tooltip $this | ||||||
|  | 	} elseif {$tooltip_timer eq {}} { | ||||||
|  | 		set tooltip_timer [after 1000 [cb _open_tooltip]] | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | method _open_tooltip {} { | ||||||
|  | 	global remote_url | ||||||
|  |  | ||||||
|  | 	set tooltip_timer {} | ||||||
|  | 	set pos_x [winfo pointerx $w_list] | ||||||
|  | 	set pos_y [winfo pointery $w_list] | ||||||
|  | 	if {[winfo containing $pos_x $pos_y] ne $w_list} { | ||||||
|  | 		_hide_tooltip $this | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	set pos @[join [list \ | ||||||
|  | 		[expr {$pos_x - [winfo rootx $w_list]}] \ | ||||||
|  | 		[expr {$pos_y - [winfo rooty $w_list]}]] ,] | ||||||
|  | 	set lno [$w_list index $pos] | ||||||
|  | 	if {$lno eq {}} { | ||||||
|  | 		_hide_tooltip $this | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	set spec [lindex $cur_specs $lno] | ||||||
|  | 	set refn [lindex $spec 1] | ||||||
|  | 	if {$refn eq {}} { | ||||||
|  | 		_hide_tooltip $this | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if {$tooltip_wm eq {}} { | ||||||
|  | 		set tooltip_wm [toplevel $w_list.tooltip -borderwidth 1] | ||||||
|  | 		wm overrideredirect $tooltip_wm 1 | ||||||
|  | 		wm transient $tooltip_wm [winfo toplevel $w_list] | ||||||
|  | 		set tooltip_t $tooltip_wm.label | ||||||
|  | 		text $tooltip_t \ | ||||||
|  | 			-takefocus 0 \ | ||||||
|  | 			-highlightthickness 0 \ | ||||||
|  | 			-relief flat \ | ||||||
|  | 			-borderwidth 0 \ | ||||||
|  | 			-wrap none \ | ||||||
|  | 			-background lightyellow \ | ||||||
|  | 			-foreground black | ||||||
|  | 		$tooltip_t tag conf section_header -font font_uibold | ||||||
|  | 		bind $tooltip_wm <Escape> [cb _hide_tooltip] | ||||||
|  | 		pack $tooltip_t | ||||||
|  | 	} else { | ||||||
|  | 		$tooltip_t conf -state normal | ||||||
|  | 		$tooltip_t delete 0.0 end | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	set data $tip_data($refn) | ||||||
|  | 	if {[lindex $data 0 0] eq {tag}} { | ||||||
|  | 		set tag  [lindex $data 0] | ||||||
|  | 		if {[lindex $data 1 0] eq {commit}} { | ||||||
|  | 			set cmit [lindex $data 1] | ||||||
|  | 		} else { | ||||||
|  | 			set cmit {} | ||||||
|  | 		} | ||||||
|  | 	} elseif {[lindex $data 0 0] eq {commit}} { | ||||||
|  | 		set tag  {} | ||||||
|  | 		set cmit [lindex $data 0] | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	$tooltip_t insert end [lindex $spec 0] | ||||||
|  | 	set last [_reflog_last $this [lindex $spec 1]] | ||||||
|  | 	if {$last ne {}} { | ||||||
|  | 		$tooltip_t insert end "\n" | ||||||
|  | 		$tooltip_t insert end "updated" | ||||||
|  | 		$tooltip_t insert end " $last" | ||||||
|  | 	} | ||||||
|  | 	$tooltip_t insert end "\n" | ||||||
|  |  | ||||||
|  | 	if {$tag ne {}} { | ||||||
|  | 		$tooltip_t insert end "\n" | ||||||
|  | 		$tooltip_t insert end "tag" section_header | ||||||
|  | 		$tooltip_t insert end "  [lindex $tag 1]\n" | ||||||
|  | 		$tooltip_t insert end [lindex $tag 2] | ||||||
|  | 		$tooltip_t insert end " ([lindex $tag 3])\n" | ||||||
|  | 		$tooltip_t insert end [lindex $tag 4] | ||||||
|  | 		$tooltip_t insert end "\n" | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if {$cmit ne {}} { | ||||||
|  | 		$tooltip_t insert end "\n" | ||||||
|  | 		$tooltip_t insert end "commit" section_header | ||||||
|  | 		$tooltip_t insert end "  [lindex $cmit 1]\n" | ||||||
|  | 		$tooltip_t insert end [lindex $cmit 2] | ||||||
|  | 		$tooltip_t insert end " ([lindex $cmit 3])\n" | ||||||
|  | 		$tooltip_t insert end [lindex $cmit 4] | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if {[llength $spec] > 2} { | ||||||
|  | 		$tooltip_t insert end "\n" | ||||||
|  | 		$tooltip_t insert end "remote" section_header | ||||||
|  | 		$tooltip_t insert end "  [lindex $spec 2]\n" | ||||||
|  | 		$tooltip_t insert end "url" | ||||||
|  | 		$tooltip_t insert end " $remote_url([lindex $spec 2])\n" | ||||||
|  | 		$tooltip_t insert end "branch" | ||||||
|  | 		$tooltip_t insert end " [lindex $spec 3]" | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	$tooltip_t conf -state disabled | ||||||
|  | 	_position_tooltip $this | ||||||
|  | } | ||||||
|  |  | ||||||
|  | method _reflog_last {name} { | ||||||
|  | 	if {[info exists reflog_last($name)]} { | ||||||
|  | 		return reflog_last($name) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	set last {} | ||||||
|  | 	if {[catch {set last [file mtime [gitdir $name]]}] | ||||||
|  | 	&& ![catch {set g [open [gitdir logs $name] r]}]} { | ||||||
|  | 		fconfigure $g -translation binary | ||||||
|  | 		while {[gets $g line] >= 0} { | ||||||
|  | 			if {[regexp {> ([1-9][0-9]*) } $line line when]} { | ||||||
|  | 				set last $when | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		close $g | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if {$last ne {}} { | ||||||
|  | 		set last [clock format $last -format {%a %b %e %H:%M:%S %Y}] | ||||||
|  | 	} | ||||||
|  | 	set reflog_last($name) $last | ||||||
|  | 	return $last | ||||||
|  | } | ||||||
|  |  | ||||||
|  | method _position_tooltip {} { | ||||||
|  | 	set max_h [lindex [split [$tooltip_t index end] .] 0] | ||||||
|  | 	set max_w 0 | ||||||
|  | 	for {set i 1} {$i <= $max_h} {incr i} { | ||||||
|  | 		set c [lindex [split [$tooltip_t index "$i.0 lineend"] .] 1] | ||||||
|  | 		if {$c > $max_w} {set max_w $c} | ||||||
|  | 	} | ||||||
|  | 	$tooltip_t conf -width $max_w -height $max_h | ||||||
|  |  | ||||||
|  | 	set req_w [winfo reqwidth  $tooltip_t] | ||||||
|  | 	set req_h [winfo reqheight $tooltip_t] | ||||||
|  | 	set pos_x [expr {[winfo pointerx .] +  5}] | ||||||
|  | 	set pos_y [expr {[winfo pointery .] + 10}] | ||||||
|  |  | ||||||
|  | 	set g "${req_w}x${req_h}" | ||||||
|  | 	if {$pos_x >= 0} {append g +} | ||||||
|  | 	append g $pos_x | ||||||
|  | 	if {$pos_y >= 0} {append g +} | ||||||
|  | 	append g $pos_y | ||||||
|  |  | ||||||
|  | 	wm geometry $tooltip_wm $g | ||||||
|  | 	raise $tooltip_wm | ||||||
|  | } | ||||||
|  |  | ||||||
|  | method _hide_tooltip {} { | ||||||
|  | 	if {$tooltip_wm ne {}} { | ||||||
|  | 		destroy $tooltip_wm | ||||||
|  | 		set tooltip_wm {} | ||||||
|  | 	} | ||||||
|  | 	if {$tooltip_timer ne {}} { | ||||||
|  | 		after cancel $tooltip_timer | ||||||
|  | 		set tooltip_timer {} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -37,9 +37,14 @@ You are currently in the middle of a merge that has not been fully completed.  Y | ||||||
| 					set enc [string tolower [string range $line 9 end]] | 					set enc [string tolower [string range $line 9 end]] | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 			set msg [encoding convertfrom $enc [read $fd]] | 			set msg [read $fd] | ||||||
| 			set msg [string trim $msg] |  | ||||||
| 			close $fd | 			close $fd | ||||||
|  |  | ||||||
|  | 			set enc [tcl_encoding $enc] | ||||||
|  | 			if {$enc ne {}} { | ||||||
|  | 				set msg [encoding convertfrom $enc $msg] | ||||||
|  | 			} | ||||||
|  | 			set msg [string trim $msg] | ||||||
| 		} err]} { | 		} err]} { | ||||||
| 		error_popup "Error loading commit data for amend:\n\n$err" | 		error_popup "Error loading commit data for amend:\n\n$err" | ||||||
| 		return | 		return | ||||||
|  | @ -148,7 +153,7 @@ The rescan will be automatically started now. | ||||||
| 		U? { | 		U? { | ||||||
| 			error_popup "Unmerged files cannot be committed. | 			error_popup "Unmerged files cannot be committed. | ||||||
|  |  | ||||||
| File [short_path $path] has merge conflicts.  You must resolve them and add the file before committing. | File [short_path $path] has merge conflicts.  You must resolve them and stage the file before committing. | ||||||
| " | " | ||||||
| 			unlock_index | 			unlock_index | ||||||
| 			return | 			return | ||||||
|  | @ -164,7 +169,7 @@ File [short_path $path] cannot be committed by this program. | ||||||
| 	if {!$files_ready && ![string match *merge $curType]} { | 	if {!$files_ready && ![string match *merge $curType]} { | ||||||
| 		info_popup {No changes to commit. | 		info_popup {No changes to commit. | ||||||
|  |  | ||||||
| You must add at least 1 file before you can commit. | You must stage at least 1 file before you can commit. | ||||||
| } | } | ||||||
| 		unlock_index | 		unlock_index | ||||||
| 		return | 		return | ||||||
|  | @ -209,7 +214,7 @@ A good commit message has the following format: | ||||||
| 	ui_status {Calling pre-commit hook...} | 	ui_status {Calling pre-commit hook...} | ||||||
| 	set pch_error {} | 	set pch_error {} | ||||||
| 	set fd_ph [open "| $pchook" r] | 	set fd_ph [open "| $pchook" r] | ||||||
| 	fconfigure $fd_ph -blocking 0 -translation binary | 	fconfigure $fd_ph -blocking 0 -translation binary -eofchar {} | ||||||
| 	fileevent $fd_ph readable \ | 	fileevent $fd_ph readable \ | ||||||
| 		[list commit_prehook_wait $fd_ph $curHEAD $msg] | 		[list commit_prehook_wait $fd_ph $curHEAD $msg] | ||||||
| } | } | ||||||
|  | @ -287,11 +292,18 @@ A rescan will be automatically started now. | ||||||
| 	# | 	# | ||||||
| 	set msg_p [gitdir COMMIT_EDITMSG] | 	set msg_p [gitdir COMMIT_EDITMSG] | ||||||
| 	set msg_wt [open $msg_p w] | 	set msg_wt [open $msg_p w] | ||||||
|  | 	fconfigure $msg_wt -translation lf | ||||||
| 	if {[catch {set enc $repo_config(i18n.commitencoding)}]} { | 	if {[catch {set enc $repo_config(i18n.commitencoding)}]} { | ||||||
| 		set enc utf-8 | 		set enc utf-8 | ||||||
| 	} | 	} | ||||||
| 	fconfigure $msg_wt -encoding binary -translation binary | 	set use_enc [tcl_encoding $enc] | ||||||
| 	puts -nonewline $msg_wt [encoding convertto $enc $msg] | 	if {$use_enc ne {}} { | ||||||
|  | 		fconfigure $msg_wt -encoding $use_enc | ||||||
|  | 	} else { | ||||||
|  | 		puts stderr "warning: Tcl does not support encoding '$enc'." | ||||||
|  | 		fconfigure $msg_wt -encoding utf-8 | ||||||
|  | 	} | ||||||
|  | 	puts -nonewline $msg_wt $msg | ||||||
| 	close $msg_wt | 	close $msg_wt | ||||||
|  |  | ||||||
| 	# -- Create the commit. | 	# -- Create the commit. | ||||||
|  | @ -367,6 +379,10 @@ A rescan will be automatically started now. | ||||||
| 	$ui_comm delete 0.0 end | 	$ui_comm delete 0.0 end | ||||||
| 	$ui_comm edit reset | 	$ui_comm edit reset | ||||||
| 	$ui_comm edit modified false | 	$ui_comm edit modified false | ||||||
|  | 	if {$::GITGUI_BCK_exists} { | ||||||
|  | 		catch {file delete [gitdir GITGUI_BCK]} | ||||||
|  | 		set ::GITGUI_BCK_exists 0 | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	if {[is_enabled singlecommit]} do_quit | 	if {[is_enabled singlecommit]} do_quit | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @ -87,3 +87,30 @@ proc do_fsck_objects {} { | ||||||
| 	lappend cmd --strict | 	lappend cmd --strict | ||||||
| 	console::exec $w $cmd | 	console::exec $w $cmd | ||||||
| } | } | ||||||
|  |  | ||||||
|  | proc hint_gc {} { | ||||||
|  | 	set object_limit 8 | ||||||
|  | 	if {[is_Windows]} { | ||||||
|  | 		set object_limit 1 | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	set objects_current [llength [glob \ | ||||||
|  | 		-directory [gitdir objects 42] \ | ||||||
|  | 		-nocomplain \ | ||||||
|  | 		-tails \ | ||||||
|  | 		-- \ | ||||||
|  | 		*]] | ||||||
|  |  | ||||||
|  | 	if {$objects_current >= $object_limit} { | ||||||
|  | 		set objects_current [expr {$objects_current * 256}] | ||||||
|  | 		set object_limit    [expr {$object_limit    * 256}] | ||||||
|  | 		if {[ask_popup \ | ||||||
|  | 			"This repository currently has approximately $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. | ||||||
|  |  | ||||||
|  | Compress the database now?"] eq yes} { | ||||||
|  | 			do_gc | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -86,6 +86,7 @@ proc show_diff {path w {lno {}}} { | ||||||
| 		set max_sz [expr {128 * 1024}] | 		set max_sz [expr {128 * 1024}] | ||||||
| 		if {[catch { | 		if {[catch { | ||||||
| 				set fd [open $path r] | 				set fd [open $path r] | ||||||
|  | 				fconfigure $fd -eofchar {} | ||||||
| 				set content [read $fd $max_sz] | 				set content [read $fd $max_sz] | ||||||
| 				close $fd | 				close $fd | ||||||
| 				set sz [file size $path] | 				set sz [file size $path] | ||||||
|  |  | ||||||
|  | @ -0,0 +1,276 @@ | ||||||
|  | # git-gui encoding support | ||||||
|  | # Copyright (C) 2005 Paul Mackerras <paulus@samba.org> | ||||||
|  | # (Copied from gitk, commit fd8ccbec4f0161) | ||||||
|  |  | ||||||
|  | # This list of encoding names and aliases is distilled from | ||||||
|  | # http://www.iana.org/assignments/character-sets. | ||||||
|  | # Not all of them are supported by Tcl. | ||||||
|  | set encoding_aliases { | ||||||
|  |     { ANSI_X3.4-1968 iso-ir-6 ANSI_X3.4-1986 ISO_646.irv:1991 ASCII | ||||||
|  |       ISO646-US US-ASCII us IBM367 cp367 csASCII } | ||||||
|  |     { ISO-10646-UTF-1 csISO10646UTF1 } | ||||||
|  |     { ISO_646.basic:1983 ref csISO646basic1983 } | ||||||
|  |     { INVARIANT csINVARIANT } | ||||||
|  |     { ISO_646.irv:1983 iso-ir-2 irv csISO2IntlRefVersion } | ||||||
|  |     { BS_4730 iso-ir-4 ISO646-GB gb uk csISO4UnitedKingdom } | ||||||
|  |     { NATS-SEFI iso-ir-8-1 csNATSSEFI } | ||||||
|  |     { NATS-SEFI-ADD iso-ir-8-2 csNATSSEFIADD } | ||||||
|  |     { NATS-DANO iso-ir-9-1 csNATSDANO } | ||||||
|  |     { NATS-DANO-ADD iso-ir-9-2 csNATSDANOADD } | ||||||
|  |     { SEN_850200_B iso-ir-10 FI ISO646-FI ISO646-SE se csISO10Swedish } | ||||||
|  |     { SEN_850200_C iso-ir-11 ISO646-SE2 se2 csISO11SwedishForNames } | ||||||
|  |     { KS_C_5601-1987 iso-ir-149 KS_C_5601-1989 KSC_5601 korean csKSC56011987 } | ||||||
|  |     { ISO-2022-KR csISO2022KR } | ||||||
|  |     { EUC-KR csEUCKR } | ||||||
|  |     { ISO-2022-JP csISO2022JP } | ||||||
|  |     { ISO-2022-JP-2 csISO2022JP2 } | ||||||
|  |     { JIS_C6220-1969-jp JIS_C6220-1969 iso-ir-13 katakana x0201-7 | ||||||
|  |       csISO13JISC6220jp } | ||||||
|  |     { JIS_C6220-1969-ro iso-ir-14 jp ISO646-JP csISO14JISC6220ro } | ||||||
|  |     { IT iso-ir-15 ISO646-IT csISO15Italian } | ||||||
|  |     { PT iso-ir-16 ISO646-PT csISO16Portuguese } | ||||||
|  |     { ES iso-ir-17 ISO646-ES csISO17Spanish } | ||||||
|  |     { greek7-old iso-ir-18 csISO18Greek7Old } | ||||||
|  |     { latin-greek iso-ir-19 csISO19LatinGreek } | ||||||
|  |     { DIN_66003 iso-ir-21 de ISO646-DE csISO21German } | ||||||
|  |     { NF_Z_62-010_(1973) iso-ir-25 ISO646-FR1 csISO25French } | ||||||
|  |     { Latin-greek-1 iso-ir-27 csISO27LatinGreek1 } | ||||||
|  |     { ISO_5427 iso-ir-37 csISO5427Cyrillic } | ||||||
|  |     { JIS_C6226-1978 iso-ir-42 csISO42JISC62261978 } | ||||||
|  |     { BS_viewdata iso-ir-47 csISO47BSViewdata } | ||||||
|  |     { INIS iso-ir-49 csISO49INIS } | ||||||
|  |     { INIS-8 iso-ir-50 csISO50INIS8 } | ||||||
|  |     { INIS-cyrillic iso-ir-51 csISO51INISCyrillic } | ||||||
|  |     { ISO_5427:1981 iso-ir-54 ISO5427Cyrillic1981 } | ||||||
|  |     { ISO_5428:1980 iso-ir-55 csISO5428Greek } | ||||||
|  |     { GB_1988-80 iso-ir-57 cn ISO646-CN csISO57GB1988 } | ||||||
|  |     { GB_2312-80 iso-ir-58 chinese csISO58GB231280 } | ||||||
|  |     { NS_4551-1 iso-ir-60 ISO646-NO no csISO60DanishNorwegian | ||||||
|  |       csISO60Norwegian1 } | ||||||
|  |     { NS_4551-2 ISO646-NO2 iso-ir-61 no2 csISO61Norwegian2 } | ||||||
|  |     { NF_Z_62-010 iso-ir-69 ISO646-FR fr csISO69French } | ||||||
|  |     { videotex-suppl iso-ir-70 csISO70VideotexSupp1 } | ||||||
|  |     { PT2 iso-ir-84 ISO646-PT2 csISO84Portuguese2 } | ||||||
|  |     { ES2 iso-ir-85 ISO646-ES2 csISO85Spanish2 } | ||||||
|  |     { MSZ_7795.3 iso-ir-86 ISO646-HU hu csISO86Hungarian } | ||||||
|  |     { JIS_C6226-1983 iso-ir-87 x0208 JIS_X0208-1983 csISO87JISX0208 } | ||||||
|  |     { greek7 iso-ir-88 csISO88Greek7 } | ||||||
|  |     { ASMO_449 ISO_9036 arabic7 iso-ir-89 csISO89ASMO449 } | ||||||
|  |     { iso-ir-90 csISO90 } | ||||||
|  |     { JIS_C6229-1984-a iso-ir-91 jp-ocr-a csISO91JISC62291984a } | ||||||
|  |     { JIS_C6229-1984-b iso-ir-92 ISO646-JP-OCR-B jp-ocr-b | ||||||
|  |       csISO92JISC62991984b } | ||||||
|  |     { JIS_C6229-1984-b-add iso-ir-93 jp-ocr-b-add csISO93JIS62291984badd } | ||||||
|  |     { JIS_C6229-1984-hand iso-ir-94 jp-ocr-hand csISO94JIS62291984hand } | ||||||
|  |     { JIS_C6229-1984-hand-add iso-ir-95 jp-ocr-hand-add | ||||||
|  |       csISO95JIS62291984handadd } | ||||||
|  |     { JIS_C6229-1984-kana iso-ir-96 csISO96JISC62291984kana } | ||||||
|  |     { ISO_2033-1983 iso-ir-98 e13b csISO2033 } | ||||||
|  |     { ANSI_X3.110-1983 iso-ir-99 CSA_T500-1983 NAPLPS csISO99NAPLPS } | ||||||
|  |     { ISO_8859-1:1987 iso-ir-100 ISO_8859-1 ISO-8859-1 latin1 l1 IBM819 | ||||||
|  |       CP819 csISOLatin1 } | ||||||
|  |     { ISO_8859-2:1987 iso-ir-101 ISO_8859-2 ISO-8859-2 latin2 l2 csISOLatin2 } | ||||||
|  |     { T.61-7bit iso-ir-102 csISO102T617bit } | ||||||
|  |     { T.61-8bit T.61 iso-ir-103 csISO103T618bit } | ||||||
|  |     { ISO_8859-3:1988 iso-ir-109 ISO_8859-3 ISO-8859-3 latin3 l3 csISOLatin3 } | ||||||
|  |     { ISO_8859-4:1988 iso-ir-110 ISO_8859-4 ISO-8859-4 latin4 l4 csISOLatin4 } | ||||||
|  |     { ECMA-cyrillic iso-ir-111 KOI8-E csISO111ECMACyrillic } | ||||||
|  |     { CSA_Z243.4-1985-1 iso-ir-121 ISO646-CA csa7-1 ca csISO121Canadian1 } | ||||||
|  |     { CSA_Z243.4-1985-2 iso-ir-122 ISO646-CA2 csa7-2 csISO122Canadian2 } | ||||||
|  |     { CSA_Z243.4-1985-gr iso-ir-123 csISO123CSAZ24341985gr } | ||||||
|  |     { ISO_8859-6:1987 iso-ir-127 ISO_8859-6 ISO-8859-6 ECMA-114 ASMO-708 | ||||||
|  |       arabic csISOLatinArabic } | ||||||
|  |     { ISO_8859-6-E csISO88596E ISO-8859-6-E } | ||||||
|  |     { ISO_8859-6-I csISO88596I ISO-8859-6-I } | ||||||
|  |     { ISO_8859-7:1987 iso-ir-126 ISO_8859-7 ISO-8859-7 ELOT_928 ECMA-118 | ||||||
|  |       greek greek8 csISOLatinGreek } | ||||||
|  |     { T.101-G2 iso-ir-128 csISO128T101G2 } | ||||||
|  |     { ISO_8859-8:1988 iso-ir-138 ISO_8859-8 ISO-8859-8 hebrew | ||||||
|  |       csISOLatinHebrew } | ||||||
|  |     { ISO_8859-8-E csISO88598E ISO-8859-8-E } | ||||||
|  |     { ISO_8859-8-I csISO88598I ISO-8859-8-I } | ||||||
|  |     { CSN_369103 iso-ir-139 csISO139CSN369103 } | ||||||
|  |     { JUS_I.B1.002 iso-ir-141 ISO646-YU js yu csISO141JUSIB1002 } | ||||||
|  |     { ISO_6937-2-add iso-ir-142 csISOTextComm } | ||||||
|  |     { IEC_P27-1 iso-ir-143 csISO143IECP271 } | ||||||
|  |     { ISO_8859-5:1988 iso-ir-144 ISO_8859-5 ISO-8859-5 cyrillic | ||||||
|  |       csISOLatinCyrillic } | ||||||
|  |     { JUS_I.B1.003-serb iso-ir-146 serbian csISO146Serbian } | ||||||
|  |     { JUS_I.B1.003-mac macedonian iso-ir-147 csISO147Macedonian } | ||||||
|  |     { ISO_8859-9:1989 iso-ir-148 ISO_8859-9 ISO-8859-9 latin5 l5 csISOLatin5 } | ||||||
|  |     { greek-ccitt iso-ir-150 csISO150 csISO150GreekCCITT } | ||||||
|  |     { NC_NC00-10:81 cuba iso-ir-151 ISO646-CU csISO151Cuba } | ||||||
|  |     { ISO_6937-2-25 iso-ir-152 csISO6937Add } | ||||||
|  |     { GOST_19768-74 ST_SEV_358-88 iso-ir-153 csISO153GOST1976874 } | ||||||
|  |     { ISO_8859-supp iso-ir-154 latin1-2-5 csISO8859Supp } | ||||||
|  |     { ISO_10367-box iso-ir-155 csISO10367Box } | ||||||
|  |     { ISO-8859-10 iso-ir-157 l6 ISO_8859-10:1992 csISOLatin6 latin6 } | ||||||
|  |     { latin-lap lap iso-ir-158 csISO158Lap } | ||||||
|  |     { JIS_X0212-1990 x0212 iso-ir-159 csISO159JISX02121990 } | ||||||
|  |     { DS_2089 DS2089 ISO646-DK dk csISO646Danish } | ||||||
|  |     { us-dk csUSDK } | ||||||
|  |     { dk-us csDKUS } | ||||||
|  |     { JIS_X0201 X0201 csHalfWidthKatakana } | ||||||
|  |     { KSC5636 ISO646-KR csKSC5636 } | ||||||
|  |     { ISO-10646-UCS-2 csUnicode } | ||||||
|  |     { ISO-10646-UCS-4 csUCS4 } | ||||||
|  |     { DEC-MCS dec csDECMCS } | ||||||
|  |     { hp-roman8 roman8 r8 csHPRoman8 } | ||||||
|  |     { macintosh mac csMacintosh } | ||||||
|  |     { IBM037 cp037 ebcdic-cp-us ebcdic-cp-ca ebcdic-cp-wt ebcdic-cp-nl | ||||||
|  |       csIBM037 } | ||||||
|  |     { IBM038 EBCDIC-INT cp038 csIBM038 } | ||||||
|  |     { IBM273 CP273 csIBM273 } | ||||||
|  |     { IBM274 EBCDIC-BE CP274 csIBM274 } | ||||||
|  |     { IBM275 EBCDIC-BR cp275 csIBM275 } | ||||||
|  |     { IBM277 EBCDIC-CP-DK EBCDIC-CP-NO csIBM277 } | ||||||
|  |     { IBM278 CP278 ebcdic-cp-fi ebcdic-cp-se csIBM278 } | ||||||
|  |     { IBM280 CP280 ebcdic-cp-it csIBM280 } | ||||||
|  |     { IBM281 EBCDIC-JP-E cp281 csIBM281 } | ||||||
|  |     { IBM284 CP284 ebcdic-cp-es csIBM284 } | ||||||
|  |     { IBM285 CP285 ebcdic-cp-gb csIBM285 } | ||||||
|  |     { IBM290 cp290 EBCDIC-JP-kana csIBM290 } | ||||||
|  |     { IBM297 cp297 ebcdic-cp-fr csIBM297 } | ||||||
|  |     { IBM420 cp420 ebcdic-cp-ar1 csIBM420 } | ||||||
|  |     { IBM423 cp423 ebcdic-cp-gr csIBM423 } | ||||||
|  |     { IBM424 cp424 ebcdic-cp-he csIBM424 } | ||||||
|  |     { IBM437 cp437 437 csPC8CodePage437 } | ||||||
|  |     { IBM500 CP500 ebcdic-cp-be ebcdic-cp-ch csIBM500 } | ||||||
|  |     { IBM775 cp775 csPC775Baltic } | ||||||
|  |     { IBM850 cp850 850 csPC850Multilingual } | ||||||
|  |     { IBM851 cp851 851 csIBM851 } | ||||||
|  |     { IBM852 cp852 852 csPCp852 } | ||||||
|  |     { IBM855 cp855 855 csIBM855 } | ||||||
|  |     { IBM857 cp857 857 csIBM857 } | ||||||
|  |     { IBM860 cp860 860 csIBM860 } | ||||||
|  |     { IBM861 cp861 861 cp-is csIBM861 } | ||||||
|  |     { IBM862 cp862 862 csPC862LatinHebrew } | ||||||
|  |     { IBM863 cp863 863 csIBM863 } | ||||||
|  |     { IBM864 cp864 csIBM864 } | ||||||
|  |     { IBM865 cp865 865 csIBM865 } | ||||||
|  |     { IBM866 cp866 866 csIBM866 } | ||||||
|  |     { IBM868 CP868 cp-ar csIBM868 } | ||||||
|  |     { IBM869 cp869 869 cp-gr csIBM869 } | ||||||
|  |     { IBM870 CP870 ebcdic-cp-roece ebcdic-cp-yu csIBM870 } | ||||||
|  |     { IBM871 CP871 ebcdic-cp-is csIBM871 } | ||||||
|  |     { IBM880 cp880 EBCDIC-Cyrillic csIBM880 } | ||||||
|  |     { IBM891 cp891 csIBM891 } | ||||||
|  |     { IBM903 cp903 csIBM903 } | ||||||
|  |     { IBM904 cp904 904 csIBBM904 } | ||||||
|  |     { IBM905 CP905 ebcdic-cp-tr csIBM905 } | ||||||
|  |     { IBM918 CP918 ebcdic-cp-ar2 csIBM918 } | ||||||
|  |     { IBM1026 CP1026 csIBM1026 } | ||||||
|  |     { EBCDIC-AT-DE csIBMEBCDICATDE } | ||||||
|  |     { EBCDIC-AT-DE-A csEBCDICATDEA } | ||||||
|  |     { EBCDIC-CA-FR csEBCDICCAFR } | ||||||
|  |     { EBCDIC-DK-NO csEBCDICDKNO } | ||||||
|  |     { EBCDIC-DK-NO-A csEBCDICDKNOA } | ||||||
|  |     { EBCDIC-FI-SE csEBCDICFISE } | ||||||
|  |     { EBCDIC-FI-SE-A csEBCDICFISEA } | ||||||
|  |     { EBCDIC-FR csEBCDICFR } | ||||||
|  |     { EBCDIC-IT csEBCDICIT } | ||||||
|  |     { EBCDIC-PT csEBCDICPT } | ||||||
|  |     { EBCDIC-ES csEBCDICES } | ||||||
|  |     { EBCDIC-ES-A csEBCDICESA } | ||||||
|  |     { EBCDIC-ES-S csEBCDICESS } | ||||||
|  |     { EBCDIC-UK csEBCDICUK } | ||||||
|  |     { EBCDIC-US csEBCDICUS } | ||||||
|  |     { UNKNOWN-8BIT csUnknown8BiT } | ||||||
|  |     { MNEMONIC csMnemonic } | ||||||
|  |     { MNEM csMnem } | ||||||
|  |     { VISCII csVISCII } | ||||||
|  |     { VIQR csVIQR } | ||||||
|  |     { KOI8-R csKOI8R } | ||||||
|  |     { IBM00858 CCSID00858 CP00858 PC-Multilingual-850+euro } | ||||||
|  |     { IBM00924 CCSID00924 CP00924 ebcdic-Latin9--euro } | ||||||
|  |     { IBM01140 CCSID01140 CP01140 ebcdic-us-37+euro } | ||||||
|  |     { IBM01141 CCSID01141 CP01141 ebcdic-de-273+euro } | ||||||
|  |     { IBM01142 CCSID01142 CP01142 ebcdic-dk-277+euro ebcdic-no-277+euro } | ||||||
|  |     { IBM01143 CCSID01143 CP01143 ebcdic-fi-278+euro ebcdic-se-278+euro } | ||||||
|  |     { IBM01144 CCSID01144 CP01144 ebcdic-it-280+euro } | ||||||
|  |     { IBM01145 CCSID01145 CP01145 ebcdic-es-284+euro } | ||||||
|  |     { IBM01146 CCSID01146 CP01146 ebcdic-gb-285+euro } | ||||||
|  |     { IBM01147 CCSID01147 CP01147 ebcdic-fr-297+euro } | ||||||
|  |     { IBM01148 CCSID01148 CP01148 ebcdic-international-500+euro } | ||||||
|  |     { IBM01149 CCSID01149 CP01149 ebcdic-is-871+euro } | ||||||
|  |     { IBM1047 IBM-1047 } | ||||||
|  |     { PTCP154 csPTCP154 PT154 CP154 Cyrillic-Asian } | ||||||
|  |     { Amiga-1251 Ami1251 Amiga1251 Ami-1251 } | ||||||
|  |     { UNICODE-1-1 csUnicode11 } | ||||||
|  |     { CESU-8 csCESU-8 } | ||||||
|  |     { BOCU-1 csBOCU-1 } | ||||||
|  |     { UNICODE-1-1-UTF-7 csUnicode11UTF7 } | ||||||
|  |     { ISO-8859-14 iso-ir-199 ISO_8859-14:1998 ISO_8859-14 latin8 iso-celtic | ||||||
|  |       l8 } | ||||||
|  |     { ISO-8859-15 ISO_8859-15 Latin-9 } | ||||||
|  |     { ISO-8859-16 iso-ir-226 ISO_8859-16:2001 ISO_8859-16 latin10 l10 } | ||||||
|  |     { GBK CP936 MS936 windows-936 } | ||||||
|  |     { JIS_Encoding csJISEncoding } | ||||||
|  |     { Shift_JIS MS_Kanji csShiftJIS } | ||||||
|  |     { Extended_UNIX_Code_Packed_Format_for_Japanese csEUCPkdFmtJapanese | ||||||
|  |       EUC-JP } | ||||||
|  |     { Extended_UNIX_Code_Fixed_Width_for_Japanese csEUCFixWidJapanese } | ||||||
|  |     { ISO-10646-UCS-Basic csUnicodeASCII } | ||||||
|  |     { ISO-10646-Unicode-Latin1 csUnicodeLatin1 ISO-10646 } | ||||||
|  |     { ISO-Unicode-IBM-1261 csUnicodeIBM1261 } | ||||||
|  |     { ISO-Unicode-IBM-1268 csUnicodeIBM1268 } | ||||||
|  |     { ISO-Unicode-IBM-1276 csUnicodeIBM1276 } | ||||||
|  |     { ISO-Unicode-IBM-1264 csUnicodeIBM1264 } | ||||||
|  |     { ISO-Unicode-IBM-1265 csUnicodeIBM1265 } | ||||||
|  |     { ISO-8859-1-Windows-3.0-Latin-1 csWindows30Latin1 } | ||||||
|  |     { ISO-8859-1-Windows-3.1-Latin-1 csWindows31Latin1 } | ||||||
|  |     { ISO-8859-2-Windows-Latin-2 csWindows31Latin2 } | ||||||
|  |     { ISO-8859-9-Windows-Latin-5 csWindows31Latin5 } | ||||||
|  |     { Adobe-Standard-Encoding csAdobeStandardEncoding } | ||||||
|  |     { Ventura-US csVenturaUS } | ||||||
|  |     { Ventura-International csVenturaInternational } | ||||||
|  |     { PC8-Danish-Norwegian csPC8DanishNorwegian } | ||||||
|  |     { PC8-Turkish csPC8Turkish } | ||||||
|  |     { IBM-Symbols csIBMSymbols } | ||||||
|  |     { IBM-Thai csIBMThai } | ||||||
|  |     { HP-Legal csHPLegal } | ||||||
|  |     { HP-Pi-font csHPPiFont } | ||||||
|  |     { HP-Math8 csHPMath8 } | ||||||
|  |     { Adobe-Symbol-Encoding csHPPSMath } | ||||||
|  |     { HP-DeskTop csHPDesktop } | ||||||
|  |     { Ventura-Math csVenturaMath } | ||||||
|  |     { Microsoft-Publishing csMicrosoftPublishing } | ||||||
|  |     { Windows-31J csWindows31J } | ||||||
|  |     { GB2312 csGB2312 } | ||||||
|  |     { Big5 csBig5 } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | proc tcl_encoding {enc} { | ||||||
|  |     global encoding_aliases | ||||||
|  |     set names [encoding names] | ||||||
|  |     set lcnames [string tolower $names] | ||||||
|  |     set enc [string tolower $enc] | ||||||
|  |     set i [lsearch -exact $lcnames $enc] | ||||||
|  |     if {$i < 0} { | ||||||
|  | 	# look for "isonnn" instead of "iso-nnn" or "iso_nnn" | ||||||
|  | 	if {[regsub {^iso[-_]} $enc iso encx]} { | ||||||
|  | 	    set i [lsearch -exact $lcnames $encx] | ||||||
|  | 	} | ||||||
|  |     } | ||||||
|  |     if {$i < 0} { | ||||||
|  | 	foreach l $encoding_aliases { | ||||||
|  | 	    set ll [string tolower $l] | ||||||
|  | 	    if {[lsearch -exact $ll $enc] < 0} continue | ||||||
|  | 	    # look through the aliases for one that tcl knows about | ||||||
|  | 	    foreach e $ll { | ||||||
|  | 		set i [lsearch -exact $lcnames $e] | ||||||
|  | 		if {$i < 0} { | ||||||
|  | 		    if {[regsub {^iso[-_]} $e iso ex]} { | ||||||
|  | 			set i [lsearch -exact $lcnames $ex] | ||||||
|  | 		    } | ||||||
|  | 		} | ||||||
|  | 		if {$i >= 0} break | ||||||
|  | 	    } | ||||||
|  | 	    break | ||||||
|  | 	} | ||||||
|  |     } | ||||||
|  |     if {$i >= 0} { | ||||||
|  | 	return [lindex $names $i] | ||||||
|  |     } | ||||||
|  |     return {} | ||||||
|  | } | ||||||
|  | @ -51,12 +51,15 @@ proc ask_popup {msg} { | ||||||
| 	if {[reponame] ne {}} { | 	if {[reponame] ne {}} { | ||||||
| 		append title " ([reponame])" | 		append title " ([reponame])" | ||||||
| 	} | 	} | ||||||
| 	return [tk_messageBox \ | 	set cmd [list tk_messageBox \ | ||||||
| 		-parent . \ |  | ||||||
| 		-icon question \ | 		-icon question \ | ||||||
| 		-type yesno \ | 		-type yesno \ | ||||||
| 		-title $title \ | 		-title $title \ | ||||||
| 		-message $msg] | 		-message $msg] | ||||||
|  | 	if {[winfo ismapped .]} { | ||||||
|  | 		lappend cmd -parent . | ||||||
|  | 	} | ||||||
|  | 	eval $cmd | ||||||
| } | } | ||||||
|  |  | ||||||
| proc hook_failed_popup {hook msg} { | proc hook_failed_popup {hook msg} { | ||||||
|  |  | ||||||
|  | @ -360,7 +360,7 @@ proc revert_helper {txt paths} { | ||||||
| 		"[appname] ([reponame])" \ | 		"[appname] ([reponame])" \ | ||||||
| 		"Revert changes in $s? | 		"Revert changes in $s? | ||||||
|  |  | ||||||
| Any unadded changes will be permanently lost by the revert." \ | Any unstaged changes will be permanently lost by the revert." \ | ||||||
| 		question \ | 		question \ | ||||||
| 		1 \ | 		1 \ | ||||||
| 		{Do Nothing} \ | 		{Do Nothing} \ | ||||||
|  |  | ||||||
|  | @ -1,9 +1,12 @@ | ||||||
| # git-gui branch merge support | # git-gui branch merge support | ||||||
| # Copyright (C) 2006, 2007 Shawn Pearce | # Copyright (C) 2006, 2007 Shawn Pearce | ||||||
|  |  | ||||||
| namespace eval merge { | class merge { | ||||||
|  |  | ||||||
| proc _can_merge {} { | field w         ; # top level window | ||||||
|  | field w_rev     ; # mega-widget to pick the revision to merge | ||||||
|  |  | ||||||
|  | method _can_merge {} { | ||||||
| 	global HEAD commit_type file_states | 	global HEAD commit_type file_states | ||||||
|  |  | ||||||
| 	if {[string match amend* $commit_type]} { | 	if {[string match amend* $commit_type]} { | ||||||
|  | @ -42,7 +45,7 @@ The rescan will be automatically started now. | ||||||
|  |  | ||||||
| File [short_path $path] has merge conflicts. | 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. | You must resolve them, stage the file, and commit to complete the current merge.  Only then can you begin another merge. | ||||||
| " | " | ||||||
| 			unlock_index | 			unlock_index | ||||||
| 			return 0 | 			return 0 | ||||||
|  | @ -63,147 +66,93 @@ You should complete the current commit before starting a merge.  Doing so will h | ||||||
| 	return 1 | 	return 1 | ||||||
| } | } | ||||||
|  |  | ||||||
| proc _refs {w list} { | method _rev {} { | ||||||
| 	set r {} | 	if {[catch {$w_rev commit_or_die}]} { | ||||||
| 	foreach i [$w.source.l curselection] { | 		return {} | ||||||
| 		lappend r [lindex [lindex $list $i] 0] |  | ||||||
| 	} | 	} | ||||||
| 	return $r | 	return [$w_rev get] | ||||||
| } | } | ||||||
|  |  | ||||||
| proc _visualize {w list} { | method _visualize {} { | ||||||
| 	set revs [_refs $w $list] | 	set rev [_rev $this] | ||||||
| 	if {$revs eq {}} return | 	if {$rev ne {}} { | ||||||
| 	lappend revs --not HEAD | 		do_gitk [list $rev --not HEAD] | ||||||
| 	do_gitk $revs | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| proc _start {w list} { | method _start {} { | ||||||
| 	global HEAD current_branch | 	global HEAD current_branch remote_url | ||||||
|  |  | ||||||
| 	set cmd [list git merge] | 	set name [_rev $this] | ||||||
| 	set names [_refs $w $list] | 	if {$name eq {}} { | ||||||
| 	set revcnt [llength $names] |  | ||||||
| 	append cmd { } $names |  | ||||||
|  |  | ||||||
| 	if {$revcnt == 0} { |  | ||||||
| 		return | 		return | ||||||
| 	} elseif {$revcnt == 1} { | 	} | ||||||
| 		set unit branch |  | ||||||
| 	} elseif {$revcnt <= 15} { |  | ||||||
| 		set unit branches |  | ||||||
|  |  | ||||||
| 		if {[tk_dialog \ | 	set spec [$w_rev get_tracking_branch] | ||||||
| 		$w.confirm_octopus \ | 	set cmit [$w_rev get_commit] | ||||||
| 		[wm title $w] \ |  | ||||||
| 		"Use octopus merge strategy? |  | ||||||
|  |  | ||||||
| You are merging $revcnt branches at once.  This requires using the octopus merge driver, which may not succeed if there are file-level conflicts. | 	set fh [open [gitdir FETCH_HEAD] w] | ||||||
| " \ | 	fconfigure $fh -translation lf | ||||||
| 		question \ | 	if {$spec eq {}} { | ||||||
| 		0 \ | 		set remote . | ||||||
| 		{Cancel} \ | 		set branch $name | ||||||
| 		{Use octopus} \ | 		set stitle $branch | ||||||
| 		] != 1} return |  | ||||||
| 	} else { | 	} else { | ||||||
| 		tk_messageBox \ | 		set remote $remote_url([lindex $spec 1]) | ||||||
| 			-icon error \ | 		if {[regexp {^[^:@]*@[^:]*:/} $remote]} { | ||||||
| 			-type ok \ | 			regsub {^[^:@]*@} $remote {} remote | ||||||
| 			-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 branch [lindex $spec 2] | ||||||
|  | 		set stitle "$branch of $remote" | ||||||
|  | 	} | ||||||
|  | 	regsub ^refs/heads/ $branch {} branch | ||||||
|  | 	puts $fh "$cmit\t\tbranch '$branch' of $remote" | ||||||
|  | 	close $fh | ||||||
|  |  | ||||||
| 	set msg "Merging $current_branch, [join $names {, }]" | 	set cmd [list git] | ||||||
|  | 	lappend cmd merge | ||||||
|  | 	lappend cmd --strategy=recursive | ||||||
|  | 	lappend cmd [git fmt-merge-msg <[gitdir FETCH_HEAD]] | ||||||
|  | 	lappend cmd HEAD | ||||||
|  | 	lappend cmd $cmit | ||||||
|  |  | ||||||
|  | 	set msg "Merging $current_branch and $stitle" | ||||||
| 	ui_status "$msg..." | 	ui_status "$msg..." | ||||||
| 	set cons [console::new "Merge" $msg] | 	set cons [console::new "Merge" "merge $stitle"] | ||||||
| 	console::exec $cons $cmd \ | 	console::exec $cons $cmd [cb _finish $cons] | ||||||
| 		[namespace code [list _finish $revcnt $cons]] |  | ||||||
|  |  | ||||||
| 	wm protocol $w WM_DELETE_WINDOW {} | 	wm protocol $w WM_DELETE_WINDOW {} | ||||||
| 	destroy $w | 	destroy $w | ||||||
| } | } | ||||||
|  |  | ||||||
| proc _finish {revcnt w ok} { | method _finish {cons ok} { | ||||||
| 	console::done $w $ok | 	console::done $cons $ok | ||||||
| 	if {$ok} { | 	if {$ok} { | ||||||
| 		set msg {Merge completed successfully.} | 		set msg {Merge completed successfully.} | ||||||
| 	} else { | 	} 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 [git_read read-tree --reset -u HEAD] |  | ||||||
| 			fconfigure $fd -blocking 0 -translation binary |  | ||||||
| 			fileevent $fd readable \ |  | ||||||
| 				[namespace code [list _reset_wait $fd]] |  | ||||||
| 			ui_status {Aborting... please wait...} |  | ||||||
| 			return |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		set msg {Merge failed.  Conflict resolution is required.} | 		set msg {Merge failed.  Conflict resolution is required.} | ||||||
| 	} | 	} | ||||||
| 	unlock_index | 	unlock_index | ||||||
| 	rescan [list ui_status $msg] | 	rescan [list ui_status $msg] | ||||||
|  | 	delete_this | ||||||
| } | } | ||||||
|  |  | ||||||
| proc dialog {} { | constructor dialog {} { | ||||||
| 	global current_branch | 	global current_branch | ||||||
| 	global M1B | 	global M1B | ||||||
|  |  | ||||||
| 	if {![_can_merge]} return | 	if {![_can_merge $this]} { | ||||||
|  | 		delete_this | ||||||
| 	set fmt {list %(objectname) %(*objectname) %(refname) %(subject)} | 		return | ||||||
| 	set fr_fd [git_read for-each-ref \ |  | ||||||
| 		--tcl \ |  | ||||||
| 		--format=$fmt \ |  | ||||||
| 		refs/heads \ |  | ||||||
| 		refs/remotes \ |  | ||||||
| 		refs/tags \ |  | ||||||
| 		] |  | ||||||
| 	fconfigure $fr_fd -translation binary |  | ||||||
| 	while {[gets $fr_fd line] > 0} { |  | ||||||
| 		set line [eval $line] |  | ||||||
| 		set ref [lindex $line 2] |  | ||||||
| 		regsub ^refs/(heads|remotes|tags)/ $ref {} ref |  | ||||||
| 		set subj($ref) [lindex $line 3] |  | ||||||
| 		lappend sha1([lindex $line 0]) $ref |  | ||||||
| 		if {[lindex $line 1] ne {}} { |  | ||||||
| 			lappend sha1([lindex $line 1]) $ref |  | ||||||
| 	} | 	} | ||||||
| 	} |  | ||||||
| 	close $fr_fd |  | ||||||
|  |  | ||||||
| 	set to_show {} | 	make_toplevel top w | ||||||
| 	set fr_fd [git_read rev-list --all --not HEAD] | 	wm title $top "[appname] ([reponame]): Merge" | ||||||
| 	while {[gets $fr_fd line] > 0} { | 	if {$top ne {.}} { | ||||||
| 		if {[catch {set ref $sha1($line)}]} continue | 		wm geometry $top "+[winfo rootx .]+[winfo rooty .]" | ||||||
| 		foreach n $ref { |  | ||||||
| 			lappend to_show [list $n $line] |  | ||||||
| 	} | 	} | ||||||
| 	} |  | ||||||
| 	close $fr_fd |  | ||||||
| 	set to_show [lsort -unique $to_show] |  | ||||||
|  |  | ||||||
| 	set w .merge_setup | 	set _start [cb _start] | ||||||
| 	toplevel $w |  | ||||||
| 	wm geometry $w "+[winfo rootx .]+[winfo rooty .]" |  | ||||||
|  |  | ||||||
| 	set _visualize [namespace code [list _visualize $w $to_show]] |  | ||||||
| 	set _start [namespace code [list _start $w $to_show]] |  | ||||||
|  |  | ||||||
| 	label $w.header \ | 	label $w.header \ | ||||||
| 		-text "Merge Into $current_branch" \ | 		-text "Merge Into $current_branch" \ | ||||||
|  | @ -211,55 +160,51 @@ proc dialog {} { | ||||||
| 	pack $w.header -side top -fill x | 	pack $w.header -side top -fill x | ||||||
|  |  | ||||||
| 	frame $w.buttons | 	frame $w.buttons | ||||||
| 	button $w.buttons.visualize -text Visualize -command $_visualize | 	button $w.buttons.visualize \ | ||||||
|  | 		-text Visualize \ | ||||||
|  | 		-command [cb _visualize] | ||||||
| 	pack $w.buttons.visualize -side left | 	pack $w.buttons.visualize -side left | ||||||
| 	button $w.buttons.create -text Merge -command $_start | 	button $w.buttons.merge \ | ||||||
| 	pack $w.buttons.create -side right | 		-text Merge \ | ||||||
|  | 		-command $_start | ||||||
|  | 	pack $w.buttons.merge -side right | ||||||
| 	button $w.buttons.cancel \ | 	button $w.buttons.cancel \ | ||||||
| 		-text {Cancel} \ | 		-text {Cancel} \ | ||||||
| 		-command "unlock_index;destroy $w" | 		-command [cb _cancel] | ||||||
| 	pack $w.buttons.cancel -side right -padx 5 | 	pack $w.buttons.cancel -side right -padx 5 | ||||||
| 	pack $w.buttons -side bottom -fill x -pady 10 -padx 10 | 	pack $w.buttons -side bottom -fill x -pady 10 -padx 10 | ||||||
|  |  | ||||||
| 	labelframe $w.source -text {Source Branches} | 	set w_rev [::choose_rev::new_unmerged $w.rev {Revision To Merge}] | ||||||
| 	listbox $w.source.l \ | 	pack $w.rev -anchor nw -fill both -expand 1 -pady 5 -padx 5 | ||||||
| 		-height 10 \ |  | ||||||
| 		-width 70 \ |  | ||||||
| 		-font font_diff \ |  | ||||||
| 		-selectmode extended \ |  | ||||||
| 		-yscrollcommand [list $w.source.sby set] |  | ||||||
| 	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 |  | ||||||
|  |  | ||||||
| 	foreach ref $to_show { |  | ||||||
| 		set n [lindex $ref 0] |  | ||||||
| 		if {[string length $n] > 20} { |  | ||||||
| 			set n "[string range $n 0 16]..." |  | ||||||
| 		} |  | ||||||
| 		$w.source.l insert end [format {%s %-20s %s} \ |  | ||||||
| 			[string range [lindex $ref 1] 0 5] \ |  | ||||||
| 			$n \ |  | ||||||
| 			$subj([lindex $ref 0])] |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	bind $w.source.l <Key-K> [list event generate %W <Shift-Key-Up>] |  | ||||||
| 	bind $w.source.l <Key-J> [list event generate %W <Shift-Key-Down>] |  | ||||||
| 	bind $w.source.l <Key-k> [list event generate %W <Key-Up>] |  | ||||||
| 	bind $w.source.l <Key-j> [list event generate %W <Key-Down>] |  | ||||||
| 	bind $w.source.l <Key-h> [list event generate %W <Key-Left>] |  | ||||||
| 	bind $w.source.l <Key-l> [list event generate %W <Key-Right>] |  | ||||||
| 	bind $w.source.l <Key-v> $_visualize |  | ||||||
|  |  | ||||||
| 	bind $w <$M1B-Key-Return> $_start | 	bind $w <$M1B-Key-Return> $_start | ||||||
| 	bind $w <Visibility> "grab $w; focus $w.source.l" | 	bind $w <Key-Return> $_start | ||||||
| 	bind $w <Key-Escape> "unlock_index;destroy $w" | 	bind $w <Key-Escape> [cb _cancel] | ||||||
| 	wm protocol $w WM_DELETE_WINDOW "unlock_index;destroy $w" | 	wm protocol $w WM_DELETE_WINDOW [cb _cancel] | ||||||
| 	wm title $w "[appname] ([reponame]): Merge" |  | ||||||
|  | 	bind $w.buttons.merge <Visibility> [cb _visible] | ||||||
| 	tkwait window $w | 	tkwait window $w | ||||||
| } | } | ||||||
|  |  | ||||||
|  | method _visible {} { | ||||||
|  | 	grab $w | ||||||
|  | 	if {[is_config_true gui.matchtrackingbranch]} { | ||||||
|  | 		$w_rev pick_tracking_branch | ||||||
|  | 	} | ||||||
|  | 	$w_rev focus_filter | ||||||
|  | } | ||||||
|  |  | ||||||
|  | method _cancel {} { | ||||||
|  | 	wm protocol $w WM_DELETE_WINDOW {} | ||||||
|  | 	unlock_index | ||||||
|  | 	destroy $w | ||||||
|  | 	delete_this | ||||||
|  | } | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | namespace eval merge { | ||||||
|  |  | ||||||
| proc reset_hard {} { | proc reset_hard {} { | ||||||
| 	global HEAD commit_type file_states | 	global HEAD commit_type file_states | ||||||
|  |  | ||||||
|  | @ -274,20 +219,24 @@ You must finish amending this commit. | ||||||
| 	if {![lock_index abort]} return | 	if {![lock_index abort]} return | ||||||
|  |  | ||||||
| 	if {[string match *merge* $commit_type]} { | 	if {[string match *merge* $commit_type]} { | ||||||
| 		set op merge | 		set op_question "Abort merge? | ||||||
|  |  | ||||||
|  | Aborting the current merge will cause *ALL* uncommitted changes to be lost. | ||||||
|  |  | ||||||
|  | Continue with aborting the current merge?" | ||||||
| 	} else { | 	} else { | ||||||
| 		set op commit | 		set op_question "Reset changes? | ||||||
|  |  | ||||||
|  | Resetting the changes will cause *ALL* uncommitted changes to be lost. | ||||||
|  |  | ||||||
|  | Continue with resetting the current changes?" | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if {[ask_popup "Abort $op? | 	if {[ask_popup $op_question] eq {yes}} { | ||||||
|  | 		set fd [git_read --stderr read-tree --reset -u -v HEAD] | ||||||
| Aborting the current $op will cause *ALL* uncommitted changes to be lost. |  | ||||||
|  |  | ||||||
| Continue with aborting the current $op?"] eq {yes}} { |  | ||||||
| 		set fd [git_read read-tree --reset -u HEAD] |  | ||||||
| 		fconfigure $fd -blocking 0 -translation binary | 		fconfigure $fd -blocking 0 -translation binary | ||||||
| 		fileevent $fd readable [namespace code [list _reset_wait $fd]] | 		fileevent $fd readable [namespace code [list _reset_wait $fd]] | ||||||
| 		ui_status {Aborting... please wait...} | 		$::main_status start {Aborting} {files reset} | ||||||
| 	} else { | 	} else { | ||||||
| 		unlock_index | 		unlock_index | ||||||
| 	} | 	} | ||||||
|  | @ -296,9 +245,12 @@ Continue with aborting the current $op?"] eq {yes}} { | ||||||
| proc _reset_wait {fd} { | proc _reset_wait {fd} { | ||||||
| 	global ui_comm | 	global ui_comm | ||||||
|  |  | ||||||
| 	read $fd | 	$::main_status update_meter [read $fd] | ||||||
|  |  | ||||||
|  | 	fconfigure $fd -blocking 1 | ||||||
| 	if {[eof $fd]} { | 	if {[eof $fd]} { | ||||||
| 		close $fd | 		set fail [catch {close $fd} err] | ||||||
|  | 		$::main_status stop | ||||||
| 		unlock_index | 		unlock_index | ||||||
|  |  | ||||||
| 		$ui_comm delete 0.0 end | 		$ui_comm delete 0.0 end | ||||||
|  | @ -310,7 +262,12 @@ proc _reset_wait {fd} { | ||||||
| 		catch {file delete [gitdir MERGE_MSG]} | 		catch {file delete [gitdir MERGE_MSG]} | ||||||
| 		catch {file delete [gitdir GITGUI_MSG]} | 		catch {file delete [gitdir GITGUI_MSG]} | ||||||
|  |  | ||||||
|  | 		if {$fail} { | ||||||
|  | 			warn_popup "Abort failed.\n\n$err" | ||||||
|  | 		} | ||||||
| 		rescan {ui_status {Abort completed.  Ready.}} | 		rescan {ui_status {Abort completed.  Ready.}} | ||||||
|  | 	} else { | ||||||
|  | 		fconfigure $fd -blocking 0 | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @ -57,6 +57,7 @@ proc all_tracking_branches {} { | ||||||
| proc load_all_remotes {} { | proc load_all_remotes {} { | ||||||
| 	global repo_config | 	global repo_config | ||||||
| 	global all_remotes tracking_branches some_heads_tracking | 	global all_remotes tracking_branches some_heads_tracking | ||||||
|  | 	global remote_url | ||||||
|  |  | ||||||
| 	set some_heads_tracking 0 | 	set some_heads_tracking 0 | ||||||
| 	set all_remotes [list] | 	set all_remotes [list] | ||||||
|  | @ -76,6 +77,10 @@ proc load_all_remotes {} { | ||||||
| 			catch { | 			catch { | ||||||
| 				set fd [open [file join $rm_dir $name] r] | 				set fd [open [file join $rm_dir $name] r] | ||||||
| 				while {[gets $fd line] >= 0} { | 				while {[gets $fd line] >= 0} { | ||||||
|  | 					if {[regexp {^URL:[ 	]*(.+)$} $line line url]} { | ||||||
|  | 						set remote_url($name) $url | ||||||
|  | 						continue | ||||||
|  | 					} | ||||||
| 					if {![regexp {^Pull:[ 	]*([^:]+):(.+)$} \ | 					if {![regexp {^Pull:[ 	]*([^:]+):(.+)$} \ | ||||||
| 						$line line src dst]} continue | 						$line line src dst]} continue | ||||||
| 					if {[string index $src 0] eq {+}} { | 					if {[string index $src 0] eq {+}} { | ||||||
|  | @ -100,6 +105,7 @@ proc load_all_remotes {} { | ||||||
| 	foreach line [array names repo_config remote.*.url] { | 	foreach line [array names repo_config remote.*.url] { | ||||||
| 		if {![regexp ^remote\.(.*)\.url\$ $line line name]} continue | 		if {![regexp ^remote\.(.*)\.url\$ $line line name]} continue | ||||||
| 		lappend all_remotes $name | 		lappend all_remotes $name | ||||||
|  | 		set remote_url($name) $repo_config(remote.$name.url) | ||||||
|  |  | ||||||
| 		if {[catch {set fl $repo_config(remote.$name.fetch)}]} { | 		if {[catch {set fl $repo_config(remote.$name.fetch)}]} { | ||||||
| 			set fl {} | 			set fl {} | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	 Junio C Hamano
						Junio C Hamano