send-pack: support pushing from a shallow clone via http
[git] / builtin / fetch-pack.c
1 #include "builtin.h"
2 #include "pkt-line.h"
3 #include "fetch-pack.h"
4 #include "remote.h"
5 #include "connect.h"
6 #include "sha1-array.h"
7
8 static const char fetch_pack_usage[] =
9 "git fetch-pack [--all] [--stdin] [--quiet|-q] [--keep|-k] [--thin] "
10 "[--include-tag] [--upload-pack=<git-upload-pack>] [--depth=<n>] "
11 "[--no-progress] [-v] [<host>:]<directory> [<refs>...]";
12
13 static void add_sought_entry_mem(struct ref ***sought, int *nr, int *alloc,
14                                  const char *name, int namelen)
15 {
16         struct ref *ref = xcalloc(1, sizeof(*ref) + namelen + 1);
17         unsigned char sha1[20];
18
19         if (namelen > 41 && name[40] == ' ' && !get_sha1_hex(name, sha1)) {
20                 hashcpy(ref->old_sha1, sha1);
21                 name += 41;
22                 namelen -= 41;
23         }
24
25         memcpy(ref->name, name, namelen);
26         ref->name[namelen] = '\0';
27         (*nr)++;
28         ALLOC_GROW(*sought, *nr, *alloc);
29         (*sought)[*nr - 1] = ref;
30 }
31
32 static void add_sought_entry(struct ref ***sought, int *nr, int *alloc,
33                              const char *string)
34 {
35         add_sought_entry_mem(sought, nr, alloc, string, strlen(string));
36 }
37
38 int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
39 {
40         int i, ret;
41         struct ref *ref = NULL;
42         const char *dest = NULL;
43         struct ref **sought = NULL;
44         int nr_sought = 0, alloc_sought = 0;
45         int fd[2];
46         char *pack_lockfile = NULL;
47         char **pack_lockfile_ptr = NULL;
48         struct child_process *conn;
49         struct fetch_pack_args args;
50         struct sha1_array shallow = SHA1_ARRAY_INIT;
51
52         packet_trace_identity("fetch-pack");
53
54         memset(&args, 0, sizeof(args));
55         args.uploadpack = "git-upload-pack";
56
57         for (i = 1; i < argc && *argv[i] == '-'; i++) {
58                 const char *arg = argv[i];
59
60                 if (!prefixcmp(arg, "--upload-pack=")) {
61                         args.uploadpack = arg + 14;
62                         continue;
63                 }
64                 if (!prefixcmp(arg, "--exec=")) {
65                         args.uploadpack = arg + 7;
66                         continue;
67                 }
68                 if (!strcmp("--quiet", arg) || !strcmp("-q", arg)) {
69                         args.quiet = 1;
70                         continue;
71                 }
72                 if (!strcmp("--keep", arg) || !strcmp("-k", arg)) {
73                         args.lock_pack = args.keep_pack;
74                         args.keep_pack = 1;
75                         continue;
76                 }
77                 if (!strcmp("--thin", arg)) {
78                         args.use_thin_pack = 1;
79                         continue;
80                 }
81                 if (!strcmp("--include-tag", arg)) {
82                         args.include_tag = 1;
83                         continue;
84                 }
85                 if (!strcmp("--all", arg)) {
86                         args.fetch_all = 1;
87                         continue;
88                 }
89                 if (!strcmp("--stdin", arg)) {
90                         args.stdin_refs = 1;
91                         continue;
92                 }
93                 if (!strcmp("-v", arg)) {
94                         args.verbose = 1;
95                         continue;
96                 }
97                 if (!prefixcmp(arg, "--depth=")) {
98                         args.depth = strtol(arg + 8, NULL, 0);
99                         continue;
100                 }
101                 if (!strcmp("--no-progress", arg)) {
102                         args.no_progress = 1;
103                         continue;
104                 }
105                 if (!strcmp("--stateless-rpc", arg)) {
106                         args.stateless_rpc = 1;
107                         continue;
108                 }
109                 if (!strcmp("--lock-pack", arg)) {
110                         args.lock_pack = 1;
111                         pack_lockfile_ptr = &pack_lockfile;
112                         continue;
113                 }
114                 if (!strcmp("--check-self-contained-and-connected", arg)) {
115                         args.check_self_contained_and_connected = 1;
116                         continue;
117                 }
118                 if (!strcmp("--cloning", arg)) {
119                         args.cloning = 1;
120                         continue;
121                 }
122                 if (!strcmp("--update-shallow", arg)) {
123                         args.update_shallow = 1;
124                         continue;
125                 }
126                 usage(fetch_pack_usage);
127         }
128
129         if (i < argc)
130                 dest = argv[i++];
131         else
132                 usage(fetch_pack_usage);
133
134         /*
135          * Copy refs from cmdline to growable list, then append any
136          * refs from the standard input:
137          */
138         for (; i < argc; i++)
139                 add_sought_entry(&sought, &nr_sought, &alloc_sought, argv[i]);
140         if (args.stdin_refs) {
141                 if (args.stateless_rpc) {
142                         /* in stateless RPC mode we use pkt-line to read
143                          * from stdin, until we get a flush packet
144                          */
145                         for (;;) {
146                                 char *line = packet_read_line(0, NULL);
147                                 if (!line)
148                                         break;
149                                 add_sought_entry(&sought, &nr_sought,  &alloc_sought, line);
150                         }
151                 }
152                 else {
153                         /* read from stdin one ref per line, until EOF */
154                         struct strbuf line = STRBUF_INIT;
155                         while (strbuf_getline(&line, stdin, '\n') != EOF)
156                                 add_sought_entry(&sought, &nr_sought, &alloc_sought, line.buf);
157                         strbuf_release(&line);
158                 }
159         }
160
161         if (args.stateless_rpc) {
162                 conn = NULL;
163                 fd[0] = 0;
164                 fd[1] = 1;
165         } else {
166                 conn = git_connect(fd, dest, args.uploadpack,
167                                    args.verbose ? CONNECT_VERBOSE : 0);
168         }
169
170         get_remote_heads(fd[0], NULL, 0, &ref, 0, NULL, &shallow);
171
172         ref = fetch_pack(&args, fd, conn, ref, dest, sought, nr_sought,
173                          &shallow, pack_lockfile_ptr);
174         if (pack_lockfile) {
175                 printf("lock %s\n", pack_lockfile);
176                 fflush(stdout);
177         }
178         if (args.check_self_contained_and_connected &&
179             args.self_contained_and_connected) {
180                 printf("connectivity-ok\n");
181                 fflush(stdout);
182         }
183         close(fd[0]);
184         close(fd[1]);
185         if (finish_connect(conn))
186                 return 1;
187
188         ret = !ref;
189
190         /*
191          * If the heads to pull were given, we should have consumed
192          * all of them by matching the remote.  Otherwise, 'git fetch
193          * remote no-such-ref' would silently succeed without issuing
194          * an error.
195          */
196         for (i = 0; i < nr_sought; i++) {
197                 if (!sought[i] || sought[i]->matched)
198                         continue;
199                 error("no such remote ref %s", sought[i]->name);
200                 ret = 1;
201         }
202
203         while (ref) {
204                 printf("%s %s\n",
205                        sha1_to_hex(ref->old_sha1), ref->name);
206                 ref = ref->next;
207         }
208
209         return ret;
210 }