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
  ...
This commit is contained in:
Junio C Hamano 2007-07-29 22:53:33 -07:00
Родитель 89b2f19cb5 84f67537b1
Коммит b8de7f764e
13 изменённых файлов: 1131 добавлений и 427 удалений

Просмотреть файл

@ -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,19 +691,24 @@ 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 {[lindex [file split $_gitdir] end] ne {.git}} { if {![is_enabled bare]} {
catch {wm withdraw .} if {[lindex [file split $_gitdir] end] ne {.git}} {
error_popup "Cannot use funny .git directory:\n\n$_gitdir" catch {wm withdraw .}
exit 1 error_popup "Cannot use funny .git directory:\n\n$_gitdir"
exit 1
}
if {[catch {cd [file dirname $_gitdir]} err]} {
catch {wm withdraw .}
error_popup "No working directory [file dirname $_gitdir]:\n\n$err"
exit 1
}
} }
if {[catch {cd [file dirname $_gitdir]} err]} { set _reponame [file split [file normalize $_gitdir]]
catch {wm withdraw .} if {[lindex $_reponame end] eq {.git}} {
error_popup "No working directory [file dirname $_gitdir]:\n\n$err" set _reponame [lindex $_reponame end-1]
exit 1 } else {
set _reponame [lindex $_reponame end]
} }
set _reponame [lindex [file split \
[file normalize [file dirname $_gitdir]]] \
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,18 +1405,30 @@ proc do_quit {} {
# -- Stash our current commit buffer. # -- Stash our current commit buffer.
# #
set save [gitdir GITGUI_MSG] set save [gitdir GITGUI_MSG]
set msg [string trim [$ui_comm get 0.0 end]] if {$GITGUI_BCK_exists && ![$ui_comm edit modified]} {
regsub -all -line {[ \r\t]+$} $msg {} msg file rename -force [gitdir GITGUI_BCK] $save
if {(![string match amend* $commit_type] set GITGUI_BCK_exists 0
|| [$ui_comm edit modified])
&& $msg ne {}} {
catch {
set fd [open $save w]
puts -nonewline $fd $msg
close $fd
}
} else { } else {
catch {file delete $save} set msg [string trim [$ui_comm get 0.0 end]]
regsub -all -line {[ \r\t]+$} $msg {} msg
if {(![string match amend* $commit_type]
|| [$ui_comm edit modified])
&& $msg ne {}} {
catch {
set fd [open $save w]
puts -nonewline $fd $msg
close $fd
}
} else {
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 {
blame::new $head $path 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
}
}
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 {[is_enabled multicommit]} {
set object_limit 2000
if {[is_Windows]} {set object_limit 200}
regexp {^([0-9]+) objects,} [git count-objects] _junk objects_current
if {$objects_current >= $object_limit} {
if {[ask_popup \
"This repository currently has $objects_current loose objects.
To maintain optimal performance it is strongly recommended that you compress the database when more than $object_limit loose objects exist. # -- If both our backup and message files exist use the
# newer of the two files to initialize the buffer.
Compress the database now?"] eq yes} { #
do_gc if {$GITGUI_BCK_exists} {
set m [gitdir GITGUI_MSG]
if {[file isfile $m]} {
if {[file mtime [gitdir GITGUI_BCK]] > [file mtime $m]} {
catch {file delete [gitdir GITGUI_MSG]}
} else {
$ui_comm delete 0.0 end
$ui_comm edit reset
$ui_comm edit modified false
catch {file delete [gitdir GITGUI_BCK]}
set GITGUI_BCK_exists 0
}
} }
unset m
} }
unset object_limit _junk objects_current
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 author_name [encoding convertfrom $enc $author_name] set enc [tcl_encoding $enc]
set committer_name [encoding convertfrom $enc $committer_name] if {$enc ne {}} {
set msg [encoding convertfrom $enc $msg]
set header($cmit,author) $author_name set author_name [encoding convertfrom $enc $author_name]
set header($cmit,committer) $committer_name set committer_name [encoding convertfrom $enc $committer_name]
set header($cmit,author) $author_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 { # The current branch is older.
ff { #
if {$mrb eq $new} { set reflog_msg "merge $new_expr: Fast-forward"
# The current branch is actually newer. } else {
# switch -- $merge_type {
set new $cur ff {
} elseif {$mrb eq $cur} { if {$merge_base eq $new} {
# The current branch is older. # The current branch is actually newer.
# #
set reflog_msg "merge $new_expr: Fast-forward" set new $cur
} else { set new_hash $cur
_error $this "Branch '$newbranch' already exists.\n\nIt cannot fast-forward to $new_expr.\nA merge is required." } else {
return 0 _error $this "Branch '$newbranch' already exists.\n\nIt cannot fast-forward to $new_expr.\nA merge is required."
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,11 +216,11 @@ method _update_ref {} {
return 0 return 0
} }
} }
} default {
default { _error $this "Merge strategy '$merge_type' not supported."
_error $this "Only 'ff' and 'reset' merge is currently supported." return 0
return 0 }
} }
} }
} }
@ -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,22 +385,24 @@ 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]
append log " to $new_branch" if {$is_detached || $current_branch ne $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]} {
_fatal $this $err _fatal $this $err
}
set current_branch $new_branch
set is_detached 0
} }
set current_branch $new_branch
set is_detached 0
} else { } else {
append log " to $new_expr" if {$new_hash ne $HEAD} {
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)]} {
lappend spec_trck [concat $name $spec] regsub ^refs/(heads|remotes)/ $refn {} name
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]

276
git-gui/lib/encoding.tcl Normal file
Просмотреть файл

@ -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 \ set branch [lindex $spec 2]
-message "Too many branches selected. set stitle "$branch of $remote"
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
} }
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 {}