Merge branch 'db/remote'
authorJunio C Hamano <junkio@cox.net>
Tue, 29 May 2007 08:24:20 +0000 (01:24 -0700)
committerJunio C Hamano <junkio@cox.net>
Tue, 29 May 2007 08:24:20 +0000 (01:24 -0700)
* db/remote:
Move refspec pattern matching to match_refs().
Update local tracking refs when pushing
Add handlers for fetch-side configuration of remotes.
Move refspec parser from connect.c and cache.h to remote.{c,h}
Move remote parsing into a library file out of builtin-push.

1  2 
Makefile
cache.h
connect.c
diff --combined Makefile
index fb11fa1987e162c13a9fba492da41e26fdad7195,35864ed3c4afe01680bd5123fc28c35f5cf328e6..75277343f6f69931bfa008d69032734e2e2d0c8d
+++ b/Makefile
@@@ -235,7 -235,7 +235,7 @@@ endi
  
  # ... and all the rest that could be moved out of bindir to gitexecdir
  PROGRAMS = \
 -      git-convert-objects$X git-fetch-pack$X git-fsck$X \
 +      git-convert-objects$X git-fetch-pack$X \
        git-hash-object$X git-index-pack$X git-local-fetch$X \
        git-fast-import$X \
        git-merge-base$X \
        git-show-index$X git-ssh-fetch$X \
        git-ssh-upload$X git-unpack-file$X \
        git-update-server-info$X \
 -      git-upload-pack$X git-verify-pack$X \
 +      git-upload-pack$X \
        git-pack-redundant$X git-var$X \
        git-merge-tree$X git-imap-send$X \
        git-merge-recursive$X \
@@@ -296,7 -296,8 +296,8 @@@ LIB_H = 
        diff.h object.h pack.h pkt-line.h quote.h refs.h list-objects.h sideband.h \
        run-command.h strbuf.h tag.h tree.h git-compat-util.h revision.h \
        tree-walk.h log-tree.h dir.h path-list.h unpack-trees.h builtin.h \
-       utf8.h reflog-walk.h patch-ids.h attr.h decorate.h progress.h mailmap.h
+       utf8.h reflog-walk.h patch-ids.h attr.h decorate.h progress.h \
+       mailmap.h remote.h
  
  DIFF_OBJS = \
        diff.o diff-lib.o diffcore-break.o diffcore-order.o \
@@@ -318,7 -319,7 +319,7 @@@ LIB_OBJS = 
        write_or_die.o trace.o list-objects.o grep.o match-trees.o \
        alloc.o merge-file.o path-list.o help.o unpack-trees.o $(DIFF_OBJS) \
        color.o wt-status.o archive-zip.o archive-tar.o shallow.o utf8.o \
-       convert.o attr.o decorate.o progress.o mailmap.o symlinks.o
+       convert.o attr.o decorate.o progress.o mailmap.o symlinks.o remote.o
  
  BUILTIN_OBJS = \
        builtin-add.o \
diff --combined cache.h
index cd875bc2e95ded83eb8619eec106fff88a9012c4,0e6439b0ddaf317a6288ab4dd40ae8b9a41e9884..ec85d93e0d39a3c55c9579c734401b80331aa19a
+++ b/cache.h
@@@ -40,8 -40,8 +40,8 @@@
   * happens that everybody shares the same bit representation
   * in the UNIX world (and apparently wider too..)
   */
 -#define S_IFDIRLNK    0160000
 -#define S_ISDIRLNK(m) (((m) & S_IFMT) == S_IFDIRLNK)
 +#define S_IFGITLINK   0160000
 +#define S_ISGITLINK(m)        (((m) & S_IFMT) == S_IFGITLINK)
  
  /*
   * Intensive research over the course of many years has shown that
@@@ -123,8 -123,8 +123,8 @@@ static inline unsigned int create_ce_mo
  {
        if (S_ISLNK(mode))
                return htonl(S_IFLNK);
 -      if (S_ISDIR(mode) || S_ISDIRLNK(mode))
 -              return htonl(S_IFDIRLNK);
 +      if (S_ISDIR(mode) || S_ISGITLINK(mode))
 +              return htonl(S_IFGITLINK);
        return htonl(S_IFREG | ce_permissions(mode));
  }
  static inline unsigned int ce_mode_from_stat(struct cache_entry *ce, unsigned int mode)
  }
  #define canon_mode(mode) \
        (S_ISREG(mode) ? (S_IFREG | ce_permissions(mode)) : \
 -      S_ISLNK(mode) ? S_IFLNK : S_ISDIR(mode) ? S_IFDIR : S_IFDIRLNK)
 +      S_ISLNK(mode) ? S_IFLNK : S_ISDIR(mode) ? S_IFDIR : S_IFGITLINK)
  
  #define cache_entry_size(len) ((offsetof(struct cache_entry,name) + (len) + 8) & ~7)
  
@@@ -467,8 -467,6 +467,6 @@@ struct ref 
  extern pid_t git_connect(int fd[2], char *url, const char *prog, int flags);
  extern int finish_connect(pid_t pid);
  extern int path_match(const char *path, int nr, char **match);
- extern int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,
-                     int nr_refspec, char **refspec, int all);
  extern int get_ack(int fd, unsigned char *result_sha1);
  extern struct ref **get_remote_heads(int in, struct ref **list, int nr_match, char **match, unsigned int flags);
  extern int server_supports(const char *feature);
diff --combined connect.c
index 375739205f72062c7b51e16ca4cdecc053e1c2da,2f61ea3422bbeba7ad381f1ae500d5b8b7b1812c..8cbda88dda02e7de74149af1b387e537f77bc497
+++ b/connect.c
@@@ -4,6 -4,7 +4,7 @@@
  #include "quote.h"
  #include "refs.h"
  #include "run-command.h"
+ #include "remote.h"
  
  static char *server_capabilities;
  
@@@ -128,245 -129,6 +129,6 @@@ int path_match(const char *path, int nr
        return 0;
  }
  
- struct refspec {
-       char *src;
-       char *dst;
-       char force;
- };
- /*
-  * A:B means fast forward remote B with local A.
-  * +A:B means overwrite remote B with local A.
-  * +A is a shorthand for +A:A.
-  * A is a shorthand for A:A.
-  * :B means delete remote B.
-  */
- static struct refspec *parse_ref_spec(int nr_refspec, char **refspec)
- {
-       int i;
-       struct refspec *rs = xcalloc(sizeof(*rs), (nr_refspec + 1));
-       for (i = 0; i < nr_refspec; i++) {
-               char *sp, *dp, *ep;
-               sp = refspec[i];
-               if (*sp == '+') {
-                       rs[i].force = 1;
-                       sp++;
-               }
-               ep = strchr(sp, ':');
-               if (ep) {
-                       dp = ep + 1;
-                       *ep = 0;
-               }
-               else
-                       dp = sp;
-               rs[i].src = sp;
-               rs[i].dst = dp;
-       }
-       rs[nr_refspec].src = rs[nr_refspec].dst = NULL;
-       return rs;
- }
- static int count_refspec_match(const char *pattern,
-                              struct ref *refs,
-                              struct ref **matched_ref)
- {
-       int patlen = strlen(pattern);
-       struct ref *matched_weak = NULL;
-       struct ref *matched = NULL;
-       int weak_match = 0;
-       int match = 0;
-       for (weak_match = match = 0; refs; refs = refs->next) {
-               char *name = refs->name;
-               int namelen = strlen(name);
-               int weak_match;
-               if (namelen < patlen ||
-                   memcmp(name + namelen - patlen, pattern, patlen))
-                       continue;
-               if (namelen != patlen && name[namelen - patlen - 1] != '/')
-                       continue;
-               /* A match is "weak" if it is with refs outside
-                * heads or tags, and did not specify the pattern
-                * in full (e.g. "refs/remotes/origin/master") or at
-                * least from the toplevel (e.g. "remotes/origin/master");
-                * otherwise "git push $URL master" would result in
-                * ambiguity between remotes/origin/master and heads/master
-                * at the remote site.
-                */
-               if (namelen != patlen &&
-                   patlen != namelen - 5 &&
-                   prefixcmp(name, "refs/heads/") &&
-                   prefixcmp(name, "refs/tags/")) {
-                       /* We want to catch the case where only weak
-                        * matches are found and there are multiple
-                        * matches, and where more than one strong
-                        * matches are found, as ambiguous.  One
-                        * strong match with zero or more weak matches
-                        * are acceptable as a unique match.
-                        */
-                       matched_weak = refs;
-                       weak_match++;
-               }
-               else {
-                       matched = refs;
-                       match++;
-               }
-       }
-       if (!matched) {
-               *matched_ref = matched_weak;
-               return weak_match;
-       }
-       else {
-               *matched_ref = matched;
-               return match;
-       }
- }
- static void link_dst_tail(struct ref *ref, struct ref ***tail)
- {
-       **tail = ref;
-       *tail = &ref->next;
-       **tail = NULL;
- }
- static struct ref *try_explicit_object_name(const char *name)
- {
-       unsigned char sha1[20];
-       struct ref *ref;
-       int len;
-       if (!*name) {
-               ref = xcalloc(1, sizeof(*ref) + 20);
-               strcpy(ref->name, "(delete)");
-               hashclr(ref->new_sha1);
-               return ref;
-       }
-       if (get_sha1(name, sha1))
-               return NULL;
-       len = strlen(name) + 1;
-       ref = xcalloc(1, sizeof(*ref) + len);
-       memcpy(ref->name, name, len);
-       hashcpy(ref->new_sha1, sha1);
-       return ref;
- }
- static int match_explicit_refs(struct ref *src, struct ref *dst,
-                              struct ref ***dst_tail, struct refspec *rs)
- {
-       int i, errs;
-       for (i = errs = 0; rs[i].src; i++) {
-               struct ref *matched_src, *matched_dst;
-               matched_src = matched_dst = NULL;
-               switch (count_refspec_match(rs[i].src, src, &matched_src)) {
-               case 1:
-                       break;
-               case 0:
-                       /* The source could be in the get_sha1() format
-                        * not a reference name.  :refs/other is a
-                        * way to delete 'other' ref at the remote end.
-                        */
-                       matched_src = try_explicit_object_name(rs[i].src);
-                       if (matched_src)
-                               break;
-                       errs = 1;
-                       error("src refspec %s does not match any.",
-                             rs[i].src);
-                       break;
-               default:
-                       errs = 1;
-                       error("src refspec %s matches more than one.",
-                             rs[i].src);
-                       break;
-               }
-               switch (count_refspec_match(rs[i].dst, dst, &matched_dst)) {
-               case 1:
-                       break;
-               case 0:
-                       if (!memcmp(rs[i].dst, "refs/", 5)) {
-                               int len = strlen(rs[i].dst) + 1;
-                               matched_dst = xcalloc(1, sizeof(*dst) + len);
-                               memcpy(matched_dst->name, rs[i].dst, len);
-                               link_dst_tail(matched_dst, dst_tail);
-                       }
-                       else if (!strcmp(rs[i].src, rs[i].dst) &&
-                                matched_src) {
-                               /* pushing "master:master" when
-                                * remote does not have master yet.
-                                */
-                               int len = strlen(matched_src->name) + 1;
-                               matched_dst = xcalloc(1, sizeof(*dst) + len);
-                               memcpy(matched_dst->name, matched_src->name,
-                                      len);
-                               link_dst_tail(matched_dst, dst_tail);
-                       }
-                       else {
-                               errs = 1;
-                               error("dst refspec %s does not match any "
-                                     "existing ref on the remote and does "
-                                     "not start with refs/.", rs[i].dst);
-                       }
-                       break;
-               default:
-                       errs = 1;
-                       error("dst refspec %s matches more than one.",
-                             rs[i].dst);
-                       break;
-               }
-               if (errs)
-                       continue;
-               if (matched_dst->peer_ref) {
-                       errs = 1;
-                       error("dst ref %s receives from more than one src.",
-                             matched_dst->name);
-               }
-               else {
-                       matched_dst->peer_ref = matched_src;
-                       matched_dst->force = rs[i].force;
-               }
-       }
-       return -errs;
- }
- static struct ref *find_ref_by_name(struct ref *list, const char *name)
- {
-       for ( ; list; list = list->next)
-               if (!strcmp(list->name, name))
-                       return list;
-       return NULL;
- }
- int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,
-              int nr_refspec, char **refspec, int all)
- {
-       struct refspec *rs = parse_ref_spec(nr_refspec, refspec);
-       if (nr_refspec)
-               return match_explicit_refs(src, dst, dst_tail, rs);
-       /* pick the remainder */
-       for ( ; src; src = src->next) {
-               struct ref *dst_peer;
-               if (src->peer_ref)
-                       continue;
-               dst_peer = find_ref_by_name(dst, src->name);
-               if ((dst_peer && dst_peer->peer_ref) || (!dst_peer && !all))
-                       continue;
-               if (!dst_peer) {
-                       /* Create a new one and link it */
-                       int len = strlen(src->name) + 1;
-                       dst_peer = xcalloc(1, sizeof(*dst_peer) + len);
-                       memcpy(dst_peer->name, src->name, len);
-                       hashcpy(dst_peer->new_sha1, src->new_sha1);
-                       link_dst_tail(dst_peer, dst_tail);
-               }
-               dst_peer->peer_ref = src;
-       }
-       return 0;
- }
  enum protocol {
        PROTO_LOCAL = 1,
        PROTO_SSH,
@@@ -391,23 -153,6 +153,23 @@@ static enum protocol get_protocol(cons
  
  #ifndef NO_IPV6
  
 +static const char *ai_name(const struct addrinfo *ai)
 +{
 +      static char addr[INET_ADDRSTRLEN];
 +      if ( AF_INET == ai->ai_family ) {
 +              struct sockaddr_in *in;
 +              in = (struct sockaddr_in *)ai->ai_addr;
 +              inet_ntop(ai->ai_family, &in->sin_addr, addr, sizeof(addr));
 +      } else if ( AF_INET6 == ai->ai_family ) {
 +              struct sockaddr_in6 *in;
 +              in = (struct sockaddr_in6 *)ai->ai_addr;
 +              inet_ntop(ai->ai_family, &in->sin6_addr, addr, sizeof(addr));
 +      } else {
 +              strcpy(addr, "(unknown)");
 +      }
 +      return addr;
 +}
 +
  /*
   * Returns a connected socket() fd, or else die()s.
   */
@@@ -418,7 -163,6 +180,7 @@@ static int git_tcp_connect_sock(char *h
        const char *port = STR(DEFAULT_GIT_PORT);
        struct addrinfo hints, *ai0, *ai;
        int gai;
 +      int cnt = 0;
  
        if (host[0] == '[') {
                end = strchr(host + 1, ']');
                }
                if (connect(sockfd, ai->ai_addr, ai->ai_addrlen) < 0) {
                        saved_errno = errno;
 +                      fprintf(stderr, "%s[%d: %s]: net=%s, errno=%s\n",
 +                              host,
 +                              cnt,
 +                              ai_name(ai),
 +                              hstrerror(h_errno),
 +                              strerror(saved_errno));
                        close(sockfd);
                        sockfd = -1;
                        continue;
                }
 +              if (flags & CONNECT_VERBOSE)
 +                      fprintf(stderr, "%s ", ai_name(ai));
                break;
        }
  
@@@ -502,7 -238,6 +264,7 @@@ static int git_tcp_connect_sock(char *h
        struct sockaddr_in sa;
        char **ap;
        unsigned int nport;
 +      int cnt;
  
        if (host[0] == '[') {
                end = strchr(host + 1, ']');
        if (flags & CONNECT_VERBOSE)
                fprintf(stderr, "done.\nConnecting to %s (port %s) ... ", host, port);
  
 -      for (ap = he->h_addr_list; *ap; ap++) {
 +      for (cnt = 0, ap = he->h_addr_list; *ap; ap++, cnt++) {
                sockfd = socket(he->h_addrtype, SOCK_STREAM, 0);
                if (sockfd < 0) {
                        saved_errno = errno;
  
                if (connect(sockfd, (struct sockaddr *)&sa, sizeof sa) < 0) {
                        saved_errno = errno;
 +                      fprintf(stderr, "%s[%d: %s]: net=%s, errno=%s\n",
 +                              host,
 +                              cnt,
 +                              inet_ntoa(*(struct in_addr *)&sa.sin_addr),
 +                              hstrerror(h_errno),
 +                              strerror(saved_errno));
                        close(sockfd);
                        sockfd = -1;
                        continue;
                }
 +              if (flags & CONNECT_VERBOSE)
 +                      fprintf(stderr, "%s ",
 +                              inet_ntoa(*(struct in_addr *)&sa.sin_addr));
                break;
        }