Code

Merge branch 'maint'
[git.git] / builtin-apply.c
index b3fc290ff33e6388b25b6cb046ad97856d81169d..e2c611bf964d8cd589171f74e5ccce5aeb392643 100644 (file)
@@ -12,7 +12,8 @@
 #include "blob.h"
 #include "delta.h"
 #include "builtin.h"
-#include "path-list.h"
+#include "string-list.h"
+#include "dir.h"
 
 /*
  *  --check turns on checking that the working tree matches the
@@ -46,7 +47,7 @@ static const char *fake_ancestor;
 static int line_termination = '\n';
 static unsigned long p_context = ULONG_MAX;
 static const char apply_usage[] =
-"git-apply [--stat] [--numstat] [--summary] [--check] [--index] [--cached] [--apply] [--no-add] [--index-info] [--allow-binary-replacement] [--reverse] [--reject] [--verbose] [-z] [-pNUM] [-CNUM] [--whitespace=<nowarn|warn|fix|error|error-all>] <patch>...";
+"git apply [--stat] [--numstat] [--summary] [--check] [--index] [--cached] [--apply] [--no-add] [--index-info] [--allow-binary-replacement] [--reverse] [--reject] [--verbose] [-z] [-pNUM] [-CNUM] [--whitespace=<nowarn|warn|fix|error|error-all>] <patch>...";
 
 static enum ws_error_action {
        nowarn_ws_error,
@@ -194,7 +195,7 @@ struct image {
  * the case where more than one patches touch the same file.
  */
 
-static struct path_list fn_table;
+static struct string_list fn_table;
 
 static uint32_t hash_line(const char *cp, size_t len)
 {
@@ -274,7 +275,7 @@ static void say_patch_name(FILE *output, const char *pre,
 static void read_patch_file(struct strbuf *sb, int fd)
 {
        if (strbuf_read(sb, fd, 0) < 0)
-               die("git-apply: read returned %s", strerror(errno));
+               die("git apply: read returned %s", strerror(errno));
 
        /*
         * Make sure that we have some slop in the buffer
@@ -506,17 +507,17 @@ static char *gitdiff_verify_name(const char *line, int isnull, char *orig_name,
                name = orig_name;
                len = strlen(name);
                if (isnull)
-                       die("git-apply: bad git-diff - expected /dev/null, got %s on line %d", name, linenr);
+                       die("git apply: bad git-diff - expected /dev/null, got %s on line %d", name, linenr);
                another = find_name(line, NULL, p_value, TERM_TAB);
                if (!another || memcmp(another, name, len))
-                       die("git-apply: bad git-diff - inconsistent %s filename on line %d", oldnew, linenr);
+                       die("git apply: bad git-diff - inconsistent %s filename on line %d", oldnew, linenr);
                free(another);
                return orig_name;
        }
        else {
                /* expect "/dev/null" */
                if (memcmp("/dev/null", line, 9) || line[9] != '\n')
-                       die("git-apply: bad git-diff - expected /dev/null on line %d", linenr);
+                       die("git apply: bad git-diff - expected /dev/null on line %d", linenr);
                return NULL;
        }
 }
@@ -1996,6 +1997,8 @@ static int apply_one_fragment(struct image *img, struct fragment *frag,
        /*
         * A hunk to change lines at the beginning would begin with
         * @@ -1,L +N,M @@
+        * but we need to be careful.  -U0 that inserts before the second
+        * line also has this pattern.
         *
         * And a hunk to add to an empty file would begin with
         * @@ -0,0 +N,M @@
@@ -2003,7 +2006,8 @@ static int apply_one_fragment(struct image *img, struct fragment *frag,
         * In other words, a hunk that is (frag->oldpos <= 1) with or
         * without leading context must match at the beginning.
         */
-       match_beginning = frag->oldpos <= 1;
+       match_beginning = (!frag->oldpos ||
+                          (frag->oldpos == 1 && !unidiff_zero));
 
        /*
         * A hunk without trailing lines must match at the end.
@@ -2250,12 +2254,12 @@ static int read_file_or_gitlink(struct cache_entry *ce, struct strbuf *buf)
 
 static struct patch *in_fn_table(const char *name)
 {
-       struct path_list_item *item;
+       struct string_list_item *item;
 
        if (name == NULL)
                return NULL;
 
-       item = path_list_lookup(name, &fn_table);
+       item = string_list_lookup(name, &fn_table);
        if (item != NULL)
                return (struct patch *)item->util;
 
@@ -2264,7 +2268,7 @@ static struct patch *in_fn_table(const char *name)
 
 static void add_to_fn_table(struct patch *patch)
 {
-       struct path_list_item *item;
+       struct string_list_item *item;
 
        /*
         * Always add new_name unless patch is a deletion
@@ -2272,7 +2276,7 @@ static void add_to_fn_table(struct patch *patch)
         * file creations and copies
         */
        if (patch->new_name != NULL) {
-               item = path_list_insert(patch->new_name, &fn_table);
+               item = string_list_insert(patch->new_name, &fn_table);
                item->util = patch;
        }
 
@@ -2281,7 +2285,7 @@ static void add_to_fn_table(struct patch *patch)
         * later chunks shouldn't patch old names
         */
        if ((patch->new_name == NULL) || (patch->is_rename)) {
-               item = path_list_insert(patch->old_name, &fn_table);
+               item = string_list_insert(patch->old_name, &fn_table);
                item->util = (struct patch *) -1;
        }
 }
@@ -2296,7 +2300,8 @@ static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *
 
        strbuf_init(&buf, 0);
 
-       if ((tpatch = in_fn_table(patch->old_name)) != NULL) {
+       if (!(patch->is_copy || patch->is_rename) &&
+           ((tpatch = in_fn_table(patch->old_name)) != NULL)) {
                if (tpatch == (struct patch *) -1) {
                        return error("patch %s has been renamed/deleted",
                                patch->old_name);
@@ -2375,7 +2380,7 @@ static int verify_index_match(struct cache_entry *ce, struct stat *st)
 static int check_preimage(struct patch *patch, struct cache_entry **ce, struct stat *st)
 {
        const char *old_name = patch->old_name;
-       struct patch *tpatch;
+       struct patch *tpatch = NULL;
        int stat_ret = 0;
        unsigned st_mode = 0;
 
@@ -2389,7 +2394,9 @@ static int check_preimage(struct patch *patch, struct cache_entry **ce, struct s
                return 0;
 
        assert(patch->is_new <= 0);
-       if ((tpatch = in_fn_table(old_name)) != NULL) {
+
+       if (!(patch->is_copy || patch->is_rename) &&
+           (tpatch = in_fn_table(old_name)) != NULL) {
                if (tpatch == (struct patch *) -1) {
                        return error("%s: has been deleted/renamed", old_name);
                }
@@ -2399,6 +2406,7 @@ static int check_preimage(struct patch *patch, struct cache_entry **ce, struct s
                if (stat_ret && errno != ENOENT)
                        return error("%s: %s", old_name, strerror(errno));
        }
+
        if (check_index && !tpatch) {
                int pos = cache_name_pos(old_name, strlen(old_name));
                if (pos < 0) {
@@ -2728,15 +2736,7 @@ static void remove_file(struct patch *patch, int rmdir_empty)
                                warning("unable to remove submodule %s",
                                        patch->old_name);
                } else if (!unlink(patch->old_name) && rmdir_empty) {
-                       char *name = xstrdup(patch->old_name);
-                       char *end = strrchr(name, '/');
-                       while (end) {
-                               *end = 0;
-                               if (rmdir(name))
-                                       break;
-                               end = strrchr(name, '/');
-                       }
-                       free(name);
+                       remove_path(patch->old_name);
                }
        }
 }
@@ -2987,29 +2987,45 @@ static int write_out_results(struct patch *list, int skipped_patch)
 
 static struct lock_file lock_file;
 
-static struct excludes {
-       struct excludes *next;
-       const char *path;
-} *excludes;
+static struct string_list limit_by_name;
+static int has_include;
+static void add_name_limit(const char *name, int exclude)
+{
+       struct string_list_item *it;
+
+       it = string_list_append(name, &limit_by_name);
+       it->util = exclude ? NULL : (void *) 1;
+}
 
 static int use_patch(struct patch *p)
 {
        const char *pathname = p->new_name ? p->new_name : p->old_name;
-       struct excludes *x = excludes;
-       while (x) {
-               if (fnmatch(x->path, pathname, 0) == 0)
-                       return 0;
-               x = x->next;
-       }
+       int i;
+
+       /* Paths outside are not touched regardless of "--include" */
        if (0 < prefix_length) {
                int pathlen = strlen(pathname);
                if (pathlen <= prefix_length ||
                    memcmp(prefix, pathname, prefix_length))
                        return 0;
        }
-       return 1;
+
+       /* See if it matches any of exclude/include rule */
+       for (i = 0; i < limit_by_name.nr; i++) {
+               struct string_list_item *it = &limit_by_name.items[i];
+               if (!fnmatch(it->string, pathname, 0))
+                       return (it->util != NULL);
+       }
+
+       /*
+        * If we had any include, a path that does not match any rule is
+        * not used.  Otherwise, we saw bunch of exclude rules (or none)
+        * and such a path is used.
+        */
+       return !has_include;
 }
 
+
 static void prefix_one(char **name)
 {
        char *old_name = *name;
@@ -3047,7 +3063,7 @@ static int apply_patch(int fd, const char *filename, int options)
        int skipped_patch = 0;
 
        /* FIXME - memory leak when using multiple patch files as inputs */
-       memset(&fn_table, 0, sizeof(struct path_list));
+       memset(&fn_table, 0, sizeof(struct string_list));
        strbuf_init(&buf, 0);
        patch_input_file = filename;
        read_patch_file(&buf, fd);
@@ -3150,10 +3166,12 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix)
                        continue;
                }
                if (!prefixcmp(arg, "--exclude=")) {
-                       struct excludes *x = xmalloc(sizeof(*x));
-                       x->path = arg + 10;
-                       x->next = excludes;
-                       excludes = x;
+                       add_name_limit(arg + 10, 1);
+                       continue;
+               }
+               if (!prefixcmp(arg, "--include=")) {
+                       add_name_limit(arg + 10, 0);
+                       has_include = 1;
                        continue;
                }
                if (!prefixcmp(arg, "-p")) {