From 6973dcaee76ef7b7bfcabd2f26e76205aae07858 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Fri, 21 Apr 2006 23:57:45 -0700 Subject: Libify diff-files. This is the first installment to libify diff brothers. The updated diff-files uses revision.c::setup_revisions() infrastructure to parse its command line arguments, which means the pathname arguments are checked more strictly than before. The tests are adjusted to separate possibly missing paths from the rest of arguments with double-dashes, to show the kosher way. As Linus pointed out, renaming diff.c to diff-lib.c was simply stupid, so I am renaming it back. The new diff-lib.c is to contain pieces extracted from diff brothers. Signed-off-by: Junio C Hamano --- diff.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'diff.h') diff --git a/diff.h b/diff.h index 52fff6643f..da4bd421fe 100644 --- a/diff.h +++ b/diff.h @@ -28,10 +28,11 @@ struct diff_options { with_raw:1, with_stat:1, tree_in_recursive:1, - full_index:1; + full_index:1, + silent_on_remove:1, + find_copies_harder:1; int break_opt; int detect_rename; - int find_copies_harder; int line_termination; int output_format; int pickaxe_opts; @@ -168,4 +169,6 @@ extern void diff_flush(struct diff_options*); extern const char *diff_unique_abbrev(const unsigned char *, int); +extern int run_diff_files(struct rev_info *revs, int silent_on_removed); + #endif /* DIFF_H */ -- cgit v1.3-5-g9baa From e09ad6e1e3308fde346b4b6287d9441363806832 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sat, 22 Apr 2006 02:43:00 -0700 Subject: Libify diff-index. The second installment to libify diff brothers. The pathname arguments are checked more strictly than before because we now use the revision.c::setup_revisions() infrastructure. Signed-off-by: Junio C Hamano --- diff-index.c | 254 ++++------------------------------------------- diff-lib.c | 203 +++++++++++++++++++++++++++++++++++++ diff.h | 2 + t/t4010-diff-pathspec.sh | 10 +- 4 files changed, 231 insertions(+), 238 deletions(-) (limited to 'diff.h') diff --git a/diff-index.c b/diff-index.c index e376d65f80..4a243b3624 100644 --- a/diff-index.c +++ b/diff-index.c @@ -1,166 +1,7 @@ #include "cache.h" -#include "tree.h" #include "diff.h" - -static int cached_only = 0; -static int match_nonexisting = 0; -static struct diff_options diff_options; - -/* A file entry went away or appeared */ -static void show_file(const char *prefix, - struct cache_entry *ce, - unsigned char *sha1, unsigned int mode) -{ - diff_addremove(&diff_options, prefix[0], ntohl(mode), - sha1, ce->name, NULL); -} - -static int get_stat_data(struct cache_entry *ce, - unsigned char ** sha1p, unsigned int *modep) -{ - unsigned char *sha1 = ce->sha1; - unsigned int mode = ce->ce_mode; - - if (!cached_only) { - static unsigned char no_sha1[20]; - int changed; - struct stat st; - if (lstat(ce->name, &st) < 0) { - if (errno == ENOENT && match_nonexisting) { - *sha1p = sha1; - *modep = mode; - return 0; - } - return -1; - } - changed = ce_match_stat(ce, &st, 0); - if (changed) { - mode = create_ce_mode(st.st_mode); - if (!trust_executable_bit && S_ISREG(st.st_mode)) - mode = ce->ce_mode; - sha1 = no_sha1; - } - } - - *sha1p = sha1; - *modep = mode; - return 0; -} - -static void show_new_file(struct cache_entry *new) -{ - unsigned char *sha1; - unsigned int mode; - - /* New file in the index: it might actually be different in - * the working copy. - */ - if (get_stat_data(new, &sha1, &mode) < 0) - return; - - show_file("+", new, sha1, mode); -} - -static int show_modified(struct cache_entry *old, - struct cache_entry *new, - int report_missing) -{ - unsigned int mode, oldmode; - unsigned char *sha1; - - if (get_stat_data(new, &sha1, &mode) < 0) { - if (report_missing) - show_file("-", old, old->sha1, old->ce_mode); - return -1; - } - - oldmode = old->ce_mode; - if (mode == oldmode && !memcmp(sha1, old->sha1, 20) && - !diff_options.find_copies_harder) - return 0; - - mode = ntohl(mode); - oldmode = ntohl(oldmode); - - diff_change(&diff_options, oldmode, mode, - old->sha1, sha1, old->name, NULL); - return 0; -} - -static int diff_cache(struct cache_entry **ac, int entries, const char **pathspec) -{ - while (entries) { - struct cache_entry *ce = *ac; - int same = (entries > 1) && ce_same_name(ce, ac[1]); - - if (!ce_path_match(ce, pathspec)) - goto skip_entry; - - switch (ce_stage(ce)) { - case 0: - /* No stage 1 entry? That means it's a new file */ - if (!same) { - show_new_file(ce); - break; - } - /* Show difference between old and new */ - show_modified(ac[1], ce, 1); - break; - case 1: - /* No stage 3 (merge) entry? That means it's been deleted */ - if (!same) { - show_file("-", ce, ce->sha1, ce->ce_mode); - break; - } - /* We come here with ce pointing at stage 1 - * (original tree) and ac[1] pointing at stage - * 3 (unmerged). show-modified with - * report-missing set to false does not say the - * file is deleted but reports true if work - * tree does not have it, in which case we - * fall through to report the unmerged state. - * Otherwise, we show the differences between - * the original tree and the work tree. - */ - if (!cached_only && !show_modified(ce, ac[1], 0)) - break; - /* fallthru */ - case 3: - diff_unmerge(&diff_options, ce->name); - break; - - default: - die("impossible cache entry stage"); - } - -skip_entry: - /* - * Ignore all the different stages for this file, - * we've handled the relevant cases now. - */ - do { - ac++; - entries--; - } while (entries && ce_same_name(ce, ac[0])); - } - return 0; -} - -/* - * This turns all merge entries into "stage 3". That guarantees that - * when we read in the new tree (into "stage 1"), we won't lose sight - * of the fact that we had unmerged entries. - */ -static void mark_merge_entries(void) -{ - int i; - for (i = 0; i < active_nr; i++) { - struct cache_entry *ce = active_cache[i]; - if (!ce_stage(ce)) - continue; - ce->ce_flags |= htons(CE_STAGEMASK); - } -} +#include "commit.h" +#include "revision.h" static const char diff_cache_usage[] = "git-diff-index [-m] [--cached] " @@ -169,85 +10,32 @@ COMMON_DIFF_OPTIONS_HELP; int main(int argc, const char **argv) { - const char *tree_name = NULL; - unsigned char sha1[20]; - const char *prefix = setup_git_directory(); - const char **pathspec = NULL; - struct tree *tree; - int ret; - int allow_options = 1; + struct rev_info rev; + int match_missing = 0; + int cached = 0; int i; git_config(git_diff_config); - diff_setup(&diff_options); + init_revisions(&rev); + rev.abbrev = 0; + + argc = setup_revisions(argc, argv, &rev, NULL); for (i = 1; i < argc; i++) { const char *arg = argv[i]; - int diff_opt_cnt; - - if (!allow_options || *arg != '-') { - if (tree_name) - break; - tree_name = arg; - continue; - } - if (!strcmp(arg, "--")) { - allow_options = 0; - continue; - } - if (!strcmp(arg, "-r")) { - /* We accept the -r flag just to look like git-diff-tree */ - continue; - } - if (!strcmp(arg, "--cc")) - /* - * I _think_ "diff-index --cached HEAD" with an - * unmerged index could show something else - * later, but pretend --cc is the same as -p for - * now. "git diff" uses --cc by default. - */ - argv[i] = arg = "-p"; - diff_opt_cnt = diff_opt_parse(&diff_options, argv + i, - argc - i); - if (diff_opt_cnt < 0) + if (!strcmp(arg, "-m")) + match_missing = 1; + else if (!strcmp(arg, "--cached")) + cached = 1; + else usage(diff_cache_usage); - else if (diff_opt_cnt) { - i += diff_opt_cnt - 1; - continue; - } - - if (!strcmp(arg, "-m")) { - match_nonexisting = 1; - continue; - } - if (!strcmp(arg, "--cached")) { - cached_only = 1; - continue; - } - usage(diff_cache_usage); } - - pathspec = get_pathspec(prefix, argv + i); - - if (diff_setup_done(&diff_options) < 0) - usage(diff_cache_usage); - - if (!tree_name || get_sha1(tree_name, sha1)) + /* + * Make sure there is one revision (i.e. pending object), + * and there is no revision filtering parameters. + */ + if (!rev.pending_objects || rev.pending_objects->next || + rev.max_count != -1 || rev.min_age != -1 || rev.max_age != -1) usage(diff_cache_usage); - - read_cache(); - - mark_merge_entries(); - - tree = parse_tree_indirect(sha1); - if (!tree) - die("bad tree object %s", tree_name); - if (read_tree(tree, 1, pathspec)) - die("unable to read tree object %s", tree_name); - - ret = diff_cache(active_cache, active_nr, pathspec); - - diffcore_std(&diff_options); - diff_flush(&diff_options); - return ret; + return run_diff_index(&rev, cached, match_missing); } diff --git a/diff-lib.c b/diff-lib.c index a28dd3dca7..63da3b521d 100644 --- a/diff-lib.c +++ b/diff-lib.c @@ -131,3 +131,206 @@ int run_diff_files(struct rev_info *revs, int silent_on_removed) return 0; } +/* + * diff-index + */ + +/* A file entry went away or appeared */ +static void diff_index_show_file(struct rev_info *revs, + const char *prefix, + struct cache_entry *ce, + unsigned char *sha1, unsigned int mode) +{ + diff_addremove(&revs->diffopt, prefix[0], ntohl(mode), + sha1, ce->name, NULL); +} + +static int get_stat_data(struct cache_entry *ce, + unsigned char **sha1p, + unsigned int *modep, + int cached, int match_missing) +{ + unsigned char *sha1 = ce->sha1; + unsigned int mode = ce->ce_mode; + + if (!cached) { + static unsigned char no_sha1[20]; + int changed; + struct stat st; + if (lstat(ce->name, &st) < 0) { + if (errno == ENOENT && match_missing) { + *sha1p = sha1; + *modep = mode; + return 0; + } + return -1; + } + changed = ce_match_stat(ce, &st, 0); + if (changed) { + mode = create_ce_mode(st.st_mode); + if (!trust_executable_bit && S_ISREG(st.st_mode)) + mode = ce->ce_mode; + sha1 = no_sha1; + } + } + + *sha1p = sha1; + *modep = mode; + return 0; +} + +static void show_new_file(struct rev_info *revs, + struct cache_entry *new, + int cached, int match_missing) +{ + unsigned char *sha1; + unsigned int mode; + + /* New file in the index: it might actually be different in + * the working copy. + */ + if (get_stat_data(new, &sha1, &mode, cached, match_missing) < 0) + return; + + diff_index_show_file(revs, "+", new, sha1, mode); +} + +static int show_modified(struct rev_info *revs, + struct cache_entry *old, + struct cache_entry *new, + int report_missing, + int cached, int match_missing) +{ + unsigned int mode, oldmode; + unsigned char *sha1; + + if (get_stat_data(new, &sha1, &mode, cached, match_missing) < 0) { + if (report_missing) + diff_index_show_file(revs, "-", old, + old->sha1, old->ce_mode); + return -1; + } + + oldmode = old->ce_mode; + if (mode == oldmode && !memcmp(sha1, old->sha1, 20) && + !revs->diffopt.find_copies_harder) + return 0; + + mode = ntohl(mode); + oldmode = ntohl(oldmode); + + diff_change(&revs->diffopt, oldmode, mode, + old->sha1, sha1, old->name, NULL); + return 0; +} + +static int diff_cache(struct rev_info *revs, + struct cache_entry **ac, int entries, + const char **pathspec, + int cached, int match_missing) +{ + while (entries) { + struct cache_entry *ce = *ac; + int same = (entries > 1) && ce_same_name(ce, ac[1]); + + if (!ce_path_match(ce, pathspec)) + goto skip_entry; + + switch (ce_stage(ce)) { + case 0: + /* No stage 1 entry? That means it's a new file */ + if (!same) { + show_new_file(revs, ce, cached, match_missing); + break; + } + /* Show difference between old and new */ + show_modified(revs,ac[1], ce, 1, + cached, match_missing); + break; + case 1: + /* No stage 3 (merge) entry? + * That means it's been deleted. + */ + if (!same) { + diff_index_show_file(revs, "-", ce, + ce->sha1, ce->ce_mode); + break; + } + /* We come here with ce pointing at stage 1 + * (original tree) and ac[1] pointing at stage + * 3 (unmerged). show-modified with + * report-missing set to false does not say the + * file is deleted but reports true if work + * tree does not have it, in which case we + * fall through to report the unmerged state. + * Otherwise, we show the differences between + * the original tree and the work tree. + */ + if (!cached && + !show_modified(revs, ce, ac[1], 0, + cached, match_missing)) + break; + /* fallthru */ + case 3: + diff_unmerge(&revs->diffopt, ce->name); + break; + + default: + die("impossible cache entry stage"); + } + +skip_entry: + /* + * Ignore all the different stages for this file, + * we've handled the relevant cases now. + */ + do { + ac++; + entries--; + } while (entries && ce_same_name(ce, ac[0])); + } + return 0; +} + +/* + * This turns all merge entries into "stage 3". That guarantees that + * when we read in the new tree (into "stage 1"), we won't lose sight + * of the fact that we had unmerged entries. + */ +static void mark_merge_entries(void) +{ + int i; + for (i = 0; i < active_nr; i++) { + struct cache_entry *ce = active_cache[i]; + if (!ce_stage(ce)) + continue; + ce->ce_flags |= htons(CE_STAGEMASK); + } +} + +int run_diff_index(struct rev_info *revs, int cached, int match_missing) +{ + int ret; + struct object *ent; + struct tree *tree; + const char *tree_name; + + if (read_cache() < 0) { + perror("read_cache"); + return -1; + } + mark_merge_entries(); + + ent = revs->pending_objects->item; + tree_name = revs->pending_objects->name; + tree = parse_tree_indirect(ent->sha1); + if (!tree) + return error("bad tree object %s", tree_name); + if (read_tree(tree, 1, revs->prune_data)) + return error("unable to read tree object %s", tree_name); + ret = diff_cache(revs, active_cache, active_nr, revs->prune_data, + cached, match_missing); + diffcore_std(&revs->diffopt); + diff_flush(&revs->diffopt); + return ret; +} diff --git a/diff.h b/diff.h index da4bd421fe..837d449f81 100644 --- a/diff.h +++ b/diff.h @@ -171,4 +171,6 @@ extern const char *diff_unique_abbrev(const unsigned char *, int); extern int run_diff_files(struct rev_info *revs, int silent_on_removed); +extern int run_diff_index(struct rev_info *revs, int cached, int match_missing); + #endif /* DIFF_H */ diff --git a/t/t4010-diff-pathspec.sh b/t/t4010-diff-pathspec.sh index 8db329d7ff..9e1544df9d 100755 --- a/t/t4010-diff-pathspec.sh +++ b/t/t4010-diff-pathspec.sh @@ -28,7 +28,7 @@ cat >expected <<\EOF EOF test_expect_success \ 'limit to path should show nothing' \ - 'git-diff-index --cached $tree path >current && + 'git-diff-index --cached $tree -- path >current && compare_diff_raw current expected' cat >expected <<\EOF @@ -36,7 +36,7 @@ cat >expected <<\EOF EOF test_expect_success \ 'limit to path1 should show path1/file1' \ - 'git-diff-index --cached $tree path1 >current && + 'git-diff-index --cached $tree -- path1 >current && compare_diff_raw current expected' cat >expected <<\EOF @@ -44,7 +44,7 @@ cat >expected <<\EOF EOF test_expect_success \ 'limit to path1/ should show path1/file1' \ - 'git-diff-index --cached $tree path1/ >current && + 'git-diff-index --cached $tree -- path1/ >current && compare_diff_raw current expected' cat >expected <<\EOF @@ -52,14 +52,14 @@ cat >expected <<\EOF EOF test_expect_success \ 'limit to file0 should show file0' \ - 'git-diff-index --cached $tree file0 >current && + 'git-diff-index --cached $tree -- file0 >current && compare_diff_raw current expected' cat >expected <<\EOF EOF test_expect_success \ 'limit to file0/ should emit nothing.' \ - 'git-diff-index --cached $tree file0/ >current && + 'git-diff-index --cached $tree -- file0/ >current && compare_diff_raw current expected' test_done -- cgit v1.3-5-g9baa From 5c21ac0e7c475c82039ab604ee9d7d8430889346 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sat, 22 Apr 2006 03:58:04 -0700 Subject: Libified diff-index: backward compatibility fix. "diff-index -m" does not mean "do not ignore merges", but means "pretend missing files match the index". The previous round tried to address this, but failed because setup_revisions() ate "-m" flag before the caller had a chance to intervene. Signed-off-by: Junio C Hamano --- diff-index.c | 6 ++---- diff-lib.c | 10 +++++++++- diff.h | 2 +- 3 files changed, 12 insertions(+), 6 deletions(-) (limited to 'diff.h') diff --git a/diff-index.c b/diff-index.c index 4a243b3624..86940123b3 100644 --- a/diff-index.c +++ b/diff-index.c @@ -23,9 +23,7 @@ int main(int argc, const char **argv) for (i = 1; i < argc; i++) { const char *arg = argv[i]; - if (!strcmp(arg, "-m")) - match_missing = 1; - else if (!strcmp(arg, "--cached")) + if (!strcmp(arg, "--cached")) cached = 1; else usage(diff_cache_usage); @@ -37,5 +35,5 @@ int main(int argc, const char **argv) if (!rev.pending_objects || rev.pending_objects->next || rev.max_count != -1 || rev.min_age != -1 || rev.max_age != -1) usage(diff_cache_usage); - return run_diff_index(&rev, cached, match_missing); + return run_diff_index(&rev, cached); } diff --git a/diff-lib.c b/diff-lib.c index 63da3b521d..2183b41b03 100644 --- a/diff-lib.c +++ b/diff-lib.c @@ -308,12 +308,20 @@ static void mark_merge_entries(void) } } -int run_diff_index(struct rev_info *revs, int cached, int match_missing) +int run_diff_index(struct rev_info *revs, int cached) { int ret; struct object *ent; struct tree *tree; const char *tree_name; + int match_missing = 0; + + /* + * Backward compatibility wart - "diff-index -m" does + * not mean "do not ignore merges", but totally different. + */ + if (!revs->ignore_merges) + match_missing = 1; if (read_cache() < 0) { perror("read_cache"); diff --git a/diff.h b/diff.h index 837d449f81..7150b90385 100644 --- a/diff.h +++ b/diff.h @@ -171,6 +171,6 @@ extern const char *diff_unique_abbrev(const unsigned char *, int); extern int run_diff_files(struct rev_info *revs, int silent_on_removed); -extern int run_diff_index(struct rev_info *revs, int cached, int match_missing); +extern int run_diff_index(struct rev_info *revs, int cached); #endif /* DIFF_H */ -- cgit v1.3-5-g9baa From 0fe7c1de16f71312e6adac4b85bddf0d62a47168 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sat, 29 Apr 2006 01:24:49 -0700 Subject: built-in diff: assorted updates. "git diff(n)" without --base, --ours, etc. defaults to --cc, which usually is the same as -p unless you are in the middle of a conflicted merge, just like the shell script version. "git diff(n) blobA blobB path" complains and dies. "git diff(n) tree0 tree1 tree2...treeN" does combined diff that shows a merge of tree1..treeN to result in tree0. Giving "-c" option to any command that defaults to "--cc" turns off dense-combined flag. Signed-off-by: Junio C Hamano --- builtin-diff.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++--------- combine-diff.c | 47 ++++++++++++++++++++++++++++++----------------- diff.h | 2 ++ revision.c | 1 + 4 files changed, 79 insertions(+), 26 deletions(-) (limited to 'diff.h') diff --git a/builtin-diff.c b/builtin-diff.c index 196821294e..c543105b8e 100644 --- a/builtin-diff.c +++ b/builtin-diff.c @@ -47,13 +47,17 @@ static int builtin_diff_files(struct rev_info *revs, } /* * Make sure there are NO revision (i.e. pending object) parameter, - * rev.max_count is reasonable (0 <= n <= 3), - * there is no other revision filtering parameters. + * specified rev.max_count is reasonable (0 <= n <= 3), and + * there is no other revision filtering parameter. */ if (revs->pending_objects || revs->min_age != -1 || - revs->max_age != -1) + revs->max_age != -1 || + 3 < revs->max_count) usage(builtin_diff_usage); + if (revs->max_count < 0 && + (revs->diffopt.output_format == DIFF_FORMAT_PATCH)) + revs->combine_merges = revs->dense_combined_merges = 1; /* * Backward compatibility wart - "diff-files -s" used to * defeat the common diff option "-s" which asked for @@ -178,9 +182,6 @@ static int builtin_diff_tree(struct rev_info *revs, int argc, const char **argv, struct object_list *ent) { - /* We saw two trees, ent[0] and ent[1]. - * unless ent[0] is unintesting, they are swapped - */ const unsigned char *(sha1[2]); int swap = 1; while (1 < argc) { @@ -191,6 +192,10 @@ static int builtin_diff_tree(struct rev_info *revs, usage(builtin_diff_usage); argv++; argc--; } + + /* We saw two trees, ent[0] and ent[1]. + * unless ent[0] is unintesting, they are swapped + */ if (ent[0].item->flags & UNINTERESTING) swap = 0; sha1[swap] = ent[0].item->sha1; @@ -200,6 +205,33 @@ static int builtin_diff_tree(struct rev_info *revs, return 0; } +static int builtin_diff_combined(struct rev_info *revs, + int argc, const char **argv, + struct object_list *ent, + int ents) +{ + const unsigned char (*parent)[20]; + int i; + + while (1 < argc) { + const char *arg = argv[1]; + if (!strcmp(arg, "--raw")) + revs->diffopt.output_format = DIFF_FORMAT_RAW; + else + usage(builtin_diff_usage); + argv++; argc--; + } + if (!revs->dense_combined_merges && !revs->combine_merges) + revs->dense_combined_merges = revs->combine_merges = 1; + parent = xmalloc(ents * sizeof(*parent)); + /* Again, the revs are all reverse */ + for (i = 0; i < ents; i++) + memcpy(parent + i, ent[ents - 1 - i].item->sha1, 20); + diff_tree_combined(parent[0], parent + 1, ents - 1, + revs->dense_combined_merges, revs); + return 0; +} + static void add_head(struct rev_info *revs) { unsigned char sha1[20]; @@ -215,7 +247,7 @@ static void add_head(struct rev_info *revs) int cmd_diff(int argc, const char **argv, char **envp) { struct rev_info rev; - struct object_list *list, ent[2]; + struct object_list *list, ent[100]; int ents = 0, blobs = 0, paths = 0; const char *path = NULL; struct blobinfo blob[2]; @@ -273,8 +305,9 @@ int cmd_diff(int argc, const char **argv, char **envp) if (!strcmp(obj->type, commit_type)) obj = &((struct commit *)obj)->tree->object; if (!strcmp(obj->type, tree_type)) { - if (2 <= ents) - die("more than two trees given: '%s'", name); + if (ARRAY_SIZE(ent) <= ents) + die("more than %d trees given: '%s'", + ARRAY_SIZE(ent), name); obj->flags |= flags; ent[ents].item = obj; ent[ents].name = name; @@ -316,6 +349,8 @@ int cmd_diff(int argc, const char **argv, char **envp) return builtin_diff_b_f(&rev, argc, argv, blob, path); break; case 2: + if (paths) + usage(builtin_diff_usage); return builtin_diff_blobs(&rev, argc, argv, blob); break; default: @@ -328,5 +363,7 @@ int cmd_diff(int argc, const char **argv, char **envp) return builtin_diff_index(&rev, argc, argv); else if (ents == 2) return builtin_diff_tree(&rev, argc, argv, ent); + else + return builtin_diff_combined(&rev, argc, argv, ent, ents); usage(builtin_diff_usage); } diff --git a/combine-diff.c b/combine-diff.c index ca36f5d5e7..8a8fe3863a 100644 --- a/combine-diff.c +++ b/combine-diff.c @@ -831,15 +831,16 @@ void show_combined_diff(struct combine_diff_path *p, } } -void diff_tree_combined_merge(const unsigned char *sha1, - int dense, struct rev_info *rev) +void diff_tree_combined(const unsigned char *sha1, + const unsigned char parent[][20], + int num_parent, + int dense, + struct rev_info *rev) { struct diff_options *opt = &rev->diffopt; - struct commit *commit = lookup_commit(sha1); struct diff_options diffopts; - struct commit_list *parents; struct combine_diff_path *p, *paths = NULL; - int num_parent, i, num_paths; + int i, num_paths; int do_diffstat; do_diffstat = (opt->output_format == DIFF_FORMAT_DIFFSTAT || @@ -849,17 +850,8 @@ void diff_tree_combined_merge(const unsigned char *sha1, diffopts.with_stat = 0; diffopts.recursive = 1; - /* count parents */ - for (parents = commit->parents, num_parent = 0; - parents; - parents = parents->next, num_parent++) - ; /* nothing */ - /* find set of paths that everybody touches */ - for (parents = commit->parents, i = 0; - parents; - parents = parents->next, i++) { - struct commit *parent = parents->item; + for (i = 0; i < num_parent; i++) { /* show stat against the first parent even * when doing combined diff. */ @@ -867,8 +859,7 @@ void diff_tree_combined_merge(const unsigned char *sha1, diffopts.output_format = DIFF_FORMAT_DIFFSTAT; else diffopts.output_format = DIFF_FORMAT_NO_OUTPUT; - diff_tree_sha1(parent->object.sha1, commit->object.sha1, "", - &diffopts); + diff_tree_sha1(parent[i], sha1, "", &diffopts); diffcore_std(&diffopts); paths = intersect_paths(paths, i, num_parent); @@ -907,3 +898,25 @@ void diff_tree_combined_merge(const unsigned char *sha1, free(tmp); } } + +void diff_tree_combined_merge(const unsigned char *sha1, + int dense, struct rev_info *rev) +{ + int num_parent; + const unsigned char (*parent)[20]; + struct commit *commit = lookup_commit(sha1); + struct commit_list *parents; + + /* count parents */ + for (parents = commit->parents, num_parent = 0; + parents; + parents = parents->next, num_parent++) + ; /* nothing */ + + parent = xmalloc(num_parent * sizeof(*parent)); + for (parents = commit->parents, num_parent = 0; + parents; + parents = parents->next, num_parent++) + memcpy(parent + num_parent, parents->item->object.sha1, 20); + diff_tree_combined(sha1, parent, num_parent, dense, rev); +} diff --git a/diff.h b/diff.h index 7150b90385..b3b2c4dd28 100644 --- a/diff.h +++ b/diff.h @@ -75,6 +75,8 @@ struct combine_diff_path { extern void show_combined_diff(struct combine_diff_path *elem, int num_parent, int dense, struct rev_info *); +extern void diff_tree_combined(const unsigned char *sha1, const unsigned char parent[][20], int num_parent, int dense, struct rev_info *rev); + extern void diff_tree_combined_merge(const unsigned char *sha1, int, struct rev_info *); extern void diff_addremove(struct diff_options *, diff --git a/revision.c b/revision.c index f2a9f25fe1..4381d455e4 100644 --- a/revision.c +++ b/revision.c @@ -664,6 +664,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch } if (!strcmp(arg, "-c")) { revs->diff = 1; + revs->dense_combined_merges = 0; revs->combine_merges = 1; continue; } -- cgit v1.3-5-g9baa