X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=diff.c;h=b8a90e91a9af75e1e5f5d69ce45c2a59e64071d1;hb=1c95c565c2472a07be8316f2658e7100e62bf94d;hp=2df14b2469362bfd8a30a45457953d993baae66d;hpb=f5c589f1dfff428a05b8783688513fe9f98309a2;p=git.git diff --git a/diff.c b/diff.c index 2df14b246..b8a90e91a 100644 --- a/diff.c +++ b/diff.c @@ -1,9 +1,6 @@ /* * Copyright (C) 2005 Junio C Hamano */ -#include -#include -#include #include "cache.h" #include "quote.h" #include "diff.h" @@ -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; @@ -208,6 +211,8 @@ static void emit_rewrite_diff(const char *name_a, diff_populate_filespec(two, 0); lc_a = count_lines(one->data, one->size); lc_b = count_lines(two->data, two->size); + name_a += (*name_a == '/'); + name_b += (*name_b == '/'); printf("--- a/%s\n+++ b/%s\n@@ -", name_a, name_b); print_line_count(lc_a); printf(" +"); @@ -542,6 +547,24 @@ static char *pprint_rename(const char *a, const char *b) 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; @@ -698,12 +721,14 @@ static void show_stats(struct diffstat_t* data, struct diff_options *options) 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); @@ -795,6 +820,35 @@ static void show_stats(struct diffstat_t* data, struct diff_options *options) 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; @@ -806,7 +860,7 @@ static void show_numstat(struct diffstat_t* data, struct diff_options *options) printf("-\t-\t"); else printf("%d\t%d\t", file->added, file->deleted); - if (options->line_termination && + if (options->line_termination && !file->is_renamed && quote_c_style(file->name, NULL, NULL, 0)) quote_c_style(file->name, NULL, stdout, 0); else @@ -828,8 +882,6 @@ static void checkdiff_consume(void *priv, char *line, unsigned long len) 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] == ' ') @@ -844,6 +896,8 @@ static void checkdiff_consume(void *priv, char *line, unsigned long len) 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] == '@') { @@ -968,8 +1022,8 @@ static void builtin_diff(const char *name_a, const char *set = diff_get_color(o->color_diff, DIFF_METAINFO); const char *reset = diff_get_color(o->color_diff, DIFF_RESET); - a_one = quote_two("a/", name_a); - b_two = quote_two("b/", name_b); + a_one = quote_two("a/", name_a + (*name_a == '/')); + b_two = quote_two("b/", name_b + (*name_b == '/')); lbl[0] = DIFF_FILE_VALID(one) ? a_one : "/dev/null"; lbl[1] = DIFF_FILE_VALID(two) ? b_two : "/dev/null"; printf("%sdiff --git %s %s%s\n", set, a_one, b_two, reset); @@ -1158,7 +1212,7 @@ void fill_filespec(struct diff_filespec *spec, const unsigned char *sha1, * 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; @@ -1179,6 +1233,18 @@ static int work_tree_matches(const char *name, const unsigned char *sha1) 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) @@ -1265,7 +1331,7 @@ int diff_populate_filespec(struct diff_filespec *s, int size_only) 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) { @@ -1297,11 +1363,10 @@ int diff_populate_filespec(struct diff_filespec *s, int size_only) 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]; @@ -1347,7 +1412,7 @@ static void prep_temp_blob(struct diff_tempfile *temp, 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; @@ -1372,7 +1437,7 @@ static void prepare_temp_file(const char *name, } 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) @@ -1753,6 +1818,7 @@ int diff_setup_done(struct diff_options *options) options->output_format &= ~(DIFF_FORMAT_RAW | DIFF_FORMAT_NUMSTAT | DIFF_FORMAT_DIFFSTAT | + DIFF_FORMAT_SHORTSTAT | DIFF_FORMAT_SUMMARY | DIFF_FORMAT_PATCH); @@ -1763,6 +1829,7 @@ int diff_setup_done(struct diff_options *options) 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; @@ -1854,6 +1921,9 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac) 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; @@ -2144,13 +2214,13 @@ static void diff_flush_raw(struct diff_filepair *p, 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); } @@ -2357,24 +2427,29 @@ static void flush_one_pair(struct diff_filepair *p, struct diff_options *opt) 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); @@ -2383,34 +2458,11 @@ static void show_mode_change(struct diff_filepair *p, int show_name) 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); } @@ -2431,8 +2483,10 @@ static void diff_summary(struct diff_filepair *p) 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; @@ -2628,7 +2682,7 @@ void diff_flush(struct diff_options *options) 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)); @@ -2642,6 +2696,8 @@ void diff_flush(struct diff_options *options) 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++; } @@ -2824,10 +2880,12 @@ void diff_change(struct diff_options *options, } 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; }