{"thread":{"id":"21948","subject":"[PATCH 00/23] nd/sparse reroll","startedAt":"2009-12-14T10:30:43Z","lastAt":"2009-12-15T08:05:56Z","messageCount":30,"participants":["Nguyễn Thái Ngọc Duy","Johannes Sixt","Nguyen Thai Ngoc Duy","Greg Price"],"isPatch":true,"patchVersion":1,"patchTotal":23},"messages":[{"id":"129836","messageId":"1260786666-8405-1-git-send-email-pclouds@gmail.com","threadId":"21948","inReplyTo":null,"subject":"[PATCH 00/23] nd/sparse reroll","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2009-12-14T10:30:43Z","receivedAt":"2009-12-14T10:30:43Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Compared to the current series in pu, patch \"Teach Git to respect\nskip-worktree (reading part)\" has been broken up into smaller patches.\nbuiltin-commit.c is also fixed to make the two failed test cases in\nt7011 now pass. Skip-worktree bit no longer relies on\nCE_MATCH_IGNORE_VALID flag, which means \n\"git update-index --really-refresh\" respects skip-worktree bit too.  \n\nThe rest is unchanged.\n\nNguyễn Thái Ngọc Duy (23):\n  update-index: refactor mark_valid() in preparation for new options\n  Add test-index-version\n  Introduce \"skip-worktree\" bit in index, teach Git to get/set this bit\n  update-index: ignore update request if it's skip-worktree\n  Teach ls-files and update-index to respect skip-worktree bit\n  Teach diff machinery to respect skip-worktree bit\n  Teach grep to respect skip-worktree bit\n  Teach commit to respect skip-worktree bit\n  Teach Git to respect skip-worktree bit (writing part)\n  Avoid writing to buffer in add_excludes_from_file_1()\n  Read .gitignore from index if it is skip-worktree\n  unpack-trees(): carry skip-worktree bit over in merged_entry()\n  excluded_1(): support exclude files in index\n  dir.c: export excluded_1() and add_excludes_from_file_1()\n  Introduce \"sparse checkout\"\n  unpack-trees(): add CE_WT_REMOVE to remove on worktree alone\n  unpack-trees.c: generalize verify_* functions\n  unpack-trees(): \"enable\" sparse checkout and load\n    $GIT_DIR/info/sparse-checkout\n  unpack_trees(): apply $GIT_DIR/info/sparse-checkout to the final\n    index\n  unpack-trees(): ignore worktree check outside checkout area\n  read-tree: add --no-sparse-checkout to disable sparse checkout\n    support\n  Add tests for sparse checkout\n  sparse checkout: inhibit empty worktree\n\n .gitignore                                        |    1 +\n Documentation/config.txt                          |    4 +\n Documentation/git-ls-files.txt                    |    1 +\n Documentation/git-read-tree.txt                   |   52 ++++++-\n Documentation/git-update-index.txt                |   29 ++++\n Documentation/technical/api-directory-listing.txt |    3 +\n Makefile                                          |    1 +\n builtin-apply.c                                   |    2 +-\n builtin-clean.c                                   |    4 +-\n builtin-commit.c                                  |   11 +-\n builtin-grep.c                                    |    2 +-\n builtin-ls-files.c                                |   11 +-\n builtin-read-tree.c                               |    4 +-\n builtin-update-index.c                            |   78 ++++++----\n cache.h                                           |   10 +-\n config.c                                          |    5 +\n diff-lib.c                                        |    5 +-\n diff.c                                            |    2 +-\n dir.c                                             |  100 ++++++++----\n dir.h                                             |    4 +\n entry.c                                           |    2 +-\n environment.c                                     |    1 +\n read-cache.c                                      |   17 ++-\n t/t1011-read-tree-sparse-checkout.sh              |  150 +++++++++++++++++\n t/t2104-update-index-skip-worktree.sh             |   57 +++++++\n t/t3001-ls-files-others-exclude.sh                |   22 +++\n t/t7011-skip-worktree-reading.sh                  |  158 ++++++++++++++++++\n t/t7012-skip-worktree-writing.sh                  |  139 ++++++++++++++++\n t/t7300-clean.sh                                  |   19 +++\n test-index-version.c                              |   14 ++\n unpack-trees.c                                    |  181 +++++++++++++++++++--\n unpack-trees.h                                    |    6 +\n 32 files changed, 994 insertions(+), 101 deletions(-)\n create mode 100755 t/t1011-read-tree-sparse-checkout.sh\n create mode 100755 t/t2104-update-index-skip-worktree.sh\n create mode 100755 t/t7011-skip-worktree-reading.sh\n create mode 100755 t/t7012-skip-worktree-writing.sh\n create mode 100644 test-index-version.c\n"},{"id":"129858","messageId":"1260786666-8405-2-git-send-email-pclouds@gmail.com","threadId":"21948","inReplyTo":"1260786666-8405-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 01/23] update-index: refactor mark_valid() in preparation for new options","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2009-12-14T10:30:44Z","receivedAt":"2009-12-14T10:30:44Z","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-update-index.c |   24 ++++++++++--------------\n 1 files changed, 10 insertions(+), 14 deletions(-)\n\ndiff --git a/builtin-update-index.c b/builtin-update-index.c\nindex 92beaaf..f1b6c8e 100644\n--- a/builtin-update-index.c\n+++ b/builtin-update-index.c\n@@ -24,8 +24,8 @@ static int info_only;\n static int force_remove;\n static int verbose;\n static int mark_valid_only;\n-#define MARK_VALID 1\n-#define UNMARK_VALID 2\n+#define MARK_FLAG 1\n+#define UNMARK_FLAG 2\n \n static void report(const char *fmt, ...)\n {\n@@ -40,19 +40,15 @@ static void report(const char *fmt, ...)\n \tva_end(vp);\n }\n \n-static int mark_valid(const char *path)\n+static int mark_ce_flags(const char *path, int flag, int mark)\n {\n \tint namelen = strlen(path);\n \tint pos = cache_name_pos(path, namelen);\n \tif (0 <= pos) {\n-\t\tswitch (mark_valid_only) {\n-\t\tcase MARK_VALID:\n-\t\t\tactive_cache[pos]->ce_flags |= CE_VALID;\n-\t\t\tbreak;\n-\t\tcase UNMARK_VALID:\n-\t\t\tactive_cache[pos]->ce_flags &= ~CE_VALID;\n-\t\t\tbreak;\n-\t\t}\n+\t\tif (mark)\n+\t\t\tactive_cache[pos]->ce_flags |= flag;\n+\t\telse\n+\t\t\tactive_cache[pos]->ce_flags &= ~flag;\n \t\tcache_tree_invalidate_path(active_cache_tree, path);\n \t\tactive_cache_changed = 1;\n \t\treturn 0;\n@@ -276,7 +272,7 @@ static void update_one(const char *path, const char *prefix, int prefix_length)\n \t\tgoto free_return;\n \t}\n \tif (mark_valid_only) {\n-\t\tif (mark_valid(p))\n+\t\tif (mark_ce_flags(p, CE_VALID, mark_valid_only == MARK_FLAG))\n \t\t\tdie(\"Unable to mark file %s\", path);\n \t\tgoto free_return;\n \t}\n@@ -647,11 +643,11 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)\n \t\t\t\tcontinue;\n \t\t\t}\n \t\t\tif (!strcmp(path, \"--assume-unchanged\")) {\n-\t\t\t\tmark_valid_only = MARK_VALID;\n+\t\t\t\tmark_valid_only = MARK_FLAG;\n \t\t\t\tcontinue;\n \t\t\t}\n \t\t\tif (!strcmp(path, \"--no-assume-unchanged\")) {\n-\t\t\t\tmark_valid_only = UNMARK_VALID;\n+\t\t\t\tmark_valid_only = UNMARK_FLAG;\n \t\t\t\tcontinue;\n \t\t\t}\n \t\t\tif (!strcmp(path, \"--info-only\")) {\n-- \n1.6.5.2.216.g9c1ec\n"},{"id":"129859","messageId":"1260786666-8405-3-git-send-email-pclouds@gmail.com","threadId":"21948","inReplyTo":"1260786666-8405-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 02/23] Add test-index-version","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2009-12-14T10:30:45Z","receivedAt":"2009-12-14T10:30:45Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Commit 06aaaa0bf70fe37d198893f4e25fa73b6516f8a9 may step index format\nversion up and down, depends on whether extended flags present in the\nindex. This adds a test to check for index format version.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n .gitignore           |    1 +\n Makefile             |    1 +\n test-index-version.c |   14 ++++++++++++++\n 3 files changed, 16 insertions(+), 0 deletions(-)\n create mode 100644 test-index-version.c\n\ndiff --git a/.gitignore b/.gitignore\nindex 41c0b20..e3a864c 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -153,6 +153,7 @@ test-date\n test-delta\n test-dump-cache-tree\n test-genrandom\n+test-index-version\n test-match-trees\n test-parse-options\n test-path-utils\ndiff --git a/Makefile b/Makefile\nindex daf4296..3c5b890 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -1580,6 +1580,7 @@ TEST_PROGRAMS += test-parse-options$X\n TEST_PROGRAMS += test-path-utils$X\n TEST_PROGRAMS += test-sha1$X\n TEST_PROGRAMS += test-sigchain$X\n+TEST_PROGRAMS += test-index-version$X\n \n all:: $(TEST_PROGRAMS)\n \ndiff --git a/test-index-version.c b/test-index-version.c\nnew file mode 100644\nindex 0000000..bfaad9e\n--- /dev/null\n+++ b/test-index-version.c\n@@ -0,0 +1,14 @@\n+#include \"cache.h\"\n+\n+int main(int argc, const char **argv)\n+{\n+\tstruct cache_header hdr;\n+\tint version;\n+\n+\tmemset(&hdr,0,sizeof(hdr));\n+\tif (read(0, &hdr, sizeof(hdr)) != sizeof(hdr))\n+\t\treturn 0;\n+\tversion = ntohl(hdr.hdr_version);\n+\tprintf(\"%d\\n\", version);\n+\treturn 0;\n+}\n-- \n1.6.5.2.216.g9c1ec\n"},{"id":"129850","messageId":"1260786666-8405-4-git-send-email-pclouds@gmail.com","threadId":"21948","inReplyTo":"1260786666-8405-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 03/23] Introduce \"skip-worktree\" bit in index, teach Git to get/set this bit","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2009-12-14T10:30:46Z","receivedAt":"2009-12-14T10:30:46Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Detail about this bit is in Documentation/git-update-index.txt.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n Documentation/git-ls-files.txt        |    1 +\n Documentation/git-update-index.txt    |   29 +++++++++++++++++\n builtin-ls-files.c                    |    5 ++-\n builtin-update-index.c                |   16 +++++++++-\n cache.h                               |    4 ++-\n t/t2104-update-index-skip-worktree.sh |   57 +++++++++++++++++++++++++++++++++\n 6 files changed, 109 insertions(+), 3 deletions(-)\n create mode 100755 t/t2104-update-index-skip-worktree.sh\n\ndiff --git a/Documentation/git-ls-files.txt b/Documentation/git-ls-files.txt\nindex 021066e..6f9d880 100644\n--- a/Documentation/git-ls-files.txt\n+++ b/Documentation/git-ls-files.txt\n@@ -107,6 +107,7 @@ OPTIONS\n \tIdentify the file status with the following tags (followed by\n \ta space) at the start of each line:\n \tH::\tcached\n+\tS::\tskip-worktree\n \tM::\tunmerged\n \tR::\tremoved/deleted\n \tC::\tmodified/changed\ndiff --git a/Documentation/git-update-index.txt b/Documentation/git-update-index.txt\nindex 25e0bbe..a10f355 100644\n--- a/Documentation/git-update-index.txt\n+++ b/Documentation/git-update-index.txt\n@@ -15,6 +15,7 @@ SYNOPSIS\n \t     [--cacheinfo <mode> <object> <file>]\\*\n \t     [--chmod=(+|-)x]\n \t     [--assume-unchanged | --no-assume-unchanged]\n+\t     [--skip-worktree | --no-skip-worktree]\n \t     [--ignore-submodules]\n \t     [--really-refresh] [--unresolve] [--again | -g]\n \t     [--info-only] [--index-info]\n@@ -99,6 +100,13 @@ in the index e.g. when merging in a commit;\n thus, in case the assumed-untracked file is changed upstream,\n you will need to handle the situation manually.\n \n+--skip-worktree::\n+--no-skip-worktree::\n+\tWhen one of these flags is specified, the object name recorded\n+\tfor the paths are not updated. Instead, these options\n+\tset and unset the \"skip-worktree\" bit for the paths. See\n+\tsection \"Skip-worktree bit\" below for more information.\n+\n -g::\n --again::\n \tRuns 'git-update-index' itself on the paths whose index\n@@ -304,6 +312,27 @@ M foo.c\n <9> now it checks with lstat(2) and finds it has been changed.\n \n \n+Skip-worktree bit\n+-----------------\n+\n+Skip-worktree bit can be defined in one (long) sentence: When reading\n+an entry, if it is marked as skip-worktree, then Git pretends its\n+working directory version is up to date and read the index version\n+instead.\n+\n+To elaborate, \"reading\" means checking for file existence, reading\n+file attributes or file content. The working directory version may be\n+present or absent. If present, its content may match against the index\n+version or not. Writing is not affected by this bit, content safety\n+is still first priority. Note that Git _can_ update working directory\n+file, that is marked skip-worktree, if it is safe to do so (i.e.\n+working directory version matches index version)\n+\n+Although this bit looks similar to assume-unchanged bit, its goal is\n+different from assume-unchanged bit's. Skip-worktree also takes\n+precedence over assume-unchanged bit when both are set.\n+\n+\n Configuration\n -------------\n \ndiff --git a/builtin-ls-files.c b/builtin-ls-files.c\nindex f473220..c1afbad 100644\n--- a/builtin-ls-files.c\n+++ b/builtin-ls-files.c\n@@ -37,6 +37,7 @@ static const char *tag_removed = \"\";\n static const char *tag_other = \"\";\n static const char *tag_killed = \"\";\n static const char *tag_modified = \"\";\n+static const char *tag_skip_worktree = \"\";\n \n static void show_dir_entry(const char *tag, struct dir_entry *ent)\n {\n@@ -178,7 +179,8 @@ static void show_files(struct dir_struct *dir, const char *prefix)\n \t\t\t\tcontinue;\n \t\t\tif (ce->ce_flags & CE_UPDATE)\n \t\t\t\tcontinue;\n-\t\t\tshow_ce_entry(ce_stage(ce) ? tag_unmerged : tag_cached, ce);\n+\t\t\tshow_ce_entry(ce_stage(ce) ? tag_unmerged :\n+\t\t\t\t(ce_skip_worktree(ce) ? tag_skip_worktree : tag_cached), ce);\n \t\t}\n \t}\n \tif (show_deleted | show_modified) {\n@@ -490,6 +492,7 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)\n \t\ttag_modified = \"C \";\n \t\ttag_other = \"? \";\n \t\ttag_killed = \"K \";\n+\t\ttag_skip_worktree = \"S \";\n \t}\n \tif (show_modified || show_others || show_deleted || (dir.flags & DIR_SHOW_IGNORED) || show_killed)\n \t\trequire_work_tree = 1;\ndiff --git a/builtin-update-index.c b/builtin-update-index.c\nindex f1b6c8e..5e97d09 100644\n--- a/builtin-update-index.c\n+++ b/builtin-update-index.c\n@@ -24,6 +24,7 @@ static int info_only;\n static int force_remove;\n static int verbose;\n static int mark_valid_only;\n+static int mark_skip_worktree_only;\n #define MARK_FLAG 1\n #define UNMARK_FLAG 2\n \n@@ -276,6 +277,11 @@ static void update_one(const char *path, const char *prefix, int prefix_length)\n \t\t\tdie(\"Unable to mark file %s\", path);\n \t\tgoto free_return;\n \t}\n+\tif (mark_skip_worktree_only) {\n+\t\tif (mark_ce_flags(p, CE_SKIP_WORKTREE, mark_skip_worktree_only == MARK_FLAG))\n+\t\t\tdie(\"Unable to mark file %s\", path);\n+\t\tgoto free_return;\n+\t}\n \n \tif (force_remove) {\n \t\tif (remove_file_from_cache(p))\n@@ -384,7 +390,7 @@ static void read_index_info(int line_termination)\n }\n \n static const char update_index_usage[] =\n-\"git update-index [-q] [--add] [--replace] [--remove] [--unmerged] [--refresh] [--really-refresh] [--cacheinfo] [--chmod=(+|-)x] [--assume-unchanged] [--info-only] [--force-remove] [--stdin] [--index-info] [--unresolve] [--again | -g] [--ignore-missing] [-z] [--verbose] [--] <file>...\";\n+\"git update-index [-q] [--add] [--replace] [--remove] [--unmerged] [--refresh] [--really-refresh] [--cacheinfo] [--chmod=(+|-)x] [--assume-unchanged] [--skip-worktree|--no-skip-worktree] [--info-only] [--force-remove] [--stdin] [--index-info] [--unresolve] [--again | -g] [--ignore-missing] [-z] [--verbose] [--] <file>...\";\n \n static unsigned char head_sha1[20];\n static unsigned char merge_head_sha1[20];\n@@ -650,6 +656,14 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)\n \t\t\t\tmark_valid_only = UNMARK_FLAG;\n \t\t\t\tcontinue;\n \t\t\t}\n+\t\t\tif (!strcmp(path, \"--no-skip-worktree\")) {\n+\t\t\t\tmark_skip_worktree_only = UNMARK_FLAG;\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\t\t\tif (!strcmp(path, \"--skip-worktree\")) {\n+\t\t\t\tmark_skip_worktree_only = MARK_FLAG;\n+\t\t\t\tcontinue;\n+\t\t\t}\n \t\t\tif (!strcmp(path, \"--info-only\")) {\n \t\t\t\tinfo_only = 1;\n \t\t\t\tcontinue;\ndiff --git a/cache.h b/cache.h\nindex 9222774..f266246 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -181,10 +181,11 @@ struct cache_entry {\n  * Extended on-disk flags\n  */\n #define CE_INTENT_TO_ADD 0x20000000\n+#define CE_SKIP_WORKTREE 0x40000000\n /* CE_EXTENDED2 is for future extension */\n #define CE_EXTENDED2 0x80000000\n \n-#define CE_EXTENDED_FLAGS (CE_INTENT_TO_ADD)\n+#define CE_EXTENDED_FLAGS (CE_INTENT_TO_ADD | CE_SKIP_WORKTREE)\n \n /*\n  * Safeguard to avoid saving wrong flags:\n@@ -233,6 +234,7 @@ static inline size_t ce_namelen(const struct cache_entry *ce)\n \t\t\t    ondisk_cache_entry_size(ce_namelen(ce)))\n #define ce_stage(ce) ((CE_STAGEMASK & (ce)->ce_flags) >> CE_STAGESHIFT)\n #define ce_uptodate(ce) ((ce)->ce_flags & CE_UPTODATE)\n+#define ce_skip_worktree(ce) ((ce)->ce_flags & CE_SKIP_WORKTREE)\n #define ce_mark_uptodate(ce) ((ce)->ce_flags |= CE_UPTODATE)\n \n #define ce_permissions(mode) (((mode) & 0100) ? 0755 : 0644)\ndiff --git a/t/t2104-update-index-skip-worktree.sh b/t/t2104-update-index-skip-worktree.sh\nnew file mode 100755\nindex 0000000..1d0879b\n--- /dev/null\n+++ b/t/t2104-update-index-skip-worktree.sh\n@@ -0,0 +1,57 @@\n+#!/bin/sh\n+#\n+# Copyright (c) 2008 Nguyễn Thái Ngọc Duy\n+#\n+\n+test_description='skip-worktree bit test'\n+\n+. ./test-lib.sh\n+\n+cat >expect.full <<EOF\n+H 1\n+H 2\n+H sub/1\n+H sub/2\n+EOF\n+\n+cat >expect.skip <<EOF\n+S 1\n+H 2\n+S sub/1\n+H sub/2\n+EOF\n+\n+test_expect_success 'setup' '\n+\tmkdir sub &&\n+\ttouch ./1 ./2 sub/1 sub/2 &&\n+\tgit add 1 2 sub/1 sub/2 &&\n+\tgit ls-files -t | test_cmp expect.full -\n+'\n+\n+test_expect_success 'index is at version 2' '\n+\ttest \"$(test-index-version < .git/index)\" = 2\n+'\n+\n+test_expect_success 'update-index --skip-worktree' '\n+\tgit update-index --skip-worktree 1 sub/1 &&\n+\tgit ls-files -t | test_cmp expect.skip -\n+'\n+\n+test_expect_success 'index is at version 3 after having some skip-worktree entries' '\n+\ttest \"$(test-index-version < .git/index)\" = 3\n+'\n+\n+test_expect_success 'ls-files -t' '\n+\tgit ls-files -t | test_cmp expect.skip -\n+'\n+\n+test_expect_success 'update-index --no-skip-worktree' '\n+\tgit update-index --no-skip-worktree 1 sub/1 &&\n+\tgit ls-files -t | test_cmp expect.full -\n+'\n+\n+test_expect_success 'index version is back to 2 when there is no skip-worktree entry' '\n+\ttest \"$(test-index-version < .git/index)\" = 2\n+'\n+\n+test_done\n-- \n1.6.5.2.216.g9c1ec\n"},{"id":"129856","messageId":"1260786666-8405-5-git-send-email-pclouds@gmail.com","threadId":"21948","inReplyTo":"1260786666-8405-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 04/23] update-index: ignore update request if it's skip-worktree","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2009-12-14T10:30:47Z","receivedAt":"2009-12-14T10:30:47Z","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 builtin-apply.c |    2 +-\n cache.h         |    2 ++\n entry.c         |    2 +-\n read-cache.c    |   17 ++++++++++++++---\n unpack-trees.c  |    6 +++---\n 5 files changed, 21 insertions(+), 8 deletions(-)\n\ndiff --git a/builtin-apply.c b/builtin-apply.c\nindex 39dc96a..7717a66 100644\n--- a/builtin-apply.c\n+++ b/builtin-apply.c\n@@ -2505,7 +2505,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 f266246..f040f24 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -462,6 +462,8 @@ extern int index_name_is_other(const struct index_state *, const char *, int);\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+/* do stat comparison even if CE_SKIP_WORKTREE is true */\n+#define CE_MATCH_IGNORE_SKIP_WORKTREE\t\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 f276cf3..efee21f 100644\n--- a/entry.c\n+++ b/entry.c\n@@ -202,7 +202,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)) {\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 4e3e272..b31861c 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -259,12 +259,17 @@ 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_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@@ -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,14 +1005,20 @@ 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 \t/*\n-\t * CE_VALID means the user promised us that the change to\n-\t * the work tree does not matter and told us not to worry.\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;\ndiff --git a/unpack-trees.c b/unpack-trees.c\nindex 720f7a1..4870da9 100644\n--- a/unpack-trees.c\n+++ b/unpack-trees.c\n@@ -454,7 +454,7 @@ static int verify_uptodate(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@@ -572,7 +572,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@@ -1007,7 +1007,7 @@ int oneway_merge(struct cache_entry **src, struct unpack_trees_options *o)\n \t\tif (o->reset && !ce_uptodate(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":"129837","messageId":"1260786666-8405-6-git-send-email-pclouds@gmail.com","threadId":"21948","inReplyTo":"1260786666-8405-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 05/23] Teach ls-files and update-index to respect skip-worktree bit","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2009-12-14T10:30:48Z","receivedAt":"2009-12-14T10:30:48Z","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 builtin-ls-files.c               |    2 +\n builtin-update-index.c           |   38 +++++++-----\n t/t7011-skip-worktree-reading.sh |  114 ++++++++++++++++++++++++++++++++++++++\n 3 files changed, 138 insertions(+), 16 deletions(-)\n create mode 100755 t/t7011-skip-worktree-reading.sh\n\ndiff --git a/builtin-ls-files.c b/builtin-ls-files.c\nindex c1afbad..ad7e447 100644\n--- a/builtin-ls-files.c\n+++ b/builtin-ls-files.c\n@@ -194,6 +194,8 @@ static void show_files(struct dir_struct *dir, const char *prefix)\n \t\t\t\tcontinue;\n \t\t\tif (ce->ce_flags & CE_UPDATE)\n \t\t\t\tcontinue;\n+\t\t\tif (ce_skip_worktree(ce))\n+\t\t\t\tcontinue;\n \t\t\terr = lstat(ce->name, &st);\n \t\t\tif (show_deleted && err)\n \t\t\t\tshow_ce_entry(tag_removed, ce);\ndiff --git a/builtin-update-index.c b/builtin-update-index.c\nindex 5e97d09..97b9ea6 100644\n--- a/builtin-update-index.c\n+++ b/builtin-update-index.c\n@@ -172,29 +172,29 @@ static int process_directory(const char *path, int len, struct stat *st)\n \treturn error(\"%s: is a directory - add files inside instead\", path);\n }\n \n-/*\n- * Process a regular file\n- */\n-static int process_file(const char *path, int len, struct stat *st)\n-{\n-\tint pos = cache_name_pos(path, len);\n-\tstruct cache_entry *ce = pos < 0 ? NULL : active_cache[pos];\n-\n-\tif (ce && S_ISGITLINK(ce->ce_mode))\n-\t\treturn error(\"%s is already a gitlink, not replacing\", path);\n-\n-\treturn add_one_path(ce, path, len, st);\n-}\n-\n static int process_path(const char *path)\n {\n-\tint len;\n+\tint pos, len;\n \tstruct stat st;\n+\tstruct cache_entry *ce;\n \n \tlen = strlen(path);\n \tif (has_symlink_leading_path(path, len))\n \t\treturn error(\"'%s' is beyond a symbolic link\", path);\n \n+\tpos = cache_name_pos(path, len);\n+\tce = pos < 0 ? NULL : active_cache[pos];\n+\tif (ce && ce_skip_worktree(ce)) {\n+\t\t/*\n+\t\t * working directory version is assumed \"good\"\n+\t\t * so updating it does not make sense.\n+\t\t * On the other hand, removing it from index should work\n+\t\t */\n+\t\tif (allow_remove && remove_file_from_cache(path))\n+\t\t\treturn error(\"%s: cannot remove from the index\", path);\n+\t\treturn 0;\n+\t}\n+\n \t/*\n \t * First things first: get the stat information, to decide\n \t * what to do about the pathname!\n@@ -205,7 +205,13 @@ static int process_path(const char *path)\n \tif (S_ISDIR(st.st_mode))\n \t\treturn process_directory(path, len, &st);\n \n-\treturn process_file(path, len, &st);\n+\t/*\n+\t * Process a regular file\n+\t */\n+\tif (ce && S_ISGITLINK(ce->ce_mode))\n+\t\treturn error(\"%s is already a gitlink, not replacing\", path);\n+\n+\treturn add_one_path(ce, path, len, &st);\n }\n \n static int add_cacheinfo(unsigned int mode, const unsigned char *sha1,\ndiff --git a/t/t7011-skip-worktree-reading.sh b/t/t7011-skip-worktree-reading.sh\nnew file mode 100755\nindex 0000000..ede3ee1\n--- /dev/null\n+++ b/t/t7011-skip-worktree-reading.sh\n@@ -0,0 +1,114 @@\n+#!/bin/sh\n+#\n+# Copyright (c) 2008 Nguyễn Thái Ngọc Duy\n+#\n+\n+test_description='skip-worktree bit test'\n+\n+. ./test-lib.sh\n+\n+cat >expect.full <<EOF\n+H 1\n+H 2\n+H init.t\n+H sub/1\n+H sub/2\n+EOF\n+\n+cat >expect.skip <<EOF\n+S 1\n+H 2\n+H init.t\n+S sub/1\n+H sub/2\n+EOF\n+\n+NULL_SHA1=e69de29bb2d1d6434b8b29ae775ad8c2e48c5391\n+ZERO_SHA1=0000000000000000000000000000000000000000\n+setup_absent() {\n+\ttest -f 1 && rm 1\n+\tgit update-index --remove 1 &&\n+\tgit update-index --add --cacheinfo 100644 $NULL_SHA1 1 &&\n+\tgit update-index --skip-worktree 1\n+}\n+\n+test_absent() {\n+\techo \"100644 $NULL_SHA1 0\t1\" > expected &&\n+\tgit ls-files --stage 1 > result &&\n+\ttest_cmp expected result &&\n+\ttest ! -f 1\n+}\n+\n+setup_dirty() {\n+\tgit update-index --force-remove 1 &&\n+\techo dirty > 1 &&\n+\tgit update-index --add --cacheinfo 100644 $NULL_SHA1 1 &&\n+\tgit update-index --skip-worktree 1\n+}\n+\n+test_dirty() {\n+\techo \"100644 $NULL_SHA1 0\t1\" > expected &&\n+\tgit ls-files --stage 1 > result &&\n+\ttest_cmp expected result &&\n+\techo dirty > expected\n+\ttest_cmp expected 1\n+}\n+\n+test_expect_success 'setup' '\n+\ttest_commit init &&\n+\tmkdir sub &&\n+\ttouch ./1 ./2 sub/1 sub/2 &&\n+\tgit add 1 2 sub/1 sub/2 &&\n+\tgit update-index --skip-worktree 1 sub/1 &&\n+\tgit ls-files -t > result &&\n+\ttest_cmp expect.skip result\n+'\n+\n+test_expect_success 'update-index' '\n+\tsetup_absent &&\n+\tgit update-index 1 &&\n+\ttest_absent\n+'\n+\n+test_expect_success 'update-index' '\n+\tsetup_dirty &&\n+\tgit update-index 1 &&\n+\ttest_dirty\n+'\n+\n+test_expect_success 'update-index --remove' '\n+\tsetup_absent &&\n+\tgit update-index --remove 1 &&\n+\ttest -z \"$(git ls-files 1)\" &&\n+\ttest ! -f 1\n+'\n+\n+test_expect_success 'update-index --remove' '\n+\tsetup_dirty &&\n+\tgit update-index --remove 1 &&\n+\ttest -z \"$(git ls-files 1)\" &&\n+\techo dirty > expected &&\n+\ttest_cmp expected 1\n+'\n+\n+test_expect_success 'ls-files --delete' '\n+\tsetup_absent &&\n+\ttest -z \"$(git ls-files -d)\"\n+'\n+\n+test_expect_success 'ls-files --delete' '\n+\tsetup_dirty &&\n+\ttest -z \"$(git ls-files -d)\"\n+'\n+\n+test_expect_success 'ls-files --modified' '\n+\tsetup_absent &&\n+\ttest -z \"$(git ls-files -m)\"\n+'\n+\n+test_expect_success 'ls-files --modified' '\n+\tsetup_dirty &&\n+\ttest -z \"$(git ls-files -m)\"\n+'\n+\n+test_done\n-- \n1.6.5.2.216.g9c1ec\n"},{"id":"129857","messageId":"1260786666-8405-7-git-send-email-pclouds@gmail.com","threadId":"21948","inReplyTo":"1260786666-8405-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 06/23] Teach diff machinery to respect skip-worktree bit","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2009-12-14T10:30:49Z","receivedAt":"2009-12-14T10:30:49Z","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 diff-lib.c                       |    5 +++--\n diff.c                           |    2 +-\n t/t7011-skip-worktree-reading.sh |   23 +++++++++++++++++++++++\n 3 files changed, 27 insertions(+), 3 deletions(-)\n\ndiff --git a/diff-lib.c b/diff-lib.c\nindex 22da66e..b0b379d 100644\n--- a/diff-lib.c\n+++ b/diff-lib.c\n@@ -159,7 +159,7 @@ int run_diff_files(struct rev_info *revs, unsigned int option)\n \t\t\t\tcontinue;\n \t\t}\n \n-\t\tif (ce_uptodate(ce))\n+\t\tif (ce_uptodate(ce) || ce_skip_worktree(ce))\n \t\t\tcontinue;\n \n \t\t/* If CE_VALID is set, don't look at workdir for file removal */\n@@ -339,7 +339,8 @@ static void do_oneway_diff(struct unpack_trees_options *o,\n \tint match_missing, cached;\n \n \t/* if the entry is not checked out, don't examine work tree */\n-\tcached = o->index_only || (idx && (idx->ce_flags & CE_VALID));\n+\tcached = o->index_only ||\n+\t\t(idx && ((idx->ce_flags & CE_VALID) || ce_skip_worktree(idx)));\n \t/*\n \t * Backward compatibility wart - \"diff-index -m\" does\n \t * not mean \"do not ignore merges\", but \"match_missing\".\ndiff --git a/diff.c b/diff.c\nindex cd35e0c..3970df4 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -1805,7 +1805,7 @@ static int reuse_worktree_file(const char *name, const unsigned char *sha1, int\n \t * If ce is marked as \"assume unchanged\", there is no\n \t * guarantee that work tree matches what we are looking for.\n \t */\n-\tif (ce->ce_flags & CE_VALID)\n+\tif ((ce->ce_flags & CE_VALID) || ce_skip_worktree(ce))\n \t\treturn 0;\n \n \t/*\ndiff --git a/t/t7011-skip-worktree-reading.sh b/t/t7011-skip-worktree-reading.sh\nindex ede3ee1..5db93d0 100755\n--- a/t/t7011-skip-worktree-reading.sh\n+++ b/t/t7011-skip-worktree-reading.sh\n@@ -111,4 +111,27 @@ test_expect_success 'ls-files --modified' '\n \ttest -z \"$(git ls-files -m)\"\n '\n \n+echo \":000000 100644 $ZERO_SHA1 $NULL_SHA1 A\t1\" > expected\n+test_expect_success 'diff-index does not examine skip-worktree absent entries' '\n+\tsetup_absent &&\n+\tgit diff-index HEAD -- 1 > result &&\n+\ttest_cmp expected result\n+'\n+\n+test_expect_success 'diff-index does not examine skip-worktree dirty entries' '\n+\tsetup_dirty &&\n+\tgit diff-index HEAD -- 1 > result &&\n+\ttest_cmp expected result\n+'\n+\n+test_expect_success 'diff-files does not examine skip-worktree absent entries' '\n+\tsetup_absent &&\n+\ttest -z \"$(git diff-files -- one)\"\n+'\n+\n+test_expect_success 'diff-files does not examine skip-worktree dirty entries' '\n+\tsetup_dirty &&\n+\ttest -z \"$(git diff-files -- one)\"\n+'\n+\n test_done\n-- \n1.6.5.2.216.g9c1ec\n"},{"id":"129844","messageId":"1260786666-8405-8-git-send-email-pclouds@gmail.com","threadId":"21948","inReplyTo":"1260786666-8405-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 07/23] Teach grep to respect skip-worktree bit","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2009-12-14T10:30:50Z","receivedAt":"2009-12-14T10:30:50Z","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 builtin-grep.c                   |    2 +-\n t/t7011-skip-worktree-reading.sh |    9 +++++++++\n 2 files changed, 10 insertions(+), 1 deletions(-)\n\ndiff --git a/builtin-grep.c b/builtin-grep.c\nindex ad0e0a5..813fe97 100644\n--- a/builtin-grep.c\n+++ b/builtin-grep.c\n@@ -517,7 +517,7 @@ static int grep_cache(struct grep_opt *opt, const char **paths, int cached,\n \t\t * are identical, even if worktree file has been modified, so use\n \t\t * cache version instead\n \t\t */\n-\t\tif (cached || (ce->ce_flags & CE_VALID)) {\n+\t\tif (cached || (ce->ce_flags & CE_VALID) || ce_skip_worktree(ce)) {\n \t\t\tif (ce_stage(ce))\n \t\t\t\tcontinue;\n \t\t\thit |= grep_sha1(opt, ce->sha1, ce->name, 0);\ndiff --git a/t/t7011-skip-worktree-reading.sh b/t/t7011-skip-worktree-reading.sh\nindex 5db93d0..2ec677a 100755\n--- a/t/t7011-skip-worktree-reading.sh\n+++ b/t/t7011-skip-worktree-reading.sh\n@@ -111,6 +111,15 @@ test_expect_success 'ls-files --modified' '\n \ttest -z \"$(git ls-files -m)\"\n '\n \n+test_expect_success 'grep with skip-worktree file' '\n+\tgit update-index --no-skip-worktree 1 &&\n+\techo test > 1 &&\n+\tgit update-index 1 &&\n+\tgit update-index --skip-worktree 1 &&\n+\trm 1 &&\n+\ttest \"$(git grep --no-ext-grep test)\" = \"1:test\"\n+'\n+\n echo \":000000 100644 $ZERO_SHA1 $NULL_SHA1 A\t1\" > expected\n test_expect_success 'diff-index does not examine skip-worktree absent entries' '\n \tsetup_absent &&\n-- \n1.6.5.2.216.g9c1ec\n"},{"id":"129838","messageId":"1260786666-8405-9-git-send-email-pclouds@gmail.com","threadId":"21948","inReplyTo":"1260786666-8405-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 08/23] Teach commit to respect skip-worktree bit","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2009-12-14T10:30:51Z","receivedAt":"2009-12-14T10:30:51Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"There is nothing much to do when the index is committed as-is. But\nwhen partial commit is used, the index will be reset to HEAD. This\nleads to loss of skip-worktree bits in the original index. Those bits\nare kept (for committed paths only) so git-commit will know which\npaths to ignore later on.\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 |   12 ++++++++++++\n 2 files changed, 21 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin-commit.c b/builtin-commit.c\nindex 4bcce06..9fe5c25 100644\n--- a/builtin-commit.c\n+++ b/builtin-commit.c\n@@ -152,7 +152,7 @@ static int commit_index_files(void)\n static int list_paths(struct string_list *list, const char *with_tree,\n \t\t      const char *prefix, const char **pattern)\n {\n-\tint i;\n+\tstatic int i;\n \tchar *m;\n \n \tfor (i = 0; pattern[i]; i++)\n@@ -164,11 +164,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 = &i; /* better a valid pointer than a fake one */\n \t}\n \n \treturn report_path_error(m, pattern, prefix ? strlen(prefix) : 0);\n@@ -181,6 +185,9 @@ static void add_remove_files(struct string_list *list)\n \t\tstruct stat st;\n \t\tstruct string_list_item *p = &(list->items[i]);\n \n+\t\tif (p->util)\n+\t\t\tcontinue;\n+\n \t\tif (!lstat(p->string, &st)) {\n \t\t\tif (add_to_cache(p->string, &st, 0))\n \t\t\t\tdie(\"updating files failed\");\ndiff --git a/t/t7011-skip-worktree-reading.sh b/t/t7011-skip-worktree-reading.sh\nindex 2ec677a..5cf2cb8 100755\n--- a/t/t7011-skip-worktree-reading.sh\n+++ b/t/t7011-skip-worktree-reading.sh\n@@ -143,4 +143,16 @@ test_expect_success 'diff-files does not examine skip-worktree dirty entries' '\n \ttest -z \"$(git diff-files -- one)\"\n '\n \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_success 'commit on skip-worktree dirty entries' '\n+\tgit reset &&\n+\tsetup_dirty &&\n+\ttest_must_fail git commit -m null 1\n+'\n+\n test_done\n-- \n1.6.5.2.216.g9c1ec\n"},{"id":"129845","messageId":"1260786666-8405-10-git-send-email-pclouds@gmail.com","threadId":"21948","inReplyTo":"1260786666-8405-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 09/23] Teach Git to respect skip-worktree bit (writing part)","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2009-12-14T10:30:52Z","receivedAt":"2009-12-14T10:30:52Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This part is mainly to remove CE_VALID shortcuts (and as a\nconsequence, ce_uptodate() shortcuts as it may be turned on by\nCE_VALID) in writing code path if skip-worktree is used. Various tests\nare added to avoid future breakages.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n t/t7012-skip-worktree-writing.sh |  139 ++++++++++++++++++++++++++++++++++++++\n unpack-trees.c                   |    4 +-\n 2 files changed, 141 insertions(+), 2 deletions(-)\n create mode 100755 t/t7012-skip-worktree-writing.sh\n\ndiff --git a/t/t7012-skip-worktree-writing.sh b/t/t7012-skip-worktree-writing.sh\nnew file mode 100755\nindex 0000000..c75efe4\n--- /dev/null\n+++ b/t/t7012-skip-worktree-writing.sh\n@@ -0,0 +1,139 @@\n+#!/bin/sh\n+#\n+# Copyright (c) 2008 Nguyễn Thái Ngọc Duy\n+#\n+\n+test_description='test worktree writing operations when skip-worktree is used'\n+\n+. ./test-lib.sh\n+\n+test_expect_success 'setup' '\n+\ttest_commit init &&\n+\techo modified >> init.t &&\n+\ttouch added &&\n+\tgit add init.t added &&\n+\tgit commit -m \"modified and added\" &&\n+\tgit tag top\n+'\n+\n+test_expect_success 'read-tree updates worktree, absent case' '\n+\tgit checkout -f top &&\n+\tgit update-index --skip-worktree init.t &&\n+\trm init.t &&\n+\tgit read-tree -m -u HEAD^ &&\n+\techo init > expected &&\n+\ttest_cmp expected init.t\n+'\n+\n+test_expect_success 'read-tree updates worktree, dirty case' '\n+\tgit checkout -f top &&\n+\tgit update-index --skip-worktree init.t &&\n+\techo dirty >> init.t &&\n+\ttest_must_fail git read-tree -m -u HEAD^ &&\n+\tgrep -q dirty init.t &&\n+\ttest \"$(git ls-files -t init.t)\" = \"S init.t\" &&\n+\tgit update-index --no-skip-worktree init.t\n+'\n+\n+test_expect_success 'read-tree removes worktree, absent case' '\n+\tgit checkout -f top &&\n+\tgit update-index --skip-worktree added &&\n+\trm added &&\n+\tgit read-tree -m -u HEAD^ &&\n+\ttest ! -f added\n+'\n+\n+test_expect_success 'read-tree removes worktree, dirty case' '\n+\tgit checkout -f top &&\n+\tgit update-index --skip-worktree added &&\n+\techo dirty >> added &&\n+\ttest_must_fail git read-tree -m -u HEAD^ &&\n+\tgrep -q dirty added &&\n+\ttest \"$(git ls-files -t added)\" = \"S added\" &&\n+\tgit update-index --no-skip-worktree added\n+'\n+\n+NULL_SHA1=e69de29bb2d1d6434b8b29ae775ad8c2e48c5391\n+ZERO_SHA0=0000000000000000000000000000000000000000\n+setup_absent() {\n+\ttest -f 1 && rm 1\n+\tgit update-index --remove 1 &&\n+\tgit update-index --add --cacheinfo 100644 $NULL_SHA1 1 &&\n+\tgit update-index --skip-worktree 1\n+}\n+\n+test_absent() {\n+\techo \"100644 $NULL_SHA1 0\t1\" > expected &&\n+\tgit ls-files --stage 1 > result &&\n+\ttest_cmp expected result &&\n+\ttest ! -f 1\n+}\n+\n+setup_dirty() {\n+\tgit update-index --force-remove 1 &&\n+\techo dirty > 1 &&\n+\tgit update-index --add --cacheinfo 100644 $NULL_SHA1 1 &&\n+\tgit update-index --skip-worktree 1\n+}\n+\n+test_dirty() {\n+\techo \"100644 $NULL_SHA1 0\t1\" > expected &&\n+\tgit ls-files --stage 1 > result &&\n+\ttest_cmp expected result &&\n+\techo dirty > expected\n+\ttest_cmp expected 1\n+}\n+\n+cat >expected <<EOF\n+S 1\n+H 2\n+H init.t\n+S sub/1\n+H sub/2\n+EOF\n+\n+test_expect_success 'index setup' '\n+\tgit checkout -f init &&\n+\tmkdir sub &&\n+\ttouch ./1 ./2 sub/1 sub/2 &&\n+\tgit add 1 2 sub/1 sub/2 &&\n+\tgit update-index --skip-worktree 1 sub/1 &&\n+\tgit ls-files -t > result &&\n+\ttest_cmp expected result\n+'\n+\n+test_expect_success 'git-add ignores worktree content' '\n+\tsetup_absent &&\n+\tgit add 1 &&\n+\ttest_absent\n+'\n+\n+test_expect_success 'git-add ignores worktree content' '\n+\tsetup_dirty &&\n+\tgit add 1 &&\n+\ttest_dirty\n+'\n+\n+test_expect_success 'git-rm fails if worktree is dirty' '\n+\tsetup_dirty &&\n+\ttest_must_fail git rm 1 &&\n+\ttest_dirty\n+'\n+\n+cat >expected <<EOF\n+Would remove expected\n+Would remove result\n+EOF\n+test_expect_success 'git-clean, absent case' '\n+\tsetup_absent &&\n+\tgit clean -n > result &&\n+\ttest_cmp expected result\n+'\n+\n+test_expect_success 'git-clean, dirty case' '\n+\tsetup_dirty &&\n+\tgit clean -n > result &&\n+\ttest_cmp expected result\n+'\n+\n+test_done\ndiff --git a/unpack-trees.c b/unpack-trees.c\nindex 4870da9..1ab3c89 100644\n--- a/unpack-trees.c\n+++ b/unpack-trees.c\n@@ -450,7 +450,7 @@ static int verify_uptodate(struct cache_entry *ce,\n {\n \tstruct stat st;\n \n-\tif (o->index_only || o->reset || ce_uptodate(ce))\n+\tif (o->index_only || (!ce_skip_worktree(ce) && (o->reset || ce_uptodate(ce))))\n \t\treturn 0;\n \n \tif (!lstat(ce->name, &st)) {\n@@ -1004,7 +1004,7 @@ int oneway_merge(struct cache_entry **src, struct unpack_trees_options *o)\n \n \tif (old && same(old, a)) {\n \t\tint update = 0;\n-\t\tif (o->reset && !ce_uptodate(old)) {\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|CE_MATCH_IGNORE_SKIP_WORKTREE))\n-- \n1.6.5.2.216.g9c1ec\n"},{"id":"129848","messageId":"1260786666-8405-11-git-send-email-pclouds@gmail.com","threadId":"21948","inReplyTo":"1260786666-8405-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 10/23] Avoid writing to buffer in add_excludes_from_file_1()","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2009-12-14T10:30:53Z","receivedAt":"2009-12-14T10:30:53Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"In the next patch, the buffer that is being used within\nadd_excludes_from_file_1() comes from another function and does not\nhave extra space to put \\n at the end.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n dir.c |    5 ++---\n 1 files changed, 2 insertions(+), 3 deletions(-)\n\ndiff --git a/dir.c b/dir.c\nindex e05b850..1170d64 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -229,10 +229,9 @@ static int add_excludes_from_file_1(const char *fname,\n \n \tif (buf_p)\n \t\t*buf_p = buf;\n-\tbuf[size++] = '\\n';\n \tentry = buf;\n-\tfor (i = 0; i < size; i++) {\n-\t\tif (buf[i] == '\\n') {\n+\tfor (i = 0; i <= size; i++) {\n+\t\tif (i == size || buf[i] == '\\n') {\n \t\t\tif (entry != buf + i && entry[0] != '#') {\n \t\t\t\tbuf[i - (i && buf[i-1] == '\\r')] = 0;\n \t\t\t\tadd_exclude(entry, base, baselen, which);\n-- \n1.6.5.2.216.g9c1ec\n"},{"id":"129849","messageId":"1260786666-8405-12-git-send-email-pclouds@gmail.com","threadId":"21948","inReplyTo":"1260786666-8405-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 11/23] Read .gitignore from index if it is skip-worktree","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2009-12-14T10:30:54Z","receivedAt":"2009-12-14T10:30:54Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This adds index as a prerequisite for directory listing (with\nexclude).  At the moment directory listing is used by \"git clean\",\n\"git add\", \"git ls-files\" and \"git status\"/\"git commit\" and\nunpack_trees()-related commands.  These commands have been\nchecked/modified to populate index before doing directory listing.\n\nadd_excludes_from_file() does not enable this feature, because it\nis used to read .git/info/exclude and some explicit files specified\nby \"git ls-files\".\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n Documentation/technical/api-directory-listing.txt |    3 +\n builtin-clean.c                                   |    4 +-\n builtin-ls-files.c                                |    4 +-\n dir.c                                             |   65 ++++++++++++++------\n t/t3001-ls-files-others-exclude.sh                |   22 +++++++\n t/t7300-clean.sh                                  |   19 ++++++\n 6 files changed, 95 insertions(+), 22 deletions(-)\n\ndiff --git a/Documentation/technical/api-directory-listing.txt b/Documentation/technical/api-directory-listing.txt\nindex 5bbd18f..add6f43 100644\n--- a/Documentation/technical/api-directory-listing.txt\n+++ b/Documentation/technical/api-directory-listing.txt\n@@ -58,6 +58,9 @@ The result of the enumeration is left in these fields::\n Calling sequence\n ----------------\n \n+Note: index may be looked at for .gitignore files that are CE_SKIP_WORKTREE\n+marked. If you to exclude files, make sure you have loaded index first.\n+\n * Prepare `struct dir_struct dir` and clear it with `memset(&dir, 0,\n   sizeof(dir))`.\n \ndiff --git a/builtin-clean.c b/builtin-clean.c\nindex 2d8c735..e424b77 100644\n--- a/builtin-clean.c\n+++ b/builtin-clean.c\n@@ -71,11 +71,13 @@ int cmd_clean(int argc, const char **argv, const char *prefix)\n \n \tdir.flags |= DIR_SHOW_OTHER_DIRECTORIES;\n \n+\tif (read_cache() < 0)\n+\t\tdie(\"index file corrupt\");\n+\n \tif (!ignored)\n \t\tsetup_standard_excludes(&dir);\n \n \tpathspec = get_pathspec(prefix, argv);\n-\tread_cache();\n \n \tfill_directory(&dir, pathspec);\n \ndiff --git a/builtin-ls-files.c b/builtin-ls-files.c\nindex ad7e447..2e47242 100644\n--- a/builtin-ls-files.c\n+++ b/builtin-ls-files.c\n@@ -485,6 +485,9 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)\n \t\tprefix_offset = strlen(prefix);\n \tgit_config(git_default_config, NULL);\n \n+\tif (read_cache() < 0)\n+\t\tdie(\"index file corrupt\");\n+\n \targc = parse_options(argc, argv, prefix, builtin_ls_files_options,\n \t\t\tls_files_usage, 0);\n \tif (show_tag || show_valid_bit) {\n@@ -513,7 +516,6 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)\n \tpathspec = get_pathspec(prefix, argv);\n \n \t/* be nice with submodule paths ending in a slash */\n-\tread_cache();\n \tif (pathspec)\n \t\tstrip_trailing_slash_from_submodules();\n \ndiff --git a/dir.c b/dir.c\nindex 1170d64..e8e5b79 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -200,11 +200,35 @@ void add_exclude(const char *string, const char *base,\n \twhich->excludes[which->nr++] = x;\n }\n \n+static void *read_skip_worktree_file_from_index(const char *path, size_t *size)\n+{\n+\tint pos, len;\n+\tunsigned long sz;\n+\tenum object_type type;\n+\tvoid *data;\n+\tstruct index_state *istate = &the_index;\n+\n+\tlen = strlen(path);\n+\tpos = index_name_pos(istate, path, len);\n+\tif (pos < 0)\n+\t\treturn NULL;\n+\tif (!ce_skip_worktree(istate->cache[pos]))\n+\t\treturn NULL;\n+\tdata = read_sha1_file(istate->cache[pos]->sha1, &type, &sz);\n+\tif (!data || type != OBJ_BLOB) {\n+\t\tfree(data);\n+\t\treturn NULL;\n+\t}\n+\t*size = xsize_t(sz);\n+\treturn data;\n+}\n+\n static int add_excludes_from_file_1(const char *fname,\n \t\t\t\t    const char *base,\n \t\t\t\t    int baselen,\n \t\t\t\t    char **buf_p,\n-\t\t\t\t    struct exclude_list *which)\n+\t\t\t\t    struct exclude_list *which,\n+\t\t\t\t    int check_index)\n {\n \tstruct stat st;\n \tint fd, i;\n@@ -212,20 +236,26 @@ static int add_excludes_from_file_1(const char *fname,\n \tchar *buf, *entry;\n \n \tfd = open(fname, O_RDONLY);\n-\tif (fd < 0 || fstat(fd, &st) < 0)\n-\t\tgoto err;\n-\tsize = xsize_t(st.st_size);\n-\tif (size == 0) {\n-\t\tclose(fd);\n-\t\treturn 0;\n+\tif (fd < 0 || fstat(fd, &st) < 0) {\n+\t\tif (0 <= fd)\n+\t\t\tclose(fd);\n+\t\tif (!check_index ||\n+\t\t    (buf = read_skip_worktree_file_from_index(fname, &size)) == NULL)\n+\t\t\treturn -1;\n \t}\n-\tbuf = xmalloc(size+1);\n-\tif (read_in_full(fd, buf, size) != size)\n-\t{\n-\t\tfree(buf);\n-\t\tgoto err;\n+\telse {\n+\t\tsize = xsize_t(st.st_size);\n+\t\tif (size == 0) {\n+\t\t\tclose(fd);\n+\t\t\treturn 0;\n+\t\t}\n+\t\tbuf = xmalloc(size);\n+\t\tif (read_in_full(fd, buf, size) != size) {\n+\t\t\tclose(fd);\n+\t\t\treturn -1;\n+\t\t}\n+\t\tclose(fd);\n \t}\n-\tclose(fd);\n \n \tif (buf_p)\n \t\t*buf_p = buf;\n@@ -240,17 +270,12 @@ static int add_excludes_from_file_1(const char *fname,\n \t\t}\n \t}\n \treturn 0;\n-\n- err:\n-\tif (0 <= fd)\n-\t\tclose(fd);\n-\treturn -1;\n }\n \n void add_excludes_from_file(struct dir_struct *dir, const char *fname)\n {\n \tif (add_excludes_from_file_1(fname, \"\", 0, NULL,\n-\t\t\t\t     &dir->exclude_list[EXC_FILE]) < 0)\n+\t\t\t\t     &dir->exclude_list[EXC_FILE], 0) < 0)\n \t\tdie(\"cannot use %s as an exclude file\", fname);\n }\n \n@@ -301,7 +326,7 @@ static void prep_exclude(struct dir_struct *dir, const char *base, int baselen)\n \t\tstrcpy(dir->basebuf + stk->baselen, dir->exclude_per_dir);\n \t\tadd_excludes_from_file_1(dir->basebuf,\n \t\t\t\t\t dir->basebuf, stk->baselen,\n-\t\t\t\t\t &stk->filebuf, el);\n+\t\t\t\t\t &stk->filebuf, el, 1);\n \t\tdir->exclude_stack = stk;\n \t\tcurrent = stk->baselen;\n \t}\ndiff --git a/t/t3001-ls-files-others-exclude.sh b/t/t3001-ls-files-others-exclude.sh\nindex c65bca8..132c476 100755\n--- a/t/t3001-ls-files-others-exclude.sh\n+++ b/t/t3001-ls-files-others-exclude.sh\n@@ -64,6 +64,8 @@ two/*.4\n echo '!*.2\n !*.8' >one/two/.gitignore\n \n+allignores='.gitignore one/.gitignore one/two/.gitignore'\n+\n test_expect_success \\\n     'git ls-files --others with various exclude options.' \\\n     'git ls-files --others \\\n@@ -85,6 +87,26 @@ test_expect_success \\\n        >output &&\n      test_cmp expect output'\n \n+test_expect_success 'setup skip-worktree gitignore' '\n+\tgit add $allignores &&\n+\tgit update-index --skip-worktree $allignores &&\n+\trm $allignores\n+'\n+\n+test_expect_success \\\n+    'git ls-files --others with various exclude options.' \\\n+    'git ls-files --others \\\n+       --exclude=\\*.6 \\\n+       --exclude-per-directory=.gitignore \\\n+       --exclude-from=.git/ignore \\\n+       >output &&\n+     test_cmp expect output'\n+\n+test_expect_success 'restore gitignore' '\n+\tgit checkout $allignores &&\n+\trm .git/index\n+'\n+\n cat > excludes-file <<\\EOF\n *.[1-8]\n e*\ndiff --git a/t/t7300-clean.sh b/t/t7300-clean.sh\nindex 929d5d4..8073d02 100755\n--- a/t/t7300-clean.sh\n+++ b/t/t7300-clean.sh\n@@ -22,6 +22,25 @@ test_expect_success 'setup' '\n \n '\n \n+test_expect_success 'git clean with skip-worktree .gitignore' '\n+\tgit update-index --skip-worktree .gitignore &&\n+\trm .gitignore &&\n+\tmkdir -p build docs &&\n+\ttouch a.out src/part3.c docs/manual.txt obj.o build/lib.so &&\n+\tgit clean &&\n+\ttest -f Makefile &&\n+\ttest -f README &&\n+\ttest -f src/part1.c &&\n+\ttest -f src/part2.c &&\n+\ttest ! -f a.out &&\n+\ttest ! -f src/part3.c &&\n+\ttest -f docs/manual.txt &&\n+\ttest -f obj.o &&\n+\ttest -f build/lib.so &&\n+\tgit update-index --no-skip-worktree .gitignore &&\n+\tgit checkout .gitignore\n+'\n+\n test_expect_success 'git clean' '\n \n \tmkdir -p build docs &&\n-- \n1.6.5.2.216.g9c1ec\n"},{"id":"129846","messageId":"1260786666-8405-13-git-send-email-pclouds@gmail.com","threadId":"21948","inReplyTo":"1260786666-8405-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 12/23] unpack-trees(): carry skip-worktree bit over in merged_entry()","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2009-12-14T10:30:55Z","receivedAt":"2009-12-14T10:30:55Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"In this code path, we would remove \"old\" and replace it with \"merge\".\n\"old\" may have skip-worktree bit, so re-add it to \"merge\".\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n unpack-trees.c |    2 ++\n 1 files changed, 2 insertions(+), 0 deletions(-)\n\ndiff --git a/unpack-trees.c b/unpack-trees.c\nindex 1ab3c89..ac59fbe 100644\n--- a/unpack-trees.c\n+++ b/unpack-trees.c\n@@ -680,6 +680,8 @@ static int merged_entry(struct cache_entry *merge, struct cache_entry *old,\n \t\t} else {\n \t\t\tif (verify_uptodate(old, o))\n \t\t\t\treturn -1;\n+\t\t\tif (ce_skip_worktree(old))\n+\t\t\t\tupdate |= CE_SKIP_WORKTREE;\n \t\t\tinvalidate_ce_path(old, o);\n \t\t}\n \t}\n-- \n1.6.5.2.216.g9c1ec\n"},{"id":"129847","messageId":"1260786666-8405-14-git-send-email-pclouds@gmail.com","threadId":"21948","inReplyTo":"1260786666-8405-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 13/23] excluded_1(): support exclude files in index","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2009-12-14T10:30:56Z","receivedAt":"2009-12-14T10:30:56Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Index does not really have \"directories\", attempts to match \"foo/\"\nagainst index will fail unless someone tries to reconstruct directories\nfrom a list of file.\n\nObserving that dtype in this function can never be NULL (otherwise\nit would segfault), dtype NULL will be used to say \"hey.. you are\nmatching against index\" and behave properly.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n dir.c |    6 ++++++\n 1 files changed, 6 insertions(+), 0 deletions(-)\n\ndiff --git a/dir.c b/dir.c\nindex e8e5b79..7735cea 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -349,6 +349,12 @@ static int excluded_1(const char *pathname,\n \t\t\tint to_exclude = x->to_exclude;\n \n \t\t\tif (x->flags & EXC_FLAG_MUSTBEDIR) {\n+\t\t\t\tif (!dtype) {\n+\t\t\t\t\tif (!prefixcmp(pathname, exclude))\n+\t\t\t\t\t\treturn to_exclude;\n+\t\t\t\t\telse\n+\t\t\t\t\t\tcontinue;\n+\t\t\t\t}\n \t\t\t\tif (*dtype == DT_UNKNOWN)\n \t\t\t\t\t*dtype = get_dtype(NULL, pathname, pathlen);\n \t\t\t\tif (*dtype != DT_DIR)\n-- \n1.6.5.2.216.g9c1ec\n"},{"id":"129843","messageId":"1260786666-8405-15-git-send-email-pclouds@gmail.com","threadId":"21948","inReplyTo":"1260786666-8405-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 14/23] dir.c: export excluded_1() and add_excludes_from_file_1()","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2009-12-14T10:30:57Z","receivedAt":"2009-12-14T10:30:57Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"These functions are used to handle .gitignore. They are now exported\nso that sparse checkout can reuse.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n dir.c |   32 ++++++++++++++++----------------\n dir.h |    4 ++++\n 2 files changed, 20 insertions(+), 16 deletions(-)\n\ndiff --git a/dir.c b/dir.c\nindex 7735cea..6b1c478 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -223,12 +223,12 @@ static void *read_skip_worktree_file_from_index(const char *path, size_t *size)\n \treturn data;\n }\n \n-static int add_excludes_from_file_1(const char *fname,\n-\t\t\t\t    const char *base,\n-\t\t\t\t    int baselen,\n-\t\t\t\t    char **buf_p,\n-\t\t\t\t    struct exclude_list *which,\n-\t\t\t\t    int check_index)\n+int add_excludes_from_file_to_list(const char *fname,\n+\t\t\t\t   const char *base,\n+\t\t\t\t   int baselen,\n+\t\t\t\t   char **buf_p,\n+\t\t\t\t   struct exclude_list *which,\n+\t\t\t\t   int check_index)\n {\n \tstruct stat st;\n \tint fd, i;\n@@ -274,8 +274,8 @@ static int add_excludes_from_file_1(const char *fname,\n \n void add_excludes_from_file(struct dir_struct *dir, const char *fname)\n {\n-\tif (add_excludes_from_file_1(fname, \"\", 0, NULL,\n-\t\t\t\t     &dir->exclude_list[EXC_FILE], 0) < 0)\n+\tif (add_excludes_from_file_to_list(fname, \"\", 0, NULL,\n+\t\t\t\t\t   &dir->exclude_list[EXC_FILE], 0) < 0)\n \t\tdie(\"cannot use %s as an exclude file\", fname);\n }\n \n@@ -324,9 +324,9 @@ static void prep_exclude(struct dir_struct *dir, const char *base, int baselen)\n \t\tmemcpy(dir->basebuf + current, base + current,\n \t\t       stk->baselen - current);\n \t\tstrcpy(dir->basebuf + stk->baselen, dir->exclude_per_dir);\n-\t\tadd_excludes_from_file_1(dir->basebuf,\n-\t\t\t\t\t dir->basebuf, stk->baselen,\n-\t\t\t\t\t &stk->filebuf, el, 1);\n+\t\tadd_excludes_from_file_to_list(dir->basebuf,\n+\t\t\t\t\t       dir->basebuf, stk->baselen,\n+\t\t\t\t\t       &stk->filebuf, el, 1);\n \t\tdir->exclude_stack = stk;\n \t\tcurrent = stk->baselen;\n \t}\n@@ -336,9 +336,9 @@ static void prep_exclude(struct dir_struct *dir, const char *base, int baselen)\n /* Scan the list and let the last match determine the fate.\n  * Return 1 for exclude, 0 for include and -1 for undecided.\n  */\n-static int excluded_1(const char *pathname,\n-\t\t      int pathlen, const char *basename, int *dtype,\n-\t\t      struct exclude_list *el)\n+int excluded_from_list(const char *pathname,\n+\t\t       int pathlen, const char *basename, int *dtype,\n+\t\t       struct exclude_list *el)\n {\n \tint i;\n \n@@ -412,8 +412,8 @@ int excluded(struct dir_struct *dir, const char *pathname, int *dtype_p)\n \n \tprep_exclude(dir, pathname, basename-pathname);\n \tfor (st = EXC_CMDL; st <= EXC_FILE; st++) {\n-\t\tswitch (excluded_1(pathname, pathlen, basename,\n-\t\t\t\t   dtype_p, &dir->exclude_list[st])) {\n+\t\tswitch (excluded_from_list(pathname, pathlen, basename,\n+\t\t\t\t\t   dtype_p, &dir->exclude_list[st])) {\n \t\tcase 0:\n \t\t\treturn 0;\n \t\tcase 1:\ndiff --git a/dir.h b/dir.h\nindex a631446..472e11e 100644\n--- a/dir.h\n+++ b/dir.h\n@@ -69,7 +69,11 @@ extern int match_pathspec(const char **pathspec, const char *name, int namelen,\n extern int fill_directory(struct dir_struct *dir, const char **pathspec);\n extern int read_directory(struct dir_struct *, const char *path, int len, const char **pathspec);\n \n+extern int excluded_from_list(const char *pathname, int pathlen, const char *basename,\n+\t\t\t      int *dtype, struct exclude_list *el);\n extern int excluded(struct dir_struct *, const char *, int *);\n+extern int add_excludes_from_file_to_list(const char *fname, const char *base, int baselen,\n+\t\t\t\t\t  char **buf_p, struct exclude_list *which, int check_index);\n extern void add_excludes_from_file(struct dir_struct *, const char *fname);\n extern void add_exclude(const char *string, const char *base,\n \t\t\tint baselen, struct exclude_list *which);\n-- \n1.6.5.2.216.g9c1ec\n"},{"id":"129842","messageId":"1260786666-8405-16-git-send-email-pclouds@gmail.com","threadId":"21948","inReplyTo":"1260786666-8405-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 15/23] Introduce \"sparse checkout\"","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2009-12-14T10:30:58Z","receivedAt":"2009-12-14T10:30:58Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"With skip-worktree bit, you can manually set it to unwanted files,\nthen remove them: you would have the so-called sparse checkout. The\ndisadvantages are:\n\n - Porcelain tools are not aware of this. Everytime you do an\n   operation that may update working directory, skip-worktree may be\n   cleared out. You have to set them again.\n\n - You still have to remove skip-worktree'd files manually, which is\n   boring and ineffective.\n\nThese will be addressed in the following patches. This patch gives an\nidea what is \"sparse checkout\" in Documentation/git-read-tree.txt.\nThis file is chosen instead of git-checkout.txt because it is quite\ntechnical and user-unfriendly. I'd expect git-checkout.txt to have\nsomething when Porcelain support is done.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n Documentation/git-read-tree.txt |   44 +++++++++++++++++++++++++++++++++++++++\n 1 files changed, 44 insertions(+), 0 deletions(-)\n\ndiff --git a/Documentation/git-read-tree.txt b/Documentation/git-read-tree.txt\nindex 4a932b0..8b39716 100644\n--- a/Documentation/git-read-tree.txt\n+++ b/Documentation/git-read-tree.txt\n@@ -360,6 +360,50 @@ middle of doing, and when your working tree is ready (i.e. you\n have finished your work-in-progress), attempt the merge again.\n \n \n+Sparse checkout\n+---------------\n+\n+\"Sparse checkout\" allows to sparsely populate working directory.\n+It uses skip-worktree bit (see linkgit:git-update-index[1]) to tell\n+Git whether a file on working directory is worth looking at.\n+\n+\"git read-tree\" and other merge-based commands (\"git merge\", \"git\n+checkout\"...) can help maintaining skip-worktree bitmap and working\n+directory update. `$GIT_DIR/info/sparse-checkout` is used to\n+define the skip-worktree reference bitmap. When \"git read-tree\" needs\n+to update working directory, it will reset skip-worktree bit in index\n+based on this file, which uses the same syntax as .gitignore files.\n+If an entry matches a pattern in this file, skip-worktree will be\n+set on that entry. Otherwise, skip-worktree will be unset.\n+\n+Then it compares the new skip-worktree value with the previous one. If\n+skip-worktree turns from unset to set, it will add the corresponding\n+file back. If it turns from set to unset, that file will be removed.\n+\n+While `$GIT_DIR/info/sparse-checkout` is usually used to specify what\n+files are in. You can also specify what files are _not_ in, using\n+negate patterns. For example, to remove file \"unwanted\":\n+\n+----------------\n+*\n+!unwanted\n+----------------\n+\n+Another tricky thing is fully repopulating working directory when you\n+no longer want sparse checkout. You cannot just disable \"sparse\n+checkout\" because skip-worktree are still in the index and you working\n+directory is still sparsely populated. You should re-populate working\n+directory with the `$GIT_DIR/info/sparse-checkout` file content as\n+follows:\n+\n+----------------\n+*\n+----------------\n+\n+Then you can disable sparse checkout. Sparse checkout support in \"git\n+read-tree\" and similar commands is disabled by default.\n+\n+\n SEE ALSO\n --------\n linkgit:git-write-tree[1]; linkgit:git-ls-files[1];\n-- \n1.6.5.2.216.g9c1ec\n"},{"id":"129840","messageId":"1260786666-8405-17-git-send-email-pclouds@gmail.com","threadId":"21948","inReplyTo":"1260786666-8405-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 16/23] unpack-trees(): add CE_WT_REMOVE to remove on worktree alone","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2009-12-14T10:30:59Z","receivedAt":"2009-12-14T10:30:59Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"CE_REMOVE now removes both worktree and index versions. Sparse\ncheckout must be able to remove worktree version while keep the\nindex intact when checkout area is narrowed.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n cache.h        |    3 +++\n unpack-trees.c |    9 ++++++++-\n 2 files changed, 11 insertions(+), 1 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex f040f24..3a37469 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -177,6 +177,9 @@ struct cache_entry {\n #define CE_HASHED    (0x100000)\n #define CE_UNHASHED  (0x200000)\n \n+/* Only remove in work directory, not index */\n+#define CE_WT_REMOVE (0x400000)\n+\n /*\n  * Extended on-disk flags\n  */\ndiff --git a/unpack-trees.c b/unpack-trees.c\nindex ac59fbe..eb1a818 100644\n--- a/unpack-trees.c\n+++ b/unpack-trees.c\n@@ -78,7 +78,7 @@ static int check_updates(struct unpack_trees_options *o)\n \tif (o->update && o->verbose_update) {\n \t\tfor (total = cnt = 0; cnt < index->cache_nr; cnt++) {\n \t\t\tstruct cache_entry *ce = index->cache[cnt];\n-\t\t\tif (ce->ce_flags & (CE_UPDATE | CE_REMOVE))\n+\t\t\tif (ce->ce_flags & (CE_UPDATE | CE_REMOVE | CE_WT_REMOVE))\n \t\t\t\ttotal++;\n \t\t}\n \n@@ -92,6 +92,13 @@ static int check_updates(struct unpack_trees_options *o)\n \tfor (i = 0; i < index->cache_nr; i++) {\n \t\tstruct cache_entry *ce = index->cache[i];\n \n+\t\tif (ce->ce_flags & CE_WT_REMOVE) {\n+\t\t\tdisplay_progress(progress, ++cnt);\n+\t\t\tif (o->update)\n+\t\t\t\tunlink_entry(ce);\n+\t\t\tcontinue;\n+\t\t}\n+\n \t\tif (ce->ce_flags & CE_REMOVE) {\n \t\t\tdisplay_progress(progress, ++cnt);\n \t\t\tif (o->update)\n-- \n1.6.5.2.216.g9c1ec\n"},{"id":"129852","messageId":"1260786666-8405-18-git-send-email-pclouds@gmail.com","threadId":"21948","inReplyTo":"1260786666-8405-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 17/23] unpack-trees.c: generalize verify_* functions","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2009-12-14T10:31:00Z","receivedAt":"2009-12-14T10:31:00Z","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 unpack-trees.c |   23 ++++++++++++++++++-----\n 1 files changed, 18 insertions(+), 5 deletions(-)\n\ndiff --git a/unpack-trees.c b/unpack-trees.c\nindex eb1a818..5467265 100644\n--- a/unpack-trees.c\n+++ b/unpack-trees.c\n@@ -452,8 +452,9 @@ static int same(struct cache_entry *a, struct cache_entry *b)\n  * When a CE gets turned into an unmerged entry, we\n  * want it to be up-to-date\n  */\n-static int verify_uptodate(struct cache_entry *ce,\n-\t\tstruct unpack_trees_options *o)\n+static int verify_uptodate_1(struct cache_entry *ce,\n+\t\t\t\t   struct unpack_trees_options *o,\n+\t\t\t\t   const char *error_msg)\n {\n \tstruct stat st;\n \n@@ -478,7 +479,13 @@ static int verify_uptodate(struct cache_entry *ce,\n \tif (errno == ENOENT)\n \t\treturn 0;\n \treturn o->gently ? -1 :\n-\t\terror(ERRORMSG(o, not_uptodate_file), ce->name);\n+\t\terror(error_msg, ce->name);\n+}\n+\n+static int verify_uptodate(struct cache_entry *ce,\n+\t\t\t   struct unpack_trees_options *o)\n+{\n+\treturn verify_uptodate_1(ce, o, ERRORMSG(o, not_uptodate_file));\n }\n \n static void invalidate_ce_path(struct cache_entry *ce, struct unpack_trees_options *o)\n@@ -586,8 +593,9 @@ static int icase_exists(struct unpack_trees_options *o, struct cache_entry *dst,\n  * We do not want to remove or overwrite a working tree file that\n  * is not tracked, unless it is ignored.\n  */\n-static int verify_absent(struct cache_entry *ce, const char *action,\n-\t\t\t struct unpack_trees_options *o)\n+static int verify_absent_1(struct cache_entry *ce, const char *action,\n+\t\t\t\t struct unpack_trees_options *o,\n+\t\t\t\t const char *error_msg)\n {\n \tstruct stat st;\n \n@@ -667,6 +675,11 @@ static int verify_absent(struct cache_entry *ce, const char *action,\n \t}\n \treturn 0;\n }\n+static int verify_absent(struct cache_entry *ce, const char *action,\n+\t\t\t struct unpack_trees_options *o)\n+{\n+\treturn verify_absent_1(ce, action, o, ERRORMSG(o, would_lose_untracked));\n+}\n \n static int merged_entry(struct cache_entry *merge, struct cache_entry *old,\n \t\tstruct unpack_trees_options *o)\n-- \n1.6.5.2.216.g9c1ec\n"},{"id":"129839","messageId":"1260786666-8405-19-git-send-email-pclouds@gmail.com","threadId":"21948","inReplyTo":"1260786666-8405-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 18/23] unpack-trees(): \"enable\" sparse checkout and load $GIT_DIR/info/sparse-checkout","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2009-12-14T10:31:01Z","receivedAt":"2009-12-14T10:31:01Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This patch introduces core.sparseCheckout, which will control whether\nsparse checkout support is enabled in unpack_trees()\n\nIt also loads sparse-checkout file that will be used in the next patch.\nI split it out so the next patch will be shorter, easier to read.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n Documentation/config.txt        |    4 ++++\n Documentation/git-read-tree.txt |    4 +++-\n cache.h                         |    1 +\n config.c                        |    5 +++++\n environment.c                   |    1 +\n unpack-trees.c                  |   36 ++++++++++++++++++++++++++++++------\n unpack-trees.h                  |    4 ++++\n 7 files changed, 48 insertions(+), 7 deletions(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex 7791c32..5825c91 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -439,6 +439,10 @@ On some file system/operating system combinations, this is unreliable.\n Set this config setting to 'rename' there; However, This will remove the\n check that makes sure that existing object files will not get overwritten.\n \n+core.sparseCheckout::\n+\tEnable \"sparse checkout\" feature. See section \"Sparse checkout\" in\n+\tlinkgit:git-read-tree[1] for more information.\n+\n add.ignore-errors::\n \tTells 'git-add' to continue adding files when some files cannot be\n \tadded due to indexing errors. Equivalent to the '--ignore-errors'\ndiff --git a/Documentation/git-read-tree.txt b/Documentation/git-read-tree.txt\nindex 8b39716..fc3f08b 100644\n--- a/Documentation/git-read-tree.txt\n+++ b/Documentation/git-read-tree.txt\n@@ -401,7 +401,9 @@ follows:\n ----------------\n \n Then you can disable sparse checkout. Sparse checkout support in \"git\n-read-tree\" and similar commands is disabled by default.\n+read-tree\" and similar commands is disabled by default. You need to\n+turn `core.sparseCheckout` on in order to have sparse checkout\n+support.\n \n \n SEE ALSO\ndiff --git a/cache.h b/cache.h\nindex 3a37469..f51b285 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -528,6 +528,7 @@ extern size_t delta_base_cache_limit;\n extern int auto_crlf;\n extern int fsync_object_files;\n extern int core_preload_index;\n+extern int core_apply_sparse_checkout;\n \n enum safe_crlf {\n \tSAFE_CRLF_FALSE = 0,\ndiff --git a/config.c b/config.c\nindex e87edea..abd762e 100644\n--- a/config.c\n+++ b/config.c\n@@ -503,6 +503,11 @@ static int git_default_core_config(const char *var, const char *value)\n \t\treturn 0;\n \t}\n \n+\tif (!strcmp(var, \"core.sparsecheckout\")) {\n+\t\tcore_apply_sparse_checkout = git_config_bool(var, value);\n+\t\treturn 0;\n+\t}\n+\n \t/* Add other config variables here and to Documentation/config.txt. */\n \treturn 0;\n }\ndiff --git a/environment.c b/environment.c\nindex 8f5eaa7..020422c 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -48,6 +48,7 @@ enum push_default_type push_default = PUSH_DEFAULT_MATCHING;\n #endif\n enum object_creation_mode object_creation_mode = OBJECT_CREATION_MODE;\n int grafts_replace_parents = 1;\n+int core_apply_sparse_checkout;\n \n /* Parallel index stat data preload? */\n int core_preload_index = 0;\ndiff --git a/unpack-trees.c b/unpack-trees.c\nindex 5467265..56f1a30 100644\n--- a/unpack-trees.c\n+++ b/unpack-trees.c\n@@ -378,6 +378,7 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options\n {\n \tint ret;\n \tstatic struct cache_entry *dfc;\n+\tstruct exclude_list el;\n \n \tif (len > MAX_UNPACK_TREES)\n \t\tdie(\"unpack_trees takes at most %d trees\", MAX_UNPACK_TREES);\n@@ -387,6 +388,16 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options\n \tstate.quiet = 1;\n \tstate.refresh_cache = 1;\n \n+\tmemset(&el, 0, sizeof(el));\n+\tif (!core_apply_sparse_checkout || !o->update)\n+\t\to->skip_sparse_checkout = 1;\n+\tif (!o->skip_sparse_checkout) {\n+\t\tif (add_excludes_from_file_to_list(git_path(\"info/sparse-checkout\"), \"\", 0, NULL, &el, 0) < 0)\n+\t\t\to->skip_sparse_checkout = 1;\n+\t\telse\n+\t\t\to->el = &el;\n+\t}\n+\n \tmemset(&o->result, 0, sizeof(o->result));\n \to->result.initialized = 1;\n \tif (o->src_index) {\n@@ -407,26 +418,39 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options\n \t\tinfo.fn = unpack_callback;\n \t\tinfo.data = o;\n \n-\t\tif (traverse_trees(len, t, &info) < 0)\n-\t\t\treturn unpack_failed(o, NULL);\n+\t\tif (traverse_trees(len, t, &info) < 0) {\n+\t\t\tret = unpack_failed(o, NULL);\n+\t\t\tgoto done;\n+\t\t}\n \t}\n \n \t/* Any left-over entries in the index? */\n \tif (o->merge) {\n \t\twhile (o->pos < o->src_index->cache_nr) {\n \t\t\tstruct cache_entry *ce = o->src_index->cache[o->pos];\n-\t\t\tif (unpack_index_entry(ce, o) < 0)\n-\t\t\t\treturn unpack_failed(o, NULL);\n+\t\t\tif (unpack_index_entry(ce, o) < 0) {\n+\t\t\t\tret = unpack_failed(o, NULL);\n+\t\t\t\tgoto done;\n+\t\t\t}\n \t\t}\n \t}\n \n-\tif (o->trivial_merges_only && o->nontrivial_merge)\n-\t\treturn unpack_failed(o, \"Merge requires file-level merging\");\n+\tif (o->trivial_merges_only && o->nontrivial_merge) {\n+\t\tret = unpack_failed(o, \"Merge requires file-level merging\");\n+\t\tgoto done;\n+\t}\n \n \to->src_index = NULL;\n \tret = check_updates(o) ? (-2) : 0;\n \tif (o->dst_index)\n \t\t*o->dst_index = o->result;\n+\n+done:\n+\tfor (i = 0;i < el.nr;i++)\n+\t\tfree(el.excludes[i]);\n+\tif (el.excludes)\n+\t\tfree(el.excludes);\n+\n \treturn ret;\n }\n \ndiff --git a/unpack-trees.h b/unpack-trees.h\nindex d19df44..5c9e98a 100644\n--- a/unpack-trees.h\n+++ b/unpack-trees.h\n@@ -4,6 +4,7 @@\n #define MAX_UNPACK_TREES 8\n \n struct unpack_trees_options;\n+struct exclude_list;\n \n typedef int (*merge_fn_t)(struct cache_entry **src,\n \t\tstruct unpack_trees_options *options);\n@@ -28,6 +29,7 @@ struct unpack_trees_options {\n \t\t     skip_unmerged,\n \t\t     initial_checkout,\n \t\t     diff_index_cached,\n+\t\t     skip_sparse_checkout,\n \t\t     gently;\n \tconst char *prefix;\n \tint pos;\n@@ -44,6 +46,8 @@ struct unpack_trees_options {\n \tstruct index_state *dst_index;\n \tstruct index_state *src_index;\n \tstruct index_state result;\n+\n+\tstruct exclude_list *el; /* for internal use */\n };\n \n extern int unpack_trees(unsigned n, struct tree_desc *t,\n-- \n1.6.5.2.216.g9c1ec\n"},{"id":"129841","messageId":"1260786666-8405-20-git-send-email-pclouds@gmail.com","threadId":"21948","inReplyTo":"1260786666-8405-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 19/23] unpack_trees(): apply $GIT_DIR/info/sparse-checkout to the final index","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2009-12-14T10:31:02Z","receivedAt":"2009-12-14T10:31:02Z","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 unpack-trees.c |   82 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-\n unpack-trees.h |    2 +\n 2 files changed, 83 insertions(+), 1 deletions(-)\n\ndiff --git a/unpack-trees.c b/unpack-trees.c\nindex 56f1a30..6288385 100644\n--- a/unpack-trees.c\n+++ b/unpack-trees.c\n@@ -32,6 +32,12 @@ static struct unpack_trees_error_msgs unpack_plumbing_errors = {\n \n \t/* bind_overlap */\n \t\"Entry '%s' overlaps with '%s'.  Cannot bind.\",\n+\n+\t/* sparse_not_uptodate_file */\n+\t\"Entry '%s' not uptodate. Cannot update sparse checkout.\",\n+\n+\t/* would_lose_orphaned */\n+\t\"Working tree file '%s' would be %s by sparse checkout update.\",\n };\n \n #define ERRORMSG(o,fld) \\\n@@ -125,6 +131,57 @@ static int check_updates(struct unpack_trees_options *o)\n \treturn errs != 0;\n }\n \n+static int verify_uptodate_sparse(struct cache_entry *ce, struct unpack_trees_options *o);\n+static int verify_absent_sparse(struct cache_entry *ce, const char *action, struct unpack_trees_options *o);\n+\n+static int will_have_skip_worktree(const struct cache_entry *ce, struct unpack_trees_options *o)\n+{\n+\tconst char *basename;\n+\n+\tif (ce_stage(ce))\n+\t\treturn 0;\n+\n+\tbasename = strrchr(ce->name, '/');\n+\tbasename = basename ? basename+1 : ce->name;\n+\treturn excluded_from_list(ce->name, ce_namelen(ce), basename, NULL, o->el) <= 0;\n+}\n+\n+static int apply_sparse_checkout(struct cache_entry *ce, struct unpack_trees_options *o)\n+{\n+\tint was_skip_worktree = ce_skip_worktree(ce);\n+\n+\tif (will_have_skip_worktree(ce, o))\n+\t\tce->ce_flags |= CE_SKIP_WORKTREE;\n+\telse\n+\t\tce->ce_flags &= ~CE_SKIP_WORKTREE;\n+\n+\t/*\n+\t * We only care about files getting into the checkout area\n+\t * If merge strategies want to remove some, go ahead, this\n+\t * flag will be removed eventually in unpack_trees() if it's\n+\t * outside checkout area.\n+\t */\n+\tif (ce->ce_flags & CE_REMOVE)\n+\t\treturn 0;\n+\n+\tif (!was_skip_worktree && ce_skip_worktree(ce)) {\n+\t\t/*\n+\t\t * If CE_UPDATE is set, verify_uptodate() must be called already\n+\t\t * also stat info may have lost after merged_entry() so calling\n+\t\t * verify_uptodate() again may fail\n+\t\t */\n+\t\tif (!(ce->ce_flags & CE_UPDATE) && verify_uptodate_sparse(ce, o))\n+\t\t\treturn -1;\n+\t\tce->ce_flags |= CE_WT_REMOVE;\n+\t}\n+\tif (was_skip_worktree && !ce_skip_worktree(ce)) {\n+\t\tif (verify_absent_sparse(ce, \"overwritten\", o))\n+\t\t\treturn -1;\n+\t\tce->ce_flags |= CE_UPDATE;\n+\t}\n+\treturn 0;\n+}\n+\n static inline int call_unpack_fn(struct cache_entry **src, struct unpack_trees_options *o)\n {\n \tint ret = o->fn(src, o);\n@@ -376,7 +433,7 @@ static int unpack_failed(struct unpack_trees_options *o, const char *message)\n  */\n int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options *o)\n {\n-\tint ret;\n+\tint i, ret;\n \tstatic struct cache_entry *dfc;\n \tstruct exclude_list el;\n \n@@ -440,6 +497,17 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options\n \t\tgoto done;\n \t}\n \n+\tif (!o->skip_sparse_checkout) {\n+\t\tfor (i = 0;i < o->result.cache_nr;i++) {\n+\t\t\tstruct cache_entry *ce = o->result.cache[i];\n+\n+\t\t\tif (apply_sparse_checkout(ce, o)) {\n+\t\t\t\tret = -1;\n+\t\t\t\tgoto done;\n+\t\t\t}\n+\t\t}\n+\t}\n+\n \to->src_index = NULL;\n \tret = check_updates(o) ? (-2) : 0;\n \tif (o->dst_index)\n@@ -512,6 +580,12 @@ static int verify_uptodate(struct cache_entry *ce,\n \treturn verify_uptodate_1(ce, o, ERRORMSG(o, not_uptodate_file));\n }\n \n+static int verify_uptodate_sparse(struct cache_entry *ce,\n+\t\t\t\t  struct unpack_trees_options *o)\n+{\n+\treturn verify_uptodate_1(ce, o, ERRORMSG(o, sparse_not_uptodate_file));\n+}\n+\n static void invalidate_ce_path(struct cache_entry *ce, struct unpack_trees_options *o)\n {\n \tif (ce)\n@@ -705,6 +779,12 @@ static int verify_absent(struct cache_entry *ce, const char *action,\n \treturn verify_absent_1(ce, action, o, ERRORMSG(o, would_lose_untracked));\n }\n \n+static int verify_absent_sparse(struct cache_entry *ce, const char *action,\n+\t\t\t struct unpack_trees_options *o)\n+{\n+\treturn verify_absent_1(ce, action, o, ERRORMSG(o, would_lose_orphaned));\n+}\n+\n static int merged_entry(struct cache_entry *merge, struct cache_entry *old,\n \t\tstruct unpack_trees_options *o)\n {\ndiff --git a/unpack-trees.h b/unpack-trees.h\nindex 5c9e98a..95ff36c 100644\n--- a/unpack-trees.h\n+++ b/unpack-trees.h\n@@ -15,6 +15,8 @@ struct unpack_trees_error_msgs {\n \tconst char *not_uptodate_dir;\n \tconst char *would_lose_untracked;\n \tconst char *bind_overlap;\n+\tconst char *sparse_not_uptodate_file;\n+\tconst char *would_lose_orphaned;\n };\n \n struct unpack_trees_options {\n-- \n1.6.5.2.216.g9c1ec\n"},{"id":"129854","messageId":"1260786666-8405-21-git-send-email-pclouds@gmail.com","threadId":"21948","inReplyTo":"1260786666-8405-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 20/23] unpack-trees(): ignore worktree check outside checkout area","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2009-12-14T10:31:03Z","receivedAt":"2009-12-14T10:31:03Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"verify_absent() and verify_uptodate() are used to ensure worktree\nis safe to be updated, then CE_REMOVE or CE_UPDATE will be set.\nFinally check_updates() bases on CE_REMOVE, CE_UPDATE and the\nrecently added CE_WT_REMOVE to update working directory accordingly.\n\nThe entries that are checked may eventually be left out of checkout\narea (done later in apply_sparse_checkout()). We don't want to update\noutside checkout area. This patch teaches Git to assume \"good\",\nskip these checks when it's sure those entries will be outside checkout\narea, and clear CE_REMOVE|CE_UPDATE that could be set due to this\nassumption.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n unpack-trees.c |   12 ++++++++++++\n 1 files changed, 12 insertions(+), 0 deletions(-)\n\ndiff --git a/unpack-trees.c b/unpack-trees.c\nindex 6288385..aac9922 100644\n--- a/unpack-trees.c\n+++ b/unpack-trees.c\n@@ -505,6 +505,14 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options\n \t\t\t\tret = -1;\n \t\t\t\tgoto done;\n \t\t\t}\n+\t\t\t/*\n+\t\t\t * Merge strategies may set CE_UPDATE|CE_REMOVE outside checkout\n+\t\t\t * area as a result of ce_skip_worktree() shortcuts in\n+\t\t\t * verify_absent() and verify_uptodate(). Clear them.\n+\t\t\t */\n+\t\t\tif (ce_skip_worktree(ce))\n+\t\t\t\tce->ce_flags &= ~(CE_UPDATE | CE_REMOVE);\n+\n \t\t}\n \t}\n \n@@ -577,6 +585,8 @@ static int verify_uptodate_1(struct cache_entry *ce,\n static int verify_uptodate(struct cache_entry *ce,\n \t\t\t   struct unpack_trees_options *o)\n {\n+\tif (!o->skip_sparse_checkout && will_have_skip_worktree(ce, o))\n+\t\treturn 0;\n \treturn verify_uptodate_1(ce, o, ERRORMSG(o, not_uptodate_file));\n }\n \n@@ -776,6 +786,8 @@ static int verify_absent_1(struct cache_entry *ce, const char *action,\n static int verify_absent(struct cache_entry *ce, const char *action,\n \t\t\t struct unpack_trees_options *o)\n {\n+\tif (!o->skip_sparse_checkout && will_have_skip_worktree(ce, o))\n+\t\treturn 0;\n \treturn verify_absent_1(ce, action, o, ERRORMSG(o, would_lose_untracked));\n }\n \n-- \n1.6.5.2.216.g9c1ec\n"},{"id":"129853","messageId":"1260786666-8405-22-git-send-email-pclouds@gmail.com","threadId":"21948","inReplyTo":"1260786666-8405-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 21/23] read-tree: add --no-sparse-checkout to disable sparse checkout support","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2009-12-14T10:31:04Z","receivedAt":"2009-12-14T10:31:04Z","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 Documentation/git-read-tree.txt |    6 +++++-\n builtin-read-tree.c             |    4 +++-\n 2 files changed, 8 insertions(+), 2 deletions(-)\n\ndiff --git a/Documentation/git-read-tree.txt b/Documentation/git-read-tree.txt\nindex fc3f08b..ea7b0b2 100644\n--- a/Documentation/git-read-tree.txt\n+++ b/Documentation/git-read-tree.txt\n@@ -10,7 +10,7 @@ SYNOPSIS\n --------\n 'git read-tree' [[-m [--trivial] [--aggressive] | --reset | --prefix=<prefix>]\n \t\t[-u [--exclude-per-directory=<gitignore>] | -i]]\n-\t\t[--index-output=<file>]\n+\t\t[--index-output=<file>] [--no-sparse-checkout]\n \t\t<tree-ish1> [<tree-ish2> [<tree-ish3>]]\n \n \n@@ -110,6 +110,10 @@ OPTIONS\n \tdirectories the index file and index output file are\n \tlocated in.\n \n+--no-sparse-checkout::\n+\tDisable sparse checkout support even if `core.sparseCheckout`\n+\tis true.\n+\n <tree-ish#>::\n \tThe id of the tree object(s) to be read/merged.\n \ndiff --git a/builtin-read-tree.c b/builtin-read-tree.c\nindex 9c2d634..f5acb1a 100644\n--- a/builtin-read-tree.c\n+++ b/builtin-read-tree.c\n@@ -31,7 +31,7 @@ static int list_tree(unsigned char *sha1)\n }\n \n static const char * const read_tree_usage[] = {\n-\t\"git read-tree [[-m [--trivial] [--aggressive] | --reset | --prefix=<prefix>] [-u [--exclude-per-directory=<gitignore>] | -i]]  [--index-output=<file>] <tree-ish1> [<tree-ish2> [<tree-ish3>]]\",\n+\t\"git read-tree [[-m [--trivial] [--aggressive] | --reset | --prefix=<prefix>] [-u [--exclude-per-directory=<gitignore>] | -i]] [--no-sparse-checkout] [--index-output=<file>] <tree-ish1> [<tree-ish2> [<tree-ish3>]]\",\n \tNULL\n };\n \n@@ -98,6 +98,8 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)\n \t\t  PARSE_OPT_NONEG, exclude_per_directory_cb },\n \t\tOPT_SET_INT('i', NULL, &opts.index_only,\n \t\t\t    \"don't check the working tree after merging\", 1),\n+\t\tOPT_SET_INT(0, \"no-sparse-checkout\", &opts.skip_sparse_checkout,\n+\t\t\t    \"skip applying sparse checkout filter\", 1),\n \t\tOPT_END()\n \t};\n \n-- \n1.6.5.2.216.g9c1ec\n"},{"id":"129855","messageId":"1260786666-8405-23-git-send-email-pclouds@gmail.com","threadId":"21948","inReplyTo":"1260786666-8405-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 22/23] Add tests for sparse checkout","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2009-12-14T10:31:05Z","receivedAt":"2009-12-14T10:31:05Z","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 t/t1011-read-tree-sparse-checkout.sh |  154 ++++++++++++++++++++++++++++++++++\n 1 files changed, 154 insertions(+), 0 deletions(-)\n create mode 100755 t/t1011-read-tree-sparse-checkout.sh\n\ndiff --git a/t/t1011-read-tree-sparse-checkout.sh b/t/t1011-read-tree-sparse-checkout.sh\nnew file mode 100755\nindex 0000000..2192f5a\n--- /dev/null\n+++ b/t/t1011-read-tree-sparse-checkout.sh\n@@ -0,0 +1,154 @@\n+#!/bin/sh\n+\n+test_description='sparse checkout tests'\n+\n+. ./test-lib.sh\n+\n+cat >expected <<EOF\n+100644 77f0ba1734ed79d12881f81b36ee134de6a3327b 0\tinit.t\n+100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0\tsub/added\n+EOF\n+test_expect_success 'setup' '\n+\ttest_commit init &&\n+\techo modified >> init.t &&\n+\tmkdir sub &&\n+\ttouch sub/added &&\n+\tgit add init.t sub/added &&\n+\tgit commit -m \"modified and added\" &&\n+\tgit tag top &&\n+\tgit rm sub/added &&\n+\tgit commit -m removed &&\n+\tgit tag removed &&\n+\tgit checkout top &&\n+\tgit ls-files --stage > result &&\n+\ttest_cmp expected result\n+'\n+\n+cat >expected.swt <<EOF\n+H init.t\n+H sub/added\n+EOF\n+test_expect_success 'read-tree without .git/info/sparse-checkout' '\n+\tgit read-tree -m -u HEAD &&\n+\tgit ls-files --stage > result &&\n+\ttest_cmp expected result &&\n+\tgit ls-files -t > result &&\n+\ttest_cmp expected.swt result\n+'\n+\n+test_expect_success 'read-tree with .git/info/sparse-checkout but disabled' '\n+\techo > .git/info/sparse-checkout\n+\tgit read-tree -m -u HEAD &&\n+\tgit ls-files -t > result &&\n+\ttest_cmp expected.swt result &&\n+\ttest -f init.t &&\n+\ttest -f sub/added\n+'\n+\n+test_expect_success 'read-tree --no-sparse-checkout with empty .git/info/sparse-checkout and enabled' '\n+\tgit config core.sparsecheckout true &&\n+\techo > .git/info/sparse-checkout &&\n+\tgit read-tree --no-sparse-checkout -m -u HEAD &&\n+\tgit ls-files -t > result &&\n+\ttest_cmp expected.swt result &&\n+\ttest -f init.t &&\n+\ttest -f sub/added\n+'\n+\n+cat >expected.swt <<EOF\n+S init.t\n+S sub/added\n+EOF\n+test_expect_success 'read-tree with empty .git/info/sparse-checkout' '\n+\tgit config core.sparsecheckout true &&\n+\techo > .git/info/sparse-checkout &&\n+\tgit read-tree -m -u HEAD &&\n+\tgit ls-files --stage > result &&\n+\ttest_cmp expected result &&\n+\tgit ls-files -t > result &&\n+\ttest_cmp expected.swt result &&\n+\ttest ! -f init.t &&\n+\ttest ! -f sub/added\n+'\n+\n+cat >expected.swt <<EOF\n+S init.t\n+H sub/added\n+EOF\n+test_expect_success 'match directories with trailing slash' '\n+\techo sub/ > .git/info/sparse-checkout &&\n+\tgit read-tree -m -u HEAD &&\n+\tgit ls-files -t > result &&\n+\ttest_cmp expected.swt result &&\n+\ttest ! -f init.t &&\n+\ttest -f sub/added\n+'\n+\n+cat >expected.swt <<EOF\n+H init.t\n+H sub/added\n+EOF\n+test_expect_failure 'match directories without trailing slash' '\n+\techo init.t > .git/info/sparse-checkout &&\n+\techo sub >> .git/info/sparse-checkout &&\n+\tgit read-tree -m -u HEAD &&\n+\tgit ls-files -t > result &&\n+\ttest_cmp expected.swt result &&\n+\ttest ! -f init.t &&\n+\ttest -f sub/added\n+'\n+\n+cat >expected.swt <<EOF\n+H init.t\n+S sub/added\n+EOF\n+test_expect_success 'checkout area changes' '\n+\techo init.t > .git/info/sparse-checkout &&\n+\tgit read-tree -m -u HEAD &&\n+\tgit ls-files -t > result &&\n+\ttest_cmp expected.swt result &&\n+\ttest -f init.t &&\n+\ttest ! -f sub/added\n+'\n+\n+test_expect_success 'read-tree updates worktree, absent case' '\n+\techo sub/added > .git/info/sparse-checkout &&\n+\tgit checkout -f top &&\n+\tgit read-tree -m -u HEAD^ &&\n+\ttest ! -f init.t\n+'\n+\n+test_expect_success 'read-tree updates worktree, dirty case' '\n+\techo sub/added > .git/info/sparse-checkout &&\n+\tgit checkout -f top &&\n+\techo dirty > init.t &&\n+\tgit read-tree -m -u HEAD^ &&\n+\tgrep -q dirty init.t &&\n+\trm init.t\n+'\n+\n+test_expect_success 'read-tree removes worktree, dirty case' '\n+\techo init.t > .git/info/sparse-checkout &&\n+\tgit checkout -f top &&\n+\techo dirty > added &&\n+\tgit read-tree -m -u HEAD^ &&\n+\tgrep -q dirty added\n+'\n+\n+test_expect_success 'read-tree adds to worktree, absent case' '\n+\techo init.t > .git/info/sparse-checkout &&\n+\tgit checkout -f removed &&\n+\tgit read-tree -u -m HEAD^ &&\n+\ttest ! -f sub/added\n+'\n+\n+test_expect_success 'read-tree adds to worktree, dirty case' '\n+\techo init.t > .git/info/sparse-checkout &&\n+\tgit checkout -f removed &&\n+\tmkdir sub &&\n+\techo dirty > sub/added &&\n+\tgit read-tree -u -m HEAD^ &&\n+\tgrep -q dirty sub/added\n+'\n+\n+test_done\n-- \n1.6.5.2.216.g9c1ec\n"},{"id":"129851","messageId":"1260786666-8405-24-git-send-email-pclouds@gmail.com","threadId":"21948","inReplyTo":"1260786666-8405-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 23/23] sparse checkout: inhibit empty worktree","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2009-12-14T10:31:06Z","receivedAt":"2009-12-14T10:31:06Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"The way sparse checkout works, users may empty their worktree\ncompletely, because of non-matching sparse-checkout spec, or empty\nspec. I believe this is not desired. This patch makes Git refuse to\nproduce such worktree.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n t/t1011-read-tree-sparse-checkout.sh |   10 +++-------\n unpack-trees.c                       |    7 +++++++\n 2 files changed, 10 insertions(+), 7 deletions(-)\n\ndiff --git a/t/t1011-read-tree-sparse-checkout.sh b/t/t1011-read-tree-sparse-checkout.sh\nindex 2192f5a..62246db 100755\n--- a/t/t1011-read-tree-sparse-checkout.sh\n+++ b/t/t1011-read-tree-sparse-checkout.sh\n@@ -55,20 +55,16 @@ test_expect_success 'read-tree --no-sparse-checkout with empty .git/info/sparse-\n \ttest -f sub/added\n '\n \n-cat >expected.swt <<EOF\n-S init.t\n-S sub/added\n-EOF\n test_expect_success 'read-tree with empty .git/info/sparse-checkout' '\n \tgit config core.sparsecheckout true &&\n \techo > .git/info/sparse-checkout &&\n-\tgit read-tree -m -u HEAD &&\n+\ttest_must_fail git read-tree -m -u HEAD &&\n \tgit ls-files --stage > result &&\n \ttest_cmp expected result &&\n \tgit ls-files -t > result &&\n \ttest_cmp expected.swt result &&\n-\ttest ! -f init.t &&\n-\ttest ! -f sub/added\n+\ttest -f init.t &&\n+\ttest -f sub/added\n '\n \n cat >expected.swt <<EOF\ndiff --git a/unpack-trees.c b/unpack-trees.c\nindex aac9922..d33b39e 100644\n--- a/unpack-trees.c\n+++ b/unpack-trees.c\n@@ -498,6 +498,7 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options\n \t}\n \n \tif (!o->skip_sparse_checkout) {\n+\t\tint empty_worktree = 1;\n \t\tfor (i = 0;i < o->result.cache_nr;i++) {\n \t\t\tstruct cache_entry *ce = o->result.cache[i];\n \n@@ -512,8 +513,14 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options\n \t\t\t */\n \t\t\tif (ce_skip_worktree(ce))\n \t\t\t\tce->ce_flags &= ~(CE_UPDATE | CE_REMOVE);\n+\t\t\telse\n+\t\t\t\tempty_worktree = 0;\n \n \t\t}\n+\t\tif (o->result.cache_nr && empty_worktree) {\n+\t\t\tret = unpack_failed(o, \"Sparse checkout leaves no entry on working directory\");\n+\t\t\tgoto done;\n+\t\t}\n \t}\n \n \to->src_index = NULL;\n-- \n1.6.5.2.216.g9c1ec\n"},{"id":"129860","messageId":"4B261CF0.8090102@viscovery.net","threadId":"21948","inReplyTo":"1260786666-8405-1-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH 00/23] nd/sparse reroll","fromName":"Johannes Sixt","fromEmail":"j.sixt@viscovery.net","sentAt":"2009-12-14T11:09:36Z","receivedAt":"2009-12-14T11:09:36Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Nguyễn Thái Ngọc Duy schrieb:\n> Compared to the current series in pu, ...\n\nObviously, you didn't notice that the series is already in next, which\nmeans that you should have made incremental patches on top of bbbe508d77.\n\n-- Hannes\n"},{"id":"129861","messageId":"fcaeb9bf0912140311n58197439k7a7b4e42316e286a@mail.gmail.com","threadId":"21948","inReplyTo":"4B261CF0.8090102@viscovery.net","subject":"Re: [PATCH 00/23] nd/sparse reroll","fromName":"Nguyen Thai Ngoc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2009-12-14T11:11:58Z","receivedAt":"2009-12-14T11:11:58Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"2009/12/14 Johannes Sixt <j.sixt@viscovery.net>:\n> Nguyễn Thái Ngọc Duy schrieb:\n>> Compared to the current series in pu, ...\n>\n> Obviously, you didn't notice that the series is already in next, which\n> means that you should have made incremental patches on top of bbbe508d77.\n\nArgh.. sorry I did not catch up with git@vger lately. Will resend.\n-- \nDuy\n"},{"id":"129915","messageId":"20091214230619.GA30538@dr-wily.mit.edu","threadId":"21948","inReplyTo":"1260786666-8405-4-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH 03/23] Introduce \"skip-worktree\" bit in index, teach Git to get/set this bit","fromName":"Greg Price","fromEmail":"price@ksplice.com","sentAt":"2009-12-14T23:06:19Z","receivedAt":"2009-12-14T23:06:19Z","isPatch":true,"sender":{"key":"price@mit.edu","avatar":"https://avatars.githubusercontent.com/u/28173?v=4"},"body":"Hi Duy,\n\n> +Skip-worktree bit\n> +-----------------\n> +\n> +Skip-worktree bit can be defined in one (long) sentence: When reading\n> +an entry, if it is marked as skip-worktree, then Git pretends its\n> +working directory version is up to date and read the index version\n> +instead.\n> +\n> +To elaborate, \"reading\" means checking for file existence, reading\n> +file attributes or file content. The working directory version may be\n> +present or absent. If present, its content may match against the index\n> +version or not. Writing is not affected by this bit, content safety\n> +is still first priority. Note that Git _can_ update working directory\n> +file, that is marked skip-worktree, if it is safe to do so (i.e.\n> +working directory version matches index version)\n> +\n> +Although this bit looks similar to assume-unchanged bit, its goal is\n> +different from assume-unchanged bit's. Skip-worktree also takes\n> +precedence over assume-unchanged bit when both are set.\n\nI confess I can't tell how the skip-worktree bit does differ from\nassume-unchanged.  Is its 'goal' different only in that you have a\ndifferent motivation for introducing it, or does it actually have a\ndifferent effect -- and what is that different effect?\n\nLooking forward to seeing sparse checkouts soon!\n\nCheers,\nGreg\n"},{"id":"129930","messageId":"fcaeb9bf0912141951l5bbb4baanb991354aa3f11ae4@mail.gmail.com","threadId":"21948","inReplyTo":"20091214230619.GA30538@dr-wily.mit.edu","subject":"Re: [PATCH 03/23] Introduce \"skip-worktree\" bit in index, teach Git to get/set this bit","fromName":"Nguyen Thai Ngoc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2009-12-15T03:51:11Z","receivedAt":"2009-12-15T03:51:11Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"2009/12/15 Greg Price <price@ksplice.com>:\n> I confess I can't tell how the skip-worktree bit does differ from\n> assume-unchanged.  Is its 'goal' different only in that you have a\n> different motivation for introducing it, or does it actually have a\n> different effect -- and what is that different effect?\n\nOn the fun side, you could use both bits in the same worktree, to\nnarrow your worktree and have some assume-unchanged files.\n\nAnother difference is that with assume-unchanged bit, you make a\npromise to Git that those assume-unchanged files are \"good\", Git does\nnot have to care for them. If somehow you violate the promise, Git can\nharm your files on worktree.\n-- \nDuy\n"},{"id":"129938","messageId":"4B2738D1.90002@viscovery.net","threadId":"21948","inReplyTo":"fcaeb9bf0912141951l5bbb4baanb991354aa3f11ae4@mail.gmail.com","subject":"Re: [PATCH 03/23] Introduce \"skip-worktree\" bit in index, teach Git to get/set this bit","fromName":"Johannes Sixt","fromEmail":"j.sixt@viscovery.net","sentAt":"2009-12-15T07:20:49Z","receivedAt":"2009-12-15T07:20:49Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Nguyen Thai Ngoc Duy schrieb:\n> 2009/12/15 Greg Price <price@ksplice.com>:\n>> I confess I can't tell how the skip-worktree bit does differ from\n>> assume-unchanged.  Is its 'goal' different only in that you have a\n>> different motivation for introducing it, or does it actually have a\n>> different effect -- and what is that different effect?\n> \n> On the fun side, you could use both bits in the same worktree, to\n> narrow your worktree and have some assume-unchanged files.\n> \n> Another difference is that with assume-unchanged bit, you make a\n> promise to Git that those assume-unchanged files are \"good\", Git does\n> not have to care for them. If somehow you violate the promise, Git can\n> harm your files on worktree.\n\nSo, the difference is that skip-worktree will not overwrite a file that is\ndifferent from the version in the index, but assume-unchanged can? Right?\n\n-- Hannes\n"},{"id":"129942","messageId":"fcaeb9bf0912150005w356744a0j6f543fd4bd2449e@mail.gmail.com","threadId":"21948","inReplyTo":"4B2738D1.90002@viscovery.net","subject":"Re: [PATCH 03/23] Introduce \"skip-worktree\" bit in index, teach Git to get/set this bit","fromName":"Nguyen Thai Ngoc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2009-12-15T08:05:56Z","receivedAt":"2009-12-15T08:05:56Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Tue, Dec 15, 2009 at 2:20 PM, Johannes Sixt <j.sixt@viscovery.net> wrote:\n> Nguyen Thai Ngoc Duy schrieb:\n>> 2009/12/15 Greg Price <price@ksplice.com>:\n>>> I confess I can't tell how the skip-worktree bit does differ from\n>>> assume-unchanged.  Is its 'goal' different only in that you have a\n>>> different motivation for introducing it, or does it actually have a\n>>> different effect -- and what is that different effect?\n>>\n>> On the fun side, you could use both bits in the same worktree, to\n>> narrow your worktree and have some assume-unchanged files.\n>>\n>> Another difference is that with assume-unchanged bit, you make a\n>> promise to Git that those assume-unchanged files are \"good\", Git does\n>> not have to care for them. If somehow you violate the promise, Git can\n>> harm your files on worktree.\n>\n> So, the difference is that skip-worktree will not overwrite a file that is\n> different from the version in the index, but assume-unchanged can? Right?\n\nYes.\n-- \nDuy\n"}]}