{"thread":{"id":"19998","subject":"[PATCH/RFC] git apply: option to ignore whitespace differences","startedAt":"2009-07-01T23:25:22Z","lastAt":"2009-07-01T23:25:22Z","messageCount":1,"participants":["Giuseppe Bilotta"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"117332","messageId":"1246490722-1544-1-git-send-email-giuseppe.bilotta@gmail.com","threadId":"19998","inReplyTo":null,"subject":"[PATCH/RFC] git apply: option to ignore whitespace differences","fromName":"Giuseppe Bilotta","fromEmail":"giuseppe.bilotta@gmail.com","sentAt":"2009-07-01T23:25:22Z","receivedAt":"2009-07-01T23:25:22Z","isPatch":true,"sender":{"key":"giuseppe.bilotta@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1464?v=4"},"body":"Introduce --ignore-whitespace option to ignore whitespace differences\nwhile applying the patch.\n\n'git am' and 'git rebase' are made aware of this option and pass it\nthrough to 'git apply', and so is the bash git completion.\n\nSigned-off-by: Giuseppe Bilotta <giuseppe.bilotta@gmail.com>\n---\n builtin-apply.c                        |   49 ++++++++++++++++++++++++++++++--\n contrib/completion/git-completion.bash |    2 +\n git-am.sh                              |    3 +-\n git-rebase.sh                          |    3 ++\n 4 files changed, 53 insertions(+), 4 deletions(-)\n\nI must say that the only thing I don't like about this patch is the fact\nthat context lines matching with whitespace differences are taken from\nthe patch rather than being left untouched.\n\ndiff --git a/builtin-apply.c b/builtin-apply.c\nindex dc0ff5e..82efee7 100644\n--- a/builtin-apply.c\n+++ b/builtin-apply.c\n@@ -39,6 +39,7 @@ static int diffstat;\n static int numstat;\n static int summary;\n static int check;\n+static int ignore_whitespace = 0;\n static int apply = 1;\n static int apply_in_reverse;\n static int apply_with_reject;\n@@ -214,6 +215,41 @@ static uint32_t hash_line(const char *cp, size_t len)\n \treturn h;\n }\n \n+/*\n+ * Compare two memory areas ignoring whitespace differences\n+ */\n+static int memcmp_ignore_whitespace(const char *s1, const char *s2, size_t n)\n+{\n+\tconst char *stop = s1 + n;\n+\tint result;\n+\n+\tif (!n)\n+\t\treturn 0;\n+\n+\tdo {\n+\t\tif (isspace(*s1) && isspace(*s2)) {\n+\t\t\twhile (isspace(*s1)) {\n+\t\t\t\ts1++;\n+\t\t\t}\n+\t\t\twhile (isspace(*s2))\n+\t\t\t\ts2++;\n+\t\t\tif (s1 >= stop)\n+\t\t\t\tbreak;\n+\t\t}\n+\t\tresult = *s1++ - *s2++;\n+\t} while (!result && (s1 < stop));\n+\n+\treturn result;\n+}\n+\n+static int memcmp_switch(const char *s1, const char *s2, size_t n)\n+{\n+\tif (ignore_whitespace)\n+\t\treturn memcmp_ignore_whitespace(s1, s2, n);\n+\telse\n+\t\treturn memcmp(s1, s2, n);\n+}\n+\n static void add_line_info(struct image *img, const char *bol, size_t len, unsigned flag)\n {\n \tALLOC_GROW(img->line_allocated, img->nr + 1, img->alloc);\n@@ -1690,10 +1726,10 @@ static int match_fragment(struct image *img,\n \tif ((match_end\n \t     ? (try + preimage->len == img->len)\n \t     : (try + preimage->len <= img->len)) &&\n-\t    !memcmp(img->buf + try, preimage->buf, preimage->len))\n+\t    !memcmp_switch(preimage->buf, img->buf + try, preimage->len))\n \t\treturn 1;\n \n-\tif (ws_error_action != correct_ws_error)\n+\tif (!ignore_whitespace && (ws_error_action != correct_ws_error))\n \t\treturn 0;\n \n \t/*\n@@ -1731,8 +1767,13 @@ static int match_fragment(struct image *img,\n \t\t * In either case, we are fixing the whitespace breakages\n \t\t * so we might as well take the fix together with their\n \t\t * real change.\n+\t\t * If we are ignoring whitespace differences, don't check\n+\t\t * for length equality.\n \t\t */\n-\t\tmatch = (tgtfixlen == fixlen && !memcmp(tgtfix, buf, fixlen));\n+\t\tif (ignore_whitespace)\n+\t\t\tmatch = !memcmp_ignore_whitespace(buf, tgtfix, fixlen);\n+\t\telse\n+\t\t\tmatch = (tgtfixlen == fixlen && !memcmp(tgtfix, buf, fixlen));\n \n \t\tif (tgtfix != tgtfixbuf)\n \t\t\tfree(tgtfix);\n@@ -3304,6 +3345,8 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix)\n \t\t{ OPTION_CALLBACK, 0, \"whitespace\", &whitespace_option, \"action\",\n \t\t\t\"detect new or modified lines that have whitespace errors\",\n \t\t\t0, option_parse_whitespace },\n+\t\tOPT_BOOLEAN(0, \"ignore-whitespace\", &ignore_whitespace,\n+\t\t\t\"ignore whitespace differences when finding context\"),\n \t\tOPT_BOOLEAN('R', \"reverse\", &apply_in_reverse,\n \t\t\t\"apply the patch in reverse\"),\n \t\tOPT_BOOLEAN(0, \"unidiff-zero\", &unidiff_zero,\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex ddb71e2..d3415b5 100755\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -663,6 +663,7 @@ _git_am ()\n \t--*)\n \t\t__gitcomp \"\n \t\t\t--3way --committer-date-is-author-date --ignore-date\n+\t\t\t--ignore-whitespace\n \t\t\t--interactive --keep --no-utf8 --signoff --utf8\n \t\t\t--whitespace=\n \t\t\t\"\n@@ -684,6 +685,7 @@ _git_apply ()\n \t\t\t--stat --numstat --summary --check --index\n \t\t\t--cached --index-info --reverse --reject --unidiff-zero\n \t\t\t--apply --no-add --exclude=\n+\t\t\t--ignore-whitespace\n \t\t\t--whitespace= --inaccurate-eof --verbose\n \t\t\t\"\n \t\treturn\ndiff --git a/git-am.sh b/git-am.sh\nindex 58d4eb6..8e8598c 100755\n--- a/git-am.sh\n+++ b/git-am.sh\n@@ -16,6 +16,7 @@ s,signoff       add a Signed-off-by line to the commit message\n u,utf8          recode into utf8 (default)\n k,keep          pass -k flag to git-mailinfo\n whitespace=     pass it through git-apply\n+ignore-whitespace pass it through git-apply\n directory=      pass it through git-apply\n C=              pass it through git-apply\n p=              pass it through git-apply\n@@ -180,7 +181,7 @@ do\n \t\tgit_apply_opt=\"$git_apply_opt $(sq \"$1=$2\")\"; shift ;;\n \t-C|-p)\n \t\tgit_apply_opt=\"$git_apply_opt $(sq \"$1$2\")\"; shift ;;\n-\t--reject)\n+\t--reject|--ignore-whitespace)\n \t\tgit_apply_opt=\"$git_apply_opt $1\" ;;\n \t--committer-date-is-author-date)\n \t\tcommitter_date_is_author_date=t ;;\ndiff --git a/git-rebase.sh b/git-rebase.sh\nindex 18bc694..d741752 100755\n--- a/git-rebase.sh\n+++ b/git-rebase.sh\n@@ -333,6 +333,9 @@ do\n \t\t\t;;\n \t\tesac\n \t\t;;\n+\t--ignore-whitespace)\n+\t\tgit_am_opt=\"$git_am_opt $1\"\n+\t\t;;\n \t--committer-date-is-author-date|--ignore-date)\n \t\tgit_am_opt=\"$git_am_opt $1\"\n \t\tforce_rebase=t\n-- \n1.6.3.3.487.gc7c49\n"}]}