diff-tree -r -t: include added/removed directories in the output
[gitweb.git] / diff-no-index.c
index 1b57feeb2454b00686b4c1acee8d97e47223be8e..7d68b7f1bef1039b4996e662fb17968c4e3e3e79 100644 (file)
@@ -14,9 +14,9 @@
 #include "revision.h"
 #include "log-tree.h"
 #include "builtin.h"
-#include "path-list.h"
+#include "string-list.h"
 
-static int read_directory(const char *path, struct path_list *list)
+static int read_directory(const char *path, struct string_list *list)
 {
        DIR *dir;
        struct dirent *e;
@@ -26,7 +26,7 @@ static int read_directory(const char *path, struct path_list *list)
 
        while ((e = readdir(dir)))
                if (strcmp(".", e->d_name) && strcmp("..", e->d_name))
-                       path_list_insert(e->d_name, list);
+                       string_list_insert(e->d_name, list);
 
        closedir(dir);
        return 0;
@@ -60,13 +60,13 @@ static int queue_diff(struct diff_options *o,
 
        if (S_ISDIR(mode1) || S_ISDIR(mode2)) {
                char buffer1[PATH_MAX], buffer2[PATH_MAX];
-               struct path_list p1 = {NULL, 0, 0, 1}, p2 = {NULL, 0, 0, 1};
+               struct string_list p1 = {NULL, 0, 0, 1}, p2 = {NULL, 0, 0, 1};
                int len1 = 0, len2 = 0, i1, i2, ret = 0;
 
                if (name1 && read_directory(name1, &p1))
                        return -1;
                if (name2 && read_directory(name2, &p2)) {
-                       path_list_clear(&p1, 0);
+                       string_list_clear(&p1, 0);
                        return -1;
                }
 
@@ -95,14 +95,14 @@ static int queue_diff(struct diff_options *o,
                        else if (i2 == p2.nr)
                                comp = -1;
                        else
-                               comp = strcmp(p1.items[i1].path,
-                                       p2.items[i2].path);
+                               comp = strcmp(p1.items[i1].string,
+                                       p2.items[i2].string);
 
                        if (comp > 0)
                                n1 = NULL;
                        else {
                                n1 = buffer1;
-                               strncpy(buffer1 + len1, p1.items[i1++].path,
+                               strncpy(buffer1 + len1, p1.items[i1++].string,
                                                PATH_MAX - len1);
                        }
 
@@ -110,14 +110,14 @@ static int queue_diff(struct diff_options *o,
                                n2 = NULL;
                        else {
                                n2 = buffer2;
-                               strncpy(buffer2 + len2, p2.items[i2++].path,
+                               strncpy(buffer2 + len2, p2.items[i2++].string,
                                                PATH_MAX - len2);
                        }
 
                        ret = queue_diff(o, n1, n2);
                }
-               path_list_clear(&p1, 0);
-               path_list_clear(&p2, 0);
+               string_list_clear(&p1, 0);
+               string_list_clear(&p2, 0);
 
                return ret;
        } else {
@@ -144,6 +144,25 @@ static int queue_diff(struct diff_options *o,
        }
 }
 
+static int path_outside_repo(const char *path)
+{
+       /*
+        * We have already done setup_git_directory_gently() so we
+        * know we are inside a git work tree already.
+        */
+       const char *work_tree;
+       size_t len;
+
+       if (!is_absolute_path(path))
+               return 0;
+       work_tree = get_git_work_tree();
+       len = strlen(work_tree);
+       if (strncmp(path, work_tree, len) ||
+           (path[len] != '\0' && path[len] != '/'))
+               return 1;
+       return 0;
+}
+
 void diff_no_index(struct rev_info *revs,
                   int argc, const char **argv,
                   int nongit, const char *prefix)
@@ -162,17 +181,30 @@ void diff_no_index(struct rev_info *revs,
                        break;
        }
 
-       /*
-        * No explicit --no-index, but "git diff --opts A B" outside
-        * a git repository is a cute hack to support.
-        */
-       if (!no_index && !nongit)
-               return;
-
+       if (!no_index && !nongit) {
+               /*
+                * Inside a git repository, without --no-index.  Only
+                * when a path outside the repository is given,
+                * e.g. "git diff /var/tmp/[12]", or "git diff
+                * Makefile /var/tmp/Makefile", allow it to be used as
+                * a colourful "diff" replacement.
+                */
+               if ((argc != i + 2) ||
+                   (!path_outside_repo(argv[i]) &&
+                    !path_outside_repo(argv[i+1])))
+                       return;
+       }
        if (argc != i + 2)
                die("git diff %s takes two paths",
                    no_index ? "--no-index" : "[--no-index]");
 
+       /*
+        * 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(&revs->diffopt, EXIT_WITH_STATUS))
+               setup_pager();
+
        diff_setup(&revs->diffopt);
        if (!revs->diffopt.output_format)
                revs->diffopt.output_format = DIFF_FORMAT_PATCH;