summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJunio C Hamano <junkio@cox.net>2007-02-22 00:05:56 (GMT)
committerJunio C Hamano <junkio@cox.net>2007-02-22 00:05:56 (GMT)
commit3e8a5db966c26a0a986161103d59683b909a6c78 (patch)
tree3a0df292e42e49cec2e49f04b29450473e8e4975
parent9987d7c58a847ab1605ae3216ff1ca95b19f0ad1 (diff)
downloadgit-3e8a5db966c26a0a986161103d59683b909a6c78.zip
git-3e8a5db966c26a0a986161103d59683b909a6c78.tar.gz
git-3e8a5db966c26a0a986161103d59683b909a6c78.tar.bz2
git-apply: guess correct -p<n> value for non-git patches.
This enhances the third point in the previous commit. When applying a non-git patch that begins like this: --- 2.6.orig/mm/slab.c +++ 2.6/mm/slab.c @@ -N,M +L,K @@@ ... and if you are in 'mm' subdirectory, we notice that -p2 is the right option to use to apply the patch in file slab.c in the current directory (i.e. mm/slab.c) The guess function also knows about this pattern, where you would need to use -p0 if applying from the top-level: --- mm/slab.c +++ mm/slab.c @@ -N,M +L,K @@@ ... Signed-off-by: Junio C Hamano <junkio@cox.net>
-rw-r--r--builtin-apply.c59
-rwxr-xr-xt/t4119-apply-config.sh56
2 files changed, 111 insertions, 4 deletions
diff --git a/builtin-apply.c b/builtin-apply.c
index 12f00e3..c7d4bdd 100644
--- a/builtin-apply.c
+++ b/builtin-apply.c
@@ -28,6 +28,7 @@ static int newfd = -1;
static int unidiff_zero;
static int p_value = 1;
+static int p_value_known;
static int check_index;
static int write_index;
static int cached;
@@ -312,11 +313,54 @@ static char *find_name(const char *line, char *def, int p_value, int terminate)
return name;
}
+static int count_slashes(const char *cp)
+{
+ int cnt = 0;
+ char ch;
+
+ while ((ch = *cp++))
+ if (ch == '/')
+ cnt++;
+ return cnt;
+}
+
+/*
+ * Given the string after "--- " or "+++ ", guess the appropriate
+ * p_value for the given patch.
+ */
+static int guess_p_value(const char *nameline)
+{
+ char *name, *cp;
+ int val = -1;
+
+ if (is_dev_null(nameline))
+ return -1;
+ name = find_name(nameline, NULL, 0, TERM_SPACE | TERM_TAB);
+ if (!name)
+ return -1;
+ cp = strchr(name, '/');
+ if (!cp)
+ val = 0;
+ else if (prefix) {
+ /*
+ * Does it begin with "a/$our-prefix" and such? Then this is
+ * very likely to apply to our directory.
+ */
+ if (!strncmp(name, prefix, prefix_length))
+ val = count_slashes(prefix);
+ else {
+ cp++;
+ if (!strncmp(cp, prefix, prefix_length))
+ val = count_slashes(prefix) + 1;
+ }
+ }
+ free(name);
+ return val;
+}
+
/*
* Get the name etc info from the --/+++ lines of a traditional patch header
*
- * NOTE! This hardcodes "-p1" behaviour in filename detection.
- *
* FIXME! The end-of-filename heuristics are kind of screwy. For existing
* files, we can happily check the index for a match, but for creating a
* new file we should try to match whatever "patch" does. I have no idea.
@@ -327,6 +371,16 @@ static void parse_traditional_patch(const char *first, const char *second, struc
first += 4; /* skip "--- " */
second += 4; /* skip "+++ " */
+ if (!p_value_known) {
+ int p, q;
+ p = guess_p_value(first);
+ q = guess_p_value(second);
+ if (p < 0) p = q;
+ if (0 <= p && p == q) {
+ p_value = p;
+ p_value_known = 1;
+ }
+ }
if (is_dev_null(first)) {
patch->is_new = 1;
patch->is_delete = 0;
@@ -2656,6 +2710,7 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix)
}
if (!strncmp(arg, "-p", 2)) {
p_value = atoi(arg + 2);
+ p_value_known = 1;
continue;
}
if (!strcmp(arg, "--no-add")) {
diff --git a/t/t4119-apply-config.sh b/t/t4119-apply-config.sh
index 32e0d71..55f4673 100755
--- a/t/t4119-apply-config.sh
+++ b/t/t4119-apply-config.sh
@@ -19,7 +19,7 @@ test_expect_success setup '
'
# Also handcraft GNU diff output; note this has trailing whitespace.
-cat >gpatch.file <<\EOF
+cat >gpatch.file <<\EOF &&
--- file1 2007-02-21 01:04:24.000000000 -0800
+++ file1+ 2007-02-21 01:07:44.000000000 -0800
@@ -1 +1 @@
@@ -27,6 +27,12 @@ cat >gpatch.file <<\EOF
+B
EOF
+sed -e 's|file1|sub/&|' gpatch.file >gpatch-sub.file &&
+sed -e '
+ /^--- /s|file1|a/sub/&|
+ /^+++ /s|file1|b/sub/&|
+' gpatch.file >gpatch-ab-sub.file &&
+
test_expect_success 'apply --whitespace=strip' '
rm -f sub/file1 &&
@@ -124,7 +130,53 @@ test_expect_success 'same in subdir but with traditional patch input' '
git update-index --refresh &&
cd sub &&
- git apply -p0 ../gpatch.file &&
+ git apply ../gpatch.file &&
+ if grep " " file1
+ then
+ echo "Eh?"
+ false
+ elif grep B file1
+ then
+ echo Happy
+ else
+ echo "Huh?"
+ false
+ fi
+'
+
+test_expect_success 'same but with traditional patch input of depth 1' '
+
+ cd "$D" &&
+ git config apply.whitespace strip &&
+ rm -f sub/file1 &&
+ cp saved sub/file1 &&
+ git update-index --refresh &&
+
+ cd sub &&
+ git apply ../gpatch-sub.file &&
+ if grep " " file1
+ then
+ echo "Eh?"
+ false
+ elif grep B file1
+ then
+ echo Happy
+ else
+ echo "Huh?"
+ false
+ fi
+'
+
+test_expect_success 'same but with traditional patch input of depth 2' '
+
+ cd "$D" &&
+ git config apply.whitespace strip &&
+ rm -f sub/file1 &&
+ cp saved sub/file1 &&
+ git update-index --refresh &&
+
+ cd sub &&
+ git apply ../gpatch-ab-sub.file &&
if grep " " file1
then
echo "Eh?"