#include "revision.h"
#include "dir.h"
#include "tag.h"
+#include "string-list.h"
static struct refspec s_tag_refspec = {
0,
int instead_of_nr;
int instead_of_alloc;
};
+struct rewrites {
+ struct rewrite **rewrite;
+ int rewrite_alloc;
+ int rewrite_nr;
+};
static struct remote **remotes;
static int remotes_alloc;
static const char *default_remote_name;
static int explicit_default_remote_name;
-static struct rewrite **rewrite;
-static int rewrite_alloc;
-static int rewrite_nr;
+static struct rewrites rewrites;
+static struct rewrites rewrites_push;
#define BUF_SIZE (2048)
static char buffer[BUF_SIZE];
-static const char *alias_url(const char *url)
+static const char *alias_url(const char *url, struct rewrites *r)
{
int i, j;
char *ret;
longest = NULL;
longest_i = -1;
- for (i = 0; i < rewrite_nr; i++) {
- if (!rewrite[i])
+ for (i = 0; i < r->rewrite_nr; i++) {
+ if (!r->rewrite[i])
continue;
- for (j = 0; j < rewrite[i]->instead_of_nr; j++) {
- if (!prefixcmp(url, rewrite[i]->instead_of[j].s) &&
+ for (j = 0; j < r->rewrite[i]->instead_of_nr; j++) {
+ if (!prefixcmp(url, r->rewrite[i]->instead_of[j].s) &&
(!longest ||
- longest->len < rewrite[i]->instead_of[j].len)) {
- longest = &(rewrite[i]->instead_of[j]);
+ longest->len < r->rewrite[i]->instead_of[j].len)) {
+ longest = &(r->rewrite[i]->instead_of[j]);
longest_i = i;
}
}
if (!longest)
return url;
- ret = xmalloc(rewrite[longest_i]->baselen +
+ ret = xmalloc(r->rewrite[longest_i]->baselen +
(strlen(url) - longest->len) + 1);
- strcpy(ret, rewrite[longest_i]->base);
- strcpy(ret + rewrite[longest_i]->baselen, url + longest->len);
+ strcpy(ret, r->rewrite[longest_i]->base);
+ strcpy(ret + r->rewrite[longest_i]->baselen, url + longest->len);
return ret;
}
remote->url[remote->url_nr++] = url;
}
+static void add_pushurl(struct remote *remote, const char *pushurl)
+{
+ ALLOC_GROW(remote->pushurl, remote->pushurl_nr + 1, remote->pushurl_alloc);
+ remote->pushurl[remote->pushurl_nr++] = pushurl;
+}
+
+static void add_pushurl_alias(struct remote *remote, const char *url)
+{
+ const char *pushurl = alias_url(url, &rewrites_push);
+ if (pushurl != url)
+ add_pushurl(remote, pushurl);
+}
+
static void add_url_alias(struct remote *remote, const char *url)
{
- add_url(remote, alias_url(url));
+ add_url(remote, alias_url(url, &rewrites));
+ add_pushurl_alias(remote, url);
}
static struct remote *make_remote(const char *name, int len)
return ret;
}
-static struct rewrite *make_rewrite(const char *base, int len)
+static struct rewrite *make_rewrite(struct rewrites *r, const char *base, int len)
{
struct rewrite *ret;
int i;
- for (i = 0; i < rewrite_nr; i++) {
+ for (i = 0; i < r->rewrite_nr; i++) {
if (len
- ? (len == rewrite[i]->baselen &&
- !strncmp(base, rewrite[i]->base, len))
- : !strcmp(base, rewrite[i]->base))
- return rewrite[i];
+ ? (len == r->rewrite[i]->baselen &&
+ !strncmp(base, r->rewrite[i]->base, len))
+ : !strcmp(base, r->rewrite[i]->base))
+ return r->rewrite[i];
}
- ALLOC_GROW(rewrite, rewrite_nr + 1, rewrite_alloc);
+ ALLOC_GROW(r->rewrite, r->rewrite_nr + 1, r->rewrite_alloc);
ret = xcalloc(1, sizeof(struct rewrite));
- rewrite[rewrite_nr++] = ret;
+ r->rewrite[r->rewrite_nr++] = ret;
if (len) {
ret->base = xstrndup(base, len);
ret->baselen = len;
strbuf_addstr(&branch, "HEAD:");
}
add_url_alias(remote, p);
- add_fetch_refspec(remote, strbuf_detach(&branch, 0));
+ add_fetch_refspec(remote, strbuf_detach(&branch, NULL));
/*
* Cogito compatible push: push current HEAD to remote #branch
* (master if missing)
strbuf_addf(&branch, ":refs/heads/%s", frag);
else
strbuf_addstr(&branch, ":refs/heads/master");
- add_push_refspec(remote, strbuf_detach(&branch, 0));
+ add_push_refspec(remote, strbuf_detach(&branch, NULL));
remote->fetch_tags = 1; /* always auto-follow */
}
subkey = strrchr(name, '.');
if (!subkey)
return 0;
- rewrite = make_rewrite(name, subkey - name);
if (!strcmp(subkey, ".insteadof")) {
+ rewrite = make_rewrite(&rewrites, name, subkey - name);
+ if (!value)
+ return config_error_nonbool(key);
+ add_instead_of(rewrite, xstrdup(value));
+ } else if (!strcmp(subkey, ".pushinsteadof")) {
+ rewrite = make_rewrite(&rewrites_push, name, subkey - name);
if (!value)
return config_error_nonbool(key);
add_instead_of(rewrite, xstrdup(value));
remote->mirror = git_config_bool(key, value);
else if (!strcmp(subkey, ".skipdefaultupdate"))
remote->skip_default_update = git_config_bool(key, value);
-
+ else if (!strcmp(subkey, ".skipfetchall"))
+ remote->skip_default_update = git_config_bool(key, value);
else if (!strcmp(subkey, ".url")) {
const char *v;
if (git_config_string(&v, key, value))
return -1;
add_url(remote, v);
+ } else if (!strcmp(subkey, ".pushurl")) {
+ const char *v;
+ if (git_config_string(&v, key, value))
+ return -1;
+ add_pushurl(remote, v);
} else if (!strcmp(subkey, ".push")) {
const char *v;
if (git_config_string(&v, key, value))
{
int i, j;
for (i = 0; i < remotes_nr; i++) {
+ int add_pushurl_aliases;
if (!remotes[i])
continue;
+ for (j = 0; j < remotes[i]->pushurl_nr; j++) {
+ remotes[i]->pushurl[j] = alias_url(remotes[i]->pushurl[j], &rewrites);
+ }
+ add_pushurl_aliases = remotes[i]->pushurl_nr == 0;
for (j = 0; j < remotes[i]->url_nr; j++) {
- remotes[i]->url[j] = alias_url(remotes[i]->url[j]);
+ if (add_pushurl_aliases)
+ add_pushurl_alias(remotes[i], remotes[i]->url[j]);
+ remotes[i]->url[j] = alias_url(remotes[i]->url[j], &rewrites);
}
}
}
void ref_remove_duplicates(struct ref *ref_map)
{
- struct ref **posn;
- struct ref *next;
- for (; ref_map; ref_map = ref_map->next) {
+ struct string_list refs = { NULL, 0, 0, 0 };
+ struct string_list_item *item = NULL;
+ struct ref *prev = NULL, *next = NULL;
+ for (; ref_map; prev = ref_map, ref_map = next) {
+ next = ref_map->next;
if (!ref_map->peer_ref)
continue;
- posn = &ref_map->next;
- while (*posn) {
- if ((*posn)->peer_ref &&
- !strcmp((*posn)->peer_ref->name,
- ref_map->peer_ref->name)) {
- if (strcmp((*posn)->name, ref_map->name))
- die("%s tracks both %s and %s",
- ref_map->peer_ref->name,
- (*posn)->name, ref_map->name);
- next = (*posn)->next;
- free((*posn)->peer_ref);
- free(*posn);
- *posn = next;
- } else {
- posn = &(*posn)->next;
- }
+
+ item = string_list_lookup(ref_map->peer_ref->name, &refs);
+ if (item) {
+ if (strcmp(((struct ref *)item->util)->name,
+ ref_map->name))
+ die("%s tracks both %s and %s",
+ ref_map->peer_ref->name,
+ ((struct ref *)item->util)->name,
+ ref_map->name);
+ prev->next = ref_map->next;
+ free(ref_map->peer_ref);
+ free(ref_map);
+ ref_map = prev; /* skip this; we freed it */
+ continue;
}
+
+ item = string_list_insert(ref_map->peer_ref->name, &refs);
+ item->util = ref_map;
}
+ string_list_clear(&refs, 0);
}
int remote_has_url(struct remote *remote, const char *url)
case 0:
if (!memcmp(dst_value, "refs/", 5))
matched_dst = make_linked_ref(dst_value, dst_tail);
- else if((dst_guess = guess_ref(dst_value, matched_src)))
+ else if ((dst_guess = guess_ref(dst_value, matched_src)))
matched_dst = make_linked_ref(dst_guess, dst_tail);
else
error("unable to push to unqualified destination: %s\n"
int send_all = flags & MATCH_REFS_ALL;
int send_mirror = flags & MATCH_REFS_MIRROR;
int errs;
- static const char *default_refspec[] = { ":", 0 };
+ static const char *default_refspec[] = { ":", NULL };
struct ref **dst_tail = tail_ref(dst);
if (!nr_refspec) {
static struct ref *get_local_ref(const char *name)
{
- if (!name)
+ if (!name || name[0] == '\0')
return NULL;
if (!prefixcmp(name, "refs/"))
return list;
}
+
+struct stale_heads_info {
+ struct remote *remote;
+ struct string_list *ref_names;
+ struct ref **stale_refs_tail;
+};
+
+static int get_stale_heads_cb(const char *refname,
+ const unsigned char *sha1, int flags, void *cb_data)
+{
+ struct stale_heads_info *info = cb_data;
+ struct refspec refspec;
+ memset(&refspec, 0, sizeof(refspec));
+ refspec.dst = (char *)refname;
+ if (!remote_find_tracking(info->remote, &refspec)) {
+ if (!((flags & REF_ISSYMREF) ||
+ string_list_has_string(info->ref_names, refspec.src))) {
+ struct ref *ref = make_linked_ref(refname, &info->stale_refs_tail);
+ hashcpy(ref->new_sha1, sha1);
+ }
+ }
+ return 0;
+}
+
+struct ref *get_stale_heads(struct remote *remote, struct ref *fetch_map)
+{
+ struct ref *ref, *stale_refs = NULL;
+ struct string_list ref_names = { NULL, 0, 0, 0 };
+ struct stale_heads_info info;
+ info.remote = remote;
+ info.ref_names = &ref_names;
+ info.stale_refs_tail = &stale_refs;
+ for (ref = fetch_map; ref; ref = ref->next)
+ string_list_append(ref->name, &ref_names);
+ sort_string_list(&ref_names);
+ for_each_ref(get_stale_heads_cb, &info);
+ string_list_clear(&ref_names, 0);
+ return stale_refs;
+}