Merge branch 'jc/diff-apply-patch'
authorJunio C Hamano <junkio@cox.net>
Wed, 14 Feb 2007 03:18:16 +0000 (19:18 -0800)
committerJunio C Hamano <junkio@cox.net>
Wed, 14 Feb 2007 03:18:16 +0000 (19:18 -0800)
* jc/diff-apply-patch:
git-diff/git-apply: make diff output a bit friendlier to GNU patch (part 2)

1  2 
diff.c
diff --combined diff.c
index 13b9b6c5602cc1aca4a95ed4d292756d3380c543,b026c737b682f9249792600032792f3e36230163..165d2520f3aec738e1b8a2b52f1a819e3edb9f33
--- 1/diff.c
--- 2/diff.c
+++ b/diff.c
@@@ -1,6 -1,9 +1,6 @@@
  /*
   * Copyright (C) 2005 Junio C Hamano
   */
 -#include <sys/types.h>
 -#include <sys/wait.h>
 -#include <signal.h>
  #include "cache.h"
  #include "quote.h"
  #include "diff.h"
@@@ -9,12 -12,6 +9,12 @@@
  #include "xdiff-interface.h"
  #include "color.h"
  
 +#ifdef NO_FAST_WORKING_DIRECTORY
 +#define FAST_WORKING_DIRECTORY 0
 +#else
 +#define FAST_WORKING_DIRECTORY 1
 +#endif
 +
  static int use_size_cache;
  
  static int diff_detect_rename_default;
@@@ -63,7 -60,7 +63,7 @@@ int git_diff_ui_config(const char *var
                diff_rename_limit_default = git_config_int(var, value);
                return 0;
        }
 -      if (!strcmp(var, "diff.color")) {
 +      if (!strcmp(var, "diff.color") || !strcmp(var, "color.diff")) {
                diff_use_color_default = git_config_colorbool(var, value);
                return 0;
        }
@@@ -77,7 -74,7 +77,7 @@@
                        diff_detect_rename_default = DIFF_DETECT_RENAME;
                return 0;
        }
 -      if (!strncmp(var, "diff.color.", 11)) {
 +      if (!strncmp(var, "diff.color.", 11) || !strncmp(var, "color.diff.", 11)) {
                int slot = parse_diff_color_slot(var, 11);
                color_parse(value, var, diff_colors[slot]);
                return 0;
@@@ -207,11 -204,18 +207,18 @@@ static void emit_rewrite_diff(const cha
                              struct diff_filespec *two)
  {
        int lc_a, lc_b;
+       const char *name_a_tab, *name_b_tab;
+       name_a_tab = strchr(name_a, ' ') ? "\t" : "";
+       name_b_tab = strchr(name_b, ' ') ? "\t" : "";
        diff_populate_filespec(one, 0);
        diff_populate_filespec(two, 0);
        lc_a = count_lines(one->data, one->size);
        lc_b = count_lines(two->data, two->size);
-       printf("--- a/%s\n+++ b/%s\n@@ -", name_a, name_b);
+       printf("--- a/%s%s\n+++ b/%s%s\n@@ -",
+              name_a, name_a_tab,
+              name_b, name_b_tab);
        print_line_count(lc_a);
        printf(" +");
        print_line_count(lc_b);
@@@ -477,8 -481,15 +484,15 @@@ static void fn_out_consume(void *priv, 
        const char *reset = diff_get_color(ecbdata->color_diff, DIFF_RESET);
  
        if (ecbdata->label_path[0]) {
-               printf("%s--- %s%s\n", set, ecbdata->label_path[0], reset);
-               printf("%s+++ %s%s\n", set, ecbdata->label_path[1], reset);
+               const char *name_a_tab, *name_b_tab;
+               name_a_tab = strchr(ecbdata->label_path[0], ' ') ? "\t" : "";
+               name_b_tab = strchr(ecbdata->label_path[1], ' ') ? "\t" : "";
+               printf("%s--- %s%s%s\n",
+                      set, ecbdata->label_path[0], reset, name_a_tab);
+               printf("%s+++ %s%s%s\n",
+                      set, ecbdata->label_path[1], reset, name_b_tab);
                ecbdata->label_path[0] = ecbdata->label_path[1] = NULL;
        }
  
@@@ -545,24 -556,6 +559,24 @@@ static char *pprint_rename(const char *
        int pfx_length, sfx_length;
        int len_a = strlen(a);
        int len_b = strlen(b);
 +      int qlen_a = quote_c_style(a, NULL, NULL, 0);
 +      int qlen_b = quote_c_style(b, NULL, NULL, 0);
 +
 +      if (qlen_a || qlen_b) {
 +              if (qlen_a) len_a = qlen_a;
 +              if (qlen_b) len_b = qlen_b;
 +              name = xmalloc( len_a + len_b + 5 );
 +              if (qlen_a)
 +                      quote_c_style(a, name, NULL, 0);
 +              else
 +                      memcpy(name, a, len_a);
 +              memcpy(name + len_a, " => ", 4);
 +              if (qlen_b)
 +                      quote_c_style(b, name + len_a + 4, NULL, 0);
 +              else
 +                      memcpy(name + len_a + 4, b, len_b + 1);
 +              return name;
 +      }
  
        /* Find common prefix */
        pfx_length = 0;
@@@ -719,14 -712,12 +733,14 @@@ static void show_stats(struct diffstat_
                struct diffstat_file *file = data->files[i];
                int change = file->added + file->deleted;
  
 -              len = quote_c_style(file->name, NULL, NULL, 0);
 -              if (len) {
 -                      char *qname = xmalloc(len + 1);
 -                      quote_c_style(file->name, qname, NULL, 0);
 -                      free(file->name);
 -                      file->name = qname;
 +              if (!file->is_renamed) {  /* renames are already quoted by pprint_rename */
 +                      len = quote_c_style(file->name, NULL, NULL, 0);
 +                      if (len) {
 +                              char *qname = xmalloc(len + 1);
 +                              quote_c_style(file->name, qname, NULL, 0);
 +                              free(file->name);
 +                              file->name = qname;
 +                      }
                }
  
                len = strlen(file->name);
               set, total_files, adds, dels, reset);
  }
  
 +static void show_shortstats(struct diffstat_t* data)
 +{
 +      int i, adds = 0, dels = 0, total_files = data->nr;
 +
 +      if (data->nr == 0)
 +              return;
 +
 +      for (i = 0; i < data->nr; i++) {
 +              if (!data->files[i]->is_binary &&
 +                  !data->files[i]->is_unmerged) {
 +                      int added = data->files[i]->added;
 +                      int deleted= data->files[i]->deleted;
 +                      if (!data->files[i]->is_renamed &&
 +                          (added + deleted == 0)) {
 +                              total_files--;
 +                      } else {
 +                              adds += added;
 +                              dels += deleted;
 +                      }
 +              }
 +              free(data->files[i]->name);
 +              free(data->files[i]);
 +      }
 +      free(data->files);
 +
 +      printf(" %d files changed, %d insertions(+), %d deletions(-)\n",
 +             total_files, adds, dels);
 +}
 +
  static void show_numstat(struct diffstat_t* data, struct diff_options *options)
  {
        int i;
        for (i = 0; i < data->nr; i++) {
                struct diffstat_file *file = data->files[i];
  
 -              printf("%d\t%d\t", file->added, file->deleted);
 -              if (options->line_termination &&
 +              if (file->is_binary)
 +                      printf("-\t-\t");
 +              else
 +                      printf("%d\t%d\t", file->added, file->deleted);
 +              if (options->line_termination && !file->is_renamed &&
                    quote_c_style(file->name, NULL, NULL, 0))
                        quote_c_style(file->name, NULL, stdout, 0);
                else
@@@ -880,6 -839,8 +894,6 @@@ static void checkdiff_consume(void *pri
        if (line[0] == '+') {
                int i, spaces = 0;
  
 -              data->lineno++;
 -
                /* check space before tab */
                for (i = 1; i < len && (line[i] == ' ' || line[i] == '\t'); i++)
                        if (line[i] == ' ')
                if (isspace(line[len - 1]))
                        printf("%s:%d: white space at end: %.*s\n",
                                data->filename, data->lineno, (int)len, line);
 +
 +              data->lineno++;
        } else if (line[0] == ' ')
                data->lineno++;
        else if (line[0] == '@') {
@@@ -1210,7 -1169,7 +1224,7 @@@ void fill_filespec(struct diff_filespe
   * the work tree has that object contents, return true, so that
   * prepare_temp_file() does not have to inflate and extract.
   */
 -static int work_tree_matches(const char *name, const unsigned char *sha1)
 +static int reuse_worktree_file(const char *name, const unsigned char *sha1, int want_file)
  {
        struct cache_entry *ce;
        struct stat st;
        if (!active_cache)
                return 0;
  
 +      /* We want to avoid the working directory if our caller
 +       * doesn't need the data in a normal file, this system
 +       * is rather slow with its stat/open/mmap/close syscalls,
 +       * and the object is contained in a pack file.  The pack
 +       * is probably already open and will be faster to obtain
 +       * the data through than the working directory.  Loose
 +       * objects however would tend to be slower as they need
 +       * to be individually opened and inflated.
 +       */
 +      if (!FAST_WORKING_DIRECTORY && !want_file && has_sha1_pack(sha1, NULL))
 +              return 0;
 +
        len = strlen(name);
        pos = cache_name_pos(name, len);
        if (pos < 0)
@@@ -1329,7 -1276,7 +1343,7 @@@ int diff_populate_filespec(struct diff_
        if (s->data)
                return err;
        if (!s->sha1_valid ||
 -          work_tree_matches(s->path, s->sha1)) {
 +          reuse_worktree_file(s->path, s->sha1, 0)) {
                struct stat st;
                int fd;
                if (lstat(s->path, &st) < 0) {
                fd = open(s->path, O_RDONLY);
                if (fd < 0)
                        goto err_empty;
 -              s->data = mmap(NULL, s->size, PROT_READ, MAP_PRIVATE, fd, 0);
 +              s->data = xmmap(NULL, s->size, PROT_READ, MAP_PRIVATE, fd, 0);
                close(fd);
 -              if (s->data == MAP_FAILED)
 -                      goto err_empty;
                s->should_munmap = 1;
 +              /* FIXME! CRLF -> LF conversion goes here, based on "s->path" */
        }
        else {
                char type[20];
@@@ -1410,7 -1358,7 +1424,7 @@@ static void prep_temp_blob(struct diff_
        fd = git_mkstemp(temp->tmp_path, TEMPFILE_PATH_LEN, ".diff_XXXXXX");
        if (fd < 0)
                die("unable to create temp-file");
 -      if (write(fd, blob, size) != size)
 +      if (write_in_full(fd, blob, size) != size)
                die("unable to write temp-file");
        close(fd);
        temp->name = temp->tmp_path;
@@@ -1435,7 -1383,7 +1449,7 @@@ static void prepare_temp_file(const cha
        }
  
        if (!one->sha1_valid ||
 -          work_tree_matches(name, one->sha1)) {
 +          reuse_worktree_file(name, one->sha1, 1)) {
                struct stat st;
                if (lstat(name, &st) < 0) {
                        if (errno == ENOENT)
@@@ -1816,7 -1764,6 +1830,7 @@@ int diff_setup_done(struct diff_option
                options->output_format &= ~(DIFF_FORMAT_RAW |
                                            DIFF_FORMAT_NUMSTAT |
                                            DIFF_FORMAT_DIFFSTAT |
 +                                          DIFF_FORMAT_SHORTSTAT |
                                            DIFF_FORMAT_SUMMARY |
                                            DIFF_FORMAT_PATCH);
  
        if (options->output_format & (DIFF_FORMAT_PATCH |
                                      DIFF_FORMAT_NUMSTAT |
                                      DIFF_FORMAT_DIFFSTAT |
 +                                    DIFF_FORMAT_SHORTSTAT |
                                      DIFF_FORMAT_SUMMARY |
                                      DIFF_FORMAT_CHECKDIFF))
                options->recursive = 1;
@@@ -1919,9 -1865,6 +1933,9 @@@ int diff_opt_parse(struct diff_options 
        else if (!strcmp(arg, "--numstat")) {
                options->output_format |= DIFF_FORMAT_NUMSTAT;
        }
 +      else if (!strcmp(arg, "--shortstat")) {
 +              options->output_format |= DIFF_FORMAT_SHORTSTAT;
 +      }
        else if (!strncmp(arg, "--stat", 6)) {
                char *end;
                int width = options->stat_width;
@@@ -2212,13 -2155,13 +2226,13 @@@ static void diff_flush_raw(struct diff_
                free((void*)path_two);
  }
  
 -static void diff_flush_name(struct diff_filepair *p, int line_termination)
 +static void diff_flush_name(struct diff_filepair *p, struct diff_options *opt)
  {
        char *path = p->two->path;
  
 -      if (line_termination)
 +      if (opt->line_termination)
                path = quote_one(p->two->path);
 -      printf("%s%c", path, line_termination);
 +      printf("%s%c", path, opt->line_termination);
        if (p->two->path != path)
                free(path);
  }
@@@ -2425,29 -2368,24 +2439,29 @@@ static void flush_one_pair(struct diff_
        else if (fmt & (DIFF_FORMAT_RAW | DIFF_FORMAT_NAME_STATUS))
                diff_flush_raw(p, opt);
        else if (fmt & DIFF_FORMAT_NAME)
 -              diff_flush_name(p, opt->line_termination);
 +              diff_flush_name(p, opt);
  }
  
  static void show_file_mode_name(const char *newdelete, struct diff_filespec *fs)
  {
 +      char *name = quote_one(fs->path);
        if (fs->mode)
 -              printf(" %s mode %06o %s\n", newdelete, fs->mode, fs->path);
 +              printf(" %s mode %06o %s\n", newdelete, fs->mode, name);
        else
 -              printf(" %s %s\n", newdelete, fs->path);
 +              printf(" %s %s\n", newdelete, name);
 +      free(name);
  }
  
  
  static void show_mode_change(struct diff_filepair *p, int show_name)
  {
        if (p->one->mode && p->two->mode && p->one->mode != p->two->mode) {
 -              if (show_name)
 +              if (show_name) {
 +                      char *name = quote_one(p->two->path);
                        printf(" mode change %06o => %06o %s\n",
 -                             p->one->mode, p->two->mode, p->two->path);
 +                             p->one->mode, p->two->mode, name);
 +                      free(name);
 +              }
                else
                        printf(" mode change %06o => %06o\n",
                               p->one->mode, p->two->mode);
  
  static void show_rename_copy(const char *renamecopy, struct diff_filepair *p)
  {
 -      const char *old, *new;
 +      char *names = pprint_rename(p->one->path, p->two->path);
  
 -      /* Find common prefix */
 -      old = p->one->path;
 -      new = p->two->path;
 -      while (1) {
 -              const char *slash_old, *slash_new;
 -              slash_old = strchr(old, '/');
 -              slash_new = strchr(new, '/');
 -              if (!slash_old ||
 -                  !slash_new ||
 -                  slash_old - old != slash_new - new ||
 -                  memcmp(old, new, slash_new - new))
 -                      break;
 -              old = slash_old + 1;
 -              new = slash_new + 1;
 -      }
 -      /* p->one->path thru old is the common prefix, and old and new
 -       * through the end of names are renames
 -       */
 -      if (old != p->one->path)
 -              printf(" %s %.*s{%s => %s} (%d%%)\n", renamecopy,
 -                     (int)(old - p->one->path), p->one->path,
 -                     old, new, (int)(0.5 + p->score * 100.0/MAX_SCORE));
 -      else
 -              printf(" %s %s => %s (%d%%)\n", renamecopy,
 -                     p->one->path, p->two->path,
 -                     (int)(0.5 + p->score * 100.0/MAX_SCORE));
 +      printf(" %s %s (%d%%)\n", renamecopy, names,
 +             (int)(0.5 + p->score * 100.0/MAX_SCORE));
 +      free(names);
        show_mode_change(p, 0);
  }
  
@@@ -2481,10 -2442,8 +2495,10 @@@ static void diff_summary(struct diff_fi
                break;
        default:
                if (p->score) {
 -                      printf(" rewrite %s (%d%%)\n", p->two->path,
 +                      char *name = quote_one(p->two->path);
 +                      printf(" rewrite %s (%d%%)\n", name,
                                (int)(0.5 + p->score * 100.0/MAX_SCORE));
 +                      free(name);
                        show_mode_change(p, 0);
                } else  show_mode_change(p, 1);
                break;
@@@ -2680,7 -2639,7 +2694,7 @@@ void diff_flush(struct diff_options *op
                separator++;
        }
  
 -      if (output_format & (DIFF_FORMAT_DIFFSTAT|DIFF_FORMAT_NUMSTAT)) {
 +      if (output_format & (DIFF_FORMAT_DIFFSTAT|DIFF_FORMAT_SHORTSTAT|DIFF_FORMAT_NUMSTAT)) {
                struct diffstat_t diffstat;
  
                memset(&diffstat, 0, sizeof(struct diffstat_t));
                        show_numstat(&diffstat, options);
                if (output_format & DIFF_FORMAT_DIFFSTAT)
                        show_stats(&diffstat, options);
 +              else if (output_format & DIFF_FORMAT_SHORTSTAT)
 +                      show_shortstats(&diffstat);
                separator++;
        }
  
@@@ -2878,12 -2835,10 +2892,12 @@@ void diff_change(struct diff_options *o
  }
  
  void diff_unmerge(struct diff_options *options,
 -                const char *path)
 +                const char *path,
 +                unsigned mode, const unsigned char *sha1)
  {
        struct diff_filespec *one, *two;
        one = alloc_filespec(path);
        two = alloc_filespec(path);
 -      diff_queue(&diff_queued_diff, one, two);
 +      fill_filespec(one, sha1, mode);
 +      diff_queue(&diff_queued_diff, one, two)->is_unmerged = 1;
  }