From 0660626caff6ac3745cd7b7908a2ca540141a2ec Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Fri, 5 May 2006 02:41:53 -0700 Subject: binary diff: further updates. This updates the user interface and generated diff data format. * "diff --binary" is used to signal that we want an e-mailable binary patch. It implies --full-index and -p. * "apply --allow-binary-replacement" acquired a short synonym "apply --binary". * After the "GIT binary patch\n" header line there is a token to record which binary patch mechanism was used, so that we can extend it later. Currently there are two mechanisms defined: "literal" and "delta". The former records the deflated postimage and the latter records the deflated delta from the preimage to postimage. For purely implementation convenience, I added the deflated length after these "literal/delta" tokens (otherwise the decoding side needs to guess and reallocate the buffer while inflating). Improvement patches are very welcomed. Signed-off-by: Junio C Hamano --- diff.h | 1 + 1 file changed, 1 insertion(+) (limited to 'diff.h') diff --git a/diff.h b/diff.h index b3b2c4dd28..d052608404 100644 --- a/diff.h +++ b/diff.h @@ -28,6 +28,7 @@ struct diff_options { with_raw:1, with_stat:1, tree_in_recursive:1, + binary:1, full_index:1, silent_on_remove:1, find_copies_harder:1; -- cgit v1.3 From ee1e5412a702674d4da95a4aef73a73d2834dcc3 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sat, 13 May 2006 13:23:48 -0700 Subject: git diff: support "-U" and "--unified" options properly We used to parse "-U" and "--unified" as part of the GIT_DIFF_OPTS environment variable, but strangely enough we would _not_ parse them as part of the normal diff command line (where we only accepted "-u"). This adds parsing of -U and --unified, both with an optional numeric argument. So now you can just say git diff --unified=5 to get a unified diff with a five-line context, instead of having to do something silly like GIT_DIFF_OPTS="--unified=5" git diff -u (that silly format does continue to still work, of course). Signed-off-by: Linus Torvalds Signed-off-by: Junio C Hamano --- combine-diff.c | 1 + diff.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++++++- diff.h | 1 + 3 files changed, 53 insertions(+), 1 deletion(-) (limited to 'diff.h') diff --git a/combine-diff.c b/combine-diff.c index 8a8fe3863a..64b20cce24 100644 --- a/combine-diff.c +++ b/combine-diff.c @@ -608,6 +608,7 @@ static int show_patch_diff(struct combine_diff_path *elem, int num_parent, int abbrev = opt->full_index ? 40 : DEFAULT_ABBREV; mmfile_t result_file; + context = opt->context; /* Read the result of merge first */ if (!working_tree_file) result = grab_blob(elem->sha1, &result_size); diff --git a/diff.c b/diff.c index 7a7b839e56..be925a3a39 100644 --- a/diff.c +++ b/diff.c @@ -558,7 +558,7 @@ static void builtin_diff(const char *name_a, ecbdata.label_path = lbl; xpp.flags = XDF_NEED_MINIMAL; - xecfg.ctxlen = 3; + xecfg.ctxlen = o->context; xecfg.flags = XDL_EMIT_FUNCNAMES; if (!diffopts) ; @@ -1182,6 +1182,7 @@ void diff_setup(struct diff_options *options) options->line_termination = '\n'; options->break_opt = -1; options->rename_limit = -1; + options->context = 3; options->change = diff_change; options->add_remove = diff_addremove; @@ -1222,11 +1223,60 @@ int diff_setup_done(struct diff_options *options) return 0; } +int opt_arg(const char *arg, int arg_short, const char *arg_long, int *val) +{ + char c, *eq; + int len; + + if (*arg != '-') + return 0; + c = *++arg; + if (!c) + return 0; + if (c == arg_short) { + c = *++arg; + if (!c) + return 1; + if (val && isdigit(c)) { + char *end; + int n = strtoul(arg, &end, 10); + if (*end) + return 0; + *val = n; + return 1; + } + return 0; + } + if (c != '-') + return 0; + arg++; + eq = strchr(arg, '='); + if (eq) + len = eq - arg; + else + len = strlen(arg); + if (!len || strncmp(arg, arg_long, len)) + return 0; + if (eq) { + int n; + char *end; + if (!isdigit(*++eq)) + return 0; + n = strtoul(eq, &end, 10); + if (*end) + return 0; + *val = n; + } + return 1; +} + int diff_opt_parse(struct diff_options *options, const char **av, int ac) { const char *arg = av[0]; if (!strcmp(arg, "-p") || !strcmp(arg, "-u")) options->output_format = DIFF_FORMAT_PATCH; + else if (opt_arg(arg, 'U', "unified", &options->context)) + options->output_format = DIFF_FORMAT_PATCH; else if (!strcmp(arg, "--patch-with-raw")) { options->output_format = DIFF_FORMAT_PATCH; options->with_raw = 1; diff --git a/diff.h b/diff.h index d052608404..bef586d850 100644 --- a/diff.h +++ b/diff.h @@ -32,6 +32,7 @@ struct diff_options { full_index:1, silent_on_remove:1, find_copies_harder:1; + int context; int break_opt; int detect_rename; int line_termination; -- cgit v1.3 From 4bbd261bbd941066735e41dff0ade9f50e6fe84d Mon Sep 17 00:00:00 2001 From: Sean Date: Sun, 14 May 2006 08:13:49 -0400 Subject: Add "--summary" option to git diff. Remove the need to pipe git diff through git apply to get the extended headers summary. Signed-off-by: Sean Estabrooks Signed-off-by: Junio C Hamano --- Documentation/diff-options.txt | 4 ++ diff.c | 88 +++++++++++++++++++++++++++++++++++++++++- diff.h | 3 +- 3 files changed, 93 insertions(+), 2 deletions(-) (limited to 'diff.h') diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt index c183dc9da0..f523ec2fbe 100644 --- a/Documentation/diff-options.txt +++ b/Documentation/diff-options.txt @@ -10,6 +10,10 @@ --stat:: Generate a diffstat instead of a patch. +--summary:: + Output a condensed summary of extended header information + such as creations, renames and mode changes. + --patch-with-stat:: Generate patch and prepend its diffstat. diff --git a/diff.c b/diff.c index 7a7b839e56..00b1044d3a 100644 --- a/diff.c +++ b/diff.c @@ -1233,6 +1233,8 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac) } else if (!strcmp(arg, "--stat")) options->output_format = DIFF_FORMAT_DIFFSTAT; + else if (!strcmp(arg, "--summary")) + options->summary = 1; else if (!strcmp(arg, "--patch-with-stat")) { options->output_format = DIFF_FORMAT_PATCH; options->with_stat = 1; @@ -1703,6 +1705,85 @@ static void flush_one_pair(struct diff_filepair *p, } } +static void show_file_mode_name(const char *newdelete, struct diff_filespec *fs) +{ + if (fs->mode) + printf(" %s mode %06o %s\n", newdelete, fs->mode, fs->path); + else + printf(" %s %s\n", newdelete, fs->path); +} + + +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) + printf(" mode change %06o => %06o %s\n", + p->one->mode, p->two->mode, p->two->path); + 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; + + /* 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)); + show_mode_change(p, 0); +} + +static void diff_summary(struct diff_filepair *p) +{ + switch(p->status) { + case DIFF_STATUS_DELETED: + show_file_mode_name("delete", p->one); + break; + case DIFF_STATUS_ADDED: + show_file_mode_name("create", p->two); + break; + case DIFF_STATUS_COPIED: + show_rename_copy("copy", p); + break; + case DIFF_STATUS_RENAMED: + show_rename_copy("rename", p); + break; + default: + if (p->score) { + printf(" rewrite %s (%d%%)\n", p->two->path, + (int)(0.5 + p->score * 100.0/MAX_SCORE)); + show_mode_change(p, 0); + } else show_mode_change(p, 1); + break; + } +} + void diff_flush(struct diff_options *options) { struct diff_queue_struct *q = &diff_queued_diff; @@ -1736,7 +1817,6 @@ void diff_flush(struct diff_options *options) for (i = 0; i < q->nr; i++) { struct diff_filepair *p = q->queue[i]; flush_one_pair(p, diff_output_format, options, diffstat); - diff_free_filepair(p); } if (diffstat) { @@ -1744,6 +1824,12 @@ void diff_flush(struct diff_options *options) free(diffstat); } + for (i = 0; i < q->nr; i++) { + if (options->summary) + diff_summary(q->queue[i]); + diff_free_filepair(q->queue[i]); + } + free(q->queue); q->queue = NULL; q->nr = q->alloc = 0; diff --git a/diff.h b/diff.h index d052608404..70077c6ed9 100644 --- a/diff.h +++ b/diff.h @@ -31,7 +31,8 @@ struct diff_options { binary:1, full_index:1, silent_on_remove:1, - find_copies_harder:1; + find_copies_harder:1, + summary:1; int break_opt; int detect_rename; int line_termination; -- cgit v1.3 From 8824689884a5673f803d77cda499f83b84145a06 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 20 May 2006 23:43:13 +0200 Subject: diff family: add --check option Actually, it is a diff option now, so you can say git diff --check to ask if what you are about to commit is a good patch. [jc: this also would work for fmt-patch, but the point is that the check is done before making a commit. format-patch is run from an already created commit, and that is too late to catch whitespace damaged change.] Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano --- diff.c | 115 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- diff.h | 1 + 2 files changed, 115 insertions(+), 1 deletion(-) (limited to 'diff.h') diff --git a/diff.c b/diff.c index e16e0bfc0a..af5db0ec12 100644 --- a/diff.c +++ b/diff.c @@ -397,6 +397,46 @@ static void show_stats(struct diffstat_t* data) total_files, adds, dels); } +struct checkdiff_t { + struct xdiff_emit_state xm; + const char *filename; + int lineno; +}; + +static void checkdiff_consume(void *priv, char *line, unsigned long len) +{ + struct checkdiff_t *data = priv; + + 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] == ' ') + spaces++; + if (line[i - 1] == '\t' && spaces) + printf("%s:%d: space before tab:%.*s\n", + data->filename, data->lineno, (int)len, line); + + /* check white space at line end */ + if (line[len - 1] == '\n') + len--; + if (isspace(line[len - 1])) + printf("%s:%d: white space at end: %.*s\n", + data->filename, data->lineno, (int)len, line); + } else if (line[0] == ' ') + data->lineno++; + else if (line[0] == '@') { + char *plus = strchr(line, '+'); + if (plus) + data->lineno = strtol(plus, line + len, 10); + else + die("invalid diff"); + } +} + static unsigned char *deflate_it(char *data, unsigned long size, unsigned long *result_size) @@ -624,6 +664,41 @@ static void builtin_diffstat(const char *name_a, const char *name_b, } } +static void builtin_checkdiff(const char *name_a, const char *name_b, + struct diff_filespec *one, + struct diff_filespec *two) +{ + mmfile_t mf1, mf2; + struct checkdiff_t data; + + if (!two) + return; + + memset(&data, 0, sizeof(data)); + data.xm.consume = checkdiff_consume; + data.filename = name_b ? name_b : name_a; + data.lineno = 0; + + if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0) + die("unable to read files to diff"); + + if (mmfile_is_binary(&mf2)) + return; + else { + /* Crazy xdl interfaces.. */ + xpparam_t xpp; + xdemitconf_t xecfg; + xdemitcb_t ecb; + + xpp.flags = XDF_NEED_MINIMAL; + xecfg.ctxlen = 0; + xecfg.flags = 0; + ecb.outf = xdiff_outf; + ecb.priv = &data; + xdl_diff(&mf1, &mf2, &xpp, &xecfg, &ecb); + } +} + struct diff_filespec *alloc_filespec(const char *path) { int namelen = strlen(path); @@ -1180,6 +1255,25 @@ static void run_diffstat(struct diff_filepair *p, struct diff_options *o, builtin_diffstat(name, other, p->one, p->two, diffstat, complete_rewrite); } +static void run_checkdiff(struct diff_filepair *p, struct diff_options *o) +{ + const char *name; + const char *other; + + if (DIFF_PAIR_UNMERGED(p)) { + /* unmerged */ + return; + } + + name = p->one->path; + other = (strcmp(name, p->two->path) ? p->two->path : NULL); + + diff_fill_sha1_info(p->one); + diff_fill_sha1_info(p->two); + + builtin_checkdiff(name, other, p->one, p->two); +} + void diff_setup(struct diff_options *options) { memset(options, 0, sizeof(*options)); @@ -1205,7 +1299,8 @@ int diff_setup_done(struct diff_options *options) * recursive bits for other formats here. */ if ((options->output_format == DIFF_FORMAT_PATCH) || - (options->output_format == DIFF_FORMAT_DIFFSTAT)) + (options->output_format == DIFF_FORMAT_DIFFSTAT) || + (options->output_format == DIFF_FORMAT_CHECKDIFF)) options->recursive = 1; if (options->detect_rename && options->rename_limit < 0) @@ -1288,6 +1383,8 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac) } else if (!strcmp(arg, "--stat")) options->output_format = DIFF_FORMAT_DIFFSTAT; + else if (!strcmp(arg, "--check")) + options->output_format = DIFF_FORMAT_CHECKDIFF; else if (!strcmp(arg, "--summary")) options->summary = 1; else if (!strcmp(arg, "--patch-with-stat")) { @@ -1610,6 +1707,19 @@ static void diff_flush_stat(struct diff_filepair *p, struct diff_options *o, run_diffstat(p, o, diffstat); } +static void diff_flush_checkdiff(struct diff_filepair *p, + struct diff_options *o) +{ + if (diff_unmodified_pair(p)) + return; + + if ((DIFF_FILE_VALID(p->one) && S_ISDIR(p->one->mode)) || + (DIFF_FILE_VALID(p->two) && S_ISDIR(p->two->mode))) + return; /* no tree diffs in patch format */ + + run_checkdiff(p, o); +} + int diff_queue_is_empty(void) { struct diff_queue_struct *q = &diff_queued_diff; @@ -1740,6 +1850,9 @@ static void flush_one_pair(struct diff_filepair *p, case DIFF_FORMAT_DIFFSTAT: diff_flush_stat(p, options, diffstat); break; + case DIFF_FORMAT_CHECKDIFF: + diff_flush_checkdiff(p, options); + break; case DIFF_FORMAT_PATCH: diff_flush_patch(p, options); break; diff --git a/diff.h b/diff.h index 3027974c1e..c672277df2 100644 --- a/diff.h +++ b/diff.h @@ -153,6 +153,7 @@ extern int diff_queue_is_empty(void); #define DIFF_FORMAT_NAME 4 #define DIFF_FORMAT_NAME_STATUS 5 #define DIFF_FORMAT_DIFFSTAT 6 +#define DIFF_FORMAT_CHECKDIFF 7 extern void diff_flush(struct diff_options*); -- cgit v1.3