static int use_size_cache;
+int diff_rename_limit_default = -1;
+
+int git_diff_config(const char *var, const char *value)
+{
+ if (!strcmp(var, "diff.renamelimit")) {
+ diff_rename_limit_default = git_config_int(var, value);
+ return 0;
+ }
+
+ return git_default_config(var, value);
+}
+
static char *quote_one(const char *str)
{
int needlen;
}
if (S_ISLNK(st.st_mode)) {
int ret;
- char *buf, buf_[1024];
- buf = ((sizeof(buf_) < st.st_size) ?
- xmalloc(st.st_size) : buf_);
+ char buf[PATH_MAX + 1]; /* ought to be SYMLINK_MAX */
+ if (sizeof(buf) <= st.st_size)
+ die("symlink too long: %s", name);
ret = readlink(name, buf, st.st_size);
if (ret < 0)
die("readlink(%s)", name);
if (DIFF_FILE_VALID(one)) {
if (!one->sha1_valid) {
struct stat st;
- if (stat(one->path, &st) < 0)
+ if (lstat(one->path, &st) < 0)
die("stat %s", one->path);
if (index_path(one->sha1, one->path, &st, 0))
die("cannot hash %s\n", one->path);
memset(one->sha1, 0, 20);
}
-static void run_diff(struct diff_filepair *p)
+static void run_diff(struct diff_filepair *p, struct diff_options *o)
{
const char *pgm = external_diff();
char msg[PATH_MAX*2+300], *xfrm_msg;
if (memcmp(one->sha1, two->sha1, 20)) {
char one_sha1[41];
+ int abbrev = o->full_index ? 40 : DIFF_DEFAULT_INDEX_ABBREV;
memcpy(one_sha1, sha1_to_hex(one->sha1), 41);
len += snprintf(msg + len, sizeof(msg) - len,
- "index %.7s..%.7s", one_sha1,
+ "index %.*s..%.*s",
+ abbrev, one_sha1, abbrev,
sha1_to_hex(two->sha1));
if (one->mode == two->mode)
len += snprintf(msg + len, sizeof(msg) - len,
int diff_setup_done(struct diff_options *options)
{
- if ((options->find_copies_harder || 0 <= options->rename_limit) &&
- options->detect_rename != DIFF_DETECT_COPY)
+ if ((options->find_copies_harder &&
+ options->detect_rename != DIFF_DETECT_COPY) ||
+ (0 <= options->rename_limit && !options->detect_rename))
return -1;
+ if (options->detect_rename && options->rename_limit < 0)
+ options->rename_limit = diff_rename_limit_default;
if (options->setup & DIFF_SETUP_USE_CACHE) {
if (!active_cache)
/* read-cache does not die even when it fails
* so it is safe for us to do this here. Also
* it does not smudge active_cache or active_nr
* when it fails, so we do not have to worry about
- * cleaning it up oufselves either.
+ * cleaning it up ourselves either.
*/
read_cache();
}
if (options->setup & DIFF_SETUP_USE_SIZE_CACHE)
use_size_cache = 1;
+ if (options->abbrev <= 0 || 40 < options->abbrev)
+ options->abbrev = 40; /* full */
return 0;
}
options->line_termination = 0;
else if (!strncmp(arg, "-l", 2))
options->rename_limit = strtoul(arg+2, NULL, 10);
+ else if (!strcmp(arg, "--full-index"))
+ options->full_index = 1;
else if (!strcmp(arg, "--name-only"))
options->output_format = DIFF_FORMAT_NAME;
else if (!strcmp(arg, "--name-status"))
}
else if (!strcmp(arg, "--find-copies-harder"))
options->find_copies_harder = 1;
+ else if (!strcmp(arg, "--abbrev"))
+ options->abbrev = DIFF_DEFAULT_ABBREV;
+ else if (!strncmp(arg, "--abbrev=", 9))
+ options->abbrev = strtoul(arg + 9, NULL, 10);
else
return 0;
return 1;
static int parse_num(const char **cp_p)
{
- int num, scale, ch, cnt;
+ unsigned long num, scale;
+ int ch, dot;
const char *cp = *cp_p;
- cnt = num = 0;
+ num = 0;
scale = 1;
- while ('0' <= (ch = *cp) && ch <= '9') {
- if (cnt++ < 5) {
- /* We simply ignore more than 5 digits precision. */
- scale *= 10;
- num = num * 10 + ch - '0';
+ dot = 0;
+ for(;;) {
+ ch = *cp;
+ if ( !dot && ch == '.' ) {
+ scale = 1;
+ dot = 1;
+ } else if ( ch == '%' ) {
+ scale = dot ? scale*100 : 100;
+ cp++; /* % is always at the end */
+ break;
+ } else if ( ch >= '0' && ch <= '9' ) {
+ if ( scale < 100000 ) {
+ scale *= 10;
+ num = (num*10) + (ch-'0');
+ }
+ } else {
+ break;
}
cp++;
}
/* user says num divided by scale and we say internally that
* is MAX_SCORE * num / scale.
*/
- return (MAX_SCORE * num / scale);
+ return (num >= scale) ? MAX_SCORE : (MAX_SCORE * num / scale);
}
int diff_scoreopt_parse(const char *opt)
free(p);
}
+/* This is different from find_unique_abbrev() in that
+ * it needs to deal with 0{40} SHA1.
+ */
+const char *diff_unique_abbrev(const unsigned char *sha1, int len)
+{
+ int abblen;
+ const char *abbrev;
+ if (len == 40)
+ return sha1_to_hex(sha1);
+
+ abbrev = find_unique_abbrev(sha1, len);
+ if (!abbrev) {
+ if (!memcmp(sha1, null_sha1, 20)) {
+ char *buf = sha1_to_hex(null_sha1);
+ if (len < 37)
+ strcpy(buf + len, "...");
+ return buf;
+ }
+ else
+ return sha1_to_hex(sha1);
+ }
+ abblen = strlen(abbrev);
+ if (abblen < 37) {
+ static char hex[41];
+ if (len < abblen && abblen <= len + 2)
+ sprintf(hex, "%s%.*s", abbrev, len+3-abblen, "..");
+ else
+ sprintf(hex, "%s...", abbrev);
+ return hex;
+ }
+ return sha1_to_hex(sha1);
+}
+
static void diff_flush_raw(struct diff_filepair *p,
int line_termination,
int inter_name_termination,
- int output_format)
+ struct diff_options *options)
{
int two_paths;
char status[10];
+ int abbrev = options->abbrev;
const char *path_one, *path_two;
+ int output_format = options->output_format;
path_one = p->one->path;
path_two = p->two->path;
}
if (output_format != DIFF_FORMAT_NAME_STATUS) {
printf(":%06o %06o %s ",
- p->one->mode, p->two->mode, sha1_to_hex(p->one->sha1));
- printf("%s ", sha1_to_hex(p->two->sha1));
+ p->one->mode, p->two->mode,
+ diff_unique_abbrev(p->one->sha1, abbrev));
+ printf("%s ",
+ diff_unique_abbrev(p->two->sha1, abbrev));
}
printf("%s%c%s", status, inter_name_termination, path_one);
if (two_paths)
return 0;
}
-static void diff_flush_patch(struct diff_filepair *p)
+static void diff_flush_patch(struct diff_filepair *p, struct diff_options *o)
{
if (diff_unmodified_pair(p))
return;
(DIFF_FILE_VALID(p->two) && S_ISDIR(p->two->mode)))
return; /* no tree diffs in patch format */
- run_diff(p);
+ run_diff(p, o);
}
int diff_queue_is_empty(void)
die("internal error in diff-resolve-rename-copy");
switch (diff_output_format) {
case DIFF_FORMAT_PATCH:
- diff_flush_patch(p);
+ diff_flush_patch(p, options);
break;
case DIFF_FORMAT_RAW:
case DIFF_FORMAT_NAME_STATUS:
diff_flush_raw(p, line_termination,
inter_name_termination,
- diff_output_format);
+ options);
break;
case DIFF_FORMAT_NAME:
diff_flush_name(p,