When specifying an absolute path, or a relative path pointing outside the working tree, do not fail, but roll your own diffopt parsing, and execute a --no-index diff. Signed-off-by: Johannes Schindelin <johannes.schindelin@xxxxxx> --- builtin-diff-files.c | 5 +++- builtin-diff.c | 5 +++- diff-lib.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++ diff.h | 2 + 4 files changed, 64 insertions(+), 2 deletions(-) diff --git a/builtin-diff-files.c b/builtin-diff-files.c index e1199f8..aec8338 100644 --- a/builtin-diff-files.c +++ b/builtin-diff-files.c @@ -23,7 +23,10 @@ int cmd_diff_files(int argc, const char **argv, const char *prefix) git_config(git_default_config); /* no "diff" UI options */ rev.abbrev = 0; - argc = setup_revisions(argc, argv, &rev, NULL); + if (!setup_diff_no_index(&rev, argc, argv, nongit, prefix)) + argc = 0; + else + 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); diff --git a/builtin-diff.c b/builtin-diff.c index 814d1fc..e7ece0a 100644 --- a/builtin-diff.c +++ b/builtin-diff.c @@ -215,7 +215,10 @@ int cmd_diff(int argc, const char **argv, const char *prefix) git_config(git_diff_ui_config); init_revisions(&rev, prefix); - argc = setup_revisions(argc, argv, &rev, NULL); + if (!setup_diff_no_index(&rev, argc, argv, nongit, prefix)) + argc = 0; + else + argc = setup_revisions(argc, argv, &rev, NULL); if (!rev.diffopt.output_format) { rev.diffopt.output_format = DIFF_FORMAT_PATCH; if (diff_setup_done(&rev.diffopt) < 0) diff --git a/diff-lib.c b/diff-lib.c index b164222..6678e22 100644 --- a/diff-lib.c +++ b/diff-lib.c @@ -200,6 +200,60 @@ static int handle_diff_files_args(struct rev_info *revs, return 0; } +static int is_outside_repo(const char *path, int nongit, const char *prefix) +{ + int i; + if (nongit || !strcmp(path, "-") || path[0] == '/') + return 1; + if (prefixcmp(path, "../")) + return 0; + if (!prefix) + return 1; + for (i = strlen(prefix); !prefixcmp(path, "../"); ) { + while (i > 0 && prefix[i - 1] != '/') + i--; + if (--i < 0) + return 1; + path += 3; + } + return 0; +} + +int setup_diff_no_index(struct rev_info *revs, + int argc, const char ** argv, int nongit, const char *prefix) +{ + int i; + for (i = 1; i < argc; i++) + if (argv[i][0] != '-') + break; + else if (!strcmp(argv[i], "--")) { + i++; + break; + } else if (i < argc - 3 && !strcmp(argv[i], "--no-index")) { + i = argc - 3; + break; + } + if (argc != i + 2 || (!is_outside_repo(argv[i + 1], nongit, prefix) && + !is_outside_repo(argv[i], nongit, prefix))) + return -1; + + diff_setup(&revs->diffopt); + for (i = 1; i < argc - 2; ) + if (!strcmp(argv[i], "--no-index")) + i++; + else { + int j = diff_opt_parse(&revs->diffopt, + argv + i, argc - i); + if (!j) + die("invalid diff option/value: %s", argv[i]); + i += j; + } + revs->diffopt.paths = argv + argc - 2; + revs->diffopt.nr_paths = 2; + revs->max_count = -2; + return 0; +} + int run_diff_files_cmd(struct rev_info *revs, int argc, const char **argv) { int silent_on_removed; diff --git a/diff.h b/diff.h index 4043cec..4b435e8 100644 --- a/diff.h +++ b/diff.h @@ -222,6 +222,8 @@ 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); +extern int setup_diff_no_index(struct rev_info *revs, + int argc, const char ** argv, int nongit, const char *prefix); extern int run_diff_files_cmd(struct rev_info *revs, int argc, const char **argv); extern int run_diff_index(struct rev_info *revs, int cached); -- 1.5.0.1.788.g8ca52 - To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html