summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@osdl.org>2005-08-17 01:06:34 (GMT)
committerJunio C Hamano <junkio@cox.net>2005-08-17 01:47:22 (GMT)
commitd288a70030eaa5c205a72b4548635e17f8e523c0 (patch)
treee446e859256bd90a9eefd1cb2406707ea5b9d555
parent83db04ff878f40146952ee5d3d2d113568455f5b (diff)
downloadgit-d288a70030eaa5c205a72b4548635e17f8e523c0.zip
git-d288a70030eaa5c205a72b4548635e17f8e523c0.tar.gz
git-d288a70030eaa5c205a72b4548635e17f8e523c0.tar.bz2
[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>
-rw-r--r--Makefile2
-rw-r--r--cache.h3
-rw-r--r--diff-cache.c12
-rw-r--r--diff-files.c11
-rw-r--r--diff-tree.c17
-rwxr-xr-xgit-diff-script4
-rw-r--r--rev-parse.c7
-rw-r--r--setup.c110
8 files changed, 147 insertions, 19 deletions
diff --git a/Makefile b/Makefile
index 16ab0c7..db75965 100644
--- a/Makefile
+++ b/Makefile
@@ -97,7 +97,7 @@ LIB_H=cache.h object.h blob.h tree.h commit.h tag.h delta.h epoch.h csum-file.h
LIB_OBJS=read-cache.o sha1_file.o usage.o object.o commit.o tree.o blob.o \
tag.o date.o index.o diff-delta.o patch-delta.o entry.o path.o \
refs.o csum-file.o pack-check.o pkt-line.o connect.o ident.o \
- sha1_name.o
+ sha1_name.o setup.o
LIB_H += rev-cache.h
LIB_OBJS += rev-cache.o
diff --git a/cache.h b/cache.h
index f14a4ce..6365381 100644
--- a/cache.h
+++ b/cache.h
@@ -140,6 +140,9 @@ extern char *get_graft_file(void);
#define ALTERNATE_DB_ENVIRONMENT "GIT_ALTERNATE_OBJECT_DIRECTORIES"
+extern const char **get_pathspec(const char *prefix, char **pathspec);
+extern const char *setup_git_directory(void);
+
#define alloc_nr(x) (((x)+16)*3/2)
/* Initialize and use the cache information */
diff --git a/diff-cache.c b/diff-cache.c
index 47a4e09..400a4cb 100644
--- a/diff-cache.c
+++ b/diff-cache.c
@@ -168,10 +168,11 @@ static const char diff_cache_usage[] =
"[<common diff options>] <tree-ish> [<path>...]"
COMMON_DIFF_OPTIONS_HELP;
-int main(int argc, const char **argv)
+int main(int argc, char **argv)
{
const char *tree_name = NULL;
unsigned char sha1[20];
+ const char *prefix = setup_git_directory();
const char **pathspec = NULL;
void *tree;
unsigned long size;
@@ -179,15 +180,12 @@ int main(int argc, const char **argv)
int allow_options = 1;
int i;
- read_cache();
for (i = 1; i < argc; i++) {
const char *arg = argv[i];
if (!allow_options || *arg != '-') {
- if (tree_name) {
- pathspec = argv + i;
+ if (tree_name)
break;
- }
tree_name = arg;
continue;
}
@@ -265,12 +263,16 @@ int main(int argc, const char **argv)
usage(diff_cache_usage);
}
+ pathspec = get_pathspec(prefix, argv + i);
+
if (find_copies_harder && detect_rename != DIFF_DETECT_COPY)
usage(diff_cache_usage);
if (!tree_name || get_sha1(tree_name, sha1))
usage(diff_cache_usage);
+ read_cache();
+
/* The rest is for paths restriction. */
diff_setup(diff_setup_opt);
diff --git a/diff-files.c b/diff-files.c
index 2e6416e..89eb29b 100644
--- a/diff-files.c
+++ b/diff-files.c
@@ -41,12 +41,12 @@ static void show_modified(int oldmode, int mode,
diff_change(oldmode, mode, old_sha1, sha1, path, NULL);
}
-int main(int argc, const char **argv)
+int main(int argc, char **argv)
{
static const unsigned char null_sha1[20] = { 0, };
const char **pathspec;
- int entries = read_cache();
- int i;
+ const char *prefix = setup_git_directory();
+ int entries, i;
while (1 < argc && argv[1][0] == '-') {
if (!strcmp(argv[1], "-p") || !strcmp(argv[1], "-u"))
@@ -95,8 +95,9 @@ int main(int argc, const char **argv)
argv++; argc--;
}
- /* Do we have a pathspec? */
- pathspec = (argc > 1) ? argv + 1 : NULL;
+ /* 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);
diff --git a/diff-tree.c b/diff-tree.c
index 0dd3cda..fc87902 100644
--- a/diff-tree.c
+++ b/diff-tree.c
@@ -395,16 +395,25 @@ static int diff_tree_stdin(char *line)
return diff_tree_commit(commit, line);
}
+static int count_paths(const char **paths)
+{
+ int i = 0;
+ while (*paths++)
+ i++;
+ return i;
+}
+
static const char diff_tree_usage[] =
"git-diff-tree [--stdin] [-m] [-s] [-v] [--pretty] [-t] "
"[<common diff options>] <tree-ish> <tree-ish>"
COMMON_DIFF_OPTIONS_HELP;
-int main(int argc, const char **argv)
+int main(int argc, char **argv)
{
int nr_sha1;
char line[1000];
unsigned char sha1[2][20];
+ const char *prefix = setup_git_directory();
nr_sha1 = 0;
for (;;) {
@@ -523,11 +532,11 @@ int main(int argc, const char **argv)
if (find_copies_harder && detect_rename != DIFF_DETECT_COPY)
usage(diff_tree_usage);
- if (argc > 0) {
+ paths = get_pathspec(prefix, argv);
+ if (paths) {
int i;
- paths = argv;
- nr_paths = argc;
+ nr_paths = count_paths(paths);
pathlens = xmalloc(nr_paths * sizeof(int));
for (i=0; i<nr_paths; i++)
pathlens[i] = strlen(paths[i]);
diff --git a/git-diff-script b/git-diff-script
index 03ed555..926f594 100755
--- a/git-diff-script
+++ b/git-diff-script
@@ -1,7 +1,5 @@
#!/bin/sh
-. git-sh-setup-script || die "Not a git archive"
-
-rev=($(git-rev-parse --revs-only "$@"))
+rev=($(git-rev-parse --revs-only "$@")) || exit
flags=($(git-rev-parse --no-revs --flags "$@"))
files=($(git-rev-parse --no-revs --no-flags "$@"))
case "${#rev[*]}" in
diff --git a/rev-parse.c b/rev-parse.c
index 1c6ae76..39cf635 100644
--- a/rev-parse.c
+++ b/rev-parse.c
@@ -134,7 +134,8 @@ int main(int argc, char **argv)
{
int i, as_is = 0;
unsigned char sha1[20];
-
+ const char *prefix = setup_git_directory();
+
for (i = 1; i < argc; i++) {
char *arg = argv[i];
char *dotdot;
@@ -189,6 +190,10 @@ int main(int argc, char **argv)
for_each_ref(show_reference);
continue;
}
+ if (!strcmp(arg, "--show-prefix")) {
+ puts(prefix);
+ continue;
+ }
show_arg(arg);
continue;
}
diff --git a/setup.c b/setup.c
new file mode 100644
index 0000000..453bddb
--- /dev/null
+++ b/setup.c
@@ -0,0 +1,110 @@
+#include "cache.h"
+
+const char **get_pathspec(const char *prefix, char **pathspec)
+{
+ char *entry = *pathspec;
+ char **p;
+ int prefixlen;
+
+ if (!prefix) {
+ char **p;
+ if (!entry)
+ return NULL;
+ p = pathspec;
+ do {
+ if (*entry != '.')
+ continue;
+ /* fixup ? */
+ } while ((entry = *++p) != NULL);
+ return (const char **) pathspec;
+ }
+
+ if (!entry) {
+ static const char *spec[2];
+ spec[0] = prefix;
+ spec[1] = NULL;
+ return spec;
+ }
+
+ /* Otherwise we have to re-write the entries.. */
+ prefixlen = strlen(prefix);
+ p = pathspec;
+ do {
+ int speclen, len = prefixlen;
+ char *n;
+
+ for (;;) {
+ if (!strcmp(entry, ".")) {
+ entry++;
+ break;
+ }
+ if (!strncmp(entry, "./", 2)) {
+ entry += 2;
+ continue;
+ }
+ if (!strncmp(entry, "../", 3)) {
+ do {
+ if (!len)
+ die("'%s' is outside repository", *p);
+ len--;
+ } while (len && prefix[len-1] != '/');
+ entry += 3;
+ continue;
+ }
+ break;
+ }
+ speclen = strlen(entry);
+ n = xmalloc(speclen + len + 1);
+
+ memcpy(n, prefix, len);
+ memcpy(n + len, entry, speclen+1);
+ *p = n;
+ } while ((entry = *++p) != NULL);
+ return (const char **) pathspec;
+}
+
+const char *setup_git_directory(void)
+{
+ static char cwd[PATH_MAX+1];
+ int len, offset;
+
+ /*
+ * If GIT_DIR is set explicitly, we're not going
+ * to do any discovery
+ */
+ if (gitenv(GIT_DIR_ENVIRONMENT))
+ return NULL;
+
+ if (!getcwd(cwd, sizeof(cwd)) || cwd[0] != '/')
+ die("Unable to read current working directory");
+
+ offset = len = strlen(cwd);
+ for (;;) {
+ /*
+ * We always want to see a .git/HEAD and a .git/refs/
+ * subdirectory
+ */
+ if (!access(".git/HEAD", R_OK) && !access(".git/refs/", X_OK)) {
+ /*
+ * Then we need either a GIT_OBJECT_DIRECTORY define
+ * or a .git/objects/ directory
+ */
+ if (gitenv(DB_ENVIRONMENT) || !access(".git/objects/", X_OK))
+ break;
+ }
+ chdir("..");
+ do {
+ if (!offset)
+ die("Not a git repository");
+ } while (cwd[--offset] != '/');
+ }
+
+ if (offset == len)
+ return NULL;
+
+ /* Make "offset" point to past the '/', and add a '/' at the end */
+ offset++;
+ cwd[len++] = '/';
+ cwd[len] = 0;
+ return cwd + offset;
+}