Imported Upstream version 2.28.0
[platform/upstream/git.git] / remote.c
index 9cc3b07..bc46413 100644 (file)
--- a/remote.c
+++ b/remote.c
@@ -111,14 +111,16 @@ struct remotes_hash_key {
 };
 
 static int remotes_hash_cmp(const void *unused_cmp_data,
-                           const void *entry,
-                           const void *entry_or_key,
+                           const struct hashmap_entry *eptr,
+                           const struct hashmap_entry *entry_or_key,
                            const void *keydata)
 {
-       const struct remote *a = entry;
-       const struct remote *b = entry_or_key;
+       const struct remote *a, *b;
        const struct remotes_hash_key *key = keydata;
 
+       a = container_of(eptr, const struct remote, ent);
+       b = container_of(entry_or_key, const struct remote, ent);
+
        if (key)
                return strncmp(a->name, key->str, key->len) || a->name[key->len];
        else
@@ -135,7 +137,7 @@ static struct remote *make_remote(const char *name, int len)
 {
        struct remote *ret, *replaced;
        struct remotes_hash_key lookup;
-       struct hashmap_entry lookup_entry;
+       struct hashmap_entry lookup_entry, *e;
 
        if (!len)
                len = strlen(name);
@@ -145,8 +147,9 @@ static struct remote *make_remote(const char *name, int len)
        lookup.len = len;
        hashmap_entry_init(&lookup_entry, memhash(name, len));
 
-       if ((ret = hashmap_get(&remotes_hash, &lookup_entry, &lookup)) != NULL)
-               return ret;
+       e = hashmap_get(&remotes_hash, &lookup_entry, &lookup);
+       if (e)
+               return container_of(e, struct remote, ent);
 
        ret = xcalloc(1, sizeof(struct remote));
        ret->prune = -1;  /* unspecified */
@@ -158,8 +161,8 @@ static struct remote *make_remote(const char *name, int len)
        ALLOC_GROW(remotes, remotes_nr + 1, remotes_alloc);
        remotes[remotes_nr++] = ret;
 
-       hashmap_entry_init(ret, lookup_entry.hash);
-       replaced = hashmap_put(&remotes_hash, ret);
+       hashmap_entry_init(&ret->ent, lookup_entry.hash);
+       replaced = hashmap_put_entry(&remotes_hash, ret, ent);
        assert(replaced == NULL);  /* no previous entry overwritten */
        return ret;
 }
@@ -171,54 +174,43 @@ static void add_merge(struct branch *branch, const char *name)
        branch->merge_name[branch->merge_nr++] = name;
 }
 
-static struct branch *make_branch(const char *name, int len)
+static struct branch *make_branch(const char *name, size_t len)
 {
        struct branch *ret;
        int i;
 
        for (i = 0; i < branches_nr; i++) {
-               if (len ? (!strncmp(name, branches[i]->name, len) &&
-                          !branches[i]->name[len]) :
-                   !strcmp(name, branches[i]->name))
+               if (!strncmp(name, branches[i]->name, len) &&
+                   !branches[i]->name[len])
                        return branches[i];
        }
 
        ALLOC_GROW(branches, branches_nr + 1, branches_alloc);
        ret = xcalloc(1, sizeof(struct branch));
        branches[branches_nr++] = ret;
-       if (len)
-               ret->name = xstrndup(name, len);
-       else
-               ret->name = xstrdup(name);
+       ret->name = xstrndup(name, len);
        ret->refname = xstrfmt("refs/heads/%s", ret->name);
 
        return ret;
 }
 
-static struct rewrite *make_rewrite(struct rewrites *r, const char *base, int len)
+static struct rewrite *make_rewrite(struct rewrites *r,
+                                   const char *base, size_t len)
 {
        struct rewrite *ret;
        int i;
 
        for (i = 0; i < r->rewrite_nr; i++) {
-               if (len
-                   ? (len == r->rewrite[i]->baselen &&
-                      !strncmp(base, r->rewrite[i]->base, len))
-                   : !strcmp(base, r->rewrite[i]->base))
+               if (len == r->rewrite[i]->baselen &&
+                   !strncmp(base, r->rewrite[i]->base, len))
                        return r->rewrite[i];
        }
 
        ALLOC_GROW(r->rewrite, r->rewrite_nr + 1, r->rewrite_alloc);
        ret = xcalloc(1, sizeof(struct rewrite));
        r->rewrite[r->rewrite_nr++] = ret;
-       if (len) {
-               ret->base = xstrndup(base, len);
-               ret->baselen = len;
-       }
-       else {
-               ret->base = xstrdup(base);
-               ret->baselen = strlen(base);
-       }
+       ret->base = xstrndup(base, len);
+       ret->baselen = len;
        return ret;
 }
 
@@ -284,7 +276,7 @@ static void read_branches_file(struct remote *remote)
 
        /*
         * The branches file would have URL and optionally
-        * #branch specified.  The "master" (or specified) branch is
+        * #branch specified.  The default (or specified) branch is
         * fetched and stored in the local branch matching the
         * remote name.
         */
@@ -292,7 +284,7 @@ static void read_branches_file(struct remote *remote)
        if (frag)
                *(frag++) = '\0';
        else
-               frag = "master";
+               frag = (char *)git_default_branch_name();
 
        add_url_alias(remote, strbuf_detach(&buf, NULL));
        strbuf_addf(&buf, "refs/heads/%s:refs/heads/%s",
@@ -313,7 +305,7 @@ 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;
+       size_t namelen;
        const char *subkey;
        struct remote *remote;
        struct branch *branch;
@@ -366,7 +358,8 @@ static int handle_config(const char *key, const char *value, void *cb)
        }
        remote = make_remote(name, namelen);
        remote->origin = REMOTE_CONFIG;
-       if (current_config_scope() == CONFIG_SCOPE_REPO)
+       if (current_config_scope() == CONFIG_SCOPE_LOCAL ||
+       current_config_scope() == CONFIG_SCOPE_WORKTREE)
                remote->configured_in_repo = 1;
        if (!strcmp(subkey, "mirror"))
                remote->mirror = git_config_bool(key, value);
@@ -466,7 +459,7 @@ static void read_config(void)
                const char *head_ref = resolve_ref_unsafe("HEAD", 0, NULL, &flag);
                if (head_ref && (flag & REF_ISSYMREF) &&
                    skip_prefix(head_ref, "refs/heads/", &head_ref)) {
-                       current_branch = make_branch(head_ref, 0);
+                       current_branch = make_branch(head_ref, strlen(head_ref));
                }
        }
        git_config(handle_config, NULL);
@@ -512,14 +505,11 @@ const char *pushremote_for_branch(struct branch *branch, int *explicit)
        return remote_for_branch(branch, explicit);
 }
 
-const char *remote_ref_for_branch(struct branch *branch, int for_push,
-                                 int *explicit)
+const char *remote_ref_for_branch(struct branch *branch, int for_push)
 {
        if (branch) {
                if (!for_push) {
                        if (branch->merge_nr) {
-                               if (explicit)
-                                       *explicit = 1;
                                return branch->merge_name[0];
                        }
                } else {
@@ -530,15 +520,11 @@ const char *remote_ref_for_branch(struct branch *branch, int for_push,
                        if (remote && remote->push.nr &&
                            (dst = apply_refspecs(&remote->push,
                                                  branch->refname))) {
-                               if (explicit)
-                                       *explicit = 1;
                                return dst;
                        }
                }
        }
-       if (explicit)
-               *explicit = 0;
-       return "";
+       return NULL;
 }
 
 static struct remote *remote_get_1(const char *name,
@@ -820,11 +806,11 @@ struct ref *copy_ref_list(const struct ref *ref)
        return ret;
 }
 
-static void free_ref(struct ref *ref)
+void free_one_ref(struct ref *ref)
 {
        if (!ref)
                return;
-       free_ref(ref->peer_ref);
+       free_one_ref(ref->peer_ref);
        free(ref->remote_status);
        free(ref->symref);
        free(ref);
@@ -835,7 +821,7 @@ void free_refs(struct ref *ref)
        struct ref *next;
        while (ref) {
                next = ref->next;
-               free_ref(ref);
+               free_one_ref(ref);
                ref = next;
        }
 }
@@ -1587,7 +1573,7 @@ struct branch *branch_get(const char *name)
        if (!name || !*name || !strcmp(name, "HEAD"))
                ret = current_branch;
        else
-               ret = make_branch(name, 0);
+               ret = make_branch(name, strlen(name));
        set_merge(ret);
        return ret;
 }
@@ -1880,37 +1866,27 @@ int resolve_remote_symref(struct ref *ref, struct ref *list)
 }
 
 /*
- * Lookup the upstream branch for the given branch and if present, optionally
- * compute the commit ahead/behind values for the pair.
+ * Compute the commit ahead/behind values for the pair branch_name, base.
  *
  * If abf is AHEAD_BEHIND_FULL, compute the full ahead/behind and return the
  * counts in *num_ours and *num_theirs.  If abf is AHEAD_BEHIND_QUICK, skip
  * the (potentially expensive) a/b computation (*num_ours and *num_theirs are
  * set to zero).
  *
- * The name of the upstream branch (or NULL if no upstream is defined) is
- * returned via *upstream_name, if it is not itself NULL.
- *
- * Returns -1 if num_ours and num_theirs could not be filled in (e.g., no
- * upstream defined, or ref does not exist).  Returns 0 if the commits are
- * identical.  Returns 1 if commits are different.
+ * Returns -1 if num_ours and num_theirs could not be filled in (e.g., ref
+ * does not exist).  Returns 0 if the commits are identical.  Returns 1 if
+ * commits are different.
  */
-int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs,
-                      const char **upstream_name, enum ahead_behind_flags abf)
+
+static int stat_branch_pair(const char *branch_name, const char *base,
+                            int *num_ours, int *num_theirs,
+                            enum ahead_behind_flags abf)
 {
        struct object_id oid;
        struct commit *ours, *theirs;
        struct rev_info revs;
-       const char *base;
        struct argv_array argv = ARGV_ARRAY_INIT;
 
-       /* Cannot stat unless we are marked to build on top of somebody else. */
-       base = branch_get_upstream(branch, NULL);
-       if (upstream_name)
-               *upstream_name = base;
-       if (!base)
-               return -1;
-
        /* Cannot stat if what we used to build on no longer exists */
        if (read_ref(base, &oid))
                return -1;
@@ -1918,7 +1894,7 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs,
        if (!theirs)
                return -1;
 
-       if (read_ref(branch->refname, &oid))
+       if (read_ref(branch_name, &oid))
                return -1;
        ours = lookup_commit_reference(the_repository, &oid);
        if (!ours)
@@ -1932,7 +1908,7 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs,
        if (abf == AHEAD_BEHIND_QUICK)
                return 1;
        if (abf != AHEAD_BEHIND_FULL)
-               BUG("stat_tracking_info: invalid abf '%d'", abf);
+               BUG("stat_branch_pair: invalid abf '%d'", abf);
 
        /* Run "rev-list --left-right ours...theirs" internally... */
        argv_array_push(&argv, ""); /* ignored */
@@ -1967,6 +1943,42 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs,
 }
 
 /*
+ * Lookup the tracking branch for the given branch and if present, optionally
+ * compute the commit ahead/behind values for the pair.
+ *
+ * If for_push is true, the tracking branch refers to the push branch,
+ * otherwise it refers to the upstream branch.
+ *
+ * The name of the tracking branch (or NULL if it is not defined) is
+ * returned via *tracking_name, if it is not itself NULL.
+ *
+ * If abf is AHEAD_BEHIND_FULL, compute the full ahead/behind and return the
+ * counts in *num_ours and *num_theirs.  If abf is AHEAD_BEHIND_QUICK, skip
+ * the (potentially expensive) a/b computation (*num_ours and *num_theirs are
+ * set to zero).
+ *
+ * Returns -1 if num_ours and num_theirs could not be filled in (e.g., no
+ * upstream defined, or ref does not exist).  Returns 0 if the commits are
+ * identical.  Returns 1 if commits are different.
+ */
+int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs,
+                      const char **tracking_name, int for_push,
+                      enum ahead_behind_flags abf)
+{
+       const char *base;
+
+       /* Cannot stat unless we are marked to build on top of somebody else. */
+       base = for_push ? branch_get_push(branch, NULL) :
+               branch_get_upstream(branch, NULL);
+       if (tracking_name)
+               *tracking_name = base;
+       if (!base)
+               return -1;
+
+       return stat_branch_pair(branch->refname, base, num_ours, num_theirs, abf);
+}
+
+/*
  * Return true when there is anything to report, otherwise false.
  */
 int format_tracking_info(struct branch *branch, struct strbuf *sb,
@@ -1977,7 +1989,7 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb,
        char *base;
        int upstream_is_gone = 0;
 
-       sti = stat_tracking_info(branch, &ours, &theirs, &full_base, abf);
+       sti = stat_tracking_info(branch, &ours, &theirs, &full_base, 0, abf);
        if (sti < 0) {
                if (!full_base)
                        return 0;
@@ -2085,8 +2097,16 @@ struct ref *guess_remote_head(const struct ref *head,
        if (head->symref)
                return copy_ref(find_ref_by_name(refs, head->symref));
 
-       /* If refs/heads/master could be right, it is. */
+       /* If a remote branch exists with the default branch name, let's use it. */
        if (!all) {
+               char *ref = xstrfmt("refs/heads/%s", git_default_branch_name());
+
+               r = find_ref_by_name(refs, ref);
+               free(ref);
+               if (r && oideq(&r->old_oid, &head->old_oid))
+                       return copy_ref(r);
+
+               /* Fall back to the hard-coded historical default */
                r = find_ref_by_name(refs, "refs/heads/master");
                if (r && oideq(&r->old_oid, &head->old_oid))
                        return copy_ref(r);