diff options
-rw-r--r-- | git-gui/Makefile | 2 | ||||
-rwxr-xr-x | git-gui/git-gui--askpass | 59 | ||||
-rwxr-xr-x | git-gui/git-gui.sh | 89 | ||||
-rw-r--r-- | git-gui/lib/blame.tcl | 65 | ||||
-rw-r--r-- | git-gui/lib/choose_repository.tcl | 16 | ||||
-rw-r--r-- | git-gui/lib/diff.tcl | 25 | ||||
-rw-r--r-- | git-gui/lib/index.tcl | 11 | ||||
-rw-r--r-- | git-gui/lib/merge.tcl | 1 | ||||
-rw-r--r-- | git-gui/lib/mergetool.tcl | 17 | ||||
-rw-r--r-- | git-gui/lib/remote.tcl | 188 | ||||
-rw-r--r-- | git-gui/lib/remote_add.tcl | 191 | ||||
-rw-r--r-- | git-gui/lib/remote_branch_delete.tcl | 6 | ||||
-rw-r--r-- | git-gui/lib/search.tcl | 190 | ||||
-rw-r--r-- | git-gui/lib/spellcheck.tcl | 3 | ||||
-rw-r--r-- | git-gui/lib/sshkey.tcl | 126 | ||||
-rw-r--r-- | git-gui/lib/transport.tcl | 2 | ||||
-rw-r--r-- | git-gui/po/de.po | 279 |
17 files changed, 1080 insertions, 190 deletions
diff --git a/git-gui/Makefile b/git-gui/Makefile index 55765c8a3a..3ad8a21b30 100644 --- a/git-gui/Makefile +++ b/git-gui/Makefile @@ -285,6 +285,7 @@ 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)' @@ -302,6 +303,7 @@ endif 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) diff --git a/git-gui/git-gui--askpass b/git-gui/git-gui--askpass new file mode 100755 index 0000000000..12e117ecb1 --- /dev/null +++ b/git-gui/git-gui--askpass @@ -0,0 +1,59 @@ +#!/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. + +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 .} + +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 . <Visibility> {focus -force .e} +bind . <Key-Return> finish +bind . <Key-Escape> {destroy .} +bind . <Destroy> {exit $rc} + +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 . +} + +wm title . "OpenSSH" +tk::PlaceWindow . diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index 4085e8fea5..12b496bec9 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -591,6 +591,12 @@ bind . <Visibility> { 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 + } } ###################################################################### @@ -995,6 +1001,7 @@ citool { ## ## repository setup +set picked 0 if {[catch { set _gitdir $env(GIT_DIR) set _prefix {} @@ -1006,6 +1013,7 @@ if {[catch { load_config 1 apply_config choose_repository::pick + set picked 1 } if {![file isdirectory $_gitdir] && [is_Cygwin]} { catch {set _gitdir [exec cygpath --windows $_gitdir]} @@ -1065,6 +1073,15 @@ set selected_commit_type new set nullid "0000000000000000000000000000000000000000" set nullid2 "0000000000000000000000000000000000000001" +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] +} + ###################################################################### ## ## task management @@ -1869,6 +1886,19 @@ proc do_gitk {revs} { } } +proc do_explore {} { + 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 [file dirname [gitdir]] & +} + set is_quitting 0 set ret_code 1 @@ -2090,7 +2120,9 @@ proc toggle_or_diff {w x y} { if {$col == 0 && $y > 1} { # Conflicts need special handling if {[string first {U} $state] >= 0} { - merge_stage_workdir $path $w $lno + # $w must always be $ui_workdir, but... + if {$w ne $ui_workdir} { set lno {} } + merge_stage_workdir $path $lno return } @@ -2219,6 +2251,11 @@ if {[is_enabled transport]} { menu .mbar.repository .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] @@ -2413,7 +2450,7 @@ if {[is_enabled multicommit] || [is_enabled singlecommit]} { .mbar.commit add separator - if {![is_enabled nocommit]} { + if {![is_enabled nocommitmsg]} { .mbar.commit add command -label [mc "Sign Off"] \ -command do_signoff \ -accelerator $M1T-S @@ -2447,11 +2484,15 @@ 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..."] \ + -label [mc "Delete Branch..."] \ -command remote_branch_delete::dialog } @@ -2487,8 +2528,7 @@ if {![is_MacOSX]} { -command do_about } -set browser {} -catch {set browser $repo_config(instaweb.browser)} + set doc_path [file dirname [gitexec]] set doc_path [file join $doc_path Documentation index.html] @@ -2496,34 +2536,23 @@ if {[is_Cygwin]} { set doc_path [exec cygpath --mixed $doc_path] } -if {$browser eq {}} { - if {[is_MacOSX]} { - set browser open - } elseif {[is_Cygwin]} { - set program_files [file dirname [exec cygpath --windir]] - set program_files [file join $program_files {Program Files}] - set firefox [file join $program_files {Mozilla Firefox} firefox.exe] - set ie [file join $program_files {Internet Explorer} IEXPLORE.EXE] - if {[file exists $firefox]} { - set browser $firefox - } elseif {[file exists $ie]} { - set browser $ie - } - unset program_files firefox ie - } -} - if {[file isfile $doc_path]} { set doc_url "file:$doc_path" } else { set doc_url {http://www.kernel.org/pub/software/scm/git/docs/} } -if {$browser ne {}} { - .mbar.help add command -label [mc "Online Documentation"] \ - -command [list exec $browser $doc_url &] +proc start_browser {url} { + git "web--browse" $url } -unset browser doc_path doc_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 # @@ -2743,7 +2772,7 @@ pack .vpane.lower.commarea.buttons.incall -side top -fill x lappend disable_on_lock \ {.vpane.lower.commarea.buttons.incall conf -state} -if {![is_enabled nocommit]} { +if {![is_enabled nocommitmsg]} { button .vpane.lower.commarea.buttons.signoff -text [mc "Sign Off"] \ -command do_signoff pack .vpane.lower.commarea.buttons.signoff -side top -fill x @@ -3261,8 +3290,7 @@ if {[is_enabled transport]} { load_all_remotes set n [.mbar.remote index end] - populate_push_menu - populate_fetch_menu + populate_remotes_menu set n [expr {[.mbar.remote index end] - $n}] if {$n > 0} { if {[.mbar.remote type 0] eq "tearoff"} { incr n } @@ -3369,3 +3397,6 @@ if {[is_enabled multicommit]} { if {[is_enabled retcode]} { bind . <Destroy> {+terminate_me %W} } +if {$picked && [is_config_true gui.autoexplore]} { + do_explore +} diff --git a/git-gui/lib/blame.tcl b/git-gui/lib/blame.tcl index eb61374d2d..765d08c004 100644 --- a/git-gui/lib/blame.tcl +++ b/git-gui/lib/blame.tcl @@ -21,9 +21,11 @@ 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 @@ -59,7 +61,7 @@ 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 + global cursor_ptr M1B M1T have_tk85 variable active_color variable group_colors @@ -69,6 +71,8 @@ constructor new {i_commit i_path i_jump} { make_toplevel top w wm title $top [append "[appname] ([reponame]): " [mc "File Viewer"]] + set font_w [font measure font_diff "0"] + frame $w.header -background gold label $w.header.commit_l \ -text [mc "Commit:"] \ @@ -114,9 +118,9 @@ constructor new {i_commit i_path i_jump} { pack $w_path -fill x -side right pack $w.header.path_l -side right - panedwindow $w.file_pane -orient vertical - frame $w.file_pane.out - frame $w.file_pane.cm + 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 \ @@ -197,6 +201,11 @@ constructor new {i_commit i_path i_jump} { -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] @@ -217,6 +226,11 @@ constructor new {i_commit i_path i_jump} { -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 \ @@ -257,6 +271,10 @@ constructor new {i_commit i_path i_jump} { -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 \ @@ -278,9 +296,15 @@ constructor new {i_commit i_path i_jump} { $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 many2scrollbar \ - $w_columns yview $w.file_pane.out.sby] + $i conf -yscrollcommand \ + "[list ::searchbar::scrolled $finder] + [list many2scrollbar $w_columns yview $w.file_pane.out.sby]" bind $i <Button-1> " [cb _hide_tooltip] [cb _click $i @%x,%y] @@ -317,6 +341,11 @@ constructor new {i_commit i_path i_jump} { bind $w_cviewer <Tab> "[list focus $w_file];break" bind $w_cviewer <Button-1> [list focus $w_cviewer] bind $w_file <Visibility> [list focus $w_file] + bind $top <F7> [list searchbar::show $finder] + bind $top <Escape> [list searchbar::hide $finder] + bind $top <F3> [list searchbar::find_next $finder] + bind $top <Shift-F3> [list searchbar::find_prev $finder] + catch { bind $top <Shift-Key-XF86_Switch_VT_3> [list searchbar::find_prev $finder] } grid configure $w.header -sticky ew grid configure $w.file_pane -sticky nsew @@ -328,9 +357,14 @@ constructor new {i_commit i_path i_jump} { set req_w [winfo reqwidth $top] set req_h [winfo reqheight $top] - set scr_h [expr {[winfo screenheight $top] - 100}] - if {$req_w < 600} {set req_w 600} + 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 @@ -338,16 +372,23 @@ constructor new {i_commit i_path i_jump} { 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.70)}] + [expr {int($old_height * 0.80)}] bind $w.file_pane <Configure> \ "if {{$w.file_pane} eq {%W}} {[cb _resize %h]}" wm protocol $top WM_DELETE_WINDOW "destroy $top" - bind $top <Destroy> [cb _kill] + bind $top <Destroy> [cb _handle_destroy %W] _load $this $i_jump } +method _handle_destroy {win} { + if {$win eq $w} { + _kill $this + delete_this + } +} + method _kill {} { if {$current_fd ne {}} { kill_file_process $current_fd @@ -866,6 +907,10 @@ method _showcommit {cur_w lno} { 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 {} diff --git a/git-gui/lib/choose_repository.tcl b/git-gui/lib/choose_repository.tcl index 3180786158..909131689e 100644 --- a/git-gui/lib/choose_repository.tcl +++ b/git-gui/lib/choose_repository.tcl @@ -381,7 +381,8 @@ method _do_new {} { label $w_body.where.l -text [mc "Directory:"] entry $w_body.where.t \ -textvariable @local_path \ - -font font_diff \ + -borderwidth 1 \ + -relief sunken \ -width 50 button $w_body.where.b \ -text [mc "Browse"] \ @@ -463,20 +464,22 @@ method _do_clone {} { frame $w_body.args pack $args -fill both - label $args.origin_l -text [mc "URL:"] + label $args.origin_l -text [mc "Source Location:"] entry $args.origin_t \ -textvariable @origin_url \ - -font font_diff \ + -borderwidth 1 \ + -relief sunken \ -width 50 button $args.origin_b \ -text [mc "Browse"] \ -command [cb _open_origin] grid $args.origin_l $args.origin_t $args.origin_b -sticky ew - label $args.where_l -text [mc "Directory:"] + label $args.where_l -text [mc "Target Directory:"] entry $args.where_t \ -textvariable @local_path \ - -font font_diff \ + -borderwidth 1 \ + -relief sunken \ -width 50 button $args.where_b \ -text [mc "Browse"] \ @@ -979,7 +982,8 @@ method _do_open {} { label $w_body.where.l -text [mc "Repository:"] entry $w_body.where.t \ -textvariable @local_path \ - -font font_diff \ + -borderwidth 1 \ + -relief sunken \ -width 50 button $w_body.where.b \ -text [mc "Browse"] \ diff --git a/git-gui/lib/diff.tcl b/git-gui/lib/diff.tcl index abe502d971..94ee38cccc 100644 --- a/git-gui/lib/diff.tcl +++ b/git-gui/lib/diff.tcl @@ -117,22 +117,22 @@ proc show_unmerged_diff {cont_info} { if {$merge_stages(2) eq {}} { set is_conflict_diff 1 lappend current_diff_queue \ - [list "LOCAL: deleted\nREMOTE:\n" d======= \ + [list [mc "LOCAL: deleted\nREMOTE:\n"] d======= \ [list ":1:$current_diff_path" ":3:$current_diff_path"]] } elseif {$merge_stages(3) eq {}} { set is_conflict_diff 1 lappend current_diff_queue \ - [list "REMOTE: deleted\nLOCAL:\n" d======= \ + [list [mc "REMOTE: deleted\nLOCAL:\n"] d======= \ [list ":1:$current_diff_path" ":2:$current_diff_path"]] } elseif {[lindex $merge_stages(1) 0] eq {120000} || [lindex $merge_stages(2) 0] eq {120000} || [lindex $merge_stages(3) 0] eq {120000}} { set is_conflict_diff 1 lappend current_diff_queue \ - [list "LOCAL:\n" d======= \ + [list [mc "LOCAL:\n"] d======= \ [list ":1:$current_diff_path" ":2:$current_diff_path"]] lappend current_diff_queue \ - [list "REMOTE:\n" d======= \ + [list [mc "REMOTE:\n"] d======= \ [list ":1:$current_diff_path" ":3:$current_diff_path"]] } else { start_show_diff $cont_info @@ -164,7 +164,7 @@ proc show_other_diff {path w m cont_info} { # - Git won't give us the diff, there's nothing to compare to! # if {$m eq {_O}} { - set max_sz [expr {128 * 1024}] + set max_sz 100000 set type unknown if {[catch { set type [file type $path] @@ -218,17 +218,17 @@ proc show_other_diff {path w m cont_info} { d_@ } else { if {$sz > $max_sz} { - $ui_diff insert end \ -"* Untracked file is $sz bytes. -* Showing only first $max_sz bytes. -" d_@ + $ui_diff insert end [mc \ +"* Untracked file is %d bytes. +* Showing only first %d bytes. +" $sz $max_sz] d_@ } $ui_diff insert end $content if {$sz > $max_sz} { - $ui_diff insert end " -* Untracked file clipped here by [appname]. + $ui_diff insert end [mc " +* Untracked file clipped here by %s. * To see the entire file, use an external editor. -" d_@ +" [appname]] d_@ } } $ui_diff conf -state disabled @@ -377,7 +377,6 @@ proc read_diff {fd cont_info} { {+} { if {[regexp {^\+([<>]{7} |={7})} $line _g op]} { set is_conflict_diff 1 - set line [string replace $line 0 0 { }] set tags d$op } else { set tags d_+ diff --git a/git-gui/lib/index.tcl b/git-gui/lib/index.tcl index b045219a1c..d33896a0ce 100644 --- a/git-gui/lib/index.tcl +++ b/git-gui/lib/index.tcl @@ -298,11 +298,18 @@ proc add_helper {txt paths} { set after {} foreach path $paths { switch -glob -- [lindex $file_states($path) 0] { + _U - + U? { + if {$path eq $current_diff_path} { + unlock_index + merge_stage_workdir $path + return + } + } _O - ?M - ?D - - ?T - - U? { + ?T { lappend pathList $path if {$path eq $current_diff_path} { set after {reshow_diff;} diff --git a/git-gui/lib/merge.tcl b/git-gui/lib/merge.tcl index 5c01875b05..283e4915e9 100644 --- a/git-gui/lib/merge.tcl +++ b/git-gui/lib/merge.tcl @@ -40,6 +40,7 @@ The rescan will be automatically started now. _O { continue; # and pray it works! } + _U - U? { error_popup [mc "You are in the middle of a conflicted merge. diff --git a/git-gui/lib/mergetool.tcl b/git-gui/lib/mergetool.tcl index 6ab5701d93..eb2b4b56a4 100644 --- a/git-gui/lib/mergetool.tcl +++ b/git-gui/lib/mergetool.tcl @@ -23,13 +23,14 @@ This operation can be undone only by restarting the merge." \ } } -proc merge_stage_workdir {path w lno} { +proc merge_stage_workdir {path {lno {}}} { global current_diff_path diff_active + global current_diff_side ui_workdir if {$diff_active} return - if {$path ne $current_diff_path} { - show_diff $path $w $lno {} [list do_merge_stage_workdir $path] + if {$path ne $current_diff_path || $ui_workdir ne $current_diff_side} { + show_diff $path $ui_workdir $lno {} [list do_merge_stage_workdir $path] } else { do_merge_stage_workdir $path } @@ -375,14 +376,6 @@ proc merge_tool_finish {fd} { } } - # Check the modification time of the target file - if {!$failed && [file mtime $mtool_target] eq $mtool_mtime} { - if {[ask_popup [mc "File %s unchanged, still accept as resolved?" \ - [short_path $mtool_target]]] ne {yes}} { - set failed 1 - } - } - # Finish if {$failed} { file rename -force -- $backup $mtool_target @@ -395,6 +388,6 @@ proc merge_tool_finish {fd} { delete_temp_files $mtool_tmpfiles - merge_add_resolution $mtool_target + reshow_diff } } diff --git a/git-gui/lib/remote.tcl b/git-gui/lib/remote.tcl index 0e86ddac09..b92b429cf7 100644 --- a/git-gui/lib/remote.tcl +++ b/git-gui/lib/remote.tcl @@ -132,91 +132,145 @@ proc load_all_remotes {} { set all_remotes [lsort -unique $all_remotes] } -proc populate_fetch_menu {} { - global all_remotes repo_config - +proc add_fetch_entry {r} { + global repo_config set remote_m .mbar.remote set fetch_m $remote_m.fetch set prune_m $remote_m.prune - - foreach r $all_remotes { - set enable 0 - if {![catch {set a $repo_config(remote.$r.url)}]} { - if {![catch {set a $repo_config(remote.$r.fetch)}]} { - set enable 1 - } - } else { - catch { - set fd [open [gitdir remotes $r] r] - while {[gets $fd n] >= 0} { - if {[regexp {^Pull:[ \t]*([^:]+):} $n]} { - set enable 1 - break - } + set remove_m $remote_m.remove + set enable 0 + if {![catch {set a $repo_config(remote.$r.url)}]} { + if {![catch {set a $repo_config(remote.$r.fetch)}]} { + set enable 1 + } + } else { + catch { + set fd [open [gitdir remotes $r] r] + while {[gets $fd n] >= 0} { + if {[regexp {^Pull:[ \t]*([^:]+):} $n]} { + set enable 1 + break } - close $fd } + close $fd } + } - if {$enable} { - if {![winfo exists $fetch_m]} { - menu $prune_m - $remote_m insert 0 cascade \ - -label [mc "Prune from"] \ - -menu $prune_m - - menu $fetch_m - $remote_m insert 0 cascade \ - -label [mc "Fetch from"] \ - -menu $fetch_m - } + if {$enable} { + if {![winfo exists $fetch_m]} { + menu $remove_m + $remote_m insert 0 cascade \ + -label [mc "Remove Remote"] \ + -menu $remove_m + + menu $prune_m + $remote_m insert 0 cascade \ + -label [mc "Prune from"] \ + -menu $prune_m - $fetch_m add command \ - -label $r \ - -command [list fetch_from $r] - $prune_m add command \ - -label $r \ - -command [list prune_from $r] + menu $fetch_m + $remote_m insert 0 cascade \ + -label [mc "Fetch from"] \ + -menu $fetch_m } + + $fetch_m add command \ + -label $r \ + -command [list fetch_from $r] + $prune_m add command \ + -label $r \ + -command [list prune_from $r] + $remove_m add command \ + -label $r \ + -command [list remove_remote $r] } } -proc populate_push_menu {} { - global all_remotes repo_config - +proc add_push_entry {r} { + global repo_config set remote_m .mbar.remote set push_m $remote_m.push - - foreach r $all_remotes { - set enable 0 - if {![catch {set a $repo_config(remote.$r.url)}]} { - if {![catch {set a $repo_config(remote.$r.push)}]} { - set enable 1 - } - } else { - catch { - set fd [open [gitdir remotes $r] r] - while {[gets $fd n] >= 0} { - if {[regexp {^Push:[ \t]*([^:]+):} $n]} { - set enable 1 - break - } + set enable 0 + if {![catch {set a $repo_config(remote.$r.url)}]} { + if {![catch {set a $repo_config(remote.$r.push)}]} { + set enable 1 + } + } else { + catch { + set fd [open [gitdir remotes $r] r] + while {[gets $fd n] >= 0} { + if {[regexp {^Push:[ \t]*([^:]+):} $n]} { + set enable 1 + break } - close $fd } + close $fd } + } - if {$enable} { - if {![winfo exists $push_m]} { - menu $push_m - $remote_m insert 0 cascade \ - -label [mc "Push to"] \ - -menu $push_m - } - - $push_m add command \ - -label $r \ - -command [list push_to $r] + if {$enable} { + if {![winfo exists $push_m]} { + menu $push_m + $remote_m insert 0 cascade \ + -label [mc "Push to"] \ + -menu $push_m } + + $push_m add command \ + -label $r \ + -command [list push_to $r] + } +} + +proc populate_remotes_menu {} { + global all_remotes + + foreach r $all_remotes { + add_fetch_entry $r + add_push_entry $r + } +} + +proc add_single_remote {name location} { + global all_remotes repo_config + lappend all_remotes $name + + git remote add $name $location + + # XXX: Better re-read the config so that we will never get out + # of sync with git remote implementation? + set repo_config(remote.$name.url) $location + set repo_config(remote.$name.fetch) "+refs/heads/*:refs/remotes/$name/*" + + add_fetch_entry $name + add_push_entry $name +} + +proc delete_from_menu {menu name} { + if {[winfo exists $menu]} { + $menu delete $name } } + +proc remove_remote {name} { + global all_remotes repo_config + + git remote rm $name + + catch { + # Missing values are ok + unset repo_config(remote.$name.url) + unset repo_config(remote.$name.fetch) + unset repo_config(remote.$name.push) + } + + set i [lsearch -exact all_remotes $name] + lreplace all_remotes $i $i + + set remote_m .mbar.remote + delete_from_menu $remote_m.fetch $name + delete_from_menu $remote_m.prune $name + delete_from_menu $remote_m.remove $name + # Not all remotes are in the push menu + catch { delete_from_menu $remote_m.push $name } +} diff --git a/git-gui/lib/remote_add.tcl b/git-gui/lib/remote_add.tcl new file mode 100644 index 0000000000..fb29422aa7 --- /dev/null +++ b/git-gui/lib/remote_add.tcl @@ -0,0 +1,191 @@ +# git-gui remote adding support +# Copyright (C) 2008 Petr Baudis + +class remote_add { + +field w ; # widget path +field w_name ; # new remote name widget +field w_loc ; # new remote location widget + +field name {}; # name of the remote the user has chosen +field location {}; # location of the remote the user has chosen + +field opt_action fetch; # action to do after registering the remote locally + +constructor dialog {} { + global repo_config + + make_toplevel top w + wm title $top [append "[appname] ([reponame]): " [mc "Add Remote"]] + if {$top ne {.}} { + wm geometry $top "+[winfo rootx .]+[winfo rooty .]" + } + + label $w.header -text [mc "Add New Remote"] -font font_uibold + pack $w.header -side top -fill x + + frame $w.buttons + button $w.buttons.create -text [mc Add] \ + -default active \ + -command [cb _add] + pack $w.buttons.create -side right + button $w.buttons.cancel -text [mc Cancel] \ + -command [list destroy $w] + pack $w.buttons.cancel -side right -padx 5 + pack $w.buttons -side bottom -fill x -pady 10 -padx 10 + + labelframe $w.desc -text [mc "Remote Details"] + + label $w.desc.name_l -text [mc "Name:"] + set w_name $w.desc.name_t + entry $w_name \ + -borderwidth 1 \ + -relief sunken \ + -width 40 \ + -textvariable @name \ + -validate key \ + -validatecommand [cb _validate_name %d %S] + grid $w.desc.name_l $w_name -sticky we -padx {0 5} + + label $w.desc.loc_l -text [mc "Location:"] + set w_loc $w.desc.loc_t + entry $w_loc \ + -borderwidth 1 \ + -relief sunken \ + -width 40 \ + -textvariable @location + grid $w.desc.loc_l $w_loc -sticky we -padx {0 5} + + grid columnconfigure $w.desc 1 -weight 1 + pack $w.desc -anchor nw -fill x -pady 5 -padx 5 + + labelframe $w.action -text [mc "Further Action"] + + radiobutton $w.action.fetch \ + -text [mc "Fetch Immediately"] \ + -value fetch \ + -variable @opt_action + pack $w.action.fetch -anchor nw + + radiobutton $w.action.push \ + -text [mc "Initialize Remote Repository and Push"] \ + -value push \ + -variable @opt_action + pack $w.action.push -anchor nw + + radiobutton $w.action.none \ + -text [mc "Do Nothing Else Now"] \ + -value none \ + -variable @opt_action + pack $w.action.none -anchor nw + + grid columnconfigure $w.action 1 -weight 1 + pack $w.action -anchor nw -fill x -pady 5 -padx 5 + + bind $w <Visibility> [cb _visible] + bind $w <Key-Escape> [list destroy $w] + bind $w <Key-Return> [cb _add]\;break + tkwait window $w +} + +method _add {} { + global repo_config env + global M1B + + if {$name eq {}} { + tk_messageBox \ + -icon error \ + -type ok \ + -title [wm title $w] \ + -parent $w \ + -message [mc "Please supply a remote name."] + focus $w_name + return + } + + # XXX: We abuse check-ref-format here, but + # that should be ok. + if {[catch {git check-ref-format "remotes/$name"}]} { + tk_messageBox \ + -icon error \ + -type ok \ + -title [wm title $w] \ + -parent $w \ + -message [mc "'%s' is not an acceptable remote name." $name] + focus $w_name + return + } + + if {[catch {add_single_remote $name $location}]} { + tk_messageBox \ + -icon error \ + -type ok \ + -title [wm title $w] \ + -parent $w \ + -message [mc "Failed to add remote '%s' of location '%s'." $name $location] + focus $w_name + return + } + + switch -- $opt_action { + fetch { + set c [console::new \ + [mc "fetch %s" $name] \ + [mc "Fetching the %s" $name]] + console::exec $c [list git fetch $name] + } + push { + set cmds [list] + + # Parse the location + if { [regexp {(?:git\+)?ssh://([^/]+)(/.+)} $location xx host path] + || [regexp {([^:][^:]+):(.+)} $location xx host path]} { + set ssh ssh + if {[info exists env(GIT_SSH)]} { + set ssh $env(GIT_SSH) + } + lappend cmds [list exec $ssh $host mkdir -p $location && git --git-dir=$path init --bare] + } elseif { ! [regexp {://} $location xx] } { + lappend cmds [list exec mkdir -p $location] + lappend cmds [list exec git --git-dir=$location init --bare] + } else { + tk_messageBox \ + -icon error \ + -type ok \ + -title [wm title $w] \ + -parent $w \ + -message [mc "Do not know how to initialize repository at location '%s'." $location] + destroy $w + return + } + + set c [console::new \ + [mc "push %s" $name] \ + [mc "Setting up the %s (at %s)" $name $location]] + + lappend cmds [list exec git push -v --all $na |