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