Merge branch 'bc/append-signed-off-by'
[gitweb.git] / builtin / branch.c
index ffd26849c7ad20ff470323621486ae8a2aeb2501..00d17d25d1866323f9e1dffcb334a573f5de5221 100644 (file)
@@ -154,10 +154,37 @@ static int branch_merged(int kind, const char *name,
        return merged;
 }
 
+static int check_branch_commit(const char *branchname, const char *refname,
+                              unsigned char *sha1, struct commit *head_rev,
+                              int kinds, int force)
+{
+       struct commit *rev = lookup_commit_reference(sha1);
+       if (!rev) {
+               error(_("Couldn't look up commit object for '%s'"), refname);
+               return -1;
+       }
+       if (!force && !branch_merged(kinds, branchname, rev, head_rev)) {
+               error(_("The branch '%s' is not fully merged.\n"
+                     "If you are sure you want to delete it, "
+                     "run 'git branch -D %s'."), branchname, branchname);
+               return -1;
+       }
+       return 0;
+}
+
+static void delete_branch_config(const char *branchname)
+{
+       struct strbuf buf = STRBUF_INIT;
+       strbuf_addf(&buf, "branch.%s", branchname);
+       if (git_config_rename_section(buf.buf, NULL) < 0)
+               warning(_("Update of config-file failed"));
+       strbuf_release(&buf);
+}
+
 static int delete_branches(int argc, const char **argv, int force, int kinds,
                           int quiet)
 {
-       struct commit *rev, *head_rev = NULL;
+       struct commit *head_rev = NULL;
        unsigned char sha1[20];
        char *name = NULL;
        const char *fmt;
@@ -187,6 +214,9 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
                        die(_("Couldn't look up commit object for HEAD"));
        }
        for (i = 0; i < argc; i++, strbuf_release(&bname)) {
+               const char *target;
+               int flags = 0;
+
                strbuf_branchname(&bname, argv[i]);
                if (kinds == REF_LOCAL_BRANCH && !strcmp(head, bname.buf)) {
                        error(_("Cannot delete the branch '%s' "
@@ -198,7 +228,9 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
                free(name);
 
                name = mkpathdup(fmt, bname.buf);
-               if (read_ref(name, sha1)) {
+               target = resolve_ref_unsafe(name, sha1, 0, &flags);
+               if (!target ||
+                   (!(flags & REF_ISSYMREF) && is_null_sha1(sha1))) {
                        error(remote_branch
                              ? _("remote branch '%s' not found.")
                              : _("branch '%s' not found."), bname.buf);
@@ -206,40 +238,31 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
                        continue;
                }
 
-               rev = lookup_commit_reference(sha1);
-               if (!rev) {
-                       error(_("Couldn't look up commit object for '%s'"), name);
+               if (!(flags & REF_ISSYMREF) &&
+                   check_branch_commit(bname.buf, name, sha1, head_rev, kinds,
+                                       force)) {
                        ret = 1;
                        continue;
                }
 
-               if (!force && !branch_merged(kinds, bname.buf, rev, head_rev)) {
-                       error(_("The branch '%s' is not fully merged.\n"
-                             "If you are sure you want to delete it, "
-                             "run 'git branch -D %s'."), bname.buf, bname.buf);
-                       ret = 1;
-                       continue;
-               }
-
-               if (delete_ref(name, sha1, 0)) {
+               if (delete_ref(name, sha1, REF_NODEREF)) {
                        error(remote_branch
                              ? _("Error deleting remote branch '%s'")
                              : _("Error deleting branch '%s'"),
                              bname.buf);
                        ret = 1;
-               } else {
-                       struct strbuf buf = STRBUF_INIT;
-                       if (!quiet)
-                               printf(remote_branch
-                                      ? _("Deleted remote branch %s (was %s).\n")
-                                      : _("Deleted branch %s (was %s).\n"),
-                                      bname.buf,
-                                      find_unique_abbrev(sha1, DEFAULT_ABBREV));
-                       strbuf_addf(&buf, "branch.%s", bname.buf);
-                       if (git_config_rename_section(buf.buf, NULL) < 0)
-                               warning(_("Update of config-file failed"));
-                       strbuf_release(&buf);
+                       continue;
                }
+               if (!quiet) {
+                       printf(remote_branch
+                              ? _("Deleted remote branch %s (was %s).\n")
+                              : _("Deleted branch %s (was %s).\n"),
+                              bname.buf,
+                              (flags & REF_ISSYMREF)
+                              ? target
+                              : find_unique_abbrev(sha1, DEFAULT_ABBREV));
+               }
+               delete_branch_config(bname.buf);
        }
 
        free(name);
@@ -443,7 +466,7 @@ static void add_verbose_info(struct strbuf *out, struct ref_item *item,
                             int verbose, int abbrev)
 {
        struct strbuf subject = STRBUF_INIT, stat = STRBUF_INIT;
-       const char *sub = " **** invalid ref ****";
+       const char *sub = _(" **** invalid ref ****");
        struct commit *commit = item->commit;
 
        if (commit && !parse_commit(commit)) {
@@ -567,7 +590,7 @@ static int print_ref_list(int kinds, int detached, int verbose, int abbrev, stru
                struct commit *filter;
                filter = lookup_commit_reference_gently(merge_filter_ref, 0);
                if (!filter)
-                       die("object '%s' does not point to a commit",
+                       die(_("object '%s' does not point to a commit"),
                            sha1_to_hex(merge_filter_ref));
 
                filter->object.flags |= UNINTERESTING;
@@ -683,11 +706,11 @@ static int edit_branch_description(const char *branch_name)
        read_branch_desc(&buf, branch_name);
        if (!buf.len || buf.buf[buf.len-1] != '\n')
                strbuf_addch(&buf, '\n');
-       strbuf_addf(&buf,
-                   "Please edit the description for the branch\n"
-                   "  %s\n"
-                   "# Lines starting with '#' will be stripped.\n",
-                   branch_name);
+       strbuf_commented_addf(&buf,
+                   "Please edit the description for the branch\n"
+                   "  %s\n"
+                   "Lines starting with '%c' will be stripped.\n",
+                   branch_name, comment_line_char);
        fp = fopen(git_path(edit_description), "w");
        if ((fwrite(buf.buf, 1, buf.len, fp) < buf.len) || fclose(fp)) {
                strbuf_release(&buf);
@@ -702,7 +725,7 @@ static int edit_branch_description(const char *branch_name)
        stripspace(&buf, 1);
 
        strbuf_addf(&name, "branch.%s.description", branch_name);
-       status = git_config_set(name.buf, buf.buf);
+       status = git_config_set(name.buf, buf.len ? buf.buf : NULL);
        strbuf_release(&name);
        strbuf_release(&buf);
 
@@ -802,6 +825,9 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
        if (!delete && !rename && !edit_description && !new_upstream && !unset_upstream && argc == 0)
                list = 1;
 
+       if (with_commit || merge_filter != NO_FILTER)
+               list = 1;
+
        if (!!delete + !!rename + !!force_create + !!list + !!new_upstream + !!unset_upstream > 1)
                usage_with_options(builtin_branch_usage, options);
 
@@ -814,9 +840,11 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
                colopts = 0;
        }
 
-       if (delete)
+       if (delete) {
+               if (!argc)
+                       die(_("branch name required"));
                return delete_branches(argc, argv, delete > 1, kinds, quiet);
-       else if (list) {
+       else if (list) {
                int ret = print_ref_list(kinds, detached, verbose, abbrev,
                                         with_commit, argv);
                print_columns(&output, colopts, NULL);
@@ -827,24 +855,25 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
                const char *branch_name;
                struct strbuf branch_ref = STRBUF_INIT;
 
-               if (detached)
-                       die("Cannot give description to detached HEAD");
-               if (!argc)
+               if (!argc) {
+                       if (detached)
+                               die(_("Cannot give description to detached HEAD"));
                        branch_name = head;
-               else if (argc == 1)
+               else if (argc == 1)
                        branch_name = argv[0];
                else
-                       usage_with_options(builtin_branch_usage, options);
+                       die(_("cannot edit description of more than one branch"));
 
                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.",
+                               return error(_("No commit on branch '%s' yet."),
                                             branch_name);
                        else
-                               return error("No such branch '%s'.", branch_name);
+                               return error(_("No branch named '%s'."),
+                                            branch_name);
                }
                strbuf_release(&branch_ref);
 
@@ -856,10 +885,21 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
                else if (argc == 2)
                        rename_branch(argv[0], argv[1], rename > 1);
                else
-                       usage_with_options(builtin_branch_usage, options);
+                       die(_("too many branches for a rename operation"));
        } else if (new_upstream) {
                struct branch *branch = branch_get(argv[0]);
 
+               if (argc > 1)
+                       die(_("too many branches to set new upstream"));
+
+               if (!branch) {
+                       if (!argc || !strcmp(argv[0], "HEAD"))
+                               die(_("could not set upstream of HEAD to %s when "
+                                     "it does not point to any branch."),
+                                   new_upstream);
+                       die(_("no such branch '%s'"), argv[0]);
+               }
+
                if (!ref_exists(branch->refname))
                        die(_("branch '%s' does not exist"), branch->name);
 
@@ -872,6 +912,16 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
                struct branch *branch = branch_get(argv[0]);
                struct strbuf buf = STRBUF_INIT;
 
+               if (argc > 1)
+                       die(_("too many branches to unset upstream"));
+
+               if (!branch) {
+                       if (!argc || !strcmp(argv[0], "HEAD"))
+                               die(_("could not unset upstream of HEAD when "
+                                     "it does not point to any branch."));
+                       die(_("no such branch '%s'"), argv[0]);
+               }
+
                if (!branch_has_merge_config(branch)) {
                        die(_("Branch '%s' has no upstream information"), branch->name);
                }
@@ -887,6 +937,12 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
                int branch_existed = 0, remote_tracking = 0;
                struct strbuf buf = STRBUF_INIT;
 
+               if (!strcmp(argv[0], "HEAD"))
+                       die(_("it does not make sense to create 'HEAD' manually"));
+
+               if (!branch)
+                       die(_("no such branch '%s'"), argv[0]);
+
                if (kinds != REF_LOCAL_BRANCH)
                        die(_("-a and -r options to 'git branch' do not make sense with a branch name"));