{"thread":{"id":"21949","subject":"[PATCH 1/2] ie_match_stat(): do not ignore skip-worktree bit with CE_MATCH_IGNORE_VALID","startedAt":"2009-12-14T11:43:58Z","lastAt":"2009-12-14T11:43:59Z","messageCount":2,"participants":["Nguyễn Thái Ngọc Duy"],"isPatch":true,"patchVersion":1,"patchTotal":2},"messages":[{"id":"129866","messageId":"1260791039-12316-1-git-send-email-pclouds@gmail.com","threadId":"21949","inReplyTo":null,"subject":"[PATCH 1/2] ie_match_stat(): do not ignore skip-worktree bit with CE_MATCH_IGNORE_VALID","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2009-12-14T11:43:58Z","receivedAt":"2009-12-14T11:43:58Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Previously CE_MATCH_IGNORE_VALID flag is used by both valid and\nskip-worktree bits. While the two bits have similar behaviour, sharing\nthis flag means \"git update-index --really-refresh\" will ignore\nskip-worktree while it should not. Instead another flag is\nintroduced to ignore skip-worktree bit, CE_MATCH_IGNORE_VALID only\napplies to valid bit.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n builtin-apply.c |    2 +-\n cache.h         |    4 +++-\n entry.c         |    2 +-\n read-cache.c    |   21 ++++++++++++++++++---\n unpack-trees.c  |    6 +++---\n 5 files changed, 26 insertions(+), 9 deletions(-)\n\ndiff --git a/builtin-apply.c b/builtin-apply.c\nindex 36e2f9d..541493e 100644\n--- a/builtin-apply.c\n+++ b/builtin-apply.c\n@@ -2666,7 +2666,7 @@ static int verify_index_match(struct cache_entry *ce, struct stat *st)\n \t\t\treturn -1;\n \t\treturn 0;\n \t}\n-\treturn ce_match_stat(ce, st, CE_MATCH_IGNORE_VALID);\n+\treturn ce_match_stat(ce, st, CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE);\n }\n \n static int check_preimage(struct patch *patch, struct cache_entry **ce, struct stat *st)\ndiff --git a/cache.h b/cache.h\nindex 0e69384..1341475 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -469,7 +469,9 @@ extern int index_name_is_other(const struct index_state *, const char *, int);\n /* do stat comparison even if CE_VALID is true */\n #define CE_MATCH_IGNORE_VALID\t\t01\n /* do not check the contents but report dirty on racily-clean entries */\n-#define CE_MATCH_RACY_IS_DIRTY\t02\n+#define CE_MATCH_RACY_IS_DIRTY\t\t02\n+/* do stat comparison even if CE_SKIP_WORKTREE is true */\n+#define CE_MATCH_IGNORE_SKIP_WORKTREE\t04\n extern int ie_match_stat(const struct index_state *, struct cache_entry *, struct stat *, unsigned int);\n extern int ie_modified(const struct index_state *, struct cache_entry *, struct stat *, unsigned int);\n \ndiff --git a/entry.c b/entry.c\nindex 06d24f1..9d5b232 100644\n--- a/entry.c\n+++ b/entry.c\n@@ -206,7 +206,7 @@ int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *t\n \tlen += ce_namelen(ce);\n \n \tif (!check_path(path, len, &st, state->base_dir_len)) {\n-\t\tunsigned changed = ce_match_stat(ce, &st, CE_MATCH_IGNORE_VALID);\n+\t\tunsigned changed = ce_match_stat(ce, &st, CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE);\n \t\tif (!changed)\n \t\t\treturn 0;\n \t\tif (!state->force) {\ndiff --git a/read-cache.c b/read-cache.c\nindex 7a2385b..b5c66f9 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -259,13 +259,18 @@ int ie_match_stat(const struct index_state *istate,\n {\n \tunsigned int changed;\n \tint ignore_valid = options & CE_MATCH_IGNORE_VALID;\n+\tint ignore_skip_worktree = options & CE_MATCH_IGNORE_SKIP_WORKTREE;\n \tint assume_racy_is_modified = options & CE_MATCH_RACY_IS_DIRTY;\n \n \t/*\n \t * If it's marked as always valid in the index, it's\n \t * valid whatever the checked-out copy says.\n+\t *\n+\t * skip-worktree has the same effect with higher precedence\n \t */\n-\tif (!ignore_valid && ((ce->ce_flags & CE_VALID) || ce_skip_worktree(ce)))\n+\tif (!ignore_skip_worktree && ce_skip_worktree(ce))\n+\t\treturn 0;\n+\tif (!ignore_valid && (ce->ce_flags & CE_VALID))\n \t\treturn 0;\n \n \t/*\n@@ -564,7 +569,7 @@ int add_to_index(struct index_state *istate, const char *path, struct stat *st,\n \tint size, namelen, was_same;\n \tmode_t st_mode = st->st_mode;\n \tstruct cache_entry *ce, *alias;\n-\tunsigned ce_option = CE_MATCH_IGNORE_VALID|CE_MATCH_RACY_IS_DIRTY;\n+\tunsigned ce_option = CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE|CE_MATCH_RACY_IS_DIRTY;\n \tint verbose = flags & (ADD_CACHE_VERBOSE | ADD_CACHE_PRETEND);\n \tint pretend = flags & ADD_CACHE_PRETEND;\n \tint intent_only = flags & ADD_CACHE_INTENT;\n@@ -1000,11 +1005,21 @@ static struct cache_entry *refresh_cache_ent(struct index_state *istate,\n \tstruct cache_entry *updated;\n \tint changed, size;\n \tint ignore_valid = options & CE_MATCH_IGNORE_VALID;\n+\tint ignore_skip_worktree = options & CE_MATCH_IGNORE_SKIP_WORKTREE;\n \n \tif (ce_uptodate(ce))\n \t\treturn ce;\n \n-\tif (!ignore_valid && ((ce->ce_flags & CE_VALID) || ce_skip_worktree(ce))) {\n+\t/*\n+\t * CE_VALID or CE_SKIP_WORKTREE means the user promised us\n+\t * that the change to the work tree does not matter and told\n+\t * us not to worry.\n+\t */\n+\tif (!ignore_skip_worktree && ce_skip_worktree(ce)) {\n+\t\tce_mark_uptodate(ce);\n+\t\treturn ce;\n+\t}\n+\tif (!ignore_valid && (ce->ce_flags & CE_VALID)) {\n \t\tce_mark_uptodate(ce);\n \t\treturn ce;\n \t}\ndiff --git a/unpack-trees.c b/unpack-trees.c\nindex ae1de3f..7570475 100644\n--- a/unpack-trees.c\n+++ b/unpack-trees.c\n@@ -569,7 +569,7 @@ static int verify_uptodate_1(struct cache_entry *ce,\n \t\treturn 0;\n \n \tif (!lstat(ce->name, &st)) {\n-\t\tunsigned changed = ie_match_stat(o->src_index, ce, &st, CE_MATCH_IGNORE_VALID);\n+\t\tunsigned changed = ie_match_stat(o->src_index, ce, &st, CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE);\n \t\tif (!changed)\n \t\t\treturn 0;\n \t\t/*\n@@ -701,7 +701,7 @@ static int icase_exists(struct unpack_trees_options *o, struct cache_entry *dst,\n \tstruct cache_entry *src;\n \n \tsrc = index_name_exists(o->src_index, dst->name, ce_namelen(dst), 1);\n-\treturn src && !ie_match_stat(o->src_index, src, st, CE_MATCH_IGNORE_VALID);\n+\treturn src && !ie_match_stat(o->src_index, src, st, CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE);\n }\n \n /*\n@@ -1152,7 +1152,7 @@ int oneway_merge(struct cache_entry **src, struct unpack_trees_options *o)\n \t\tif (o->reset && !ce_uptodate(old) && !ce_skip_worktree(old)) {\n \t\t\tstruct stat st;\n \t\t\tif (lstat(old->name, &st) ||\n-\t\t\t    ie_match_stat(o->src_index, old, &st, CE_MATCH_IGNORE_VALID))\n+\t\t\t    ie_match_stat(o->src_index, old, &st, CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE))\n \t\t\t\tupdate |= CE_UPDATE;\n \t\t}\n \t\tadd_entry(o, old, update, 0);\n-- \n1.6.5.2.216.g9c1ec\n"},{"id":"129867","messageId":"1260791039-12316-2-git-send-email-pclouds@gmail.com","threadId":"21949","inReplyTo":"1260791039-12316-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 2/2] commit: correctly respect skip-worktree bit","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2009-12-14T11:43:59Z","receivedAt":"2009-12-14T11:43:59Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Commit b4d1690 (Teach Git to respect skip-worktree bit (reading part))\nfails to make \"git commit -- a b c\" respect skip-worktree\n(i.e. not committing paths that are skip-worktree). This is because\nwhen the index is reset back to HEAD, all skip-worktree information is\ngone.\n\nThis patch saves skip-worktree information in the string list of\ncommitted paths, then reuse it later on to skip skip-worktree paths.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n builtin-commit.c                 |   11 +++++++----\n t/t7011-skip-worktree-reading.sh |    4 ++--\n 2 files changed, 9 insertions(+), 6 deletions(-)\n\ndiff --git a/builtin-commit.c b/builtin-commit.c\nindex a11e585..6e368f0 100644\n--- a/builtin-commit.c\n+++ b/builtin-commit.c\n@@ -180,11 +180,15 @@ static int list_paths(struct string_list *list, const char *with_tree,\n \n \tfor (i = 0; i < active_nr; i++) {\n \t\tstruct cache_entry *ce = active_cache[i];\n+\t\tstruct string_list_item *item;\n+\n \t\tif (ce->ce_flags & CE_UPDATE)\n \t\t\tcontinue;\n \t\tif (!match_pathspec(pattern, ce->name, ce_namelen(ce), 0, m))\n \t\t\tcontinue;\n-\t\tstring_list_insert(ce->name, list);\n+\t\titem = string_list_insert(ce->name, list);\n+\t\tif (ce_skip_worktree(ce))\n+\t\t\titem->util = item; /* better a valid pointer than a fake one */\n \t}\n \n \treturn report_path_error(m, pattern, prefix ? strlen(prefix) : 0);\n@@ -196,10 +200,9 @@ static void add_remove_files(struct string_list *list)\n \tfor (i = 0; i < list->nr; i++) {\n \t\tstruct stat st;\n \t\tstruct string_list_item *p = &(list->items[i]);\n-\t\tint pos = index_name_pos(&the_index, p->string, strlen(p->string));\n-\t\tstruct cache_entry *ce = pos < 0 ? NULL : active_cache[pos];\n \n-\t\tif (ce && ce_skip_worktree(ce))\n+\t\t/* p->util is skip-worktree */\n+\t\tif (p->util)\n \t\t\tcontinue;\n \n \t\tif (!lstat(p->string, &st)) {\ndiff --git a/t/t7011-skip-worktree-reading.sh b/t/t7011-skip-worktree-reading.sh\nindex e996928..bb4066f 100755\n--- a/t/t7011-skip-worktree-reading.sh\n+++ b/t/t7011-skip-worktree-reading.sh\n@@ -148,13 +148,13 @@ test_expect_success 'git-rm succeeds on skip-worktree absent entries' '\n \tgit rm 1\n '\n \n-test_expect_failure 'commit on skip-worktree absent entries' '\n+test_expect_success 'commit on skip-worktree absent entries' '\n \tgit reset &&\n \tsetup_absent &&\n \ttest_must_fail git commit -m null 1\n '\n \n-test_expect_failure 'commit on skip-worktree dirty entries' '\n+test_expect_success 'commit on skip-worktree dirty entries' '\n \tgit reset &&\n \tsetup_dirty &&\n \ttest_must_fail git commit -m null 1\n-- \n1.6.5.2.216.g9c1ec\n"}]}