builtin/commit.c: fix a typo in the comment
[gitweb.git] / remote.c
index 6e5c1a876f5044ffdea71531695ce04305b072f1..16eb39e06e77f081abedab31ba30eae36834c84a 100644 (file)
--- a/remote.c
+++ b/remote.c
@@ -255,8 +255,9 @@ static void read_remotes_file(struct remote *remote)
 
        if (!f)
                return;
+       remote->configured_in_repo = 1;
        remote->origin = REMOTE_REMOTES;
-       while (strbuf_getline(&buf, f, '\n') != EOF) {
+       while (strbuf_getline(&buf, f) != EOF) {
                const char *v;
 
                strbuf_rtrim(&buf);
@@ -281,7 +282,7 @@ static void read_branches_file(struct remote *remote)
        if (!f)
                return;
 
-       strbuf_getline(&buf, f, '\n');
+       strbuf_getline_lf(&buf, f);
        fclose(f);
        strbuf_trim(&buf);
        if (!buf.len) {
@@ -289,6 +290,7 @@ static void read_branches_file(struct remote *remote)
                return;
        }
 
+       remote->configured_in_repo = 1;
        remote->origin = REMOTE_BRANCHES;
 
        /*
@@ -318,93 +320,90 @@ static void read_branches_file(struct remote *remote)
 static int handle_config(const char *key, const char *value, void *cb)
 {
        const char *name;
+       int namelen;
        const char *subkey;
        struct remote *remote;
        struct branch *branch;
-       if (starts_with(key, "branch.")) {
-               name = key + 7;
-               subkey = strrchr(name, '.');
-               if (!subkey)
+       if (parse_config_key(key, "branch", &name, &namelen, &subkey) >= 0) {
+               if (!name)
                        return 0;
-               branch = make_branch(name, subkey - name);
-               if (!strcmp(subkey, ".remote")) {
+               branch = make_branch(name, namelen);
+               if (!strcmp(subkey, "remote")) {
                        return git_config_string(&branch->remote_name, key, value);
-               } else if (!strcmp(subkey, ".pushremote")) {
+               } else if (!strcmp(subkey, "pushremote")) {
                        return git_config_string(&branch->pushremote_name, key, value);
-               } else if (!strcmp(subkey, ".merge")) {
+               } else if (!strcmp(subkey, "merge")) {
                        if (!value)
                                return config_error_nonbool(key);
                        add_merge(branch, xstrdup(value));
                }
                return 0;
        }
-       if (starts_with(key, "url.")) {
+       if (parse_config_key(key, "url", &name, &namelen, &subkey) >= 0) {
                struct rewrite *rewrite;
-               name = key + 4;
-               subkey = strrchr(name, '.');
-               if (!subkey)
+               if (!name)
                        return 0;
-               if (!strcmp(subkey, ".insteadof")) {
-                       rewrite = make_rewrite(&rewrites, name, subkey - name);
+               if (!strcmp(subkey, "insteadof")) {
+                       rewrite = make_rewrite(&rewrites, name, namelen);
                        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);
+               } else if (!strcmp(subkey, "pushinsteadof")) {
+                       rewrite = make_rewrite(&rewrites_push, name, namelen);
                        if (!value)
                                return config_error_nonbool(key);
                        add_instead_of(rewrite, xstrdup(value));
                }
        }
 
-       if (!starts_with(key,  "remote."))
+       if (parse_config_key(key, "remote", &name, &namelen, &subkey) < 0)
                return 0;
-       name = key + 7;
 
        /* Handle remote.* variables */
-       if (!strcmp(name, "pushdefault"))
+       if (!name && !strcmp(subkey, "pushdefault"))
                return git_config_string(&pushremote_name, key, value);
 
+       if (!name)
+               return 0;
        /* Handle remote.<name>.* variables */
        if (*name == '/') {
                warning("Config remote shorthand cannot begin with '/': %s",
                        name);
                return 0;
        }
-       subkey = strrchr(name, '.');
-       if (!subkey)
-               return 0;
-       remote = make_remote(name, subkey - name);
+       remote = make_remote(name, namelen);
        remote->origin = REMOTE_CONFIG;
-       if (!strcmp(subkey, ".mirror"))
+       if (current_config_scope() == CONFIG_SCOPE_REPO)
+               remote->configured_in_repo = 1;
+       if (!strcmp(subkey, "mirror"))
                remote->mirror = git_config_bool(key, value);
-       else if (!strcmp(subkey, ".skipdefaultupdate"))
+       else if (!strcmp(subkey, "skipdefaultupdate"))
                remote->skip_default_update = git_config_bool(key, value);
-       else if (!strcmp(subkey, ".skipfetchall"))
+       else if (!strcmp(subkey, "skipfetchall"))
                remote->skip_default_update = git_config_bool(key, value);
-       else if (!strcmp(subkey, ".prune"))
+       else if (!strcmp(subkey, "prune"))
                remote->prune = git_config_bool(key, value);
-       else if (!strcmp(subkey, ".url")) {
+       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")) {
+       } 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")) {
+       } else if (!strcmp(subkey, "push")) {
                const char *v;
                if (git_config_string(&v, key, value))
                        return -1;
                add_push_refspec(remote, v);
-       } else if (!strcmp(subkey, ".fetch")) {
+       } else if (!strcmp(subkey, "fetch")) {
                const char *v;
                if (git_config_string(&v, key, value))
                        return -1;
                add_fetch_refspec(remote, v);
-       } else if (!strcmp(subkey, ".receivepack")) {
+       } else if (!strcmp(subkey, "receivepack")) {
                const char *v;
                if (git_config_string(&v, key, value))
                        return -1;
@@ -412,7 +411,7 @@ static int handle_config(const char *key, const char *value, void *cb)
                        remote->receivepack = v;
                else
                        error("more than one receivepack given, using the first");
-       } else if (!strcmp(subkey, ".uploadpack")) {
+       } else if (!strcmp(subkey, "uploadpack")) {
                const char *v;
                if (git_config_string(&v, key, value))
                        return -1;
@@ -420,15 +419,18 @@ static int handle_config(const char *key, const char *value, void *cb)
                        remote->uploadpack = v;
                else
                        error("more than one uploadpack given, using the first");
-       } else if (!strcmp(subkey, ".tagopt")) {
+       } else if (!strcmp(subkey, "tagopt")) {
                if (!strcmp(value, "--no-tags"))
                        remote->fetch_tags = -1;
                else if (!strcmp(value, "--tags"))
                        remote->fetch_tags = 2;
-       } else if (!strcmp(subkey, ".proxy")) {
+       } else if (!strcmp(subkey, "proxy")) {
                return git_config_string((const char **)&remote->http_proxy,
                                         key, value);
-       } else if (!strcmp(subkey, ".vcs")) {
+       } else if (!strcmp(subkey, "proxyauthmethod")) {
+               return git_config_string((const char **)&remote->http_proxy_authmethod,
+                                        key, value);
+       } else if (!strcmp(subkey, "vcs")) {
                return git_config_string(&remote->foreign_vcs, key, value);
        }
        return 0;
@@ -457,7 +459,6 @@ static void read_config(void)
 {
        static int loaded;
        struct object_id oid;
-       const char *head_ref;
        int flag;
 
        if (loaded)
@@ -465,35 +466,17 @@ static void read_config(void)
        loaded = 1;
 
        current_branch = NULL;
-       head_ref = resolve_ref_unsafe("HEAD", 0, oid.hash, &flag);
-       if (head_ref && (flag & REF_ISSYMREF) &&
-           skip_prefix(head_ref, "refs/heads/", &head_ref)) {
-               current_branch = make_branch(head_ref, 0);
+       if (startup_info->have_repository) {
+               const char *head_ref = resolve_ref_unsafe("HEAD", 0, oid.hash, &flag);
+               if (head_ref && (flag & REF_ISSYMREF) &&
+                   skip_prefix(head_ref, "refs/heads/", &head_ref)) {
+                       current_branch = make_branch(head_ref, 0);
+               }
        }
        git_config(handle_config, NULL);
        alias_all_urls();
 }
 
-/*
- * This function frees a refspec array.
- * Warning: code paths should be checked to ensure that the src
- *          and dst pointers are always freeable pointers as well
- *          as the refspec pointer itself.
- */
-static void free_refspecs(struct refspec *refspec, int nr_refspec)
-{
-       int i;
-
-       if (!refspec)
-               return;
-
-       for (i = 0; i < nr_refspec; i++) {
-               free(refspec[i].src);
-               free(refspec[i].dst);
-       }
-       free(refspec);
-}
-
 static struct refspec *parse_refspec_internal(int nr_refspec, const char **refspec, int fetch, int verify)
 {
        int i;
@@ -607,7 +590,7 @@ static struct refspec *parse_refspec_internal(int nr_refspec, const char **refsp
                 * since it is only possible to reach this point from within
                 * the for loop above.
                 */
-               free_refspecs(rs, i+1);
+               free_refspec(i+1, rs);
                return NULL;
        }
        die("Invalid refspec '%s'", refspec[i]);
@@ -618,7 +601,7 @@ int valid_fetch_refspec(const char *fetch_refspec_str)
        struct refspec *refspec;
 
        refspec = parse_refspec_internal(1, &fetch_refspec_str, 1, 1);
-       free_refspecs(refspec, 1);
+       free_refspec(1, refspec);
        return !!refspec;
 }
 
@@ -627,7 +610,7 @@ struct refspec *parse_fetch_refspec(int nr_refspec, const char **refspec)
        return parse_refspec_internal(nr_refspec, refspec, 1, 0);
 }
 
-static struct refspec *parse_push_refspec(int nr_refspec, const char **refspec)
+struct refspec *parse_push_refspec(int nr_refspec, const char **refspec)
 {
        return parse_refspec_internal(nr_refspec, refspec, 0, 0);
 }
@@ -635,6 +618,10 @@ static struct refspec *parse_push_refspec(int nr_refspec, const char **refspec)
 void free_refspec(int nr_refspec, struct refspec *refspec)
 {
        int i;
+
+       if (!refspec)
+               return;
+
        for (i = 0; i < nr_refspec; i++) {
                free(refspec[i].src);
                free(refspec[i].dst);
@@ -646,7 +633,12 @@ static int valid_remote_nick(const char *name)
 {
        if (!name[0] || is_dot_or_dotdot(name))
                return 0;
-       return !strchr(name, '/'); /* no slash */
+
+       /* remote nicknames cannot contain slashes */
+       while (*name)
+               if (is_dir_sep(*name++))
+                       return 0;
+       return 1;
 }
 
 const char *remote_for_branch(struct branch *branch, int *explicit)
@@ -690,7 +682,7 @@ static struct remote *remote_get_1(const char *name,
                name = get_default(current_branch, &name_given);
 
        ret = make_remote(name, 0);
-       if (valid_remote_nick(name)) {
+       if (valid_remote_nick(name) && have_git_dir()) {
                if (!valid_remote(ret))
                        read_remotes_file(ret);
                if (!valid_remote(ret))
@@ -715,18 +707,13 @@ struct remote *pushremote_get(const char *name)
        return remote_get_1(name, pushremote_for_branch);
 }
 
-int remote_is_configured(const char *name)
+int remote_is_configured(struct remote *remote, int in_repo)
 {
-       struct remotes_hash_key lookup;
-       struct hashmap_entry lookup_entry;
-       read_config();
-
-       init_remotes_hash();
-       lookup.str = name;
-       lookup.len = strlen(name);
-       hashmap_entry_init(&lookup_entry, memhash(name, lookup.len));
-
-       return hashmap_get(&remotes_hash, &lookup_entry, &lookup) != NULL;
+       if (!remote)
+               return 0;
+       if (in_repo)
+               return remote->configured_in_repo;
+       return !!remote->origin;
 }
 
 int for_each_remote(each_remote_fn fn, void *priv)
@@ -1193,9 +1180,10 @@ static int match_explicit(struct ref *src, struct ref *dst,
                else if (is_null_oid(&matched_src->new_oid))
                        error("unable to delete '%s': remote ref does not exist",
                              dst_value);
-               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
+                       free(dst_guess);
+               } else
                        error("unable to push to unqualified destination: %s\n"
                              "The destination refspec neither matches an "
                              "existing ref on the remote nor\n"
@@ -1554,8 +1542,7 @@ void set_ref_status_for_push(struct ref *remote_refs, int send_mirror,
                 * branch.
                 */
                if (ref->expect_old_sha1) {
-                       if (ref->expect_old_no_trackback ||
-                           oidcmp(&ref->old_oid, &ref->old_oid_expect))
+                       if (oidcmp(&ref->old_oid, &ref->old_oid_expect))
                                reject_reason = REF_STATUS_REJECT_STALE;
                        else
                                /* If the ref isn't stale then force the update. */
@@ -1670,7 +1657,7 @@ int branch_merge_matches(struct branch *branch,
        return refname_match(branch->merge[i]->src, refname);
 }
 
-__attribute((format (printf,2,3)))
+__attribute__((format (printf,2,3)))
 static const char *error_buf(struct strbuf *err, const char *fmt, ...)
 {
        if (err) {
@@ -1727,9 +1714,6 @@ static const char *branch_get_push_1(struct branch *branch, struct strbuf *err)
 {
        struct remote *remote;
 
-       if (!branch)
-               return error_buf(err, _("HEAD does not point to a branch"));
-
        remote = remote_get(pushremote_for_branch(branch, NULL));
        if (!remote)
                return error_buf(err,
@@ -1789,6 +1773,9 @@ static const char *branch_get_push_1(struct branch *branch, struct strbuf *err)
 
 const char *branch_get_push(struct branch *branch, struct strbuf *err)
 {
+       if (!branch)
+               return error_buf(err, _("HEAD does not point to a branch"));
+
        if (!branch->push_tracking_ref)
                branch->push_tracking_ref = branch_get_push_1(branch, err);
        return branch->push_tracking_ref;
@@ -2084,7 +2071,7 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb)
                        _("Your branch is based on '%s', but the upstream is gone.\n"),
                        base);
                if (advice_status_hints)
-                       strbuf_addf(sb,
+                       strbuf_addstr(sb,
                                _("  (use \"git branch --unset-upstream\" to fixup)\n"));
        } else if (!ours && !theirs) {
                strbuf_addf(sb,
@@ -2097,7 +2084,7 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb)
                           ours),
                        base, ours);
                if (advice_status_hints)
-                       strbuf_addf(sb,
+                       strbuf_addstr(sb,
                                _("  (use \"git push\" to publish your local commits)\n"));
        } else if (!ours) {
                strbuf_addf(sb,
@@ -2108,7 +2095,7 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb)
                           theirs),
                        base, theirs);
                if (advice_status_hints)
-                       strbuf_addf(sb,
+                       strbuf_addstr(sb,
                                _("  (use \"git pull\" to update your local branch)\n"));
        } else {
                strbuf_addf(sb,
@@ -2118,10 +2105,10 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb)
                           "Your branch and '%s' have diverged,\n"
                               "and have %d and %d different commits each, "
                               "respectively.\n",
-                          theirs),
+                          ours + theirs),
                        base, ours, theirs);
                if (advice_status_hints)
-                       strbuf_addf(sb,
+                       strbuf_addstr(sb,
                                _("  (use \"git pull\" to merge the remote branch into yours)\n"));
        }
        free(base);
@@ -2282,7 +2269,7 @@ static struct push_cas *add_cas_entry(struct push_cas_option *cas,
        return entry;
 }
 
-int parse_push_cas_option(struct push_cas_option *cas, const char *arg, int unset)
+static int parse_push_cas_option(struct push_cas_option *cas, const char *arg, int unset)
 {
        const char *colon;
        struct push_cas *entry;
@@ -2304,6 +2291,8 @@ int parse_push_cas_option(struct push_cas_option *cas, const char *arg, int unse
        entry = add_cas_entry(cas, arg, colon - arg);
        if (!*colon)
                entry->use_tracking = 1;
+       else if (!colon[1])
+               hashclr(entry->expect);
        else if (get_sha1(colon + 1, entry->expect))
                return error("cannot parse expected object name '%s'", colon + 1);
        return 0;
@@ -2353,7 +2342,7 @@ static void apply_cas(struct push_cas_option *cas,
                if (!entry->use_tracking)
                        hashcpy(ref->old_oid_expect.hash, cas->entry[i].expect);
                else if (remote_tracking(remote, ref->name, &ref->old_oid_expect))
-                       ref->expect_old_no_trackback = 1;
+                       oidclr(&ref->old_oid_expect);
                return;
        }
 
@@ -2363,7 +2352,7 @@ static void apply_cas(struct push_cas_option *cas,
 
        ref->expect_old_sha1 = 1;
        if (remote_tracking(remote, ref->name, &ref->old_oid_expect))
-               ref->expect_old_no_trackback = 1;
+               oidclr(&ref->old_oid_expect);
 }
 
 void apply_push_cas(struct push_cas_option *cas,