#include "log-tree.h"
#include "builtin.h"
-/* NEEDSWORK: struct object has place for name but we _do_
- * know mode when we extracted the blob out of a tree, which
- * we currently lose.
- */
struct blobinfo {
unsigned char sha1[20];
const char *name;
+ unsigned mode;
};
static const char builtin_diff_usage[] =
struct diff_filespec *one, *two;
if (!is_null_sha1(old_sha1) && !is_null_sha1(new_sha1) &&
- !hashcmp(old_sha1, new_sha1))
+ !hashcmp(old_sha1, new_sha1) && (old_mode == new_mode))
return;
if (opt->reverse_diff) {
die("'%s': %s", path, strerror(errno));
if (!(S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)))
die("'%s': not a regular file or symlink", path);
+
+ if (blob[0].mode == S_IFINVALID)
+ blob[0].mode = canon_mode(st.st_mode);
+
stuff_change(&revs->diffopt,
- canon_mode(st.st_mode), canon_mode(st.st_mode),
+ blob[0].mode, canon_mode(st.st_mode),
blob[0].sha1, null_sha1,
path, path);
diffcore_std(&revs->diffopt);
if (argc > 1)
usage(builtin_diff_usage);
+ if (blob[0].mode == S_IFINVALID)
+ blob[0].mode = mode;
+
+ if (blob[1].mode == S_IFINVALID)
+ blob[1].mode = mode;
+
stuff_change(&revs->diffopt,
- mode, mode,
+ blob[0].mode, blob[1].mode,
blob[0].sha1, blob[1].sha1,
blob[0].name, blob[1].name);
diffcore_std(&revs->diffopt);
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.
prefix = setup_git_directory_gently(&nongit);
git_config(git_diff_ui_config);
init_revisions(&rev, prefix);
+ rev.diffopt.skip_stat_unmatch = 1;
if (!setup_diff_no_index(&rev, argc, argv, nongit, prefix))
argc = 0;
if (diff_setup_done(&rev.diffopt) < 0)
die("diff_setup_done failed");
}
+ rev.diffopt.allow_external = 1;
+ rev.diffopt.recursive = 1;
+
+ /* 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 (!rev.diffopt.exit_with_status)
+ setup_pager();
/* Do we have --cached and not have a pending object, then
* default to HEAD by hand. Eek.
die("more than two blobs given: '%s'", name);
hashcpy(blob[blobs].sha1, obj->sha1);
blob[blobs].name = name;
+ blob[blobs].mode = list->mode;
blobs++;
continue;
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);
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;
+
+ if ((rev.diffopt.output_format & DIFF_FORMAT_PATCH)
+ && (1 < rev.diffopt.skip_stat_unmatch))
+ printf("Warning: %d path%s touched but unmodified. "
+ "Consider running git-status.\n",
+ rev.diffopt.skip_stat_unmatch - 1,
+ rev.diffopt.skip_stat_unmatch == 2 ? "" : "s");
+ return result;
}