{"thread":{"id":"50442","subject":"[PATCH v1 0/3] Add post-indexchanged hook","startedAt":"2019-02-08T19:51:27Z","lastAt":"2019-02-15T18:03:00Z","messageCount":13,"participants":["Ben Peart","brian m. carlson","Ramsay Jones","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":3},"messages":[{"id":"368867","messageId":"20190208195115.12156-1-peartben@gmail.com","threadId":"50442","inReplyTo":null,"subject":"[PATCH v1 0/3] Add post-indexchanged hook","fromName":"Ben Peart","fromEmail":"peartben@gmail.com","sentAt":"2019-02-08T19:51:12Z","receivedAt":"2019-02-08T19:51:27Z","isPatch":true,"sender":{"key":"benpeart@microsoft.com","avatar":"https://avatars.githubusercontent.com/u/15252029?v=4"},"body":"From: Ben Peart <benpeart@microsoft.com>\n\nAdd a post-indexchanged hook that is invoked after the index is written in\ndo_write_locked_index().\n\nThis hook is meant primarily for notification, and cannot affect\nthe outcome of git commands that trigger the index write.\n\nVFSForGit uses this hook to be notified when a git command has made a\nchange that could impact the virtual files projected in the working\ndirectory.\n\nI'm submitting this in an effort to further minimize the set of differences\nbetween the VFSForGit fork and git.git in the hope that we can someday\nnot need a separate fork at all.\n\nBase Ref: v2.21.0-rc0\nWeb-Diff: https://github.com/benpeart/git/commit/639e57486a\nCheckout: git fetch https://github.com/benpeart/git post-index-changed-v1 && git checkout 639e57486a\n\nBen Peart (2):\n  read-cache: add post-indexchanged hook\n  read-cache: add test for post-indexchanged hook\n\nKevin Willford (1):\n  read-cache: Add documentation for the post-indexchanged hook\n\n Documentation/githooks.txt         |  18 ++++\n builtin/reset.c                    |   1 +\n builtin/update-index.c             |   2 +\n cache.h                            |   4 +-\n read-cache.c                       |  14 ++-\n t/t7113-post-index-changed-hook.sh | 144 +++++++++++++++++++++++++++++\n unpack-trees.c                     |   2 +\n 7 files changed, 182 insertions(+), 3 deletions(-)\n create mode 100755 t/t7113-post-index-changed-hook.sh\n\n\nbase-commit: d62dad7a7dca3f6a65162bf0e52cdf6927958e78\n-- \n2.20.1.windows.1\n\n\n"},{"id":"368868","messageId":"20190208195115.12156-2-peartben@gmail.com","threadId":"50442","inReplyTo":"20190208195115.12156-1-peartben@gmail.com","subject":"[PATCH v1 1/3] read-cache: add post-indexchanged hook","fromName":"Ben Peart","fromEmail":"peartben@gmail.com","sentAt":"2019-02-08T19:51:13Z","receivedAt":"2019-02-08T19:51:29Z","isPatch":true,"sender":{"key":"benpeart@microsoft.com","avatar":"https://avatars.githubusercontent.com/u/15252029?v=4"},"body":"From: Ben Peart <benpeart@microsoft.com>\n\nAdd a post-indexchanged hook that is invoked after the index is written in\ndo_write_locked_index().\n\nThis hook is meant primarily for notification, and cannot affect\nthe outcome of git commands that trigger the index write.\n\nSigned-off-by: Ben Peart <benpeart@microsoft.com>\n---\n builtin/reset.c        |  1 +\n builtin/update-index.c |  2 ++\n cache.h                |  4 +++-\n read-cache.c           | 14 ++++++++++++--\n unpack-trees.c         |  2 ++\n 5 files changed, 20 insertions(+), 3 deletions(-)\n\ndiff --git a/builtin/reset.c b/builtin/reset.c\nindex 4d18a461fa..e173afcaac 100644\n--- a/builtin/reset.c\n+++ b/builtin/reset.c\n@@ -380,6 +380,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)\n \t\t\tint flags = quiet ? REFRESH_QUIET : REFRESH_IN_PORCELAIN;\n \t\t\tif (read_from_tree(&pathspec, &oid, intent_to_add))\n \t\t\t\treturn 1;\n+\t\t\tthe_index.updated_skipworktree = 1;\n \t\t\tif (!quiet && get_git_work_tree()) {\n \t\t\t\tuint64_t t_begin, t_delta_in_ms;\n \ndiff --git a/builtin/update-index.c b/builtin/update-index.c\nindex 02ace602b9..cf731640fa 100644\n--- a/builtin/update-index.c\n+++ b/builtin/update-index.c\n@@ -1071,6 +1071,8 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)\n \tif (entries < 0)\n \t\tdie(\"cache corrupted\");\n \n+\tthe_index.updated_skipworktree = 1;\n+\n \t/*\n \t * Custom copy of parse_options() because we want to handle\n \t * filename arguments as they come.\ndiff --git a/cache.h b/cache.h\nindex 27fe635f62..46eb862d3e 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -338,7 +338,9 @@ struct index_state {\n \tstruct cache_time timestamp;\n \tunsigned name_hash_initialized : 1,\n \t\t initialized : 1,\n-\t\t drop_cache_tree : 1;\n+\t\t drop_cache_tree : 1,\n+\t\t updated_workdir : 1,\n+\t\t updated_skipworktree : 1;\n \tstruct hashmap name_hash;\n \tstruct hashmap dir_hash;\n \tstruct object_id oid;\ndiff --git a/read-cache.c b/read-cache.c\nindex 0e0c93edc9..0fcfa8a075 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -17,6 +17,7 @@\n #include \"commit.h\"\n #include \"blob.h\"\n #include \"resolve-undo.h\"\n+#include \"run-command.h\"\n #include \"strbuf.h\"\n #include \"varint.h\"\n #include \"split-index.h\"\n@@ -2999,8 +3000,17 @@ static int do_write_locked_index(struct index_state *istate, struct lock_file *l\n \tif (ret)\n \t\treturn ret;\n \tif (flags & COMMIT_LOCK)\n-\t\treturn commit_locked_index(lock);\n-\treturn close_lock_file_gently(lock);\n+\t\tret = commit_locked_index(lock);\n+\telse\n+\t\tret = close_lock_file_gently(lock);\n+\n+\trun_hook_le(NULL, \"post-indexchanged\",\n+\t\t\tistate->updated_workdir ? \"1\" : \"0\",\n+\t\t\tistate->updated_skipworktree ? \"1\" : \"0\", NULL);\n+\tistate->updated_workdir = 0;\n+\tistate->updated_skipworktree = 0;\n+\n+\treturn ret;\n }\n \n static int write_split_index(struct index_state *istate,\ndiff --git a/unpack-trees.c b/unpack-trees.c\nindex 3563daae1a..8665a4a7c0 100644\n--- a/unpack-trees.c\n+++ b/unpack-trees.c\n@@ -1637,6 +1637,8 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options\n \t\t\t\t\t\t  WRITE_TREE_SILENT |\n \t\t\t\t\t\t  WRITE_TREE_REPAIR);\n \t\t}\n+\n+\t\to->result.updated_workdir = 1;\n \t\tdiscard_index(o->dst_index);\n \t\t*o->dst_index = o->result;\n \t} else {\n-- \n2.20.1.windows.1\n\n"},{"id":"368869","messageId":"20190208195115.12156-4-peartben@gmail.com","threadId":"50442","inReplyTo":"20190208195115.12156-1-peartben@gmail.com","subject":"[PATCH v1 3/3] read-cache: Add documentation for the post-indexchanged hook","fromName":"Ben Peart","fromEmail":"peartben@gmail.com","sentAt":"2019-02-08T19:51:15Z","receivedAt":"2019-02-08T19:51:31Z","isPatch":true,"sender":{"key":"benpeart@microsoft.com","avatar":"https://avatars.githubusercontent.com/u/15252029?v=4"},"body":"From: Kevin Willford <kewillf@microsoft.com>\n\nDocument the new post-indexchanged hook with information on when it is\ncalled as well as the flags passed and what each of them mean.\n\nSigned-off-by: Kevin Willford <kewillf@microsoft.com>\nSigned-off-by: Ben Peart <benpeart@microsoft.com>\n---\n Documentation/githooks.txt | 18 ++++++++++++++++++\n 1 file changed, 18 insertions(+)\n\ndiff --git a/Documentation/githooks.txt b/Documentation/githooks.txt\nindex 959044347e..9349cd8900 100644\n--- a/Documentation/githooks.txt\n+++ b/Documentation/githooks.txt\n@@ -492,6 +492,24 @@ This hook is invoked by `git-p4 submit`. It takes no parameters and nothing\n from standard input. Exiting with non-zero status from this script prevent\n `git-p4 submit` from launching. Run `git-p4 submit --help` for details.\n \n+post-indexchanged\n+~~~~~~~~~~~~~~~~~\n+\n+This hook is invoked when the index is written in read-cache.c\n+do_write_locked_index.\n+\n+The first parameter passed to the hook is the indicator for the\n+working directory being updated.  \"1\" meaning working directory\n+was updated or \"0\" when the working directory was not updated.\n+\n+The second parameter passed to the hook is the indicator for whether\n+or not the index was updated and the skip-worktree bit could have\n+changed.  \"1\" meaning skip-worktree bits could have been updated\n+and \"0\" meaning they were not.\n+\n+Only one parameter should be set to \"1\" when the hook runs.  The hook\n+running passing \"1\", \"1\" should not be possible.\n+\n GIT\n ---\n Part of the linkgit:git[1] suite\n-- \n2.20.1.windows.1\n\n"},{"id":"368870","messageId":"20190208195115.12156-3-peartben@gmail.com","threadId":"50442","inReplyTo":"20190208195115.12156-1-peartben@gmail.com","subject":"[PATCH v1 2/3] read-cache: add test for post-indexchanged hook","fromName":"Ben Peart","fromEmail":"peartben@gmail.com","sentAt":"2019-02-08T19:51:14Z","receivedAt":"2019-02-08T19:51:32Z","isPatch":true,"sender":{"key":"benpeart@microsoft.com","avatar":"https://avatars.githubusercontent.com/u/15252029?v=4"},"body":"From: Ben Peart <benpeart@microsoft.com>\n\nTest the new post-indexchanged hook and ensure it is triggered and passes\nthe correct flags for various git commands.\n\nSigned-off-by: Ben Peart <benpeart@microsoft.com>\n---\n t/t7113-post-index-changed-hook.sh | 144 +++++++++++++++++++++++++++++\n 1 file changed, 144 insertions(+)\n create mode 100755 t/t7113-post-index-changed-hook.sh\n\ndiff --git a/t/t7113-post-index-changed-hook.sh b/t/t7113-post-index-changed-hook.sh\nnew file mode 100755\nindex 0000000000..5aeb726e37\n--- /dev/null\n+++ b/t/t7113-post-index-changed-hook.sh\n@@ -0,0 +1,144 @@\n+#!/bin/sh\n+\n+test_description='post index changed hook'\n+\n+. ./test-lib.sh\n+\n+test_expect_success 'setup' '\n+\tmkdir -p dir1 &&\n+\ttouch dir1/file1.txt &&\n+\techo testing >dir1/file2.txt &&\n+\tgit add . &&\n+\tgit commit -m \"initial\"\n+'\n+\n+test_expect_success 'test status, add, commit, others trigger hook without flags set' '\n+\tmkdir -p .git/hooks &&\n+\twrite_script .git/hooks/post-indexchanged <<-\\EOF &&\n+\t\tif test \"$1\" -eq 1; then\n+\t\t\techo \"Invalid combination of flags passed to hook; updated_workdir is set.\" >testfailure\n+\t\t\texit 1\n+\t\tfi\n+\t\tif test \"$2\" -eq 1; then\n+\t\t\techo \"Invalid combination of flags passed to hook; updated_skipworktree is set.\" >testfailure\n+\t\t\texit 1\n+\t\tfi\n+\t\tif test -f \".git/index.lock\"; then\n+\t\t\techo \".git/index.lock exists\" >testfailure\n+\t\t\texit 3\n+\t\tfi\n+\t\tif ! test -f \".git/index\"; then\n+\t\t\techo \".git/index does not exist\" >testfailure\n+\t\t\texit 3\n+\t\tfi\n+\t\techo \"success\" >testsuccess\n+\tEOF\n+\tmkdir -p dir2 &&\n+\ttouch dir2/file1.txt &&\n+\ttouch dir2/file2.txt &&\n+\t: force index to be dirty &&\n+\ttest-tool chmtime +60 dir1/file1.txt &&\n+\tgit status &&\n+\ttest_path_is_file testsuccess && rm -f testsuccess &&\n+\ttest_path_is_missing testfailure &&\n+\tgit add . &&\n+\ttest_path_is_file testsuccess && rm -f testsuccess &&\n+\ttest_path_is_missing testfailure &&\n+\tgit commit -m \"second\" &&\n+\ttest_path_is_file testsuccess && rm -f testsuccess &&\n+\ttest_path_is_missing testfailure &&\n+\tgit checkout -- dir1/file1.txt &&\n+\ttest_path_is_file testsuccess && rm -f testsuccess &&\n+\ttest_path_is_missing testfailure &&\n+\tgit update-index &&\n+\ttest_path_is_missing testsuccess &&\n+\ttest_path_is_missing testfailure &&\n+\tgit reset --soft &&\n+\ttest_path_is_missing testsuccess &&\n+\ttest_path_is_missing testfailure\n+'\n+\n+test_expect_success 'test checkout and reset trigger the hook' '\n+\twrite_script .git/hooks/post-indexchanged <<-\\EOF &&\n+\t\tif test \"$1\" -eq 1 && test \"$2\" -eq 1; then\n+\t\t\techo \"Invalid combination of flags passed to hook; updated_workdir and updated_skipworktree are both set.\" >testfailure\n+\t\t\texit 1\n+\t\tfi\n+\t\tif test \"$1\" -eq 0 && test \"$2\" -eq 0; then\n+\t\t\techo \"Invalid combination of flags passed to hook; neither updated_workdir or updated_skipworktree are set.\" >testfailure\n+\t\t\texit 2\n+\t\tfi\n+\t\tif test \"$1\" -eq 1; then\n+\t\t\tif test -f \".git/index.lock\"; then\n+\t\t\t\techo \"updated_workdir set but .git/index.lock exists\" >testfailure\n+\t\t\t\texit 3\n+\t\t\tfi\n+\t\t\tif ! test -f \".git/index\"; then\n+\t\t\t\techo \"updated_workdir set but .git/index does not exist\" >testfailure\n+\t\t\t\texit 3\n+\t\t\tfi\n+\t\telse\n+\t\t\techo \"update_workdir should be set for checkout\" >testfailure\n+\t\t\texit 4\n+\t\tfi\n+\t\techo \"success\" >testsuccess\n+\tEOF\n+\t: force index to be dirty &&\n+\ttest-tool chmtime +60 dir1/file1.txt &&\n+\tgit checkout master &&\n+\ttest_path_is_file testsuccess && rm -f testsuccess &&\n+\ttest_path_is_missing testfailure &&\n+\ttest-tool chmtime +60 dir1/file1.txt &&\n+\tgit checkout HEAD &&\n+\ttest_path_is_file testsuccess && rm -f testsuccess &&\n+\ttest_path_is_missing testfailure &&\n+\ttest-tool chmtime +60 dir1/file1.txt &&\n+\tgit reset --hard &&\n+\ttest_path_is_file testsuccess && rm -f testsuccess &&\n+\ttest_path_is_missing testfailure &&\n+\tgit checkout -B test &&\n+\ttest_path_is_file testsuccess && rm -f testsuccess &&\n+\ttest_path_is_missing testfailure\n+'\n+\n+test_expect_success 'test reset --mixed and update-index triggers the hook' '\n+\twrite_script .git/hooks/post-indexchanged <<-\\EOF &&\n+\t\tif test \"$1\" -eq 1 && test \"$2\" -eq 1; then\n+\t\t\techo \"Invalid combination of flags passed to hook; updated_workdir and updated_skipworktree are both set.\" >testfailure\n+\t\t\texit 1\n+\t\tfi\n+\t\tif test \"$1\" -eq 0 && test \"$2\" -eq 0; then\n+\t\t\techo \"Invalid combination of flags passed to hook; neither updated_workdir or updated_skipworktree are set.\" >testfailure\n+\t\t\texit 2\n+\t\tfi\n+\t\tif test \"$2\" -eq 1; then\n+\t\t\tif test -f \".git/index.lock\"; then\n+\t\t\t\techo \"updated_skipworktree set but .git/index.lock exists\" >testfailure\n+\t\t\t\texit 3\n+\t\t\tfi\n+\t\t\tif ! test -f \".git/index\"; then\n+\t\t\t\techo \"updated_skipworktree set but .git/index does not exist\" >testfailure\n+\t\t\t\texit 3\n+\t\t\tfi\n+\t\telse\n+\t\t\techo \"updated_skipworktree should be set for reset --mixed and update-index\" >testfailure\n+\t\t\texit 4\n+\t\tfi\n+\t\techo \"success\" >testsuccess\n+\tEOF\n+\t: force index to be dirty &&\n+\ttest-tool chmtime +60 dir1/file1.txt &&\n+\tgit reset --mixed --quiet HEAD~1 &&\n+\ttest_path_is_file testsuccess && rm -f testsuccess &&\n+\ttest_path_is_missing testfailure &&\n+\tgit hash-object -w --stdin <dir1/file2.txt >expect &&\n+\tgit update-index --cacheinfo 100644 \"$(cat expect)\" dir1/file1.txt &&\n+\ttest_path_is_file testsuccess && rm -f testsuccess &&\n+\ttest_path_is_missing testfailure &&\n+\tgit update-index --skip-worktree dir1/file2.txt &&\n+\tgit update-index --remove dir1/file2.txt &&\n+\ttest_path_is_file testsuccess && rm -f testsuccess &&\n+\ttest_path_is_missing testfailure\n+'\n+\n+test_done\n-- \n2.20.1.windows.1\n\n"},{"id":"368902","messageId":"20190208235317.GI11927@genre.crustytoothpaste.net","threadId":"50442","inReplyTo":"20190208195115.12156-2-peartben@gmail.com","subject":"Re: [PATCH v1 1/3] read-cache: add post-indexchanged hook","fromName":"brian m. carlson","fromEmail":"sandals@crustytoothpaste.net","sentAt":"2019-02-08T23:53:17Z","receivedAt":"2019-02-08T23:53:25Z","isPatch":true,"sender":{"key":"sandals@crustytoothpaste.net","avatar":"https://avatars.githubusercontent.com/u/497054?v=4"},"body":"On Fri, Feb 08, 2019 at 02:51:13PM -0500, Ben Peart wrote:\n> From: Ben Peart <benpeart@microsoft.com>\n> \n> Add a post-indexchanged hook that is invoked after the index is written in\n> do_write_locked_index().\n> \n> This hook is meant primarily for notification, and cannot affect\n> the outcome of git commands that trigger the index write.\n> \n> Signed-off-by: Ben Peart <benpeart@microsoft.com>\n\nFirst, I think the tests should be merged into this commit. That's what\nwe typically do.\n\nI'm also going to bikeshed slightly and suggest \"post-index-changed\",\nsince we normally use dashes between words in our hook names.\n\n> diff --git a/cache.h b/cache.h\n> index 27fe635f62..46eb862d3e 100644\n> --- a/cache.h\n> +++ b/cache.h\n> @@ -338,7 +338,9 @@ struct index_state {\n>  \tstruct cache_time timestamp;\n>  \tunsigned name_hash_initialized : 1,\n>  \t\t initialized : 1,\n> -\t\t drop_cache_tree : 1;\n> +\t\t drop_cache_tree : 1,\n> +\t\t updated_workdir : 1,\n> +\t\t updated_skipworktree : 1;\n\nHow important is it that we expose whether the skip-worktree bit is\nchanged? I can understand if we expose the workdir is updated, since\nthat's a thing a general user of this hook is likely to be interested\nin. However, I'm not sure that for a general-purpose hook, the\nskip-worktree bit is interesting.\n\n> diff --git a/read-cache.c b/read-cache.c\n> index 0e0c93edc9..0fcfa8a075 100644\n> --- a/read-cache.c\n> +++ b/read-cache.c\n> @@ -17,6 +17,7 @@\n>  #include \"commit.h\"\n>  #include \"blob.h\"\n>  #include \"resolve-undo.h\"\n> +#include \"run-command.h\"\n>  #include \"strbuf.h\"\n>  #include \"varint.h\"\n>  #include \"split-index.h\"\n> @@ -2999,8 +3000,17 @@ static int do_write_locked_index(struct index_state *istate, struct lock_file *l\n>  \tif (ret)\n>  \t\treturn ret;\n>  \tif (flags & COMMIT_LOCK)\n> -\t\treturn commit_locked_index(lock);\n> -\treturn close_lock_file_gently(lock);\n> +\t\tret = commit_locked_index(lock);\n> +\telse\n> +\t\tret = close_lock_file_gently(lock);\n> +\n> +\trun_hook_le(NULL, \"post-indexchanged\",\n> +\t\t\tistate->updated_workdir ? \"1\" : \"0\",\n> +\t\t\tistate->updated_skipworktree ? \"1\" : \"0\", NULL);\n\nI have, in general, some concerns about this API. First, I think we need\nto consider that if we're going to expose various bits of information,\nwe might in the future want to expose more such bits. If so, adding\ninteger parameters is not likely to be a good way to do this. It's hard\nto remember and if a binary is used as the hook, it may not always\nhandle additional arguments gracefully like shell scripts tend to.\n\nIf we're not going to expose the skip-worktree bit, then I suppose one\nargument is fine. Otherwise, it might be better to expose key-value\npairs on stdin instead, or something like that.\n\nFinally, I have questions about performance. What's the overhead of\ndetermining whether the hook exists in this code path when there isn't\none? Since the index is frequently used, and can be written out as an\noptimization by some commands, it would be nice to keep overhead low if\nthe hook isn't present.\n-- \nbrian m. carlson: Houston, Texas, US\nOpenPGP: https://keybase.io/bk2204\n"},{"id":"369174","messageId":"782f0801-a207-96c9-2f1c-ed7939a9e3a5@gmail.com","threadId":"50442","inReplyTo":"20190208235317.GI11927@genre.crustytoothpaste.net","subject":"Re: [PATCH v1 1/3] read-cache: add post-indexchanged hook","fromName":"Ben Peart","fromEmail":"peartben@gmail.com","sentAt":"2019-02-12T17:39:56Z","receivedAt":"2019-02-12T17:40:01Z","isPatch":true,"sender":{"key":"benpeart@microsoft.com","avatar":"https://avatars.githubusercontent.com/u/15252029?v=4"},"body":"\n\nOn 2/8/2019 6:53 PM, brian m. carlson wrote:\n> On Fri, Feb 08, 2019 at 02:51:13PM -0500, Ben Peart wrote:\n>> From: Ben Peart <benpeart@microsoft.com>\n>>\n>> Add a post-indexchanged hook that is invoked after the index is written in\n>> do_write_locked_index().\n>>\n>> This hook is meant primarily for notification, and cannot affect\n>> the outcome of git commands that trigger the index write.\n>>\n>> Signed-off-by: Ben Peart <benpeart@microsoft.com>\n> \n> First, I think the tests should be merged into this commit. That's what\n> we typically do.\n\nHappy to.  In fact, I'd be happy to add the documentation as well and \nhave a single commit. That's what _I'd_ typically do for something small \nlike this. :)\n\n> \n> I'm also going to bikeshed slightly and suggest \"post-index-changed\",\n> since we normally use dashes between words in our hook names.\n> \n\nI can do that as well to help make it more consistent.\n\n>> diff --git a/cache.h b/cache.h\n>> index 27fe635f62..46eb862d3e 100644\n>> --- a/cache.h\n>> +++ b/cache.h\n>> @@ -338,7 +338,9 @@ struct index_state {\n>>   \tstruct cache_time timestamp;\n>>   \tunsigned name_hash_initialized : 1,\n>>   \t\t initialized : 1,\n>> -\t\t drop_cache_tree : 1;\n>> +\t\t drop_cache_tree : 1,\n>> +\t\t updated_workdir : 1,\n>> +\t\t updated_skipworktree : 1;\n> \n> How important is it that we expose whether the skip-worktree bit is\n> changed? I can understand if we expose the workdir is updated, since\n> that's a thing a general user of this hook is likely to be interested\n> in. However, I'm not sure that for a general-purpose hook, the\n> skip-worktree bit is interesting.\n> \n\nIn our use case, we needed the skip-worktree flag because if something \nclears the skip-worktree bit on a file, we need to start paying \nattention to it in the work directory.  This flag tells us that may have \nhappened and enables us to not have to do the extra work for other index \nchanged events that don't change the index without updating the working \ndirectory.\n\nInitially this was just to deal with 'reset --mixed' as it behaves \ndifferently with regards to updating the index and working directory \nthan most other commands.  However, the update-index command can also \narbitrarily clear the skip-worktree bit so we renamed the flag to be \nmore generic.\n\n>> diff --git a/read-cache.c b/read-cache.c\n>> index 0e0c93edc9..0fcfa8a075 100644\n>> --- a/read-cache.c\n>> +++ b/read-cache.c\n>> @@ -17,6 +17,7 @@\n>>   #include \"commit.h\"\n>>   #include \"blob.h\"\n>>   #include \"resolve-undo.h\"\n>> +#include \"run-command.h\"\n>>   #include \"strbuf.h\"\n>>   #include \"varint.h\"\n>>   #include \"split-index.h\"\n>> @@ -2999,8 +3000,17 @@ static int do_write_locked_index(struct index_state *istate, struct lock_file *l\n>>   \tif (ret)\n>>   \t\treturn ret;\n>>   \tif (flags & COMMIT_LOCK)\n>> -\t\treturn commit_locked_index(lock);\n>> -\treturn close_lock_file_gently(lock);\n>> +\t\tret = commit_locked_index(lock);\n>> +\telse\n>> +\t\tret = close_lock_file_gently(lock);\n>> +\n>> +\trun_hook_le(NULL, \"post-indexchanged\",\n>> +\t\t\tistate->updated_workdir ? \"1\" : \"0\",\n>> +\t\t\tistate->updated_skipworktree ? \"1\" : \"0\", NULL);\n> \n> I have, in general, some concerns about this API. First, I think we need\n> to consider that if we're going to expose various bits of information,\n> we might in the future want to expose more such bits. If so, adding\n> integer parameters is not likely to be a good way to do this. It's hard\n> to remember and if a binary is used as the hook, it may not always\n> handle additional arguments gracefully like shell scripts tend to.\n> \n\nBinaries deal with a variable number of arguments all the time via `int \nargc, const char **argv` so this isn't a problem (we actually use a \nbinary for this hook already).\n\n> If we're not going to expose the skip-worktree bit, then I suppose one\n> argument is fine. Otherwise, it might be better to expose key-value\n> pairs on stdin instead, or something like that.\n> \n\nI'm not sure what else we may want to add in the future; this is all \nwe've needed for our uses.  For now, I'd suggest we keep it simple and \njust pass them as command line parameters like we do with the other \nhooks.  It's easy to add additional arguments in the future and if we \never get to where that is unwieldy, we can address it then (YAGNI).\n\n> Finally, I have questions about performance. What's the overhead of\n> determining whether the hook exists in this code path when there isn't\n> one? Since the index is frequently used, and can be written out as an\n> optimization by some commands, it would be nice to keep overhead low if\n> the hook isn't present.\n> \n\nIf you ever hit this code path, we've just updated the index which means \nwe read the index file, did an lstat() on every file in the repo plus \nvarious refs, config files, etc, and then wrote out a new index file. \nAdding one more test for a hooks existence doesn't have any measurable \nimpact.\n\nThank you for the feedback!\n\n"},{"id":"369311","messageId":"20190214144241.11240-1-peartben@gmail.com","threadId":"50442","inReplyTo":"20190208195115.12156-1-peartben@gmail.com","subject":"[PATCH v2] read-cache: add post-indexchanged hook","fromName":"Ben Peart","fromEmail":"peartben@gmail.com","sentAt":"2019-02-14T14:42:41Z","receivedAt":"2019-02-14T14:42:55Z","isPatch":true,"sender":{"key":"benpeart@microsoft.com","avatar":"https://avatars.githubusercontent.com/u/15252029?v=4"},"body":"From: Ben Peart <benpeart@microsoft.com>\n\nAdd a post-indexchanged hook that is invoked after the index is written in\ndo_write_locked_index().\n\nThis hook is meant primarily for notification, and cannot affect\nthe outcome of git commands that trigger the index write.\n\nThe hook is passed a flag to indicate whether the working directory was\nupdated or not and a flag indicating if a skip-worktree bit could have\nchanged.  These flags enable the hook to optmize its response to the\nindex changed notification.\n\nSigned-off-by: Ben Peart <benpeart@microsoft.com>\n---\n\nNotes:\n    Base Ref: v2.21.0-rc0\n    Web-Diff: https://github.com/benpeart/git/commit/03b96ccbd5\n    Checkout: git fetch https://github.com/benpeart/git post-index-changed-v2 && git checkout 03b96ccbd5\n    \n    ### Interdiff (v1..v2):\n    \n    diff --git a/Documentation/githooks.txt b/Documentation/githooks.txt\n    index 9349cd8900..94b4dadf30 100644\n    --- a/Documentation/githooks.txt\n    +++ b/Documentation/githooks.txt\n    @@ -492,7 +492,7 @@ This hook is invoked by `git-p4 submit`. It takes no parameters and nothing\n     from standard input. Exiting with non-zero status from this script prevent\n     `git-p4 submit` from launching. Run `git-p4 submit --help` for details.\n    \n    -post-indexchanged\n    +post-index-changed\n     ~~~~~~~~~~~~~~~~~\n    \n     This hook is invoked when the index is written in read-cache.c\n    diff --git a/read-cache.c b/read-cache.c\n    index 0fcfa8a075..b6ead7bf8f 100644\n    --- a/read-cache.c\n    +++ b/read-cache.c\n    @@ -3004,7 +3004,7 @@ static int do_write_locked_index(struct index_state *istate, struct lock_file *l\n     \telse\n     \t\tret = close_lock_file_gently(lock);\n    \n    -\trun_hook_le(NULL, \"post-indexchanged\",\n    +\trun_hook_le(NULL, \"post-index-changed\",\n     \t\t\tistate->updated_workdir ? \"1\" : \"0\",\n     \t\t\tistate->updated_skipworktree ? \"1\" : \"0\", NULL);\n     \tistate->updated_workdir = 0;\n    diff --git a/t/t7113-post-index-changed-hook.sh b/t/t7113-post-index-changed-hook.sh\n    index 5aeb726e37..6231b88fca 100755\n    --- a/t/t7113-post-index-changed-hook.sh\n    +++ b/t/t7113-post-index-changed-hook.sh\n    @@ -14,7 +14,7 @@ test_expect_success 'setup' '\n    \n     test_expect_success 'test status, add, commit, others trigger hook without flags set' '\n     \tmkdir -p .git/hooks &&\n    -\twrite_script .git/hooks/post-indexchanged <<-\\EOF &&\n    +\twrite_script .git/hooks/post-index-changed <<-\\EOF &&\n     \t\tif test \"$1\" -eq 1; then\n     \t\t\techo \"Invalid combination of flags passed to hook; updated_workdir is set.\" >testfailure\n     \t\t\texit 1\n    @@ -59,7 +59,7 @@ test_expect_success 'test status, add, commit, others trigger hook without flags\n     '\n    \n     test_expect_success 'test checkout and reset trigger the hook' '\n    -\twrite_script .git/hooks/post-indexchanged <<-\\EOF &&\n    +\twrite_script .git/hooks/post-index-changed <<-\\EOF &&\n     \t\tif test \"$1\" -eq 1 && test \"$2\" -eq 1; then\n     \t\t\techo \"Invalid combination of flags passed to hook; updated_workdir and updated_skipworktree are both set.\" >testfailure\n     \t\t\texit 1\n    @@ -102,7 +102,7 @@ test_expect_success 'test checkout and reset trigger the hook' '\n     '\n    \n     test_expect_success 'test reset --mixed and update-index triggers the hook' '\n    -\twrite_script .git/hooks/post-indexchanged <<-\\EOF &&\n    +\twrite_script .git/hooks/post-index-changed <<-\\EOF &&\n     \t\tif test \"$1\" -eq 1 && test \"$2\" -eq 1; then\n     \t\t\techo \"Invalid combination of flags passed to hook; updated_workdir and updated_skipworktree are both set.\" >testfailure\n     \t\t\texit 1\n    \n    ### Patches\n\n Documentation/githooks.txt         |  18 ++++\n builtin/reset.c                    |   1 +\n builtin/update-index.c             |   2 +\n cache.h                            |   4 +-\n read-cache.c                       |  14 ++-\n t/t7113-post-index-changed-hook.sh | 144 +++++++++++++++++++++++++++++\n unpack-trees.c                     |   2 +\n 7 files changed, 182 insertions(+), 3 deletions(-)\n create mode 100755 t/t7113-post-index-changed-hook.sh\n\ndiff --git a/Documentation/githooks.txt b/Documentation/githooks.txt\nindex 959044347e..94b4dadf30 100644\n--- a/Documentation/githooks.txt\n+++ b/Documentation/githooks.txt\n@@ -492,6 +492,24 @@ This hook is invoked by `git-p4 submit`. It takes no parameters and nothing\n from standard input. Exiting with non-zero status from this script prevent\n `git-p4 submit` from launching. Run `git-p4 submit --help` for details.\n \n+post-index-changed\n+~~~~~~~~~~~~~~~~~\n+\n+This hook is invoked when the index is written in read-cache.c\n+do_write_locked_index.\n+\n+The first parameter passed to the hook is the indicator for the\n+working directory being updated.  \"1\" meaning working directory\n+was updated or \"0\" when the working directory was not updated.\n+\n+The second parameter passed to the hook is the indicator for whether\n+or not the index was updated and the skip-worktree bit could have\n+changed.  \"1\" meaning skip-worktree bits could have been updated\n+and \"0\" meaning they were not.\n+\n+Only one parameter should be set to \"1\" when the hook runs.  The hook\n+running passing \"1\", \"1\" should not be possible.\n+\n GIT\n ---\n Part of the linkgit:git[1] suite\ndiff --git a/builtin/reset.c b/builtin/reset.c\nindex 4d18a461fa..e173afcaac 100644\n--- a/builtin/reset.c\n+++ b/builtin/reset.c\n@@ -380,6 +380,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)\n \t\t\tint flags = quiet ? REFRESH_QUIET : REFRESH_IN_PORCELAIN;\n \t\t\tif (read_from_tree(&pathspec, &oid, intent_to_add))\n \t\t\t\treturn 1;\n+\t\t\tthe_index.updated_skipworktree = 1;\n \t\t\tif (!quiet && get_git_work_tree()) {\n \t\t\t\tuint64_t t_begin, t_delta_in_ms;\n \ndiff --git a/builtin/update-index.c b/builtin/update-index.c\nindex 02ace602b9..cf731640fa 100644\n--- a/builtin/update-index.c\n+++ b/builtin/update-index.c\n@@ -1071,6 +1071,8 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)\n \tif (entries < 0)\n \t\tdie(\"cache corrupted\");\n \n+\tthe_index.updated_skipworktree = 1;\n+\n \t/*\n \t * Custom copy of parse_options() because we want to handle\n \t * filename arguments as they come.\ndiff --git a/cache.h b/cache.h\nindex 27fe635f62..46eb862d3e 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -338,7 +338,9 @@ struct index_state {\n \tstruct cache_time timestamp;\n \tunsigned name_hash_initialized : 1,\n \t\t initialized : 1,\n-\t\t drop_cache_tree : 1;\n+\t\t drop_cache_tree : 1,\n+\t\t updated_workdir : 1,\n+\t\t updated_skipworktree : 1;\n \tstruct hashmap name_hash;\n \tstruct hashmap dir_hash;\n \tstruct object_id oid;\ndiff --git a/read-cache.c b/read-cache.c\nindex 0e0c93edc9..b6ead7bf8f 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -17,6 +17,7 @@\n #include \"commit.h\"\n #include \"blob.h\"\n #include \"resolve-undo.h\"\n+#include \"run-command.h\"\n #include \"strbuf.h\"\n #include \"varint.h\"\n #include \"split-index.h\"\n@@ -2999,8 +3000,17 @@ static int do_write_locked_index(struct index_state *istate, struct lock_file *l\n \tif (ret)\n \t\treturn ret;\n \tif (flags & COMMIT_LOCK)\n-\t\treturn commit_locked_index(lock);\n-\treturn close_lock_file_gently(lock);\n+\t\tret = commit_locked_index(lock);\n+\telse\n+\t\tret = close_lock_file_gently(lock);\n+\n+\trun_hook_le(NULL, \"post-index-changed\",\n+\t\t\tistate->updated_workdir ? \"1\" : \"0\",\n+\t\t\tistate->updated_skipworktree ? \"1\" : \"0\", NULL);\n+\tistate->updated_workdir = 0;\n+\tistate->updated_skipworktree = 0;\n+\n+\treturn ret;\n }\n \n static int write_split_index(struct index_state *istate,\ndiff --git a/t/t7113-post-index-changed-hook.sh b/t/t7113-post-index-changed-hook.sh\nnew file mode 100755\nindex 0000000000..6231b88fca\n--- /dev/null\n+++ b/t/t7113-post-index-changed-hook.sh\n@@ -0,0 +1,144 @@\n+#!/bin/sh\n+\n+test_description='post index changed hook'\n+\n+. ./test-lib.sh\n+\n+test_expect_success 'setup' '\n+\tmkdir -p dir1 &&\n+\ttouch dir1/file1.txt &&\n+\techo testing >dir1/file2.txt &&\n+\tgit add . &&\n+\tgit commit -m \"initial\"\n+'\n+\n+test_expect_success 'test status, add, commit, others trigger hook without flags set' '\n+\tmkdir -p .git/hooks &&\n+\twrite_script .git/hooks/post-index-changed <<-\\EOF &&\n+\t\tif test \"$1\" -eq 1; then\n+\t\t\techo \"Invalid combination of flags passed to hook; updated_workdir is set.\" >testfailure\n+\t\t\texit 1\n+\t\tfi\n+\t\tif test \"$2\" -eq 1; then\n+\t\t\techo \"Invalid combination of flags passed to hook; updated_skipworktree is set.\" >testfailure\n+\t\t\texit 1\n+\t\tfi\n+\t\tif test -f \".git/index.lock\"; then\n+\t\t\techo \".git/index.lock exists\" >testfailure\n+\t\t\texit 3\n+\t\tfi\n+\t\tif ! test -f \".git/index\"; then\n+\t\t\techo \".git/index does not exist\" >testfailure\n+\t\t\texit 3\n+\t\tfi\n+\t\techo \"success\" >testsuccess\n+\tEOF\n+\tmkdir -p dir2 &&\n+\ttouch dir2/file1.txt &&\n+\ttouch dir2/file2.txt &&\n+\t: force index to be dirty &&\n+\ttest-tool chmtime +60 dir1/file1.txt &&\n+\tgit status &&\n+\ttest_path_is_file testsuccess && rm -f testsuccess &&\n+\ttest_path_is_missing testfailure &&\n+\tgit add . &&\n+\ttest_path_is_file testsuccess && rm -f testsuccess &&\n+\ttest_path_is_missing testfailure &&\n+\tgit commit -m \"second\" &&\n+\ttest_path_is_file testsuccess && rm -f testsuccess &&\n+\ttest_path_is_missing testfailure &&\n+\tgit checkout -- dir1/file1.txt &&\n+\ttest_path_is_file testsuccess && rm -f testsuccess &&\n+\ttest_path_is_missing testfailure &&\n+\tgit update-index &&\n+\ttest_path_is_missing testsuccess &&\n+\ttest_path_is_missing testfailure &&\n+\tgit reset --soft &&\n+\ttest_path_is_missing testsuccess &&\n+\ttest_path_is_missing testfailure\n+'\n+\n+test_expect_success 'test checkout and reset trigger the hook' '\n+\twrite_script .git/hooks/post-index-changed <<-\\EOF &&\n+\t\tif test \"$1\" -eq 1 && test \"$2\" -eq 1; then\n+\t\t\techo \"Invalid combination of flags passed to hook; updated_workdir and updated_skipworktree are both set.\" >testfailure\n+\t\t\texit 1\n+\t\tfi\n+\t\tif test \"$1\" -eq 0 && test \"$2\" -eq 0; then\n+\t\t\techo \"Invalid combination of flags passed to hook; neither updated_workdir or updated_skipworktree are set.\" >testfailure\n+\t\t\texit 2\n+\t\tfi\n+\t\tif test \"$1\" -eq 1; then\n+\t\t\tif test -f \".git/index.lock\"; then\n+\t\t\t\techo \"updated_workdir set but .git/index.lock exists\" >testfailure\n+\t\t\t\texit 3\n+\t\t\tfi\n+\t\t\tif ! test -f \".git/index\"; then\n+\t\t\t\techo \"updated_workdir set but .git/index does not exist\" >testfailure\n+\t\t\t\texit 3\n+\t\t\tfi\n+\t\telse\n+\t\t\techo \"update_workdir should be set for checkout\" >testfailure\n+\t\t\texit 4\n+\t\tfi\n+\t\techo \"success\" >testsuccess\n+\tEOF\n+\t: force index to be dirty &&\n+\ttest-tool chmtime +60 dir1/file1.txt &&\n+\tgit checkout master &&\n+\ttest_path_is_file testsuccess && rm -f testsuccess &&\n+\ttest_path_is_missing testfailure &&\n+\ttest-tool chmtime +60 dir1/file1.txt &&\n+\tgit checkout HEAD &&\n+\ttest_path_is_file testsuccess && rm -f testsuccess &&\n+\ttest_path_is_missing testfailure &&\n+\ttest-tool chmtime +60 dir1/file1.txt &&\n+\tgit reset --hard &&\n+\ttest_path_is_file testsuccess && rm -f testsuccess &&\n+\ttest_path_is_missing testfailure &&\n+\tgit checkout -B test &&\n+\ttest_path_is_file testsuccess && rm -f testsuccess &&\n+\ttest_path_is_missing testfailure\n+'\n+\n+test_expect_success 'test reset --mixed and update-index triggers the hook' '\n+\twrite_script .git/hooks/post-index-changed <<-\\EOF &&\n+\t\tif test \"$1\" -eq 1 && test \"$2\" -eq 1; then\n+\t\t\techo \"Invalid combination of flags passed to hook; updated_workdir and updated_skipworktree are both set.\" >testfailure\n+\t\t\texit 1\n+\t\tfi\n+\t\tif test \"$1\" -eq 0 && test \"$2\" -eq 0; then\n+\t\t\techo \"Invalid combination of flags passed to hook; neither updated_workdir or updated_skipworktree are set.\" >testfailure\n+\t\t\texit 2\n+\t\tfi\n+\t\tif test \"$2\" -eq 1; then\n+\t\t\tif test -f \".git/index.lock\"; then\n+\t\t\t\techo \"updated_skipworktree set but .git/index.lock exists\" >testfailure\n+\t\t\t\texit 3\n+\t\t\tfi\n+\t\t\tif ! test -f \".git/index\"; then\n+\t\t\t\techo \"updated_skipworktree set but .git/index does not exist\" >testfailure\n+\t\t\t\texit 3\n+\t\t\tfi\n+\t\telse\n+\t\t\techo \"updated_skipworktree should be set for reset --mixed and update-index\" >testfailure\n+\t\t\texit 4\n+\t\tfi\n+\t\techo \"success\" >testsuccess\n+\tEOF\n+\t: force index to be dirty &&\n+\ttest-tool chmtime +60 dir1/file1.txt &&\n+\tgit reset --mixed --quiet HEAD~1 &&\n+\ttest_path_is_file testsuccess && rm -f testsuccess &&\n+\ttest_path_is_missing testfailure &&\n+\tgit hash-object -w --stdin <dir1/file2.txt >expect &&\n+\tgit update-index --cacheinfo 100644 \"$(cat expect)\" dir1/file1.txt &&\n+\ttest_path_is_file testsuccess && rm -f testsuccess &&\n+\ttest_path_is_missing testfailure &&\n+\tgit update-index --skip-worktree dir1/file2.txt &&\n+\tgit update-index --remove dir1/file2.txt &&\n+\ttest_path_is_file testsuccess && rm -f testsuccess &&\n+\ttest_path_is_missing testfailure\n+'\n+\n+test_done\ndiff --git a/unpack-trees.c b/unpack-trees.c\nindex 3563daae1a..8665a4a7c0 100644\n--- a/unpack-trees.c\n+++ b/unpack-trees.c\n@@ -1637,6 +1637,8 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options\n \t\t\t\t\t\t  WRITE_TREE_SILENT |\n \t\t\t\t\t\t  WRITE_TREE_REPAIR);\n \t\t}\n+\n+\t\to->result.updated_workdir = 1;\n \t\tdiscard_index(o->dst_index);\n \t\t*o->dst_index = o->result;\n \t} else {\n\nbase-commit: d62dad7a7dca3f6a65162bf0e52cdf6927958e78\n-- \n2.20.1.windows.1\n\n"},{"id":"369315","messageId":"2f08ee3b-4511-2838-4c70-640d01fe1658@ramsayjones.plus.com","threadId":"50442","inReplyTo":"20190214144241.11240-1-peartben@gmail.com","subject":"Re: [PATCH v2] read-cache: add post-indexchanged hook","fromName":"Ramsay Jones","fromEmail":"ramsay@ramsayjones.plus.com","sentAt":"2019-02-14T16:28:09Z","receivedAt":"2019-02-14T16:28:15Z","isPatch":true,"sender":{"key":"ramsay@ramsayjones.plus.com","avatar":"https://avatars.githubusercontent.com/u/33702710?v=4"},"body":"\n\nOn 14/02/2019 14:42, Ben Peart wrote:\n> From: Ben Peart <benpeart@microsoft.com>\n> \n> Add a post-indexchanged hook that is invoked after the index is written in\n\ns/post-indexchanged/post-index-changed/\n\n> do_write_locked_index().\n> \n> This hook is meant primarily for notification, and cannot affect\n> the outcome of git commands that trigger the index write.\n> \n> The hook is passed a flag to indicate whether the working directory was\n> updated or not and a flag indicating if a skip-worktree bit could have\n> changed.  These flags enable the hook to optmize its response to the\n\ns/optmize/optimize/\n\nATB,\nRamsay Jones\n"},{"id":"369339","messageId":"xmqqa7iy860g.fsf@gitster-ct.c.googlers.com","threadId":"50442","inReplyTo":"2f08ee3b-4511-2838-4c70-640d01fe1658@ramsayjones.plus.com","subject":"Re: [PATCH v2] read-cache: add post-indexchanged hook","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-02-14T20:33:19Z","receivedAt":"2019-02-14T20:33:23Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ramsay Jones <ramsay@ramsayjones.plus.com> writes:\n\n> On 14/02/2019 14:42, Ben Peart wrote:\n>> From: Ben Peart <benpeart@microsoft.com>\n>> \n>> Add a post-indexchanged hook that is invoked after the index is written in\n>\n> s/post-indexchanged/post-index-changed/\n\nGood.  I wasn't paying close attention to the previous round, but is\nthat the only name-related bikeshedding?  I somehow feel that\nwithout s/changed/change/ the name does not roll well on my tongue\nand does not sit well together with existing ones like post-receive\n(which is not post-received).  I dunno.\n\nWill queue.  Thanks.\n\n>> do_write_locked_index().\n>> \n>> This hook is meant primarily for notification, and cannot affect\n>> the outcome of git commands that trigger the index write.\n>> \n>> The hook is passed a flag to indicate whether the working directory was\n>> updated or not and a flag indicating if a skip-worktree bit could have\n>> changed.  These flags enable the hook to optmize its response to the\n>\n> s/optmize/optimize/\n>\n> ATB,\n> Ramsay Jones\n"},{"id":"369363","messageId":"dc851640-ac3b-74a1-a753-7ff2a43a4a5b@gmail.com","threadId":"50442","inReplyTo":"xmqqa7iy860g.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v2] read-cache: add post-indexchanged hook","fromName":"Ben Peart","fromEmail":"peartben@gmail.com","sentAt":"2019-02-15T00:14:37Z","receivedAt":"2019-02-15T00:14:42Z","isPatch":true,"sender":{"key":"benpeart@microsoft.com","avatar":"https://avatars.githubusercontent.com/u/15252029?v=4"},"body":"\n\nOn 2/14/2019 3:33 PM, Junio C Hamano wrote:\n> Ramsay Jones <ramsay@ramsayjones.plus.com> writes:\n> \n>> On 14/02/2019 14:42, Ben Peart wrote:\n>>> From: Ben Peart <benpeart@microsoft.com>\n>>>\n>>> Add a post-indexchanged hook that is invoked after the index is written in\n>>\n>> s/post-indexchanged/post-index-changed/\n> \n> Good.  I wasn't paying close attention to the previous round, but is\n> that the only name-related bikeshedding?  I somehow feel that\n> without s/changed/change/ the name does not roll well on my tongue\n> and does not sit well together with existing ones like post-receive\n> (which is not post-received).  I dunno.\n> \n> Will queue.  Thanks.\n\nWould you like me to submit another version with the above spelling \ncorrections in the commit message or is it easier to fix it up yourself?\n\n> \n>>> do_write_locked_index().\n>>>\n>>> This hook is meant primarily for notification, and cannot affect\n>>> the outcome of git commands that trigger the index write.\n>>>\n>>> The hook is passed a flag to indicate whether the working directory was\n>>> updated or not and a flag indicating if a skip-worktree bit could have\n>>> changed.  These flags enable the hook to optmize its response to the\n>>\n>> s/optmize/optimize/\n>>\n>> ATB,\n>> Ramsay Jones\n"},{"id":"369397","messageId":"xmqq1s496iwe.fsf@gitster-ct.c.googlers.com","threadId":"50442","inReplyTo":"dc851640-ac3b-74a1-a753-7ff2a43a4a5b@gmail.com","subject":"Re: [PATCH v2] read-cache: add post-indexchanged hook","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-02-15T17:50:09Z","receivedAt":"2019-02-15T17:50:14Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ben Peart <peartben@gmail.com> writes:\n\n> On 2/14/2019 3:33 PM, Junio C Hamano wrote:\n>> Ramsay Jones <ramsay@ramsayjones.plus.com> writes:\n>>\n>>> On 14/02/2019 14:42, Ben Peart wrote:\n>>>> From: Ben Peart <benpeart@microsoft.com>\n>>>>\n>>>> Add a post-indexchanged hook that is invoked after the index is written in\n>>>\n>>> s/post-indexchanged/post-index-changed/\n>>\n>> Good.  I wasn't paying close attention to the previous round, but is\n>> that the only name-related bikeshedding?  I somehow feel that\n>> without s/changed/change/ the name does not roll well on my tongue\n>> and does not sit well together with existing ones like post-receive\n>> (which is not post-received).  I dunno.\n>>\n>> Will queue.  Thanks.\n>\n> Would you like me to submit another version with the above spelling\n> corrections in the commit message or is it easier to fix it up\n> yourself?\n\nI've already done s/indexchanged/index-changed/ before queuing\n(there was only one IIRC in the log message), and also the\n'optimize' typofix.\n\nI didn't do anything about dropping 'd' at the end, as I haven't\nheard any feedback on that from anybody yet.\n\n>>>> do_write_locked_index().\n>>>>\n>>>> This hook is meant primarily for notification, and cannot affect\n>>>> the outcome of git commands that trigger the index write.\n>>>>\n>>>> The hook is passed a flag to indicate whether the working directory was\n>>>> updated or not and a flag indicating if a skip-worktree bit could have\n>>>> changed.  These flags enable the hook to optmize its response to the\n>>>\n>>> s/optmize/optimize/\n>>>\n>>> ATB,\n>>> Ramsay Jones\n"},{"id":"369400","messageId":"20190215175921.13400-1-peartben@gmail.com","threadId":"50442","inReplyTo":"20190208195115.12156-1-peartben@gmail.com","subject":"[PATCH v3] read-cache: add post-index-change hook","fromName":"Ben Peart","fromEmail":"peartben@gmail.com","sentAt":"2019-02-15T17:59:21Z","receivedAt":"2019-02-15T17:59:33Z","isPatch":true,"sender":{"key":"benpeart@microsoft.com","avatar":"https://avatars.githubusercontent.com/u/15252029?v=4"},"body":"From: Ben Peart <benpeart@microsoft.com>\n\nAdd a post-index-change hook that is invoked after the index is written in\ndo_write_locked_index().\n\nThis hook is meant primarily for notification, and cannot affect\nthe outcome of git commands that trigger the index write.\n\nThe hook is passed a flag to indicate whether the working directory was\nupdated or not and a flag indicating if a skip-worktree bit could have\nchanged.  These flags enable the hook to optimize its response to the\nindex change notification.\n\nSigned-off-by: Ben Peart <benpeart@microsoft.com>\n---\n\nNotes:\n    Base Ref: v2.21.0-rc0\n    Web-Diff: https://github.com/benpeart/git/commit/27001af8db\n    Checkout: git fetch https://github.com/benpeart/git post-index-changed-v3 && git checkout 27001af8db\n    \n    ### Interdiff (v2..v3):\n    \n    diff --git a/Documentation/githooks.txt b/Documentation/githooks.txt\n    index 94b4dadf30..bfb0be3659 100644\n    --- a/Documentation/githooks.txt\n    +++ b/Documentation/githooks.txt\n    @@ -492,7 +492,7 @@ This hook is invoked by `git-p4 submit`. It takes no parameters and nothing\n     from standard input. Exiting with non-zero status from this script prevent\n     `git-p4 submit` from launching. Run `git-p4 submit --help` for details.\n    \n    -post-index-changed\n    +post-index-change\n     ~~~~~~~~~~~~~~~~~\n    \n     This hook is invoked when the index is written in read-cache.c\n    diff --git a/read-cache.c b/read-cache.c\n    index b6ead7bf8f..862bdf383d 100644\n    --- a/read-cache.c\n    +++ b/read-cache.c\n    @@ -3004,7 +3004,7 @@ static int do_write_locked_index(struct index_state *istate, struct lock_file *l\n     \telse\n     \t\tret = close_lock_file_gently(lock);\n    \n    -\trun_hook_le(NULL, \"post-index-changed\",\n    +\trun_hook_le(NULL, \"post-index-change\",\n     \t\t\tistate->updated_workdir ? \"1\" : \"0\",\n     \t\t\tistate->updated_skipworktree ? \"1\" : \"0\", NULL);\n     \tistate->updated_workdir = 0;\n    diff --git a/t/t7113-post-index-changed-hook.sh b/t/t7113-post-index-change-hook.sh\n    similarity index 95%\n    rename from t/t7113-post-index-changed-hook.sh\n    rename to t/t7113-post-index-change-hook.sh\n    index 6231b88fca..f011ad7eec 100755\n    --- a/t/t7113-post-index-changed-hook.sh\n    +++ b/t/t7113-post-index-change-hook.sh\n    @@ -1,6 +1,6 @@\n     #!/bin/sh\n    \n    -test_description='post index changed hook'\n    +test_description='post index change hook'\n    \n     . ./test-lib.sh\n    \n    @@ -14,7 +14,7 @@ test_expect_success 'setup' '\n    \n     test_expect_success 'test status, add, commit, others trigger hook without flags set' '\n     \tmkdir -p .git/hooks &&\n    -\twrite_script .git/hooks/post-index-changed <<-\\EOF &&\n    +\twrite_script .git/hooks/post-index-change <<-\\EOF &&\n     \t\tif test \"$1\" -eq 1; then\n     \t\t\techo \"Invalid combination of flags passed to hook; updated_workdir is set.\" >testfailure\n     \t\t\texit 1\n    @@ -59,7 +59,7 @@ test_expect_success 'test status, add, commit, others trigger hook without flags\n     '\n    \n     test_expect_success 'test checkout and reset trigger the hook' '\n    -\twrite_script .git/hooks/post-index-changed <<-\\EOF &&\n    +\twrite_script .git/hooks/post-index-change <<-\\EOF &&\n     \t\tif test \"$1\" -eq 1 && test \"$2\" -eq 1; then\n     \t\t\techo \"Invalid combination of flags passed to hook; updated_workdir and updated_skipworktree are both set.\" >testfailure\n     \t\t\texit 1\n    @@ -102,7 +102,7 @@ test_expect_success 'test checkout and reset trigger the hook' '\n     '\n    \n     test_expect_success 'test reset --mixed and update-index triggers the hook' '\n    -\twrite_script .git/hooks/post-index-changed <<-\\EOF &&\n    +\twrite_script .git/hooks/post-index-change <<-\\EOF &&\n     \t\tif test \"$1\" -eq 1 && test \"$2\" -eq 1; then\n     \t\t\techo \"Invalid combination of flags passed to hook; updated_workdir and updated_skipworktree are both set.\" >testfailure\n     \t\t\texit 1\n    \n    ### Patches\n\n Documentation/githooks.txt        |  18 ++++\n builtin/reset.c                   |   1 +\n builtin/update-index.c            |   2 +\n cache.h                           |   4 +-\n read-cache.c                      |  14 ++-\n t/t7113-post-index-change-hook.sh | 144 ++++++++++++++++++++++++++++++\n unpack-trees.c                    |   2 +\n 7 files changed, 182 insertions(+), 3 deletions(-)\n create mode 100755 t/t7113-post-index-change-hook.sh\n\ndiff --git a/Documentation/githooks.txt b/Documentation/githooks.txt\nindex 959044347e..bfb0be3659 100644\n--- a/Documentation/githooks.txt\n+++ b/Documentation/githooks.txt\n@@ -492,6 +492,24 @@ This hook is invoked by `git-p4 submit`. It takes no parameters and nothing\n from standard input. Exiting with non-zero status from this script prevent\n `git-p4 submit` from launching. Run `git-p4 submit --help` for details.\n \n+post-index-change\n+~~~~~~~~~~~~~~~~~\n+\n+This hook is invoked when the index is written in read-cache.c\n+do_write_locked_index.\n+\n+The first parameter passed to the hook is the indicator for the\n+working directory being updated.  \"1\" meaning working directory\n+was updated or \"0\" when the working directory was not updated.\n+\n+The second parameter passed to the hook is the indicator for whether\n+or not the index was updated and the skip-worktree bit could have\n+changed.  \"1\" meaning skip-worktree bits could have been updated\n+and \"0\" meaning they were not.\n+\n+Only one parameter should be set to \"1\" when the hook runs.  The hook\n+running passing \"1\", \"1\" should not be possible.\n+\n GIT\n ---\n Part of the linkgit:git[1] suite\ndiff --git a/builtin/reset.c b/builtin/reset.c\nindex 4d18a461fa..e173afcaac 100644\n--- a/builtin/reset.c\n+++ b/builtin/reset.c\n@@ -380,6 +380,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)\n \t\t\tint flags = quiet ? REFRESH_QUIET : REFRESH_IN_PORCELAIN;\n \t\t\tif (read_from_tree(&pathspec, &oid, intent_to_add))\n \t\t\t\treturn 1;\n+\t\t\tthe_index.updated_skipworktree = 1;\n \t\t\tif (!quiet && get_git_work_tree()) {\n \t\t\t\tuint64_t t_begin, t_delta_in_ms;\n \ndiff --git a/builtin/update-index.c b/builtin/update-index.c\nindex 02ace602b9..cf731640fa 100644\n--- a/builtin/update-index.c\n+++ b/builtin/update-index.c\n@@ -1071,6 +1071,8 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)\n \tif (entries < 0)\n \t\tdie(\"cache corrupted\");\n \n+\tthe_index.updated_skipworktree = 1;\n+\n \t/*\n \t * Custom copy of parse_options() because we want to handle\n \t * filename arguments as they come.\ndiff --git a/cache.h b/cache.h\nindex 27fe635f62..46eb862d3e 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -338,7 +338,9 @@ struct index_state {\n \tstruct cache_time timestamp;\n \tunsigned name_hash_initialized : 1,\n \t\t initialized : 1,\n-\t\t drop_cache_tree : 1;\n+\t\t drop_cache_tree : 1,\n+\t\t updated_workdir : 1,\n+\t\t updated_skipworktree : 1;\n \tstruct hashmap name_hash;\n \tstruct hashmap dir_hash;\n \tstruct object_id oid;\ndiff --git a/read-cache.c b/read-cache.c\nindex 0e0c93edc9..862bdf383d 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -17,6 +17,7 @@\n #include \"commit.h\"\n #include \"blob.h\"\n #include \"resolve-undo.h\"\n+#include \"run-command.h\"\n #include \"strbuf.h\"\n #include \"varint.h\"\n #include \"split-index.h\"\n@@ -2999,8 +3000,17 @@ static int do_write_locked_index(struct index_state *istate, struct lock_file *l\n \tif (ret)\n \t\treturn ret;\n \tif (flags & COMMIT_LOCK)\n-\t\treturn commit_locked_index(lock);\n-\treturn close_lock_file_gently(lock);\n+\t\tret = commit_locked_index(lock);\n+\telse\n+\t\tret = close_lock_file_gently(lock);\n+\n+\trun_hook_le(NULL, \"post-index-change\",\n+\t\t\tistate->updated_workdir ? \"1\" : \"0\",\n+\t\t\tistate->updated_skipworktree ? \"1\" : \"0\", NULL);\n+\tistate->updated_workdir = 0;\n+\tistate->updated_skipworktree = 0;\n+\n+\treturn ret;\n }\n \n static int write_split_index(struct index_state *istate,\ndiff --git a/t/t7113-post-index-change-hook.sh b/t/t7113-post-index-change-hook.sh\nnew file mode 100755\nindex 0000000000..f011ad7eec\n--- /dev/null\n+++ b/t/t7113-post-index-change-hook.sh\n@@ -0,0 +1,144 @@\n+#!/bin/sh\n+\n+test_description='post index change hook'\n+\n+. ./test-lib.sh\n+\n+test_expect_success 'setup' '\n+\tmkdir -p dir1 &&\n+\ttouch dir1/file1.txt &&\n+\techo testing >dir1/file2.txt &&\n+\tgit add . &&\n+\tgit commit -m \"initial\"\n+'\n+\n+test_expect_success 'test status, add, commit, others trigger hook without flags set' '\n+\tmkdir -p .git/hooks &&\n+\twrite_script .git/hooks/post-index-change <<-\\EOF &&\n+\t\tif test \"$1\" -eq 1; then\n+\t\t\techo \"Invalid combination of flags passed to hook; updated_workdir is set.\" >testfailure\n+\t\t\texit 1\n+\t\tfi\n+\t\tif test \"$2\" -eq 1; then\n+\t\t\techo \"Invalid combination of flags passed to hook; updated_skipworktree is set.\" >testfailure\n+\t\t\texit 1\n+\t\tfi\n+\t\tif test -f \".git/index.lock\"; then\n+\t\t\techo \".git/index.lock exists\" >testfailure\n+\t\t\texit 3\n+\t\tfi\n+\t\tif ! test -f \".git/index\"; then\n+\t\t\techo \".git/index does not exist\" >testfailure\n+\t\t\texit 3\n+\t\tfi\n+\t\techo \"success\" >testsuccess\n+\tEOF\n+\tmkdir -p dir2 &&\n+\ttouch dir2/file1.txt &&\n+\ttouch dir2/file2.txt &&\n+\t: force index to be dirty &&\n+\ttest-tool chmtime +60 dir1/file1.txt &&\n+\tgit status &&\n+\ttest_path_is_file testsuccess && rm -f testsuccess &&\n+\ttest_path_is_missing testfailure &&\n+\tgit add . &&\n+\ttest_path_is_file testsuccess && rm -f testsuccess &&\n+\ttest_path_is_missing testfailure &&\n+\tgit commit -m \"second\" &&\n+\ttest_path_is_file testsuccess && rm -f testsuccess &&\n+\ttest_path_is_missing testfailure &&\n+\tgit checkout -- dir1/file1.txt &&\n+\ttest_path_is_file testsuccess && rm -f testsuccess &&\n+\ttest_path_is_missing testfailure &&\n+\tgit update-index &&\n+\ttest_path_is_missing testsuccess &&\n+\ttest_path_is_missing testfailure &&\n+\tgit reset --soft &&\n+\ttest_path_is_missing testsuccess &&\n+\ttest_path_is_missing testfailure\n+'\n+\n+test_expect_success 'test checkout and reset trigger the hook' '\n+\twrite_script .git/hooks/post-index-change <<-\\EOF &&\n+\t\tif test \"$1\" -eq 1 && test \"$2\" -eq 1; then\n+\t\t\techo \"Invalid combination of flags passed to hook; updated_workdir and updated_skipworktree are both set.\" >testfailure\n+\t\t\texit 1\n+\t\tfi\n+\t\tif test \"$1\" -eq 0 && test \"$2\" -eq 0; then\n+\t\t\techo \"Invalid combination of flags passed to hook; neither updated_workdir or updated_skipworktree are set.\" >testfailure\n+\t\t\texit 2\n+\t\tfi\n+\t\tif test \"$1\" -eq 1; then\n+\t\t\tif test -f \".git/index.lock\"; then\n+\t\t\t\techo \"updated_workdir set but .git/index.lock exists\" >testfailure\n+\t\t\t\texit 3\n+\t\t\tfi\n+\t\t\tif ! test -f \".git/index\"; then\n+\t\t\t\techo \"updated_workdir set but .git/index does not exist\" >testfailure\n+\t\t\t\texit 3\n+\t\t\tfi\n+\t\telse\n+\t\t\techo \"update_workdir should be set for checkout\" >testfailure\n+\t\t\texit 4\n+\t\tfi\n+\t\techo \"success\" >testsuccess\n+\tEOF\n+\t: force index to be dirty &&\n+\ttest-tool chmtime +60 dir1/file1.txt &&\n+\tgit checkout master &&\n+\ttest_path_is_file testsuccess && rm -f testsuccess &&\n+\ttest_path_is_missing testfailure &&\n+\ttest-tool chmtime +60 dir1/file1.txt &&\n+\tgit checkout HEAD &&\n+\ttest_path_is_file testsuccess && rm -f testsuccess &&\n+\ttest_path_is_missing testfailure &&\n+\ttest-tool chmtime +60 dir1/file1.txt &&\n+\tgit reset --hard &&\n+\ttest_path_is_file testsuccess && rm -f testsuccess &&\n+\ttest_path_is_missing testfailure &&\n+\tgit checkout -B test &&\n+\ttest_path_is_file testsuccess && rm -f testsuccess &&\n+\ttest_path_is_missing testfailure\n+'\n+\n+test_expect_success 'test reset --mixed and update-index triggers the hook' '\n+\twrite_script .git/hooks/post-index-change <<-\\EOF &&\n+\t\tif test \"$1\" -eq 1 && test \"$2\" -eq 1; then\n+\t\t\techo \"Invalid combination of flags passed to hook; updated_workdir and updated_skipworktree are both set.\" >testfailure\n+\t\t\texit 1\n+\t\tfi\n+\t\tif test \"$1\" -eq 0 && test \"$2\" -eq 0; then\n+\t\t\techo \"Invalid combination of flags passed to hook; neither updated_workdir or updated_skipworktree are set.\" >testfailure\n+\t\t\texit 2\n+\t\tfi\n+\t\tif test \"$2\" -eq 1; then\n+\t\t\tif test -f \".git/index.lock\"; then\n+\t\t\t\techo \"updated_skipworktree set but .git/index.lock exists\" >testfailure\n+\t\t\t\texit 3\n+\t\t\tfi\n+\t\t\tif ! test -f \".git/index\"; then\n+\t\t\t\techo \"updated_skipworktree set but .git/index does not exist\" >testfailure\n+\t\t\t\texit 3\n+\t\t\tfi\n+\t\telse\n+\t\t\techo \"updated_skipworktree should be set for reset --mixed and update-index\" >testfailure\n+\t\t\texit 4\n+\t\tfi\n+\t\techo \"success\" >testsuccess\n+\tEOF\n+\t: force index to be dirty &&\n+\ttest-tool chmtime +60 dir1/file1.txt &&\n+\tgit reset --mixed --quiet HEAD~1 &&\n+\ttest_path_is_file testsuccess && rm -f testsuccess &&\n+\ttest_path_is_missing testfailure &&\n+\tgit hash-object -w --stdin <dir1/file2.txt >expect &&\n+\tgit update-index --cacheinfo 100644 \"$(cat expect)\" dir1/file1.txt &&\n+\ttest_path_is_file testsuccess && rm -f testsuccess &&\n+\ttest_path_is_missing testfailure &&\n+\tgit update-index --skip-worktree dir1/file2.txt &&\n+\tgit update-index --remove dir1/file2.txt &&\n+\ttest_path_is_file testsuccess && rm -f testsuccess &&\n+\ttest_path_is_missing testfailure\n+'\n+\n+test_done\ndiff --git a/unpack-trees.c b/unpack-trees.c\nindex 3563daae1a..8665a4a7c0 100644\n--- a/unpack-trees.c\n+++ b/unpack-trees.c\n@@ -1637,6 +1637,8 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options\n \t\t\t\t\t\t  WRITE_TREE_SILENT |\n \t\t\t\t\t\t  WRITE_TREE_REPAIR);\n \t\t}\n+\n+\t\to->result.updated_workdir = 1;\n \t\tdiscard_index(o->dst_index);\n \t\t*o->dst_index = o->result;\n \t} else {\n\nbase-commit: d62dad7a7dca3f6a65162bf0e52cdf6927958e78\n-- \n2.20.1.windows.1\n\n"},{"id":"369401","messageId":"BL0PR2101MB0914080996B40B6240322DD2F4600@BL0PR2101MB0914.namprd21.prod.outlook.com","threadId":"50442","inReplyTo":"xmqq1s496iwe.fsf@gitster-ct.c.googlers.com","subject":"RE: [PATCH v2] read-cache: add post-indexchanged hook","fromName":"Ben Peart","fromEmail":"ben.peart@microsoft.com","sentAt":"2019-02-15T18:02:53Z","receivedAt":"2019-02-15T18:03:00Z","isPatch":true,"sender":{"key":"benpeart@microsoft.com","avatar":"https://avatars.githubusercontent.com/u/15252029?v=4"},"body":"> -----Original Message-----\n> From: Junio C Hamano <jch2355@gmail.com> On Behalf Of Junio C Hamano\n> Sent: Friday, February 15, 2019 12:50 PM\n> To: Ben Peart <peartben@gmail.com>\n> Cc: Ramsay Jones <ramsay@ramsayjones.plus.com>; git@vger.kernel.org;\n> Ben Peart <Ben.Peart@microsoft.com>; Kevin Willford\n> <kewillf@microsoft.com>; sandals@crustytoothpaste.net\n> Subject: Re: [PATCH v2] read-cache: add post-indexchanged hook\n> \n> Ben Peart <peartben@gmail.com> writes:\n> \n> > On 2/14/2019 3:33 PM, Junio C Hamano wrote:\n> >> Ramsay Jones <ramsay@ramsayjones.plus.com> writes:\n> >>\n> >>> On 14/02/2019 14:42, Ben Peart wrote:\n> >>>> From: Ben Peart <benpeart@microsoft.com>\n> >>>>\n> >>>> Add a post-indexchanged hook that is invoked after the index is\n> >>>> written in\n> >>>\n> >>> s/post-indexchanged/post-index-changed/\n> >>\n> >> Good.  I wasn't paying close attention to the previous round, but is\n> >> that the only name-related bikeshedding?  I somehow feel that without\n> >> s/changed/change/ the name does not roll well on my tongue and does\n> >> not sit well together with existing ones like post-receive (which is\n> >> not post-received).  I dunno.\n> >>\n> >> Will queue.  Thanks.\n> >\n> > Would you like me to submit another version with the above spelling\n> > corrections in the commit message or is it easier to fix it up\n> > yourself?\n> \n> I've already done s/indexchanged/index-changed/ before queuing (there\n> was only one IIRC in the log message), and also the 'optimize' typofix.\n> \n> I didn't do anything about dropping 'd' at the end, as I haven't heard any\n> feedback on that from anybody yet.\n> \n\nI'm ok with either.  post-index-changed sounded clearer to me but you're right, none of the other hooks use the post tense.  I've submitted one with 'post-index-change' - feel free to keep/user either.\n\n> >>>> do_write_locked_index().\n> >>>>\n> >>>> This hook is meant primarily for notification, and cannot affect\n> >>>> the outcome of git commands that trigger the index write.\n> >>>>\n> >>>> The hook is passed a flag to indicate whether the working directory\n> >>>> was updated or not and a flag indicating if a skip-worktree bit\n> >>>> could have changed.  These flags enable the hook to optmize its\n> >>>> response to the\n> >>>\n> >>> s/optmize/optimize/\n> >>>\n> >>> ATB,\n> >>> Ramsay Jones\n"}]}