Merge branch 'jk/url-decode'
[git] / builtin / ls-remote.c
1 #include "builtin.h"
2 #include "cache.h"
3 #include "transport.h"
4 #include "remote.h"
5
6 static const char ls_remote_usage[] =
7 "git ls-remote [--heads] [--tags]  [-u <exec> | --upload-pack <exec>]\n"
8 "                     [-q|--quiet] [<repository> [<refs>...]]";
9
10 /*
11  * Is there one among the list of patterns that match the tail part
12  * of the path?
13  */
14 static int tail_match(const char **pattern, const char *path)
15 {
16         const char *p;
17         char pathbuf[PATH_MAX];
18
19         if (!pattern)
20                 return 1; /* no restriction */
21
22         if (snprintf(pathbuf, sizeof(pathbuf), "/%s", path) > sizeof(pathbuf))
23                 return error("insanely long ref %.*s...", 20, path);
24         while ((p = *(pattern++)) != NULL) {
25                 if (!fnmatch(p, pathbuf, 0))
26                         return 1;
27         }
28         return 0;
29 }
30
31 int cmd_ls_remote(int argc, const char **argv, const char *prefix)
32 {
33         int i;
34         const char *dest = NULL;
35         int nongit;
36         unsigned flags = 0;
37         int quiet = 0;
38         const char *uploadpack = NULL;
39         const char **pattern = NULL;
40
41         struct remote *remote;
42         struct transport *transport;
43         const struct ref *ref;
44
45         setup_git_directory_gently(&nongit);
46
47         for (i = 1; i < argc; i++) {
48                 const char *arg = argv[i];
49
50                 if (*arg == '-') {
51                         if (!prefixcmp(arg, "--upload-pack=")) {
52                                 uploadpack = arg + 14;
53                                 continue;
54                         }
55                         if (!prefixcmp(arg, "--exec=")) {
56                                 uploadpack = arg + 7;
57                                 continue;
58                         }
59                         if (!strcmp("--tags", arg) || !strcmp("-t", arg)) {
60                                 flags |= REF_TAGS;
61                                 continue;
62                         }
63                         if (!strcmp("--heads", arg) || !strcmp("-h", arg)) {
64                                 flags |= REF_HEADS;
65                                 continue;
66                         }
67                         if (!strcmp("--refs", arg)) {
68                                 flags |= REF_NORMAL;
69                                 continue;
70                         }
71                         if (!strcmp("--quiet", arg) || !strcmp("-q", arg)) {
72                                 quiet = 1;
73                                 continue;
74                         }
75                         usage(ls_remote_usage);
76                 }
77                 dest = arg;
78                 i++;
79                 break;
80         }
81
82         if (argv[i]) {
83                 int j;
84                 pattern = xcalloc(sizeof(const char *), argc - i + 1);
85                 for (j = i; j < argc; j++) {
86                         int len = strlen(argv[j]);
87                         char *p = xmalloc(len + 3);
88                         sprintf(p, "*/%s", argv[j]);
89                         pattern[j - i] = p;
90                 }
91         }
92         remote = remote_get(dest);
93         if (!remote) {
94                 if (dest)
95                         die("bad repository '%s'", dest);
96                 die("No remote configured to list refs from.");
97         }
98         if (!remote->url_nr)
99                 die("remote %s has no configured URL", dest);
100         transport = transport_get(remote, NULL);
101         if (uploadpack != NULL)
102                 transport_set_option(transport, TRANS_OPT_UPLOADPACK, uploadpack);
103
104         ref = transport_get_remote_refs(transport);
105         if (transport_disconnect(transport))
106                 return 1;
107
108         if (!dest && !quiet)
109                 fprintf(stderr, "From %s\n", *remote->url);
110         for ( ; ref; ref = ref->next) {
111                 if (!check_ref_type(ref, flags))
112                         continue;
113                 if (!tail_match(pattern, ref->name))
114                         continue;
115                 printf("%s      %s\n", sha1_to_hex(ref->old_sha1), ref->name);
116         }
117         return 0;
118 }