};
static const char builtin_diff_usage[] =
-"git-diff <options> <rev>{0,2} -- <path>*";
+"git diff <options> <rev>{0,2} -- <path>*";
static void stuff_change(struct diff_options *opt,
unsigned old_mode, unsigned new_mode,
if (!(S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)))
die("'%s': not a regular file or symlink", path);
+ diff_set_mnemonic_prefix(&revs->diffopt, "o/", "w/");
+
if (blob[0].mode == S_IFINVALID)
blob[0].mode = canon_mode(st.st_mode);
int cached = 0;
while (1 < argc) {
const char *arg = argv[1];
- if (!strcmp(arg, "--cached"))
+ if (!strcmp(arg, "--cached") || !strcmp(arg, "--staged"))
cached = 1;
else
usage(builtin_diff_usage);
argv++; argc--;
}
+ if (!cached)
+ setup_work_tree();
/*
* Make sure there is one revision (i.e. pending object),
* and there is no revision filtering parameters.
revs->max_count != -1 || revs->min_age != -1 ||
revs->max_age != -1)
usage(builtin_diff_usage);
- if (read_cache() < 0) {
- perror("read_cache");
+ if (read_cache_preload(revs->diffopt.paths) < 0) {
+ perror("read_cache_preload");
return -1;
}
return run_diff_index(revs, cached);
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++)
- hashcpy((unsigned char *)(parent + i),
- ent[ents - 1 - i].item->sha1);
+ hashcpy((unsigned char *)(parent + i), ent[i].item->sha1);
diff_tree_combined(parent[0], parent + 1, ents - 1,
revs->dense_combined_merges, revs);
return 0;
rollback_lock_file(lock_file);
}
+static int builtin_diff_files(struct rev_info *revs, int argc, const char **argv)
+{
+ int result;
+ unsigned int options = 0;
+
+ while (1 < argc && argv[1][0] == '-') {
+ if (!strcmp(argv[1], "--base"))
+ revs->max_count = 1;
+ else if (!strcmp(argv[1], "--ours"))
+ revs->max_count = 2;
+ else if (!strcmp(argv[1], "--theirs"))
+ revs->max_count = 3;
+ else if (!strcmp(argv[1], "-q"))
+ options |= DIFF_SILENT_ON_REMOVED;
+ else
+ return error("invalid option: %s", argv[1]);
+ argv++; argc--;
+ }
+
+ /*
+ * "diff --base" should not combine merges because it was not
+ * asked to. "diff -c" should not densify (if the user wants
+ * dense one, --cc can be explicitly asked for, or just rely
+ * on the default).
+ */
+ if (revs->max_count == -1 && !revs->combine_merges &&
+ (revs->diffopt.output_format & DIFF_FORMAT_PATCH))
+ revs->combine_merges = revs->dense_combined_merges = 1;
+
+ setup_work_tree();
+ if (read_cache_preload(revs->diffopt.paths) < 0) {
+ perror("read_cache_preload");
+ return -1;
+ }
+ result = run_diff_files(revs, options);
+ return diff_result_code(&revs->diffopt, result);
+}
+
int cmd_diff(int argc, const char **argv, const char *prefix)
{
int i;
* N=2, M=0:
* tree vs tree (diff-tree)
*
+ * N=0, M=0, P=2:
+ * compare two filesystem entities (aka --no-index).
+ *
* Other cases are errors.
*/
prefix = setup_git_directory_gently(&nongit);
- git_config(git_diff_ui_config);
+ git_config(git_diff_ui_config, NULL);
if (diff_use_color_default == -1)
diff_use_color_default = git_use_color_default;
init_revisions(&rev, prefix);
+
+ /* If this is a no-index diff, just run it and exit there. */
+ diff_no_index(&rev, argc, argv, nongit, prefix);
+
+ /* Otherwise, we are doing the usual "git" diff */
rev.diffopt.skip_stat_unmatch = !!diff_auto_refresh_index;
- if (!setup_diff_no_index(&rev, argc, argv, nongit, prefix))
- argc = 0;
- else
- argc = setup_revisions(argc, argv, &rev, NULL);
+ /* Default to let external and textconv be used */
+ DIFF_OPT_SET(&rev.diffopt, ALLOW_EXTERNAL);
+ DIFF_OPT_SET(&rev.diffopt, ALLOW_TEXTCONV);
+
+ if (nongit)
+ die("Not a git repository");
+ 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)
die("diff_setup_done failed");
}
- if (rev.diffopt.prefix && nongit) {
- rev.diffopt.prefix = NULL;
- rev.diffopt.prefix_length = 0;
- }
- DIFF_OPT_SET(&rev.diffopt, ALLOW_EXTERNAL);
+
DIFF_OPT_SET(&rev.diffopt, RECURSIVE);
/*
* If the user asked for our exit code then don't start a
* pager or we would end up reporting its exit code instead.
*/
- if (!DIFF_OPT_TST(&rev.diffopt, EXIT_WITH_STATUS))
+ if (!DIFF_OPT_TST(&rev.diffopt, EXIT_WITH_STATUS) &&
+ check_pager_config("diff") != 0)
setup_pager();
- /* Do we have --cached and not have a pending object, then
+ /*
+ * Do we have --cached and not have a pending object, then
* default to HEAD by hand. Eek.
*/
if (!rev.pending.nr) {
const char *arg = argv[i];
if (!strcmp(arg, "--"))
break;
- else if (!strcmp(arg, "--cached")) {
+ else if (!strcmp(arg, "--cached") ||
+ !strcmp(arg, "--staged")) {
add_head_to_pending(&rev);
if (!rev.pending.nr)
die("No HEAD commit to compare with (yet)");
if (!ents) {
switch (blobs) {
case 0:
- result = run_diff_files_cmd(&rev, argc, argv);
+ result = builtin_diff_files(&rev, argc, argv);
break;
case 1:
if (paths != 1)