static int use_size_cache;
+static int diff_detect_rename_default = 0;
static int diff_rename_limit_default = -1;
static int diff_use_color_default = 0;
#define COLOR_WHITE "\033[37m"
static const char *diff_colors[] = {
- [DIFF_RESET] = COLOR_RESET,
- [DIFF_PLAIN] = COLOR_NORMAL,
- [DIFF_METAINFO] = COLOR_BOLD,
- [DIFF_FRAGINFO] = COLOR_CYAN,
- [DIFF_FILE_OLD] = COLOR_RED,
- [DIFF_FILE_NEW] = COLOR_GREEN,
+ COLOR_RESET,
+ COLOR_NORMAL,
+ COLOR_BOLD,
+ COLOR_CYAN,
+ COLOR_RED,
+ COLOR_GREEN
};
static int parse_diff_color_slot(const char *var, int ofs)
die("bad config value '%s' for variable '%s'", value, var);
}
-int git_diff_config(const char *var, const char *value)
+/*
+ * These are to give UI layer defaults.
+ * The core-level commands such as git-diff-files should
+ * never be affected by the setting of diff.renames
+ * the user happens to have in the configuration file.
+ */
+int git_diff_ui_config(const char *var, const char *value)
{
if (!strcmp(var, "diff.renamelimit")) {
diff_rename_limit_default = git_config_int(var, value);
if (!strcmp(var, "diff.color")) {
if (!value)
diff_use_color_default = 1; /* bool */
- else if (!strcasecmp(value, "auto"))
- diff_use_color_default = isatty(1);
+ else if (!strcasecmp(value, "auto")) {
+ diff_use_color_default = 0;
+ if (isatty(1) || pager_in_use) {
+ char *term = getenv("TERM");
+ if (term && strcmp(term, "dumb"))
+ diff_use_color_default = 1;
+ }
+ }
else if (!strcasecmp(value, "never"))
diff_use_color_default = 0;
else if (!strcasecmp(value, "always"))
diff_use_color_default = git_config_bool(var, value);
return 0;
}
+ if (!strcmp(var, "diff.renames")) {
+ if (!value)
+ diff_detect_rename_default = DIFF_DETECT_RENAME;
+ else if (!strcasecmp(value, "copies") ||
+ !strcasecmp(value, "copy"))
+ diff_detect_rename_default = DIFF_DETECT_COPY;
+ else if (git_config_bool(var,value))
+ diff_detect_rename_default = DIFF_DETECT_RENAME;
+ return 0;
+ }
if (!strncmp(var, "diff.color.", 11)) {
int slot = parse_diff_color_slot(var, 11);
diff_colors[slot] = parse_diff_color_value(value, var);
}
if (len > 0 && line[len-1] == '\n')
len--;
- printf("%s%.*s%s\n", set, (int) len, line, reset);
+ fputs (set, stdout);
+ fwrite (line, len, 1, stdout);
+ puts (reset);
}
static char *pprint_rename(const char *a, const char *b)
z_stream stream;
memset(&stream, 0, sizeof(stream));
- deflateInit(&stream, Z_BEST_COMPRESSION);
+ deflateInit(&stream, zlib_compression_level);
bound = deflateBound(&stream, size);
deflated = xmalloc(bound);
stream.next_out = deflated;
if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0)
die("unable to read files to diff");
- if (mmfile_is_binary(&mf1) || mmfile_is_binary(&mf2)) {
+ if (!o->text && (mmfile_is_binary(&mf1) || mmfile_is_binary(&mf2))) {
/* Quite common confusing case */
if (mf1.size == mf2.size &&
!memcmp(mf1.ptr, mf2.ptr, mf1.size))
options->break_opt = -1;
options->rename_limit = -1;
options->context = 3;
- options->msg_sep = "\n";
+ options->msg_sep = "";
options->change = diff_change;
options->add_remove = diff_addremove;
options->color_diff = diff_use_color_default;
+ options->detect_rename = diff_detect_rename_default;
}
int diff_setup_done(struct diff_options *options)
DIFF_FORMAT_DIFFSTAT |
DIFF_FORMAT_CHECKDIFF))
options->recursive = 1;
+ /*
+ * Also pickaxe would not work very well if you do not say recursive
+ */
+ if (options->pickaxe)
+ options->recursive = 1;
if (options->detect_rename && options->rename_limit < 0)
options->rename_limit = diff_rename_limit_default;
options->output_format |= DIFF_FORMAT_PATCH;
options->full_index = options->binary = 1;
}
+ else if (!strcmp(arg, "-a") || !strcmp(arg, "--text")) {
+ options->text = 1;
+ }
else if (!strcmp(arg, "--name-only"))
options->output_format |= DIFF_FORMAT_NAME;
else if (!strcmp(arg, "--name-status"))
}
else if (!strcmp(arg, "--color"))
options->color_diff = 1;
+ else if (!strcmp(arg, "--no-color"))
+ options->color_diff = 0;
else if (!strcmp(arg, "-w") || !strcmp(arg, "--ignore-all-space"))
options->xdl_opts |= XDF_IGNORE_WHITESPACE;
else if (!strcmp(arg, "-b") || !strcmp(arg, "--ignore-space-change"))
options->xdl_opts |= XDF_IGNORE_WHITESPACE_CHANGE;
+ else if (!strcmp(arg, "--no-renames"))
+ options->detect_rename = 0;
else
return 0;
return 1;
}
}
+struct patch_id_t {
+ struct xdiff_emit_state xm;
+ SHA_CTX *ctx;
+ int patchlen;
+};
+
+static int remove_space(char *line, int len)
+{
+ int i;
+ char *dst = line;
+ unsigned char c;
+
+ for (i = 0; i < len; i++)
+ if (!isspace((c = line[i])))
+ *dst++ = c;
+
+ return dst - line;
+}
+
+static void patch_id_consume(void *priv, char *line, unsigned long len)
+{
+ struct patch_id_t *data = priv;
+ int new_len;
+
+ /* Ignore line numbers when computing the SHA1 of the patch */
+ if (!strncmp(line, "@@ -", 4))
+ return;
+
+ new_len = remove_space(line, len);
+
+ SHA1_Update(data->ctx, line, new_len);
+ data->patchlen += new_len;
+}
+
+/* returns 0 upon success, and writes result into sha1 */
+static int diff_get_patch_id(struct diff_options *options, unsigned char *sha1)
+{
+ struct diff_queue_struct *q = &diff_queued_diff;
+ int i;
+ SHA_CTX ctx;
+ struct patch_id_t data;
+ char buffer[PATH_MAX * 4 + 20];
+
+ SHA1_Init(&ctx);
+ memset(&data, 0, sizeof(struct patch_id_t));
+ data.ctx = &ctx;
+ data.xm.consume = patch_id_consume;
+
+ for (i = 0; i < q->nr; i++) {
+ xpparam_t xpp;
+ xdemitconf_t xecfg;
+ xdemitcb_t ecb;
+ mmfile_t mf1, mf2;
+ struct diff_filepair *p = q->queue[i];
+ int len1, len2;
+
+ if (p->status == 0)
+ return error("internal diff status error");
+ if (p->status == DIFF_STATUS_UNKNOWN)
+ continue;
+ if (diff_unmodified_pair(p))
+ continue;
+ if ((DIFF_FILE_VALID(p->one) && S_ISDIR(p->one->mode)) ||
+ (DIFF_FILE_VALID(p->two) && S_ISDIR(p->two->mode)))
+ continue;
+ if (DIFF_PAIR_UNMERGED(p))
+ continue;
+
+ diff_fill_sha1_info(p->one);
+ diff_fill_sha1_info(p->two);
+ if (fill_mmfile(&mf1, p->one) < 0 ||
+ fill_mmfile(&mf2, p->two) < 0)
+ return error("unable to read files to diff");
+
+ /* Maybe hash p->two? into the patch id? */
+ if (mmfile_is_binary(&mf2))
+ continue;
+
+ len1 = remove_space(p->one->path, strlen(p->one->path));
+ len2 = remove_space(p->two->path, strlen(p->two->path));
+ if (p->one->mode == 0)
+ len1 = snprintf(buffer, sizeof(buffer),
+ "diff--gita/%.*sb/%.*s"
+ "newfilemode%06o"
+ "---/dev/null"
+ "+++b/%.*s",
+ len1, p->one->path,
+ len2, p->two->path,
+ p->two->mode,
+ len2, p->two->path);
+ else if (p->two->mode == 0)
+ len1 = snprintf(buffer, sizeof(buffer),
+ "diff--gita/%.*sb/%.*s"
+ "deletedfilemode%06o"
+ "---a/%.*s"
+ "+++/dev/null",
+ len1, p->one->path,
+ len2, p->two->path,
+ p->one->mode,
+ len1, p->one->path);
+ else
+ len1 = snprintf(buffer, sizeof(buffer),
+ "diff--gita/%.*sb/%.*s"
+ "---a/%.*s"
+ "+++b/%.*s",
+ len1, p->one->path,
+ len2, p->two->path,
+ len1, p->one->path,
+ len2, p->two->path);
+ SHA1_Update(&ctx, buffer, len1);
+
+ xpp.flags = XDF_NEED_MINIMAL;
+ xecfg.ctxlen = 3;
+ xecfg.flags = XDL_EMIT_FUNCNAMES;
+ ecb.outf = xdiff_outf;
+ ecb.priv = &data;
+ xdl_diff(&mf1, &mf2, &xpp, &xecfg, &ecb);
+ }
+
+ SHA1_Final(sha1, &ctx);
+ return 0;
+}
+
+int diff_flush_patch_id(struct diff_options *options, unsigned char *sha1)
+{
+ struct diff_queue_struct *q = &diff_queued_diff;
+ int i;
+ int result = diff_get_patch_id(options, sha1);
+
+ for (i = 0; i < q->nr; i++)
+ diff_free_filepair(q->queue[i]);
+
+ free(q->queue);
+ q->queue = NULL;
+ q->nr = q->alloc = 0;
+
+ return result;
+}
+
static int is_summary_empty(const struct diff_queue_struct *q)
{
int i;
if (output_format & DIFF_FORMAT_DIFFSTAT) {
struct diffstat_t diffstat;
- if (separator++)
- putchar('\n');
-
memset(&diffstat, 0, sizeof(struct diffstat_t));
diffstat.xm.consume = diffstat_consume;
for (i = 0; i < q->nr; i++) {
diff_flush_stat(p, options, &diffstat);
}
show_stats(&diffstat);
+ separator++;
}
if (output_format & DIFF_FORMAT_SUMMARY && !is_summary_empty(q)) {
- if (separator++)
- putchar('\n');
-
for (i = 0; i < q->nr; i++)
diff_summary(q->queue[i]);
+ separator++;
}
if (output_format & DIFF_FORMAT_PATCH) {