]> Pileus Git - ~andy/git/commitdiff
Merge branch 'tm/fetch-prune'
authorJunio C Hamano <gitster@pobox.com>
Fri, 10 Jan 2014 18:32:50 +0000 (10:32 -0800)
committerJunio C Hamano <gitster@pobox.com>
Fri, 10 Jan 2014 18:32:50 +0000 (10:32 -0800)
Fetching 'frotz' branch with "git fetch", while having
'frotz/nitfol' remote-tracking branch from an earlier fetch, would
error out, primarily because the command has not been told to
remove anything on our side. In such a case, "git fetch --prune"
can be used to remove 'frotz/nitfol' to make room to fetch and
store 'frotz' remote-tracking branch.

* tm/fetch-prune:
  fetch --prune: Run prune before fetching
  fetch --prune: always print header url

builtin/fetch.c
t/t5510-fetch.sh

index 1e7d617f4671c43f704afe912edac5f5dc6dc316..09825c84d731014e075a6f77791f0681b7c4efb0 100644 (file)
@@ -44,6 +44,7 @@ static struct transport *gtransport;
 static struct transport *gsecondary;
 static const char *submodule_prefix = "";
 static const char *recurse_submodules_default;
+static int shown_url = 0;
 
 static int option_parse_recurse_submodules(const struct option *opt,
                                   const char *arg, int unset)
@@ -535,7 +536,7 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
 {
        FILE *fp;
        struct commit *commit;
-       int url_len, i, shown_url = 0, rc = 0;
+       int url_len, i, rc = 0;
        struct strbuf note = STRBUF_INIT;
        const char *what, *kind;
        struct ref *rm;
@@ -708,17 +709,36 @@ static int fetch_refs(struct transport *transport, struct ref *ref_map)
        return ret;
 }
 
-static int prune_refs(struct refspec *refs, int ref_count, struct ref *ref_map)
+static int prune_refs(struct refspec *refs, int ref_count, struct ref *ref_map,
+               const char *raw_url)
 {
-       int result = 0;
+       int url_len, i, result = 0;
        struct ref *ref, *stale_refs = get_stale_heads(refs, ref_count, ref_map);
+       char *url;
        const char *dangling_msg = dry_run
                ? _("   (%s will become dangling)")
                : _("   (%s has become dangling)");
 
+       if (raw_url)
+               url = transport_anonymize_url(raw_url);
+       else
+               url = xstrdup("foreign");
+
+       url_len = strlen(url);
+       for (i = url_len - 1; url[i] == '/' && 0 <= i; i--)
+               ;
+
+       url_len = i + 1;
+       if (4 < i && !strncmp(".git", url + i - 3, 4))
+               url_len = i - 3;
+
        for (ref = stale_refs; ref; ref = ref->next) {
                if (!dry_run)
                        result |= delete_ref(ref->name, NULL, 0);
+               if (verbosity >= 0 && !shown_url) {
+                       fprintf(stderr, _("From %.*s\n"), url_len, url);
+                       shown_url = 1;
+               }
                if (verbosity >= 0) {
                        fprintf(stderr, " x %-*s %-*s -> %s\n",
                                TRANSPORT_SUMMARY(_("[deleted]")),
@@ -726,6 +746,7 @@ static int prune_refs(struct refspec *refs, int ref_count, struct ref *ref_map)
                        warn_dangling_symref(stderr, dangling_msg, ref->name);
                }
        }
+       free(url);
        free_refs(stale_refs);
        return result;
 }
@@ -842,11 +863,6 @@ static int do_fetch(struct transport *transport,
 
        if (tags == TAGS_DEFAULT && autotags)
                transport_set_option(transport, TRANS_OPT_FOLLOWTAGS, "1");
-       if (fetch_refs(transport, ref_map)) {
-               free_refs(ref_map);
-               retcode = 1;
-               goto cleanup;
-       }
        if (prune) {
                /*
                 * We only prune based on refspecs specified
@@ -854,13 +870,19 @@ static int do_fetch(struct transport *transport,
                 * don't care whether --tags was specified.
                 */
                if (ref_count) {
-                       prune_refs(refs, ref_count, ref_map);
+                       prune_refs(refs, ref_count, ref_map, transport->url);
                } else {
                        prune_refs(transport->remote->fetch,
                                   transport->remote->fetch_refspec_nr,
-                                  ref_map);
+                                  ref_map,
+                                  transport->url);
                }
        }
+       if (fetch_refs(transport, ref_map)) {
+               free_refs(ref_map);
+               retcode = 1;
+               goto cleanup;
+       }
        free_refs(ref_map);
 
        /* if neither --no-tags nor --tags was specified, do automated tag
index 5d4581dac84f0688389ca96ba139518336b78dba..12674ac0980fdafd60037bdff8009bb02a6da14a 100755 (executable)
@@ -614,4 +614,30 @@ test_expect_success 'all boundary commits are excluded' '
        test_bundle_object_count .git/objects/pack/pack-${pack##pack    }.pack 3
 '
 
+test_expect_success 'fetch --prune prints the remotes url' '
+       git branch goodbye &&
+       git clone . only-prunes &&
+       git branch -D goodbye &&
+       (
+               cd only-prunes &&
+               git fetch --prune origin 2>&1 | head -n1 >../actual
+       ) &&
+       echo "From ${D}/." >expect &&
+       test_cmp expect actual
+'
+
+test_expect_success 'branchname D/F conflict resolved by --prune' '
+       git branch dir/file &&
+       git clone . prune-df-conflict &&
+       git branch -D dir/file &&
+       git branch dir &&
+       (
+               cd prune-df-conflict &&
+               git fetch --prune &&
+               git rev-parse origin/dir >../actual
+       ) &&
+       git rev-parse dir >expect &&
+       test_cmp expect actual
+'
+
 test_done