merge-recursive: option to specify rename threshold
[gitweb.git] / dir.c
diff --git a/dir.c b/dir.c
index 133c333df61be37e7908f77367f63c85cfc9c548..151ea670d961d39394990f122469557b6f217de3 100644 (file)
--- a/dir.c
+++ b/dir.c
@@ -31,22 +31,22 @@ static int common_prefix(const char **pathspec)
        if (!slash)
                return 0;
 
+       /*
+        * The first 'prefix' characters of 'path' are common leading
+        * path components among the pathspecs we have seen so far,
+        * including the trailing slash.
+        */
        prefix = slash - path + 1;
        while ((next = *++pathspec) != NULL) {
-               int len = strlen(next);
-               if (len >= prefix && !memcmp(path, next, prefix))
+               int len, last_matching_slash = -1;
+               for (len = 0; len < prefix && next[len] == path[len]; len++)
+                       if (next[len] == '/')
+                               last_matching_slash = len;
+               if (len == prefix)
                        continue;
-               len = prefix - 1;
-               for (;;) {
-                       if (!len)
-                               return 0;
-                       if (next[--len] != '/')
-                               continue;
-                       if (memcmp(path, next, len+1))
-                               continue;
-                       prefix = len + 1;
-                       break;
-               }
+               if (last_matching_slash < 0)
+                       return 0;
+               prefix = last_matching_slash + 1;
        }
        return prefix;
 }
@@ -465,7 +465,7 @@ static struct dir_entry *dir_add_ignored(struct dir_struct *dir, const char *pat
 enum exist_status {
        index_nonexistent = 0,
        index_directory,
-       index_gitdir,
+       index_gitdir
 };
 
 /*
@@ -533,7 +533,7 @@ static enum exist_status directory_exists_in_index(const char *dirname, int len)
 enum directory_treatment {
        show_directory,
        ignore_directory,
-       recurse_into_directory,
+       recurse_into_directory
 };
 
 static enum directory_treatment treat_directory(struct dir_struct *dir,
@@ -594,13 +594,29 @@ static int simplify_away(const char *path, int pathlen, const struct path_simpli
        return 0;
 }
 
-static int in_pathspec(const char *path, int len, const struct path_simplify *simplify)
+/*
+ * This function tells us whether an excluded path matches a
+ * list of "interesting" pathspecs. That is, whether a path matched
+ * by any of the pathspecs could possibly be ignored by excluding
+ * the specified path. This can happen if:
+ *
+ *   1. the path is mentioned explicitly in the pathspec
+ *
+ *   2. the path is a directory prefix of some element in the
+ *      pathspec
+ */
+static int exclude_matches_pathspec(const char *path, int len,
+               const struct path_simplify *simplify)
 {
        if (simplify) {
                for (; simplify->path; simplify++) {
                        if (len == simplify->len
                            && !memcmp(path, simplify->path, len))
                                return 1;
+                       if (len < simplify->len
+                           && simplify->path[len] == '/'
+                           && !memcmp(path, simplify->path, len))
+                               return 1;
                }
        }
        return 0;
@@ -668,7 +684,7 @@ static int get_dtype(struct dirent *de, const char *path, int len)
 enum path_treatment {
        path_ignored,
        path_handled,
-       path_recurse,
+       path_recurse
 };
 
 static enum path_treatment treat_one_path(struct dir_struct *dir,
@@ -678,7 +694,7 @@ static enum path_treatment treat_one_path(struct dir_struct *dir,
 {
        int exclude = excluded(dir, path, &dtype);
        if (exclude && (dir->flags & DIR_COLLECT_IGNORED)
-           && in_pathspec(path, *len, simplify))
+           && exclude_matches_pathspec(path, *len, simplify))
                dir_add_ignored(dir, path, *len);
 
        /*
@@ -942,9 +958,14 @@ char *get_relative_cwd(char *buffer, int size, const char *dir)
        }
        if (*dir)
                return NULL;
-       if (*cwd == '/')
+       switch (*cwd) {
+       case '\0':
+               return cwd;
+       case '/':
                return cwd + 1;
-       return cwd;
+       default:
+               return NULL;
+       }
 }
 
 int is_inside_dir(const char *dir)