Merge branches zj/decimal-width, zj/term-columns and jc/diff-stat-scaler
[gitweb.git] / builtin / branch.c
index ad02f0fd7e8819f436baf27d7836cc181d613bab..cb17bc367571a88b6e6bcac5020c1746c4385480 100644 (file)
@@ -104,6 +104,7 @@ static int branch_merged(int kind, const char *name,
         */
        struct commit *reference_rev = NULL;
        const char *reference_name = NULL;
+       void *reference_name_to_free = NULL;
        int merged;
 
        if (kind == REF_LOCAL_BRANCH) {
@@ -114,8 +115,8 @@ static int branch_merged(int kind, const char *name,
                    branch->merge &&
                    branch->merge[0] &&
                    branch->merge[0]->dst &&
-                   (reference_name =
-                    resolve_ref(branch->merge[0]->dst, sha1, 1, NULL)) != NULL)
+                   (reference_name = reference_name_to_free =
+                    resolve_refdup(branch->merge[0]->dst, sha1, 1, NULL)) != NULL)
                        reference_rev = lookup_commit_reference(sha1);
        }
        if (!reference_rev)
@@ -141,6 +142,7 @@ static int branch_merged(int kind, const char *name,
                                "         '%s', even though it is merged to HEAD."),
                                name, reference_name);
        }
+       free(reference_name_to_free);
        return merged;
 }
 
@@ -186,7 +188,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds)
                free(name);
 
                name = xstrdup(mkpath(fmt, bname.buf));
-               if (!resolve_ref(name, sha1, 1, NULL)) {
+               if (read_ref(name, sha1)) {
                        error(_("%sbranch '%s' not found."),
                                        remote, bname.buf);
                        ret = 1;
@@ -250,7 +252,7 @@ static char *resolve_symref(const char *src, const char *prefix)
        int flag;
        const char *dst, *cp;
 
-       dst = resolve_ref(src, sha1, 0, &flag);
+       dst = resolve_ref_unsafe(src, sha1, 0, &flag);
        if (!(dst && (flag & REF_ISSYMREF)))
                return NULL;
        if (prefix && (cp = skip_prefix(dst, prefix)))
@@ -565,9 +567,9 @@ static int print_ref_list(int kinds, int detached, int verbose, int abbrev, stru
 static void rename_branch(const char *oldname, const char *newname, int force)
 {
        struct strbuf oldref = STRBUF_INIT, newref = STRBUF_INIT, logmsg = STRBUF_INIT;
-       unsigned char sha1[20];
        struct strbuf oldsection = STRBUF_INIT, newsection = STRBUF_INIT;
        int recovery = 0;
+       int clobber_head_ok;
 
        if (!oldname)
                die(_("cannot rename the current branch while not on any."));
@@ -577,13 +579,19 @@ static void rename_branch(const char *oldname, const char *newname, int force)
                 * Bad name --- this could be an attempt to rename a
                 * ref that we used to allow to be created by accident.
                 */
-               if (resolve_ref(oldref.buf, sha1, 1, NULL))
+               if (ref_exists(oldref.buf))
                        recovery = 1;
                else
                        die(_("Invalid branch name: '%s'"), oldname);
        }
 
-       validate_new_branchname(newname, &newref, force, 0);
+       /*
+        * A command like "git branch -M currentbranch currentbranch" cannot
+        * cause the worktree to become inconsistent with HEAD, so allow it.
+        */
+       clobber_head_ok = !strcmp(oldname, newname);
+
+       validate_new_branchname(newname, &newref, force, clobber_head_ok);
 
        strbuf_addf(&logmsg, "Branch: renamed %s to %s",
                 oldref.buf, newref.buf);
@@ -729,10 +737,9 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
 
        track = git_branch_track;
 
-       head = resolve_ref("HEAD", head_sha1, 0, NULL);
+       head = resolve_refdup("HEAD", head_sha1, 0, NULL);
        if (!head)
                die(_("Failed to resolve HEAD as a valid ref."));
-       head = xstrdup(head);
        if (!strcmp(head, "HEAD")) {
                detached = 1;
        } else {
@@ -761,6 +768,8 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
                                      with_commit, argv);
        else if (edit_description) {
                const char *branch_name;
+               struct strbuf branch_ref = STRBUF_INIT;
+
                if (detached)
                        die("Cannot give description to detached HEAD");
                if (!argc)
@@ -769,6 +778,19 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
                        branch_name = argv[0];
                else
                        usage_with_options(builtin_branch_usage, options);
+
+               strbuf_addf(&branch_ref, "refs/heads/%s", branch_name);
+               if (!ref_exists(branch_ref.buf)) {
+                       strbuf_release(&branch_ref);
+
+                       if (!argc)
+                               return error("No commit on branch '%s' yet.",
+                                            branch_name);
+                       else
+                               return error("No such branch '%s'.", branch_name);
+               }
+               strbuf_release(&branch_ref);
+
                if (edit_branch_description(branch_name))
                        return 1;
        } else if (rename) {
@@ -782,7 +804,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
                if (kinds != REF_LOCAL_BRANCH)
                        die(_("-a and -r options to 'git branch' do not make sense with a branch name"));
                create_branch(head, argv[0], (argc == 2) ? argv[1] : head,
-                             force_create, reflog, track);
+                             force_create, reflog, 0, track);
        } else
                usage_with_options(builtin_branch_usage, options);