summaryrefslogtreecommitdiff
path: root/diff.c
diff options
context:
space:
mode:
Diffstat (limited to 'diff.c')
-rw-r--r--diff.c75
1 files changed, 70 insertions, 5 deletions
diff --git a/diff.c b/diff.c
index dca87e164f..7b5601de2f 100644
--- a/diff.c
+++ b/diff.c
@@ -2444,6 +2444,15 @@ static int fn_out_consume(void *priv, char *line, unsigned long len)
return 0;
}
+static int quick_consume(void *priv, char *line UNUSED, unsigned long len UNUSED)
+{
+ struct emit_callback *ecbdata = priv;
+ struct diff_options *o = ecbdata->opt;
+
+ o->found_changes = 1;
+ return 1;
+}
+
static void pprint_rename(struct strbuf *name, const char *a, const char *b)
{
const char *old_name = a;
@@ -3759,8 +3768,21 @@ static void builtin_diff(const char *name_a,
if (o->word_diff)
init_diff_words_data(&ecbdata, o, one, two);
- if (xdi_diff_outf(&mf1, &mf2, NULL, fn_out_consume,
- &ecbdata, &xpp, &xecfg))
+ if (o->dry_run) {
+ /*
+ * Unlike the !dry_run case, we need to ignore the
+ * return value from xdi_diff_outf() here, because
+ * xdi_diff_outf() takes non-zero return from its
+ * callback function as a sign of error and returns
+ * early (which is why we return non-zero from our
+ * callback, quick_consume()). Unfortunately,
+ * xdi_diff_outf() signals an error by returning
+ * non-zero.
+ */
+ xdi_diff_outf(&mf1, &mf2, NULL, quick_consume,
+ &ecbdata, &xpp, &xecfg);
+ } else if (xdi_diff_outf(&mf1, &mf2, NULL, fn_out_consume,
+ &ecbdata, &xpp, &xecfg))
die("unable to generate diff for %s", one->path);
if (o->word_diff)
free_diff_words_data(&ecbdata);
@@ -6150,6 +6172,22 @@ static void diff_flush_patch(struct diff_filepair *p, struct diff_options *o)
run_diff(p, o);
}
+/* return 1 if any change is found; otherwise, return 0 */
+static int diff_flush_patch_quietly(struct diff_filepair *p, struct diff_options *o)
+{
+ int saved_dry_run = o->dry_run;
+ int saved_found_changes = o->found_changes;
+ int ret;
+
+ o->dry_run = 1;
+ o->found_changes = 0;
+ diff_flush_patch(p, o);
+ ret = o->found_changes;
+ o->dry_run = saved_dry_run;
+ o->found_changes |= saved_found_changes;
+ return ret;
+}
+
static void diff_flush_stat(struct diff_filepair *p, struct diff_options *o,
struct diffstat_t *diffstat)
{
@@ -6776,10 +6814,37 @@ void diff_flush(struct diff_options *options)
DIFF_FORMAT_NAME |
DIFF_FORMAT_NAME_STATUS |
DIFF_FORMAT_CHECKDIFF)) {
+ /*
+ * make sure diff_Flush_patch_quietly() to be silent.
+ */
+ FILE *dev_null = NULL;
+ int saved_color_moved = options->color_moved;
+
+ if (options->flags.diff_from_contents) {
+ dev_null = xfopen("/dev/null", "w");
+ options->color_moved = 0;
+ }
for (i = 0; i < q->nr; i++) {
struct diff_filepair *p = q->queue[i];
- if (check_pair_status(p))
- flush_one_pair(p, options);
+
+ if (!check_pair_status(p))
+ continue;
+
+ if (options->flags.diff_from_contents) {
+ FILE *saved_file = options->file;
+ int found_changes;
+
+ options->file = dev_null;
+ found_changes = diff_flush_patch_quietly(p, options);
+ options->file = saved_file;
+ if (!found_changes)
+ continue;
+ }
+ flush_one_pair(p, options);
+ }
+ if (options->flags.diff_from_contents) {
+ fclose(dev_null);
+ options->color_moved = saved_color_moved;
}
separator++;
}
@@ -6843,7 +6908,7 @@ void diff_flush(struct diff_options *options)
for (i = 0; i < q->nr; i++) {
struct diff_filepair *p = q->queue[i];
if (check_pair_status(p))
- diff_flush_patch(p, options);
+ diff_flush_patch_quietly(p, options);
if (options->found_changes)
break;
}