* Copyright (c) 2006 Junio C Hamano
*/
#include "cache.h"
+#include "color.h"
#include "commit.h"
#include "blob.h"
#include "tag.h"
#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) {
+ if (DIFF_OPT_TST(opt, REVERSE_DIFF)) {
unsigned tmp;
const unsigned char *tmp_u;
const char *tmp_c;
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);
return 0;
}
-void add_head(struct rev_info *revs)
+static void refresh_index_quietly(void)
{
- unsigned char sha1[20];
- struct object *obj;
- if (get_sha1("HEAD", sha1))
- return;
- obj = parse_object(sha1);
- if (!obj)
+ 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;
- add_pending_object(revs, obj, "HEAD");
+ discard_cache();
+ read_cache();
+ refresh_cache(REFRESH_QUIET|REFRESH_UNMERGED);
+
+ if (active_cache_changed &&
+ !write_cache(fd, active_cache, active_nr))
+ commit_locked_index(lock_file);
+
+ rollback_lock_file(lock_file);
}
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.
prefix = setup_git_directory_gently(&nongit);
git_config(git_diff_ui_config);
+
+ if (diff_use_color_default == -1)
+ diff_use_color_default = git_use_color_default;
+
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");
}
+ 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))
+ setup_pager();
/* Do we have --cached and not have a pending object, then
* default to HEAD by hand. Eek.
if (!strcmp(arg, "--"))
break;
else if (!strcmp(arg, "--cached")) {
- add_head(&rev);
+ add_head_to_pending(&rev);
if (!rev.pending.nr)
die("No HEAD commit to compare with (yet)");
break;
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);
+ result = diff_result_code(&rev.diffopt, result);
+ if (1 < rev.diffopt.skip_stat_unmatch)
+ refresh_index_quietly();
+ return result;
}