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