static struct path_list branch_list;
-static int config_read_branches(const char *key, const char *value)
+static int config_read_branches(const char *key, const char *value, void *cb)
{
if (!prefixcmp(key, "branch.")) {
char *name;
{
if (branch_list.nr)
return;
- git_config(config_read_branches);
+ git_config(config_read_branches, NULL);
sort_path_list(&branch_list);
}
struct ref_states {
struct remote *remote;
- struct strbuf remote_prefix;
struct path_list new, stale, tracked;
};
}
free_refs(fetch_map);
- strbuf_addf(&states->remote_prefix,
- "refs/remotes/%s/", states->remote->name);
for_each_ref(handle_one_branch, states);
sort_path_list(&states->stale);
return 0;
}
+struct known_remote {
+ struct known_remote *next;
+ struct remote *remote;
+};
+
+struct known_remotes {
+ struct remote *to_delete;
+ struct known_remote *list;
+};
+
+static int add_known_remote(struct remote *remote, void *cb_data)
+{
+ struct known_remotes *all = cb_data;
+ struct known_remote *r;
+
+ if (!strcmp(all->to_delete->name, remote->name))
+ return 0;
+
+ r = xmalloc(sizeof(*r));
+ r->remote = remote;
+ r->next = all->list;
+ all->list = r;
+ return 0;
+}
+
struct branches_for_remote {
- const char *prefix;
+ struct remote *remote;
struct path_list *branches;
+ struct known_remotes *keep;
};
static int add_branch_for_removal(const char *refname,
const unsigned char *sha1, int flags, void *cb_data)
{
struct branches_for_remote *branches = cb_data;
+ struct refspec refspec;
+ struct path_list_item *item;
+ struct known_remote *kr;
- if (!prefixcmp(refname, branches->prefix)) {
- struct path_list_item *item;
+ memset(&refspec, 0, sizeof(refspec));
+ refspec.dst = (char *)refname;
+ if (remote_find_tracking(branches->remote, &refspec))
+ return 0;
+
+ /* don't delete a branch if another remote also uses it */
+ for (kr = branches->keep->list; kr; kr = kr->next) {
+ memset(&refspec, 0, sizeof(refspec));
+ refspec.dst = (char *)refname;
+ if (!remote_find_tracking(kr->remote, &refspec))
+ return 0;
+ }
- /* make sure that symrefs are deleted */
- if (flags & REF_ISSYMREF)
- return unlink(git_path(refname));
+ /* make sure that symrefs are deleted */
+ if (flags & REF_ISSYMREF)
+ return unlink(git_path(refname));
- item = path_list_append(refname, branches->branches);
- item->util = xmalloc(20);
- hashcpy(item->util, sha1);
- }
+ item = path_list_append(refname, branches->branches);
+ item->util = xmalloc(20);
+ hashcpy(item->util, sha1);
return 0;
}
};
struct remote *remote;
struct strbuf buf;
+ struct known_remotes known_remotes = { NULL, NULL };
struct path_list branches = { NULL, 0, 0, 1 };
- struct branches_for_remote cb_data = { NULL, &branches };
+ struct branches_for_remote cb_data = { NULL, &branches, &known_remotes };
int i;
if (argc != 2)
if (!remote)
die("No such remote: %s", argv[1]);
+ known_remotes.to_delete = remote;
+ for_each_remote(add_known_remote, &known_remotes);
+
strbuf_init(&buf, 0);
strbuf_addf(&buf, "remote.%s", remote->name);
if (git_config_rename_section(buf.buf, NULL) < 1)
* the branches one by one, since for_each_ref() relies on cached
* refs, which are invalidated when deleting a branch.
*/
- strbuf_reset(&buf);
- strbuf_addf(&buf, "refs/remotes/%s/", remote->name);
- cb_data.prefix = buf.buf;
+ cb_data.remote = remote;
i = for_each_ref(add_branch_for_removal, &cb_data);
strbuf_release(&buf);
states.remote->name);
if (prune) {
- struct strbuf buf;
- int prefix_len;
-
- strbuf_init(&buf, 0);
- if (states.remote->fetch_refspec_nr == 1 &&
- states.remote->fetch->pattern &&
- !strcmp(states.remote->fetch->src,
- states.remote->fetch->dst))
- /* handle --mirror remote */
- strbuf_addstr(&buf, "refs/heads/");
- else
- strbuf_addf(&buf, "refs/remotes/%s/", *argv);
- prefix_len = buf.len;
-
for (i = 0; i < states.stale.nr; i++) {
- strbuf_setlen(&buf, prefix_len);
- strbuf_addstr(&buf, states.stale.items[i].path);
- result |= delete_ref(buf.buf, NULL);
+ const char *refname = states.stale.items[i].util;
+ result |= delete_ref(refname, NULL);
}
-
- strbuf_release(&buf);
goto cleanup_states;
}
struct path_list *list;
} remote_group;
-static int get_remote_group(const char *key, const char *value)
+static int get_remote_group(const char *key, const char *value, void *cb)
{
if (!prefixcmp(key, "remotes.") &&
!strcmp(key + 8, remote_group.name)) {
remote_group.list = &list;
for (i = 1; i < argc; i++) {
remote_group.name = argv[i];
- result = git_config(get_remote_group);
+ result = git_config(get_remote_group, NULL);
}
if (!result && !list.nr && argc == 2 && !strcmp(argv[1], "default"))