+/*
+ * GIT - The information manager from hell
+ *
+ * Copyright (C) Linus Torvalds, 2005
+ */
#include "cache.h"
-#define MTIME_CHANGED 0x0001
-#define CTIME_CHANGED 0x0002
-#define OWNER_CHANGED 0x0004
-#define MODE_CHANGED 0x0008
-#define INODE_CHANGED 0x0010
-#define DATA_CHANGED 0x0020
+static const char *show_diff_usage = "show-diff [-q] [-s] [-z] [paths...]";
-static int match_stat(struct cache_entry *ce, struct stat *st)
-{
- unsigned int changed = 0;
+static int recursive = 0;
+static int line_termination = '\n';
+static int silent = 0;
+static int silent_on_nonexisting_files = 0;
- if (ce->mtime.sec != (unsigned int)st->st_mtim.tv_sec ||
- ce->mtime.nsec != (unsigned int)st->st_mtim.tv_nsec)
- changed |= MTIME_CHANGED;
- if (ce->ctime.sec != (unsigned int)st->st_ctim.tv_sec ||
- ce->ctime.nsec != (unsigned int)st->st_ctim.tv_nsec)
- changed |= CTIME_CHANGED;
- if (ce->st_uid != (unsigned int)st->st_uid ||
- ce->st_gid != (unsigned int)st->st_gid)
- changed |= OWNER_CHANGED;
- if (ce->st_mode != (unsigned int)st->st_mode)
- changed |= MODE_CHANGED;
- if (ce->st_dev != (unsigned int)st->st_dev ||
- ce->st_ino != (unsigned int)st->st_ino)
- changed |= INODE_CHANGED;
- if (ce->st_size != (unsigned int)st->st_size)
- changed |= DATA_CHANGED;
- return changed;
+static int matches_pathspec(struct cache_entry *ce, char **spec, int cnt)
+{
+ int i;
+ int namelen = ce_namelen(ce);
+ for (i = 0; i < cnt; i++) {
+ int speclen = strlen(spec[i]);
+ if (! strncmp(spec[i], ce->name, speclen) &&
+ speclen <= namelen &&
+ (ce->name[speclen] == 0 ||
+ ce->name[speclen] == '/'))
+ return 1;
+ }
+ return 0;
}
-static void show_differences(struct cache_entry *ce, struct stat *cur,
- void *old_contents, unsigned long long old_size)
+static void show_file(const char *prefix, struct cache_entry *ce)
{
- static char cmd[1000];
- FILE *f;
-
- snprintf(cmd, sizeof(cmd), "diff -u - %s", ce->name);
- f = popen(cmd, "w");
- fwrite(old_contents, old_size, 1, f);
- pclose(f);
+ printf("%s%o\t%s\t%s\t%s%c", prefix, ntohl(ce->ce_mode), "blob",
+ sha1_to_hex(ce->sha1), ce->name, line_termination);
}
int main(int argc, char **argv)
{
+ static const char null_sha1_hex[] = "0000000000000000000000000000000000000000";
int entries = read_cache();
int i;
+ while (1 < argc && argv[1][0] == '-') {
+ if (!strcmp(argv[1], "-s"))
+ silent_on_nonexisting_files = silent = 1;
+ else if (!strcmp(argv[1], "-q"))
+ silent_on_nonexisting_files = 1;
+ else if (!strcmp(argv[1], "-z"))
+ line_termination = 0;
+ else if (!strcmp(argv[1], "-r"))
+ recursive = 1; /* No-op */
+ else
+ usage(show_diff_usage);
+ argv++; argc--;
+ }
+
+ /* At this point, if argc == 1, then we are doing everything.
+ * Otherwise argv[1] .. argv[argc-1] have the explicit paths.
+ */
if (entries < 0) {
perror("read_cache");
exit(1);
}
+
for (i = 0; i < entries; i++) {
struct stat st;
+ unsigned int oldmode, mode;
struct cache_entry *ce = active_cache[i];
- int n, changed;
- unsigned int mode;
- unsigned long size;
- char type[20];
- void *new;
+ int changed;
- if (stat(ce->name, &st) < 0) {
- printf("%s: %s\n", ce->name, strerror(errno));
+ if (1 < argc &&
+ ! matches_pathspec(ce, argv+1, argc-1))
+ continue;
+
+ if (ce_stage(ce)) {
+ printf("U %s%c", ce->name, line_termination);
+
+ while (i < entries &&
+ !strcmp(ce->name, active_cache[i]->name))
+ i++;
+ i--; /* compensate for loop control increments */
continue;
}
- changed = match_stat(ce, &st);
- if (!changed) {
- printf("%s: ok\n", ce->name);
+
+ if (stat(ce->name, &st) < 0) {
+ if (errno != ENOENT) {
+ perror(ce->name);
+ continue;
+ }
+ if (silent_on_nonexisting_files)
+ continue;
+ show_file("-", ce);
continue;
}
- printf("%.*s: ", ce->namelen, ce->name);
- for (n = 0; n < 20; n++)
- printf("%02x", ce->sha1[n]);
- printf("\n");
- new = read_sha1_file(ce->sha1, type, &size);
- show_differences(ce, &st, new, size);
- free(new);
+ changed = cache_match_stat(ce, &st);
+ if (!changed)
+ continue;
+
+ oldmode = ntohl(ce->ce_mode);
+ mode = S_IFREG | ce_permissions(st.st_mode);
+
+ printf("*%o->%o\t%s\t%s->%s\t%s%c",
+ oldmode, mode, "blob",
+ sha1_to_hex(ce->sha1), null_sha1_hex,
+ ce->name, line_termination);
}
return 0;
}