[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>
This commit is contained in:
parent
26dee0adfc
commit
6b14d7faf0
9
Makefile
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
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
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;
|
||||||
}
|
}
|
||||||
|
@ -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
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;
|
||||||
}
|
}
|
||||||
|
174
diff.c
174
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;
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
reverse_diff = reverse_diff_;
|
reverse_diff = reverse_diff_;
|
||||||
generate_patch = 0;
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct diff_queue_struct diff_queued_diff;
|
struct diff_queue_struct diff_queued_diff;
|
||||||
|
|
||||||
|
void diff_q(struct diff_queue_struct *queue, struct diff_filepair *dp)
|
||||||
|
{
|
||||||
|
if (queue->alloc <= queue->nr) {
|
||||||
|
queue->alloc = alloc_nr(queue->alloc);
|
||||||
|
queue->queue = xrealloc(queue->queue,
|
||||||
|
sizeof(dp) * queue->alloc);
|
||||||
|
}
|
||||||
|
queue->queue[queue->nr++] = dp;
|
||||||
|
}
|
||||||
|
|
||||||
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_FILE_VALID(one) && !DIFF_FILE_VALID(two))
|
if (DIFF_PAIR_UNMERGED(p))
|
||||||
return 1; /* not interesting */
|
return 0; /* unmerged is interesting */
|
||||||
|
|
||||||
|
one = p->one;
|
||||||
|
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
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
Normal file
63
diffcore-pathspec.c
Normal file
@ -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;
|
||||||
|
}
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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…
Reference in New Issue
Block a user