git-gui: Added support for pulling from default branch of a remote.
[gitweb.git] / git-gui
diff --git a/git-gui b/git-gui
index 0cd85e3c92fe1e596f1733f0ca189f60480583cd..4aa035a6c4536d266f21ec41d131ecbd9651fe6f 100755 (executable)
--- a/git-gui
+++ b/git-gui
@@ -592,16 +592,31 @@ proc fetch_from {remote} {
        set w [new_console "fetch $remote" \
                "Fetching new changes from $remote"]
        set cmd [list git fetch]
-       lappend cmd -v
        lappend cmd $remote
        console_exec $w $cmd
 }
 
+proc pull_remote {remote branch} {
+       set w [new_console "pull $remote $branch" \
+               "Pulling new changes from branch $branch in $remote"]
+       set cmd [list git pull]
+       lappend cmd $remote
+       lappend cmd $branch
+       console_exec $w $cmd [list post_pull_remote $remote $branch]
+}
+
+proc post_pull_remote {remote branch success} {
+       if {$success} {
+               update_status "Successfully pulled $branch from $remote."
+       } else {
+               update_status "Conflicts detected while pulling $branch from $remote."
+       }
+}
+
 proc push_to {remote} {
        set w [new_console "push $remote" \
                "Pushing changes to $remote"]
        set cmd [list git push]
-       lappend -v
        lappend cmd $remote
        console_exec $w $cmd
 }
@@ -791,29 +806,45 @@ proc toggle_mode {path} {
 ##
 ## config (fetch push pull)
 
+proc load_repo_config {} {
+       global repo_config
+
+       array unset repo_config
+       catch {
+               set fd_rc [open "| git repo-config --list" r]
+               while {[gets $fd_rc line] >= 0} {
+                       if {[regexp {^([^=]+)=(.*)$} $line line name value]} {
+                               lappend repo_config($name) $value
+                       }
+               }
+               close $fd_rc
+       }
+}
+
 proc load_all_remotes {} {
-       global gitdir all_remotes
+       global gitdir all_remotes repo_config
 
        set all_remotes [list]
        set rm_dir [file join $gitdir remotes]
        if {[file isdirectory $rm_dir]} {
-               set all_remotes [concat $all_remotes \
-                       [glob -types f -tails -directory $rm_dir * *]]
+               set all_remotes [concat $all_remotes [glob \
+                       -types f \
+                       -tails \
+                       -nocomplain \
+                       -directory $rm_dir *]]
        }
 
-       set fd_rc [open "| git repo-config --list" r]
-       while {[gets $fd_rc line] >= 0} {
-               if {[regexp ^remote\.(.*)\.url= $line line name]} {
+       foreach line [array names repo_config remote.*.url] {
+               if {[regexp ^remote\.(.*)\.url\$ $line line name]} {
                        lappend all_remotes $name
                }
        }
-       close $fd_rc
 
        set all_remotes [lsort -unique $all_remotes]
 }
 
 proc populate_remote_menu {m pfx op} {
-       global gitdir all_remotes mainfont
+       global all_remotes mainfont
 
        foreach remote $all_remotes {
                $m add command -label "$pfx $remote..." \
@@ -822,6 +853,40 @@ proc populate_remote_menu {m pfx op} {
        }
 }
 
+proc populate_pull_menu {m} {
+       global gitdir repo_config all_remotes mainfont
+
+       foreach remote $all_remotes {
+               set rb {}
+               if {[array get repo_config remote.$remote.url] != {}} {
+                       if {[array get repo_config remote.$remote.fetch] != {}} {
+                               regexp {^([^:]+):} \
+                                       [lindex $repo_config(remote.$remote.fetch) 0] \
+                                       line rb
+                       }
+               } else {
+                       catch {
+                               set fd [open [file join $gitdir remotes $remote] r]
+                               while {[gets $fd line] >= 0} {
+                                       if {[regexp {^Pull:[ \t]*([^:]+):} $line line rb]} {
+                                               break
+                                       }
+                               }
+                               close $fd
+                       }
+               }
+
+               set rb_short $rb
+               regsub ^refs/heads/ $rb {} rb_short
+               if {$rb_short != {}} {
+                       $m add command \
+                               -label "Branch $rb_short from $remote..." \
+                               -command [list pull_remote $remote $rb] \
+                               -font $mainfont
+               }
+       }
+}
+
 ######################################################################
 ##
 ## icons
@@ -950,7 +1015,9 @@ proc show_msg {w top msg} {
        pack $w.ok -side bottom
        bind $top <Visibility> "grab $top; focus $top"
        bind $top <Key-Return> "destroy $top"
-       wm title $top "error: $appname ([file normalize [file dirname $gitdir]])"
+       wm title $w "$appname ([lindex [file split \
+               [file normalize [file dirname $gitdir]]] \
+               end]): error"
        tkwait window $top
 }
 
@@ -995,21 +1062,29 @@ proc hook_failed_popup {hook msg} {
 
        bind $w <Visibility> "grab $w; focus $w"
        bind $w <Key-Return> "destroy $w"
-       wm title $w "error: $appname ([file normalize [file dirname $gitdir]])"
+       wm title $w "$appname ([lindex [file split \
+               [file normalize [file dirname $gitdir]]] \
+               end]): error"
        tkwait window $w
 }
 
 set next_console_id 0
 
 proc new_console {short_title long_title} {
-       global next_console_id console_cr
+       global next_console_id console_data
+       set w .console[incr next_console_id]
+       set console_data($w) [list $short_title $long_title]
+       return [console_init $w]
+}
+
+proc console_init {w} {
+       global console_cr console_data
        global gitdir appname mainfont difffont
 
-       set w .console[incr next_console_id]
        set console_cr($w) 1.0
        toplevel $w
        frame $w.m
-       label $w.m.l1 -text "$long_title:" \
+       label $w.m.l1 -text "[lindex $console_data($w) 1]:" \
                -anchor w \
                -justify left \
                -font [concat $mainfont bold]
@@ -1038,12 +1113,13 @@ proc new_console {short_title long_title} {
        pack $w.ok -side bottom
 
        bind $w <Visibility> "focus $w"
-       bind $w <Destroy> break
-       wm title $w "$appname ([file dirname [file normalize [file dirname $gitdir]]]): $short_title"
+       wm title $w "$appname ([lindex [file split \
+               [file normalize [file dirname $gitdir]]] \
+               end]): [lindex $console_data($w) 0]"
        return $w
 }
 
-proc console_exec {w cmd} {
+proc console_exec {w cmd {after {}}} {
        global tcl_platform
 
        # -- Windows tosses the enviroment when we exec our child.
@@ -1060,48 +1136,60 @@ proc console_exec {w cmd} {
 
        set fd_f [open $cmd r]
        fconfigure $fd_f -blocking 0 -translation binary
-       fileevent $fd_f readable [list console_read $w $fd_f]
+       fileevent $fd_f readable [list console_read $w $fd_f $after]
 }
 
-proc console_read {w fd} {
-       global console_cr
+proc console_read {w fd after} {
+       global console_cr console_data
 
-       $w.m.t conf -state normal
        set buf [read $fd]
-       set c 0
-       set n [string length $buf]
-       while {$c < $n} {
-               set cr [string first "\r" $buf $c]
-               set lf [string first "\n" $buf $c]
-               if {$cr < 0} {set cr [expr $n + 1]}
-               if {$lf < 0} {set lf [expr $n + 1]}
-
-               if {$lf < $cr} {
-                       $w.m.t insert end [string range $buf $c $lf]
-                       set console_cr($w) [$w.m.t index {end -1c}]
-                       set c $lf
-                       incr c
-               } else {
-                       $w.m.t delete $console_cr($w) end
-                       $w.m.t insert end "\n"
-                       $w.m.t insert end [string range $buf $c $cr]
-                       set c $cr
-                       incr c
+       if {$buf != {}} {
+               if {![winfo exists $w]} {console_init $w}
+               $w.m.t conf -state normal
+               set c 0
+               set n [string length $buf]
+               while {$c < $n} {
+                       set cr [string first "\r" $buf $c]
+                       set lf [string first "\n" $buf $c]
+                       if {$cr < 0} {set cr [expr $n + 1]}
+                       if {$lf < 0} {set lf [expr $n + 1]}
+
+                       if {$lf < $cr} {
+                               $w.m.t insert end [string range $buf $c $lf]
+                               set console_cr($w) [$w.m.t index {end -1c}]
+                               set c $lf
+                               incr c
+                       } else {
+                               $w.m.t delete $console_cr($w) end
+                               $w.m.t insert end "\n"
+                               $w.m.t insert end [string range $buf $c $cr]
+                               set c $cr
+                               incr c
+                       }
                }
+               $w.m.t conf -state disabled
+               $w.m.t see end
        }
-       $w.m.t conf -state disabled
-       $w.m.t see end
 
        fconfigure $fd -blocking 1
        if {[eof $fd]} {
                if {[catch {close $fd}]} {
+                       if {![winfo exists $w]} {console_init $w}
                        $w.m.s conf -background red -text {Error: Command Failed}
-               } else {
+                       $w.ok conf -text Close
+                       $w.ok conf -state normal
+                       set ok 0
+               } elseif {[winfo exists $w]} {
                        $w.m.s conf -background green -text {Success}
+                       $w.ok conf -text Close
+                       $w.ok conf -state normal
+                       set ok 1
                }
-               $w.ok conf -text Close
-               $w.ok conf -state normal
                array unset console_cr $w
+               array unset console_data $w
+               if {$after != {}} {
+                       uplevel #0 $after $ok
+               }
                return
        }
        fconfigure $fd -blocking 0
@@ -1526,7 +1614,9 @@ if {$appname == {git-citool}} {
 
 wm title . "$appname ([file normalize [file dirname $gitdir]])"
 focus -force $ui_comm
+load_repo_config
 load_all_remotes
 populate_remote_menu .mbar.fetch From fetch_from
 populate_remote_menu .mbar.push To push_to
+populate_pull_menu .mbar.pull
 update_status