Browse Source

[PATCH] Diffcore updates.

This moves the path selection logic from individual programs to a new
diffcore transformer (diff-tree still needs to have its own for
performance reasons).  Also the header printing code in diff-tree was
tweaked not to produce anything when pickaxe is in effect and there is
nothing interesting to report.  An interesting example is the following
in the GIT archive itself:

    $ git-whatchanged -p -C -S'or something in a real script'

Signed-off-by: Junio C Hamano <junkio@cox.net>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
maint
Junio C Hamano 20 years ago committed by Linus Torvalds
parent
commit
6b14d7faf0
  1. 9
      Makefile
  2. 27
      diff-cache.c
  3. 38
      diff-files.c
  4. 17
      diff-helper.c
  5. 44
      diff-tree.c
  6. 172
      diff.c
  7. 22
      diff.h
  8. 63
      diffcore-pathspec.c
  9. 15
      diffcore-pickaxe.c
  10. 21
      diffcore-rename.c
  11. 4
      diffcore.h

9
Makefile

@ -45,7 +45,7 @@ LIB_H += strbuf.h
LIB_OBJS += strbuf.o LIB_OBJS += strbuf.o


LIB_H += diff.h LIB_H += diff.h
LIB_OBJS += diff.o diffcore-rename.o diffcore-pickaxe.o LIB_OBJS += diff.o diffcore-rename.o diffcore-pickaxe.o diffcore-pathspec.o


LIB_OBJS += gitenv.o LIB_OBJS += gitenv.o


@ -123,9 +123,10 @@ sha1_file.o: $(LIB_H)
usage.o: $(LIB_H) usage.o: $(LIB_H)
strbuf.o: $(LIB_H) strbuf.o: $(LIB_H)
gitenv.o: $(LIB_H) gitenv.o: $(LIB_H)
diff.o: $(LIB_H) diff.o: $(LIB_H) diffcore.h
diffcore-rename.o : $(LIB_H) diffcore-rename.o : $(LIB_H) diffcore.h
diffcore-pickaxe.o : $(LIB_H) diffcore-pathspec.o : $(LIB_H) diffcore.h
diffcore-pickaxe.o : $(LIB_H) diffcore.h


test: all test: all
make -C t/ all make -C t/ all

27
diff-cache.c

@ -71,7 +71,7 @@ static int show_modified(struct cache_entry *old,


oldmode = old->ce_mode; oldmode = old->ce_mode;
if (mode == oldmode && !memcmp(sha1, old->sha1, 20) && if (mode == oldmode && !memcmp(sha1, old->sha1, 20) &&
detect_rename < 2) detect_rename < DIFF_DETECT_COPY)
return 0; return 0;


mode = ntohl(mode); mode = ntohl(mode);
@ -156,7 +156,7 @@ static void mark_merge_entries(void)
static char *diff_cache_usage = static char *diff_cache_usage =
"git-diff-cache [-p] [-r] [-z] [-m] [-M] [-C] [-R] [-S<string>] [--cached] <tree-ish>"; "git-diff-cache [-p] [-r] [-z] [-m] [-M] [-C] [-R] [-S<string>] [--cached] <tree-ish>";


int main(int argc, char **argv) int main(int argc, const char **argv)
{ {
unsigned char tree_sha1[20]; unsigned char tree_sha1[20];
void *tree; void *tree;
@ -165,7 +165,7 @@ int main(int argc, char **argv)


read_cache(); read_cache();
while (argc > 2) { while (argc > 2) {
char *arg = argv[1]; const char *arg = argv[1];
argv++; argv++;
argc--; argc--;
if (!strcmp(arg, "-r")) { if (!strcmp(arg, "-r")) {
@ -177,12 +177,12 @@ int main(int argc, char **argv)
continue; continue;
} }
if (!strncmp(arg, "-M", 2)) { if (!strncmp(arg, "-M", 2)) {
detect_rename = 1; detect_rename = DIFF_DETECT_RENAME;
diff_score_opt = diff_scoreopt_parse(arg); diff_score_opt = diff_scoreopt_parse(arg);
continue; continue;
} }
if (!strncmp(arg, "-C", 2)) { if (!strncmp(arg, "-C", 2)) {
detect_rename = 2; detect_rename = DIFF_DETECT_COPY;
diff_score_opt = diff_scoreopt_parse(arg); diff_score_opt = diff_scoreopt_parse(arg);
continue; continue;
} }
@ -209,10 +209,14 @@ int main(int argc, char **argv)
usage(diff_cache_usage); usage(diff_cache_usage);
} }


if (argc != 2 || get_sha1(argv[1], tree_sha1)) if (argc < 2 || get_sha1(argv[1], tree_sha1))
usage(diff_cache_usage); usage(diff_cache_usage);
argv++;
argc--;


diff_setup(reverse_diff, diff_output_format); /* The rest is for paths restriction. */

diff_setup(reverse_diff);


mark_merge_entries(); mark_merge_entries();


@ -224,9 +228,12 @@ int main(int argc, char **argv)


ret = diff_cache(active_cache, active_nr); ret = diff_cache(active_cache, active_nr);
if (detect_rename) if (detect_rename)
diff_detect_rename(detect_rename, diff_score_opt); diffcore_rename(detect_rename, diff_score_opt);
diffcore_prune();
if (pickaxe) if (pickaxe)
diff_pickaxe(pickaxe); diffcore_pickaxe(pickaxe);
diff_flush(NULL, 0); if (2 <= argc)
diffcore_pathspec(argv + 1);
diff_flush(diff_output_format);
return ret; return ret;
} }

38
diff-files.c

@ -16,21 +16,6 @@ static int diff_score_opt = 0;
static const char *pickaxe = NULL; static const char *pickaxe = NULL;
static int silent = 0; static int silent = 0;


static int matches_pathspec(struct cache_entry *ce, char **spec, int cnt)
{
int i;
int namelen = ce_namelen(ce);
for (i = 0; i < cnt; i++) {
int speclen = strlen(spec[i]);
if (! strncmp(spec[i], ce->name, speclen) &&
speclen <= namelen &&
(ce->name[speclen] == 0 ||
ce->name[speclen] == '/'))
return 1;
}
return 0;
}

static void show_unmerge(const char *path) static void show_unmerge(const char *path)
{ {
diff_unmerge(path); diff_unmerge(path);
@ -48,7 +33,7 @@ static void show_modified(int oldmode, int mode,
diff_change(oldmode, mode, old_sha1, sha1, path, NULL); diff_change(oldmode, mode, old_sha1, sha1, path, NULL);
} }


int main(int argc, char **argv) int main(int argc, const char **argv)
{ {
static const unsigned char null_sha1[20] = { 0, }; static const unsigned char null_sha1[20] = { 0, };
int entries = read_cache(); int entries = read_cache();
@ -71,11 +56,11 @@ int main(int argc, char **argv)
pickaxe = argv[1] + 2; pickaxe = argv[1] + 2;
else if (!strncmp(argv[1], "-M", 2)) { else if (!strncmp(argv[1], "-M", 2)) {
diff_score_opt = diff_scoreopt_parse(argv[1]); diff_score_opt = diff_scoreopt_parse(argv[1]);
detect_rename = 1; detect_rename = DIFF_DETECT_RENAME;
} }
else if (!strncmp(argv[1], "-C", 2)) { else if (!strncmp(argv[1], "-C", 2)) {
diff_score_opt = diff_scoreopt_parse(argv[1]); diff_score_opt = diff_scoreopt_parse(argv[1]);
detect_rename = 2; detect_rename = DIFF_DETECT_COPY;
} }
else else
usage(diff_files_usage); usage(diff_files_usage);
@ -90,7 +75,7 @@ int main(int argc, char **argv)
exit(1); exit(1);
} }


diff_setup(reverse_diff, diff_output_format); diff_setup(reverse_diff);


for (i = 0; i < entries; i++) { for (i = 0; i < entries; i++) {
struct stat st; struct stat st;
@ -98,10 +83,6 @@ int main(int argc, char **argv)
struct cache_entry *ce = active_cache[i]; struct cache_entry *ce = active_cache[i];
int changed; int changed;


if (1 < argc &&
! matches_pathspec(ce, argv+1, argc-1))
continue;

if (ce_stage(ce)) { if (ce_stage(ce)) {
show_unmerge(ce->name); show_unmerge(ce->name);
while (i < entries && while (i < entries &&
@ -122,7 +103,7 @@ int main(int argc, char **argv)
continue; continue;
} }
changed = ce_match_stat(ce, &st); changed = ce_match_stat(ce, &st);
if (!changed && detect_rename < 2) if (!changed && detect_rename < DIFF_DETECT_COPY)
continue; continue;


oldmode = ntohl(ce->ce_mode); oldmode = ntohl(ce->ce_mode);
@ -133,9 +114,12 @@ int main(int argc, char **argv)
ce->name); ce->name);
} }
if (detect_rename) if (detect_rename)
diff_detect_rename(detect_rename, diff_score_opt); diffcore_rename(detect_rename, diff_score_opt);
diffcore_prune();
if (pickaxe) if (pickaxe)
diff_pickaxe(pickaxe); diffcore_pickaxe(pickaxe);
diff_flush(NULL, 0); if (1 < argc)
diffcore_pathspec(argv + 1);
diff_flush(diff_output_format);
return 0; return 0;
} }

17
diff-helper.c

@ -77,11 +77,11 @@ int main(int ac, const char **av) {
else if (av[1][1] == 'P') /* hidden from the help */ else if (av[1][1] == 'P') /* hidden from the help */
diff_output_style = DIFF_FORMAT_MACHINE; diff_output_style = DIFF_FORMAT_MACHINE;
else if (av[1][1] == 'M') { else if (av[1][1] == 'M') {
detect_rename = 1; detect_rename = DIFF_DETECT_RENAME;
diff_score_opt = diff_scoreopt_parse(av[1]); diff_score_opt = diff_scoreopt_parse(av[1]);
} }
else if (av[1][1] == 'C') { else if (av[1][1] == 'C') {
detect_rename = 2; detect_rename = DIFF_DETECT_COPY;
diff_score_opt = diff_scoreopt_parse(av[1]); diff_score_opt = diff_scoreopt_parse(av[1]);
} }
else if (av[1][1] == 'S') { else if (av[1][1] == 'S') {
@ -93,7 +93,7 @@ int main(int ac, const char **av) {
} }
/* the remaining parameters are paths patterns */ /* the remaining parameters are paths patterns */


diff_setup(reverse_diff, diff_output_style); diff_setup(reverse_diff);
while (1) { while (1) {
int status; int status;
read_line(&sb1, stdin, line_termination); read_line(&sb1, stdin, line_termination);
@ -121,14 +121,17 @@ int main(int ac, const char **av) {
status = parse_diff_raw(sb1.buf+1, NULL, NULL); status = parse_diff_raw(sb1.buf+1, NULL, NULL);
if (status) { if (status) {
unrecognized: unrecognized:
diff_flush(av+1, ac-1); diff_flush(diff_output_style);
printf("%s%c", sb1.buf, line_termination); printf("%s%c", sb1.buf, line_termination);
} }
} }
if (detect_rename) if (detect_rename)
diff_detect_rename(detect_rename, diff_score_opt); diffcore_rename(detect_rename, diff_score_opt);
diffcore_prune();
if (pickaxe) if (pickaxe)
diff_pickaxe(pickaxe); diffcore_pickaxe(pickaxe);
diff_flush(av+1, ac-1); if (ac)
diffcore_pathspec(av + 1);
diff_flush(diff_output_style);
return 0; return 0;
} }

44
diff-tree.c

@ -18,7 +18,7 @@ static const char *header_prefix = "";


// What paths are we interested in? // What paths are we interested in?
static int nr_paths = 0; static int nr_paths = 0;
static char **paths = NULL; static const char **paths = NULL;
static int *pathlens = NULL; static int *pathlens = NULL;


static int diff_tree_sha1(const unsigned char *old, const unsigned char *new, const char *base); static int diff_tree_sha1(const unsigned char *old, const unsigned char *new, const char *base);
@ -67,11 +67,6 @@ static void show_file(const char *prefix, void *tree, unsigned long size, const
const char *path; const char *path;
const unsigned char *sha1 = extract(tree, size, &path, &mode); const unsigned char *sha1 = extract(tree, size, &path, &mode);


if (header) {
printf("%s", header);
header = NULL;
}

if (silent) if (silent)
return; return;


@ -137,10 +132,6 @@ static int compare_tree_entry(void *tree1, unsigned long size1, void *tree2, uns
return retval; return retval;
} }


if (header) {
printf("%s", header);
header = NULL;
}
if (silent) if (silent)
return 0; return 0;


@ -268,16 +259,29 @@ static int diff_tree_sha1(const unsigned char *old, const unsigned char *new, co


static void call_diff_setup(void) static void call_diff_setup(void)
{ {
diff_setup(reverse_diff, diff_output_format); diff_setup(reverse_diff);
} }


static void call_diff_flush(void) static int call_diff_flush()
{ {
if (detect_rename) if (detect_rename)
diff_detect_rename(detect_rename, diff_score_opt); diffcore_rename(detect_rename, diff_score_opt);
if (pickaxe) diffcore_prune();
diff_pickaxe(pickaxe); if (pickaxe) {
diff_flush(NULL, 0); diffcore_pickaxe(pickaxe);
if (diff_queue_is_empty()) {
diff_flush(DIFF_FORMAT_NO_OUTPUT);
return 0;
}
}
if (nr_paths)
diffcore_pathspec(paths);
if (header) {
printf("%s", header);
header = NULL;
}
diff_flush(diff_output_format);
return 1;
} }


static int diff_tree_sha1_top(const unsigned char *old, static int diff_tree_sha1_top(const unsigned char *old,
@ -462,7 +466,7 @@ static int diff_tree_stdin(char *line)
static char *diff_tree_usage = static char *diff_tree_usage =
"git-diff-tree [-p] [-r] [-z] [--stdin] [-M] [-C] [-R] [-S<string>] [-m] [-s] [-v] <tree-ish> <tree-ish>"; "git-diff-tree [-p] [-r] [-z] [--stdin] [-M] [-C] [-R] [-S<string>] [-m] [-s] [-v] <tree-ish> <tree-ish>";


int main(int argc, char **argv) int main(int argc, const char **argv)
{ {
int nr_sha1; int nr_sha1;
char line[1000]; char line[1000];
@ -470,7 +474,7 @@ int main(int argc, char **argv)


nr_sha1 = 0; nr_sha1 = 0;
for (;;) { for (;;) {
char *arg; const char *arg;


argv++; argv++;
argc--; argc--;
@ -509,12 +513,12 @@ int main(int argc, char **argv)
continue; continue;
} }
if (!strncmp(arg, "-M", 2)) { if (!strncmp(arg, "-M", 2)) {
detect_rename = 1; detect_rename = DIFF_DETECT_RENAME;
diff_score_opt = diff_scoreopt_parse(arg); diff_score_opt = diff_scoreopt_parse(arg);
continue; continue;
} }
if (!strncmp(arg, "-C", 2)) { if (!strncmp(arg, "-C", 2)) {
detect_rename = 2; detect_rename = DIFF_DETECT_COPY;
diff_score_opt = diff_scoreopt_parse(arg); diff_score_opt = diff_scoreopt_parse(arg);
continue; continue;
} }

172
diff.c

@ -16,8 +16,6 @@ static int reverse_diff;
static int generate_patch; static int generate_patch;
static int line_termination = '\n'; static int line_termination = '\n';
static int inter_name_termination = '\t'; static int inter_name_termination = '\t';
static const char **pathspec;
static int speccnt;


static const char *external_diff(void) static const char *external_diff(void)
{ {
@ -286,6 +284,12 @@ int diff_populate_filespec(struct diff_filespec *s)
return 0; return 0;
} }


void diff_free_filepair(struct diff_filepair *p)
{
free(p->xfrm_msg);
free(p);
}

void diff_free_filespec_data(struct diff_filespec *s) void diff_free_filespec_data(struct diff_filespec *s)
{ {
if (s->should_free) if (s->should_free)
@ -390,25 +394,6 @@ static void remove_tempfile_on_signal(int signo)
remove_tempfile(); remove_tempfile();
} }


static int matches_pathspec(const char *name)
{
int i;
int namelen;

if (speccnt == 0)
return 1;

namelen = strlen(name);
for (i = 0; i < speccnt; i++) {
int speclen = strlen(pathspec[i]);
if (! strncmp(pathspec[i], name, speclen) &&
speclen <= namelen &&
(name[speclen] == 0 || name[speclen] == '/'))
return 1;
}
return 0;
}

/* An external diff command takes: /* An external diff command takes:
* *
* diff-cmd name infile1 infile1-sha1 infile1-mode \ * diff-cmd name infile1 infile1-sha1 infile1-mode \
@ -426,9 +411,6 @@ static void run_external_diff(const char *name,
int status; int status;
static int atexit_asked = 0; static int atexit_asked = 0;


if (!matches_pathspec(name) && (!other || !matches_pathspec(other)))
return;

if (one && two) { if (one && two) {
prepare_temp_file(name, &temp[0], one); prepare_temp_file(name, &temp[0], one);
prepare_temp_file(other ? : name, &temp[1], two); prepare_temp_file(other ? : name, &temp[1], two);
@ -496,47 +478,26 @@ static void run_external_diff(const char *name,
remove_tempfile(); remove_tempfile();
} }


int diff_scoreopt_parse(const char *opt) void diff_setup(int reverse_diff_)
{ {
int diglen, num, scale, i; reverse_diff = reverse_diff_;
if (opt[0] != '-' || (opt[1] != 'M' && opt[1] != 'C'))
return -1; /* that is not a -M nor -C option */
diglen = strspn(opt+2, "0123456789");
if (diglen == 0 || strlen(opt+2) != diglen)
return 0; /* use default */
sscanf(opt+2, "%d", &num);
for (i = 0, scale = 1; i < diglen; i++)
scale *= 10;

/* user says num divided by scale and we say internally that
* is MAX_SCORE * num / scale.
*/
return MAX_SCORE * num / scale;
} }


void diff_setup(int reverse_diff_, int diff_output_style) struct diff_queue_struct diff_queued_diff;

void diff_q(struct diff_queue_struct *queue, struct diff_filepair *dp)
{ {
reverse_diff = reverse_diff_; if (queue->alloc <= queue->nr) {
generate_patch = 0; queue->alloc = alloc_nr(queue->alloc);
switch (diff_output_style) { queue->queue = xrealloc(queue->queue,
case DIFF_FORMAT_HUMAN: sizeof(dp) * queue->alloc);
line_termination = '\n';
inter_name_termination = '\t';
break;
case DIFF_FORMAT_MACHINE:
line_termination = inter_name_termination = 0;
break;
case DIFF_FORMAT_PATCH:
generate_patch = 1;
break;
} }
queue->queue[queue->nr++] = dp;
} }


struct diff_queue_struct diff_queued_diff;

struct diff_filepair *diff_queue(struct diff_queue_struct *queue, struct diff_filepair *diff_queue(struct diff_queue_struct *queue,
struct diff_filespec *one, struct diff_filespec *one,
struct diff_filespec *two) struct diff_filespec *two)
{ {
struct diff_filepair *dp = xmalloc(sizeof(*dp)); struct diff_filepair *dp = xmalloc(sizeof(*dp));
dp->one = one; dp->one = one;
@ -544,20 +505,16 @@ struct diff_filepair *diff_queue(struct diff_queue_struct *queue,
dp->xfrm_msg = 0; dp->xfrm_msg = 0;
dp->orig_order = queue->nr; dp->orig_order = queue->nr;
dp->xfrm_work = 0; dp->xfrm_work = 0;
if (queue->alloc <= queue->nr) { diff_q(queue, dp);
queue->alloc = alloc_nr(queue->alloc);
queue->queue = xrealloc(queue->queue,
sizeof(dp) * queue->alloc);
}
queue->queue[queue->nr++] = dp;
return dp; return dp;
} }


static void diff_flush_raw(struct diff_filepair *p) static void diff_flush_raw(struct diff_filepair *p)
{ {
/* if (DIFF_PAIR_UNMERGED(p)) {
* We used to reject rename/copy but new diff-raw can express them. printf("U %s%c", p->one->path, line_termination);
*/ return;
}
printf(":%06o %06o %s ", printf(":%06o %06o %s ",
p->one->mode, p->two->mode, sha1_to_hex(p->one->sha1)); p->one->mode, p->two->mode, sha1_to_hex(p->one->sha1));
printf("%s%c%s%c%s%c", printf("%s%c%s%c%s%c",
@ -576,19 +533,26 @@ static void diff_flush_patch(struct diff_filepair *p)
(DIFF_FILE_VALID(p->two) && S_ISDIR(p->two->mode))) (DIFF_FILE_VALID(p->two) && S_ISDIR(p->two->mode)))
return; /* no tree diffs in patch format */ return; /* no tree diffs in patch format */


run_external_diff(name, other, p->one, p->two, p->xfrm_msg); if (DIFF_PAIR_UNMERGED(p))
run_external_diff(name, NULL, NULL, NULL, NULL);
else
run_external_diff(name, other, p->one, p->two, p->xfrm_msg);
} }


static int identical(struct diff_filespec *one, struct diff_filespec *two) static int uninteresting(struct diff_filepair *p)
{ {
/* This function is written stricter than necessary to support /* This function is written stricter than necessary to support
* the currently implemented transformers, but the idea is to * the currently implemented transformers, but the idea is to
* let transformers to produce diff_filepairs any way they want, * let transformers to produce diff_filepairs any way they want,
* and filter and clean them up here before producing the output. * and filter and clean them up here before producing the output.
*/ */
struct diff_filespec *one, *two;

if (DIFF_PAIR_UNMERGED(p))
return 0; /* unmerged is interesting */


if (!DIFF_FILE_VALID(one) && !DIFF_FILE_VALID(two)) one = p->one;
return 1; /* not interesting */ two = p->two;


/* deletion, addition, mode change and renames are all interesting. */ /* deletion, addition, mode change and renames are all interesting. */
if (DIFF_FILE_VALID(one) != DIFF_FILE_VALID(two) || if (DIFF_FILE_VALID(one) != DIFF_FILE_VALID(two) ||
@ -607,9 +571,44 @@ static int identical(struct diff_filespec *one, struct diff_filespec *two)
return 0; return 0;
} }


void diffcore_prune(void)
{
/*
* Although rename/copy detection wants to have "no-change"
* entries fed into them, the downstream do not need to see
* them. This function removes such entries.
*
* The applications that use rename/copy should:
*
* (1) feed change and "no-change" entries via diff_queue().
* (2) call diffcore_rename, and any other future diffcore_xxx
* that would benefit by still having "no-change" entries.
* (3) call diffcore_prune
* (4) call other diffcore_xxx that do not need to see
* "no-change" entries.
*/
struct diff_queue_struct *q = &diff_queued_diff;
struct diff_queue_struct outq;
int i;

outq.queue = NULL;
outq.nr = outq.alloc = 0;

for (i = 0; i < q->nr; i++) {
struct diff_filepair *p = q->queue[i];
if (!uninteresting(p))
diff_q(&outq, p);
else
diff_free_filepair(p);
}
free(q->queue);
*q = outq;
return;
}

static void diff_flush_one(struct diff_filepair *p) static void diff_flush_one(struct diff_filepair *p)
{ {
if (identical(p->one, p->two)) if (uninteresting(p))
return; return;
if (generate_patch) if (generate_patch)
diff_flush_patch(p); diff_flush_patch(p);
@ -624,23 +623,32 @@ int diff_queue_is_empty(void)


for (i = 0; i < q->nr; i++) { for (i = 0; i < q->nr; i++) {
struct diff_filepair *p = q->queue[i]; struct diff_filepair *p = q->queue[i];
if (!identical(p->one, p->two)) if (!uninteresting(p))
return 0; return 0;
} }
return 1; return 1;
} }


void diff_flush(const char **pathspec_, int speccnt_) void diff_flush(int diff_output_style)
{ {
struct diff_queue_struct *q = &diff_queued_diff; struct diff_queue_struct *q = &diff_queued_diff;
int i; int i;


pathspec = pathspec_; generate_patch = 0;
speccnt = speccnt_; switch (diff_output_style) {

case DIFF_FORMAT_HUMAN:
line_termination = '\n';
inter_name_termination = '\t';
break;
case DIFF_FORMAT_MACHINE:
line_termination = inter_name_termination = 0;
break;
case DIFF_FORMAT_PATCH:
generate_patch = 1;
break;
}
for (i = 0; i < q->nr; i++) for (i = 0; i < q->nr; i++)
diff_flush_one(q->queue[i]); diff_flush_one(q->queue[i]);

for (i = 0; i < q->nr; i++) { for (i = 0; i < q->nr; i++) {
struct diff_filepair *p = q->queue[i]; struct diff_filepair *p = q->queue[i];
diff_free_filespec_data(p->one); diff_free_filespec_data(p->one);
@ -669,7 +677,7 @@ void diff_addremove(int addremove, unsigned mode,
* which but should not make any difference). * which but should not make any difference).
* Feeding the same new and old to diff_change() should * Feeding the same new and old to diff_change() should
* also have the same effect. diff_flush() should * also have the same effect. diff_flush() should
* filter the identical ones out at the final output * filter uninteresting ones out at the final output
* stage. * stage.
*/ */
if (reverse_diff) if (reverse_diff)
@ -739,8 +747,8 @@ void diff_change(unsigned old_mode, unsigned new_mode,


void diff_unmerge(const char *path) void diff_unmerge(const char *path)
{ {
if (generate_patch) struct diff_filespec *one, *two;
run_external_diff(path, NULL, NULL, NULL, NULL); one = alloc_filespec(path);
else two = alloc_filespec(path);
printf("U %s%c", path, line_termination); diff_queue(&diff_queued_diff, one, two);
} }

22
diff.h

@ -26,16 +26,24 @@ extern void diff_unmerge(const char *path);


extern int diff_scoreopt_parse(const char *opt); extern int diff_scoreopt_parse(const char *opt);


#define DIFF_FORMAT_HUMAN 0 #define DIFF_FORMAT_HUMAN 0
#define DIFF_FORMAT_MACHINE 1 #define DIFF_FORMAT_MACHINE 1
#define DIFF_FORMAT_PATCH 2 #define DIFF_FORMAT_PATCH 2
extern void diff_setup(int reverse, int diff_output_style); #define DIFF_FORMAT_NO_OUTPUT 3
extern void diff_setup(int reverse);


extern void diff_detect_rename(int, int); #define DIFF_DETECT_RENAME 1
extern void diff_pickaxe(const char *); #define DIFF_DETECT_COPY 2

extern void diffcore_rename(int rename_copy, int minimum_score);

extern void diffcore_prune(void);

extern void diffcore_pickaxe(const char *needle);
extern void diffcore_pathspec(const char **pathspec);


extern int diff_queue_is_empty(void); extern int diff_queue_is_empty(void);


extern void diff_flush(const char **, int); extern void diff_flush(int output_style);


#endif /* DIFF_H */ #endif /* DIFF_H */

63
diffcore-pathspec.c

@ -0,0 +1,63 @@
/*
* Copyright (C) 2005 Junio C Hamano
*/
#include "cache.h"
#include "diff.h"
#include "diffcore.h"
#include "delta.h"

struct path_spec {
const char *spec;
int len;
};

static int matches_pathspec(const char *name, struct path_spec *s, int cnt)
{
int i;
int namelen;

if (cnt == 0)
return 1;

namelen = strlen(name);
for (i = 0; i < cnt; i++) {
int len = s->len;
if (! strncmp(s->spec, name, len) &&
len <= namelen &&
(name[len] == 0 || name[len] == '/'))
return 1;
}
return 0;
}

void diffcore_pathspec(const char **pathspec)
{
struct diff_queue_struct *q = &diff_queued_diff;
int i, speccnt;
struct diff_queue_struct outq;
struct path_spec *spec;

outq.queue = NULL;
outq.nr = outq.alloc = 0;

for (i = 0; pathspec[i]; i++)
;
speccnt = i;
spec = xmalloc(sizeof(*spec) * speccnt);
for (i = 0; pathspec[i]; i++) {
spec[i].spec = pathspec[i];
spec[i].len = strlen(pathspec[i]);
}

for (i = 0; i < q->nr; i++) {
struct diff_filepair *p = q->queue[i];
if (matches_pathspec(p->one->path, spec, speccnt) ||
matches_pathspec(p->two->path, spec, speccnt))
diff_q(&outq, p);
else
diff_free_filepair(p);
}
free(q->queue);
*q = outq;
return;
}

15
diffcore-pickaxe.c

@ -21,7 +21,7 @@ static int contains(struct diff_filespec *one,
return 0; return 0;
} }


void diff_pickaxe(const char *needle) void diffcore_pickaxe(const char *needle)
{ {
struct diff_queue_struct *q = &diff_queued_diff; struct diff_queue_struct *q = &diff_queued_diff;
unsigned long len = strlen(needle); unsigned long len = strlen(needle);
@ -32,24 +32,23 @@ void diff_pickaxe(const char *needle)


for (i = 0; i < q->nr; i++) { for (i = 0; i < q->nr; i++) {
struct diff_filepair *p = q->queue[i]; struct diff_filepair *p = q->queue[i];
int onum = outq.nr;
if (!DIFF_FILE_VALID(p->one)) { if (!DIFF_FILE_VALID(p->one)) {
if (!DIFF_FILE_VALID(p->two)) if (!DIFF_FILE_VALID(p->two))
continue; /* ignore nonsense */ continue; /* ignore nonsense */
/* created */ /* created */
if (contains(p->two, needle, len)) if (contains(p->two, needle, len))
diff_queue(&outq, p->one, p->two); diff_q(&outq, p);
} }
else if (!DIFF_FILE_VALID(p->two)) { else if (!DIFF_FILE_VALID(p->two)) {
if (contains(p->one, needle, len)) if (contains(p->one, needle, len))
diff_queue(&outq, p->one, p->two); diff_q(&outq, p);
} }
else if (contains(p->one, needle, len) != else if (contains(p->one, needle, len) !=
contains(p->two, needle, len)) contains(p->two, needle, len))
diff_queue(&outq, p->one, p->two); diff_q(&outq, p);
} if (onum == outq.nr)
for (i = 0; i < q->nr; i++) { diff_free_filepair(p);
struct diff_filepair *p = q->queue[i];
free(p);
} }
free(q->queue); free(q->queue);
*q = outq; *q = outq;

21
diffcore-rename.c

@ -224,8 +224,25 @@ static int needs_to_stay(struct diff_queue_struct *q, int i,
return 0; return 0;
} }


void diff_detect_rename(int detect_rename, int diff_scoreopt_parse(const char *opt)
int minimum_score) {
int diglen, num, scale, i;
if (opt[0] != '-' || (opt[1] != 'M' && opt[1] != 'C'))
return -1; /* that is not a -M nor -C option */
diglen = strspn(opt+2, "0123456789");
if (diglen == 0 || strlen(opt+2) != diglen)
return 0; /* use default */
sscanf(opt+2, "%d", &num);
for (i = 0, scale = 1; i < diglen; i++)
scale *= 10;

/* user says num divided by scale and we say internally that
* is MAX_SCORE * num / scale.
*/
return MAX_SCORE * num / scale;
}

void diffcore_rename(int detect_rename, int minimum_score)
{ {
struct diff_queue_struct *q = &diff_queued_diff; struct diff_queue_struct *q = &diff_queued_diff;
struct diff_queue_struct outq; struct diff_queue_struct outq;

4
diffcore.h

@ -45,6 +45,8 @@ struct diff_filepair {
int orig_order; /* the original order of insertion into the queue */ int orig_order; /* the original order of insertion into the queue */
int xfrm_work; /* for use by tramsformers, not by diffcore */ int xfrm_work; /* for use by tramsformers, not by diffcore */
}; };
#define DIFF_PAIR_UNMERGED(p) \
(!DIFF_FILE_VALID((p)->one) && !DIFF_FILE_VALID((p)->two))


struct diff_queue_struct { struct diff_queue_struct {
struct diff_filepair **queue; struct diff_filepair **queue;
@ -56,5 +58,7 @@ extern struct diff_queue_struct diff_queued_diff;
extern struct diff_filepair *diff_queue(struct diff_queue_struct *, extern struct diff_filepair *diff_queue(struct diff_queue_struct *,
struct diff_filespec *, struct diff_filespec *,
struct diff_filespec *); struct diff_filespec *);
extern void diff_q(struct diff_queue_struct *, struct diff_filepair *);
extern void diff_free_filepair(struct diff_filepair *);


#endif #endif

Loading…
Cancel
Save