Merge branch 'rr/shortlog-doc'
authorJunio C Hamano <gitster@pobox.com>
Fri, 26 Apr 2013 22:28:39 +0000 (15:28 -0700)
committerJunio C Hamano <gitster@pobox.com>
Fri, 26 Apr 2013 22:28:39 +0000 (15:28 -0700)
Update documentation for "log" and "shortlog".

* rr/shortlog-doc:
builtin/shortlog.c: make usage string consistent with log
builtin/log.c: make usage string consistent with doc
git-shortlog.txt: make SYNOPSIS match log, update OPTIONS
git-log.txt: rewrite note on why "--" may be required
git-log.txt: generalize <since>..<until>
git-log.txt: order OPTIONS properly; move <since>..<until>
revisions.txt: clarify the .. and ... syntax
git-shortlog.txt: remove (-h|--help) from OPTIONS

1  2 
Documentation/revisions.txt
builtin/log.c
index a8ff691492927eef2f31d889f7bd20b4e60e7a91,242682af07f120ec50fb7a7a1bb85d63e26902ad..d477b3f6bcb2c410952b573421d28189d1d1a790
@@@ -2,13 -2,13 +2,13 @@@ SPECIFYING REVISION
  --------------------
  
  A revision parameter '<rev>' typically, but not necessarily, names a
 -commit object.  It uses what is called an 'extended SHA1'
 +commit object.  It uses what is called an 'extended SHA-1'
  syntax.  Here are various ways to spell object names.  The
  ones listed near the end of this list name trees and
  blobs contained in a commit.
  
  '<sha1>', e.g. 'dae86e1950b1277e545cee180551750029cfe735', 'dae86e'::
 -  The full SHA1 object name (40-byte hexadecimal string), or
 +  The full SHA-1 object name (40-byte hexadecimal string), or
    a leading substring that is unique within the repository.
    E.g. dae86e1950b1277e545cee180551750029cfe735 and dae86e both
    name the same commit object if there is no other object in
@@@ -116,11 -116,6 +116,11 @@@ some output processing may assume ref n
    object of that type is found or the object cannot be
    dereferenced anymore (in which case, barf).  '<rev>{caret}0'
    is a short-hand for '<rev>{caret}\{commit\}'.
 ++
 +'rev{caret}\{object\}' can be used to make sure 'rev' names an
 +object that exists, without requiring 'rev' to be a tag, and
 +without dereferencing 'rev'; because a tag is already an object,
 +it does not have to be dereferenced even once to get to an object.
  
  '<rev>{caret}\{\}', e.g. 'v0.99.8{caret}\{\}'::
    A suffix '{caret}' followed by an empty brace pair
@@@ -244,11 -239,13 +244,13 @@@ To summarize
  
  '<rev1>..<rev2>'::
        Include commits that are reachable from <rev2> but exclude
-       those that are reachable from <rev1>.
+       those that are reachable from <rev1>.  When either <rev1> or
+       <rev2> is omitted, it defaults to 'HEAD'.
  
  '<rev1>\...<rev2>'::
        Include commits that are reachable from either <rev1> or
-       <rev2> but exclude those that are reachable from both.
+       <rev2> but exclude those that are reachable from both.  When
+       either <rev1> or <rev2> is omitted, it defaults to 'HEAD'.
  
  '<rev>{caret}@', e.g. 'HEAD{caret}@'::
    A suffix '{caret}' followed by an at sign is the same as listing
diff --combined builtin/log.c
index ad46f72950f3e4fda292da25f936e48c59705410,4398abf3aec23c5ca258e861cf93c763bea2c7cc..6e56a50002194e0a452266a580932b9e4e9647c9
@@@ -23,7 -23,6 +23,7 @@@
  #include "streaming.h"
  #include "version.h"
  #include "mailmap.h"
 +#include "gpg-interface.h"
  
  /* Set a default date-time format for git log ("log.date" config variable) */
  static const char *default_date_mode = NULL;
@@@ -37,7 -36,7 +37,7 @@@ static const char *fmt_patch_subject_pr
  static const char *fmt_pretty;
  
  static const char * const builtin_log_usage[] = {
-       N_("git log [<options>] [<since>..<until>] [[--] <path>...]\n")
+       N_("git log [<options>] [<revision range>] [[--] <path>...]\n")
        N_("   or: git show [options] <object>..."),
        NULL
  };
@@@ -100,9 -99,9 +100,9 @@@ static void cmd_log_init_finish(int arg
        int quiet = 0, source = 0, mailmap = 0;
  
        const struct option builtin_log_options[] = {
 -              OPT_BOOLEAN(0, "quiet", &quiet, N_("suppress diff output")),
 -              OPT_BOOLEAN(0, "source", &source, N_("show source")),
 -              OPT_BOOLEAN(0, "use-mailmap", &mailmap, N_("Use mail map file")),
 +              OPT_BOOL(0, "quiet", &quiet, N_("suppress diff output")),
 +              OPT_BOOL(0, "source", &source, N_("show source")),
 +              OPT_BOOL(0, "use-mailmap", &mailmap, N_("Use mail map file")),
                { OPTION_CALLBACK, 0, "decorate", NULL, NULL, N_("decorate options"),
                  PARSE_OPT_OPTARG, decorate_callback},
                OPT_END()
@@@ -368,8 -367,6 +368,8 @@@ static int git_log_config(const char *v
  
        if (grep_config(var, value, cb) < 0)
                return -1;
 +      if (git_gpg_config(var, value, cb) < 0)
 +              return -1;
        return git_diff_ui_config(var, value, cb);
  }
  
@@@ -622,14 -619,6 +622,14 @@@ static void add_header(const char *valu
  static int thread;
  static int do_signoff;
  static const char *signature = git_version_string;
 +static int config_cover_letter;
 +
 +enum {
 +      COVER_UNSET,
 +      COVER_OFF,
 +      COVER_ON,
 +      COVER_AUTO
 +};
  
  static int git_format_config(const char *var, const char *value, void *cb)
  {
        }
        if (!strcmp(var, "format.signature"))
                return git_config_string(&signature, var, value);
 +      if (!strcmp(var, "format.coverletter")) {
 +              if (value && !strcasecmp(value, "auto")) {
 +                      config_cover_letter = COVER_AUTO;
 +                      return 0;
 +              }
 +              config_cover_letter = git_config_bool(var, value) ? COVER_ON : COVER_OFF;
 +              return 0;
 +      }
  
        return git_log_config(var, value, cb);
  }
@@@ -810,37 -791,9 +810,37 @@@ static void add_branch_description(stru
        }
  }
  
 +static char *find_branch_name(struct rev_info *rev)
 +{
 +      int i, positive = -1;
 +      unsigned char branch_sha1[20];
 +      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)
 +                      continue;
 +              if (positive < 0)
 +                      positive = i;
 +              else
 +                      return NULL;
 +      }
 +      if (positive < 0)
 +              return NULL;
 +      ref = rev->cmdline.rev[positive].name;
 +      tip_sha1 = rev->cmdline.rev[positive].item->sha1;
 +      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;
 +}
 +
  static void make_cover_letter(struct rev_info *rev, int use_stdout,
                              struct commit *origin,
 -                            int nr, struct commit **list, struct commit *head,
 +                            int nr, struct commit **list,
                              const char *branch_name,
                              int quiet)
  {
        struct diff_options opts;
        int need_8bit_cte = 0;
        struct pretty_print_context pp = {0};
 +      struct commit *head = list[0];
  
        if (rev->commit_format != CMIT_FMT_EMAIL)
                die(_("Cover letter needs email format"));
                if (has_non_ascii(list[i]->buffer))
                        need_8bit_cte = 1;
  
 +      if (!branch_name)
 +              branch_name = find_branch_name(rev);
 +
        msg = body;
        pp.fmt = CMIT_FMT_EMAIL;
        pp.date_mode = DATE_RFC2822;
@@@ -1081,6 -1030,45 +1081,6 @@@ static int cc_callback(const struct opt
        return 0;
  }
  
 -static char *find_branch_name(struct rev_info *rev)
 -{
 -      int i, positive = -1;
 -      unsigned char branch_sha1[20];
 -      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)
 -                      continue;
 -              if (positive < 0)
 -                      positive = i;
 -              else
 -                      return NULL;
 -      }
 -      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;
 -      }
 -      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)
  {
        struct commit *commit;
        int start_number = -1;
        int just_numbers = 0;
        int ignore_if_in_upstream = 0;
 -      int cover_letter = 0;
 +      int cover_letter = -1;
        int boundary_count = 0;
        int no_binary_diff = 0;
 -      struct commit *origin = NULL, *head = NULL;
 +      struct commit *origin = NULL;
        const char *in_reply_to = NULL;
        struct patch_ids ids;
 -      char *add_signoff = NULL;
        struct strbuf buf = STRBUF_INIT;
        int use_patch_format = 0;
        int quiet = 0;
                { OPTION_CALLBACK, 'N', "no-numbered", &numbered, NULL,
                            N_("use [PATCH] even with multiple patches"),
                            PARSE_OPT_NOARG, no_numbered_callback },
 -              OPT_BOOLEAN('s', "signoff", &do_signoff, N_("add Signed-off-by:")),
 -              OPT_BOOLEAN(0, "stdout", &use_stdout,
 +              OPT_BOOL('s', "signoff", &do_signoff, N_("add Signed-off-by:")),
 +              OPT_BOOL(0, "stdout", &use_stdout,
                            N_("print patches to standard out")),
 -              OPT_BOOLEAN(0, "cover-letter", &cover_letter,
 +              OPT_BOOL(0, "cover-letter", &cover_letter,
                            N_("generate a cover letter")),
 -              OPT_BOOLEAN(0, "numbered-files", &just_numbers,
 +              OPT_BOOL(0, "numbered-files", &just_numbers,
                            N_("use simple number sequence for output file names")),
                OPT_STRING(0, "suffix", &fmt_patch_suffix, N_("sfx"),
                            N_("use <sfx> instead of '.patch'")),
                rev.subject_prefix = strbuf_detach(&sprefix, NULL);
        }
  
 -      if (do_signoff) {
 -              const char *committer;
 -              const char *endpos;
 -              committer = git_committer_info(IDENT_STRICT);
 -              endpos = strchr(committer, '>');
 -              if (!endpos)
 -                      die(_("bogus committer info %s"), committer);
 -              add_signoff = xmemdupz(committer, endpos - committer + 1);
 -      }
 -
        for (i = 0; i < extra_hdr.nr; i++) {
                strbuf_addstr(&buf, extra_hdr.items[i].string);
                strbuf_addch(&buf, '\n');
        }
  
        if (rev.pending.nr == 1) {
 +              int check_head = 0;
 +
                if (rev.max_count < 0 && !rev.show_root_diff) {
                        /*
                         * This is traditional behaviour of "git format-patch
                         * origin" that prepares what the origin side still
                         * does not have.
                         */
 -                      unsigned char sha1[20];
 -                      const char *ref;
 -
                        rev.pending.objects[0].item->flags |= UNINTERESTING;
                        add_head_to_pending(&rev);
 -                      ref = resolve_ref_unsafe("HEAD", sha1, 1, NULL);
 -                      if (ref && !prefixcmp(ref, "refs/heads/"))
 -                              branch_name = xstrdup(ref + strlen("refs/heads/"));
 -                      else
 -                              branch_name = xstrdup(""); /* no branch */
 +                      check_head = 1;
                }
                /*
                 * Otherwise, it is "format-patch -22 HEAD", and/or
                 * "format-patch --root HEAD".  The user wants
                 * get_revision() to do the usual traversal.
                 */
 +
 +              if (!strcmp(rev.pending.objects[0].name, "HEAD"))
 +                      check_head = 1;
 +
 +              if (check_head) {
 +                      unsigned char sha1[20];
 +                      const char *ref;
 +                      ref = resolve_ref_unsafe("HEAD", sha1, 1, NULL);
 +                      if (ref && !prefixcmp(ref, "refs/heads/"))
 +                              branch_name = xstrdup(ref + strlen("refs/heads/"));
 +                      else
 +                              branch_name = xstrdup(""); /* no branch */
 +              }
        }
  
        /*
         */
        rev.show_root_diff = 1;
  
 -      if (cover_letter) {
 -              /*
 -               * NEEDSWORK:randomly pick one positive commit to show
 -               * diffstat; this is often the tip and the command
 -               * happens to do the right thing in most cases, but a
 -               * complex command like "--cover-letter a b c ^bottom"
 -               * picks "c" and shows diffstat between bottom..c
 -               * which may not match what the series represents at
 -               * all and totally broken.
 -               */
 -              int i;
 -              for (i = 0; i < rev.pending.nr; i++) {
 -                      struct object *o = rev.pending.objects[i].item;
 -                      if (!(o->flags & UNINTERESTING))
 -                              head = (struct commit *)o;
 -              }
 -              /* There is nothing to show; it is not an error, though. */
 -              if (!head)
 -                      return 0;
 -              if (!branch_name)
 -                      branch_name = find_branch_name(&rev);
 -      }
 -
        if (ignore_if_in_upstream) {
                /* Don't say anything if head and upstream are the same. */
                if (rev.pending.nr == 2) {
                list = xrealloc(list, nr * sizeof(list[0]));
                list[nr - 1] = commit;
        }
 +      if (nr == 0)
 +              /* nothing to do */
 +              return 0;
        total = nr;
        if (!keep_subject && auto_number && total > 1)
                numbered = 1;
        if (numbered)
                rev.total = total + start_number - 1;
 +      if (cover_letter == -1) {
 +              if (config_cover_letter == COVER_AUTO)
 +                      cover_letter = (total > 1);
 +              else
 +                      cover_letter = (config_cover_letter == COVER_ON);
 +      }
 +
        if (in_reply_to || thread || cover_letter)
                rev.ref_message_ids = xcalloc(1, sizeof(struct string_list));
        if (in_reply_to) {
                if (thread)
                        gen_message_id(&rev, "cover");
                make_cover_letter(&rev, use_stdout,
 -                                origin, nr, list, head, branch_name, quiet);
 +                                origin, nr, list, branch_name, quiet);
                total++;
                start_number--;
        }
 -      rev.add_signoff = add_signoff;
 +      rev.add_signoff = do_signoff;
        while (0 <= --nr) {
                int shown;
                commit = list[nr];