Merge branch 'maint' to sync with 1.6.5.7
authorJunio C Hamano <gitster@pobox.com>
Wed, 16 Dec 2009 19:09:31 +0000 (11:09 -0800)
committerJunio C Hamano <gitster@pobox.com>
Wed, 16 Dec 2009 20:47:15 +0000 (12:47 -0800)
* maint:
Git 1.6.5.7
worktree: don't segfault with an absolute pathspec without a work tree
ignore unknown color configuration
help.autocorrect: do not run a command if the command given is junk
Illustrate "filter" attribute with an example

1  2 
Documentation/git.txt
builtin-branch.c
builtin-commit.c
diff.c
setup.c
diff --combined Documentation/git.txt
index 3d0cbf63ed29b6549f5deacf52af07d74bc25105,ff310950936d9d8a074379efb345b21a67ec3c93..51ca39291f281ddc4c971d1aa824e800a02857fd
@@@ -10,7 -10,7 +10,7 @@@ SYNOPSI
  --------
  [verse]
  'git' [--version] [--exec-path[=GIT_EXEC_PATH]] [--html-path]
 -    [-p|--paginate|--no-pager]
 +    [-p|--paginate|--no-pager] [--no-replace-objects]
      [--bare] [--git-dir=GIT_DIR] [--work-tree=GIT_WORK_TREE]
      [--help] COMMAND [ARGS]
  
@@@ -43,9 -43,10 +43,10 @@@ unreleased) version of git, that is ava
  branch of the `git.git` repository.
  Documentation for older releases are available here:
  
- * link:v1.6.5.6/git.html[documentation for release 1.6.5.6]
+ * link:v1.6.5.7/git.html[documentation for release 1.6.5.7]
  
  * release notes for
+   link:RelNotes-1.6.5.7.txt[1.6.5.7],
    link:RelNotes-1.6.5.6.txt[1.6.5.6],
    link:RelNotes-1.6.5.5.txt[1.6.5.5],
    link:RelNotes-1.6.5.4.txt[1.6.5.4],
@@@ -243,10 -244,6 +244,10 @@@ help ...`
        environment is not set, it is set to the current working
        directory.
  
 +--no-replace-objects::
 +      Do not use replacement refs to replace git objects. See
 +      linkgit:git-replace[1] for more information.
 +
  
  FURTHER DOCUMENTATION
  ---------------------
diff --combined builtin-branch.c
index 05e876e28554fec546ee4256bf3576dcb8017047,c77f6328861a929d1564f131d38e91155bb9c858..c87e63b02dd3bb0e12e5bf14aec22a0f219867b0
@@@ -65,7 -65,7 +65,7 @@@ static int parse_branch_color_slot(cons
                return BRANCH_COLOR_LOCAL;
        if (!strcasecmp(var+ofs, "current"))
                return BRANCH_COLOR_CURRENT;
-       die("bad config variable '%s'", var);
+       return -1;
  }
  
  static int git_branch_config(const char *var, const char *value, void *cb)
@@@ -76,6 -76,8 +76,8 @@@
        }
        if (!prefixcmp(var, "color.branch.")) {
                int slot = parse_branch_color_slot(var, 13);
+               if (slot < 0)
+                       return 0;
                if (!value)
                        return config_error_nonbool(var);
                color_parse(value, var, branch_colors[slot]);
@@@ -387,9 -389,8 +389,9 @@@ static void print_ref_item(struct ref_i
  
                commit = item->commit;
                if (commit && !parse_commit(commit)) {
 +                      struct pretty_print_context ctx = {0};
                        pretty_print_commit(CMIT_FMT_ONELINE, commit,
 -                                          &subject, 0, NULL, NULL, 0, 0);
 +                                          &subject, &ctx);
                        sub = subject.buf;
                }
  
diff --combined builtin-commit.c
index e93a647c59f1f52a4b0eb92b6c84fd9cec0aad6a,7d3c6a86f786bb0caa50c129b972fed9746f6a01..f54772f74a14e480ae978b38ce3bcd49ee994411
@@@ -51,7 -51,7 +51,7 @@@ static const char *template_file
  static char *edit_message, *use_message;
  static char *author_name, *author_email, *author_date;
  static int all, edit_flag, also, interactive, only, amend, signoff;
 -static int quiet, verbose, no_verify, allow_empty, dry_run;
 +static int quiet, verbose, no_verify, allow_empty, dry_run, renew_authorship;
  static char *untracked_files_arg;
  /*
   * The default commit message cleanup mode will remove the lines
@@@ -91,9 -91,8 +91,9 @@@ static struct option builtin_commit_opt
        OPT_FILENAME('F', "file", &logfile, "read log from file"),
        OPT_STRING(0, "author", &force_author, "AUTHOR", "override author for commit"),
        OPT_CALLBACK('m', "message", &message, "MESSAGE", "specify commit message", opt_parse_m),
 -      OPT_STRING('c', "reedit-message", &edit_message, "COMMIT", "reuse and edit message from specified commit "),
 +      OPT_STRING('c', "reedit-message", &edit_message, "COMMIT", "reuse and edit message from specified commit"),
        OPT_STRING('C', "reuse-message", &use_message, "COMMIT", "reuse message from specified commit"),
 +      OPT_BOOLEAN(0, "reset-author", &renew_authorship, "the commit is authored by me now (used with -C-c/--amend)"),
        OPT_BOOLEAN('s', "signoff", &signoff, "add Signed-off-by:"),
        OPT_FILENAME('t', "template", &template_file, "use specified template file"),
        OPT_BOOLEAN('e', "edit", &edit_flag, "force edit of commit"),
@@@ -382,7 -381,7 +382,7 @@@ static void determine_author_info(void
        email = getenv("GIT_AUTHOR_EMAIL");
        date = getenv("GIT_AUTHOR_DATE");
  
 -      if (use_message) {
 +      if (use_message && !renew_authorship) {
                const char *a, *lb, *rb, *eol;
  
                a = strstr(use_message_buffer, "\nauthor ");
        author_date = date;
  }
  
 +static int ends_rfc2822_footer(struct strbuf *sb)
 +{
 +      int ch;
 +      int hit = 0;
 +      int i, j, k;
 +      int len = sb->len;
 +      int first = 1;
 +      const char *buf = sb->buf;
 +
 +      for (i = len - 1; i > 0; i--) {
 +              if (hit && buf[i] == '\n')
 +                      break;
 +              hit = (buf[i] == '\n');
 +      }
 +
 +      while (i < len - 1 && buf[i] == '\n')
 +              i++;
 +
 +      for (; i < len; i = k) {
 +              for (k = i; k < len && buf[k] != '\n'; k++)
 +                      ; /* do nothing */
 +              k++;
 +
 +              if ((buf[k] == ' ' || buf[k] == '\t') && !first)
 +                      continue;
 +
 +              first = 0;
 +
 +              for (j = 0; i + j < len; j++) {
 +                      ch = buf[i + j];
 +                      if (ch == ':')
 +                              break;
 +                      if (isalnum(ch) ||
 +                          (ch == '-'))
 +                              continue;
 +                      return 0;
 +              }
 +      }
 +      return 1;
 +}
 +
  static int prepare_to_commit(const char *index_file, const char *prefix,
                             struct wt_status *s)
  {
                for (i = sb.len - 1; i > 0 && sb.buf[i - 1] != '\n'; i--)
                        ; /* do nothing */
                if (prefixcmp(sb.buf + i, sob.buf)) {
 -                      if (prefixcmp(sb.buf + i, sign_off_header))
 +                      if (!i || !ends_rfc2822_footer(&sb))
                                strbuf_addch(&sb, '\n');
                        strbuf_addbuf(&sb, &sob);
                }
@@@ -726,10 -684,8 +726,10 @@@ static const char *find_author_by_nickn
        prepare_revision_walk(&revs);
        commit = get_revision(&revs);
        if (commit) {
 +              struct pretty_print_context ctx = {0};
 +              ctx.date_mode = DATE_NORMAL;
                strbuf_release(&buf);
 -              format_commit_message(commit, "%an <%ae>", &buf, DATE_NORMAL);
 +              format_commit_message(commit, "%an <%ae>", &buf, &ctx);
                return strbuf_detach(&buf, NULL);
        }
        die("No existing author found with '%s'", name);
@@@ -748,9 -704,6 +748,9 @@@ static int parse_and_validate_options(i
        if (force_author && !strchr(force_author, '>'))
                force_author = find_author_by_nickname(force_author);
  
 +      if (force_author && renew_authorship)
 +              die("Using both --reset-author and --author does not make sense");
 +
        if (logfile || message.len || use_message)
                use_editor = 0;
        if (edit_flag)
                use_message = edit_message;
        if (amend && !use_message)
                use_message = "HEAD";
 +      if (!use_message && renew_authorship)
 +              die("--reset-author can be used only with -C, -c or --amend.");
        if (use_message) {
                unsigned char sha1[20];
                static char utf8[] = "UTF-8";
@@@ -890,7 -841,7 +890,7 @@@ static int parse_status_slot(const cha
                return WT_STATUS_NOBRANCH;
        if (!strcasecmp(var+offset, "unmerged"))
                return WT_STATUS_UNMERGED;
-       die("bad config variable '%s'", var);
+       return -1;
  }
  
  static int git_status_config(const char *k, const char *v, void *cb)
        }
        if (!prefixcmp(k, "status.color.") || !prefixcmp(k, "color.status.")) {
                int slot = parse_status_slot(k, 13);
+               if (slot < 0)
+                       return 0;
                if (!v)
                        return config_error_nonbool(k);
                color_parse(v, k, s->color_palette[slot]);
@@@ -991,10 -944,8 +993,10 @@@ static void print_summary(const char *p
                initial_commit ? " (root-commit)" : "");
  
        if (!log_tree_commit(&rev, commit)) {
 +              struct pretty_print_context ctx = {0};
                struct strbuf buf = STRBUF_INIT;
 -              format_commit_message(commit, format + 7, &buf, DATE_NORMAL);
 +              ctx.date_mode = DATE_NORMAL;
 +              format_commit_message(commit, format + 7, &buf, &ctx);
                printf("%s\n", buf.buf);
                strbuf_release(&buf);
        }
diff --combined diff.c
index d952686926e2e97aab3e369ad192027b4d7e676b,72f25b52847e0a170e01b2b5aa9600f2e39a3d5d..08bbd3e9070996b38f4d34cedf7640d93aa5808d
--- 1/diff.c
--- 2/diff.c
+++ b/diff.c
@@@ -13,7 -13,6 +13,7 @@@
  #include "utf8.h"
  #include "userdiff.h"
  #include "sigchain.h"
 +#include "submodule.h"
  
  #ifdef NO_FAST_WORKING_DIRECTORY
  #define FAST_WORKING_DIRECTORY 0
@@@ -39,7 -38,6 +39,7 @@@ static char diff_colors[][COLOR_MAXLEN
        GIT_COLOR_GREEN,        /* NEW */
        GIT_COLOR_YELLOW,       /* COMMIT */
        GIT_COLOR_BG_RED,       /* WHITESPACE */
 +      GIT_COLOR_NORMAL,       /* FUNCINFO */
  };
  
  static void diff_filespec_load_driver(struct diff_filespec *one);
@@@ -61,9 -59,7 +61,9 @@@ static int parse_diff_color_slot(const 
                return DIFF_COMMIT;
        if (!strcasecmp(var+ofs, "whitespace"))
                return DIFF_WHITESPACE;
-       die("bad config variable '%s'", var);
 +      if (!strcasecmp(var+ofs, "func"))
 +              return DIFF_FUNCINFO;
+       return -1;
  }
  
  static int git_config_rename(const char *var, const char *value)
@@@ -122,6 -118,8 +122,8 @@@ int git_diff_basic_config(const char *v
  
        if (!prefixcmp(var, "diff.color.") || !prefixcmp(var, "color.diff.")) {
                int slot = parse_diff_color_slot(var, 11);
+               if (slot < 0)
+                       return 0;
                if (!value)
                        return config_error_nonbool(var);
                color_parse(value, var, diff_colors[slot]);
@@@ -298,13 -296,12 +300,13 @@@ static void emit_line_0(FILE *file, con
                nofirst = 0;
        }
  
 -      fputs(set, file);
 -
 -      if (!nofirst)
 -              fputc(first, file);
 -      fwrite(line, len, 1, file);
 -      fputs(reset, file);
 +      if (len || !nofirst) {
 +              fputs(set, file);
 +              if (!nofirst)
 +                      fputc(first, file);
 +              fwrite(line, len, 1, file);
 +              fputs(reset, file);
 +      }
        if (has_trailing_carriage_return)
                fputc('\r', file);
        if (has_trailing_newline)
@@@ -348,42 -345,6 +350,42 @@@ static void emit_add_line(const char *r
        }
  }
  
 +static void emit_hunk_header(struct emit_callback *ecbdata,
 +                           const char *line, int len)
 +{
 +      const char *plain = diff_get_color(ecbdata->color_diff, DIFF_PLAIN);
 +      const char *frag = diff_get_color(ecbdata->color_diff, DIFF_FRAGINFO);
 +      const char *func = diff_get_color(ecbdata->color_diff, DIFF_FUNCINFO);
 +      const char *reset = diff_get_color(ecbdata->color_diff, DIFF_RESET);
 +      static const char atat[2] = { '@', '@' };
 +      const char *cp, *ep;
 +
 +      /*
 +       * As a hunk header must begin with "@@ -<old>, +<new> @@",
 +       * it always is at least 10 bytes long.
 +       */
 +      if (len < 10 ||
 +          memcmp(line, atat, 2) ||
 +          !(ep = memmem(line + 2, len - 2, atat, 2))) {
 +              emit_line(ecbdata->file, plain, reset, line, len);
 +              return;
 +      }
 +      ep += 2; /* skip over @@ */
 +
 +      /* The hunk header in fraginfo color */
 +      emit_line(ecbdata->file, frag, reset, line, ep - line);
 +
 +      /* blank before the func header */
 +      for (cp = ep; ep - line < len; ep++)
 +              if (*ep != ' ' && *ep != '\t')
 +                      break;
 +      if (ep != cp)
 +              emit_line(ecbdata->file, plain, reset, cp, ep - cp);
 +
 +      if (ep < line + len)
 +              emit_line(ecbdata->file, func, reset, ep, line + len - ep);
 +}
 +
  static struct diff_tempfile *claim_diff_tempfile(void) {
        int i;
        for (i = 0; i < ARRAY_SIZE(diff_temp); i++)
@@@ -821,7 -782,9 +823,7 @@@ static void fn_out_consume(void *priv, 
                        diff_words_flush(ecbdata);
                len = sane_truncate_line(ecbdata, line, len);
                find_lno(line, ecbdata);
 -              emit_line(ecbdata->file,
 -                        diff_get_color(ecbdata->color_diff, DIFF_FRAGINFO),
 -                        reset, line, len);
 +              emit_hunk_header(ecbdata, line, len);
                if (line[len-1] != '\n')
                        putc('\n', ecbdata->file);
                return;
@@@ -1153,7 -1116,7 +1155,7 @@@ static void show_stats(struct diffstat_
               total_files, adds, dels);
  }
  
 -static void show_shortstats(struct diffstat_tdata, struct diff_options *options)
 +static void show_shortstats(struct diffstat_t *data, struct diff_options *options)
  {
        int i, adds = 0, dels = 0, total_files = data->nr;
  
@@@ -1600,17 -1563,6 +1602,17 @@@ static void builtin_diff(const char *na
        const char *a_prefix, *b_prefix;
        const char *textconv_one = NULL, *textconv_two = NULL;
  
 +      if (DIFF_OPT_TST(o, SUBMODULE_LOG) &&
 +                      (!one->mode || S_ISGITLINK(one->mode)) &&
 +                      (!two->mode || S_ISGITLINK(two->mode))) {
 +              const char *del = diff_get_color_opt(o, DIFF_FILE_OLD);
 +              const char *add = diff_get_color_opt(o, DIFF_FILE_NEW);
 +              show_submodule_summary(o->file, one ? one->path : two->path,
 +                              one->sha1, two->sha1,
 +                              del, add, reset);
 +              return;
 +      }
 +
        if (DIFF_OPT_TST(o, ALLOW_TEXTCONV)) {
                textconv_one = get_textconv(one);
                textconv_two = get_textconv(two);
@@@ -2811,12 -2763,6 +2813,12 @@@ int diff_opt_parse(struct diff_options 
                DIFF_OPT_CLR(options, ALLOW_TEXTCONV);
        else if (!strcmp(arg, "--ignore-submodules"))
                DIFF_OPT_SET(options, IGNORE_SUBMODULES);
 +      else if (!strcmp(arg, "--submodule"))
 +              DIFF_OPT_SET(options, SUBMODULE_LOG);
 +      else if (!prefixcmp(arg, "--submodule=")) {
 +              if (!strcmp(arg + 12, "log"))
 +                      DIFF_OPT_SET(options, SUBMODULE_LOG);
 +      }
  
        /* misc options */
        else if (!strcmp(arg, "-z"))
diff --combined setup.c
index f67250b7c1f7b5a62c30de0122c404554357f61b,4272ec0ef2fd833923a5303286a0dd237ec6eab8..2cf0f1993718fd737cd87e79d2f4950832c59c9f
+++ b/setup.c
@@@ -18,9 -18,12 +18,12 @@@ const char *prefix_path(const char *pre
        if (normalize_path_copy(sanitized, sanitized))
                goto error_out;
        if (is_absolute_path(orig)) {
+               size_t len, total;
                const char *work_tree = get_git_work_tree();
-               size_t len = strlen(work_tree);
-               size_t total = strlen(sanitized) + 1;
+               if (!work_tree)
+                       goto error_out;
+               len = strlen(work_tree);
+               total = strlen(sanitized) + 1;
                if (strncmp(sanitized, work_tree, len) ||
                    (sanitized[len] != '\0' && sanitized[len] != '/')) {
                error_out:
@@@ -61,19 -64,6 +64,19 @@@ const char *prefix_filename(const char 
        return path;
  }
  
 +int check_filename(const char *prefix, const char *arg)
 +{
 +      const char *name;
 +      struct stat st;
 +
 +      name = prefix ? prefix_filename(prefix, strlen(prefix), arg) : arg;
 +      if (!lstat(name, &st))
 +              return 1; /* file exists */
 +      if (errno == ENOENT || errno == ENOTDIR)
 +              return 0; /* file does not exist */
 +      die_errno("failed to stat '%s'", arg);
 +}
 +
  /*
   * Verify a filename that we got as an argument for a pathspec
   * entry. Note that a filename that begins with "-" never verifies
   */
  void verify_filename(const char *prefix, const char *arg)
  {
 -      const char *name;
 -      struct stat st;
 -
        if (*arg == '-')
                die("bad flag '%s' used after filename", arg);
 -      name = prefix ? prefix_filename(prefix, strlen(prefix), arg) : arg;
 -      if (!lstat(name, &st))
 +      if (check_filename(prefix, arg))
                return;
 -      if (errno == ENOENT)
 -              die("ambiguous argument '%s': unknown revision or path not in the working tree.\n"
 -                  "Use '--' to separate paths from revisions", arg);
 -      die_errno("failed to stat '%s'", arg);
 +      die("ambiguous argument '%s': unknown revision or path not in the working tree.\n"
 +          "Use '--' to separate paths from revisions", arg);
  }
  
  /*
   */
  void verify_non_filename(const char *prefix, const char *arg)
  {
 -      const char *name;
 -      struct stat st;
 -
        if (!is_inside_work_tree() || is_inside_git_dir())
                return;
        if (*arg == '-')
                return; /* flag */
 -      name = prefix ? prefix_filename(prefix, strlen(prefix), arg) : arg;
 -      if (!lstat(name, &st))
 -              die("ambiguous argument '%s': both revision and filename\n"
 -                  "Use '--' to separate filenames from revisions", arg);
 -      if (errno != ENOENT && errno != ENOTDIR)
 -              die_errno("failed to stat '%s'", arg);
 +      if (!check_filename(prefix, arg))
 +              return;
 +      die("ambiguous argument '%s': both revision and filename\n"
 +          "Use '--' to separate filenames from revisions", arg);
  }
  
  const char **get_pathspec(const char *prefix, const char **pathspec)