Merge branch 'nd/maint-branch-desc-doc'
authorJunio C Hamano <gitster@pobox.com>
Wed, 9 Jan 2013 16:27:09 +0000 (08:27 -0800)
committerJunio C Hamano <gitster@pobox.com>
Wed, 9 Jan 2013 16:27:09 +0000 (08:27 -0800)
Teach various forms of "format-patch" command line to identify what
branch the patches are taken from, so that the branch description
is picked up in more cases.

* nd/maint-branch-desc-doc:
format-patch: pick up branch description when no ref is specified
format-patch: pick up correct branch name from symbolic ref
t4014: a few more tests on cover letter using branch description
branch: delete branch description if it's empty
config.txt: a few lines about branch.<name>.description

1  2 
Documentation/config.txt
builtin/branch.c
builtin/log.c
t/t4014-format-patch.sh
diff --combined Documentation/config.txt
index 53c4ca1d7a0f7441a3ff84d50574efabce5a79f5,96a3d31de9249e30d6812b14a5c85febad82497e..d5809e0e8c4dca414a863cfd019a6f8860c46c4d
@@@ -140,11 -140,10 +140,11 @@@ advice.*:
        can tell Git that you do not need help by setting these to 'false':
  +
  --
 -      pushNonFastForward::
 +      pushUpdateRejected::
                Set this variable to 'false' if you want to disable
 -              'pushNonFFCurrent', 'pushNonFFDefault', and
 -              'pushNonFFMatching' simultaneously.
 +              'pushNonFFCurrent', 'pushNonFFDefault',
 +              'pushNonFFMatching', and 'pushAlreadyExists'
 +              simultaneously.
        pushNonFFCurrent::
                Advice shown when linkgit:git-push[1] fails due to a
                non-fast-forward update to the current branch.
                'matching refs' explicitly (i.e. you used ':', or
                specified a refspec that isn't your current branch) and
                it resulted in a non-fast-forward error.
 +      pushAlreadyExists::
 +              Shown when linkgit:git-push[1] rejects an update that
 +              does not qualify for fast-forwarding (e.g., a tag.)
        statusHints::
                Show directions on how to proceed from the current
 -              state in the output of linkgit:git-status[1] and in
 +              state in the output of linkgit:git-status[1], in
                the template shown when writing commit messages in
 -              linkgit:git-commit[1].
 +              linkgit:git-commit[1], and in the help message shown
 +              by linkgit:git-checkout[1] when switching branch.
        commitBeforeMerge::
                Advice shown when linkgit:git-merge[1] refuses to
                merge to avoid overwriting local changes.
@@@ -543,14 -538,14 +543,14 @@@ core.pager:
        `LESS` variable to some other value.  Alternately,
        these settings can be overridden on a project or
        global basis by setting the `core.pager` option.
 -      Setting `core.pager` has no affect on the `LESS`
 +      Setting `core.pager` has no effect on the `LESS`
        environment variable behaviour above, so if you want
        to override git's default settings this way, you need
        to be explicit.  For example, to disable the S option
        in a backward compatible manner, set `core.pager`
 -      to `less -+$LESS -FRX`.  This will be passed to the
 -      shell by git, which will translate the final command to
 -      `LESS=FRSX less -+FRSX -FRX`.
 +      to `less -+S`.  This will be passed to the shell by
 +      git, which will translate the final command to
 +      `LESS=FRSX less -+S`.
  
  core.whitespace::
        A comma separated list of common whitespace problems to
@@@ -739,6 -734,12 +739,12 @@@ branch.<name>.rebase:
  it unless you understand the implications (see linkgit:git-rebase[1]
  for details).
  
+ branch.<name>.description::
+       Branch description, can be edited with
+       `git branch --edit-description`. Branch description is
+       automatically added in the format-patch cover letter or
+       request-pull summary.
  browser.<tool>.cmd::
        Specify the command to invoke the specified browser. The
        specified command is evaluated in shell with the URLs passed
@@@ -967,6 -968,12 +973,6 @@@ difftool.<tool>.cmd:
  difftool.prompt::
        Prompt before each invocation of the diff tool.
  
 -diff.wordRegex::
 -      A POSIX Extended Regular Expression used to determine what is a "word"
 -      when performing word-by-word difference calculations.  Character
 -      sequences that match the regular expression are "words", all other
 -      characters are *ignorable* whitespace.
 -
  fetch.recurseSubmodules::
        This option can be either set to a boolean value or to 'on-demand'.
        Setting it to a boolean changes the behavior of fetch and pull to
@@@ -1210,16 -1217,8 +1216,16 @@@ gitweb.snapshot:
  grep.lineNumber::
        If set to true, enable '-n' option by default.
  
 +grep.patternType::
 +      Set the default matching behavior. Using a value of 'basic', 'extended',
 +      'fixed', or 'perl' will enable the '--basic-regexp', '--extended-regexp',
 +      '--fixed-strings', or '--perl-regexp' option accordingly, while the
 +      value 'default' will return to the default matching behavior.
 +
  grep.extendedRegexp::
 -      If set to true, enable '--extended-regexp' option by default.
 +      If set to true, enable '--extended-regexp' option by default. This
 +      option is ignored when the 'grep.patternType' option is set to a value
 +      other than 'default'.
  
  gpg.program::
        Use this custom program instead of "gpg" found on $PATH when
@@@ -1521,14 -1520,6 +1527,14 @@@ mailmap.file:
        subdirectory, or somewhere outside of the repository itself.
        See linkgit:git-shortlog[1] and linkgit:git-blame[1].
  
 +mailmap.blob::
 +      Like `mailmap.file`, but consider the value as a reference to a
 +      blob in the repository. If both `mailmap.file` and
 +      `mailmap.blob` are given, both are parsed, with entries from
 +      `mailmap.file` taking precedence. In a bare repository, this
 +      defaults to `HEAD:.mailmap`. In a non-bare repository, it
 +      defaults to empty.
 +
  man.viewer::
        Specify the programs that may be used to display help in the
        'man' format. See linkgit:git-help[1].
@@@ -2007,12 -1998,6 +2013,12 @@@ submodule.<name>.update:
        URL and other values found in the `.gitmodules` file.  See
        linkgit:git-submodule[1] and linkgit:gitmodules[5] for details.
  
 +submodule.<name>.branch::
 +      The remote branch name for a submodule, used by `git submodule
 +      update --remote`.  Set this option to override the value found in
 +      the `.gitmodules` file.  See linkgit:git-submodule[1] and
 +      linkgit:gitmodules[5] for details.
 +
  submodule.<name>.fetchRecurseSubmodules::
        This option can be used to control recursive fetching of this
        submodule. It can be overridden by using the --[no-]recurse-submodules
diff --combined builtin/branch.c
index 1ec9c02612d0391984b484a5850f45c277a3e804,a6d33502f238168a604ca10455cc46239c06745a..873f624d1cc70e03da4c67b30f8c839b4afe099d
  #include "revision.h"
  #include "string-list.h"
  #include "column.h"
 +#include "utf8.h"
  
  static const char * const builtin_branch_usage[] = {
 -      "git branch [options] [-r | -a] [--merged | --no-merged]",
 -      "git branch [options] [-l] [-f] <branchname> [<start-point>]",
 -      "git branch [options] [-r] (-d | -D) <branchname>...",
 -      "git branch [options] (-m | -M) [<oldbranch>] <newbranch>",
 +      N_("git branch [options] [-r | -a] [--merged | --no-merged]"),
 +      N_("git branch [options] [-l] [-f] <branchname> [<start-point>]"),
 +      N_("git branch [options] [-r] (-d | -D) <branchname>..."),
 +      N_("git branch [options] (-m | -M) [<oldbranch>] <newbranch>"),
        NULL
  };
  
@@@ -130,7 -129,7 +130,7 @@@ static int branch_merged(int kind, cons
        if (!reference_rev)
                reference_rev = head_rev;
  
 -      merged = in_merge_bases(rev, &reference_rev, 1);
 +      merged = in_merge_bases(rev, reference_rev);
  
        /*
         * After the safety valve is fully redefined to "check with
         * a gentle reminder is in order.
         */
        if ((head_rev != reference_rev) &&
 -          in_merge_bases(rev, &head_rev, 1) != merged) {
 +          in_merge_bases(rev, head_rev) != merged) {
                if (merged)
                        warning(_("deleting branch '%s' that has been merged to\n"
                                "         '%s', but not yet merged to HEAD."),
        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;
                        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' "
  
                free(name);
  
 -              name = xstrdup(mkpath(fmt, bname.buf));
 -              if (read_ref(name, sha1)) {
 +              name = mkpathdup(fmt, bname.buf);
 +              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);
                        continue;
                }
  
 -              rev = lookup_commit_reference(sha1);
 -              if (!rev) {
 -                      error(_("Couldn't look up commit object for '%s'"), name);
 -                      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);
 +              if (!(flags & REF_ISSYMREF) &&
 +                  check_branch_commit(bname.buf, name, sha1, head_rev, kinds,
 +                                      force)) {
                        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);
  struct ref_item {
        char *name;
        char *dest;
 -      unsigned int kind, len;
 +      unsigned int kind, width;
        struct commit *commit;
  };
  
@@@ -378,14 -354,14 +378,14 @@@ static int append_ref(const char *refna
        newitem->name = xstrdup(refname);
        newitem->kind = kind;
        newitem->commit = commit;
 -      newitem->len = strlen(refname);
 +      newitem->width = utf8_strwidth(refname);
        newitem->dest = resolve_symref(orig_refname, prefix);
        /* adjust for "remotes/" */
        if (newitem->kind == REF_REMOTE_BRANCH &&
            ref_list->kinds != REF_REMOTE_BRANCH)
 -              newitem->len += 8;
 -      if (newitem->len > ref_list->maxwidth)
 -              ref_list->maxwidth = newitem->len;
 +              newitem->width += 8;
 +      if (newitem->width > ref_list->maxwidth)
 +              ref_list->maxwidth = newitem->width;
  
        return 0;
  }
@@@ -514,12 -490,11 +514,12 @@@ static void print_ref_item(struct ref_i
        }
  
        strbuf_addf(&name, "%s%s", prefix, item->name);
 -      if (verbose)
 +      if (verbose) {
 +              int utf8_compensation = strlen(name.buf) - utf8_strwidth(name.buf);
                strbuf_addf(&out, "%c %s%-*s%s", c, branch_get_color(color),
 -                          maxwidth, name.buf,
 +                          maxwidth + utf8_compensation, name.buf,
                            branch_get_color(BRANCH_COLOR_RESET));
 -      else
 +      else
                strbuf_addf(&out, "%c %s%s%s", c, branch_get_color(color),
                            name.buf, branch_get_color(BRANCH_COLOR_RESET));
  
@@@ -544,8 -519,8 +544,8 @@@ static int calc_maxwidth(struct ref_lis
        for (i = 0; i < refs->index; i++) {
                if (!matches_merge_filter(refs->list[i].commit))
                        continue;
 -              if (refs->list[i].len > w)
 -                      w = refs->list[i].len;
 +              if (refs->list[i].width > w)
 +                      w = refs->list[i].width;
        }
        return w;
  }
@@@ -558,12 -533,12 +558,12 @@@ static void show_detached(struct ref_li
        if (head_commit && is_descendant_of(head_commit, ref_list->with_commit)) {
                struct ref_item item;
                item.name = xstrdup(_("(no branch)"));
 -              item.len = strlen(item.name);
 +              item.width = utf8_strwidth(item.name);
                item.kind = REF_LOCAL_BRANCH;
                item.dest = NULL;
                item.commit = head_commit;
 -              if (item.len > ref_list->maxwidth)
 -                      ref_list->maxwidth = item.len;
 +              if (item.width > ref_list->maxwidth)
 +                      ref_list->maxwidth = item.width;
                print_ref_item(&item, ref_list->maxwidth, ref_list->verbose, ref_list->abbrev, 1, "");
                free(item.name);
        }
@@@ -725,7 -700,7 +725,7 @@@ static int edit_branch_description(cons
        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);
  
@@@ -737,65 -712,62 +737,65 @@@ int cmd_branch(int argc, const char **a
        int delete = 0, rename = 0, force_create = 0, list = 0;
        int verbose = 0, abbrev = -1, detached = 0;
        int reflog = 0, edit_description = 0;
 -      int quiet = 0;
 +      int quiet = 0, unset_upstream = 0;
 +      const char *new_upstream = NULL;
        enum branch_track track;
        int kinds = REF_LOCAL_BRANCH;
        struct commit_list *with_commit = NULL;
  
        struct option options[] = {
 -              OPT_GROUP("Generic options"),
 +              OPT_GROUP(N_("Generic options")),
                OPT__VERBOSE(&verbose,
 -                      "show hash and subject, give twice for upstream branch"),
 -              OPT__QUIET(&quiet, "suppress informational messages"),
 -              OPT_SET_INT('t', "track",  &track, "set up tracking mode (see git-pull(1))",
 +                      N_("show hash and subject, give twice for upstream branch")),
 +              OPT__QUIET(&quiet, N_("suppress informational messages")),
 +              OPT_SET_INT('t', "track",  &track, N_("set up tracking mode (see git-pull(1))"),
                        BRANCH_TRACK_EXPLICIT),
 -              OPT_SET_INT( 0, "set-upstream",  &track, "change upstream info",
 +              OPT_SET_INT( 0, "set-upstream",  &track, N_("change upstream info"),
                        BRANCH_TRACK_OVERRIDE),
 -              OPT__COLOR(&branch_use_color, "use colored output"),
 -              OPT_SET_INT('r', "remotes",     &kinds, "act on remote-tracking branches",
 +              OPT_STRING('u', "set-upstream-to", &new_upstream, "upstream", "change the upstream info"),
 +              OPT_BOOLEAN(0, "unset-upstream", &unset_upstream, "Unset the upstream info"),
 +              OPT__COLOR(&branch_use_color, N_("use colored output")),
 +              OPT_SET_INT('r', "remotes",     &kinds, N_("act on remote-tracking branches"),
                        REF_REMOTE_BRANCH),
                {
 -                      OPTION_CALLBACK, 0, "contains", &with_commit, "commit",
 -                      "print only branches that contain the commit",
 +                      OPTION_CALLBACK, 0, "contains", &with_commit, N_("commit"),
 +                      N_("print only branches that contain the commit"),
                        PARSE_OPT_LASTARG_DEFAULT,
                        parse_opt_with_commit, (intptr_t)"HEAD",
                },
                {
 -                      OPTION_CALLBACK, 0, "with", &with_commit, "commit",
 -                      "print only branches that contain the commit",
 +                      OPTION_CALLBACK, 0, "with", &with_commit, N_("commit"),
 +                      N_("print only branches that contain the commit"),
                        PARSE_OPT_HIDDEN | PARSE_OPT_LASTARG_DEFAULT,
                        parse_opt_with_commit, (intptr_t) "HEAD",
                },
                OPT__ABBREV(&abbrev),
  
 -              OPT_GROUP("Specific git-branch actions:"),
 -              OPT_SET_INT('a', "all", &kinds, "list both remote-tracking and local branches",
 +              OPT_GROUP(N_("Specific git-branch actions:")),
 +              OPT_SET_INT('a', "all", &kinds, N_("list both remote-tracking and local branches"),
                        REF_REMOTE_BRANCH | REF_LOCAL_BRANCH),
 -              OPT_BIT('d', "delete", &delete, "delete fully merged branch", 1),
 -              OPT_BIT('D', NULL, &delete, "delete branch (even if not merged)", 2),
 -              OPT_BIT('m', "move", &rename, "move/rename a branch and its reflog", 1),
 -              OPT_BIT('M', NULL, &rename, "move/rename a branch, even if target exists", 2),
 -              OPT_BOOLEAN(0, "list", &list, "list branch names"),
 -              OPT_BOOLEAN('l', "create-reflog", &reflog, "create the branch's reflog"),
 +              OPT_BIT('d', "delete", &delete, N_("delete fully merged branch"), 1),
 +              OPT_BIT('D', NULL, &delete, N_("delete branch (even if not merged)"), 2),
 +              OPT_BIT('m', "move", &rename, N_("move/rename a branch and its reflog"), 1),
 +              OPT_BIT('M', NULL, &rename, N_("move/rename a branch, even if target exists"), 2),
 +              OPT_BOOLEAN(0, "list", &list, N_("list branch names")),
 +              OPT_BOOLEAN('l', "create-reflog", &reflog, N_("create the branch's reflog")),
                OPT_BOOLEAN(0, "edit-description", &edit_description,
 -                          "edit the description for the branch"),
 -              OPT__FORCE(&force_create, "force creation (when already exists)"),
 +                          N_("edit the description for the branch")),
 +              OPT__FORCE(&force_create, N_("force creation (when already exists)")),
                {
                        OPTION_CALLBACK, 0, "no-merged", &merge_filter_ref,
 -                      "commit", "print only not merged branches",
 +                      N_("commit"), N_("print only not merged branches"),
                        PARSE_OPT_LASTARG_DEFAULT | PARSE_OPT_NONEG,
                        opt_parse_merge_filter, (intptr_t) "HEAD",
                },
                {
                        OPTION_CALLBACK, 0, "merged", &merge_filter_ref,
 -                      "commit", "print only merged branches",
 +                      N_("commit"), N_("print only merged branches"),
                        PARSE_OPT_LASTARG_DEFAULT | PARSE_OPT_NONEG,
                        opt_parse_merge_filter, (intptr_t) "HEAD",
                },
 -              OPT_COLUMN(0, "column", &colopts, "list branches in columns"),
 +              OPT_COLUMN(0, "column", &colopts, N_("list branches in columns")),
                OPT_END(),
        };
  
        argc = parse_options(argc, argv, prefix, options, builtin_branch_usage,
                             0);
  
 -      if (!delete && !rename && !edit_description && argc == 0)
 +      if (!delete && !rename && !edit_description && !new_upstream && !unset_upstream && argc == 0)
                list = 1;
  
 -      if (!!delete + !!rename + !!force_create + !!list > 1)
 +      if (!!delete + !!rename + !!force_create + !!list + !!new_upstream + !!unset_upstream > 1)
                usage_with_options(builtin_branch_usage, options);
  
        if (abbrev == -1)
                        rename_branch(argv[0], argv[1], rename > 1);
                else
                        usage_with_options(builtin_branch_usage, options);
 +      } else if (new_upstream) {
 +              struct branch *branch = branch_get(argv[0]);
 +
 +              if (!ref_exists(branch->refname))
 +                      die(_("branch '%s' does not exist"), branch->name);
 +
 +              /*
 +               * create_branch takes care of setting up the tracking
 +               * info and making sure new_upstream is correct
 +               */
 +              create_branch(head, branch->name, new_upstream, 0, 0, 0, quiet, BRANCH_TRACK_OVERRIDE);
 +      } else if (unset_upstream) {
 +              struct branch *branch = branch_get(argv[0]);
 +              struct strbuf buf = STRBUF_INIT;
 +
 +              if (!branch_has_merge_config(branch)) {
 +                      die(_("Branch '%s' has no upstream information"), branch->name);
 +              }
 +
 +              strbuf_addf(&buf, "branch.%s.remote", branch->name);
 +              git_config_set_multivar(buf.buf, NULL, NULL, 1);
 +              strbuf_reset(&buf);
 +              strbuf_addf(&buf, "branch.%s.merge", branch->name);
 +              git_config_set_multivar(buf.buf, NULL, NULL, 1);
 +              strbuf_release(&buf);
        } else if (argc > 0 && argc <= 2) {
 +              struct branch *branch = branch_get(argv[0]);
 +              int branch_existed = 0, remote_tracking = 0;
 +              struct strbuf buf = STRBUF_INIT;
 +
                if (kinds != REF_LOCAL_BRANCH)
                        die(_("-a and -r options to 'git branch' do not make sense with a branch name"));
 +
 +              if (track == BRANCH_TRACK_OVERRIDE)
 +                      fprintf(stderr, _("The --set-upstream flag is deprecated and will be removed. Consider using --track or --set-upstream-to\n"));
 +
 +              strbuf_addf(&buf, "refs/remotes/%s", branch->name);
 +              remote_tracking = ref_exists(buf.buf);
 +              strbuf_release(&buf);
 +
 +              branch_existed = ref_exists(branch->refname);
                create_branch(head, argv[0], (argc == 2) ? argv[1] : head,
                              force_create, reflog, 0, quiet, track);
 +
 +              /*
 +               * We only show the instructions if the user gave us
 +               * one branch which doesn't exist locally, but is the
 +               * name of a remote-tracking branch.
 +               */
 +              if (argc == 1 && track == BRANCH_TRACK_OVERRIDE &&
 +                  !branch_existed && remote_tracking) {
 +                      fprintf(stderr, _("\nIf you wanted to make '%s' track '%s', do this:\n\n"), head, branch->name);
 +                      fprintf(stderr, _("    git branch -d %s\n"), branch->name);
 +                      fprintf(stderr, _("    git branch --set-upstream-to %s\n"), branch->name);
 +              }
 +
        } else
                usage_with_options(builtin_branch_usage, options);
  
diff --combined builtin/log.c
index e7b7db1cacf1934a9bb0b96beb98ddda15a66074,8f488853e18aceb56c00ebacd1da578365a4ea64..3899b1d43acc8c51e7609be94469eac057116440
@@@ -34,8 -34,8 +34,8 @@@ static const char *fmt_patch_subject_pr
  static const char *fmt_pretty;
  
  static const char * const builtin_log_usage[] = {
 -      "git log [<options>] [<since>..<until>] [[--] <path>...]\n"
 -      "   or: git show [options] <object>...",
 +      N_("git log [<options>] [<since>..<until>] [[--] <path>...]\n")
 +      N_("   or: git show [options] <object>..."),
        NULL
  };
  
@@@ -97,9 -97,9 +97,9 @@@ static void cmd_log_init_finish(int arg
        int quiet = 0, source = 0;
  
        const struct option builtin_log_options[] = {
 -              OPT_BOOLEAN(0, "quiet", &quiet, "suppress diff output"),
 -              OPT_BOOLEAN(0, "source", &source, "show source"),
 -              { OPTION_CALLBACK, 0, "decorate", NULL, NULL, "decorate options",
 +              OPT_BOOLEAN(0, "quiet", &quiet, N_("suppress diff output")),
 +              OPT_BOOLEAN(0, "source", &source, N_("show source")),
 +              { OPTION_CALLBACK, 0, "decorate", NULL, NULL, N_("decorate options"),
                  PARSE_OPT_OPTARG, decorate_callback},
                OPT_END()
        };
@@@ -351,8 -351,7 +351,8 @@@ static int git_log_config(const char *v
        }
        if (!prefixcmp(var, "color.decorate."))
                return parse_decorate_color_config(var, 15, value);
 -
 +      if (grep_config(var, value, cb) < 0)
 +              return -1;
        return git_diff_ui_config(var, value, cb);
  }
  
@@@ -361,7 -360,6 +361,7 @@@ int cmd_whatchanged(int argc, const cha
        struct rev_info rev;
        struct setup_revision_opt opt;
  
 +      init_grep_defaults();
        git_config(git_log_config, NULL);
  
        init_revisions(&rev, prefix);
@@@ -452,7 -450,6 +452,7 @@@ int cmd_show(int argc, const char **arg
        struct pathspec match_all;
        int i, count, ret = 0;
  
 +      init_grep_defaults();
        git_config(git_log_config, NULL);
  
        init_pathspec(&match_all, NULL);
@@@ -533,7 -530,6 +533,7 @@@ int cmd_log_reflog(int argc, const cha
        struct rev_info rev;
        struct setup_revision_opt opt;
  
 +      init_grep_defaults();
        git_config(git_log_config, NULL);
  
        init_revisions(&rev, prefix);
@@@ -556,7 -552,6 +556,7 @@@ int cmd_log(int argc, const char **argv
        struct rev_info rev;
        struct setup_revision_opt opt;
  
 +      init_grep_defaults();
        git_config(git_log_config, NULL);
  
        init_revisions(&rev, prefix);
@@@ -701,7 -696,7 +701,7 @@@ static int reopen_stdout(struct commit 
        return 0;
  }
  
 -static void get_patch_ids(struct rev_info *rev, struct patch_ids *ids, const char *prefix)
 +static void get_patch_ids(struct rev_info *rev, struct patch_ids *ids)
  {
        struct rev_info check_rev;
        struct commit *commit;
        init_patch_ids(ids);
  
        /* given a range a..b get all patch ids for b..a */
 -      init_revisions(&check_rev, prefix);
 +      init_revisions(&check_rev, rev->prefix);
 +      check_rev.max_parents = 1;
        o1->flags ^= UNINTERESTING;
        o2->flags ^= UNINTERESTING;
        add_pending_object(&check_rev, o1, "o1");
                die(_("revision walk setup failed"));
  
        while ((commit = get_revision(&check_rev)) != NULL) {
 -              /* ignore merges */
 -              if (commit->parents && commit->parents->next)
 -                      continue;
 -
                add_commit_patch_id(commit, ids);
        }
  
@@@ -892,7 -890,7 +892,7 @@@ static const char *set_outdir(const cha
  }
  
  static const char * const builtin_format_patch_usage[] = {
 -      "git format-patch [options] [<since> | <revision range>]",
 +      N_("git format-patch [options] [<since> | <revision range>]"),
        NULL
  };
  
@@@ -1016,8 -1014,9 +1016,9 @@@ static char *find_branch_name(struct re
  {
        int i, positive = -1;
        unsigned char branch_sha1[20];
-       struct strbuf buf = STRBUF_INIT;
-       const char *branch;
+       const unsigned char *tip_sha1;
+       const char *ref;
+       char *full_ref, *branch = NULL;
  
        for (i = 0; i < rev->cmdline.nr; i++) {
                if (rev->cmdline.rev[i].flags & UNINTERESTING)
                else
                        return NULL;
        }
-       if (positive < 0)
+       if (0 <= positive) {
+               ref = rev->cmdline.rev[positive].name;
+               tip_sha1 = rev->cmdline.rev[positive].item->sha1;
+       } else if (!rev->cmdline.nr && rev->pending.nr == 1 &&
+                  !strcmp(rev->pending.objects[0].name, "HEAD")) {
+               /*
+                * No actual ref from command line, but "HEAD" from
+                * rev->def was added in setup_revisions()
+                * e.g. format-patch --cover-letter -12
+                */
+               ref = "HEAD";
+               tip_sha1 = rev->pending.objects[0].item->sha1;
+       } else {
                return NULL;
-       strbuf_addf(&buf, "refs/heads/%s", rev->cmdline.rev[positive].name);
-       branch = resolve_ref_unsafe(buf.buf, branch_sha1, 1, NULL);
-       if (!branch ||
-           prefixcmp(branch, "refs/heads/") ||
-           hashcmp(rev->cmdline.rev[positive].item->sha1, branch_sha1))
-               branch = NULL;
-       strbuf_release(&buf);
-       if (branch)
-               return xstrdup(rev->cmdline.rev[positive].name);
-       return NULL;
+       }
+       if (dwim_ref(ref, strlen(ref), branch_sha1, &full_ref) &&
+           !prefixcmp(full_ref, "refs/heads/") &&
+           !hashcmp(tip_sha1, branch_sha1))
+               branch = xstrdup(full_ref + strlen("refs/heads/"));
+       free(full_ref);
+       return branch;
  }
  
  int cmd_format_patch(int argc, const char **argv, const char *prefix)
        char *branch_name = NULL;
        const struct option builtin_format_patch_options[] = {
                { OPTION_CALLBACK, 'n', "numbered", &numbered, NULL,
 -                          "use [PATCH n/m] even with a single patch",
 +                          N_("use [PATCH n/m] even with a single patch"),
                            PARSE_OPT_NOARG, numbered_callback },
                { OPTION_CALLBACK, 'N', "no-numbered", &numbered, NULL,
 -                          "use [PATCH] even with multiple patches",
 +                          N_("use [PATCH] even with multiple patches"),
                            PARSE_OPT_NOARG, no_numbered_callback },
 -              OPT_BOOLEAN('s', "signoff", &do_signoff, "add Signed-off-by:"),
 +              OPT_BOOLEAN('s', "signoff", &do_signoff, N_("add Signed-off-by:")),
                OPT_BOOLEAN(0, "stdout", &use_stdout,
 -                          "print patches to standard out"),
 +                          N_("print patches to standard out")),
                OPT_BOOLEAN(0, "cover-letter", &cover_letter,
 -                          "generate a cover letter"),
 +                          N_("generate a cover letter")),
                OPT_BOOLEAN(0, "numbered-files", &numbered_files,
 -                          "use simple number sequence for output file names"),
 -              OPT_STRING(0, "suffix", &fmt_patch_suffix, "sfx",
 -                          "use <sfx> instead of '.patch'"),
 +                          N_("use simple number sequence for output file names")),
 +              OPT_STRING(0, "suffix", &fmt_patch_suffix, N_("sfx"),
 +                          N_("use <sfx> instead of '.patch'")),
                OPT_INTEGER(0, "start-number", &start_number,
 -                          "start numbering patches at <n> instead of 1"),
 -              { OPTION_CALLBACK, 0, "subject-prefix", &rev, "prefix",
 -                          "Use [<prefix>] instead of [PATCH]",
 +                          N_("start numbering patches at <n> instead of 1")),
 +              { OPTION_CALLBACK, 0, "subject-prefix", &rev, N_("prefix"),
 +                          N_("Use [<prefix>] instead of [PATCH]"),
                            PARSE_OPT_NONEG, subject_prefix_callback },
                { OPTION_CALLBACK, 'o', "output-directory", &output_directory,
 -                          "dir", "store resulting files in <dir>",
 +                          N_("dir"), N_("store resulting files in <dir>"),
                            PARSE_OPT_NONEG, output_directory_callback },
                { OPTION_CALLBACK, 'k', "keep-subject", &rev, NULL,
 -                          "don't strip/add [PATCH]",
 +                          N_("don't strip/add [PATCH]"),
                            PARSE_OPT_NOARG | PARSE_OPT_NONEG, keep_callback },
                OPT_BOOLEAN(0, "no-binary", &no_binary_diff,
 -                          "don't output binary diffs"),
 +                          N_("don't output binary diffs")),
                OPT_BOOLEAN(0, "ignore-if-in-upstream", &ignore_if_in_upstream,
 -                          "don't include a patch matching a commit upstream"),
 +                          N_("don't include a patch matching a commit upstream")),
                { OPTION_BOOLEAN, 'p', "no-stat", &use_patch_format, NULL,
 -                "show patch format instead of default (patch + stat)",
 +                N_("show patch format instead of default (patch + stat)"),
                  PARSE_OPT_NONEG | PARSE_OPT_NOARG },
 -              OPT_GROUP("Messaging"),
 -              { OPTION_CALLBACK, 0, "add-header", NULL, "header",
 -                          "add email header", 0, header_callback },
 -              { OPTION_CALLBACK, 0, "to", NULL, "email", "add To: header",
 +              OPT_GROUP(N_("Messaging")),
 +              { OPTION_CALLBACK, 0, "add-header", NULL, N_("header"),
 +                          N_("add email header"), 0, header_callback },
 +              { OPTION_CALLBACK, 0, "to", NULL, N_("email"), N_("add To: header"),
                            0, to_callback },
 -              { OPTION_CALLBACK, 0, "cc", NULL, "email", "add Cc: header",
 +              { OPTION_CALLBACK, 0, "cc", NULL, N_("email"), N_("add Cc: header"),
                            0, cc_callback },
 -              OPT_STRING(0, "in-reply-to", &in_reply_to, "message-id",
 -                          "make first mail a reply to <message-id>"),
 -              { OPTION_CALLBACK, 0, "attach", &rev, "boundary",
 -                          "attach the patch", PARSE_OPT_OPTARG,
 +              OPT_STRING(0, "in-reply-to", &in_reply_to, N_("message-id"),
 +                          N_("make first mail a reply to <message-id>")),
 +              { OPTION_CALLBACK, 0, "attach", &rev, N_("boundary"),
 +                          N_("attach the patch"), PARSE_OPT_OPTARG,
                            attach_callback },
 -              { OPTION_CALLBACK, 0, "inline", &rev, "boundary",
 -                          "inline the patch",
 +              { OPTION_CALLBACK, 0, "inline", &rev, N_("boundary"),
 +                          N_("inline the patch"),
                            PARSE_OPT_OPTARG | PARSE_OPT_NONEG,
                            inline_callback },
 -              { OPTION_CALLBACK, 0, "thread", &thread, "style",
 -                          "enable message threading, styles: shallow, deep",
 +              { OPTION_CALLBACK, 0, "thread", &thread, N_("style"),
 +                          N_("enable message threading, styles: shallow, deep"),
                            PARSE_OPT_OPTARG, thread_callback },
 -              OPT_STRING(0, "signature", &signature, "signature",
 -                          "add a signature"),
 +              OPT_STRING(0, "signature", &signature, N_("signature"),
 +                          N_("add a signature")),
                OPT_BOOLEAN(0, "quiet", &quiet,
 -                          "don't print the patch filenames"),
 +                          N_("don't print the patch filenames")),
                OPT_END()
        };
  
        extra_hdr.strdup_strings = 1;
        extra_to.strdup_strings = 1;
        extra_cc.strdup_strings = 1;
 +      init_grep_defaults();
        git_config(git_format_config, NULL);
        init_revisions(&rev, prefix);
        rev.commit_format = CMIT_FMT_EMAIL;
                        if (hashcmp(o[0].item->sha1, o[1].item->sha1) == 0)
                                return 0;
                }
 -              get_patch_ids(&rev, &ids, prefix);
 +              get_patch_ids(&rev, &ids);
        }
  
        if (!use_stdout)
@@@ -1446,7 -1453,7 +1456,7 @@@ static int add_pending_commit(const cha
  }
  
  static const char * const cherry_usage[] = {
 -      "git cherry [-v] [<upstream> [<head> [<limit>]]]",
 +      N_("git cherry [-v] [<upstream> [<head> [<limit>]]]"),
        NULL
  };
  
@@@ -1480,7 -1487,7 +1490,7 @@@ int cmd_cherry(int argc, const char **a
  
        struct option options[] = {
                OPT__ABBREV(&abbrev),
 -              OPT__VERBOSE(&verbose, "be verbose"),
 +              OPT__VERBOSE(&verbose, N_("be verbose")),
                OPT_END()
        };
  
        }
  
        init_revisions(&revs, prefix);
 -      revs.diff = 1;
 -      revs.combine_merges = 0;
 -      revs.ignore_merges = 1;
 -      DIFF_OPT_SET(&revs.diffopt, RECURSIVE);
 +      revs.max_parents = 1;
  
        if (add_pending_commit(head, &revs, 0))
                die(_("Unknown commit %s"), head);
                        return 0;
        }
  
 -      get_patch_ids(&revs, &ids, prefix);
 +      get_patch_ids(&revs, &ids);
  
        if (limit && add_pending_commit(limit, &revs, UNINTERESTING))
                die(_("Unknown commit %s"), limit);
        if (prepare_revision_walk(&revs))
                die(_("revision walk setup failed"));
        while ((commit = get_revision(&revs)) != NULL) {
 -              /* ignore merges */
 -              if (commit->parents && commit->parents->next)
 -                      continue;
 -
                commit_list_insert(commit, &list);
        }
  
diff --combined t/t4014-format-patch.sh
index 90fd598c747482354c7fa1a9fa281c26c06e9de8,8197c74fe5bf6b30392d66dbde352f292bd23bdf..dc0d8ae928229e3e0abbc1c486905f2a713075b5
@@@ -110,107 -110,73 +110,107 @@@ test_expect_success 'replay did not scr
  
  test_expect_success 'extra headers' '
  
 -      git config format.headers "To: R. E. Cipient <rcipient@example.com>
 +      git config format.headers "To: R E Cipient <rcipient@example.com>
  " &&
 -      git config --add format.headers "Cc: S. E. Cipient <scipient@example.com>
 +      git config --add format.headers "Cc: S E Cipient <scipient@example.com>
  " &&
        git format-patch --stdout master..side > patch2 &&
        sed -e "/^\$/q" patch2 > hdrs2 &&
 -      grep "^To: R. E. Cipient <rcipient@example.com>\$" hdrs2 &&
 -      grep "^Cc: S. E. Cipient <scipient@example.com>\$" hdrs2
 +      grep "^To: R E Cipient <rcipient@example.com>\$" hdrs2 &&
 +      grep "^Cc: S E Cipient <scipient@example.com>\$" hdrs2
  
  '
  
  test_expect_success 'extra headers without newlines' '
  
 -      git config --replace-all format.headers "To: R. E. Cipient <rcipient@example.com>" &&
 -      git config --add format.headers "Cc: S. E. Cipient <scipient@example.com>" &&
 +      git config --replace-all format.headers "To: R E Cipient <rcipient@example.com>" &&
 +      git config --add format.headers "Cc: S E Cipient <scipient@example.com>" &&
        git format-patch --stdout master..side >patch3 &&
        sed -e "/^\$/q" patch3 > hdrs3 &&
 -      grep "^To: R. E. Cipient <rcipient@example.com>\$" hdrs3 &&
 -      grep "^Cc: S. E. Cipient <scipient@example.com>\$" hdrs3
 +      grep "^To: R E Cipient <rcipient@example.com>\$" hdrs3 &&
 +      grep "^Cc: S E Cipient <scipient@example.com>\$" hdrs3
  
  '
  
  test_expect_success 'extra headers with multiple To:s' '
  
 -      git config --replace-all format.headers "To: R. E. Cipient <rcipient@example.com>" &&
 -      git config --add format.headers "To: S. E. Cipient <scipient@example.com>" &&
 +      git config --replace-all format.headers "To: R E Cipient <rcipient@example.com>" &&
 +      git config --add format.headers "To: S E Cipient <scipient@example.com>" &&
        git format-patch --stdout master..side > patch4 &&
        sed -e "/^\$/q" patch4 > hdrs4 &&
 -      grep "^To: R. E. Cipient <rcipient@example.com>,\$" hdrs4 &&
 -      grep "^ *S. E. Cipient <scipient@example.com>\$" hdrs4
 +      grep "^To: R E Cipient <rcipient@example.com>,\$" hdrs4 &&
 +      grep "^ *S E Cipient <scipient@example.com>\$" hdrs4
  '
  
 -test_expect_success 'additional command line cc' '
 +test_expect_success 'additional command line cc (ascii)' '
  
 -      git config --replace-all format.headers "Cc: R. E. Cipient <rcipient@example.com>" &&
 +      git config --replace-all format.headers "Cc: R E Cipient <rcipient@example.com>" &&
 +      git format-patch --cc="S E Cipient <scipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch5 &&
 +      grep "^Cc: R E Cipient <rcipient@example.com>,\$" patch5 &&
 +      grep "^ *S E Cipient <scipient@example.com>\$" patch5
 +'
 +
 +test_expect_failure 'additional command line cc (rfc822)' '
 +
 +      git config --replace-all format.headers "Cc: R E Cipient <rcipient@example.com>" &&
        git format-patch --cc="S. E. Cipient <scipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch5 &&
 -      grep "^Cc: R. E. Cipient <rcipient@example.com>,\$" patch5 &&
 -      grep "^ *S. E. Cipient <scipient@example.com>\$" patch5
 +      grep "^Cc: R E Cipient <rcipient@example.com>,\$" patch5 &&
 +      grep "^ *\"S. E. Cipient\" <scipient@example.com>\$" patch5
  '
  
  test_expect_success 'command line headers' '
  
        git config --unset-all format.headers &&
 -      git format-patch --add-header="Cc: R. E. Cipient <rcipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch6 &&
 -      grep "^Cc: R. E. Cipient <rcipient@example.com>\$" patch6
 +      git format-patch --add-header="Cc: R E Cipient <rcipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch6 &&
 +      grep "^Cc: R E Cipient <rcipient@example.com>\$" patch6
  '
  
  test_expect_success 'configuration headers and command line headers' '
  
 -      git config --replace-all format.headers "Cc: R. E. Cipient <rcipient@example.com>" &&
 -      git format-patch --add-header="Cc: S. E. Cipient <scipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch7 &&
 -      grep "^Cc: R. E. Cipient <rcipient@example.com>,\$" patch7 &&
 -      grep "^ *S. E. Cipient <scipient@example.com>\$" patch7
 +      git config --replace-all format.headers "Cc: R E Cipient <rcipient@example.com>" &&
 +      git format-patch --add-header="Cc: S E Cipient <scipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch7 &&
 +      grep "^Cc: R E Cipient <rcipient@example.com>,\$" patch7 &&
 +      grep "^ *S E Cipient <scipient@example.com>\$" patch7
  '
  
 -test_expect_success 'command line To: header' '
 +test_expect_success 'command line To: header (ascii)' '
  
        git config --unset-all format.headers &&
 +      git format-patch --to="R E Cipient <rcipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch8 &&
 +      grep "^To: R E Cipient <rcipient@example.com>\$" patch8
 +'
 +
 +test_expect_failure 'command line To: header (rfc822)' '
 +
        git format-patch --to="R. E. Cipient <rcipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch8 &&
 -      grep "^To: R. E. Cipient <rcipient@example.com>\$" patch8
 +      grep "^To: \"R. E. Cipient\" <rcipient@example.com>\$" patch8
 +'
 +
 +test_expect_failure 'command line To: header (rfc2047)' '
 +
 +      git format-patch --to="R Ä Cipient <rcipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch8 &&
 +      grep "^To: =?UTF-8?q?R=20=C3=84=20Cipient?= <rcipient@example.com>\$" patch8
 +'
 +
 +test_expect_success 'configuration To: header (ascii)' '
 +
 +      git config format.to "R E Cipient <rcipient@example.com>" &&
 +      git format-patch --stdout master..side | sed -e "/^\$/q" >patch9 &&
 +      grep "^To: R E Cipient <rcipient@example.com>\$" patch9
  '
  
 -test_expect_success 'configuration To: header' '
 +test_expect_failure 'configuration To: header (rfc822)' '
  
        git config format.to "R. E. Cipient <rcipient@example.com>" &&
        git format-patch --stdout master..side | sed -e "/^\$/q" >patch9 &&
 -      grep "^To: R. E. Cipient <rcipient@example.com>\$" patch9
 +      grep "^To: \"R. E. Cipient\" <rcipient@example.com>\$" patch9
 +'
 +
 +test_expect_failure 'configuration To: header (rfc2047)' '
 +
 +      git config format.to "R Ä Cipient <rcipient@example.com>" &&
 +      git format-patch --stdout master..side | sed -e "/^\$/q" >patch9 &&
 +      grep "^To: =?UTF-8?q?R=20=C3=84=20Cipient?= <rcipient@example.com>\$" patch9
  '
  
  # check_patch <patch>: Verify that <patch> looks like a half-sane
@@@ -224,11 -190,11 +224,11 @@@ check_patch () 
  test_expect_success '--no-to overrides config.to' '
  
        git config --replace-all format.to \
 -              "R. E. Cipient <rcipient@example.com>" &&
 +              "R E Cipient <rcipient@example.com>" &&
        git format-patch --no-to --stdout master..side |
        sed -e "/^\$/q" >patch10 &&
        check_patch patch10 &&
 -      ! grep "^To: R. E. Cipient <rcipient@example.com>\$" patch10
 +      ! grep "^To: R E Cipient <rcipient@example.com>\$" patch10
  '
  
  test_expect_success '--no-to and --to replaces config.to' '
  test_expect_success '--no-cc overrides config.cc' '
  
        git config --replace-all format.cc \
 -              "C. E. Cipient <rcipient@example.com>" &&
 +              "C E Cipient <rcipient@example.com>" &&
        git format-patch --no-cc --stdout master..side |
        sed -e "/^\$/q" >patch12 &&
        check_patch patch12 &&
 -      ! grep "^Cc: C. E. Cipient <rcipient@example.com>\$" patch12
 +      ! grep "^Cc: C E Cipient <rcipient@example.com>\$" patch12
  '
  
  test_expect_success '--no-add-header overrides config.headers' '
  
        git config --replace-all format.headers \
 -              "Header1: B. E. Cipient <rcipient@example.com>" &&
 +              "Header1: B E Cipient <rcipient@example.com>" &&
        git format-patch --no-add-header --stdout master..side |
        sed -e "/^\$/q" >patch13 &&
        check_patch patch13 &&
 -      ! grep "^Header1: B. E. Cipient <rcipient@example.com>\$" patch13
 +      ! grep "^Header1: B E Cipient <rcipient@example.com>\$" patch13
  '
  
  test_expect_success 'multiple files' '
@@@ -650,19 -616,8 +650,19 @@@ test_expect_success 'format-patch --in-
  '
  
  test_expect_success 'format-patch --signoff' '
 -      git format-patch -1 --signoff --stdout |
 -      grep "^Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>"
 +      git format-patch -1 --signoff --stdout >out &&
 +      grep "^Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>" out
 +'
 +
 +test_expect_success 'format-patch --notes --signoff' '
 +      git notes --ref test add -m "test message" HEAD &&
 +      git format-patch -1 --signoff --stdout --notes=test >out &&
 +      # Three dashes must come after S-o-b
 +      ! sed "/^Signed-off-by: /q" out | grep "test message" &&
 +      sed "1,/^Signed-off-by: /d" out | grep "test message" &&
 +      # Notes message must come after three dashes
 +      ! sed "/^---$/q" out | grep "test message" &&
 +      sed "1,/^---$/d" out | grep "test message"
  '
  
  echo "fatal: --name-only does not make sense" > expect.name-only
@@@ -797,14 -752,16 +797,14 @@@ M64=$M8$M8$M8$M8$M8$M8$M8$M
  M512=$M64$M64$M64$M64$M64$M64$M64$M64
  cat >expect <<'EOF'
  Subject: [PATCH] foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo
 - bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
 - foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo
 - bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
 - foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo
 - bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
 - foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo
 - bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
 - foo bar foo bar foo bar foo bar
 + bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
 + foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo
 + bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
 + foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo
 + bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
 + foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
  EOF
 -test_expect_success 'format-patch wraps extremely long headers (ascii)' '
 +test_expect_success 'format-patch wraps extremely long subject (ascii)' '
        echo content >>file &&
        git add file &&
        git commit -m "$M512" &&
@@@ -817,31 -774,30 +817,31 @@@ M8="föö bar 
  M64=$M8$M8$M8$M8$M8$M8$M8$M8
  M512=$M64$M64$M64$M64$M64$M64$M64$M64
  cat >expect <<'EOF'
 -Subject: [PATCH] =?UTF-8?q?f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
 - =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
 - =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
 - =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
 - =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
 - =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
 - =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
 - =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
 - =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
 - =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
 - =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
 - =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
 - =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
 - =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
 - =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
 - =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
 - =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
 - =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
 - =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
 - =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
 - =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
 - =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?=
 +Subject: [PATCH] =?UTF-8?q?f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f?=
 + =?UTF-8?q?=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?=
 + =?UTF-8?q?=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20?=
 + =?UTF-8?q?bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6?=
 + =?UTF-8?q?=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3?=
 + =?UTF-8?q?=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
 + =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3?=
 + =?UTF-8?q?=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f?=
 + =?UTF-8?q?=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?=
 + =?UTF-8?q?=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20?=
 + =?UTF-8?q?bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6?=
 + =?UTF-8?q?=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3?=
 + =?UTF-8?q?=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
 + =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3?=
 + =?UTF-8?q?=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f?=
 + =?UTF-8?q?=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?=
 + =?UTF-8?q?=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20?=
 + =?UTF-8?q?bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6?=
 + =?UTF-8?q?=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3?=
 + =?UTF-8?q?=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
 + =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3?=
 + =?UTF-8?q?=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f?=
 + =?UTF-8?q?=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?=
  EOF
 -test_expect_success 'format-patch wraps extremely long headers (rfc2047)' '
 +test_expect_success 'format-patch wraps extremely long subject (rfc2047)' '
        rm -rf patches/ &&
        echo content >>file &&
        git add file &&
        test_cmp expect subject
  '
  
 -M8="foo_bar_"
 -M64=$M8$M8$M8$M8$M8$M8$M8$M8
 -cat >expect <<EOF
 -From: $M64
 - <foobar@foo.bar>
 -EOF
 -test_expect_success 'format-patch wraps non-quotable headers' '
 -      rm -rf patches/ &&
 -      echo content >>file &&
 -      git add file &&
 -      git commit -mfoo --author "$M64 <foobar@foo.bar>" &&
 -      git format-patch --stdout -1 >patch &&
 -      sed -n "/^From: /p; /^ /p; /^$/q" <patch >from &&
 -      test_cmp expect from
 -'
 -
  check_author() {
        echo content >>file &&
        git add file &&
        GIT_AUTHOR_NAME=$1 git commit -m author-check &&
        git format-patch --stdout -1 >patch &&
 -      grep ^From: patch >actual &&
 +      sed -n "/^From: /p; /^ /p; /^$/q" <patch >actual &&
        test_cmp expect actual
  }
  
  cat >expect <<'EOF'
  From: "Foo B. Bar" <author@example.com>
  EOF
 -test_expect_success 'format-patch quotes dot in headers' '
 +test_expect_success 'format-patch quotes dot in from-headers' '
        check_author "Foo B. Bar"
  '
  
  cat >expect <<'EOF'
  From: "Foo \"The Baz\" Bar" <author@example.com>
  EOF
 -test_expect_success 'format-patch quotes double-quote in headers' '
 +test_expect_success 'format-patch quotes double-quote in from-headers' '
        check_author "Foo \"The Baz\" Bar"
  '
  
  cat >expect <<'EOF'
 -From: =?UTF-8?q?"F=C3=B6o=20B.=20Bar"?= <author@example.com>
 +From: =?UTF-8?q?F=C3=B6o=20Bar?= <author@example.com>
 +EOF
 +test_expect_success 'format-patch uses rfc2047-encoded from-headers when necessary' '
 +      check_author "Föo Bar"
 +'
 +
 +cat >expect <<'EOF'
 +From: =?UTF-8?q?F=C3=B6o=20B=2E=20Bar?= <author@example.com>
  EOF
 -test_expect_success 'rfc2047-encoded headers also double-quote 822 specials' '
 +test_expect_success 'rfc2047-encoded from-headers leave no rfc822 specials' '
        check_author "Föo B. Bar"
  '
  
 +cat >expect <<EOF
 +From: foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_
 + <author@example.com>
 +EOF
 +test_expect_success 'format-patch wraps moderately long from-header (ascii)' '
 +      check_author "foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_"
 +'
 +
 +cat >expect <<'EOF'
 +From: Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar
 + Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo
 + Bar Foo Bar Foo Bar Foo Bar <author@example.com>
 +EOF
 +test_expect_success 'format-patch wraps extremely long from-header (ascii)' '
 +      check_author "Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar"
 +'
 +
 +cat >expect <<'EOF'
 +From: "Foo.Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar
 + Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo
 + Bar Foo Bar Foo Bar Foo Bar" <author@example.com>
 +EOF
 +test_expect_success 'format-patch wraps extremely long from-header (rfc822)' '
 +      check_author "Foo.Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar"
 +'
 +
 +cat >expect <<'EOF'
 +From: =?UTF-8?q?Fo=C3=B6=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo?=
 + =?UTF-8?q?=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20?=
 + =?UTF-8?q?Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar?=
 + =?UTF-8?q?=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20?=
 + =?UTF-8?q?Foo=20Bar=20Foo=20Bar?= <author@example.com>
 +EOF
 +test_expect_success 'format-patch wraps extremely long from-header (rfc2047)' '
 +      check_author "Foö Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar"
 +'
 +
  cat >expect <<'EOF'
  Subject: header with . in it
  EOF
@@@ -963,4 -891,46 +963,46 @@@ test_expect_success 'format patch ignor
        test_cmp expect actual
  '
  
+ test_expect_success 'cover letter using branch description (1)' '
+       git checkout rebuild-1 &&
+       test_config branch.rebuild-1.description hello &&
+       git format-patch --stdout --cover-letter master >actual &&
+       grep hello actual >/dev/null
+ '
+ test_expect_success 'cover letter using branch description (2)' '
+       git checkout rebuild-1 &&
+       test_config branch.rebuild-1.description hello &&
+       git format-patch --stdout --cover-letter rebuild-1~2..rebuild-1 >actual &&
+       grep hello actual >/dev/null
+ '
+ test_expect_success 'cover letter using branch description (3)' '
+       git checkout rebuild-1 &&
+       test_config branch.rebuild-1.description hello &&
+       git format-patch --stdout --cover-letter ^master rebuild-1 >actual &&
+       grep hello actual >/dev/null
+ '
+ test_expect_success 'cover letter using branch description (4)' '
+       git checkout rebuild-1 &&
+       test_config branch.rebuild-1.description hello &&
+       git format-patch --stdout --cover-letter master.. >actual &&
+       grep hello actual >/dev/null
+ '
+ test_expect_success 'cover letter using branch description (5)' '
+       git checkout rebuild-1 &&
+       test_config branch.rebuild-1.description hello &&
+       git format-patch --stdout --cover-letter -2 HEAD >actual &&
+       grep hello actual >/dev/null
+ '
+ test_expect_success 'cover letter using branch description (6)' '
+       git checkout rebuild-1 &&
+       test_config branch.rebuild-1.description hello &&
+       git format-patch --stdout --cover-letter -2 >actual &&
+       grep hello actual >/dev/null
+ '
  test_done