#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);
add_pending_object(revs, obj, "HEAD");
}
+static void refresh_index_quietly(void)
+{
+ struct lock_file *lock_file;
+ int fd;
+
+ lock_file = xcalloc(1, sizeof(struct lock_file));
+ fd = hold_locked_index(lock_file, 0);
+ if (fd < 0)
+ return;
+ discard_cache();
+ read_cache();
+ refresh_cache(REFRESH_QUIET|REFRESH_UNMERGED);
+
+ if (active_cache_changed &&
+ !write_cache(fd, active_cache, active_nr) && !close(fd))
+ commit_locked_index(lock_file);
+
+ rollback_lock_file(lock_file);
+}
+
int cmd_diff(int argc, const char **argv, const char *prefix)
{
int i;
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 = !!diff_auto_refresh_index;
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 (1 < rev.diffopt.skip_stat_unmatch)
+ refresh_index_quietly();
+ return result;
}