]> git.ipfire.org Git - thirdparty/git.git/blame - builtin-remote.c
builtin-remote: new show output style
[thirdparty/git.git] / builtin-remote.c
CommitLineData
211c8968
JS
1#include "cache.h"
2#include "parse-options.h"
3#include "transport.h"
4#include "remote.h"
c455c87c 5#include "string-list.h"
211c8968
JS
6#include "strbuf.h"
7#include "run-command.h"
8#include "refs.h"
9
10static const char * const builtin_remote_usage[] = {
357af14f
CR
11 "git remote [-v | --verbose]",
12 "git remote add [-t <branch>] [-m <master>] [-f] [--mirror] <name> <url>",
bf98421a 13 "git remote rename <old> <new>",
211c8968 14 "git remote rm <name>",
bc14fac8 15 "git remote set-head <name> [-a | -d | <branch>]",
357af14f
CR
16 "git remote show [-n] <name>",
17 "git remote prune [-n | --dry-run] <name>",
dbbd56f1 18 "git remote [-v | --verbose] update [group]",
211c8968
JS
19 NULL
20};
21
e61e0cc6
JS
22#define GET_REF_STATES (1<<0)
23#define GET_HEAD_NAMES (1<<1)
24
211c8968
JS
25static int verbose;
26
c4112bb6
JK
27static int show_all(void);
28
211c8968
JS
29static inline int postfixcmp(const char *string, const char *postfix)
30{
31 int len1 = strlen(string), len2 = strlen(postfix);
32 if (len1 < len2)
33 return 1;
34 return strcmp(string + len1 - len2, postfix);
35}
36
211c8968
JS
37static int opt_parse_track(const struct option *opt, const char *arg, int not)
38{
c455c87c 39 struct string_list *list = opt->value;
211c8968 40 if (not)
c455c87c 41 string_list_clear(list, 0);
211c8968 42 else
c455c87c 43 string_list_append(arg, list);
211c8968
JS
44 return 0;
45}
46
47static int fetch_remote(const char *name)
48{
dbbd56f1
CR
49 const char *argv[] = { "fetch", name, NULL, NULL };
50 if (verbose) {
51 argv[1] = "-v";
52 argv[2] = name;
53 }
3000658f 54 printf("Updating %s\n", name);
211c8968
JS
55 if (run_command_v_opt(argv, RUN_GIT_CMD))
56 return error("Could not fetch %s", name);
57 return 0;
58}
59
60static int add(int argc, const char **argv)
61{
62 int fetch = 0, mirror = 0;
c455c87c 63 struct string_list track = { NULL, 0, 0 };
211c8968
JS
64 const char *master = NULL;
65 struct remote *remote;
f285a2d7 66 struct strbuf buf = STRBUF_INIT, buf2 = STRBUF_INIT;
211c8968
JS
67 const char *name, *url;
68 int i;
69
70 struct option options[] = {
71 OPT_GROUP("add specific options"),
72 OPT_BOOLEAN('f', "fetch", &fetch, "fetch the remote branches"),
73 OPT_CALLBACK('t', "track", &track, "branch",
74 "branch(es) to track", opt_parse_track),
75 OPT_STRING('m', "master", &master, "branch", "master branch"),
76 OPT_BOOLEAN(0, "mirror", &mirror, "no separate remotes"),
77 OPT_END()
78 };
79
80 argc = parse_options(argc, argv, options, builtin_remote_usage, 0);
81
82 if (argc < 2)
83 usage_with_options(builtin_remote_usage, options);
84
85 name = argv[0];
86 url = argv[1];
87
88 remote = remote_get(name);
89 if (remote && (remote->url_nr > 1 || strcmp(name, remote->url[0]) ||
90 remote->fetch_refspec_nr))
91 die("remote %s already exists.", name);
92
24b6177e
JF
93 strbuf_addf(&buf2, "refs/heads/test:refs/remotes/%s/test", name);
94 if (!valid_fetch_refspec(buf2.buf))
95 die("'%s' is not a valid remote name", name);
96
211c8968
JS
97 strbuf_addf(&buf, "remote.%s.url", name);
98 if (git_config_set(buf.buf, url))
99 return 1;
100
24b6177e
JF
101 strbuf_reset(&buf);
102 strbuf_addf(&buf, "remote.%s.fetch", name);
103
211c8968 104 if (track.nr == 0)
c455c87c 105 string_list_append("*", &track);
211c8968 106 for (i = 0; i < track.nr; i++) {
c455c87c 107 struct string_list_item *item = track.items + i;
211c8968 108
211c8968 109 strbuf_reset(&buf2);
1ce89cc4 110 strbuf_addch(&buf2, '+');
211c8968
JS
111 if (mirror)
112 strbuf_addf(&buf2, "refs/%s:refs/%s",
c455c87c 113 item->string, item->string);
211c8968
JS
114 else
115 strbuf_addf(&buf2, "refs/heads/%s:refs/remotes/%s/%s",
c455c87c 116 item->string, name, item->string);
211c8968
JS
117 if (git_config_set_multivar(buf.buf, buf2.buf, "^$", 0))
118 return 1;
119 }
120
84bb2dfd
PB
121 if (mirror) {
122 strbuf_reset(&buf);
123 strbuf_addf(&buf, "remote.%s.mirror", name);
bc699afc 124 if (git_config_set(buf.buf, "true"))
84bb2dfd
PB
125 return 1;
126 }
127
211c8968
JS
128 if (fetch && fetch_remote(name))
129 return 1;
130
131 if (master) {
132 strbuf_reset(&buf);
133 strbuf_addf(&buf, "refs/remotes/%s/HEAD", name);
134
135 strbuf_reset(&buf2);
136 strbuf_addf(&buf2, "refs/remotes/%s/%s", name, master);
137
138 if (create_symref(buf.buf, buf2.buf, "remote add"))
139 return error("Could not setup master '%s'", master);
140 }
141
142 strbuf_release(&buf);
143 strbuf_release(&buf2);
c455c87c 144 string_list_clear(&track, 0);
211c8968
JS
145
146 return 0;
147}
148
149struct branch_info {
e0cc81e6 150 char *remote_name;
c455c87c 151 struct string_list merge;
7ecbbf87 152 int rebase;
211c8968
JS
153};
154
c455c87c 155static struct string_list branch_list;
211c8968 156
72972eb3
JH
157static const char *abbrev_ref(const char *name, const char *prefix)
158{
159 const char *abbrev = skip_prefix(name, prefix);
160 if (abbrev)
161 return abbrev;
162 return name;
163}
164#define abbrev_branch(name) abbrev_ref((name), "refs/heads/")
165
ef90d6d4 166static int config_read_branches(const char *key, const char *value, void *cb)
211c8968
JS
167{
168 if (!prefixcmp(key, "branch.")) {
7ecbbf87 169 const char *orig_key = key;
211c8968 170 char *name;
c455c87c 171 struct string_list_item *item;
211c8968 172 struct branch_info *info;
7ecbbf87 173 enum { REMOTE, MERGE, REBASE } type;
211c8968
JS
174
175 key += 7;
176 if (!postfixcmp(key, ".remote")) {
177 name = xstrndup(key, strlen(key) - 7);
178 type = REMOTE;
179 } else if (!postfixcmp(key, ".merge")) {
180 name = xstrndup(key, strlen(key) - 6);
181 type = MERGE;
7ecbbf87
JS
182 } else if (!postfixcmp(key, ".rebase")) {
183 name = xstrndup(key, strlen(key) - 7);
184 type = REBASE;
211c8968
JS
185 } else
186 return 0;
187
c455c87c 188 item = string_list_insert(name, &branch_list);
211c8968
JS
189
190 if (!item->util)
191 item->util = xcalloc(sizeof(struct branch_info), 1);
192 info = item->util;
193 if (type == REMOTE) {
e0cc81e6 194 if (info->remote_name)
7ecbbf87 195 warning("more than one %s", orig_key);
e0cc81e6 196 info->remote_name = xstrdup(value);
7ecbbf87 197 } else if (type == MERGE) {
211c8968 198 char *space = strchr(value, ' ');
72972eb3 199 value = abbrev_branch(value);
211c8968
JS
200 while (space) {
201 char *merge;
202 merge = xstrndup(value, space - value);
c455c87c 203 string_list_append(merge, &info->merge);
72972eb3 204 value = abbrev_branch(space + 1);
211c8968
JS
205 space = strchr(value, ' ');
206 }
c455c87c 207 string_list_append(xstrdup(value), &info->merge);
7ecbbf87
JS
208 } else
209 info->rebase = git_config_bool(orig_key, value);
211c8968
JS
210 }
211 return 0;
212}
213
214static void read_branches(void)
215{
216 if (branch_list.nr)
217 return;
ef90d6d4 218 git_config(config_read_branches, NULL);
211c8968
JS
219}
220
221struct ref_states {
222 struct remote *remote;
e61e0cc6 223 struct string_list new, stale, tracked, heads;
7ecbbf87 224 int queried;
211c8968
JS
225};
226
227static int handle_one_branch(const char *refname,
228 const unsigned char *sha1, int flags, void *cb_data)
229{
230 struct ref_states *states = cb_data;
231 struct refspec refspec;
232
233 memset(&refspec, 0, sizeof(refspec));
234 refspec.dst = (char *)refname;
235 if (!remote_find_tracking(states->remote, &refspec)) {
c455c87c 236 struct string_list_item *item;
72972eb3 237 const char *name = abbrev_branch(refspec.src);
740fdd27
JS
238 /* symbolic refs pointing nowhere were handled already */
239 if ((flags & REF_ISSYMREF) ||
3bd92563
JS
240 string_list_has_string(&states->tracked, name) ||
241 string_list_has_string(&states->new, name))
211c8968 242 return 0;
c455c87c 243 item = string_list_append(name, &states->stale);
211c8968
JS
244 item->util = xstrdup(refname);
245 }
246 return 0;
247}
248
e0cc81e6 249static int get_ref_states(const struct ref *remote_refs, struct ref_states *states)
211c8968
JS
250{
251 struct ref *fetch_map = NULL, **tail = &fetch_map;
e0cc81e6 252 struct ref *ref;
211c8968
JS
253 int i;
254
255 for (i = 0; i < states->remote->fetch_refspec_nr; i++)
e0cc81e6 256 if (get_fetch_map(remote_refs, states->remote->fetch + i, &tail, 1))
211c8968
JS
257 die("Could not get fetch map for refspec %s",
258 states->remote->fetch_refspec[i]);
259
c455c87c 260 states->new.strdup_strings = states->tracked.strdup_strings = 1;
211c8968 261 for (ref = fetch_map; ref; ref = ref->next) {
211c8968 262 unsigned char sha1[20];
211c8968 263 if (!ref->peer_ref || read_ref(ref->peer_ref->name, sha1))
7b9a5e27
JS
264 string_list_append(abbrev_branch(ref->name), &states->new);
265 else
266 string_list_append(abbrev_branch(ref->name), &states->tracked);
211c8968
JS
267 }
268 free_refs(fetch_map);
269
3bd92563
JS
270 sort_string_list(&states->new);
271 sort_string_list(&states->tracked);
211c8968 272 for_each_ref(handle_one_branch, states);
c455c87c 273 sort_string_list(&states->stale);
211c8968
JS
274
275 return 0;
276}
277
e61e0cc6
JS
278static int get_head_names(const struct ref *remote_refs, struct ref_states *states)
279{
280 struct ref *ref, *matches;
281 struct ref *fetch_map = NULL, **fetch_map_tail = &fetch_map;
282 struct refspec refspec;
283
284 refspec.force = 0;
285 refspec.pattern = 1;
286 refspec.src = refspec.dst = "refs/heads/";
287 states->heads.strdup_strings = 1;
288 get_fetch_map(remote_refs, &refspec, &fetch_map_tail, 0);
289 matches = guess_remote_head(find_ref_by_name(remote_refs, "HEAD"),
290 fetch_map, 1);
291 for(ref = matches; ref; ref = ref->next)
292 string_list_append(abbrev_branch(ref->name), &states->heads);
293
294 free_refs(fetch_map);
295 free_refs(matches);
296
297 return 0;
298}
299
7ad2458f
SP
300struct known_remote {
301 struct known_remote *next;
302 struct remote *remote;
303};
304
305struct known_remotes {
306 struct remote *to_delete;
307 struct known_remote *list;
308};
309
310static int add_known_remote(struct remote *remote, void *cb_data)
311{
312 struct known_remotes *all = cb_data;
313 struct known_remote *r;
314
315 if (!strcmp(all->to_delete->name, remote->name))
316 return 0;
317
318 r = xmalloc(sizeof(*r));
319 r->remote = remote;
320 r->next = all->list;
321 all->list = r;
322 return 0;
323}
324
211c8968 325struct branches_for_remote {
7ad2458f 326 struct remote *remote;
441adf0c 327 struct string_list *branches, *skipped;
7ad2458f 328 struct known_remotes *keep;
211c8968
JS
329};
330
331static int add_branch_for_removal(const char *refname,
332 const unsigned char *sha1, int flags, void *cb_data)
333{
334 struct branches_for_remote *branches = cb_data;
7ad2458f 335 struct refspec refspec;
c455c87c 336 struct string_list_item *item;
7ad2458f 337 struct known_remote *kr;
211c8968 338
7ad2458f
SP
339 memset(&refspec, 0, sizeof(refspec));
340 refspec.dst = (char *)refname;
341 if (remote_find_tracking(branches->remote, &refspec))
342 return 0;
343
344 /* don't delete a branch if another remote also uses it */
345 for (kr = branches->keep->list; kr; kr = kr->next) {
346 memset(&refspec, 0, sizeof(refspec));
347 refspec.dst = (char *)refname;
348 if (!remote_find_tracking(kr->remote, &refspec))
349 return 0;
350 }
3b9dcff5 351
441adf0c
JS
352 /* don't delete non-remote refs */
353 if (prefixcmp(refname, "refs/remotes")) {
354 /* advise user how to delete local branches */
355 if (!prefixcmp(refname, "refs/heads/"))
356 string_list_append(abbrev_branch(refname),
357 branches->skipped);
358 /* silently skip over other non-remote refs */
359 return 0;
360 }
361
7ad2458f
SP
362 /* make sure that symrefs are deleted */
363 if (flags & REF_ISSYMREF)
9db56f71 364 return unlink(git_path("%s", refname));
3b9dcff5 365
c455c87c 366 item = string_list_append(refname, branches->branches);
7ad2458f
SP
367 item->util = xmalloc(20);
368 hashcpy(item->util, sha1);
211c8968
JS
369
370 return 0;
371}
372
bf98421a
MV
373struct rename_info {
374 const char *old;
375 const char *new;
376 struct string_list *remote_branches;
377};
378
379static int read_remote_branches(const char *refname,
380 const unsigned char *sha1, int flags, void *cb_data)
381{
382 struct rename_info *rename = cb_data;
383 struct strbuf buf = STRBUF_INIT;
384 struct string_list_item *item;
385 int flag;
386 unsigned char orig_sha1[20];
387 const char *symref;
388
389 strbuf_addf(&buf, "refs/remotes/%s", rename->old);
390 if(!prefixcmp(refname, buf.buf)) {
391 item = string_list_append(xstrdup(refname), rename->remote_branches);
392 symref = resolve_ref(refname, orig_sha1, 1, &flag);
393 if (flag & REF_ISSYMREF)
394 item->util = xstrdup(symref);
395 else
396 item->util = NULL;
397 }
398
399 return 0;
400}
401
1dd1239a
MV
402static int migrate_file(struct remote *remote)
403{
404 struct strbuf buf = STRBUF_INIT;
405 int i;
406 char *path = NULL;
407
408 strbuf_addf(&buf, "remote.%s.url", remote->name);
409 for (i = 0; i < remote->url_nr; i++)
410 if (git_config_set_multivar(buf.buf, remote->url[i], "^$", 0))
411 return error("Could not append '%s' to '%s'",
412 remote->url[i], buf.buf);
413 strbuf_reset(&buf);
414 strbuf_addf(&buf, "remote.%s.push", remote->name);
415 for (i = 0; i < remote->push_refspec_nr; i++)
416 if (git_config_set_multivar(buf.buf, remote->push_refspec[i], "^$", 0))
417 return error("Could not append '%s' to '%s'",
418 remote->push_refspec[i], buf.buf);
419 strbuf_reset(&buf);
420 strbuf_addf(&buf, "remote.%s.fetch", remote->name);
421 for (i = 0; i < remote->fetch_refspec_nr; i++)
422 if (git_config_set_multivar(buf.buf, remote->fetch_refspec[i], "^$", 0))
423 return error("Could not append '%s' to '%s'",
424 remote->fetch_refspec[i], buf.buf);
425 if (remote->origin == REMOTE_REMOTES)
426 path = git_path("remotes/%s", remote->name);
427 else if (remote->origin == REMOTE_BRANCHES)
428 path = git_path("branches/%s", remote->name);
429 if (path && unlink(path))
430 warning("failed to remove '%s'", path);
431 return 0;
432}
433
bf98421a
MV
434static int mv(int argc, const char **argv)
435{
436 struct option options[] = {
437 OPT_END()
438 };
439 struct remote *oldremote, *newremote;
440 struct strbuf buf = STRBUF_INIT, buf2 = STRBUF_INIT, buf3 = STRBUF_INIT;
441 struct string_list remote_branches = { NULL, 0, 0, 0 };
442 struct rename_info rename;
443 int i;
444
445 if (argc != 3)
446 usage_with_options(builtin_remote_usage, options);
447
448 rename.old = argv[1];
449 rename.new = argv[2];
450 rename.remote_branches = &remote_branches;
451
452 oldremote = remote_get(rename.old);
453 if (!oldremote)
454 die("No such remote: %s", rename.old);
455
1dd1239a
MV
456 if (!strcmp(rename.old, rename.new) && oldremote->origin != REMOTE_CONFIG)
457 return migrate_file(oldremote);
458
bf98421a
MV
459 newremote = remote_get(rename.new);
460 if (newremote && (newremote->url_nr > 1 || newremote->fetch_refspec_nr))
461 die("remote %s already exists.", rename.new);
462
463 strbuf_addf(&buf, "refs/heads/test:refs/remotes/%s/test", rename.new);
464 if (!valid_fetch_refspec(buf.buf))
465 die("'%s' is not a valid remote name", rename.new);
466
467 strbuf_reset(&buf);
468 strbuf_addf(&buf, "remote.%s", rename.old);
469 strbuf_addf(&buf2, "remote.%s", rename.new);
470 if (git_config_rename_section(buf.buf, buf2.buf) < 1)
471 return error("Could not rename config section '%s' to '%s'",
472 buf.buf, buf2.buf);
473
474 strbuf_reset(&buf);
475 strbuf_addf(&buf, "remote.%s.fetch", rename.new);
476 if (git_config_set_multivar(buf.buf, NULL, NULL, 1))
477 return error("Could not remove config section '%s'", buf.buf);
478 for (i = 0; i < oldremote->fetch_refspec_nr; i++) {
479 char *ptr;
480
481 strbuf_reset(&buf2);
482 strbuf_addstr(&buf2, oldremote->fetch_refspec[i]);
483 ptr = strstr(buf2.buf, rename.old);
484 if (ptr)
485 strbuf_splice(&buf2, ptr-buf2.buf, strlen(rename.old),
486 rename.new, strlen(rename.new));
487 if (git_config_set_multivar(buf.buf, buf2.buf, "^$", 0))
488 return error("Could not append '%s'", buf.buf);
489 }
490
491 read_branches();
492 for (i = 0; i < branch_list.nr; i++) {
493 struct string_list_item *item = branch_list.items + i;
494 struct branch_info *info = item->util;
e0cc81e6 495 if (info->remote_name && !strcmp(info->remote_name, rename.old)) {
bf98421a
MV
496 strbuf_reset(&buf);
497 strbuf_addf(&buf, "branch.%s.remote", item->string);
498 if (git_config_set(buf.buf, rename.new)) {
499 return error("Could not set '%s'", buf.buf);
500 }
501 }
502 }
503
504 /*
505 * First remove symrefs, then rename the rest, finally create
506 * the new symrefs.
507 */
508 for_each_ref(read_remote_branches, &rename);
509 for (i = 0; i < remote_branches.nr; i++) {
510 struct string_list_item *item = remote_branches.items + i;
511 int flag = 0;
512 unsigned char sha1[20];
513 const char *symref;
514
515 symref = resolve_ref(item->string, sha1, 1, &flag);
516 if (!(flag & REF_ISSYMREF))
517 continue;
518 if (delete_ref(item->string, NULL, REF_NODEREF))
519 die("deleting '%s' failed", item->string);
520 }
521 for (i = 0; i < remote_branches.nr; i++) {
522 struct string_list_item *item = remote_branches.items + i;
523
524 if (item->util)
525 continue;
526 strbuf_reset(&buf);
527 strbuf_addstr(&buf, item->string);
528 strbuf_splice(&buf, strlen("refs/remotes/"), strlen(rename.old),
529 rename.new, strlen(rename.new));
530 strbuf_reset(&buf2);
531 strbuf_addf(&buf2, "remote: renamed %s to %s",
532 item->string, buf.buf);
533 if (rename_ref(item->string, buf.buf, buf2.buf))
534 die("renaming '%s' failed", item->string);
535 }
536 for (i = 0; i < remote_branches.nr; i++) {
537 struct string_list_item *item = remote_branches.items + i;
538
539 if (!item->util)
540 continue;
541 strbuf_reset(&buf);
542 strbuf_addstr(&buf, item->string);
543 strbuf_splice(&buf, strlen("refs/remotes/"), strlen(rename.old),
544 rename.new, strlen(rename.new));
545 strbuf_reset(&buf2);
546 strbuf_addstr(&buf2, item->util);
547 strbuf_splice(&buf2, strlen("refs/remotes/"), strlen(rename.old),
548 rename.new, strlen(rename.new));
549 strbuf_reset(&buf3);
550 strbuf_addf(&buf3, "remote: renamed %s to %s",
551 item->string, buf.buf);
552 if (create_symref(buf.buf, buf2.buf, buf3.buf))
553 die("creating '%s' failed", buf.buf);
554 }
555 return 0;
556}
557
c455c87c 558static int remove_branches(struct string_list *branches)
211c8968
JS
559{
560 int i, result = 0;
561 for (i = 0; i < branches->nr; i++) {
c455c87c
JS
562 struct string_list_item *item = branches->items + i;
563 const char *refname = item->string;
211c8968
JS
564 unsigned char *sha1 = item->util;
565
eca35a25 566 if (delete_ref(refname, sha1, 0))
211c8968
JS
567 result |= error("Could not remove branch %s", refname);
568 }
569 return result;
570}
571
572static int rm(int argc, const char **argv)
573{
574 struct option options[] = {
575 OPT_END()
576 };
577 struct remote *remote;
f285a2d7 578 struct strbuf buf = STRBUF_INIT;
7ad2458f 579 struct known_remotes known_remotes = { NULL, NULL };
c455c87c 580 struct string_list branches = { NULL, 0, 0, 1 };
441adf0c
JS
581 struct string_list skipped = { NULL, 0, 0, 1 };
582 struct branches_for_remote cb_data = {
583 NULL, &branches, &skipped, &known_remotes
584 };
e02f1762 585 int i, result;
211c8968
JS
586
587 if (argc != 2)
588 usage_with_options(builtin_remote_usage, options);
589
590 remote = remote_get(argv[1]);
591 if (!remote)
592 die("No such remote: %s", argv[1]);
593
7ad2458f
SP
594 known_remotes.to_delete = remote;
595 for_each_remote(add_known_remote, &known_remotes);
596
211c8968
JS
597 strbuf_addf(&buf, "remote.%s", remote->name);
598 if (git_config_rename_section(buf.buf, NULL) < 1)
599 return error("Could not remove config section '%s'", buf.buf);
600
601 read_branches();
602 for (i = 0; i < branch_list.nr; i++) {
c455c87c 603 struct string_list_item *item = branch_list.items + i;
211c8968 604 struct branch_info *info = item->util;
e0cc81e6 605 if (info->remote_name && !strcmp(info->remote_name, remote->name)) {
211c8968
JS
606 const char *keys[] = { "remote", "merge", NULL }, **k;
607 for (k = keys; *k; k++) {
608 strbuf_reset(&buf);
609 strbuf_addf(&buf, "branch.%s.%s",
c455c87c 610 item->string, *k);
211c8968
JS
611 if (git_config_set(buf.buf, NULL)) {
612 strbuf_release(&buf);
613 return -1;
614 }
615 }
616 }
617 }
618
619 /*
620 * We cannot just pass a function to for_each_ref() which deletes
621 * the branches one by one, since for_each_ref() relies on cached
622 * refs, which are invalidated when deleting a branch.
623 */
7ad2458f 624 cb_data.remote = remote;
e02f1762 625 result = for_each_ref(add_branch_for_removal, &cb_data);
211c8968
JS
626 strbuf_release(&buf);
627
e02f1762
JS
628 if (!result)
629 result = remove_branches(&branches);
c455c87c 630 string_list_clear(&branches, 1);
211c8968 631
441adf0c
JS
632 if (skipped.nr) {
633 fprintf(stderr, skipped.nr == 1 ?
634 "Note: A non-remote branch was not removed; "
635 "to delete it, use:\n" :
636 "Note: Non-remote branches were not removed; "
637 "to delete them, use:\n");
638 for (i = 0; i < skipped.nr; i++)
639 fprintf(stderr, " git branch -d %s\n",
640 skipped.items[i].string);
641 }
642 string_list_clear(&skipped, 0);
643
e02f1762 644 return result;
211c8968
JS
645}
646
88733235
JS
647static void free_remote_ref_states(struct ref_states *states)
648{
649 string_list_clear(&states->new, 0);
650 string_list_clear(&states->stale, 0);
651 string_list_clear(&states->tracked, 0);
e61e0cc6 652 string_list_clear(&states->heads, 0);
88733235
JS
653}
654
cca7c97e
JS
655static int append_ref_to_tracked_list(const char *refname,
656 const unsigned char *sha1, int flags, void *cb_data)
657{
658 struct ref_states *states = cb_data;
659 struct refspec refspec;
660
3bd92563
JS
661 if (flags & REF_ISSYMREF)
662 return 0;
663
cca7c97e
JS
664 memset(&refspec, 0, sizeof(refspec));
665 refspec.dst = (char *)refname;
666 if (!remote_find_tracking(states->remote, &refspec))
667 string_list_append(abbrev_branch(refspec.src), &states->tracked);
668
669 return 0;
670}
671
67a7e2d0
OM
672static int get_remote_ref_states(const char *name,
673 struct ref_states *states,
674 int query)
675{
676 struct transport *transport;
e0cc81e6 677 const struct ref *remote_refs;
67a7e2d0
OM
678
679 states->remote = remote_get(name);
680 if (!states->remote)
681 return error("No such remote: %s", name);
682
683 read_branches();
684
685 if (query) {
686 transport = transport_get(NULL, states->remote->url_nr > 0 ?
687 states->remote->url[0] : NULL);
e0cc81e6 688 remote_refs = transport_get_remote_refs(transport);
67a7e2d0
OM
689 transport_disconnect(transport);
690
7ecbbf87 691 states->queried = 1;
e61e0cc6
JS
692 if (query & GET_REF_STATES)
693 get_ref_states(remote_refs, states);
694 if (query & GET_HEAD_NAMES)
695 get_head_names(remote_refs, states);
3bd92563 696 } else {
cca7c97e 697 for_each_ref(append_ref_to_tracked_list, states);
3bd92563
JS
698 sort_string_list(&states->tracked);
699 }
e7d5a97d
OM
700
701 return 0;
702}
703
7ecbbf87
JS
704struct show_info {
705 struct string_list *list;
706 struct ref_states *states;
707 int width;
708 int any_rebase;
709};
710
711int add_remote_to_show_info(struct string_list_item *item, void *cb_data)
712{
713 struct show_info *info = cb_data;
714 int n = strlen(item->string);
715 if (n > info->width)
716 info->width = n;
717 string_list_insert(item->string, info->list);
718 return 0;
719}
720
721int show_remote_info_item(struct string_list_item *item, void *cb_data)
722{
723 struct show_info *info = cb_data;
724 struct ref_states *states = info->states;
725 const char *name = item->string;
726
727 if (states->queried) {
728 const char *fmt = "%s";
729 const char *arg = "";
730 if (string_list_has_string(&states->new, name)) {
731 fmt = " new (next fetch will store in remotes/%s)";
732 arg = states->remote->name;
733 } else if (string_list_has_string(&states->tracked, name))
734 arg = " tracked";
735 else if (string_list_has_string(&states->stale, name))
736 arg = " stale (use 'git remote prune' to remove)";
737 else
738 arg = " ???";
739 printf(" %-*s", info->width, name);
740 printf(fmt, arg);
741 printf("\n");
742 } else
743 printf(" %s\n", name);
744
745 return 0;
746}
747
748int add_local_to_show_info(struct string_list_item *branch_item, void *cb_data)
749{
750 struct show_info *show_info = cb_data;
751 struct ref_states *states = show_info->states;
752 struct branch_info *branch_info = branch_item->util;
753 struct string_list_item *item;
754 int n;
755
756 if (!branch_info->merge.nr || !branch_info->remote_name ||
757 strcmp(states->remote->name, branch_info->remote_name))
758 return 0;
759 if ((n = strlen(branch_item->string)) > show_info->width)
760 show_info->width = n;
761 if (branch_info->rebase)
762 show_info->any_rebase = 1;
763
764 item = string_list_insert(branch_item->string, show_info->list);
765 item->util = branch_info;
766
767 return 0;
768}
769
770int show_local_info_item(struct string_list_item *item, void *cb_data)
771{
772 struct show_info *show_info = cb_data;
773 struct branch_info *branch_info = item->util;
774 struct string_list *merge = &branch_info->merge;
775 const char *also;
776 int i;
777
778 if (branch_info->rebase && branch_info->merge.nr > 1) {
779 error("invalid branch.%s.merge; cannot rebase onto > 1 branch",
780 item->string);
781 return 0;
782 }
783
784 printf(" %-*s ", show_info->width, item->string);
785 if (branch_info->rebase) {
786 printf("rebases onto remote %s\n", merge->items[0].string);
787 return 0;
788 } else if (show_info->any_rebase) {
789 printf(" merges with remote %s\n", merge->items[0].string);
790 also = " and with remote";
791 } else {
792 printf("merges with remote %s\n", merge->items[0].string);
793 also = " and with remote";
794 }
795 for (i = 1; i < merge->nr; i++)
796 printf(" %-*s %s %s\n", show_info->width, "", also,
797 merge->items[i].string);
798
799 return 0;
800}
801
67a7e2d0 802static int show(int argc, const char **argv)
211c8968 803{
e61e0cc6 804 int no_query = 0, result = 0, query_flag = 0;
211c8968
JS
805 struct option options[] = {
806 OPT_GROUP("show specific options"),
0ecfcb3b 807 OPT_BOOLEAN('n', NULL, &no_query, "do not query remotes"),
211c8968
JS
808 OPT_END()
809 };
810 struct ref_states states;
7ecbbf87
JS
811 struct string_list info_list = { NULL, 0, 0, 0 };
812 struct show_info info;
211c8968
JS
813
814 argc = parse_options(argc, argv, options, builtin_remote_usage, 0);
815
67a7e2d0
OM
816 if (argc < 1)
817 return show_all();
211c8968 818
e61e0cc6
JS
819 if (!no_query)
820 query_flag = (GET_REF_STATES | GET_HEAD_NAMES);
821
211c8968 822 memset(&states, 0, sizeof(states));
7ecbbf87
JS
823 memset(&info, 0, sizeof(info));
824 info.states = &states;
825 info.list = &info_list;
211c8968 826 for (; argc; argc--, argv++) {
0ecfcb3b 827 int i;
211c8968 828
e61e0cc6 829 get_remote_ref_states(*argv, &states, query_flag);
211c8968
JS
830
831 printf("* remote %s\n URL: %s\n", *argv,
832 states.remote->url_nr > 0 ?
833 states.remote->url[0] : "(no URL)");
e61e0cc6
JS
834 if (no_query)
835 printf(" HEAD branch: (not queried)\n");
836 else if (!states.heads.nr)
837 printf(" HEAD branch: (unknown)\n");
838 else if (states.heads.nr == 1)
839 printf(" HEAD branch: %s\n", states.heads.items[0].string);
840 else {
841 printf(" HEAD branch (remote HEAD is ambiguous,"
842 " may be one of the following):\n");
843 for (i = 0; i < states.heads.nr; i++)
844 printf(" %s\n", states.heads.items[i].string);
845 }
211c8968 846
7ecbbf87
JS
847 /* remote branch info */
848 info.width = 0;
849 for_each_string_list(add_remote_to_show_info, &states.new, &info);
850 for_each_string_list(add_remote_to_show_info, &states.tracked, &info);
851 for_each_string_list(add_remote_to_show_info, &states.stale, &info);
852 if (info.list->nr)
853 printf(" Remote branch%s:%s\n",
854 info.list->nr > 1 ? "es" : "",
855 no_query ? " (status not queried)" : "");
856 for_each_string_list(show_remote_info_item, info.list, &info);
857 string_list_clear(info.list, 0);
858
859 /* git pull info */
860 info.width = 0;
861 info.any_rebase = 0;
862 for_each_string_list(add_local_to_show_info, &branch_list, &info);
863 if (info.list->nr)
864 printf(" Local branch%s configured for 'git pull':\n",
865 info.list->nr > 1 ? "es" : "");
866 for_each_string_list(show_local_info_item, info.list, &info);
867 string_list_clear(info.list, 0);
868
869 /* git push info */
211c8968 870 if (states.remote->push_refspec_nr) {
20244ea2 871 printf(" Local branch%s pushed with 'git push'\n",
211c8968
JS
872 states.remote->push_refspec_nr > 1 ?
873 "es" : "");
874 for (i = 0; i < states.remote->push_refspec_nr; i++) {
875 struct refspec *spec = states.remote->push + i;
20244ea2
JS
876 printf(" %s%s%s%s\n",
877 spec->force ? "+" : "",
72972eb3
JH
878 abbrev_branch(spec->src),
879 spec->dst ? ":" : "",
880 spec->dst ? abbrev_branch(spec->dst) : "");
211c8968
JS
881 }
882 }
67a7e2d0 883
88733235 884 free_remote_ref_states(&states);
67a7e2d0
OM
885 }
886
887 return result;
888}
889
bc14fac8
JS
890static int set_head(int argc, const char **argv)
891{
892 int i, opt_a = 0, opt_d = 0, result = 0;
893 struct strbuf buf = STRBUF_INIT, buf2 = STRBUF_INIT;
894 char *head_name = NULL;
895
896 struct option options[] = {
897 OPT_GROUP("set-head specific options"),
898 OPT_BOOLEAN('a', "auto", &opt_a,
899 "set refs/remotes/<name>/HEAD according to remote"),
900 OPT_BOOLEAN('d', "delete", &opt_d,
901 "delete refs/remotes/<name>/HEAD"),
902 OPT_END()
903 };
904 argc = parse_options(argc, argv, options, builtin_remote_usage, 0);
905 if (argc)
906 strbuf_addf(&buf, "refs/remotes/%s/HEAD", argv[0]);
907
908 if (!opt_a && !opt_d && argc == 2) {
909 head_name = xstrdup(argv[1]);
910 } else if (opt_a && !opt_d && argc == 1) {
911 struct ref_states states;
912 memset(&states, 0, sizeof(states));
913 get_remote_ref_states(argv[0], &states, GET_HEAD_NAMES);
914 if (!states.heads.nr)
915 result |= error("Cannot determine remote HEAD");
916 else if (states.heads.nr > 1) {
917 result |= error("Multiple remote HEAD branches. "
918 "Please choose one explicitly with:");
919 for (i = 0; i < states.heads.nr; i++)
920 fprintf(stderr, " git remote set-head %s %s\n",
921 argv[0], states.heads.items[i].string);
922 } else
923 head_name = xstrdup(states.heads.items[0].string);
924 free_remote_ref_states(&states);
925 } else if (opt_d && !opt_a && argc == 1) {
926 if (delete_ref(buf.buf, NULL, REF_NODEREF))
927 result |= error("Could not delete %s", buf.buf);
928 } else
929 usage_with_options(builtin_remote_usage, options);
930
931 if (head_name) {
932 unsigned char sha1[20];
933 strbuf_addf(&buf2, "refs/remotes/%s/%s", argv[0], head_name);
934 /* make sure it's valid */
935 if (!resolve_ref(buf2.buf, sha1, 1, NULL))
936 result |= error("Not a valid ref: %s", buf2.buf);
937 else if (create_symref(buf.buf, buf2.buf, "remote set-head"))
938 result |= error("Could not setup %s", buf.buf);
939 if (opt_a)
940 printf("%s/HEAD set to %s\n", argv[0], head_name);
941 free(head_name);
942 }
943
944 strbuf_release(&buf);
945 strbuf_release(&buf2);
946 return result;
947}
948
67a7e2d0
OM
949static int prune(int argc, const char **argv)
950{
8d767927 951 int dry_run = 0, result = 0;
67a7e2d0
OM
952 struct option options[] = {
953 OPT_GROUP("prune specific options"),
8d767927 954 OPT__DRY_RUN(&dry_run),
67a7e2d0
OM
955 OPT_END()
956 };
957 struct ref_states states;
f8948e2f 958 const char *dangling_msg;
67a7e2d0
OM
959
960 argc = parse_options(argc, argv, options, builtin_remote_usage, 0);
961
962 if (argc < 1)
963 usage_with_options(builtin_remote_usage, options);
964
f8948e2f
JH
965 dangling_msg = (dry_run
966 ? " %s will become dangling!\n"
967 : " %s has become dangling!\n");
968
67a7e2d0
OM
969 memset(&states, 0, sizeof(states));
970 for (; argc; argc--, argv++) {
971 int i;
972
e61e0cc6 973 get_remote_ref_states(*argv, &states, GET_REF_STATES);
8d767927 974
8b7d4e73
JH
975 if (states.stale.nr) {
976 printf("Pruning %s\n", *argv);
8d767927
OM
977 printf("URL: %s\n",
978 states.remote->url_nr
979 ? states.remote->url[0]
980 : "(no URL)");
8b7d4e73 981 }
67a7e2d0
OM
982
983 for (i = 0; i < states.stale.nr; i++) {
984 const char *refname = states.stale.items[i].util;
8d767927
OM
985
986 if (!dry_run)
eca35a25 987 result |= delete_ref(refname, NULL, 0);
8d767927
OM
988
989 printf(" * [%s] %s\n", dry_run ? "would prune" : "pruned",
72972eb3 990 abbrev_ref(refname, "refs/remotes/"));
f8948e2f 991 warn_dangling_symref(dangling_msg, refname);
67a7e2d0
OM
992 }
993
88733235 994 free_remote_ref_states(&states);
211c8968
JS
995 }
996
997 return result;
998}
999
84521ed6 1000static int get_one_remote_for_update(struct remote *remote, void *priv)
211c8968 1001{
c455c87c 1002 struct string_list *list = priv;
211c8968 1003 if (!remote->skip_default_update)
83b76736 1004 string_list_append(remote->name, list);
84521ed6
JS
1005 return 0;
1006}
1007
1008struct remote_group {
1009 const char *name;
c455c87c 1010 struct string_list *list;
84521ed6
JS
1011} remote_group;
1012
ef90d6d4 1013static int get_remote_group(const char *key, const char *value, void *cb)
84521ed6
JS
1014{
1015 if (!prefixcmp(key, "remotes.") &&
1016 !strcmp(key + 8, remote_group.name)) {
1017 /* split list by white space */
1018 int space = strcspn(value, " \t\n");
1019 while (*value) {
1020 if (space > 1)
c455c87c 1021 string_list_append(xstrndup(value, space),
84521ed6
JS
1022 remote_group.list);
1023 value += space + (value[space] != '\0');
1024 space = strcspn(value, " \t\n");
1025 }
1026 }
1027
211c8968
JS
1028 return 0;
1029}
1030
1031static int update(int argc, const char **argv)
1032{
84521ed6 1033 int i, result = 0;
c455c87c 1034 struct string_list list = { NULL, 0, 0, 0 };
84521ed6 1035 static const char *default_argv[] = { NULL, "default", NULL };
211c8968 1036
84521ed6
JS
1037 if (argc < 2) {
1038 argc = 2;
1039 argv = default_argv;
1040 }
211c8968 1041
84521ed6
JS
1042 remote_group.list = &list;
1043 for (i = 1; i < argc; i++) {
1044 remote_group.name = argv[i];
ef90d6d4 1045 result = git_config(get_remote_group, NULL);
84521ed6
JS
1046 }
1047
1048 if (!result && !list.nr && argc == 2 && !strcmp(argv[1], "default"))
1049 result = for_each_remote(get_one_remote_for_update, &list);
1050
1051 for (i = 0; i < list.nr; i++)
c455c87c 1052 result |= fetch_remote(list.items[i].string);
84521ed6
JS
1053
1054 /* all names were strdup()ed or strndup()ed */
c455c87c
JS
1055 list.strdup_strings = 1;
1056 string_list_clear(&list, 0);
84521ed6
JS
1057
1058 return result;
211c8968
JS
1059}
1060
1061static int get_one_entry(struct remote *remote, void *priv)
1062{
c455c87c 1063 struct string_list *list = priv;
211c8968 1064
7d20e218
MG
1065 if (remote->url_nr > 0) {
1066 int i;
1067
1068 for (i = 0; i < remote->url_nr; i++)
1069 string_list_append(remote->name, list)->util = (void *)remote->url[i];
1070 } else
1071 string_list_append(remote->name, list)->util = NULL;
211c8968
JS
1072
1073 return 0;
1074}
1075
1076static int show_all(void)
1077{
c455c87c 1078 struct string_list list = { NULL, 0, 0 };
211c8968
JS
1079 int result = for_each_remote(get_one_entry, &list);
1080
1081 if (!result) {
1082 int i;
1083
c455c87c 1084 sort_string_list(&list);
211c8968 1085 for (i = 0; i < list.nr; i++) {
c455c87c 1086 struct string_list_item *item = list.items + i;
7d20e218
MG
1087 if (verbose)
1088 printf("%s\t%s\n", item->string,
1089 item->util ? (const char *)item->util : "");
1090 else {
1091 if (i && !strcmp((item - 1)->string, item->string))
1092 continue;
1093 printf("%s\n", item->string);
1094 }
211c8968
JS
1095 }
1096 }
1097 return result;
1098}
1099
1100int cmd_remote(int argc, const char **argv, const char *prefix)
1101{
1102 struct option options[] = {
1103 OPT__VERBOSE(&verbose),
1104 OPT_END()
1105 };
1106 int result;
1107
1108 argc = parse_options(argc, argv, options, builtin_remote_usage,
1109 PARSE_OPT_STOP_AT_NON_OPTION);
1110
1111 if (argc < 1)
1112 result = show_all();
1113 else if (!strcmp(argv[0], "add"))
1114 result = add(argc, argv);
bf98421a
MV
1115 else if (!strcmp(argv[0], "rename"))
1116 result = mv(argc, argv);
211c8968
JS
1117 else if (!strcmp(argv[0], "rm"))
1118 result = rm(argc, argv);
bc14fac8
JS
1119 else if (!strcmp(argv[0], "set-head"))
1120 result = set_head(argc, argv);
211c8968 1121 else if (!strcmp(argv[0], "show"))
67a7e2d0 1122 result = show(argc, argv);
211c8968 1123 else if (!strcmp(argv[0], "prune"))
67a7e2d0 1124 result = prune(argc, argv);
211c8968
JS
1125 else if (!strcmp(argv[0], "update"))
1126 result = update(argc, argv);
1127 else {
1128 error("Unknown subcommand: %s", argv[0]);
1129 usage_with_options(builtin_remote_usage, options);
1130 }
1131
1132 return result ? 1 : 0;
1133}