branch.con commit submodule: ignore trailing slash on superproject URL (0878850)
   1#include "git-compat-util.h"
   2#include "cache.h"
   3#include "branch.h"
   4#include "refs.h"
   5#include "remote.h"
   6#include "commit.h"
   7#include "worktree.h"
   8
   9struct tracking {
  10        struct refspec spec;
  11        char *src;
  12        const char *remote;
  13        int matches;
  14};
  15
  16static int find_tracked_branch(struct remote *remote, void *priv)
  17{
  18        struct tracking *tracking = priv;
  19
  20        if (!remote_find_tracking(remote, &tracking->spec)) {
  21                if (++tracking->matches == 1) {
  22                        tracking->src = tracking->spec.src;
  23                        tracking->remote = remote->name;
  24                } else {
  25                        free(tracking->spec.src);
  26                        if (tracking->src) {
  27                                free(tracking->src);
  28                                tracking->src = NULL;
  29                        }
  30                }
  31                tracking->spec.src = NULL;
  32        }
  33
  34        return 0;
  35}
  36
  37static int should_setup_rebase(const char *origin)
  38{
  39        switch (autorebase) {
  40        case AUTOREBASE_NEVER:
  41                return 0;
  42        case AUTOREBASE_LOCAL:
  43                return origin == NULL;
  44        case AUTOREBASE_REMOTE:
  45                return origin != NULL;
  46        case AUTOREBASE_ALWAYS:
  47                return 1;
  48        }
  49        return 0;
  50}
  51
  52static const char tracking_advice[] =
  53N_("\n"
  54"After fixing the error cause you may try to fix up\n"
  55"the remote tracking information by invoking\n"
  56"\"git branch --set-upstream-to=%s%s%s\".");
  57
  58int install_branch_config(int flag, const char *local, const char *origin, const char *remote)
  59{
  60        const char *shortname = NULL;
  61        struct strbuf key = STRBUF_INIT;
  62        int rebasing = should_setup_rebase(origin);
  63
  64        if (skip_prefix(remote, "refs/heads/", &shortname)
  65            && !strcmp(local, shortname)
  66            && !origin) {
  67                warning(_("Not setting branch %s as its own upstream."),
  68                        local);
  69                return 0;
  70        }
  71
  72        strbuf_addf(&key, "branch.%s.remote", local);
  73        if (git_config_set_gently(key.buf, origin ? origin : ".") < 0)
  74                goto out_err;
  75
  76        strbuf_reset(&key);
  77        strbuf_addf(&key, "branch.%s.merge", local);
  78        if (git_config_set_gently(key.buf, remote) < 0)
  79                goto out_err;
  80
  81        if (rebasing) {
  82                strbuf_reset(&key);
  83                strbuf_addf(&key, "branch.%s.rebase", local);
  84                if (git_config_set_gently(key.buf, "true") < 0)
  85                        goto out_err;
  86        }
  87        strbuf_release(&key);
  88
  89        if (flag & BRANCH_CONFIG_VERBOSE) {
  90                if (shortname) {
  91                        if (origin)
  92                                printf_ln(rebasing ?
  93                                          _("Branch %s set up to track remote branch %s from %s by rebasing.") :
  94                                          _("Branch %s set up to track remote branch %s from %s."),
  95                                          local, shortname, origin);
  96                        else
  97                                printf_ln(rebasing ?
  98                                          _("Branch %s set up to track local branch %s by rebasing.") :
  99                                          _("Branch %s set up to track local branch %s."),
 100                                          local, shortname);
 101                } else {
 102                        if (origin)
 103                                printf_ln(rebasing ?
 104                                          _("Branch %s set up to track remote ref %s by rebasing.") :
 105                                          _("Branch %s set up to track remote ref %s."),
 106                                          local, remote);
 107                        else
 108                                printf_ln(rebasing ?
 109                                          _("Branch %s set up to track local ref %s by rebasing.") :
 110                                          _("Branch %s set up to track local ref %s."),
 111                                          local, remote);
 112                }
 113        }
 114
 115        return 0;
 116
 117out_err:
 118        strbuf_release(&key);
 119        error(_("Unable to write upstream branch configuration"));
 120
 121        advise(_(tracking_advice),
 122               origin ? origin : "",
 123               origin ? "/" : "",
 124               shortname ? shortname : remote);
 125
 126        return -1;
 127}
 128
 129/*
 130 * This is called when new_ref is branched off of orig_ref, and tries
 131 * to infer the settings for branch.<new_ref>.{remote,merge} from the
 132 * config.
 133 */
 134static void setup_tracking(const char *new_ref, const char *orig_ref,
 135                           enum branch_track track, int quiet)
 136{
 137        struct tracking tracking;
 138        int config_flags = quiet ? 0 : BRANCH_CONFIG_VERBOSE;
 139
 140        memset(&tracking, 0, sizeof(tracking));
 141        tracking.spec.dst = (char *)orig_ref;
 142        if (for_each_remote(find_tracked_branch, &tracking))
 143                return;
 144
 145        if (!tracking.matches)
 146                switch (track) {
 147                case BRANCH_TRACK_ALWAYS:
 148                case BRANCH_TRACK_EXPLICIT:
 149                case BRANCH_TRACK_OVERRIDE:
 150                        break;
 151                default:
 152                        return;
 153                }
 154
 155        if (tracking.matches > 1)
 156                die(_("Not tracking: ambiguous information for ref %s"),
 157                    orig_ref);
 158
 159        if (install_branch_config(config_flags, new_ref, tracking.remote,
 160                              tracking.src ? tracking.src : orig_ref) < 0)
 161                exit(-1);
 162
 163        free(tracking.src);
 164}
 165
 166int read_branch_desc(struct strbuf *buf, const char *branch_name)
 167{
 168        char *v = NULL;
 169        struct strbuf name = STRBUF_INIT;
 170        strbuf_addf(&name, "branch.%s.description", branch_name);
 171        if (git_config_get_string(name.buf, &v)) {
 172                strbuf_release(&name);
 173                return -1;
 174        }
 175        strbuf_addstr(buf, v);
 176        free(v);
 177        strbuf_release(&name);
 178        return 0;
 179}
 180
 181int validate_new_branchname(const char *name, struct strbuf *ref,
 182                            int force, int attr_only)
 183{
 184        if (strbuf_check_branch_ref(ref, name))
 185                die(_("'%s' is not a valid branch name."), name);
 186
 187        if (!ref_exists(ref->buf))
 188                return 0;
 189        else if (!force && !attr_only)
 190                die(_("A branch named '%s' already exists."), ref->buf + strlen("refs/heads/"));
 191
 192        if (!attr_only) {
 193                const char *head;
 194                unsigned char sha1[20];
 195
 196                head = resolve_ref_unsafe("HEAD", 0, sha1, NULL);
 197                if (!is_bare_repository() && head && !strcmp(head, ref->buf))
 198                        die(_("Cannot force update the current branch."));
 199        }
 200        return 1;
 201}
 202
 203static int check_tracking_branch(struct remote *remote, void *cb_data)
 204{
 205        char *tracking_branch = cb_data;
 206        struct refspec query;
 207        memset(&query, 0, sizeof(struct refspec));
 208        query.dst = tracking_branch;
 209        return !remote_find_tracking(remote, &query);
 210}
 211
 212static int validate_remote_tracking_branch(char *ref)
 213{
 214        return !for_each_remote(check_tracking_branch, ref);
 215}
 216
 217static const char upstream_not_branch[] =
 218N_("Cannot setup tracking information; starting point '%s' is not a branch.");
 219static const char upstream_missing[] =
 220N_("the requested upstream branch '%s' does not exist");
 221static const char upstream_advice[] =
 222N_("\n"
 223"If you are planning on basing your work on an upstream\n"
 224"branch that already exists at the remote, you may need to\n"
 225"run \"git fetch\" to retrieve it.\n"
 226"\n"
 227"If you are planning to push out a new local branch that\n"
 228"will track its remote counterpart, you may want to use\n"
 229"\"git push -u\" to set the upstream config as you push.");
 230
 231void create_branch(const char *head,
 232                   const char *name, const char *start_name,
 233                   int force, int reflog, int clobber_head,
 234                   int quiet, enum branch_track track)
 235{
 236        struct commit *commit;
 237        unsigned char sha1[20];
 238        char *real_ref, msg[PATH_MAX + 20];
 239        struct strbuf ref = STRBUF_INIT;
 240        int forcing = 0;
 241        int dont_change_ref = 0;
 242        int explicit_tracking = 0;
 243
 244        if (track == BRANCH_TRACK_EXPLICIT || track == BRANCH_TRACK_OVERRIDE)
 245                explicit_tracking = 1;
 246
 247        if (validate_new_branchname(name, &ref, force,
 248                                    track == BRANCH_TRACK_OVERRIDE ||
 249                                    clobber_head)) {
 250                if (!force)
 251                        dont_change_ref = 1;
 252                else
 253                        forcing = 1;
 254        }
 255
 256        real_ref = NULL;
 257        if (get_sha1(start_name, sha1)) {
 258                if (explicit_tracking) {
 259                        if (advice_set_upstream_failure) {
 260                                error(_(upstream_missing), start_name);
 261                                advise(_(upstream_advice));
 262                                exit(1);
 263                        }
 264                        die(_(upstream_missing), start_name);
 265                }
 266                die(_("Not a valid object name: '%s'."), start_name);
 267        }
 268
 269        switch (dwim_ref(start_name, strlen(start_name), sha1, &real_ref)) {
 270        case 0:
 271                /* Not branching from any existing branch */
 272                if (explicit_tracking)
 273                        die(_(upstream_not_branch), start_name);
 274                break;
 275        case 1:
 276                /* Unique completion -- good, only if it is a real branch */
 277                if (!starts_with(real_ref, "refs/heads/") &&
 278                    validate_remote_tracking_branch(real_ref)) {
 279                        if (explicit_tracking)
 280                                die(_(upstream_not_branch), start_name);
 281                        else
 282                                real_ref = NULL;
 283                }
 284                break;
 285        default:
 286                die(_("Ambiguous object name: '%s'."), start_name);
 287                break;
 288        }
 289
 290        if ((commit = lookup_commit_reference(sha1)) == NULL)
 291                die(_("Not a valid branch point: '%s'."), start_name);
 292        hashcpy(sha1, commit->object.oid.hash);
 293
 294        if (forcing)
 295                snprintf(msg, sizeof msg, "branch: Reset to %s",
 296                         start_name);
 297        else if (!dont_change_ref)
 298                snprintf(msg, sizeof msg, "branch: Created from %s",
 299                         start_name);
 300
 301        if (reflog)
 302                log_all_ref_updates = 1;
 303
 304        if (!dont_change_ref) {
 305                struct ref_transaction *transaction;
 306                struct strbuf err = STRBUF_INIT;
 307
 308                transaction = ref_transaction_begin(&err);
 309                if (!transaction ||
 310                    ref_transaction_update(transaction, ref.buf,
 311                                           sha1, forcing ? NULL : null_sha1,
 312                                           0, msg, &err) ||
 313                    ref_transaction_commit(transaction, &err))
 314                        die("%s", err.buf);
 315                ref_transaction_free(transaction);
 316                strbuf_release(&err);
 317        }
 318
 319        if (real_ref && track)
 320                setup_tracking(ref.buf + 11, real_ref, track, quiet);
 321
 322        strbuf_release(&ref);
 323        free(real_ref);
 324}
 325
 326void remove_branch_state(void)
 327{
 328        unlink(git_path_cherry_pick_head());
 329        unlink(git_path_revert_head());
 330        unlink(git_path_merge_head());
 331        unlink(git_path_merge_rr());
 332        unlink(git_path_merge_msg());
 333        unlink(git_path_merge_mode());
 334        unlink(git_path_squash_msg());
 335}
 336
 337void die_if_checked_out(const char *branch)
 338{
 339        char *existing;
 340
 341        existing = find_shared_symref("HEAD", branch);
 342        if (existing) {
 343                skip_prefix(branch, "refs/heads/", &branch);
 344                die(_("'%s' is already checked out at '%s'"), branch, existing);
 345        }
 346}