git-fetch: Always fetch tags if the object they reference exists
[gitweb.git] / git-gui / lib / remote.tcl
index 99f353ed7d793ca9accf2c5d246938c8a51fea02..cf9b9d582959e62c805a92a86c33e0f3ae7f304e 100644 (file)
@@ -1,14 +1,13 @@
 # git-gui remote management
 # Copyright (C) 2006, 2007 Shawn Pearce
 
+set some_heads_tracking 0;  # assume not
+
 proc is_tracking_branch {name} {
        global tracking_branches
-
-       if {![catch {set info $tracking_branches($name)}]} {
-               return 1
-       }
-       foreach t [array names tracking_branches] {
-               if {[string match {*/\*} $t] && [string match $t $name]} {
+       foreach spec $tracking_branches {
+               set t [lindex $spec 0]
+               if {$t eq $name || [string match $t $name]} {
                        return 1
                }
        }
@@ -18,36 +17,54 @@ proc is_tracking_branch {name} {
 proc all_tracking_branches {} {
        global tracking_branches
 
-       set all_trackings {}
-       set cmd {}
-       foreach name [array names tracking_branches] {
-               if {[regsub {/\*$} $name {} name]} {
-                       lappend cmd $name
+       set all [list]
+       set pat [list]
+       set cmd [list]
+
+       foreach spec $tracking_branches {
+               set dst [lindex $spec 0]
+               if {[string range $dst end-1 end] eq {/*}} {
+                       lappend pat $spec
+                       lappend cmd [string range $dst 0 end-2]
                } else {
-                       regsub ^refs/(heads|remotes)/ $name {} name
-                       lappend all_trackings $name
+                       lappend all $spec
                }
        }
 
-       if {$cmd ne {}} {
-               set fd [open "| git for-each-ref --format=%(refname) $cmd" r]
-               while {[gets $fd name] > 0} {
-                       regsub ^refs/(heads|remotes)/ $name {} name
-                       lappend all_trackings $name
+       if {$pat ne {}} {
+               set fd [eval git_read for-each-ref --format=%(refname) $cmd]
+               while {[gets $fd n] > 0} {
+                       foreach spec $pat {
+                               set dst [string range [lindex $spec 0] 0 end-2]
+                               set len [string length $dst]
+                               if {[string equal -length $len $dst $n]} {
+                                       set src [string range [lindex $spec 2] 0 end-2]
+                                       set spec [list \
+                                               $n \
+                                               [lindex $spec 1] \
+                                               $src[string range $n $len end] \
+                                               ]
+                                       lappend all $spec
+                               }
+                       }
                }
                close $fd
        }
 
-       return [lsort -unique $all_trackings]
+       return [lsort -index 0 -unique $all]
 }
 
 proc load_all_remotes {} {
        global repo_config
-       global all_remotes tracking_branches
+       global all_remotes tracking_branches some_heads_tracking
+       global remote_url
 
+       set some_heads_tracking 0
        set all_remotes [list]
-       array unset tracking_branches
+       set trck [list]
 
+       set rh_str refs/heads/
+       set rh_len [string length $rh_str]
        set rm_dir [gitdir remotes]
        if {[file isdirectory $rm_dir]} {
                set all_remotes [glob \
@@ -60,12 +77,25 @@ proc load_all_remotes {} {
                        catch {
                                set fd [open [file join $rm_dir $name] r]
                                while {[gets $fd line] >= 0} {
+                                       if {[regexp {^URL:[     ]*(.+)$} $line line url]} {
+                                               set remote_url($name) $url
+                                               continue
+                                       }
                                        if {![regexp {^Pull:[   ]*([^:]+):(.+)$} \
                                                $line line src dst]} continue
-                                       if {![regexp ^refs/ $dst]} {
-                                               set dst "refs/heads/$dst"
+                                       if {[string index $src 0] eq {+}} {
+                                               set src [string range $src 1 end]
+                                       }
+                                       if {![string equal -length 5 refs/ $src]} {
+                                               set src $rh_str$src
                                        }
-                                       set tracking_branches($dst) [list $name $src]
+                                       if {![string equal -length 5 refs/ $dst]} {
+                                               set dst $rh_str$dst
+                                       }
+                                       if {[string equal -length $rh_len $rh_str $dst]} {
+                                               set some_heads_tracking 1
+                                       }
+                                       lappend trck [list $dst $name $src]
                                }
                                close $fd
                        }
@@ -75,19 +105,30 @@ proc load_all_remotes {} {
        foreach line [array names repo_config remote.*.url] {
                if {![regexp ^remote\.(.*)\.url\$ $line line name]} continue
                lappend all_remotes $name
+               set remote_url($name) $repo_config(remote.$name.url)
 
                if {[catch {set fl $repo_config(remote.$name.fetch)}]} {
                        set fl {}
                }
                foreach line $fl {
                        if {![regexp {^([^:]+):(.+)$} $line line src dst]} continue
-                       if {![regexp ^refs/ $dst]} {
-                               set dst "refs/heads/$dst"
+                       if {[string index $src 0] eq {+}} {
+                               set src [string range $src 1 end]
+                       }
+                       if {![string equal -length 5 refs/ $src]} {
+                               set src $rh_str$src
+                       }
+                       if {![string equal -length 5 refs/ $dst]} {
+                               set dst $rh_str$dst
                        }
-                       set tracking_branches($dst) [list $name $src]
+                       if {[string equal -length $rh_len $rh_str $dst]} {
+                               set some_heads_tracking 1
+                       }
+                       lappend trck [list $dst $name $src]
                }
        }
 
+       set tracking_branches [lsort -index 0 -unique $trck]
        set all_remotes [lsort -unique $all_remotes]
 }
 
@@ -95,6 +136,7 @@ proc populate_fetch_menu {} {
        global all_remotes repo_config
 
        set m .mbar.fetch
+       set prune_list [list]
        foreach r $all_remotes {
                set enable 0
                if {![catch {set a $repo_config(remote.$r.url)}]} {
@@ -115,11 +157,21 @@ proc populate_fetch_menu {} {
                }
 
                if {$enable} {
+                       lappend prune_list $r
                        $m add command \
                                -label "Fetch from $r..." \
                                -command [list fetch_from $r]
                }
        }
+
+       if {$prune_list ne {}} {
+               $m add separator
+       }
+       foreach r $prune_list {
+               $m add command \
+                       -label "Prune from $r..." \
+                       -command [list prune_from $r]
+       }
 }
 
 proc populate_push_menu {} {