git/diff-files.c
Linus Torvalds d288a70030 [PATCH] Make "git diff" work inside relative subdirectories
We always show the diff as an absolute path, but pathnames to diff are
taken relative to the current working directory (and if no pathnames are
given, the default ends up being all of the current working directory).

Note that "../xyz" also works, so you can do

	cd linux/drivers/char
	git diff ../block

and it will generate a diff of the linux/drivers/block changes.

Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-08-16 18:47:22 -07:00

159 lines
4.1 KiB
C

/*
* GIT - The information manager from hell
*
* Copyright (C) Linus Torvalds, 2005
*/
#include "cache.h"
#include "diff.h"
static const char diff_files_usage[] =
"git-diff-files [-q] "
"[<common diff options>] [<path>...]"
COMMON_DIFF_OPTIONS_HELP;
static int diff_output_format = DIFF_FORMAT_RAW;
static int diff_line_termination = '\n';
static int detect_rename = 0;
static int find_copies_harder = 0;
static int diff_setup_opt = 0;
static int diff_score_opt = 0;
static const char *pickaxe = NULL;
static int pickaxe_opts = 0;
static int diff_break_opt = -1;
static const char *orderfile = NULL;
static const char *diff_filter = NULL;
static int silent = 0;
static void show_unmerge(const char *path)
{
diff_unmerge(path);
}
static void show_file(int pfx, struct cache_entry *ce)
{
diff_addremove(pfx, ntohl(ce->ce_mode), ce->sha1, ce->name, NULL);
}
static void show_modified(int oldmode, int mode,
const unsigned char *old_sha1, const unsigned char *sha1,
char *path)
{
diff_change(oldmode, mode, old_sha1, sha1, path, NULL);
}
int main(int argc, char **argv)
{
static const unsigned char null_sha1[20] = { 0, };
const char **pathspec;
const char *prefix = setup_git_directory();
int entries, i;
while (1 < argc && argv[1][0] == '-') {
if (!strcmp(argv[1], "-p") || !strcmp(argv[1], "-u"))
diff_output_format = DIFF_FORMAT_PATCH;
else if (!strcmp(argv[1], "-q"))
silent = 1;
else if (!strcmp(argv[1], "-r"))
; /* no-op */
else if (!strcmp(argv[1], "-s"))
; /* no-op */
else if (!strcmp(argv[1], "-z"))
diff_line_termination = 0;
else if (!strcmp(argv[1], "--name-only"))
diff_output_format = DIFF_FORMAT_NAME;
else if (!strcmp(argv[1], "-R"))
diff_setup_opt |= DIFF_SETUP_REVERSE;
else if (!strncmp(argv[1], "-S", 2))
pickaxe = argv[1] + 2;
else if (!strncmp(argv[1], "-O", 2))
orderfile = argv[1] + 2;
else if (!strncmp(argv[1], "--diff-filter=", 14))
diff_filter = argv[1] + 14;
else if (!strcmp(argv[1], "--pickaxe-all"))
pickaxe_opts = DIFF_PICKAXE_ALL;
else if (!strncmp(argv[1], "-B", 2)) {
if ((diff_break_opt =
diff_scoreopt_parse(argv[1])) == -1)
usage(diff_files_usage);
}
else if (!strncmp(argv[1], "-M", 2)) {
if ((diff_score_opt =
diff_scoreopt_parse(argv[1])) == -1)
usage(diff_files_usage);
detect_rename = DIFF_DETECT_RENAME;
}
else if (!strncmp(argv[1], "-C", 2)) {
if ((diff_score_opt =
diff_scoreopt_parse(argv[1])) == -1)
usage(diff_files_usage);
detect_rename = DIFF_DETECT_COPY;
}
else if (!strcmp(argv[1], "--find-copies-harder"))
find_copies_harder = 1;
else
usage(diff_files_usage);
argv++; argc--;
}
/* Find the directory, and set up the pathspec */
pathspec = get_pathspec(prefix, argv + 1);
entries = read_cache();
if (find_copies_harder && detect_rename != DIFF_DETECT_COPY)
usage(diff_files_usage);
/* 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);
}
diff_setup(diff_setup_opt);
for (i = 0; i < entries; i++) {
struct stat st;
unsigned int oldmode;
struct cache_entry *ce = active_cache[i];
int changed;
if (!ce_path_match(ce, pathspec))
continue;
if (ce_stage(ce)) {
show_unmerge(ce->name);
while (i < entries &&
!strcmp(ce->name, active_cache[i]->name))
i++;
i--; /* compensate for loop control increments */
continue;
}
if (lstat(ce->name, &st) < 0) {
if (errno != ENOENT && errno != ENOTDIR) {
perror(ce->name);
continue;
}
if (silent)
continue;
show_file('-', ce);
continue;
}
changed = ce_match_stat(ce, &st);
if (!changed && !find_copies_harder)
continue;
oldmode = ntohl(ce->ce_mode);
show_modified(oldmode, DIFF_FILE_CANON_MODE(st.st_mode),
ce->sha1, (changed ? null_sha1 : ce->sha1),
ce->name);
}
diffcore_std(pathspec,
detect_rename, diff_score_opt,
pickaxe, pickaxe_opts,
diff_break_opt,
orderfile, diff_filter);
diff_flush(diff_output_format, diff_line_termination);
return 0;
}