From: Junio C Hamano Date: Sat, 26 Mar 2011 17:42:26 +0000 (-0700) Subject: Merge git-gui 0.14.0 X-Git-Tag: v1.7.5-rc0~24 X-Git-Url: https://git.tokkee.org/?a=commitdiff_plain;h=42f98745732c68baa6d79a50eab0d726b549025d;p=git.git Merge git-gui 0.14.0 --- 42f98745732c68baa6d79a50eab0d726b549025d diff --cc git-gui/git-gui.sh index d3acf0d21,000000000..fd6a43d0a mode 100755,000000..100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@@ -1,3861 -1,0 +1,3894 @@@ +#!/bin/sh +# Tcl ignores the next line -*- tcl -*- \ + if test "z$*" = zversion \ + || test "z$*" = z--version; \ + then \ + echo 'git-gui version @@GITGUI_VERSION@@'; \ + exit; \ + fi; \ + argv0=$0; \ + exec wish "$argv0" -- "$@" + +set appvers {@@GITGUI_VERSION@@} +set copyright [string map [list (c) \u00a9] { +Copyright (c) 2006-2010 Shawn Pearce, et. al. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA}] + +###################################################################### +## +## Tcl/Tk sanity check + +if {[catch {package require Tcl 8.4} err] + || [catch {package require Tk 8.4} err] +} { + catch {wm withdraw .} + tk_messageBox \ + -icon error \ + -type ok \ + -title "git-gui: fatal error" \ + -message $err + exit 1 +} + +catch {rename send {}} ; # What an evil concept... + +###################################################################### +## +## locate our library + +set oguilib {@@GITGUI_LIBDIR@@} +set oguirel {@@GITGUI_RELATIVE@@} +if {$oguirel eq {1}} { + set oguilib [file dirname [file normalize $argv0]] + if {[file tail $oguilib] eq {git-core}} { + set oguilib [file dirname $oguilib] + } + set oguilib [file dirname $oguilib] + set oguilib [file join $oguilib share git-gui lib] + set oguimsg [file join $oguilib msgs] +} elseif {[string match @@* $oguirel]} { + set oguilib [file join [file dirname [file normalize $argv0]] lib] + set oguimsg [file join [file dirname [file normalize $argv0]] po] +} else { + set oguimsg [file join $oguilib msgs] +} +unset oguirel + +###################################################################### +## +## enable verbose loading? + +if {![catch {set _verbose $env(GITGUI_VERBOSE)}]} { + unset _verbose + rename auto_load real__auto_load + proc auto_load {name args} { + puts stderr "auto_load $name" + return [uplevel 1 real__auto_load $name $args] + } + rename source real__source + proc source {name} { + puts stderr "source $name" + uplevel 1 real__source $name + } + if {[tk windowingsystem] eq "win32"} { console show } +} + +###################################################################### +## +## Internationalization (i18n) through msgcat and gettext. See +## http://www.gnu.org/software/gettext/manual/html_node/Tcl.html + +package require msgcat + ++# Check for Windows 7 MUI language pack (missed by msgcat < 1.4.4) ++if {[tk windowingsystem] eq "win32" ++ && [package vcompare [package provide msgcat] 1.4.4] < 0 ++} then { ++ proc _mc_update_locale {} { ++ set key {HKEY_CURRENT_USER\Control Panel\Desktop} ++ if {![catch { ++ package require registry ++ set uilocale [registry get $key "PreferredUILanguages"] ++ msgcat::ConvertLocale [string map {- _} [lindex $uilocale 0]] ++ } uilocale]} { ++ if {[string length $uilocale] > 0} { ++ msgcat::mclocale $uilocale ++ } ++ } ++ } ++ _mc_update_locale ++} ++ +proc _mc_trim {fmt} { + set cmk [string first @@ $fmt] + if {$cmk > 0} { + return [string range $fmt 0 [expr {$cmk - 1}]] + } + return $fmt +} + +proc mc {en_fmt args} { + set fmt [_mc_trim [::msgcat::mc $en_fmt]] + if {[catch {set msg [eval [list format $fmt] $args]} err]} { + set msg [eval [list format [_mc_trim $en_fmt]] $args] + } + return $msg +} + +proc strcat {args} { + return [join $args {}] +} + +::msgcat::mcload $oguimsg +unset oguimsg + +###################################################################### +## +## read only globals + +set _appname {Git Gui} +set _gitdir {} +set _gitworktree {} +set _isbare {} +set _gitexec {} +set _githtmldir {} +set _reponame {} +set _iscygwin {} +set _search_path {} +set _shellpath {@@SHELL_PATH@@} + +set _trace [lsearch -exact $argv --trace] +if {$_trace >= 0} { + set argv [lreplace $argv $_trace $_trace] + set _trace 1 +} else { + set _trace 0 +} + ++# variable for the last merged branch (useful for a default when deleting ++# branches). ++set _last_merged_branch {} ++ +proc shellpath {} { + global _shellpath env + if {[string match @@* $_shellpath]} { + if {[info exists env(SHELL)]} { + return $env(SHELL) + } else { + return /bin/sh + } + } + return $_shellpath +} + +proc appname {} { + global _appname + return $_appname +} + +proc gitdir {args} { + global _gitdir + if {$args eq {}} { + return $_gitdir + } + return [eval [list file join $_gitdir] $args] +} + +proc gitexec {args} { + global _gitexec + if {$_gitexec eq {}} { + if {[catch {set _gitexec [git --exec-path]} err]} { + error "Git not installed?\n\n$err" + } + if {[is_Cygwin]} { + set _gitexec [exec cygpath \ + --windows \ + --absolute \ + $_gitexec] + } else { + set _gitexec [file normalize $_gitexec] + } + } + if {$args eq {}} { + return $_gitexec + } + return [eval [list file join $_gitexec] $args] +} + +proc githtmldir {args} { + global _githtmldir + if {$_githtmldir eq {}} { + if {[catch {set _githtmldir [git --html-path]}]} { + # Git not installed or option not yet supported + return {} + } + if {[is_Cygwin]} { + set _githtmldir [exec cygpath \ + --windows \ + --absolute \ + $_githtmldir] + } else { + set _githtmldir [file normalize $_githtmldir] + } + } + if {$args eq {}} { + return $_githtmldir + } + return [eval [list file join $_githtmldir] $args] +} + +proc reponame {} { + return $::_reponame +} + +proc is_MacOSX {} { + if {[tk windowingsystem] eq {aqua}} { + return 1 + } + return 0 +} + +proc is_Windows {} { + if {$::tcl_platform(platform) eq {windows}} { + return 1 + } + return 0 +} + +proc is_Cygwin {} { + global _iscygwin + if {$_iscygwin eq {}} { + if {$::tcl_platform(platform) eq {windows}} { + if {[catch {set p [exec cygpath --windir]} err]} { + set _iscygwin 0 + } else { + set _iscygwin 1 + } + } else { + set _iscygwin 0 + } + } + return $_iscygwin +} + +proc is_enabled {option} { + global enabled_options + if {[catch {set on $enabled_options($option)}]} {return 0} + return $on +} + +proc enable_option {option} { + global enabled_options + set enabled_options($option) 1 +} + +proc disable_option {option} { + global enabled_options + set enabled_options($option) 0 +} + +###################################################################### +## +## config + +proc is_many_config {name} { + switch -glob -- $name { + gui.recentrepo - + remote.*.fetch - + remote.*.push + {return 1} + * + {return 0} + } +} + +proc is_config_true {name} { + global repo_config + if {[catch {set v $repo_config($name)}]} { + return 0 + } elseif {$v eq {true} || $v eq {1} || $v eq {yes}} { + return 1 + } else { + return 0 + } +} + +proc is_config_false {name} { + global repo_config + if {[catch {set v $repo_config($name)}]} { + return 0 + } elseif {$v eq {false} || $v eq {0} || $v eq {no}} { + return 1 + } else { + return 0 + } +} + +proc get_config {name} { + global repo_config + if {[catch {set v $repo_config($name)}]} { + return {} + } else { + return $v + } +} + +proc is_bare {} { + global _isbare + global _gitdir + global _gitworktree + + if {$_isbare eq {}} { + if {[catch { + set _bare [git rev-parse --is-bare-repository] + switch -- $_bare { + true { set _isbare 1 } + false { set _isbare 0} + default { throw } + } + }]} { + if {[is_config_true core.bare] + || ($_gitworktree eq {} + && [lindex [file split $_gitdir] end] ne {.git})} { + set _isbare 1 + } else { + set _isbare 0 + } + } + } + return $_isbare +} + +###################################################################### +## +## handy utils + +proc _trace_exec {cmd} { + if {!$::_trace} return + set d {} + foreach v $cmd { + if {$d ne {}} { + append d { } + } + if {[regexp {[ \t\r\n'"$?*]} $v]} { + set v [sq $v] + } + append d $v + } + puts stderr $d +} + +#'" fix poor old emacs font-lock mode + +proc _git_cmd {name} { + global _git_cmd_path + + if {[catch {set v $_git_cmd_path($name)}]} { + switch -- $name { + version - + --version - + --exec-path { return [list $::_git $name] } + } + + set p [gitexec git-$name$::_search_exe] + if {[file exists $p]} { + set v [list $p] + } elseif {[is_Windows] && [file exists [gitexec git-$name]]} { + # Try to determine what sort of magic will make + # git-$name go and do its thing, because native + # Tcl on Windows doesn't know it. + # + set p [gitexec git-$name] + set f [open $p r] + set s [gets $f] + close $f + + switch -glob -- [lindex $s 0] { + #!*sh { set i sh } + #!*perl { set i perl } + #!*python { set i python } + default { error "git-$name is not supported: $s" } + } + + upvar #0 _$i interp + if {![info exists interp]} { + set interp [_which $i] + } + if {$interp eq {}} { + error "git-$name requires $i (not in PATH)" + } + set v [concat [list $interp] [lrange $s 1 end] [list $p]] + } else { + # Assume it is builtin to git somehow and we + # aren't actually able to see a file for it. + # + set v [list $::_git $name] + } + set _git_cmd_path($name) $v + } + return $v +} + +proc _which {what args} { + global env _search_exe _search_path + + if {$_search_path eq {}} { + if {[is_Cygwin] && [regexp {^(/|\.:)} $env(PATH)]} { + set _search_path [split [exec cygpath \ + --windows \ + --path \ + --absolute \ + $env(PATH)] {;}] + set _search_exe .exe + } elseif {[is_Windows]} { + set gitguidir [file dirname [info script]] + regsub -all ";" $gitguidir "\\;" gitguidir + set env(PATH) "$gitguidir;$env(PATH)" + set _search_path [split $env(PATH) {;}] + set _search_exe .exe + } else { + set _search_path [split $env(PATH) :] + set _search_exe {} + } + } + + if {[is_Windows] && [lsearch -exact $args -script] >= 0} { + set suffix {} + } else { + set suffix $_search_exe + } + + foreach p $_search_path { + set p [file join $p $what$suffix] + if {[file exists $p]} { + return [file normalize $p] + } + } + return {} +} + +proc _lappend_nice {cmd_var} { + global _nice + upvar $cmd_var cmd + + if {![info exists _nice]} { + set _nice [_which nice] + if {[catch {exec $_nice git version}]} { + set _nice {} + } elseif {[is_Windows] && [file dirname $_nice] ne [file dirname $::_git]} { + set _nice {} + } + } + if {$_nice ne {}} { + lappend cmd $_nice + } +} + +proc git {args} { + set opt [list] + + while {1} { + switch -- [lindex $args 0] { + --nice { + _lappend_nice opt + } + + default { + break + } + + } + + set args [lrange $args 1 end] + } + + set cmdp [_git_cmd [lindex $args 0]] + set args [lrange $args 1 end] + + _trace_exec [concat $opt $cmdp $args] + set result [eval exec $opt $cmdp $args] + if {$::_trace} { + puts stderr "< $result" + } + return $result +} + +proc _open_stdout_stderr {cmd} { + _trace_exec $cmd + if {[catch { + set fd [open [concat [list | ] $cmd] r] + } err]} { + if { [lindex $cmd end] eq {2>@1} + && $err eq {can not find channel named "1"} + } { + # Older versions of Tcl 8.4 don't have this 2>@1 IO + # redirect operator. Fallback to |& cat for those. + # The command was not actually started, so its safe + # to try to start it a second time. + # + set fd [open [concat \ + [list | ] \ + [lrange $cmd 0 end-1] \ + [list |& cat] \ + ] r] + } else { + error $err + } + } + fconfigure $fd -eofchar {} + return $fd +} + +proc git_read {args} { + set opt [list] + + while {1} { + switch -- [lindex $args 0] { + --nice { + _lappend_nice opt + } + + --stderr { + lappend args 2>@1 + } + + default { + break + } + + } + + set args [lrange $args 1 end] + } + + set cmdp [_git_cmd [lindex $args 0]] + set args [lrange $args 1 end] + + return [_open_stdout_stderr [concat $opt $cmdp $args]] +} + +proc git_write {args} { + set opt [list] + + while {1} { + switch -- [lindex $args 0] { + --nice { + _lappend_nice opt + } + + default { + break + } + + } + + set args [lrange $args 1 end] + } + + set cmdp [_git_cmd [lindex $args 0]] + set args [lrange $args 1 end] + + _trace_exec [concat $opt $cmdp $args] + return [open [concat [list | ] $opt $cmdp $args] w] +} + +proc githook_read {hook_name args} { + set pchook [gitdir hooks $hook_name] + lappend args 2>@1 + + # On Windows [file executable] might lie so we need to ask + # the shell if the hook is executable. Yes that's annoying. + # + if {[is_Windows]} { + upvar #0 _sh interp + if {![info exists interp]} { + set interp [_which sh] + } + if {$interp eq {}} { + error "hook execution requires sh (not in PATH)" + } + + set scr {if test -x "$1";then exec "$@";fi} + set sh_c [list $interp -c $scr $interp $pchook] + return [_open_stdout_stderr [concat $sh_c $args]] + } + + if {[file executable $pchook]} { + return [_open_stdout_stderr [concat [list $pchook] $args]] + } + + return {} +} + +proc kill_file_process {fd} { + set process [pid $fd] + + catch { + if {[is_Windows]} { + # Use a Cygwin-specific flag to allow killing + # native Windows processes + exec kill -f $process + } else { + exec kill $process + } + } +} + +proc gitattr {path attr default} { + if {[catch {set r [git check-attr $attr -- $path]}]} { + set r unspecified + } else { + set r [join [lrange [split $r :] 2 end] :] + regsub {^ } $r {} r + } + if {$r eq {unspecified}} { + return $default + } + return $r +} + +proc sq {value} { + regsub -all ' $value "'\\''" value + return "'$value'" +} + +proc load_current_branch {} { + global current_branch is_detached + + set fd [open [gitdir HEAD] r] + if {[gets $fd ref] < 1} { + set ref {} + } + close $fd + + set pfx {ref: refs/heads/} + set len [string length $pfx] + if {[string equal -length $len $pfx $ref]} { + # We're on a branch. It might not exist. But + # HEAD looks good enough to be a branch. + # + set current_branch [string range $ref $len end] + set is_detached 0 + } else { + # Assume this is a detached head. + # + set current_branch HEAD + set is_detached 1 + } +} + +auto_load tk_optionMenu +rename tk_optionMenu real__tkOptionMenu +proc tk_optionMenu {w varName args} { + set m [eval real__tkOptionMenu $w $varName $args] + $m configure -font font_ui + $w configure -font font_ui + return $m +} + +proc rmsel_tag {text} { + $text tag conf sel \ + -background [$text cget -background] \ + -foreground [$text cget -foreground] \ + -borderwidth 0 + $text tag conf in_sel -background lightgray + bind $text break + return $text +} + +wm withdraw . +set root_exists 0 +bind . { + bind . {} + set root_exists 1 +} + +if {[is_Windows]} { + wm iconbitmap . -default $oguilib/git-gui.ico + set ::tk::AlwaysShowSelection 1 + bind . {console show} + + # Spoof an X11 display for SSH + if {![info exists env(DISPLAY)]} { + set env(DISPLAY) :9999 + } +} else { + catch { + image create photo gitlogo -width 16 -height 16 + + gitlogo put #33CC33 -to 7 0 9 2 + gitlogo put #33CC33 -to 4 2 12 4 + gitlogo put #33CC33 -to 7 4 9 6 + gitlogo put #CC3333 -to 4 6 12 8 + gitlogo put gray26 -to 4 9 6 10 + gitlogo put gray26 -to 3 10 6 12 + gitlogo put gray26 -to 8 9 13 11 + gitlogo put gray26 -to 8 11 10 12 + gitlogo put gray26 -to 11 11 13 14 + gitlogo put gray26 -to 3 12 5 14 + gitlogo put gray26 -to 5 13 + gitlogo put gray26 -to 10 13 + gitlogo put gray26 -to 4 14 12 15 + gitlogo put gray26 -to 5 15 11 16 + gitlogo redither + + wm iconphoto . -default gitlogo + } +} + +###################################################################### +## +## config defaults + +set cursor_ptr arrow +font create font_ui +if {[lsearch -exact [font names] TkDefaultFont] != -1} { + eval [linsert [font actual TkDefaultFont] 0 font configure font_ui] + eval [linsert [font actual TkFixedFont] 0 font create font_diff] +} else { + font create font_diff -family Courier -size 10 + catch { + label .dummy + eval font configure font_ui [font actual [.dummy cget -font]] + destroy .dummy + } +} + +font create font_uiitalic +font create font_uibold +font create font_diffbold +font create font_diffitalic + +foreach class {Button Checkbutton Entry Label + Labelframe Listbox Message + Radiobutton Spinbox Text} { + option add *$class.font font_ui +} +if {![is_MacOSX]} { + option add *Menu.font font_ui + option add *Entry.borderWidth 1 startupFile + option add *Entry.relief sunken startupFile + option add *RadioButton.anchor w startupFile +} +unset class + +if {[is_Windows] || [is_MacOSX]} { + option add *Menu.tearOff 0 +} + +if {[is_MacOSX]} { + set M1B M1 + set M1T Cmd +} else { + set M1B Control + set M1T Ctrl +} + +proc bind_button3 {w cmd} { + bind $w $cmd + if {[is_MacOSX]} { + # Mac OS X sends Button-2 on right click through three-button mouse, + # or through trackpad right-clicking (two-finger touch + click). + bind $w $cmd + bind $w $cmd + } +} + +proc apply_config {} { + global repo_config font_descs + + foreach option $font_descs { + set name [lindex $option 0] + set font [lindex $option 1] + if {[catch { + set need_weight 1 + foreach {cn cv} $repo_config(gui.$name) { + if {$cn eq {-weight}} { + set need_weight 0 + } + font configure $font $cn $cv + } + if {$need_weight} { + font configure $font -weight normal + } + } err]} { + error_popup [strcat [mc "Invalid font specified in %s:" "gui.$name"] "\n\n$err"] + } + foreach {cn cv} [font configure $font] { + font configure ${font}bold $cn $cv + font configure ${font}italic $cn $cv + } + font configure ${font}bold -weight bold + font configure ${font}italic -slant italic + } + + global use_ttk NS + set use_ttk 0 + set NS {} + if {$repo_config(gui.usettk)} { + set use_ttk [package vsatisfies [package provide Tk] 8.5] + if {$use_ttk} { + set NS ttk + bind [winfo class .] <> [list InitTheme] + pave_toplevel . + } + } +} + +set default_config(branch.autosetupmerge) true +set default_config(merge.tool) {} +set default_config(mergetool.keepbackup) true +set default_config(merge.diffstat) true +set default_config(merge.summary) false +set default_config(merge.verbosity) 2 +set default_config(user.name) {} +set default_config(user.email) {} + +set default_config(gui.encoding) [encoding system] +set default_config(gui.matchtrackingbranch) false +set default_config(gui.textconv) true +set default_config(gui.pruneduringfetch) false +set default_config(gui.trustmtime) false +set default_config(gui.fastcopyblame) false +set default_config(gui.copyblamethreshold) 40 +set default_config(gui.blamehistoryctx) 7 +set default_config(gui.diffcontext) 5 +set default_config(gui.commitmsgwidth) 75 +set default_config(gui.newbranchtemplate) {} +set default_config(gui.spellingdictionary) {} +set default_config(gui.fontui) [font configure font_ui] +set default_config(gui.fontdiff) [font configure font_diff] +# TODO: this option should be added to the git-config documentation +set default_config(gui.maxfilesdisplayed) 5000 +set default_config(gui.usettk) 1 +set font_descs { + {fontui font_ui {mc "Main Font"}} + {fontdiff font_diff {mc "Diff/Console Font"}} +} + +###################################################################### +## +## find git + +set _git [_which git] +if {$_git eq {}} { + catch {wm withdraw .} + tk_messageBox \ + -icon error \ + -type ok \ + -title [mc "git-gui: fatal error"] \ + -message [mc "Cannot find git in PATH."] + exit 1 +} + +###################################################################### +## +## version check + +if {[catch {set _git_version [git --version]} err]} { + catch {wm withdraw .} + tk_messageBox \ + -icon error \ + -type ok \ + -title [mc "git-gui: fatal error"] \ + -message "Cannot determine Git version: + +$err + +[appname] requires Git 1.5.0 or later." + exit 1 +} +if {![regsub {^git version } $_git_version {} _git_version]} { + catch {wm withdraw .} + tk_messageBox \ + -icon error \ + -type ok \ + -title [mc "git-gui: fatal error"] \ + -message [strcat [mc "Cannot parse Git version string:"] "\n\n$_git_version"] + exit 1 +} + +proc get_trimmed_version {s} { + set r {} + foreach x [split $s -._] { + if {[string is integer -strict $x]} { + lappend r $x + } else { + break + } + } + return [join $r .] +} +set _real_git_version $_git_version +set _git_version [get_trimmed_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 [mc "Git version cannot be determined. + +%s claims it is version '%s'. + +%s requires at least Git 1.5.0 or later. + +Assume '%s' is version 1.5.0? +" $_git $_real_git_version [appname] $_real_git_version]] eq {yes}} { + set _git_version 1.5.0 + } else { + exit 1 + } +} +unset _real_git_version + +proc git-version {args} { + global _git_version + + switch [llength $args] { + 0 { + return $_git_version + } + + 2 { + set op [lindex $args 0] + set vr [lindex $args 1] + set cm [package vcompare $_git_version $vr] + return [expr $cm $op 0] + } + + 4 { + set type [lindex $args 0] + set name [lindex $args 1] + set parm [lindex $args 2] + set body [lindex $args 3] + + if {($type ne {proc} && $type ne {method})} { + error "Invalid arguments to git-version" + } + if {[llength $body] < 2 || [lindex $body end-1] ne {default}} { + error "Last arm of $type $name must be default" + } + + foreach {op vr cb} [lrange $body 0 end-2] { + if {[git-version $op $vr]} { + return [uplevel [list $type $name $parm $cb]] + } + } + + return [uplevel [list $type $name $parm [lindex $body end]]] + } + + default { + error "git-version >= x" + } + + } +} + +if {[git-version < 1.5]} { + catch {wm withdraw .} + tk_messageBox \ + -icon error \ + -type ok \ + -title [mc "git-gui: fatal error"] \ + -message "[appname] requires Git 1.5.0 or later. + +You are using [git-version]: + +[git --version]" + exit 1 +} + +###################################################################### +## +## configure our library + +set idx [file join $oguilib tclIndex] +if {[catch {set fd [open $idx r]} err]} { + catch {wm withdraw .} + tk_messageBox \ + -icon error \ + -type ok \ + -title [mc "git-gui: fatal error"] \ + -message $err + exit 1 +} +if {[gets $fd] eq {# Autogenerated by git-gui Makefile}} { + set idx [list] + while {[gets $fd n] >= 0} { + if {$n ne {} && ![string match #* $n]} { + lappend idx $n + } + } +} else { + set idx {} +} +close $fd + +if {$idx ne {}} { + set loaded [list] + foreach p $idx { + if {[lsearch -exact $loaded $p] >= 0} continue + source [file join $oguilib $p] + lappend loaded $p + } + unset loaded p +} else { + set auto_path [concat [list $oguilib] $auto_path] +} +unset -nocomplain idx fd + +###################################################################### +## +## config file parsing + +git-version proc _parse_config {arr_name args} { + >= 1.5.3 { + upvar $arr_name arr + array unset arr + set buf {} + catch { + set fd_rc [eval \ + [list git_read config] \ + $args \ + [list --null --list]] + fconfigure $fd_rc -translation binary + set buf [read $fd_rc] + close $fd_rc + } + foreach line [split $buf "\0"] { + if {[regexp {^([^\n]+)\n(.*)$} $line line name value]} { + if {[is_many_config $name]} { + lappend arr($name) $value + } else { + set arr($name) $value + } + } + } + } + default { + upvar $arr_name arr + array unset arr + catch { + set fd_rc [eval [list git_read config --list] $args] + while {[gets $fd_rc line] >= 0} { + if {[regexp {^([^=]+)=(.*)$} $line line name value]} { + if {[is_many_config $name]} { + lappend arr($name) $value + } else { + set arr($name) $value + } + } + } + close $fd_rc + } + } +} + +proc load_config {include_global} { + global repo_config global_config system_config default_config + + if {$include_global} { + _parse_config system_config --system + _parse_config global_config --global + } + _parse_config repo_config + + foreach name [array names default_config] { + if {[catch {set v $system_config($name)}]} { + set system_config($name) $default_config($name) + } + } + foreach name [array names system_config] { + if {[catch {set v $global_config($name)}]} { + set global_config($name) $system_config($name) + } + if {[catch {set v $repo_config($name)}]} { + set repo_config($name) $system_config($name) + } + } +} + +###################################################################### +## +## feature option selection + +if {[regexp {^git-(.+)$} [file tail $argv0] _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 + enable_option retcode + + disable_option multicommit + disable_option branch + disable_option transport + + while {[llength $argv] > 0} { + set a [lindex $argv 0] + switch -- $a { + --amend { + enable_option initialamend + } + --nocommit { + enable_option nocommit + enable_option nocommitmsg + } + --commitmsg { + disable_option nocommitmsg + } + default { + break + } + } + + set argv [lrange $argv 1 end] + } +} +} + +###################################################################### +## +## execution environment + +set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}] + +# Suggest our implementation of askpass, if none is set +if {![info exists env(SSH_ASKPASS)]} { + set env(SSH_ASKPASS) [gitexec git-gui--askpass] +} + +###################################################################### +## +## repository setup + +set picked 0 +if {[catch { + set _gitdir $env(GIT_DIR) + set _prefix {} + }] + && [catch { + # beware that from the .git dir this sets _gitdir to . + # and _prefix to the empty string + set _gitdir [git rev-parse --git-dir] + set _prefix [git rev-parse --show-prefix] + } err]} { + load_config 1 + apply_config + choose_repository::pick + set picked 1 +} + +# we expand the _gitdir when it's just a single dot (i.e. when we're being +# run from the .git dir itself) lest the routines to find the worktree +# get confused +if {$_gitdir eq "."} { + set _gitdir [pwd] +} + +if {![file isdirectory $_gitdir] && [is_Cygwin]} { + catch {set _gitdir [exec cygpath --windows $_gitdir]} +} +if {![file isdirectory $_gitdir]} { + catch {wm withdraw .} + error_popup [strcat [mc "Git directory not found:"] "\n\n$_gitdir"] + exit 1 +} +# _gitdir exists, so try loading the config +load_config 0 +apply_config + +# v1.7.0 introduced --show-toplevel to return the canonical work-tree +if {[package vsatisfies $_git_version 1.7.0]} { + set _gitworktree [git rev-parse --show-toplevel] +} else { + # try to set work tree from environment, core.worktree or use + # cdup to obtain a relative path to the top of the worktree. If + # run from the top, the ./ prefix ensures normalize expands pwd. + if {[catch { set _gitworktree $env(GIT_WORK_TREE) }]} { + set _gitworktree [get_config core.worktree] + if {$_gitworktree eq ""} { + set _gitworktree [file normalize ./[git rev-parse --show-cdup]] + } + } +} + +if {$_prefix ne {}} { + if {$_gitworktree eq {}} { + regsub -all {[^/]+/} $_prefix ../ cdup + } else { + set cdup $_gitworktree + } + if {[catch {cd $cdup} err]} { + catch {wm withdraw .} + error_popup [strcat [mc "Cannot move to top of working directory:"] "\n\n$err"] + exit 1 + } + set _gitworktree [pwd] + unset cdup +} elseif {![is_enabled bare]} { + if {[is_bare]} { + catch {wm withdraw .} + error_popup [strcat [mc "Cannot use bare repository:"] "\n\n$_gitdir"] + exit 1 + } + if {$_gitworktree eq {}} { + set _gitworktree [file dirname $_gitdir] + } + if {[catch {cd $_gitworktree} err]} { + catch {wm withdraw .} + error_popup [strcat [mc "No working directory"] " $_gitworktree:\n\n$err"] + exit 1 + } + set _gitworktree [pwd] +} +set _reponame [file split [file normalize $_gitdir]] +if {[lindex $_reponame end] eq {.git}} { + set _reponame [lindex $_reponame end-1] +} else { + set _reponame [lindex $_reponame end] +} + +set env(GIT_DIR) $_gitdir +set env(GIT_WORK_TREE) $_gitworktree + +###################################################################### +## +## global init + +set current_diff_path {} +set current_diff_side {} +set diff_actions [list] + +set HEAD {} +set PARENT {} +set MERGE_HEAD [list] +set commit_type {} +set empty_tree {} +set current_branch {} +set is_detached 0 +set current_diff_path {} +set is_3way_diff 0 +set is_submodule_diff 0 +set is_conflict_diff 0 +set selected_commit_type new +set diff_empty_count 0 + +set nullid "0000000000000000000000000000000000000000" +set nullid2 "0000000000000000000000000000000000000001" + +###################################################################### +## +## task management + +set rescan_active 0 +set diff_active 0 +set last_clicked {} + +set disable_on_lock [list] +set index_lock_type none + +proc lock_index {type} { + global index_lock_type disable_on_lock + + if {$index_lock_type eq {none}} { + set index_lock_type $type + foreach w $disable_on_lock { + uplevel #0 $w disabled + } + return 1 + } elseif {$index_lock_type eq "begin-$type"} { + set index_lock_type $type + return 1 + } + return 0 +} + +proc unlock_index {} { + global index_lock_type disable_on_lock + + set index_lock_type none + foreach w $disable_on_lock { + uplevel #0 $w normal + } +} + +###################################################################### +## +## status + +proc repository_state {ctvar hdvar mhvar} { + global current_branch + upvar $ctvar ct $hdvar hd $mhvar mh + + set mh [list] + + load_current_branch + if {[catch {set hd [git rev-parse --verify HEAD]}]} { + set hd {} + set ct initial + return + } + + set merge_head [gitdir MERGE_HEAD] + if {[file exists $merge_head]} { + set ct merge + set fd_mh [open $merge_head r] + while {[gets $fd_mh line] >= 0} { + lappend mh $line + } + close $fd_mh + return + } + + set ct normal +} + +proc PARENT {} { + global PARENT empty_tree + + set p [lindex $PARENT 0] + if {$p ne {}} { + return $p + } + if {$empty_tree eq {}} { + set empty_tree [git mktree << {}] + } + return $empty_tree +} + +proc force_amend {} { + global selected_commit_type + global HEAD PARENT MERGE_HEAD commit_type + + repository_state newType newHEAD newMERGE_HEAD + set HEAD $newHEAD + set PARENT $newHEAD + set MERGE_HEAD $newMERGE_HEAD + set commit_type $newType + + set selected_commit_type amend + do_select_commit_type +} + +proc rescan {after {honor_trustmtime 1}} { + global HEAD PARENT MERGE_HEAD commit_type + global ui_index ui_workdir ui_comm + global rescan_active file_states + global repo_config + + if {$rescan_active > 0 || ![lock_index read]} return + + repository_state newType newHEAD newMERGE_HEAD + if {[string match amend* $commit_type] + && $newType eq {normal} + && $newHEAD eq $HEAD} { + } else { + set HEAD $newHEAD + set PARENT $newHEAD + set MERGE_HEAD $newMERGE_HEAD + set commit_type $newType + } + + array unset file_states + + if {!$::GITGUI_BCK_exists && + (![$ui_comm edit modified] + || [string trim [$ui_comm get 0.0 end]] eq {})} { + if {[string match amend* $commit_type]} { + } elseif {[load_message GITGUI_MSG]} { + } elseif {[run_prepare_commit_msg_hook]} { + } elseif {[load_message MERGE_MSG]} { + } elseif {[load_message SQUASH_MSG]} { + } + $ui_comm edit reset + $ui_comm edit modified false + } + + if {$honor_trustmtime && $repo_config(gui.trustmtime) eq {true}} { + rescan_stage2 {} $after + } else { + set rescan_active 1 + ui_status [mc "Refreshing file status..."] + set fd_rf [git_read update-index \ + -q \ + --unmerged \ + --ignore-missing \ + --refresh \ + ] + fconfigure $fd_rf -blocking 0 -translation binary + fileevent $fd_rf readable \ + [list rescan_stage2 $fd_rf $after] + } +} + +if {[is_Cygwin]} { + set is_git_info_exclude {} + proc have_info_exclude {} { + global is_git_info_exclude + + if {$is_git_info_exclude eq {}} { + if {[catch {exec test -f [gitdir info exclude]}]} { + set is_git_info_exclude 0 + } else { + set is_git_info_exclude 1 + } + } + return $is_git_info_exclude + } +} else { + proc have_info_exclude {} { + return [file readable [gitdir info exclude]] + } +} + +proc rescan_stage2 {fd after} { + global rescan_active buf_rdi buf_rdf buf_rlo + + if {$fd ne {}} { + read $fd + if {![eof $fd]} return + close $fd + } + - set ls_others [list --exclude-per-directory=.gitignore] - if {[have_info_exclude]} { - lappend ls_others "--exclude-from=[gitdir info exclude]" - } - set user_exclude [get_config core.excludesfile] - if {$user_exclude ne {} && [file readable $user_exclude]} { - lappend ls_others "--exclude-from=$user_exclude" ++ if {[package vsatisfies $::_git_version 1.6.3]} { ++ set ls_others [list --exclude-standard] ++ } else { ++ set ls_others [list --exclude-per-directory=.gitignore] ++ if {[have_info_exclude]} { ++ lappend ls_others "--exclude-from=[gitdir info exclude]" ++ } ++ set user_exclude [get_config core.excludesfile] ++ if {$user_exclude ne {} && [file readable $user_exclude]} { ++ lappend ls_others "--exclude-from=[file normalize $user_exclude]" ++ } + } + + set buf_rdi {} + set buf_rdf {} + set buf_rlo {} + + set rescan_active 3 + ui_status [mc "Scanning for modified files ..."] + set fd_di [git_read diff-index --cached -z [PARENT]] + set fd_df [git_read diff-files -z] + set fd_lo [eval git_read ls-files --others -z $ls_others] + + fconfigure $fd_di -blocking 0 -translation binary -encoding binary + fconfigure $fd_df -blocking 0 -translation binary -encoding binary + fconfigure $fd_lo -blocking 0 -translation binary -encoding binary + fileevent $fd_di readable [list read_diff_index $fd_di $after] + fileevent $fd_df readable [list read_diff_files $fd_df $after] + fileevent $fd_lo readable [list read_ls_others $fd_lo $after] +} + +proc load_message {file} { + global ui_comm + + set f [gitdir $file] + if {[file isfile $f]} { + if {[catch {set fd [open $f r]}]} { + return 0 + } + fconfigure $fd -eofchar {} + set content [string trim [read $fd]] + close $fd + regsub -all -line {[ \r\t]+$} $content {} content + $ui_comm delete 0.0 end + $ui_comm insert end $content + return 1 + } + return 0 +} + +proc run_prepare_commit_msg_hook {} { + global pch_error + + # prepare-commit-msg requires PREPARE_COMMIT_MSG exist. From git-gui + # it will be .git/MERGE_MSG (merge), .git/SQUASH_MSG (squash), or an + # empty file but existant file. + + set fd_pcm [open [gitdir PREPARE_COMMIT_MSG] a] + + if {[file isfile [gitdir MERGE_MSG]]} { + set pcm_source "merge" + set fd_mm [open [gitdir MERGE_MSG] r] + puts -nonewline $fd_pcm [read $fd_mm] + close $fd_mm + } elseif {[file isfile [gitdir SQUASH_MSG]]} { + set pcm_source "squash" + set fd_sm [open [gitdir SQUASH_MSG] r] + puts -nonewline $fd_pcm [read $fd_sm] + close $fd_sm + } else { + set pcm_source "" + } + + close $fd_pcm + + set fd_ph [githook_read prepare-commit-msg \ + [gitdir PREPARE_COMMIT_MSG] $pcm_source] + if {$fd_ph eq {}} { + catch {file delete [gitdir PREPARE_COMMIT_MSG]} + return 0; + } + + ui_status [mc "Calling prepare-commit-msg hook..."] + set pch_error {} + + fconfigure $fd_ph -blocking 0 -translation binary -eofchar {} + fileevent $fd_ph readable \ + [list prepare_commit_msg_hook_wait $fd_ph] + + return 1; +} + +proc prepare_commit_msg_hook_wait {fd_ph} { + global pch_error + + append pch_error [read $fd_ph] + fconfigure $fd_ph -blocking 1 + if {[eof $fd_ph]} { + if {[catch {close $fd_ph}]} { + ui_status [mc "Commit declined by prepare-commit-msg hook."] + hook_failed_popup prepare-commit-msg $pch_error + catch {file delete [gitdir PREPARE_COMMIT_MSG]} + exit 1 + } else { + load_message PREPARE_COMMIT_MSG + } + set pch_error {} + catch {file delete [gitdir PREPARE_COMMIT_MSG]} + return + } + fconfigure $fd_ph -blocking 0 + catch {file delete [gitdir PREPARE_COMMIT_MSG]} +} + +proc read_diff_index {fd after} { + global buf_rdi + + append buf_rdi [read $fd] + set c 0 + set n [string length $buf_rdi] + while {$c < $n} { + set z1 [string first "\0" $buf_rdi $c] + if {$z1 == -1} break + incr z1 + set z2 [string first "\0" $buf_rdi $z1] + if {$z2 == -1} break + + incr c + set i [split [string range $buf_rdi $c [expr {$z1 - 2}]] { }] + set p [string range $buf_rdi $z1 [expr {$z2 - 1}]] + merge_state \ + [encoding convertfrom $p] \ + [lindex $i 4]? \ + [list [lindex $i 0] [lindex $i 2]] \ + [list] + set c $z2 + incr c + } + if {$c < $n} { + set buf_rdi [string range $buf_rdi $c end] + } else { + set buf_rdi {} + } + + rescan_done $fd buf_rdi $after +} + +proc read_diff_files {fd after} { + global buf_rdf + + append buf_rdf [read $fd] + set c 0 + set n [string length $buf_rdf] + while {$c < $n} { + set z1 [string first "\0" $buf_rdf $c] + if {$z1 == -1} break + incr z1 + set z2 [string first "\0" $buf_rdf $z1] + if {$z2 == -1} break + + incr c + set i [split [string range $buf_rdf $c [expr {$z1 - 2}]] { }] + set p [string range $buf_rdf $z1 [expr {$z2 - 1}]] + merge_state \ + [encoding convertfrom $p] \ + ?[lindex $i 4] \ + [list] \ + [list [lindex $i 0] [lindex $i 2]] + set c $z2 + incr c + } + if {$c < $n} { + set buf_rdf [string range $buf_rdf $c end] + } else { + set buf_rdf {} + } + + rescan_done $fd buf_rdf $after +} + +proc read_ls_others {fd after} { + global buf_rlo + + append buf_rlo [read $fd] + set pck [split $buf_rlo "\0"] + set buf_rlo [lindex $pck end] + foreach p [lrange $pck 0 end-1] { + set p [encoding convertfrom $p] + if {[string index $p end] eq {/}} { + set p [string range $p 0 end-1] + } + merge_state $p ?O + } + rescan_done $fd buf_rlo $after +} + +proc rescan_done {fd buf after} { + global rescan_active current_diff_path + global file_states repo_config + upvar $buf to_clear + + if {![eof $fd]} return + set to_clear {} + close $fd + if {[incr rescan_active -1] > 0} return + + prune_selection + unlock_index + display_all_files + if {$current_diff_path ne {}} { reshow_diff $after } + if {$current_diff_path eq {}} { select_first_diff $after } +} + +proc prune_selection {} { + global file_states selected_paths + + foreach path [array names selected_paths] { + if {[catch {set still_here $file_states($path)}]} { + unset selected_paths($path) + } + } +} + +###################################################################### +## +## ui helpers + +proc mapicon {w state path} { + global all_icons + + if {[catch {set r $all_icons($state$w)}]} { + puts "error: no icon for $w state={$state} $path" + return file_plain + } + return $r +} + +proc mapdesc {state path} { + global all_descs + + if {[catch {set r $all_descs($state)}]} { + puts "error: no desc for state={$state} $path" + return $state + } + return $r +} + +proc ui_status {msg} { + global main_status + if {[info exists main_status]} { + $main_status show $msg + } +} + +proc ui_ready {{test {}}} { + global main_status + if {[info exists main_status]} { + $main_status show [mc "Ready."] $test + } +} + +proc escape_path {path} { + regsub -all {\\} $path "\\\\" path + regsub -all "\n" $path "\\n" path + return $path +} + +proc short_path {path} { + return [escape_path [lindex [file split $path] end]] +} + +set next_icon_id 0 +set null_sha1 [string repeat 0 40] + +proc merge_state {path new_state {head_info {}} {index_info {}}} { + global file_states next_icon_id null_sha1 + + set s0 [string index $new_state 0] + set s1 [string index $new_state 1] + + if {[catch {set info $file_states($path)}]} { + set state __ + set icon n[incr next_icon_id] + } else { + set state [lindex $info 0] + set icon [lindex $info 1] + if {$head_info eq {}} {set head_info [lindex $info 2]} + if {$index_info eq {}} {set index_info [lindex $info 3]} + } + + if {$s0 eq {?}} {set s0 [string index $state 0]} \ + elseif {$s0 eq {_}} {set s0 _} + + if {$s1 eq {?}} {set s1 [string index $state 1]} \ + elseif {$s1 eq {_}} {set s1 _} + + if {$s0 eq {A} && $s1 eq {_} && $head_info eq {}} { + set head_info [list 0 $null_sha1] + } elseif {$s0 ne {_} && [string index $state 0] eq {_} + && $head_info eq {}} { + set head_info $index_info + } elseif {$s0 eq {_} && [string index $state 0] ne {_}} { + set index_info $head_info + set head_info {} + } + + set file_states($path) [list $s0$s1 $icon \ + $head_info $index_info \ + ] + return $state +} + +proc display_file_helper {w path icon_name old_m new_m} { + global file_lists + + if {$new_m eq {_}} { + set lno [lsearch -sorted -exact $file_lists($w) $path] + if {$lno >= 0} { + set file_lists($w) [lreplace $file_lists($w) $lno $lno] + incr lno + $w conf -state normal + $w delete $lno.0 [expr {$lno + 1}].0 + $w conf -state disabled + } + } elseif {$old_m eq {_} && $new_m ne {_}} { + lappend file_lists($w) $path + set file_lists($w) [lsort -unique $file_lists($w)] + set lno [lsearch -sorted -exact $file_lists($w) $path] + incr lno + $w conf -state normal + $w image create $lno.0 \ + -align center -padx 5 -pady 1 \ + -name $icon_name \ + -image [mapicon $w $new_m $path] + $w insert $lno.1 "[escape_path $path]\n" + $w conf -state disabled + } elseif {$old_m ne $new_m} { + $w conf -state normal + $w image conf $icon_name -image [mapicon $w $new_m $path] + $w conf -state disabled + } +} + +proc display_file {path state} { + global file_states selected_paths + global ui_index ui_workdir + + set old_m [merge_state $path $state] + set s $file_states($path) + set new_m [lindex $s 0] + set icon_name [lindex $s 1] + + set o [string index $old_m 0] + set n [string index $new_m 0] + if {$o eq {U}} { + set o _ + } + if {$n eq {U}} { + set n _ + } + display_file_helper $ui_index $path $icon_name $o $n + + if {[string index $old_m 0] eq {U}} { + set o U + } else { + set o [string index $old_m 1] + } + if {[string index $new_m 0] eq {U}} { + set n U + } else { + set n [string index $new_m 1] + } + display_file_helper $ui_workdir $path $icon_name $o $n + + if {$new_m eq {__}} { + unset file_states($path) + catch {unset selected_paths($path)} + } +} + +proc display_all_files_helper {w path icon_name m} { + global file_lists + + lappend file_lists($w) $path + set lno [expr {[lindex [split [$w index end] .] 0] - 1}] + $w image create end \ + -align center -padx 5 -pady 1 \ + -name $icon_name \ + -image [mapicon $w $m $path] + $w insert end "[escape_path $path]\n" +} + +set files_warning 0 +proc display_all_files {} { + global ui_index ui_workdir + global file_states file_lists + global last_clicked + global files_warning + + $ui_index conf -state normal + $ui_workdir conf -state normal + + $ui_index delete 0.0 end + $ui_workdir delete 0.0 end + set last_clicked {} + + set file_lists($ui_index) [list] + set file_lists($ui_workdir) [list] + + set to_display [lsort [array names file_states]] + set display_limit [get_config gui.maxfilesdisplayed] + if {[llength $to_display] > $display_limit} { + if {!$files_warning} { + # do not repeatedly warn: + set files_warning 1 + info_popup [mc "Displaying only %s of %s files." \ + $display_limit [llength $to_display]] + } + set to_display [lrange $to_display 0 [expr {$display_limit-1}]] + } + foreach path $to_display { + set s $file_states($path) + set m [lindex $s 0] + set icon_name [lindex $s 1] + + set s [string index $m 0] + if {$s ne {U} && $s ne {_}} { + display_all_files_helper $ui_index $path \ + $icon_name $s + } + + if {[string index $m 0] eq {U}} { + set s U + } else { + set s [string index $m 1] + } + if {$s ne {_}} { + display_all_files_helper $ui_workdir $path \ + $icon_name $s + } + } + + $ui_index conf -state disabled + $ui_workdir conf -state disabled +} + +###################################################################### +## +## icons + +set filemask { +#define mask_width 14 +#define mask_height 15 +static unsigned char mask_bits[] = { + 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, + 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, + 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f}; +} + +image create bitmap file_plain -background white -foreground black -data { +#define plain_width 14 +#define plain_height 15 +static unsigned char plain_bits[] = { + 0xfe, 0x01, 0x02, 0x03, 0x02, 0x05, 0x02, 0x09, 0x02, 0x1f, 0x02, 0x10, + 0x02, 0x10, 0x02, 0x10, 0x02, 0x10, 0x02, 0x10, 0x02, 0x10, 0x02, 0x10, + 0x02, 0x10, 0x02, 0x10, 0xfe, 0x1f}; +} -maskdata $filemask + +image create bitmap file_mod -background white -foreground blue -data { +#define mod_width 14 +#define mod_height 15 +static unsigned char mod_bits[] = { + 0xfe, 0x01, 0x02, 0x03, 0x7a, 0x05, 0x02, 0x09, 0x7a, 0x1f, 0x02, 0x10, + 0xfa, 0x17, 0x02, 0x10, 0xfa, 0x17, 0x02, 0x10, 0xfa, 0x17, 0x02, 0x10, + 0xfa, 0x17, 0x02, 0x10, 0xfe, 0x1f}; +} -maskdata $filemask + +image create bitmap file_fulltick -background white -foreground "#007000" -data { +#define file_fulltick_width 14 +#define file_fulltick_height 15 +static unsigned char file_fulltick_bits[] = { + 0xfe, 0x01, 0x02, 0x1a, 0x02, 0x0c, 0x02, 0x0c, 0x02, 0x16, 0x02, 0x16, + 0x02, 0x13, 0x00, 0x13, 0x86, 0x11, 0x8c, 0x11, 0xd8, 0x10, 0xf2, 0x10, + 0x62, 0x10, 0x02, 0x10, 0xfe, 0x1f}; +} -maskdata $filemask + +image create bitmap file_question -background white -foreground black -data { +#define file_question_width 14 +#define file_question_height 15 +static unsigned char file_question_bits[] = { + 0xfe, 0x01, 0x02, 0x02, 0xe2, 0x04, 0xf2, 0x09, 0x1a, 0x1b, 0x0a, 0x13, + 0x82, 0x11, 0xc2, 0x10, 0x62, 0x10, 0x62, 0x10, 0x02, 0x10, 0x62, 0x10, + 0x62, 0x10, 0x02, 0x10, 0xfe, 0x1f}; +} -maskdata $filemask + +image create bitmap file_removed -background white -foreground red -data { +#define file_removed_width 14 +#define file_removed_height 15 +static unsigned char file_removed_bits[] = { + 0xfe, 0x01, 0x02, 0x03, 0x02, 0x05, 0x02, 0x09, 0x02, 0x1f, 0x02, 0x10, + 0x1a, 0x16, 0x32, 0x13, 0xe2, 0x11, 0xc2, 0x10, 0xe2, 0x11, 0x32, 0x13, + 0x1a, 0x16, 0x02, 0x10, 0xfe, 0x1f}; +} -maskdata $filemask + +image create bitmap file_merge -background white -foreground blue -data { +#define file_merge_width 14 +#define file_merge_height 15 +static unsigned char file_merge_bits[] = { + 0xfe, 0x01, 0x02, 0x03, 0x62, 0x05, 0x62, 0x09, 0x62, 0x1f, 0x62, 0x10, + 0xfa, 0x11, 0xf2, 0x10, 0x62, 0x10, 0x02, 0x10, 0xfa, 0x17, 0x02, 0x10, + 0xfa, 0x17, 0x02, 0x10, 0xfe, 0x1f}; +} -maskdata $filemask + +image create bitmap file_statechange -background white -foreground green -data { - #define file_merge_width 14 - #define file_merge_height 15 ++#define file_statechange_width 14 ++#define file_statechange_height 15 +static unsigned char file_statechange_bits[] = { + 0xfe, 0x01, 0x02, 0x03, 0x02, 0x05, 0x02, 0x09, 0x02, 0x1f, 0x62, 0x10, + 0x62, 0x10, 0xba, 0x11, 0xba, 0x11, 0x62, 0x10, 0x62, 0x10, 0x02, 0x10, + 0x02, 0x10, 0x02, 0x10, 0xfe, 0x1f}; +} -maskdata $filemask + +set ui_index .vpane.files.index.list +set ui_workdir .vpane.files.workdir.list + +set all_icons(_$ui_index) file_plain +set all_icons(A$ui_index) file_plain +set all_icons(M$ui_index) file_fulltick +set all_icons(D$ui_index) file_removed +set all_icons(U$ui_index) file_merge +set all_icons(T$ui_index) file_statechange + +set all_icons(_$ui_workdir) file_plain +set all_icons(M$ui_workdir) file_mod +set all_icons(D$ui_workdir) file_question +set all_icons(U$ui_workdir) file_merge +set all_icons(O$ui_workdir) file_plain +set all_icons(T$ui_workdir) file_statechange + +set max_status_desc 0 +foreach i { + {__ {mc "Unmodified"}} + + {_M {mc "Modified, not staged"}} + {M_ {mc "Staged for commit"}} + {MM {mc "Portions staged for commit"}} + {MD {mc "Staged for commit, missing"}} + + {_T {mc "File type changed, not staged"}} ++ {MT {mc "File type changed, old type staged for commit"}} ++ {AT {mc "File type changed, old type staged for commit"}} + {T_ {mc "File type changed, staged"}} ++ {TM {mc "File type change staged, modification not staged"}} ++ {TD {mc "File type change staged, file missing"}} + + {_O {mc "Untracked, not staged"}} + {A_ {mc "Staged for commit"}} + {AM {mc "Portions staged for commit"}} + {AD {mc "Staged for commit, missing"}} + + {_D {mc "Missing"}} + {D_ {mc "Staged for removal"}} + {DO {mc "Staged for removal, still present"}} + + {_U {mc "Requires merge resolution"}} + {U_ {mc "Requires merge resolution"}} + {UU {mc "Requires merge resolution"}} + {UM {mc "Requires merge resolution"}} + {UD {mc "Requires merge resolution"}} + {UT {mc "Requires merge resolution"}} + } { + set text [eval [lindex $i 1]] + if {$max_status_desc < [string length $text]} { + set max_status_desc [string length $text] + } + set all_descs([lindex $i 0]) $text +} +unset i + +###################################################################### +## +## util + +proc scrollbar2many {list mode args} { + foreach w $list {eval $w $mode $args} +} + +proc many2scrollbar {list mode sb top bottom} { + $sb set $top $bottom + foreach w $list {$w $mode moveto $top} +} + +proc incr_font_size {font {amt 1}} { + set sz [font configure $font -size] + incr sz $amt + font configure $font -size $sz + font configure ${font}bold -size $sz + font configure ${font}italic -size $sz +} + +###################################################################### +## +## ui commands + +set starting_gitk_msg [mc "Starting gitk... please wait..."] + +proc do_gitk {revs {is_submodule false}} { + global current_diff_path file_states current_diff_side ui_index + global _gitdir _gitworktree + + # -- Always start gitk through whatever we were loaded with. This + # lets us bypass using shell process on Windows systems. + # + set exe [_which gitk -script] + set cmd [list [info nameofexecutable] $exe] + if {$exe eq {}} { + error_popup [mc "Couldn't find gitk in PATH"] + } else { + global env + + set pwd [pwd] + + if {!$is_submodule} { + if {![is_bare]} { + cd $_gitworktree + } + } else { + cd $current_diff_path + if {$revs eq {--}} { + set s $file_states($current_diff_path) + set old_sha1 {} + set new_sha1 {} + switch -glob -- [lindex $s 0] { + M_ { set old_sha1 [lindex [lindex $s 2] 1] } + _M { set old_sha1 [lindex [lindex $s 3] 1] } + MM { + if {$current_diff_side eq $ui_index} { + set old_sha1 [lindex [lindex $s 2] 1] + set new_sha1 [lindex [lindex $s 3] 1] + } else { + set old_sha1 [lindex [lindex $s 3] 1] + } + } + } + set revs $old_sha1...$new_sha1 + } + # GIT_DIR and GIT_WORK_TREE for the submodule are not the ones + # we've been using for the main repository, so unset them. + # TODO we could make life easier (start up faster?) for gitk + # by setting these to the appropriate values to allow gitk + # to skip the heuristics to find their proper value + unset env(GIT_DIR) + unset env(GIT_WORK_TREE) + } + eval exec $cmd $revs "--" "--" & + + set env(GIT_DIR) $_gitdir + set env(GIT_WORK_TREE) $_gitworktree + cd $pwd + + ui_status $::starting_gitk_msg + after 10000 { + ui_ready $starting_gitk_msg + } + } +} + +proc do_git_gui {} { + global current_diff_path + + # -- Always start git gui through whatever we were loaded with. This + # lets us bypass using shell process on Windows systems. + # + set exe [list [_which git]] + if {$exe eq {}} { + error_popup [mc "Couldn't find git gui in PATH"] + } else { + global env + global _gitdir _gitworktree + + # see note in do_gitk about unsetting these vars when + # running tools in a submodule + unset env(GIT_DIR) + unset env(GIT_WORK_TREE) + + set pwd [pwd] + cd $current_diff_path + + eval exec $exe gui & + + set env(GIT_DIR) $_gitdir + set env(GIT_WORK_TREE) $_gitworktree + cd $pwd + + ui_status $::starting_gitk_msg + after 10000 { + ui_ready $starting_gitk_msg + } + } +} + +proc do_explore {} { + global _gitworktree + set explorer {} + if {[is_Cygwin] || [is_Windows]} { + set explorer "explorer.exe" + } elseif {[is_MacOSX]} { + set explorer "open" + } else { + # freedesktop.org-conforming system is our best shot + set explorer "xdg-open" + } + eval exec $explorer [list [file nativename $_gitworktree]] & +} + +set is_quitting 0 +set ret_code 1 + +proc terminate_me {win} { + global ret_code + if {$win ne {.}} return + exit $ret_code +} + +proc do_quit {{rc {1}}} { + global ui_comm is_quitting repo_config commit_type + global GITGUI_BCK_exists GITGUI_BCK_i + global ui_comm_spell + global ret_code use_ttk + + if {$is_quitting} return + set is_quitting 1 + + if {[winfo exists $ui_comm]} { + # -- Stash our current commit buffer. + # + 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]] + 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} + } + } + + # -- Cancel our spellchecker if its running. + # + if {[info exists ui_comm_spell]} { + $ui_comm_spell stop + } + + # -- 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. + # + set cfg_wmstate [wm state .] + if {[catch {set rc_wmstate $repo_config(gui.wmstate)}]} { + set rc_wmstate {} + } + if {$cfg_wmstate ne $rc_wmstate} { + catch {git config gui.wmstate $cfg_wmstate} + } + if {$cfg_wmstate eq {zoomed}} { + # on Windows wm geometry will lie about window + # position (but not size) when window is zoomed + # restore the window before querying wm geometry + wm state . normal + } + set cfg_geometry [list] + lappend cfg_geometry [wm geometry .] + if {$use_ttk} { + lappend cfg_geometry [.vpane sashpos 0] + lappend cfg_geometry [.vpane.files sashpos 0] + } else { + lappend cfg_geometry [lindex [.vpane sash coord 0] 0] + lappend cfg_geometry [lindex [.vpane.files sash coord 0] 1] + } + if {[catch {set rc_geometry $repo_config(gui.geometry)}]} { + set rc_geometry {} + } + if {$cfg_geometry ne $rc_geometry} { + catch {git config gui.geometry $cfg_geometry} + } + } + + set ret_code $rc + + # Briefly enable send again, working around Tk bug + # http://sourceforge.net/tracker/?func=detail&atid=112997&aid=1821174&group_id=12997 + tk appname [appname] + + destroy . +} + +proc do_rescan {} { + rescan ui_ready +} + +proc ui_do_rescan {} { + rescan {force_first_diff ui_ready} +} + +proc do_commit {} { + commit_tree +} + +proc next_diff {{after {}}} { + global next_diff_p next_diff_w next_diff_i + show_diff $next_diff_p $next_diff_w {} {} $after +} + +proc find_anchor_pos {lst name} { + set lid [lsearch -sorted -exact $lst $name] + + if {$lid == -1} { + set lid 0 + foreach lname $lst { + if {$lname >= $name} break + incr lid + } + } + + return $lid +} + +proc find_file_from {flist idx delta path mmask} { + global file_states + + set len [llength $flist] + while {$idx >= 0 && $idx < $len} { + set name [lindex $flist $idx] + + if {$name ne $path && [info exists file_states($name)]} { + set state [lindex $file_states($name) 0] + + if {$mmask eq {} || [regexp $mmask $state]} { + return $idx + } + } + + incr idx $delta + } + + return {} +} + +proc find_next_diff {w path {lno {}} {mmask {}}} { + global next_diff_p next_diff_w next_diff_i + global file_lists ui_index ui_workdir + + set flist $file_lists($w) + if {$lno eq {}} { + set lno [find_anchor_pos $flist $path] + } else { + incr lno -1 + } + + if {$mmask ne {} && ![regexp {(^\^)|(\$$)} $mmask]} { + if {$w eq $ui_index} { + set mmask "^$mmask" + } else { + set mmask "$mmask\$" + } + } + + set idx [find_file_from $flist $lno 1 $path $mmask] + if {$idx eq {}} { + incr lno -1 + set idx [find_file_from $flist $lno -1 $path $mmask] + } + + if {$idx ne {}} { + set next_diff_w $w + set next_diff_p [lindex $flist $idx] + set next_diff_i [expr {$idx+1}] + return 1 + } else { + return 0 + } +} + +proc next_diff_after_action {w path {lno {}} {mmask {}}} { + global current_diff_path + + if {$path ne $current_diff_path} { + return {} + } elseif {[find_next_diff $w $path $lno $mmask]} { + return {next_diff;} + } else { + return {reshow_diff;} + } +} + +proc select_first_diff {after} { + global ui_workdir + + if {[find_next_diff $ui_workdir {} 1 {^_?U}] || + [find_next_diff $ui_workdir {} 1 {[^O]$}]} { + next_diff $after + } else { + uplevel #0 $after + } +} + +proc force_first_diff {after} { + global ui_workdir current_diff_path file_states + + if {[info exists file_states($current_diff_path)]} { + set state [lindex $file_states($current_diff_path) 0] + } else { + set state {OO} + } + + set reselect 0 + if {[string first {U} $state] >= 0} { + # Already a conflict, do nothing + } elseif {[find_next_diff $ui_workdir $current_diff_path {} {^_?U}]} { + set reselect 1 + } elseif {[string index $state 1] ne {O}} { + # Already a diff & no conflicts, do nothing + } elseif {[find_next_diff $ui_workdir $current_diff_path {} {[^O]$}]} { + set reselect 1 + } + + if {$reselect} { + next_diff $after + } else { + uplevel #0 $after + } +} + +proc toggle_or_diff {w x y} { + global file_states file_lists current_diff_path ui_index ui_workdir + global last_clicked selected_paths + + set pos [split [$w index @$x,$y] .] + set lno [lindex $pos 0] + set col [lindex $pos 1] + set path [lindex $file_lists($w) [expr {$lno - 1}]] + if {$path eq {}} { + set last_clicked {} + return + } + + set last_clicked [list $w $lno] + array unset selected_paths + $ui_index tag remove in_sel 0.0 end + $ui_workdir tag remove in_sel 0.0 end + + # Determine the state of the file + if {[info exists file_states($path)]} { + set state [lindex $file_states($path) 0] + } else { + set state {__} + } + + # Restage the file, or simply show the diff + if {$col == 0 && $y > 1} { + # Conflicts need special handling + if {[string first {U} $state] >= 0} { + # $w must always be $ui_workdir, but... + if {$w ne $ui_workdir} { set lno {} } + merge_stage_workdir $path $lno + return + } + + if {[string index $state 1] eq {O}} { + set mmask {} + } else { + set mmask {[^O]} + } + + set after [next_diff_after_action $w $path $lno $mmask] + + if {$w eq $ui_index} { + update_indexinfo \ + "Unstaging [short_path $path] from commit" \ + [list $path] \ + [concat $after [list ui_ready]] + } elseif {$w eq $ui_workdir} { + update_index \ + "Adding [short_path $path]" \ + [list $path] \ + [concat $after [list ui_ready]] + } + } else { + show_diff $path $w $lno + } +} + +proc add_one_to_selection {w x y} { + global file_lists last_clicked selected_paths + + set lno [lindex [split [$w index @$x,$y] .] 0] + set path [lindex $file_lists($w) [expr {$lno - 1}]] + if {$path eq {}} { + set last_clicked {} + return + } + + if {$last_clicked ne {} + && [lindex $last_clicked 0] ne $w} { + array unset selected_paths + [lindex $last_clicked 0] tag remove in_sel 0.0 end + } + + set last_clicked [list $w $lno] + if {[catch {set in_sel $selected_paths($path)}]} { + set in_sel 0 + } + if {$in_sel} { + unset selected_paths($path) + $w tag remove in_sel $lno.0 [expr {$lno + 1}].0 + } else { + set selected_paths($path) 1 + $w tag add in_sel $lno.0 [expr {$lno + 1}].0 + } +} + +proc add_range_to_selection {w x y} { + global file_lists last_clicked selected_paths + + if {[lindex $last_clicked 0] ne $w} { + toggle_or_diff $w $x $y + return + } + + set lno [lindex [split [$w index @$x,$y] .] 0] + set lc [lindex $last_clicked 1] + if {$lc < $lno} { + set begin $lc + set end $lno + } else { + set begin $lno + set end $lc + } + + foreach path [lrange $file_lists($w) \ + [expr {$begin - 1}] \ + [expr {$end - 1}]] { + set selected_paths($path) 1 + } + $w tag add in_sel $begin.0 [expr {$end + 1}].0 +} + +proc show_more_context {} { + global repo_config + if {$repo_config(gui.diffcontext) < 99} { + incr repo_config(gui.diffcontext) + reshow_diff + } +} + +proc show_less_context {} { + global repo_config + if {$repo_config(gui.diffcontext) > 1} { + incr repo_config(gui.diffcontext) -1 + reshow_diff + } +} + +###################################################################### +## +## ui construction + +set ui_comm {} + +# -- Menu Bar +# +menu .mbar -tearoff 0 +if {[is_MacOSX]} { + # -- Apple Menu (Mac OS X only) + # + .mbar add cascade -label Apple -menu .mbar.apple + menu .mbar.apple +} +.mbar add cascade -label [mc Repository] -menu .mbar.repository +.mbar add cascade -label [mc Edit] -menu .mbar.edit +if {[is_enabled branch]} { + .mbar add cascade -label [mc Branch] -menu .mbar.branch +} +if {[is_enabled multicommit] || [is_enabled singlecommit]} { + .mbar add cascade -label [mc Commit@@noun] -menu .mbar.commit +} +if {[is_enabled transport]} { + .mbar add cascade -label [mc Merge] -menu .mbar.merge + .mbar add cascade -label [mc Remote] -menu .mbar.remote +} +if {[is_enabled multicommit] || [is_enabled singlecommit]} { + .mbar add cascade -label [mc Tools] -menu .mbar.tools +} + +# -- Repository Menu +# +menu .mbar.repository + +if {![is_bare]} { + .mbar.repository add command \ + -label [mc "Explore Working Copy"] \ + -command {do_explore} + .mbar.repository add separator +} + +.mbar.repository add command \ + -label [mc "Browse Current Branch's Files"] \ + -command {browser::new $current_branch} +set ui_browse_current [.mbar.repository index last] +.mbar.repository add command \ + -label [mc "Browse Branch Files..."] \ + -command browser_open::dialog +.mbar.repository add separator + +.mbar.repository add command \ + -label [mc "Visualize Current Branch's History"] \ + -command {do_gitk $current_branch} +set ui_visualize_current [.mbar.repository index last] +.mbar.repository add command \ + -label [mc "Visualize All Branch History"] \ + -command {do_gitk --all} +.mbar.repository add separator + +proc current_branch_write {args} { + global current_branch + .mbar.repository entryconf $::ui_browse_current \ + -label [mc "Browse %s's Files" $current_branch] + .mbar.repository entryconf $::ui_visualize_current \ + -label [mc "Visualize %s's History" $current_branch] +} +trace add variable current_branch write current_branch_write + +if {[is_enabled multicommit]} { + .mbar.repository add command -label [mc "Database Statistics"] \ + -command do_stats + + .mbar.repository add command -label [mc "Compress Database"] \ + -command do_gc + + .mbar.repository add command -label [mc "Verify Database"] \ + -command do_fsck_objects + + .mbar.repository add separator + + if {[is_Cygwin]} { + .mbar.repository add command \ + -label [mc "Create Desktop Icon"] \ + -command do_cygwin_shortcut + } elseif {[is_Windows]} { + .mbar.repository add command \ + -label [mc "Create Desktop Icon"] \ + -command do_windows_shortcut + } elseif {[is_MacOSX]} { + .mbar.repository add command \ + -label [mc "Create Desktop Icon"] \ + -command do_macosx_app + } +} + +if {[is_MacOSX]} { + proc ::tk::mac::Quit {args} { do_quit } +} else { + .mbar.repository add command -label [mc Quit] \ + -command do_quit \ + -accelerator $M1T-Q +} + +# -- Edit Menu +# +menu .mbar.edit +.mbar.edit add command -label [mc Undo] \ + -command {catch {[focus] edit undo}} \ + -accelerator $M1T-Z +.mbar.edit add command -label [mc Redo] \ + -command {catch {[focus] edit redo}} \ + -accelerator $M1T-Y +.mbar.edit add separator +.mbar.edit add command -label [mc Cut] \ + -command {catch {tk_textCut [focus]}} \ + -accelerator $M1T-X +.mbar.edit add command -label [mc Copy] \ + -command {catch {tk_textCopy [focus]}} \ + -accelerator $M1T-C +.mbar.edit add command -label [mc Paste] \ + -command {catch {tk_textPaste [focus]; [focus] see insert}} \ + -accelerator $M1T-V +.mbar.edit add command -label [mc Delete] \ + -command {catch {[focus] delete sel.first sel.last}} \ + -accelerator Del +.mbar.edit add separator +.mbar.edit add command -label [mc "Select All"] \ + -command {catch {[focus] tag add sel 0.0 end}} \ + -accelerator $M1T-A + +# -- Branch Menu +# +if {[is_enabled branch]} { + menu .mbar.branch + + .mbar.branch add command -label [mc "Create..."] \ + -command branch_create::dialog \ + -accelerator $M1T-N + lappend disable_on_lock [list .mbar.branch entryconf \ + [.mbar.branch index last] -state] + + .mbar.branch add command -label [mc "Checkout..."] \ + -command branch_checkout::dialog \ + -accelerator $M1T-O + lappend disable_on_lock [list .mbar.branch entryconf \ + [.mbar.branch index last] -state] + + .mbar.branch add command -label [mc "Rename..."] \ + -command branch_rename::dialog + lappend disable_on_lock [list .mbar.branch entryconf \ + [.mbar.branch index last] -state] + + .mbar.branch add command -label [mc "Delete..."] \ + -command branch_delete::dialog + lappend disable_on_lock [list .mbar.branch entryconf \ + [.mbar.branch index last] -state] + + .mbar.branch add command -label [mc "Reset..."] \ + -command merge::reset_hard + lappend disable_on_lock [list .mbar.branch entryconf \ + [.mbar.branch index last] -state] +} + +# -- Commit Menu +# +proc commit_btn_caption {} { + if {[is_enabled nocommit]} { + return [mc "Done"] + } else { + return [mc Commit@@verb] + } +} + +if {[is_enabled multicommit] || [is_enabled singlecommit]} { + menu .mbar.commit + + if {![is_enabled nocommit]} { + .mbar.commit add radiobutton \ + -label [mc "New Commit"] \ + -command do_select_commit_type \ + -variable selected_commit_type \ + -value new + lappend disable_on_lock \ + [list .mbar.commit entryconf [.mbar.commit index last] -state] + + .mbar.commit add radiobutton \ + -label [mc "Amend Last Commit"] \ + -command do_select_commit_type \ + -variable selected_commit_type \ + -value amend + lappend disable_on_lock \ + [list .mbar.commit entryconf [.mbar.commit index last] -state] + + .mbar.commit add separator + } + + .mbar.commit add command -label [mc Rescan] \ + -command ui_do_rescan \ + -accelerator F5 + lappend disable_on_lock \ + [list .mbar.commit entryconf [.mbar.commit index last] -state] + + .mbar.commit add command -label [mc "Stage To Commit"] \ + -command do_add_selection \ + -accelerator $M1T-T + lappend disable_on_lock \ + [list .mbar.commit entryconf [.mbar.commit index last] -state] + + .mbar.commit add command -label [mc "Stage Changed Files To Commit"] \ + -command do_add_all \ + -accelerator $M1T-I + lappend disable_on_lock \ + [list .mbar.commit entryconf [.mbar.commit index last] -state] + + .mbar.commit add command -label [mc "Unstage From Commit"] \ + -command do_unstage_selection \ + -accelerator $M1T-U + lappend disable_on_lock \ + [list .mbar.commit entryconf [.mbar.commit index last] -state] + + .mbar.commit add command -label [mc "Revert Changes"] \ + -command do_revert_selection \ + -accelerator $M1T-J + lappend disable_on_lock \ + [list .mbar.commit entryconf [.mbar.commit index last] -state] + + .mbar.commit add separator + + .mbar.commit add command -label [mc "Show Less Context"] \ + -command show_less_context \ + -accelerator $M1T-\- + + .mbar.commit add command -label [mc "Show More Context"] \ + -command show_more_context \ + -accelerator $M1T-= + + .mbar.commit add separator + + if {![is_enabled nocommitmsg]} { + .mbar.commit add command -label [mc "Sign Off"] \ + -command do_signoff \ + -accelerator $M1T-S + } + + .mbar.commit add command -label [commit_btn_caption] \ + -command do_commit \ + -accelerator $M1T-Return + lappend disable_on_lock \ + [list .mbar.commit entryconf [.mbar.commit index last] -state] +} + +# -- Merge Menu +# +if {[is_enabled branch]} { + menu .mbar.merge + .mbar.merge add command -label [mc "Local Merge..."] \ + -command merge::dialog \ + -accelerator $M1T-M + lappend disable_on_lock \ + [list .mbar.merge entryconf [.mbar.merge index last] -state] + .mbar.merge add command -label [mc "Abort Merge..."] \ + -command merge::reset_hard + lappend disable_on_lock \ + [list .mbar.merge entryconf [.mbar.merge index last] -state] +} + +# -- Transport Menu +# +if {[is_enabled transport]} { + menu .mbar.remote + + .mbar.remote add command \ + -label [mc "Add..."] \ + -command remote_add::dialog \ + -accelerator $M1T-A + .mbar.remote add command \ + -label [mc "Push..."] \ + -command do_push_anywhere \ + -accelerator $M1T-P + .mbar.remote add command \ + -label [mc "Delete Branch..."] \ + -command remote_branch_delete::dialog +} + +if {[is_MacOSX]} { + proc ::tk::mac::ShowPreferences {} {do_options} +} else { + # -- Edit Menu + # + .mbar.edit add separator + .mbar.edit add command -label [mc "Options..."] \ + -command do_options +} + +# -- Tools Menu +# +if {[is_enabled multicommit] || [is_enabled singlecommit]} { + set tools_menubar .mbar.tools + menu $tools_menubar + $tools_menubar add separator + $tools_menubar add command -label [mc "Add..."] -command tools_add::dialog + $tools_menubar add command -label [mc "Remove..."] -command tools_remove::dialog + set tools_tailcnt 3 + if {[array names repo_config guitool.*.cmd] ne {}} { + tools_populate_all + } +} + +# -- Help Menu +# +.mbar add cascade -label [mc Help] -menu .mbar.help +menu .mbar.help + +if {[is_MacOSX]} { + .mbar.apple add command -label [mc "About %s" [appname]] \ + -command do_about + .mbar.apple add separator +} else { + .mbar.help add command -label [mc "About %s" [appname]] \ + -command do_about +} +. configure -menu .mbar + +set doc_path [githtmldir] +if {$doc_path ne {}} { + set doc_path [file join $doc_path index.html] + + if {[is_Cygwin]} { + set doc_path [exec cygpath --mixed $doc_path] + } +} + +if {[file isfile $doc_path]} { + set doc_url "file:$doc_path" +} else { + set doc_url {http://www.kernel.org/pub/software/scm/git/docs/} +} + +proc start_browser {url} { + git "web--browse" $url +} + +.mbar.help add command -label [mc "Online Documentation"] \ + -command [list start_browser $doc_url] + +.mbar.help add command -label [mc "Show SSH Key"] \ + -command do_ssh_key + +unset doc_path doc_url + +# -- Standard bindings +# +wm protocol . WM_DELETE_WINDOW do_quit +bind all <$M1B-Key-q> do_quit +bind all <$M1B-Key-Q> do_quit +bind all <$M1B-Key-w> {destroy [winfo toplevel %W]} +bind all <$M1B-Key-W> {destroy [winfo toplevel %W]} + +set subcommand_args {} +proc usage {} { + set s "usage: $::argv0 $::subcommand $::subcommand_args" + if {[tk windowingsystem] eq "win32"} { + wm withdraw . + tk_messageBox -icon info -message $s \ + -title [mc "Usage"] + } else { + puts stderr $s + } + exit 1 +} + +proc normalize_relpath {path} { + set elements {} + foreach item [file split $path] { + if {$item eq {.}} continue + if {$item eq {..} && [llength $elements] > 0 + && [lindex $elements end] ne {..}} { + set elements [lrange $elements 0 end-1] + continue + } + lappend elements $item + } + return [eval file join $elements] +} + +# -- Not a normal commit type invocation? Do that instead! +# +switch -- $subcommand { +browser - +blame { + if {$subcommand eq "blame"} { + set subcommand_args {[--line=] rev? path} + } else { + set subcommand_args {rev? path} + } + if {$argv eq {}} usage + set head {} + set path {} + set jump_spec {} + set is_path 0 + foreach a $argv { + if {$is_path || [file exists $_prefix$a]} { + if {$path ne {}} usage + set path [normalize_relpath $_prefix$a] + break + } elseif {$a eq {--}} { + if {$path ne {}} { + if {$head ne {}} usage + set head $path + set path {} + } + set is_path 1 + } elseif {[regexp {^--line=(\d+)$} $a a lnum]} { + if {$jump_spec ne {} || $head ne {}} usage + set jump_spec [list $lnum] + } elseif {$head eq {}} { + if {$head ne {}} usage + set head $a + set is_path 1 + } else { + usage + } + } + unset is_path + + if {$head ne {} && $path eq {}} { + set path [normalize_relpath $_prefix$head] + set head {} + } + + if {$head eq {}} { + load_current_branch + } else { + if {[regexp {^[0-9a-f]{1,39}$} $head]} { + if {[catch { + set head [git rev-parse --verify $head] + } err]} { + if {[tk windowingsystem] eq "win32"} { + tk_messageBox -icon error -title [mc Error] -message $err + } else { + puts stderr $err + } + exit 1 + } + } + set current_branch $head + } + + wm deiconify . + switch -- $subcommand { + browser { + if {$jump_spec ne {}} usage + 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]} { + catch {wm withdraw .} + tk_messageBox \ + -icon error \ + -type ok \ + -title [mc "git-gui: fatal error"] \ + -message [mc "fatal: cannot stat path %s: No such file or directory" $path] + exit 1 + } + blame::new $head $path $jump_spec + } + } + return +} +citool - +gui { + if {[llength $argv] != 0} { + usage + } + # fall through to setup UI for commits +} +default { + set err "usage: $argv0 \[{blame|browser|citool}\]" + if {[tk windowingsystem] eq "win32"} { + wm withdraw . + tk_messageBox -icon error -message $err \ + -title [mc "Usage"] + } else { + puts stderr $err + } + exit 1 +} +} + +# -- Branch Control +# +${NS}::frame .branch +if {!$use_ttk} {.branch configure -borderwidth 1 -relief sunken} +${NS}::label .branch.l1 \ + -text [mc "Current Branch:"] \ + -anchor w \ + -justify left +${NS}::label .branch.cb \ + -textvariable current_branch \ + -anchor w \ + -justify left +pack .branch.l1 -side left +pack .branch.cb -side left -fill x +pack .branch -side top -fill x + +# -- Main Window Layout +# +${NS}::panedwindow .vpane -orient horizontal +${NS}::panedwindow .vpane.files -orient vertical +if {$use_ttk} { + .vpane add .vpane.files +} else { + .vpane add .vpane.files -sticky nsew -height 100 -width 200 +} +pack .vpane -anchor n -side top -fill both -expand 1 + +# -- Index File List +# +${NS}::frame .vpane.files.index -height 100 -width 200 +tlabel .vpane.files.index.title \ + -text [mc "Staged Changes (Will Commit)"] \ + -background lightgreen -foreground black +text $ui_index -background white -foreground black \ + -borderwidth 0 \ + -width 20 -height 10 \ + -wrap none \ + -cursor $cursor_ptr \ + -xscrollcommand {.vpane.files.index.sx set} \ + -yscrollcommand {.vpane.files.index.sy set} \ + -state disabled +${NS}::scrollbar .vpane.files.index.sx -orient h -command [list $ui_index xview] +${NS}::scrollbar .vpane.files.index.sy -orient v -command [list $ui_index yview] +pack .vpane.files.index.title -side top -fill x +pack .vpane.files.index.sx -side bottom -fill x +pack .vpane.files.index.sy -side right -fill y +pack $ui_index -side left -fill both -expand 1 + +# -- Working Directory File List +# +${NS}::frame .vpane.files.workdir -height 100 -width 200 +tlabel .vpane.files.workdir.title -text [mc "Unstaged Changes"] \ + -background lightsalmon -foreground black +text $ui_workdir -background white -foreground black \ + -borderwidth 0 \ + -width 20 -height 10 \ + -wrap none \ + -cursor $cursor_ptr \ + -xscrollcommand {.vpane.files.workdir.sx set} \ + -yscrollcommand {.vpane.files.workdir.sy set} \ + -state disabled +${NS}::scrollbar .vpane.files.workdir.sx -orient h -command [list $ui_workdir xview] +${NS}::scrollbar .vpane.files.workdir.sy -orient v -command [list $ui_workdir yview] +pack .vpane.files.workdir.title -side top -fill x +pack .vpane.files.workdir.sx -side bottom -fill x +pack .vpane.files.workdir.sy -side right -fill y +pack $ui_workdir -side left -fill both -expand 1 + +.vpane.files add .vpane.files.workdir +.vpane.files add .vpane.files.index +if {!$use_ttk} { + .vpane.files paneconfigure .vpane.files.workdir -sticky news + .vpane.files paneconfigure .vpane.files.index -sticky news +} + +foreach i [list $ui_index $ui_workdir] { + rmsel_tag $i + $i tag conf in_diff -background [$i tag cget in_sel -background] +} +unset i + +# -- Diff and Commit Area +# +${NS}::frame .vpane.lower -height 300 -width 400 +${NS}::frame .vpane.lower.commarea +${NS}::frame .vpane.lower.diff -relief sunken -borderwidth 1 +pack .vpane.lower.diff -fill both -expand 1 +pack .vpane.lower.commarea -side bottom -fill x +.vpane add .vpane.lower +if {!$use_ttk} {.vpane paneconfigure .vpane.lower -sticky nsew} + +# -- Commit Area Buttons +# +${NS}::frame .vpane.lower.commarea.buttons +${NS}::label .vpane.lower.commarea.buttons.l -text {} \ + -anchor w \ + -justify left +pack .vpane.lower.commarea.buttons.l -side top -fill x +pack .vpane.lower.commarea.buttons -side left -fill y + +${NS}::button .vpane.lower.commarea.buttons.rescan -text [mc Rescan] \ + -command ui_do_rescan +pack .vpane.lower.commarea.buttons.rescan -side top -fill x +lappend disable_on_lock \ + {.vpane.lower.commarea.buttons.rescan conf -state} + +${NS}::button .vpane.lower.commarea.buttons.incall -text [mc "Stage Changed"] \ + -command do_add_all +pack .vpane.lower.commarea.buttons.incall -side top -fill x +lappend disable_on_lock \ + {.vpane.lower.commarea.buttons.incall conf -state} + +if {![is_enabled nocommitmsg]} { + ${NS}::button .vpane.lower.commarea.buttons.signoff -text [mc "Sign Off"] \ + -command do_signoff + pack .vpane.lower.commarea.buttons.signoff -side top -fill x +} + +${NS}::button .vpane.lower.commarea.buttons.commit -text [commit_btn_caption] \ + -command do_commit +pack .vpane.lower.commarea.buttons.commit -side top -fill x +lappend disable_on_lock \ + {.vpane.lower.commarea.buttons.commit conf -state} + +if {![is_enabled nocommit]} { + ${NS}::button .vpane.lower.commarea.buttons.push -text [mc Push] \ + -command do_push_anywhere + pack .vpane.lower.commarea.buttons.push -side top -fill x +} + +# -- Commit Message Buffer +# +${NS}::frame .vpane.lower.commarea.buffer +${NS}::frame .vpane.lower.commarea.buffer.header +set ui_comm .vpane.lower.commarea.buffer.t +set ui_coml .vpane.lower.commarea.buffer.header.l + +if {![is_enabled nocommit]} { + ${NS}::radiobutton .vpane.lower.commarea.buffer.header.new \ + -text [mc "New Commit"] \ + -command do_select_commit_type \ + -variable selected_commit_type \ + -value new + lappend disable_on_lock \ + [list .vpane.lower.commarea.buffer.header.new conf -state] + ${NS}::radiobutton .vpane.lower.commarea.buffer.header.amend \ + -text [mc "Amend Last Commit"] \ + -command do_select_commit_type \ + -variable selected_commit_type \ + -value amend + lappend disable_on_lock \ + [list .vpane.lower.commarea.buffer.header.amend conf -state] +} + +${NS}::label $ui_coml \ + -anchor w \ + -justify left +proc trace_commit_type {varname args} { + global ui_coml commit_type + switch -glob -- $commit_type { + initial {set txt [mc "Initial Commit Message:"]} + amend {set txt [mc "Amended Commit Message:"]} + amend-initial {set txt [mc "Amended Initial Commit Message:"]} + amend-merge {set txt [mc "Amended Merge Commit Message:"]} + merge {set txt [mc "Merge Commit Message:"]} + * {set txt [mc "Commit Message:"]} + } + $ui_coml conf -text $txt +} +trace add variable commit_type write trace_commit_type +pack $ui_coml -side left -fill x + +if {![is_enabled nocommit]} { + pack .vpane.lower.commarea.buffer.header.amend -side right + pack .vpane.lower.commarea.buffer.header.new -side right +} + +text $ui_comm -background white -foreground black \ + -borderwidth 1 \ + -undo true \ + -maxundo 20 \ + -autoseparators true \ + -relief sunken \ + -width $repo_config(gui.commitmsgwidth) -height 9 -wrap none \ + -font font_diff \ + -yscrollcommand {.vpane.lower.commarea.buffer.sby set} +${NS}::scrollbar .vpane.lower.commarea.buffer.sby \ + -command [list $ui_comm yview] +pack .vpane.lower.commarea.buffer.header -side top -fill x +pack .vpane.lower.commarea.buffer.sby -side right -fill y +pack $ui_comm -side left -fill y +pack .vpane.lower.commarea.buffer -side left -fill y + +# -- Commit Message Buffer Context Menu +# +set ctxm .vpane.lower.commarea.buffer.ctxm +menu $ctxm -tearoff 0 +$ctxm add command \ + -label [mc Cut] \ + -command {tk_textCut $ui_comm} +$ctxm add command \ + -label [mc Copy] \ + -command {tk_textCopy $ui_comm} +$ctxm add command \ + -label [mc Paste] \ + -command {tk_textPaste $ui_comm} +$ctxm add command \ + -label [mc Delete] \ + -command {catch {$ui_comm delete sel.first sel.last}} +$ctxm add separator +$ctxm add command \ + -label [mc "Select All"] \ + -command {focus $ui_comm;$ui_comm tag add sel 0.0 end} +$ctxm add command \ + -label [mc "Copy All"] \ + -command { + $ui_comm tag add sel 0.0 end + tk_textCopy $ui_comm + $ui_comm tag remove sel 0.0 end + } +$ctxm add separator +$ctxm add command \ + -label [mc "Sign Off"] \ + -command do_signoff +set ui_comm_ctxm $ctxm + +# -- Diff Header +# +proc trace_current_diff_path {varname args} { + global current_diff_path diff_actions file_states + if {$current_diff_path eq {}} { + set s {} + set f {} + set p {} + set o disabled + } else { + set p $current_diff_path + set s [mapdesc [lindex $file_states($p) 0] $p] + set f [mc "File:"] + set p [escape_path $p] + set o normal + } + + .vpane.lower.diff.header.status configure -text $s + .vpane.lower.diff.header.file configure -text $f + .vpane.lower.diff.header.path configure -text $p + foreach w $diff_actions { + uplevel #0 $w $o + } +} +trace add variable current_diff_path write trace_current_diff_path + +gold_frame .vpane.lower.diff.header +tlabel .vpane.lower.diff.header.status \ + -background gold \ + -foreground black \ + -width $max_status_desc \ + -anchor w \ + -justify left +tlabel .vpane.lower.diff.header.file \ + -background gold \ + -foreground black \ + -anchor w \ + -justify left +tlabel .vpane.lower.diff.header.path \ + -background gold \ + -foreground black \ + -anchor w \ + -justify left +pack .vpane.lower.diff.header.status -side left +pack .vpane.lower.diff.header.file -side left +pack .vpane.lower.diff.header.path -fill x +set ctxm .vpane.lower.diff.header.ctxm +menu $ctxm -tearoff 0 +$ctxm add command \ + -label [mc Copy] \ + -command { + clipboard clear + clipboard append \ + -format STRING \ + -type STRING \ + -- $current_diff_path + } +lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state] +bind_button3 .vpane.lower.diff.header.path "tk_popup $ctxm %X %Y" + +# -- Diff Body +# +${NS}::frame .vpane.lower.diff.body +set ui_diff .vpane.lower.diff.body.t +text $ui_diff -background white -foreground black \ + -borderwidth 0 \ + -width 80 -height 5 -wrap none \ + -font font_diff \ + -xscrollcommand {.vpane.lower.diff.body.sbx set} \ + -yscrollcommand {.vpane.lower.diff.body.sby set} \ + -state disabled +catch {$ui_diff configure -tabstyle wordprocessor} +${NS}::scrollbar .vpane.lower.diff.body.sbx -orient horizontal \ + -command [list $ui_diff xview] +${NS}::scrollbar .vpane.lower.diff.body.sby -orient vertical \ + -command [list $ui_diff yview] +pack .vpane.lower.diff.body.sbx -side bottom -fill x +pack .vpane.lower.diff.body.sby -side right -fill y +pack $ui_diff -side left -fill both -expand 1 +pack .vpane.lower.diff.header -side top -fill x +pack .vpane.lower.diff.body -side bottom -fill both -expand 1 + +foreach {n c} {0 black 1 red4 2 green4 3 yellow4 4 blue4 5 magenta4 6 cyan4 7 grey60} { + $ui_diff tag configure clr4$n -background $c + $ui_diff tag configure clri4$n -foreground $c + $ui_diff tag configure clr3$n -foreground $c + $ui_diff tag configure clri3$n -background $c +} +$ui_diff tag configure clr1 -font font_diffbold + ++$ui_diff tag conf d_info -foreground blue -font font_diffbold ++ +$ui_diff tag conf d_cr -elide true +$ui_diff tag conf d_@ -font font_diffbold +$ui_diff tag conf d_+ -foreground {#00a000} +$ui_diff tag conf d_- -foreground red + +$ui_diff tag conf d_++ -foreground {#00a000} +$ui_diff tag conf d_-- -foreground red +$ui_diff tag conf d_+s \ + -foreground {#00a000} \ + -background {#e2effa} +$ui_diff tag conf d_-s \ + -foreground red \ + -background {#e2effa} +$ui_diff tag conf d_s+ \ + -foreground {#00a000} \ + -background ivory1 +$ui_diff tag conf d_s- \ + -foreground red \ + -background ivory1 + - $ui_diff tag conf d<<<<<<< \ ++$ui_diff tag conf d< \ + -foreground orange \ + -font font_diffbold - $ui_diff tag conf d======= \ ++$ui_diff tag conf d= \ + -foreground orange \ + -font font_diffbold - $ui_diff tag conf d>>>>>>> \ ++$ui_diff tag conf d> \ + -foreground orange \ + -font font_diffbold + +$ui_diff tag raise sel + +# -- Diff Body Context Menu +# + +proc create_common_diff_popup {ctxm} { + $ctxm add command \ + -label [mc Refresh] \ + -command reshow_diff + lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state] + $ctxm add command \ + -label [mc Copy] \ + -command {tk_textCopy $ui_diff} + lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state] + $ctxm add command \ + -label [mc "Select All"] \ + -command {focus $ui_diff;$ui_diff tag add sel 0.0 end} + lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state] + $ctxm add command \ + -label [mc "Copy All"] \ + -command { + $ui_diff tag add sel 0.0 end + tk_textCopy $ui_diff + $ui_diff tag remove sel 0.0 end + } + lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state] + $ctxm add separator + $ctxm add command \ + -label [mc "Decrease Font Size"] \ + -command {incr_font_size font_diff -1} + lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state] + $ctxm add command \ + -label [mc "Increase Font Size"] \ + -command {incr_font_size font_diff 1} + lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state] + $ctxm add separator + set emenu $ctxm.enc + menu $emenu + build_encoding_menu $emenu [list force_diff_encoding] + $ctxm add cascade \ + -label [mc "Encoding"] \ + -menu $emenu + lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state] + $ctxm add separator + $ctxm add command -label [mc "Options..."] \ + -command do_options +} + +set ctxm .vpane.lower.diff.body.ctxm +menu $ctxm -tearoff 0 +$ctxm add command \ + -label [mc "Apply/Reverse Hunk"] \ + -command {apply_hunk $cursorX $cursorY} +set ui_diff_applyhunk [$ctxm index last] +lappend diff_actions [list $ctxm entryconf $ui_diff_applyhunk -state] +$ctxm add command \ + -label [mc "Apply/Reverse Line"] \ + -command {apply_range_or_line $cursorX $cursorY; do_rescan} +set ui_diff_applyline [$ctxm index last] +lappend diff_actions [list $ctxm entryconf $ui_diff_applyline -state] +$ctxm add separator +$ctxm add command \ + -label [mc "Show Less Context"] \ + -command show_less_context +lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state] +$ctxm add command \ + -label [mc "Show More Context"] \ + -command show_more_context +lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state] +$ctxm add separator +create_common_diff_popup $ctxm + +set ctxmmg .vpane.lower.diff.body.ctxmmg +menu $ctxmmg -tearoff 0 +$ctxmmg add command \ + -label [mc "Run Merge Tool"] \ + -command {merge_resolve_tool} +lappend diff_actions [list $ctxmmg entryconf [$ctxmmg index last] -state] +$ctxmmg add separator +$ctxmmg add command \ + -label [mc "Use Remote Version"] \ + -command {merge_resolve_one 3} +lappend diff_actions [list $ctxmmg entryconf [$ctxmmg index last] -state] +$ctxmmg add command \ + -label [mc "Use Local Version"] \ + -command {merge_resolve_one 2} +lappend diff_actions [list $ctxmmg entryconf [$ctxmmg index last] -state] +$ctxmmg add command \ + -label [mc "Revert To Base"] \ + -command {merge_resolve_one 1} +lappend diff_actions [list $ctxmmg entryconf [$ctxmmg index last] -state] +$ctxmmg add separator +$ctxmmg add command \ + -label [mc "Show Less Context"] \ + -command show_less_context +lappend diff_actions [list $ctxmmg entryconf [$ctxmmg index last] -state] +$ctxmmg add command \ + -label [mc "Show More Context"] \ + -command show_more_context +lappend diff_actions [list $ctxmmg entryconf [$ctxmmg index last] -state] +$ctxmmg add separator +create_common_diff_popup $ctxmmg + +set ctxmsm .vpane.lower.diff.body.ctxmsm +menu $ctxmsm -tearoff 0 +$ctxmsm add command \ + -label [mc "Visualize These Changes In The Submodule"] \ + -command {do_gitk -- true} +lappend diff_actions [list $ctxmsm entryconf [$ctxmsm index last] -state] +$ctxmsm add command \ + -label [mc "Visualize Current Branch History In The Submodule"] \ + -command {do_gitk {} true} +lappend diff_actions [list $ctxmsm entryconf [$ctxmsm index last] -state] +$ctxmsm add command \ + -label [mc "Visualize All Branch History In The Submodule"] \ + -command {do_gitk --all true} +lappend diff_actions [list $ctxmsm entryconf [$ctxmsm index last] -state] +$ctxmsm add separator +$ctxmsm add command \ + -label [mc "Start git gui In The Submodule"] \ + -command {do_git_gui} +lappend diff_actions [list $ctxmsm entryconf [$ctxmsm index last] -state] +$ctxmsm add separator +create_common_diff_popup $ctxmsm + +proc has_textconv {path} { + if {[is_config_false gui.textconv]} { + return 0 + } + set filter [gitattr $path diff set] + set textconv [get_config [join [list diff $filter textconv] .]] + if {$filter ne {set} && $textconv ne {}} { + return 1 + } else { + return 0 + } +} + +proc popup_diff_menu {ctxm ctxmmg ctxmsm x y X Y} { + global current_diff_path file_states + set ::cursorX $x + set ::cursorY $y + if {[info exists file_states($current_diff_path)]} { + set state [lindex $file_states($current_diff_path) 0] + } else { + set state {__} + } + if {[string first {U} $state] >= 0} { + tk_popup $ctxmmg $X $Y + } elseif {$::is_submodule_diff} { + tk_popup $ctxmsm $X $Y + } else { + set has_range [expr {[$::ui_diff tag nextrange sel 0.0] != {}}] + if {$::ui_index eq $::current_diff_side} { + set l [mc "Unstage Hunk From Commit"] + if {$has_range} { + set t [mc "Unstage Lines From Commit"] + } else { + set t [mc "Unstage Line From Commit"] + } + } else { + set l [mc "Stage Hunk For Commit"] + if {$has_range} { + set t [mc "Stage Lines For Commit"] + } else { + set t [mc "Stage Line For Commit"] + } + } + if {$::is_3way_diff + || $current_diff_path eq {} + || {__} eq $state + || {_O} eq $state - || {_T} eq $state - || {T_} eq $state ++ || [string match {?T} $state] ++ || [string match {T?} $state] + || [has_textconv $current_diff_path]} { + set s disabled + } else { + set s normal + } + $ctxm entryconf $::ui_diff_applyhunk -state $s -label $l + $ctxm entryconf $::ui_diff_applyline -state $s -label $t + tk_popup $ctxm $X $Y + } +} +bind_button3 $ui_diff [list popup_diff_menu $ctxm $ctxmmg $ctxmsm %x %y %X %Y] + +# -- Status Bar +# +set main_status [::status_bar::new .status] +pack .status -anchor w -side bottom -fill x +$main_status show [mc "Initializing..."] + +# -- Load geometry +# +proc on_ttk_pane_mapped {w pane pos} { + bind $w {} + after 0 [list after idle [list $w sashpos $pane $pos]] +} +proc on_tk_pane_mapped {w pane x y} { + bind $w {} + after 0 [list after idle [list $w sash place $pane $x $y]] +} +proc on_application_mapped {} { + global repo_config use_ttk + bind . {} + set gm $repo_config(gui.geometry) + if {$use_ttk} { + bind .vpane \ + [list on_ttk_pane_mapped %W 0 [lindex $gm 1]] + bind .vpane.files \ + [list on_ttk_pane_mapped %W 0 [lindex $gm 2]] + } else { + bind .vpane \ + [list on_tk_pane_mapped %W 0 \ + [lindex $gm 1] \ + [lindex [.vpane sash coord 0] 1]] + bind .vpane.files \ + [list on_tk_pane_mapped %W 0 \ + [lindex [.vpane.files sash coord 0] 0] \ + [lindex $gm 2]] + } + wm geometry . [lindex $gm 0] +} +if {[info exists repo_config(gui.geometry)]} { + bind . [list on_application_mapped] + wm geometry . [lindex $repo_config(gui.geometry) 0] +} + +# -- Load window state +# +if {[info exists repo_config(gui.wmstate)]} { + catch {wm state . $repo_config(gui.wmstate)} +} + +# -- Key Bindings +# +bind $ui_comm <$M1B-Key-Return> {do_commit;break} +bind $ui_comm <$M1B-Key-t> {do_add_selection;break} +bind $ui_comm <$M1B-Key-T> {do_add_selection;break} +bind $ui_comm <$M1B-Key-u> {do_unstage_selection;break} +bind $ui_comm <$M1B-Key-U> {do_unstage_selection;break} +bind $ui_comm <$M1B-Key-j> {do_revert_selection;break} +bind $ui_comm <$M1B-Key-J> {do_revert_selection;break} +bind $ui_comm <$M1B-Key-i> {do_add_all;break} +bind $ui_comm <$M1B-Key-I> {do_add_all;break} +bind $ui_comm <$M1B-Key-x> {tk_textCut %W;break} +bind $ui_comm <$M1B-Key-X> {tk_textCut %W;break} +bind $ui_comm <$M1B-Key-c> {tk_textCopy %W;break} +bind $ui_comm <$M1B-Key-C> {tk_textCopy %W;break} +bind $ui_comm <$M1B-Key-v> {tk_textPaste %W; %W see insert; break} +bind $ui_comm <$M1B-Key-V> {tk_textPaste %W; %W see insert; break} +bind $ui_comm <$M1B-Key-a> {%W tag add sel 0.0 end;break} +bind $ui_comm <$M1B-Key-A> {%W tag add sel 0.0 end;break} +bind $ui_comm <$M1B-Key-minus> {show_less_context;break} +bind $ui_comm <$M1B-Key-KP_Subtract> {show_less_context;break} +bind $ui_comm <$M1B-Key-equal> {show_more_context;break} +bind $ui_comm <$M1B-Key-plus> {show_more_context;break} +bind $ui_comm <$M1B-Key-KP_Add> {show_more_context;break} + +bind $ui_diff <$M1B-Key-x> {tk_textCopy %W;break} +bind $ui_diff <$M1B-Key-X> {tk_textCopy %W;break} +bind $ui_diff <$M1B-Key-c> {tk_textCopy %W;break} +bind $ui_diff <$M1B-Key-C> {tk_textCopy %W;break} +bind $ui_diff <$M1B-Key-v> {break} +bind $ui_diff <$M1B-Key-V> {break} +bind $ui_diff <$M1B-Key-a> {%W tag add sel 0.0 end;break} +bind $ui_diff <$M1B-Key-A> {%W tag add sel 0.0 end;break} +bind $ui_diff {catch {%W yview scroll -1 units};break} +bind $ui_diff {catch {%W yview scroll 1 units};break} +bind $ui_diff {catch {%W xview scroll -1 units};break} +bind $ui_diff {catch {%W xview scroll 1 units};break} +bind $ui_diff {catch {%W yview scroll -1 units};break} +bind $ui_diff {catch {%W yview scroll 1 units};break} +bind $ui_diff {catch {%W xview scroll -1 units};break} +bind $ui_diff {catch {%W xview scroll 1 units};break} +bind $ui_diff {catch {%W yview scroll -1 pages};break} +bind $ui_diff {catch {%W yview scroll 1 pages};break} +bind $ui_diff {focus %W} + +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-m> merge::dialog + bind . <$M1B-Key-M> merge::dialog +} +if {[is_enabled transport]} { + bind . <$M1B-Key-p> do_push_anywhere + bind . <$M1B-Key-P> do_push_anywhere +} + +bind . ui_do_rescan +bind . <$M1B-Key-r> ui_do_rescan +bind . <$M1B-Key-R> ui_do_rescan +bind . <$M1B-Key-s> do_signoff +bind . <$M1B-Key-S> do_signoff +bind . <$M1B-Key-t> do_add_selection +bind . <$M1B-Key-T> do_add_selection +bind . <$M1B-Key-j> do_revert_selection +bind . <$M1B-Key-J> do_revert_selection +bind . <$M1B-Key-i> do_add_all +bind . <$M1B-Key-I> do_add_all +bind . <$M1B-Key-minus> {show_less_context;break} +bind . <$M1B-Key-KP_Subtract> {show_less_context;break} +bind . <$M1B-Key-equal> {show_more_context;break} +bind . <$M1B-Key-plus> {show_more_context;break} +bind . <$M1B-Key-KP_Add> {show_more_context;break} +bind . <$M1B-Key-Return> do_commit +foreach i [list $ui_index $ui_workdir] { + bind $i "toggle_or_diff $i %x %y; break" + bind $i <$M1B-Button-1> "add_one_to_selection $i %x %y; break" + bind $i "add_range_to_selection $i %x %y; break" +} +unset i + +set file_lists($ui_index) [list] +set file_lists($ui_workdir) [list] + +wm title . "[appname] ([reponame]) [file normalize $_gitworktree]" +focus -force $ui_comm + +# -- Warn the user about environmental problems. Cygwin's Tcl +# does *not* pass its env array onto any processes it spawns. +# This means that git processes get none of our environment. +# +if {[is_Cygwin]} { + set ignored_env 0 + set suggest_user {} + set msg [mc "Possible environment issues exist. + +The following environment variables are probably +going to be ignored by any Git subprocess run +by %s: + +" [appname]] + foreach name [array names env] { + switch -regexp -- $name { + {^GIT_INDEX_FILE$} - + {^GIT_OBJECT_DIRECTORY$} - + {^GIT_ALTERNATE_OBJECT_DIRECTORIES$} - + {^GIT_DIFF_OPTS$} - + {^GIT_EXTERNAL_DIFF$} - + {^GIT_PAGER$} - + {^GIT_TRACE$} - + {^GIT_CONFIG$} - + {^GIT_(AUTHOR|COMMITTER)_DATE$} { + append msg " - $name\n" + incr ignored_env + } + {^GIT_(AUTHOR|COMMITTER)_(NAME|EMAIL)$} { + append msg " - $name\n" + incr ignored_env + set suggest_user $name + } + } + } + if {$ignored_env > 0} { + append msg [mc " +This is due to a known issue with the +Tcl binary distributed by Cygwin."] + + if {$suggest_user ne {}} { + append msg [mc " + +A good replacement for %s +is placing values for the user.name and +user.email settings into your personal +~/.gitconfig file. +" $suggest_user] + } + warn_popup $msg + } + unset ignored_env msg suggest_user name +} + +# -- Only initialize complex UI if we are going to stay running. +# +if {[is_enabled transport]} { + load_all_remotes + + set n [.mbar.remote index end] + populate_remotes_menu + set n [expr {[.mbar.remote index end] - $n}] + if {$n > 0} { + if {[.mbar.remote type 0] eq "tearoff"} { incr n } + .mbar.remote insert $n separator + } + unset n +} + +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 {$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 + } + + 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 + + # -- If the user has aspell available we can drive it + # in pipe mode to spellcheck the commit message. + # + set spell_cmd [list |] + set spell_dict [get_config gui.spellingdictionary] + lappend spell_cmd aspell + if {$spell_dict ne {}} { + lappend spell_cmd --master=$spell_dict + } + lappend spell_cmd --mode=none + lappend spell_cmd --encoding=utf-8 + lappend spell_cmd pipe + if {$spell_dict eq {none} + || [catch {set spell_fd [open $spell_cmd r+]} spell_err]} { + bind_button3 $ui_comm [list tk_popup $ui_comm_ctxm %X %Y] + } else { + set ui_comm_spell [spellcheck::init \ + $spell_fd \ + $ui_comm \ + $ui_comm_ctxm \ + ] + } + unset -nocomplain spell_cmd spell_fd spell_err spell_dict +} + +lock_index begin-read +if {![winfo ismapped .]} { + wm deiconify . +} +after 1 { + if {[is_enabled initialamend]} { + force_amend + } else { + do_rescan + } + + if {[is_enabled nocommitmsg]} { + $ui_comm configure -state disabled -background gray + } +} +if {[is_enabled multicommit]} { + after 1000 hint_gc +} +if {[is_enabled retcode]} { + bind . {+terminate_me %W} +} +if {$picked && [is_config_true gui.autoexplore]} { + do_explore +} + +# Local variables: +# mode: tcl +# indent-tabs-mode: t +# tab-width: 4 +# End: diff --cc git-gui/lib/browser.tcl index c2415729e,000000000..a8c622351 mode 100644,000000..100644 --- a/git-gui/lib/browser.tcl +++ b/git-gui/lib/browser.tcl @@@ -1,316 -1,0 +1,316 @@@ +# git-gui tree browser +# Copyright (C) 2006, 2007 Shawn Pearce + +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 browser_commit +field browser_path +field browser_files {} +field browser_status [mc "Starting..."] +field browser_stack {} +field browser_busy 1 + +field ls_buf {}; # Buffered record output from ls-tree + +constructor new {commit {path {}}} { + global cursor_ptr M1B use_ttk NS + make_dialog top w + wm withdraw $top + wm title $top [append "[appname] ([reponame]): " [mc "File Browser"]] + + set browser_commit $commit + set browser_path $browser_commit:$path + + ${NS}::label $w.path \ + -textvariable @browser_path \ + -anchor w \ + -justify left \ + -font font_uibold + if {!$use_ttk} { $w.path configure -borderwidth 1 -relief sunken} + pack $w.path -anchor w -side top -fill x + + ${NS}::frame $w.list + set w_list $w.list.l + text $w_list -background white -foreground black \ + -borderwidth 0 \ + -cursor $cursor_ptr \ + -state disabled \ + -wrap none \ + -height 20 \ + -width 70 \ + -xscrollcommand [list $w.list.sbx set] \ + -yscrollcommand [list $w.list.sby set] + rmsel_tag $w_list + ${NS}::scrollbar $w.list.sbx -orient h -command [list $w_list xview] + ${NS}::scrollbar $w.list.sby -orient v -command [list $w_list yview] + pack $w.list.sbx -side bottom -fill x + pack $w.list.sby -side right -fill y + pack $w_list -side left -fill both -expand 1 + pack $w.list -side top -fill both -expand 1 + + ${NS}::label $w.status \ + -textvariable @browser_status \ + -anchor w \ + -justify left + if {!$use_ttk} { $w.status configure -borderwidth 1 -relief sunken} + pack $w.status -anchor w -side bottom -fill x + + bind $w_list "[cb _click 0 @%x,%y];break" + bind $w_list "[cb _click 1 @%x,%y];break" + bind $w_list <$M1B-Up> "[cb _parent] ;break" + bind $w_list <$M1B-Left> "[cb _parent] ;break" + bind $w_list "[cb _move -1] ;break" + bind $w_list "[cb _move 1] ;break" + bind $w_list <$M1B-Right> "[cb _enter] ;break" + bind $w_list "[cb _enter] ;break" + bind $w_list "[cb _page -1] ;break" + bind $w_list "[cb _page 1] ;break" + bind $w_list break + bind $w_list break + + bind $w_list [list focus $w_list] + wm deiconify $top + set w $w_list + if {$path ne {}} { + _ls $this $browser_commit:$path $path + } else { + _ls $this $browser_commit $path + } + return $this +} + +method _move {dir} { + if {$browser_busy} return + set lno [lindex [split [$w index in_sel.first] .] 0] + incr lno $dir + if {[lindex $browser_files [expr {$lno - 1}]] ne {}} { + $w tag remove in_sel 0.0 end + $w tag add in_sel $lno.0 [expr {$lno + 1}].0 + $w see $lno.0 + } +} + +method _page {dir} { + if {$browser_busy} return + $w yview scroll $dir pages + set lno [expr {int( + [lindex [$w yview] 0] + * [llength $browser_files] + + 1)}] + if {[lindex $browser_files [expr {$lno - 1}]] ne {}} { + $w tag remove in_sel 0.0 end + $w tag add in_sel $lno.0 [expr {$lno + 1}].0 + $w see $lno.0 + } +} + +method _parent {} { + if {$browser_busy} return + set info [lindex $browser_files 0] + if {[lindex $info 0] eq {parent}} { + set parent [lindex $browser_stack end-1] + set browser_stack [lrange $browser_stack 0 end-2] + if {$browser_stack eq {}} { + regsub {:.*$} $browser_path {:} browser_path + } else { - regsub {/[^/]+$} $browser_path {} browser_path ++ regsub {/[^/]+/$} $browser_path {/} browser_path + } + set browser_status [mc "Loading %s..." $browser_path] + _ls $this [lindex $parent 0] [lindex $parent 1] + } +} + +method _enter {} { + if {$browser_busy} return + set lno [lindex [split [$w index in_sel.first] .] 0] + set info [lindex $browser_files [expr {$lno - 1}]] + if {$info ne {}} { + switch -- [lindex $info 0] { + parent { + _parent $this + } + tree { + set name [lindex $info 2] + set escn [escape_path $name] + set browser_status [mc "Loading %s..." $escn] + append browser_path $escn + _ls $this [lindex $info 1] $name + } + blob { + set name [lindex $info 2] + set p {} + foreach n $browser_stack { + append p [lindex $n 1] + } + append p $name + blame::new $browser_commit $p {} + } + } + } +} + +method _click {was_double_click pos} { + if {$browser_busy} return + set lno [lindex [split [$w index $pos] .] 0] + focus $w + + if {[lindex $browser_files [expr {$lno - 1}]] ne {}} { + $w tag remove in_sel 0.0 end + $w tag add in_sel $lno.0 [expr {$lno + 1}].0 + if {$was_double_click} { + _enter $this + } + } +} + +method _ls {tree_id {name {}}} { + set ls_buf {} + set browser_files {} + set browser_busy 1 + + $w conf -state normal + $w tag remove in_sel 0.0 end + $w delete 0.0 end + if {$browser_stack ne {}} { + $w image create end \ + -align center -padx 5 -pady 1 \ + -name icon0 \ + -image ::browser::img_parent + $w insert end [mc "\[Up To Parent\]"] + lappend browser_files parent + } + lappend browser_stack [list $tree_id $name] + $w conf -state disabled + + set fd [git_read ls-tree -z $tree_id] + fconfigure $fd -blocking 0 -translation binary -encoding binary + fileevent $fd readable [cb _read $fd] +} + +method _read {fd} { + append ls_buf [read $fd] + set pck [split $ls_buf "\0"] + set ls_buf [lindex $pck end] + + set n [llength $browser_files] + $w conf -state normal + foreach p [lrange $pck 0 end-1] { + set tab [string first "\t" $p] + if {$tab == -1} continue + + set info [split [string range $p 0 [expr {$tab - 1}]] { }] + set path [string range $p [expr {$tab + 1}] end] + set type [lindex $info 1] + set object [lindex $info 2] + + switch -- $type { + blob { + 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 { + set image ::browser::img_tree + append path / + } + default { + set image ::browser::img_unknown + } + } + + if {$n > 0} {$w insert end "\n"} + $w image create end \ + -align center -padx 5 -pady 1 \ + -name icon[incr n] \ + -image $image + $w insert end [escape_path $path] + lappend browser_files [list $type $object $path] + } + $w conf -state disabled + + if {[eof $fd]} { + close $fd + set browser_status [mc "Ready."] + set browser_busy 0 + set ls_buf {} + if {$n > 0} { + $w tag add in_sel 1.0 2.0 + focus -force $w + } + } +} ifdeleted { + catch {close $fd} +} + +} + +class browser_open { + +field w ; # widget path +field w_rev ; # mega-widget to pick the initial revision + +constructor dialog {} { + global use_ttk NS + make_dialog top w + wm withdraw $top + wm title $top [append "[appname] ([reponame]): " [mc "Browse Branch Files"]] + if {$top ne {.}} { + wm geometry $top "+[winfo rootx .]+[winfo rooty .]" + wm transient $top . + } + + ${NS}::label $w.header \ + -text [mc "Browse Branch Files"] \ + -font font_uibold \ + -anchor center + pack $w.header -side top -fill x + + ${NS}::frame $w.buttons + ${NS}::button $w.buttons.browse -text [mc Browse] \ + -default active \ + -command [cb _open] + pack $w.buttons.browse -side right + ${NS}::button $w.buttons.cancel -text [mc 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 [mc Revision]] + $w_rev bind_listbox [cb _open] + pack $w.rev -anchor nw -fill both -expand 1 -pady 5 -padx 5 + + bind $w [cb _visible] + bind $w [list destroy $w] + bind $w [cb _open]\;break + wm deiconify $top + 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 +} + +} diff --cc git-gui/lib/choose_repository.tcl index fae119286,000000000..657f7d5dc mode 100644,000000..100644 --- a/git-gui/lib/choose_repository.tcl +++ b/git-gui/lib/choose_repository.tcl @@@ -1,1082 -1,0 +1,1074 @@@ +# git-gui Git repository chooser +# Copyright (C) 2007 Shawn Pearce + +class choose_repository { + +field top +field w +field w_body ; # Widget holding the center content +field w_next ; # Next button +field w_quit ; # Quit button +field o_cons ; # Console object (if active) +field w_types ; # List of type buttons in clone +field w_recentlist ; # Listbox containing recent repositories +field w_localpath ; # Entry widget bound to local_path + +field done 0 ; # Finished picking the repository? +field local_path {} ; # Where this repository is locally +field origin_url {} ; # Where we are cloning from +field origin_name origin ; # What we shall call 'origin' +field clone_type hardlink ; # Type of clone to construct +field readtree_err ; # Error output from read-tree (if any) +field sorted_recent ; # recent repositories (sorted) + +constructor pick {} { + global M1T M1B use_ttk NS + + make_dialog top w + wm title $top [mc "Git Gui"] + + if {$top eq {.}} { + menu $w.mbar -tearoff 0 + $top configure -menu $w.mbar + + set m_repo $w.mbar.repository + $w.mbar add cascade \ + -label [mc Repository] \ + -menu $m_repo + menu $m_repo + + if {[is_MacOSX]} { + $w.mbar add cascade -label Apple -menu .mbar.apple + menu $w.mbar.apple + $w.mbar.apple add command \ + -label [mc "About %s" [appname]] \ + -command do_about + $w.mbar.apple add command \ + -label [mc "Show SSH Key"] \ + -command do_ssh_key + } else { + $w.mbar add cascade -label [mc Help] -menu $w.mbar.help + menu $w.mbar.help + $w.mbar.help add command \ + -label [mc "About %s" [appname]] \ + -command do_about + $w.mbar.help add command \ + -label [mc "Show SSH Key"] \ + -command do_ssh_key + } + + wm protocol $top WM_DELETE_WINDOW exit + bind $top <$M1B-q> exit + bind $top <$M1B-Q> exit + bind $top exit + } else { + wm geometry $top "+[winfo rootx .]+[winfo rooty .]" + bind $top [list destroy $top] + set m_repo {} + } + + pack [git_logo $w.git_logo] -side left -fill y -padx 10 -pady 10 + + set w_body $w.body + set opts $w_body.options + ${NS}::frame $w_body + text $opts \ + -cursor $::cursor_ptr \ + -relief flat \ + -background [get_bg_color $w_body] \ + -wrap none \ + -spacing1 5 \ + -width 50 \ + -height 3 + pack $opts -anchor w -fill x + + $opts tag conf link_new -foreground blue -underline 1 + $opts tag bind link_new <1> [cb _next new] + $opts insert end [mc "Create New Repository"] link_new + $opts insert end "\n" + if {$m_repo ne {}} { + $m_repo add command \ + -command [cb _next new] \ + -accelerator $M1T-N \ + -label [mc "New..."] + bind $top <$M1B-n> [cb _next new] + bind $top <$M1B-N> [cb _next new] + } + + $opts tag conf link_clone -foreground blue -underline 1 + $opts tag bind link_clone <1> [cb _next clone] + $opts insert end [mc "Clone Existing Repository"] link_clone + $opts insert end "\n" + if {$m_repo ne {}} { + if {[tk windowingsystem] eq "win32"} { + set key L + } else { + set key C + } + $m_repo add command \ + -command [cb _next clone] \ + -accelerator $M1T-$key \ + -label [mc "Clone..."] + bind $top <$M1B-[string tolower $key]> [cb _next clone] + bind $top <$M1B-[string toupper $key]> [cb _next clone] + } + + $opts tag conf link_open -foreground blue -underline 1 + $opts tag bind link_open <1> [cb _next open] + $opts insert end [mc "Open Existing Repository"] link_open + $opts insert end "\n" + if {$m_repo ne {}} { + $m_repo add command \ + -command [cb _next open] \ + -accelerator $M1T-O \ + -label [mc "Open..."] + bind $top <$M1B-o> [cb _next open] + bind $top <$M1B-O> [cb _next open] + } + + $opts conf -state disabled + + set sorted_recent [_get_recentrepos] + if {[llength $sorted_recent] > 0} { + if {$m_repo ne {}} { + $m_repo add separator + $m_repo add command \ + -state disabled \ + -label [mc "Recent Repositories"] + } + + ${NS}::label $w_body.space + ${NS}::label $w_body.recentlabel \ + -anchor w \ + -text [mc "Open Recent Repository:"] + set w_recentlist $w_body.recentlist + text $w_recentlist \ + -cursor $::cursor_ptr \ + -relief flat \ + -background [get_bg_color $w_body.recentlabel] \ + -wrap none \ + -width 50 \ + -height 10 + $w_recentlist tag conf link \ + -foreground blue \ + -underline 1 + set home $::env(HOME) + if {[is_Cygwin]} { + set home [exec cygpath --windows --absolute $home] + } + set home "[file normalize $home]/" + set hlen [string length $home] + foreach p $sorted_recent { + set path $p + if {[string equal -length $hlen $home $p]} { + set p "~/[string range $p $hlen end]" + } + regsub -all "\n" $p "\\n" p + $w_recentlist insert end $p link + $w_recentlist insert end "\n" + + if {$m_repo ne {}} { + $m_repo add command \ + -command [cb _open_recent_path $path] \ + -label " $p" + } + } + $w_recentlist conf -state disabled + $w_recentlist tag bind link <1> [cb _open_recent %x,%y] + pack $w_body.space -anchor w -fill x + pack $w_body.recentlabel -anchor w -fill x + pack $w_recentlist -anchor w -fill x + } + pack $w_body -fill x -padx 10 -pady 10 + + ${NS}::frame $w.buttons + set w_next $w.buttons.next + set w_quit $w.buttons.quit + ${NS}::button $w_quit \ + -text [mc "Quit"] \ + -command exit + pack $w_quit -side right -padx 5 + pack $w.buttons -side bottom -fill x -padx 10 -pady 10 + + if {$m_repo ne {}} { + $m_repo add separator + $m_repo add command \ + -label [mc Quit] \ + -command exit \ + -accelerator $M1T-Q + } + + bind $top [cb _invoke_next] + bind $top " + [cb _center] + grab $top + focus $top + bind $top {} + " + wm deiconify $top + tkwait variable @done + + grab release $top + if {$top eq {.}} { + eval destroy [winfo children $top] + } +} + - proc _home {} { - if {[catch {set h $::env(HOME)}] - || ![file isdirectory $h]} { - set h . - } - return $h - } - +method _center {} { + set nx [winfo reqwidth $top] + set ny [winfo reqheight $top] + set rx [expr {([winfo screenwidth $top] - $nx) / 3}] + set ry [expr {([winfo screenheight $top] - $ny) / 3}] + wm geometry $top [format {+%d+%d} $rx $ry] +} + +method _invoke_next {} { + if {[winfo exists $w_next]} { + uplevel #0 [$w_next cget -command] + } +} + +proc _get_recentrepos {} { + set recent [list] + foreach p [get_config gui.recentrepo] { + if {[_is_git [file join $p .git]]} { + lappend recent $p + } else { + _unset_recentrepo $p + } + } + return [lsort $recent] +} + +proc _unset_recentrepo {p} { + regsub -all -- {([()\[\]{}\.^$+*?\\])} $p {\\\1} p + git config --global --unset gui.recentrepo "^$p\$" + load_config 1 +} + +proc _append_recentrepos {path} { + set path [file normalize $path] + set recent [get_config gui.recentrepo] + + if {[lindex $recent end] eq $path} { + return + } + + set i [lsearch $recent $path] + if {$i >= 0} { + _unset_recentrepo $path + set recent [lreplace $recent $i $i] + } + + lappend recent $path + git config --global --add gui.recentrepo $path + load_config 1 + + while {[llength $recent] > 10} { + _unset_recentrepo [lindex $recent 0] + set recent [lrange $recent 1 end] + } +} + +method _open_recent {xy} { + set id [lindex [split [$w_recentlist index @$xy] .] 0] + set local_path [lindex $sorted_recent [expr {$id - 1}]] + _do_open2 $this +} + +method _open_recent_path {p} { + set local_path $p + _do_open2 $this +} + +method _next {action} { + global NS + destroy $w_body + if {![winfo exists $w_next]} { + ${NS}::button $w_next -default active + pack $w_next -side right -padx 5 -before $w_quit + } + _do_$action $this +} + +method _write_local_path {args} { + if {$local_path eq {}} { + $w_next conf -state disabled + } else { + $w_next conf -state normal + } +} + +method _git_init {} { + if {[catch {file mkdir $local_path} err]} { + error_popup [strcat \ + [mc "Failed to create repository %s:" $local_path] \ + "\n\n$err"] + return 0 + } + + if {[catch {cd $local_path} err]} { + error_popup [strcat \ + [mc "Failed to create repository %s:" $local_path] \ + "\n\n$err"] + return 0 + } + + if {[catch {git init} err]} { + error_popup [strcat \ + [mc "Failed to create repository %s:" $local_path] \ + "\n\n$err"] + return 0 + } + + _append_recentrepos [pwd] + set ::_gitdir .git + set ::_prefix {} + return 1 +} + +proc _is_git {path} { + if {[file exists [file join $path HEAD]] + && [file exists [file join $path objects]] + && [file exists [file join $path config]]} { + return 1 + } + if {[is_Cygwin]} { + if {[file exists [file join $path HEAD]] + && [file exists [file join $path objects.lnk]] + && [file exists [file join $path config.lnk]]} { + return 1 + } + } + return 0 +} + +proc _objdir {path} { + set objdir [file join $path .git objects] + if {[file isdirectory $objdir]} { + return $objdir + } + + set objdir [file join $path objects] + if {[file isdirectory $objdir]} { + return $objdir + } + + if {[is_Cygwin]} { + set objdir [file join $path .git objects.lnk] + if {[file isfile $objdir]} { + return [win32_read_lnk $objdir] + } + + set objdir [file join $path objects.lnk] + if {[file isfile $objdir]} { + return [win32_read_lnk $objdir] + } + } + + return {} +} + +###################################################################### +## +## Create New Repository + +method _do_new {} { + global use_ttk NS + $w_next conf \ + -state disabled \ + -command [cb _do_new2] \ + -text [mc "Create"] + + ${NS}::frame $w_body + ${NS}::label $w_body.h \ + -font font_uibold -anchor center \ + -text [mc "Create New Repository"] + pack $w_body.h -side top -fill x -pady 10 + pack $w_body -fill x -padx 10 + + ${NS}::frame $w_body.where + ${NS}::label $w_body.where.l -text [mc "Directory:"] + ${NS}::entry $w_body.where.t \ + -textvariable @local_path \ + -width 50 + ${NS}::button $w_body.where.b \ + -text [mc "Browse"] \ + -command [cb _new_local_path] + set w_localpath $w_body.where.t + + grid $w_body.where.l $w_body.where.t $w_body.where.b -sticky ew + pack $w_body.where -fill x + + grid columnconfigure $w_body.where 1 -weight 1 + + trace add variable @local_path write [cb _write_local_path] + bind $w_body.h [list trace remove variable @local_path write [cb _write_local_path]] + update + focus $w_body.where.t +} + +method _new_local_path {} { + if {$local_path ne {}} { + set p [file dirname $local_path] + } else { - set p [_home] ++ set p [pwd] + } + + set p [tk_chooseDirectory \ + -initialdir $p \ + -parent $top \ + -title [mc "Git Repository"] \ + -mustexist false] + if {$p eq {}} return + + set p [file normalize $p] + if {![_new_ok $p]} { + return + } + set local_path $p + $w_localpath icursor end +} + +method _do_new2 {} { + if {![_new_ok $local_path]} { + return + } + if {![_git_init $this]} { + return + } + set done 1 +} + +proc _new_ok {p} { + if {[file isdirectory $p]} { + if {[_is_git [file join $p .git]]} { + error_popup [mc "Directory %s already exists." $p] + return 0 + } + } elseif {[file exists $p]} { + error_popup [mc "File %s already exists." $p] + return 0 + } + return 1 +} + +###################################################################### +## +## Clone Existing Repository + +method _do_clone {} { + global use_ttk NS + $w_next conf \ + -state disabled \ + -command [cb _do_clone2] \ + -text [mc "Clone"] + + ${NS}::frame $w_body + ${NS}::label $w_body.h \ + -font font_uibold -anchor center \ + -text [mc "Clone Existing Repository"] + pack $w_body.h -side top -fill x -pady 10 + pack $w_body -fill x -padx 10 + + set args $w_body.args + ${NS}::frame $w_body.args + pack $args -fill both + + ${NS}::label $args.origin_l -text [mc "Source Location:"] + ${NS}::entry $args.origin_t \ + -textvariable @origin_url \ + -width 50 + ${NS}::button $args.origin_b \ + -text [mc "Browse"] \ + -command [cb _open_origin] + grid $args.origin_l $args.origin_t $args.origin_b -sticky ew + + ${NS}::label $args.where_l -text [mc "Target Directory:"] + ${NS}::entry $args.where_t \ + -textvariable @local_path \ + -width 50 + ${NS}::button $args.where_b \ + -text [mc "Browse"] \ + -command [cb _new_local_path] + grid $args.where_l $args.where_t $args.where_b -sticky ew + set w_localpath $args.where_t + + ${NS}::label $args.type_l -text [mc "Clone Type:"] + ${NS}::frame $args.type_f + set w_types [list] + lappend w_types [${NS}::radiobutton $args.type_f.hardlink \ + -state disabled \ + -text [mc "Standard (Fast, Semi-Redundant, Hardlinks)"] \ + -variable @clone_type \ + -value hardlink] + lappend w_types [${NS}::radiobutton $args.type_f.full \ + -state disabled \ + -text [mc "Full Copy (Slower, Redundant Backup)"] \ + -variable @clone_type \ + -value full] + lappend w_types [${NS}::radiobutton $args.type_f.shared \ + -state disabled \ + -text [mc "Shared (Fastest, Not Recommended, No Backup)"] \ + -variable @clone_type \ + -value shared] + foreach r $w_types { + pack $r -anchor w + } + grid $args.type_l $args.type_f -sticky new + + grid columnconfigure $args 1 -weight 1 + + trace add variable @local_path write [cb _update_clone] + trace add variable @origin_url write [cb _update_clone] + bind $w_body.h " + [list trace remove variable @local_path write [cb _update_clone]] + [list trace remove variable @origin_url write [cb _update_clone]] + " + update + focus $args.origin_t +} + +method _open_origin {} { + if {$origin_url ne {} && [file isdirectory $origin_url]} { + set p $origin_url + } else { - set p [_home] ++ set p [pwd] + } + + set p [tk_chooseDirectory \ + -initialdir $p \ + -parent $top \ + -title [mc "Git Repository"] \ + -mustexist true] + if {$p eq {}} return + + set p [file normalize $p] + if {![_is_git [file join $p .git]] && ![_is_git $p]} { + error_popup [mc "Not a Git repository: %s" [file tail $p]] + return + } + set origin_url $p +} + +method _update_clone {args} { + if {$local_path ne {} && $origin_url ne {}} { + $w_next conf -state normal + } else { + $w_next conf -state disabled + } + + if {$origin_url ne {} && + ( [_is_git [file join $origin_url .git]] + || [_is_git $origin_url])} { + set e normal + if {[[lindex $w_types 0] cget -state] eq {disabled}} { + set clone_type hardlink + } + } else { + set e disabled + set clone_type full + } + + foreach r $w_types { + $r conf -state $e + } +} + +method _do_clone2 {} { + if {[file isdirectory $origin_url]} { + set origin_url [file normalize $origin_url] + } + + if {$clone_type eq {hardlink} && ![file isdirectory $origin_url]} { + error_popup [mc "Standard only available for local repository."] + return + } + if {$clone_type eq {shared} && ![file isdirectory $origin_url]} { + error_popup [mc "Shared only available for local repository."] + return + } + + if {$clone_type eq {hardlink} || $clone_type eq {shared}} { + set objdir [_objdir $origin_url] + if {$objdir eq {}} { + error_popup [mc "Not a Git repository: %s" [file tail $origin_url]] + return + } + } + + set giturl $origin_url + if {[is_Cygwin] && [file isdirectory $giturl]} { + set giturl [exec cygpath --unix --absolute $giturl] + if {$clone_type eq {shared}} { + set objdir [exec cygpath --unix --absolute $objdir] + } + } + + if {[file exists $local_path]} { + error_popup [mc "Location %s already exists." $local_path] + return + } + + if {![_git_init $this]} return + set local_path [pwd] + + if {[catch { + git config remote.$origin_name.url $giturl + git config remote.$origin_name.fetch +refs/heads/*:refs/remotes/$origin_name/* + } err]} { + error_popup [strcat [mc "Failed to configure origin"] "\n\n$err"] + return + } + + destroy $w_body $w_next + + switch -exact -- $clone_type { + hardlink { + set o_cons [status_bar::two_line $w_body] + pack $w_body -fill x -padx 10 -pady 10 + + $o_cons start \ + [mc "Counting objects"] \ + [mc "buckets"] + update + + if {[file exists [file join $objdir info alternates]]} { + set pwd [pwd] + if {[catch { + file mkdir [gitdir objects info] + set f_in [open [file join $objdir info alternates] r] + set f_cp [open [gitdir objects info alternates] w] + fconfigure $f_in -translation binary -encoding binary + fconfigure $f_cp -translation binary -encoding binary + cd $objdir + while {[gets $f_in line] >= 0} { + if {[is_Cygwin]} { + puts $f_cp [exec cygpath --unix --absolute $line] + } else { + puts $f_cp [file normalize $line] + } + } + close $f_in + close $f_cp + cd $pwd + } err]} { + catch {cd $pwd} + _clone_failed $this [mc "Unable to copy objects/info/alternates: %s" $err] + return + } + } + + set tolink [list] + set buckets [glob \ + -tails \ + -nocomplain \ + -directory [file join $objdir] ??] + set bcnt [expr {[llength $buckets] + 2}] + set bcur 1 + $o_cons update $bcur $bcnt + update + + file mkdir [file join .git objects pack] + foreach i [glob -tails -nocomplain \ + -directory [file join $objdir pack] *] { + lappend tolink [file join pack $i] + } + $o_cons update [incr bcur] $bcnt + update + + foreach i $buckets { + file mkdir [file join .git objects $i] + foreach j [glob -tails -nocomplain \ + -directory [file join $objdir $i] *] { + lappend tolink [file join $i $j] + } + $o_cons update [incr bcur] $bcnt + update + } + $o_cons stop + + if {$tolink eq {}} { + info_popup [strcat \ + [mc "Nothing to clone from %s." $origin_url] \ + "\n" \ + [mc "The 'master' branch has not been initialized."] \ + ] + destroy $w_body + set done 1 + return + } + + set i [lindex $tolink 0] + if {[catch { + file link -hard \ + [file join .git objects $i] \ + [file join $objdir $i] + } err]} { + info_popup [mc "Hardlinks are unavailable. Falling back to copying."] + set i [_copy_files $this $objdir $tolink] + } else { + set i [_link_files $this $objdir [lrange $tolink 1 end]] + } + if {!$i} return + + destroy $w_body + } + full { + set o_cons [console::embed \ + $w_body \ + [mc "Cloning from %s" $origin_url]] + pack $w_body -fill both -expand 1 -padx 10 + $o_cons exec \ + [list git fetch --no-tags -k $origin_name] \ + [cb _do_clone_tags] + } + shared { + set fd [open [gitdir objects info alternates] w] + fconfigure $fd -translation binary + puts $fd $objdir + close $fd + } + } + + if {$clone_type eq {hardlink} || $clone_type eq {shared}} { + if {![_clone_refs $this]} return + set pwd [pwd] + if {[catch { + cd $origin_url + set HEAD [git rev-parse --verify HEAD^0] + } err]} { + _clone_failed $this [mc "Not a Git repository: %s" [file tail $origin_url]] + return 0 + } + cd $pwd + _do_clone_checkout $this $HEAD + } +} + +method _copy_files {objdir tocopy} { + $o_cons start \ + [mc "Copying objects"] \ + [mc "KiB"] + set tot 0 + set cmp 0 + foreach p $tocopy { + incr tot [file size [file join $objdir $p]] + } + foreach p $tocopy { + if {[catch { + set f_in [open [file join $objdir $p] r] + set f_cp [open [file join .git objects $p] w] + fconfigure $f_in -translation binary -encoding binary + fconfigure $f_cp -translation binary -encoding binary + + while {![eof $f_in]} { + incr cmp [fcopy $f_in $f_cp -size 16384] + $o_cons update \ + [expr {$cmp / 1024}] \ + [expr {$tot / 1024}] + update + } + + close $f_in + close $f_cp + } err]} { + _clone_failed $this [mc "Unable to copy object: %s" $err] + return 0 + } + } + return 1 +} + +method _link_files {objdir tolink} { + set total [llength $tolink] + $o_cons start \ + [mc "Linking objects"] \ + [mc "objects"] + for {set i 0} {$i < $total} {} { + set p [lindex $tolink $i] + if {[catch { + file link -hard \ + [file join .git objects $p] \ + [file join $objdir $p] + } err]} { + _clone_failed $this [mc "Unable to hardlink object: %s" $err] + return 0 + } + + incr i + if {$i % 5 == 0} { + $o_cons update $i $total + update + } + } + return 1 +} + +method _clone_refs {} { + set pwd [pwd] + if {[catch {cd $origin_url} err]} { + error_popup [mc "Not a Git repository: %s" [file tail $origin_url]] + return 0 + } + set fd_in [git_read for-each-ref \ + --tcl \ + {--format=list %(refname) %(objectname) %(*objectname)}] + cd $pwd + + set fd [open [gitdir packed-refs] w] + fconfigure $fd -translation binary + puts $fd "# pack-refs with: peeled" + while {[gets $fd_in line] >= 0} { + set line [eval $line] + set refn [lindex $line 0] + set robj [lindex $line 1] + set tobj [lindex $line 2] + + if {[regsub ^refs/heads/ $refn \ + "refs/remotes/$origin_name/" refn]} { + puts $fd "$robj $refn" + } elseif {[string match refs/tags/* $refn]} { + puts $fd "$robj $refn" + if {$tobj ne {}} { + puts $fd "^$tobj" + } + } + } + close $fd_in + close $fd + return 1 +} + +method _do_clone_tags {ok} { + if {$ok} { + $o_cons exec \ + [list git fetch --tags -k $origin_name] \ + [cb _do_clone_HEAD] + } else { + $o_cons done $ok + _clone_failed $this [mc "Cannot fetch branches and objects. See console output for details."] + } +} + +method _do_clone_HEAD {ok} { + if {$ok} { + $o_cons exec \ + [list git fetch $origin_name HEAD] \ + [cb _do_clone_full_end] + } else { + $o_cons done $ok + _clone_failed $this [mc "Cannot fetch tags. See console output for details."] + } +} + +method _do_clone_full_end {ok} { + $o_cons done $ok + + if {$ok} { + destroy $w_body + + set HEAD {} + if {[file exists [gitdir FETCH_HEAD]]} { + set fd [open [gitdir FETCH_HEAD] r] + while {[gets $fd line] >= 0} { + if {[regexp "^(.{40})\t\t" $line line HEAD]} { + break + } + } + close $fd + } + + catch {git pack-refs} + _do_clone_checkout $this $HEAD + } else { + _clone_failed $this [mc "Cannot determine HEAD. See console output for details."] + } +} + +method _clone_failed {{why {}}} { + if {[catch {file delete -force $local_path} err]} { + set why [strcat \ + $why \ + "\n\n" \ + [mc "Unable to cleanup %s" $local_path] \ + "\n\n" \ + $err] + } + if {$why ne {}} { + update + error_popup [strcat [mc "Clone failed."] "\n" $why] + } +} + +method _do_clone_checkout {HEAD} { + if {$HEAD eq {}} { + info_popup [strcat \ + [mc "No default branch obtained."] \ + "\n" \ + [mc "The 'master' branch has not been initialized."] \ + ] + set done 1 + return + } + if {[catch { + git update-ref HEAD $HEAD^0 + } err]} { + info_popup [strcat \ + [mc "Cannot resolve %s as a commit." $HEAD^0] \ + "\n $err" \ + "\n" \ + [mc "The 'master' branch has not been initialized."] \ + ] + set done 1 + return + } + + set o_cons [status_bar::two_line $w_body] + pack $w_body -fill x -padx 10 -pady 10 + $o_cons start \ + [mc "Creating working directory"] \ + [mc "files"] + + set readtree_err {} + set fd [git_read --stderr read-tree \ + -m \ + -u \ + -v \ + HEAD \ + HEAD \ + ] + fconfigure $fd -blocking 0 -translation binary + fileevent $fd readable [cb _readtree_wait $fd] +} + +method _readtree_wait {fd} { + set buf [read $fd] + $o_cons update_meter $buf + append readtree_err $buf + + fconfigure $fd -blocking 1 + if {![eof $fd]} { + fconfigure $fd -blocking 0 + return + } + + if {[catch {close $fd}]} { + set err $readtree_err + regsub {^fatal: } $err {} err + error_popup [strcat \ + [mc "Initial file checkout failed."] \ + "\n\n$err"] + return + } + + # -- Run the post-checkout hook. + # + set fd_ph [githook_read post-checkout [string repeat 0 40] \ + [git rev-parse HEAD] 1] + if {$fd_ph ne {}} { + global pch_error + set pch_error {} + fconfigure $fd_ph -blocking 0 -translation binary -eofchar {} + fileevent $fd_ph readable [cb _postcheckout_wait $fd_ph] + } else { + set done 1 + } +} + +method _postcheckout_wait {fd_ph} { + global pch_error + + append pch_error [read $fd_ph] + fconfigure $fd_ph -blocking 1 + if {[eof $fd_ph]} { + if {[catch {close $fd_ph}]} { + hook_failed_popup post-checkout $pch_error 0 + } + unset pch_error + set done 1 + return + } + fconfigure $fd_ph -blocking 0 +} + +###################################################################### +## +## Open Existing Repository + +method _do_open {} { + global NS + $w_next conf \ + -state disabled \ + -command [cb _do_open2] \ + -text [mc "Open"] + + ${NS}::frame $w_body + ${NS}::label $w_body.h \ + -font font_uibold -anchor center \ + -text [mc "Open Existing Repository"] + pack $w_body.h -side top -fill x -pady 10 + pack $w_body -fill x -padx 10 + + ${NS}::frame $w_body.where + ${NS}::label $w_body.where.l -text [mc "Repository:"] + ${NS}::entry $w_body.where.t \ + -textvariable @local_path \ + -width 50 + ${NS}::button $w_body.where.b \ + -text [mc "Browse"] \ + -command [cb _open_local_path] + + grid $w_body.where.l $w_body.where.t $w_body.where.b -sticky ew + pack $w_body.where -fill x + + grid columnconfigure $w_body.where 1 -weight 1 + + trace add variable @local_path write [cb _write_local_path] + bind $w_body.h [list trace remove variable @local_path write [cb _write_local_path]] + update + focus $w_body.where.t +} + +method _open_local_path {} { + if {$local_path ne {}} { + set p $local_path + } else { - set p [_home] ++ set p [pwd] + } + + set p [tk_chooseDirectory \ + -initialdir $p \ + -parent $top \ + -title [mc "Git Repository"] \ + -mustexist true] + if {$p eq {}} return + + set p [file normalize $p] + if {![_is_git [file join $p .git]]} { + error_popup [mc "Not a Git repository: %s" [file tail $p]] + return + } + set local_path $p +} + +method _do_open2 {} { + if {![_is_git [file join $local_path .git]]} { + error_popup [mc "Not a Git repository: %s" [file tail $local_path]] + return + } + + if {[catch {cd $local_path} err]} { + error_popup [strcat \ + [mc "Failed to open repository %s:" $local_path] \ + "\n\n$err"] + return + } + + _append_recentrepos [pwd] + set ::_gitdir .git + set ::_prefix {} + set done 1 +} + +} diff --cc git-gui/lib/commit.tcl index 7f459cd56,000000000..5ce46877b mode 100644,000000..100644 --- a/git-gui/lib/commit.tcl +++ b/git-gui/lib/commit.tcl @@@ -1,485 -1,0 +1,490 @@@ +# git-gui misc. commit reading/writing support +# Copyright (C) 2006, 2007 Shawn Pearce + +proc load_last_commit {} { + global HEAD PARENT MERGE_HEAD commit_type ui_comm + global repo_config + + if {[llength $PARENT] == 0} { + error_popup [mc "There is nothing to amend. + +You are about to create the initial commit. There is no commit before this to amend. +"] + return + } + + repository_state curType curHEAD curMERGE_HEAD + if {$curType eq {merge}} { + error_popup [mc "Cannot amend while merging. + +You are currently in the middle of a merge that has not been fully completed. You cannot amend the prior commit unless you first abort the current merge activity. +"] + return + } + + set msg {} + set parents [list] + if {[catch { + set fd [git_read cat-file commit $curHEAD] + fconfigure $fd -encoding binary -translation lf + # By default commits are assumed to be in utf-8 + set enc utf-8 + while {[gets $fd line] > 0} { + if {[string match {parent *} $line]} { + lappend parents [string range $line 7 end] + } elseif {[string match {encoding *} $line]} { + set enc [string tolower [string range $line 9 end]] + } + } + set msg [read $fd] + close $fd + + set enc [tcl_encoding $enc] + if {$enc ne {}} { + set msg [encoding convertfrom $enc $msg] + } + set msg [string trim $msg] + } err]} { + error_popup [strcat [mc "Error loading commit data for amend:"] "\n\n$err"] + return + } + + set HEAD $curHEAD + set PARENT $parents + set MERGE_HEAD [list] + switch -- [llength $parents] { + 0 {set commit_type amend-initial} + 1 {set commit_type amend} + default {set commit_type amend-merge} + } + + $ui_comm delete 0.0 end + $ui_comm insert end $msg + $ui_comm edit reset + $ui_comm edit modified false + rescan ui_ready +} + +set GIT_COMMITTER_IDENT {} + +proc committer_ident {} { + global GIT_COMMITTER_IDENT + + if {$GIT_COMMITTER_IDENT eq {}} { + if {[catch {set me [git var GIT_COMMITTER_IDENT]} err]} { + error_popup [strcat [mc "Unable to obtain your identity:"] "\n\n$err"] + return {} + } + if {![regexp {^(.*) [0-9]+ [-+0-9]+$} \ + $me me GIT_COMMITTER_IDENT]} { + error_popup [strcat [mc "Invalid GIT_COMMITTER_IDENT:"] "\n\n$me"] + return {} + } + } + + return $GIT_COMMITTER_IDENT +} + +proc do_signoff {} { + global ui_comm + + set me [committer_ident] + if {$me eq {}} return + + set sob "Signed-off-by: $me" + set last [$ui_comm get {end -1c linestart} {end -1c}] + if {$last ne $sob} { + $ui_comm edit separator + if {$last ne {} + && ![regexp {^[A-Z][A-Za-z]*-[A-Za-z-]+: *} $last]} { + $ui_comm insert end "\n" + } + $ui_comm insert end "\n$sob" + $ui_comm edit separator + $ui_comm see end + } +} + +proc create_new_commit {} { + global commit_type ui_comm + + set commit_type normal + $ui_comm delete 0.0 end + $ui_comm edit reset + $ui_comm edit modified false + rescan ui_ready +} + +proc setup_commit_encoding {msg_wt {quiet 0}} { + global repo_config + + if {[catch {set enc $repo_config(i18n.commitencoding)}]} { + set enc utf-8 + } + set use_enc [tcl_encoding $enc] + if {$use_enc ne {}} { + fconfigure $msg_wt -encoding $use_enc + } else { + if {!$quiet} { + error_popup [mc "warning: Tcl does not support encoding '%s'." $enc] + } + fconfigure $msg_wt -encoding utf-8 + } +} + +proc commit_tree {} { + global HEAD commit_type file_states ui_comm repo_config + global pch_error + + if {[committer_ident] eq {}} return + if {![lock_index update]} return + + # -- Our in memory state should match the repository. + # + repository_state curType curHEAD curMERGE_HEAD + if {[string match amend* $commit_type] + && $curType eq {normal} + && $curHEAD eq $HEAD} { + } elseif {$commit_type ne $curType || $HEAD ne $curHEAD} { + info_popup [mc "Last scanned state does not match repository state. + +Another Git program has modified this repository since the last scan. A rescan must be performed before another commit can be created. + +The rescan will be automatically started now. +"] + unlock_index + rescan ui_ready + return + } + + # -- At least one file should differ in the index. + # + set files_ready 0 + foreach path [array names file_states] { - switch -glob -- [lindex $file_states($path) 0] { ++ set s $file_states($path) ++ switch -glob -- [lindex $s 0] { + _? {continue} + A? - + D? - - T_ - ++ T? - + M? {set files_ready 1} + _U - + U? { + error_popup [mc "Unmerged files cannot be committed. + +File %s has merge conflicts. You must resolve them and stage the file before committing. +" [short_path $path]] + unlock_index + return + } + default { + error_popup [mc "Unknown file state %s detected. + +File %s cannot be committed by this program. +" [lindex $s 0] [short_path $path]] + } + } + } + if {!$files_ready && ![string match *merge $curType] && ![is_enabled nocommit]} { + info_popup [mc "No changes to commit. + +You must stage at least 1 file before you can commit. +"] + unlock_index + return + } + + if {[is_enabled nocommitmsg]} { do_quit 0 } + + # -- A message is required. + # + set msg [string trim [$ui_comm get 1.0 end]] + regsub -all -line {[ \t\r]+$} $msg {} msg + if {$msg eq {}} { + error_popup [mc "Please supply a commit message. + +A good commit message has the following format: + +- First line: Describe in one sentence what you did. +- Second line: Blank +- Remaining lines: Describe why this change is good. +"] + unlock_index + return + } + + # -- Build the message file. + # + set msg_p [gitdir GITGUI_EDITMSG] + set msg_wt [open $msg_p w] + fconfigure $msg_wt -translation lf + setup_commit_encoding $msg_wt + puts $msg_wt $msg + close $msg_wt + + if {[is_enabled nocommit]} { do_quit 0 } + + # -- Run the pre-commit hook. + # + set fd_ph [githook_read pre-commit] + if {$fd_ph eq {}} { + commit_commitmsg $curHEAD $msg_p + return + } + + ui_status [mc "Calling pre-commit hook..."] + set pch_error {} + fconfigure $fd_ph -blocking 0 -translation binary -eofchar {} + fileevent $fd_ph readable \ + [list commit_prehook_wait $fd_ph $curHEAD $msg_p] +} + +proc commit_prehook_wait {fd_ph curHEAD msg_p} { + global pch_error + + append pch_error [read $fd_ph] + fconfigure $fd_ph -blocking 1 + if {[eof $fd_ph]} { + if {[catch {close $fd_ph}]} { + catch {file delete $msg_p} + ui_status [mc "Commit declined by pre-commit hook."] + hook_failed_popup pre-commit $pch_error + unlock_index + } else { + commit_commitmsg $curHEAD $msg_p + } + set pch_error {} + return + } + fconfigure $fd_ph -blocking 0 +} + +proc commit_commitmsg {curHEAD msg_p} { + global pch_error + + # -- Run the commit-msg hook. + # + set fd_ph [githook_read commit-msg $msg_p] + if {$fd_ph eq {}} { + commit_writetree $curHEAD $msg_p + return + } + + ui_status [mc "Calling commit-msg hook..."] + set pch_error {} + fconfigure $fd_ph -blocking 0 -translation binary -eofchar {} + fileevent $fd_ph readable \ + [list commit_commitmsg_wait $fd_ph $curHEAD $msg_p] +} + +proc commit_commitmsg_wait {fd_ph curHEAD msg_p} { + global pch_error + + append pch_error [read $fd_ph] + fconfigure $fd_ph -blocking 1 + if {[eof $fd_ph]} { + if {[catch {close $fd_ph}]} { + catch {file delete $msg_p} + ui_status [mc "Commit declined by commit-msg hook."] + hook_failed_popup commit-msg $pch_error + unlock_index + } else { + commit_writetree $curHEAD $msg_p + } + set pch_error {} + return + } + fconfigure $fd_ph -blocking 0 +} + +proc commit_writetree {curHEAD msg_p} { + ui_status [mc "Committing changes..."] + set fd_wt [git_read write-tree] + fileevent $fd_wt readable \ + [list commit_committree $fd_wt $curHEAD $msg_p] +} + +proc commit_committree {fd_wt curHEAD msg_p} { + global HEAD PARENT MERGE_HEAD commit_type + global current_branch + global ui_comm selected_commit_type + global file_states selected_paths rescan_active + global repo_config + + gets $fd_wt tree_id + if {[catch {close $fd_wt} err]} { + catch {file delete $msg_p} + error_popup [strcat [mc "write-tree failed:"] "\n\n$err"] + ui_status [mc "Commit failed."] + unlock_index + return + } + + # -- Verify this wasn't an empty change. + # + if {$commit_type eq {normal}} { + set fd_ot [git_read cat-file commit $PARENT] + fconfigure $fd_ot -encoding binary -translation lf + set old_tree [gets $fd_ot] + close $fd_ot + + if {[string equal -length 5 {tree } $old_tree] + && [string length $old_tree] == 45} { + set old_tree [string range $old_tree 5 end] + } else { + error [mc "Commit %s appears to be corrupt" $PARENT] + } + + if {$tree_id eq $old_tree} { + catch {file delete $msg_p} + info_popup [mc "No changes to commit. + +No files were modified by this commit and it was not a merge commit. + +A rescan will be automatically started now. +"] + unlock_index + rescan {ui_status [mc "No changes to commit."]} + return + } + } + + # -- Create the commit. + # + set cmd [list commit-tree $tree_id] + foreach p [concat $PARENT $MERGE_HEAD] { + lappend cmd -p $p + } + lappend cmd <$msg_p + if {[catch {set cmt_id [eval git $cmd]} err]} { + catch {file delete $msg_p} + error_popup [strcat [mc "commit-tree failed:"] "\n\n$err"] + ui_status [mc "Commit failed."] + unlock_index + return + } + + # -- Update the HEAD ref. + # + set reflogm commit + if {$commit_type ne {normal}} { + append reflogm " ($commit_type)" + } + set msg_fd [open $msg_p r] + setup_commit_encoding $msg_fd 1 + gets $msg_fd subject + close $msg_fd + append reflogm {: } $subject + if {[catch { + git update-ref -m $reflogm HEAD $cmt_id $curHEAD + } err]} { + catch {file delete $msg_p} + error_popup [strcat [mc "update-ref failed:"] "\n\n$err"] + ui_status [mc "Commit failed."] + unlock_index + return + } + + # -- Cleanup after ourselves. + # + catch {file delete $msg_p} + catch {file delete [gitdir MERGE_HEAD]} + catch {file delete [gitdir MERGE_MSG]} + catch {file delete [gitdir SQUASH_MSG]} + catch {file delete [gitdir GITGUI_MSG]} + + # -- Let rerere do its thing. + # + if {[get_config rerere.enabled] eq {}} { + set rerere [file isdirectory [gitdir rr-cache]] + } else { + set rerere [is_config_true rerere.enabled] + } + if {$rerere} { + catch {git rerere} + } + + # -- Run the post-commit hook. + # + set fd_ph [githook_read post-commit] + if {$fd_ph ne {}} { + global pch_error + set pch_error {} + fconfigure $fd_ph -blocking 0 -translation binary -eofchar {} + fileevent $fd_ph readable \ + [list commit_postcommit_wait $fd_ph $cmt_id] + } + + $ui_comm delete 0.0 end + $ui_comm edit reset + $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 0 } + + # -- Update in memory status + # + set selected_commit_type new + set commit_type normal + set HEAD $cmt_id + set PARENT $cmt_id + set MERGE_HEAD [list] + + foreach path [array names file_states] { + set s $file_states($path) + set m [lindex $s 0] + switch -glob -- $m { + _O - + _M - + _D {continue} + __ - + A_ - + M_ - + T_ - + D_ { + unset file_states($path) + catch {unset selected_paths($path)} + } + DO { + set file_states($path) [list _O [lindex $s 1] {} {}] + } + AM - + AD - ++ AT - ++ TM - ++ TD - + MM - ++ MT - + MD { + set file_states($path) [list \ + _[string index $m 1] \ + [lindex $s 1] \ + [lindex $s 3] \ + {}] + } + } + } + + display_all_files + unlock_index + reshow_diff + ui_status [mc "Created commit %s: %s" [string range $cmt_id 0 7] $subject] +} + +proc commit_postcommit_wait {fd_ph cmt_id} { + global pch_error + + append pch_error [read $fd_ph] + fconfigure $fd_ph -blocking 1 + if {[eof $fd_ph]} { + if {[catch {close $fd_ph}]} { + hook_failed_popup post-commit $pch_error 0 + } + unset pch_error + return + } + fconfigure $fd_ph -blocking 0 +} diff --cc git-gui/lib/diff.tcl index dcf0711be,000000000..cf8a95ec3 mode 100644,000000..100644 --- a/git-gui/lib/diff.tcl +++ b/git-gui/lib/diff.tcl @@@ -1,765 -1,0 +1,804 @@@ +# git-gui diff viewer +# Copyright (C) 2006, 2007 Shawn Pearce + +proc clear_diff {} { + global ui_diff current_diff_path current_diff_header + global ui_index ui_workdir + + $ui_diff conf -state normal + $ui_diff delete 0.0 end + $ui_diff conf -state disabled + + set current_diff_path {} + set current_diff_header {} + + $ui_index tag remove in_diff 0.0 end + $ui_workdir tag remove in_diff 0.0 end +} + +proc reshow_diff {{after {}}} { + global file_states file_lists + global current_diff_path current_diff_side + global ui_diff + + set p $current_diff_path + if {$p eq {}} { + # No diff is being shown. + } elseif {$current_diff_side eq {}} { + clear_diff + } elseif {[catch {set s $file_states($p)}] + || [lsearch -sorted -exact $file_lists($current_diff_side) $p] == -1} { + + if {[find_next_diff $current_diff_side $p {} {[^O]}]} { + next_diff $after + } else { + clear_diff + } + } else { + set save_pos [lindex [$ui_diff yview] 0] + show_diff $p $current_diff_side {} $save_pos $after + } +} + +proc force_diff_encoding {enc} { + global current_diff_path + + if {$current_diff_path ne {}} { + force_path_encoding $current_diff_path $enc + reshow_diff + } +} + +proc handle_empty_diff {} { + global current_diff_path file_states file_lists + global diff_empty_count + + set path $current_diff_path + set s $file_states($path) + if {[lindex $s 0] ne {_M} || [has_textconv $path]} return + + # Prevent infinite rescan loops + incr diff_empty_count + if {$diff_empty_count > 1} return + + info_popup [mc "No differences detected. + +%s has no changes. + +The modification date of this file was updated by another application, but the content within the file was not changed. + +A rescan will be automatically started to find other files which may have the same state." [short_path $path]] + + clear_diff + display_file $path __ + rescan ui_ready 0 +} + +proc show_diff {path w {lno {}} {scroll_pos {}} {callback {}}} { + global file_states file_lists + global is_3way_diff is_conflict_diff diff_active repo_config + global ui_diff ui_index ui_workdir + global current_diff_path current_diff_side current_diff_header + global current_diff_queue + + if {$diff_active || ![lock_index read]} return + + clear_diff + if {$lno == {}} { + set lno [lsearch -sorted -exact $file_lists($w) $path] + if {$lno >= 0} { + incr lno + } + } + if {$lno >= 1} { + $w tag add in_diff $lno.0 [expr {$lno + 1}].0 + $w see $lno.0 + } + + set s $file_states($path) + set m [lindex $s 0] + set is_conflict_diff 0 + set current_diff_path $path + set current_diff_side $w + set current_diff_queue {} + ui_status [mc "Loading diff of %s..." [escape_path $path]] + + set cont_info [list $scroll_pos $callback] + + if {[string first {U} $m] >= 0} { + merge_load_stages $path [list show_unmerged_diff $cont_info] + } elseif {$m eq {_O}} { + show_other_diff $path $w $m $cont_info + } else { + start_show_diff $cont_info + } +} + +proc show_unmerged_diff {cont_info} { + global current_diff_path current_diff_side + global merge_stages ui_diff is_conflict_diff + global current_diff_queue + + if {$merge_stages(2) eq {}} { + set is_conflict_diff 1 + lappend current_diff_queue \ - [list [mc "LOCAL: deleted\nREMOTE:\n"] d======= \ ++ [list [mc "LOCAL: deleted\nREMOTE:\n"] d= \ + [list ":1:$current_diff_path" ":3:$current_diff_path"]] + } elseif {$merge_stages(3) eq {}} { + set is_conflict_diff 1 + lappend current_diff_queue \ - [list [mc "REMOTE: deleted\nLOCAL:\n"] d======= \ ++ [list [mc "REMOTE: deleted\nLOCAL:\n"] d= \ + [list ":1:$current_diff_path" ":2:$current_diff_path"]] + } elseif {[lindex $merge_stages(1) 0] eq {120000} + || [lindex $merge_stages(2) 0] eq {120000} + || [lindex $merge_stages(3) 0] eq {120000}} { + set is_conflict_diff 1 + lappend current_diff_queue \ - [list [mc "LOCAL:\n"] d======= \ ++ [list [mc "LOCAL:\n"] d= \ + [list ":1:$current_diff_path" ":2:$current_diff_path"]] + lappend current_diff_queue \ - [list [mc "REMOTE:\n"] d======= \ ++ [list [mc "REMOTE:\n"] d= \ + [list ":1:$current_diff_path" ":3:$current_diff_path"]] + } else { + start_show_diff $cont_info + return + } + + advance_diff_queue $cont_info +} + +proc advance_diff_queue {cont_info} { + global current_diff_queue ui_diff + + set item [lindex $current_diff_queue 0] + set current_diff_queue [lrange $current_diff_queue 1 end] + + $ui_diff conf -state normal + $ui_diff insert end [lindex $item 0] [lindex $item 1] + $ui_diff conf -state disabled + + start_show_diff $cont_info [lindex $item 2] +} + +proc show_other_diff {path w m cont_info} { + global file_states file_lists + global is_3way_diff diff_active repo_config + global ui_diff ui_index ui_workdir + global current_diff_path current_diff_side current_diff_header + + # - Git won't give us the diff, there's nothing to compare to! + # + if {$m eq {_O}} { + set max_sz 100000 + set type unknown + if {[catch { + set type [file type $path] + switch -- $type { + directory { + set type submodule + set content {} + set sz 0 + } + link { + set content [file readlink $path] + set sz [string length $content] + } + file { + set fd [open $path r] + fconfigure $fd \ + -eofchar {} \ + -encoding [get_path_encoding $path] + set content [read $fd $max_sz] + close $fd + set sz [file size $path] + } + default { + error "'$type' not supported" + } + } + } err ]} { + set diff_active 0 + unlock_index + ui_status [mc "Unable to display %s" [escape_path $path]] + error_popup [strcat [mc "Error loading file:"] "\n\n$err"] + return + } + $ui_diff conf -state normal + if {$type eq {submodule}} { + $ui_diff insert end [append \ + "* " \ + [mc "Git Repository (subproject)"] \ - "\n"] d_@ ++ "\n"] d_info + } elseif {![catch {set type [exec file $path]}]} { + set n [string length $path] + if {[string equal -length $n $path $type]} { + set type [string range $type $n end] + regsub {^:?\s*} $type {} type + } - $ui_diff insert end "* $type\n" d_@ ++ $ui_diff insert end "* $type\n" d_info + } + if {[string first "\0" $content] != -1} { + $ui_diff insert end \ + [mc "* Binary file (not showing content)."] \ - d_@ ++ d_info + } else { + if {$sz > $max_sz} { + $ui_diff insert end [mc \ +"* Untracked file is %d bytes. +* Showing only first %d bytes. - " $sz $max_sz] d_@ ++" $sz $max_sz] d_info + } + $ui_diff insert end $content + if {$sz > $max_sz} { + $ui_diff insert end [mc " +* Untracked file clipped here by %s. +* To see the entire file, use an external editor. - " [appname]] d_@ ++" [appname]] d_info + } + } + $ui_diff conf -state disabled + set diff_active 0 + unlock_index + set scroll_pos [lindex $cont_info 0] + if {$scroll_pos ne {}} { + update + $ui_diff yview moveto $scroll_pos + } + ui_ready + set callback [lindex $cont_info 1] + if {$callback ne {}} { + eval $callback + } + return + } +} + ++proc get_conflict_marker_size {path} { ++ set size 7 ++ catch { ++ set fd_rc [eval [list git_read check-attr "conflict-marker-size" -- $path]] ++ set ret [gets $fd_rc line] ++ close $fd_rc ++ if {$ret > 0} { ++ regexp {.*: conflict-marker-size: (\d+)$} $line line size ++ } ++ } ++ return $size ++} ++ +proc start_show_diff {cont_info {add_opts {}}} { + global file_states file_lists + global is_3way_diff is_submodule_diff diff_active repo_config + global ui_diff ui_index ui_workdir + global current_diff_path current_diff_side current_diff_header + + set path $current_diff_path + set w $current_diff_side + + set s $file_states($path) + set m [lindex $s 0] + set is_3way_diff 0 + set is_submodule_diff 0 + set diff_active 1 + set current_diff_header {} ++ set conflict_size [get_conflict_marker_size $path] + + set cmd [list] + if {$w eq $ui_index} { + lappend cmd diff-index + lappend cmd --cached + } elseif {$w eq $ui_workdir} { + if {[string first {U} $m] >= 0} { + lappend cmd diff + } else { + lappend cmd diff-files + } + } + if {![is_config_false gui.textconv] && [git-version >= 1.6.1]} { + lappend cmd --textconv + } + + if {[string match {160000 *} [lindex $s 2]] + || [string match {160000 *} [lindex $s 3]]} { + set is_submodule_diff 1 + + if {[git-version >= "1.6.6"]} { + lappend cmd --submodule + } + } + + lappend cmd -p + lappend cmd --color + if {$repo_config(gui.diffcontext) >= 1} { + lappend cmd "-U$repo_config(gui.diffcontext)" + } + if {$w eq $ui_index} { + lappend cmd [PARENT] + } + if {$add_opts ne {}} { + eval lappend cmd $add_opts + } else { + lappend cmd -- + lappend cmd $path + } + + if {$is_submodule_diff && [git-version < "1.6.6"]} { + if {$w eq $ui_index} { + set cmd [list submodule summary --cached -- $path] + } else { + set cmd [list submodule summary --files -- $path] + } + } + + if {[catch {set fd [eval git_read --nice $cmd]} err]} { + set diff_active 0 + unlock_index + ui_status [mc "Unable to display %s" [escape_path $path]] + error_popup [strcat [mc "Error loading diff:"] "\n\n$err"] + return + } + + set ::current_diff_inheader 1 + fconfigure $fd \ + -blocking 0 \ + -encoding [get_path_encoding $path] \ + -translation lf - fileevent $fd readable [list read_diff $fd $cont_info] ++ fileevent $fd readable [list read_diff $fd $conflict_size $cont_info] +} + +proc parse_color_line {line} { + set start 0 + set result "" + set markup [list] + set regexp {\033\[((?:\d+;)*\d+)?m} ++ set need_reset 0 + while {[regexp -indices -start $start $regexp $line match code]} { + foreach {begin end} $match break + append result [string range $line $start [expr {$begin - 1}]] - lappend markup [string length $result] \ - [eval [linsert $code 0 string range $line]] ++ set pos [string length $result] ++ set col [eval [linsert $code 0 string range $line]] + set start [incr end] ++ if {$col eq "0" || $col eq ""} { ++ if {!$need_reset} continue ++ set need_reset 0 ++ } else { ++ set need_reset 1 ++ } ++ lappend markup $pos $col + } + append result [string range $line $start end] + if {[llength $markup] < 4} {set markup {}} + return [list $result $markup] +} + - proc read_diff {fd cont_info} { ++proc read_diff {fd conflict_size cont_info} { + global ui_diff diff_active is_submodule_diff + global is_3way_diff is_conflict_diff current_diff_header + global current_diff_queue + global diff_empty_count + + $ui_diff conf -state normal + while {[gets $fd line] >= 0} { + foreach {line markup} [parse_color_line $line] break + set line [string map {\033 ^} $line] + - # -- Cleanup uninteresting diff header lines. ++ set tags {} ++ ++ # -- Check for start of diff header. ++ if { [string match {diff --git *} $line] ++ || [string match {diff --cc *} $line] ++ || [string match {diff --combined *} $line]} { ++ set ::current_diff_inheader 1 ++ } ++ ++ # -- Check for end of diff header (any hunk line will do this). ++ # ++ if {[regexp {^@@+ } $line]} {set ::current_diff_inheader 0} ++ ++ # -- Automatically detect if this is a 3 way diff. + # ++ if {[string match {@@@ *} $line]} {set is_3way_diff 1} ++ + if {$::current_diff_inheader} { ++ ++ # -- These two lines stop a diff header and shouldn't be in there ++ if { [string match {Binary files * and * differ} $line] ++ || [regexp {^\* Unmerged path } $line]} { ++ set ::current_diff_inheader 0 ++ } else { ++ append current_diff_header $line "\n" ++ } ++ ++ # -- Cleanup uninteresting diff header lines. ++ # + if { [string match {diff --git *} $line] + || [string match {diff --cc *} $line] + || [string match {diff --combined *} $line] + || [string match {--- *} $line] - || [string match {+++ *} $line]} { - append current_diff_header $line "\n" ++ || [string match {+++ *} $line] ++ || [string match {index *} $line]} { + continue + } - } - if {[string match {index *} $line]} continue - if {$line eq {deleted file mode 120000}} { - set line "deleted symlink" - } - set ::current_diff_inheader 0 + - # -- Automatically detect if this is a 3 way diff. - # - if {[string match {@@@ *} $line]} {set is_3way_diff 1} ++ # -- Name it symlink, not 120000 ++ # Note, that the original line is in $current_diff_header ++ regsub {^(deleted|new) file mode 120000} $line {\1 symlink} line + - if {[string match {mode *} $line] - || [string match {new file *} $line] - || [regexp {^(old|new) mode *} $line] - || [string match {deleted file *} $line] - || [string match {deleted symlink} $line] - || [string match {Binary files * and * differ} $line] - || $line eq {\ No newline at end of file} - || [regexp {^\* Unmerged path } $line]} { - set tags {} ++ } elseif { $line eq {\ No newline at end of file}} { ++ # -- Handle some special lines + } elseif {$is_3way_diff} { + set op [string range $line 0 1] + switch -- $op { + { } {set tags {}} + {@@} {set tags d_@} + { +} {set tags d_s+} + { -} {set tags d_s-} + {+ } {set tags d_+s} + {- } {set tags d_-s} + {--} {set tags d_--} + {++} { - if {[regexp {^\+\+([<>]{7} |={7})} $line _g op]} { ++ set regexp [string map [list %conflict_size $conflict_size]\ ++ {^\+\+([<>=]){%conflict_size}(?: |$)}] ++ if {[regexp $regexp $line _g op]} { + set is_conflict_diff 1 + set line [string replace $line 0 1 { }] + set tags d$op + } else { + set tags d_++ + } + } + default { + puts "error: Unhandled 3 way diff marker: {$op}" + set tags {} + } + } + } elseif {$is_submodule_diff} { + if {$line == ""} continue + if {[regexp {^Submodule } $line]} { - set tags d_@ ++ set tags d_info + } elseif {[regexp {^\* } $line]} { + set line [string replace $line 0 1 {Submodule }] - set tags d_@ ++ set tags d_info + } else { + set op [string range $line 0 2] + switch -- $op { + { <} {set tags d_-} + { >} {set tags d_+} + { W} {set tags {}} + default { + puts "error: Unhandled submodule diff marker: {$op}" + set tags {} + } + } + } + } else { + set op [string index $line 0] + switch -- $op { + { } {set tags {}} + {@} {set tags d_@} + {-} {set tags d_-} + {+} { - if {[regexp {^\+([<>]{7} |={7})} $line _g op]} { ++ set regexp [string map [list %conflict_size $conflict_size]\ ++ {^\+([<>=]){%conflict_size}(?: |$)}] ++ if {[regexp $regexp $line _g op]} { + set is_conflict_diff 1 + set tags d$op + } else { + set tags d_+ + } + } + default { + puts "error: Unhandled 2 way diff marker: {$op}" + set tags {} + } + } + } + set mark [$ui_diff index "end - 1 line linestart"] + $ui_diff insert end $line $tags + if {[string index $line end] eq "\r"} { + $ui_diff tag add d_cr {end - 2c} + } + $ui_diff insert end "\n" $tags + + foreach {posbegin colbegin posend colend} $markup { + set prefix clr + foreach style [split $colbegin ";"] { + if {$style eq "7"} {append prefix i; continue} + if {$style < 30 || $style > 47} {continue} + set a "$mark linestart + $posbegin chars" + set b "$mark linestart + $posend chars" + catch {$ui_diff tag add $prefix$style $a $b} + } + } + } + $ui_diff conf -state disabled + + if {[eof $fd]} { + close $fd + + if {$current_diff_queue ne {}} { + advance_diff_queue $cont_info + return + } + + set diff_active 0 + unlock_index + set scroll_pos [lindex $cont_info 0] + if {$scroll_pos ne {}} { + update + $ui_diff yview moveto $scroll_pos + } + ui_ready + + if {[$ui_diff index end] eq {2.0}} { + handle_empty_diff + } else { + set diff_empty_count 0 + } + + set callback [lindex $cont_info 1] + if {$callback ne {}} { + eval $callback + } + } +} + +proc apply_hunk {x y} { + global current_diff_path current_diff_header current_diff_side + global ui_diff ui_index file_states + + if {$current_diff_path eq {} || $current_diff_header eq {}} return + if {![lock_index apply_hunk]} return + + set apply_cmd {apply --cached --whitespace=nowarn} + set mi [lindex $file_states($current_diff_path) 0] + if {$current_diff_side eq $ui_index} { + set failed_msg [mc "Failed to unstage selected hunk."] + lappend apply_cmd --reverse + if {[string index $mi 0] ne {M}} { + unlock_index + return + } + } else { + set failed_msg [mc "Failed to stage selected hunk."] + if {[string index $mi 1] ne {M}} { + unlock_index + return + } + } + + set s_lno [lindex [split [$ui_diff index @$x,$y] .] 0] + set s_lno [$ui_diff search -backwards -regexp ^@@ $s_lno.0 0.0] + if {$s_lno eq {}} { + unlock_index + return + } + + set e_lno [$ui_diff search -forwards -regexp ^@@ "$s_lno + 1 lines" end] + if {$e_lno eq {}} { + set e_lno end + } + + if {[catch { + set enc [get_path_encoding $current_diff_path] + set p [eval git_write $apply_cmd] + fconfigure $p -translation binary -encoding $enc + puts -nonewline $p $current_diff_header + puts -nonewline $p [$ui_diff get $s_lno $e_lno] + close $p} err]} { + error_popup [append $failed_msg "\n\n$err"] + unlock_index + return + } + + $ui_diff conf -state normal + $ui_diff delete $s_lno $e_lno + $ui_diff conf -state disabled + + if {[$ui_diff get 1.0 end] eq "\n"} { + set o _ + } else { + set o ? + } + + if {$current_diff_side eq $ui_index} { + set mi ${o}M + } elseif {[string index $mi 0] eq {_}} { + set mi M$o + } else { + set mi ?$o + } + unlock_index + display_file $current_diff_path $mi + # This should trigger shift to the next changed file + if {$o eq {_}} { + reshow_diff + } +} + +proc apply_range_or_line {x y} { + global current_diff_path current_diff_header current_diff_side + global ui_diff ui_index file_states + + set selected [$ui_diff tag nextrange sel 0.0] + + if {$selected == {}} { + set first [$ui_diff index "@$x,$y"] + set last $first + } else { + set first [lindex $selected 0] + set last [lindex $selected 1] + } + + set first_l [$ui_diff index "$first linestart"] + set last_l [$ui_diff index "$last lineend"] + + if {$current_diff_path eq {} || $current_diff_header eq {}} return + if {![lock_index apply_hunk]} return + + set apply_cmd {apply --cached --whitespace=nowarn} + set mi [lindex $file_states($current_diff_path) 0] + if {$current_diff_side eq $ui_index} { + set failed_msg [mc "Failed to unstage selected line."] + set to_context {+} + lappend apply_cmd --reverse + if {[string index $mi 0] ne {M}} { + unlock_index + return + } + } else { + set failed_msg [mc "Failed to stage selected line."] + set to_context {-} + if {[string index $mi 1] ne {M}} { + unlock_index + return + } + } + + set wholepatch {} + + while {$first_l < $last_l} { + set i_l [$ui_diff search -backwards -regexp ^@@ $first_l 0.0] + if {$i_l eq {}} { + # If there's not a @@ above, then the selected range + # must have come before the first_l @@ + set i_l [$ui_diff search -regexp ^@@ $first_l $last_l] + } + if {$i_l eq {}} { + unlock_index + return + } + # $i_l is now at the beginning of a line + + # pick start line number from hunk header + set hh [$ui_diff get $i_l "$i_l + 1 lines"] + set hh [lindex [split $hh ,] 0] + set hln [lindex [split $hh -] 1] + + # There is a special situation to take care of. Consider this + # hunk: + # + # @@ -10,4 +10,4 @@ + # context before + # -old 1 + # -old 2 + # +new 1 + # +new 2 + # context after + # + # We used to keep the context lines in the order they appear in + # the hunk. But then it is not possible to correctly stage only + # "-old 1" and "+new 1" - it would result in this staged text: + # + # context before + # old 2 + # new 1 + # context after + # + # (By symmetry it is not possible to *un*stage "old 2" and "new + # 2".) + # + # We resolve the problem by introducing an asymmetry, namely, + # when a "+" line is *staged*, it is moved in front of the + # context lines that are generated from the "-" lines that are + # immediately before the "+" block. That is, we construct this + # patch: + # + # @@ -10,4 +10,5 @@ + # context before + # +new 1 + # old 1 + # old 2 + # context after + # + # But we do *not* treat "-" lines that are *un*staged in a + # special way. + # + # With this asymmetry it is possible to stage the change "old + # 1" -> "new 1" directly, and to stage the change "old 2" -> + # "new 2" by first staging the entire hunk and then unstaging + # the change "old 1" -> "new 1". + # + # Applying multiple lines adds complexity to the special + # situation. The pre_context must be moved after the entire + # first block of consecutive staged "+" lines, so that + # staging both additions gives the following patch: + # + # @@ -10,4 +10,6 @@ + # context before + # +new 1 + # +new 2 + # old 1 + # old 2 + # context after + + # This is non-empty if and only if we are _staging_ changes; + # then it accumulates the consecutive "-" lines (after + # converting them to context lines) in order to be moved after + # "+" change lines. + set pre_context {} + + set n 0 + set m 0 + set i_l [$ui_diff index "$i_l + 1 lines"] + set patch {} + while {[$ui_diff compare $i_l < "end - 1 chars"] && + [$ui_diff get $i_l "$i_l + 2 chars"] ne {@@}} { + set next_l [$ui_diff index "$i_l + 1 lines"] + set c1 [$ui_diff get $i_l] + if {[$ui_diff compare $first_l <= $i_l] && + [$ui_diff compare $i_l < $last_l] && + ($c1 eq {-} || $c1 eq {+})} { + # a line to stage/unstage + set ln [$ui_diff get $i_l $next_l] + if {$c1 eq {-}} { + set n [expr $n+1] + set patch "$patch$pre_context$ln" + set pre_context {} + } else { + set m [expr $m+1] + set patch "$patch$ln" + } + } elseif {$c1 ne {-} && $c1 ne {+}} { + # context line + set ln [$ui_diff get $i_l $next_l] + set patch "$patch$pre_context$ln" + set n [expr $n+1] + set m [expr $m+1] + set pre_context {} + } elseif {$c1 eq $to_context} { + # turn change line into context line + set ln [$ui_diff get "$i_l + 1 chars" $next_l] + if {$c1 eq {-}} { + set pre_context "$pre_context $ln" + } else { + set patch "$patch $ln" + } + set n [expr $n+1] + set m [expr $m+1] + } else { + # a change in the opposite direction of + # to_context which is outside the range of + # lines to apply. + set patch "$patch$pre_context" + set pre_context {} + } + set i_l $next_l + } + set patch "$patch$pre_context" + set wholepatch "$wholepatch@@ -$hln,$n +$hln,$m @@\n$patch" + set first_l [$ui_diff index "$next_l + 1 lines"] + } + + if {[catch { + set enc [get_path_encoding $current_diff_path] + set p [eval git_write $apply_cmd] + fconfigure $p -translation binary -encoding $enc + puts -nonewline $p $current_diff_header + puts -nonewline $p $wholepatch + close $p} err]} { + error_popup [append $failed_msg "\n\n$err"] + } + + unlock_index +} diff --cc git-gui/lib/index.tcl index e9db0c498,000000000..5d7bbf23e mode 100644,000000..100644 --- a/git-gui/lib/index.tcl +++ b/git-gui/lib/index.tcl @@@ -1,457 -1,0 +1,463 @@@ +# git-gui index (add/remove) support +# Copyright (C) 2006, 2007 Shawn Pearce + +proc _delete_indexlock {} { + if {[catch {file delete -- [gitdir index.lock]} err]} { + error_popup [strcat [mc "Unable to unlock the index."] "\n\n$err"] + } +} + +proc _close_updateindex {fd after} { + global use_ttk NS + fconfigure $fd -blocking 1 + if {[catch {close $fd} err]} { + set w .indexfried + Dialog $w + wm withdraw $w + wm title $w [strcat "[appname] ([reponame]): " [mc "Index Error"]] + wm geometry $w "+[winfo rootx .]+[winfo rooty .]" + set s [mc "Updating the Git index failed. A rescan will be automatically started to resynchronize git-gui."] + text $w.msg -yscrollcommand [list $w.vs set] \ + -width [string length $s] -relief flat \ + -borderwidth 0 -highlightthickness 0 \ + -background [get_bg_color $w] + $w.msg tag configure bold -font font_uibold -justify center + ${NS}::scrollbar $w.vs -command [list $w.msg yview] + $w.msg insert end $s bold \n\n$err {} + $w.msg configure -state disabled + + ${NS}::button $w.continue \ + -text [mc "Continue"] \ + -command [list destroy $w] + ${NS}::button $w.unlock \ + -text [mc "Unlock Index"] \ + -command "destroy $w; _delete_indexlock" + grid $w.msg - $w.vs -sticky news + grid $w.unlock $w.continue - -sticky se -padx 2 -pady 2 + grid columnconfigure $w 0 -weight 1 + grid rowconfigure $w 0 -weight 1 + + wm protocol $w WM_DELETE_WINDOW update + bind $w.continue " + grab $w + focus %W + " + wm deiconify $w + tkwait window $w + + $::main_status stop + unlock_index + rescan $after 0 + return + } + + $::main_status stop + unlock_index + uplevel #0 $after +} + +proc update_indexinfo {msg pathList after} { + global update_index_cp + + if {![lock_index update]} return + + set update_index_cp 0 + set pathList [lsort $pathList] + set totalCnt [llength $pathList] + set batch [expr {int($totalCnt * .01) + 1}] + if {$batch > 25} {set batch 25} + + $::main_status start $msg [mc "files"] + set fd [git_write update-index -z --index-info] + fconfigure $fd \ + -blocking 0 \ + -buffering full \ + -buffersize 512 \ + -encoding binary \ + -translation binary + fileevent $fd writable [list \ + write_update_indexinfo \ + $fd \ + $pathList \ + $totalCnt \ + $batch \ + $after \ + ] +} + +proc write_update_indexinfo {fd pathList totalCnt batch after} { + global update_index_cp + global file_states current_diff_path + + if {$update_index_cp >= $totalCnt} { + _close_updateindex $fd $after + return + } + + for {set i $batch} \ + {$update_index_cp < $totalCnt && $i > 0} \ + {incr i -1} { + set path [lindex $pathList $update_index_cp] + incr update_index_cp + + set s $file_states($path) + switch -glob -- [lindex $s 0] { + A? {set new _O} - M? {set new _M} ++ MT - ++ TM - + T_ {set new _T} ++ M? {set new _M} ++ TD - + D_ {set new _D} + D? {set new _?} + ?? {continue} + } + set info [lindex $s 2] + if {$info eq {}} continue + + puts -nonewline $fd "$info\t[encoding convertto $path]\0" + display_file $path $new + } + + $::main_status update $update_index_cp $totalCnt +} + +proc update_index {msg pathList after} { + global update_index_cp + + if {![lock_index update]} return + + set update_index_cp 0 + set pathList [lsort $pathList] + set totalCnt [llength $pathList] + set batch [expr {int($totalCnt * .01) + 1}] + if {$batch > 25} {set batch 25} + + $::main_status start $msg [mc "files"] + set fd [git_write update-index --add --remove -z --stdin] + fconfigure $fd \ + -blocking 0 \ + -buffering full \ + -buffersize 512 \ + -encoding binary \ + -translation binary + fileevent $fd writable [list \ + write_update_index \ + $fd \ + $pathList \ + $totalCnt \ + $batch \ + $after \ + ] +} + +proc write_update_index {fd pathList totalCnt batch after} { + global update_index_cp + global file_states current_diff_path + + if {$update_index_cp >= $totalCnt} { + _close_updateindex $fd $after + return + } + + for {set i $batch} \ + {$update_index_cp < $totalCnt && $i > 0} \ + {incr i -1} { + set path [lindex $pathList $update_index_cp] + incr update_index_cp + + switch -glob -- [lindex $file_states($path) 0] { + AD {set new __} + ?D {set new D_} + _O - ++ AT - + AM {set new A_} ++ TM - ++ MT - + _T {set new T_} + _U - + U? { + if {[file exists $path]} { + set new M_ + } else { + set new D_ + } + } + ?M {set new M_} + ?? {continue} + } + puts -nonewline $fd "[encoding convertto $path]\0" + display_file $path $new + } + + $::main_status update $update_index_cp $totalCnt +} + +proc checkout_index {msg pathList after} { + global update_index_cp + + if {![lock_index update]} return + + set update_index_cp 0 + set pathList [lsort $pathList] + set totalCnt [llength $pathList] + set batch [expr {int($totalCnt * .01) + 1}] + if {$batch > 25} {set batch 25} + + $::main_status start $msg [mc "files"] + set fd [git_write checkout-index \ + --index \ + --quiet \ + --force \ + -z \ + --stdin \ + ] + fconfigure $fd \ + -blocking 0 \ + -buffering full \ + -buffersize 512 \ + -encoding binary \ + -translation binary + fileevent $fd writable [list \ + write_checkout_index \ + $fd \ + $pathList \ + $totalCnt \ + $batch \ + $after \ + ] +} + +proc write_checkout_index {fd pathList totalCnt batch after} { + global update_index_cp + global file_states current_diff_path + + if {$update_index_cp >= $totalCnt} { + _close_updateindex $fd $after + return + } + + for {set i $batch} \ + {$update_index_cp < $totalCnt && $i > 0} \ + {incr i -1} { + set path [lindex $pathList $update_index_cp] + incr update_index_cp + switch -glob -- [lindex $file_states($path) 0] { + U? {continue} + ?M - + ?T - + ?D { + puts -nonewline $fd "[encoding convertto $path]\0" + display_file $path ?_ + } + } + } + + $::main_status update $update_index_cp $totalCnt +} + +proc unstage_helper {txt paths} { + global file_states current_diff_path + + if {![lock_index begin-update]} return + + set pathList [list] + set after {} + foreach path $paths { + switch -glob -- [lindex $file_states($path) 0] { + A? - + M? - - T_ - ++ T? - + D? { + lappend pathList $path + if {$path eq $current_diff_path} { + set after {reshow_diff;} + } + } + } + } + if {$pathList eq {}} { + unlock_index + } else { + update_indexinfo \ + $txt \ + $pathList \ + [concat $after [list ui_ready]] + } +} + +proc do_unstage_selection {} { + global current_diff_path selected_paths + + if {[array size selected_paths] > 0} { + unstage_helper \ + {Unstaging selected files from commit} \ + [array names selected_paths] + } elseif {$current_diff_path ne {}} { + unstage_helper \ + [mc "Unstaging %s from commit" [short_path $current_diff_path]] \ + [list $current_diff_path] + } +} + +proc add_helper {txt paths} { + global file_states current_diff_path + + if {![lock_index begin-update]} return + + set pathList [list] + set after {} + foreach path $paths { + switch -glob -- [lindex $file_states($path) 0] { + _U - + U? { + if {$path eq $current_diff_path} { + unlock_index + merge_stage_workdir $path + return + } + } + _O - + ?M - + ?D - + ?T { + lappend pathList $path + if {$path eq $current_diff_path} { + set after {reshow_diff;} + } + } + } + } + if {$pathList eq {}} { + unlock_index + } else { + update_index \ + $txt \ + $pathList \ + [concat $after {ui_status [mc "Ready to commit."]}] + } +} + +proc do_add_selection {} { + global current_diff_path selected_paths + + if {[array size selected_paths] > 0} { + add_helper \ + {Adding selected files} \ + [array names selected_paths] + } elseif {$current_diff_path ne {}} { + add_helper \ + [mc "Adding %s" [short_path $current_diff_path]] \ + [list $current_diff_path] + } +} + +proc do_add_all {} { + global file_states + + set paths [list] + foreach path [array names file_states] { + switch -glob -- [lindex $file_states($path) 0] { + U? {continue} + ?M - + ?T - + ?D {lappend paths $path} + } + } + add_helper {Adding all changed files} $paths +} + +proc revert_helper {txt paths} { + global file_states current_diff_path + + if {![lock_index begin-update]} return + + set pathList [list] + set after {} + foreach path $paths { + switch -glob -- [lindex $file_states($path) 0] { + U? {continue} + ?M - + ?T - + ?D { + lappend pathList $path + if {$path eq $current_diff_path} { + set after {reshow_diff;} + } + } + } + } + + + # Split question between singular and plural cases, because + # such distinction is needed in some languages. Previously, the + # code used "Revert changes in" for both, but that can't work + # in languages where 'in' must be combined with word from + # rest of string (in diffrent way for both cases of course). + # + # FIXME: Unfortunately, even that isn't enough in some languages + # as they have quite complex plural-form rules. Unfortunately, + # msgcat doesn't seem to support that kind of string translation. + # + set n [llength $pathList] + if {$n == 0} { + unlock_index + return + } elseif {$n == 1} { + set query [mc "Revert changes in file %s?" [short_path [lindex $pathList]]] + } else { + set query [mc "Revert changes in these %i files?" $n] + } + + set reply [tk_dialog \ + .confirm_revert \ + "[appname] ([reponame])" \ + "$query + +[mc "Any unstaged changes will be permanently lost by the revert."]" \ + question \ + 1 \ + [mc "Do Nothing"] \ + [mc "Revert Changes"] \ + ] + if {$reply == 1} { + checkout_index \ + $txt \ + $pathList \ + [concat $after [list ui_ready]] + } else { + unlock_index + } +} + +proc do_revert_selection {} { + global current_diff_path selected_paths + + if {[array size selected_paths] > 0} { + revert_helper \ + [mc "Reverting selected files"] \ + [array names selected_paths] + } elseif {$current_diff_path ne {}} { + revert_helper \ + [mc "Reverting %s" [short_path $current_diff_path]] \ + [list $current_diff_path] + } +} + +proc do_select_commit_type {} { + global commit_type selected_commit_type + + if {$selected_commit_type eq {new} + && [string match amend* $commit_type]} { + create_new_commit + } elseif {$selected_commit_type eq {amend} + && ![string match amend* $commit_type]} { + load_last_commit + + # The amend request was rejected... + # + if {![string match amend* $commit_type]} { + set selected_commit_type new + } + } +} diff --cc git-gui/lib/merge.tcl index 5cded2341,000000000..460d32fa2 mode 100644,000000..100644 --- a/git-gui/lib/merge.tcl +++ b/git-gui/lib/merge.tcl @@@ -1,275 -1,0 +1,277 @@@ +# git-gui branch merge support +# Copyright (C) 2006, 2007 Shawn Pearce + +class 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 + + if {[string match amend* $commit_type]} { + info_popup [mc "Cannot merge while amending. + +You must finish amending this commit before starting any type of merge. +"] + return 0 + } + + if {[committer_ident] eq {}} {return 0} + if {![lock_index merge]} {return 0} + + # -- Our in memory state should match the repository. + # + repository_state curType curHEAD curMERGE_HEAD + if {$commit_type ne $curType || $HEAD ne $curHEAD} { + info_popup [mc "Last scanned state does not match repository state. + +Another Git program has modified this repository since the last scan. A rescan must be performed before a merge can be performed. + +The rescan will be automatically started now. +"] + unlock_index + rescan ui_ready + return 0 + } + + foreach path [array names file_states] { + switch -glob -- [lindex $file_states($path) 0] { + _O { + continue; # and pray it works! + } + _U - + U? { + error_popup [mc "You are in the middle of a conflicted merge. + +File %s has merge conflicts. + +You must resolve them, stage the file, and commit to complete the current merge. Only then can you begin another merge. +" [short_path $path]] + unlock_index + return 0 + } + ?? { + error_popup [mc "You are in the middle of a change. + +File %s is modified. + +You should complete the current commit before starting a merge. Doing so will help you abort a failed merge, should the need arise. +" [short_path $path]] + unlock_index + return 0 + } + } + } + + return 1 +} + +method _rev {} { + if {[catch {$w_rev commit_or_die}]} { + return {} + } + return [$w_rev get] +} + +method _visualize {} { + set rev [_rev $this] + if {$rev ne {}} { + do_gitk [list $rev --not HEAD] + } +} + +method _start {} { + global HEAD current_branch remote_url ++ global _last_merged_branch + + set name [_rev $this] + if {$name eq {}} { + return + } + + set spec [$w_rev get_tracking_branch] + set cmit [$w_rev get_commit] + + set fh [open [gitdir FETCH_HEAD] w] + fconfigure $fh -translation lf + if {$spec eq {}} { + set remote . + set branch $name + set stitle $branch + } else { + set remote $remote_url([lindex $spec 1]) + if {[regexp {^[^:@]*@[^:]*:/} $remote]} { + regsub {^[^:@]*@} $remote {} remote + } + set branch [lindex $spec 2] + set stitle [mc "%s of %s" $branch $remote] + } + regsub ^refs/heads/ $branch {} branch + puts $fh "$cmit\t\tbranch '$branch' of $remote" + close $fh ++ set _last_merged_branch $branch + + 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 $name + + ui_status [mc "Merging %s and %s..." $current_branch $stitle] + set cons [console::new [mc "Merge"] "merge $stitle"] + console::exec $cons $cmd [cb _finish $cons] + + wm protocol $w WM_DELETE_WINDOW {} + destroy $w +} + +method _finish {cons ok} { + console::done $cons $ok + if {$ok} { + set msg [mc "Merge completed successfully."] + } else { + set msg [mc "Merge failed. Conflict resolution is required."] + } + unlock_index + rescan [list ui_status $msg] + delete_this +} + +constructor dialog {} { + global current_branch + global M1B use_ttk NS + + if {![_can_merge $this]} { + delete_this + return + } + + make_dialog top w + wm title $top [append "[appname] ([reponame]): " [mc "Merge"]] + if {$top ne {.}} { + wm geometry $top "+[winfo rootx .]+[winfo rooty .]" + } + + set _start [cb _start] + + ${NS}::label $w.header \ + -text [mc "Merge Into %s" $current_branch] \ + -font font_uibold + pack $w.header -side top -fill x + + ${NS}::frame $w.buttons + ${NS}::button $w.buttons.visualize \ + -text [mc Visualize] \ + -command [cb _visualize] + pack $w.buttons.visualize -side left + ${NS}::button $w.buttons.merge \ + -text [mc Merge] \ + -command $_start + pack $w.buttons.merge -side right + ${NS}::button $w.buttons.cancel \ + -text [mc "Cancel"] \ + -command [cb _cancel] + 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_unmerged $w.rev [mc "Revision To Merge"]] + pack $w.rev -anchor nw -fill both -expand 1 -pady 5 -padx 5 + + bind $w <$M1B-Key-Return> $_start + bind $w $_start + bind $w [cb _cancel] + wm protocol $w WM_DELETE_WINDOW [cb _cancel] + + bind $w.buttons.merge [cb _visible] + 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 {} { + global HEAD commit_type file_states + + if {[string match amend* $commit_type]} { + info_popup [mc "Cannot abort while amending. + +You must finish amending this commit. +"] + return + } + + if {![lock_index abort]} return + + if {[string match *merge* $commit_type]} { + set op_question [mc "Abort merge? + +Aborting the current merge will cause *ALL* uncommitted changes to be lost. + +Continue with aborting the current merge?"] + } else { + set op_question [mc "Reset changes? + +Resetting the changes will cause *ALL* uncommitted changes to be lost. + +Continue with resetting the current changes?"] + } + + if {[ask_popup $op_question] eq {yes}} { + set fd [git_read --stderr read-tree --reset -u -v HEAD] + fconfigure $fd -blocking 0 -translation binary + fileevent $fd readable [namespace code [list _reset_wait $fd]] + $::main_status start [mc "Aborting"] [mc "files reset"] + } else { + unlock_index + } +} + +proc _reset_wait {fd} { + global ui_comm + + $::main_status update_meter [read $fd] + + fconfigure $fd -blocking 1 + if {[eof $fd]} { + set fail [catch {close $fd} err] + $::main_status stop + unlock_index + + $ui_comm delete 0.0 end + $ui_comm edit modified false + + catch {file delete [gitdir MERGE_HEAD]} + catch {file delete [gitdir rr-cache MERGE_RR]} + catch {file delete [gitdir MERGE_RR]} + catch {file delete [gitdir SQUASH_MSG]} + catch {file delete [gitdir MERGE_MSG]} + catch {file delete [gitdir GITGUI_MSG]} + + if {$fail} { + warn_popup "[mc "Abort failed."]\n\n$err" + } + rescan {ui_status [mc "Abort completed. Ready."]} + } else { + fconfigure $fd -blocking 0 + } +} + +} diff --cc git-gui/lib/mergetool.tcl index 3fe90e697,000000000..3c8e73bce mode 100644,000000..100644 --- a/git-gui/lib/mergetool.tcl +++ b/git-gui/lib/mergetool.tcl @@@ -1,393 -1,0 +1,400 @@@ +# git-gui merge conflict resolution +# parts based on git-mergetool (c) 2006 Theodore Y. Ts'o + +proc merge_resolve_one {stage} { + global current_diff_path + + switch -- $stage { + 1 { set targetquestion [mc "Force resolution to the base version?"] } + 2 { set targetquestion [mc "Force resolution to this branch?"] } + 3 { set targetquestion [mc "Force resolution to the other branch?"] } + } + + set op_question [strcat $targetquestion "\n" \ +[mc "Note that the diff shows only conflicting changes. + +%s will be overwritten. + +This operation can be undone only by restarting the merge." \ + [short_path $current_diff_path]]] + + if {[ask_popup $op_question] eq {yes}} { + merge_load_stages $current_diff_path [list merge_force_stage $stage] + } +} + +proc merge_stage_workdir {path {lno {}}} { + global current_diff_path diff_active + global current_diff_side ui_workdir + + if {$diff_active} return + + if {$path ne $current_diff_path || $ui_workdir ne $current_diff_side} { + show_diff $path $ui_workdir $lno {} [list do_merge_stage_workdir $path] + } else { + do_merge_stage_workdir $path + } +} + +proc do_merge_stage_workdir {path} { + global current_diff_path is_conflict_diff + + if {$path ne $current_diff_path} return; + + if {$is_conflict_diff} { + if {[ask_popup [mc "File %s seems to have unresolved conflicts, still stage?" \ + [short_path $path]]] ne {yes}} { + return + } + } + + merge_add_resolution $path +} + +proc merge_add_resolution {path} { + global current_diff_path ui_workdir + + set after [next_diff_after_action $ui_workdir $path {} {^_?U}] + + update_index \ + [mc "Adding resolution for %s" [short_path $path]] \ + [list $path] \ + [concat $after [list ui_ready]] +} + +proc merge_force_stage {stage} { + global current_diff_path merge_stages + + if {$merge_stages($stage) ne {}} { + git checkout-index -f --stage=$stage -- $current_diff_path + } else { + file delete -- $current_diff_path + } + + merge_add_resolution $current_diff_path +} + +proc merge_load_stages {path cont} { + global merge_stages_fd merge_stages merge_stages_buf + + if {[info exists merge_stages_fd]} { + catch { kill_file_process $merge_stages_fd } + catch { close $merge_stages_fd } + } + + set merge_stages(0) {} + set merge_stages(1) {} + set merge_stages(2) {} + set merge_stages(3) {} + set merge_stages_buf {} + + set merge_stages_fd [eval git_read ls-files -u -z -- {$path}] + + fconfigure $merge_stages_fd -blocking 0 -translation binary -encoding binary + fileevent $merge_stages_fd readable [list read_merge_stages $merge_stages_fd $cont] +} + +proc read_merge_stages {fd cont} { + global merge_stages_buf merge_stages_fd merge_stages + + append merge_stages_buf [read $fd] + set pck [split $merge_stages_buf "\0"] + set merge_stages_buf [lindex $pck end] + + if {[eof $fd] && $merge_stages_buf ne {}} { + lappend pck {} + set merge_stages_buf {} + } + + foreach p [lrange $pck 0 end-1] { + set fcols [split $p "\t"] + set cols [split [lindex $fcols 0] " "] + set stage [lindex $cols 2] + + set merge_stages($stage) [lrange $cols 0 1] + } + + if {[eof $fd]} { + close $fd + unset merge_stages_fd + eval $cont + } +} + +proc merge_resolve_tool {} { + global current_diff_path + + merge_load_stages $current_diff_path [list merge_resolve_tool2] +} + +proc merge_resolve_tool2 {} { + global current_diff_path merge_stages + + # Validate the stages + if {$merge_stages(2) eq {} || + [lindex $merge_stages(2) 0] eq {120000} || + [lindex $merge_stages(2) 0] eq {160000} || + $merge_stages(3) eq {} || + [lindex $merge_stages(3) 0] eq {120000} || + [lindex $merge_stages(3) 0] eq {160000} + } { + error_popup [mc "Cannot resolve deletion or link conflicts using a tool"] + return + } + + if {![file exists $current_diff_path]} { + error_popup [mc "Conflict file does not exist"] + return + } + + # Determine the tool to use + set tool [get_config merge.tool] + if {$tool eq {}} { set tool meld } + + set merge_tool_path [get_config "mergetool.$tool.path"] + if {$merge_tool_path eq {}} { + switch -- $tool { + emerge { set merge_tool_path "emacs" } + araxis { set merge_tool_path "compare" } + default { set merge_tool_path $tool } + } + } + + # Make file names + set filebase [file rootname $current_diff_path] + set fileext [file extension $current_diff_path] + set basename [lindex [file split $current_diff_path] end] + + set MERGED $current_diff_path + set BASE "./$MERGED.BASE$fileext" + set LOCAL "./$MERGED.LOCAL$fileext" + set REMOTE "./$MERGED.REMOTE$fileext" + set BACKUP "./$MERGED.BACKUP$fileext" + + set base_stage $merge_stages(1) + + # Build the command line + switch -- $tool { - kdiff3 { ++ araxis { + if {$base_stage ne {}} { - set cmdline [list "$merge_tool_path" --auto --L1 "$MERGED (Base)" \ - --L2 "$MERGED (Local)" --L3 "$MERGED (Remote)" -o "$MERGED" "$BASE" "$LOCAL" "$REMOTE"] ++ set cmdline [list "$merge_tool_path" -wait -merge -3 -a1 \ ++ -title1:"'$MERGED (Base)'" -title2:"'$MERGED (Local)'" \ ++ -title3:"'$MERGED (Remote)'" \ ++ "$BASE" "$LOCAL" "$REMOTE" "$MERGED"] + } else { - set cmdline [list "$merge_tool_path" --auto --L1 "$MERGED (Local)" \ - --L2 "$MERGED (Remote)" -o "$MERGED" "$LOCAL" "$REMOTE"] ++ set cmdline [list "$merge_tool_path" -wait -2 \ ++ -title1:"'$MERGED (Local)'" -title2:"'$MERGED (Remote)'" \ ++ "$LOCAL" "$REMOTE" "$MERGED"] + } + } - tkdiff { ++ bc3 { + if {$base_stage ne {}} { - set cmdline [list "$merge_tool_path" -a "$BASE" -o "$MERGED" "$LOCAL" "$REMOTE"] ++ set cmdline [list "$merge_tool_path" "$LOCAL" "$REMOTE" "$BASE" -mergeoutput="$MERGED"] + } else { - set cmdline [list "$merge_tool_path" -o "$MERGED" "$LOCAL" "$REMOTE"] ++ set cmdline [list "$merge_tool_path" "$LOCAL" "$REMOTE" -mergeoutput="$MERGED"] + } + } - meld { - set cmdline [list "$merge_tool_path" "$LOCAL" "$MERGED" "$REMOTE"] ++ ecmerge { ++ if {$base_stage ne {}} { ++ set cmdline [list "$merge_tool_path" "$BASE" "$LOCAL" "$REMOTE" --default --mode=merge3 --to="$MERGED"] ++ } else { ++ set cmdline [list "$merge_tool_path" "$LOCAL" "$REMOTE" --default --mode=merge2 --to="$MERGED"] ++ } ++ } ++ emerge { ++ if {$base_stage ne {}} { ++ set cmdline [list "$merge_tool_path" -f emerge-files-with-ancestor-command \ ++ "$LOCAL" "$REMOTE" "$BASE" "$basename"] ++ } else { ++ set cmdline [list "$merge_tool_path" -f emerge-files-command \ ++ "$LOCAL" "$REMOTE" "$basename"] ++ } + } + gvimdiff { + set cmdline [list "$merge_tool_path" -f "$LOCAL" "$MERGED" "$REMOTE"] + } - xxdiff { ++ kdiff3 { + if {$base_stage ne {}} { - set cmdline [list "$merge_tool_path" -X --show-merged-pane \ - -R {Accel.SaveAsMerged: "Ctrl-S"} \ - -R {Accel.Search: "Ctrl+F"} \ - -R {Accel.SearchForward: "Ctrl-G"} \ - --merged-file "$MERGED" "$LOCAL" "$BASE" "$REMOTE"] ++ set cmdline [list "$merge_tool_path" --auto --L1 "$MERGED (Base)" \ ++ --L2 "$MERGED (Local)" --L3 "$MERGED (Remote)" -o "$MERGED" "$BASE" "$LOCAL" "$REMOTE"] + } else { - set cmdline [list "$merge_tool_path" -X --show-merged-pane \ - -R {Accel.SaveAsMerged: "Ctrl-S"} \ - -R {Accel.Search: "Ctrl+F"} \ - -R {Accel.SearchForward: "Ctrl-G"} \ - --merged-file "$MERGED" "$LOCAL" "$REMOTE"] ++ set cmdline [list "$merge_tool_path" --auto --L1 "$MERGED (Local)" \ ++ --L2 "$MERGED (Remote)" -o "$MERGED" "$LOCAL" "$REMOTE"] + } + } ++ meld { ++ set cmdline [list "$merge_tool_path" "$LOCAL" "$MERGED" "$REMOTE"] ++ } + opendiff { + if {$base_stage ne {}} { + set cmdline [list "$merge_tool_path" "$LOCAL" "$REMOTE" -ancestor "$BASE" -merge "$MERGED"] + } else { + set cmdline [list "$merge_tool_path" "$LOCAL" "$REMOTE" -merge "$MERGED"] + } + } - ecmerge { - if {$base_stage ne {}} { - set cmdline [list "$merge_tool_path" "$BASE" "$LOCAL" "$REMOTE" --default --mode=merge3 --to="$MERGED"] - } else { - set cmdline [list "$merge_tool_path" "$LOCAL" "$REMOTE" --default --mode=merge2 --to="$MERGED"] - } ++ p4merge { ++ set cmdline [list "$merge_tool_path" "$BASE" "$REMOTE" "$LOCAL" "$MERGED"] + } - emerge { ++ tkdiff { + if {$base_stage ne {}} { - set cmdline [list "$merge_tool_path" -f emerge-files-with-ancestor-command \ - "$LOCAL" "$REMOTE" "$BASE" "$basename"] ++ set cmdline [list "$merge_tool_path" -a "$BASE" -o "$MERGED" "$LOCAL" "$REMOTE"] + } else { - set cmdline [list "$merge_tool_path" -f emerge-files-command \ - "$LOCAL" "$REMOTE" "$basename"] ++ set cmdline [list "$merge_tool_path" -o "$MERGED" "$LOCAL" "$REMOTE"] + } + } ++ vimdiff { ++ error_popup [mc "Not a GUI merge tool: '%s'" $tool] ++ return ++ } + winmerge { + if {$base_stage ne {}} { + # This tool does not support 3-way merges. + # Use the 'conflict file' resolution feature instead. + set cmdline [list "$merge_tool_path" -e -ub "$MERGED"] + } else { + set cmdline [list "$merge_tool_path" -e -ub -wl \ + -dl "Theirs File" -dr "Mine File" "$REMOTE" "$LOCAL" "$MERGED"] + } + } - araxis { ++ xxdiff { + if {$base_stage ne {}} { - set cmdline [list "$merge_tool_path" -wait -merge -3 -a1 \ - -title1:"'$MERGED (Base)'" -title2:"'$MERGED (Local)'" \ - -title3:"'$MERGED (Remote)'" \ - "$BASE" "$LOCAL" "$REMOTE" "$MERGED"] ++ set cmdline [list "$merge_tool_path" -X --show-merged-pane \ ++ -R {Accel.SaveAsMerged: "Ctrl-S"} \ ++ -R {Accel.Search: "Ctrl+F"} \ ++ -R {Accel.SearchForward: "Ctrl-G"} \ ++ --merged-file "$MERGED" "$LOCAL" "$BASE" "$REMOTE"] + } else { - set cmdline [list "$merge_tool_path" -wait -2 \ - -title1:"'$MERGED (Local)'" -title2:"'$MERGED (Remote)'" \ - "$LOCAL" "$REMOTE" "$MERGED"] ++ set cmdline [list "$merge_tool_path" -X --show-merged-pane \ ++ -R {Accel.SaveAsMerged: "Ctrl-S"} \ ++ -R {Accel.Search: "Ctrl+F"} \ ++ -R {Accel.SearchForward: "Ctrl-G"} \ ++ --merged-file "$MERGED" "$LOCAL" "$REMOTE"] + } + } - p4merge { - set cmdline [list "$merge_tool_path" "$BASE" "$REMOTE" "$LOCAL" "$MERGED"] - } - vimdiff { - error_popup [mc "Not a GUI merge tool: '%s'" $tool] - return - } + default { + error_popup [mc "Unsupported merge tool '%s'" $tool] + return + } + } + + merge_tool_start $cmdline $MERGED $BACKUP [list $BASE $LOCAL $REMOTE] +} + +proc delete_temp_files {files} { + foreach fname $files { + file delete $fname + } +} + +proc merge_tool_get_stages {target stages} { + global merge_stages + + set i 1 + foreach fname $stages { + if {$merge_stages($i) eq {}} { + file delete $fname + catch { close [open $fname w] } + } else { + # A hack to support autocrlf properly + git checkout-index -f --stage=$i -- $target + file rename -force -- $target $fname + } + incr i + } +} + +proc merge_tool_start {cmdline target backup stages} { + global merge_stages mtool_target mtool_tmpfiles mtool_fd mtool_mtime + + if {[info exists mtool_fd]} { + if {[ask_popup [mc "Merge tool is already running, terminate it?"]] eq {yes}} { + catch { kill_file_process $mtool_fd } + catch { close $mtool_fd } + unset mtool_fd + + set old_backup [lindex $mtool_tmpfiles end] + file rename -force -- $old_backup $mtool_target + delete_temp_files $mtool_tmpfiles + } else { + return + } + } + + # Save the original file + file rename -force -- $target $backup + + # Get the blobs; it destroys $target + if {[catch {merge_tool_get_stages $target $stages} err]} { + file rename -force -- $backup $target + delete_temp_files $stages + error_popup [mc "Error retrieving versions:\n%s" $err] + return + } + + # Restore the conflict file + file copy -force -- $backup $target + + # Initialize global state + set mtool_target $target + set mtool_mtime [file mtime $target] + set mtool_tmpfiles $stages + + lappend mtool_tmpfiles $backup + + # Force redirection to avoid interpreting output on stderr + # as an error, and launch the tool + lappend cmdline {2>@1} + + if {[catch { set mtool_fd [_open_stdout_stderr $cmdline] } err]} { + delete_temp_files $mtool_tmpfiles + error_popup [mc "Could not start the merge tool:\n\n%s" $err] + return + } + + ui_status [mc "Running merge tool..."] + + fconfigure $mtool_fd -blocking 0 -translation binary -encoding binary + fileevent $mtool_fd readable [list read_mtool_output $mtool_fd] +} + +proc read_mtool_output {fd} { + global mtool_fd mtool_tmpfiles + + read $fd + if {[eof $fd]} { + unset mtool_fd + + fconfigure $fd -blocking 1 + merge_tool_finish $fd + } +} + +proc merge_tool_finish {fd} { + global mtool_tmpfiles mtool_target mtool_mtime + + set backup [lindex $mtool_tmpfiles end] + set failed 0 + + # Check the return code + if {[catch {close $fd} err]} { + set failed 1 + if {$err ne {child process exited abnormally}} { + error_popup [strcat [mc "Merge tool failed."] "\n\n$err"] + } + } + + # Finish + if {$failed} { + file rename -force -- $backup $mtool_target + delete_temp_files $mtool_tmpfiles + ui_status [mc "Merge tool failed."] + } else { + if {[is_config_true mergetool.keepbackup]} { + file rename -force -- $backup "$mtool_target.orig" + } + + delete_temp_files $mtool_tmpfiles + + reshow_diff + } +} diff --cc git-gui/lib/remote.tcl index b92b429cf,000000000..5e4e7f4c8 mode 100644,000000..100644 --- a/git-gui/lib/remote.tcl +++ b/git-gui/lib/remote.tcl @@@ -1,276 -1,0 +1,331 @@@ +# git-gui remote management +# Copyright (C) 2006, 2007 Shawn Pearce + +set some_heads_tracking 0; # assume not + +proc is_tracking_branch {name} { + global tracking_branches + foreach spec $tracking_branches { + set t [lindex $spec 0] + if {$t eq $name || [string match $t $name]} { + return 1 + } + } + return 0 +} + +proc all_tracking_branches {} { + global tracking_branches + + set all [list] + set pat [list] + set cmd [list] + + foreach spec $tracking_branches { + set dst [lindex $spec 0] + if {[string range $dst end-1 end] eq {/*}} { + lappend pat $spec + lappend cmd [string range $dst 0 end-2] + } else { + lappend all $spec + } + } + + if {$pat ne {}} { + set fd [eval git_read for-each-ref --format=%(refname) $cmd] + while {[gets $fd n] > 0} { + foreach spec $pat { + set dst [string range [lindex $spec 0] 0 end-2] + set len [string length $dst] + if {[string equal -length $len $dst $n]} { + set src [string range [lindex $spec 2] 0 end-2] + set spec [list \ + $n \ + [lindex $spec 1] \ + $src[string range $n $len end] \ + ] + lappend all $spec + } + } + } + close $fd + } + + return [lsort -index 0 -unique $all] +} + +proc load_all_remotes {} { + global repo_config + global all_remotes tracking_branches some_heads_tracking + global remote_url + + set some_heads_tracking 0 + set all_remotes [list] + set trck [list] + + set rh_str refs/heads/ + set rh_len [string length $rh_str] + set rm_dir [gitdir remotes] + if {[file isdirectory $rm_dir]} { + set all_remotes [glob \ + -types f \ + -tails \ + -nocomplain \ + -directory $rm_dir *] + + foreach name $all_remotes { + catch { + set fd [open [file join $rm_dir $name] r] + while {[gets $fd line] >= 0} { + if {[regexp {^URL:[ ]*(.+)$} $line line url]} { + set remote_url($name) $url + continue + } + if {![regexp {^Pull:[ ]*([^:]+):(.+)$} \ + $line line src dst]} continue + if {[string index $src 0] eq {+}} { + set src [string range $src 1 end] + } + if {![string equal -length 5 refs/ $src]} { + set src $rh_str$src + } + if {![string equal -length 5 refs/ $dst]} { + set dst $rh_str$dst + } + if {[string equal -length $rh_len $rh_str $dst]} { + set some_heads_tracking 1 + } + lappend trck [list $dst $name $src] + } + close $fd + } + } + } + + foreach line [array names repo_config remote.*.url] { + if {![regexp ^remote\.(.*)\.url\$ $line line name]} continue + lappend all_remotes $name + set remote_url($name) $repo_config(remote.$name.url) + + if {[catch {set fl $repo_config(remote.$name.fetch)}]} { + set fl {} + } + foreach line $fl { + if {![regexp {^([^:]+):(.+)$} $line line src dst]} continue + if {[string index $src 0] eq {+}} { + set src [string range $src 1 end] + } + if {![string equal -length 5 refs/ $src]} { + set src $rh_str$src + } + if {![string equal -length 5 refs/ $dst]} { + set dst $rh_str$dst + } + if {[string equal -length $rh_len $rh_str $dst]} { + set some_heads_tracking 1 + } + lappend trck [list $dst $name $src] + } + } + + set tracking_branches [lsort -index 0 -unique $trck] + set all_remotes [lsort -unique $all_remotes] +} + +proc add_fetch_entry {r} { + global repo_config + set remote_m .mbar.remote + set fetch_m $remote_m.fetch + set prune_m $remote_m.prune + set remove_m $remote_m.remove + set enable 0 + if {![catch {set a $repo_config(remote.$r.url)}]} { + if {![catch {set a $repo_config(remote.$r.fetch)}]} { + set enable 1 + } + } else { + catch { + set fd [open [gitdir remotes $r] r] + while {[gets $fd n] >= 0} { + if {[regexp {^Pull:[ \t]*([^:]+):} $n]} { + set enable 1 + break + } + } + close $fd + } + } + + if {$enable} { - if {![winfo exists $fetch_m]} { - menu $remove_m - $remote_m insert 0 cascade \ - -label [mc "Remove Remote"] \ - -menu $remove_m - - menu $prune_m - $remote_m insert 0 cascade \ - -label [mc "Prune from"] \ - -menu $prune_m - - menu $fetch_m - $remote_m insert 0 cascade \ - -label [mc "Fetch from"] \ - -menu $fetch_m - } ++ make_sure_remote_submenues_exist $remote_m + + $fetch_m add command \ + -label $r \ + -command [list fetch_from $r] + $prune_m add command \ + -label $r \ + -command [list prune_from $r] + $remove_m add command \ + -label $r \ + -command [list remove_remote $r] + } +} + +proc add_push_entry {r} { + global repo_config + set remote_m .mbar.remote + set push_m $remote_m.push + set enable 0 + if {![catch {set a $repo_config(remote.$r.url)}]} { + if {![catch {set a $repo_config(remote.$r.push)}]} { + set enable 1 + } + } else { + catch { + set fd [open [gitdir remotes $r] r] + while {[gets $fd n] >= 0} { + if {[regexp {^Push:[ \t]*([^:]+):} $n]} { + set enable 1 + break + } + } + close $fd + } + } + + if {$enable} { + if {![winfo exists $push_m]} { + menu $push_m + $remote_m insert 0 cascade \ + -label [mc "Push to"] \ + -menu $push_m + } + + $push_m add command \ + -label $r \ + -command [list push_to $r] + } +} + ++proc make_sure_remote_submenues_exist {remote_m} { ++ set fetch_m $remote_m.fetch ++ set prune_m $remote_m.prune ++ set remove_m $remote_m.remove ++ ++ if {![winfo exists $fetch_m]} { ++ menu $remove_m ++ $remote_m insert 0 cascade \ ++ -label [mc "Remove Remote"] \ ++ -menu $remove_m ++ ++ menu $prune_m ++ $remote_m insert 0 cascade \ ++ -label [mc "Prune from"] \ ++ -menu $prune_m ++ ++ menu $fetch_m ++ $remote_m insert 0 cascade \ ++ -label [mc "Fetch from"] \ ++ -menu $fetch_m ++ } ++} ++ ++proc update_all_remotes_menu_entry {} { ++ global all_remotes ++ ++ if {[git-version < 1.6.6]} { return } ++ ++ set have_remote 0 ++ foreach r $all_remotes { ++ incr have_remote ++ } ++ ++ set remote_m .mbar.remote ++ set fetch_m $remote_m.fetch ++ set prune_m $remote_m.prune ++ if {$have_remote > 1} { ++ make_sure_remote_submenues_exist $remote_m ++ if {[$fetch_m entrycget end -label] ne "All"} { ++ ++ $fetch_m insert end separator ++ $fetch_m insert end command \ ++ -label "All" \ ++ -command fetch_from_all ++ ++ $prune_m insert end separator ++ $prune_m insert end command \ ++ -label "All" \ ++ -command prune_from_all ++ } ++ } else { ++ if {[winfo exists $fetch_m]} { ++ if {[$fetch_m entrycget end -label] eq "All"} { ++ ++ delete_from_menu $fetch_m end ++ delete_from_menu $fetch_m end ++ ++ delete_from_menu $prune_m end ++ delete_from_menu $prune_m end ++ } ++ } ++ } ++} ++ +proc populate_remotes_menu {} { + global all_remotes + + foreach r $all_remotes { + add_fetch_entry $r + add_push_entry $r + } ++ ++ update_all_remotes_menu_entry +} + +proc add_single_remote {name location} { + global all_remotes repo_config + lappend all_remotes $name + + git remote add $name $location + + # XXX: Better re-read the config so that we will never get out + # of sync with git remote implementation? + set repo_config(remote.$name.url) $location + set repo_config(remote.$name.fetch) "+refs/heads/*:refs/remotes/$name/*" + + add_fetch_entry $name + add_push_entry $name ++ ++ update_all_remotes_menu_entry +} + +proc delete_from_menu {menu name} { + if {[winfo exists $menu]} { + $menu delete $name + } +} + +proc remove_remote {name} { + global all_remotes repo_config + + git remote rm $name + + catch { + # Missing values are ok + unset repo_config(remote.$name.url) + unset repo_config(remote.$name.fetch) + unset repo_config(remote.$name.push) + } + - set i [lsearch -exact all_remotes $name] - lreplace all_remotes $i $i ++ set i [lsearch -exact $all_remotes $name] ++ set all_remotes [lreplace $all_remotes $i $i] + + set remote_m .mbar.remote + delete_from_menu $remote_m.fetch $name + delete_from_menu $remote_m.prune $name + delete_from_menu $remote_m.remove $name + # Not all remotes are in the push menu + catch { delete_from_menu $remote_m.push $name } ++ ++ update_all_remotes_menu_entry +} diff --cc git-gui/lib/remote_branch_delete.tcl index f872a3d89,000000000..fcc06d03a mode 100644,000000..100644 --- a/git-gui/lib/remote_branch_delete.tcl +++ b/git-gui/lib/remote_branch_delete.tcl @@@ -1,352 -1,0 +1,359 @@@ +# git-gui remote branch deleting support +# Copyright (C) 2007 Shawn Pearce + +class remote_branch_delete { + +field w +field head_m + +field urltype {url} +field remote {} +field url {} + +field checktype {head} +field check_head {} + +field status {} +field idle_id {} +field full_list {} +field head_list {} +field active_ls {} +field head_cache +field full_cache +field cached + +constructor dialog {} { + global all_remotes M1B use_ttk NS + + make_dialog top w + wm title $top [append "[appname] ([reponame]): " [mc "Delete Branch Remotely"]] + if {$top ne {.}} { + wm geometry $top "+[winfo rootx .]+[winfo rooty .]" + } + + ${NS}::label $w.header -text [mc "Delete Branch Remotely"] \ + -font font_uibold -anchor center + pack $w.header -side top -fill x + + ${NS}::frame $w.buttons + ${NS}::button $w.buttons.delete -text [mc Delete] \ + -default active \ + -command [cb _delete] + pack $w.buttons.delete -side right + ${NS}::button $w.buttons.cancel -text [mc "Cancel"] \ + -command [list destroy $w] + pack $w.buttons.cancel -side right -padx 5 + pack $w.buttons -side bottom -fill x -pady 10 -padx 10 + + ${NS}::labelframe $w.dest -text [mc "From Repository"] + if {$all_remotes ne {}} { + ${NS}::radiobutton $w.dest.remote_r \ + -text [mc "Remote:"] \ + -value remote \ + -variable @urltype + if {$use_ttk} { + ttk::combobox $w.dest.remote_m -textvariable @remote \ + -values $all_remotes -state readonly + } else { + eval tk_optionMenu $w.dest.remote_m @remote $all_remotes + } + grid $w.dest.remote_r $w.dest.remote_m -sticky w + if {[lsearch -sorted -exact $all_remotes origin] != -1} { + set remote origin + } else { + set remote [lindex $all_remotes 0] + } + set urltype remote + trace add variable @remote write [cb _write_remote] + } else { + set urltype url + } + ${NS}::radiobutton $w.dest.url_r \ + -text [mc "Arbitrary Location:"] \ + -value url \ + -variable @urltype + ${NS}::entry $w.dest.url_t \ + -width 50 \ + -textvariable @url \ + -validate key \ + -validatecommand { + if {%d == 1 && [regexp {\s} %S]} {return 0} + return 1 + } + trace add variable @url write [cb _write_url] + grid $w.dest.url_r $w.dest.url_t -sticky we -padx {0 5} + grid columnconfigure $w.dest 1 -weight 1 + pack $w.dest -anchor nw -fill x -pady 5 -padx 5 + + ${NS}::labelframe $w.heads -text [mc "Branches"] + slistbox $w.heads.l \ + -height 10 \ + -width 70 \ + -listvariable @head_list \ + -selectmode extended + + ${NS}::frame $w.heads.footer + ${NS}::label $w.heads.footer.status \ + -textvariable @status \ + -anchor w \ + -justify left + ${NS}::button $w.heads.footer.rescan \ + -text [mc "Rescan"] \ + -command [cb _rescan] + pack $w.heads.footer.status -side left -fill x + pack $w.heads.footer.rescan -side right + + pack $w.heads.footer -side bottom -fill x + pack $w.heads.l -side left -fill both -expand 1 + pack $w.heads -fill both -expand 1 -pady 5 -padx 5 + + ${NS}::labelframe $w.validate -text [mc "Delete Only If"] + ${NS}::radiobutton $w.validate.head_r \ + -text [mc "Merged Into:"] \ + -value head \ + -variable @checktype + set head_m [tk_optionMenu $w.validate.head_m @check_head {}] + trace add variable @head_list write [cb _write_head_list] + trace add variable @check_head write [cb _write_check_head] + grid $w.validate.head_r $w.validate.head_m -sticky w + ${NS}::radiobutton $w.validate.always_r \ + -text [mc "Always (Do not perform merge checks)"] \ + -value always \ + -variable @checktype + grid $w.validate.always_r -columnspan 2 -sticky w + grid columnconfigure $w.validate 1 -weight 1 + pack $w.validate -anchor nw -fill x -pady 5 -padx 5 + + trace add variable @urltype write [cb _write_urltype] + _rescan $this + + bind $w [cb _rescan] + bind $w <$M1B-Key-r> [cb _rescan] + bind $w <$M1B-Key-R> [cb _rescan] + bind $w [cb _delete] + bind $w [list destroy $w] + return $w +} + +method _delete {} { + switch $urltype { + remote {set uri $remote} + url {set uri $url} + } + + set cache $urltype:$uri + set crev {} + if {$checktype eq {head}} { + if {$check_head eq {}} { + tk_messageBox \ + -icon error \ + -type ok \ + -title [wm title $w] \ + -parent $w \ + -message [mc "A branch is required for 'Merged Into'."] + return + } + set crev $full_cache("$cache\nrefs/heads/$check_head") + } + + set not_merged [list] + set need_fetch 0 + set have_selection 0 + set push_cmd [list git push] + lappend push_cmd -v + lappend push_cmd $uri + + foreach i [$w.heads.l curselection] { + set ref [lindex $full_list $i] + if {$crev ne {}} { + set obj $full_cache("$cache\n$ref") + if {[catch {set m [git merge-base $obj $crev]}]} { + set need_fetch 1 + set m {} + } + if {$obj ne $m} { + lappend not_merged [lindex $head_list $i] + continue + } + } + + lappend push_cmd :$ref + set have_selection 1 + } + + if {$not_merged ne {}} { + set msg [mc "The following branches are not completely merged into %s: + + - %s" $check_head [join $not_merged "\n - "]] + + if {$need_fetch} { + append msg "\n\n" [mc "One or more of the merge tests failed because you have not fetched the necessary commits. Try fetching from %s first." $uri] + } + + tk_messageBox \ + -icon info \ + -type ok \ + -title [wm title $w] \ + -parent $w \ + -message $msg + if {!$have_selection} return + } + + if {!$have_selection} { + tk_messageBox \ + -icon error \ + -type ok \ + -title [wm title $w] \ + -parent $w \ + -message [mc "Please select one or more branches to delete."] + return + } + + if {$checktype ne {head}} { + if {[tk_messageBox \ + -icon warning \ + -type yesno \ + -title [wm title $w] \ + -parent $w \ + -message [mc "Recovering deleted branches is difficult.\n\nDelete the selected branches?"]] ne yes} { + return + } + } + + destroy $w + + set cons [console::new \ + "push $uri" \ + [mc "Deleting branches from %s" $uri]] + console::exec $cons $push_cmd +} + +method _rescan {{force 1}} { + switch $urltype { + remote {set uri $remote} + url {set uri $url} + } + + if {$force} { + unset -nocomplain cached($urltype:$uri) + } + + if {$idle_id ne {}} { + after cancel $idle_id + set idle_id {} + } + + _load $this $urltype:$uri $uri +} + +method _write_remote {args} { set urltype remote } +method _write_url {args} { set urltype url } +method _write_check_head {args} { set checktype head } + +method _write_head_list {args} { - global current_branch ++ global current_branch _last_merged_branch + + $head_m delete 0 end + foreach abr $head_list { + $head_m insert end radiobutton \ + -label $abr \ + -value $abr \ + -variable @check_head + } + if {[lsearch -exact -sorted $head_list $check_head] < 0} { + if {[lsearch -exact -sorted $head_list $current_branch] < 0} { + set check_head {} + } else { + set check_head $current_branch + } + } ++ set lmb [lsearch -exact -sorted $head_list $_last_merged_branch] ++ if {$lmb >= 0} { ++ $w.heads.l conf -state normal ++ $w.heads.l select set $lmb ++ $w.heads.l yview $lmb ++ $w.heads.l conf -state disabled ++ } +} + +method _write_urltype {args} { + if {$urltype eq {url}} { + if {$idle_id ne {}} { + after cancel $idle_id + } + _load $this none: {} + set idle_id [after 1000 [cb _rescan 0]] + } else { + _rescan $this 0 + } +} + +method _load {cache uri} { + if {$active_ls ne {}} { + catch {close $active_ls} + } + + if {$uri eq {}} { + $w.heads.l conf -state disabled + set head_list [list] + set full_list [list] + set status [mc "No repository selected."] + return + } + + if {[catch {set x $cached($cache)}]} { + set status [mc "Scanning %s..." $uri] + $w.heads.l conf -state disabled + set head_list [list] + set full_list [list] + set head_cache($cache) [list] + set full_cache($cache) [list] + set active_ls [git_read ls-remote $uri] + fconfigure $active_ls \ + -blocking 0 \ + -translation lf \ + -encoding utf-8 + fileevent $active_ls readable [cb _read $cache $active_ls] + } else { + set status {} + set full_list $full_cache($cache) + set head_list $head_cache($cache) + $w.heads.l conf -state normal + } +} + +method _read {cache fd} { + if {$fd ne $active_ls} { + catch {close $fd} + return + } + + while {[gets $fd line] >= 0} { + if {[string match {*^{}} $line]} continue + if {[regexp {^([0-9a-f]{40}) (.*)$} $line _junk obj ref]} { + if {[regsub ^refs/heads/ $ref {} abr]} { + lappend head_list $abr + lappend head_cache($cache) $abr + lappend full_list $ref + lappend full_cache($cache) $ref + set full_cache("$cache\n$ref") $obj + } + } + } + + if {[eof $fd]} { + if {[catch {close $fd} err]} { + set status $err + set head_list [list] + set full_list [list] + } else { + set status {} + set cached($cache) 1 + $w.heads.l conf -state normal + } + } +} ifdeleted { + catch {close $fd} +} + +} diff --cc git-gui/lib/transport.tcl index 60e3a642c,000000000..7fad9b7d9 mode 100644,000000..100644 --- a/git-gui/lib/transport.tcl +++ b/git-gui/lib/transport.tcl @@@ -1,199 -1,0 +1,231 @@@ +# git-gui transport (fetch/push) support +# Copyright (C) 2006, 2007 Shawn Pearce + +proc fetch_from {remote} { + set w [console::new \ + [mc "fetch %s" $remote] \ + [mc "Fetching new changes from %s" $remote]] + set cmds [list] + lappend cmds [list exec git fetch $remote] + if {[is_config_true gui.pruneduringfetch]} { + lappend cmds [list exec git remote prune $remote] + } + console::chain $w $cmds +} + +proc prune_from {remote} { + set w [console::new \ + [mc "remote prune %s" $remote] \ + [mc "Pruning tracking branches deleted from %s" $remote]] + console::exec $w [list git remote prune $remote] +} + ++proc fetch_from_all {} { ++ set w [console::new \ ++ [mc "fetch all remotes"] \ ++ [mc "Fetching new changes from all remotes"]] ++ ++ set cmd [list git fetch --all] ++ if {[is_config_true gui.pruneduringfetch]} { ++ lappend cmd --prune ++ } ++ ++ console::exec $w $cmd ++} ++ ++proc prune_from_all {} { ++ global all_remotes ++ ++ set w [console::new \ ++ [mc "remote prune all remotes"] \ ++ [mc "Pruning tracking branches deleted from all remotes"]] ++ ++ set cmd [list git remote prune] ++ ++ foreach r $all_remotes { ++ lappend cmd $r ++ } ++ ++ console::exec $w $cmd ++} ++ +proc push_to {remote} { + set w [console::new \ + [mc "push %s" $remote] \ + [mc "Pushing changes to %s" $remote]] + set cmd [list git push] + lappend cmd -v + lappend cmd $remote + console::exec $w $cmd +} + +proc start_push_anywhere_action {w} { + global push_urltype push_remote push_url push_thin push_tags + global push_force + global repo_config + + set is_mirror 0 + set r_url {} + switch -- $push_urltype { + remote { + set r_url $push_remote + catch {set is_mirror $repo_config(remote.$push_remote.mirror)} + } + url {set r_url $push_url} + } + if {$r_url eq {}} return + + set cmd [list git push] + lappend cmd -v + if {$push_thin} { + lappend cmd --thin + } + if {$push_force} { + lappend cmd --force + } + if {$push_tags} { + lappend cmd --tags + } + lappend cmd $r_url + if {$is_mirror} { + set cons [console::new \ + [mc "push %s" $r_url] \ + [mc "Mirroring to %s" $r_url]] + } else { + set cnt 0 + foreach i [$w.source.l curselection] { + set b [$w.source.l get $i] + lappend cmd "refs/heads/$b:refs/heads/$b" + incr cnt + } + if {$cnt == 0} { + return + } elseif {$cnt == 1} { + set unit branch + } else { + set unit branches + } + + set cons [console::new \ + [mc "push %s" $r_url] \ + [mc "Pushing %s %s to %s" $cnt $unit $r_url]] + } + console::exec $cons $cmd + destroy $w +} + +trace add variable push_remote write \ + [list radio_selector push_urltype remote] + +proc do_push_anywhere {} { + global all_remotes current_branch + global push_urltype push_remote push_url push_thin push_tags + global push_force use_ttk NS + + set w .push_setup + toplevel $w + wm withdraw $w + wm geometry $w "+[winfo rootx .]+[winfo rooty .]" + pave_toplevel $w + + ${NS}::label $w.header -text [mc "Push Branches"] \ + -font font_uibold -anchor center + pack $w.header -side top -fill x + + ${NS}::frame $w.buttons + ${NS}::button $w.buttons.create -text [mc Push] \ + -default active \ + -command [list start_push_anywhere_action $w] + pack $w.buttons.create -side right + ${NS}::button $w.buttons.cancel -text [mc "Cancel"] \ + -default normal \ + -command [list destroy $w] + pack $w.buttons.cancel -side right -padx 5 + pack $w.buttons -side bottom -fill x -pady 10 -padx 10 + + ${NS}::labelframe $w.source -text [mc "Source Branches"] + slistbox $w.source.l \ + -height 10 \ + -width 70 \ + -selectmode extended + foreach h [load_all_heads] { + $w.source.l insert end $h + if {$h eq $current_branch} { + $w.source.l select set end ++ $w.source.l yview end + } + } + pack $w.source.l -side left -fill both -expand 1 + pack $w.source -fill both -expand 1 -pady 5 -padx 5 + + ${NS}::labelframe $w.dest -text [mc "Destination Repository"] + if {$all_remotes ne {}} { + ${NS}::radiobutton $w.dest.remote_r \ + -text [mc "Remote:"] \ + -value remote \ + -variable push_urltype + if {$use_ttk} { - ttk::combobox $w.dest.remote_m -textvariable push_remote \ ++ ttk::combobox $w.dest.remote_m -state readonly \ ++ -exportselection false \ ++ -textvariable push_remote \ + -values $all_remotes + } else { + eval tk_optionMenu $w.dest.remote_m push_remote $all_remotes + } + grid $w.dest.remote_r $w.dest.remote_m -sticky w + if {[lsearch -sorted -exact $all_remotes origin] != -1} { + set push_remote origin + } else { + set push_remote [lindex $all_remotes 0] + } + set push_urltype remote + } else { + set push_urltype url + } + ${NS}::radiobutton $w.dest.url_r \ + -text [mc "Arbitrary Location:"] \ + -value url \ + -variable push_urltype + ${NS}::entry $w.dest.url_t \ + -width 50 \ + -textvariable push_url \ + -validate key \ + -validatecommand { + if {%d == 1 && [regexp {\s} %S]} {return 0} + if {%d == 1 && [string length %S] > 0} { + set push_urltype url + } + return 1 + } + grid $w.dest.url_r $w.dest.url_t -sticky we -padx {0 5} + grid columnconfigure $w.dest 1 -weight 1 + pack $w.dest -anchor nw -fill x -pady 5 -padx 5 + + ${NS}::labelframe $w.options -text [mc "Transfer Options"] + ${NS}::checkbutton $w.options.force \ + -text [mc "Force overwrite existing branch (may discard changes)"] \ + -variable push_force + grid $w.options.force -columnspan 2 -sticky w + ${NS}::checkbutton $w.options.thin \ + -text [mc "Use thin pack (for slow network connections)"] \ + -variable push_thin + grid $w.options.thin -columnspan 2 -sticky w + ${NS}::checkbutton $w.options.tags \ + -text [mc "Include tags"] \ + -variable push_tags + grid $w.options.tags -columnspan 2 -sticky w + grid columnconfigure $w.options 1 -weight 1 + pack $w.options -anchor nw -fill x -pady 5 -padx 5 + + set push_url {} + set push_force 0 + set push_thin 0 + set push_tags 0 + + bind $w "grab $w; focus $w.buttons.create" + bind $w "destroy $w" + bind $w [list start_push_anywhere_action $w] + wm title $w [append "[appname] ([reponame]): " [mc "Push"]] + wm deiconify $w + tkwait window $w +} diff --cc git-gui/po/glossary/pt_br.po index 000000000,000000000..eb039b2b4 new file mode 100644 --- /dev/null +++ b/git-gui/po/glossary/pt_br.po @@@ -1,0 -1,0 +1,169 @@@ ++# Translation of git-gui to Brazilian Portuguese ++# Copyright (C) 2007 Shawn Pearce, et al. ++# This file is distributed under the same license as the git-gui package. ++# ++# Alexandre Erwin Ittner , 2010. ++msgid "" ++msgstr "" ++"Project-Id-Version: git-gui\n" ++"Report-Msgid-Bugs-To: \n" ++"POT-Creation-Date: 2010-01-26 15:47-0800\n" ++"PO-Revision-Date: 2010-09-18 11:09-0300\n" ++"Last-Translator: Alexandre Erwin Ittner \n" ++"Language-Team: Brazilian Portuguese <>\n" ++"MIME-Version: 1.0\n" ++"Content-Type: text/plain; charset=UTF-8\n" ++"Content-Transfer-Encoding: 8bit\n" ++ ++#. "English Definition (Dear translator: This file will never be visible to the user! It should only serve as a tool for you, the translator. Nothing more.)" ++msgid "" ++"English Term (Dear translator: This file will never be visible to the user!)" ++msgstr "" ++ ++#. "" ++msgid "amend" ++msgstr "corrigir" ++ ++#. "" ++msgid "annotate" ++msgstr "anotar" ++ ++#. "A 'branch' is an active line of development." ++msgid "branch [noun]" ++msgstr "ramo" ++ ++#. "" ++msgid "branch [verb]" ++msgstr "ramificar" ++ ++#. "" ++msgid "checkout [noun]" ++msgstr "checkout" ++ ++#. "The action of updating the working tree to a revision which was stored in the object database." ++msgid "checkout [verb]" ++msgstr "efetuar checkout" ++ ++#. "" ++msgid "clone [verb]" ++msgstr "clonar" ++ ++#. "A single point in the git history." ++msgid "commit [noun]" ++msgstr "revisão" ++ ++#. "The action of storing a new snapshot of the project's state in the git history." ++msgid "commit [verb]" ++msgstr "salvar revisão" ++ ++#. "" ++msgid "diff [noun]" ++msgstr "diff" ++ ++#. "" ++msgid "diff [verb]" ++msgstr "comparar" ++ ++#. "A fast-forward is a special type of merge where you have a revision and you are merging another branch's changes that happen to be a descendant of what you have." ++msgid "fast forward merge" ++msgstr "mesclagem rápida" ++ ++#. "Fetching a branch means to get the branch's head from a remote repository, to find out which objects are missing from the local object database, and to get them, too." ++msgid "fetch" ++msgstr "receber" ++ ++#. "One context of consecutive lines in a whole patch, which consists of many such hunks" ++msgid "hunk" ++msgstr "trecho" ++ ++#. "A collection of files. The index is a stored version of your working tree." ++msgid "index (in git-gui: staging area)" ++msgstr "índice" ++ ++#. "A successful merge results in the creation of a new commit representing the result of the merge." ++msgid "merge [noun]" ++msgstr "mesclagem" ++ ++#. "To bring the contents of another branch into the current branch." ++msgid "merge [verb]" ++msgstr "mesclar" ++ ++#. "" ++msgid "message" ++msgstr "descrição da revisão" ++ ++#. "Deletes all stale tracking branches under . These stale branches have already been removed from the remote repository referenced by , but are still locally available in 'remotes/'." ++msgid "prune" ++msgstr "limpar" ++ ++#. "Pulling a branch means to fetch it and merge it." ++msgid "pull" ++msgstr "receber e mesclar" ++ ++#. "Pushing a branch means to get the branch's head ref from a remote repository, and ... (well, can someone please explain it for mere mortals?)" ++msgid "push" ++msgstr "enviar" ++ ++#. "" ++msgid "redo" ++msgstr "refazer" ++ ++#. "An other repository ('remote'). One might have a set of remotes whose branches one tracks." ++msgid "remote" ++msgstr "repositório remoto" ++ ++#. "A collection of refs (?) together with an object database containing all objects which are reachable from the refs... (oops, you've lost me here. Again, please an explanation for mere mortals?)" ++msgid "repository" ++msgstr "repositório" ++ ++#. "" ++msgid "reset" ++msgstr "descartar, redefinir" ++ ++#. "" ++msgid "revert" ++msgstr "reverter" ++ ++#. "A particular state of files and directories which was stored in the object database." ++msgid "revision" ++msgstr "revisão" ++ ++#. "" ++msgid "sign off" ++msgstr "assinar embaixo" ++ ++#. "" ++msgid "staging area" ++msgstr "???" ++ ++#. "" ++msgid "status" ++msgstr "status" ++ ++#. "A ref pointing to a tag or commit object" ++msgid "tag [noun]" ++msgstr "etiqueta" ++ ++#. "" ++msgid "tag [verb]" ++msgstr "marcar etiqueta" ++ ++#. "A regular git branch that is used to follow changes from another repository." ++msgid "tracking branch" ++msgstr "ramo de rastreamento" ++ ++#. "" ++msgid "undo" ++msgstr "desfazer" ++ ++#. "" ++msgid "update" ++msgstr "atualizar" ++ ++#. "" ++msgid "verify" ++msgstr "verificar" ++ ++#. "The tree of actual checked out files." ++msgid "working copy, working tree" ++msgstr "cópia de trabalho, árvore de trabalho" diff --cc git-gui/po/pt_br.po index 000000000,000000000..b175b9791 new file mode 100644 --- /dev/null +++ b/git-gui/po/pt_br.po @@@ -1,0 -1,0 +1,2568 @@@ ++# Translation of git-gui to Brazilian Portuguese ++# Copyright (C) 2007 Shawn Pearce, et al. ++# This file is distributed under the same license as the git-gui package. ++# ++# Alexandre Erwin Ittner , 2010. ++msgid "" ++msgstr "" ++"Project-Id-Version: git-gui\n" ++"Report-Msgid-Bugs-To: \n" ++"POT-Creation-Date: 2010-01-26 15:47-0800\n" ++"PO-Revision-Date: 2010-09-18 11:09-0300\n" ++"Last-Translator: Alexandre Erwin Ittner \n" ++"Language-Team: Brazilian Portuguese <>\n" ++"MIME-Version: 1.0\n" ++"Content-Type: text/plain; charset=UTF-8\n" ++"Content-Transfer-Encoding: 8bit\n" ++ ++#: git-gui.sh:41 git-gui.sh:793 git-gui.sh:807 git-gui.sh:820 git-gui.sh:903 ++#: git-gui.sh:922 ++msgid "git-gui: fatal error" ++msgstr "git-gui: erro fatal" ++ ++#: git-gui.sh:743 ++#, tcl-format ++msgid "Invalid font specified in %s:" ++msgstr "Fonte inválida indicada em %s:" ++ ++#: git-gui.sh:779 ++msgid "Main Font" ++msgstr "Fonte principal" ++ ++#: git-gui.sh:780 ++msgid "Diff/Console Font" ++msgstr "Fonte para o diff/console" ++ ++#: git-gui.sh:794 ++msgid "Cannot find git in PATH." ++msgstr "Impossível encontrar o git no \"PATH\"" ++ ++#: git-gui.sh:821 ++msgid "Cannot parse Git version string:" ++msgstr "Impossível interpretar a versão do git:" ++ ++#: git-gui.sh:839 ++#, tcl-format ++msgid "" ++"Git version cannot be determined.\n" ++"\n" ++"%s claims it is version '%s'.\n" ++"\n" ++"%s requires at least Git 1.5.0 or later.\n" ++"\n" ++"Assume '%s' is version 1.5.0?\n" ++msgstr "" ++"Não foi possível determinar a versão do git:\n" ++"\n" ++"%s afirmar que sua versão é \"%s\".\n" ++"\n" ++"%s exige o Git 1.5.0 ou posterior.\n" ++"\n" ++"Assumir que '%s' é a versão 1.5.0?\n" ++ ++#: git-gui.sh:1128 ++msgid "Git directory not found:" ++msgstr "Diretório do Git não encontrado:" ++ ++#: git-gui.sh:1146 ++msgid "Cannot move to top of working directory:" ++msgstr "Impossível mover para o início do diretório de trabalho:" ++ ++#: git-gui.sh:1154 ++msgid "Cannot use bare repository:" ++msgstr "Impossível usar repositório puro:" ++ ++#: git-gui.sh:1162 ++msgid "No working directory" ++msgstr "Sem diretório de trabalho" ++ ++#: git-gui.sh:1334 lib/checkout_op.tcl:306 ++msgid "Refreshing file status..." ++msgstr "Atualizando estado dos arquivos..." ++ ++#: git-gui.sh:1390 ++msgid "Scanning for modified files ..." ++msgstr "Procurando por arquivos modificados ..." ++ ++#: git-gui.sh:1454 ++msgid "Calling prepare-commit-msg hook..." ++msgstr "Executando hook \"prepare-commit-msg\"..." ++ ++#: git-gui.sh:1471 ++msgid "Commit declined by prepare-commit-msg hook." ++msgstr "O script \"prepare-commit-msg\" negou a criação de uma nova revisão" ++ ++#: git-gui.sh:1629 lib/browser.tcl:246 ++msgid "Ready." ++msgstr "Pronto." ++ ++#: git-gui.sh:1787 ++#, tcl-format ++msgid "Displaying only %s of %s files." ++msgstr "Exibindo apenas %s de %s arquivos." ++ ++#: git-gui.sh:1913 ++msgid "Unmodified" ++msgstr "Não modificado" ++ ++#: git-gui.sh:1915 ++msgid "Modified, not staged" ++msgstr "Modificado, não marcado" ++ ++#: git-gui.sh:1916 git-gui.sh:1924 ++msgid "Staged for commit" ++msgstr "Marcado para uma nova revisão" ++ ++#: git-gui.sh:1917 git-gui.sh:1925 ++msgid "Portions staged for commit" ++msgstr "Trechos marcados para revisão" ++ ++#: git-gui.sh:1918 git-gui.sh:1926 ++msgid "Staged for commit, missing" ++msgstr "Marcado para revisão, faltando" ++ ++#: git-gui.sh:1920 ++msgid "File type changed, not staged" ++msgstr "Tipo do arquivo modificado, não marcado" ++ ++#: git-gui.sh:1921 ++msgid "File type changed, staged" ++msgstr "Tipo do arquivo modificado, marcado" ++ ++#: git-gui.sh:1923 ++msgid "Untracked, not staged" ++msgstr "Não monitorado, não marcado" ++ ++#: git-gui.sh:1928 ++msgid "Missing" ++msgstr "Faltando" ++ ++#: git-gui.sh:1929 ++msgid "Staged for removal" ++msgstr "Marcado para remoção" ++ ++#: git-gui.sh:1930 ++msgid "Staged for removal, still present" ++msgstr "Marcado para remoção, ainda presente" ++ ++#: git-gui.sh:1932 git-gui.sh:1933 git-gui.sh:1934 git-gui.sh:1935 ++#: git-gui.sh:1936 git-gui.sh:1937 ++msgid "Requires merge resolution" ++msgstr "Requer resolução de conflitos" ++ ++#: git-gui.sh:1972 ++msgid "Starting gitk... please wait..." ++msgstr "Iniciando gitk... Aguarde..." ++ ++#: git-gui.sh:1984 ++msgid "Couldn't find gitk in PATH" ++msgstr "Impossível encontrar o gitk no PATH" ++ ++#: git-gui.sh:2043 ++msgid "Couldn't find git gui in PATH" ++msgstr "Impossível encontrar o \"git gui\" no PATH" ++ ++#: git-gui.sh:2455 lib/choose_repository.tcl:36 ++msgid "Repository" ++msgstr "Repositório" ++ ++#: git-gui.sh:2456 ++msgid "Edit" ++msgstr "Editar" ++ ++#: git-gui.sh:2458 lib/choose_rev.tcl:561 ++msgid "Branch" ++msgstr "Ramo" ++ ++#: git-gui.sh:2461 lib/choose_rev.tcl:548 ++msgid "Commit@@noun" ++msgstr "Revisão" ++ ++#: git-gui.sh:2464 lib/merge.tcl:121 lib/merge.tcl:150 lib/merge.tcl:168 ++msgid "Merge" ++msgstr "Mesclar" ++ ++#: git-gui.sh:2465 lib/choose_rev.tcl:557 ++msgid "Remote" ++msgstr "Remoto" ++ ++#: git-gui.sh:2468 ++msgid "Tools" ++msgstr "Ferramentas" ++ ++#: git-gui.sh:2477 ++msgid "Explore Working Copy" ++msgstr "Explorar cópia de trabalho" ++ ++#: git-gui.sh:2483 ++msgid "Browse Current Branch's Files" ++msgstr "Explorar arquivos do ramo atual" ++ ++#: git-gui.sh:2487 ++msgid "Browse Branch Files..." ++msgstr "Explorar arquivos do ramo..." ++ ++#: git-gui.sh:2492 ++msgid "Visualize Current Branch's History" ++msgstr "Visualizar histórico do ramo atual" ++ ++#: git-gui.sh:2496 ++msgid "Visualize All Branch History" ++msgstr "Visualizar histórico de todos os ramos" ++ ++#: git-gui.sh:2503 ++#, tcl-format ++msgid "Browse %s's Files" ++msgstr "Explorar arquivos de %s" ++ ++#: git-gui.sh:2505 ++#, tcl-format ++msgid "Visualize %s's History" ++msgstr "Visualizar histórico de %s" ++ ++#: git-gui.sh:2510 lib/database.tcl:27 lib/database.tcl:67 ++msgid "Database Statistics" ++msgstr "Estatísticas do banco de dados" ++ ++#: git-gui.sh:2513 lib/database.tcl:34 ++msgid "Compress Database" ++msgstr "Compactar banco de dados" ++ ++#: git-gui.sh:2516 ++msgid "Verify Database" ++msgstr "Verificar banco de dados" ++ ++#: git-gui.sh:2523 git-gui.sh:2527 git-gui.sh:2531 lib/shortcut.tcl:8 ++#: lib/shortcut.tcl:40 lib/shortcut.tcl:72 ++msgid "Create Desktop Icon" ++msgstr "Criar ícone na área de trabalho" ++ ++#: git-gui.sh:2539 lib/choose_repository.tcl:183 lib/choose_repository.tcl:191 ++msgid "Quit" ++msgstr "Sair" ++ ++#: git-gui.sh:2547 ++msgid "Undo" ++msgstr "Desfazer" ++ ++#: git-gui.sh:2550 ++msgid "Redo" ++msgstr "Refazer" ++ ++#: git-gui.sh:2554 git-gui.sh:3109 ++msgid "Cut" ++msgstr "Recortar" ++ ++#: git-gui.sh:2557 git-gui.sh:3112 git-gui.sh:3186 git-gui.sh:3259 ++#: lib/console.tcl:69 ++msgid "Copy" ++msgstr "Copiar" ++ ++#: git-gui.sh:2560 git-gui.sh:3115 ++msgid "Paste" ++msgstr "Colar" ++ ++#: git-gui.sh:2563 git-gui.sh:3118 lib/branch_delete.tcl:26 ++#: lib/remote_branch_delete.tcl:38 ++msgid "Delete" ++msgstr "Apagar" ++ ++#: git-gui.sh:2567 git-gui.sh:3122 git-gui.sh:3263 lib/console.tcl:71 ++msgid "Select All" ++msgstr "Selecionar tudo" ++ ++#: git-gui.sh:2576 ++msgid "Create..." ++msgstr "Criar..." ++ ++#: git-gui.sh:2582 ++msgid "Checkout..." ++msgstr "Checkout..." ++ ++#: git-gui.sh:2588 ++msgid "Rename..." ++msgstr "Renomear..." ++ ++#: git-gui.sh:2593 ++msgid "Delete..." ++msgstr "Apagar..." ++ ++#: git-gui.sh:2598 ++msgid "Reset..." ++msgstr "Redefinir..." ++ ++#: git-gui.sh:2608 ++msgid "Done" ++msgstr "Pronto" ++ ++#: git-gui.sh:2610 ++msgid "Commit@@verb" ++msgstr "Salvar revisão" ++ ++#: git-gui.sh:2619 git-gui.sh:3050 ++msgid "New Commit" ++msgstr "Nova revisão" ++ ++#: git-gui.sh:2627 git-gui.sh:3057 ++msgid "Amend Last Commit" ++msgstr "Corrigir última revisão" ++ ++#: git-gui.sh:2637 git-gui.sh:3011 lib/remote_branch_delete.tcl:99 ++msgid "Rescan" ++msgstr "Atualizar" ++ ++#: git-gui.sh:2643 ++msgid "Stage To Commit" ++msgstr "Marcar para revisão" ++ ++#: git-gui.sh:2649 ++msgid "Stage Changed Files To Commit" ++msgstr "Marcar arquivos modificados" ++ ++#: git-gui.sh:2655 ++msgid "Unstage From Commit" ++msgstr "Desmarcar" ++ ++#: git-gui.sh:2661 lib/index.tcl:412 ++msgid "Revert Changes" ++msgstr "Reverter mudanças" ++ ++#: git-gui.sh:2669 git-gui.sh:3310 git-gui.sh:3341 ++msgid "Show Less Context" ++msgstr "Mostrar menos contexto" ++ ++#: git-gui.sh:2673 git-gui.sh:3314 git-gui.sh:3345 ++msgid "Show More Context" ++msgstr "Mostrar mais contexto" ++ ++#: git-gui.sh:2680 git-gui.sh:3024 git-gui.sh:3133 ++msgid "Sign Off" ++msgstr "Assinar embaixo" ++ ++#: git-gui.sh:2696 ++msgid "Local Merge..." ++msgstr "Mesclar localmente..." ++ ++#: git-gui.sh:2701 ++msgid "Abort Merge..." ++msgstr "Abortar mesclagem..." ++ ++#: git-gui.sh:2713 git-gui.sh:2741 ++msgid "Add..." ++msgstr "Adicionar..." ++ ++#: git-gui.sh:2717 ++msgid "Push..." ++msgstr "Enviar..." ++ ++#: git-gui.sh:2721 ++msgid "Delete Branch..." ++msgstr "Apagar ramo..." ++ ++#: git-gui.sh:2731 git-gui.sh:3292 ++msgid "Options..." ++msgstr "Opções..." ++ ++#: git-gui.sh:2742 ++msgid "Remove..." ++msgstr "Remover..." ++ ++#: git-gui.sh:2751 lib/choose_repository.tcl:50 ++msgid "Help" ++msgstr "Ajuda" ++ ++#: git-gui.sh:2755 git-gui.sh:2759 lib/about.tcl:14 ++#: lib/choose_repository.tcl:44 lib/choose_repository.tcl:53 ++#, tcl-format ++msgid "About %s" ++msgstr "Sobre o %s" ++ ++#: git-gui.sh:2783 ++msgid "Online Documentation" ++msgstr "Ajuda online" ++ ++#: git-gui.sh:2786 lib/choose_repository.tcl:47 lib/choose_repository.tcl:56 ++msgid "Show SSH Key" ++msgstr "Mostrar chave SSH" ++ ++#: git-gui.sh:2893 ++#, tcl-format ++msgid "fatal: cannot stat path %s: No such file or directory" ++msgstr "" ++"erro fatal: impossível executar \"stat\" em %s: Arquivo ou diretório não " ++"encontrado" ++ ++#: git-gui.sh:2926 ++msgid "Current Branch:" ++msgstr "Ramo atual:" ++ ++#: git-gui.sh:2947 ++msgid "Staged Changes (Will Commit)" ++msgstr "Mudanças marcadas" ++ ++#: git-gui.sh:2967 ++msgid "Unstaged Changes" ++msgstr "Mudanças não marcadas" ++ ++#: git-gui.sh:3017 ++msgid "Stage Changed" ++msgstr "Marcar alterados" ++ ++#: git-gui.sh:3036 lib/transport.tcl:104 lib/transport.tcl:193 ++msgid "Push" ++msgstr "Enviar" ++ ++#: git-gui.sh:3071 ++msgid "Initial Commit Message:" ++msgstr "Descrição da revisão inicial:" ++ ++#: git-gui.sh:3072 ++msgid "Amended Commit Message:" ++msgstr "Descrição da revisão corrigida:" ++ ++#: git-gui.sh:3073 ++msgid "Amended Initial Commit Message:" ++msgstr "Descrição da revisão inicial corrigida:" ++ ++#: git-gui.sh:3074 ++msgid "Amended Merge Commit Message:" ++msgstr "Descrição da revisão de mescla corrigida:" ++ ++#: git-gui.sh:3075 ++msgid "Merge Commit Message:" ++msgstr "Descrição da revisão de mescla:" ++ ++#: git-gui.sh:3076 ++msgid "Commit Message:" ++msgstr "Descrição da revisão:" ++ ++#: git-gui.sh:3125 git-gui.sh:3267 lib/console.tcl:73 ++msgid "Copy All" ++msgstr "Copiar todos" ++ ++#: git-gui.sh:3149 lib/blame.tcl:104 ++msgid "File:" ++msgstr "Arquivo:" ++ ++#: git-gui.sh:3255 ++msgid "Refresh" ++msgstr "Atualizar" ++ ++#: git-gui.sh:3276 ++msgid "Decrease Font Size" ++msgstr "Reduzir tamanho da fonte" ++ ++#: git-gui.sh:3280 ++msgid "Increase Font Size" ++msgstr "Aumentar tamanho da fonte" ++ ++#: git-gui.sh:3288 lib/blame.tcl:281 ++msgid "Encoding" ++msgstr "Codificação" ++ ++#: git-gui.sh:3299 ++msgid "Apply/Reverse Hunk" ++msgstr "Aplicar/reverter trecho" ++ ++#: git-gui.sh:3304 ++msgid "Apply/Reverse Line" ++msgstr "Aplicar/reverter linha" ++ ++#: git-gui.sh:3323 ++msgid "Run Merge Tool" ++msgstr "Executar ferramenta de mescla" ++ ++#: git-gui.sh:3328 ++msgid "Use Remote Version" ++msgstr "Usar versão remota" ++ ++#: git-gui.sh:3332 ++msgid "Use Local Version" ++msgstr "Usar versão local" ++ ++#: git-gui.sh:3336 ++msgid "Revert To Base" ++msgstr "Reverter para a versão-base" ++ ++#: git-gui.sh:3354 ++msgid "Visualize These Changes In The Submodule" ++msgstr "Visualizar estas mudanças no sub-módulo" ++ ++#: git-gui.sh:3358 ++msgid "Visualize Current Branch History In The Submodule" ++msgstr "Visualizar histórico do ramo atual no sub-módulo" ++ ++#: git-gui.sh:3362 ++msgid "Visualize All Branch History In The Submodule" ++msgstr "Visualizar histórico de todos os camos no sub-módulo" ++ ++#: git-gui.sh:3367 ++msgid "Start git gui In The Submodule" ++msgstr "Iniciar \"git gui\" no sub-módulo" ++ ++#: git-gui.sh:3389 ++msgid "Unstage Hunk From Commit" ++msgstr "Desmarcar trecho para revisão" ++ ++#: git-gui.sh:3391 ++msgid "Unstage Lines From Commit" ++msgstr "Desmarcar linhas para revisão" ++ ++#: git-gui.sh:3393 ++msgid "Unstage Line From Commit" ++msgstr "Desmarcar linha para revisão" ++ ++#: git-gui.sh:3396 ++msgid "Stage Hunk For Commit" ++msgstr "Marcar trecho para revisão" ++ ++#: git-gui.sh:3398 ++msgid "Stage Lines For Commit" ++msgstr "Marcar linhas para revisão" ++ ++#: git-gui.sh:3400 ++msgid "Stage Line For Commit" ++msgstr "Marcar linha para revisão" ++ ++#: git-gui.sh:3424 ++msgid "Initializing..." ++msgstr "Iniciando..." ++ ++#: git-gui.sh:3541 ++#, tcl-format ++msgid "" ++"Possible environment issues exist.\n" ++"\n" ++"The following environment variables are probably\n" ++"going to be ignored by any Git subprocess run\n" ++"by %s:\n" ++"\n" ++msgstr "" ++"Possíveis problemas com as variáveis de ambiente.\n" ++"\n" ++"As seguintes variáveis de ambiente provavelmente serão\n" ++"ignoradas por qualquer sub-processo do Git executado por\n" ++"%s:\n" ++ ++#: git-gui.sh:3570 ++msgid "" ++"\n" ++"This is due to a known issue with the\n" ++"Tcl binary distributed by Cygwin." ++msgstr "" ++"\n" ++"Isto se deve a um problema conhecido com os binários da Tcl \n" ++"distribuídos com o Cygwin" ++ ++#: git-gui.sh:3575 ++#, tcl-format ++msgid "" ++"\n" ++"\n" ++"A good replacement for %s\n" ++"is placing values for the user.name and\n" ++"user.email settings into your personal\n" ++"~/.gitconfig file.\n" ++msgstr "" ++"\n" ++"\n" ++"Uma boa alternativa para %s\n" ++"é colocar os valores para o nome de usuário e e-mail\n" ++"no seu arquivo \"~/.gitconfig\"\n" ++ ++#: lib/about.tcl:26 ++msgid "git-gui - a graphical user interface for Git." ++msgstr "git-gui - uma interface gráfica para o Git" ++ ++#: lib/blame.tcl:72 ++msgid "File Viewer" ++msgstr "Visualizador de arquivos" ++ ++#: lib/blame.tcl:78 ++msgid "Commit:" ++msgstr "Revisão:" ++ ++#: lib/blame.tcl:271 ++msgid "Copy Commit" ++msgstr "Copiar revisão" ++ ++#: lib/blame.tcl:275 ++msgid "Find Text..." ++msgstr "Procurar texto..." ++ ++#: lib/blame.tcl:284 ++msgid "Do Full Copy Detection" ++msgstr "Executar detecção completa de cópias" ++ ++#: lib/blame.tcl:288 ++msgid "Show History Context" ++msgstr "Mostrar contexto do histórico" ++ ++#: lib/blame.tcl:291 ++msgid "Blame Parent Commit" ++msgstr "Anotar revisão anterior" ++ ++#: lib/blame.tcl:450 ++#, tcl-format ++msgid "Reading %s..." ++msgstr "Lendo %s..." ++ ++#: lib/blame.tcl:557 ++msgid "Loading copy/move tracking annotations..." ++msgstr "Carregando anotações de cópia/movimentação..." ++ ++#: lib/blame.tcl:577 ++msgid "lines annotated" ++msgstr "linhas anotadas" ++ ++#: lib/blame.tcl:769 ++msgid "Loading original location annotations..." ++msgstr "Carregando anotações originais..." ++ ++#: lib/blame.tcl:772 ++msgid "Annotation complete." ++msgstr "Anotação completa." ++ ++#: lib/blame.tcl:802 ++msgid "Busy" ++msgstr "Ocupado" ++ ++#: lib/blame.tcl:803 ++msgid "Annotation process is already running." ++msgstr "O processo de anotação já está em execução" ++ ++#: lib/blame.tcl:842 ++msgid "Running thorough copy detection..." ++msgstr "Executando detecção de cópia..." ++ ++#: lib/blame.tcl:910 ++msgid "Loading annotation..." ++msgstr "Carregando anotações..." ++ ++#: lib/blame.tcl:963 ++msgid "Author:" ++msgstr "Autor:" ++ ++#: lib/blame.tcl:967 ++msgid "Committer:" ++msgstr "Revisor:" ++ ++#: lib/blame.tcl:972 ++msgid "Original File:" ++msgstr "Arquivo original:" ++ ++#: lib/blame.tcl:1020 ++msgid "Cannot find HEAD commit:" ++msgstr "Impossível encontrar revisão HEAD:" ++ ++#: lib/blame.tcl:1075 ++msgid "Cannot find parent commit:" ++msgstr "Impossível encontrar revisão anterior:" ++ ++#: lib/blame.tcl:1090 ++msgid "Unable to display parent" ++msgstr "Impossível exibir revisão anterior" ++ ++#: lib/blame.tcl:1091 lib/diff.tcl:320 ++msgid "Error loading diff:" ++msgstr "Erro ao carregar as diferenças:" ++ ++#: lib/blame.tcl:1231 ++msgid "Originally By:" ++msgstr "Originalmente por:" ++ ++#: lib/blame.tcl:1237 ++msgid "In File:" ++msgstr "No arquivo:" ++ ++#: lib/blame.tcl:1242 ++msgid "Copied Or Moved Here By:" ++msgstr "Copiado ou movido para cá por:" ++ ++#: lib/branch_checkout.tcl:14 lib/branch_checkout.tcl:19 ++msgid "Checkout Branch" ++msgstr "Efetuar checkout do ramo" ++ ++#: lib/branch_checkout.tcl:23 ++msgid "Checkout" ++msgstr "Checkout" ++ ++#: lib/branch_checkout.tcl:27 lib/branch_create.tcl:35 ++#: lib/branch_delete.tcl:32 lib/branch_rename.tcl:30 lib/browser.tcl:282 ++#: lib/checkout_op.tcl:579 lib/choose_font.tcl:43 lib/merge.tcl:172 ++#: lib/option.tcl:125 lib/remote_add.tcl:32 lib/remote_branch_delete.tcl:42 ++#: lib/tools_dlg.tcl:40 lib/tools_dlg.tcl:204 lib/tools_dlg.tcl:352 ++#: lib/transport.tcl:108 ++msgid "Cancel" ++msgstr "Cancelar" ++ ++#: lib/branch_checkout.tcl:32 lib/browser.tcl:287 lib/tools_dlg.tcl:328 ++msgid "Revision" ++msgstr "Revisão" ++ ++#: lib/branch_checkout.tcl:36 lib/branch_create.tcl:69 lib/option.tcl:280 ++msgid "Options" ++msgstr "Opções" ++ ++#: lib/branch_checkout.tcl:39 lib/branch_create.tcl:92 ++msgid "Fetch Tracking Branch" ++msgstr "Obter ramo de rastreamento" ++ ++#: lib/branch_checkout.tcl:44 ++msgid "Detach From Local Branch" ++msgstr "Separar do ramo local" ++ ++#: lib/branch_create.tcl:22 ++msgid "Create Branch" ++msgstr "Criar ramo" ++ ++#: lib/branch_create.tcl:27 ++msgid "Create New Branch" ++msgstr "Criar novo ramo" ++ ++#: lib/branch_create.tcl:31 lib/choose_repository.tcl:381 ++msgid "Create" ++msgstr "Criar" ++ ++#: lib/branch_create.tcl:40 ++msgid "Branch Name" ++msgstr "Nome do ramo" ++ ++#: lib/branch_create.tcl:43 lib/remote_add.tcl:39 lib/tools_dlg.tcl:50 ++msgid "Name:" ++msgstr "Nome:" ++ ++#: lib/branch_create.tcl:58 ++msgid "Match Tracking Branch Name" ++msgstr "Coincidir nome do ramo de rastreamento" ++ ++#: lib/branch_create.tcl:66 ++msgid "Starting Revision" ++msgstr "Revisão inicial" ++ ++#: lib/branch_create.tcl:72 ++msgid "Update Existing Branch:" ++msgstr "Atualizar ramo existente:" ++ ++#: lib/branch_create.tcl:75 ++msgid "No" ++msgstr "Não" ++ ++#: lib/branch_create.tcl:80 ++msgid "Fast Forward Only" ++msgstr "Somente se for um avanço rápido" ++ ++#: lib/branch_create.tcl:85 lib/checkout_op.tcl:571 ++msgid "Reset" ++msgstr "Redefinir" ++ ++#: lib/branch_create.tcl:97 ++msgid "Checkout After Creation" ++msgstr "Efetuar checkout após a criação" ++ ++#: lib/branch_create.tcl:131 ++msgid "Please select a tracking branch." ++msgstr "Selecione um ramo de rastreamento." ++ ++#: lib/branch_create.tcl:140 ++#, tcl-format ++msgid "Tracking branch %s is not a branch in the remote repository." ++msgstr "O ramo de rastreamento %s não é um ramo do repositório remoto." ++ ++#: lib/branch_create.tcl:153 lib/branch_rename.tcl:86 ++msgid "Please supply a branch name." ++msgstr "Indique um nome para o ramo." ++ ++#: lib/branch_create.tcl:164 lib/branch_rename.tcl:106 ++#, tcl-format ++msgid "'%s' is not an acceptable branch name." ++msgstr "\"%s\" não é um nome de ramo válido" ++ ++#: lib/branch_delete.tcl:15 ++msgid "Delete Branch" ++msgstr "Apagar ramo" ++ ++#: lib/branch_delete.tcl:20 ++msgid "Delete Local Branch" ++msgstr "Apagar ramo local" ++ ++#: lib/branch_delete.tcl:37 ++msgid "Local Branches" ++msgstr "Ramos locais" ++ ++#: lib/branch_delete.tcl:52 ++msgid "Delete Only If Merged Into" ++msgstr "Apagar somente se mesclado em" ++ ++#: lib/branch_delete.tcl:54 lib/remote_branch_delete.tcl:119 ++msgid "Always (Do not perform merge checks)" ++msgstr "Forçar exclusão (não verificar se o ramo foi mesclado)" ++ ++#: lib/branch_delete.tcl:103 ++#, tcl-format ++msgid "The following branches are not completely merged into %s:" ++msgstr "Os ramos seguintes não foram completamente mesclados em %s:" ++ ++#: lib/branch_delete.tcl:115 lib/remote_branch_delete.tcl:217 ++msgid "" ++"Recovering deleted branches is difficult.\n" ++"\n" ++"Delete the selected branches?" ++msgstr "" ++"Recuperar ramos apagados é difícil.\n" ++"\n" ++"Apagar os ramos selecionados?" ++ ++#: lib/branch_delete.tcl:141 ++#, tcl-format ++msgid "" ++"Failed to delete branches:\n" ++"%s" ++msgstr "" ++"Erro ao apagar ramos:\n" ++"%s" ++ ++#: lib/branch_rename.tcl:14 lib/branch_rename.tcl:22 ++msgid "Rename Branch" ++msgstr "Renomear ramo" ++ ++#: lib/branch_rename.tcl:26 ++msgid "Rename" ++msgstr "Renomear" ++ ++#: lib/branch_rename.tcl:36 ++msgid "Branch:" ++msgstr "Ramo:" ++ ++#: lib/branch_rename.tcl:39 ++msgid "New Name:" ++msgstr "Novo nome:" ++ ++#: lib/branch_rename.tcl:75 ++msgid "Please select a branch to rename." ++msgstr "Selecione um ramo para renomear." ++ ++#: lib/branch_rename.tcl:96 lib/checkout_op.tcl:202 ++#, tcl-format ++msgid "Branch '%s' already exists." ++msgstr "O ramo \"%s\" já existe." ++ ++#: lib/branch_rename.tcl:117 ++#, tcl-format ++msgid "Failed to rename '%s'." ++msgstr "Erro ao renomear \"%s\"." ++ ++#: lib/browser.tcl:17 ++msgid "Starting..." ++msgstr "Inciando..." ++ ++#: lib/browser.tcl:26 ++msgid "File Browser" ++msgstr "Navegador de arquivos" ++ ++#: lib/browser.tcl:126 lib/browser.tcl:143 ++#, tcl-format ++msgid "Loading %s..." ++msgstr "Carregando %s..." ++ ++#: lib/browser.tcl:187 ++msgid "[Up To Parent]" ++msgstr "[Subir]" ++ ++#: lib/browser.tcl:267 lib/browser.tcl:273 ++msgid "Browse Branch Files" ++msgstr "Explorar arquivos do ramo" ++ ++#: lib/browser.tcl:278 lib/choose_repository.tcl:398 ++#: lib/choose_repository.tcl:486 lib/choose_repository.tcl:497 ++#: lib/choose_repository.tcl:1028 ++msgid "Browse" ++msgstr "Explorar" ++ ++#: lib/checkout_op.tcl:85 ++#, tcl-format ++msgid "Fetching %s from %s" ++msgstr "Obtendo %s de %s" ++ ++#: lib/checkout_op.tcl:133 ++#, tcl-format ++msgid "fatal: Cannot resolve %s" ++msgstr "Erro fatal: impossível resolver %s" ++ ++#: lib/checkout_op.tcl:146 lib/console.tcl:81 lib/database.tcl:31 ++#: lib/sshkey.tcl:53 ++msgid "Close" ++msgstr "Fechar" ++ ++#: lib/checkout_op.tcl:175 ++#, tcl-format ++msgid "Branch '%s' does not exist." ++msgstr "O ramo \"%s\" não existe." ++ ++#: lib/checkout_op.tcl:194 ++#, tcl-format ++msgid "Failed to configure simplified git-pull for '%s'." ++msgstr "Erro ao configurar git-pull simplificado para \"%s\"." ++ ++#: lib/checkout_op.tcl:229 ++#, tcl-format ++msgid "" ++"Branch '%s' already exists.\n" ++"\n" ++"It cannot fast-forward to %s.\n" ++"A merge is required." ++msgstr "" ++"O ramo \"%s\" já existe.\n" ++"\n" ++"Não é possível avançá-lo para %s.\n" ++"É preciso mesclar." ++ ++#: lib/checkout_op.tcl:243 ++#, tcl-format ++msgid "Merge strategy '%s' not supported." ++msgstr "Estratégia de mesclagem \"%s\" não suportada." ++ ++#: lib/checkout_op.tcl:262 ++#, tcl-format ++msgid "Failed to update '%s'." ++msgstr "Erro ao atualizar \"%s\"." ++ ++#: lib/checkout_op.tcl:274 ++msgid "Staging area (index) is already locked." ++msgstr "A área de marcação (staging area, index) já está bloqueada." ++ ++#: lib/checkout_op.tcl:289 ++msgid "" ++"Last scanned state does not match repository state.\n" ++"\n" ++"Another Git program has modified this repository since the last scan. A " ++"rescan must be performed before the current branch can be changed.\n" ++"\n" ++"The rescan will be automatically started now.\n" ++msgstr "" ++"O último estado lido não confere com o estado atual.\n" ++"\n" ++"Outro programa do Git modificou o repositório desde a última leitura. Uma " ++"atualização deve ser executada antes de alterar o ramo atual.\n" ++"\n" ++"A atualização começará automaticamente agora.\n" ++ ++#: lib/checkout_op.tcl:345 ++#, tcl-format ++msgid "Updating working directory to '%s'..." ++msgstr "Atualizando diretório de trabalho para \"%s\"..." ++ ++#: lib/checkout_op.tcl:346 ++msgid "files checked out" ++msgstr "arquivos retirados" ++ ++#: lib/checkout_op.tcl:376 ++#, tcl-format ++msgid "Aborted checkout of '%s' (file level merging is required)." ++msgstr "Checkout de \"%s\" abortado (é preciso mesclar alguns arquivos)" ++ ++#: lib/checkout_op.tcl:377 ++msgid "File level merge required." ++msgstr "Mesclagem de arquivos necessária." ++ ++#: lib/checkout_op.tcl:381 ++#, tcl-format ++msgid "Staying on branch '%s'." ++msgstr "Permanecendo no ramo \"%s\"." ++ ++#: lib/checkout_op.tcl:452 ++msgid "" ++"You are no longer on a local branch.\n" ++"\n" ++"If you wanted to be on a branch, create one now starting from 'This Detached " ++"Checkout'." ++msgstr "" ++"Você não está mais em um ramo local\n" ++"\n" ++"Se você deseja um ramo, crie um agora a partir deste checkout." ++ ++#: lib/checkout_op.tcl:503 lib/checkout_op.tcl:507 ++#, tcl-format ++msgid "Checked out '%s'." ++msgstr "Checkout de \"%s\" concluído." ++ ++#: lib/checkout_op.tcl:535 ++#, tcl-format ++msgid "Resetting '%s' to '%s' will lose the following commits:" ++msgstr "Redefinir \"%s\" para \"%s\" provocará a perda das seguintes revisões:" ++ ++#: lib/checkout_op.tcl:557 ++msgid "Recovering lost commits may not be easy." ++msgstr "Recuperar revisões perdidas pode não ser fácil." ++ ++#: lib/checkout_op.tcl:562 ++#, tcl-format ++msgid "Reset '%s'?" ++msgstr "Redefinir \"%s\"?" ++ ++#: lib/checkout_op.tcl:567 lib/merge.tcl:164 lib/tools_dlg.tcl:343 ++msgid "Visualize" ++msgstr "Visualizar" ++ ++#: lib/checkout_op.tcl:635 ++#, tcl-format ++msgid "" ++"Failed to set current branch.\n" ++"\n" ++"This working directory is only partially switched. We successfully updated " ++"your files, but failed to update an internal Git file.\n" ++"\n" ++"This should not have occurred. %s will now close and give up." ++msgstr "" ++"Erro ao definir o ramo atual.\n" ++"\n" ++"Este diretório de trabalho está incompleto. Foi possível atualizar seus " ++"arquivos, mas houve uma falha ao atualizar os arquivos internos do Git.\n" ++"\n" ++"Isto não deveria ter acontecido, %s terminará agora." ++ ++#: lib/choose_font.tcl:39 ++msgid "Select" ++msgstr "Selecionar" ++ ++#: lib/choose_font.tcl:53 ++msgid "Font Family" ++msgstr "Tipo da fonte" ++ ++#: lib/choose_font.tcl:74 ++msgid "Font Size" ++msgstr "Tamanho da fonte" ++ ++#: lib/choose_font.tcl:91 ++msgid "Font Example" ++msgstr "Exemplo" ++ ++#: lib/choose_font.tcl:103 ++msgid "" ++"This is example text.\n" ++"If you like this text, it can be your font." ++msgstr "" ++"Este é um texto de exemplo.\n" ++"Se você gostar deste texto, esta pode ser sua fonte." ++ ++#: lib/choose_repository.tcl:28 ++msgid "Git Gui" ++msgstr "Git Gui" ++ ++#: lib/choose_repository.tcl:87 lib/choose_repository.tcl:386 ++msgid "Create New Repository" ++msgstr "Criar novo repositório" ++ ++#: lib/choose_repository.tcl:93 ++msgid "New..." ++msgstr "Novo..." ++ ++#: lib/choose_repository.tcl:100 lib/choose_repository.tcl:471 ++msgid "Clone Existing Repository" ++msgstr "Clonar repositório existente" ++ ++#: lib/choose_repository.tcl:106 ++msgid "Clone..." ++msgstr "Clonar..." ++ ++#: lib/choose_repository.tcl:113 lib/choose_repository.tcl:1016 ++msgid "Open Existing Repository" ++msgstr "Abrir repositório existente" ++ ++#: lib/choose_repository.tcl:119 ++msgid "Open..." ++msgstr "Abrir..." ++ ++#: lib/choose_repository.tcl:132 ++msgid "Recent Repositories" ++msgstr "Repositórios recentes" ++ ++#: lib/choose_repository.tcl:138 ++msgid "Open Recent Repository:" ++msgstr "Abrir repositório recente:" ++ ++#: lib/choose_repository.tcl:306 lib/choose_repository.tcl:313 ++#: lib/choose_repository.tcl:320 ++#, tcl-format ++msgid "Failed to create repository %s:" ++msgstr "Erro ao criar repositório %s:" ++ ++#: lib/choose_repository.tcl:391 ++msgid "Directory:" ++msgstr "Diretório:" ++ ++#: lib/choose_repository.tcl:423 lib/choose_repository.tcl:550 ++#: lib/choose_repository.tcl:1052 ++msgid "Git Repository" ++msgstr "Repositório Git" ++ ++#: lib/choose_repository.tcl:448 ++#, tcl-format ++msgid "Directory %s already exists." ++msgstr "O diretório %s já existe." ++ ++#: lib/choose_repository.tcl:452 ++#, tcl-format ++msgid "File %s already exists." ++msgstr "O arquivo %s já existe." ++ ++#: lib/choose_repository.tcl:466 ++msgid "Clone" ++msgstr "Clonar" ++ ++#: lib/choose_repository.tcl:479 ++msgid "Source Location:" ++msgstr "Origem:" ++ ++#: lib/choose_repository.tcl:490 ++msgid "Target Directory:" ++msgstr "Diretório de destino:" ++ ++#: lib/choose_repository.tcl:502 ++msgid "Clone Type:" ++msgstr "Tipo de clonagem:" ++ ++#: lib/choose_repository.tcl:508 ++msgid "Standard (Fast, Semi-Redundant, Hardlinks)" ++msgstr "Padrão (rápida, semi-redundante, com hardlinks)" ++ ++#: lib/choose_repository.tcl:514 ++msgid "Full Copy (Slower, Redundant Backup)" ++msgstr "Cópia completa (mais lenta, backup redundante)" ++ ++#: lib/choose_repository.tcl:520 ++msgid "Shared (Fastest, Not Recommended, No Backup)" ++msgstr "Compartilhada (A mais rápida, não recomendada, sem backup)" ++ ++#: lib/choose_repository.tcl:556 lib/choose_repository.tcl:603 ++#: lib/choose_repository.tcl:749 lib/choose_repository.tcl:819 ++#: lib/choose_repository.tcl:1058 lib/choose_repository.tcl:1066 ++#, tcl-format ++msgid "Not a Git repository: %s" ++msgstr "Este não é um repositório do Git: %s" ++ ++#: lib/choose_repository.tcl:592 ++msgid "Standard only available for local repository." ++msgstr "Clonagens padrões só são possíveis em repositórios locais." ++ ++#: lib/choose_repository.tcl:596 ++msgid "Shared only available for local repository." ++msgstr "Clonagens parciais só são possíveis em repositórios locais." ++ ++#: lib/choose_repository.tcl:617 ++#, tcl-format ++msgid "Location %s already exists." ++msgstr "O local %s já existe." ++ ++#: lib/choose_repository.tcl:628 ++msgid "Failed to configure origin" ++msgstr "Erro ao configurar origem" ++ ++#: lib/choose_repository.tcl:640 ++msgid "Counting objects" ++msgstr "Contando objetos" ++ ++#: lib/choose_repository.tcl:641 ++msgid "buckets" ++msgstr "buckets" ++ ++#: lib/choose_repository.tcl:665 ++#, tcl-format ++msgid "Unable to copy objects/info/alternates: %s" ++msgstr "Erro ao copiar objetos ou informações adicionais: %s" ++ ++#: lib/choose_repository.tcl:701 ++#, tcl-format ++msgid "Nothing to clone from %s." ++msgstr "Não há nada para clonar em %s." ++ ++#: lib/choose_repository.tcl:703 lib/choose_repository.tcl:917 ++#: lib/choose_repository.tcl:929 ++msgid "The 'master' branch has not been initialized." ++msgstr "O ramo \"master\" não foi inicializado." ++ ++#: lib/choose_repository.tcl:716 ++msgid "Hardlinks are unavailable. Falling back to copying." ++msgstr "Não foi possível criar hardlinks, usando cópias convencionais." ++ ++#: lib/choose_repository.tcl:728 ++#, tcl-format ++msgid "Cloning from %s" ++msgstr "Clonando de %s" ++ ++#: lib/choose_repository.tcl:759 ++msgid "Copying objects" ++msgstr "Copiando objetos" ++ ++#: lib/choose_repository.tcl:760 ++msgid "KiB" ++msgstr "KiB" ++ ++#: lib/choose_repository.tcl:784 ++#, tcl-format ++msgid "Unable to copy object: %s" ++msgstr "Não foi possível copiar o objeto: %s" ++ ++#: lib/choose_repository.tcl:794 ++msgid "Linking objects" ++msgstr "Ligando objetos" ++ ++#: lib/choose_repository.tcl:795 ++msgid "objects" ++msgstr "objetos" ++ ++#: lib/choose_repository.tcl:803 ++#, tcl-format ++msgid "Unable to hardlink object: %s" ++msgstr "Não foi possível ligar o objeto: %s" ++ ++#: lib/choose_repository.tcl:858 ++msgid "Cannot fetch branches and objects. See console output for details." ++msgstr "" ++"Não foi possível receber ramos ou objetos. Veja a saída do console para " ++"detalhes." ++ ++#: lib/choose_repository.tcl:869 ++msgid "Cannot fetch tags. See console output for details." ++msgstr "" ++"Não foi possível receber as etiquetas. Veja a saída do console para detalhes." ++ ++#: lib/choose_repository.tcl:893 ++msgid "Cannot determine HEAD. See console output for details." ++msgstr "" ++"Não foi possível determinar a etiqueta HEAD. Veja a saída do console para " ++"detalhes." ++ ++#: lib/choose_repository.tcl:902 ++#, tcl-format ++msgid "Unable to cleanup %s" ++msgstr "Não foi possível limpar %s" ++ ++#: lib/choose_repository.tcl:908 ++msgid "Clone failed." ++msgstr "A clonagem falhou." ++ ++#: lib/choose_repository.tcl:915 ++msgid "No default branch obtained." ++msgstr "O ramo padrão não foi recebido." ++ ++#: lib/choose_repository.tcl:926 ++#, tcl-format ++msgid "Cannot resolve %s as a commit." ++msgstr "Não foi possível resolver %s como uma revisão." ++ ++#: lib/choose_repository.tcl:938 ++msgid "Creating working directory" ++msgstr "Criando diretório de trabalho." ++ ++#: lib/choose_repository.tcl:939 lib/index.tcl:67 lib/index.tcl:130 ++#: lib/index.tcl:198 ++msgid "files" ++msgstr "arquivos" ++ ++#: lib/choose_repository.tcl:968 ++msgid "Initial file checkout failed." ++msgstr "Erro ao efetuar checkout inicial." ++ ++#: lib/choose_repository.tcl:1011 ++msgid "Open" ++msgstr "Abrir" ++ ++#: lib/choose_repository.tcl:1021 ++msgid "Repository:" ++msgstr "Repositório:" ++ ++#: lib/choose_repository.tcl:1072 ++#, tcl-format ++msgid "Failed to open repository %s:" ++msgstr "Erro ao abrir o repositório %s:" ++ ++#: lib/choose_rev.tcl:53 ++msgid "This Detached Checkout" ++msgstr "Este checkout" ++ ++#: lib/choose_rev.tcl:60 ++msgid "Revision Expression:" ++msgstr "Expressão de revisão:" ++ ++#: lib/choose_rev.tcl:74 ++msgid "Local Branch" ++msgstr "Ramo local" ++ ++#: lib/choose_rev.tcl:79 ++msgid "Tracking Branch" ++msgstr "Ramo de rastreamento" ++ ++#: lib/choose_rev.tcl:84 lib/choose_rev.tcl:538 ++msgid "Tag" ++msgstr "Etiqueta" ++ ++#: lib/choose_rev.tcl:317 ++#, tcl-format ++msgid "Invalid revision: %s" ++msgstr "Revisão inválida: %s" ++ ++#: lib/choose_rev.tcl:338 ++msgid "No revision selected." ++msgstr "Nenhuma revisão selecionada." ++ ++#: lib/choose_rev.tcl:346 ++msgid "Revision expression is empty." ++msgstr "A expressão de revisão está vazia." ++ ++#: lib/choose_rev.tcl:531 ++msgid "Updated" ++msgstr "Atualizado" ++ ++#: lib/choose_rev.tcl:559 ++msgid "URL" ++msgstr "URL" ++ ++#: lib/commit.tcl:9 ++msgid "" ++"There is nothing to amend.\n" ++"\n" ++"You are about to create the initial commit. There is no commit before this " ++"to amend.\n" ++msgstr "" ++"Não há nada para corrigir.\n" ++"\n" ++"Você está prestes a criar uma revisão inicial. Não há revisão anterior para " ++"corrigir.\n" ++ ++#: lib/commit.tcl:18 ++msgid "" ++"Cannot amend while merging.\n" ++"\n" ++"You are currently in the middle of a merge that has not been fully " ++"completed. You cannot amend the prior commit unless you first abort the " ++"current merge activity.\n" ++msgstr "" ++"Não é possível corrigir durante uma mesclagem.\n" ++"\n" ++"Você está em meio a uma operação de mesclagem que não foi completada. Não é " ++"possível corrigir a revisão anterior a menos que você aborte a mescla atual " ++"antes.\n" ++ ++#: lib/commit.tcl:48 ++msgid "Error loading commit data for amend:" ++msgstr "Erro ao carregar dados da revisão para corrigir:" ++ ++#: lib/commit.tcl:75 ++msgid "Unable to obtain your identity:" ++msgstr "Não foi possível obter a sua identidade:" ++ ++#: lib/commit.tcl:80 ++msgid "Invalid GIT_COMMITTER_IDENT:" ++msgstr "Variável \"GIT_COMMITTER_IDENT\" inválida:" ++ ++#: lib/commit.tcl:129 ++#, tcl-format ++msgid "warning: Tcl does not support encoding '%s'." ++msgstr "aviso: O Tcl não suporta a codificação \"%s\"." ++ ++#: lib/commit.tcl:149 ++msgid "" ++"Last scanned state does not match repository state.\n" ++"\n" ++"Another Git program has modified this repository since the last scan. A " ++"rescan must be performed before another commit can be created.\n" ++"\n" ++"The rescan will be automatically started now.\n" ++msgstr "" ++"O último estado lido não confere com o estado atual.\n" ++"\n" ++"Outro programa do Git modificou o repositório desde a última leitura. Uma " ++"atualização deve ser executada antes de criar outra revisão.\n" ++"\n" ++"A atualização começará automaticamente agora.\n" ++ ++#: lib/commit.tcl:172 ++#, tcl-format ++msgid "" ++"Unmerged files cannot be committed.\n" ++"\n" ++"File %s has merge conflicts. You must resolve them and stage the file " ++"before committing.\n" ++msgstr "" ++"Não é possível salvar revisões para arquivos não mesclados.\n" ++"\n" ++"O arquivo %s possui conflitos de mesclagem. Você deve resolvê-los e marcar o " ++"arquivo antes de salvar a revisão.\n" ++ ++#: lib/commit.tcl:180 ++#, tcl-format ++msgid "" ++"Unknown file state %s detected.\n" ++"\n" ++"File %s cannot be committed by this program.\n" ++msgstr "" ++"Estado desconhecido detectado para o arquivo %s.\n" ++"\n" ++"Este programa não pode salvar uma revisão para o arquivo %s.\n" ++ ++#: lib/commit.tcl:188 ++msgid "" ++"No changes to commit.\n" ++"\n" ++"You must stage at least 1 file before you can commit.\n" ++msgstr "" ++"Não há mudanças para salvar.\n" ++"\n" ++"Você deve marcar ao menos um arquivo antes de salvar a revisão.\n" ++ ++#: lib/commit.tcl:203 ++msgid "" ++"Please supply a commit message.\n" ++"\n" ++"A good commit message has the following format:\n" ++"\n" ++"- First line: Describe in one sentence what you did.\n" ++"- Second line: Blank\n" ++"- Remaining lines: Describe why this change is good.\n" ++msgstr "" ++"Por favor, indique uma descrição para a revisão.\n" ++"\n" ++"Uma boa descrição tem o seguinte formato:\n" ++"\n" ++"- Primeira linha: descreve, em uma única frase, o que você fez.\n" ++"- Segunda linha: em branco.\n" ++"- Demais linhas: Descreve detalhadamente a revisão.\n" ++ ++#: lib/commit.tcl:234 ++msgid "Calling pre-commit hook..." ++msgstr "Executando script \"pre-commit\"..." ++ ++#: lib/commit.tcl:249 ++msgid "Commit declined by pre-commit hook." ++msgstr "A revisão foi bloqueada pelo script \"pre-commit\"." ++ ++#: lib/commit.tcl:272 ++msgid "Calling commit-msg hook..." ++msgstr "Executando script \"commit-msg\"..." ++ ++#: lib/commit.tcl:287 ++msgid "Commit declined by commit-msg hook." ++msgstr "Revisão bloqueada pelo script \"commit-msg\"." ++ ++#: lib/commit.tcl:300 ++msgid "Committing changes..." ++msgstr "Salvando revisão..." ++ ++#: lib/commit.tcl:316 ++msgid "write-tree failed:" ++msgstr "write-tree falhou:" ++ ++#: lib/commit.tcl:317 lib/commit.tcl:361 lib/commit.tcl:382 ++msgid "Commit failed." ++msgstr "A revisão falhou." ++ ++#: lib/commit.tcl:334 ++#, tcl-format ++msgid "Commit %s appears to be corrupt" ++msgstr "A revisão %s parece estar corrompida." ++ ++#: lib/commit.tcl:339 ++msgid "" ++"No changes to commit.\n" ++"\n" ++"No files were modified by this commit and it was not a merge commit.\n" ++"\n" ++"A rescan will be automatically started now.\n" ++msgstr "" ++"Não há alterações para salvar.\n" ++"\n" ++"Nenhum arquivo foi modificado e esta não é uma revisão de mesclagem.\n" ++"\n" ++"Uma atualização será executada automaticamente agora.\n" ++ ++#: lib/commit.tcl:346 ++msgid "No changes to commit." ++msgstr "Não há alterações para salvar." ++ ++#: lib/commit.tcl:360 ++msgid "commit-tree failed:" ++msgstr "commit-tree falhou:" ++ ++#: lib/commit.tcl:381 ++msgid "update-ref failed:" ++msgstr "update-ref falhou:" ++ ++#: lib/commit.tcl:469 ++#, tcl-format ++msgid "Created commit %s: %s" ++msgstr "Revisão %s criada: %s" ++ ++#: lib/console.tcl:59 ++msgid "Working... please wait..." ++msgstr "Trabalhando... aguarde..." ++ ++#: lib/console.tcl:186 ++msgid "Success" ++msgstr "Sucesso" ++ ++#: lib/console.tcl:200 ++msgid "Error: Command Failed" ++msgstr "Erro: o comando falhou" ++ ++#: lib/database.tcl:43 ++msgid "Number of loose objects" ++msgstr "Número de objetos soltos" ++ ++#: lib/database.tcl:44 ++msgid "Disk space used by loose objects" ++msgstr "Espaço ocupado pelos objetos soltos" ++ ++#: lib/database.tcl:45 ++msgid "Number of packed objects" ++msgstr "Número de objetos compactados" ++ ++#: lib/database.tcl:46 ++msgid "Number of packs" ++msgstr "Número de pacotes" ++ ++#: lib/database.tcl:47 ++msgid "Disk space used by packed objects" ++msgstr "Espaço ocupado pelos objetos compactados" ++ ++#: lib/database.tcl:48 ++msgid "Packed objects waiting for pruning" ++msgstr "Objetos compactados aguardando eliminação" ++ ++#: lib/database.tcl:49 ++msgid "Garbage files" ++msgstr "Arquivos de lixo" ++ ++#: lib/database.tcl:72 ++msgid "Compressing the object database" ++msgstr "Compactando banco de dados de objetos" ++ ++#: lib/database.tcl:83 ++msgid "Verifying the object database with fsck-objects" ++msgstr "Verificando banco de dados de objetos com fsck-objects" ++ ++#: lib/database.tcl:107 ++#, tcl-format ++msgid "" ++"This repository currently has approximately %i loose objects.\n" ++"\n" ++"To maintain optimal performance it is strongly recommended that you compress " ++"the database.\n" ++"\n" ++"Compress the database now?" ++msgstr "" ++"Este repositório possui aproximadamente %i objetos soltos.\n" ++"\n" ++"Para manter o desempenho ótimo é altamente recomendado que você compacte o " ++"banco de dados.\n" ++"\n" ++"Compactar o banco de dados agora?" ++ ++#: lib/date.tcl:25 ++#, tcl-format ++msgid "Invalid date from Git: %s" ++msgstr "Data inválida recebida do Git: %s" ++ ++#: lib/diff.tcl:64 ++#, tcl-format ++msgid "" ++"No differences detected.\n" ++"\n" ++"%s has no changes.\n" ++"\n" ++"The modification date of this file was updated by another application, but " ++"the content within the file was not changed.\n" ++"\n" ++"A rescan will be automatically started to find other files which may have " ++"the same state." ++msgstr "" ++"Nenhuma diferença foi detectada.\n" ++"\n" ++"%s não possui mudanças.\n" ++"\n" ++"A data de modificação deste arquivo foi atualizada por outro aplicativo, mas " ++"o conteúdo do arquivo não foi alterado.\n" ++"\n" ++"Uma atualização ser executada para encontrar outros arquivos que possam ter " ++"o mesmo estado." ++ ++#: lib/diff.tcl:104 ++#, tcl-format ++msgid "Loading diff of %s..." ++msgstr "Carregando diferenças de %s..." ++ ++#: lib/diff.tcl:125 ++msgid "" ++"LOCAL: deleted\n" ++"REMOTE:\n" ++msgstr "" ++"Local: apagado\n" ++"Remoto:\n" ++ ++#: lib/diff.tcl:130 ++msgid "" ++"REMOTE: deleted\n" ++"LOCAL:\n" ++msgstr "" ++"Remoto: apagado\n" ++"Local:\n" ++ ++#: lib/diff.tcl:137 ++msgid "LOCAL:\n" ++msgstr "Local:\n" ++ ++#: lib/diff.tcl:140 ++msgid "REMOTE:\n" ++msgstr "Remoto:\n" ++ ++#: lib/diff.tcl:202 lib/diff.tcl:319 ++#, tcl-format ++msgid "Unable to display %s" ++msgstr "Impossível exibir %s" ++ ++#: lib/diff.tcl:203 ++msgid "Error loading file:" ++msgstr "Erro ao carregar o arquivo:" ++ ++#: lib/diff.tcl:210 ++msgid "Git Repository (subproject)" ++msgstr "Repositório Git (sub-projeto)" ++ ++#: lib/diff.tcl:222 ++msgid "* Binary file (not showing content)." ++msgstr "* Arquivo binário (conteúdo não exibido)." ++ ++#: lib/diff.tcl:227 ++#, tcl-format ++msgid "" ++"* Untracked file is %d bytes.\n" ++"* Showing only first %d bytes.\n" ++msgstr "" ++"* O arquivo não rastreado possui %d bytes.\n" ++"* Exibindo apenas os primeiros %d bytes.\n" ++ ++#: lib/diff.tcl:233 ++#, tcl-format ++msgid "" ++"\n" ++"* Untracked file clipped here by %s.\n" ++"* To see the entire file, use an external editor.\n" ++msgstr "" ++"\n" ++"* O arquivo não rastreado foi cortado aqui por %s.\n" ++"* Para ver o arquivo completo, use um editor externo.\n" ++ ++#: lib/diff.tcl:482 ++msgid "Failed to unstage selected hunk." ++msgstr "Erro ao desmarcar o trecho selecionado." ++ ++#: lib/diff.tcl:489 ++msgid "Failed to stage selected hunk." ++msgstr "Erro ao marcar o trecho selecionado." ++ ++#: lib/diff.tcl:568 ++msgid "Failed to unstage selected line." ++msgstr "Erro ao desmarcar a linha selecionada." ++ ++#: lib/diff.tcl:576 ++msgid "Failed to stage selected line." ++msgstr "Erro ao marcar a linha selecionada." ++ ++#: lib/encoding.tcl:443 ++msgid "Default" ++msgstr "Padrão" ++ ++#: lib/encoding.tcl:448 ++#, tcl-format ++msgid "System (%s)" ++msgstr "Sistema (%s)" ++ ++#: lib/encoding.tcl:459 lib/encoding.tcl:465 ++msgid "Other" ++msgstr "Outro" ++ ++#: lib/error.tcl:20 lib/error.tcl:114 ++msgid "error" ++msgstr "Erro" ++ ++#: lib/error.tcl:36 ++msgid "warning" ++msgstr "aviso" ++ ++#: lib/error.tcl:94 ++msgid "You must correct the above errors before committing." ++msgstr "Você precisa corrigir os erros acima antes de salvar a revisão." ++ ++#: lib/index.tcl:6 ++msgid "Unable to unlock the index." ++msgstr "Impossível desbloquear o índice." ++ ++#: lib/index.tcl:15 ++msgid "Index Error" ++msgstr "Erro no índice" ++ ++#: lib/index.tcl:17 ++msgid "" ++"Updating the Git index failed. A rescan will be automatically started to " ++"resynchronize git-gui." ++msgstr "" ++"A atualização do índice do Git falhou. Uma atualização será executada " ++"automaticamente para ressincronizar o Git GUI" ++ ++#: lib/index.tcl:28 ++msgid "Continue" ++msgstr "Continuar" ++ ++#: lib/index.tcl:31 ++msgid "Unlock Index" ++msgstr "Desbloquear índice" ++ ++#: lib/index.tcl:289 ++#, tcl-format ++msgid "Unstaging %s from commit" ++msgstr "Desmarcando %s para revisão" ++ ++#: lib/index.tcl:328 ++msgid "Ready to commit." ++msgstr "Pronto para salvar a revisão." ++ ++#: lib/index.tcl:341 ++#, tcl-format ++msgid "Adding %s" ++msgstr "Adicionando %s" ++ ++#: lib/index.tcl:398 ++#, tcl-format ++msgid "Revert changes in file %s?" ++msgstr "Reverter as alterações no arquivo %s?" ++ ++#: lib/index.tcl:400 ++#, tcl-format ++msgid "Revert changes in these %i files?" ++msgstr "Reverter as alterações nestes %i arquivos?" ++ ++#: lib/index.tcl:408 ++msgid "Any unstaged changes will be permanently lost by the revert." ++msgstr "" ++"Qualquer alteração não marcada será permanentemente perdida na reversão." ++ ++#: lib/index.tcl:411 ++msgid "Do Nothing" ++msgstr "Não fazer nada" ++ ++#: lib/index.tcl:429 ++msgid "Reverting selected files" ++msgstr "Revertendo os arquivos selecionados" ++ ++#: lib/index.tcl:433 ++#, tcl-format ++msgid "Reverting %s" ++msgstr "Revertendo %s" ++ ++#: lib/merge.tcl:13 ++msgid "" ++"Cannot merge while amending.\n" ++"\n" ++"You must finish amending this commit before starting any type of merge.\n" ++msgstr "" ++"Não é possível mesclar durante uma correção.\n" ++"\n" ++"Você deve concluir a correção antes de começar qualquer mesclagem.\n" ++ ++#: lib/merge.tcl:27 ++msgid "" ++"Last scanned state does not match repository state.\n" ++"\n" ++"Another Git program has modified this repository since the last scan. A " ++"rescan must be performed before a merge can be performed.\n" ++"\n" ++"The rescan will be automatically started now.\n" ++msgstr "" ++"O último estado lido não confere com o estado atual.\n" ++"\n" ++"Outro programa do Git modificou o repositório desde a última leitura. Uma " ++"atualização deve ser executada antes de efetuar uma mesclagem.\n" ++"\n" ++"A atualização começará automaticamente agora.\n" ++ ++#: lib/merge.tcl:45 ++#, tcl-format ++msgid "" ++"You are in the middle of a conflicted merge.\n" ++"\n" ++"File %s has merge conflicts.\n" ++"\n" ++"You must resolve them, stage the file, and commit to complete the current " ++"merge. Only then can you begin another merge.\n" ++msgstr "" ++"Há uma mesclagem com conflitos em progresso.\n" ++"\n" ++"O arquivo %s possui conflitos de mesclagem.\n" ++"\n" ++"Você deve resolvê-los, marcar o arquivo e salvar a revisão para completar a " ++"mesclagem atual. Só então você poderá começar outra.\n" ++ ++#: lib/merge.tcl:55 ++#, tcl-format ++msgid "" ++"You are in the middle of a change.\n" ++"\n" ++"File %s is modified.\n" ++"\n" ++"You should complete the current commit before starting a merge. Doing so " ++"will help you abort a failed merge, should the need arise.\n" ++msgstr "" ++"Você está em meio a uma mudança.\n" ++"\n" ++"O arquivo %s foi modificado.\n" ++"\n" ++"Você deve completar e salvar a revisão atual antes de começar uma mesclagem. " ++"Ao fazê-lo, você poderá abortar a mesclagem caso haja algum erro.\n" ++ ++#: lib/merge.tcl:107 ++#, tcl-format ++msgid "%s of %s" ++msgstr "%s de %s" ++ ++#: lib/merge.tcl:120 ++#, tcl-format ++msgid "Merging %s and %s..." ++msgstr "Mesclando %s e %s..." ++ ++#: lib/merge.tcl:131 ++msgid "Merge completed successfully." ++msgstr "Mesclagem completada com sucesso." ++ ++#: lib/merge.tcl:133 ++msgid "Merge failed. Conflict resolution is required." ++msgstr "A mesclagem falhou. É necessário resolver conflitos." ++ ++#: lib/merge.tcl:158 ++#, tcl-format ++msgid "Merge Into %s" ++msgstr "Mesclar em %s" ++ ++#: lib/merge.tcl:177 ++msgid "Revision To Merge" ++msgstr "Revisão para mesclar" ++ ++#: lib/merge.tcl:212 ++msgid "" ++"Cannot abort while amending.\n" ++"\n" ++"You must finish amending this commit.\n" ++msgstr "" ++"Não é possível abortar durante uma correção.\n" ++"\n" ++"Você precisa finalizar a correção desta revisão.\n" ++ ++#: lib/merge.tcl:222 ++msgid "" ++"Abort merge?\n" ++"\n" ++"Aborting the current merge will cause *ALL* uncommitted changes to be lost.\n" ++"\n" ++"Continue with aborting the current merge?" ++msgstr "" ++"Abortar mesclagem?\n" ++"\n" ++"Abortar a mesclagem atual implicará na perda de *TODAS* as mudanças não " ++"salvas.\n" ++"\n" ++"Abortar a mesclagem atual?" ++ ++#: lib/merge.tcl:228 ++msgid "" ++"Reset changes?\n" ++"\n" ++"Resetting the changes will cause *ALL* uncommitted changes to be lost.\n" ++"\n" ++"Continue with resetting the current changes?" ++msgstr "" ++"Descartar as mudanças?\n" ++"\n" ++"Ao fazê-lo, *TODAS* as alterações não salvas serão perdidas.\n" ++"\n" ++"Continuar e descartar as mudanças atuais?" ++ ++#: lib/merge.tcl:239 ++msgid "Aborting" ++msgstr "Abortando" ++ ++#: lib/merge.tcl:239 ++msgid "files reset" ++msgstr "arquivos redefindos" ++ ++#: lib/merge.tcl:267 ++msgid "Abort failed." ++msgstr "A tentativa de abortar a operação falhou" ++ ++#: lib/merge.tcl:269 ++msgid "Abort completed. Ready." ++msgstr "Operação abortada com sucesso. Pronto." ++ ++#: lib/mergetool.tcl:8 ++msgid "Force resolution to the base version?" ++msgstr "Forçar a resolução para a versão base?" ++ ++#: lib/mergetool.tcl:9 ++msgid "Force resolution to this branch?" ++msgstr "Forçar resolução para este ramo?" ++ ++#: lib/mergetool.tcl:10 ++msgid "Force resolution to the other branch?" ++msgstr "Forçar resolução para o outro ramo?" ++ ++#: lib/mergetool.tcl:14 ++#, tcl-format ++msgid "" ++"Note that the diff shows only conflicting changes.\n" ++"\n" ++"%s will be overwritten.\n" ++"\n" ++"This operation can be undone only by restarting the merge." ++msgstr "" ++"Note que o diff mostra apenas as mudanças conflitantes.\n" ++"\n" ++"%s será sobrescrito.\n" ++"\n" ++"Caso necessário, será preciso reiniciar a mesclagem para desfazer esta " ++"operação." ++ ++#: lib/mergetool.tcl:45 ++#, tcl-format ++msgid "File %s seems to have unresolved conflicts, still stage?" ++msgstr "O arquivo %s parece ter conflitos não resolvidos. Marcar mesmo assim?" ++ ++#: lib/mergetool.tcl:60 ++#, tcl-format ++msgid "Adding resolution for %s" ++msgstr "Adicionando resolução para %s" ++ ++#: lib/mergetool.tcl:141 ++msgid "Cannot resolve deletion or link conflicts using a tool" ++msgstr "" ++"Impossível resolver conflitos envolvendo exclusão ou links de arquivos com " ++"esta ferramenta." ++ ++#: lib/mergetool.tcl:146 ++msgid "Conflict file does not exist" ++msgstr "O arquivo conflitante não existe" ++ ++#: lib/mergetool.tcl:264 ++#, tcl-format ++msgid "Not a GUI merge tool: '%s'" ++msgstr "Não é uma ferramenta de mesclagem gráfica: \"%s\"" ++ ++#: lib/mergetool.tcl:268 ++#, tcl-format ++msgid "Unsupported merge tool '%s'" ++msgstr "Ferramenta de mesclagem não suportada \"%s\"" ++ ++#: lib/mergetool.tcl:303 ++msgid "Merge tool is already running, terminate it?" ++msgstr "A ferramenta de mesclagem já está em execução. Finalizar?" ++ ++#: lib/mergetool.tcl:323 ++#, tcl-format ++msgid "" ++"Error retrieving versions:\n" ++"%s" ++msgstr "" ++"Erro ao obter as versões:\n" ++"%s" ++ ++#: lib/mergetool.tcl:343 ++#, tcl-format ++msgid "" ++"Could not start the merge tool:\n" ++"\n" ++"%s" ++msgstr "" ++"Não foi possível iniciar a ferramenta de mesclagem:\n" ++"\n" ++"%s" ++ ++#: lib/mergetool.tcl:347 ++msgid "Running merge tool..." ++msgstr "Executando ferramenta de mesclagem..." ++ ++#: lib/mergetool.tcl:375 lib/mergetool.tcl:383 ++msgid "Merge tool failed." ++msgstr "Ferramenta de mesclagem falhou." ++ ++#: lib/option.tcl:11 ++#, tcl-format ++msgid "Invalid global encoding '%s'" ++msgstr "Codificação global inválida \"%s\"" ++ ++#: lib/option.tcl:19 ++#, tcl-format ++msgid "Invalid repo encoding '%s'" ++msgstr "Codificação do repositório inválida \"%s\"" ++ ++#: lib/option.tcl:117 ++msgid "Restore Defaults" ++msgstr "Restaurar padrões" ++ ++#: lib/option.tcl:121 ++msgid "Save" ++msgstr "Salvar" ++ ++#: lib/option.tcl:131 ++#, tcl-format ++msgid "%s Repository" ++msgstr "Repositório %s" ++ ++#: lib/option.tcl:132 ++msgid "Global (All Repositories)" ++msgstr "Global (todos os repositórios)" ++ ++#: lib/option.tcl:138 ++msgid "User Name" ++msgstr "Nome do usuário" ++ ++#: lib/option.tcl:139 ++msgid "Email Address" ++msgstr "Endereço de e-mail" ++ ++#: lib/option.tcl:141 ++msgid "Summarize Merge Commits" ++msgstr "Exibir sumário das revisões de mesclagem" ++ ++#: lib/option.tcl:142 ++msgid "Merge Verbosity" ++msgstr "Nível de detalhamento da mesclagem" ++ ++#: lib/option.tcl:143 ++msgid "Show Diffstat After Merge" ++msgstr "Exibir estatísticas após mesclagens" ++ ++#: lib/option.tcl:144 ++msgid "Use Merge Tool" ++msgstr "Usar ferramenta de mesclagem" ++ ++#: lib/option.tcl:146 ++msgid "Trust File Modification Timestamps" ++msgstr "Confiar nas datas de modificação dos arquivos" ++ ++#: lib/option.tcl:147 ++msgid "Prune Tracking Branches During Fetch" ++msgstr "Eliminar ramos de rastreamento ao receber" ++ ++#: lib/option.tcl:148 ++msgid "Match Tracking Branches" ++msgstr "Coincidir ramos de rastreamento" ++ ++#: lib/option.tcl:149 ++msgid "Blame Copy Only On Changed Files" ++msgstr "Detectar cópias somente em arquivos modificados" ++ ++#: lib/option.tcl:150 ++msgid "Minimum Letters To Blame Copy On" ++msgstr "Número mínimo de letras para detectar cópias" ++ ++#: lib/option.tcl:151 ++msgid "Blame History Context Radius (days)" ++msgstr "Extensão do contexto de detecção (em dias)" ++ ++#: lib/option.tcl:152 ++msgid "Number of Diff Context Lines" ++msgstr "Número de linhas para o diff contextual" ++ ++#: lib/option.tcl:153 ++msgid "Commit Message Text Width" ++msgstr "Largura do texto da descrição da revisão" ++ ++#: lib/option.tcl:154 ++msgid "New Branch Name Template" ++msgstr "Modelo de nome para novos ramos" ++ ++#: lib/option.tcl:155 ++msgid "Default File Contents Encoding" ++msgstr "Codificação padrão dos arquivos" ++ ++#: lib/option.tcl:203 ++msgid "Change" ++msgstr "Alterar" ++ ++#: lib/option.tcl:230 ++msgid "Spelling Dictionary:" ++msgstr "Dicionário para o verificador ortográfico:" ++ ++#: lib/option.tcl:254 ++msgid "Change Font" ++msgstr "Mudar fonte" ++ ++#: lib/option.tcl:258 ++#, tcl-format ++msgid "Choose %s" ++msgstr "Escolher %s" ++ ++#: lib/option.tcl:264 ++msgid "pt." ++msgstr "pt." ++ ++#: lib/option.tcl:278 ++msgid "Preferences" ++msgstr "Preferências" ++ ++#: lib/option.tcl:314 ++msgid "Failed to completely save options:" ++msgstr "Houve um erro ao salvar as opções:" ++ ++#: lib/remote.tcl:163 ++msgid "Remove Remote" ++msgstr "Excluir" ++ ++#: lib/remote.tcl:168 ++msgid "Prune from" ++msgstr "Limpar de" ++ ++#: lib/remote.tcl:173 ++msgid "Fetch from" ++msgstr "Receber de" ++ ++#: lib/remote.tcl:215 ++msgid "Push to" ++msgstr "Enviar para" ++ ++#: lib/remote_add.tcl:19 ++msgid "Add Remote" ++msgstr "Adicionar repositório remoto" ++ ++#: lib/remote_add.tcl:24 ++msgid "Add New Remote" ++msgstr "Adicionar novo repositório remoto" ++ ++#: lib/remote_add.tcl:28 lib/tools_dlg.tcl:36 ++msgid "Add" ++msgstr "Adicionar" ++ ++#: lib/remote_add.tcl:37 ++msgid "Remote Details" ++msgstr "Detalhes do repositório remoto" ++ ++#: lib/remote_add.tcl:50 ++msgid "Location:" ++msgstr "Local:" ++ ++#: lib/remote_add.tcl:62 ++msgid "Further Action" ++msgstr "Ações adicionais" ++ ++#: lib/remote_add.tcl:65 ++msgid "Fetch Immediately" ++msgstr "Receber imediatamente" ++ ++#: lib/remote_add.tcl:71 ++msgid "Initialize Remote Repository and Push" ++msgstr "Inicializar repositório remoto e enviar" ++ ++#: lib/remote_add.tcl:77 ++msgid "Do Nothing Else Now" ++msgstr "Não fazer nada agora" ++ ++#: lib/remote_add.tcl:101 ++msgid "Please supply a remote name." ++msgstr "Por favor, indique um nome para o repositório remoto." ++ ++#: lib/remote_add.tcl:114 ++#, tcl-format ++msgid "'%s' is not an acceptable remote name." ++msgstr "\"%s\" não é um nome válido para um repositório remoto." ++ ++#: lib/remote_add.tcl:125 ++#, tcl-format ++msgid "Failed to add remote '%s' of location '%s'." ++msgstr "Erro ao adicionar repositório remoto \"%s\" do local \"%s\":" ++ ++#: lib/remote_add.tcl:133 lib/transport.tcl:6 ++#, tcl-format ++msgid "fetch %s" ++msgstr "receber %s" ++ ++#: lib/remote_add.tcl:134 ++#, tcl-format ++msgid "Fetching the %s" ++msgstr "Recebendo o %s" ++ ++#: lib/remote_add.tcl:157 ++#, tcl-format ++msgid "Do not know how to initialize repository at location '%s'." ++msgstr "Não sabe como inicializar o repositório remoto em \"%s\"." ++ ++#: lib/remote_add.tcl:163 lib/transport.tcl:25 lib/transport.tcl:63 ++#: lib/transport.tcl:81 ++#, tcl-format ++msgid "push %s" ++msgstr "enviar %s" ++ ++#: lib/remote_add.tcl:164 ++#, tcl-format ++msgid "Setting up the %s (at %s)" ++msgstr "Configurando %s (em %s)" ++ ++#: lib/remote_branch_delete.tcl:29 lib/remote_branch_delete.tcl:34 ++msgid "Delete Branch Remotely" ++msgstr "Apagar ramo remoto" ++ ++#: lib/remote_branch_delete.tcl:47 ++msgid "From Repository" ++msgstr "Do repositório" ++ ++#: lib/remote_branch_delete.tcl:50 lib/transport.tcl:134 ++msgid "Remote:" ++msgstr "Remoto:" ++ ++#: lib/remote_branch_delete.tcl:66 lib/transport.tcl:149 ++msgid "Arbitrary Location:" ++msgstr "Outro local:" ++ ++#: lib/remote_branch_delete.tcl:84 ++msgid "Branches" ++msgstr "Ramos" ++ ++#: lib/remote_branch_delete.tcl:109 ++msgid "Delete Only If" ++msgstr "Apagar somente se" ++ ++#: lib/remote_branch_delete.tcl:111 ++msgid "Merged Into:" ++msgstr "Mesclado em:" ++ ++#: lib/remote_branch_delete.tcl:152 ++msgid "A branch is required for 'Merged Into'." ++msgstr "É preciso indicar um ramo para \"Mesclado em\"." ++ ++#: lib/remote_branch_delete.tcl:184 ++#, tcl-format ++msgid "" ++"The following branches are not completely merged into %s:\n" ++"\n" ++" - %s" ++msgstr "" ++"Os seguintes ramos não estão inteiramente mesclados em %s:\n" ++"\n" ++" - %s" ++ ++#: lib/remote_branch_delete.tcl:189 ++#, tcl-format ++msgid "" ++"One or more of the merge tests failed because you have not fetched the " ++"necessary commits. Try fetching from %s first." ++msgstr "" ++"Um ou mais testes de mesclagem falharam porque você não possui as revisões " ++"necessárias. Tente receber revisões de %s primeiro." ++ ++#: lib/remote_branch_delete.tcl:207 ++msgid "Please select one or more branches to delete." ++msgstr "Por favor selecione um ou mais ramos para apagar." ++ ++#: lib/remote_branch_delete.tcl:226 ++#, tcl-format ++msgid "Deleting branches from %s" ++msgstr "Apagar ramos de %s" ++ ++#: lib/remote_branch_delete.tcl:292 ++msgid "No repository selected." ++msgstr "Nenhum repositório foi selecionado." ++ ++#: lib/remote_branch_delete.tcl:297 ++#, tcl-format ++msgid "Scanning %s..." ++msgstr "Atualizando %s..." ++ ++#: lib/search.tcl:21 ++msgid "Find:" ++msgstr "Encontrar:" ++ ++#: lib/search.tcl:23 ++msgid "Next" ++msgstr "Próximo" ++ ++#: lib/search.tcl:24 ++msgid "Prev" ++msgstr "Anterior" ++ ++#: lib/search.tcl:25 ++msgid "Case-Sensitive" ++msgstr "Sensível a maiúsculas/minúsculas" ++ ++#: lib/shortcut.tcl:21 lib/shortcut.tcl:62 ++msgid "Cannot write shortcut:" ++msgstr "Não foi possível gravar o atalho:" ++ ++#: lib/shortcut.tcl:137 ++msgid "Cannot write icon:" ++msgstr "Não foi possível gravar o ícone:" ++ ++#: lib/spellcheck.tcl:57 ++msgid "Unsupported spell checker" ++msgstr "Verificador ortográfico não suportado" ++ ++#: lib/spellcheck.tcl:65 ++msgid "Spell checking is unavailable" ++msgstr "Verificação ortográfica indisponível" ++ ++#: lib/spellcheck.tcl:68 ++msgid "Invalid spell checking configuration" ++msgstr "Configuração do verificador ortográfico inválida" ++ ++#: lib/spellcheck.tcl:70 ++#, tcl-format ++msgid "Reverting dictionary to %s." ++msgstr "Revertendo dicionário para %s." ++ ++#: lib/spellcheck.tcl:73 ++msgid "Spell checker silently failed on startup" ++msgstr "O verificador ortográfico falhou sem relatar nenhum erro" ++ ++#: lib/spellcheck.tcl:80 ++msgid "Unrecognized spell checker" ++msgstr "Verificador ortográfico não reconhecido" ++ ++#: lib/spellcheck.tcl:186 ++msgid "No Suggestions" ++msgstr "Sem sugestões" ++ ++#: lib/spellcheck.tcl:388 ++msgid "Unexpected EOF from spell checker" ++msgstr "Final de arquivo inesperado recebido do verificador ortográfico" ++ ++#: lib/spellcheck.tcl:392 ++msgid "Spell Checker Failed" ++msgstr "A verificação ortográfica falhou" ++ ++#: lib/sshkey.tcl:31 ++msgid "No keys found." ++msgstr "Nenhuma chave encontrada" ++ ++#: lib/sshkey.tcl:34 ++#, tcl-format ++msgid "Found a public key in: %s" ++msgstr "Chave pública encontrada em: %s" ++ ++#: lib/sshkey.tcl:40 ++msgid "Generate Key" ++msgstr "Gerar chave" ++ ++#: lib/sshkey.tcl:56 ++msgid "Copy To Clipboard" ++msgstr "Copiar para a área de transferência" ++ ++#: lib/sshkey.tcl:70 ++msgid "Your OpenSSH Public Key" ++msgstr "Sua chave pública OpenSSH" ++ ++#: lib/sshkey.tcl:78 ++msgid "Generating..." ++msgstr "Gerando..." ++ ++#: lib/sshkey.tcl:84 ++#, tcl-format ++msgid "" ++"Could not start ssh-keygen:\n" ++"\n" ++"%s" ++msgstr "" ++"Impossível iniciar ssh-keygen:\n" ++"\n" ++"%s" ++ ++#: lib/sshkey.tcl:111 ++msgid "Generation failed." ++msgstr "A geração da chave falhou." ++ ++#: lib/sshkey.tcl:118 ++msgid "Generation succeded, but no keys found." ++msgstr "A geração da chave foi bem-sucedida, mas nenhuma chave foi encontrada." ++ ++#: lib/sshkey.tcl:121 ++#, tcl-format ++msgid "Your key is in: %s" ++msgstr "Sua chave em: %s" ++ ++#: lib/status_bar.tcl:83 ++#, tcl-format ++msgid "%s ... %*i of %*i %s (%3i%%)" ++msgstr "%s ... %*i de %*i %s (%3i%%)" ++ ++#: lib/tools.tcl:75 ++#, tcl-format ++msgid "Running %s requires a selected file." ++msgstr "É preciso selecionar um arquivo para executar %s." ++ ++#: lib/tools.tcl:90 ++#, tcl-format ++msgid "Are you sure you want to run %s?" ++msgstr "Você tem certeza que deseja executar %s?" ++ ++#: lib/tools.tcl:110 ++#, tcl-format ++msgid "Tool: %s" ++msgstr "Ferramenta: %s" ++ ++#: lib/tools.tcl:111 ++#, tcl-format ++msgid "Running: %s" ++msgstr "Executando: %s" ++ ++#: lib/tools.tcl:149 ++#, tcl-format ++msgid "Tool completed successfully: %s" ++msgstr "Execução completada com sucesso: %s" ++ ++#: lib/tools.tcl:151 ++#, tcl-format ++msgid "Tool failed: %s" ++msgstr "Ferramenta falhou: %s" ++ ++#: lib/tools_dlg.tcl:22 ++msgid "Add Tool" ++msgstr "Adicionar ferramenta" ++ ++#: lib/tools_dlg.tcl:28 ++msgid "Add New Tool Command" ++msgstr "Adicionar novo comando de ferramenta" ++ ++#: lib/tools_dlg.tcl:33 ++msgid "Add globally" ++msgstr "Adicionar globalmente" ++ ++#: lib/tools_dlg.tcl:45 ++msgid "Tool Details" ++msgstr "Detalhes da ferramenta" ++ ++#: lib/tools_dlg.tcl:48 ++msgid "Use '/' separators to create a submenu tree:" ++msgstr "Use o separador \"/\" para criar uma árvore de sub-menus:" ++ ++#: lib/tools_dlg.tcl:61 ++msgid "Command:" ++msgstr "Comando:" ++ ++#: lib/tools_dlg.tcl:74 ++msgid "Show a dialog before running" ++msgstr "Exibir uma caixa de diálogo antes de executar" ++ ++#: lib/tools_dlg.tcl:80 ++msgid "Ask the user to select a revision (sets $REVISION)" ++msgstr "Solicitar a seleção de uma revisão (a variável $REVISION)" ++ ++#: lib/tools_dlg.tcl:85 ++msgid "Ask the user for additional arguments (sets $ARGS)" ++msgstr "Solicitar argumentos adicionais (define a variável $ARGS)" ++ ++#: lib/tools_dlg.tcl:92 ++msgid "Don't show the command output window" ++msgstr "Não exibir a janela de saída do comando" ++ ++#: lib/tools_dlg.tcl:97 ++msgid "Run only if a diff is selected ($FILENAME not empty)" ++msgstr "Executar apenas se houver um diff selecionado ($FILENAME não-vazio)" ++ ++#: lib/tools_dlg.tcl:121 ++msgid "Please supply a name for the tool." ++msgstr "Por favor, indique um nome para a ferramenta." ++ ++#: lib/tools_dlg.tcl:129 ++#, tcl-format ++msgid "Tool '%s' already exists." ++msgstr "A ferramenta \"%s\" já existe." ++ ++#: lib/tools_dlg.tcl:151 ++#, tcl-format ++msgid "" ++"Could not add tool:\n" ++"%s" ++msgstr "" ++"Não foi possível adicionar a ferramenta:\n" ++"%s" ++ ++#: lib/tools_dlg.tcl:190 ++msgid "Remove Tool" ++msgstr "Excluir ferramenta" ++ ++#: lib/tools_dlg.tcl:196 ++msgid "Remove Tool Commands" ++msgstr "Excluir comando de ferramenta" ++ ++#: lib/tools_dlg.tcl:200 ++msgid "Remove" ++msgstr "Excluir" ++ ++#: lib/tools_dlg.tcl:236 ++msgid "(Blue denotes repository-local tools)" ++msgstr "(Azul indica ferramentas do repositório local)" ++ ++#: lib/tools_dlg.tcl:297 ++#, tcl-format ++msgid "Run Command: %s" ++msgstr "Executar comando: %s" ++ ++#: lib/tools_dlg.tcl:311 ++msgid "Arguments" ++msgstr "Argumentos" ++ ++#: lib/tools_dlg.tcl:348 ++msgid "OK" ++msgstr "OK" ++ ++#: lib/transport.tcl:7 ++#, tcl-format ++msgid "Fetching new changes from %s" ++msgstr "Recebendo novas mudanças de %s" ++ ++#: lib/transport.tcl:18 ++#, tcl-format ++msgid "remote prune %s" ++msgstr "Limpar %s" ++ ++#: lib/transport.tcl:19 ++#, tcl-format ++msgid "Pruning tracking branches deleted from %s" ++msgstr "Limpando ramos excluídos de %s" ++ ++#: lib/transport.tcl:26 ++#, tcl-format ++msgid "Pushing changes to %s" ++msgstr "Enviando mudanças para %s" ++ ++#: lib/transport.tcl:64 ++#, tcl-format ++msgid "Mirroring to %s" ++msgstr "Duplicando para %s" ++ ++#: lib/transport.tcl:82 ++#, tcl-format ++msgid "Pushing %s %s to %s" ++msgstr "Enviando %s %s para %s" ++ ++#: lib/transport.tcl:100 ++msgid "Push Branches" ++msgstr "Enviar ramos" ++ ++#: lib/transport.tcl:114 ++msgid "Source Branches" ++msgstr "Ramos de origem" ++ ++#: lib/transport.tcl:131 ++msgid "Destination Repository" ++msgstr "Repositório de destino" ++ ++#: lib/transport.tcl:169 ++msgid "Transfer Options" ++msgstr "Opções de transferência" ++ ++#: lib/transport.tcl:171 ++msgid "Force overwrite existing branch (may discard changes)" ++msgstr "Sobrescrever ramos existentes (pode descartar mudanças)" ++ ++#: lib/transport.tcl:175 ++msgid "Use thin pack (for slow network connections)" ++msgstr "Usar compactação minimalista (para redes lentas)" ++ ++#: lib/transport.tcl:179 ++msgid "Include tags" ++msgstr "Incluir etiquetas" diff --cc git-gui/po/ru.po index 364c074c5,000000000..30f4b77da mode 100644,000000..100644 --- a/git-gui/po/ru.po +++ b/git-gui/po/ru.po @@@ -1,2545 -1,0 +1,2564 @@@ +# Translation of git-gui to russian +# Copyright (C) 2007 Shawn Pearce +# This file is distributed under the same license as the git-gui package. +# Irina Riesen , 2007. +# +msgid "" +msgstr "" +"Project-Id-Version: git-gui\n" +"Report-Msgid-Bugs-To: \n" - "POT-Creation-Date: 2008-12-08 08:31-0800\n" ++"POT-Creation-Date: 2010-01-26 15:47-0800\n" +"PO-Revision-Date: 2007-10-22 22:30-0200\n" +"Last-Translator: Alex Riesen \n" +"Language-Team: Russian Translation \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + - #: git-gui.sh:41 git-gui.sh:737 git-gui.sh:751 git-gui.sh:764 git-gui.sh:847 - #: git-gui.sh:866 ++#: git-gui.sh:41 git-gui.sh:793 git-gui.sh:807 git-gui.sh:820 git-gui.sh:903 ++#: git-gui.sh:922 +msgid "git-gui: fatal error" +msgstr "git-gui: критическая ошибка" + - #: git-gui.sh:689 ++#: git-gui.sh:743 +#, tcl-format +msgid "Invalid font specified in %s:" +msgstr "В %s установлен неверный шрифт:" + - #: git-gui.sh:723 ++#: git-gui.sh:779 +msgid "Main Font" +msgstr "Шрифт интерфейса" + - #: git-gui.sh:724 ++#: git-gui.sh:780 +msgid "Diff/Console Font" +msgstr "Шрифт консоли и изменений (diff)" + - #: git-gui.sh:738 ++#: git-gui.sh:794 +msgid "Cannot find git in PATH." +msgstr "git не найден в PATH." + - #: git-gui.sh:765 ++#: git-gui.sh:821 +msgid "Cannot parse Git version string:" +msgstr "Невозможно распознать строку версии Git: " + - #: git-gui.sh:783 ++#: git-gui.sh:839 +#, tcl-format +msgid "" +"Git version cannot be determined.\n" +"\n" +"%s claims it is version '%s'.\n" +"\n" +"%s requires at least Git 1.5.0 or later.\n" +"\n" +"Assume '%s' is version 1.5.0?\n" +msgstr "" +"Невозможно определить версию Git\n" +"\n" +"%s указывает на версию '%s'.\n" +"\n" +"для %s требуется версия Git, начиная с 1.5.0\n" +"\n" +"Принять '%s' как версию 1.5.0?\n" + - #: git-gui.sh:1062 ++#: git-gui.sh:1128 +msgid "Git directory not found:" +msgstr "Каталог Git не найден:" + - #: git-gui.sh:1069 ++#: git-gui.sh:1146 +msgid "Cannot move to top of working directory:" +msgstr "Невозможно перейти к корню рабочего каталога репозитория: " + - #: git-gui.sh:1076 - msgid "Cannot use funny .git directory:" - msgstr "Каталог .git испорчен: " ++#: git-gui.sh:1154 ++msgid "Cannot use bare repository:" ++msgstr "Невозможно использование репозитория без рабочего каталога:" + - #: git-gui.sh:1081 ++#: git-gui.sh:1162 +msgid "No working directory" +msgstr "Отсутствует рабочий каталог" + - #: git-gui.sh:1247 lib/checkout_op.tcl:305 ++#: git-gui.sh:1334 lib/checkout_op.tcl:306 +msgid "Refreshing file status..." +msgstr "Обновление информации о состоянии файлов..." + - #: git-gui.sh:1303 ++#: git-gui.sh:1390 +msgid "Scanning for modified files ..." +msgstr "Поиск измененных файлов..." + - #: git-gui.sh:1367 ++#: git-gui.sh:1454 +msgid "Calling prepare-commit-msg hook..." +msgstr "Вызов программы поддержки репозитория prepare-commit-msg..." + - #: git-gui.sh:1384 ++#: git-gui.sh:1471 +msgid "Commit declined by prepare-commit-msg hook." +msgstr "" +"Сохранение прервано программой поддержки репозитория prepare-commit-msg" + - #: git-gui.sh:1542 lib/browser.tcl:246 ++#: git-gui.sh:1629 lib/browser.tcl:246 +msgid "Ready." +msgstr "Готово." + - #: git-gui.sh:1726 ++#: git-gui.sh:1787 +#, tcl-format +msgid "Displaying only %s of %s files." +msgstr "Показано %s из %s файлов." + - #: git-gui.sh:1819 ++#: git-gui.sh:1913 +msgid "Unmodified" +msgstr "Не изменено" + - #: git-gui.sh:1821 ++#: git-gui.sh:1915 +msgid "Modified, not staged" +msgstr "Изменено, не подготовлено" + - #: git-gui.sh:1822 git-gui.sh:1830 ++#: git-gui.sh:1916 git-gui.sh:1924 +msgid "Staged for commit" +msgstr "Подготовлено для сохранения" + - #: git-gui.sh:1823 git-gui.sh:1831 ++#: git-gui.sh:1917 git-gui.sh:1925 +msgid "Portions staged for commit" +msgstr "Части, подготовленные для сохранения" + - #: git-gui.sh:1824 git-gui.sh:1832 ++#: git-gui.sh:1918 git-gui.sh:1926 +msgid "Staged for commit, missing" +msgstr "Подготовлено для сохранения, отсутствует" + - #: git-gui.sh:1826 ++#: git-gui.sh:1920 +msgid "File type changed, not staged" +msgstr "Тип файла изменён, не подготовлено" + - #: git-gui.sh:1827 ++#: git-gui.sh:1921 +msgid "File type changed, staged" +msgstr "Тип файла изменён, подготовлено" + - #: git-gui.sh:1829 ++#: git-gui.sh:1923 +msgid "Untracked, not staged" +msgstr "Не отслеживается, не подготовлено" + - #: git-gui.sh:1834 ++#: git-gui.sh:1928 +msgid "Missing" +msgstr "Отсутствует" + - #: git-gui.sh:1835 ++#: git-gui.sh:1929 +msgid "Staged for removal" +msgstr "Подготовлено для удаления" + - #: git-gui.sh:1836 ++#: git-gui.sh:1930 +msgid "Staged for removal, still present" +msgstr "Подготовлено для удаления, еще не удалено" + - #: git-gui.sh:1838 git-gui.sh:1839 git-gui.sh:1840 git-gui.sh:1841 - #: git-gui.sh:1842 git-gui.sh:1843 ++#: git-gui.sh:1932 git-gui.sh:1933 git-gui.sh:1934 git-gui.sh:1935 ++#: git-gui.sh:1936 git-gui.sh:1937 +msgid "Requires merge resolution" +msgstr "Требуется разрешение конфликта при слиянии" + - #: git-gui.sh:1878 ++#: git-gui.sh:1972 +msgid "Starting gitk... please wait..." +msgstr "Запускается gitk... Подождите, пожалуйста..." + - #: git-gui.sh:1887 ++#: git-gui.sh:1984 +msgid "Couldn't find gitk in PATH" +msgstr "gitk не найден в PATH." + - #: git-gui.sh:2280 lib/choose_repository.tcl:36 ++#: git-gui.sh:2043 ++msgid "Couldn't find git gui in PATH" ++msgstr "git gui не найден в PATH." ++ ++#: git-gui.sh:2455 lib/choose_repository.tcl:36 +msgid "Repository" +msgstr "Репозиторий" + - #: git-gui.sh:2281 ++#: git-gui.sh:2456 +msgid "Edit" +msgstr "Редактировать" + - #: git-gui.sh:2283 lib/choose_rev.tcl:561 ++#: git-gui.sh:2458 lib/choose_rev.tcl:561 +msgid "Branch" +msgstr "Ветвь" + - #: git-gui.sh:2286 lib/choose_rev.tcl:548 ++#: git-gui.sh:2461 lib/choose_rev.tcl:548 +msgid "Commit@@noun" +msgstr "Состояние" + - #: git-gui.sh:2289 lib/merge.tcl:121 lib/merge.tcl:150 lib/merge.tcl:168 ++#: git-gui.sh:2464 lib/merge.tcl:121 lib/merge.tcl:150 lib/merge.tcl:168 +msgid "Merge" +msgstr "Слияние" + - #: git-gui.sh:2290 lib/choose_rev.tcl:557 ++#: git-gui.sh:2465 lib/choose_rev.tcl:557 +msgid "Remote" +msgstr "Внешние репозитории" + - #: git-gui.sh:2293 ++#: git-gui.sh:2468 +msgid "Tools" +msgstr "Вспомогательные операции" + - #: git-gui.sh:2302 ++#: git-gui.sh:2477 +msgid "Explore Working Copy" +msgstr "Просмотр рабочего каталога" + - #: git-gui.sh:2307 ++#: git-gui.sh:2483 +msgid "Browse Current Branch's Files" +msgstr "Просмотреть файлы текущей ветви" + - #: git-gui.sh:2311 ++#: git-gui.sh:2487 +msgid "Browse Branch Files..." +msgstr "Показать файлы ветви..." + - #: git-gui.sh:2316 ++#: git-gui.sh:2492 +msgid "Visualize Current Branch's History" +msgstr "Показать историю текущей ветви" + - #: git-gui.sh:2320 ++#: git-gui.sh:2496 +msgid "Visualize All Branch History" +msgstr "Показать историю всех ветвей" + - #: git-gui.sh:2327 ++#: git-gui.sh:2503 +#, tcl-format +msgid "Browse %s's Files" +msgstr "Показать файлы ветви %s" + - #: git-gui.sh:2329 ++#: git-gui.sh:2505 +#, tcl-format +msgid "Visualize %s's History" +msgstr "Показать историю ветви %s" + - #: git-gui.sh:2334 lib/database.tcl:27 lib/database.tcl:67 ++#: git-gui.sh:2510 lib/database.tcl:27 lib/database.tcl:67 +msgid "Database Statistics" +msgstr "Статистика базы данных" + - #: git-gui.sh:2337 lib/database.tcl:34 ++#: git-gui.sh:2513 lib/database.tcl:34 +msgid "Compress Database" +msgstr "Сжать базу данных" + - #: git-gui.sh:2340 ++#: git-gui.sh:2516 +msgid "Verify Database" +msgstr "Проверить базу данных" + - #: git-gui.sh:2347 git-gui.sh:2351 git-gui.sh:2355 lib/shortcut.tcl:7 - #: lib/shortcut.tcl:39 lib/shortcut.tcl:71 ++#: git-gui.sh:2523 git-gui.sh:2527 git-gui.sh:2531 lib/shortcut.tcl:8 ++#: lib/shortcut.tcl:40 lib/shortcut.tcl:72 +msgid "Create Desktop Icon" +msgstr "Создать ярлык на рабочем столе" + - #: git-gui.sh:2363 lib/choose_repository.tcl:183 lib/choose_repository.tcl:191 ++#: git-gui.sh:2539 lib/choose_repository.tcl:183 lib/choose_repository.tcl:191 +msgid "Quit" +msgstr "Выход" + - #: git-gui.sh:2371 ++#: git-gui.sh:2547 +msgid "Undo" +msgstr "Отменить" + - #: git-gui.sh:2374 ++#: git-gui.sh:2550 +msgid "Redo" +msgstr "Повторить" + - #: git-gui.sh:2378 git-gui.sh:2937 ++#: git-gui.sh:2554 git-gui.sh:3109 +msgid "Cut" +msgstr "Вырезать" + - #: git-gui.sh:2381 git-gui.sh:2940 git-gui.sh:3014 git-gui.sh:3096 ++#: git-gui.sh:2557 git-gui.sh:3112 git-gui.sh:3186 git-gui.sh:3259 +#: lib/console.tcl:69 +msgid "Copy" +msgstr "Копировать" + - #: git-gui.sh:2384 git-gui.sh:2943 ++#: git-gui.sh:2560 git-gui.sh:3115 +msgid "Paste" +msgstr "Вставить" + - #: git-gui.sh:2387 git-gui.sh:2946 lib/branch_delete.tcl:26 ++#: git-gui.sh:2563 git-gui.sh:3118 lib/branch_delete.tcl:26 +#: lib/remote_branch_delete.tcl:38 +msgid "Delete" +msgstr "Удалить" + - #: git-gui.sh:2391 git-gui.sh:2950 git-gui.sh:3100 lib/console.tcl:71 ++#: git-gui.sh:2567 git-gui.sh:3122 git-gui.sh:3263 lib/console.tcl:71 +msgid "Select All" +msgstr "Выделить все" + - #: git-gui.sh:2400 ++#: git-gui.sh:2576 +msgid "Create..." +msgstr "Создать..." + - #: git-gui.sh:2406 ++#: git-gui.sh:2582 +msgid "Checkout..." +msgstr "Перейти..." + - #: git-gui.sh:2412 ++#: git-gui.sh:2588 +msgid "Rename..." +msgstr "Переименовать..." + - #: git-gui.sh:2417 ++#: git-gui.sh:2593 +msgid "Delete..." +msgstr "Удалить..." + - #: git-gui.sh:2422 ++#: git-gui.sh:2598 +msgid "Reset..." +msgstr "Сбросить..." + - #: git-gui.sh:2432 ++#: git-gui.sh:2608 +msgid "Done" +msgstr "Завершено" + - #: git-gui.sh:2434 ++#: git-gui.sh:2610 +msgid "Commit@@verb" +msgstr "Сохранить" + - #: git-gui.sh:2443 git-gui.sh:2878 ++#: git-gui.sh:2619 git-gui.sh:3050 +msgid "New Commit" +msgstr "Новое состояние" + - #: git-gui.sh:2451 git-gui.sh:2885 ++#: git-gui.sh:2627 git-gui.sh:3057 +msgid "Amend Last Commit" +msgstr "Исправить последнее состояние" + - #: git-gui.sh:2461 git-gui.sh:2839 lib/remote_branch_delete.tcl:99 ++#: git-gui.sh:2637 git-gui.sh:3011 lib/remote_branch_delete.tcl:99 +msgid "Rescan" +msgstr "Перечитать" + - #: git-gui.sh:2467 ++#: git-gui.sh:2643 +msgid "Stage To Commit" +msgstr "Подготовить для сохранения" + - #: git-gui.sh:2473 ++#: git-gui.sh:2649 +msgid "Stage Changed Files To Commit" +msgstr "Подготовить измененные файлы для сохранения" + - #: git-gui.sh:2479 ++#: git-gui.sh:2655 +msgid "Unstage From Commit" +msgstr "Убрать из подготовленного" + - #: git-gui.sh:2484 lib/index.tcl:410 ++#: git-gui.sh:2661 lib/index.tcl:412 +msgid "Revert Changes" +msgstr "Отменить изменения" + - #: git-gui.sh:2491 git-gui.sh:3083 ++#: git-gui.sh:2669 git-gui.sh:3310 git-gui.sh:3341 +msgid "Show Less Context" +msgstr "Меньше контекста" + - #: git-gui.sh:2495 git-gui.sh:3087 ++#: git-gui.sh:2673 git-gui.sh:3314 git-gui.sh:3345 +msgid "Show More Context" +msgstr "Больше контекста" + - #: git-gui.sh:2502 git-gui.sh:2852 git-gui.sh:2961 ++#: git-gui.sh:2680 git-gui.sh:3024 git-gui.sh:3133 +msgid "Sign Off" +msgstr "Вставить Signed-off-by" + - #: git-gui.sh:2518 ++#: git-gui.sh:2696 +msgid "Local Merge..." +msgstr "Локальное слияние..." + - #: git-gui.sh:2523 ++#: git-gui.sh:2701 +msgid "Abort Merge..." +msgstr "Прервать слияние..." + - #: git-gui.sh:2535 git-gui.sh:2575 ++#: git-gui.sh:2713 git-gui.sh:2741 +msgid "Add..." +msgstr "Добавить..." + - #: git-gui.sh:2539 ++#: git-gui.sh:2717 +msgid "Push..." +msgstr "Отправить..." + - #: git-gui.sh:2543 ++#: git-gui.sh:2721 +msgid "Delete Branch..." +msgstr "Удалить ветвь..." + - #: git-gui.sh:2553 git-gui.sh:2589 lib/about.tcl:14 - #: lib/choose_repository.tcl:44 lib/choose_repository.tcl:53 - #, tcl-format - msgid "About %s" - msgstr "О %s" - - #: git-gui.sh:2557 - msgid "Preferences..." - msgstr "Настройки..." - - #: git-gui.sh:2565 git-gui.sh:3129 ++#: git-gui.sh:2731 git-gui.sh:3292 +msgid "Options..." +msgstr "Настройки..." + - #: git-gui.sh:2576 ++#: git-gui.sh:2742 +msgid "Remove..." +msgstr "Удалить..." + - #: git-gui.sh:2585 lib/choose_repository.tcl:50 ++#: git-gui.sh:2751 lib/choose_repository.tcl:50 +msgid "Help" +msgstr "Помощь" + - #: git-gui.sh:2611 ++#: git-gui.sh:2755 git-gui.sh:2759 lib/about.tcl:14 ++#: lib/choose_repository.tcl:44 lib/choose_repository.tcl:53 ++#, tcl-format ++msgid "About %s" ++msgstr "О %s" ++ ++#: git-gui.sh:2783 +msgid "Online Documentation" +msgstr "Документация в интернете" + - #: git-gui.sh:2614 lib/choose_repository.tcl:47 lib/choose_repository.tcl:56 ++#: git-gui.sh:2786 lib/choose_repository.tcl:47 lib/choose_repository.tcl:56 +msgid "Show SSH Key" +msgstr "Показать ключ SSH" + - #: git-gui.sh:2721 ++#: git-gui.sh:2893 +#, tcl-format +msgid "fatal: cannot stat path %s: No such file or directory" +msgstr "критическая ошибка: %s: нет такого файла или каталога" + - #: git-gui.sh:2754 ++#: git-gui.sh:2926 +msgid "Current Branch:" +msgstr "Текущая ветвь:" + - #: git-gui.sh:2775 ++#: git-gui.sh:2947 +msgid "Staged Changes (Will Commit)" +msgstr "Подготовлено (будет сохранено)" + - #: git-gui.sh:2795 ++#: git-gui.sh:2967 +msgid "Unstaged Changes" +msgstr "Изменено (не будет сохранено)" + - #: git-gui.sh:2845 ++#: git-gui.sh:3017 +msgid "Stage Changed" +msgstr "Подготовить все" + - #: git-gui.sh:2864 lib/transport.tcl:104 lib/transport.tcl:193 ++#: git-gui.sh:3036 lib/transport.tcl:104 lib/transport.tcl:193 +msgid "Push" +msgstr "Отправить" + - #: git-gui.sh:2899 ++#: git-gui.sh:3071 +msgid "Initial Commit Message:" +msgstr "Комментарий к первому состоянию:" + - #: git-gui.sh:2900 ++#: git-gui.sh:3072 +msgid "Amended Commit Message:" +msgstr "Комментарий к исправленному состоянию:" + - #: git-gui.sh:2901 ++#: git-gui.sh:3073 +msgid "Amended Initial Commit Message:" +msgstr "Комментарий к исправленному первоначальному состоянию:" + - #: git-gui.sh:2902 ++#: git-gui.sh:3074 +msgid "Amended Merge Commit Message:" +msgstr "Комментарий к исправленному слиянию:" + - #: git-gui.sh:2903 ++#: git-gui.sh:3075 +msgid "Merge Commit Message:" +msgstr "Комментарий к слиянию:" + - #: git-gui.sh:2904 ++#: git-gui.sh:3076 +msgid "Commit Message:" +msgstr "Комментарий к состоянию:" + - #: git-gui.sh:2953 git-gui.sh:3104 lib/console.tcl:73 ++#: git-gui.sh:3125 git-gui.sh:3267 lib/console.tcl:73 +msgid "Copy All" +msgstr "Копировать все" + - #: git-gui.sh:2977 lib/blame.tcl:104 ++#: git-gui.sh:3149 lib/blame.tcl:104 +msgid "File:" +msgstr "Файл:" + - #: git-gui.sh:3092 ++#: git-gui.sh:3255 +msgid "Refresh" +msgstr "Обновить" + - #: git-gui.sh:3113 ++#: git-gui.sh:3276 +msgid "Decrease Font Size" +msgstr "Уменьшить размер шрифта" + - #: git-gui.sh:3117 ++#: git-gui.sh:3280 +msgid "Increase Font Size" +msgstr "Увеличить размер шрифта" + - #: git-gui.sh:3125 lib/blame.tcl:281 ++#: git-gui.sh:3288 lib/blame.tcl:281 +msgid "Encoding" +msgstr "Кодировка" + - #: git-gui.sh:3136 ++#: git-gui.sh:3299 +msgid "Apply/Reverse Hunk" +msgstr "Применить/Убрать изменение" + - #: git-gui.sh:3141 ++#: git-gui.sh:3304 +msgid "Apply/Reverse Line" +msgstr "Применить/Убрать строку" + - #: git-gui.sh:3151 ++#: git-gui.sh:3323 +msgid "Run Merge Tool" +msgstr "Запустить программу слияния" + - #: git-gui.sh:3156 ++#: git-gui.sh:3328 +msgid "Use Remote Version" +msgstr "Взять внешнюю версию" + - #: git-gui.sh:3160 ++#: git-gui.sh:3332 +msgid "Use Local Version" +msgstr "Взять локальную версию" + - #: git-gui.sh:3164 ++#: git-gui.sh:3336 +msgid "Revert To Base" +msgstr "Отменить изменения" + - #: git-gui.sh:3183 ++#: git-gui.sh:3354 ++msgid "Visualize These Changes In The Submodule" ++msgstr "" ++ ++#: git-gui.sh:3358 ++msgid "Visualize Current Branch History In The Submodule" ++msgstr "Показать историю текущей ветви подмодуля" ++ ++#: git-gui.sh:3362 ++msgid "Visualize All Branch History In The Submodule" ++msgstr "Показать историю всех ветвей подмодуля" ++ ++#: git-gui.sh:3367 ++msgid "Start git gui In The Submodule" ++msgstr "" ++ ++#: git-gui.sh:3389 +msgid "Unstage Hunk From Commit" +msgstr "Не сохранять часть" + - #: git-gui.sh:3184 ++#: git-gui.sh:3391 ++msgid "Unstage Lines From Commit" ++msgstr "Убрать строки из подготовленного" ++ ++#: git-gui.sh:3393 +msgid "Unstage Line From Commit" +msgstr "Убрать строку из подготовленного" + - #: git-gui.sh:3186 ++#: git-gui.sh:3396 +msgid "Stage Hunk For Commit" +msgstr "Подготовить часть для сохранения" + - #: git-gui.sh:3187 ++#: git-gui.sh:3398 ++msgid "Stage Lines For Commit" ++msgstr "Подготовить строки для сохранения" ++ ++#: git-gui.sh:3400 +msgid "Stage Line For Commit" +msgstr "Подготовить строку для сохранения" + - #: git-gui.sh:3210 ++#: git-gui.sh:3424 +msgid "Initializing..." +msgstr "Инициализация..." + - #: git-gui.sh:3315 ++#: git-gui.sh:3541 +#, tcl-format +msgid "" +"Possible environment issues exist.\n" +"\n" +"The following environment variables are probably\n" +"going to be ignored by any Git subprocess run\n" +"by %s:\n" +"\n" +msgstr "" +"Возможны ошибки в переменных окружения.\n" +"\n" +"Переменные окружения, которые возможно\n" +"будут проигнорированы командами Git,\n" +"запущенными из %s\n" +"\n" + - #: git-gui.sh:3345 ++#: git-gui.sh:3570 +msgid "" +"\n" +"This is due to a known issue with the\n" +"Tcl binary distributed by Cygwin." +msgstr "" +"\n" +"Это известная проблема с Tcl,\n" +"распространяемым Cygwin." + - #: git-gui.sh:3350 ++#: git-gui.sh:3575 +#, tcl-format +msgid "" +"\n" +"\n" +"A good replacement for %s\n" +"is placing values for the user.name and\n" +"user.email settings into your personal\n" +"~/.gitconfig file.\n" +msgstr "" +"\n" +"\n" +"Вместо использования %s можно\n" +"сохранить значения user.name и\n" +"user.email в Вашем персональном\n" +"файле ~/.gitconfig.\n" + +#: lib/about.tcl:26 +msgid "git-gui - a graphical user interface for Git." +msgstr "git-gui - графический пользовательский интерфейс к Git." + +#: lib/blame.tcl:72 +msgid "File Viewer" +msgstr "Просмотр файла" + +#: lib/blame.tcl:78 +msgid "Commit:" +msgstr "Сохраненное состояние:" + +#: lib/blame.tcl:271 +msgid "Copy Commit" +msgstr "Скопировать SHA-1" + +#: lib/blame.tcl:275 +msgid "Find Text..." +msgstr "Найти текст..." + +#: lib/blame.tcl:284 +msgid "Do Full Copy Detection" +msgstr "Провести полный поиск копий" + +#: lib/blame.tcl:288 +msgid "Show History Context" +msgstr "Показать исторический контекст" + +#: lib/blame.tcl:291 +msgid "Blame Parent Commit" +msgstr "Рассмотреть состояние предка" + +#: lib/blame.tcl:450 +#, tcl-format +msgid "Reading %s..." +msgstr "Чтение %s..." + +#: lib/blame.tcl:557 +msgid "Loading copy/move tracking annotations..." +msgstr "Загрузка аннотации копирований/переименований..." + +#: lib/blame.tcl:577 +msgid "lines annotated" +msgstr "строк прокомментировано" + +#: lib/blame.tcl:769 +msgid "Loading original location annotations..." +msgstr "Загрузка аннотаций первоначального положения объекта..." + +#: lib/blame.tcl:772 +msgid "Annotation complete." +msgstr "Аннотация завершена." + +#: lib/blame.tcl:802 +msgid "Busy" +msgstr "Занят" + +#: lib/blame.tcl:803 +msgid "Annotation process is already running." +msgstr "Аннотация уже запущена" + +#: lib/blame.tcl:842 +msgid "Running thorough copy detection..." +msgstr "Выполнение полного поиска копий..." + +#: lib/blame.tcl:910 +msgid "Loading annotation..." +msgstr "Загрузка аннотации..." + +#: lib/blame.tcl:963 +msgid "Author:" +msgstr "Автор:" + +#: lib/blame.tcl:967 +msgid "Committer:" +msgstr "Сохранил:" + +#: lib/blame.tcl:972 +msgid "Original File:" +msgstr "Исходный файл:" + +#: lib/blame.tcl:1020 +msgid "Cannot find HEAD commit:" +msgstr "Невозможно найти текущее состояние:" + +#: lib/blame.tcl:1075 +msgid "Cannot find parent commit:" +msgstr "Невозможно найти состояние предка:" + +#: lib/blame.tcl:1090 +msgid "Unable to display parent" +msgstr "Не могу показать предка" + - #: lib/blame.tcl:1091 lib/diff.tcl:297 ++#: lib/blame.tcl:1091 lib/diff.tcl:320 +msgid "Error loading diff:" +msgstr "Ошибка загрузки изменений:" + +#: lib/blame.tcl:1231 +msgid "Originally By:" +msgstr "Источник:" + +#: lib/blame.tcl:1237 +msgid "In File:" +msgstr "Файл:" + +#: lib/blame.tcl:1242 +msgid "Copied Or Moved Here By:" +msgstr "Скопировано/перемещено в:" + +#: lib/branch_checkout.tcl:14 lib/branch_checkout.tcl:19 +msgid "Checkout Branch" +msgstr "Перейти на ветвь" + +#: lib/branch_checkout.tcl:23 +msgid "Checkout" +msgstr "Перейти" + +#: lib/branch_checkout.tcl:27 lib/branch_create.tcl:35 +#: lib/branch_delete.tcl:32 lib/branch_rename.tcl:30 lib/browser.tcl:282 - #: lib/checkout_op.tcl:544 lib/choose_font.tcl:43 lib/merge.tcl:172 ++#: lib/checkout_op.tcl:579 lib/choose_font.tcl:43 lib/merge.tcl:172 +#: lib/option.tcl:125 lib/remote_add.tcl:32 lib/remote_branch_delete.tcl:42 +#: lib/tools_dlg.tcl:40 lib/tools_dlg.tcl:204 lib/tools_dlg.tcl:352 +#: lib/transport.tcl:108 +msgid "Cancel" +msgstr "Отмена" + +#: lib/branch_checkout.tcl:32 lib/browser.tcl:287 lib/tools_dlg.tcl:328 +msgid "Revision" +msgstr "Версия" + +#: lib/branch_checkout.tcl:36 lib/branch_create.tcl:69 lib/option.tcl:280 +msgid "Options" +msgstr "Настройки" + +#: lib/branch_checkout.tcl:39 lib/branch_create.tcl:92 +msgid "Fetch Tracking Branch" +msgstr "Получить изменения из внешней ветви" + +#: lib/branch_checkout.tcl:44 +msgid "Detach From Local Branch" +msgstr "Отсоединить от локальной ветви" + +#: lib/branch_create.tcl:22 +msgid "Create Branch" +msgstr "Создание ветви" + +#: lib/branch_create.tcl:27 +msgid "Create New Branch" +msgstr "Создать новую ветвь" + - #: lib/branch_create.tcl:31 lib/choose_repository.tcl:377 ++#: lib/branch_create.tcl:31 lib/choose_repository.tcl:381 +msgid "Create" +msgstr "Создать" + +#: lib/branch_create.tcl:40 +msgid "Branch Name" +msgstr "Название ветви" + +#: lib/branch_create.tcl:43 lib/remote_add.tcl:39 lib/tools_dlg.tcl:50 +msgid "Name:" +msgstr "Название:" + +#: lib/branch_create.tcl:58 +msgid "Match Tracking Branch Name" +msgstr "Взять из имен ветвей слежения" + +#: lib/branch_create.tcl:66 +msgid "Starting Revision" +msgstr "Начальная версия" + +#: lib/branch_create.tcl:72 +msgid "Update Existing Branch:" +msgstr "Обновить имеющуюся ветвь:" + +#: lib/branch_create.tcl:75 +msgid "No" +msgstr "Нет" + +#: lib/branch_create.tcl:80 +msgid "Fast Forward Only" +msgstr "Только Fast Forward" + - #: lib/branch_create.tcl:85 lib/checkout_op.tcl:536 ++#: lib/branch_create.tcl:85 lib/checkout_op.tcl:571 +msgid "Reset" +msgstr "Сброс" + +#: lib/branch_create.tcl:97 +msgid "Checkout After Creation" +msgstr "После создания сделать текущей" + +#: lib/branch_create.tcl:131 +msgid "Please select a tracking branch." +msgstr "Укажите ветвь слежения." + +#: lib/branch_create.tcl:140 +#, tcl-format +msgid "Tracking branch %s is not a branch in the remote repository." +msgstr "Ветвь слежения %s не является ветвью во внешнем репозитории." + +#: lib/branch_create.tcl:153 lib/branch_rename.tcl:86 +msgid "Please supply a branch name." +msgstr "Укажите название ветви." + +#: lib/branch_create.tcl:164 lib/branch_rename.tcl:106 +#, tcl-format +msgid "'%s' is not an acceptable branch name." +msgstr "Недопустимое название ветви '%s'." + +#: lib/branch_delete.tcl:15 +msgid "Delete Branch" +msgstr "Удаление ветви" + +#: lib/branch_delete.tcl:20 +msgid "Delete Local Branch" +msgstr "Удалить локальную ветвь" + +#: lib/branch_delete.tcl:37 +msgid "Local Branches" +msgstr "Локальные ветви" + +#: lib/branch_delete.tcl:52 +msgid "Delete Only If Merged Into" +msgstr "Удалить только в случае, если было слияние с" + - #: lib/branch_delete.tcl:54 - msgid "Always (Do not perform merge test.)" ++#: lib/branch_delete.tcl:54 lib/remote_branch_delete.tcl:119 ++msgid "Always (Do not perform merge checks)" +msgstr "Всегда (не выполнять проверку на слияние)" + +#: lib/branch_delete.tcl:103 +#, tcl-format +msgid "The following branches are not completely merged into %s:" +msgstr "Ветви, которые не полностью сливаются с %s:" + ++#: lib/branch_delete.tcl:115 lib/remote_branch_delete.tcl:217 ++msgid "" ++"Recovering deleted branches is difficult.\n" ++"\n" ++"Delete the selected branches?" ++msgstr "" ++"Восстановить удаленные ветви сложно.\n" ++"\n" ++"Продолжить?" ++ +#: lib/branch_delete.tcl:141 +#, tcl-format +msgid "" +"Failed to delete branches:\n" +"%s" +msgstr "" +"Не удалось удалить ветви:\n" +"%s" + +#: lib/branch_rename.tcl:14 lib/branch_rename.tcl:22 +msgid "Rename Branch" +msgstr "Переименование ветви" + +#: lib/branch_rename.tcl:26 +msgid "Rename" +msgstr "Переименовать" + +#: lib/branch_rename.tcl:36 +msgid "Branch:" +msgstr "Ветвь:" + +#: lib/branch_rename.tcl:39 +msgid "New Name:" +msgstr "Новое название:" + +#: lib/branch_rename.tcl:75 +msgid "Please select a branch to rename." +msgstr "Укажите ветвь для переименования." + - #: lib/branch_rename.tcl:96 lib/checkout_op.tcl:201 ++#: lib/branch_rename.tcl:96 lib/checkout_op.tcl:202 +#, tcl-format +msgid "Branch '%s' already exists." +msgstr "Ветвь '%s' уже существует." + +#: lib/branch_rename.tcl:117 +#, tcl-format +msgid "Failed to rename '%s'." +msgstr "Не удалось переименовать '%s'. " + +#: lib/browser.tcl:17 +msgid "Starting..." +msgstr "Запуск..." + +#: lib/browser.tcl:26 +msgid "File Browser" +msgstr "Просмотр списка файлов" + +#: lib/browser.tcl:126 lib/browser.tcl:143 +#, tcl-format +msgid "Loading %s..." +msgstr "Загрузка %s..." + +#: lib/browser.tcl:187 +msgid "[Up To Parent]" +msgstr "[На уровень выше]" + +#: lib/browser.tcl:267 lib/browser.tcl:273 +msgid "Browse Branch Files" +msgstr "Показать файлы ветви" + - #: lib/browser.tcl:278 lib/choose_repository.tcl:394 - #: lib/choose_repository.tcl:480 lib/choose_repository.tcl:491 - #: lib/choose_repository.tcl:995 ++#: lib/browser.tcl:278 lib/choose_repository.tcl:398 ++#: lib/choose_repository.tcl:486 lib/choose_repository.tcl:497 ++#: lib/choose_repository.tcl:1028 +msgid "Browse" +msgstr "Показать" + - #: lib/checkout_op.tcl:84 ++#: lib/checkout_op.tcl:85 +#, tcl-format +msgid "Fetching %s from %s" +msgstr "Получение %s из %s " + - #: lib/checkout_op.tcl:132 ++#: lib/checkout_op.tcl:133 +#, tcl-format +msgid "fatal: Cannot resolve %s" +msgstr "критическая ошибка: невозможно разрешить %s" + - #: lib/checkout_op.tcl:145 lib/console.tcl:81 lib/database.tcl:31 ++#: lib/checkout_op.tcl:146 lib/console.tcl:81 lib/database.tcl:31 +#: lib/sshkey.tcl:53 +msgid "Close" +msgstr "Закрыть" + - #: lib/checkout_op.tcl:174 ++#: lib/checkout_op.tcl:175 +#, tcl-format +msgid "Branch '%s' does not exist." +msgstr "Ветвь '%s' не существует " + - #: lib/checkout_op.tcl:193 ++#: lib/checkout_op.tcl:194 +#, tcl-format +msgid "Failed to configure simplified git-pull for '%s'." +msgstr "Ошибка создания упрощённой конфигурации git pull для '%s'." + - #: lib/checkout_op.tcl:228 ++#: lib/checkout_op.tcl:229 +#, tcl-format +msgid "" +"Branch '%s' already exists.\n" +"\n" +"It cannot fast-forward to %s.\n" +"A merge is required." +msgstr "" +"Ветвь '%s' уже существует.\n" +"\n" +"Она не может быть прокручена(fast-forward) к %s.\n" +"Требуется слияние." + - #: lib/checkout_op.tcl:242 ++#: lib/checkout_op.tcl:243 +#, tcl-format +msgid "Merge strategy '%s' not supported." +msgstr "Неизвестная стратегия слияния: '%s'." + - #: lib/checkout_op.tcl:261 ++#: lib/checkout_op.tcl:262 +#, tcl-format +msgid "Failed to update '%s'." +msgstr "Не удалось обновить '%s'." + - #: lib/checkout_op.tcl:273 ++#: lib/checkout_op.tcl:274 +msgid "Staging area (index) is already locked." +msgstr "Рабочая область заблокирована другим процессом." + - #: lib/checkout_op.tcl:288 ++#: lib/checkout_op.tcl:289 +msgid "" +"Last scanned state does not match repository state.\n" +"\n" +"Another Git program has modified this repository since the last scan. A " +"rescan must be performed before the current branch can be changed.\n" +"\n" +"The rescan will be automatically started now.\n" +msgstr "" +"Последнее прочитанное состояние репозитория не соответствует текущему.\n" +"\n" +"С момента последней проверки репозиторий был изменен другой программой Git. " +"Необходимо перечитать репозиторий, прежде чем изменять текущую ветвь.\n" +"\n" +"Это будет сделано сейчас автоматически.\n" + - #: lib/checkout_op.tcl:344 ++#: lib/checkout_op.tcl:345 +#, tcl-format +msgid "Updating working directory to '%s'..." +msgstr "Обновление рабочего каталога из '%s'..." + - #: lib/checkout_op.tcl:345 ++#: lib/checkout_op.tcl:346 +msgid "files checked out" +msgstr "файлы извлечены" + - #: lib/checkout_op.tcl:375 ++#: lib/checkout_op.tcl:376 +#, tcl-format +msgid "Aborted checkout of '%s' (file level merging is required)." +msgstr "Прерван переход на '%s' (требуется слияние содержания файлов)" + - #: lib/checkout_op.tcl:376 ++#: lib/checkout_op.tcl:377 +msgid "File level merge required." +msgstr "Требуется слияние содержания файлов." + - #: lib/checkout_op.tcl:380 ++#: lib/checkout_op.tcl:381 +#, tcl-format +msgid "Staying on branch '%s'." +msgstr "Ветвь '%s' остается текущей." + - #: lib/checkout_op.tcl:451 ++#: lib/checkout_op.tcl:452 +msgid "" +"You are no longer on a local branch.\n" +"\n" +"If you wanted to be on a branch, create one now starting from 'This Detached " +"Checkout'." +msgstr "" +"Вы находитесь не в локальной ветви.\n" +"\n" +"Если вы хотите снова вернуться к какой-нибудь ветви, создайте ее сейчас, " +"начиная с 'Текущего отсоединенного состояния'." + - #: lib/checkout_op.tcl:468 lib/checkout_op.tcl:472 ++#: lib/checkout_op.tcl:503 lib/checkout_op.tcl:507 +#, tcl-format +msgid "Checked out '%s'." +msgstr "Ветвь '%s' сделана текущей." + - #: lib/checkout_op.tcl:500 ++#: lib/checkout_op.tcl:535 +#, tcl-format +msgid "Resetting '%s' to '%s' will lose the following commits:" +msgstr "Сброс '%s' в '%s' приведет к потере следующих сохраненных состояний: " + - #: lib/checkout_op.tcl:522 ++#: lib/checkout_op.tcl:557 +msgid "Recovering lost commits may not be easy." +msgstr "Восстановить потерянные сохраненные состояния будет сложно." + - #: lib/checkout_op.tcl:527 ++#: lib/checkout_op.tcl:562 +#, tcl-format +msgid "Reset '%s'?" +msgstr "Сбросить '%s'?" + - #: lib/checkout_op.tcl:532 lib/merge.tcl:164 lib/tools_dlg.tcl:343 ++#: lib/checkout_op.tcl:567 lib/merge.tcl:164 lib/tools_dlg.tcl:343 +msgid "Visualize" +msgstr "Наглядно" + - #: lib/checkout_op.tcl:600 ++#: lib/checkout_op.tcl:635 +#, tcl-format +msgid "" +"Failed to set current branch.\n" +"\n" +"This working directory is only partially switched. We successfully updated " +"your files, but failed to update an internal Git file.\n" +"\n" +"This should not have occurred. %s will now close and give up." +msgstr "" +"Не удалось установить текущую ветвь.\n" +"\n" +"Ваш рабочий каталог обновлен только частично. Были обновлены все файлы кроме " +"служебных файлов Git. \n" +"\n" +"Этого не должно было произойти. %s завершается." + +#: lib/choose_font.tcl:39 +msgid "Select" +msgstr "Выбрать" + +#: lib/choose_font.tcl:53 +msgid "Font Family" +msgstr "Шрифт" + +#: lib/choose_font.tcl:74 +msgid "Font Size" +msgstr "Размер шрифта" + +#: lib/choose_font.tcl:91 +msgid "Font Example" +msgstr "Пример текста" + +#: lib/choose_font.tcl:103 +msgid "" +"This is example text.\n" +"If you like this text, it can be your font." +msgstr "" +"Это пример текста.\n" +"Если Вам нравится этот текст, это может быть Ваш шрифт." + +#: lib/choose_repository.tcl:28 +msgid "Git Gui" +msgstr "Git Gui" + - #: lib/choose_repository.tcl:87 lib/choose_repository.tcl:382 ++#: lib/choose_repository.tcl:87 lib/choose_repository.tcl:386 +msgid "Create New Repository" +msgstr "Создать новый репозиторий" + +#: lib/choose_repository.tcl:93 +msgid "New..." +msgstr "Новый..." + - #: lib/choose_repository.tcl:100 lib/choose_repository.tcl:465 ++#: lib/choose_repository.tcl:100 lib/choose_repository.tcl:471 +msgid "Clone Existing Repository" +msgstr "Склонировать существующий репозиторий" + +#: lib/choose_repository.tcl:106 +msgid "Clone..." +msgstr "Склонировать..." + - #: lib/choose_repository.tcl:113 lib/choose_repository.tcl:983 ++#: lib/choose_repository.tcl:113 lib/choose_repository.tcl:1016 +msgid "Open Existing Repository" +msgstr "Выбрать существующий репозиторий" + +#: lib/choose_repository.tcl:119 +msgid "Open..." +msgstr "Открыть..." + +#: lib/choose_repository.tcl:132 +msgid "Recent Repositories" +msgstr "Недавние репозитории" + +#: lib/choose_repository.tcl:138 +msgid "Open Recent Repository:" +msgstr "Открыть последний репозиторий" + - #: lib/choose_repository.tcl:302 lib/choose_repository.tcl:309 - #: lib/choose_repository.tcl:316 ++#: lib/choose_repository.tcl:306 lib/choose_repository.tcl:313 ++#: lib/choose_repository.tcl:320 +#, tcl-format +msgid "Failed to create repository %s:" +msgstr "Не удалось создать репозиторий %s:" + - #: lib/choose_repository.tcl:387 ++#: lib/choose_repository.tcl:391 +msgid "Directory:" +msgstr "Каталог:" + - #: lib/choose_repository.tcl:417 lib/choose_repository.tcl:544 - #: lib/choose_repository.tcl:1017 ++#: lib/choose_repository.tcl:423 lib/choose_repository.tcl:550 ++#: lib/choose_repository.tcl:1052 +msgid "Git Repository" +msgstr "Репозиторий" + - #: lib/choose_repository.tcl:442 ++#: lib/choose_repository.tcl:448 +#, tcl-format +msgid "Directory %s already exists." +msgstr "Каталог '%s' уже существует." + - #: lib/choose_repository.tcl:446 ++#: lib/choose_repository.tcl:452 +#, tcl-format +msgid "File %s already exists." +msgstr "Файл '%s' уже существует." + - #: lib/choose_repository.tcl:460 ++#: lib/choose_repository.tcl:466 +msgid "Clone" +msgstr "Склонировать" + - #: lib/choose_repository.tcl:473 ++#: lib/choose_repository.tcl:479 +msgid "Source Location:" +msgstr "Исходное положение:" + - #: lib/choose_repository.tcl:484 ++#: lib/choose_repository.tcl:490 +msgid "Target Directory:" +msgstr "Каталог назначения:" + - #: lib/choose_repository.tcl:496 ++#: lib/choose_repository.tcl:502 +msgid "Clone Type:" +msgstr "Тип клона:" + - #: lib/choose_repository.tcl:502 ++#: lib/choose_repository.tcl:508 +msgid "Standard (Fast, Semi-Redundant, Hardlinks)" +msgstr "Стандартный (Быстрый, полуизбыточный, \"жесткие\" ссылки)" + - #: lib/choose_repository.tcl:508 ++#: lib/choose_repository.tcl:514 +msgid "Full Copy (Slower, Redundant Backup)" +msgstr "Полная копия (Медленный, создает резервную копию)" + - #: lib/choose_repository.tcl:514 ++#: lib/choose_repository.tcl:520 +msgid "Shared (Fastest, Not Recommended, No Backup)" +msgstr "Общий (Самый быстрый, не рекомендуется, без резервной копии)" + - #: lib/choose_repository.tcl:550 lib/choose_repository.tcl:597 - #: lib/choose_repository.tcl:743 lib/choose_repository.tcl:813 - #: lib/choose_repository.tcl:1023 lib/choose_repository.tcl:1031 ++#: lib/choose_repository.tcl:556 lib/choose_repository.tcl:603 ++#: lib/choose_repository.tcl:749 lib/choose_repository.tcl:819 ++#: lib/choose_repository.tcl:1058 lib/choose_repository.tcl:1066 +#, tcl-format +msgid "Not a Git repository: %s" +msgstr "Каталог не является репозиторием: %s" + - #: lib/choose_repository.tcl:586 ++#: lib/choose_repository.tcl:592 +msgid "Standard only available for local repository." +msgstr "Стандартный клон возможен только для локального репозитория." + - #: lib/choose_repository.tcl:590 ++#: lib/choose_repository.tcl:596 +msgid "Shared only available for local repository." +msgstr "Общий клон возможен только для локального репозитория." + - #: lib/choose_repository.tcl:611 ++#: lib/choose_repository.tcl:617 +#, tcl-format +msgid "Location %s already exists." +msgstr "Путь '%s' уже существует." + - #: lib/choose_repository.tcl:622 ++#: lib/choose_repository.tcl:628 +msgid "Failed to configure origin" +msgstr "Не могу сконфигурировать исходный репозиторий." + - #: lib/choose_repository.tcl:634 ++#: lib/choose_repository.tcl:640 +msgid "Counting objects" +msgstr "Считаю объекты" + - #: lib/choose_repository.tcl:635 ++#: lib/choose_repository.tcl:641 +msgid "buckets" +msgstr "" + - #: lib/choose_repository.tcl:659 ++#: lib/choose_repository.tcl:665 +#, tcl-format +msgid "Unable to copy objects/info/alternates: %s" +msgstr "Не могу скопировать objects/info/alternates: %s" + - #: lib/choose_repository.tcl:695 ++#: lib/choose_repository.tcl:701 +#, tcl-format +msgid "Nothing to clone from %s." +msgstr "Нечего клонировать с %s." + - #: lib/choose_repository.tcl:697 lib/choose_repository.tcl:911 - #: lib/choose_repository.tcl:923 ++#: lib/choose_repository.tcl:703 lib/choose_repository.tcl:917 ++#: lib/choose_repository.tcl:929 +msgid "The 'master' branch has not been initialized." +msgstr "Не инициализирована ветвь 'master'." + - #: lib/choose_repository.tcl:710 ++#: lib/choose_repository.tcl:716 +msgid "Hardlinks are unavailable. Falling back to copying." +msgstr "\"Жесткие ссылки\" недоступны. Будет использовано копирование." + - #: lib/choose_repository.tcl:722 ++#: lib/choose_repository.tcl:728 +#, tcl-format +msgid "Cloning from %s" +msgstr "Клонирование %s" + - #: lib/choose_repository.tcl:753 ++#: lib/choose_repository.tcl:759 +msgid "Copying objects" +msgstr "Копирование objects" + - #: lib/choose_repository.tcl:754 ++#: lib/choose_repository.tcl:760 +msgid "KiB" +msgstr "КБ" + - #: lib/choose_repository.tcl:778 ++#: lib/choose_repository.tcl:784 +#, tcl-format +msgid "Unable to copy object: %s" +msgstr "Не могу скопировать объект: %s" + - #: lib/choose_repository.tcl:788 ++#: lib/choose_repository.tcl:794 +msgid "Linking objects" +msgstr "Создание ссылок на objects" + - #: lib/choose_repository.tcl:789 ++#: lib/choose_repository.tcl:795 +msgid "objects" +msgstr "объекты" + - #: lib/choose_repository.tcl:797 ++#: lib/choose_repository.tcl:803 +#, tcl-format +msgid "Unable to hardlink object: %s" +msgstr "Не могу \"жестко связать\" объект: %s" + - #: lib/choose_repository.tcl:852 ++#: lib/choose_repository.tcl:858 +msgid "Cannot fetch branches and objects. See console output for details." +msgstr "" +"Не могу получить ветви и объекты. Дополнительная информация на консоли." + - #: lib/choose_repository.tcl:863 ++#: lib/choose_repository.tcl:869 +msgid "Cannot fetch tags. See console output for details." +msgstr "Не могу получить метки. Дополнительная информация на консоли." + - #: lib/choose_repository.tcl:887 ++#: lib/choose_repository.tcl:893 +msgid "Cannot determine HEAD. See console output for details." +msgstr "Не могу определить HEAD. Дополнительная информация на консоли." + - #: lib/choose_repository.tcl:896 ++#: lib/choose_repository.tcl:902 +#, tcl-format +msgid "Unable to cleanup %s" +msgstr "Не могу очистить %s" + - #: lib/choose_repository.tcl:902 ++#: lib/choose_repository.tcl:908 +msgid "Clone failed." +msgstr "Клонирование не удалось." + - #: lib/choose_repository.tcl:909 ++#: lib/choose_repository.tcl:915 +msgid "No default branch obtained." +msgstr "Не было получено ветви по умолчанию." + - #: lib/choose_repository.tcl:920 ++#: lib/choose_repository.tcl:926 +#, tcl-format +msgid "Cannot resolve %s as a commit." +msgstr "Не могу распознать %s как состояние." + - #: lib/choose_repository.tcl:932 ++#: lib/choose_repository.tcl:938 +msgid "Creating working directory" +msgstr "Создаю рабочий каталог" + - #: lib/choose_repository.tcl:933 lib/index.tcl:65 lib/index.tcl:128 - #: lib/index.tcl:196 ++#: lib/choose_repository.tcl:939 lib/index.tcl:67 lib/index.tcl:130 ++#: lib/index.tcl:198 +msgid "files" +msgstr "файлов" + - #: lib/choose_repository.tcl:962 ++#: lib/choose_repository.tcl:968 +msgid "Initial file checkout failed." +msgstr "Не удалось получить начальное состояние файлов репозитория." + - #: lib/choose_repository.tcl:978 ++#: lib/choose_repository.tcl:1011 +msgid "Open" +msgstr "Открыть" + - #: lib/choose_repository.tcl:988 ++#: lib/choose_repository.tcl:1021 +msgid "Repository:" +msgstr "Репозиторий:" + - #: lib/choose_repository.tcl:1037 ++#: lib/choose_repository.tcl:1072 +#, tcl-format +msgid "Failed to open repository %s:" +msgstr "Не удалось открыть репозиторий %s:" + +#: lib/choose_rev.tcl:53 +msgid "This Detached Checkout" +msgstr "Текущее отсоединенное состояние" + +#: lib/choose_rev.tcl:60 +msgid "Revision Expression:" +msgstr "Выражение для определения версии:" + +#: lib/choose_rev.tcl:74 +msgid "Local Branch" +msgstr "Локальная ветвь:" + +#: lib/choose_rev.tcl:79 +msgid "Tracking Branch" +msgstr "Ветвь слежения" + +#: lib/choose_rev.tcl:84 lib/choose_rev.tcl:538 +msgid "Tag" +msgstr "Метка" + +#: lib/choose_rev.tcl:317 +#, tcl-format +msgid "Invalid revision: %s" +msgstr "Неверная версия: %s" + +#: lib/choose_rev.tcl:338 +msgid "No revision selected." +msgstr "Версия не указана." + +#: lib/choose_rev.tcl:346 +msgid "Revision expression is empty." +msgstr "Пустое выражение для определения версии." + +#: lib/choose_rev.tcl:531 +msgid "Updated" +msgstr "Обновлено" + +#: lib/choose_rev.tcl:559 +msgid "URL" +msgstr "Ссылка" + +#: lib/commit.tcl:9 +msgid "" +"There is nothing to amend.\n" +"\n" +"You are about to create the initial commit. There is no commit before this " +"to amend.\n" +msgstr "" +"Отсутствует состояние для исправления.\n" +"\n" +"Вы создаете первое состояние в репозитории, здесь еще нечего исправлять.\n" + +#: lib/commit.tcl:18 +msgid "" +"Cannot amend while merging.\n" +"\n" +"You are currently in the middle of a merge that has not been fully " +"completed. You cannot amend the prior commit unless you first abort the " +"current merge activity.\n" +msgstr "" +"Невозможно исправить состояние во время операции слияния.\n" +"\n" +"Текущее слияние не завершено. Невозможно исправить предыдущее сохраненное " +"состояние, не прерывая эту операцию.\n" + +#: lib/commit.tcl:48 +msgid "Error loading commit data for amend:" +msgstr "Ошибка при загрузке данных для исправления сохраненного состояния:" + +#: lib/commit.tcl:75 +msgid "Unable to obtain your identity:" +msgstr "Невозможно получить информацию об авторстве:" + +#: lib/commit.tcl:80 +msgid "Invalid GIT_COMMITTER_IDENT:" +msgstr "Неверный GIT_COMMITTER_IDENT:" + - #: lib/commit.tcl:132 ++#: lib/commit.tcl:129 ++#, tcl-format ++msgid "warning: Tcl does not support encoding '%s'." ++msgstr "предупреждение: Tcl не поддерживает кодировку '%s'." ++ ++#: lib/commit.tcl:149 +msgid "" +"Last scanned state does not match repository state.\n" +"\n" +"Another Git program has modified this repository since the last scan. A " +"rescan must be performed before another commit can be created.\n" +"\n" +"The rescan will be automatically started now.\n" +msgstr "" +"Последнее прочитанное состояние репозитория не соответствует текущему.\n" +"\n" +"С момента последней проверки репозиторий был изменен другой программой Git. " +"Необходимо перечитать репозиторий, прежде чем изменять текущую ветвь. \n" +"\n" +"Это будет сделано сейчас автоматически.\n" + - #: lib/commit.tcl:155 ++#: lib/commit.tcl:172 +#, tcl-format +msgid "" +"Unmerged files cannot be committed.\n" +"\n" +"File %s has merge conflicts. You must resolve them and stage the file " +"before committing.\n" +msgstr "" - "Нельзя сохранить файлы с незавершённой операцей слияния.\n" ++"Нельзя сохранить файлы с незавершённой операцией слияния.\n" +"\n" +"Для файла %s возник конфликт слияния. Разрешите конфликт и добавьте к " +"подготовленным файлам перед сохранением.\n" + - #: lib/commit.tcl:163 ++#: lib/commit.tcl:180 +#, tcl-format +msgid "" +"Unknown file state %s detected.\n" +"\n" +"File %s cannot be committed by this program.\n" +msgstr "" +"Обнаружено неизвестное состояние файла %s.\n" +"\n" +"Файл %s не может быть сохранен данной программой.\n" + - #: lib/commit.tcl:171 ++#: lib/commit.tcl:188 +msgid "" +"No changes to commit.\n" +"\n" +"You must stage at least 1 file before you can commit.\n" +msgstr "" +"Отсутствуют изменения для сохранения.\n" +"\n" +"Подготовьте хотя бы один файл до создания сохраненного состояния.\n" + - #: lib/commit.tcl:186 ++#: lib/commit.tcl:203 +msgid "" +"Please supply a commit message.\n" +"\n" +"A good commit message has the following format:\n" +"\n" +"- First line: Describe in one sentence what you did.\n" +"- Second line: Blank\n" +"- Remaining lines: Describe why this change is good.\n" +msgstr "" +"Напишите комментарий к сохраненному состоянию.\n" +"\n" +"Рекомендуется следующий формат комментария:\n" +"\n" +"- первая строка: краткое описание сделанных изменений.\n" +"- вторая строка пустая\n" +"- оставшиеся строки: опишите, что дают ваши изменения.\n" + - #: lib/commit.tcl:210 - #, tcl-format - msgid "warning: Tcl does not support encoding '%s'." - msgstr "предупреждение: Tcl не поддерживает кодировку '%s'." - - #: lib/commit.tcl:226 ++#: lib/commit.tcl:234 +msgid "Calling pre-commit hook..." +msgstr "Вызов программы поддержки репозитория pre-commit..." + - #: lib/commit.tcl:241 ++#: lib/commit.tcl:249 +msgid "Commit declined by pre-commit hook." +msgstr "Сохранение прервано программой поддержки репозитория pre-commit" + - #: lib/commit.tcl:264 ++#: lib/commit.tcl:272 +msgid "Calling commit-msg hook..." +msgstr "Вызов программы поддержки репозитория commit-msg..." + - #: lib/commit.tcl:279 ++#: lib/commit.tcl:287 +msgid "Commit declined by commit-msg hook." +msgstr "Сохранение прервано программой поддержки репозитория commit-msg" + - #: lib/commit.tcl:292 ++#: lib/commit.tcl:300 +msgid "Committing changes..." +msgstr "Сохранение изменений..." + - #: lib/commit.tcl:308 ++#: lib/commit.tcl:316 +msgid "write-tree failed:" +msgstr "Программа write-tree завершилась с ошибкой:" + - #: lib/commit.tcl:309 lib/commit.tcl:353 lib/commit.tcl:373 ++#: lib/commit.tcl:317 lib/commit.tcl:361 lib/commit.tcl:382 +msgid "Commit failed." +msgstr "Сохранить состояние не удалось." + - #: lib/commit.tcl:326 ++#: lib/commit.tcl:334 +#, tcl-format +msgid "Commit %s appears to be corrupt" +msgstr "Состояние %s выглядит поврежденным" + - #: lib/commit.tcl:331 ++#: lib/commit.tcl:339 +msgid "" +"No changes to commit.\n" +"\n" +"No files were modified by this commit and it was not a merge commit.\n" +"\n" +"A rescan will be automatically started now.\n" +msgstr "" +"Отсутствуют изменения для сохранения.\n" +"\n" +"Ни один файл не был изменен и не было слияния.\n" +"\n" +"Сейчас автоматически запустится перечитывание репозитория.\n" + - #: lib/commit.tcl:338 ++#: lib/commit.tcl:346 +msgid "No changes to commit." - msgstr "Отуствуют измения для сохранения." ++msgstr "Отсутствуют изменения для сохранения." + - #: lib/commit.tcl:352 ++#: lib/commit.tcl:360 +msgid "commit-tree failed:" +msgstr "Программа commit-tree завершилась с ошибкой:" + - #: lib/commit.tcl:372 ++#: lib/commit.tcl:381 +msgid "update-ref failed:" +msgstr "Программа update-ref завершилась с ошибкой:" + - #: lib/commit.tcl:460 ++#: lib/commit.tcl:469 +#, tcl-format +msgid "Created commit %s: %s" +msgstr "Создано состояние %s: %s " + +#: lib/console.tcl:59 +msgid "Working... please wait..." +msgstr "В процессе... пожалуйста, ждите..." + +#: lib/console.tcl:186 +msgid "Success" +msgstr "Процесс успешно завершен" + +#: lib/console.tcl:200 +msgid "Error: Command Failed" +msgstr "Ошибка: не удалось выполнить команду" + +#: lib/database.tcl:43 +msgid "Number of loose objects" +msgstr "Количество несвязанных объектов" + +#: lib/database.tcl:44 +msgid "Disk space used by loose objects" +msgstr "Объем дискового пространства, занятый несвязанными объектами" + +#: lib/database.tcl:45 +msgid "Number of packed objects" +msgstr "Количество упакованных объектов" + +#: lib/database.tcl:46 +msgid "Number of packs" +msgstr "Количество pack-файлов" + +#: lib/database.tcl:47 +msgid "Disk space used by packed objects" +msgstr "Объем дискового пространства, занятый упакованными объектами" + +#: lib/database.tcl:48 +msgid "Packed objects waiting for pruning" +msgstr "Несвязанные объекты, которые можно удалить" + +#: lib/database.tcl:49 +msgid "Garbage files" +msgstr "Мусор" + +#: lib/database.tcl:72 +msgid "Compressing the object database" +msgstr "Сжатие базы объектов" + +#: lib/database.tcl:83 +msgid "Verifying the object database with fsck-objects" +msgstr "Проверка базы объектов при помощи fsck" + - #: lib/database.tcl:108 ++#: lib/database.tcl:107 +#, tcl-format +msgid "" +"This repository currently has approximately %i loose objects.\n" +"\n" +"To maintain optimal performance it is strongly recommended that you compress " - "the database when more than %i loose objects exist.\n" ++"the database.\n" +"\n" +"Compress the database now?" +msgstr "" +"Этот репозиторий сейчас содержит примерно %i свободных объектов\n" +"\n" - "Для лучшей производительности рекомендуется сжать базу данных, когда есть " - "более %i несвязанных объектов.\n" ++"Для лучшей производительности рекомендуется сжать базу данных.\n" +"\n" +"Сжать базу данных сейчас?" + +#: lib/date.tcl:25 +#, tcl-format +msgid "Invalid date from Git: %s" +msgstr "Неправильная дата в репозитории: %s" + - #: lib/diff.tcl:59 ++#: lib/diff.tcl:64 +#, tcl-format +msgid "" +"No differences detected.\n" +"\n" +"%s has no changes.\n" +"\n" +"The modification date of this file was updated by another application, but " +"the content within the file was not changed.\n" +"\n" +"A rescan will be automatically started to find other files which may have " +"the same state." +msgstr "" +"Изменений не обнаружено.\n" +"\n" - "в %s отутствуют изменения.\n" ++"в %s отсутствуют изменения.\n" +"\n" +"Дата изменения файла была обновлена другой программой, но содержимое файла " +"осталось прежним.\n" +"\n" +"Сейчас будет запущено перечитывание репозитория, чтобы найти подобные файлы." + - #: lib/diff.tcl:99 ++#: lib/diff.tcl:104 +#, tcl-format +msgid "Loading diff of %s..." +msgstr "Загрузка изменений в %s..." + - #: lib/diff.tcl:120 ++#: lib/diff.tcl:125 +msgid "" +"LOCAL: deleted\n" +"REMOTE:\n" +msgstr "" +"ЛОКАЛЬНО: удалён\n" +"ВНЕШНИЙ:\n" + - #: lib/diff.tcl:125 ++#: lib/diff.tcl:130 +msgid "" +"REMOTE: deleted\n" +"LOCAL:\n" +msgstr "" +"ВНЕШНИЙ: удалён\n" +"ЛОКАЛЬНО:\n" + - #: lib/diff.tcl:132 ++#: lib/diff.tcl:137 +msgid "LOCAL:\n" +msgstr "ЛОКАЛЬНО:\n" + - #: lib/diff.tcl:135 ++#: lib/diff.tcl:140 +msgid "REMOTE:\n" +msgstr "ВНЕШНИЙ:\n" + - #: lib/diff.tcl:197 lib/diff.tcl:296 ++#: lib/diff.tcl:202 lib/diff.tcl:319 +#, tcl-format +msgid "Unable to display %s" +msgstr "Не могу показать %s" + - #: lib/diff.tcl:198 ++#: lib/diff.tcl:203 +msgid "Error loading file:" +msgstr "Ошибка загрузки файла:" + - #: lib/diff.tcl:205 ++#: lib/diff.tcl:210 +msgid "Git Repository (subproject)" +msgstr "Репозиторий Git (подпроект)" + - #: lib/diff.tcl:217 ++#: lib/diff.tcl:222 +msgid "* Binary file (not showing content)." +msgstr "* Двоичный файл (содержимое не показано)" + - #: lib/diff.tcl:222 ++#: lib/diff.tcl:227 +#, tcl-format +msgid "" +"* Untracked file is %d bytes.\n" +"* Showing only first %d bytes.\n" +msgstr "" - "* Размер неподготовленого файла %d байт.\n" ++"* Размер неподготовленного файла %d байт.\n" +"* Показано первых %d байт.\n" + - #: lib/diff.tcl:228 ++#: lib/diff.tcl:233 +#, tcl-format +msgid "" +"\n" +"* Untracked file clipped here by %s.\n" +"* To see the entire file, use an external editor.\n" +msgstr "" +"\n" - "* Неподготовленый файл обрезан: %s.\n" ++"* Неподготовленный файл обрезан: %s.\n" +"* Чтобы увидеть весь файл, используйте программу-редактор.\n" + - #: lib/diff.tcl:436 ++#: lib/diff.tcl:482 +msgid "Failed to unstage selected hunk." +msgstr "Не удалось исключить выбранную часть." + - #: lib/diff.tcl:443 ++#: lib/diff.tcl:489 +msgid "Failed to stage selected hunk." +msgstr "Не удалось подготовить к сохранению выбранную часть." + - #: lib/diff.tcl:509 ++#: lib/diff.tcl:568 +msgid "Failed to unstage selected line." +msgstr "Не удалось исключить выбранную строку." + - #: lib/diff.tcl:517 ++#: lib/diff.tcl:576 +msgid "Failed to stage selected line." +msgstr "Не удалось подготовить к сохранению выбранную строку." + +#: lib/encoding.tcl:443 +msgid "Default" +msgstr "По умолчанию" + +#: lib/encoding.tcl:448 +#, tcl-format +msgid "System (%s)" +msgstr "Системная (%s)" + +#: lib/encoding.tcl:459 lib/encoding.tcl:465 +msgid "Other" +msgstr "Другая" + +#: lib/error.tcl:20 lib/error.tcl:114 +msgid "error" +msgstr "ошибка" + +#: lib/error.tcl:36 +msgid "warning" +msgstr "предупреждение" + +#: lib/error.tcl:94 +msgid "You must correct the above errors before committing." +msgstr "Прежде чем сохранить, исправьте вышеуказанные ошибки." + +#: lib/index.tcl:6 +msgid "Unable to unlock the index." +msgstr "Не удалось разблокировать индекс" + +#: lib/index.tcl:15 +msgid "Index Error" +msgstr "Ошибка в индексе" + - #: lib/index.tcl:21 ++#: lib/index.tcl:17 +msgid "" +"Updating the Git index failed. A rescan will be automatically started to " +"resynchronize git-gui." +msgstr "" - "Не удалось обновить индекс Git. Состояние репозитория будетперечитано " ++"Не удалось обновить индекс Git. Состояние репозитория будет перечитано " +"автоматически." + - #: lib/index.tcl:27 ++#: lib/index.tcl:28 +msgid "Continue" +msgstr "Продолжить" + +#: lib/index.tcl:31 +msgid "Unlock Index" +msgstr "Разблокировать индекс" + - #: lib/index.tcl:287 ++#: lib/index.tcl:289 +#, tcl-format +msgid "Unstaging %s from commit" +msgstr "Удаление %s из подготовленного" + - #: lib/index.tcl:326 ++#: lib/index.tcl:328 +msgid "Ready to commit." +msgstr "Подготовлено для сохранения" + - #: lib/index.tcl:339 ++#: lib/index.tcl:341 +#, tcl-format +msgid "Adding %s" +msgstr "Добавление %s..." + - #: lib/index.tcl:396 ++#: lib/index.tcl:398 +#, tcl-format +msgid "Revert changes in file %s?" +msgstr "Отменить изменения в файле %s?" + - #: lib/index.tcl:398 ++#: lib/index.tcl:400 +#, tcl-format +msgid "Revert changes in these %i files?" +msgstr "Отменить изменения в %i файле(-ах)?" + - #: lib/index.tcl:406 ++#: lib/index.tcl:408 +msgid "Any unstaged changes will be permanently lost by the revert." +msgstr "" +"Любые изменения, не подготовленные к сохранению, будут потеряны при данной " +"операции." + - #: lib/index.tcl:409 ++#: lib/index.tcl:411 +msgid "Do Nothing" +msgstr "Ничего не делать" + - #: lib/index.tcl:427 ++#: lib/index.tcl:429 +msgid "Reverting selected files" - msgstr "Удаление изменений в выбраных файлах" ++msgstr "Удаление изменений в выбранных файлах" + - #: lib/index.tcl:431 ++#: lib/index.tcl:433 +#, tcl-format +msgid "Reverting %s" +msgstr "Отмена изменений в %s" + +#: lib/merge.tcl:13 +msgid "" +"Cannot merge while amending.\n" +"\n" +"You must finish amending this commit before starting any type of merge.\n" +msgstr "" +"Невозможно выполнить слияние во время исправления.\n" +"\n" +"Завершите исправление данного состояния перед выполнением операции слияния.\n" + +#: lib/merge.tcl:27 +msgid "" +"Last scanned state does not match repository state.\n" +"\n" +"Another Git program has modified this repository since the last scan. A " +"rescan must be performed before a merge can be performed.\n" +"\n" +"The rescan will be automatically started now.\n" +msgstr "" +"Последнее прочитанное состояние репозитория не соответствует текущему.\n" +"\n" +"С момента последней проверки репозиторий был изменен другой программой Git. " +"Необходимо перечитать репозиторий, прежде чем изменять текущую ветвь.\n" +"\n" +"Это будет сделано сейчас автоматически.\n" + +#: lib/merge.tcl:45 +#, tcl-format +msgid "" +"You are in the middle of a conflicted merge.\n" +"\n" +"File %s has merge conflicts.\n" +"\n" +"You must resolve them, stage the file, and commit to complete the current " +"merge. Only then can you begin another merge.\n" +msgstr "" +"Предыдущее слияние не завершено из-за конфликта.\n" +"\n" +"Для файла %s возник конфликт слияния.\n" +"\n" +"Разрешите конфликт, подготовьте файл и сохраните. Только после этого можно " +"начать следующее слияние.\n" + +#: lib/merge.tcl:55 +#, tcl-format +msgid "" +"You are in the middle of a change.\n" +"\n" +"File %s is modified.\n" +"\n" +"You should complete the current commit before starting a merge. Doing so " +"will help you abort a failed merge, should the need arise.\n" +msgstr "" +"Изменения не сохранены.\n" +"\n" +"Файл %s изменен.\n" +"\n" - "Подготовьте и сохраните измения перед началом слияния. В случае " ++"Подготовьте и сохраните изменения перед началом слияния. В случае " +"необходимости это позволит прервать операцию слияния.\n" + +#: lib/merge.tcl:107 +#, tcl-format +msgid "%s of %s" +msgstr "%s из %s" + +#: lib/merge.tcl:120 +#, tcl-format +msgid "Merging %s and %s..." +msgstr "Слияние %s и %s..." + +#: lib/merge.tcl:131 +msgid "Merge completed successfully." +msgstr "Слияние успешно завершено." + +#: lib/merge.tcl:133 +msgid "Merge failed. Conflict resolution is required." +msgstr "Не удалось завершить слияние. Требуется разрешение конфликта." + +#: lib/merge.tcl:158 +#, tcl-format +msgid "Merge Into %s" +msgstr "Слияние с %s" + +#: lib/merge.tcl:177 +msgid "Revision To Merge" +msgstr "Версия, с которой провести слияние" + +#: lib/merge.tcl:212 +msgid "" +"Cannot abort while amending.\n" +"\n" +"You must finish amending this commit.\n" +msgstr "" +"Невозможно прервать исправление.\n" +"\n" +"Завершите текущее исправление сохраненного состояния.\n" + +#: lib/merge.tcl:222 +msgid "" +"Abort merge?\n" +"\n" +"Aborting the current merge will cause *ALL* uncommitted changes to be lost.\n" +"\n" +"Continue with aborting the current merge?" +msgstr "" +"Прервать операцию слияния?\n" +"\n" +"Прерывание этой операции приведет к потере *ВСЕХ* несохраненных изменений.\n" +"\n" +"Продолжить?" + +#: lib/merge.tcl:228 +msgid "" +"Reset changes?\n" +"\n" +"Resetting the changes will cause *ALL* uncommitted changes to be lost.\n" +"\n" +"Continue with resetting the current changes?" +msgstr "" +"Прервать операцию слияния?\n" +"\n" +"Прерывание этой операции приведет к потере *ВСЕХ* несохраненных изменений.\n" +"\n" +"Продолжить?" + +#: lib/merge.tcl:239 +msgid "Aborting" +msgstr "Прерываю" + +#: lib/merge.tcl:239 +msgid "files reset" +msgstr "изменения в файлах отменены" + +#: lib/merge.tcl:267 +msgid "Abort failed." +msgstr "Прервать не удалось." + +#: lib/merge.tcl:269 +msgid "Abort completed. Ready." +msgstr "Прервано." + +#: lib/mergetool.tcl:8 +msgid "Force resolution to the base version?" +msgstr "Использовать базовую версию для разрешения конфликта?" + +#: lib/mergetool.tcl:9 +msgid "Force resolution to this branch?" +msgstr "Использовать версию этой ветви для разрешения конфликта?" + +#: lib/mergetool.tcl:10 +msgid "Force resolution to the other branch?" +msgstr "Использовать версию другой ветви для разрешения конфликта?" + +#: lib/mergetool.tcl:14 +#, tcl-format +msgid "" +"Note that the diff shows only conflicting changes.\n" +"\n" +"%s will be overwritten.\n" +"\n" +"This operation can be undone only by restarting the merge." +msgstr "" +"Внимание! Список изменений показывает только конфликтующие отличия.\n" +"\n" +"%s будет переписан.\n" +"\n" +"Это действие можно отменить только перезапуском операции слияния." + +#: lib/mergetool.tcl:45 +#, tcl-format +msgid "File %s seems to have unresolved conflicts, still stage?" +msgstr "" - "Файл %s кажется содержит необработаные конфликты. Продолжить подготовку к " ++"Файл %s, похоже, содержит необработанные конфликты. Продолжить подготовку к " +"сохранению?" + +#: lib/mergetool.tcl:60 +#, tcl-format +msgid "Adding resolution for %s" +msgstr "Добавляю результат разрешения для %s" + +#: lib/mergetool.tcl:141 +msgid "Cannot resolve deletion or link conflicts using a tool" +msgstr "" +"Программа слияния не обрабатывает конфликты с удалением или участием ссылок" + +#: lib/mergetool.tcl:146 +msgid "Conflict file does not exist" +msgstr "Конфликтующий файл не существует" + +#: lib/mergetool.tcl:264 +#, tcl-format +msgid "Not a GUI merge tool: '%s'" +msgstr "'%s' не является программой слияния" + +#: lib/mergetool.tcl:268 +#, tcl-format +msgid "Unsupported merge tool '%s'" +msgstr "Неизвестная программа слияния '%s'" + +#: lib/mergetool.tcl:303 +msgid "Merge tool is already running, terminate it?" +msgstr "Программа слияния уже работает. Прервать?" + +#: lib/mergetool.tcl:323 +#, tcl-format +msgid "" +"Error retrieving versions:\n" +"%s" +msgstr "" +"Ошибка получения версий:\n" +"%s" + +#: lib/mergetool.tcl:343 +#, tcl-format +msgid "" +"Could not start the merge tool:\n" +"\n" +"%s" +msgstr "" +"Ошибка запуска программы слияния:\n" +"\n" +"%s" + +#: lib/mergetool.tcl:347 +msgid "Running merge tool..." +msgstr "Запуск программы слияния..." + +#: lib/mergetool.tcl:375 lib/mergetool.tcl:383 +msgid "Merge tool failed." +msgstr "Ошибка выполнения программы слияния." + +#: lib/option.tcl:11 +#, tcl-format +msgid "Invalid global encoding '%s'" +msgstr "Ошибка в глобальной установке кодировки '%s'" + +#: lib/option.tcl:19 +#, tcl-format +msgid "Invalid repo encoding '%s'" +msgstr "Неверная кодировка репозитория: '%s'" + +#: lib/option.tcl:117 +msgid "Restore Defaults" +msgstr "Восстановить настройки по умолчанию" + +#: lib/option.tcl:121 +msgid "Save" +msgstr "Сохранить" + +#: lib/option.tcl:131 +#, tcl-format +msgid "%s Repository" +msgstr "Для репозитория %s" + +#: lib/option.tcl:132 +msgid "Global (All Repositories)" +msgstr "Общие (для всех репозиториев)" + +#: lib/option.tcl:138 +msgid "User Name" +msgstr "Имя пользователя" + +#: lib/option.tcl:139 +msgid "Email Address" +msgstr "Адрес электронной почты" + +#: lib/option.tcl:141 +msgid "Summarize Merge Commits" +msgstr "Суммарный комментарий при слиянии" + +#: lib/option.tcl:142 +msgid "Merge Verbosity" +msgstr "Уровень детальности сообщений при слиянии" + +#: lib/option.tcl:143 +msgid "Show Diffstat After Merge" +msgstr "Показать отчет об изменениях после слияния" + +#: lib/option.tcl:144 +msgid "Use Merge Tool" +msgstr "Использовать для слияния программу" + +#: lib/option.tcl:146 +msgid "Trust File Modification Timestamps" +msgstr "Доверять времени модификации файла" + +#: lib/option.tcl:147 +msgid "Prune Tracking Branches During Fetch" +msgstr "Чистка ветвей слежения при получении изменений" + +#: lib/option.tcl:148 +msgid "Match Tracking Branches" +msgstr "Имя новой ветви взять из имен ветвей слежения" + +#: lib/option.tcl:149 +msgid "Blame Copy Only On Changed Files" +msgstr "Поиск копий только в изменённых файлах" + +#: lib/option.tcl:150 +msgid "Minimum Letters To Blame Copy On" +msgstr "Минимальное количество символов для поиска копий" + +#: lib/option.tcl:151 +msgid "Blame History Context Radius (days)" +msgstr "Радиус исторического контекста (в днях)" + +#: lib/option.tcl:152 +msgid "Number of Diff Context Lines" +msgstr "Число строк в контексте diff" + +#: lib/option.tcl:153 +msgid "Commit Message Text Width" +msgstr "Ширина текста комментария" + +#: lib/option.tcl:154 +msgid "New Branch Name Template" +msgstr "Шаблон для имени новой ветви" + +#: lib/option.tcl:155 +msgid "Default File Contents Encoding" +msgstr "Кодировка содержания файла по умолчанию" + +#: lib/option.tcl:203 +msgid "Change" +msgstr "Изменить" + +#: lib/option.tcl:230 +msgid "Spelling Dictionary:" +msgstr "Словарь для проверки правописания:" + +#: lib/option.tcl:254 +msgid "Change Font" +msgstr "Изменить" + +#: lib/option.tcl:258 +#, tcl-format +msgid "Choose %s" +msgstr "Выберите %s" + +# carbon copy +#: lib/option.tcl:264 +msgid "pt." +msgstr "pt." + +#: lib/option.tcl:278 +msgid "Preferences" +msgstr "Настройки" + +#: lib/option.tcl:314 +msgid "Failed to completely save options:" +msgstr "Не удалось полностью сохранить настройки:" + +#: lib/remote.tcl:163 +msgid "Remove Remote" +msgstr "Удалить ссылку на внешний репозиторий" + +#: lib/remote.tcl:168 +msgid "Prune from" +msgstr "Чистка" + +#: lib/remote.tcl:173 +msgid "Fetch from" +msgstr "Получение из" + +#: lib/remote.tcl:215 +msgid "Push to" +msgstr "Отправить" + +#: lib/remote_add.tcl:19 +msgid "Add Remote" +msgstr "Зарегистрировать внешний репозиторий" + +#: lib/remote_add.tcl:24 +msgid "Add New Remote" +msgstr "Добавить внешний репозиторий" + +#: lib/remote_add.tcl:28 lib/tools_dlg.tcl:36 +msgid "Add" +msgstr "" + +#: lib/remote_add.tcl:37 +msgid "Remote Details" +msgstr "Информация о внешнем репозитории" + +#: lib/remote_add.tcl:50 +msgid "Location:" +msgstr "Положение:" + +#: lib/remote_add.tcl:62 +msgid "Further Action" +msgstr "Следующая операция" + +#: lib/remote_add.tcl:65 +msgid "Fetch Immediately" +msgstr "Скачать сразу" + +#: lib/remote_add.tcl:71 +msgid "Initialize Remote Repository and Push" +msgstr "Инициализировать внешний репозиторий и отправить" + +#: lib/remote_add.tcl:77 +msgid "Do Nothing Else Now" +msgstr "Больше ничего не делать" + +#: lib/remote_add.tcl:101 +msgid "Please supply a remote name." +msgstr "Укажите название внешнего репозитория." + +#: lib/remote_add.tcl:114 +#, tcl-format +msgid "'%s' is not an acceptable remote name." +msgstr "Недопустимое название внешнего репозитория '%s'." + +#: lib/remote_add.tcl:125 +#, tcl-format +msgid "Failed to add remote '%s' of location '%s'." +msgstr "Не удалось добавить '%s' из '%s'. " + +#: lib/remote_add.tcl:133 lib/transport.tcl:6 +#, tcl-format +msgid "fetch %s" +msgstr "получение %s" + +#: lib/remote_add.tcl:134 +#, tcl-format +msgid "Fetching the %s" +msgstr "Получение %s" + +#: lib/remote_add.tcl:157 +#, tcl-format +msgid "Do not know how to initialize repository at location '%s'." - msgstr "Невозможно инициалировать репозиторий в '%s'." ++msgstr "Невозможно инициализировать репозиторий в '%s'." + +#: lib/remote_add.tcl:163 lib/transport.tcl:25 lib/transport.tcl:63 +#: lib/transport.tcl:81 +#, tcl-format +msgid "push %s" +msgstr "отправить %s" + +#: lib/remote_add.tcl:164 +#, tcl-format +msgid "Setting up the %s (at %s)" +msgstr "Настройка %s (в %s)" + +#: lib/remote_branch_delete.tcl:29 lib/remote_branch_delete.tcl:34 +msgid "Delete Branch Remotely" +msgstr "Удаление ветви во внешнем репозитории" + +#: lib/remote_branch_delete.tcl:47 +msgid "From Repository" +msgstr "Из репозитория" + +#: lib/remote_branch_delete.tcl:50 lib/transport.tcl:134 +msgid "Remote:" +msgstr "внешний:" + +#: lib/remote_branch_delete.tcl:66 lib/transport.tcl:149 +msgid "Arbitrary Location:" - msgstr "Указаное положение:" ++msgstr "Указанное положение:" + +#: lib/remote_branch_delete.tcl:84 +msgid "Branches" +msgstr "Ветви" + +#: lib/remote_branch_delete.tcl:109 +msgid "Delete Only If" +msgstr "Удалить только в случае, если" + +#: lib/remote_branch_delete.tcl:111 +msgid "Merged Into:" +msgstr "Слияние с:" + - #: lib/remote_branch_delete.tcl:119 - msgid "Always (Do not perform merge checks)" - msgstr "Всегда (не выполнять проверку на слияние)" - +#: lib/remote_branch_delete.tcl:152 +msgid "A branch is required for 'Merged Into'." +msgstr "Для опции 'Слияние с' требуется указать ветвь." + +#: lib/remote_branch_delete.tcl:184 +#, tcl-format +msgid "" +"The following branches are not completely merged into %s:\n" +"\n" +" - %s" +msgstr "" +"Следующие ветви могут быть объединены с %s при помощи операции слияния:\n" +"\n" +" - %s" + +#: lib/remote_branch_delete.tcl:189 +#, tcl-format +msgid "" +"One or more of the merge tests failed because you have not fetched the " +"necessary commits. Try fetching from %s first." +msgstr "" +"Некоторые тесты на слияние не прошли, потому что Вы не получили необходимые " +"состояния. Попытайтесь получить их из %s." + +#: lib/remote_branch_delete.tcl:207 +msgid "Please select one or more branches to delete." +msgstr "Укажите одну или несколько ветвей для удаления." + - #: lib/remote_branch_delete.tcl:216 - msgid "" - "Recovering deleted branches is difficult.\n" - "\n" - "Delete the selected branches?" - msgstr "" - "Восстановить удаленные ветви сложно.\n" - "\n" - "Продолжить?" - +#: lib/remote_branch_delete.tcl:226 +#, tcl-format +msgid "Deleting branches from %s" +msgstr "Удаление ветвей из %s" + - #: lib/remote_branch_delete.tcl:286 ++#: lib/remote_branch_delete.tcl:292 +msgid "No repository selected." +msgstr "Не указан репозиторий." + - #: lib/remote_branch_delete.tcl:291 ++#: lib/remote_branch_delete.tcl:297 +#, tcl-format +msgid "Scanning %s..." +msgstr "Перечитывание %s... " + +#: lib/search.tcl:21 +msgid "Find:" +msgstr "Поиск:" + +#: lib/search.tcl:23 +msgid "Next" +msgstr "Дальше" + +#: lib/search.tcl:24 +msgid "Prev" +msgstr "Обратно" + +#: lib/search.tcl:25 +msgid "Case-Sensitive" +msgstr "Игн. большие/маленькие" + - #: lib/shortcut.tcl:20 lib/shortcut.tcl:61 ++#: lib/shortcut.tcl:21 lib/shortcut.tcl:62 +msgid "Cannot write shortcut:" +msgstr "Невозможно записать ссылку:" + - #: lib/shortcut.tcl:136 ++#: lib/shortcut.tcl:137 +msgid "Cannot write icon:" +msgstr "Невозможно записать значок:" + +#: lib/spellcheck.tcl:57 +msgid "Unsupported spell checker" +msgstr "Неподдерживаемая программа проверки правописания" + +#: lib/spellcheck.tcl:65 +msgid "Spell checking is unavailable" +msgstr "Проверка правописания не доступна" + +#: lib/spellcheck.tcl:68 +msgid "Invalid spell checking configuration" +msgstr "Неправильная конфигурация программы проверки правописания" + +#: lib/spellcheck.tcl:70 +#, tcl-format +msgid "Reverting dictionary to %s." +msgstr "Словарь вернут к %s." + +#: lib/spellcheck.tcl:73 +msgid "Spell checker silently failed on startup" - msgstr "Программа проверки правописания не смогла запустится" ++msgstr "Программа проверки правописания не смогла запуститься" + +#: lib/spellcheck.tcl:80 +msgid "Unrecognized spell checker" - msgstr "Нераспознаная программа проверки правописания" ++msgstr "Нераспознанная программа проверки правописания" + +#: lib/spellcheck.tcl:186 +msgid "No Suggestions" +msgstr "Исправлений не найдено" + +#: lib/spellcheck.tcl:388 +msgid "Unexpected EOF from spell checker" +msgstr "Программа проверки правописания прервала передачу данных" + +#: lib/spellcheck.tcl:392 +msgid "Spell Checker Failed" +msgstr "Ошибка проверки правописания" + +#: lib/sshkey.tcl:31 +msgid "No keys found." +msgstr "Ключ не найден" + +#: lib/sshkey.tcl:34 +#, tcl-format +msgid "Found a public key in: %s" +msgstr "Публичный ключ из %s" + +#: lib/sshkey.tcl:40 +msgid "Generate Key" +msgstr "Создать ключ" + +#: lib/sshkey.tcl:56 +msgid "Copy To Clipboard" +msgstr "Скопировать в буфер обмена" + +#: lib/sshkey.tcl:70 +msgid "Your OpenSSH Public Key" +msgstr "Ваш публичный ключ OpenSSH" + +#: lib/sshkey.tcl:78 +msgid "Generating..." +msgstr "Создание..." + +#: lib/sshkey.tcl:84 +#, tcl-format +msgid "" +"Could not start ssh-keygen:\n" +"\n" +"%s" +msgstr "" +"Ошибка запуска ssh-keygen:\n" +"\n" +"%s" + +#: lib/sshkey.tcl:111 +msgid "Generation failed." +msgstr "Ключ не создан." + +#: lib/sshkey.tcl:118 +msgid "Generation succeded, but no keys found." +msgstr "Создание ключа завершилось, но результат не был найден" + +#: lib/sshkey.tcl:121 +#, tcl-format +msgid "Your key is in: %s" +msgstr "Ваш ключ находится в: %s" + +#: lib/status_bar.tcl:83 +#, tcl-format +msgid "%s ... %*i of %*i %s (%3i%%)" +msgstr "%s ... %*i из %*i %s (%3i%%)" + +#: lib/tools.tcl:75 +#, tcl-format +msgid "Running %s requires a selected file." +msgstr "Запуск %s требует выбранного файла." + +#: lib/tools.tcl:90 +#, tcl-format +msgid "Are you sure you want to run %s?" +msgstr "Действительно запустить %s?" + +#: lib/tools.tcl:110 +#, tcl-format +msgid "Tool: %s" +msgstr "Вспомогательная операция: %s" + +#: lib/tools.tcl:111 +#, tcl-format +msgid "Running: %s" +msgstr "Выполнение: %s" + +#: lib/tools.tcl:149 +#, tcl-format +msgid "Tool completed successfully: %s" +msgstr "Программа %s завершилась успешно." + +#: lib/tools.tcl:151 +#, tcl-format +msgid "Tool failed: %s" +msgstr "Ошибка выполнения программы: %s" + +#: lib/tools_dlg.tcl:22 +msgid "Add Tool" +msgstr "Добавить вспомогательную операцию" + +#: lib/tools_dlg.tcl:28 +msgid "Add New Tool Command" +msgstr "Новая вспомогательная операция" + +#: lib/tools_dlg.tcl:33 +msgid "Add globally" +msgstr "Добавить для всех репозиториев" + +#: lib/tools_dlg.tcl:45 +msgid "Tool Details" +msgstr "Описание вспомогательной операции" + +#: lib/tools_dlg.tcl:48 +msgid "Use '/' separators to create a submenu tree:" - msgstr "Испольуйте '/' для создания подменю" ++msgstr "Используйте '/' для создания подменю" + +#: lib/tools_dlg.tcl:61 +msgid "Command:" +msgstr "Команда:" + +#: lib/tools_dlg.tcl:74 +msgid "Show a dialog before running" +msgstr "Показать диалог перед запуском" + +#: lib/tools_dlg.tcl:80 +msgid "Ask the user to select a revision (sets $REVISION)" +msgstr "Запрос на выбор версии (устанавливает $REVISION)" + +#: lib/tools_dlg.tcl:85 +msgid "Ask the user for additional arguments (sets $ARGS)" +msgstr "Запрос дополнительных аргументов (устанавливает $ARGS)" + +#: lib/tools_dlg.tcl:92 +msgid "Don't show the command output window" +msgstr "Не показывать окно вывода команды" + +#: lib/tools_dlg.tcl:97 +msgid "Run only if a diff is selected ($FILENAME not empty)" +msgstr "Запуск только если показан список изменений ($FILENAME не пусто)" + +#: lib/tools_dlg.tcl:121 +msgid "Please supply a name for the tool." +msgstr "Укажите название вспомогательной операции." + +#: lib/tools_dlg.tcl:129 +#, tcl-format +msgid "Tool '%s' already exists." +msgstr "Вспомогательная операция '%s' уже существует." + +#: lib/tools_dlg.tcl:151 +#, tcl-format +msgid "" +"Could not add tool:\n" +"%s" +msgstr "" +"Ошибка добавления программы:\n" +"%s" + +#: lib/tools_dlg.tcl:190 +msgid "Remove Tool" +msgstr "Удалить программу" + +#: lib/tools_dlg.tcl:196 +msgid "Remove Tool Commands" +msgstr "Удалить команды программы" + +#: lib/tools_dlg.tcl:200 +msgid "Remove" +msgstr "Удалить" + +#: lib/tools_dlg.tcl:236 +msgid "(Blue denotes repository-local tools)" +msgstr "(Синим выделены программы локальные репозиторию)" + +#: lib/tools_dlg.tcl:297 +#, tcl-format +msgid "Run Command: %s" +msgstr "Запуск команды: %s" + +#: lib/tools_dlg.tcl:311 +msgid "Arguments" +msgstr "Аргументы" + +#: lib/tools_dlg.tcl:348 +msgid "OK" +msgstr "OK" + +#: lib/transport.tcl:7 +#, tcl-format +msgid "Fetching new changes from %s" +msgstr "Получение изменений из %s " + +# carbon copy +#: lib/transport.tcl:18 +#, tcl-format +msgid "remote prune %s" +msgstr "чистка внешнего %s" + +#: lib/transport.tcl:19 +#, tcl-format +msgid "Pruning tracking branches deleted from %s" +msgstr "Чистка ветвей слежения, удаленных из %s" + +#: lib/transport.tcl:26 +#, tcl-format +msgid "Pushing changes to %s" +msgstr "Отправка изменений в %s " + +#: lib/transport.tcl:64 +#, tcl-format +msgid "Mirroring to %s" +msgstr "Точное копирование в %s" + +#: lib/transport.tcl:82 +#, tcl-format +msgid "Pushing %s %s to %s" +msgstr "Отправка %s %s в %s" + +#: lib/transport.tcl:100 +msgid "Push Branches" +msgstr "Отправить изменения в ветвях" + +#: lib/transport.tcl:114 +msgid "Source Branches" +msgstr "Исходные ветви" + +#: lib/transport.tcl:131 +msgid "Destination Repository" +msgstr "Репозиторий назначения" + +#: lib/transport.tcl:169 +msgid "Transfer Options" +msgstr "Настройки отправки" + +#: lib/transport.tcl:171 +msgid "Force overwrite existing branch (may discard changes)" +msgstr "Намеренно переписать существующую ветвь (возможна потеря изменений)" + +#: lib/transport.tcl:175 +msgid "Use thin pack (for slow network connections)" +msgstr "Использовать thin pack (для медленных сетевых подключений)" + +#: lib/transport.tcl:179 +msgid "Include tags" +msgstr "Передать метки"