From: Junio C Hamano Date: Wed, 15 Sep 2010 19:34:37 +0000 (-0700) Subject: Merge git://repo.or.cz/git-gui X-Git-Tag: v1.7.3-rc2~7 X-Git-Url: https://git.tokkee.org/?a=commitdiff_plain;h=12644fa99fd16c33379c885670be0963cec07fc1;p=git.git Merge git://repo.or.cz/git-gui * 'master' of git://repo.or.cz/git-gui: git-gui 0.13 git-gui: avoid mis-encoding the copyright message on Windows. git-gui: Update Swedish translation (521t). git-gui: ensure correct application termination in git-gui--askpass git-gui: handle textconv filter on Windows and in development git-gui: use shell to launch textconv filter in "blame" git-gui: display error launching blame as a message box. git-gui: Make usage statement visible on Windows. --- 12644fa99fd16c33379c885670be0963cec07fc1 diff --cc git-gui/GIT-VERSION-GEN index b3f937eac,000000000..1fb4d9b4b mode 100755,000000..100755 --- a/git-gui/GIT-VERSION-GEN +++ b/git-gui/GIT-VERSION-GEN @@@ -1,80 -1,0 +1,80 @@@ +#!/bin/sh + +GVF=GIT-VERSION-FILE - DEF_VER=0.12.GITGUI ++DEF_VER=0.13.GITGUI + +LF=' +' + +tree_search () +{ + head=$1 + tree=$2 + for p in $(git rev-list --parents --max-count=1 $head 2>/dev/null) + do + test $tree = $(git rev-parse $p^{tree} 2>/dev/null) && + vn=$(git describe --abbrev=4 $p 2>/dev/null) && + case "$vn" in + gitgui-[0-9]*) echo $vn; break;; + esac + done +} + +# Always use the tarball version file if found, just +# in case we are somehow contained in a larger git +# repository that doesn't actually track our state. +# (At least one package manager is doing this.) +# +# We may be a subproject, so try looking for the merge +# commit that supplied this directory content if we are +# not at the toplevel. We probably will always be the +# second parent in the commit, but we shouldn't rely on +# that fact. +# +# If we are at the toplevel or the merge assumption fails +# try looking for a gitgui-* tag. + +if test -f version && + VN=$(cat version) +then + : happy +elif prefix="$(git rev-parse --show-prefix 2>/dev/null)" + test -n "$prefix" && + head=$(git rev-list --max-count=1 HEAD -- . 2>/dev/null) && + tree=$(git rev-parse --verify "HEAD:$prefix" 2>/dev/null) && + VN=$(tree_search $head $tree) + case "$VN" in + gitgui-[0-9]*) : happy ;; + *) (exit 1) ;; + esac +then + VN=$(echo "$VN" | sed -e 's/^gitgui-//;s/-/./g'); +elif VN=$(git describe --abbrev=4 HEAD 2>/dev/null) && + case "$VN" in + gitgui-[0-9]*) : happy ;; + *) (exit 1) ;; + esac +then + VN=$(echo "$VN" | sed -e 's/^gitgui-//;s/-/./g'); +else + VN="$DEF_VER" +fi + +dirty=$(sh -c 'git diff-index --name-only HEAD' 2>/dev/null) || dirty= +case "$dirty" in +'') + ;; +*) + VN="$VN-dirty" ;; +esac + +if test -r $GVF +then + VC=$(sed -e 's/^GITGUI_VERSION = //' <$GVF) +else + VC=unset +fi +test "$VN" = "$VC" || { + echo >&2 "GITGUI_VERSION = $VN" + echo "GITGUI_VERSION = $VN" >$GVF +} diff --cc git-gui/Makefile index 197b55edf,000000000..e22ba5c32 mode 100644,000000..100644 --- a/git-gui/Makefile +++ b/git-gui/Makefile @@@ -1,343 -1,0 +1,344 @@@ +all:: + +# Define V=1 to have a more verbose compile. +# +# Define NO_MSGFMT if you do not have msgfmt from the GNU gettext +# package and want to use our rough pure Tcl po->msg translator. +# TCL_PATH must be vaild for this to work. +# + +GIT-VERSION-FILE: FORCE + @$(SHELL_PATH) ./GIT-VERSION-GEN +-include GIT-VERSION-FILE + +uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not') +uname_O := $(shell sh -c 'uname -o 2>/dev/null || echo not') +uname_R := $(shell sh -c 'uname -r 2>/dev/null || echo not') + +SCRIPT_SH = git-gui.sh +GITGUI_MAIN := git-gui +GITGUI_BUILT_INS = git-citool +ALL_LIBFILES = $(wildcard lib/*.tcl) +PRELOAD_FILES = lib/class.tcl +NONTCL_LIBFILES = \ + lib/git-gui.ico \ + $(wildcard lib/win32_*.js) \ +#end NONTCL_LIBFILES + +ifndef SHELL_PATH + SHELL_PATH = /bin/sh +endif + +ifndef gitexecdir + gitexecdir := $(shell git --exec-path) +endif + +ifndef sharedir +ifeq (git-core,$(notdir $(gitexecdir))) + sharedir := $(dir $(patsubst %/,%,$(dir $(gitexecdir))))share +else + sharedir := $(dir $(gitexecdir))share +endif +endif + +ifndef INSTALL + INSTALL = install +endif + +RM_RF ?= rm -rf +RMDIR ?= rmdir + +INSTALL_D0 = $(INSTALL) -d -m 755 # space is required here +INSTALL_D1 = +INSTALL_R0 = $(INSTALL) -m 644 # space is required here +INSTALL_R1 = +INSTALL_X0 = $(INSTALL) -m 755 # space is required here +INSTALL_X1 = +INSTALL_A0 = find # space is required here +INSTALL_A1 = | cpio -pud +INSTALL_L0 = rm -f # space is required here +INSTALL_L1 = && ln # space is required here +INSTALL_L2 = +INSTALL_L3 = + +REMOVE_D0 = $(RMDIR) # space is required here +REMOVE_D1 = || true +REMOVE_F0 = $(RM_RF) # space is required here +REMOVE_F1 = +CLEAN_DST = true + +ifndef V + QUIET = @ + QUIET_GEN = $(QUIET)echo ' ' GEN '$@' && + QUIET_INDEX = $(QUIET)echo ' ' INDEX $(dir $@) && + QUIET_MSGFMT0 = $(QUIET)printf ' MSGFMT %12s ' $@ && v=` + QUIET_MSGFMT1 = 2>&1` && echo "$$v" | sed -e 's/fuzzy translations/fuzzy/' | sed -e 's/ messages*//g' + QUIET_2DEVNULL = 2>/dev/null + + INSTALL_D0 = dir= + INSTALL_D1 = && echo ' ' DEST $$dir && $(INSTALL) -d -m 755 "$$dir" + INSTALL_R0 = src= + INSTALL_R1 = && echo ' ' INSTALL 644 `basename $$src` && $(INSTALL) -m 644 $$src + INSTALL_X0 = src= + INSTALL_X1 = && echo ' ' INSTALL 755 `basename $$src` && $(INSTALL) -m 755 $$src + INSTALL_A0 = src= + INSTALL_A1 = && echo ' ' INSTALL ' ' `basename "$$src"` && find "$$src" | cpio -pud + + INSTALL_L0 = dst= + INSTALL_L1 = && src= + INSTALL_L2 = && dst= + INSTALL_L3 = && echo ' ' 'LINK ' `basename "$$dst"` '->' `basename "$$src"` && rm -f "$$dst" && ln "$$src" "$$dst" + + CLEAN_DST = echo ' ' UNINSTALL + REMOVE_D0 = dir= + REMOVE_D1 = && echo ' ' REMOVE $$dir && test -d "$$dir" && $(RMDIR) "$$dir" || true + REMOVE_F0 = dst= + REMOVE_F1 = && echo ' ' REMOVE `basename "$$dst"` && $(RM_RF) "$$dst" +endif + +TCLTK_PATH ?= wish +ifeq (./,$(dir $(TCLTK_PATH))) + TCL_PATH ?= $(subst wish,tclsh,$(TCLTK_PATH)) +else + TCL_PATH ?= $(dir $(TCLTK_PATH))$(notdir $(subst wish,tclsh,$(TCLTK_PATH))) +endif + +ifeq ($(uname_S),Darwin) + TKFRAMEWORK = /Library/Frameworks/Tk.framework/Resources/Wish.app + ifeq ($(shell echo "$(uname_R)" | awk -F. '{if ($$1 >= 9) print "y"}')_$(shell test -d $(TKFRAMEWORK) || echo n),y_n) + TKFRAMEWORK = /System/Library/Frameworks/Tk.framework/Resources/Wish.app + ifeq ($(shell test -d $(TKFRAMEWORK) || echo n),n) + TKFRAMEWORK = /System/Library/Frameworks/Tk.framework/Resources/Wish\ Shell.app + endif + endif + TKEXECUTABLE = $(shell basename "$(TKFRAMEWORK)" .app) +endif + +ifeq ($(findstring $(MAKEFLAGS),s),s) +QUIET_GEN = +endif + +-include config.mak + +DESTDIR_SQ = $(subst ','\'',$(DESTDIR)) +gitexecdir_SQ = $(subst ','\'',$(gitexecdir)) +SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH)) +TCL_PATH_SQ = $(subst ','\'',$(TCL_PATH)) +TCLTK_PATH_SQ = $(subst ','\'',$(TCLTK_PATH)) +TCLTK_PATH_SED = $(subst ','\'',$(subst \,\\,$(TCLTK_PATH))) + +gg_libdir ?= $(sharedir)/git-gui/lib +libdir_SQ = $(subst ','\'',$(gg_libdir)) +libdir_SED = $(subst ','\'',$(subst \,\\,$(gg_libdir_sed_in))) +exedir = $(dir $(gitexecdir))share/git-gui/lib + +GITGUI_SCRIPT := $$0 +GITGUI_RELATIVE := +GITGUI_MACOSXAPP := + +ifeq ($(uname_O),Cygwin) + GITGUI_SCRIPT := `cygpath --windows --absolute "$(GITGUI_SCRIPT)"` + + # Is this a Cygwin Tcl/Tk binary? If so it knows how to do + # POSIX path translation just like cygpath does and we must + # keep libdir in POSIX format so Cygwin packages of git-gui + # work no matter where the user installs them. + # + ifeq ($(shell echo 'puts [file normalize /]' | '$(TCL_PATH_SQ)'),$(shell cygpath --mixed --absolute /)) + gg_libdir_sed_in := $(gg_libdir) + else + gg_libdir_sed_in := $(shell cygpath --windows --absolute "$(gg_libdir)") + endif +else + ifeq ($(exedir),$(gg_libdir)) + GITGUI_RELATIVE := 1 + endif + gg_libdir_sed_in := $(gg_libdir) +endif +ifeq ($(uname_S),Darwin) + ifeq ($(shell test -d $(TKFRAMEWORK) && echo y),y) + GITGUI_MACOSXAPP := YesPlease + endif +endif +ifneq (,$(findstring MINGW,$(uname_S))) + NO_MSGFMT=1 + GITGUI_WINDOWS_WRAPPER := YesPlease + GITGUI_RELATIVE := 1 +endif + +ifdef GITGUI_MACOSXAPP +GITGUI_MAIN := git-gui.tcl + +git-gui: GIT-VERSION-FILE GIT-GUI-VARS + $(QUIET_GEN)rm -f $@ $@+ && \ + echo '#!$(SHELL_PATH_SQ)' >$@+ && \ + echo 'if test "z$$*" = zversion ||' >>$@+ && \ + echo ' test "z$$*" = z--version' >>$@+ && \ + echo then >>$@+ && \ + echo ' 'echo \'git-gui version '$(GITGUI_VERSION)'\' >>$@+ && \ + echo else >>$@+ && \ + echo ' 'exec \''$(libdir_SQ)/Git Gui.app/Contents/MacOS/$(subst \,,$(TKEXECUTABLE))'\' \ + '"$$0" "$$@"' >>$@+ && \ + echo fi >>$@+ && \ + chmod +x $@+ && \ + mv $@+ $@ + +Git\ Gui.app: GIT-VERSION-FILE GIT-GUI-VARS \ + macosx/Info.plist \ + macosx/git-gui.icns \ + macosx/AppMain.tcl \ + $(TKFRAMEWORK)/Contents/MacOS/$(TKEXECUTABLE) + $(QUIET_GEN)rm -rf '$@' '$@'+ && \ + mkdir -p '$@'+/Contents/MacOS && \ + mkdir -p '$@'+/Contents/Resources/Scripts && \ + cp '$(subst ','\'',$(subst \,,$(TKFRAMEWORK)/Contents/MacOS/$(TKEXECUTABLE)))' \ + '$@'+/Contents/MacOS && \ + cp macosx/git-gui.icns '$@'+/Contents/Resources && \ + sed -e 's/@@GITGUI_VERSION@@/$(GITGUI_VERSION)/g' \ + -e 's/@@GITGUI_TKEXECUTABLE@@/$(TKEXECUTABLE)/g' \ + macosx/Info.plist \ + >'$@'+/Contents/Info.plist && \ + sed -e 's|@@gitexecdir@@|$(gitexecdir_SQ)|' \ + -e 's|@@GITGUI_LIBDIR@@|$(libdir_SED)|' \ + macosx/AppMain.tcl \ + >'$@'+/Contents/Resources/Scripts/AppMain.tcl && \ + mv '$@'+ '$@' +endif + +ifdef GITGUI_WINDOWS_WRAPPER +GITGUI_MAIN := git-gui.tcl + +git-gui: windows/git-gui.sh + cp $< $@ +endif + +$(GITGUI_MAIN): git-gui.sh GIT-VERSION-FILE GIT-GUI-VARS + $(QUIET_GEN)rm -f $@ $@+ && \ + sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \ ++ -e 's|@@SHELL_PATH@@|$(SHELL_PATH_SQ)|' \ + -e '1,30s|^ argv0=$$0| argv0=$(GITGUI_SCRIPT)|' \ + -e '1,30s|^ exec wish | exec '\''$(TCLTK_PATH_SED)'\'' |' \ + -e 's/@@GITGUI_VERSION@@/$(GITGUI_VERSION)/g' \ + -e 's|@@GITGUI_RELATIVE@@|$(GITGUI_RELATIVE)|' \ + -e '$(GITGUI_RELATIVE)s|@@GITGUI_LIBDIR@@|$(libdir_SED)|' \ + git-gui.sh >$@+ && \ + chmod +x $@+ && \ + mv $@+ $@ + +XGETTEXT ?= xgettext +ifdef NO_MSGFMT + MSGFMT ?= $(TCL_PATH) po/po2msg.sh +else + MSGFMT ?= msgfmt + ifneq ($(shell $(MSGFMT) --tcl -l C -d . /dev/null 2>/dev/null; echo $$?),0) + MSGFMT := $(TCL_PATH) po/po2msg.sh + endif +endif + +msgsdir = $(gg_libdir)/msgs +msgsdir_SQ = $(subst ','\'',$(msgsdir)) +PO_TEMPLATE = po/git-gui.pot +ALL_POFILES = $(wildcard po/*.po) +ALL_MSGFILES = $(subst .po,.msg,$(ALL_POFILES)) + +$(PO_TEMPLATE): $(SCRIPT_SH) $(ALL_LIBFILES) + $(XGETTEXT) -kmc -LTcl -o $@ $(SCRIPT_SH) $(ALL_LIBFILES) +update-po:: $(PO_TEMPLATE) + $(foreach p, $(ALL_POFILES), echo Updating $p ; msgmerge -U $p $(PO_TEMPLATE) ; ) +$(ALL_MSGFILES): %.msg : %.po + $(QUIET_MSGFMT0)$(MSGFMT) --statistics --tcl -l $(basename $(notdir $<)) -d $(dir $@) $< $(QUIET_MSGFMT1) + +lib/tclIndex: $(ALL_LIBFILES) GIT-GUI-VARS + $(QUIET_INDEX)if echo \ + $(foreach p,$(PRELOAD_FILES),source $p\;) \ + auto_mkindex lib '*.tcl' \ + | $(TCL_PATH) $(QUIET_2DEVNULL); then : ok; \ + else \ + echo 1>&2 " * $(TCL_PATH) failed; using unoptimized loading"; \ + rm -f $@ ; \ + echo '# Autogenerated by git-gui Makefile' >$@ && \ + echo >>$@ && \ + $(foreach p,$(PRELOAD_FILES) $(ALL_LIBFILES),echo '$(subst lib/,,$p)' >>$@ &&) \ + echo >>$@ ; \ + fi + +TRACK_VARS = \ + $(subst ','\'',SHELL_PATH='$(SHELL_PATH_SQ)') \ + $(subst ','\'',TCL_PATH='$(TCL_PATH_SQ)') \ + $(subst ','\'',TCLTK_PATH='$(TCLTK_PATH_SQ)') \ + $(subst ','\'',gitexecdir='$(gitexecdir_SQ)') \ + $(subst ','\'',gg_libdir='$(libdir_SQ)') \ + GITGUI_MACOSXAPP=$(GITGUI_MACOSXAPP) \ +#end TRACK_VARS + +GIT-GUI-VARS: FORCE + @VARS='$(TRACK_VARS)'; \ + if test x"$$VARS" != x"`cat $@ 2>/dev/null`" ; then \ + echo 1>&2 " * new locations or Tcl/Tk interpreter"; \ + echo 1>$@ "$$VARS"; \ + fi + +ifdef GITGUI_MACOSXAPP +all:: git-gui Git\ Gui.app +endif +ifdef GITGUI_WINDOWS_WRAPPER +all:: git-gui +endif +all:: $(GITGUI_MAIN) lib/tclIndex $(ALL_MSGFILES) + +install: all + $(QUIET)$(INSTALL_D0)'$(DESTDIR_SQ)$(gitexecdir_SQ)' $(INSTALL_D1) + $(QUIET)$(INSTALL_X0)git-gui $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' + $(QUIET)$(INSTALL_X0)git-gui--askpass $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' + $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(INSTALL_L0)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L1)'$(DESTDIR_SQ)$(gitexecdir_SQ)/git-gui' $(INSTALL_L2)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L3) &&) true +ifdef GITGUI_WINDOWS_WRAPPER + $(QUIET)$(INSTALL_R0)git-gui.tcl $(INSTALL_R1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' +endif + $(QUIET)$(INSTALL_D0)'$(DESTDIR_SQ)$(libdir_SQ)' $(INSTALL_D1) + $(QUIET)$(INSTALL_R0)lib/tclIndex $(INSTALL_R1) '$(DESTDIR_SQ)$(libdir_SQ)' +ifdef GITGUI_MACOSXAPP + $(QUIET)$(INSTALL_A0)'Git Gui.app' $(INSTALL_A1) '$(DESTDIR_SQ)$(libdir_SQ)' + $(QUIET)$(INSTALL_X0)git-gui.tcl $(INSTALL_X1) '$(DESTDIR_SQ)$(libdir_SQ)' +endif + $(QUIET)$(foreach p,$(ALL_LIBFILES) $(NONTCL_LIBFILES), $(INSTALL_R0)$p $(INSTALL_R1) '$(DESTDIR_SQ)$(libdir_SQ)' &&) true + $(QUIET)$(INSTALL_D0)'$(DESTDIR_SQ)$(msgsdir_SQ)' $(INSTALL_D1) + $(QUIET)$(foreach p,$(ALL_MSGFILES), $(INSTALL_R0)$p $(INSTALL_R1) '$(DESTDIR_SQ)$(msgsdir_SQ)' &&) true + +uninstall: + $(QUIET)$(CLEAN_DST) '$(DESTDIR_SQ)$(gitexecdir_SQ)' + $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui $(REMOVE_F1) + $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askpass $(REMOVE_F1) + $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/$p $(REMOVE_F1) &&) true +ifdef GITGUI_WINDOWS_WRAPPER + $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui.tcl $(REMOVE_F1) +endif + $(QUIET)$(CLEAN_DST) '$(DESTDIR_SQ)$(libdir_SQ)' + $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(libdir_SQ)'/tclIndex $(REMOVE_F1) +ifdef GITGUI_MACOSXAPP + $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(libdir_SQ)/Git Gui.app' $(REMOVE_F1) + $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(libdir_SQ)'/git-gui.tcl $(REMOVE_F1) +endif + $(QUIET)$(foreach p,$(ALL_LIBFILES) $(NONTCL_LIBFILES), $(REMOVE_F0)'$(DESTDIR_SQ)$(libdir_SQ)'/$(notdir $p) $(REMOVE_F1) &&) true + $(QUIET)$(CLEAN_DST) '$(DESTDIR_SQ)$(msgsdir_SQ)' + $(QUIET)$(foreach p,$(ALL_MSGFILES), $(REMOVE_F0)'$(DESTDIR_SQ)$(msgsdir_SQ)'/$(notdir $p) $(REMOVE_F1) &&) true + $(QUIET)$(REMOVE_D0)'$(DESTDIR_SQ)$(gitexecdir_SQ)' $(REMOVE_D1) + $(QUIET)$(REMOVE_D0)'$(DESTDIR_SQ)$(msgsdir_SQ)' $(REMOVE_D1) + $(QUIET)$(REMOVE_D0)'$(DESTDIR_SQ)$(libdir_SQ)' $(REMOVE_D1) + $(QUIET)$(REMOVE_D0)`dirname '$(DESTDIR_SQ)$(libdir_SQ)'` $(REMOVE_D1) + +dist-version: + @mkdir -p $(TARDIR) + @echo $(GITGUI_VERSION) > $(TARDIR)/version + +clean:: + $(RM_RF) $(GITGUI_MAIN) lib/tclIndex po/*.msg + $(RM_RF) GIT-VERSION-FILE GIT-GUI-VARS +ifdef GITGUI_MACOSXAPP + $(RM_RF) 'Git Gui.app'* git-gui +endif +ifdef GITGUI_WINDOWS_WRAPPER + $(RM_RF) git-gui +endif + +.PHONY: all install uninstall dist-version clean +.PHONY: FORCE diff --cc git-gui/git-gui--askpass index 12e117ecb,000000000..4277f30c4 mode 100755,000000..100755 --- a/git-gui/git-gui--askpass +++ b/git-gui/git-gui--askpass @@@ -1,59 -1,0 +1,66 @@@ +#!/bin/sh +# Tcl ignores the next line -*- tcl -*- \ +exec wish "$0" -- "$@" + +# This is a trivial implementation of an SSH_ASKPASS handler. +# Git-gui uses this script if none are already configured. + ++package require Tk ++ +set answer {} +set yesno 0 +set rc 255 + +if {$argc < 1} { + set prompt "Enter your OpenSSH passphrase:" +} else { + set prompt [join $argv " "] + if {[regexp -nocase {\(yes\/no\)\?\s*$} $prompt]} { + set yesno 1 + } +} + +message .m -text $prompt -justify center -aspect 4000 +pack .m -side top -fill x -padx 20 -pady 20 -expand 1 + +entry .e -textvariable answer -width 50 +pack .e -side top -fill x -padx 10 -pady 10 + +if {!$yesno} { + .e configure -show "*" +} + +frame .b +button .b.ok -text OK -command finish - button .b.cancel -text Cancel -command {destroy .} ++button .b.cancel -text Cancel -command cancel + +pack .b.ok -side left -expand 1 +pack .b.cancel -side right -expand 1 +pack .b -side bottom -fill x -padx 10 -pady 10 + +bind . {focus -force .e} - bind . finish - bind . {destroy .} - bind . {exit $rc} ++bind . [list .b.ok invoke] ++bind . [list .b.cancel invoke] ++bind . {set rc $rc} ++ ++proc cancel {} { ++ set ::rc 255 ++} + +proc finish {} { + if {$::yesno} { + if {$::answer ne "yes" && $::answer ne "no"} { + tk_messageBox -icon error -title "Error" -type ok \ + -message "Only 'yes' or 'no' input allowed." + return + } + } + - set ::rc 0 + puts $::answer - destroy . ++ set ::rc 0 +} + +wm title . "OpenSSH" +tk::PlaceWindow . ++vwait rc ++exit $rc diff --cc git-gui/git-gui.sh index bb104895a,000000000..4617f29c2 mode 100755,000000..100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@@ -1,3802 -1,0 +1,3826 @@@ +#!/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 [encoding convertfrom utf-8 { - Copyright © 2006, 2007 Shawn Pearce, et. al. ++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 + } +} + +###################################################################### +## +## Internationalization (i18n) through msgcat and gettext. See +## http://www.gnu.org/software/gettext/manual/html_node/Tcl.html + +package require msgcat + +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 +} + ++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 {} + } + } + 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 + + # 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 +} + +set _real_git_version $_git_version +regsub -- {[\-\.]dirty$} $_git_version {} _git_version +regsub {\.[0-9]+\.g[0-9a-f]+$} $_git_version {} _git_version +regsub {\.[a-zA-Z]+\.?[0-9]+$} $_git_version {} _git_version +regsub {\.GIT$} $_git_version {} _git_version +regsub {\.[a-zA-Z]+\.?[0-9]+$} $_git_version {} _git_version + +if {![regexp {^[1-9]+(\.[0-9]+)+$} $_git_version]} { + catch {wm withdraw .} + if {[tk_messageBox \ + -icon warning \ + -type yesno \ + -default no \ + -title "[appname]: warning" \ + -message [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 +# try to set work tree from environment, falling back to core.worktree +if {[catch { set _gitworktree $env(GIT_WORK_TREE) }]} { + set _gitworktree [get_config core.worktree] + if {$_gitworktree eq ""} { + set _gitworktree [file dirname [file normalize $_gitdir]] + } +} +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" + } + + 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 +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"}} + {T_ {mc "File type changed, staged"}} + + {_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 {} { - puts stderr "usage: $::argv0 $::subcommand $::subcommand_args" ++ set s "usage: $::argv0 $::subcommand $::subcommand_args" ++ if {[tk windowingsystem] eq "win32"} { ++ wm withdraw . ++ tk_messageBox -icon info -title "Usage" -message $s ++ } 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]} { + 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]} { - puts stderr [mc "fatal: cannot stat path %s: No such file or directory" $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} { + puts -nonewline stderr "usage: $argv0" + if {$subcommand ne {gui} + && [file tail $argv0] ne "git-$subcommand"} { + puts -nonewline stderr " $subcommand" + } + puts stderr {} + exit 1 + } + # fall through to setup UI for commits +} +default { + puts stderr "usage: $argv0 \[{blame|browser|citool}\]" + 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 +${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 + +$ui_diff tag conf d_cr -elide true +$ui_diff tag conf d_@ -foreground blue -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<<<<<<< \ + -foreground orange \ + -font font_diffbold +$ui_diff tag conf d======= \ + -foreground orange \ + -font font_diffbold +$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 + || [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/blame.tcl index 2137ec968,000000000..61e358f96 mode 100644,000000..100644 --- a/git-gui/lib/blame.tcl +++ b/git-gui/lib/blame.tcl @@@ -1,1332 -1,0 +1,1339 @@@ +# git-gui blame viewer +# Copyright (C) 2006, 2007 Shawn Pearce + +class blame { + +image create photo ::blame::img_back_arrow -data {R0lGODlhGAAYAIUAAPwCBEzKXFTSZIz+nGzmhGzqfGTidIT+nEzGXHTqhGzmfGzifFzadETCVES+VARWDFzWbHzyjAReDGTadFTOZDSyRDyyTCymPARaFGTedFzSbDy2TCyqRCyqPARaDAyCHES6VDy6VCyiPAR6HCSeNByWLARyFARiDARqFGTifARiFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAYABgAAAajQIBwSCwaj8ikcsk0BppJwRPqHEypQwHBis0WDAdEFyBIKBaMAKLBdjQeSkFBYTBAIvgEoS6JmhUTEwIUDQ4VFhcMGEhyCgoZExoUaxsWHB0THkgfAXUGAhoBDSAVFR0XBnCbDRmgog0hpSIiDJpJIyEQhBUcJCIlwA22SSYVogknEg8eD82qSigdDSknY0IqJQXPYxIl1dZCGNvWw+Dm510GQQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7} + +# Persistant data (survives loads) +# +field history {}; # viewer history: {commit path} +field header ; # array commit,key -> header field + +# Tk UI control paths +# +field w ; # top window in this viewer +field w_back ; # our back button +field w_path ; # label showing the current file path +field w_columns ; # list of all column widgets in the viewer +field w_line ; # text column: all line numbers +field w_amov ; # text column: annotations + move tracking +field w_asim ; # text column: annotations (simple computation) +field w_file ; # text column: actual file data +field w_cviewer ; # pane showing commit message +field finder ; # find mini-dialog frame +field status ; # status mega-widget instance +field old_height ; # last known height of $w.file_pane + + +# Tk UI colors +# +variable active_color #c0edc5 +variable group_colors { + #d6d6d6 + #e1e1e1 + #ececec +} + +# Current blame data; cleared/reset on each load +# +field commit ; # input commit to blame +field path ; # input filename to view in $commit + +field current_fd {} ; # background process running +field highlight_line -1 ; # current line selected +field highlight_column {} ; # current commit column selected +field highlight_commit {} ; # sha1 of commit selected + +field total_lines 0 ; # total length of file +field blame_lines 0 ; # number of lines computed +field amov_data ; # list of {commit origfile origline} +field asim_data ; # list of {commit origfile origline} + +field r_commit ; # commit currently being parsed +field r_orig_line ; # original line number +field r_final_line ; # final line number +field r_line_count ; # lines in this region + +field tooltip_wm {} ; # Current tooltip toplevel, if open +field tooltip_t {} ; # Text widget in $tooltip_wm +field tooltip_timer {} ; # Current timer event for our tooltip +field tooltip_commit {} ; # Commit(s) in tooltip + +constructor new {i_commit i_path i_jump} { + global cursor_ptr M1B M1T have_tk85 use_ttk NS + variable active_color + variable group_colors + + set commit $i_commit + set path $i_path + + make_toplevel top w + wm title $top [append "[appname] ([reponame]): " [mc "File Viewer"]] + + set font_w [font measure font_diff "0"] + + gold_frame $w.header + tlabel $w.header.commit_l \ + -text [mc "Commit:"] \ + -background gold \ + -foreground black \ + -anchor w \ + -justify left + set w_back $w.header.commit_b + tlabel $w_back \ + -image ::blame::img_back_arrow \ + -borderwidth 0 \ + -relief flat \ + -state disabled \ + -background gold \ + -foreground black \ + -activebackground gold + bind $w_back " + if {\[$w_back cget -state\] eq {normal}} { + [cb _history_menu] + } + " + tlabel $w.header.commit \ + -textvariable @commit \ + -background gold \ + -foreground black \ + -anchor w \ + -justify left + tlabel $w.header.path_l \ + -text [mc "File:"] \ + -background gold \ + -foreground black \ + -anchor w \ + -justify left + set w_path $w.header.path + tlabel $w_path \ + -background gold \ + -foreground black \ + -anchor w \ + -justify left + pack $w.header.commit_l -side left + pack $w_back -side left + pack $w.header.commit -side left + pack $w_path -fill x -side right + pack $w.header.path_l -side right + + panedwindow $w.file_pane -orient vertical -borderwidth 0 -sashwidth 3 + frame $w.file_pane.out -relief flat -borderwidth 1 + frame $w.file_pane.cm -relief sunken -borderwidth 1 + $w.file_pane add $w.file_pane.out \ + -sticky nsew \ + -minsize 100 \ + -height 100 \ + -width 100 + $w.file_pane add $w.file_pane.cm \ + -sticky nsew \ + -minsize 25 \ + -height 25 \ + -width 100 + + set w_line $w.file_pane.out.linenumber_t + text $w_line \ + -takefocus 0 \ + -highlightthickness 0 \ + -padx 0 -pady 0 \ + -background white \ + -foreground black \ + -borderwidth 0 \ + -state disabled \ + -wrap none \ + -height 40 \ + -width 6 \ + -font font_diff + $w_line tag conf linenumber -justify right -rmargin 5 + + set w_amov $w.file_pane.out.amove_t + text $w_amov \ + -takefocus 0 \ + -highlightthickness 0 \ + -padx 0 -pady 0 \ + -background white \ + -foreground black \ + -borderwidth 0 \ + -state disabled \ + -wrap none \ + -height 40 \ + -width 5 \ + -font font_diff + $w_amov tag conf author_abbr -justify right -rmargin 5 + $w_amov tag conf curr_commit + $w_amov tag conf prior_commit -foreground blue -underline 1 + $w_amov tag bind prior_commit \ + \ + "[cb _load_commit $w_amov @amov_data @%x,%y];break" + + set w_asim $w.file_pane.out.asimple_t + text $w_asim \ + -takefocus 0 \ + -highlightthickness 0 \ + -padx 0 -pady 0 \ + -background white \ + -foreground black \ + -borderwidth 0 \ + -state disabled \ + -wrap none \ + -height 40 \ + -width 4 \ + -font font_diff + $w_asim tag conf author_abbr -justify right + $w_asim tag conf curr_commit + $w_asim tag conf prior_commit -foreground blue -underline 1 + $w_asim tag bind prior_commit \ + \ + "[cb _load_commit $w_asim @asim_data @%x,%y];break" + + set w_file $w.file_pane.out.file_t + text $w_file \ + -takefocus 0 \ + -highlightthickness 0 \ + -padx 0 -pady 0 \ + -background white \ + -foreground black \ + -borderwidth 0 \ + -state disabled \ + -wrap none \ + -height 40 \ + -width 80 \ + -xscrollcommand [list $w.file_pane.out.sbx set] \ + -font font_diff + if {$have_tk85} { + $w_file configure -inactiveselectbackground darkblue + } + $w_file tag conf found \ + -background yellow + + set w_columns [list $w_amov $w_asim $w_line $w_file] + + ${NS}::scrollbar $w.file_pane.out.sbx \ + -orient h \ + -command [list $w_file xview] + ${NS}::scrollbar $w.file_pane.out.sby \ + -orient v \ + -command [list scrollbar2many $w_columns yview] + eval grid $w_columns $w.file_pane.out.sby -sticky nsew + grid conf \ + $w.file_pane.out.sbx \ + -column [expr {[llength $w_columns] - 1}] \ + -sticky we + grid columnconfigure \ + $w.file_pane.out \ + [expr {[llength $w_columns] - 1}] \ + -weight 1 + grid rowconfigure $w.file_pane.out 0 -weight 1 + + set finder [::searchbar::new \ + $w.file_pane.out.ff $w_file \ + -column [expr {[llength $w_columns] - 1}] \ + ] + + set w_cviewer $w.file_pane.cm.t + text $w_cviewer \ + -background white \ + -foreground black \ + -borderwidth 0 \ + -state disabled \ + -wrap none \ + -height 10 \ + -width 80 \ + -xscrollcommand [list $w.file_pane.cm.sbx set] \ + -yscrollcommand [list $w.file_pane.cm.sby set] \ + -font font_diff + $w_cviewer tag conf still_loading \ + -font font_uiitalic \ + -justify center + $w_cviewer tag conf header_key \ + -tabs {3c} \ + -background $active_color \ + -font font_uibold + $w_cviewer tag conf header_val \ + -background $active_color \ + -font font_ui + $w_cviewer tag raise sel + ${NS}::scrollbar $w.file_pane.cm.sbx \ + -orient h \ + -command [list $w_cviewer xview] + ${NS}::scrollbar $w.file_pane.cm.sby \ + -orient v \ + -command [list $w_cviewer yview] + pack $w.file_pane.cm.sby -side right -fill y + pack $w.file_pane.cm.sbx -side bottom -fill x + pack $w_cviewer -expand 1 -fill both + + set status [::status_bar::new $w.status] + + menu $w.ctxm -tearoff 0 + $w.ctxm add command \ + -label [mc "Copy Commit"] \ + -command [cb _copycommit] + $w.ctxm add separator + $w.ctxm add command \ + -label [mc "Find Text..."] \ + -accelerator F7 \ + -command [list searchbar::show $finder] + menu $w.ctxm.enc + build_encoding_menu $w.ctxm.enc [cb _setencoding] + $w.ctxm add cascade \ + -label [mc "Encoding"] \ + -menu $w.ctxm.enc + $w.ctxm add command \ + -label [mc "Do Full Copy Detection"] \ + -command [cb _fullcopyblame] + $w.ctxm add separator + $w.ctxm add command \ + -label [mc "Show History Context"] \ + -command [cb _gitkcommit] + $w.ctxm add command \ + -label [mc "Blame Parent Commit"] \ + -command [cb _blameparent] + + foreach i $w_columns { + for {set g 0} {$g < [llength $group_colors]} {incr g} { + $i tag conf color$g -background [lindex $group_colors $g] + } + + if {$i eq $w_file} { + $w_file tag raise found + } + $i tag raise sel + + $i conf -cursor $cursor_ptr + $i conf -yscrollcommand \ + "[list ::searchbar::scrolled $finder] + [list many2scrollbar $w_columns yview $w.file_pane.out.sby]" + bind $i " + [cb _hide_tooltip] + [cb _click $i @%x,%y] + focus $i + " + bind $i [cb _show_tooltip $i @%x,%y] + bind $i [cb _hide_tooltip] + bind $i [cb _hide_tooltip] + bind_button3 $i " + [cb _hide_tooltip] + set cursorX %x + set cursorY %y + set cursorW %W + tk_popup $w.ctxm %X %Y + " + bind $i "[list focus $w_cviewer];break" + bind $i "[cb _focus_search $w_cviewer];break" + } + + foreach i [concat $w_columns $w_cviewer] { + bind $i {catch {%W yview scroll -1 units};break} + bind $i {catch {%W yview scroll 1 units};break} + bind $i {catch {%W xview scroll -1 units};break} + bind $i {catch {%W xview scroll 1 units};break} + bind $i {catch {%W yview scroll -1 units};break} + bind $i {catch {%W yview scroll 1 units};break} + bind $i {catch {%W xview scroll -1 units};break} + bind $i {catch {%W xview scroll 1 units};break} + bind $i {catch {%W yview scroll -1 pages};break} + bind $i {catch {%W yview scroll 1 pages};break} + } + + bind $w_cviewer "[cb _focus_search $w_file];break" + bind $w_cviewer "[list focus $w_file];break" + bind $w_cviewer [list focus $w_cviewer] + bind $w_file [cb _focus_search $w_file] + bind $top [list searchbar::show $finder] + bind $top [list searchbar::hide $finder] + bind $top [list searchbar::find_next $finder] + bind $top [list searchbar::find_prev $finder] + catch { bind $top [list searchbar::find_prev $finder] } + + grid configure $w.header -sticky ew + grid configure $w.file_pane -sticky nsew + grid configure $w.status -sticky ew + grid columnconfigure $top 0 -weight 1 + grid rowconfigure $top 0 -weight 0 + grid rowconfigure $top 1 -weight 1 + grid rowconfigure $top 2 -weight 0 + + set req_w [winfo reqwidth $top] + set req_h [winfo reqheight $top] + set scr_w [expr {[winfo screenwidth $top] - 40}] + set scr_h [expr {[winfo screenheight $top] - 120}] + set opt_w [expr {$font_w * (80 + 5*3 + 3)}] + if {$req_w < $opt_w} {set req_w $opt_w} + if {$req_w > $scr_w} {set req_w $scr_w} + set opt_h [expr {$req_w*4/3}] + if {$req_h < $scr_h} {set req_h $scr_h} + if {$req_h > $opt_h} {set req_h $opt_h} + set g "${req_w}x${req_h}" + wm geometry $top $g + update + + set old_height [winfo height $w.file_pane] + $w.file_pane sash place 0 \ + [lindex [$w.file_pane sash coord 0] 0] \ + [expr {int($old_height * 0.80)}] + bind $w.file_pane \ + "if {{$w.file_pane} eq {%W}} {[cb _resize %h]}" + + wm protocol $top WM_DELETE_WINDOW "destroy $top" + bind $top [cb _handle_destroy %W] + + _load $this $i_jump +} + +method _focus_search {win} { + if {[searchbar::visible $finder]} { + focus [searchbar::editor $finder] + } else { + focus $win + } +} + +method _handle_destroy {win} { + if {$win eq $w} { + _kill $this + delete_this + } +} + +method _kill {} { + if {$current_fd ne {}} { + kill_file_process $current_fd + catch {close $current_fd} + set current_fd {} + } +} + +method _load {jump} { + variable group_colors + + _hide_tooltip $this + + if {$total_lines != 0 || $current_fd ne {}} { + _kill $this + + foreach i $w_columns { + $i conf -state normal + $i delete 0.0 end + foreach g [$i tag names] { + if {[regexp {^g[0-9a-f]{40}$} $g]} { + $i tag delete $g + } + } + $i conf -state disabled + } + + $w_cviewer conf -state normal + $w_cviewer delete 0.0 end + $w_cviewer conf -state disabled + + set highlight_line -1 + set highlight_column {} + set highlight_commit {} + set total_lines 0 + } + + if {$history eq {}} { + $w_back conf -state disabled + } else { + $w_back conf -state normal + } + + # Index 0 is always empty. There is never line 0 as + # we use only 1 based lines, as that matches both with + # git-blame output and with Tk's text widget. + # + set amov_data [list [list]] + set asim_data [list [list]] + + $status show [mc "Reading %s..." "$commit:[escape_path $path]"] + $w_path conf -text [escape_path $path] + + set do_textconv 0 + if {![is_config_false gui.textconv] && [git-version >= 1.7.2]} { + set filter [gitattr $path diff set] + set textconv [get_config [join [list diff $filter textconv] .]] + if {$filter ne {set} && $textconv ne {}} { + set do_textconv 1 + } + } + if {$commit eq {}} { + if {$do_textconv ne 0} { - set fd [open |[list $textconv $path] r] ++ # Run textconv with sh -c "..." to allow it to ++ # contain command + arguments. On windows, just ++ # call the filter command. ++ if {![file executable [shellpath]]} { ++ set fd [open |[linsert $textconv end $path] r] ++ } else { ++ set fd [open |[list [shellpath] -c "$textconv \"\$0\"" $path] r] ++ } + } else { + set fd [open $path r] + } + fconfigure $fd -eofchar {} + } else { + if {$do_textconv ne 0} { + set fd [git_read cat-file --textconv "$commit:$path"] + } else { + set fd [git_read cat-file blob "$commit:$path"] + } + } + fconfigure $fd \ + -blocking 0 \ + -translation lf \ + -encoding [get_path_encoding $path] + fileevent $fd readable [cb _read_file $fd $jump] + set current_fd $fd +} + +method _history_menu {} { + set m $w.backmenu + if {[winfo exists $m]} { + $m delete 0 end + } else { + menu $m -tearoff 0 + } + + for {set i [expr {[llength $history] - 1}] + } {$i >= 0} {incr i -1} { + set e [lindex $history $i] + set c [lindex $e 0] + set f [lindex $e 1] + + if {[regexp {^[0-9a-f]{40}$} $c]} { + set t [string range $c 0 8]... + } elseif {$c eq {}} { + set t {Working Directory} + } else { + set t $c + } + if {![catch {set summary $header($c,summary)}]} { + append t " $summary" + if {[string length $t] > 70} { + set t [string range $t 0 66]... + } + } + + $m add command -label $t -command [cb _goback $i] + } + set X [winfo rootx $w_back] + set Y [expr {[winfo rooty $w_back] + [winfo height $w_back]}] + tk_popup $m $X $Y +} + +method _goback {i} { + set dat [lindex $history $i] + set history [lrange $history 0 [expr {$i - 1}]] + set commit [lindex $dat 0] + set path [lindex $dat 1] + _load $this [lrange $dat 2 5] +} + +method _read_file {fd jump} { + if {$fd ne $current_fd} { + catch {close $fd} + return + } + + foreach i $w_columns {$i conf -state normal} + while {[gets $fd line] >= 0} { + regsub "\r\$" $line {} line + incr total_lines + lappend amov_data {} + lappend asim_data {} + + if {$total_lines > 1} { + foreach i $w_columns {$i insert end "\n"} + } + + $w_line insert end "$total_lines" linenumber + $w_file insert end "$line" + } + + set ln_wc [expr {[string length $total_lines] + 2}] + if {[$w_line cget -width] < $ln_wc} { + $w_line conf -width $ln_wc + } + + foreach i $w_columns {$i conf -state disabled} + + if {[eof $fd]} { + close $fd + + # If we don't force Tk to update the widgets *right now* + # none of our jump commands will cause a change in the UI. + # + update + + if {[llength $jump] == 1} { + set highlight_line [lindex $jump 0] + $w_file see "$highlight_line.0" + } elseif {[llength $jump] == 4} { + set highlight_column [lindex $jump 0] + set highlight_line [lindex $jump 1] + $w_file xview moveto [lindex $jump 2] + $w_file yview moveto [lindex $jump 3] + } + + _exec_blame $this $w_asim @asim_data \ + [list] \ + [mc "Loading copy/move tracking annotations..."] + } +} ifdeleted { catch {close $fd} } + +method _exec_blame {cur_w cur_d options cur_s} { + lappend options --incremental --encoding=utf-8 + if {$commit eq {}} { + lappend options --contents $path + } else { + lappend options $commit + } + lappend options -- $path + set fd [eval git_read --nice blame $options] + fconfigure $fd -blocking 0 -translation lf -encoding utf-8 + fileevent $fd readable [cb _read_blame $fd $cur_w $cur_d] + set current_fd $fd + set blame_lines 0 + + $status start \ + $cur_s \ + [mc "lines annotated"] +} + +method _read_blame {fd cur_w cur_d} { + upvar #0 $cur_d line_data + variable group_colors + + if {$fd ne $current_fd} { + catch {close $fd} + return + } + + $cur_w conf -state normal + while {[gets $fd line] >= 0} { + if {[regexp {^([a-z0-9]{40}) (\d+) (\d+) (\d+)$} $line line \ + cmit original_line final_line line_count]} { + set r_commit $cmit + set r_orig_line $original_line + set r_final_line $final_line + set r_line_count $line_count + } elseif {[string match {filename *} $line]} { + set file [string range $line 9 end] + set n $r_line_count + set lno $r_final_line + set oln $r_orig_line + set cmit $r_commit + + if {[regexp {^0{40}$} $cmit]} { + set commit_abbr work + set commit_type curr_commit + } elseif {$cmit eq $commit} { + set commit_abbr this + set commit_type curr_commit + } else { + set commit_type prior_commit + set commit_abbr [string range $cmit 0 3] + } + + set author_abbr {} + set a_name {} + catch {set a_name $header($cmit,author)} + while {$a_name ne {}} { + if {$author_abbr ne {} + && [string index $a_name 0] eq {'}} { + regsub {^'[^']+'\s+} $a_name {} a_name + } + if {![regexp {^([[:upper:]])} $a_name _a]} break + append author_abbr $_a + unset _a + if {![regsub \ + {^[[:upper:]][^\s]*\s+} \ + $a_name {} a_name ]} break + } + if {$author_abbr eq {}} { + set author_abbr { |} + } else { + set author_abbr [string range $author_abbr 0 3] + } + unset a_name + + set first_lno $lno + while { + $first_lno > 1 + && $cmit eq [lindex $line_data [expr {$first_lno - 1}] 0] + && $file eq [lindex $line_data [expr {$first_lno - 1}] 1] + } { + incr first_lno -1 + } + + set color {} + if {$first_lno < $lno} { + foreach g [$w_file tag names $first_lno.0] { + if {[regexp {^color[0-9]+$} $g]} { + set color $g + break + } + } + } else { + set i [lsort [concat \ + [$w_file tag names "[expr {$first_lno - 1}].0"] \ + [$w_file tag names "[expr {$lno + $n}].0"] \ + ]] + for {set g 0} {$g < [llength $group_colors]} {incr g} { + if {[lsearch -sorted -exact $i color$g] == -1} { + set color color$g + break + } + } + } + if {$color eq {}} { + set color color0 + } + + while {$n > 0} { + set lno_e "$lno.0 lineend + 1c" + if {[lindex $line_data $lno] ne {}} { + set g [lindex $line_data $lno 0] + foreach i $w_columns { + $i tag remove g$g $lno.0 $lno_e + } + } + lset line_data $lno [list $cmit $file $oln] + + $cur_w delete $lno.0 "$lno.0 lineend" + if {$lno == $first_lno} { + $cur_w insert $lno.0 $commit_abbr $commit_type + } elseif {$lno == [expr {$first_lno + 1}]} { + $cur_w insert $lno.0 $author_abbr author_abbr + } else { + $cur_w insert $lno.0 { |} + } + + foreach i $w_columns { + if {$cur_w eq $w_amov} { + for {set g 0} \ + {$g < [llength $group_colors]} \ + {incr g} { + $i tag remove color$g $lno.0 $lno_e + } + $i tag add $color $lno.0 $lno_e + } + $i tag add g$cmit $lno.0 $lno_e + } + + if {$highlight_column eq $cur_w} { + if {$highlight_line == -1 + && [lindex [$w_file yview] 0] == 0} { + $w_file see $lno.0 + set highlight_line $lno + } + if {$highlight_line == $lno} { + _showcommit $this $cur_w $lno + } + } + + incr n -1 + incr lno + incr oln + incr blame_lines + } + + while { + $cmit eq [lindex $line_data $lno 0] + && $file eq [lindex $line_data $lno 1] + } { + $cur_w delete $lno.0 "$lno.0 lineend" + + if {$lno == $first_lno} { + $cur_w insert $lno.0 $commit_abbr $commit_type + } elseif {$lno == [expr {$first_lno + 1}]} { + $cur_w insert $lno.0 $author_abbr author_abbr + } else { + $cur_w insert $lno.0 { |} + } + + if {$cur_w eq $w_amov} { + foreach i $w_columns { + for {set g 0} \ + {$g < [llength $group_colors]} \ + {incr g} { + $i tag remove color$g $lno.0 $lno_e + } + $i tag add $color $lno.0 $lno_e + } + } + + incr lno + } + + } elseif {[regexp {^([a-z-]+) (.*)$} $line line key data]} { + set header($r_commit,$key) $data + } + } + $cur_w conf -state disabled + + if {[eof $fd]} { + close $fd + if {$cur_w eq $w_asim} { + # Switches for original location detection + set threshold [get_config gui.copyblamethreshold] + set original_options [list "-C$threshold"] + + if {![is_config_true gui.fastcopyblame]} { + # thorough copy search; insert before the threshold + set original_options [linsert $original_options 0 -C] + } + if {[git-version >= 1.5.3]} { + lappend original_options -w ; # ignore indentation changes + } + + _exec_blame $this $w_amov @amov_data \ + $original_options \ + [mc "Loading original location annotations..."] + } else { + set current_fd {} + $status stop [mc "Annotation complete."] + } + } else { + $status update $blame_lines $total_lines + } +} ifdeleted { catch {close $fd} } + +method _find_commit_bound {data_list start_idx delta} { + upvar #0 $data_list line_data + set pos $start_idx + set limit [expr {[llength $line_data] - 1}] + set base_commit [lindex $line_data $pos 0] + + while {$pos > 0 && $pos < $limit} { + set new_pos [expr {$pos + $delta}] + if {[lindex $line_data $new_pos 0] ne $base_commit} { + return $pos + } + + set pos $new_pos + } + + return $pos +} + +method _fullcopyblame {} { + if {$current_fd ne {}} { + tk_messageBox \ + -icon error \ + -type ok \ + -title [mc "Busy"] \ + -message [mc "Annotation process is already running."] + + return + } + + # Switches for original location detection + set threshold [get_config gui.copyblamethreshold] + set original_options [list -C -C "-C$threshold"] + + if {[git-version >= 1.5.3]} { + lappend original_options -w ; # ignore indentation changes + } + + # Find the line range + set pos @$::cursorX,$::cursorY + set lno [lindex [split [$::cursorW index $pos] .] 0] + set min_amov_lno [_find_commit_bound $this @amov_data $lno -1] + set max_amov_lno [_find_commit_bound $this @amov_data $lno 1] + set min_asim_lno [_find_commit_bound $this @asim_data $lno -1] + set max_asim_lno [_find_commit_bound $this @asim_data $lno 1] + + if {$min_asim_lno < $min_amov_lno} { + set min_amov_lno $min_asim_lno + } + + if {$max_asim_lno > $max_amov_lno} { + set max_amov_lno $max_asim_lno + } + + lappend original_options -L "$min_amov_lno,$max_amov_lno" + + # Clear lines + for {set i $min_amov_lno} {$i <= $max_amov_lno} {incr i} { + lset amov_data $i [list ] + } + + # Start the back-end process + _exec_blame $this $w_amov @amov_data \ + $original_options \ + [mc "Running thorough copy detection..."] +} + +method _click {cur_w pos} { + set lno [lindex [split [$cur_w index $pos] .] 0] + _showcommit $this $cur_w $lno +} + +method _setencoding {enc} { + force_path_encoding $path $enc + _load $this [list \ + $highlight_column \ + $highlight_line \ + [lindex [$w_file xview] 0] \ + [lindex [$w_file yview] 0] \ + ] +} + +method _load_commit {cur_w cur_d pos} { + upvar #0 $cur_d line_data + set lno [lindex [split [$cur_w index $pos] .] 0] + set dat [lindex $line_data $lno] + if {$dat ne {}} { + _load_new_commit $this \ + [lindex $dat 0] \ + [lindex $dat 1] \ + [list [lindex $dat 2]] + } +} + +method _load_new_commit {new_commit new_path jump} { + lappend history [list \ + $commit $path \ + $highlight_column \ + $highlight_line \ + [lindex [$w_file xview] 0] \ + [lindex [$w_file yview] 0] \ + ] + + set commit $new_commit + set path $new_path + _load $this $jump +} + +method _showcommit {cur_w lno} { + global repo_config + variable active_color + + if {$highlight_commit ne {}} { + foreach i $w_columns { + $i tag conf g$highlight_commit -background {} + $i tag lower g$highlight_commit + } + } + + if {$cur_w eq $w_asim} { + set dat [lindex $asim_data $lno] + set highlight_column $w_asim + } else { + set dat [lindex $amov_data $lno] + set highlight_column $w_amov + } + + $w_cviewer conf -state normal + $w_cviewer delete 0.0 end + + if {$dat eq {}} { + set cmit {} + $w_cviewer insert end [mc "Loading annotation..."] still_loading + } else { + set cmit [lindex $dat 0] + set file [lindex $dat 1] + + foreach i $w_columns { + $i tag conf g$cmit -background $active_color + $i tag raise g$cmit + if {$i eq $w_file} { + $w_file tag raise found + } + $i tag raise sel + } + + set author_name {} + set author_email {} + set author_time {} + catch {set author_name $header($cmit,author)} + catch {set author_email $header($cmit,author-mail)} + catch {set author_time [format_date $header($cmit,author-time)]} + + set committer_name {} + set committer_email {} + set committer_time {} + catch {set committer_name $header($cmit,committer)} + catch {set committer_email $header($cmit,committer-mail)} + catch {set committer_time [format_date $header($cmit,committer-time)]} + + if {[catch {set msg $header($cmit,message)}]} { + set msg {} + catch { + set fd [git_read cat-file commit $cmit] + 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 {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] + } + set header($cmit,message) $msg + } + + $w_cviewer insert end "commit $cmit\n" header_key + $w_cviewer insert end [strcat [mc "Author:"] "\t"] header_key + $w_cviewer insert end "$author_name $author_email" header_val + $w_cviewer insert end " $author_time\n" header_val + + $w_cviewer insert end [strcat [mc "Committer:"] "\t"] header_key + $w_cviewer insert end "$committer_name $committer_email" header_val + $w_cviewer insert end " $committer_time\n" header_val + + if {$file ne $path} { + $w_cviewer insert end [strcat [mc "Original File:"] "\t"] header_key + $w_cviewer insert end "[escape_path $file]\n" header_val + } + + $w_cviewer insert end "\n$msg" + } + $w_cviewer conf -state disabled + + set highlight_line $lno + set highlight_commit $cmit + + if {[lsearch -exact $tooltip_commit $highlight_commit] != -1} { + _hide_tooltip $this + } +} + +method _get_click_amov_info {} { + set pos @$::cursorX,$::cursorY + set lno [lindex [split [$::cursorW index $pos] .] 0] + return [lindex $amov_data $lno] +} + +method _copycommit {} { + set dat [_get_click_amov_info $this] + if {$dat ne {}} { + clipboard clear + clipboard append \ + -format STRING \ + -type STRING \ + -- [lindex $dat 0] + } +} + +method _format_offset_date {base offset} { + set exval [expr {$base + $offset*24*60*60}] + return [clock format $exval -format {%Y-%m-%d}] +} + +method _gitkcommit {} { + global nullid + + set dat [_get_click_amov_info $this] + if {$dat ne {}} { + set cmit [lindex $dat 0] + + # If the line belongs to the working copy, use HEAD instead + if {$cmit eq $nullid} { + if {[catch {set cmit [git rev-parse --verify HEAD]} err]} { + error_popup [strcat [mc "Cannot find HEAD commit:"] "\n\n$err"] + return; + } + } + + set radius [get_config gui.blamehistoryctx] + set cmdline [list --select-commit=$cmit] + + if {$radius > 0} { + set author_time {} + set committer_time {} + + catch {set author_time $header($cmit,author-time)} + catch {set committer_time $header($cmit,committer-time)} + + if {$committer_time eq {}} { + set committer_time $author_time + } + + set after_time [_format_offset_date $this $committer_time [expr {-$radius}]] + set before_time [_format_offset_date $this $committer_time $radius] + + lappend cmdline --after=$after_time --before=$before_time + } + + lappend cmdline $cmit + + set base_rev "HEAD" + if {$commit ne {}} { + set base_rev $commit + } + + if {$base_rev ne $cmit} { + lappend cmdline $base_rev + } + + do_gitk $cmdline + } +} + +method _blameparent {} { + global nullid + + set dat [_get_click_amov_info $this] + if {$dat ne {}} { + set cmit [lindex $dat 0] + set new_path [lindex $dat 1] + + # Allow using Blame Parent on lines modified in the working copy + if {$cmit eq $nullid} { + set parent_ref "HEAD" + } else { + set parent_ref "$cmit^" + } + if {[catch {set cparent [git rev-parse --verify $parent_ref]} err]} { + error_popup [strcat [mc "Cannot find parent commit:"] "\n\n$err"] + return; + } + + _kill $this + + # Generate a diff between the commit and its parent, + # and use the hunks to update the line number. + # Request zero context to simplify calculations. + if {$cmit eq $nullid} { + set diffcmd [list diff-index --unified=0 $cparent -- $new_path] + } else { + set diffcmd [list diff-tree --unified=0 $cparent $cmit -- $new_path] + } + if {[catch {set fd [eval git_read $diffcmd]} err]} { + $status stop [mc "Unable to display parent"] + error_popup [strcat [mc "Error loading diff:"] "\n\n$err"] + return + } + + set r_orig_line [lindex $dat 2] + + fconfigure $fd \ + -blocking 0 \ + -encoding binary \ + -translation binary + fileevent $fd readable [cb _read_diff_load_commit \ + $fd $cparent $new_path $r_orig_line] + set current_fd $fd + } +} + +method _read_diff_load_commit {fd cparent new_path tline} { + if {$fd ne $current_fd} { + catch {close $fd} + return + } + + while {[gets $fd line] >= 0} { + if {[regexp {^@@ -(\d+)(,(\d+))? \+(\d+)(,(\d+))? @@} $line line \ + old_line osz old_size new_line nsz new_size]} { + + if {$osz eq {}} { set old_size 1 } + if {$nsz eq {}} { set new_size 1 } + + if {$new_line <= $tline} { + if {[expr {$new_line + $new_size}] > $tline} { + # Target line within the hunk + set line_shift [expr { + ($new_size-$old_size)*($tline-$new_line)/$new_size + }] + } else { + set line_shift [expr {$new_size-$old_size}] + } + + set r_orig_line [expr {$r_orig_line - $line_shift}] + } + } + } + + if {[eof $fd]} { + close $fd; + set current_fd {} + + _load_new_commit $this \ + $cparent \ + $new_path \ + [list $r_orig_line] + } +} ifdeleted { catch {close $fd} } + +method _show_tooltip {cur_w pos} { + if {$tooltip_wm ne {}} { + _open_tooltip $this $cur_w + } elseif {$tooltip_timer eq {}} { + set tooltip_timer [after 1000 [cb _open_tooltip $cur_w]] + } +} + +method _open_tooltip {cur_w} { + set tooltip_timer {} + set pos_x [winfo pointerx $cur_w] + set pos_y [winfo pointery $cur_w] + if {[winfo containing $pos_x $pos_y] ne $cur_w} { + _hide_tooltip $this + return + } + + if {$tooltip_wm ne "$cur_w.tooltip"} { + _hide_tooltip $this + + set tooltip_wm [toplevel $cur_w.tooltip -borderwidth 1] + wm overrideredirect $tooltip_wm 1 + wm transient $tooltip_wm [winfo toplevel $cur_w] + set tooltip_t $tooltip_wm.label + text $tooltip_t \ + -takefocus 0 \ + -highlightthickness 0 \ + -relief flat \ + -borderwidth 0 \ + -wrap none \ + -background lightyellow \ + -foreground black + $tooltip_t tag conf section_header -font font_uibold + pack $tooltip_t + } else { + $tooltip_t conf -state normal + $tooltip_t delete 0.0 end + } + + set pos @[join [list \ + [expr {$pos_x - [winfo rootx $cur_w]}] \ + [expr {$pos_y - [winfo rooty $cur_w]}]] ,] + set lno [lindex [split [$cur_w index $pos] .] 0] + if {$cur_w eq $w_amov} { + set dat [lindex $amov_data $lno] + set org {} + } else { + set dat [lindex $asim_data $lno] + set org [lindex $amov_data $lno] + } + + if {$dat eq {}} { + _hide_tooltip $this + return + } + + set cmit [lindex $dat 0] + set tooltip_commit [list $cmit] + + set author_name {} + set summary {} + set author_time {} + catch {set author_name $header($cmit,author)} + catch {set summary $header($cmit,summary)} + catch {set author_time [format_date $header($cmit,author-time)]} + + $tooltip_t insert end "commit $cmit\n" + $tooltip_t insert end "$author_name $author_time\n" + $tooltip_t insert end "$summary" + + if {$org ne {} && [lindex $org 0] ne $cmit} { + set save [$tooltip_t get 0.0 end] + $tooltip_t delete 0.0 end + + set cmit [lindex $org 0] + set file [lindex $org 1] + lappend tooltip_commit $cmit + + set author_name {} + set summary {} + set author_time {} + catch {set author_name $header($cmit,author)} + catch {set summary $header($cmit,summary)} + catch {set author_time [format_date $header($cmit,author-time)]} + + $tooltip_t insert end [strcat [mc "Originally By:"] "\n"] section_header + $tooltip_t insert end "commit $cmit\n" + $tooltip_t insert end "$author_name $author_time\n" + $tooltip_t insert end "$summary\n" + + if {$file ne $path} { + $tooltip_t insert end [strcat [mc "In File:"] " "] section_header + $tooltip_t insert end "$file\n" + } + + $tooltip_t insert end "\n" + $tooltip_t insert end [strcat [mc "Copied Or Moved Here By:"] "\n"] section_header + $tooltip_t insert end $save + } + + $tooltip_t conf -state disabled + _position_tooltip $this + + # On MacOS raising a window causes it to acquire focus. + # Tk 8.5 on MacOS seems to properly support wm transient, + # so we can safely counter the effect there. + if {$::have_tk85 && [is_MacOSX]} { + update + if {$w eq {}} { + raise . + } else { + raise $w + } + } +} + +method _position_tooltip {} { + set max_h [lindex [split [$tooltip_t index end] .] 0] + set max_w 0 + for {set i 1} {$i <= $max_h} {incr i} { + set c [lindex [split [$tooltip_t index "$i.0 lineend"] .] 1] + if {$c > $max_w} {set max_w $c} + } + $tooltip_t conf -width $max_w -height $max_h + + set req_w [winfo reqwidth $tooltip_t] + set req_h [winfo reqheight $tooltip_t] + set pos_x [expr {[winfo pointerx .] + 5}] + set pos_y [expr {[winfo pointery .] + 10}] + + set g "${req_w}x${req_h}" + if {$pos_x >= 0} {append g +} + append g $pos_x + if {$pos_y >= 0} {append g +} + append g $pos_y + + wm geometry $tooltip_wm $g + if {![is_MacOSX]} { + raise $tooltip_wm + } +} + +method _hide_tooltip {} { + if {$tooltip_wm ne {}} { + destroy $tooltip_wm + set tooltip_wm {} + set tooltip_commit {} + } + if {$tooltip_timer ne {}} { + after cancel $tooltip_timer + set tooltip_timer {} + } +} + +method _resize {new_height} { + set diff [expr {$new_height - $old_height}] + if {$diff == 0} return + + set my [expr {[winfo height $w.file_pane] - 25}] + set o [$w.file_pane sash coord 0] + set ox [lindex $o 0] + set oy [expr {[lindex $o 1] + $diff}] + if {$oy < 0} {set oy 0} + if {$oy > $my} {set oy $my} + $w.file_pane sash place 0 $ox $oy + + set old_height $new_height +} + +} diff --cc git-gui/po/sv.po index d8d73acf2,000000000..8bd3c5d75 mode 100644,000000..100644 --- a/git-gui/po/sv.po +++ b/git-gui/po/sv.po @@@ -1,2601 -1,0 +1,2605 @@@ +# Swedish translation of git-gui. +# Copyright (C) 2007-2008 Shawn Pearce, et al. +# This file is distributed under the same license as the git-gui package. +# +# Peter Krefting , 2007-2008. +# Mikael Magnusson , 2008. +msgid "" +msgstr "" +"Project-Id-Version: sv\n" +"Report-Msgid-Bugs-To: \n" - "POT-Creation-Date: 2010-01-26 15:47-0800\n" - "PO-Revision-Date: 2010-01-28 13:57+0100\n" ++"POT-Creation-Date: 2010-09-12 21:11+0100\n" ++"PO-Revision-Date: 2010-09-12 21:12+0100\n" +"Last-Translator: Peter Krefting \n" +"Language-Team: Swedish \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit" + - #: 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: ödesdigert fel" - - #: git-gui.sh:743 ++#: git-gui.sh:781 +#, tcl-format +msgid "Invalid font specified in %s:" +msgstr "Ogiltigt teckensnitt angivet i %s:" + - #: git-gui.sh:779 ++#: git-gui.sh:831 +msgid "Main Font" +msgstr "Huvudteckensnitt" + - #: git-gui.sh:780 ++#: git-gui.sh:832 +msgid "Diff/Console Font" +msgstr "Diff/konsolteckensnitt" + - #: git-gui.sh:794 ++#: git-gui.sh:845 git-gui.sh:859 git-gui.sh:872 git-gui.sh:955 git-gui.sh:974 ++#: git-gui.sh:2964 ++msgid "git-gui: fatal error" ++msgstr "git-gui: ödesdigert fel" ++ ++#: git-gui.sh:846 +msgid "Cannot find git in PATH." +msgstr "Hittar inte git i PATH." + - #: git-gui.sh:821 ++#: git-gui.sh:873 +msgid "Cannot parse Git version string:" +msgstr "Kan inte tolka versionssträng från Git:" + - #: git-gui.sh:839 ++#: git-gui.sh:891 +#, 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 "" +"Kan inte avgöra Gits version.\n" +"\n" +"%s säger att dess version är \"%s\".\n" +"\n" +"%s kräver minst Git 1.5.0 eller senare.\n" +"\n" +"Anta att \"%s\" är version 1.5.0?\n" + - #: git-gui.sh:1128 ++#: git-gui.sh:1180 +msgid "Git directory not found:" +msgstr "Git-katalogen hittades inte:" + - #: git-gui.sh:1146 ++#: git-gui.sh:1201 +msgid "Cannot move to top of working directory:" +msgstr "Kan inte gå till början på arbetskatalogen:" + - #: git-gui.sh:1154 ++#: git-gui.sh:1209 +msgid "Cannot use bare repository:" +msgstr "Kan inte använda naket arkiv:" + - #: git-gui.sh:1162 ++#: git-gui.sh:1217 +msgid "No working directory" +msgstr "Ingen arbetskatalog" + - #: git-gui.sh:1334 lib/checkout_op.tcl:306 ++#: git-gui.sh:1389 lib/checkout_op.tcl:306 +msgid "Refreshing file status..." +msgstr "Uppdaterar filstatus..." + - #: git-gui.sh:1390 ++#: git-gui.sh:1445 +msgid "Scanning for modified files ..." +msgstr "Söker efter ändrade filer..." + - #: git-gui.sh:1454 ++#: git-gui.sh:1509 +msgid "Calling prepare-commit-msg hook..." +msgstr "" +"Anropar kroken för förberedelse av incheckningsmeddelande (prepare-commit-" +"msg)..." + - #: git-gui.sh:1471 ++#: git-gui.sh:1526 +msgid "Commit declined by prepare-commit-msg hook." +msgstr "" +"Incheckningen avvisades av kroken för förberedelse av incheckningsmeddelande " +"(prepare-commit-msg)." + - #: git-gui.sh:1629 lib/browser.tcl:246 ++#: git-gui.sh:1684 lib/browser.tcl:246 +msgid "Ready." +msgstr "Klar." + - #: git-gui.sh:1787 ++#: git-gui.sh:1842 +#, tcl-format +msgid "Displaying only %s of %s files." +msgstr "Visar endast %s av %s filer." + - #: git-gui.sh:1913 ++#: git-gui.sh:1968 +msgid "Unmodified" +msgstr "Oförändrade" + - #: git-gui.sh:1915 ++#: git-gui.sh:1970 +msgid "Modified, not staged" +msgstr "Förändrade, ej köade" + - #: git-gui.sh:1916 git-gui.sh:1924 ++#: git-gui.sh:1971 git-gui.sh:1979 +msgid "Staged for commit" +msgstr "Köade för incheckning" + - #: git-gui.sh:1917 git-gui.sh:1925 ++#: git-gui.sh:1972 git-gui.sh:1980 +msgid "Portions staged for commit" +msgstr "Delar köade för incheckning" + - #: git-gui.sh:1918 git-gui.sh:1926 ++#: git-gui.sh:1973 git-gui.sh:1981 +msgid "Staged for commit, missing" +msgstr "Köade för incheckning, saknade" + - #: git-gui.sh:1920 ++#: git-gui.sh:1975 +msgid "File type changed, not staged" +msgstr "Filtyp ändrad, ej köade" + - #: git-gui.sh:1921 ++#: git-gui.sh:1976 +msgid "File type changed, staged" +msgstr "Filtyp ändrad, köade" + - #: git-gui.sh:1923 ++#: git-gui.sh:1978 +msgid "Untracked, not staged" +msgstr "Ej spårade, ej köade" + - #: git-gui.sh:1928 ++#: git-gui.sh:1983 +msgid "Missing" +msgstr "Saknade" + - #: git-gui.sh:1929 ++#: git-gui.sh:1984 +msgid "Staged for removal" +msgstr "Köade för borttagning" + - #: git-gui.sh:1930 ++#: git-gui.sh:1985 +msgid "Staged for removal, still present" +msgstr "Köade för borttagning, fortfarande närvarande" + - #: git-gui.sh:1932 git-gui.sh:1933 git-gui.sh:1934 git-gui.sh:1935 - #: git-gui.sh:1936 git-gui.sh:1937 ++#: git-gui.sh:1987 git-gui.sh:1988 git-gui.sh:1989 git-gui.sh:1990 ++#: git-gui.sh:1991 git-gui.sh:1992 +msgid "Requires merge resolution" +msgstr "Kräver konflikthantering efter sammanslagning" + - #: git-gui.sh:1972 ++#: git-gui.sh:2027 +msgid "Starting gitk... please wait..." +msgstr "Startar gitk... vänta..." + - #: git-gui.sh:1984 ++#: git-gui.sh:2039 +msgid "Couldn't find gitk in PATH" +msgstr "Hittade inte gitk i PATH." + - #: git-gui.sh:2043 ++#: git-gui.sh:2098 +msgid "Couldn't find git gui in PATH" +msgstr "Hittade inte git gui i PATH." + - #: git-gui.sh:2455 lib/choose_repository.tcl:36 ++#: git-gui.sh:2515 lib/choose_repository.tcl:36 +msgid "Repository" +msgstr "Arkiv" + - #: git-gui.sh:2456 ++#: git-gui.sh:2516 +msgid "Edit" +msgstr "Redigera" + - #: git-gui.sh:2458 lib/choose_rev.tcl:561 ++#: git-gui.sh:2518 lib/choose_rev.tcl:566 +msgid "Branch" +msgstr "Gren" + - #: git-gui.sh:2461 lib/choose_rev.tcl:548 ++#: git-gui.sh:2521 lib/choose_rev.tcl:553 +msgid "Commit@@noun" +msgstr "Incheckning" + - #: git-gui.sh:2464 lib/merge.tcl:121 lib/merge.tcl:150 lib/merge.tcl:168 ++#: git-gui.sh:2524 lib/merge.tcl:121 lib/merge.tcl:150 lib/merge.tcl:168 +msgid "Merge" +msgstr "Slå ihop" + - #: git-gui.sh:2465 lib/choose_rev.tcl:557 ++#: git-gui.sh:2525 lib/choose_rev.tcl:562 +msgid "Remote" +msgstr "Fjärrarkiv" + - #: git-gui.sh:2468 ++#: git-gui.sh:2528 +msgid "Tools" +msgstr "Verktyg" + - #: git-gui.sh:2477 ++#: git-gui.sh:2537 +msgid "Explore Working Copy" +msgstr "Utforska arbetskopia" + - #: git-gui.sh:2483 ++#: git-gui.sh:2543 +msgid "Browse Current Branch's Files" +msgstr "Bläddra i grenens filer" + - #: git-gui.sh:2487 ++#: git-gui.sh:2547 +msgid "Browse Branch Files..." +msgstr "Bläddra filer på gren..." + - #: git-gui.sh:2492 ++#: git-gui.sh:2552 +msgid "Visualize Current Branch's History" +msgstr "Visualisera grenens historik" + - #: git-gui.sh:2496 ++#: git-gui.sh:2556 +msgid "Visualize All Branch History" +msgstr "Visualisera alla grenars historik" + - #: git-gui.sh:2503 ++#: git-gui.sh:2563 +#, tcl-format +msgid "Browse %s's Files" +msgstr "Bläddra i filer för %s" + - #: git-gui.sh:2505 ++#: git-gui.sh:2565 +#, tcl-format +msgid "Visualize %s's History" +msgstr "Visualisera historik för %s" + - #: git-gui.sh:2510 lib/database.tcl:27 lib/database.tcl:67 ++#: git-gui.sh:2570 lib/database.tcl:40 lib/database.tcl:66 +msgid "Database Statistics" +msgstr "Databasstatistik" + - #: git-gui.sh:2513 lib/database.tcl:34 ++#: git-gui.sh:2573 lib/database.tcl:33 +msgid "Compress Database" +msgstr "Komprimera databas" + - #: git-gui.sh:2516 ++#: git-gui.sh:2576 +msgid "Verify Database" +msgstr "Verifiera databas" + - #: git-gui.sh:2523 git-gui.sh:2527 git-gui.sh:2531 lib/shortcut.tcl:8 ++#: git-gui.sh:2583 git-gui.sh:2587 git-gui.sh:2591 lib/shortcut.tcl:8 +#: lib/shortcut.tcl:40 lib/shortcut.tcl:72 +msgid "Create Desktop Icon" +msgstr "Skapa skrivbordsikon" + - #: git-gui.sh:2539 lib/choose_repository.tcl:183 lib/choose_repository.tcl:191 ++#: git-gui.sh:2599 lib/choose_repository.tcl:188 lib/choose_repository.tcl:196 +msgid "Quit" +msgstr "Avsluta" + - #: git-gui.sh:2547 ++#: git-gui.sh:2607 +msgid "Undo" +msgstr "Ångra" + - #: git-gui.sh:2550 ++#: git-gui.sh:2610 +msgid "Redo" +msgstr "Gör om" + - #: git-gui.sh:2554 git-gui.sh:3109 ++#: git-gui.sh:2614 git-gui.sh:3190 +msgid "Cut" +msgstr "Klipp ut" + - #: git-gui.sh:2557 git-gui.sh:3112 git-gui.sh:3186 git-gui.sh:3259 ++#: git-gui.sh:2617 git-gui.sh:3193 git-gui.sh:3267 git-gui.sh:3340 +#: lib/console.tcl:69 +msgid "Copy" +msgstr "Kopiera" + - #: git-gui.sh:2560 git-gui.sh:3115 ++#: git-gui.sh:2620 git-gui.sh:3196 +msgid "Paste" +msgstr "Klistra in" + - #: git-gui.sh:2563 git-gui.sh:3118 lib/branch_delete.tcl:26 - #: lib/remote_branch_delete.tcl:38 ++#: git-gui.sh:2623 git-gui.sh:3199 lib/branch_delete.tcl:28 ++#: lib/remote_branch_delete.tcl:39 +msgid "Delete" +msgstr "Ta bort" + - #: git-gui.sh:2567 git-gui.sh:3122 git-gui.sh:3263 lib/console.tcl:71 ++#: git-gui.sh:2627 git-gui.sh:3203 git-gui.sh:3344 lib/console.tcl:71 +msgid "Select All" +msgstr "Markera alla" + - #: git-gui.sh:2576 ++#: git-gui.sh:2636 +msgid "Create..." +msgstr "Skapa..." + - #: git-gui.sh:2582 ++#: git-gui.sh:2642 +msgid "Checkout..." +msgstr "Checka ut..." + - #: git-gui.sh:2588 ++#: git-gui.sh:2648 +msgid "Rename..." +msgstr "Byt namn..." + - #: git-gui.sh:2593 ++#: git-gui.sh:2653 +msgid "Delete..." +msgstr "Ta bort..." + - #: git-gui.sh:2598 ++#: git-gui.sh:2658 +msgid "Reset..." +msgstr "Återställ..." + - #: git-gui.sh:2608 ++#: git-gui.sh:2668 +msgid "Done" +msgstr "Färdig" + - #: git-gui.sh:2610 ++#: git-gui.sh:2670 +msgid "Commit@@verb" +msgstr "Checka in" + - #: git-gui.sh:2619 git-gui.sh:3050 ++#: git-gui.sh:2679 git-gui.sh:3131 +msgid "New Commit" +msgstr "Ny incheckning" + - #: git-gui.sh:2627 git-gui.sh:3057 ++#: git-gui.sh:2687 git-gui.sh:3138 +msgid "Amend Last Commit" +msgstr "Lägg till föregående incheckning" + - #: git-gui.sh:2637 git-gui.sh:3011 lib/remote_branch_delete.tcl:99 ++#: git-gui.sh:2697 git-gui.sh:3092 lib/remote_branch_delete.tcl:101 +msgid "Rescan" +msgstr "Sök på nytt" + - #: git-gui.sh:2643 ++#: git-gui.sh:2703 +msgid "Stage To Commit" +msgstr "Köa för incheckning" + - #: git-gui.sh:2649 ++#: git-gui.sh:2709 +msgid "Stage Changed Files To Commit" +msgstr "Köa ändrade filer för incheckning" + - #: git-gui.sh:2655 ++#: git-gui.sh:2715 +msgid "Unstage From Commit" +msgstr "Ta bort från incheckningskö" + - #: git-gui.sh:2661 lib/index.tcl:412 ++#: git-gui.sh:2721 lib/index.tcl:415 +msgid "Revert Changes" +msgstr "Återställ ändringar" + - #: git-gui.sh:2669 git-gui.sh:3310 git-gui.sh:3341 ++#: git-gui.sh:2729 git-gui.sh:3391 git-gui.sh:3422 +msgid "Show Less Context" +msgstr "Visa mindre sammanhang" + - #: git-gui.sh:2673 git-gui.sh:3314 git-gui.sh:3345 ++#: git-gui.sh:2733 git-gui.sh:3395 git-gui.sh:3426 +msgid "Show More Context" +msgstr "Visa mer sammanhang" + - #: git-gui.sh:2680 git-gui.sh:3024 git-gui.sh:3133 ++#: git-gui.sh:2740 git-gui.sh:3105 git-gui.sh:3214 +msgid "Sign Off" +msgstr "Skriv under" + - #: git-gui.sh:2696 ++#: git-gui.sh:2756 +msgid "Local Merge..." +msgstr "Lokal sammanslagning..." + - #: git-gui.sh:2701 ++#: git-gui.sh:2761 +msgid "Abort Merge..." +msgstr "Avbryt sammanslagning..." + - #: git-gui.sh:2713 git-gui.sh:2741 ++#: git-gui.sh:2773 git-gui.sh:2801 +msgid "Add..." +msgstr "Lägg till..." + - #: git-gui.sh:2717 ++#: git-gui.sh:2777 +msgid "Push..." +msgstr "Sänd..." + - #: git-gui.sh:2721 ++#: git-gui.sh:2781 +msgid "Delete Branch..." +msgstr "Ta bort gren..." + - #: git-gui.sh:2731 git-gui.sh:3292 ++#: git-gui.sh:2791 git-gui.sh:3373 +msgid "Options..." +msgstr "Alternativ..." + - #: git-gui.sh:2742 ++#: git-gui.sh:2802 +msgid "Remove..." +msgstr "Ta bort..." + - #: git-gui.sh:2751 lib/choose_repository.tcl:50 ++#: git-gui.sh:2811 lib/choose_repository.tcl:50 +msgid "Help" +msgstr "Hjälp" + - #: git-gui.sh:2755 git-gui.sh:2759 lib/about.tcl:14 ++#: git-gui.sh:2815 git-gui.sh:2819 lib/about.tcl:14 +#: lib/choose_repository.tcl:44 lib/choose_repository.tcl:53 +#, tcl-format +msgid "About %s" +msgstr "Om %s" + - #: git-gui.sh:2783 ++#: git-gui.sh:2843 +msgid "Online Documentation" +msgstr "Webbdokumentation" + - #: git-gui.sh:2786 lib/choose_repository.tcl:47 lib/choose_repository.tcl:56 ++#: git-gui.sh:2846 lib/choose_repository.tcl:47 lib/choose_repository.tcl:56 +msgid "Show SSH Key" +msgstr "Visa SSH-nyckel" + - #: git-gui.sh:2893 ++#: git-gui.sh:2965 +#, tcl-format +msgid "fatal: cannot stat path %s: No such file or directory" +msgstr "" +"ödesdigert: kunde inte ta status på sökvägen %s: Fil eller katalog saknas" + - #: git-gui.sh:2926 ++#: git-gui.sh:2997 +msgid "Current Branch:" +msgstr "Aktuell gren:" + - #: git-gui.sh:2947 ++#: git-gui.sh:3023 +msgid "Staged Changes (Will Commit)" +msgstr "Köade ändringar (kommer att checkas in)" + - #: git-gui.sh:2967 ++#: git-gui.sh:3043 +msgid "Unstaged Changes" +msgstr "Oköade ändringar" + - #: git-gui.sh:3017 ++#: git-gui.sh:3098 +msgid "Stage Changed" +msgstr "Köa ändrade" + - #: git-gui.sh:3036 lib/transport.tcl:104 lib/transport.tcl:193 ++#: git-gui.sh:3117 lib/transport.tcl:107 lib/transport.tcl:196 +msgid "Push" +msgstr "Sänd" + - #: git-gui.sh:3071 ++#: git-gui.sh:3152 +msgid "Initial Commit Message:" +msgstr "Inledande incheckningsmeddelande:" + - #: git-gui.sh:3072 ++#: git-gui.sh:3153 +msgid "Amended Commit Message:" +msgstr "Utökat incheckningsmeddelande:" + - #: git-gui.sh:3073 ++#: git-gui.sh:3154 +msgid "Amended Initial Commit Message:" +msgstr "Utökat inledande incheckningsmeddelande:" + - #: git-gui.sh:3074 ++#: git-gui.sh:3155 +msgid "Amended Merge Commit Message:" +msgstr "Utökat incheckningsmeddelande för sammanslagning:" + - #: git-gui.sh:3075 ++#: git-gui.sh:3156 +msgid "Merge Commit Message:" +msgstr "Incheckningsmeddelande för sammanslagning:" + - #: git-gui.sh:3076 ++#: git-gui.sh:3157 +msgid "Commit Message:" +msgstr "Incheckningsmeddelande:" + - #: git-gui.sh:3125 git-gui.sh:3267 lib/console.tcl:73 ++#: git-gui.sh:3206 git-gui.sh:3348 lib/console.tcl:73 +msgid "Copy All" +msgstr "Kopiera alla" + - #: git-gui.sh:3149 lib/blame.tcl:104 ++#: git-gui.sh:3230 lib/blame.tcl:104 +msgid "File:" +msgstr "Fil:" + - #: git-gui.sh:3255 ++#: git-gui.sh:3336 +msgid "Refresh" +msgstr "Uppdatera" + - #: git-gui.sh:3276 ++#: git-gui.sh:3357 +msgid "Decrease Font Size" +msgstr "Minska teckensnittsstorlek" + - #: git-gui.sh:3280 ++#: git-gui.sh:3361 +msgid "Increase Font Size" +msgstr "Öka teckensnittsstorlek" + - #: git-gui.sh:3288 lib/blame.tcl:281 ++#: git-gui.sh:3369 lib/blame.tcl:281 +msgid "Encoding" +msgstr "Teckenkodning" + - #: git-gui.sh:3299 ++#: git-gui.sh:3380 +msgid "Apply/Reverse Hunk" +msgstr "Använd/återställ del" + - #: git-gui.sh:3304 ++#: git-gui.sh:3385 +msgid "Apply/Reverse Line" +msgstr "Använd/återställ rad" + - #: git-gui.sh:3323 ++#: git-gui.sh:3404 +msgid "Run Merge Tool" +msgstr "Starta verktyg för sammanslagning" + - #: git-gui.sh:3328 ++#: git-gui.sh:3409 +msgid "Use Remote Version" +msgstr "Använd versionen från fjärrarkivet" + - #: git-gui.sh:3332 ++#: git-gui.sh:3413 +msgid "Use Local Version" +msgstr "Använd lokala versionen" + - #: git-gui.sh:3336 ++#: git-gui.sh:3417 +msgid "Revert To Base" +msgstr "Återställ till basversionen" + - #: git-gui.sh:3354 ++#: git-gui.sh:3435 +msgid "Visualize These Changes In The Submodule" +msgstr "Visualisera ändringarna i undermodulen" + - #: git-gui.sh:3358 ++#: git-gui.sh:3439 +msgid "Visualize Current Branch History In The Submodule" +msgstr "Visualisera grenens historik i undermodulen" + - #: git-gui.sh:3362 ++#: git-gui.sh:3443 +msgid "Visualize All Branch History In The Submodule" +msgstr "Visualisera alla grenars historik i undermodulen" + - #: git-gui.sh:3367 ++#: git-gui.sh:3448 +msgid "Start git gui In The Submodule" +msgstr "Starta git gui i undermodulen" + - #: git-gui.sh:3389 ++#: git-gui.sh:3483 +msgid "Unstage Hunk From Commit" +msgstr "Ta bort del ur incheckningskö" + - #: git-gui.sh:3391 ++#: git-gui.sh:3485 +msgid "Unstage Lines From Commit" +msgstr "Ta bort rader ur incheckningskö" + - #: git-gui.sh:3393 ++#: git-gui.sh:3487 +msgid "Unstage Line From Commit" +msgstr "Ta bort rad ur incheckningskö" + - #: git-gui.sh:3396 ++#: git-gui.sh:3490 +msgid "Stage Hunk For Commit" +msgstr "Ställ del i incheckningskö" + - #: git-gui.sh:3398 ++#: git-gui.sh:3492 +msgid "Stage Lines For Commit" +msgstr "Ställ rader i incheckningskö" + - #: git-gui.sh:3400 ++#: git-gui.sh:3494 +msgid "Stage Line For Commit" +msgstr "Ställ rad i incheckningskö" + - #: git-gui.sh:3424 ++#: git-gui.sh:3519 +msgid "Initializing..." +msgstr "Initierar..." + - #: git-gui.sh:3541 ++#: git-gui.sh:3658 +#, 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 "" +"Det finns möjliga problem med miljövariabler.\n" +"\n" +"Följande miljövariabler kommer troligen att\n" +"ignoreras av alla Git-underprocesser som körs\n" +"av %s:\n" +"\n" + - #: git-gui.sh:3570 ++#: git-gui.sh:3687 +msgid "" +"\n" +"This is due to a known issue with the\n" +"Tcl binary distributed by Cygwin." +msgstr "" +"\n" +"Detta beror på ett känt problem med\n" +"Tcl-binären som följer med Cygwin." + - #: git-gui.sh:3575 ++#: git-gui.sh:3692 +#, 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" +"Du kan ersätta %s\n" +"med att lägga in värden för inställningarna\n" +"user.name och user.email i din personliga\n" +"~/.gitconfig-fil.\n" + +#: lib/about.tcl:26 +msgid "git-gui - a graphical user interface for Git." +msgstr "git-gui - ett grafiskt användargränssnitt för Git." + +#: lib/blame.tcl:72 +msgid "File Viewer" +msgstr "Filvisare" + +#: lib/blame.tcl:78 +msgid "Commit:" +msgstr "Incheckning:" + +#: lib/blame.tcl:271 +msgid "Copy Commit" +msgstr "Kopiera incheckning" + +#: lib/blame.tcl:275 +msgid "Find Text..." +msgstr "Sök text..." + +#: lib/blame.tcl:284 +msgid "Do Full Copy Detection" +msgstr "Gör full kopieringsigenkänning" + +#: lib/blame.tcl:288 +msgid "Show History Context" +msgstr "Visa historiksammanhang" + +#: lib/blame.tcl:291 +msgid "Blame Parent Commit" +msgstr "Klandra föräldraincheckning" + +#: lib/blame.tcl:450 +#, tcl-format +msgid "Reading %s..." +msgstr "Läser %s..." + - #: lib/blame.tcl:557 ++#: lib/blame.tcl:581 +msgid "Loading copy/move tracking annotations..." +msgstr "Läser annoteringar för kopiering/flyttning..." + - #: lib/blame.tcl:577 ++#: lib/blame.tcl:601 +msgid "lines annotated" +msgstr "rader annoterade" + - #: lib/blame.tcl:769 ++#: lib/blame.tcl:793 +msgid "Loading original location annotations..." +msgstr "Läser in annotering av originalplacering..." + - #: lib/blame.tcl:772 ++#: lib/blame.tcl:796 +msgid "Annotation complete." +msgstr "Annotering fullbordad." + - #: lib/blame.tcl:802 ++#: lib/blame.tcl:826 +msgid "Busy" +msgstr "Upptagen" + - #: lib/blame.tcl:803 ++#: lib/blame.tcl:827 +msgid "Annotation process is already running." +msgstr "Annoteringsprocess körs redan." + - #: lib/blame.tcl:842 ++#: lib/blame.tcl:866 +msgid "Running thorough copy detection..." +msgstr "Kör grundlig kopieringsigenkänning..." + - #: lib/blame.tcl:910 ++#: lib/blame.tcl:934 +msgid "Loading annotation..." +msgstr "Läser in annotering..." + - #: lib/blame.tcl:963 ++#: lib/blame.tcl:987 +msgid "Author:" +msgstr "Författare:" + - #: lib/blame.tcl:967 ++#: lib/blame.tcl:991 +msgid "Committer:" +msgstr "Incheckare:" + - #: lib/blame.tcl:972 ++#: lib/blame.tcl:996 +msgid "Original File:" +msgstr "Ursprunglig fil:" + - #: lib/blame.tcl:1020 ++#: lib/blame.tcl:1044 +msgid "Cannot find HEAD commit:" +msgstr "Hittar inte incheckning för HEAD:" + - #: lib/blame.tcl:1075 ++#: lib/blame.tcl:1099 +msgid "Cannot find parent commit:" +msgstr "Hittar inte föräldraincheckning:" + - #: lib/blame.tcl:1090 ++#: lib/blame.tcl:1114 +msgid "Unable to display parent" +msgstr "Kan inte visa förälder" + - #: lib/blame.tcl:1091 lib/diff.tcl:320 ++#: lib/blame.tcl:1115 lib/diff.tcl:323 +msgid "Error loading diff:" +msgstr "Fel vid inläsning av differens:" + - #: lib/blame.tcl:1231 ++#: lib/blame.tcl:1255 +msgid "Originally By:" +msgstr "Ursprungligen av:" + - #: lib/blame.tcl:1237 ++#: lib/blame.tcl:1261 +msgid "In File:" +msgstr "I filen:" + - #: lib/blame.tcl:1242 ++#: lib/blame.tcl:1266 +msgid "Copied Or Moved Here By:" +msgstr "Kopierad eller flyttad hit av:" + - #: lib/branch_checkout.tcl:14 lib/branch_checkout.tcl:19 ++#: lib/branch_checkout.tcl:16 lib/branch_checkout.tcl:21 +msgid "Checkout Branch" +msgstr "Checka ut gren" + - #: lib/branch_checkout.tcl:23 ++#: lib/branch_checkout.tcl:26 +msgid "Checkout" +msgstr "Checka ut" + - #: 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 ++#: lib/branch_checkout.tcl:30 lib/branch_create.tcl:37 ++#: lib/branch_delete.tcl:34 lib/branch_rename.tcl:32 lib/browser.tcl:286 ++#: lib/checkout_op.tcl:579 lib/choose_font.tcl:45 lib/merge.tcl:172 ++#: lib/option.tcl:127 lib/remote_add.tcl:34 lib/remote_branch_delete.tcl:43 ++#: lib/tools_dlg.tcl:41 lib/tools_dlg.tcl:202 lib/tools_dlg.tcl:345 ++#: lib/transport.tcl:111 +msgid "Cancel" +msgstr "Avbryt" + - #: lib/branch_checkout.tcl:32 lib/browser.tcl:287 lib/tools_dlg.tcl:328 ++#: lib/branch_checkout.tcl:35 lib/browser.tcl:291 lib/tools_dlg.tcl:321 +msgid "Revision" +msgstr "Revision" + - #: lib/branch_checkout.tcl:36 lib/branch_create.tcl:69 lib/option.tcl:280 ++#: lib/branch_checkout.tcl:39 lib/branch_create.tcl:69 lib/option.tcl:287 +msgid "Options" +msgstr "Alternativ" + - #: lib/branch_checkout.tcl:39 lib/branch_create.tcl:92 ++#: lib/branch_checkout.tcl:42 lib/branch_create.tcl:92 +msgid "Fetch Tracking Branch" +msgstr "Hämta spårande gren" + - #: lib/branch_checkout.tcl:44 ++#: lib/branch_checkout.tcl:47 +msgid "Detach From Local Branch" +msgstr "Koppla bort från lokal gren" + - #: lib/branch_create.tcl:22 ++#: lib/branch_create.tcl:23 +msgid "Create Branch" +msgstr "Skapa gren" + - #: lib/branch_create.tcl:27 ++#: lib/branch_create.tcl:28 +msgid "Create New Branch" +msgstr "Skapa ny gren" + - #: lib/branch_create.tcl:31 lib/choose_repository.tcl:381 ++#: lib/branch_create.tcl:33 lib/choose_repository.tcl:389 +msgid "Create" +msgstr "Skapa" + - #: lib/branch_create.tcl:40 ++#: lib/branch_create.tcl:42 +msgid "Branch Name" +msgstr "Namn på gren" + - #: lib/branch_create.tcl:43 lib/remote_add.tcl:39 lib/tools_dlg.tcl:50 ++#: lib/branch_create.tcl:44 lib/remote_add.tcl:41 lib/tools_dlg.tcl:51 +msgid "Name:" +msgstr "Namn:" + - #: lib/branch_create.tcl:58 ++#: lib/branch_create.tcl:57 +msgid "Match Tracking Branch Name" +msgstr "Använd namn på spårad gren" + +#: lib/branch_create.tcl:66 +msgid "Starting Revision" +msgstr "Inledande revision" + +#: lib/branch_create.tcl:72 +msgid "Update Existing Branch:" +msgstr "Uppdatera befintlig gren:" + +#: lib/branch_create.tcl:75 +msgid "No" +msgstr "Nej" + +#: lib/branch_create.tcl:80 +msgid "Fast Forward Only" +msgstr "Endast snabbspolning" + +#: lib/branch_create.tcl:85 lib/checkout_op.tcl:571 +msgid "Reset" +msgstr "Återställ" + +#: lib/branch_create.tcl:97 +msgid "Checkout After Creation" +msgstr "Checka ut när skapad" + - #: lib/branch_create.tcl:131 ++#: lib/branch_create.tcl:132 +msgid "Please select a tracking branch." +msgstr "Välj en gren att spåra." + - #: lib/branch_create.tcl:140 ++#: lib/branch_create.tcl:141 +#, tcl-format +msgid "Tracking branch %s is not a branch in the remote repository." +msgstr "Den spårade grenen %s är inte en gren i fjärrarkivet." + - #: lib/branch_create.tcl:153 lib/branch_rename.tcl:86 ++#: lib/branch_create.tcl:154 lib/branch_rename.tcl:92 +msgid "Please supply a branch name." +msgstr "Ange ett namn för grenen." + - #: lib/branch_create.tcl:164 lib/branch_rename.tcl:106 ++#: lib/branch_create.tcl:165 lib/branch_rename.tcl:112 +#, tcl-format +msgid "'%s' is not an acceptable branch name." +msgstr "\"%s\" kan inte användas som namn på grenen." + - #: lib/branch_delete.tcl:15 ++#: lib/branch_delete.tcl:16 +msgid "Delete Branch" +msgstr "Ta bort gren" + - #: lib/branch_delete.tcl:20 ++#: lib/branch_delete.tcl:21 +msgid "Delete Local Branch" +msgstr "Ta bort lokal gren" + - #: lib/branch_delete.tcl:37 ++#: lib/branch_delete.tcl:39 +msgid "Local Branches" +msgstr "Lokala grenar" + - #: lib/branch_delete.tcl:52 ++#: lib/branch_delete.tcl:51 +msgid "Delete Only If Merged Into" +msgstr "Ta bara bort om sammanslagen med" + - #: lib/branch_delete.tcl:54 lib/remote_branch_delete.tcl:119 ++#: lib/branch_delete.tcl:53 lib/remote_branch_delete.tcl:120 +msgid "Always (Do not perform merge checks)" +msgstr "Alltid (utför inte sammanslagningstest)" + +#: lib/branch_delete.tcl:103 +#, tcl-format +msgid "The following branches are not completely merged into %s:" +msgstr "Följande grenar är inte till fullo sammanslagna med %s:" + - #: lib/branch_delete.tcl:115 lib/remote_branch_delete.tcl:217 ++#: lib/branch_delete.tcl:115 lib/remote_branch_delete.tcl:218 +msgid "" +"Recovering deleted branches is difficult.\n" +"\n" +"Delete the selected branches?" +msgstr "" +"Det kan vara svårt att återställa borttagna grenar.\n" +"\n" +"Ta bort de valda grenarna?" + +#: lib/branch_delete.tcl:141 +#, tcl-format +msgid "" +"Failed to delete branches:\n" +"%s" +msgstr "" +"Kunde inte ta bort grenar:\n" +"%s" + - #: lib/branch_rename.tcl:14 lib/branch_rename.tcl:22 ++#: lib/branch_rename.tcl:15 lib/branch_rename.tcl:23 +msgid "Rename Branch" +msgstr "Byt namn på gren" + - #: lib/branch_rename.tcl:26 ++#: lib/branch_rename.tcl:28 +msgid "Rename" +msgstr "Byt namn" + - #: lib/branch_rename.tcl:36 ++#: lib/branch_rename.tcl:38 +msgid "Branch:" +msgstr "Gren:" + - #: lib/branch_rename.tcl:39 ++#: lib/branch_rename.tcl:46 +msgid "New Name:" +msgstr "Nytt namn:" + - #: lib/branch_rename.tcl:75 ++#: lib/branch_rename.tcl:81 +msgid "Please select a branch to rename." +msgstr "Välj en gren att byta namn på." + - #: lib/branch_rename.tcl:96 lib/checkout_op.tcl:202 ++#: lib/branch_rename.tcl:102 lib/checkout_op.tcl:202 +#, tcl-format +msgid "Branch '%s' already exists." +msgstr "Grenen \"%s\" finns redan." + - #: lib/branch_rename.tcl:117 ++#: lib/branch_rename.tcl:123 +#, tcl-format +msgid "Failed to rename '%s'." +msgstr "Kunde inte byta namn på \"%s\"." + +#: lib/browser.tcl:17 +msgid "Starting..." +msgstr "Startar..." + - #: lib/browser.tcl:26 ++#: lib/browser.tcl:27 +msgid "File Browser" +msgstr "Filbläddrare" + +#: lib/browser.tcl:126 lib/browser.tcl:143 +#, tcl-format +msgid "Loading %s..." +msgstr "Läser %s..." + +#: lib/browser.tcl:187 +msgid "[Up To Parent]" +msgstr "[Upp till förälder]" + - #: lib/browser.tcl:267 lib/browser.tcl:273 ++#: lib/browser.tcl:269 lib/browser.tcl:276 +msgid "Browse Branch Files" +msgstr "Bläddra filer på grenen" + - #: lib/browser.tcl:278 lib/choose_repository.tcl:398 - #: lib/choose_repository.tcl:486 lib/choose_repository.tcl:497 - #: lib/choose_repository.tcl:1028 ++#: lib/browser.tcl:282 lib/choose_repository.tcl:404 ++#: lib/choose_repository.tcl:491 lib/choose_repository.tcl:500 ++#: lib/choose_repository.tcl:1027 +msgid "Browse" +msgstr "Bläddra" + +#: lib/checkout_op.tcl:85 +#, tcl-format +msgid "Fetching %s from %s" +msgstr "Hämtar %s från %s" + +#: lib/checkout_op.tcl:133 +#, tcl-format +msgid "fatal: Cannot resolve %s" +msgstr "ödesdigert: Kunde inte slå upp %s" + - #: lib/checkout_op.tcl:146 lib/console.tcl:81 lib/database.tcl:31 - #: lib/sshkey.tcl:53 ++#: lib/checkout_op.tcl:146 lib/console.tcl:81 lib/database.tcl:30 ++#: lib/sshkey.tcl:55 +msgid "Close" +msgstr "Stäng" + +#: lib/checkout_op.tcl:175 +#, tcl-format +msgid "Branch '%s' does not exist." +msgstr "Grenen \"%s\" finns inte." + +#: lib/checkout_op.tcl:194 +#, tcl-format +msgid "Failed to configure simplified git-pull for '%s'." +msgstr "Kunde inte konfigurera förenklad git-pull för '%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 "" +"Grenen \"%s\" finns redan.\n" +"\n" +"Den kan inte snabbspolas till %s.\n" +"En sammanslagning krävs." + +#: lib/checkout_op.tcl:243 +#, tcl-format +msgid "Merge strategy '%s' not supported." +msgstr "Sammanslagningsstrategin \"%s\" stöds inte." + +#: lib/checkout_op.tcl:262 +#, tcl-format +msgid "Failed to update '%s'." +msgstr "Misslyckades med att uppdatera \"%s\"." + +#: lib/checkout_op.tcl:274 +msgid "Staging area (index) is already locked." +msgstr "Köområdet (index) är redan låst." + +#: 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 "" +"Det senaste inlästa tillståndet motsvarar inte tillståndet i arkivet.\n" +"\n" +"Ett annat Git-program har ändrat arkivet sedan senaste avsökningen. Du måste " +"utföra en ny sökning innan den aktuella grenen kan ändras.\n" +"\n" +"Sökningen kommer att startas automatiskt nu.\n" + +#: lib/checkout_op.tcl:345 +#, tcl-format +msgid "Updating working directory to '%s'..." +msgstr "Uppdaterar arbetskatalogen till \"%s\"..." + +#: lib/checkout_op.tcl:346 +msgid "files checked out" +msgstr "filer utcheckade" + +#: lib/checkout_op.tcl:376 +#, tcl-format +msgid "Aborted checkout of '%s' (file level merging is required)." +msgstr "Avbryter utcheckning av \"%s\" (sammanslagning på filnivå krävs)." + +#: lib/checkout_op.tcl:377 +msgid "File level merge required." +msgstr "Sammanslagning på filnivå krävs." + +#: lib/checkout_op.tcl:381 +#, tcl-format +msgid "Staying on branch '%s'." +msgstr "Stannar på grenen \"%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 "" +"Du är inte längre på en lokal gren.\n" +"\n" +"Om du ville vara på en gren skapar du en nu, baserad på \"Denna frånkopplade " +"utcheckning\"." + +#: lib/checkout_op.tcl:503 lib/checkout_op.tcl:507 +#, tcl-format +msgid "Checked out '%s'." +msgstr "Checkade ut \"%s\"." + +#: lib/checkout_op.tcl:535 +#, tcl-format +msgid "Resetting '%s' to '%s' will lose the following commits:" +msgstr "" +"Om du återställer \"%s\" till \"%s\" går följande incheckningar förlorade:" + +#: lib/checkout_op.tcl:557 +msgid "Recovering lost commits may not be easy." +msgstr "Det kanske inte är så enkelt att återskapa förlorade incheckningar." + +#: lib/checkout_op.tcl:562 +#, tcl-format +msgid "Reset '%s'?" +msgstr "Återställa \"%s\"?" + - #: lib/checkout_op.tcl:567 lib/merge.tcl:164 lib/tools_dlg.tcl:343 ++#: lib/checkout_op.tcl:567 lib/merge.tcl:164 lib/tools_dlg.tcl:336 +msgid "Visualize" +msgstr "Visualisera" + +#: 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 "" +"Kunde inte ställa in aktuell gren.\n" +"\n" +"Arbetskatalogen har bara växlats delvis. Vi uppdaterade filerna utan " +"problem, men kunde inte uppdatera en intern fil i Git.\n" +"\n" +"Detta skulle inte ha hänt. %s kommer nu stängas och ge upp." + - #: lib/choose_font.tcl:39 ++#: lib/choose_font.tcl:41 +msgid "Select" +msgstr "Välj" + - #: lib/choose_font.tcl:53 ++#: lib/choose_font.tcl:55 +msgid "Font Family" +msgstr "Teckensnittsfamilj" + - #: lib/choose_font.tcl:74 ++#: lib/choose_font.tcl:76 +msgid "Font Size" +msgstr "Storlek" + - #: lib/choose_font.tcl:91 ++#: lib/choose_font.tcl:93 +msgid "Font Example" +msgstr "Exempel" + - #: lib/choose_font.tcl:103 ++#: lib/choose_font.tcl:105 +msgid "" +"This is example text.\n" +"If you like this text, it can be your font." +msgstr "" +"Detta är en exempeltext.\n" +"Om du tycker om den här texten kan den vara ditt teckensnitt." + +#: lib/choose_repository.tcl:28 +msgid "Git Gui" +msgstr "Git Gui" + - #: lib/choose_repository.tcl:87 lib/choose_repository.tcl:386 ++#: lib/choose_repository.tcl:87 lib/choose_repository.tcl:394 +msgid "Create New Repository" +msgstr "Skapa nytt arkiv" + +#: lib/choose_repository.tcl:93 +msgid "New..." +msgstr "Nytt..." + - #: lib/choose_repository.tcl:100 lib/choose_repository.tcl:471 ++#: lib/choose_repository.tcl:100 lib/choose_repository.tcl:478 +msgid "Clone Existing Repository" +msgstr "Klona befintligt arkiv" + - #: lib/choose_repository.tcl:106 ++#: lib/choose_repository.tcl:111 +msgid "Clone..." +msgstr "Klona..." + - #: lib/choose_repository.tcl:113 lib/choose_repository.tcl:1016 ++#: lib/choose_repository.tcl:118 lib/choose_repository.tcl:1017 +msgid "Open Existing Repository" +msgstr "Öppna befintligt arkiv" + - #: lib/choose_repository.tcl:119 ++#: lib/choose_repository.tcl:124 +msgid "Open..." +msgstr "Öppna..." + - #: lib/choose_repository.tcl:132 ++#: lib/choose_repository.tcl:137 +msgid "Recent Repositories" +msgstr "Senaste arkiven" + - #: lib/choose_repository.tcl:138 ++#: lib/choose_repository.tcl:143 +msgid "Open Recent Repository:" +msgstr "Öppna tidigare arkiv:" + - #: lib/choose_repository.tcl:306 lib/choose_repository.tcl:313 - #: lib/choose_repository.tcl:320 ++#: lib/choose_repository.tcl:313 lib/choose_repository.tcl:320 ++#: lib/choose_repository.tcl:327 +#, tcl-format +msgid "Failed to create repository %s:" +msgstr "Kunde inte skapa arkivet %s:" + - #: lib/choose_repository.tcl:391 ++#: lib/choose_repository.tcl:399 +msgid "Directory:" +msgstr "Katalog:" + - #: lib/choose_repository.tcl:423 lib/choose_repository.tcl:550 - #: lib/choose_repository.tcl:1052 ++#: lib/choose_repository.tcl:429 lib/choose_repository.tcl:550 ++#: lib/choose_repository.tcl:1051 +msgid "Git Repository" +msgstr "Gitarkiv" + - #: lib/choose_repository.tcl:448 ++#: lib/choose_repository.tcl:454 +#, tcl-format +msgid "Directory %s already exists." +msgstr "Katalogen %s finns redan." + - #: lib/choose_repository.tcl:452 ++#: lib/choose_repository.tcl:458 +#, tcl-format +msgid "File %s already exists." +msgstr "Filen %s finns redan." + - #: lib/choose_repository.tcl:466 ++#: lib/choose_repository.tcl:473 +msgid "Clone" +msgstr "Klona" + - #: lib/choose_repository.tcl:479 ++#: lib/choose_repository.tcl:486 +msgid "Source Location:" +msgstr "Plats för källkod:" + - #: lib/choose_repository.tcl:490 ++#: lib/choose_repository.tcl:495 +msgid "Target Directory:" +msgstr "Målkatalog:" + - #: lib/choose_repository.tcl:502 ++#: lib/choose_repository.tcl:505 +msgid "Clone Type:" +msgstr "Typ av klon:" + - #: lib/choose_repository.tcl:508 ++#: lib/choose_repository.tcl:510 +msgid "Standard (Fast, Semi-Redundant, Hardlinks)" +msgstr "Standard (snabb, semiredundant, hårda länkar)" + - #: lib/choose_repository.tcl:514 ++#: lib/choose_repository.tcl:515 +msgid "Full Copy (Slower, Redundant Backup)" +msgstr "Full kopia (långsammare, redundant säkerhetskopia)" + +#: lib/choose_repository.tcl:520 +msgid "Shared (Fastest, Not Recommended, No Backup)" +msgstr "Delad (snabbast, rekommenderas ej, ingen säkerhetskopia)" + +#: 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 ++#: lib/choose_repository.tcl:1057 lib/choose_repository.tcl:1065 +#, tcl-format +msgid "Not a Git repository: %s" +msgstr "Inte ett Gitarkiv: %s" + +#: lib/choose_repository.tcl:592 +msgid "Standard only available for local repository." +msgstr "Standard är endast tillgängligt för lokala arkiv." + +#: lib/choose_repository.tcl:596 +msgid "Shared only available for local repository." +msgstr "Delat är endast tillgängligt för lokala arkiv." + +#: lib/choose_repository.tcl:617 +#, tcl-format +msgid "Location %s already exists." +msgstr "Platsen %s finns redan." + +#: lib/choose_repository.tcl:628 +msgid "Failed to configure origin" +msgstr "Kunde inte konfigurera ursprung" + +#: lib/choose_repository.tcl:640 +msgid "Counting objects" +msgstr "Räknar objekt" + +#: lib/choose_repository.tcl:641 +msgid "buckets" +msgstr "hinkar" + +#: lib/choose_repository.tcl:665 +#, tcl-format +msgid "Unable to copy objects/info/alternates: %s" +msgstr "Kunde inte kopiera objekt/info/alternativ: %s" + +#: lib/choose_repository.tcl:701 +#, tcl-format +msgid "Nothing to clone from %s." +msgstr "Ingenting att klona från %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 "Grenen \"master\" har inte initierats." + +#: lib/choose_repository.tcl:716 +msgid "Hardlinks are unavailable. Falling back to copying." +msgstr "Hårda länkar är inte tillgängliga. Faller tillbaka på kopiering." + +#: lib/choose_repository.tcl:728 +#, tcl-format +msgid "Cloning from %s" +msgstr "Klonar från %s" + +#: lib/choose_repository.tcl:759 +msgid "Copying objects" +msgstr "Kopierar objekt" + +#: lib/choose_repository.tcl:760 +msgid "KiB" +msgstr "KiB" + +#: lib/choose_repository.tcl:784 +#, tcl-format +msgid "Unable to copy object: %s" +msgstr "Kunde inte kopiera objekt: %s" + +#: lib/choose_repository.tcl:794 +msgid "Linking objects" +msgstr "Länkar objekt" + +#: lib/choose_repository.tcl:795 +msgid "objects" +msgstr "objekt" + +#: lib/choose_repository.tcl:803 +#, tcl-format +msgid "Unable to hardlink object: %s" +msgstr "Kunde inte hårdlänka objekt: %s" + +#: lib/choose_repository.tcl:858 +msgid "Cannot fetch branches and objects. See console output for details." +msgstr "Kunde inte hämta grenar och objekt. Se konsolutdata för detaljer." + +#: lib/choose_repository.tcl:869 +msgid "Cannot fetch tags. See console output for details." +msgstr "Kunde inte hämta taggar. Se konsolutdata för detaljer." + +#: lib/choose_repository.tcl:893 +msgid "Cannot determine HEAD. See console output for details." +msgstr "Kunde inte avgöra HEAD. Se konsolutdata för detaljer." + +#: lib/choose_repository.tcl:902 +#, tcl-format +msgid "Unable to cleanup %s" +msgstr "Kunde inte städa upp %s" + +#: lib/choose_repository.tcl:908 +msgid "Clone failed." +msgstr "Kloning misslyckades." + +#: lib/choose_repository.tcl:915 +msgid "No default branch obtained." +msgstr "Hämtade ingen standardgren." + +#: lib/choose_repository.tcl:926 +#, tcl-format +msgid "Cannot resolve %s as a commit." +msgstr "Kunde inte slå upp %s till någon incheckning." + +#: lib/choose_repository.tcl:938 +msgid "Creating working directory" +msgstr "Skapar arbetskatalog" + - #: lib/choose_repository.tcl:939 lib/index.tcl:67 lib/index.tcl:130 - #: lib/index.tcl:198 ++#: lib/choose_repository.tcl:939 lib/index.tcl:70 lib/index.tcl:133 ++#: lib/index.tcl:201 +msgid "files" +msgstr "filer" + +#: lib/choose_repository.tcl:968 +msgid "Initial file checkout failed." +msgstr "Inledande filutcheckning misslyckades." + - #: lib/choose_repository.tcl:1011 ++#: lib/choose_repository.tcl:1012 +msgid "Open" +msgstr "Öppna" + - #: lib/choose_repository.tcl:1021 ++#: lib/choose_repository.tcl:1022 +msgid "Repository:" +msgstr "Arkiv:" + - #: lib/choose_repository.tcl:1072 ++#: lib/choose_repository.tcl:1071 +#, tcl-format +msgid "Failed to open repository %s:" +msgstr "Kunde inte öppna arkivet %s:" + - #: lib/choose_rev.tcl:53 ++#: lib/choose_rev.tcl:52 +msgid "This Detached Checkout" +msgstr "Denna frånkopplade utcheckning" + +#: lib/choose_rev.tcl:60 +msgid "Revision Expression:" +msgstr "Revisionsuttryck:" + - #: lib/choose_rev.tcl:74 ++#: lib/choose_rev.tcl:72 +msgid "Local Branch" +msgstr "Lokal gren" + - #: lib/choose_rev.tcl:79 ++#: lib/choose_rev.tcl:77 +msgid "Tracking Branch" +msgstr "Spårande gren" + - #: lib/choose_rev.tcl:84 lib/choose_rev.tcl:538 ++#: lib/choose_rev.tcl:82 lib/choose_rev.tcl:543 +msgid "Tag" +msgstr "Tagg" + - #: lib/choose_rev.tcl:317 ++#: lib/choose_rev.tcl:321 +#, tcl-format +msgid "Invalid revision: %s" +msgstr "Ogiltig revision: %s" + - #: lib/choose_rev.tcl:338 ++#: lib/choose_rev.tcl:342 +msgid "No revision selected." +msgstr "Ingen revision vald." + - #: lib/choose_rev.tcl:346 ++#: lib/choose_rev.tcl:350 +msgid "Revision expression is empty." +msgstr "Revisionsuttrycket är tomt." + - #: lib/choose_rev.tcl:531 ++#: lib/choose_rev.tcl:536 +msgid "Updated" +msgstr "Uppdaterad" + - #: lib/choose_rev.tcl:559 ++#: lib/choose_rev.tcl:564 +msgid "URL" +msgstr "Webbadress" + +#: 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 "" +"Det finns ingenting att utöka.\n" +"\n" +"Du håller på att skapa den inledande incheckningen. Det finns ingen tidigare " +"incheckning att utöka.\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 "" +"Kan inte utöka vid sammanslagning.\n" +"\n" +"Du är i mitten av en sammanslagning som inte är fullbordad. Du kan inte " +"utöka tidigare incheckningar om du inte först avbryter den pågående " +"sammanslagningen.\n" + +#: lib/commit.tcl:48 +msgid "Error loading commit data for amend:" +msgstr "Fel vid inläsning av incheckningsdata för utökning:" + +#: lib/commit.tcl:75 +msgid "Unable to obtain your identity:" +msgstr "Kunde inte hämta din identitet:" + +#: lib/commit.tcl:80 +msgid "Invalid GIT_COMMITTER_IDENT:" +msgstr "Felaktig GIT_COMMITTER_IDENT:" + +#: lib/commit.tcl:129 +#, tcl-format +msgid "warning: Tcl does not support encoding '%s'." +msgstr "varning: Tcl stöder inte teckenkodningen \"%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 "" +"Det senaste inlästa tillståndet motsvarar inte tillståndet i arkivet.\n" +"\n" +"Ett annat Git-program har ändrat arkivet sedan senaste avsökningen. Du måste " +"utföra en ny sökning innan du kan göra en ny incheckning.\n" +"\n" +"Sökningen kommer att startas automatiskt nu.\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 "" +"Osammanslagna filer kan inte checkas in.\n" +"\n" +"Filen %s har sammanslagningskonflikter. Du måste lösa dem och köa filen " +"innan du checkar in den.\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 "" +"Okänd filstatus %s upptäckt.\n" +"\n" +"Filen %s kan inte checkas in av programmet.\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 "" +"Inga ändringar att checka in.\n" +"\n" +"Du måste köa åtminstone en fil innan du kan checka in.\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 "" +"Ange ett incheckningsmeddelande.\n" +"\n" +"Ett bra incheckningsmeddelande har följande format:\n" +"\n" +"- Första raden: Beskriv i en mening vad du gjorde.\n" +"- Andra raden: Tom\n" +"- Följande rader: Beskriv varför det här är en bra ändring.\n" + +#: lib/commit.tcl:234 +msgid "Calling pre-commit hook..." +msgstr "Anropar kroken före incheckning (pre-commit)..." + +#: lib/commit.tcl:249 +msgid "Commit declined by pre-commit hook." +msgstr "Incheckningen avvisades av kroken före incheckning (pre-commit)." + +#: lib/commit.tcl:272 +msgid "Calling commit-msg hook..." +msgstr "Anropar kroken för incheckningsmeddelande (commit-msg)..." + +#: lib/commit.tcl:287 +msgid "Commit declined by commit-msg hook." +msgstr "Incheckning avvisad av kroken för incheckningsmeddelande (commit-msg)." + +#: lib/commit.tcl:300 +msgid "Committing changes..." +msgstr "Checkar in ändringar..." + +#: lib/commit.tcl:316 +msgid "write-tree failed:" +msgstr "write-tree misslyckades:" + +#: lib/commit.tcl:317 lib/commit.tcl:361 lib/commit.tcl:382 +msgid "Commit failed." +msgstr "Incheckningen misslyckades." + +#: lib/commit.tcl:334 +#, tcl-format +msgid "Commit %s appears to be corrupt" +msgstr "Incheckningen %s verkar vara trasig" + +#: 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 "" +"Inga ändringar att checka in.\n" +"\n" +"Inga filer ändrades av incheckningen och det var inte en sammanslagning.\n" +"\n" +"En sökning kommer att startas automatiskt nu.\n" + +#: lib/commit.tcl:346 +msgid "No changes to commit." +msgstr "Inga ändringar att checka in." + +#: lib/commit.tcl:360 +msgid "commit-tree failed:" +msgstr "commit-tree misslyckades:" + +#: lib/commit.tcl:381 +msgid "update-ref failed:" +msgstr "update-ref misslyckades:" + +#: lib/commit.tcl:469 +#, tcl-format +msgid "Created commit %s: %s" +msgstr "Skapade incheckningen %s: %s" + +#: lib/console.tcl:59 +msgid "Working... please wait..." +msgstr "Arbetar... vänta..." + +#: lib/console.tcl:186 +msgid "Success" +msgstr "Lyckades" + +#: lib/console.tcl:200 +msgid "Error: Command Failed" +msgstr "Fel: Kommando misslyckades" + - #: lib/database.tcl:43 ++#: lib/database.tcl:42 +msgid "Number of loose objects" +msgstr "Antal lösa objekt" + - #: lib/database.tcl:44 ++#: lib/database.tcl:43 +msgid "Disk space used by loose objects" +msgstr "Diskutrymme använt av lösa objekt" + - #: lib/database.tcl:45 ++#: lib/database.tcl:44 +msgid "Number of packed objects" +msgstr "Antal packade objekt" + - #: lib/database.tcl:46 ++#: lib/database.tcl:45 +msgid "Number of packs" +msgstr "Antal paket" + - #: lib/database.tcl:47 ++#: lib/database.tcl:46 +msgid "Disk space used by packed objects" +msgstr "Diskutrymme använt av packade objekt" + - #: lib/database.tcl:48 ++#: lib/database.tcl:47 +msgid "Packed objects waiting for pruning" +msgstr "Packade objekt som väntar på städning" + - #: lib/database.tcl:49 ++#: lib/database.tcl:48 +msgid "Garbage files" +msgstr "Skräpfiler" + +#: lib/database.tcl:72 +msgid "Compressing the object database" +msgstr "Komprimerar objektdatabasen" + +#: lib/database.tcl:83 +msgid "Verifying the object database with fsck-objects" +msgstr "Verifierar objektdatabasen med 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 "" +"Arkivet har för närvarande omkring %i lösa objekt.\n" +"\n" +"För att bibehålla optimal prestanda rekommenderas det å det bestämdaste att " +"du komprimerar databasen.\n" +"\n" +"Komprimera databasen nu?" + +#: lib/date.tcl:25 +#, tcl-format +msgid "Invalid date from Git: %s" +msgstr "Ogiltigt datum från 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 "" +"Hittade inga skillnader.\n" +"\n" +"%s innehåller inga ändringar.\n" +"\n" +"Modifieringsdatum för filen uppdaterades av ett annat program, men " +"innehållet i filen har inte ändrats.\n" +"\n" +"En sökning kommer automatiskt att startas för att hitta andra filer som kan " +"vara i samma tillstånd." + +#: lib/diff.tcl:104 +#, tcl-format +msgid "Loading diff of %s..." +msgstr "Läser differens för %s..." + +#: lib/diff.tcl:125 +msgid "" +"LOCAL: deleted\n" +"REMOTE:\n" +msgstr "" +"LOKAL: borttagen\n" +"FJÄRR:\n" + +#: lib/diff.tcl:130 +msgid "" +"REMOTE: deleted\n" +"LOCAL:\n" +msgstr "" +"FJÄRR: borttagen\n" +"LOKAL:\n" + +#: lib/diff.tcl:137 +msgid "LOCAL:\n" +msgstr "LOKAL:\n" + +#: lib/diff.tcl:140 +msgid "REMOTE:\n" +msgstr "FJÄRR:\n" + - #: lib/diff.tcl:202 lib/diff.tcl:319 ++#: lib/diff.tcl:202 lib/diff.tcl:322 +#, tcl-format +msgid "Unable to display %s" +msgstr "Kan inte visa %s" + +#: lib/diff.tcl:203 +msgid "Error loading file:" +msgstr "Fel vid läsning av fil:" + +#: lib/diff.tcl:210 +msgid "Git Repository (subproject)" +msgstr "Gitarkiv (underprojekt)" + +#: lib/diff.tcl:222 +msgid "* Binary file (not showing content)." +msgstr "* Binärfil (visar inte innehållet)." + +#: lib/diff.tcl:227 +#, tcl-format +msgid "" +"* Untracked file is %d bytes.\n" +"* Showing only first %d bytes.\n" +msgstr "" +"* Den ospårade filen är %d byte.\n" +"* Visar endast inledande %d byte.\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" +"* Den ospårade filen klipptes här av %s.\n" +"* För att se hela filen, använd ett externt redigeringsprogram.\n" + - #: lib/diff.tcl:482 ++#: lib/diff.tcl:485 +msgid "Failed to unstage selected hunk." +msgstr "Kunde inte ta bort den valda delen från kön." + - #: lib/diff.tcl:489 ++#: lib/diff.tcl:492 +msgid "Failed to stage selected hunk." +msgstr "Kunde inte lägga till den valda delen till kön." + - #: lib/diff.tcl:568 ++#: lib/diff.tcl:571 +msgid "Failed to unstage selected line." +msgstr "Kunde inte ta bort den valda raden från kön." + - #: lib/diff.tcl:576 ++#: lib/diff.tcl:579 +msgid "Failed to stage selected line." +msgstr "Kunde inte lägga till den valda raden till kön." + +#: lib/encoding.tcl:443 +msgid "Default" +msgstr "Standard" + +#: lib/encoding.tcl:448 +#, tcl-format +msgid "System (%s)" +msgstr "Systemets (%s)" + +#: lib/encoding.tcl:459 lib/encoding.tcl:465 +msgid "Other" +msgstr "Annan" + - #: lib/error.tcl:20 lib/error.tcl:114 ++#: lib/error.tcl:20 lib/error.tcl:116 +msgid "error" +msgstr "fel" + +#: lib/error.tcl:36 +msgid "warning" +msgstr "varning" + - #: lib/error.tcl:94 ++#: lib/error.tcl:96 +msgid "You must correct the above errors before committing." +msgstr "Du måste rätta till felen ovan innan du checkar in." + +#: lib/index.tcl:6 +msgid "Unable to unlock the index." +msgstr "Kunde inte låsa upp indexet." + - #: lib/index.tcl:15 ++#: lib/index.tcl:17 +msgid "Index Error" +msgstr "Indexfel" + - #: lib/index.tcl:17 ++#: lib/index.tcl:19 +msgid "" +"Updating the Git index failed. A rescan will be automatically started to " +"resynchronize git-gui." +msgstr "" +"Misslyckades med att uppdatera Gitindexet. En omsökning kommer att startas " +"automatiskt för att synkronisera om git-gui." + - #: lib/index.tcl:28 ++#: lib/index.tcl:30 +msgid "Continue" +msgstr "Forstätt" + - #: lib/index.tcl:31 ++#: lib/index.tcl:33 +msgid "Unlock Index" +msgstr "Lås upp index" + - #: lib/index.tcl:289 ++#: lib/index.tcl:292 +#, tcl-format +msgid "Unstaging %s from commit" +msgstr "Tar bort %s för incheckningskön" + - #: lib/index.tcl:328 ++#: lib/index.tcl:331 +msgid "Ready to commit." +msgstr "Redo att checka in." + - #: lib/index.tcl:341 ++#: lib/index.tcl:344 +#, tcl-format +msgid "Adding %s" +msgstr "Lägger till %s" + - #: lib/index.tcl:398 ++#: lib/index.tcl:401 +#, tcl-format +msgid "Revert changes in file %s?" +msgstr "Återställ ändringarna i filen %s?" + - #: lib/index.tcl:400 ++#: lib/index.tcl:403 +#, tcl-format +msgid "Revert changes in these %i files?" +msgstr "Återställ ändringarna i dessa %i filer?" + - #: lib/index.tcl:408 ++#: lib/index.tcl:411 +msgid "Any unstaged changes will be permanently lost by the revert." +msgstr "" +"Alla oköade ändringar kommer permanent gå förlorade vid återställningen." + - #: lib/index.tcl:411 ++#: lib/index.tcl:414 +msgid "Do Nothing" +msgstr "Gör ingenting" + - #: lib/index.tcl:429 ++#: lib/index.tcl:432 +msgid "Reverting selected files" +msgstr "Återställer valda filer" + - #: lib/index.tcl:433 ++#: lib/index.tcl:436 +#, tcl-format +msgid "Reverting %s" +msgstr "Återställer %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 "" +"Kan inte slå ihop vid utökning.\n" +"\n" +"Du måste göra färdig utökningen av incheckningen innan du påbörjar någon " +"slags sammanslagning.\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 "" +"Det senaste inlästa tillståndet motsvarar inte tillståndet i arkivet.\n" +"\n" +"Ett annat Git-program har ändrat arkivet sedan senaste avsökningen. Du måste " +"utföra en ny sökning innan du kan utföra en sammanslagning.\n" +"\n" +"Sökningen kommer att startas automatiskt nu.\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 "" +"Du är mitt i en sammanslagning med konflikter.\n" +"\n" +"Filen %s har sammanslagningskonflikter.\n" +"\n" +"Du måste lösa dem, köa filen och checka in för att fullborda den aktuella " +"sammanslagningen. När du gjort det kan du påbörja en ny sammanslagning.\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 "" +"Du är mitt i en ändring.\n" +"\n" +"Filen %s har ändringar.\n" +"\n" +"Du bör fullborda den aktuella incheckningen innan du påbörjar en " +"sammanslagning. Om du gör det blir det enklare att avbryta en misslyckad " +"sammanslagning, om det skulle vara nödvändigt.\n" + +#: lib/merge.tcl:107 +#, tcl-format +msgid "%s of %s" +msgstr "%s av %s" + +#: lib/merge.tcl:120 +#, tcl-format +msgid "Merging %s and %s..." +msgstr "Slår ihop %s och %s..." + +#: lib/merge.tcl:131 +msgid "Merge completed successfully." +msgstr "Sammanslagningen avslutades framgångsrikt." + +#: lib/merge.tcl:133 +msgid "Merge failed. Conflict resolution is required." +msgstr "Sammanslagningen misslyckades. Du måste lösa konflikterna." + +#: lib/merge.tcl:158 +#, tcl-format +msgid "Merge Into %s" +msgstr "Slå ihop i %s" + +#: lib/merge.tcl:177 +msgid "Revision To Merge" +msgstr "Revisioner att slå ihop" + +#: lib/merge.tcl:212 +msgid "" +"Cannot abort while amending.\n" +"\n" +"You must finish amending this commit.\n" +msgstr "" +"Kan inte avbryta vid utökning.\n" +"\n" +"Du måste göra dig färdig med att utöka incheckningen.\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 "" +"Avbryt sammanslagning?\n" +"\n" +"Om du avbryter sammanslagningen kommer *ALLA* ej incheckade ändringar att gå " +"förlorade.\n" +"\n" +"Gå vidare med att avbryta den aktuella sammanslagningen?" + +#: 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 "" +"Återställ ändringar?\n" +"\n" +"Om du återställer ändringarna kommer *ALLA* ej incheckade ändringar att gå " +"förlorade.\n" +"\n" +"Gå vidare med att återställa de aktuella ändringarna?" + +#: lib/merge.tcl:239 +msgid "Aborting" +msgstr "Avbryter" + +#: lib/merge.tcl:239 +msgid "files reset" +msgstr "filer återställda" + +#: lib/merge.tcl:267 +msgid "Abort failed." +msgstr "Misslyckades avbryta." + +#: lib/merge.tcl:269 +msgid "Abort completed. Ready." +msgstr "Avbrytning fullbordad. Redo." + +#: lib/mergetool.tcl:8 +msgid "Force resolution to the base version?" +msgstr "Tvinga lösning att använda basversionen?" + +#: lib/mergetool.tcl:9 +msgid "Force resolution to this branch?" +msgstr "Tvinga lösning att använda den aktuella grenen?" + +#: lib/mergetool.tcl:10 +msgid "Force resolution to the other branch?" +msgstr "Tvinga lösning att använda den andra grenen?" + +#: 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 "" +"Observera att diffen endast visar de ändringar som står i konflikt.\n" +"\n" +"%s kommer att skrivas över.\n" +"\n" +"Du måste starta om sammanslagningen för att göra den här operationen ogjord." + +#: lib/mergetool.tcl:45 +#, tcl-format +msgid "File %s seems to have unresolved conflicts, still stage?" +msgstr "Filen %s verkar innehålla olösta konflikter. Vill du köa ändå?" + +#: lib/mergetool.tcl:60 +#, tcl-format +msgid "Adding resolution for %s" +msgstr "Lägger till lösning för %s" + +#: lib/mergetool.tcl:141 +msgid "Cannot resolve deletion or link conflicts using a tool" +msgstr "Kan inte lösa borttagnings- eller länkkonflikter med ett verktyg" + +#: lib/mergetool.tcl:146 +msgid "Conflict file does not exist" +msgstr "Konfliktfil existerar inte" + +#: lib/mergetool.tcl:264 +#, tcl-format +msgid "Not a GUI merge tool: '%s'" +msgstr "Inte ett grafiskt verktyg för sammanslagning: %s" + +#: lib/mergetool.tcl:268 +#, tcl-format +msgid "Unsupported merge tool '%s'" +msgstr "Verktyget \"%s\" för sammanslagning stöds inte" + +#: lib/mergetool.tcl:303 +msgid "Merge tool is already running, terminate it?" +msgstr "Verktyget för sammanslagning körs redan. Vill du avsluta det?" + +#: lib/mergetool.tcl:323 +#, tcl-format +msgid "" +"Error retrieving versions:\n" +"%s" +msgstr "" +"Fel vid hämtning av versioner:\n" +"%s" + +#: lib/mergetool.tcl:343 +#, tcl-format +msgid "" +"Could not start the merge tool:\n" +"\n" +"%s" +msgstr "" +"Kunde inte starta verktyg för sammanslagning:\n" +"\n" +"%s" + +#: lib/mergetool.tcl:347 +msgid "Running merge tool..." +msgstr "Kör verktyg för sammanslagning..." + +#: lib/mergetool.tcl:375 lib/mergetool.tcl:383 +msgid "Merge tool failed." +msgstr "Verktyget för sammanslagning misslyckades." + +#: lib/option.tcl:11 +#, tcl-format +msgid "Invalid global encoding '%s'" +msgstr "Den globala teckenkodningen \"%s\" är ogiltig" + +#: lib/option.tcl:19 +#, tcl-format +msgid "Invalid repo encoding '%s'" +msgstr "Arkivets teckenkodning \"%s\" är ogiltig" + - #: lib/option.tcl:117 ++#: lib/option.tcl:119 +msgid "Restore Defaults" +msgstr "Återställ standardvärden" + - #: lib/option.tcl:121 ++#: lib/option.tcl:123 +msgid "Save" +msgstr "Spara" + - #: lib/option.tcl:131 ++#: lib/option.tcl:133 +#, tcl-format +msgid "%s Repository" +msgstr "Arkivet %s" + - #: lib/option.tcl:132 ++#: lib/option.tcl:134 +msgid "Global (All Repositories)" +msgstr "Globalt (alla arkiv)" + - #: lib/option.tcl:138 ++#: lib/option.tcl:140 +msgid "User Name" +msgstr "Användarnamn" + - #: lib/option.tcl:139 ++#: lib/option.tcl:141 +msgid "Email Address" +msgstr "E-postadress" + - #: lib/option.tcl:141 ++#: lib/option.tcl:143 +msgid "Summarize Merge Commits" +msgstr "Summera sammanslagningsincheckningar" + - #: lib/option.tcl:142 ++#: lib/option.tcl:144 +msgid "Merge Verbosity" +msgstr "Pratsamhet för sammanslagningar" + - #: lib/option.tcl:143 ++#: lib/option.tcl:145 +msgid "Show Diffstat After Merge" +msgstr "Visa diffstatistik efter sammanslagning" + - #: lib/option.tcl:144 ++#: lib/option.tcl:146 +msgid "Use Merge Tool" +msgstr "Använd verktyg för sammanslagning" + - #: lib/option.tcl:146 ++#: lib/option.tcl:148 +msgid "Trust File Modification Timestamps" +msgstr "Lita på filändringstidsstämplar" + - #: lib/option.tcl:147 ++#: lib/option.tcl:149 +msgid "Prune Tracking Branches During Fetch" +msgstr "Städa spårade grenar vid hämtning" + - #: lib/option.tcl:148 ++#: lib/option.tcl:150 +msgid "Match Tracking Branches" +msgstr "Matcha spårade grenar" + - #: lib/option.tcl:149 ++#: lib/option.tcl:151 ++msgid "Use Textconv For Diffs and Blames" ++msgstr "Använd Textconv för diff och klandring" ++ ++#: lib/option.tcl:152 +msgid "Blame Copy Only On Changed Files" +msgstr "Klandra kopiering bara i ändrade filer" + - #: lib/option.tcl:150 ++#: lib/option.tcl:153 +msgid "Minimum Letters To Blame Copy On" +msgstr "Minsta antal tecken att klandra kopiering för" + - #: lib/option.tcl:151 ++#: lib/option.tcl:154 +msgid "Blame History Context Radius (days)" +msgstr "Historikradie för klandring (dagar)" + - #: lib/option.tcl:152 ++#: lib/option.tcl:155 +msgid "Number of Diff Context Lines" +msgstr "Antal rader sammanhang i differenser" + - #: lib/option.tcl:153 ++#: lib/option.tcl:156 +msgid "Commit Message Text Width" +msgstr "Textbredd för incheckningsmeddelande" + - #: lib/option.tcl:154 ++#: lib/option.tcl:157 +msgid "New Branch Name Template" +msgstr "Mall för namn på nya grenar" + - #: lib/option.tcl:155 ++#: lib/option.tcl:158 +msgid "Default File Contents Encoding" +msgstr "Standardteckenkodning för filinnehåll" + - #: lib/option.tcl:203 ++#: lib/option.tcl:204 +msgid "Change" +msgstr "Ändra" + - #: lib/option.tcl:230 ++#: lib/option.tcl:231 +msgid "Spelling Dictionary:" +msgstr "Stavningsordlista:" + - #: lib/option.tcl:254 ++#: lib/option.tcl:261 +msgid "Change Font" +msgstr "Byt teckensnitt" + - #: lib/option.tcl:258 ++#: lib/option.tcl:265 +#, tcl-format +msgid "Choose %s" +msgstr "Välj %s" + - #: lib/option.tcl:264 ++#: lib/option.tcl:271 +msgid "pt." +msgstr "p." + - #: lib/option.tcl:278 ++#: lib/option.tcl:285 +msgid "Preferences" +msgstr "Inställningar" + - #: lib/option.tcl:314 ++#: lib/option.tcl:322 +msgid "Failed to completely save options:" +msgstr "Misslyckades med att helt spara alternativ:" + - #: lib/remote.tcl:163 - msgid "Remove Remote" - msgstr "Ta bort fjärrarkiv" - - #: lib/remote.tcl:168 - msgid "Prune from" - msgstr "Ta bort från" - - #: lib/remote.tcl:173 - msgid "Fetch from" - msgstr "Hämta från" - - #: lib/remote.tcl:215 - msgid "Push to" - msgstr "Sänd till" - - #: lib/remote_add.tcl:19 ++#: lib/remote_add.tcl:20 +msgid "Add Remote" +msgstr "Lägg till fjärrarkiv" + - #: lib/remote_add.tcl:24 ++#: lib/remote_add.tcl:25 +msgid "Add New Remote" +msgstr "Lägg till nytt fjärrarkiv" + - #: lib/remote_add.tcl:28 lib/tools_dlg.tcl:36 ++#: lib/remote_add.tcl:30 lib/tools_dlg.tcl:37 +msgid "Add" +msgstr "Lägg till" + - #: lib/remote_add.tcl:37 ++#: lib/remote_add.tcl:39 +msgid "Remote Details" +msgstr "Detaljer för fjärrarkiv" + +#: lib/remote_add.tcl:50 +msgid "Location:" +msgstr "Plats:" + - #: lib/remote_add.tcl:62 ++#: lib/remote_add.tcl:60 +msgid "Further Action" +msgstr "Ytterligare åtgärd" + - #: lib/remote_add.tcl:65 ++#: lib/remote_add.tcl:63 +msgid "Fetch Immediately" +msgstr "Hämta omedelbart" + - #: lib/remote_add.tcl:71 ++#: lib/remote_add.tcl:69 +msgid "Initialize Remote Repository and Push" +msgstr "Initiera fjärrarkiv och sänd till" + - #: lib/remote_add.tcl:77 ++#: lib/remote_add.tcl:75 +msgid "Do Nothing Else Now" +msgstr "Gör ingent mer nu" + - #: lib/remote_add.tcl:101 ++#: lib/remote_add.tcl:100 +msgid "Please supply a remote name." +msgstr "Ange ett namn för fjärrarkivet." + - #: lib/remote_add.tcl:114 ++#: lib/remote_add.tcl:113 +#, tcl-format +msgid "'%s' is not an acceptable remote name." +msgstr "\"%s\" kan inte användas som namn på fjärrarkivet." + - #: lib/remote_add.tcl:125 ++#: lib/remote_add.tcl:124 +#, tcl-format +msgid "Failed to add remote '%s' of location '%s'." +msgstr "Kunde inte lägga till fjärrarkivet \"%s\" på platsen \"%s\"." + - #: lib/remote_add.tcl:133 lib/transport.tcl:6 ++#: lib/remote_add.tcl:132 lib/transport.tcl:6 +#, tcl-format +msgid "fetch %s" +msgstr "hämta %s" + - #: lib/remote_add.tcl:134 ++#: lib/remote_add.tcl:133 +#, tcl-format +msgid "Fetching the %s" +msgstr "Hämtar %s" + - #: lib/remote_add.tcl:157 ++#: lib/remote_add.tcl:156 +#, tcl-format +msgid "Do not know how to initialize repository at location '%s'." +msgstr "Vet inte hur arkivet på platsen \"%s\" skall initieras." + - #: lib/remote_add.tcl:163 lib/transport.tcl:25 lib/transport.tcl:63 ++#: lib/remote_add.tcl:162 lib/transport.tcl:25 lib/transport.tcl:63 +#: lib/transport.tcl:81 +#, tcl-format +msgid "push %s" +msgstr "sänd %s" + - #: lib/remote_add.tcl:164 ++#: lib/remote_add.tcl:163 +#, tcl-format +msgid "Setting up the %s (at %s)" +msgstr "Konfigurerar %s (på %s)" + +#: lib/remote_branch_delete.tcl:29 lib/remote_branch_delete.tcl:34 +msgid "Delete Branch Remotely" +msgstr "Ta bort gren från fjärrarkiv" + - #: lib/remote_branch_delete.tcl:47 ++#: lib/remote_branch_delete.tcl:48 +msgid "From Repository" +msgstr "Från arkiv" + - #: lib/remote_branch_delete.tcl:50 lib/transport.tcl:134 ++#: lib/remote_branch_delete.tcl:51 lib/transport.tcl:134 +msgid "Remote:" +msgstr "Fjärrarkiv:" + - #: lib/remote_branch_delete.tcl:66 lib/transport.tcl:149 ++#: lib/remote_branch_delete.tcl:72 lib/transport.tcl:154 +msgid "Arbitrary Location:" +msgstr "Godtycklig plats:" + - #: lib/remote_branch_delete.tcl:84 ++#: lib/remote_branch_delete.tcl:88 +msgid "Branches" +msgstr "Grenar" + - #: lib/remote_branch_delete.tcl:109 ++#: lib/remote_branch_delete.tcl:110 +msgid "Delete Only If" +msgstr "Ta endast bort om" + - #: lib/remote_branch_delete.tcl:111 ++#: lib/remote_branch_delete.tcl:112 +msgid "Merged Into:" +msgstr "Sammanslagen i:" + - #: lib/remote_branch_delete.tcl:152 ++#: lib/remote_branch_delete.tcl:153 +msgid "A branch is required for 'Merged Into'." +msgstr "En gren krävs för \"Sammanslagen i\"." + - #: lib/remote_branch_delete.tcl:184 ++#: lib/remote_branch_delete.tcl:185 +#, tcl-format +msgid "" +"The following branches are not completely merged into %s:\n" +"\n" +" - %s" +msgstr "" +"Följande grenar har inte helt slagits samman i %s:\n" +"\n" +" - %s" + - #: lib/remote_branch_delete.tcl:189 ++#: lib/remote_branch_delete.tcl:190 +#, 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 "" +"En eller flera av sammanslagningstesterna misslyckades eftersom du inte har " +"hämtat de nödvändiga incheckningarna. Försök hämta från %s först." + - #: lib/remote_branch_delete.tcl:207 ++#: lib/remote_branch_delete.tcl:208 +msgid "Please select one or more branches to delete." +msgstr "Välj en eller flera grenar att ta bort." + - #: lib/remote_branch_delete.tcl:226 ++#: lib/remote_branch_delete.tcl:227 +#, tcl-format +msgid "Deleting branches from %s" +msgstr "Tar bort grenar från %s" + - #: lib/remote_branch_delete.tcl:292 ++#: lib/remote_branch_delete.tcl:293 +msgid "No repository selected." +msgstr "Inget arkiv markerat." + - #: lib/remote_branch_delete.tcl:297 ++#: lib/remote_branch_delete.tcl:298 +#, tcl-format +msgid "Scanning %s..." +msgstr "Söker %s..." + - #: lib/search.tcl:21 ++#: lib/remote.tcl:163 ++msgid "Remove Remote" ++msgstr "Ta bort fjärrarkiv" ++ ++#: lib/remote.tcl:168 ++msgid "Prune from" ++msgstr "Ta bort från" ++ ++#: lib/remote.tcl:173 ++msgid "Fetch from" ++msgstr "Hämta från" ++ ++#: lib/remote.tcl:215 ++msgid "Push to" ++msgstr "Sänd till" ++ ++#: lib/search.tcl:22 +msgid "Find:" +msgstr "Sök:" + - #: lib/search.tcl:23 ++#: lib/search.tcl:24 +msgid "Next" +msgstr "Nästa" + - #: lib/search.tcl:24 ++#: lib/search.tcl:25 +msgid "Prev" +msgstr "Föreg" + - #: lib/search.tcl:25 ++#: lib/search.tcl:26 +msgid "Case-Sensitive" +msgstr "Skilj på VERSALER/gemener" + +#: lib/shortcut.tcl:21 lib/shortcut.tcl:62 +msgid "Cannot write shortcut:" +msgstr "Kan inte skriva genväg:" + +#: lib/shortcut.tcl:137 +msgid "Cannot write icon:" +msgstr "Kan inte skriva ikon:" + +#: lib/spellcheck.tcl:57 +msgid "Unsupported spell checker" +msgstr "Stavningskontrollprogrammet stöds inte" + +#: lib/spellcheck.tcl:65 +msgid "Spell checking is unavailable" +msgstr "Stavningskontroll är ej tillgänglig" + +#: lib/spellcheck.tcl:68 +msgid "Invalid spell checking configuration" +msgstr "Ogiltig inställning för stavningskontroll" + +#: lib/spellcheck.tcl:70 +#, tcl-format +msgid "Reverting dictionary to %s." +msgstr "Återställer ordlistan till %s." + +#: lib/spellcheck.tcl:73 +msgid "Spell checker silently failed on startup" +msgstr "Stavningskontroll misslyckades tyst vid start" + +#: lib/spellcheck.tcl:80 +msgid "Unrecognized spell checker" +msgstr "Stavningskontrollprogrammet känns inte igen" + +#: lib/spellcheck.tcl:186 +msgid "No Suggestions" +msgstr "Inga förslag" + +#: lib/spellcheck.tcl:388 +msgid "Unexpected EOF from spell checker" +msgstr "Oväntat filslut från stavningskontroll" + +#: lib/spellcheck.tcl:392 +msgid "Spell Checker Failed" +msgstr "Stavningskontroll misslyckades" + +#: lib/sshkey.tcl:31 +msgid "No keys found." +msgstr "Inga nycklar hittades." + +#: lib/sshkey.tcl:34 +#, tcl-format +msgid "Found a public key in: %s" +msgstr "Hittade öppen nyckel i: %s" + +#: lib/sshkey.tcl:40 +msgid "Generate Key" +msgstr "Skapa nyckel" + - #: lib/sshkey.tcl:56 ++#: lib/sshkey.tcl:58 +msgid "Copy To Clipboard" +msgstr "Kopiera till Urklipp" + - #: lib/sshkey.tcl:70 ++#: lib/sshkey.tcl:72 +msgid "Your OpenSSH Public Key" +msgstr "Din öppna OpenSSH-nyckel" + - #: lib/sshkey.tcl:78 ++#: lib/sshkey.tcl:80 +msgid "Generating..." +msgstr "Skapar..." + - #: lib/sshkey.tcl:84 ++#: lib/sshkey.tcl:86 +#, tcl-format +msgid "" +"Could not start ssh-keygen:\n" +"\n" +"%s" +msgstr "" +"Kunde inte starta ssh-keygen:\n" +"\n" +"%s" + - #: lib/sshkey.tcl:111 ++#: lib/sshkey.tcl:113 +msgid "Generation failed." +msgstr "Misslyckades med att skapa." + - #: lib/sshkey.tcl:118 ++#: lib/sshkey.tcl:120 +msgid "Generation succeded, but no keys found." +msgstr "Lyckades skapa nyckeln, men hittar inte någon nyckel." + - #: lib/sshkey.tcl:121 ++#: lib/sshkey.tcl:123 +#, tcl-format +msgid "Your key is in: %s" +msgstr "Din nyckel finns i: %s" + - #: lib/status_bar.tcl:83 ++#: lib/status_bar.tcl:86 +#, tcl-format +msgid "%s ... %*i of %*i %s (%3i%%)" +msgstr "%s... %*i av %*i %s (%3i%%)" + - #: lib/tools.tcl:75 - #, tcl-format - msgid "Running %s requires a selected file." - msgstr "För att starta %s måste du välja en fil." - - #: lib/tools.tcl:90 - #, tcl-format - msgid "Are you sure you want to run %s?" - msgstr "Är du säker på att du vill starta %s?" - - #: lib/tools.tcl:110 - #, tcl-format - msgid "Tool: %s" - msgstr "Verktyg: %s" - - #: lib/tools.tcl:111 - #, tcl-format - msgid "Running: %s" - msgstr "Exekverar: %s" - - #: lib/tools.tcl:149 - #, tcl-format - msgid "Tool completed successfully: %s" - msgstr "Verktyget avslutades framgångsrikt: %s" - - #: lib/tools.tcl:151 - #, tcl-format - msgid "Tool failed: %s" - msgstr "Verktyget misslyckades: %s" - +#: lib/tools_dlg.tcl:22 +msgid "Add Tool" +msgstr "Lägg till verktyg" + +#: lib/tools_dlg.tcl:28 +msgid "Add New Tool Command" +msgstr "Lägg till nytt verktygskommando" + - #: lib/tools_dlg.tcl:33 ++#: lib/tools_dlg.tcl:34 +msgid "Add globally" +msgstr "Lägg till globalt" + - #: lib/tools_dlg.tcl:45 ++#: lib/tools_dlg.tcl:46 +msgid "Tool Details" +msgstr "Detaljer för verktyg" + - #: lib/tools_dlg.tcl:48 ++#: lib/tools_dlg.tcl:49 +msgid "Use '/' separators to create a submenu tree:" +msgstr "Använd \"/\"-avdelare för att skapa ett undermenyträd:" + - #: lib/tools_dlg.tcl:61 ++#: lib/tools_dlg.tcl:60 +msgid "Command:" +msgstr "Kommando:" + - #: lib/tools_dlg.tcl:74 ++#: lib/tools_dlg.tcl:71 +msgid "Show a dialog before running" +msgstr "Visa dialog innan programmet startas" + - #: lib/tools_dlg.tcl:80 ++#: lib/tools_dlg.tcl:77 +msgid "Ask the user to select a revision (sets $REVISION)" +msgstr "Be användaren välja en version (sätter $REVISION)" + - #: lib/tools_dlg.tcl:85 ++#: lib/tools_dlg.tcl:82 +msgid "Ask the user for additional arguments (sets $ARGS)" +msgstr "Be användaren om ytterligare parametrar (sätter $ARGS)" + - #: lib/tools_dlg.tcl:92 ++#: lib/tools_dlg.tcl:89 +msgid "Don't show the command output window" +msgstr "Visa inte kommandots utdatafönster" + - #: lib/tools_dlg.tcl:97 ++#: lib/tools_dlg.tcl:94 +msgid "Run only if a diff is selected ($FILENAME not empty)" +msgstr "Kör endast om en diff har markerats ($FILENAME är inte tomt)" + - #: lib/tools_dlg.tcl:121 ++#: lib/tools_dlg.tcl:118 +msgid "Please supply a name for the tool." +msgstr "Ange ett namn för verktyget." + - #: lib/tools_dlg.tcl:129 ++#: lib/tools_dlg.tcl:126 +#, tcl-format +msgid "Tool '%s' already exists." +msgstr "Verktyget \"%s\" finns redan." + - #: lib/tools_dlg.tcl:151 ++#: lib/tools_dlg.tcl:148 +#, tcl-format +msgid "" +"Could not add tool:\n" +"%s" +msgstr "" +"Kunde inte lägga till verktyget:\n" +"%s" + - #: lib/tools_dlg.tcl:190 ++#: lib/tools_dlg.tcl:187 +msgid "Remove Tool" +msgstr "Ta bort verktyg" + - #: lib/tools_dlg.tcl:196 ++#: lib/tools_dlg.tcl:193 +msgid "Remove Tool Commands" +msgstr "Ta bort verktygskommandon" + - #: lib/tools_dlg.tcl:200 ++#: lib/tools_dlg.tcl:198 +msgid "Remove" +msgstr "Ta bort" + - #: lib/tools_dlg.tcl:236 ++#: lib/tools_dlg.tcl:231 +msgid "(Blue denotes repository-local tools)" +msgstr "(Blått anger verktyg lokala för arkivet)" + - #: lib/tools_dlg.tcl:297 ++#: lib/tools_dlg.tcl:292 +#, tcl-format +msgid "Run Command: %s" +msgstr "Kör kommandot: %s" + - #: lib/tools_dlg.tcl:311 ++#: lib/tools_dlg.tcl:306 +msgid "Arguments" +msgstr "Argument" + - #: lib/tools_dlg.tcl:348 ++#: lib/tools_dlg.tcl:341 +msgid "OK" +msgstr "OK" + ++#: lib/tools.tcl:75 ++#, tcl-format ++msgid "Running %s requires a selected file." ++msgstr "För att starta %s måste du välja en fil." ++ ++#: lib/tools.tcl:90 ++#, tcl-format ++msgid "Are you sure you want to run %s?" ++msgstr "Är du säker på att du vill starta %s?" ++ ++#: lib/tools.tcl:110 ++#, tcl-format ++msgid "Tool: %s" ++msgstr "Verktyg: %s" ++ ++#: lib/tools.tcl:111 ++#, tcl-format ++msgid "Running: %s" ++msgstr "Exekverar: %s" ++ ++#: lib/tools.tcl:149 ++#, tcl-format ++msgid "Tool completed successfully: %s" ++msgstr "Verktyget avslutades framgångsrikt: %s" ++ ++#: lib/tools.tcl:151 ++#, tcl-format ++msgid "Tool failed: %s" ++msgstr "Verktyget misslyckades: %s" ++ +#: lib/transport.tcl:7 +#, tcl-format +msgid "Fetching new changes from %s" +msgstr "Hämtar nya ändringar från %s" + +#: lib/transport.tcl:18 +#, tcl-format +msgid "remote prune %s" +msgstr "fjärrborttagning %s" + +#: lib/transport.tcl:19 +#, tcl-format +msgid "Pruning tracking branches deleted from %s" +msgstr "Tar bort spårande grenar som tagits bort från %s" + +#: lib/transport.tcl:26 +#, tcl-format +msgid "Pushing changes to %s" +msgstr "Sänder ändringar till %s" + +#: lib/transport.tcl:64 +#, tcl-format +msgid "Mirroring to %s" +msgstr "Speglar till %s" + +#: lib/transport.tcl:82 +#, tcl-format +msgid "Pushing %s %s to %s" +msgstr "Sänder %s %s till %s" + - #: lib/transport.tcl:100 ++#: lib/transport.tcl:102 +msgid "Push Branches" +msgstr "Sänd grenar" + - #: lib/transport.tcl:114 ++#: lib/transport.tcl:117 +msgid "Source Branches" +msgstr "Källgrenar" + +#: lib/transport.tcl:131 +msgid "Destination Repository" +msgstr "Destinationsarkiv" + - #: lib/transport.tcl:169 ++#: lib/transport.tcl:172 +msgid "Transfer Options" +msgstr "Överföringsalternativ" + - #: lib/transport.tcl:171 ++#: lib/transport.tcl:174 +msgid "Force overwrite existing branch (may discard changes)" +msgstr "Tvinga överskrivning av befintlig gren (kan kasta bort ändringar)" + - #: lib/transport.tcl:175 ++#: lib/transport.tcl:178 +msgid "Use thin pack (for slow network connections)" +msgstr "Använd tunt paket (för långsamma nätverksanslutningar)" + - #: lib/transport.tcl:179 ++#: lib/transport.tcl:182 +msgid "Include tags" +msgstr "Ta med taggar" + +#~ msgid "Cannot use funny .git directory:" +#~ msgstr "Kan inte använda underlig .git-katalog:" + +#~ msgid "Preferences..." +#~ msgstr "Inställningar..." + +#~ msgid "Always (Do not perform merge test.)" +#~ msgstr "Alltid (utför inte sammanslagningstest)." + +#~ msgid "URL:" +#~ msgstr "Webbadress:" + +#~ msgid "Delete Remote Branch" +#~ msgstr "Ta bort fjärrgren" + +#~ msgid "" +#~ "Unable to start gitk:\n" +#~ "\n" +#~ "%s does not exist" +#~ msgstr "" +#~ "Kan inte starta gitk:\n" +#~ "\n" +#~ "%s finns inte" + +#~ msgid "Apple" +#~ msgstr "Äpple" + +#~ msgid "Not connected to aspell" +#~ msgstr "Inte ansluten till aspell"