diff options
author | Junio C Hamano <junkio@cox.net> | 2007-03-18 15:48:06 -0700 |
---|---|---|
committer | Junio C Hamano <junkio@cox.net> | 2007-03-18 15:48:06 -0700 |
commit | d54fe394acbad36e9d0fd960d5e10f2769a8041b (patch) | |
tree | ffd71f86a9a602f4b52d2e518a530d5a2de2921f | |
parent | Avoid unnecessary strlen() calls (diff) | |
parent | Add tests for --quiet option of diff programs (diff) | |
download | tgif-d54fe394acbad36e9d0fd960d5e10f2769a8041b.tar.xz |
Merge branch 'ar/diff'
* ar/diff:
Add tests for --quiet option of diff programs
try-to-simplify-commit: use diff-tree --quiet machinery.
revision.c: explain what tree_difference does
Teach --quiet to diff backends.
diff --quiet
Remove unused diffcore_std_no_resolve
Allow git-diff exit with codes similar to diff(1)
-rw-r--r-- | Documentation/diff-options.txt | 5 | ||||
-rw-r--r-- | builtin-diff-files.c | 4 | ||||
-rw-r--r-- | builtin-diff-index.c | 4 | ||||
-rw-r--r-- | builtin-diff-tree.c | 5 | ||||
-rw-r--r-- | builtin-diff.c | 19 | ||||
-rw-r--r-- | diff-lib.c | 11 | ||||
-rw-r--r-- | diff.c | 36 | ||||
-rw-r--r-- | diff.h | 7 | ||||
-rw-r--r-- | revision.c | 17 | ||||
-rwxr-xr-x | t/t4017-diff-retval.sh | 79 | ||||
-rwxr-xr-x | t/t4017-quiet.sh | 80 | ||||
-rw-r--r-- | tree-diff.c | 2 |
12 files changed, 242 insertions, 27 deletions
diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt index d8696b7b36..77a3f78dd7 100644 --- a/Documentation/diff-options.txt +++ b/Documentation/diff-options.txt @@ -159,5 +159,10 @@ -w:: Shorthand for "--ignore-all-space". +--exit-code:: + Make the program exit with codes similar to diff(1). + That is, it exits with 1 if there were differences and + 0 means no differences. + For more detailed explanation on these common options, see also link:diffcore.html[diffcore documentation]. diff --git a/builtin-diff-files.c b/builtin-diff-files.c index aec8338429..6ba5077a2b 100644 --- a/builtin-diff-files.c +++ b/builtin-diff-files.c @@ -17,6 +17,7 @@ int cmd_diff_files(int argc, const char **argv, const char *prefix) { struct rev_info rev; int nongit = 0; + int result; prefix = setup_git_directory_gently(&nongit); init_revisions(&rev, prefix); @@ -29,5 +30,6 @@ int cmd_diff_files(int argc, const char **argv, const char *prefix) argc = setup_revisions(argc, argv, &rev, NULL); if (!rev.diffopt.output_format) rev.diffopt.output_format = DIFF_FORMAT_RAW; - return run_diff_files_cmd(&rev, argc, argv); + result = run_diff_files_cmd(&rev, argc, argv); + return rev.diffopt.exit_with_status ? rev.diffopt.has_changes: result; } diff --git a/builtin-diff-index.c b/builtin-diff-index.c index 083599d5c4..d90eba95a6 100644 --- a/builtin-diff-index.c +++ b/builtin-diff-index.c @@ -14,6 +14,7 @@ int cmd_diff_index(int argc, const char **argv, const char *prefix) struct rev_info rev; int cached = 0; int i; + int result; init_revisions(&rev, prefix); git_config(git_default_config); /* no "diff" UI options */ @@ -42,5 +43,6 @@ int cmd_diff_index(int argc, const char **argv, const char *prefix) perror("read_cache"); return -1; } - return run_diff_index(&rev, cached); + result = run_diff_index(&rev, cached); + return rev.diffopt.exit_with_status ? rev.diffopt.has_changes: result; } diff --git a/builtin-diff-tree.c b/builtin-diff-tree.c index 24cb2d7f84..0b591c8716 100644 --- a/builtin-diff-tree.c +++ b/builtin-diff-tree.c @@ -118,7 +118,8 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix) } if (!read_stdin) - return 0; + return opt->diffopt.exit_with_status ? + opt->diffopt.has_changes: 0; if (opt->diffopt.detect_rename) opt->diffopt.setup |= (DIFF_SETUP_USE_SIZE_CACHE | @@ -133,5 +134,5 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix) else diff_tree_stdin(line); } - return 0; + return opt->diffopt.exit_with_status ? opt->diffopt.has_changes: 0; } diff --git a/builtin-diff.c b/builtin-diff.c index 4efbb8237b..21d13f0b30 100644 --- a/builtin-diff.c +++ b/builtin-diff.c @@ -190,6 +190,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix) const char *path = NULL; struct blobinfo blob[2]; int nongit = 0; + int result = 0; /* * We could get N tree-ish in the rev.pending_objects list. @@ -292,17 +293,17 @@ int cmd_diff(int argc, const char **argv, const char *prefix) if (!ents) { switch (blobs) { case 0: - return run_diff_files_cmd(&rev, argc, argv); + result = run_diff_files_cmd(&rev, argc, argv); break; case 1: if (paths != 1) usage(builtin_diff_usage); - return builtin_diff_b_f(&rev, argc, argv, blob, path); + result = 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); + result = builtin_diff_blobs(&rev, argc, argv, blob); break; default: usage(builtin_diff_usage); @@ -311,19 +312,21 @@ int cmd_diff(int argc, const char **argv, const char *prefix) else if (blobs) usage(builtin_diff_usage); else if (ents == 1) - return builtin_diff_index(&rev, argc, argv); + result = builtin_diff_index(&rev, argc, argv); else if (ents == 2) - return builtin_diff_tree(&rev, argc, argv, ent); + result = builtin_diff_tree(&rev, argc, argv, ent); else if ((ents == 3) && (ent[0].item->flags & UNINTERESTING)) { /* diff A...B where there is one sane merge base between * A and B. We have ent[0] == merge-base, ent[1] == A, * and ent[2] == B. Show diff between the base and B. */ ent[1] = ent[2]; - return builtin_diff_tree(&rev, argc, argv, ent); + result = builtin_diff_tree(&rev, argc, argv, ent); } else - return builtin_diff_combined(&rev, argc, argv, + result = builtin_diff_combined(&rev, argc, argv, ent, ents); - usage(builtin_diff_usage); + if (rev.diffopt.exit_with_status) + result = rev.diffopt.has_changes; + return result; } diff --git a/diff-lib.c b/diff-lib.c index 6abb981534..5c5b05bfe3 100644 --- a/diff-lib.c +++ b/diff-lib.c @@ -170,8 +170,10 @@ static int handle_diff_files_args(struct rev_info *revs, else if (!strcmp(argv[1], "--theirs")) revs->max_count = 3; else if (!strcmp(argv[1], "-n") || - !strcmp(argv[1], "--no-index")) + !strcmp(argv[1], "--no-index")) { revs->max_count = -2; + revs->diffopt.exit_with_status = 1; + } else if (!strcmp(argv[1], "-q")) *silent = 1; else @@ -237,6 +239,7 @@ int setup_diff_no_index(struct rev_info *revs, break; } else if (i < argc - 3 && !strcmp(argv[i], "--no-index")) { i = argc - 3; + revs->diffopt.exit_with_status = 1; break; } if (argc != i + 2 || (!is_outside_repo(argv[i + 1], nongit, prefix) && @@ -321,6 +324,9 @@ int run_diff_files(struct rev_info *revs, int silent_on_removed) struct cache_entry *ce = active_cache[i]; int changed; + if (revs->diffopt.quiet && revs->diffopt.has_changes) + break; + if (!ce_path_match(ce, revs->prune_data)) continue; @@ -562,6 +568,9 @@ static int diff_cache(struct rev_info *revs, struct cache_entry *ce = *ac; int same = (entries > 1) && ce_same_name(ce, ac[1]); + if (revs->diffopt.quiet && revs->diffopt.has_changes) + break; + if (!ce_path_match(ce, pathspec)) goto skip_entry; @@ -1958,6 +1958,23 @@ int diff_setup_done(struct diff_options *options) if (options->abbrev <= 0 || 40 < options->abbrev) options->abbrev = 40; /* full */ + /* + * It does not make sense to show the first hit we happened + * to have found. It does not make sense not to return with + * exit code in such a case either. + */ + if (options->quiet) { + options->output_format = DIFF_FORMAT_NO_OUTPUT; + options->exit_with_status = 1; + } + + /* + * If we postprocess in diffcore, we cannot simply return + * upon the first hit. We need to run diff as usual. + */ + if (options->pickaxe || options->filter) + options->quiet = 0; + return 0; } @@ -2134,6 +2151,10 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac) options->color_diff = options->color_diff_words = 1; else if (!strcmp(arg, "--no-renames")) options->detect_rename = 0; + else if (!strcmp(arg, "--exit-code")) + options->exit_with_status = 1; + else if (!strcmp(arg, "--quiet")) + options->quiet = 1; else return 0; return 1; @@ -2898,6 +2919,8 @@ static void diffcore_apply_filter(const char *filter) void diffcore_std(struct diff_options *options) { + if (options->quiet) + return; if (options->break_opt != -1) diffcore_break(options->break_opt); if (options->detect_rename) @@ -2910,18 +2933,11 @@ void diffcore_std(struct diff_options *options) diffcore_order(options->orderfile); diff_resolve_rename_copy(); diffcore_apply_filter(options->filter); -} - -void diffcore_std_no_resolve(struct diff_options *options) -{ - if (options->pickaxe) - diffcore_pickaxe(options->pickaxe, options->pickaxe_opts); - if (options->orderfile) - diffcore_order(options->orderfile); - diffcore_apply_filter(options->filter); + options->has_changes = !!diff_queued_diff.nr; } + void diff_addremove(struct diff_options *options, int addremove, unsigned mode, const unsigned char *sha1, @@ -2957,6 +2973,7 @@ void diff_addremove(struct diff_options *options, fill_filespec(two, sha1, mode); diff_queue(&diff_queued_diff, one, two); + options->has_changes = 1; } void diff_change(struct diff_options *options, @@ -2982,6 +2999,7 @@ void diff_change(struct diff_options *options, fill_filespec(two, new_sha1, new_mode); diff_queue(&diff_queued_diff, one, two); + options->has_changes = 1; } void diff_unmerge(struct diff_options *options, @@ -56,7 +56,10 @@ struct diff_options { silent_on_remove:1, find_copies_harder:1, color_diff:1, - color_diff_words:1; + color_diff_words:1, + has_changes:1, + quiet:1, + exit_with_status:1; int context; int break_opt; int detect_rename; @@ -170,8 +173,6 @@ extern int diff_setup_done(struct diff_options *); extern void diffcore_std(struct diff_options *); -extern void diffcore_std_no_resolve(struct diff_options *); - #define COMMON_DIFF_OPTIONS_HELP \ "\ncommon diff options:\n" \ " -z output diff-raw with lines terminated with NUL.\n" \ diff --git a/revision.c b/revision.c index 3c2eb125e6..bcdb6a1212 100644 --- a/revision.c +++ b/revision.c @@ -213,6 +213,13 @@ static int everybody_uninteresting(struct commit_list *orig) return 1; } +/* + * The goal is to get REV_TREE_NEW as the result only if the + * diff consists of all '+' (and no other changes), and + * REV_TREE_DIFFERENT otherwise (of course if the trees are + * the same we want REV_TREE_SAME). That means that once we + * get to REV_TREE_DIFFERENT, we do not have to look any further. + */ static int tree_difference = REV_TREE_SAME; static void file_add_remove(struct diff_options *options, @@ -236,6 +243,8 @@ static void file_add_remove(struct diff_options *options, diff = REV_TREE_NEW; } tree_difference = diff; + if (tree_difference == REV_TREE_DIFFERENT) + options->has_changes = 1; } static void file_change(struct diff_options *options, @@ -245,6 +254,7 @@ static void file_change(struct diff_options *options, const char *base, const char *path) { tree_difference = REV_TREE_DIFFERENT; + options->has_changes = 1; } int rev_compare_tree(struct rev_info *revs, struct tree *t1, struct tree *t2) @@ -254,6 +264,7 @@ int rev_compare_tree(struct rev_info *revs, struct tree *t1, struct tree *t2) if (!t2) return REV_TREE_DIFFERENT; tree_difference = REV_TREE_SAME; + revs->pruning.has_changes = 0; if (diff_tree_sha1(t1->object.sha1, t2->object.sha1, "", &revs->pruning) < 0) return REV_TREE_DIFFERENT; @@ -277,11 +288,12 @@ int rev_same_tree_as_empty(struct rev_info *revs, struct tree *t1) empty.buf = ""; empty.size = 0; - tree_difference = 0; + tree_difference = REV_TREE_SAME; + revs->pruning.has_changes = 0; retval = diff_tree(&empty, &real, "", &revs->pruning); free(tree); - return retval >= 0 && !tree_difference; + return retval >= 0 && (tree_difference == REV_TREE_SAME); } static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit) @@ -545,6 +557,7 @@ void init_revisions(struct rev_info *revs, const char *prefix) revs->ignore_merges = 1; revs->simplify_history = 1; revs->pruning.recursive = 1; + revs->pruning.quiet = 1; revs->pruning.add_remove = file_add_remove; revs->pruning.change = file_change; revs->lifo = 1; diff --git a/t/t4017-diff-retval.sh b/t/t4017-diff-retval.sh new file mode 100755 index 0000000000..68731908be --- /dev/null +++ b/t/t4017-diff-retval.sh @@ -0,0 +1,79 @@ +#!/bin/sh + +test_description='Return value of diffs' + +. ./test-lib.sh + +test_expect_success 'setup' ' + echo 1 >a && + git add . && + git commit -m first && + echo 2 >b && + git add . && + git commit -a -m second +' + +test_expect_success 'git diff-tree HEAD^ HEAD' ' + git diff-tree --exit-code HEAD^ HEAD + test $? = 1 +' +test_expect_success 'git diff-tree HEAD^ HEAD -- a' ' + git diff-tree --exit-code HEAD^ HEAD -- a + test $? = 0 +' +test_expect_success 'git diff-tree HEAD^ HEAD -- b' ' + git diff-tree --exit-code HEAD^ HEAD -- b + test $? = 1 +' +test_expect_success 'echo HEAD | git diff-tree --stdin' ' + echo $(git rev-parse HEAD) | git diff-tree --exit-code --stdin + test $? = 1 +' +test_expect_success 'git diff-tree HEAD HEAD' ' + git diff-tree --exit-code HEAD HEAD + test $? = 0 +' +test_expect_success 'git diff-files' ' + git diff-files --exit-code + test $? = 0 +' +test_expect_success 'git diff-index --cached HEAD' ' + git diff-index --exit-code --cached HEAD + test $? = 0 +' +test_expect_success 'git diff-index --cached HEAD^' ' + git diff-index --exit-code --cached HEAD^ + test $? = 1 +' +test_expect_success 'git diff-index --cached HEAD^' ' + echo text >>b && + echo 3 >c && + git add . && { + git diff-index --exit-code --cached HEAD^ + test $? = 1 + } +' +test_expect_success 'git diff-tree -Stext HEAD^ HEAD -- b' ' + git commit -m "text in b" && { + git diff-tree -p --exit-code -Stext HEAD^ HEAD -- b + test $? = 1 + } +' +test_expect_success 'git diff-tree -Snot-found HEAD^ HEAD -- b' ' + git diff-tree -p --exit-code -Snot-found HEAD^ HEAD -- b + test $? = 0 +' +test_expect_success 'git diff-files' ' + echo 3 >>c && { + git diff-files --exit-code + test $? = 1 + } +' +test_expect_success 'git diff-index --cached HEAD' ' + git update-index c && { + git diff-index --exit-code --cached HEAD + test $? = 1 + } +' + +test_done diff --git a/t/t4017-quiet.sh b/t/t4017-quiet.sh new file mode 100755 index 0000000000..e747e84227 --- /dev/null +++ b/t/t4017-quiet.sh @@ -0,0 +1,80 @@ +#!/bin/sh + +test_description='Return value of diffs' + +. ./test-lib.sh + +test_expect_success 'setup' ' + echo 1 >a && + git add . && + git commit -m first && + echo 2 >b && + git add . && + git commit -a -m second +' + +test_expect_success 'git diff-tree HEAD^ HEAD' ' + git diff-tree --quiet HEAD^ HEAD >cnt + test $? = 1 && test $(wc -l <cnt) = 0 +' +test_expect_success 'git diff-tree HEAD^ HEAD -- a' ' + git diff-tree --quiet HEAD^ HEAD -- a >cnt + test $? = 0 && test $(wc -l <cnt) = 0 +' +test_expect_success 'git diff-tree HEAD^ HEAD -- b' ' + git diff-tree --quiet HEAD^ HEAD -- b >cnt + test $? = 1 && test $(wc -l <cnt) = 0 +' +# this diff outputs one line: sha1 of the given head +test_expect_success 'echo HEAD | git diff-tree --stdin' ' + echo $(git rev-parse HEAD) | git diff-tree --quiet --stdin >cnt + test $? = 1 && test $(wc -l <cnt) = 1 +' +test_expect_success 'git diff-tree HEAD HEAD' ' + git diff-tree --quiet HEAD HEAD >cnt + test $? = 0 && test $(wc -l <cnt) = 0 +' +test_expect_success 'git diff-files' ' + git diff-files --quiet >cnt + test $? = 0 && test $(wc -l <cnt) = 0 +' +test_expect_success 'git diff-index --cached HEAD' ' + git diff-index --quiet --cached HEAD >cnt + test $? = 0 && test $(wc -l <cnt) = 0 +' +test_expect_success 'git diff-index --cached HEAD^' ' + git diff-index --quiet --cached HEAD^ >cnt + test $? = 1 && test $(wc -l <cnt) = 0 +' +test_expect_success 'git diff-index --cached HEAD^' ' + echo text >>b && + echo 3 >c && + git add . && { + git diff-index --quiet --cached HEAD^ >cnt + test $? = 1 && test $(wc -l <cnt) = 0 + } +' +test_expect_success 'git diff-tree -Stext HEAD^ HEAD -- b' ' + git commit -m "text in b" && { + git diff-tree --quiet -Stext HEAD^ HEAD -- b >cnt + test $? = 1 && test $(wc -l <cnt) = 0 + } +' +test_expect_success 'git diff-tree -Snot-found HEAD^ HEAD -- b' ' + git diff-tree --quiet -Snot-found HEAD^ HEAD -- b >cnt + test $? = 0 && test $(wc -l <cnt) = 0 +' +test_expect_success 'git diff-files' ' + echo 3 >>c && { + git diff-files --quiet >cnt + test $? = 1 && test $(wc -l <cnt) = 0 + } +' +test_expect_success 'git diff-index --cached HEAD' ' + git update-index c && { + git diff-index --quiet --cached HEAD >cnt + test $? = 1 && test $(wc -l <cnt) = 0 + } +' + +test_done diff --git a/tree-diff.c b/tree-diff.c index f89b9d31e4..3940962e79 100644 --- a/tree-diff.c +++ b/tree-diff.c @@ -163,6 +163,8 @@ int diff_tree(struct tree_desc *t1, struct tree_desc *t2, const char *base, stru int baselen = strlen(base); while (t1->size | t2->size) { + if (opt->quiet && opt->has_changes) + break; if (opt->nr_paths && t1->size && !interesting(t1, base, baselen, opt)) { update_tree_entry(t1); continue; |