{"thread":{"id":"14127","subject":"[PATCH v2] pre-commit hook should ignore carriage returns at EOL","startedAt":"2008-06-24T19:21:22Z","lastAt":"2008-06-27T04:24:46Z","messageCount":14,"participants":["Christian Holtje","Alex Riesen","Junio C Hamano","Jeff King"],"isPatch":true,"patchVersion":2,"patchTotal":null},"messages":[{"id":"80955","messageId":"3BA781AD-4C44-4F43-902A-07580B6CA075@gmail.com","threadId":"14127","inReplyTo":null,"subject":"[PATCH v2] pre-commit hook should ignore carriage returns at EOL","fromName":"Christian Holtje","fromEmail":"docwhat@gmail.com","sentAt":"2008-06-24T19:21:22Z","receivedAt":"2008-06-24T19:21:22Z","isPatch":true,"sender":{"key":"docwhat@gmail.com","avatar":"https://gravatar.com/avatar/b87944ebf1ff49feaeefaa1c19a6e98baee691c531ecb860c2bc4f63b464a395?d=mp&s=160"},"body":"When commit files that use DOS style CRLF end-of-lines, the pre-commit\nhook would raise an error.  When combined with the fact that the hooks\nget activated by default on windows, it makes life difficult for\npeople working with DOS files.\n\nThis patch causes the pre-commit hook to deal with crlf files\ncorrectly.\n\nSigned-off-by: Christian Höltje <docwhat@gmail.com>\n---\n  t/t7503-template-hook--pre-commit.sh |   75 +++++++++++++++++++++++++ \n+++++++++\n  templates/hooks--pre-commit          |   10 ++++-\n  2 files changed, 83 insertions(+), 2 deletions(-)\n  create mode 100755 t/t7503-template-hook--pre-commit.sh\n\ndiff --git a/t/t7503-template-hook--pre-commit.sh b/t/t7503-template- \nhook--pre-commit.sh\nnew file mode 100755\nindex 0000000..c78a507\n--- /dev/null\n+++ b/t/t7503-template-hook--pre-commit.sh\n@@ -0,0 +1,75 @@\n+#!/bin/sh\n+#\n+# Copyright (c) 2008 Christian Höltje\n+#\n+\n+test_description='t7503 templates-hooks--pre-commit\n+\n+This test verifies that the pre-commit hook shipped with\n+git by default works correctly.\n+'\n+\n+. ./test-lib.sh\n+\n+test_expect_success 'verify that autocrlf is unset' '\n+   if git config core.autocrlf\n+   then\n+     false\n+   else\n+     test $? -eq 1\n+   fi\n+'\n+\n+test_expect_success 'lf without hook' '\n+\n+\tprintf \"foo\" > lf.txt &&\n+\tgit add lf.txt &&\n+\tgit commit -m \"lf without hook\" lf.txt\n+\n+'\n+\n+test_expect_success 'crlf without hook' '\n+\n+\tprintf \"foo\\r\" > crlf.txt &&\n+\tgit add crlf.txt &&\n+\tgit commit -m \"crlf without hook\" crlf.txt\n+\n+'\n+\n+# Set up the pre-commit hook.\n+HOOKDIR=\"$(git rev-parse --git-dir)/hooks\"\n+mkdir -p \"${HOOKDIR}\"\n+cp -r \"${HOOKDIR}-disabled/pre-commit\" \"${HOOKDIR}/pre-commit\"\n+chmod +x \"${HOOKDIR}/pre-commit\"\n+\n+test_expect_success 'lf with hook' '\n+\n+\tprintf \"bar\" >> lf.txt &&\n+\tgit add lf.txt &&\n+\tgit commit -m \"lf with hook\" lf.txt\n+\n+'\n+test_expect_success 'crlf with hook' '\n+\n+\tprintf \"bar\\r\" >> crlf.txt &&\n+\tgit add crlf.txt &&\n+\tgit commit -m \"crlf with hook\" crlf.txt\n+\n+'\n+\n+test_expect_success 'lf with hook white-space failure' '\n+\n+\tprintf \"bar \" >> lf.txt &&\n+\tgit add lf.txt &&\n+\t! git commit -m \"lf with hook\" lf.txt\n+\n+'\n+test_expect_success 'crlf with hook white-space failure' '\n+\n+\tprintf \"bar \\r\" >> crlf.txt &&\n+\tgit add crlf.txt &&\n+\t! git commit -m \"crlf with hook\" crlf.txt\n+\n+'\n+\n+test_done\ndiff --git a/templates/hooks--pre-commit b/templates/hooks--pre-commit\nindex b25dce6..335ca09 100644\n--- a/templates/hooks--pre-commit\n+++ b/templates/hooks--pre-commit\n@@ -55,8 +55,14 @@ perl -e '\n  \tif (s/^\\+//) {\n  \t    $lineno++;\n  \t    chomp;\n-\t    if (/\\s$/) {\n-\t\tbad_line(\"trailing whitespace\", $_);\n+\t    if (/\\r$/) {\n+\t\tif (/\\s\\r$/) {\n+\t\t    bad_line(\"trailing whitespace\", $_);\n+\t\t}\n+\t    } else {\n+\t\tif (/\\s$/) {\n+\t\t    bad_line(\"trailing whitespace\", $_);\n+\t\t}\n  \t    }\n  \t    if (/^\\s* \\t/) {\n  \t\tbad_line(\"indent SP followed by a TAB\", $_);\n-- \n1.5.5.4\n"},{"id":"81154","messageId":"20080625181422.GC4039@steel.home","threadId":"14127","inReplyTo":"3BA781AD-4C44-4F43-902A-07580B6CA075@gmail.com","subject":"Re: [PATCH v2] pre-commit hook should ignore carriage returns at EOL","fromName":"Alex Riesen","fromEmail":"raa.lkml@gmail.com","sentAt":"2008-06-25T18:14:22Z","receivedAt":"2008-06-25T18:14:22Z","isPatch":true,"sender":{"key":"raa.lkml@gmail.com","avatar":"https://avatars.githubusercontent.com/u/324101?v=4"},"body":"Christian Holtje, Tue, Jun 24, 2008 21:21:22 +0200:\n> diff --git a/t/t7503-template-hook--pre-commit.sh b/t/t7503-template- \n> hook--pre-commit.sh\n\nYour patch has long lines wrapped.\n\n> diff --git a/templates/hooks--pre-commit b/templates/hooks--pre-commit\n> index b25dce6..335ca09 100644\n> --- a/templates/hooks--pre-commit\n> +++ b/templates/hooks--pre-commit\n> @@ -55,8 +55,14 @@ perl -e '\n>  \tif (s/^\\+//) {\n>  \t    $lineno++;\n>  \t    chomp;\n> -\t    if (/\\s$/) {\n> -\t\tbad_line(\"trailing whitespace\", $_);\n> +\t    if (/\\r$/) {\n> +\t\tif (/\\s\\r$/) {\n> +\t\t    bad_line(\"trailing whitespace\", $_);\n> +\t\t}\n> +\t    } else {\n> +\t\tif (/\\s$/) {\n> +\t\t    bad_line(\"trailing whitespace\", $_);\n> +\t\t}\n\nYou coud just strip the trailing (cr)lf, instead of chomp:\n\n  \tif (s/^\\+//) {\n  \t    $lineno++;\n- \t    chomp;\n+\t    s/\\r?\\n$//so;\n \t    if (/\\s$/) {\n \t\tbad_line(\"trailing whitespace\", $_);\n\nMakes for a shorter patch and less code.\n"},{"id":"81156","messageId":"5B163827-204D-4F76-88C9-8F0C93E60AF3@gmail.com","threadId":"14127","inReplyTo":"20080625181422.GC4039@steel.home","subject":"Re: [PATCH v2] pre-commit hook should ignore carriage returns at EOL","fromName":"Christian Holtje","fromEmail":"docwhat@gmail.com","sentAt":"2008-06-25T18:47:58Z","receivedAt":"2008-06-25T18:47:58Z","isPatch":true,"sender":{"key":"docwhat@gmail.com","avatar":"https://gravatar.com/avatar/b87944ebf1ff49feaeefaa1c19a6e98baee691c531ecb860c2bc4f63b464a395?d=mp&s=160"},"body":"On Jun 25, 2008, at 2:14 PM, Alex Riesen wrote:\n> Christian Holtje, Tue, Jun 24, 2008 21:21:22 +0200:\n>> diff --git a/t/t7503-template-hook--pre-commit.sh b/t/t7503-template-\n>> hook--pre-commit.sh\n>\n> Your patch has long lines wrapped.\n>\n>> diff --git a/templates/hooks--pre-commit b/templates/hooks--pre- \n>> commit\n>> index b25dce6..335ca09 100644\n>> --- a/templates/hooks--pre-commit\n>> +++ b/templates/hooks--pre-commit\n>> @@ -55,8 +55,14 @@ perl -e '\n>> \tif (s/^\\+//) {\n>> \t    $lineno++;\n>> \t    chomp;\n>> -\t    if (/\\s$/) {\n>> -\t\tbad_line(\"trailing whitespace\", $_);\n>> +\t    if (/\\r$/) {\n>> +\t\tif (/\\s\\r$/) {\n>> +\t\t    bad_line(\"trailing whitespace\", $_);\n>> +\t\t}\n>> +\t    } else {\n>> +\t\tif (/\\s$/) {\n>> +\t\t    bad_line(\"trailing whitespace\", $_);\n>> +\t\t}\n>\n> You coud just strip the trailing (cr)lf, instead of chomp:\n>\n>  \tif (s/^\\+//) {\n>  \t    $lineno++;\n> - \t    chomp;\n> +\t    s/\\r?\\n$//so;\n> \t    if (/\\s$/) {\n> \t\tbad_line(\"trailing whitespace\", $_);\n>\n> Makes for a shorter patch and less code.\n\nThat's a good idea!  However, this patch is not going anyplace, I  \nthink.  Junio submitted a different patch to disable the pre-commit  \nexample.\n\nJunio, do you want me to make this change anyway?  It does make  \nsense.  The unittests for the pre-commit hook may or may not still be  \nuseful.\n\nCiao!\n"},{"id":"81163","messageId":"7vhcbh1g4e.fsf@gitster.siamese.dyndns.org","threadId":"14127","inReplyTo":"5B163827-204D-4F76-88C9-8F0C93E60AF3@gmail.com","subject":"Re: [PATCH v2] pre-commit hook should ignore carriage returns at EOL","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-06-25T19:14:41Z","receivedAt":"2008-06-25T19:14:41Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Christian Holtje <docwhat@gmail.com> writes:\n\n> On Jun 25, 2008, at 2:14 PM, Alex Riesen wrote:\n>> Christian Holtje, Tue, Jun 24, 2008 21:21:22 +0200:\n>>> diff --git a/t/t7503-template-hook--pre-commit.sh b/t/t7503-template-\n>>> hook--pre-commit.sh\n>>\n>> Your patch has long lines wrapped.\n>>\n>>> diff --git a/templates/hooks--pre-commit b/templates/hooks--pre-\n>>> commit\n>>> index b25dce6..335ca09 100644\n>>> --- a/templates/hooks--pre-commit\n>>> +++ b/templates/hooks--pre-commit\n>>> @@ -55,8 +55,14 @@ perl -e '\n>>> \tif (s/^\\+//) {\n>>> \t    $lineno++;\n>>> \t    chomp;\n>>> -\t    if (/\\s$/) {\n>>> -\t\tbad_line(\"trailing whitespace\", $_);\n>>> +\t    if (/\\r$/) {\n>>> +\t\tif (/\\s\\r$/) {\n>>> +\t\t    bad_line(\"trailing whitespace\", $_);\n>>> +\t\t}\n>>> +\t    } else {\n>>> +\t\tif (/\\s$/) {\n>>> +\t\t    bad_line(\"trailing whitespace\", $_);\n>>> +\t\t}\n>>\n>> You coud just strip the trailing (cr)lf, instead of chomp:\n>>\n>>  \tif (s/^\\+//) {\n>>  \t    $lineno++;\n>> - \t    chomp;\n>> +\t    s/\\r?\\n$//so;\n>> \t    if (/\\s$/) {\n>> \t\tbad_line(\"trailing whitespace\", $_);\n>>\n>> Makes for a shorter patch and less code.\n>\n> That's a good idea!  However, this patch is not going anyplace, I\n> think.  Junio submitted a different patch to disable the pre-commit\n> example.\n>\n> Junio, do you want me to make this change anyway?  It does make sense.\n> The unittests for the pre-commit hook may or may not still be  useful.\n\n\"disable\" is not an issue.  The intention has always been that these are\nsamples, and it was an accident that some packaging shipped them enabled\nby mistake.  The patch was to make that mistake harder to make.\n\nThe issue now is about keeping the example hooks _relevant_.  The one we\nhave does not work well with projects that want to check in files with\nCRLF line endings (iow, without using autocrlf to attempt to make the\nproject files cross-platform), so it is irrelevant for such projects with\nWindows origin.\n\nThe \"solution\" you are proposing to strip out \\r makes the check less\nuseful for projects that want to keep files with LF line endings in the\ncommited history, because your patch would stop catching such a mistake of\nadding an CR before LF.  It is robbing from Peter to pay Paul, and I am\nafraid it would make the sample even more irrelevant in the end.  I do not\nthink we would want to go there.\n\nI suggested using \"diff --check\" (and possibly teaching \"diff --check\"\nother things the scripted example checks, such as conflict markers),\nwhich would know to honor the line endings specified per path via\ngitattributes(5), instead of building on top of the big Perl script, and I\nhad an impression that you agreed to the approach.\n"},{"id":"81225","messageId":"635350D7-2CC0-4FA6-BB74-CE9ED930ECE8@gmail.com","threadId":"14127","inReplyTo":"7vhcbh1g4e.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH v2] pre-commit hook should ignore carriage returns at EOL","fromName":"Christian Holtje","fromEmail":"docwhat@gmail.com","sentAt":"2008-06-26T02:41:12Z","receivedAt":"2008-06-26T02:41:12Z","isPatch":true,"sender":{"key":"docwhat@gmail.com","avatar":"https://gravatar.com/avatar/b87944ebf1ff49feaeefaa1c19a6e98baee691c531ecb860c2bc4f63b464a395?d=mp&s=160"},"body":"On Jun 25, 2008, at 3:14 PM, Junio C Hamano wrote:\n> Christian Holtje <docwhat@gmail.com> writes:\n>>\n>> Junio, do you want me to make this change anyway?  It does make  \n>> sense.\n>> The unittests for the pre-commit hook may or may not still be   \n>> useful.\n>\n> \"disable\" is not an issue.  The intention has always been that these  \n> are\n> samples, and it was an accident that some packaging shipped them  \n> enabled\n> by mistake.  The patch was to make that mistake harder to make.\n>\n> The issue now is about keeping the example hooks _relevant_.  The  \n> one we\n> have does not work well with projects that want to check in files with\n> CRLF line endings (iow, without using autocrlf to attempt to make the\n> project files cross-platform), so it is irrelevant for such projects  \n> with\n> Windows origin.\n>\n> The \"solution\" you are proposing to strip out \\r makes the check less\n> useful for projects that want to keep files with LF line endings in  \n> the\n> commited history, because your patch would stop catching such a  \n> mistake of\n> adding an CR before LF.  It is robbing from Peter to pay Paul, and I  \n> am\n> afraid it would make the sample even more irrelevant in the end.  I  \n> do not\n> think we would want to go there.\n>\n> I suggested using \"diff --check\" (and possibly teaching \"diff --check\"\n> other things the scripted example checks, such as conflict markers),\n> which would know to honor the line endings specified per path via\n> gitattributes(5), instead of building on top of the big Perl script,  \n> and I\n> had an impression that you agreed to the approach.\n\nI'm completely confused how gitattributes and core.autocrlf interact,  \netc.\n\nI'm expecting the default behavior is that git will leave my files  \nalone.  This seems to be the case.\n\nIn order for the crlf stuff to work, does it need to have  \ncore.autocrlf set to true?  If so, that seems wrong.  gitattributes(5)  \nis supposed to let you have fine grain control over files.  In  \naddition, .git/config isn't passed around via clone so .gitattributes  \nworks differently depending on who clones it and their settings.\n\nFurthermore, how would 'git diff --check' know what the line endings  \nare for a file?  I may have a mostly unix repository but I may have a  \nfew crlf text files I need to have checked out as crlf on windows (but  \nnot unix).\n\nShouldn't the crlf stuff be something like:\n.gitattributes:\n   eol=crlf -- dos files. no conversion, but diff --check will know  \nwhat is what.\n   eol=lf -- unix (otherwise same)\n   eol=convert -- stores internally as lf, converts on the fly to lf  \nor crlf on filesystem based on system preference. diff --check won't  \nworry about new lines matching system-eol if they don't match the eol  \nin the file.\n   eol=binary -- binary\n\ncore.eol=crlf -- ony files with all crlf endings are text.\ncore.eol=lf -- only files with all lf (no crlf) endings are text.\ncore.eol=convert -- crlf changes will be converted to lf as per system- \neol\ncore.eol=false -- do nothing (default) (binary)\n\ncore.system-eol=crlf -- pretend the system is windows\ncore.system-eol=lf -- pretend the system is unix\ncore.system-eol=auto -- determine from the system (default)\n\nOtherwise, I have no clue what's going on.  Once someone writes this  \nin english, I'll try to write unittests and I'll submit them.  Then  \nsomeone who knows what he/she is doing can write the actual code to  \nmake the tests pass.  Or maybe I'll try, who knows.\n\nCiao!\n"},{"id":"81332","messageId":"7vk5gbq10p.fsf@gitster.siamese.dyndns.org","threadId":"14127","inReplyTo":"635350D7-2CC0-4FA6-BB74-CE9ED930ECE8@gmail.com","subject":"Re: [PATCH v2] pre-commit hook should ignore carriage returns at EOL","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-06-26T22:33:58Z","receivedAt":"2008-06-26T22:33:58Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Christian Holtje <docwhat@gmail.com> writes:\n\n>> I suggested using \"diff --check\" (and possibly teaching \"diff --check\"\n>> other things the scripted example checks, such as conflict markers),\n>> which would know to honor the line endings specified per path via\n>> gitattributes(5), instead of building on top of the big Perl script,\n>> and I\n>> had an impression that you agreed to the approach.\n>\n> I'm completely confused how gitattributes and core.autocrlf interact,\n> etc.\n\nHere is a series I just cooked up so that we can remove the whole Perl\nscript and replace it by adding --check to \"diff-index\" used there. \n\nThe first three are code clean-ups and the last two implements necessary\nnew features to \"diff --check\".  The whole series somewhat depend on the\nfix to 'maint' not to lose the exit status I sent earlier.\n\n[PATCH 1/5] diff --check: explain why we do not care whether old side is binary\n[PATCH 2/5] check_and_emit_line(): rename and refactor\n[PATCH 3/5] checkdiff: pass diff_options to the callback\n[PATCH 4/5] Teach \"diff --check\" about a new blank lines at end\n[PATCH 5/5] diff --check: detect leftover conflict markers\n"},{"id":"81333","messageId":"7vfxqzq0z5.fsf_-_@gitster.siamese.dyndns.org","threadId":"14127","inReplyTo":"7vk5gbq10p.fsf@gitster.siamese.dyndns.org","subject":"[PATCH 1/5] diff --check: explain why we do not care whether old side is binary","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-06-26T22:34:54Z","receivedAt":"2008-06-26T22:34:54Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"All other codepaths refrain from running textual diff when either the old\nor the new side is binary, but this function only checks the new side.  I\nwas almost going to change it to check both, but that would be a bad\nchange.  Explain why to prevent future mistakes.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n diff.c |   11 +++++++++--\n 1 files changed, 9 insertions(+), 2 deletions(-)\n\ndiff --git a/diff.c b/diff.c\nindex 8939423..c00d633 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -1544,8 +1544,9 @@ static void builtin_diffstat(const char *name_a, const char *name_b,\n \n static void builtin_checkdiff(const char *name_a, const char *name_b,\n \t\t\t      const char *attr_path,\n-\t\t\t     struct diff_filespec *one,\n-\t\t\t     struct diff_filespec *two, struct diff_options *o)\n+\t\t\t      struct diff_filespec *one,\n+\t\t\t      struct diff_filespec *two,\n+\t\t\t      struct diff_options *o)\n {\n \tmmfile_t mf1, mf2;\n \tstruct checkdiff_t data;\n@@ -1564,6 +1565,12 @@ static void builtin_checkdiff(const char *name_a, const char *name_b,\n \tif (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0)\n \t\tdie(\"unable to read files to diff\");\n \n+\t/*\n+\t * All the other codepaths check both sides, but not checking\n+\t * the \"old\" side here is deliberate.  We are checking the newly\n+\t * introduced changes, and as long as the \"new\" side is text, we\n+\t * can and should check what it introduces.\n+\t */\n \tif (diff_filespec_is_binary(two))\n \t\tgoto free_and_return;\n \telse {\n-- \n1.5.6.1.78.gde8d9\n"},{"id":"81334","messageId":"7vbq1nq0ye.fsf_-_@gitster.siamese.dyndns.org","threadId":"14127","inReplyTo":"7vk5gbq10p.fsf@gitster.siamese.dyndns.org","subject":"[PATCH 2/5] check_and_emit_line(): rename and refactor","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-06-26T22:35:21Z","receivedAt":"2008-06-26T22:35:21Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"The function name was too bland and not explicit enough as to what it is\nchecking.  Split it into two, and call the one that checks if there is a\nwhitespace breakage \"ws_check()\", and call the other one that checks and\nemits the line after color coding \"ws_check_emit()\".\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin-apply.c |    5 ++---\n cache.h         |    5 ++---\n diff.c          |   13 ++++++-------\n ws.c            |   18 +++++++++++++++---\n 4 files changed, 25 insertions(+), 16 deletions(-)\n\ndiff --git a/builtin-apply.c b/builtin-apply.c\nindex c497889..92f0047 100644\n--- a/builtin-apply.c\n+++ b/builtin-apply.c\n@@ -979,8 +979,7 @@ static int find_header(char *line, unsigned long size, int *hdrsize, struct patc\n static void check_whitespace(const char *line, int len, unsigned ws_rule)\n {\n \tchar *err;\n-\tunsigned result = check_and_emit_line(line + 1, len - 1, ws_rule,\n-\t    NULL, NULL, NULL, NULL);\n+\tunsigned result = ws_check(line + 1, len - 1, ws_rule);\n \tif (!result)\n \t\treturn;\n \n@@ -991,7 +990,7 @@ static void check_whitespace(const char *line, int len, unsigned ws_rule)\n \telse {\n \t\terr = whitespace_error_string(result);\n \t\tfprintf(stderr, \"%s:%d: %s.\\n%.*s\\n\",\n-\t\t     patch_input_file, linenr, err, len - 2, line + 1);\n+\t\t\tpatch_input_file, linenr, err, len - 2, line + 1);\n \t\tfree(err);\n \t}\n }\ndiff --git a/cache.h b/cache.h\nindex 64ef86e..3dfa53c 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -819,9 +819,8 @@ void shift_tree(const unsigned char *, const unsigned char *, unsigned char *, i\n extern unsigned whitespace_rule_cfg;\n extern unsigned whitespace_rule(const char *);\n extern unsigned parse_whitespace_rule(const char *);\n-extern unsigned check_and_emit_line(const char *line, int len, unsigned ws_rule,\n-    FILE *stream, const char *set,\n-    const char *reset, const char *ws);\n+extern unsigned ws_check(const char *line, int len, unsigned ws_rule);\n+extern void ws_check_emit(const char *line, int len, unsigned ws_rule, FILE *stream, const char *set, const char *reset, const char *ws);\n extern char *whitespace_error_string(unsigned ws);\n extern int ws_fix_copy(char *, const char *, int, unsigned, int *);\n \ndiff --git a/diff.c b/diff.c\nindex c00d633..52a34ee 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -535,9 +535,9 @@ static void emit_add_line(const char *reset, struct emit_callback *ecbdata, cons\n \telse {\n \t\t/* Emit just the prefix, then the rest. */\n \t\temit_line(ecbdata->file, set, reset, line, ecbdata->nparents);\n-\t\t(void)check_and_emit_line(line + ecbdata->nparents,\n-\t\t    len - ecbdata->nparents, ecbdata->ws_rule,\n-\t\t    ecbdata->file, set, reset, ws);\n+\t\tws_check_emit(line + ecbdata->nparents,\n+\t\t\t      len - ecbdata->nparents, ecbdata->ws_rule,\n+\t\t\t      ecbdata->file, set, reset, ws);\n \t}\n }\n \n@@ -1153,8 +1153,7 @@ static void checkdiff_consume(void *priv, char *line, unsigned long len)\n \tif (line[0] == '+') {\n \t\tunsigned bad;\n \t\tdata->lineno++;\n-\t\tbad = check_and_emit_line(line + 1, len - 1,\n-\t\t    data->ws_rule, NULL, NULL, NULL, NULL);\n+\t\tbad = ws_check(line + 1, len - 1, data->ws_rule);\n \t\tif (!bad)\n \t\t\treturn;\n \t\tdata->status |= bad;\n@@ -1162,8 +1161,8 @@ static void checkdiff_consume(void *priv, char *line, unsigned long len)\n \t\tfprintf(data->file, \"%s:%d: %s.\\n\", data->filename, data->lineno, err);\n \t\tfree(err);\n \t\temit_line(data->file, set, reset, line, 1);\n-\t\t(void)check_and_emit_line(line + 1, len - 1, data->ws_rule,\n-\t\t    data->file, set, reset, ws);\n+\t\tws_check_emit(line + 1, len - 1, data->ws_rule,\n+\t\t\t      data->file, set, reset, ws);\n \t} else if (line[0] == ' ')\n \t\tdata->lineno++;\n \telse if (line[0] == '@') {\ndiff --git a/ws.c b/ws.c\nindex ba7e834..24d3e3d 100644\n--- a/ws.c\n+++ b/ws.c\n@@ -117,9 +117,9 @@ char *whitespace_error_string(unsigned ws)\n }\n \n /* If stream is non-NULL, emits the line after checking. */\n-unsigned check_and_emit_line(const char *line, int len, unsigned ws_rule,\n-\t\t\t     FILE *stream, const char *set,\n-\t\t\t     const char *reset, const char *ws)\n+static unsigned ws_check_emit_1(const char *line, int len, unsigned ws_rule,\n+\t\t\t\tFILE *stream, const char *set,\n+\t\t\t\tconst char *reset, const char *ws)\n {\n \tunsigned result = 0;\n \tint written = 0;\n@@ -213,6 +213,18 @@ unsigned check_and_emit_line(const char *line, int len, unsigned ws_rule,\n \treturn result;\n }\n \n+void ws_check_emit(const char *line, int len, unsigned ws_rule,\n+\t\t   FILE *stream, const char *set,\n+\t\t   const char *reset, const char *ws)\n+{\n+\t(void)ws_check_emit_1(line, len, ws_rule, stream, set, reset, ws);\n+}\n+\n+unsigned ws_check(const char *line, int len, unsigned ws_rule)\n+{\n+\treturn ws_check_emit_1(line, len, ws_rule, NULL, NULL, NULL, NULL);\n+}\n+\n /* Copy the line to the buffer while fixing whitespaces */\n int ws_fix_copy(char *dst, const char *src, int len, unsigned ws_rule, int *error_count)\n {\n-- \n1.5.6.1.78.gde8d9\n"},{"id":"81335","messageId":"7v63rvq0wd.fsf_-_@gitster.siamese.dyndns.org","threadId":"14127","inReplyTo":"7vk5gbq10p.fsf@gitster.siamese.dyndns.org","subject":"[PATCH 3/5] checkdiff: pass diff_options to the callback","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-06-26T22:36:34Z","receivedAt":"2008-06-26T22:36:34Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"We could later use more information from the diff_options.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n diff.c |   21 +++++++++++----------\n 1 files changed, 11 insertions(+), 10 deletions(-)\n\ndiff --git a/diff.c b/diff.c\nindex 52a34ee..6bcbe20 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -1136,18 +1136,19 @@ static void free_diffstat_info(struct diffstat_t *diffstat)\n struct checkdiff_t {\n \tstruct xdiff_emit_state xm;\n \tconst char *filename;\n-\tint lineno, color_diff;\n+\tint lineno;\n+\tstruct diff_options *o;\n \tunsigned ws_rule;\n \tunsigned status;\n-\tFILE *file;\n };\n \n static void checkdiff_consume(void *priv, char *line, unsigned long len)\n {\n \tstruct checkdiff_t *data = priv;\n-\tconst char *ws = diff_get_color(data->color_diff, DIFF_WHITESPACE);\n-\tconst char *reset = diff_get_color(data->color_diff, DIFF_RESET);\n-\tconst char *set = diff_get_color(data->color_diff, DIFF_FILE_NEW);\n+\tint color_diff = DIFF_OPT_TST(data->o, COLOR_DIFF);\n+\tconst char *ws = diff_get_color(color_diff, DIFF_WHITESPACE);\n+\tconst char *reset = diff_get_color(color_diff, DIFF_RESET);\n+\tconst char *set = diff_get_color(color_diff, DIFF_FILE_NEW);\n \tchar *err;\n \n \tif (line[0] == '+') {\n@@ -1158,11 +1159,12 @@ static void checkdiff_consume(void *priv, char *line, unsigned long len)\n \t\t\treturn;\n \t\tdata->status |= bad;\n \t\terr = whitespace_error_string(bad);\n-\t\tfprintf(data->file, \"%s:%d: %s.\\n\", data->filename, data->lineno, err);\n+\t\tfprintf(data->o->file, \"%s:%d: %s.\\n\",\n+\t\t\tdata->filename, data->lineno, err);\n \t\tfree(err);\n-\t\temit_line(data->file, set, reset, line, 1);\n+\t\temit_line(data->o->file, set, reset, line, 1);\n \t\tws_check_emit(line + 1, len - 1, data->ws_rule,\n-\t\t\t      data->file, set, reset, ws);\n+\t\t\t      data->o->file, set, reset, ws);\n \t} else if (line[0] == ' ')\n \t\tdata->lineno++;\n \telse if (line[0] == '@') {\n@@ -1557,9 +1559,8 @@ static void builtin_checkdiff(const char *name_a, const char *name_b,\n \tdata.xm.consume = checkdiff_consume;\n \tdata.filename = name_b ? name_b : name_a;\n \tdata.lineno = 0;\n-\tdata.color_diff = DIFF_OPT_TST(o, COLOR_DIFF);\n+\tdata.o = o;\n \tdata.ws_rule = whitespace_rule(attr_path);\n-\tdata.file = o->file;\n \n \tif (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0)\n \t\tdie(\"unable to read files to diff\");\n-- \n1.5.6.1.78.gde8d9\n"},{"id":"81336","messageId":"7v1w2jq0vo.fsf_-_@gitster.siamese.dyndns.org","threadId":"14127","inReplyTo":"7vk5gbq10p.fsf@gitster.siamese.dyndns.org","subject":"[PATCH 4/5] Teach \"diff --check\" about a new blank lines at end","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-06-26T22:36:59Z","receivedAt":"2008-06-26T22:36:59Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"When a patch adds new blank lines at the end, \"git apply --whitespace\"\nwarns.  This teaches \"diff --check\" to do the same.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n cache.h                    |    1 +\n diff.c                     |   17 +++++++++++++++--\n t/t4015-diff-whitespace.sh |    6 ++++++\n ws.c                       |   15 +++++++++++++++\n 4 files changed, 37 insertions(+), 2 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex 3dfa53c..188428d 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -823,6 +823,7 @@ extern unsigned ws_check(const char *line, int len, unsigned ws_rule);\n extern void ws_check_emit(const char *line, int len, unsigned ws_rule, FILE *stream, const char *set, const char *reset, const char *ws);\n extern char *whitespace_error_string(unsigned ws);\n extern int ws_fix_copy(char *, const char *, int, unsigned, int *);\n+extern int ws_blank_line(const char *line, int len, unsigned ws_rule);\n \n /* ls-files */\n int pathspec_match(const char **spec, char *matched, const char *filename, int skiplen);\ndiff --git a/diff.c b/diff.c\nindex 6bcbe20..f31c721 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -1140,6 +1140,7 @@ struct checkdiff_t {\n \tstruct diff_options *o;\n \tunsigned ws_rule;\n \tunsigned status;\n+\tint trailing_blanks_start;\n };\n \n static void checkdiff_consume(void *priv, char *line, unsigned long len)\n@@ -1154,6 +1155,10 @@ static void checkdiff_consume(void *priv, char *line, unsigned long len)\n \tif (line[0] == '+') {\n \t\tunsigned bad;\n \t\tdata->lineno++;\n+\t\tif (!ws_blank_line(line + 1, len - 1, data->ws_rule))\n+\t\t\tdata->trailing_blanks_start = 0;\n+\t\telse if (!data->trailing_blanks_start)\n+\t\t\tdata->trailing_blanks_start = data->lineno;\n \t\tbad = ws_check(line + 1, len - 1, data->ws_rule);\n \t\tif (!bad)\n \t\t\treturn;\n@@ -1165,14 +1170,16 @@ static void checkdiff_consume(void *priv, char *line, unsigned long len)\n \t\temit_line(data->o->file, set, reset, line, 1);\n \t\tws_check_emit(line + 1, len - 1, data->ws_rule,\n \t\t\t      data->o->file, set, reset, ws);\n-\t} else if (line[0] == ' ')\n+\t} else if (line[0] == ' ') {\n \t\tdata->lineno++;\n-\telse if (line[0] == '@') {\n+\t\tdata->trailing_blanks_start = 0;\n+\t} else if (line[0] == '@') {\n \t\tchar *plus = strchr(line, '+');\n \t\tif (plus)\n \t\t\tdata->lineno = strtol(plus, NULL, 10) - 1;\n \t\telse\n \t\t\tdie(\"invalid diff\");\n+\t\tdata->trailing_blanks_start = 0;\n \t}\n }\n \n@@ -1584,6 +1591,12 @@ static void builtin_checkdiff(const char *name_a, const char *name_b,\n \t\tecb.outf = xdiff_outf;\n \t\tecb.priv = &data;\n \t\txdi_diff(&mf1, &mf2, &xpp, &xecfg, &ecb);\n+\n+\t\tif (data.trailing_blanks_start) {\n+\t\t\tfprintf(o->file, \"%s:%d: ends with blank lines.\\n\",\n+\t\t\t\tdata.filename, data.trailing_blanks_start);\n+\t\t\tdata.status = 1; /* report errors */\n+\t\t}\n \t}\n  free_and_return:\n \tdiff_free_filespec_data(one);\ndiff --git a/t/t4015-diff-whitespace.sh b/t/t4015-diff-whitespace.sh\nindex b7cc6b2..0922c70 100755\n--- a/t/t4015-diff-whitespace.sh\n+++ b/t/t4015-diff-whitespace.sh\n@@ -335,4 +335,10 @@ test_expect_success 'line numbers in --check output are correct' '\n \n '\n \n+test_expect_success 'checkdiff detects trailing blank lines' '\n+\techo \"foo();\" >x &&\n+\techo \"\" >>x &&\n+\tgit diff --check | grep \"ends with blank\"\n+'\n+\n test_done\ndiff --git a/ws.c b/ws.c\nindex 24d3e3d..7a7ff13 100644\n--- a/ws.c\n+++ b/ws.c\n@@ -225,6 +225,21 @@ unsigned ws_check(const char *line, int len, unsigned ws_rule)\n \treturn ws_check_emit_1(line, len, ws_rule, NULL, NULL, NULL, NULL);\n }\n \n+int ws_blank_line(const char *line, int len, unsigned ws_rule)\n+{\n+\t/*\n+\t * We _might_ want to treat CR differently from other\n+\t * whitespace characters when ws_rule has WS_CR_AT_EOL, but\n+\t * for now we just use this stupid definition.\n+\t */\n+\twhile (len-- > 0) {\n+\t\tif (!isspace(*line))\n+\t\t\treturn 0;\n+\t\tline++;\n+\t}\n+\treturn 1;\n+}\n+\n /* Copy the line to the buffer while fixing whitespaces */\n int ws_fix_copy(char *dst, const char *src, int len, unsigned ws_rule, int *error_count)\n {\n-- \n1.5.6.1.78.gde8d9\n"},{"id":"81337","messageId":"7vwskbomam.fsf_-_@gitster.siamese.dyndns.org","threadId":"14127","inReplyTo":"7vk5gbq10p.fsf@gitster.siamese.dyndns.org","subject":"[PATCH 5/5] diff --check: detect leftover conflict markers","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-06-26T22:37:21Z","receivedAt":"2008-06-26T22:37:21Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This teaches \"diff --check\" to detect and complain if new lines\nhave lines that look like leftover conflict markers.\n\nWe should be able to remove the old Perl script used in the sample\npre-commit hook and modernize the script with this facility.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n diff.c                 |   35 +++++++++++++++++++++++++++++++++++\n t/t4017-diff-retval.sh |   14 ++++++++++++++\n 2 files changed, 49 insertions(+), 0 deletions(-)\n\ndiff --git a/diff.c b/diff.c\nindex f31c721..d515b06 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -1143,6 +1143,35 @@ struct checkdiff_t {\n \tint trailing_blanks_start;\n };\n \n+static int is_conflict_marker(const char *line, unsigned long len)\n+{\n+\tchar firstchar;\n+\tint cnt;\n+\n+\tif (len < 8)\n+\t\treturn 0;\n+\tfirstchar = line[0];\n+\tswitch (firstchar) {\n+\tcase '=': case '>': case '<':\n+\t\tbreak;\n+\tdefault:\n+\t\treturn 0;\n+\t}\n+\tfor (cnt = 1; cnt < 7; cnt++)\n+\t\tif (line[cnt] != firstchar)\n+\t\t\treturn 0;\n+\t/* line[0] thru line[6] are same as firstchar */\n+\tif (firstchar == '=') {\n+\t\t/* divider between ours and theirs? */\n+\t\tif (len != 8 || line[7] != '\\n')\n+\t\t\treturn 0;\n+\t} else if (len < 8 || !isspace(line[7])) {\n+\t\t/* not divider before ours nor after theirs */\n+\t\treturn 0;\n+\t}\n+\treturn 1;\n+}\n+\n static void checkdiff_consume(void *priv, char *line, unsigned long len)\n {\n \tstruct checkdiff_t *data = priv;\n@@ -1159,6 +1188,12 @@ static void checkdiff_consume(void *priv, char *line, unsigned long len)\n \t\t\tdata->trailing_blanks_start = 0;\n \t\telse if (!data->trailing_blanks_start)\n \t\t\tdata->trailing_blanks_start = data->lineno;\n+\t\tif (is_conflict_marker(line + 1, len - 1)) {\n+\t\t\tdata->status |= 1;\n+\t\t\tfprintf(data->o->file,\n+\t\t\t\t\"%s:%d: leftover conflict marker\\n\",\n+\t\t\t\tdata->filename, data->lineno);\n+\t\t}\n \t\tbad = ws_check(line + 1, len - 1, data->ws_rule);\n \t\tif (!bad)\n \t\t\treturn;\ndiff --git a/t/t4017-diff-retval.sh b/t/t4017-diff-retval.sh\nindex 0d0fb87..d748d45 100755\n--- a/t/t4017-diff-retval.sh\n+++ b/t/t4017-diff-retval.sh\n@@ -113,4 +113,18 @@ test_expect_success 'check should test not just the last line' '\n \n '\n \n+test_expect_success 'check detects leftover conflict markers' '\n+\tgit reset --hard &&\n+\tgit checkout HEAD^ &&\n+\techo binary >>b &&\n+\tgit commit -m \"side\" b &&\n+\ttest_must_fail git merge master &&\n+\tgit add b && (\n+\t\tgit --no-pager diff --cached --check >test.out\n+\t\ttest $? = 2\n+\t) &&\n+\ttest \"$(grep \"conflict marker\" test.out | wc -l)\" = 3 &&\n+\tgit reset --hard\n+'\n+\n test_done\n-- \n1.5.6.1.78.gde8d9\n"},{"id":"81338","messageId":"7vprq3ol63.fsf@gitster.siamese.dyndns.org","threadId":"14127","inReplyTo":"7vk5gbq10p.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH v2] pre-commit hook should ignore carriage returns at EOL","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-06-26T23:01:40Z","receivedAt":"2008-06-26T23:01:40Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Christian Holtje <docwhat@gmail.com> writes:\n>\n>>> I suggested using \"diff --check\" (and possibly teaching \"diff --check\"\n>>> other things the scripted example checks, such as conflict markers),\n>>> which would know to honor the line endings specified per path via\n>>> gitattributes(5), instead of building on top of the big Perl script,\n>>> and I\n>>> had an impression that you agreed to the approach.\n>>\n>> I'm completely confused how gitattributes and core.autocrlf interact,\n>> etc.\n>\n> Here is a series I just cooked up so that we can remove the whole Perl\n> script and replace it by adding --check to \"diff-index\" used there. \n>\n> The first three are code clean-ups and the last two implements necessary\n> new features to \"diff --check\".  The whole series somewhat depend on the\n> fix to 'maint' not to lose the exit status I sent earlier.\n>\n> [PATCH 1/5] diff --check: explain why we do not care whether old side is binary\n> [PATCH 2/5] check_and_emit_line(): rename and refactor\n> [PATCH 3/5] checkdiff: pass diff_options to the callback\n> [PATCH 4/5] Teach \"diff --check\" about a new blank lines at end\n> [PATCH 5/5] diff --check: detect leftover conflict markers\n\nWith these enhancements in place, I think the pre-commit hook to find\nproblematic change would become essentially a one-liner, something like:\n\n\tgit diff-index --check -M --cached\n\nand the checking will obey what you configured with core.whitespace, which\nglobally defines what kind of whitespace breakages are \"problematic\",\nand/or whitespace attribute which determines the same per path.\n\nIf you have for example Python source files that you would want all the\ndefault whitespace checks (that is, trailing whitespaces are not allowed,\ninitial indentation part should not have SP followed by HT), you would\nhave\n\n\t*.py whitespace=trail,space-before-tab\n\nin your .gitattributes, and the above command would catch such a\nbreakage.  If you further want to catch indentation with more than 8\nSPs that can be replaced with HTs in your C sources, you would say:\n\n\t*.[ch] whitespace=indent-with-no-tab,trail,space-before-tab\n\nYou could choose to have CRLF line endings in the repository [*1*], and\nfor such projects, diff output would have tons of lines that end with\nCRs.  To consider these CRs part of the line terminator, add cr-at-eol\nto the value of whitespace attribute, like so:\n\n\t*.py whitespace=trail,space,cr-at-eol\n\t*.[ch] whitespace=indent,trail,space,cr-at-eol\n\n[Footnote]\n\n*1* I do not do Windows, but my understanding is that this practice is not\nrecommended because it would hurt cross-platform use of the project.  You\nwould instead keep your repository copy with LF line endings, and make\nyour checkouts have CRLF line endings by core.autocrlf configuration.\n"},{"id":"81339","messageId":"7vlk0rokxb.fsf@gitster.siamese.dyndns.org","threadId":"14127","inReplyTo":"7vprq3ol63.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH v2] pre-commit hook should ignore carriage returns at EOL","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-06-26T23:06:56Z","receivedAt":"2008-06-26T23:06:56Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> With these enhancements in place, I think the pre-commit hook to find\n> problematic change would become essentially a one-liner, something like:\n>\n> \tgit diff-index --check -M --cached\n\nMore specifically, it would be like this.\n\n templates/hooks--pre-commit.sample |   89 ++++++++----------------------------\n 1 files changed, 19 insertions(+), 70 deletions(-)\n\ndiff --git a/templates/hooks--pre-commit.sample b/templates/hooks--pre-commit.sample\ndissimilarity index 79%\nindex 71c10f2..c302ed1 100755\n--- a/templates/hooks--pre-commit.sample\n+++ b/templates/hooks--pre-commit.sample\n@@ -1,70 +1,19 @@\n-#!/bin/sh\n-#\n-# An example hook script to verify what is about to be committed.\n-# Called by git-commit with no arguments.  The hook should\n-# exit with non-zero status after issuing an appropriate message if\n-# it wants to stop the commit.\n-#\n-# To enable this hook, rename this file to \"pre-commit\".\n-\n-# This is slightly modified from Andrew Morton's Perfect Patch.\n-# Lines you introduce should not have trailing whitespace.\n-# Also check for an indentation that has SP before a TAB.\n-\n-if git-rev-parse --verify HEAD 2>/dev/null\n-then\n-\tgit-diff-index -p -M --cached HEAD --\n-else\n-\t# NEEDSWORK: we should produce a diff with an empty tree here\n-\t# if we want to do the same verification for the initial import.\n-\t:\n-fi |\n-perl -e '\n-    my $found_bad = 0;\n-    my $filename;\n-    my $reported_filename = \"\";\n-    my $lineno;\n-    sub bad_line {\n-\tmy ($why, $line) = @_;\n-\tif (!$found_bad) {\n-\t    print STDERR \"*\\n\";\n-\t    print STDERR \"* You have some suspicious patch lines:\\n\";\n-\t    print STDERR \"*\\n\";\n-\t    $found_bad = 1;\n-\t}\n-\tif ($reported_filename ne $filename) {\n-\t    print STDERR \"* In $filename\\n\";\n-\t    $reported_filename = $filename;\n-\t}\n-\tprint STDERR \"* $why (line $lineno)\\n\";\n-\tprint STDERR \"$filename:$lineno:$line\\n\";\n-    }\n-    while (<>) {\n-\tif (m|^diff --git a/(.*) b/\\1$|) {\n-\t    $filename = $1;\n-\t    next;\n-\t}\n-\tif (/^@@ -\\S+ \\+(\\d+)/) {\n-\t    $lineno = $1 - 1;\n-\t    next;\n-\t}\n-\tif (/^ /) {\n-\t    $lineno++;\n-\t    next;\n-\t}\n-\tif (s/^\\+//) {\n-\t    $lineno++;\n-\t    chomp;\n-\t    if (/\\s$/) {\n-\t\tbad_line(\"trailing whitespace\", $_);\n-\t    }\n-\t    if (/^\\s* \\t/) {\n-\t\tbad_line(\"indent SP followed by a TAB\", $_);\n-\t    }\n-\t    if (/^([<>])\\1{6} |^={7}$/) {\n-\t\tbad_line(\"unresolved merge conflict\", $_);\n-\t    }\n-\t}\n-    }\n-    exit($found_bad);\n-'\n+#!/bin/sh\n+#\n+# An example hook script to verify what is about to be committed.\n+# Called by git-commit with no arguments.  The hook should\n+# exit with non-zero status after issuing an appropriate message if\n+# it wants to stop the commit.\n+#\n+# To enable this hook, rename this file to \"pre-commit\".\n+\n+if git-rev-parse --verify HEAD 2>/dev/null\n+then\n+\tagainst=\n+else\n+\t# Initial commit: diff against an empty tree object\n+\tagainst=4b825dc642cb6eb9a060e54bf8d69288fbee4904\n+fi\n+\n+exec git diff-index --check --cached $against\n+\n"},{"id":"81360","messageId":"20080627042446.GD7144@sigill.intra.peff.net","threadId":"14127","inReplyTo":"7vlk0rokxb.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH v2] pre-commit hook should ignore carriage returns at EOL","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2008-06-27T04:24:46Z","receivedAt":"2008-06-27T04:24:46Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Jun 26, 2008 at 04:06:56PM -0700, Junio C Hamano wrote:\n\n> +if git-rev-parse --verify HEAD 2>/dev/null\n> +then\n> +\tagainst=\n> +else\n> +\t# Initial commit: diff against an empty tree object\n> +\tagainst=4b825dc642cb6eb9a060e54bf8d69288fbee4904\n> +fi\n\nHeh, I am happy that the virtual empty tree object is coming in handy\nagain.\n\n>From quick review, the series looks good to me (and it was, btw, very\neasy to read -- I think that you, as somebody who reviews a lot of\npatches, have gotten very good at splitting up your own sensibly. :) ).\n\n-Peff\n"}]}