{"thread":{"id":"29569","subject":"[PATCH v2 1/4] cache-tree: update API to take abitrary flags","startedAt":"2012-02-07T12:46:40Z","lastAt":"2012-02-09T02:23:47Z","messageCount":10,"participants":["Nguyễn Thái Ngọc Duy","Junio C Hamano","Nguyen Thai Ngoc Duy"],"isPatch":true,"patchVersion":2,"patchTotal":4},"messages":[{"id":"184122","messageId":"1328618804-31796-1-git-send-email-pclouds@gmail.com","threadId":"29569","inReplyTo":null,"subject":"[PATCH v2 0/4] Deprecate \"not allow as-is commit with i-t-a entries\"","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2012-02-07T12:46:40Z","receivedAt":"2012-02-07T12:46:40Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":" - git-add.txt changes are removed. In the end all kinds of commit\n   behave the same way, not worth putting more explanation during the\n   transition.\n\n - reword config text and warning text (or more precisely copy/paste\n   from Junio/Jonathan's words)\n\n - Hard coded release numbers are removed. Now it's simply \"in future\".\n\n - Step 2 may be too annoying. Users are warned on every commit if\n   commit.ignoreIntentToAdd is set. I think it's good because it keeps\n   config file clean, but people may think otherwise.\n\nNguyễn Thái Ngọc Duy (4):\n  cache-tree: update API to take abitrary flags\n  commit: introduce a config key to allow as-is commit with i-t-a entries\n  commit: turn commit.ignoreIntentToAdd to true by default\n  commit: remove commit.ignoreIntentToAdd, assume it's always true\n\n builtin/commit.c       |    9 ++++++---\n cache-tree.c           |   35 +++++++++++++++++------------------\n cache-tree.h           |    5 ++++-\n merge-recursive.c      |    2 +-\n t/t2203-add-intent.sh  |   21 ++++++++++++++++++++-\n test-dump-cache-tree.c |    2 +-\n 6 files changed, 49 insertions(+), 25 deletions(-)\n\n-- \n1.7.8.36.g69ee2\n"},{"id":"184121","messageId":"1328618804-31796-2-git-send-email-pclouds@gmail.com","threadId":"29569","inReplyTo":"1328618804-31796-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v2 1/4] cache-tree: update API to take abitrary flags","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2012-02-07T12:46:41Z","receivedAt":"2012-02-07T12:46:41Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/commit.c       |    4 ++--\n cache-tree.c           |   27 ++++++++++++---------------\n cache-tree.h           |    4 +++-\n merge-recursive.c      |    2 +-\n test-dump-cache-tree.c |    2 +-\n 5 files changed, 19 insertions(+), 20 deletions(-)\n\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex eba1377..bf42bb3 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -400,7 +400,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix,\n \t\tfd = hold_locked_index(&index_lock, 1);\n \t\tadd_files_to_cache(also ? prefix : NULL, pathspec, 0);\n \t\trefresh_cache_or_die(refresh_flags);\n-\t\tupdate_main_cache_tree(1);\n+\t\tupdate_main_cache_tree(WRITE_TREE_SILENT);\n \t\tif (write_cache(fd, active_cache, active_nr) ||\n \t\t    close_lock_file(&index_lock))\n \t\t\tdie(_(\"unable to write new_index file\"));\n@@ -421,7 +421,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix,\n \t\tfd = hold_locked_index(&index_lock, 1);\n \t\trefresh_cache_or_die(refresh_flags);\n \t\tif (active_cache_changed) {\n-\t\t\tupdate_main_cache_tree(1);\n+\t\t\tupdate_main_cache_tree(WRITE_TREE_SILENT);\n \t\t\tif (write_cache(fd, active_cache, active_nr) ||\n \t\t\t    commit_locked_index(&index_lock))\n \t\t\t\tdie(_(\"unable to write new_index file\"));\ndiff --git a/cache-tree.c b/cache-tree.c\nindex 8de3959..16355d6 100644\n--- a/cache-tree.c\n+++ b/cache-tree.c\n@@ -150,9 +150,10 @@ void cache_tree_invalidate_path(struct cache_tree *it, const char *path)\n }\n \n static int verify_cache(struct cache_entry **cache,\n-\t\t\tint entries, int silent)\n+\t\t\tint entries, int flags)\n {\n \tint i, funny;\n+\tint silent = flags & WRITE_TREE_SILENT;\n \n \t/* Verify that the tree is merged */\n \tfunny = 0;\n@@ -241,10 +242,11 @@ static int update_one(struct cache_tree *it,\n \t\t      int entries,\n \t\t      const char *base,\n \t\t      int baselen,\n-\t\t      int missing_ok,\n-\t\t      int dryrun)\n+\t\t      int flags)\n {\n \tstruct strbuf buffer;\n+\tint missing_ok = flags & WRITE_TREE_MISSING_OK;\n+\tint dryrun = flags & WRITE_TREE_DRY_RUN;\n \tint i;\n \n \tif (0 <= it->entry_count && has_sha1_file(it->sha1))\n@@ -288,8 +290,7 @@ static int update_one(struct cache_tree *it,\n \t\t\t\t    cache + i, entries - i,\n \t\t\t\t    path,\n \t\t\t\t    baselen + sublen + 1,\n-\t\t\t\t    missing_ok,\n-\t\t\t\t    dryrun);\n+\t\t\t\t    flags);\n \t\tif (subcnt < 0)\n \t\t\treturn subcnt;\n \t\ti += subcnt - 1;\n@@ -371,15 +372,13 @@ static int update_one(struct cache_tree *it,\n int cache_tree_update(struct cache_tree *it,\n \t\t      struct cache_entry **cache,\n \t\t      int entries,\n-\t\t      int missing_ok,\n-\t\t      int dryrun,\n-\t\t      int silent)\n+\t\t      int flags)\n {\n \tint i;\n-\ti = verify_cache(cache, entries, silent);\n+\ti = verify_cache(cache, entries, flags);\n \tif (i)\n \t\treturn i;\n-\ti = update_one(it, cache, entries, \"\", 0, missing_ok, dryrun);\n+\ti = update_one(it, cache, entries, \"\", 0, flags);\n \tif (i < 0)\n \t\treturn i;\n \treturn 0;\n@@ -572,11 +571,9 @@ int write_cache_as_tree(unsigned char *sha1, int flags, const char *prefix)\n \n \twas_valid = cache_tree_fully_valid(active_cache_tree);\n \tif (!was_valid) {\n-\t\tint missing_ok = flags & WRITE_TREE_MISSING_OK;\n-\n \t\tif (cache_tree_update(active_cache_tree,\n \t\t\t\t      active_cache, active_nr,\n-\t\t\t\t      missing_ok, 0, 0) < 0)\n+\t\t\t\t      flags) < 0)\n \t\t\treturn WRITE_TREE_UNMERGED_INDEX;\n \t\tif (0 <= newfd) {\n \t\t\tif (!write_cache(newfd, active_cache, active_nr) &&\n@@ -672,10 +669,10 @@ int cache_tree_matches_traversal(struct cache_tree *root,\n \treturn 0;\n }\n \n-int update_main_cache_tree (int silent)\n+int update_main_cache_tree (int flags)\n {\n \tif (!the_index.cache_tree)\n \t\tthe_index.cache_tree = cache_tree();\n \treturn cache_tree_update(the_index.cache_tree,\n-\t\t\t\t the_index.cache, the_index.cache_nr, 0, 0, silent);\n+\t\t\t\t the_index.cache, the_index.cache_nr, flags);\n }\ndiff --git a/cache-tree.h b/cache-tree.h\nindex 0ec0b2a..d8cb2e9 100644\n--- a/cache-tree.h\n+++ b/cache-tree.h\n@@ -29,13 +29,15 @@ void cache_tree_write(struct strbuf *, struct cache_tree *root);\n struct cache_tree *cache_tree_read(const char *buffer, unsigned long size);\n \n int cache_tree_fully_valid(struct cache_tree *);\n-int cache_tree_update(struct cache_tree *, struct cache_entry **, int, int, int, int);\n+int cache_tree_update(struct cache_tree *, struct cache_entry **, int, int);\n \n int update_main_cache_tree(int);\n \n /* bitmasks to write_cache_as_tree flags */\n #define WRITE_TREE_MISSING_OK 1\n #define WRITE_TREE_IGNORE_CACHE_TREE 2\n+#define WRITE_TREE_DRY_RUN 4\n+#define WRITE_TREE_SILENT 8\n \n /* error return codes */\n #define WRITE_TREE_UNREADABLE_INDEX (-1)\ndiff --git a/merge-recursive.c b/merge-recursive.c\nindex d83cd6c..6479a60 100644\n--- a/merge-recursive.c\n+++ b/merge-recursive.c\n@@ -264,7 +264,7 @@ struct tree *write_tree_from_memory(struct merge_options *o)\n \n \tif (!cache_tree_fully_valid(active_cache_tree) &&\n \t    cache_tree_update(active_cache_tree,\n-\t\t\t      active_cache, active_nr, 0, 0, 0) < 0)\n+\t\t\t      active_cache, active_nr, 0) < 0)\n \t\tdie(\"error building trees\");\n \n \tresult = lookup_tree(active_cache_tree->sha1);\ndiff --git a/test-dump-cache-tree.c b/test-dump-cache-tree.c\nindex e6c2923..a6ffdf3 100644\n--- a/test-dump-cache-tree.c\n+++ b/test-dump-cache-tree.c\n@@ -59,6 +59,6 @@ int main(int ac, char **av)\n \tstruct cache_tree *another = cache_tree();\n \tif (read_cache() < 0)\n \t\tdie(\"unable to read index file\");\n-\tcache_tree_update(another, active_cache, active_nr, 0, 1, 0);\n+\tcache_tree_update(another, active_cache, active_nr, WRITE_TREE_DRY_RUN);\n \treturn dump_cache_tree(active_cache_tree, another, \"\");\n }\n-- \n1.7.8.36.g69ee2\n"},{"id":"184123","messageId":"1328618804-31796-3-git-send-email-pclouds@gmail.com","threadId":"29569","inReplyTo":"1328618804-31796-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v2 2/4] commit: introduce a config key to allow as-is commit with i-t-a entries","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2012-02-07T12:46:42Z","receivedAt":"2012-02-07T12:46:42Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"\"git add -N\" is introduced some time ago to help prevent users's\nforgetting to add new files when committing. \"git add -N\" sets\nCE_INTENT_TO_ADD bit to index, hence i-t-a entries from now on. For\nsafety reasons, as-is commits in the existence of i-t-a entries are\nrejected (\"I intend to add these files. If I type \"git commit -m foo\", it\nmay be a mistake if those files's contents are not added yet. Stop me in\nthat case\").\n\nHowever unless you are doing \"commit -a\" or \"commit pathspec\", you are\nresponsible for adding all contents you want to have in the commit\nbefore you run the \"git commit\" command (and for the purpose of this\nstatement, \"add -N\" to tell Git to keey an eye on a path does _not_ add\ncontents).\n\nA change to the file in the working tree that is left unadded is what\nyou decided to deliberately leave out of the commit, be it a change to a\npath already in HEAD, or a path marked with \"add -N\". Forgetting to add\nmodified file and forgetting to add a file you earlier used \"add -N\"\namount to the same kind of risk, and \"git status\" is the way to make\nsure your partial commit has exactly what you want. If you are not\nworried about partial commit, you would be doing \"commit -a\", so the\n\"safety\" is a moot point.\n\nThis patch is the beginning of the deprecation process to remove this\nsafety check, allowing \"git commit\" to proceed anyway. The process\nconsists of three steps to help users get used to new behavior:\n\n1. Introduce a temporary config var, commit.ignoreIntentToAdd to help\nthe migration process, default to false. If the var is true, the remove\nsafety check.\n\nUsers who encounter the safety check are pointed to\ncommit.ignoreIntentToAdd documentation and advised to set the variable\nto true.\n\n2. A few releases after step 1 is out in the field, turn\ncommit.ignoreIntentToAdd default value to true (affecting mostly new\nusers).\n\nThose who decided to stick to \"false\" from step 1 are warned the \"false\"\nsupport will soon be gone and encouraged to move to \"true\" (or simply\nremove the config variable).\n\nThose who set the config to \"true\" is advised to remove it to keep\nconfig file clean.\n\nThose who encountered the safety check and did not bother to set this\nconfig var is left out in the cold.\n\n3. A few more releases after step 2, commit.ignoreIntentToAdd is\nremoved. There's no way to bring back the safety check.\n\nThis patch implements step 1.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Documentation/config.txt |   16 ++++++++++++++++\n builtin/commit.c         |   29 ++++++++++++++++++++++++++---\n cache-tree.c             |    8 +++++---\n cache-tree.h             |    1 +\n t/t2203-add-intent.sh    |   21 ++++++++++++++++++++-\n 5 files changed, 68 insertions(+), 7 deletions(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex abeb82b..6839e44 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -831,6 +831,22 @@ commit.template::\n \t\"{tilde}/\" is expanded to the value of `$HOME` and \"{tilde}user/\" to the\n \tspecified user's home directory.\n \n+commit.ignoreIntentToAdd::\n+\tWhen set to `false`, prevent `git commit` from creating a\n+\tcommit from an index that has entries that were added with\n+\t`git add -N` but have not been updated with real contents, as\n+\tthe user may have forgotten to tell the final contents for\n+\tthese entries.  Setting this to `true` makes `git commit`\n+\tpretend as if these entries do not exist in the index.\n++\n+The default for this variable is `false`, but it will change to `true`\n+in future releases of git. To ease the transition, you may want to set\n+it to `true` now and get used to the new behaviour early, or you may\n+want to set it to `false` to keep the old behaviour a bit longer. We\n+however expect to support setting this to `false` (to keep the current\n+behaviour) only for a limited time after the default is changed to\n+`true`.\n+\n credential.helper::\n \tSpecify an external helper to be called when a username or\n \tpassword credential is needed; the helper may consult external\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex bf42bb3..da67653 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -86,6 +86,7 @@ static int all, also, interactive, patch_interactive, only, amend, signoff;\n static int edit_flag = -1; /* unspecified */\n static int quiet, verbose, no_verify, allow_empty, dry_run, renew_authorship;\n static int no_post_rewrite, allow_empty_message;\n+static int cache_tree_flags;\n static char *untracked_files_arg, *force_date, *ignore_submodule_arg;\n static char *sign_commit;\n \n@@ -117,6 +118,8 @@ static enum {\n } status_format = STATUS_FORMAT_LONG;\n static int status_show_branch;\n \n+static int set_commit_ignoreintenttoadd;\n+\n static int opt_parse_m(const struct option *opt, const char *arg, int unset)\n {\n \tstruct strbuf *buf = opt->value;\n@@ -400,7 +403,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix,\n \t\tfd = hold_locked_index(&index_lock, 1);\n \t\tadd_files_to_cache(also ? prefix : NULL, pathspec, 0);\n \t\trefresh_cache_or_die(refresh_flags);\n-\t\tupdate_main_cache_tree(WRITE_TREE_SILENT);\n+\t\tupdate_main_cache_tree(cache_tree_flags | WRITE_TREE_SILENT);\n \t\tif (write_cache(fd, active_cache, active_nr) ||\n \t\t    close_lock_file(&index_lock))\n \t\t\tdie(_(\"unable to write new_index file\"));\n@@ -420,8 +423,21 @@ static char *prepare_index(int argc, const char **argv, const char *prefix,\n \tif (!pathspec || !*pathspec) {\n \t\tfd = hold_locked_index(&index_lock, 1);\n \t\trefresh_cache_or_die(refresh_flags);\n+\t\tif (!set_commit_ignoreintenttoadd) {\n+\t\t\tint i;\n+\t\t\tfor (i = 0; i < active_nr; i++)\n+\t\t\t\tif (active_cache[i]->ce_flags & CE_INTENT_TO_ADD)\n+\t\t\t\t\tbreak;\n+\t\t\tif (i < active_nr) {\n+\t\t\t\terror(_(\"you intended to add \\\"%s\\\" but did not add it; not committing\\n\"\n+\t\t\t\t\t\"hint: to commit all changes to tracked files, use \\\"commit -a\\\"\\n\"\n+\t\t\t\t\t\"hint: to commit anyway without adding, set commit.ignoreIntentToAdd to true\"),\n+\t\t\t\t      active_cache[i]->name);\n+\t\t\t\texit(128); /* die() */\n+\t\t\t}\n+\t\t}\n \t\tif (active_cache_changed) {\n-\t\t\tupdate_main_cache_tree(WRITE_TREE_SILENT);\n+\t\t\tupdate_main_cache_tree(cache_tree_flags | WRITE_TREE_SILENT);\n \t\t\tif (write_cache(fd, active_cache, active_nr) ||\n \t\t\t    commit_locked_index(&index_lock))\n \t\t\t\tdie(_(\"unable to write new_index file\"));\n@@ -870,7 +886,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,\n \t */\n \tdiscard_cache();\n \tread_cache_from(index_file);\n-\tif (update_main_cache_tree(0)) {\n+\tif (update_main_cache_tree(cache_tree_flags)) {\n \t\terror(_(\"Error building trees\"));\n \t\treturn 0;\n \t}\n@@ -1338,6 +1354,13 @@ static int git_commit_config(const char *k, const char *v, void *cb)\n \t\tinclude_status = git_config_bool(k, v);\n \t\treturn 0;\n \t}\n+\tif (!strcmp(k, \"commit.ignoreintenttoadd\")) {\n+\t\tset_commit_ignoreintenttoadd = 1;\n+\t\tif (git_config_bool(k, v))\n+\t\t\tcache_tree_flags |= WRITE_TREE_IGNORE_INTENT_TO_ADD;\n+\t\telse\n+\t\t\tcache_tree_flags &= ~WRITE_TREE_IGNORE_INTENT_TO_ADD;\n+\t}\n \n \tstatus = git_gpg_config(k, v, NULL);\n \tif (status)\ndiff --git a/cache-tree.c b/cache-tree.c\nindex 16355d6..d0be159 100644\n--- a/cache-tree.c\n+++ b/cache-tree.c\n@@ -159,7 +159,9 @@ static int verify_cache(struct cache_entry **cache,\n \tfunny = 0;\n \tfor (i = 0; i < entries; i++) {\n \t\tstruct cache_entry *ce = cache[i];\n-\t\tif (ce_stage(ce) || (ce->ce_flags & CE_INTENT_TO_ADD)) {\n+\t\tif (ce_stage(ce) ||\n+\t\t    ((flags & WRITE_TREE_IGNORE_INTENT_TO_ADD) == 0 &&\n+\t\t     (ce->ce_flags & CE_INTENT_TO_ADD))) {\n \t\t\tif (silent)\n \t\t\t\treturn -1;\n \t\t\tif (10 < ++funny) {\n@@ -339,8 +341,8 @@ static int update_one(struct cache_tree *it,\n \t\t\t\tmode, sha1_to_hex(sha1), entlen+baselen, path);\n \t\t}\n \n-\t\tif (ce->ce_flags & CE_REMOVE)\n-\t\t\tcontinue; /* entry being removed */\n+\t\tif (ce->ce_flags & (CE_REMOVE | CE_INTENT_TO_ADD))\n+\t\t\tcontinue; /* entry being removed or placeholder */\n \n \t\tstrbuf_grow(&buffer, entlen + 100);\n \t\tstrbuf_addf(&buffer, \"%o %.*s%c\", mode, entlen, path + baselen, '\\0');\ndiff --git a/cache-tree.h b/cache-tree.h\nindex d8cb2e9..af3b917 100644\n--- a/cache-tree.h\n+++ b/cache-tree.h\n@@ -38,6 +38,7 @@ int update_main_cache_tree(int);\n #define WRITE_TREE_IGNORE_CACHE_TREE 2\n #define WRITE_TREE_DRY_RUN 4\n #define WRITE_TREE_SILENT 8\n+#define WRITE_TREE_IGNORE_INTENT_TO_ADD 16\n \n /* error return codes */\n #define WRITE_TREE_UNREADABLE_INDEX (-1)\ndiff --git a/t/t2203-add-intent.sh b/t/t2203-add-intent.sh\nindex 58a3299..88a508e 100755\n--- a/t/t2203-add-intent.sh\n+++ b/t/t2203-add-intent.sh\n@@ -41,7 +41,26 @@ test_expect_success 'cannot commit with i-t-a entry' '\n \techo frotz >nitfol &&\n \tgit add rezrov &&\n \tgit add -N nitfol &&\n-\ttest_must_fail git commit\n+\ttest_must_fail git commit -minitial\n+'\n+\n+test_expect_success 'can commit tree with i-t-a entry' '\n+\tgit reset --hard &&\n+\techo xyzzy >rezrov &&\n+\techo frotz >nitfol &&\n+\tgit add rezrov &&\n+\tgit add -N nitfol &&\n+\tgit config commit.ignoreIntentToAdd true &&\n+\tgit commit -m initial &&\n+\tgit ls-tree -r HEAD >actual &&\n+\tcat >expected <<EOF &&\n+100644 blob ce013625030ba8dba906f756967f9e9ca394464a\telif\n+100644 blob ce013625030ba8dba906f756967f9e9ca394464a\tfile\n+100644 blob cf7711b63209d0dbc2d030f7fe3513745a9880e4\trezrov\n+EOF\n+\ttest_cmp expected actual &&\n+\tgit config commit.ignoreIntentToAdd false &&\n+\tgit reset HEAD^\n '\n \n test_expect_success 'can commit with an unrelated i-t-a entry in index' '\n-- \n1.7.8.36.g69ee2\n"},{"id":"184124","messageId":"1328618804-31796-4-git-send-email-pclouds@gmail.com","threadId":"29569","inReplyTo":"1328618804-31796-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v2 3/4] commit: turn commit.ignoreIntentToAdd to true by default","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2012-02-07T12:46:43Z","receivedAt":"2012-02-07T12:46:43Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This is step 2 from commit.ignoreIntentToAdd deprecation plan. To\nrecap:\n\n2. A few releases after step 1 is out in the field, turn\ncommit.ignoreIntentToAdd default value to true (affecting mostly new\nusers).\n\nThose who decided to stick to \"false\" from step 1 are warned the \"false\"\nsupport will soon be gone and encouraged to move to \"true\" (or simply\nremove the config variable).\n\nThose who set the config to \"true\" is advised to remove it to keep\nconfig file clean.\n\nThose who encountered the safety check and did not bother to set this\nconfig var is left out in the cold.\n\n3. A few more releases after step 2, commit.ignoreIntentToAdd is\nremoved. There's no way to bring back the safety check.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Documentation/config.txt |   11 ++++-------\n builtin/commit.c         |   19 ++++++++++++++++---\n t/t2203-add-intent.sh    |    4 ++--\n 3 files changed, 22 insertions(+), 12 deletions(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex 6839e44..fa56753 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -839,13 +839,10 @@ commit.ignoreIntentToAdd::\n \tthese entries.  Setting this to `true` makes `git commit`\n \tpretend as if these entries do not exist in the index.\n +\n-The default for this variable is `false`, but it will change to `true`\n-in future releases of git. To ease the transition, you may want to set\n-it to `true` now and get used to the new behaviour early, or you may\n-want to set it to `false` to keep the old behaviour a bit longer. We\n-however expect to support setting this to `false` (to keep the current\n-behaviour) only for a limited time after the default is changed to\n-`true`.\n+The default for this variable is `true`. You are discouraged to set it\n+to `false` to keep the old behaviour a bit longer because support\n+setting this to `false` will be removed in future releases without\n+warning.\n \n credential.helper::\n \tSpecify an external helper to be called when a username or\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex da67653..cd28081 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -423,15 +423,16 @@ static char *prepare_index(int argc, const char **argv, const char *prefix,\n \tif (!pathspec || !*pathspec) {\n \t\tfd = hold_locked_index(&index_lock, 1);\n \t\trefresh_cache_or_die(refresh_flags);\n-\t\tif (!set_commit_ignoreintenttoadd) {\n+\t\tif (!(cache_tree_flags & WRITE_TREE_IGNORE_INTENT_TO_ADD)) {\n \t\t\tint i;\n \t\t\tfor (i = 0; i < active_nr; i++)\n \t\t\t\tif (active_cache[i]->ce_flags & CE_INTENT_TO_ADD)\n \t\t\t\t\tbreak;\n \t\t\tif (i < active_nr) {\n \t\t\t\terror(_(\"you intended to add \\\"%s\\\" but did not add it; not committing\\n\"\n-\t\t\t\t\t\"hint: to commit all changes to tracked files, use \\\"commit -a\\\"\\n\"\n-\t\t\t\t\t\"hint: to commit anyway without adding, set commit.ignoreIntentToAdd to true\"),\n+\t\t\t\t\t\"this behavior is deprecated, please set commit.ignoreIntentToAdd\\n\"\n+\t\t\t\t\t\"to true or remove the configuration variable. See the configuration\\n\"\n+\t\t\t\t\t\"variable documentation for more information.\"),\n \t\t\t\t      active_cache[i]->name);\n \t\t\t\texit(128); /* die() */\n \t\t\t}\n@@ -1424,6 +1425,9 @@ int cmd_commit(int argc, const char **argv, const char *prefix)\n \tgit_config(git_commit_config, &s);\n \tdetermine_whence(&s);\n \n+\tif (!set_commit_ignoreintenttoadd)\n+\t\tcache_tree_flags |= WRITE_TREE_IGNORE_INTENT_TO_ADD;\n+\n \tif (get_sha1(\"HEAD\", sha1))\n \t\tcurrent_head = NULL;\n \telse {\n@@ -1583,5 +1587,14 @@ int cmd_commit(int argc, const char **argv, const char *prefix)\n \tif (!quiet)\n \t\tprint_summary(prefix, sha1, !current_head);\n \n+\tif (set_commit_ignoreintenttoadd) {\n+\t\tif (cache_tree_flags & WRITE_TREE_IGNORE_INTENT_TO_ADD)\n+\t\t\twarning(_(\"commit.ignoreIntentToAdd = true is not needed anymore.\\n\"\n+\t\t\t\t  \"Please remove it.\"));\n+\t\telse\n+\t\t\twarning(_(\"commit.ignoreIntentToAdd = false is deprecated.\\n\"\n+\t\t\t\t  \"Please see the commit.ignoreIntentToAdd documentation for\\n\"\n+\t\t\t\t  \"more information and remove the configuration variable.\"));\n+\t}\n \treturn 0;\n }\ndiff --git a/t/t2203-add-intent.sh b/t/t2203-add-intent.sh\nindex 88a508e..09b8bbf 100755\n--- a/t/t2203-add-intent.sh\n+++ b/t/t2203-add-intent.sh\n@@ -41,11 +41,11 @@ test_expect_success 'cannot commit with i-t-a entry' '\n \techo frotz >nitfol &&\n \tgit add rezrov &&\n \tgit add -N nitfol &&\n-\ttest_must_fail git commit -minitial\n+\tgit commit -minitial\n '\n \n test_expect_success 'can commit tree with i-t-a entry' '\n-\tgit reset --hard &&\n+\tgit reset --hard HEAD^ &&\n \techo xyzzy >rezrov &&\n \techo frotz >nitfol &&\n \tgit add rezrov &&\n-- \n1.7.8.36.g69ee2\n"},{"id":"184125","messageId":"1328618804-31796-5-git-send-email-pclouds@gmail.com","threadId":"29569","inReplyTo":"1328618804-31796-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v2 4/4] commit: remove commit.ignoreIntentToAdd, assume it's always true","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2012-02-07T12:46:44Z","receivedAt":"2012-02-07T12:46:44Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Documentation/config.txt |   13 -------------\n builtin/commit.c         |   35 +----------------------------------\n t/t2203-add-intent.sh    |    4 ++--\n 3 files changed, 3 insertions(+), 49 deletions(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex fa56753..abeb82b 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -831,19 +831,6 @@ commit.template::\n \t\"{tilde}/\" is expanded to the value of `$HOME` and \"{tilde}user/\" to the\n \tspecified user's home directory.\n \n-commit.ignoreIntentToAdd::\n-\tWhen set to `false`, prevent `git commit` from creating a\n-\tcommit from an index that has entries that were added with\n-\t`git add -N` but have not been updated with real contents, as\n-\tthe user may have forgotten to tell the final contents for\n-\tthese entries.  Setting this to `true` makes `git commit`\n-\tpretend as if these entries do not exist in the index.\n-+\n-The default for this variable is `true`. You are discouraged to set it\n-to `false` to keep the old behaviour a bit longer because support\n-setting this to `false` will be removed in future releases without\n-warning.\n-\n credential.helper::\n \tSpecify an external helper to be called when a username or\n \tpassword credential is needed; the helper may consult external\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex cd28081..491cae1 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -118,8 +118,6 @@ static enum {\n } status_format = STATUS_FORMAT_LONG;\n static int status_show_branch;\n \n-static int set_commit_ignoreintenttoadd;\n-\n static int opt_parse_m(const struct option *opt, const char *arg, int unset)\n {\n \tstruct strbuf *buf = opt->value;\n@@ -423,20 +421,6 @@ static char *prepare_index(int argc, const char **argv, const char *prefix,\n \tif (!pathspec || !*pathspec) {\n \t\tfd = hold_locked_index(&index_lock, 1);\n \t\trefresh_cache_or_die(refresh_flags);\n-\t\tif (!(cache_tree_flags & WRITE_TREE_IGNORE_INTENT_TO_ADD)) {\n-\t\t\tint i;\n-\t\t\tfor (i = 0; i < active_nr; i++)\n-\t\t\t\tif (active_cache[i]->ce_flags & CE_INTENT_TO_ADD)\n-\t\t\t\t\tbreak;\n-\t\t\tif (i < active_nr) {\n-\t\t\t\terror(_(\"you intended to add \\\"%s\\\" but did not add it; not committing\\n\"\n-\t\t\t\t\t\"this behavior is deprecated, please set commit.ignoreIntentToAdd\\n\"\n-\t\t\t\t\t\"to true or remove the configuration variable. See the configuration\\n\"\n-\t\t\t\t\t\"variable documentation for more information.\"),\n-\t\t\t\t      active_cache[i]->name);\n-\t\t\t\texit(128); /* die() */\n-\t\t\t}\n-\t\t}\n \t\tif (active_cache_changed) {\n \t\t\tupdate_main_cache_tree(cache_tree_flags | WRITE_TREE_SILENT);\n \t\t\tif (write_cache(fd, active_cache, active_nr) ||\n@@ -1355,13 +1339,6 @@ static int git_commit_config(const char *k, const char *v, void *cb)\n \t\tinclude_status = git_config_bool(k, v);\n \t\treturn 0;\n \t}\n-\tif (!strcmp(k, \"commit.ignoreintenttoadd\")) {\n-\t\tset_commit_ignoreintenttoadd = 1;\n-\t\tif (git_config_bool(k, v))\n-\t\t\tcache_tree_flags |= WRITE_TREE_IGNORE_INTENT_TO_ADD;\n-\t\telse\n-\t\t\tcache_tree_flags &= ~WRITE_TREE_IGNORE_INTENT_TO_ADD;\n-\t}\n \n \tstatus = git_gpg_config(k, v, NULL);\n \tif (status)\n@@ -1425,8 +1402,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)\n \tgit_config(git_commit_config, &s);\n \tdetermine_whence(&s);\n \n-\tif (!set_commit_ignoreintenttoadd)\n-\t\tcache_tree_flags |= WRITE_TREE_IGNORE_INTENT_TO_ADD;\n+\tcache_tree_flags |= WRITE_TREE_IGNORE_INTENT_TO_ADD;\n \n \tif (get_sha1(\"HEAD\", sha1))\n \t\tcurrent_head = NULL;\n@@ -1587,14 +1563,5 @@ int cmd_commit(int argc, const char **argv, const char *prefix)\n \tif (!quiet)\n \t\tprint_summary(prefix, sha1, !current_head);\n \n-\tif (set_commit_ignoreintenttoadd) {\n-\t\tif (cache_tree_flags & WRITE_TREE_IGNORE_INTENT_TO_ADD)\n-\t\t\twarning(_(\"commit.ignoreIntentToAdd = true is not needed anymore.\\n\"\n-\t\t\t\t  \"Please remove it.\"));\n-\t\telse\n-\t\t\twarning(_(\"commit.ignoreIntentToAdd = false is deprecated.\\n\"\n-\t\t\t\t  \"Please see the commit.ignoreIntentToAdd documentation for\\n\"\n-\t\t\t\t  \"more information and remove the configuration variable.\"));\n-\t}\n \treturn 0;\n }\ndiff --git a/t/t2203-add-intent.sh b/t/t2203-add-intent.sh\nindex 09b8bbf..6dbfb74 100755\n--- a/t/t2203-add-intent.sh\n+++ b/t/t2203-add-intent.sh\n@@ -44,13 +44,13 @@ test_expect_success 'cannot commit with i-t-a entry' '\n \tgit commit -minitial\n '\n \n-test_expect_success 'can commit tree with i-t-a entry' '\n+test_expect_success 'commit.ignoreIntentToAdd = false is ignored' '\n \tgit reset --hard HEAD^ &&\n \techo xyzzy >rezrov &&\n \techo frotz >nitfol &&\n \tgit add rezrov &&\n \tgit add -N nitfol &&\n-\tgit config commit.ignoreIntentToAdd true &&\n+\tgit config commit.ignoreIntentToAdd false &&\n \tgit commit -m initial &&\n \tgit ls-tree -r HEAD >actual &&\n \tcat >expected <<EOF &&\n-- \n1.7.8.36.g69ee2\n"},{"id":"184137","messageId":"7v8vke38a1.fsf@alter.siamese.dyndns.org","threadId":"29569","inReplyTo":"1328618804-31796-1-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH v2 0/4] Deprecate \"not allow as-is commit with i-t-a entries\"","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-02-07T16:41:58Z","receivedAt":"2012-02-07T16:41:58Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:\n\n>  - git-add.txt changes are removed. In the end all kinds of commit\n>    behave the same way, not worth putting more explanation during the\n>    transition.\n>\n>  - reword config text and warning text (or more precisely copy/paste\n>    from Junio/Jonathan's words)\n>\n>  - Hard coded release numbers are removed. Now it's simply \"in future\".\n>\n>  - Step 2 may be too annoying. Users are warned on every commit if\n>    commit.ignoreIntentToAdd is set. I think it's good because it keeps\n>    config file clean, but people may think otherwise.\n\nAhh, thanks.\n\nBut when I said \"let's admit that this is just fixing an UI mistake, no\nconfiguration, no options\", I really meant it.  Without the backward\ncompatiblity \"For now please do not fix this bug for me and keep being\nbuggy until I get used to the non-buggy behaviour\" fuss, which we never do\nto any bugfix.\n\nThat is how we are planning to handle \"git merge\" update to spawn editor\nin interactive session in the next release. There is no \"Please keep the\nbuggy behaviour\" option; only an environment variable to help when we\nmistake a scripted use as interactive, whose support is not going away\nbecause it is not about \"until I get used to the new behaviour\".\n"},{"id":"184161","messageId":"7v62fi1kqj.fsf@alter.siamese.dyndns.org","threadId":"29569","inReplyTo":"7v8vke38a1.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH v2 0/4] Deprecate \"not allow as-is commit with i-t-a entries\"","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-02-07T19:55:48Z","receivedAt":"2012-02-07T19:55:48Z","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> Ahh, thanks.\n>\n> But when I said \"let's admit that this is just fixing an UI mistake, no\n> configuration, no options\", I really meant it.  Without the backward\n> compatiblity \"For now please do not fix this bug for me and keep being\n> buggy until I get used to the non-buggy behaviour\" fuss, which we never do\n> to any bugfix.\n\nGiven that a patch to do so (with or without your 1/4 which is an\nindependently good change) on top of an ancient v1.7.6 codebase looks like\nthis, I am inclined to think this is the way to go.\n\nI still need to review the existing documentation to see if anything needs\nto be fixed up, though.\n\n-- >8 --\nFrom: Junio C Hamano <gitster@pobox.com>\nSubject: [PATCH] commit: ignore intent-to-add entries instead of refusing\n\nOriginally, \"git add -N\" was introduced to help users from forgetting to\nadd new files to the index before they ran \"git commit -a\".  As an attempt\nto help them further so that they do not forget to say \"-a\", \"git commit\"\nto commit the index as-is was taught to error out, reminding the user that\nthey may have forgotten to add the final contents of the paths before\nrunning the command.\n\nThis turned out to be a false \"safety\" that is useless.  If the user made\nchanges to already tracked paths and paths added with \"git add -N\", and\nthen ran \"git add\" to register the final contents of the paths added with\n\"git add -N\", \"git commit\" will happily create a commit out of the index,\nwithout including the local changes made to the already tracked paths. It\nwas not a useful \"safety\" measure to prevent \"forgetful\" mistakes from\nhappening.\n\nIt turns out that this behaviour is not just a useless false \"safety\", but\nactively hurts use cases of \"git add -N\" that were discovered later and\nhave become popular, namely, to tell Git to be aware of these paths added\nby \"git add -N\", so that commands like \"git status\" and \"git diff\" would\ninclude them in their output, even though the user is not interested in\nincluding them in the next commit they are going to make.\n\nFix this ancient UI mistake, and instead make a commit from the index\nignoring the paths added by \"git add -N\" without adding real contents.\n\nBased on the work by Nguyễn Thái Ngọc Duy, and helped by injection of\nsanity from Jonathan Nieder and others on the Git mailing list.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n * The last hunk of t2203 is because the test assumed the previous one\n   failed to make a commit and \"rezrov\" in HEAD does not have \"xyzzy\".\n   Now that the previous test creates a commit and records \"xyzzy\" in\n   \"rezrov\", this test will fail with \"Nothing to commit\" without it.\n\n cache-tree.c          |    6 +++---\n t/t2203-add-intent.sh |    8 +++++---\n 2 files changed, 8 insertions(+), 6 deletions(-)\n\ndiff --git a/cache-tree.c b/cache-tree.c\nindex f755590..ce0d0e3 100644\n--- a/cache-tree.c\n+++ b/cache-tree.c\n@@ -158,7 +158,7 @@ static int verify_cache(struct cache_entry **cache,\n \tfunny = 0;\n \tfor (i = 0; i < entries; i++) {\n \t\tstruct cache_entry *ce = cache[i];\n-\t\tif (ce_stage(ce) || (ce->ce_flags & CE_INTENT_TO_ADD)) {\n+\t\tif (ce_stage(ce)) {\n \t\t\tif (10 < ++funny) {\n \t\t\t\tfprintf(stderr, \"...\\n\");\n \t\t\t\tbreak;\n@@ -336,8 +336,8 @@ static int update_one(struct cache_tree *it,\n \t\t\t\tmode, sha1_to_hex(sha1), entlen+baselen, path);\n \t\t}\n \n-\t\tif (ce->ce_flags & CE_REMOVE)\n-\t\t\tcontinue; /* entry being removed */\n+\t\tif (ce->ce_flags & (CE_REMOVE | CE_INTENT_TO_ADD))\n+\t\t\tcontinue; /* entry being removed or placeholder */\n \n \t\tstrbuf_grow(&buffer, entlen + 100);\n \t\tstrbuf_addf(&buffer, \"%o %.*s%c\", mode, entlen, path + baselen, '\\0');\ndiff --git a/t/t2203-add-intent.sh b/t/t2203-add-intent.sh\nindex 2543529..ec35409 100755\n--- a/t/t2203-add-intent.sh\n+++ b/t/t2203-add-intent.sh\n@@ -32,7 +32,7 @@ test_expect_success 'intent to add does not clobber existing paths' '\n \t! grep \"$empty\" actual\n '\n \n-test_expect_success 'cannot commit with i-t-a entry' '\n+test_expect_success 'i-t-a entry is simply ignored' '\n \ttest_tick &&\n \tgit commit -a -m initial &&\n \tgit reset --hard &&\n@@ -41,12 +41,14 @@ test_expect_success 'cannot commit with i-t-a entry' '\n \techo frotz >nitfol &&\n \tgit add rezrov &&\n \tgit add -N nitfol &&\n-\ttest_must_fail git commit -m initial\n+\tgit commit -m second &&\n+\ttest $(git ls-tree HEAD -- nitfol | wc -l) = 0 &&\n+\ttest $(git diff --name-only HEAD -- nitfol | wc -l) = 1\n '\n \n test_expect_success 'can commit with an unrelated i-t-a entry in index' '\n \tgit reset --hard &&\n-\techo xyzzy >rezrov &&\n+\techo bozbar >rezrov &&\n \techo frotz >nitfol &&\n \tgit add rezrov &&\n \tgit add -N nitfol &&\n-- \n1.7.9.231.g87173\n"},{"id":"184173","messageId":"CACsJy8DSM3kPXJ4oYexCLs5qp6YdZ4Mf9RrGo78a0tHkRaTe4g@mail.gmail.com","threadId":"29569","inReplyTo":"7v8vke38a1.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH v2 0/4] Deprecate \"not allow as-is commit with i-t-a entries\"","fromName":"Nguyen Thai Ngoc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2012-02-08T04:03:46Z","receivedAt":"2012-02-08T04:03:46Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"2012/2/7 Junio C Hamano <gitster@pobox.com>:\n> But when I said \"let's admit that this is just fixing an UI mistake, no\n> configuration, no options\", I really meant it.  Without the backward\n> compatiblity \"For now please do not fix this bug for me and keep being\n> buggy until I get used to the non-buggy behaviour\" fuss, which we never do\n> to any bugfix.\n\nAhh I missed something again. Your patch looks good too.\n\n> That is how we are planning to handle \"git merge\" update to spawn editor\n> in interactive session in the next release. There is no \"Please keep the\n> buggy behaviour\" option; only an environment variable to help when we\n> mistake a scripted use as interactive, whose support is not going away\n> because it is not about \"until I get used to the new behaviour\".\n-- \nDuy\n"},{"id":"184192","messageId":"7v8vkdz0sg.fsf@alter.siamese.dyndns.org","threadId":"29569","inReplyTo":"CACsJy8DSM3kPXJ4oYexCLs5qp6YdZ4Mf9RrGo78a0tHkRaTe4g@mail.gmail.com","subject":"Re: [PATCH v2 0/4] Deprecate \"not allow as-is commit with i-t-a entries\"","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-02-08T17:34:55Z","receivedAt":"2012-02-08T17:34:55Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Nguyen Thai Ngoc Duy <pclouds@gmail.com> writes:\n\n> 2012/2/7 Junio C Hamano <gitster@pobox.com>:\n>> But when I said \"let's admit that this is just fixing an UI mistake, no\n>> configuration, no options\", I really meant it. Without the backward\n>> compatiblity \"For now please do not fix this bug for me and keep being\n>> buggy until I get used to the non-buggy behaviour\" fuss, which we never do\n>> to any bugfix.\n>\n> Ahh I missed something again. Your patch looks good too.\n\nOk, the strategy part is now behind us, but I have this slight suspicion\n(I didn't look at the code nor tried it out myself---I don't have time to\ndo this myself today) that using this codepath might result in a corrupt\ncache-tree, whose entries point at a section of the index it covers as a\nsubtree of the whole project but with incorrect counters or something like\nthat.  It would be good to make sure this \"just ignoring i-t-a\" is doing\nthe right thing not to the resulting commit, but in the resulting index as\nwell, before we go forward with this change.\n"},{"id":"184213","messageId":"CACsJy8CC-VuriJO3WhzwwU9WYVuC7hudnziopd1+upp6AFLYfQ@mail.gmail.com","threadId":"29569","inReplyTo":"7v8vkdz0sg.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH v2 0/4] Deprecate \"not allow as-is commit with i-t-a entries\"","fromName":"Nguyen Thai Ngoc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2012-02-09T02:23:47Z","receivedAt":"2012-02-09T02:23:47Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Thu, Feb 9, 2012 at 12:34 AM, Junio C Hamano <gitster@pobox.com> wrote:\n> Ok, the strategy part is now behind us, but I have this slight suspicion\n> (I didn't look at the code nor tried it out myself---I don't have time to\n> do this myself today) that using this codepath might result in a corrupt\n> cache-tree, whose entries point at a section of the index it covers as a\n> subtree of the whole project but with incorrect counters or something like\n> that.  It would be good to make sure this \"just ignoring i-t-a\" is doing\n> the right thing not to the resulting commit, but in the resulting index as\n> well, before we go forward with this change.\n\nI looked a little bit and I think i-t-a entries do not break\ncache-tree. CE_REMOVE ones might though because they are taken into\naccount in entry_count field, but they are not written down to file.\nWill look into it tonight.\n-- \nDuy\n"}]}