{"thread":{"id":"1692","subject":"[PATCH 2/3] Fix the processing of multiple patch files with --check in git-apply.","startedAt":"2005-08-30T00:01:51Z","lastAt":"2005-09-07T00:54:22Z","messageCount":4,"participants":["Robert Fitzsmons","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":3},"messages":[{"id":"7924","messageId":"11253601111257-git-send-email-robfitz@273k.net","threadId":"1692","inReplyTo":"1125360111916-git-send-email-robfitz@273k.net","subject":"[PATCH 2/3] Fix the processing of multiple patch files with --check in git-apply.","fromName":"Robert Fitzsmons","fromEmail":"robfitz@273k.net","sentAt":"2005-08-30T00:01:51Z","receivedAt":"2005-08-30T00:01:51Z","isPatch":true,"sender":{"key":"robfitz@273k.net","avatar":null},"body":"When the --check option was used with multiple patch files which\nmodify the same files, the patch can fail because the previously\nmodified contents aren't written to the disk.\n\nSo save the in memory patch contents across the processing of multiple\npatch files.  Added a new test case for --check with multiple patch\nfiles.\n\nSigned-off-by: Robert Fitzsimons <robfitz@273k.net>\n\n---\n\n apply.c                |   10 ++++-\n t/t4105-apply-check.sh |   89 ++++++++++++++++++++++++++++++++++++++++++++++++\n 2 files changed, 97 insertions(+), 2 deletions(-)\n create mode 100644 t/t4105-apply-check.sh\n\n797cc1bdcc647b9fb744784969c814145803407d\ndiff --git a/apply.c b/apply.c\n--- a/apply.c\n+++ b/apply.c\n@@ -1439,13 +1439,16 @@ static int use_patch(struct patch *p)\n \treturn 1;\n }\n \n+struct patch *master_list = NULL;\n+struct patch *master_list_prev = NULL;\n+\n static int apply_patch(int fd)\n {\n \tint newfd;\n \tunsigned long offset, size;\n \tchar *buffer = read_patch_file(fd, &size);\n-\tstruct patch *list = NULL, **listp = &list;\n-\tstruct patch *list_prev = NULL;\n+\tstruct patch *list = master_list, **listp = &list;\n+\tstruct patch *list_prev = master_list_prev;\n \tint skipped_patch = 0;\n \n \tif (!buffer)\n@@ -1504,6 +1507,9 @@ static int apply_patch(int fd)\n \tif (summary)\n \t\tsummary_patch_list(list);\n \n+\tmaster_list = list;\n+\tmaster_list_prev = list_prev;\n+\n \tfree(buffer);\n \treturn 0;\n }\ndiff --git a/t/t4105-apply-check.sh b/t/t4105-apply-check.sh\nnew file mode 100644\n--- /dev/null\n+++ b/t/t4105-apply-check.sh\n@@ -0,0 +1,89 @@\n+#!/bin/sh\n+#\n+# Copyright (c) 2005 Junio C Hamano\n+# Copyright (c) 2005 Robert Fitzsimons\n+#\n+\n+test_description='git-apply --check with multiple files.\n+\n+'\n+. ./test-lib.sh\n+\n+# setup\n+\n+cat > patch1.patch <<\\EOF\n+diff --git a/main.c b/main.c\n+new file mode 100644\n+--- /dev/null\n++++ b/main.c\n+@@ -0,0 +1,23 @@\n++#include <stdio.h>\n++\n++void print_int(int num);\n++int func(int num);\n++\n++int main() {\n++\tint i;\n++\n++\tfor (i = 0; i < 10; i++) {\n++\t\tprint_int(func(i));\n++\t}\n++\n++\treturn 0;\n++}\n++\n++int func(int num) {\n++\treturn num * num;\n++}\n++\n++void print_int(int num) {\n++\tprintf(\"%d\", num);\n++}\n++\n+EOF\n+cat > patch2.patch <<\\EOF\n+diff --git a/main.c b/main.c\n+--- a/main.c\n++++ b/main.c\n+@@ -10,6 +10,8 @@\n+ \t\tprint_int(func(i));\n+ \t}\n+ \n++\tprintf(\"\\n\");\n++\n+ \treturn 0;\n+ }\n+ \n+EOF\n+cat > patch3.patch <<\\EOF\n+diff --git a/main.c b/main.c\n+--- a/main.c\n++++ b/main.c\n+@@ -18,6 +20,6 @@\n+ }\n+ \n+ void print_int(int num) {\n+-\tprintf(\"%d\", num);\n++\tprintf(\"%d \", num);\n+ }\n+ \n+EOF\n+\n+test_expect_success \"S = test 1 (files)\" \\\n+    'git-apply patch1.patch patch2.patch patch3.patch'\n+rm -f main.c\n+\n+test_expect_success \"S = test 2 (files --check)\" \\\n+    'git-apply --check patch1.patch patch2.patch patch3.patch'\n+rm -f main.c\n+\n+test_expect_success \"S = test 3 (stdin)\" \\\n+    'cat patch1.patch patch2.patch patch3.patch | git-apply'\n+rm -f main.c\n+\n+test_expect_success \"S = test 4 (stdin --check)\" \\\n+    'cat patch1.patch patch2.patch patch3.patch | git-apply --check'\n+rm -f main.c\n+\n+test_done\n+\n"},{"id":"7926","messageId":"1125360111916-git-send-email-robfitz@273k.net","threadId":"1692","inReplyTo":null,"subject":"[PATCH 1/3] Fix the processing of a patch file which modifies the same file in git-apply.","fromName":"Robert Fitzsmons","fromEmail":"robfitz@273k.net","sentAt":"2005-08-30T00:01:51Z","receivedAt":"2005-08-30T00:01:51Z","isPatch":true,"sender":{"key":"robfitz@273k.net","avatar":null},"body":"A patch file (or stdin) which modifies the same file more then once\nwill fail to apply the patch correctly.  In the worst case it will\napply some of the patch and leave an invalid output file(s).\n\napply.c has been changed to search for previously processed files and\nuse the in memory copy of the data instead of the on disk image.\n\nAdded a series of test cases for the processing of complex single\nfile patches.  The test cases have been updated to not use empty\nfiles.\n\nSigned-off-by: Robert Fitzsimons <robfitz@273k.net>\n\n---\n\n apply.c                  |   64 +++++++++++-\n t/t4104-apply-complex.sh |  241 ++++++++++++++++++++++++++++++++++++++++++++++\n 2 files changed, 300 insertions(+), 5 deletions(-)\n create mode 100644 t/t4104-apply-complex.sh\n\n1c680d2768e248e4df3ef24591b7d53913199885\ndiff --git a/apply.c b/apply.c\n--- a/apply.c\n+++ b/apply.c\n@@ -67,6 +67,7 @@ struct patch {\n \tchar *result;\n \tunsigned long resultsize;\n \tstruct patch *next;\n+\tstruct patch *prev;\n };\n \n #define CHUNKSIZE (8192)\n@@ -974,7 +975,7 @@ static int apply_fragments(struct buffer\n \treturn 0;\n }\n \n-static int apply_data(struct patch *patch, struct stat *st)\n+static int apply_data(struct patch *patch, struct patch *old_patch, struct stat *st)\n {\n \tchar *buf;\n \tunsigned long size, alloc;\n@@ -983,7 +984,13 @@ static int apply_data(struct patch *patc\n \tsize = 0;\n \talloc = 0;\n \tbuf = NULL;\n-\tif (patch->old_name) {\n+\n+\tif (patch->old_name && old_patch) {\n+\t\tsize = old_patch->resultsize;\n+\t\talloc = size + 8192;\n+\t\tbuf = xmalloc(alloc);\n+\t\tmemcpy(buf, old_patch->result, size);\n+\t} else if (patch->old_name) {\n \t\tsize = st->st_size;\n \t\talloc = size + 8192;\n \t\tbuf = xmalloc(alloc);\n@@ -1010,8 +1017,46 @@ static int check_patch(struct patch *pat\n \tstruct stat st;\n \tconst char *old_name = patch->old_name;\n \tconst char *new_name = patch->new_name;\n+\tstruct patch *old_patch = NULL;\n+\tstruct patch *new_patch = NULL;\n \n \tif (old_name) {\n+\t\tfor (old_patch = patch->prev; old_patch; old_patch = old_patch->prev) {\n+\t\t\tif (old_patch->new_name && !strcmp(old_name, old_patch->new_name)) {\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\tif (old_patch->old_name && !strcmp(old_name, old_patch->old_name)) {\n+\t\t\t\tif (old_patch->is_delete || old_patch->is_rename) {\n+\t\t\t\t\treturn error(\"%s: file missing because of previous patch\", old_name);\n+\t\t\t\t}\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\tif (new_name) {\n+\t\tfor (new_patch = patch->prev; new_patch; new_patch = new_patch->prev) {\n+\t\t\tif (new_patch->new_name && !strcmp(new_name, new_patch->new_name)) {\n+\t\t\t\tif (patch->is_new || patch->is_rename || patch->is_copy)\n+\t\t\t\t\treturn error(\"%s: file exists from previous patch (new)\", new_name);\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\tif (new_patch->old_name && !strcmp(new_name, new_patch->old_name)) {\n+\t\t\t\tif (!(patch->is_new || patch->is_delete || patch->is_rename || patch->is_copy))\n+\t\t\t\t\tbreak;\n+\t\t\t\tif (new_patch->is_delete || new_patch->is_rename)\n+\t\t\t\t\tbreak;\n+\t\t\t\treturn error(\"%s: file exists from previous patch (old)\", new_name);\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\tif (old_patch) {\n+\t\tif (patch->is_new < 0)\n+\t\t\tpatch->is_new = 0;\n+\t\tif (!patch->old_mode)\n+\t\t\tpatch->old_mode = old_patch->new_mode;\n+\t} else if (old_name) {\n \t\tint changed;\n \n \t\tif (lstat(old_name, &st) < 0)\n@@ -1036,7 +1081,14 @@ static int check_patch(struct patch *pat\n \t\t\t\told_name, st.st_mode, patch->old_mode);\n \t}\n \n-\tif (new_name && (patch->is_new | patch->is_rename | patch->is_copy)) {\n+\tif (new_patch) {\n+\t\tif (!patch->new_mode) {\n+\t\t\tif (patch->is_new)\n+\t\t\t\tpatch->new_mode = S_IFREG | 0644;\n+\t\t\telse\n+\t\t\t\tpatch->new_mode = patch->old_mode;\n+\t\t}\n+\t} else if (new_name && (patch->is_new | patch->is_rename | patch->is_copy)) {\n \t\tif (check_index && cache_name_pos(new_name, strlen(new_name)) >= 0)\n \t\t\treturn error(\"%s: already exists in index\", new_name);\n \t\tif (!lstat(new_name, &st))\n@@ -1061,7 +1113,7 @@ static int check_patch(struct patch *pat\n \t\t\t\tsame ? \"\" : \" of \", same ? \"\" : old_name);\n \t}\t\n \n-\tif (apply_data(patch, &st) < 0)\n+\tif (apply_data(patch, old_patch, &st) < 0)\n \t\treturn error(\"%s: patch does not apply\", old_name);\n \treturn 0;\n }\n@@ -1393,6 +1445,7 @@ static int apply_patch(int fd)\n \tunsigned long offset, size;\n \tchar *buffer = read_patch_file(fd, &size);\n \tstruct patch *list = NULL, **listp = &list;\n+\tstruct patch *list_prev = NULL;\n \tint skipped_patch = 0;\n \n \tif (!buffer)\n@@ -1409,7 +1462,8 @@ static int apply_patch(int fd)\n \t\t\tbreak;\n \t\tif (use_patch(patch)) {\n \t\t\tpatch_stats(patch);\n-\t\t\t*listp = patch;\n+\t\t\tpatch->prev = list_prev;\n+\t\t\tlist_prev = *listp = patch;\n \t\t\tlistp = &patch->next;\n \t\t} else {\n \t\t\t/* perhaps free it a bit better? */\ndiff --git a/t/t4104-apply-complex.sh b/t/t4104-apply-complex.sh\nnew file mode 100644\n--- /dev/null\n+++ b/t/t4104-apply-complex.sh\n@@ -0,0 +1,241 @@\n+#!/bin/sh\n+#\n+# Copyright (c) 2005 Junio C Hamano\n+# Copyright (c) 2005 Robert Fitzsimons\n+#\n+\n+test_description='git-apply complex patches.\n+\n+'\n+. ./test-lib.sh\n+\n+# setup\n+\n+# Nx, new file x.txt\n+# Dx, delete file x.txt\n+# Rxy, rename x.txt to y.txt\n+# Cxy, copy x.txt to y.txt\n+# Px1, patch x.txt with patch number 1\n+# etc\n+\n+cat > Nx <<\\EOF\n+diff --git a/x.txt b/x.txt\n+new file mode 100644\n+--- /dev/null\n++++ b/x.txt\n+@@ -0,0 +1 @@\n++XYZ\n+EOF\n+cat > Ny <<\\EOF\n+diff --git a/y.txt b/y.txt\n+new file mode 100644\n+--- /dev/null\n++++ b/y.txt\n+@@ -0,0 +1 @@\n++XYZ\n+EOF\n+cat > Rxy <<\\EOF\n+diff --git a/x.txt b/y.txt\n+rename from x.txt\n+rename to y.txt\n+--- a/x.txt\n++++ b/y.txt\n+EOF\n+cat > Ryx <<\\EOF\n+diff --git a/y.txt b/x.txt\n+rename from y.txt\n+rename to x.txt\n+--- a/y.txt\n++++ b/x.txt\n+EOF\n+cat > Cxy <<\\EOF\n+diff --git a/x.txt b/y.txt\n+copy from x.txt\n+copy to y.txt\n+--- a/x.txt\n++++ b/y.txt\n+EOF\n+cat > Cyx <<\\EOF\n+diff --git a/y.txt b/x.txt\n+copy from y.txt\n+copy to x.txt\n+--- a/y.txt\n++++ b/x.txt\n+EOF\n+cat > Dx <<\\EOF\n+diff --git a/x.txt b/x.txt\n+deleted file mode 100644\n+--- a/x.txt\n++++ /dev/null\n+@@ -1 +0,0 @@\n+-XYZ\n+EOF\n+cat > Dy <<\\EOF\n+diff --git a/y.txt b/y.txt\n+deleted file mode 100644\n+--- a/y.txt\n++++ /dev/null\n+@@ -1 +0,0 @@\n+-XYZ\n+EOF\n+cat > Px1 <<\\EOF\n+diff --git a/x.txt b/x.txt\n+--- a/x.txt\n++++ b/x.txt\n+@@ -1 +1,2 @@\n+ XYZ\n++XXX\n+EOF\n+cat > Px2 <<\\EOF\n+diff --git a/x.txt b/x.txt\n+--- a/x.txt\n++++ b/x.txt\n+@@ -1,2 +1,3 @@\n+ XYZ\n+ XXX\n++XX\n+EOF\n+cat > Px3 <<\\EOF\n+diff --git a/x.txt b/x.txt\n+--- a/x.txt\n++++ b/x.txt\n+@@ -1,3 +1,2 @@\n+ XYZ\n+ XXX\n+-XX\n+EOF\n+cat > Px4 <<\\EOF\n+diff --git a/x.txt b/x.txt\n+--- a/x.txt\n++++ b/x.txt\n+@@ -1,2 +1 @@\n+ XYZ\n+-XXX\n+EOF\n+\n+test_expect_success \"S = Nx Cxy Dx Dy Ny Ryx Cxy Dx Dy (files)\" \\\n+    'git-apply Nx Cxy Dx Dy Ny Ryx Cxy Dx Dy'\n+rm -f x.txt y.txt\n+\n+test_expect_success \"S = Nx Cxy Dx Dy Ny Ryx Cxy Dx Dy (stdin)\" \\\n+    'cat Nx Cxy Dx Dy Ny Ryx Cxy Dx Dy | git-apply -'\n+rm -f x.txt y.txt\n+\n+test_expect_success \"S = Nx\" \\\n+    'cat Nx | git-apply -'\n+rm -f x.txt y.txt\n+\n+test_expect_success \"S = Nx Dx\" \\\n+    'cat Nx Dx | git-apply -'\n+rm -f x.txt y.txt\n+\n+test_expect_success \"S = Nx Px1\" \\\n+    'cat Nx Px1 | git-apply -'\n+rm -f x.txt y.txt\n+\n+test_expect_success \"S = Nx Px1 Px2\" \\\n+    'cat Nx Px1 Px2 | git-apply -'\n+rm -f x.txt y.txt\n+\n+test_expect_success \"S = Nx Px1 Px2 Px3\" \\\n+    'cat Nx Px1 Px2 Px3 | git-apply -'\n+rm -f x.txt y.txt\n+\n+test_expect_success \"S = Nx Px1 Px2 Px3 Px4\" \\\n+    'cat Nx Px1 Px2 Px3 Px4 | git-apply -'\n+rm -f x.txt y.txt\n+\n+test_expect_success \"S = Nx Px1 Px2 Px3 Px4 Dx\" \\\n+    'cat Nx Px1 Px2 Px3 Px4 Dx | git-apply -'\n+rm -f x.txt y.txt\n+\n+test_expect_success \"S = Nx Rxy\" \\\n+    'cat Nx Rxy | git-apply -'\n+rm -f x.txt y.txt\n+\n+test_expect_success \"S = Nx Rxy Dy\" \\\n+    'cat Nx Rxy Dy| git-apply -'\n+rm -f x.txt y.txt\n+\n+test_expect_success \"S = Nx Cxy\" \\\n+    'cat Nx Cxy | git-apply -'\n+rm -f x.txt y.txt\n+\n+test_expect_success \"S = Nx Rxy Dx Dy\" \\\n+    'cat Nx Cxy Dx Dy | git-apply -'\n+rm -f x.txt y.txt\n+\n+test_expect_success \"S = Ny Ryx Px1 Px2 Cxy Px3 Px4 Dx\" \\\n+    'cat Ny Ryx Px1 Px2 Cxy Px3 Px4 Dx | git-apply -'\n+rm -f x.txt y.txt\n+\n+test_expect_success \"S = Ny Ryx Px1 Px2 Cxy Px3 Px4 Dx Cyx\" \\\n+    'cat Ny Ryx Px1 Px2 Cxy Px3 Px4 Dx Cyx | git-apply -'\n+rm -f x.txt y.txt\n+\n+test_expect_success \"S = Ny Cyx Px1 Px2 Px3 Px4 Dy Cxy Dx Cyx Dy Rxy Dy\" \\\n+    'cat Ny Cyx Px1 Px2 Px3 Px4 Dy Cxy Dx Cyx Dy Rxy Dy | git-apply -'\n+rm -f x.txt y.txt\n+\n+test_expect_failure \"F = Dx\" \\\n+    'cat Dx | git-apply -'\n+rm -f x.txt y.txt\n+\n+test_expect_failure \"F = Rxy\" \\\n+    'cat Rxy | git-apply -'\n+rm -f x.txt y.txt\n+\n+test_expect_failure \"F = Cxy\" \\\n+    'cat Cxy | git-apply -'\n+rm -f x.txt y.txt\n+\n+test_expect_failure \"F = Nx Dx Dx\" \\\n+    'cat Nx Dx Dx | git-apply -'\n+rm -f x.txt y.txt\n+\n+test_expect_failure \"F = Nx Ny Rxy\" \\\n+    'cat Nx Ny Rxy | git-apply -'\n+rm -f x.txt y.txt\n+\n+test_expect_failure \"F = Ny Rxy\" \\\n+    'cat Ny Rxy | git-apply -'\n+rm -f x.txt y.txt\n+\n+test_expect_failure \"F = Nx Ny Cxy\" \\\n+    'cat Nx Ny Cxy | git-apply -'\n+rm -f x.txt y.txt\n+\n+test_expect_failure \"F = Ny Cxy\" \\\n+    'cat Ny Cxy | git-apply -'\n+rm -f x.txt y.txt\n+\n+test_expect_failure \"F = Nx Cxy Cxy\" \\\n+    'cat Nx Cxy Cxy | git-apply -'\n+rm -f x.txt y.txt\n+\n+test_expect_failure \"F = Nx Cxy Cyx\" \\\n+    'cat Nx Cxy Cyx | git-apply -'\n+rm -f x.txt y.txt\n+\n+test_expect_failure \"F = Nx Rxy Rxy\" \\\n+    'cat Nx Rxy Rxy | git-apply -'\n+rm -f x.txt y.txt\n+\n+test_expect_failure \"F = Nx Rxy Cxy\" \\\n+    'cat Nx Rxy Cxy | git-apply -'\n+rm -f x.txt y.txt\n+\n+test_expect_failure \"F = Ny Ryx Px1 Px2 Px3 Dx Cyx Px2\" \\\n+    'cat Ny Ryx Px1 Px2 Px3 Dx Cyx Px2 | git-apply -'\n+rm -f x.txt y.txt\n+\n+test_expect_success \"S = Nx Cxy Dx Cyx Dy Rxy Dy Nx Ny Dx Ryx Cxy Dx Dy Nx Rxy Dy Nx Cxy Dy Dx (--check)\" \\\n+    'cat Nx Cxy Dx Cyx Dy Rxy Dy Nx Ny Dx Ryx Cxy Dx Dy Nx Rxy Dy Nx Cxy Dy Dx | git-apply --check -'\n+rm -f x.txt y.txt\n+\n+test_expect_success \"S = Nx Cxy Dx Cyx Dy Rxy Dy Nx Ny Dx Ryx Cxy Dx Dy Nx Rxy Dy Nx Cxy Dy Dx\" \\\n+    'cat Nx Cxy Dx Cyx Dy Rxy Dy Nx Ny Dx Ryx Cxy Dx Dy Nx Rxy Dy Nx Cxy Dy Dx | git-apply -'\n+rm -f x.txt y.txt\n+\n+test_done\n+\n"},{"id":"7925","messageId":"11253601123047-git-send-email-robfitz@273k.net","threadId":"1692","inReplyTo":"11253601111257-git-send-email-robfitz@273k.net","subject":"[PATCH 3/3] New option --ignore-applied for git-apply.","fromName":"Robert Fitzsmons","fromEmail":"robfitz@273k.net","sentAt":"2005-08-30T00:01:52Z","receivedAt":"2005-08-30T00:01:52Z","isPatch":true,"sender":{"key":"robfitz@273k.net","avatar":null},"body":"Allow the user to allow a patch which has some hunks (fragments)\nalready applied to succeed.  Added test case and documentation.\n\nSigned-off-by: Robert Fitzsimons <robfitz@273k.net>\n\n---\n\n Documentation/git-apply.txt     |    7 ++-\n apply.c                         |   12 +++++\n t/t4108-apply-ignore-applied.sh |   94 +++++++++++++++++++++++++++++++++++++++\n 3 files changed, 111 insertions(+), 2 deletions(-)\n create mode 100644 t/t4108-apply-ignore-applied.sh\n\ne8f2ff89f44b0c4d35dea3d86331a5e00fadf27e\ndiff --git a/Documentation/git-apply.txt b/Documentation/git-apply.txt\n--- a/Documentation/git-apply.txt\n+++ b/Documentation/git-apply.txt\n@@ -9,7 +9,9 @@ git-apply - Apply patch on a GIT index f\n \n SYNOPSIS\n --------\n-'git-apply' [--no-merge] [--stat] [--summary] [--check] [--index] [--show-files] [--apply] [<patch>...]\n+'git-apply' [--no-merge] [--stat] [--summary] [--check]\n+\t\t[--index] [--show-files] [--apply]\n+\t\t[--ignore-applied] [<patch>...]\n \n DESCRIPTION\n -----------\n@@ -61,6 +63,9 @@ OPTIONS\n \tpatch.  Give this flag after those flags to also apply\n \tthe patch.\n \n+--ignore-applied::\n+\tIf a patch hunk (fragment) fails to apply, reverse the\n+\thunk and check if the hunk has already been applied.\n \n Author\n ------\ndiff --git a/apply.c b/apply.c\n--- a/apply.c\n+++ b/apply.c\n@@ -32,8 +32,9 @@ static int summary = 0;\n static int check = 0;\n static int apply = 1;\n static int show_files = 0;\n+static int ignore_applied = 0;\n static const char apply_usage[] =\n-\"git-apply [--no-merge] [--stat] [--summary] [--check] [--index] [--apply] [--show-files] <patch>...\";\n+\"git-apply [--no-merge] [--stat] [--summary] [--check] [--index] [--apply] [--show-files] [--ignore-applied] <patch>...\";\n \n /*\n  * For \"diff-stat\" like behaviour, we keep track of the biggest change\n@@ -956,6 +957,11 @@ static int apply_one_fragment(struct buf\n \t\tmemmove(buf + offset + newsize, buf + offset + oldsize, size - offset - newsize);\n \t\tmemcpy(buf + offset, new, newsize);\n \t\toffset = 0;\n+\t} else if (ignore_applied) {\n+\t\toffset = find_offset(buf, desc->size, new, newsize, frag->newpos);\n+\t\tif (offset >= 0) {\n+\t\t\toffset = 0;\n+\t\t}\n \t}\n \n \tfree(old);\n@@ -1567,6 +1573,10 @@ int main(int argc, char **argv)\n \t\t\tshow_files = 1;\n \t\t\tcontinue;\n \t\t}\n+\t\tif (!strcmp(arg, \"--ignore-applied\")) {\n+\t\t\tignore_applied = 1;\n+\t\t\tcontinue;\n+\t\t}\n \t\tfd = open(arg, O_RDONLY);\n \t\tif (fd < 0)\n \t\t\tusage(apply_usage);\ndiff --git a/t/t4108-apply-ignore-applied.sh b/t/t4108-apply-ignore-applied.sh\nnew file mode 100644\n--- /dev/null\n+++ b/t/t4108-apply-ignore-applied.sh\n@@ -0,0 +1,94 @@\n+#!/bin/sh\n+#\n+# Copyright (c) 2005 Junio C Hamano\n+# Copyright (c) 2005 Robert Fitzsimons\n+#\n+\n+test_description='git-apply --ignore-applied.\n+\n+'\n+. ./test-lib.sh\n+\n+# setup\n+\n+cat > patch1.patch <<\\EOF\n+diff --git a/main.c b/main.c\n+new file mode 100644\n+--- /dev/null\n++++ b/main.c\n+@@ -0,0 +1,23 @@\n++#include <stdio.h>\n++\n++void print_int(int num);\n++int func(int num);\n++\n++int main() {\n++\tint i;\n++\n++\tfor (i = 0; i < 10; i++) {\n++\t\tprint_int(func(i));\n++\t}\n++\n++\treturn 0;\n++}\n++\n++int func(int num) {\n++\treturn num * num;\n++}\n++\n++void print_int(int num) {\n++\tprintf(\"%d\", num);\n++}\n++\n+EOF\n+cat > patch2.patch <<\\EOF\n+diff --git a/main.c b/main.c\n+--- a/main.c\n++++ b/main.c\n+@@ -10,6 +10,8 @@\n+ \t\tprint_int(func(i));\n+ \t}\n+ \n++\tprintf(\"\\n\");\n++\n+ \treturn 0;\n+ }\n+ \n+EOF\n+cat > patch3.patch <<\\EOF\n+diff --git a/main.c b/main.c\n+--- a/main.c\n++++ b/main.c\n+@@ -10,6 +10,8 @@\n+ \t\tprint_int(func(i));\n+ \t}\n+ \n++\tprintf(\"\\n\");\n++\n+ \treturn 0;\n+ }\n+ \n+@@ -18,6 +20,6 @@\n+ }\n+ \n+ void print_int(int num) {\n+-\tprintf(\"%d\", num);\n++\tprintf(\"%d \", num);\n+ }\n+ \n+EOF\n+\n+test_expect_failure \"F = test 1\" \\\n+    'cat patch1.patch patch2.patch patch2.patch | git-apply --check'\n+\n+test_expect_success \"S = test 2 (--ignore-applied)\" \\\n+    'cat patch1.patch patch2.patch patch2.patch | git-apply --check --ignore-applied'\n+\n+test_expect_failure \"F = test 3\" \\\n+    'cat patch1.patch patch3.patch patch3.patch | git-apply --check'\n+\n+test_expect_success \"S = test 4 (--ignore-applied)\" \\\n+    'cat patch1.patch patch2.patch patch3.patch | git-apply --check --ignore-applied'\n+\n+test_done\n+\n"},{"id":"8154","messageId":"7vslwhbsu9.fsf@assigned-by-dhcp.cox.net","threadId":"1692","inReplyTo":"20050905123445.GA27107@localhost","subject":"Re: [PATCH 2/3] Fix the processing of multiple patch files with --check in git-apply.","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-09-07T00:54:22Z","receivedAt":"2005-09-07T00:54:22Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Robert Fitzsimons <robfitz@273k.net> writes:\n\n> No problem I know it's a controversial change.\n\nNot really controversial anymore, as long as --ignore-applied is\nused only when appropriate.\n\n>>> Yes my change has a bug with a copy patch which modifies the same file.\n> I'll send on a fix now.\n\nHere is another one that the patch seems to regress.\n\nUnfortunately this turns out to be a death sentence to the\n'multiple patch touching the same file' patch.\n\nNote that patches from a single 'git-diff-*' run are supposed to\nbe independent, so the second one that copy-edits from frotz to\nrezrov copies frotz _before_ it is modified and then makes its\nmodification.\n\nOn the other hand, we can have one 'git-diff-*' run that\nmodifies frotz in place, and then a separate 'git-diff-*' run\nthat copies frotz to rezrov and then modifies rezrov, and feed\nthe concatenation of the two to git-apply.  That would look very\nsimilar to a single run that edits frotz and copy-edits rezrov,\nbut the pre-image to create rezrov would use the post-edit image\nof frotz from the first patch.  Without an explicit \"here an\noutput from the next git-diff-*' run begins\" marker, we cannot\ntell these two apart.\n\nThis means that applying multiple-patches concatenated in a\nsingle file does not make much sense.  There is no guarantee\nthat we can detect where the first 'git-diff-*' output ends, at\nwhich point we need to reset the status of 'frotz' to\npost-modification image of the first patch.  And if we can\ndetect reliably where one 'git-diff-*' output ends and the next\none begins, we could just split the input there and run\ngit-apply independently.  So my conclusion is to just drop this\npatch, and instead tell people not to feed overlapping outputs\nfrom multiple git-diff-* runs to a single invocation of\ngit-apply.\n\nI personally do not mind considering --ignore-applied\nindependently from the multiple-patch-files changes, though.\n\n------------\necho frotz >frotz\ngit-apply --check <<\\EOF\ndiff --git a/frotz b/frotz\n--- a/frotz\n+++ b/frotz\n@@ -1 +1 @@\n-frotz\n+frottz\ndiff --git a/frotz b/rezrov\nsimilarity index 64%\ncopy from frotz\ncopy to rezrov\n--- a/frotz\n+++ b/rezrov\n@@ -1 +1 @@\n-frotz\n+frotttz\nEOF\n"}]}