git-apply: notice "diff --git" patch again
authorJunio C Hamano <junkio@cox.net>
Wed, 21 Feb 2007 22:31:10 +0000 (14:31 -0800)
committerJunio C Hamano <junkio@cox.net>
Wed, 21 Feb 2007 22:42:15 +0000 (14:42 -0800)
Earlier one that tried to be too consistent with GNU patch by
not stripping the leading path when we _know_ we are in a
subdirectory and the patch is relative to the toplevel was a
mistake.  This fixes it.

 - No change to behaviour when it is run from the toplevel of
   the repository.

 - When run from a subdirectory to apply a git-generated patch,
   it uses the right -p<n> value automatically, with or without
   --index nor --cached option.

 - When run from a subdirectory to apply a randomly generated
   patch, it wants the right -p<n> value to be given by the
   user.

The second one is a pure improvement to correct inconsistency
between --index and non --index case, compared with 1.5.0.  The
third point could be further improved to guess what the right
value for -p<n> should be by looking at the patch, but should be
a topic of a separate patch.

Signed-off-by: Junio C Hamano <junkio@cox.net>
builtin-apply.c
t/t4119-apply-config.sh

index 1beebe5..12f00e3 100644 (file)
@@ -144,6 +144,7 @@ struct patch {
        unsigned long deflate_origlen;
        int lines_added, lines_deleted;
        int score;
+       unsigned int is_toplevel_relative:1;
        unsigned int inaccurate_eof:1;
        unsigned int is_binary:1;
        unsigned int is_copy:1;
@@ -362,7 +363,7 @@ static int gitdiff_hdrend(const char *line, struct patch *patch)
 static char *gitdiff_verify_name(const char *line, int isnull, char *orig_name, const char *oldnew)
 {
        if (!orig_name && !isnull)
-               return find_name(line, NULL, p_value, TERM_TAB);
+               return find_name(line, NULL, 1, TERM_TAB);
 
        if (orig_name) {
                int len;
@@ -372,7 +373,7 @@ static char *gitdiff_verify_name(const char *line, int isnull, char *orig_name,
                len = strlen(name);
                if (isnull)
                        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);
+               another = find_name(line, NULL, 1, TERM_TAB);
                if (!another || memcmp(another, name, len))
                        die("git-apply: bad git-diff - inconsistent %s filename on line %d", oldnew, linenr);
                free(another);
@@ -427,28 +428,28 @@ static int gitdiff_newfile(const char *line, struct patch *patch)
 static int gitdiff_copysrc(const char *line, struct patch *patch)
 {
        patch->is_copy = 1;
-       patch->old_name = find_name(line, NULL, p_value-1, 0);
+       patch->old_name = find_name(line, NULL, 0, 0);
        return 0;
 }
 
 static int gitdiff_copydst(const char *line, struct patch *patch)
 {
        patch->is_copy = 1;
-       patch->new_name = find_name(line, NULL, p_value-1, 0);
+       patch->new_name = find_name(line, NULL, 0, 0);
        return 0;
 }
 
 static int gitdiff_renamesrc(const char *line, struct patch *patch)
 {
        patch->is_rename = 1;
-       patch->old_name = find_name(line, NULL, p_value-1, 0);
+       patch->old_name = find_name(line, NULL, 0, 0);
        return 0;
 }
 
 static int gitdiff_renamedst(const char *line, struct patch *patch)
 {
        patch->is_rename = 1;
-       patch->new_name = find_name(line, NULL, p_value-1, 0);
+       patch->new_name = find_name(line, NULL, 0, 0);
        return 0;
 }
 
@@ -787,6 +788,7 @@ static int find_header(char *line, unsigned long size, int *hdrsize, struct patc
 {
        unsigned long offset, len;
 
+       patch->is_toplevel_relative = 0;
        patch->is_rename = patch->is_copy = 0;
        patch->is_new = patch->is_delete = -1;
        patch->old_mode = patch->new_mode = 0;
@@ -831,6 +833,7 @@ static int find_header(char *line, unsigned long size, int *hdrsize, struct patc
                                        die("git diff header lacks filename information (line %d)", linenr);
                                patch->old_name = patch->new_name = patch->def_name;
                        }
+                       patch->is_toplevel_relative = 1;
                        *hdrsize = git_hdr_len;
                        return offset;
                }
@@ -2499,6 +2502,12 @@ static int use_patch(struct patch *p)
                        return 0;
                x = x->next;
        }
+       if (0 < prefix_length) {
+               int pathlen = strlen(pathname);
+               if (pathlen <= prefix_length ||
+                   memcmp(prefix, pathname, prefix_length))
+                       return 0;
+       }
        return 1;
 }
 
@@ -2513,7 +2522,7 @@ static void prefix_one(char **name)
 
 static void prefix_patches(struct patch *p)
 {
-       if (!prefix)
+       if (!prefix || p->is_toplevel_relative)
                return;
        for ( ; p; p = p->next) {
                if (p->new_name == p->old_name) {
index f9b9425..32e0d71 100755 (executable)
@@ -78,7 +78,7 @@ test_expect_success 'apply --whitespace=strip in subdir' '
        git update-index --refresh &&
 
        cd sub &&
-       git apply --whitespace=strip -p2 ../patch.file &&
+       git apply --whitespace=strip ../patch.file &&
        if grep " " file1
        then
                echo "Eh?"
@@ -101,7 +101,7 @@ test_expect_success 'apply --whitespace=strip from config in subdir' '
        git update-index --refresh &&
 
        cd sub &&
-       git apply -p2 ../patch.file &&
+       git apply ../patch.file &&
        if grep " " file1
        then
                echo "Eh?"