@matheusbsbs / matheus-bagliano / commits / f8948e2fbc
Fork 0

remote prune: warn dangling symrefs

If you prune from the remote "frotz" that deleted the ref your tracking branch remotes/frotz/HEAD points at, the symbolic ref will become dangling. We used to detect this as an error condition and issued a message every time refs are enumerated. This stops the error message, but moves the warning to "remote prune". Signed-off-by: Junio C Hamano <gitster@pobox.com>

Junio C Hamano committed Feb 8, 2009 at 23:27 UTC f8948e2fbc7fbd63e81006408965e3e89380bfaa
4 files changed +86 -18
builtin-remote.c
+6
@@ -756,12 +756,17 @@ static int prune(int argc, const char **argv)
756 OPT_END()
757 };
758 struct ref_states states;
759 + const char *dangling_msg;
760
761 argc = parse_options(argc, argv, options, builtin_remote_usage, 0);
762
763 if (argc < 1)
764 usage_with_options(builtin_remote_usage, options);
765
766 + dangling_msg = (dry_run
767 + ? " %s will become dangling!\n"
768 + : " %s has become dangling!\n");
769 +
770 memset(&states, 0, sizeof(states));
771 for (; argc; argc--, argv++) {
772 int i;
@@ -784,6 +789,7 @@ static int prune(int argc, const char **argv)
789
790 printf(" * [%s] %s\n", dry_run ? "would prune" : "pruned",
791 abbrev_ref(refname, "refs/remotes/"));
792 + warn_dangling_symref(dangling_msg, refname);
793 }
794
795 /* NEEDSWORK: free remote */
refs.c
+54 -18
@@ -275,10 +275,8 @@ static struct ref_list *get_ref_dir(const char *base, struct ref_list *list)
275 list = get_ref_dir(ref, list);
276 continue;
277 }
278 - if (!resolve_ref(ref, sha1, 1, &flag)) {
279 - error("%s points nowhere!", ref);
280 - continue;
281 - }
278 + if (!resolve_ref(ref, sha1, 1, &flag))
279 + hashclr(sha1);
280 list = add_ref(ref, sha1, flag, list, NULL);
281 }
282 free(ref);
@@ -287,6 +285,35 @@ static struct ref_list *get_ref_dir(const char *base, struct ref_list *list)
285 return sort_ref_list(list);
286 }
287
288 +struct warn_if_dangling_data {
289 + const char *refname;
290 + const char *msg_fmt;
291 +};
292 +
293 +static int warn_if_dangling_symref(const char *refname, const unsigned char *sha1,
294 + int flags, void *cb_data)
295 +{
296 + struct warn_if_dangling_data *d = cb_data;
297 + const char *resolves_to;
298 + unsigned char junk[20];
299 +
300 + if (!(flags & REF_ISSYMREF))
301 + return 0;
302 +
303 + resolves_to = resolve_ref(refname, junk, 0, NULL);
304 + if (!resolves_to || strcmp(resolves_to, d->refname))
305 + return 0;
306 +
307 + printf(d->msg_fmt, refname);
308 + return 0;
309 +}
310 +
311 +void warn_dangling_symref(const char *msg_fmt, const char *refname)
312 +{
313 + struct warn_if_dangling_data data = { refname, msg_fmt };
314 + for_each_rawref(warn_if_dangling_symref, &data);
315 +}
316 +
317 static struct ref_list *get_loose_refs(void)
318 {
319 if (!cached_refs.did_loose) {
@@ -498,16 +525,19 @@ int read_ref(const char *ref, unsigned char *sha1)
525 return -1;
526 }
527
528 +#define DO_FOR_EACH_INCLUDE_BROKEN 01
529 static int do_one_ref(const char *base, each_ref_fn fn, int trim,
502 - void *cb_data, struct ref_list *entry)
530 + int flags, void *cb_data, struct ref_list *entry)
531 {
532 if (strncmp(base, entry->name, trim))
533 return 0;
506 - if (is_null_sha1(entry->sha1))
507 - return 0;
508 - if (!has_sha1_file(entry->sha1)) {
509 - error("%s does not point to a valid object!", entry->name);
510 - return 0;
534 + if (!(flags & DO_FOR_EACH_INCLUDE_BROKEN)) {
535 + if (is_null_sha1(entry->sha1))
536 + return 0;
537 + if (!has_sha1_file(entry->sha1)) {
538 + error("%s does not point to a valid object!", entry->name);
539 + return 0;
540 + }
541 }
542 current_ref = entry;
543 return fn(entry->name + trim, entry->sha1, entry->flag, cb_data);
@@ -561,7 +591,7 @@ fallback:
591 }
592
593 static int do_for_each_ref(const char *base, each_ref_fn fn, int trim,
564 - void *cb_data)
594 + int flags, void *cb_data)
595 {
596 int retval = 0;
597 struct ref_list *packed = get_packed_refs();
@@ -570,7 +600,7 @@ static int do_for_each_ref(const char *base, each_ref_fn fn, int trim,
600 struct ref_list *extra;
601
602 for (extra = extra_refs; extra; extra = extra->next)
573 - retval = do_one_ref(base, fn, trim, cb_data, extra);
603 + retval = do_one_ref(base, fn, trim, flags, cb_data, extra);
604
605 while (packed && loose) {
606 struct ref_list *entry;
@@ -586,13 +616,13 @@ static int do_for_each_ref(const char *base, each_ref_fn fn, int trim,
616 entry = packed;
617 packed = packed->next;
618 }
589 - retval = do_one_ref(base, fn, trim, cb_data, entry);
619 + retval = do_one_ref(base, fn, trim, flags, cb_data, entry);
620 if (retval)
621 goto end_each;
622 }
623
624 for (packed = packed ? packed : loose; packed; packed = packed->next) {
595 - retval = do_one_ref(base, fn, trim, cb_data, packed);
625 + retval = do_one_ref(base, fn, trim, flags, cb_data, packed);
626 if (retval)
627 goto end_each;
628 }
@@ -614,22 +644,28 @@ int head_ref(each_ref_fn fn, void *cb_data)
644
645 int for_each_ref(each_ref_fn fn, void *cb_data)
646 {
617 - return do_for_each_ref("refs/", fn, 0, cb_data);
647 + return do_for_each_ref("refs/", fn, 0, 0, cb_data);
648 }
649
650 int for_each_tag_ref(each_ref_fn fn, void *cb_data)
651 {
622 - return do_for_each_ref("refs/tags/", fn, 10, cb_data);
652 + return do_for_each_ref("refs/tags/", fn, 10, 0, cb_data);
653 }
654
655 int for_each_branch_ref(each_ref_fn fn, void *cb_data)
656 {
627 - return do_for_each_ref("refs/heads/", fn, 11, cb_data);
657 + return do_for_each_ref("refs/heads/", fn, 11, 0, cb_data);
658 }
659
660 int for_each_remote_ref(each_ref_fn fn, void *cb_data)
661 {
632 - return do_for_each_ref("refs/remotes/", fn, 13, cb_data);
662 + return do_for_each_ref("refs/remotes/", fn, 13, 0, cb_data);
663 +}
664 +
665 +int for_each_rawref(each_ref_fn fn, void *cb_data)
666 +{
667 + return do_for_each_ref("refs/", fn, 0,
668 + DO_FOR_EACH_INCLUDE_BROKEN, cb_data);
669 }
670
671 /*
refs.h
+5
@@ -24,6 +24,11 @@ extern int for_each_tag_ref(each_ref_fn, void *);
24 extern int for_each_branch_ref(each_ref_fn, void *);
25 extern int for_each_remote_ref(each_ref_fn, void *);
26
27 +/* can be used to learn about broken ref and symref */
28 +extern int for_each_rawref(each_ref_fn, void *);
29 +
30 +extern void warn_dangling_symref(const char *msg_fmt, const char *refname);
31 +
32 /*
33 * Extra refs will be listed by for_each_ref() before any actual refs
34 * for the duration of this process or until clear_extra_refs() is
t/t5505-remote.sh
+21
@@ -402,4 +402,25 @@ test_expect_success 'migrate a remote from named file in $GIT_DIR/branches' '
402 test "$(git config remote.origin.fetch)" = "refs/heads/master:refs/heads/origin")
403 '
404
405 +test_expect_success 'remote prune to cause a dangling symref' '
406 + git clone one seven &&
407 + (
408 + cd one &&
409 + git checkout side2 &&
410 + git branch -D master
411 + ) &&
412 + (
413 + cd seven &&
414 + git remote prune origin
415 + ) 2>err &&
416 + grep "has become dangling" err &&
417 +
418 + : And the dangling symref will not cause other annoying errors
419 + (
420 + cd seven &&
421 + git branch -a
422 + ) 2>err &&
423 + ! grep "points nowhere" err
424 +'
425 +
426 test_done