|
|
@ -1999,16 +1999,86 @@ static void run_external_diff(const char *pgm, |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int similarity_index(struct diff_filepair *p) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
return p->score * 100 / MAX_SCORE; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void fill_metainfo(struct strbuf *msg, |
|
|
|
|
|
|
|
const char *name, |
|
|
|
|
|
|
|
const char *other, |
|
|
|
|
|
|
|
struct diff_filespec *one, |
|
|
|
|
|
|
|
struct diff_filespec *two, |
|
|
|
|
|
|
|
struct diff_options *o, |
|
|
|
|
|
|
|
struct diff_filepair *p) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
strbuf_init(msg, PATH_MAX * 2 + 300); |
|
|
|
|
|
|
|
switch (p->status) { |
|
|
|
|
|
|
|
case DIFF_STATUS_COPIED: |
|
|
|
|
|
|
|
strbuf_addf(msg, "similarity index %d%%", similarity_index(p)); |
|
|
|
|
|
|
|
strbuf_addstr(msg, "\ncopy from "); |
|
|
|
|
|
|
|
quote_c_style(name, msg, NULL, 0); |
|
|
|
|
|
|
|
strbuf_addstr(msg, "\ncopy to "); |
|
|
|
|
|
|
|
quote_c_style(other, msg, NULL, 0); |
|
|
|
|
|
|
|
strbuf_addch(msg, '\n'); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case DIFF_STATUS_RENAMED: |
|
|
|
|
|
|
|
strbuf_addf(msg, "similarity index %d%%", similarity_index(p)); |
|
|
|
|
|
|
|
strbuf_addstr(msg, "\nrename from "); |
|
|
|
|
|
|
|
quote_c_style(name, msg, NULL, 0); |
|
|
|
|
|
|
|
strbuf_addstr(msg, "\nrename to "); |
|
|
|
|
|
|
|
quote_c_style(other, msg, NULL, 0); |
|
|
|
|
|
|
|
strbuf_addch(msg, '\n'); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case DIFF_STATUS_MODIFIED: |
|
|
|
|
|
|
|
if (p->score) { |
|
|
|
|
|
|
|
strbuf_addf(msg, "dissimilarity index %d%%\n", |
|
|
|
|
|
|
|
similarity_index(p)); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
/* fallthru */ |
|
|
|
|
|
|
|
default: |
|
|
|
|
|
|
|
/* nothing */ |
|
|
|
|
|
|
|
; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (one && two && hashcmp(one->sha1, two->sha1)) { |
|
|
|
|
|
|
|
int abbrev = DIFF_OPT_TST(o, FULL_INDEX) ? 40 : DEFAULT_ABBREV; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (DIFF_OPT_TST(o, BINARY)) { |
|
|
|
|
|
|
|
mmfile_t mf; |
|
|
|
|
|
|
|
if ((!fill_mmfile(&mf, one) && diff_filespec_is_binary(one)) || |
|
|
|
|
|
|
|
(!fill_mmfile(&mf, two) && diff_filespec_is_binary(two))) |
|
|
|
|
|
|
|
abbrev = 40; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
strbuf_addf(msg, "index %.*s..%.*s", |
|
|
|
|
|
|
|
abbrev, sha1_to_hex(one->sha1), |
|
|
|
|
|
|
|
abbrev, sha1_to_hex(two->sha1)); |
|
|
|
|
|
|
|
if (one->mode == two->mode) |
|
|
|
|
|
|
|
strbuf_addf(msg, " %06o", one->mode); |
|
|
|
|
|
|
|
strbuf_addch(msg, '\n'); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (msg->len) |
|
|
|
|
|
|
|
strbuf_setlen(msg, msg->len - 1); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void run_diff_cmd(const char *pgm, |
|
|
|
static void run_diff_cmd(const char *pgm, |
|
|
|
const char *name, |
|
|
|
const char *name, |
|
|
|
const char *other, |
|
|
|
const char *other, |
|
|
|
const char *attr_path, |
|
|
|
const char *attr_path, |
|
|
|
struct diff_filespec *one, |
|
|
|
struct diff_filespec *one, |
|
|
|
struct diff_filespec *two, |
|
|
|
struct diff_filespec *two, |
|
|
|
const char *xfrm_msg, |
|
|
|
struct strbuf *msg, |
|
|
|
struct diff_options *o, |
|
|
|
struct diff_options *o, |
|
|
|
int complete_rewrite) |
|
|
|
struct diff_filepair *p) |
|
|
|
{ |
|
|
|
{ |
|
|
|
|
|
|
|
const char *xfrm_msg = NULL; |
|
|
|
|
|
|
|
int complete_rewrite = (p->status == DIFF_STATUS_MODIFIED) && p->score; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (msg) { |
|
|
|
|
|
|
|
fill_metainfo(msg, name, other, one, two, o, p); |
|
|
|
|
|
|
|
xfrm_msg = msg->len ? msg->buf : NULL; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (!DIFF_OPT_TST(o, ALLOW_EXTERNAL)) |
|
|
|
if (!DIFF_OPT_TST(o, ALLOW_EXTERNAL)) |
|
|
|
pgm = NULL; |
|
|
|
pgm = NULL; |
|
|
|
else { |
|
|
|
else { |
|
|
@ -2048,11 +2118,6 @@ static void diff_fill_sha1_info(struct diff_filespec *one) |
|
|
|
hashclr(one->sha1); |
|
|
|
hashclr(one->sha1); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static int similarity_index(struct diff_filepair *p) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
return p->score * 100 / MAX_SCORE; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void strip_prefix(int prefix_length, const char **namep, const char **otherp) |
|
|
|
static void strip_prefix(int prefix_length, const char **namep, const char **otherp) |
|
|
|
{ |
|
|
|
{ |
|
|
|
/* Strip the prefix but do not molest /dev/null and absolute paths */ |
|
|
|
/* Strip the prefix but do not molest /dev/null and absolute paths */ |
|
|
@ -2066,13 +2131,11 @@ static void run_diff(struct diff_filepair *p, struct diff_options *o) |
|
|
|
{ |
|
|
|
{ |
|
|
|
const char *pgm = external_diff(); |
|
|
|
const char *pgm = external_diff(); |
|
|
|
struct strbuf msg; |
|
|
|
struct strbuf msg; |
|
|
|
char *xfrm_msg; |
|
|
|
|
|
|
|
struct diff_filespec *one = p->one; |
|
|
|
struct diff_filespec *one = p->one; |
|
|
|
struct diff_filespec *two = p->two; |
|
|
|
struct diff_filespec *two = p->two; |
|
|
|
const char *name; |
|
|
|
const char *name; |
|
|
|
const char *other; |
|
|
|
const char *other; |
|
|
|
const char *attr_path; |
|
|
|
const char *attr_path; |
|
|
|
int complete_rewrite = 0; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
name = p->one->path; |
|
|
|
name = p->one->path; |
|
|
|
other = (strcmp(name, p->two->path) ? p->two->path : NULL); |
|
|
|
other = (strcmp(name, p->two->path) ? p->two->path : NULL); |
|
|
@ -2082,83 +2145,34 @@ static void run_diff(struct diff_filepair *p, struct diff_options *o) |
|
|
|
|
|
|
|
|
|
|
|
if (DIFF_PAIR_UNMERGED(p)) { |
|
|
|
if (DIFF_PAIR_UNMERGED(p)) { |
|
|
|
run_diff_cmd(pgm, name, NULL, attr_path, |
|
|
|
run_diff_cmd(pgm, name, NULL, attr_path, |
|
|
|
NULL, NULL, NULL, o, 0); |
|
|
|
NULL, NULL, NULL, o, p); |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
diff_fill_sha1_info(one); |
|
|
|
diff_fill_sha1_info(one); |
|
|
|
diff_fill_sha1_info(two); |
|
|
|
diff_fill_sha1_info(two); |
|
|
|
|
|
|
|
|
|
|
|
strbuf_init(&msg, PATH_MAX * 2 + 300); |
|
|
|
|
|
|
|
switch (p->status) { |
|
|
|
|
|
|
|
case DIFF_STATUS_COPIED: |
|
|
|
|
|
|
|
strbuf_addf(&msg, "similarity index %d%%", similarity_index(p)); |
|
|
|
|
|
|
|
strbuf_addstr(&msg, "\ncopy from "); |
|
|
|
|
|
|
|
quote_c_style(name, &msg, NULL, 0); |
|
|
|
|
|
|
|
strbuf_addstr(&msg, "\ncopy to "); |
|
|
|
|
|
|
|
quote_c_style(other, &msg, NULL, 0); |
|
|
|
|
|
|
|
strbuf_addch(&msg, '\n'); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case DIFF_STATUS_RENAMED: |
|
|
|
|
|
|
|
strbuf_addf(&msg, "similarity index %d%%", similarity_index(p)); |
|
|
|
|
|
|
|
strbuf_addstr(&msg, "\nrename from "); |
|
|
|
|
|
|
|
quote_c_style(name, &msg, NULL, 0); |
|
|
|
|
|
|
|
strbuf_addstr(&msg, "\nrename to "); |
|
|
|
|
|
|
|
quote_c_style(other, &msg, NULL, 0); |
|
|
|
|
|
|
|
strbuf_addch(&msg, '\n'); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case DIFF_STATUS_MODIFIED: |
|
|
|
|
|
|
|
if (p->score) { |
|
|
|
|
|
|
|
strbuf_addf(&msg, "dissimilarity index %d%%\n", |
|
|
|
|
|
|
|
similarity_index(p)); |
|
|
|
|
|
|
|
complete_rewrite = 1; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
/* fallthru */ |
|
|
|
|
|
|
|
default: |
|
|
|
|
|
|
|
/* nothing */ |
|
|
|
|
|
|
|
; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (hashcmp(one->sha1, two->sha1)) { |
|
|
|
|
|
|
|
int abbrev = DIFF_OPT_TST(o, FULL_INDEX) ? 40 : DEFAULT_ABBREV; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (DIFF_OPT_TST(o, BINARY)) { |
|
|
|
|
|
|
|
mmfile_t mf; |
|
|
|
|
|
|
|
if ((!fill_mmfile(&mf, one) && diff_filespec_is_binary(one)) || |
|
|
|
|
|
|
|
(!fill_mmfile(&mf, two) && diff_filespec_is_binary(two))) |
|
|
|
|
|
|
|
abbrev = 40; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
strbuf_addf(&msg, "index %.*s..%.*s", |
|
|
|
|
|
|
|
abbrev, sha1_to_hex(one->sha1), |
|
|
|
|
|
|
|
abbrev, sha1_to_hex(two->sha1)); |
|
|
|
|
|
|
|
if (one->mode == two->mode) |
|
|
|
|
|
|
|
strbuf_addf(&msg, " %06o", one->mode); |
|
|
|
|
|
|
|
strbuf_addch(&msg, '\n'); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (msg.len) |
|
|
|
|
|
|
|
strbuf_setlen(&msg, msg.len - 1); |
|
|
|
|
|
|
|
xfrm_msg = msg.len ? msg.buf : NULL; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!pgm && |
|
|
|
if (!pgm && |
|
|
|
DIFF_FILE_VALID(one) && DIFF_FILE_VALID(two) && |
|
|
|
DIFF_FILE_VALID(one) && DIFF_FILE_VALID(two) && |
|
|
|
(S_IFMT & one->mode) != (S_IFMT & two->mode)) { |
|
|
|
(S_IFMT & one->mode) != (S_IFMT & two->mode)) { |
|
|
|
/* a filepair that changes between file and symlink |
|
|
|
/* |
|
|
|
|
|
|
|
* a filepair that changes between file and symlink |
|
|
|
* needs to be split into deletion and creation. |
|
|
|
* needs to be split into deletion and creation. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
struct diff_filespec *null = alloc_filespec(two->path); |
|
|
|
struct diff_filespec *null = alloc_filespec(two->path); |
|
|
|
run_diff_cmd(NULL, name, other, attr_path, |
|
|
|
run_diff_cmd(NULL, name, other, attr_path, |
|
|
|
one, null, xfrm_msg, o, 0); |
|
|
|
one, null, &msg, o, p); |
|
|
|
free(null); |
|
|
|
free(null); |
|
|
|
|
|
|
|
strbuf_release(&msg); |
|
|
|
|
|
|
|
|
|
|
|
null = alloc_filespec(one->path); |
|
|
|
null = alloc_filespec(one->path); |
|
|
|
run_diff_cmd(NULL, name, other, attr_path, |
|
|
|
run_diff_cmd(NULL, name, other, attr_path, |
|
|
|
null, two, xfrm_msg, o, 0); |
|
|
|
null, two, &msg, o, p); |
|
|
|
free(null); |
|
|
|
free(null); |
|
|
|
} |
|
|
|
} |
|
|
|
else |
|
|
|
else |
|
|
|
run_diff_cmd(pgm, name, other, attr_path, |
|
|
|
run_diff_cmd(pgm, name, other, attr_path, |
|
|
|
one, two, xfrm_msg, o, complete_rewrite); |
|
|
|
one, two, &msg, o, p); |
|
|
|
|
|
|
|
|
|
|
|
strbuf_release(&msg); |
|
|
|
strbuf_release(&msg); |
|
|
|
} |
|
|
|
} |
|
|
|