Git v1.6.6-rc0
[gitweb.git] / remote.c
index ff8e71f0b955e9806759f37459c5499b9dd1a559..e0d17bb83060561c17114905c253eebdf925a01c 100644 (file)
--- a/remote.c
+++ b/remote.c
@@ -6,6 +6,7 @@
 #include "revision.h"
 #include "dir.h"
 #include "tag.h"
+#include "string-list.h"
 
 static struct refspec s_tag_refspec = {
        0,
@@ -47,6 +48,7 @@ static const char *default_remote_name;
 static int explicit_default_remote_name;
 
 static struct rewrites rewrites;
+static struct rewrites rewrites_push;
 
 #define BUF_SIZE (2048)
 static char buffer[BUF_SIZE];
@@ -104,17 +106,25 @@ static void add_url(struct remote *remote, const char *url)
        remote->url[remote->url_nr++] = url;
 }
 
-static void add_url_alias(struct remote *remote, const char *url)
-{
-       add_url(remote, alias_url(url, &rewrites));
-}
-
 static void add_pushurl(struct remote *remote, const char *pushurl)
 {
        ALLOC_GROW(remote->pushurl, remote->pushurl_nr + 1, remote->pushurl_alloc);
        remote->pushurl[remote->pushurl_nr++] = pushurl;
 }
 
+static void add_pushurl_alias(struct remote *remote, const char *url)
+{
+       const char *pushurl = alias_url(url, &rewrites_push);
+       if (pushurl != url)
+               add_pushurl(remote, pushurl);
+}
+
+static void add_url_alias(struct remote *remote, const char *url)
+{
+       add_url(remote, alias_url(url, &rewrites));
+       add_pushurl_alias(remote, url);
+}
+
 static struct remote *make_remote(const char *name, int len)
 {
        struct remote *ret;
@@ -358,8 +368,13 @@ static int handle_config(const char *key, const char *value, void *cb)
                subkey = strrchr(name, '.');
                if (!subkey)
                        return 0;
-               rewrite = make_rewrite(&rewrites, name, subkey - name);
                if (!strcmp(subkey, ".insteadof")) {
+                       rewrite = make_rewrite(&rewrites, name, subkey - name);
+                       if (!value)
+                               return config_error_nonbool(key);
+                       add_instead_of(rewrite, xstrdup(value));
+               } else if (!strcmp(subkey, ".pushinsteadof")) {
+                       rewrite = make_rewrite(&rewrites_push, name, subkey - name);
                        if (!value)
                                return config_error_nonbool(key);
                        add_instead_of(rewrite, xstrdup(value));
@@ -433,14 +448,18 @@ static void alias_all_urls(void)
 {
        int i, j;
        for (i = 0; i < remotes_nr; i++) {
+               int add_pushurl_aliases;
                if (!remotes[i])
                        continue;
-               for (j = 0; j < remotes[i]->url_nr; j++) {
-                       remotes[i]->url[j] = alias_url(remotes[i]->url[j], &rewrites);
-               }
                for (j = 0; j < remotes[i]->pushurl_nr; j++) {
                        remotes[i]->pushurl[j] = alias_url(remotes[i]->pushurl[j], &rewrites);
                }
+               add_pushurl_aliases = remotes[i]->pushurl_nr == 0;
+               for (j = 0; j < remotes[i]->url_nr; j++) {
+                       if (add_pushurl_aliases)
+                               add_pushurl_alias(remotes[i], remotes[i]->url[j]);
+                       remotes[i]->url[j] = alias_url(remotes[i]->url[j], &rewrites);
+               }
        }
 }
 
@@ -716,29 +735,33 @@ int for_each_remote(each_remote_fn fn, void *priv)
 
 void ref_remove_duplicates(struct ref *ref_map)
 {
-       struct ref **posn;
-       struct ref *next;
-       for (; ref_map; ref_map = ref_map->next) {
+       struct string_list refs = { NULL, 0, 0, 0 };
+       struct string_list_item *item = NULL;
+       struct ref *prev = NULL, *next = NULL;
+       for (; ref_map; prev = ref_map, ref_map = next) {
+               next = ref_map->next;
                if (!ref_map->peer_ref)
                        continue;
-               posn = &ref_map->next;
-               while (*posn) {
-                       if ((*posn)->peer_ref &&
-                           !strcmp((*posn)->peer_ref->name,
-                                   ref_map->peer_ref->name)) {
-                               if (strcmp((*posn)->name, ref_map->name))
-                                       die("%s tracks both %s and %s",
-                                           ref_map->peer_ref->name,
-                                           (*posn)->name, ref_map->name);
-                               next = (*posn)->next;
-                               free((*posn)->peer_ref);
-                               free(*posn);
-                               *posn = next;
-                       } else {
-                               posn = &(*posn)->next;
-                       }
+
+               item = string_list_lookup(ref_map->peer_ref->name, &refs);
+               if (item) {
+                       if (strcmp(((struct ref *)item->util)->name,
+                                  ref_map->name))
+                               die("%s tracks both %s and %s",
+                                   ref_map->peer_ref->name,
+                                   ((struct ref *)item->util)->name,
+                                   ref_map->name);
+                       prev->next = ref_map->next;
+                       free(ref_map->peer_ref);
+                       free(ref_map);
+                       ref_map = prev; /* skip this; we freed it */
+                       continue;
                }
+
+               item = string_list_insert(ref_map->peer_ref->name, &refs);
+               item->util = ref_map;
        }
+       string_list_clear(&refs, 0);
 }
 
 int remote_has_url(struct remote *remote, const char *url)