{"thread":{"id":"15604","subject":"[PATCH v2 00/14] Sparse checkout","startedAt":"2008-09-20T10:01:39Z","lastAt":"2008-09-26T16:00:02Z","messageCount":37,"participants":["Nguyễn Thái Ngọc Duy","Santi Béjar","Nguyen Thai Ngoc Duy","Jakub Narebski","Uwe Kleine-König","Junio C Hamano"],"isPatch":true,"patchVersion":2,"patchTotal":14},"messages":[{"id":"91168","messageId":"1221904913-25887-1-git-send-email-pclouds@gmail.com","threadId":"15604","inReplyTo":null,"subject":"[PATCH v2 00/14] Sparse checkout","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2008-09-20T10:01:39Z","receivedAt":"2008-09-20T10:01:39Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Main changes from the last round are:\n - The name is now \"sparse checkout\"\n - \"git clone --path\" => \"git clone --narrow-path\"\n - \"git checkout --path\" => \"git checkout --reset-path\"\n - New narrow spec (or \"sparse patterns\" from now) resembles\n   .gitignore patterns\n - \"git ls-files\" now supports more fine-grained listing. It can now\n   list checkout files, no-checkout files or orphaned (previously\n   \"overlay\") files. --overlay is gone\n - \"git status\" shows orphaned entries and remedies\n - Documentation has been restructured to accompany code changes.\n   Thanks to Jakub, Baz for lots of input.\n\nFor code changes, significant changes are:\n  [03/14] ls-files: add options to support sparse checkout\n  [10/14] ls-files: support \"sparse patterns\", used to form sparse checkout areas\n\nI hope I have addressed all the issues. If I miss anything, please speak up.\n\nNguyá»n ThÃ¡i Ngá»c Duy (14):\n  Extend index to save more flags\n  Introduce CE_NO_CHECKOUT bit\n  ls-files: add options to support sparse checkout\n  update-index: refactor mark_valid() in preparation for new options\n  update-index: add --checkout/--no-checkout to update CE_NO_CHECKOUT bit\n  ls-files: Add tests for --sparse and friends\n  Prevent diff machinery from examining worktree outside sparse checkout\n  checkout_entry(): CE_NO_CHECKOUT on checked out entries.\n  grep: skip files outside sparse checkout area\n  ls-files: support \"sparse patterns\", used to form sparse checkout areas\n  unpack_trees(): add support for sparse checkout\n  clone: support sparse checkout with --narrow-path option\n  checkout: add new options to support sparse checkout\n  wt-status: Show orphaned entries in \"git status\" output\n\n .gitignore                            |    1 +\n Documentation/git-checkout.txt        |  131 ++++++++++++++++++++-\n Documentation/git-clone.txt           |   10 ++-\n Documentation/git-grep.txt            |    4 +-\n Documentation/git-ls-files.txt        |   30 +++++-\n Documentation/git-update-index.txt    |   13 ++\n Makefile                              |    2 +-\n builtin-checkout.c                    |   37 ++++++\n builtin-clone.c                       |   13 ++\n builtin-grep.c                        |    7 +-\n builtin-ls-files.c                    |   60 +++++++++-\n builtin-update-index.c                |   40 ++++---\n cache.h                               |   69 ++++++++++-\n diff-lib.c                            |    5 +-\n diff.c                                |    4 +-\n entry.c                               |    1 +\n read-cache.c                          |   57 +++++++--\n t/t2011-checkout-sparse.sh            |  108 +++++++++++++++++\n t/t2104-update-index-no-checkout.sh   |   36 ++++++\n t/t3003-ls-files-narrow-match.sh      |   39 ++++++\n t/t3003/1                             |    3 +\n t/t3003/12                            |    6 +\n t/t3003/clone-escape                  |    4 +\n t/t3003/cur-12                        |    2 +\n t/t3003/root-sub-1                    |    1 +\n t/t3003/slash-1                       |    1 +\n t/t3003/sub-1                         |    2 +\n t/t3003/sub-only                      |    3 +\n t/t3003/subsub-slash                  |    3 +\n t/t3004-ls-files-sparse.sh            |   40 ++++++\n t/t3004/cached.expected               |    5 +\n t/t3004/deleted.expected              |    1 +\n t/t3004/everything.expected           |   10 ++\n t/t3004/modified.expected             |    2 +\n t/t3004/no-checkout.expected          |    2 +\n t/t3004/orphaned-no-checkout.expected |    3 +\n t/t3004/orphaned.expected             |    1 +\n t/t3004/others.expected               |    2 +\n t/t3004/sparse-cached.expected        |    3 +\n t/t3004/sparse-everything.expected    |   11 ++\n t/t5703-clone-narrow.sh               |   39 ++++++\n test-index-version.c                  |   14 ++\n unpack-trees.c                        |  210 ++++++++++++++++++++++++++++++++-\n unpack-trees.h                        |   22 ++++\n wt-status.c                           |   39 ++++++\n wt-status.h                           |    1 +\n 46 files changed, 1047 insertions(+), 50 deletions(-)\n create mode 100755 t/t2011-checkout-sparse.sh\n create mode 100755 t/t2104-update-index-no-checkout.sh\n create mode 100755 t/t3003-ls-files-narrow-match.sh\n create mode 100644 t/t3003/1\n create mode 100644 t/t3003/12\n create mode 100644 t/t3003/clone-escape\n create mode 100644 t/t3003/cur-12\n create mode 100644 t/t3003/root-sub-1\n create mode 100644 t/t3003/slash-1\n create mode 100644 t/t3003/sub\n create mode 100644 t/t3003/sub-1\n create mode 100644 t/t3003/sub-only\n create mode 100644 t/t3003/subsub-slash\n create mode 100755 t/t3004-ls-files-sparse.sh\n create mode 100644 t/t3004/cached.expected\n create mode 100644 t/t3004/deleted.expected\n create mode 100644 t/t3004/everything.expected\n create mode 100644 t/t3004/modified.expected\n create mode 100644 t/t3004/no-checkout.expected\n create mode 100644 t/t3004/orphaned-no-checkout.expected\n create mode 100644 t/t3004/orphaned.expected\n create mode 100644 t/t3004/others.expected\n create mode 100644 t/t3004/sparse-cached.expected\n create mode 100644 t/t3004/sparse-everything.expected\n create mode 100755 t/t5703-clone-narrow.sh\n create mode 100644 test-index-version.c\n"},{"id":"91169","messageId":"1221904913-25887-2-git-send-email-pclouds@gmail.com","threadId":"15604","inReplyTo":"1221904913-25887-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 01/14] Extend index to save more flags","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2008-09-20T10:01:40Z","receivedAt":"2008-09-20T10:01:40Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"The on-disk format of index only saves 16 bit flags, nearly all have\nbeen used. The last bit (CE_EXTENDED) is used to for future extension.\n\nThis patch extends index entry format to save more flags in future.\nThe new entry format will be used when CE_EXTENDED bit is 1.\n\nBecause older implementation may not understand CE_EXTENDED bit and\nmisread the new format, if there is any extended entry in index, index\nheader version will turn 3, which makes it incompatible for older git.\nIf there is none, header version will return to 2 again.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n cache.h      |   58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++----\n read-cache.c |   51 +++++++++++++++++++++++++++++++++++++++++----------\n 2 files changed, 95 insertions(+), 14 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex f4b8ddf..77b6eb3 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -109,6 +109,26 @@ struct ondisk_cache_entry {\n \tchar name[FLEX_ARRAY]; /* more */\n };\n \n+/*\n+ * This struct is used when CE_EXTENDED bit is 1\n+ * The struct must match ondisk_cache_entry exactly from\n+ * ctime till flags\n+ */\n+struct ondisk_cache_entry_extended {\n+\tstruct cache_time ctime;\n+\tstruct cache_time mtime;\n+\tunsigned int dev;\n+\tunsigned int ino;\n+\tunsigned int mode;\n+\tunsigned int uid;\n+\tunsigned int gid;\n+\tunsigned int size;\n+\tunsigned char sha1[20];\n+\tunsigned short flags;\n+\tunsigned short flags2;\n+\tchar name[FLEX_ARRAY]; /* more */\n+};\n+\n struct cache_entry {\n \tunsigned int ce_ctime;\n \tunsigned int ce_mtime;\n@@ -130,7 +150,15 @@ struct cache_entry {\n #define CE_VALID     (0x8000)\n #define CE_STAGESHIFT 12\n \n-/* In-memory only */\n+/*\n+ * Range 0xFFFF0000 in ce_flags is divided into\n+ * two parts: in-memory flags and on-disk ones.\n+ * Flags in CE_EXTENDED_FLAGS will get saved on-disk\n+ * if you want to save a new flag, add it in\n+ * CE_EXTENDED_FLAGS\n+ *\n+ * In-memory only flags\n+ */\n #define CE_UPDATE    (0x10000)\n #define CE_REMOVE    (0x20000)\n #define CE_UPTODATE  (0x40000)\n@@ -140,6 +168,24 @@ struct cache_entry {\n #define CE_UNHASHED  (0x200000)\n \n /*\n+ * Extended on-disk flags\n+ */\n+/* CE_EXTENDED2 is for future extension */\n+#define CE_EXTENDED2 0x80000000\n+\n+#define CE_EXTENDED_FLAGS (0)\n+\n+/*\n+ * Safeguard to avoid saving wrong flags:\n+ *  - CE_EXTENDED2 won't get saved until its semantic is known\n+ *  - Bits in 0x0000FFFF have been saved in ce_flags already\n+ *  - Bits in 0x003F0000 are currently in-memory flags\n+ */\n+#if CE_EXTENDED_FLAGS & 0x80CFFFFF\n+#error \"CE_EXTENDED_FLAGS out of range\"\n+#endif\n+\n+/*\n  * Copy the sha1 and stat state of a cache entry from one to\n  * another. But we never change the name, or the hash state!\n  */\n@@ -171,7 +217,9 @@ static inline size_t ce_namelen(const struct cache_entry *ce)\n }\n \n #define ce_size(ce) cache_entry_size(ce_namelen(ce))\n-#define ondisk_ce_size(ce) ondisk_cache_entry_size(ce_namelen(ce))\n+#define ondisk_ce_size(ce) (((ce)->ce_flags & CE_EXTENDED) ? \\\n+\t\t\t    ondisk_cache_entry_extended_size(ce_namelen(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_mark_uptodate(ce) ((ce)->ce_flags |= CE_UPTODATE)\n@@ -214,8 +262,10 @@ static inline int ce_to_dtype(const struct cache_entry *ce)\n \t(S_ISREG(mode) ? (S_IFREG | ce_permissions(mode)) : \\\n \tS_ISLNK(mode) ? S_IFLNK : S_ISDIR(mode) ? S_IFDIR : S_IFGITLINK)\n \n-#define cache_entry_size(len) ((offsetof(struct cache_entry,name) + (len) + 8) & ~7)\n-#define ondisk_cache_entry_size(len) ((offsetof(struct ondisk_cache_entry,name) + (len) + 8) & ~7)\n+#define flexible_size(STRUCT,len) ((offsetof(struct STRUCT,name) + (len) + 8) & ~7)\n+#define cache_entry_size(len) flexible_size(cache_entry,len)\n+#define ondisk_cache_entry_size(len) flexible_size(ondisk_cache_entry,len)\n+#define ondisk_cache_entry_extended_size(len) flexible_size(ondisk_cache_entry_extended,len)\n \n struct index_state {\n \tstruct cache_entry **cache;\ndiff --git a/read-cache.c b/read-cache.c\nindex c5a8659..667c36b 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -1096,7 +1096,7 @@ static int verify_hdr(struct cache_header *hdr, unsigned long size)\n \n \tif (hdr->hdr_signature != htonl(CACHE_SIGNATURE))\n \t\treturn error(\"bad signature\");\n-\tif (hdr->hdr_version != htonl(2))\n+\tif (hdr->hdr_version != htonl(2) && hdr->hdr_version != htonl(3))\n \t\treturn error(\"bad index version\");\n \tSHA1_Init(&c);\n \tSHA1_Update(&c, hdr, size - 20);\n@@ -1131,6 +1131,7 @@ int read_index(struct index_state *istate)\n static void convert_from_disk(struct ondisk_cache_entry *ondisk, struct cache_entry *ce)\n {\n \tsize_t len;\n+\tconst char *name;\n \n \tce->ce_ctime = ntohl(ondisk->ctime.sec);\n \tce->ce_mtime = ntohl(ondisk->mtime.sec);\n@@ -1143,19 +1144,31 @@ static void convert_from_disk(struct ondisk_cache_entry *ondisk, struct cache_en\n \t/* On-disk flags are just 16 bits */\n \tce->ce_flags = ntohs(ondisk->flags);\n \n-\t/* For future extension: we do not understand this entry yet */\n-\tif (ce->ce_flags & CE_EXTENDED)\n-\t\tdie(\"Unknown index entry format\");\n \thashcpy(ce->sha1, ondisk->sha1);\n \n \tlen = ce->ce_flags & CE_NAMEMASK;\n+\n+\tif (ce->ce_flags & CE_EXTENDED) {\n+\t\tstruct ondisk_cache_entry_extended *ondisk2;\n+\t\tint extended_flags;\n+\t\tondisk2 = (struct ondisk_cache_entry_extended *)ondisk;\n+\t\textended_flags = ntohs(ondisk2->flags2) << 16;\n+\t\t/* We do not yet understand any bit out of CE_EXTENDED_FLAGS */\n+\t\tif (extended_flags & ~CE_EXTENDED_FLAGS)\n+\t\t\tdie(\"Unknown index entry format %08x\", extended_flags);\n+\t\tce->ce_flags |= extended_flags;\n+\t\tname = ondisk2->name;\n+\t}\n+\telse\n+\t\tname = ondisk->name;\n+\n \tif (len == CE_NAMEMASK)\n-\t\tlen = strlen(ondisk->name);\n+\t\tlen = strlen(name);\n \t/*\n \t * NEEDSWORK: If the original index is crafted, this copy could\n \t * go unchecked.\n \t */\n-\tmemcpy(ce->name, ondisk->name, len + 1);\n+\tmemcpy(ce->name, name, len + 1);\n }\n \n static inline size_t estimate_cache_size(size_t ondisk_size, unsigned int entries)\n@@ -1415,6 +1428,7 @@ static int ce_write_entry(SHA_CTX *c, int fd, struct cache_entry *ce)\n {\n \tint size = ondisk_ce_size(ce);\n \tstruct ondisk_cache_entry *ondisk = xcalloc(1, size);\n+\tchar *name;\n \n \tondisk->ctime.sec = htonl(ce->ce_ctime);\n \tondisk->ctime.nsec = 0;\n@@ -1428,7 +1442,15 @@ static int ce_write_entry(SHA_CTX *c, int fd, struct cache_entry *ce)\n \tondisk->size = htonl(ce->ce_size);\n \thashcpy(ondisk->sha1, ce->sha1);\n \tondisk->flags = htons(ce->ce_flags);\n-\tmemcpy(ondisk->name, ce->name, ce_namelen(ce));\n+\tif (ce->ce_flags & CE_EXTENDED) {\n+\t\tstruct ondisk_cache_entry_extended *ondisk2;\n+\t\tondisk2 = (struct ondisk_cache_entry_extended *)ondisk;\n+\t\tondisk2->flags2 = htons((ce->ce_flags & CE_EXTENDED_FLAGS) >> 16);\n+\t\tname = ondisk2->name;\n+\t}\n+\telse\n+\t\tname = ondisk->name;\n+\tmemcpy(name, ce->name, ce_namelen(ce));\n \n \treturn ce_write(c, fd, ondisk, size);\n }\n@@ -1437,16 +1459,25 @@ int write_index(const struct index_state *istate, int newfd)\n {\n \tSHA_CTX c;\n \tstruct cache_header hdr;\n-\tint i, err, removed;\n+\tint i, err, removed, extended;\n \tstruct cache_entry **cache = istate->cache;\n \tint entries = istate->cache_nr;\n \n-\tfor (i = removed = 0; i < entries; i++)\n+\tfor (i = removed = extended = 0; i < entries; i++) {\n \t\tif (cache[i]->ce_flags & CE_REMOVE)\n \t\t\tremoved++;\n \n+\t\t/* reduce extended entries if possible */\n+\t\tcache[i]->ce_flags &= ~CE_EXTENDED;\n+\t\tif (cache[i]->ce_flags & CE_EXTENDED_FLAGS) {\n+\t\t\textended++;\n+\t\t\tcache[i]->ce_flags |= CE_EXTENDED;\n+\t\t}\n+\t}\n+\n \thdr.hdr_signature = htonl(CACHE_SIGNATURE);\n-\thdr.hdr_version = htonl(2);\n+\t/* for extended format, increase version so older git won't try to read it */\n+\thdr.hdr_version = htonl(extended ? 3 : 2);\n \thdr.hdr_entries = htonl(entries - removed);\n \n \tSHA1_Init(&c);\n-- \n1.6.0.96.g2fad1.dirty\n"},{"id":"91170","messageId":"1221904913-25887-3-git-send-email-pclouds@gmail.com","threadId":"15604","inReplyTo":"1221904913-25887-2-git-send-email-pclouds@gmail.com","subject":"[PATCH 02/14] Introduce CE_NO_CHECKOUT bit","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2008-09-20T10:01:41Z","receivedAt":"2008-09-20T10:01:41Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This bit is the basis of sparse checkout. If this bit is on, the entry\nis outside sparse checkout and therefore should be ignored (similar\nto CE_VALID)\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Documentation/git-checkout.txt |   33 +++++++++++++++++++++++++++++++++\n cache.h                        |   10 +++++++++-\n read-cache.c                   |    6 +++---\n 3 files changed, 45 insertions(+), 4 deletions(-)\n\ndiff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt\nindex 82e154d..4bd9eba 100644\n--- a/Documentation/git-checkout.txt\n+++ b/Documentation/git-checkout.txt\n@@ -171,6 +171,39 @@ the reflog for HEAD where you were, e.g.\n $ git log -g -2 HEAD\n ------------\n \n+Sparse checkout\n+---------------\n+\n+Normally when you checkout a branch, your working directory\n+will be fully populated. In some situations, you just need to\n+work on certain files, no full checkout is needed. Sparse\n+checkout is a mode that limits the checkout area according to your\n+needs. With sparse checkout, you can work on a single file, a\n+collection of files, a subdirectory or a collection of separated\n+subdirectories.\n+\n+Because sparse checkout uses a new index format, it will be\n+incompatible with git prior to 1.6.0 regarding worktree operations.\n+Operations that only need access to the repository itself, such as\n+clone, push, or pull/fetch from another (normal) repository... should\n+not be affected by sparse checkout.\n+\n+In sparse checkout mode, checkout status of every files in your\n+working directory will be recorded in index. If a file is marked\n+\"no-checkout\", it means that file is not needed to be present in\n+working directory by user or any git command. When a new file is added\n+to index, it will be marked \"checkout\" unless sparse patterns are\n+applied.  Unmerged files are always \"checkout\". When you checkout new\n+files using \"git checkout <file>\" they will be automatically marked\n+\"checkout\". Other commands such as \"git apply\" can also checkout new\n+files if they are needed.\n+\n+\"No-checkout\" status is very similar to \"assume-unchanged bit\"\n+(see linkgit:git-update-index[1]). The main difference between them\n+is \"assume unchanged\" bit just ignores corresponding files in working\n+directory while sparse checkout goes a bit farther, remove those files\n+when it is safe to do so.\n+\n \n EXAMPLES\n --------\ndiff --git a/cache.h b/cache.h\nindex 77b6eb3..6e875d5 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -170,10 +170,11 @@ struct cache_entry {\n /*\n  * Extended on-disk flags\n  */\n+#define CE_NO_CHECKOUT 0x40000000\n /* CE_EXTENDED2 is for future extension */\n #define CE_EXTENDED2 0x80000000\n \n-#define CE_EXTENDED_FLAGS (0)\n+#define CE_EXTENDED_FLAGS (CE_NO_CHECKOUT)\n \n /*\n  * Safeguard to avoid saving wrong flags:\n@@ -185,6 +186,9 @@ struct cache_entry {\n #error \"CE_EXTENDED_FLAGS out of range\"\n #endif\n \n+/* \"Assume unchanged\" mask */\n+#define CE_VALID_MASK (CE_VALID | CE_NO_CHECKOUT)\n+\n /*\n  * Copy the sha1 and stat state of a cache entry from one to\n  * another. But we never change the name, or the hash state!\n@@ -222,6 +226,10 @@ 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_no_checkout(ce) ((ce)->ce_flags & CE_NO_CHECKOUT)\n+#define ce_checkout(ce) (!ce_no_checkout(ce))\n+#define ce_mark_no_checkout(ce) ((ce)->ce_flags |= CE_NO_CHECKOUT)\n+#define ce_mark_checkout(ce) ((ce)->ce_flags &= ~CE_NO_CHECKOUT)\n #define ce_mark_uptodate(ce) ((ce)->ce_flags |= CE_UPTODATE)\n \n #define ce_permissions(mode) (((mode) & 0100) ? 0755 : 0644)\ndiff --git a/read-cache.c b/read-cache.c\nindex 667c36b..e965a4c 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -254,7 +254,7 @@ int ie_match_stat(const struct index_state *istate,\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-\tif (!ignore_valid && (ce->ce_flags & CE_VALID))\n+\tif (!ignore_valid && (ce->ce_flags & CE_VALID_MASK))\n \t\treturn 0;\n \n \tchanged = ce_match_stat_basic(ce, st);\n@@ -962,10 +962,10 @@ static struct cache_entry *refresh_cache_ent(struct index_state *istate,\n \t\treturn ce;\n \n \t/*\n-\t * CE_VALID means the user promised us that the change to\n+\t * CE_VALID_MASK 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 */\n-\tif (!ignore_valid && (ce->ce_flags & CE_VALID)) {\n+\tif (!ignore_valid && (ce->ce_flags & CE_VALID_MASK)) {\n \t\tce_mark_uptodate(ce);\n \t\treturn ce;\n \t}\n-- \n1.6.0.96.g2fad1.dirty\n"},{"id":"91172","messageId":"1221904913-25887-4-git-send-email-pclouds@gmail.com","threadId":"15604","inReplyTo":"1221904913-25887-3-git-send-email-pclouds@gmail.com","subject":"[PATCH 03/14] ls-files: add options to support sparse checkout","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2008-09-20T10:01:42Z","receivedAt":"2008-09-20T10:01:42Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"The first option to be introduced is --sparse, which puts ls-files\nin \"sparse mode\". In this mode, cached entries are divided into\n - checkout entries: shown by --cached (new behavior with --sparse)\n - no-checkout entries: show by --no-checkout (new option)\n - orphaned entries: shown by --orphaned (new option)\n\nOrphaned entries are themselves no-checkout ones but for some reasons\nstill be present in working directory.\n\nWhile at it, fix \"--deleted\" running out of checkout area.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Documentation/git-ls-files.txt |   24 +++++++++++++++++++++-\n builtin-ls-files.c             |   41 ++++++++++++++++++++++++++++++++++++---\n 2 files changed, 59 insertions(+), 6 deletions(-)\n\ndiff --git a/Documentation/git-ls-files.txt b/Documentation/git-ls-files.txt\nindex 9f85d60..1de68e2 100644\n--- a/Documentation/git-ls-files.txt\n+++ b/Documentation/git-ls-files.txt\n@@ -10,8 +10,9 @@ SYNOPSIS\n --------\n [verse]\n 'git ls-files' [-z] [-t] [-v]\n-\t\t(--[cached|deleted|others|ignored|stage|unmerged|killed|modified])\\*\n+\t\t(--[cached|deleted|others|ignored|stage|unmerged|killed|modified|orphaned|no-checkout])\\*\n \t\t(-[c|d|o|i|s|u|k|m])\\*\n+\t\t[--sparse]\n \t\t[-x <pattern>|--exclude=<pattern>]\n \t\t[-X <file>|--exclude-from=<file>]\n \t\t[--exclude-per-directory=<file>]\n@@ -32,7 +33,9 @@ OPTIONS\n -------\n -c::\n --cached::\n-\tShow cached files in the output (default)\n+\tShow cached files in the output (default). When used with --sparse,\n+\tshow only cached files that are marked \"checkout\", no-checkout\n+\tentries will be excluded.\n \n -d::\n --deleted::\n@@ -72,6 +75,21 @@ OPTIONS\n \tto file/directory conflicts for checkout-index to\n \tsucceed.\n \n+--no-checkout::\n+\tShow no-checkout entries. This option implies --sparse.\n+\n+--orphaned::\n+\tShow orphaned entries. Orphaned entries are no-checkout\n+\tentries that are present in working directory. This option\n+\timplies --sparse.\n+\n+--sparse::\n+\tWhen --sparse is passed, cached files will be divided into two\n+\tparts: checkout entries and no-checkout entries.\n+\t--cached will only show checkout entries.\n+\tNo-checkout entries can be shown using --orphaned or\n+\t--no-checkout (or both).\n+\n -z::\n \t\\0 line termination on output.\n \n@@ -107,6 +125,8 @@ 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+\t-::\tno-checkout entries\n+\tO::\torphaned entries\n \tM::\tunmerged\n \tR::\tremoved/deleted\n \tC::\tmodified/changed\ndiff --git a/builtin-ls-files.c b/builtin-ls-files.c\nindex 068f424..873de15 100644\n--- a/builtin-ls-files.c\n+++ b/builtin-ls-files.c\n@@ -20,6 +20,9 @@ static int show_unmerged;\n static int show_modified;\n static int show_killed;\n static int show_valid_bit;\n+static int show_orphaned;\n+static int show_no_checkout;\n+static int sparse_checkout;\n static int line_terminator = '\\n';\n \n static int prefix_len;\n@@ -35,6 +38,8 @@ 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_orphaned = \"\";\n+static const char *tag_no_checkout = \"\";\n \n \n /*\n@@ -235,7 +240,7 @@ static void show_files(struct dir_struct *dir, const char *prefix)\n \t\tif (show_killed)\n \t\t\tshow_killed_files(dir);\n \t}\n-\tif (show_cached | show_stage) {\n+\tif (show_cached | show_stage | show_orphaned | show_no_checkout) {\n \t\tfor (i = 0; i < active_nr; i++) {\n \t\t\tstruct cache_entry *ce = active_cache[i];\n \t\t\tint dtype = ce_to_dtype(ce);\n@@ -245,6 +250,16 @@ 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 (sparse_checkout && ce_no_checkout(ce)) {\n+\t\t\t\tstruct stat st;\n+\t\t\t\tif (show_no_checkout)\n+\t\t\t\t\tshow_ce_entry(tag_no_checkout, ce);\n+\t\t\t\tif (show_orphaned && !lstat(ce->name, &st))\n+\t\t\t\t\tshow_ce_entry(tag_orphaned, ce);\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\t\t\tif (!(show_cached | show_stage))\n+\t\t\t\tcontinue;\n \t\t\tshow_ce_entry(ce_stage(ce) ? tag_unmerged : tag_cached, ce);\n \t\t}\n \t}\n@@ -257,7 +272,7 @@ static void show_files(struct dir_struct *dir, const char *prefix)\n \t\t\tif (excluded(dir, ce->name, &dtype) != dir->show_ignored)\n \t\t\t\tcontinue;\n \t\t\terr = lstat(ce->name, &st);\n-\t\t\tif (show_deleted && err)\n+\t\t\tif (show_deleted && err && ce_checkout(ce))\n \t\t\t\tshow_ce_entry(tag_removed, ce);\n \t\t\tif (show_modified && ce_modified(ce, &st, 0))\n \t\t\t\tshow_ce_entry(tag_modified, ce);\n@@ -423,7 +438,8 @@ int report_path_error(const char *ps_matched, const char **pathspec, int prefix_\n }\n \n static const char ls_files_usage[] =\n-\t\"git ls-files [-z] [-t] [-v] (--[cached|deleted|others|stage|unmerged|killed|modified])* \"\n+\t\"git ls-files [-z] [-t] [-v] (--[cached|deleted|others|stage|unmerged|killed|modified|orphaned|no-checkout])* \"\n+\t\"[ --sparse ] \"\n \t\"[ --ignored ] [--exclude=<pattern>] [--exclude-from=<file>] \"\n \t\"[ --exclude-per-directory=<filename> ] [--exclude-standard] \"\n \t\"[--full-name] [--abbrev] [--] [<file>]*\";\n@@ -457,6 +473,8 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)\n \t\t\ttag_modified = \"C \";\n \t\t\ttag_other = \"? \";\n \t\t\ttag_killed = \"K \";\n+\t\t\ttag_orphaned = \"O \";\n+\t\t\ttag_no_checkout = \"- \";\n \t\t\tif (arg[1] == 'v')\n \t\t\t\tshow_valid_bit = 1;\n \t\t\tcontinue;\n@@ -465,6 +483,21 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)\n \t\t\tshow_cached = 1;\n \t\t\tcontinue;\n \t\t}\n+\t\tif (!strcmp(arg, \"--sparse\")) {\n+\t\t\tsparse_checkout = 1;\n+\t\t\tcontinue;\n+\t\t}\n+\t\tif (!strcmp(arg, \"--orphaned\")) {\n+\t\t\tshow_orphaned = 1;\n+\t\t\tsparse_checkout = 1;\n+\t\t\trequire_work_tree = 1;\n+\t\t\tcontinue;\n+\t\t}\n+\t\tif (!strcmp(arg, \"--no-checkout\")) {\n+\t\t\tshow_no_checkout = 1;\n+\t\t\tsparse_checkout = 1;\n+\t\t\tcontinue;\n+\t\t}\n \t\tif (!strcmp(arg, \"-d\") || !strcmp(arg, \"--deleted\")) {\n \t\t\tshow_deleted = 1;\n \t\t\tcontinue;\n@@ -593,7 +626,7 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)\n \n \t/* With no flags, we default to showing the cached files */\n \tif (!(show_stage | show_deleted | show_others | show_unmerged |\n-\t      show_killed | show_modified))\n+\t      show_killed | show_modified | show_orphaned | show_no_checkout))\n \t\tshow_cached = 1;\n \n \tread_cache();\n-- \n1.6.0.96.g2fad1.dirty\n"},{"id":"91171","messageId":"1221904913-25887-5-git-send-email-pclouds@gmail.com","threadId":"15604","inReplyTo":"1221904913-25887-4-git-send-email-pclouds@gmail.com","subject":"[PATCH 04/14] update-index: refactor mark_valid() in preparation for new options","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2008-09-20T10:01:43Z","receivedAt":"2008-09-20T10:01:43Z","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-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 417f972..ae94739 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@@ -649,11 +645,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.0.96.g2fad1.dirty\n"},{"id":"91173","messageId":"1221904913-25887-6-git-send-email-pclouds@gmail.com","threadId":"15604","inReplyTo":"1221904913-25887-5-git-send-email-pclouds@gmail.com","subject":"[PATCH 05/14] update-index: add --checkout/--no-checkout to update CE_NO_CHECKOUT bit","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2008-09-20T10:01:44Z","receivedAt":"2008-09-20T10:01:44Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n .gitignore                          |    1 +\n Documentation/git-checkout.txt      |    3 +-\n Documentation/git-update-index.txt  |   13 ++++++++++++\n Makefile                            |    2 +-\n builtin-update-index.c              |   16 ++++++++++++++-\n t/t2104-update-index-no-checkout.sh |   36 +++++++++++++++++++++++++++++++++++\n test-index-version.c                |   14 +++++++++++++\n 7 files changed, 82 insertions(+), 3 deletions(-)\n create mode 100755 t/t2104-update-index-no-checkout.sh\n create mode 100644 test-index-version.c\n\ndiff --git a/.gitignore b/.gitignore\nindex bbaf9de..0c35577 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -147,6 +147,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/Documentation/git-checkout.txt b/Documentation/git-checkout.txt\nindex 4bd9eba..2b344e1 100644\n--- a/Documentation/git-checkout.txt\n+++ b/Documentation/git-checkout.txt\n@@ -196,7 +196,8 @@ to index, it will be marked \"checkout\" unless sparse patterns are\n applied.  Unmerged files are always \"checkout\". When you checkout new\n files using \"git checkout <file>\" they will be automatically marked\n \"checkout\". Other commands such as \"git apply\" can also checkout new\n-files if they are needed.\n+files if they are needed. linkgit:git-update-index[1] can be used to\n+update \"checkout/no-checkout\" status in index.\n \n \"No-checkout\" status is very similar to \"assume-unchanged bit\"\n (see linkgit:git-update-index[1]). The main difference between them\ndiff --git a/Documentation/git-update-index.txt b/Documentation/git-update-index.txt\nindex 1d9d81a..ec03e05 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     [--checkout | --no-checkout]\n \t     [--ignore-submodules]\n \t     [--really-refresh] [--unresolve] [--again | -g]\n \t     [--info-only] [--index-info]\n@@ -99,6 +100,18 @@ 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+--checkout::\n+--no-checkout::\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 \"no-checkout\" bit for the paths. This\n+\tbit is used for marking files for sparse checkout. If\n+\ta path is marked \"no-checkout\", then it should not be\n+\tchecked out unless requested by user or needed for a git\n+\tcommand to function.\n+\tSee linkgit:git-checkout[1] for more information about\n+\tsparse checkout.\n+\n -g::\n --again::\n \tRuns 'git-update-index' itself on the paths whose index\ndiff --git a/Makefile b/Makefile\nindex e0c03c3..edb33cb 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -1327,7 +1327,7 @@ endif\n \n ### Testing rules\n \n-TEST_PROGRAMS = test-chmtime$X test-genrandom$X test-date$X test-delta$X test-sha1$X test-match-trees$X test-parse-options$X test-path-utils$X\n+TEST_PROGRAMS = test-chmtime$X test-genrandom$X test-date$X test-delta$X test-sha1$X test-match-trees$X test-parse-options$X test-path-utils$X test-index-version$X\n \n all:: $(TEST_PROGRAMS)\n \ndiff --git a/builtin-update-index.c b/builtin-update-index.c\nindex ae94739..7514aff 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_no_checkout_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_no_checkout_only) {\n+\t\tif (mark_ce_flags(p, CE_NO_CHECKOUT, mark_no_checkout_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@@ -386,7 +392,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] [--checkout|--no-checkout] [--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@@ -652,6 +658,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, \"--checkout\")) {\n+\t\t\t\tmark_no_checkout_only = UNMARK_FLAG;\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\t\t\tif (!strcmp(path, \"--no-checkout\")) {\n+\t\t\t\tmark_no_checkout_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/t/t2104-update-index-no-checkout.sh b/t/t2104-update-index-no-checkout.sh\nnew file mode 100755\nindex 0000000..be9f913\n--- /dev/null\n+++ b/t/t2104-update-index-no-checkout.sh\n@@ -0,0 +1,36 @@\n+#!/bin/sh\n+#\n+# Copyright (c) 2008 Nguyễn Thái Ngọc Duy\n+#\n+\n+test_description='git update-index no-checkout bits (a.k.a sparse checkout)'\n+\n+. ./test-lib.sh\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+'\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 --no-checkout' '\n+\tgit update-index --no-checkout 1 sub/1 &&\n+\ttest -z \"$(git ls-files --sparse|grep 1)\"'\n+\n+test_expect_success 'index is at version 3 after having some no-checkout entries' '\n+\ttest \"$(test-index-version < .git/index)\" = 3\n+'\n+\n+test_expect_success 'update-index --checkout' '\n+\tgit update-index --checkout 1 sub/1 &&\n+\ttest \"$(git ls-files)\" = \"$(git ls-files --sparse)\"'\n+\n+test_expect_success 'index version is back to 2 when there is no no-checkout entry' '\n+\ttest \"$(test-index-version < .git/index)\" = 2\n+'\n+\n+test_done\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.0.96.g2fad1.dirty\n"},{"id":"91174","messageId":"1221904913-25887-7-git-send-email-pclouds@gmail.com","threadId":"15604","inReplyTo":"1221904913-25887-6-git-send-email-pclouds@gmail.com","subject":"[PATCH 06/14] ls-files: Add tests for --sparse and friends","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2008-09-20T10:01:45Z","receivedAt":"2008-09-20T10:01:45Z","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 t/t3004-ls-files-sparse.sh            |   40 +++++++++++++++++++++++++++++++++\n t/t3004/cached.expected               |    5 ++++\n t/t3004/deleted.expected              |    1 +\n t/t3004/everything.expected           |   10 ++++++++\n t/t3004/modified.expected             |    2 +\n t/t3004/no-checkout.expected          |    2 +\n t/t3004/orphaned-no-checkout.expected |    3 ++\n t/t3004/orphaned.expected             |    1 +\n t/t3004/others.expected               |    2 +\n t/t3004/sparse-cached.expected        |    3 ++\n t/t3004/sparse-everything.expected    |   11 +++++++++\n 11 files changed, 80 insertions(+), 0 deletions(-)\n create mode 100755 t/t3004-ls-files-sparse.sh\n create mode 100644 t/t3004/cached.expected\n create mode 100644 t/t3004/deleted.expected\n create mode 100644 t/t3004/everything.expected\n create mode 100644 t/t3004/modified.expected\n create mode 100644 t/t3004/no-checkout.expected\n create mode 100644 t/t3004/orphaned-no-checkout.expected\n create mode 100644 t/t3004/orphaned.expected\n create mode 100644 t/t3004/others.expected\n create mode 100644 t/t3004/sparse-cached.expected\n create mode 100644 t/t3004/sparse-everything.expected\n\ndiff --git a/t/t3004-ls-files-sparse.sh b/t/t3004-ls-files-sparse.sh\nnew file mode 100755\nindex 0000000..ec2c869\n--- /dev/null\n+++ b/t/t3004-ls-files-sparse.sh\n@@ -0,0 +1,40 @@\n+#!/bin/sh\n+\n+test_description=\"test ls-files in --sparse mode\"\n+\n+. test-lib.sh\n+\n+test_ls_files() {\n+\tT=../t3004/$1.expected\n+\tshift\n+\ttest_expect_success \"ls-files $*\" \"git ls-files $* > result && test_cmp $T result\"\n+}\n+\n+test_expect_success 'setup' '\n+\ttouch other orphaned no-checkout cached modified deleted &&\n+\tgit add orphaned no-checkout cached modified deleted &&\n+\tgit update-index --no-checkout orphaned no-checkout &&\n+\techo modified >> modified &&\n+\trm no-checkout deleted\n+'\n+\n+test_ls_files cached\n+test_ls_files cached --cached\n+test_ls_files sparse-cached --sparse\n+test_ls_files sparse-cached --sparse --cached\n+test_ls_files no-checkout --no-checkout\n+test_ls_files no-checkout --sparse --no-checkout\n+test_ls_files orphaned --orphaned\n+test_ls_files orphaned --sparse --orphaned\n+test_ls_files orphaned-no-checkout -v --no-checkout --orphaned\n+test_ls_files orphaned-no-checkout -v --sparse --no-checkout --orphaned\n+test_ls_files deleted --deleted\n+test_ls_files deleted --sparse --deleted\n+test_ls_files modified --modified\n+test_ls_files modified --sparse --modified\n+test_ls_files others --others\n+test_ls_files others --sparse --others\n+test_ls_files everything -v --cached --deleted --modified --others\n+test_ls_files sparse-everything -v --cached --no-checkout --orphaned --deleted --modified --others\n+\n+test_done\n\\ No newline at end of file\ndiff --git a/t/t3004/cached.expected b/t/t3004/cached.expected\nnew file mode 100644\nindex 0000000..6fd0c78\n--- /dev/null\n+++ b/t/t3004/cached.expected\n@@ -0,0 +1,5 @@\n+cached\n+deleted\n+modified\n+no-checkout\n+orphaned\ndiff --git a/t/t3004/deleted.expected b/t/t3004/deleted.expected\nnew file mode 100644\nindex 0000000..71779d2\n--- /dev/null\n+++ b/t/t3004/deleted.expected\n@@ -0,0 +1 @@\n+deleted\ndiff --git a/t/t3004/everything.expected b/t/t3004/everything.expected\nnew file mode 100644\nindex 0000000..6000328\n--- /dev/null\n+++ b/t/t3004/everything.expected\n@@ -0,0 +1,10 @@\n+? other\n+? result\n+H cached\n+H deleted\n+H modified\n+H no-checkout\n+H orphaned\n+R deleted\n+C deleted\n+C modified\ndiff --git a/t/t3004/modified.expected b/t/t3004/modified.expected\nnew file mode 100644\nindex 0000000..644a96e\n--- /dev/null\n+++ b/t/t3004/modified.expected\n@@ -0,0 +1,2 @@\n+deleted\n+modified\ndiff --git a/t/t3004/no-checkout.expected b/t/t3004/no-checkout.expected\nnew file mode 100644\nindex 0000000..b2a429f\n--- /dev/null\n+++ b/t/t3004/no-checkout.expected\n@@ -0,0 +1,2 @@\n+no-checkout\n+orphaned\ndiff --git a/t/t3004/orphaned-no-checkout.expected b/t/t3004/orphaned-no-checkout.expected\nnew file mode 100644\nindex 0000000..d687ef0\n--- /dev/null\n+++ b/t/t3004/orphaned-no-checkout.expected\n@@ -0,0 +1,3 @@\n+- no-checkout\n+- orphaned\n+O orphaned\ndiff --git a/t/t3004/orphaned.expected b/t/t3004/orphaned.expected\nnew file mode 100644\nindex 0000000..571b267\n--- /dev/null\n+++ b/t/t3004/orphaned.expected\n@@ -0,0 +1 @@\n+orphaned\ndiff --git a/t/t3004/others.expected b/t/t3004/others.expected\nnew file mode 100644\nindex 0000000..bf5bf2b\n--- /dev/null\n+++ b/t/t3004/others.expected\n@@ -0,0 +1,2 @@\n+other\n+result\ndiff --git a/t/t3004/sparse-cached.expected b/t/t3004/sparse-cached.expected\nnew file mode 100644\nindex 0000000..3453483\n--- /dev/null\n+++ b/t/t3004/sparse-cached.expected\n@@ -0,0 +1,3 @@\n+cached\n+deleted\n+modified\ndiff --git a/t/t3004/sparse-everything.expected b/t/t3004/sparse-everything.expected\nnew file mode 100644\nindex 0000000..5df0599\n--- /dev/null\n+++ b/t/t3004/sparse-everything.expected\n@@ -0,0 +1,11 @@\n+? other\n+? result\n+H cached\n+H deleted\n+H modified\n+- no-checkout\n+- orphaned\n+O orphaned\n+R deleted\n+C deleted\n+C modified\n-- \n1.6.0.96.g2fad1.dirty\n"},{"id":"91175","messageId":"1221904913-25887-8-git-send-email-pclouds@gmail.com","threadId":"15604","inReplyTo":"1221904913-25887-7-git-send-email-pclouds@gmail.com","subject":"[PATCH 07/14] Prevent diff machinery from examining worktree outside sparse checkout","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2008-09-20T10:01:46Z","receivedAt":"2008-09-20T10:01:46Z","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     |    4 +++-\n 2 files changed, 6 insertions(+), 3 deletions(-)\n\ndiff --git a/diff-lib.c b/diff-lib.c\nindex ae96c64..992280b 100644\n--- a/diff-lib.c\n+++ b/diff-lib.c\n@@ -161,7 +161,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_no_checkout(ce))\n \t\t\tcontinue;\n \n \t\tchanged = check_removed(ce, &st);\n@@ -348,6 +348,8 @@ static void do_oneway_diff(struct unpack_trees_options *o,\n \tstruct rev_info *revs = cbdata->revs;\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 && ce_no_checkout(idx));\n \t/*\n \t * Backward compatibility wart - \"diff-index -m\" does\n \t * not mean \"do not ignore merges\", but \"match_missing\".\n@@ -355,7 +357,6 @@ static void do_oneway_diff(struct unpack_trees_options *o,\n \t * But with the revision flag parsing, that's found in\n \t * \"!revs->ignore_merges\".\n \t */\n-\tcached = o->index_only;\n \tmatch_missing = !revs->ignore_merges;\n \n \tif (cached && idx && ce_stage(idx)) {\ndiff --git a/diff.c b/diff.c\nindex a2dd931..b5b7249 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -1793,8 +1793,10 @@ static int reuse_worktree_file(const char *name, const unsigned char *sha1, int\n \n \t/*\n \t * If ce matches the file in the work tree, we can reuse it.\n+\t * For sparse checkout case, ce_uptodate() may be true although\n+\t * the file may or may not exist in the work tree.\n \t */\n-\tif (ce_uptodate(ce) ||\n+\tif ((ce_uptodate(ce) && ce_checkout(ce)) ||\n \t    (!lstat(name, &st) && !ce_match_stat(ce, &st, 0)))\n \t\treturn 1;\n \n-- \n1.6.0.96.g2fad1.dirty\n"},{"id":"91177","messageId":"1221904913-25887-9-git-send-email-pclouds@gmail.com","threadId":"15604","inReplyTo":"1221904913-25887-8-git-send-email-pclouds@gmail.com","subject":"[PATCH 08/14] checkout_entry(): CE_NO_CHECKOUT on checked out entries.","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2008-09-20T10:01:47Z","receivedAt":"2008-09-20T10:01:47Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"With this you can just do \"git checkout some-files\" to\nwiden your checkout. One caveat though: caller must save\nthe index.\n\nFor all of its callers (unpack_trees(), checkout-index, checkout\nand apply), only \"git apply\" does not write index back.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n entry.c |    1 +\n 1 files changed, 1 insertions(+), 0 deletions(-)\n\ndiff --git a/entry.c b/entry.c\nindex aa2ee46..305f8d3 100644\n--- a/entry.c\n+++ b/entry.c\n@@ -230,5 +230,6 @@ int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *t\n \t} else if (state->not_new)\n \t\treturn 0;\n \tcreate_directories(path, state);\n+\tce_mark_checkout(ce);\n \treturn write_entry(ce, path, state, 0);\n }\n-- \n1.6.0.96.g2fad1.dirty\n"},{"id":"91176","messageId":"1221904913-25887-10-git-send-email-pclouds@gmail.com","threadId":"15604","inReplyTo":"1221904913-25887-9-git-send-email-pclouds@gmail.com","subject":"[PATCH 09/14] grep: skip files outside sparse checkout area","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2008-09-20T10:01:48Z","receivedAt":"2008-09-20T10:01: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 Documentation/git-grep.txt |    4 +++-\n builtin-grep.c             |    7 ++++++-\n 2 files changed, 9 insertions(+), 2 deletions(-)\n\ndiff --git a/Documentation/git-grep.txt b/Documentation/git-grep.txt\nindex fa4d133..ee359c9 100644\n--- a/Documentation/git-grep.txt\n+++ b/Documentation/git-grep.txt\n@@ -24,7 +24,9 @@ SYNOPSIS\n DESCRIPTION\n -----------\n Look for specified patterns in the working tree files, blobs\n-registered in the index file, or given tree objects.\n+registered in the index file, or given tree objects. By default\n+it will search in the working tree files. When in sparse checkout\n+mode, it only searches checked-out files.\n \n \n OPTIONS\ndiff --git a/builtin-grep.c b/builtin-grep.c\nindex 3a51662..d5507d7 100644\n--- a/builtin-grep.c\n+++ b/builtin-grep.c\n@@ -343,6 +343,8 @@ static int external_grep(struct grep_opt *opt, const char **paths, int cached)\n \t\t\tcontinue;\n \t\tif (!pathspec_matches(paths, ce->name))\n \t\t\tcontinue;\n+\t\tif (ce_no_checkout(ce))\n+\t\t\tcontinue;\n \t\tname = ce->name;\n \t\tif (name[0] == '-') {\n \t\t\tint len = ce_namelen(ce);\n@@ -404,8 +406,11 @@ static int grep_cache(struct grep_opt *opt, const char **paths, int cached)\n \t\t\t\tcontinue;\n \t\t\thit |= grep_sha1(opt, ce->sha1, ce->name, 0);\n \t\t}\n-\t\telse\n+\t\telse {\n+\t\t\tif (ce_no_checkout(ce))\n+\t\t\t\tcontinue;\n \t\t\thit |= grep_file(opt, ce->name);\n+\t\t}\n \t\tif (ce_stage(ce)) {\n \t\t\tdo {\n \t\t\t\tnr++;\n-- \n1.6.0.96.g2fad1.dirty\n"},{"id":"91178","messageId":"1221904913-25887-11-git-send-email-pclouds@gmail.com","threadId":"15604","inReplyTo":"1221904913-25887-10-git-send-email-pclouds@gmail.com","subject":"[PATCH 10/14] ls-files: support \"sparse patterns\", used to form sparse checkout areas","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2008-09-20T10:01:49Z","receivedAt":"2008-09-20T10:01:49Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This implements sparse patterns and adds --narrow-match option in order\nto test the patterns.\n\nSparse patterns are basically like .gitignore patterns, but they can be\ncombined in one line, separating by colons like $PATH.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Documentation/git-checkout.txt   |   45 +++++++++++++\n Documentation/git-ls-files.txt   |    8 ++-\n builtin-ls-files.c               |   21 +++++-\n t/t3003-ls-files-narrow-match.sh |   39 +++++++++++\n t/t3003/1                        |    3 +\n t/t3003/12                       |    6 ++\n t/t3003/clone-escape             |    4 +\n t/t3003/cur-12                   |    2 +\n t/t3003/root-sub-1               |    1 +\n t/t3003/slash-1                  |    1 +\n t/t3003/sub-1                    |    2 +\n t/t3003/sub-only                 |    3 +\n t/t3003/subsub-slash             |    3 +\n unpack-trees.c                   |  136 ++++++++++++++++++++++++++++++++++++++\n unpack-trees.h                   |   18 +++++\n 15 files changed, 288 insertions(+), 4 deletions(-)\n create mode 100755 t/t3003-ls-files-narrow-match.sh\n create mode 100644 t/t3003/1\n create mode 100644 t/t3003/12\n create mode 100644 t/t3003/clone-escape\n create mode 100644 t/t3003/cur-12\n create mode 100644 t/t3003/root-sub-1\n create mode 100644 t/t3003/slash-1\n create mode 100644 t/t3003/sub\n create mode 100644 t/t3003/sub-1\n create mode 100644 t/t3003/sub-only\n create mode 100644 t/t3003/subsub-slash\n\ndiff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt\nindex 2b344e1..d6f94a6 100644\n--- a/Documentation/git-checkout.txt\n+++ b/Documentation/git-checkout.txt\n@@ -205,6 +205,51 @@ is \"assume unchanged\" bit just ignores corresponding files in working\n directory while sparse checkout goes a bit farther, remove those files\n when it is safe to do so.\n \n+Sparse patterns\n+---------------\n+\n+Sparse patterns specify how do you want to form your checkout area.\n+Many patterns can be specified on one line, separated by colons.\n+The patterns specify what files should or should not be checked out\n+on working directory (depends on the option used with the patterns).\n+Patterns have the following format:\n+\n+ - An optional prefix '!' which negates the pattern; any\n+   matching file by a previous pattern will become\n+   unmatched again.  If a negated pattern matches, this will\n+   override lower precedence patterns sources.\n+\n+ - If the pattern ends with a slash, it is removed for the\n+   purpose of the following description, but it would only find\n+   a match with a directory.  In other words, `foo/` will match a\n+   directory `foo` and paths underneath it, but will not match a\n+   regular file or a symbolic link `foo` (this is consistent\n+   with the way how pathspec works in general in git).\n+\n+ - If the pattern does not contain a slash '/', git treats it as\n+   a shell glob pattern and checks for a match against the\n+   pathname without leading directories.\n+\n+ - Otherwise, git treats the pattern as a shell glob suitable\n+   for consumption by fnmatch(3) with the FNM_PATHNAME flag:\n+   wildcards in the pattern will not match a / in the pathname.\n+   For example, \"Documentation/\\*.html\" matches\n+   \"Documentation/git.html\" but not\n+   \"Documentation/ppc/ppc.html\".  A leading slash matches the\n+   beginning of the pathname; for example, \"/*.c\" matches\n+   \"cat-file.c\" but not \"mozilla-sha1/sha1.c\".\n+\n+ - Patterns begin with a slash will match against full pathname,\n+   as opposed to normal case when it only matches pathnames relative\n+   to current working directory.\n+\n+ - Patterns begin with \"./\" are treated like normal patterns. That is\n+   it will follow above rules. But since it has a slash inside,\n+   \"fnmatch rule\" will apply. This is a work-around when you do not\n+   want to apply \"no slash\" rule.\n+\n+ - Because colons are used to separate patterns, you cannot put them\n+   in patterns directly. You must quote them using backslash.\n \n EXAMPLES\n --------\ndiff --git a/Documentation/git-ls-files.txt b/Documentation/git-ls-files.txt\nindex 1de68e2..fbed73b 100644\n--- a/Documentation/git-ls-files.txt\n+++ b/Documentation/git-ls-files.txt\n@@ -12,7 +12,7 @@ SYNOPSIS\n 'git ls-files' [-z] [-t] [-v]\n \t\t(--[cached|deleted|others|ignored|stage|unmerged|killed|modified|orphaned|no-checkout])\\*\n \t\t(-[c|d|o|i|s|u|k|m])\\*\n-\t\t[--sparse]\n+\t\t[--sparse] [--narrow-match=<sparse patterns>]\n \t\t[-x <pattern>|--exclude=<pattern>]\n \t\t[-X <file>|--exclude-from=<file>]\n \t\t[--exclude-per-directory=<file>]\n@@ -90,6 +90,12 @@ OPTIONS\n \tNo-checkout entries can be shown using --orphaned or\n \t--no-checkout (or both).\n \n+--narrow-match=<sparse patterns>::\n+\tThis option can be used to test sparse patterns. The given sparse patterns will\n+\tbe used to filter ls-files output. Entries not matching the spec will be\n+\tignored. This option can only be used with --cached or --stage.\n+\tSee linkgit:git-checkout[1] for more information about sparse patterns.\n+\n -z::\n \t\\0 line termination on output.\n \ndiff --git a/builtin-ls-files.c b/builtin-ls-files.c\nindex 873de15..1c81022 100644\n--- a/builtin-ls-files.c\n+++ b/builtin-ls-files.c\n@@ -10,6 +10,8 @@\n #include \"dir.h\"\n #include \"builtin.h\"\n #include \"tree.h\"\n+#include \"tree-walk.h\"\n+#include \"unpack-trees.h\"\n \n static int abbrev;\n static int show_deleted;\n@@ -31,6 +33,7 @@ static const char **pathspec;\n static int error_unmatch;\n static char *ps_matched;\n static const char *with_tree;\n+static struct narrow_spec *narrow_spec;\n \n static const char *tag_cached = \"\";\n static const char *tag_unmerged = \"\";\n@@ -187,7 +190,7 @@ static void show_ce_entry(const char *tag, struct cache_entry *ce)\n \tint len = prefix_len;\n \tint offset = prefix_offset;\n \n-\tif (len >= ce_namelen(ce))\n+\tif (len >= ce_namelen(ce) && !narrow_spec)\n \t\tdie(\"git ls-files: internal error - cache entry not superset of prefix\");\n \n \tif (pathspec && !pathspec_match(pathspec, ps_matched, ce->name, len))\n@@ -260,6 +263,8 @@ static void show_files(struct dir_struct *dir, const char *prefix)\n \t\t\t}\n \t\t\tif (!(show_cached | show_stage))\n \t\t\t\tcontinue;\n+\t\t\tif (narrow_spec && !match_narrow_spec(narrow_spec, ce->name))\n+\t\t\t\tcontinue;\n \t\t\tshow_ce_entry(ce_stage(ce) ? tag_unmerged : tag_cached, ce);\n \t\t}\n \t}\n@@ -439,7 +444,7 @@ int report_path_error(const char *ps_matched, const char **pathspec, int prefix_\n \n static const char ls_files_usage[] =\n \t\"git ls-files [-z] [-t] [-v] (--[cached|deleted|others|stage|unmerged|killed|modified|orphaned|no-checkout])* \"\n-\t\"[ --sparse ] \"\n+\t\"[ --sparse ] [--narrow-match=<narrow_spec>] \"\n \t\"[ --ignored ] [--exclude=<pattern>] [--exclude-from=<file>] \"\n \t\"[ --exclude-per-directory=<filename> ] [--exclude-standard] \"\n \t\"[--full-name] [--abbrev] [--] [<file>]*\";\n@@ -498,6 +503,10 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)\n \t\t\tsparse_checkout = 1;\n \t\t\tcontinue;\n \t\t}\n+\t\tif (!prefixcmp(arg, \"--narrow-match=\")) {\n+\t\t\tnarrow_spec = parse_narrow_spec(arg+15, prefix);\n+\t\t\tcontinue;\n+\t\t}\n \t\tif (!strcmp(arg, \"-d\") || !strcmp(arg, \"--deleted\")) {\n \t\t\tshow_deleted = 1;\n \t\t\tcontinue;\n@@ -629,8 +638,14 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)\n \t      show_killed | show_modified | show_orphaned | show_no_checkout))\n \t\tshow_cached = 1;\n \n+\tif (narrow_spec && !show_cached && !show_stage)\n+\t\tdie(\"ls-files: --narrow-match can only be used with either --cached or --stage\");\n+\n+\tif (narrow_spec && narrow_spec->has_root && prefix_offset != 0)\n+\t\tdie(\"ls-files: --narrow-match with root matching patterns requires --full-name\");\n+\n \tread_cache();\n-\tif (prefix)\n+\tif (prefix && (!narrow_spec || !narrow_spec->has_root))\n \t\tprune_cache(prefix);\n \tif (with_tree) {\n \t\t/*\ndiff --git a/t/t3003-ls-files-narrow-match.sh b/t/t3003-ls-files-narrow-match.sh\nnew file mode 100755\nindex 0000000..5611cab\n--- /dev/null\n+++ b/t/t3003-ls-files-narrow-match.sh\n@@ -0,0 +1,39 @@\n+#!/bin/sh\n+\n+test_description='This test is for narrow spec matching'\n+\n+. test-lib.sh\n+\n+D=\"$(cd ..;pwd)\"/t3003\n+\n+test_pattern() {\n+\ttest_expect_success \"pattern $1\" '\n+\t\t(\n+\t\tif [ -n \"'$3'\" ]; then cd '$3'; fi\n+\t\tgit ls-files --full-name --narrow-match=\"'\"$2\"'\" > result &&\n+\t\tdiff -u result \"'\"$D/$1\"'\"\n+\t\t)\n+\t'\n+}\n+\n+test_expect_success 'setup' '\n+\ttouch 1 2 3 \"1:2\" &&\n+\tmkdir -p sub/subsub &&\n+\ttouch sub/1 sub/2 sub/3 &&\n+\ttouch sub/subsub/1 sub/subsub/2 sub/subsub/3 &&\n+\tgit add .\n+'\n+\n+test_pattern 1 1\n+test_pattern sub sub\n+test_pattern sub-1 1 sub\n+test_pattern root-sub-1 /1 sub\n+test_pattern subsub-slash subsub/ sub\n+test_pattern sub-only 'sub/:!sub/subsub/'\n+test_pattern 12 1:2\n+test_pattern cur-12 ./1:./2\n+test_pattern slash-1 'sub/*1'\n+test_pattern clone-escape '1\\:2:1'\n+\n+test_done\n+\ndiff --git a/t/t3003/1 b/t/t3003/1\nnew file mode 100644\nindex 0000000..9b73321\n--- /dev/null\n+++ b/t/t3003/1\n@@ -0,0 +1,3 @@\n+1\n+sub/1\n+sub/subsub/1\ndiff --git a/t/t3003/12 b/t/t3003/12\nnew file mode 100644\nindex 0000000..5d71811\n--- /dev/null\n+++ b/t/t3003/12\n@@ -0,0 +1,6 @@\n+1\n+2\n+sub/1\n+sub/2\n+sub/subsub/1\n+sub/subsub/2\ndiff --git a/t/t3003/clone-escape b/t/t3003/clone-escape\nnew file mode 100644\nindex 0000000..11cdf68\n--- /dev/null\n+++ b/t/t3003/clone-escape\n@@ -0,0 +1,4 @@\n+1\n+1:2\n+sub/1\n+sub/subsub/1\ndiff --git a/t/t3003/cur-12 b/t/t3003/cur-12\nnew file mode 100644\nindex 0000000..1191247\n--- /dev/null\n+++ b/t/t3003/cur-12\n@@ -0,0 +1,2 @@\n+1\n+2\ndiff --git a/t/t3003/root-sub-1 b/t/t3003/root-sub-1\nnew file mode 100644\nindex 0000000..d00491f\n--- /dev/null\n+++ b/t/t3003/root-sub-1\n@@ -0,0 +1 @@\n+1\ndiff --git a/t/t3003/slash-1 b/t/t3003/slash-1\nnew file mode 100644\nindex 0000000..5798e42\n--- /dev/null\n+++ b/t/t3003/slash-1\n@@ -0,0 +1 @@\n+sub/1\ndiff --git a/t/t3003/sub b/t/t3003/sub\nnew file mode 100644\nindex 0000000..e69de29\ndiff --git a/t/t3003/sub-1 b/t/t3003/sub-1\nnew file mode 100644\nindex 0000000..3ef951a\n--- /dev/null\n+++ b/t/t3003/sub-1\n@@ -0,0 +1,2 @@\n+sub/1\n+sub/subsub/1\ndiff --git a/t/t3003/sub-only b/t/t3003/sub-only\nnew file mode 100644\nindex 0000000..3115212\n--- /dev/null\n+++ b/t/t3003/sub-only\n@@ -0,0 +1,3 @@\n+sub/1\n+sub/2\n+sub/3\ndiff --git a/t/t3003/subsub-slash b/t/t3003/subsub-slash\nnew file mode 100644\nindex 0000000..bc585b0\n--- /dev/null\n+++ b/t/t3003/subsub-slash\n@@ -0,0 +1,3 @@\n+sub/subsub/1\n+sub/subsub/2\n+sub/subsub/3\ndiff --git a/unpack-trees.c b/unpack-trees.c\nindex e59d144..ce4c826 100644\n--- a/unpack-trees.c\n+++ b/unpack-trees.c\n@@ -726,6 +726,142 @@ static void show_stage_entry(FILE *o,\n }\n #endif\n \n+struct narrow_spec *parse_narrow_spec(const char *spec, const char *prefix)\n+{\n+\tstruct narrow_spec *ns;\n+\tstruct narrow_pattern *p;\n+\tconst char *start = spec, *end;\n+\tint has_wildcards, has_slashes;\n+\n+\tns = xmalloc(sizeof(*ns));\n+\tmemset(ns, 0, sizeof(*ns));\n+\tif (prefix)\n+\t\tns->prefix = xstrdup(prefix);\n+\n+\twhile (*start) {\n+\t\tend = start;\n+\t\thas_slashes = has_wildcards = 0;\n+\t\twhile (*end && *end != ':') {\n+\t\t\tif (*end == '*' || *end == '[' || *end == '?')\n+\t\t\t\thas_wildcards = 1;\n+\t\t\tif (*end == '/')\n+\t\t\t\thas_slashes = 1;\n+\t\t\tif (*end == '\\\\') {\n+\t\t\t\tend++;\n+\t\t\t\thas_wildcards = 1;\n+\t\t\t\tif (*end == '\\0') /* trailing backslash */\n+\t\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\tend++;\n+\t\t}\n+\t\tif (start == end)\n+\t\t\tcontinue;\n+\n+\t\tp = xmalloc(offsetof(struct narrow_pattern, pattern)+(end-start)+1);\n+\t\tp->negative = *start == '!';\n+\t\tif (p->negative)\n+\t\t\tstart++;\n+\t\tp->has_slashes = has_slashes;\n+\t\tp->has_wildcards = has_wildcards;\n+\t\tp->has_trailing_slash = end[-1] == '/';\n+\t\tp->has_root = *start == '/';\n+\t\tif (p->has_root)\n+\t\t\tstart++;\n+\t\telse if (*start == '.' && start[1] == '/')\n+\t\t\tstart += 2;\n+\t\tp->len = end-start;\n+\t\tmemcpy(p->pattern, start, p->len);\n+\t\tp->pattern[p->len] = '\\0';\n+\n+\t\tALLOC_GROW(ns->patterns, ns->nr + 1, ns->alloc);\n+\t\tns->patterns[ns->nr++] = p;\n+\t\tns->has_root |= p->has_root;\n+\n+\t\tif (*end != ':')\n+\t\t\tbreak;\n+\t\tstart = end + 1;\n+\t}\n+\treturn ns;\n+}\n+\n+int match_narrow_spec(struct narrow_spec *spec, const char *path)\n+{\n+\tint i, prefix_len = 0;\n+\n+\tif (!spec || !spec->nr)\n+\t\treturn 1; /* always match if spec is NULL */\n+\n+\tif (spec->prefix) {\n+\t\t/*\n+\t\t * optimization:\n+\t\t * if there is no pattern with leading slash\n+\t\t * then it is safe to only match inside prefix\n+\t\t */\n+\t\tif (!spec->has_root && prefixcmp(path, spec->prefix))\n+\t\t\treturn 0;\n+\t\tprefix_len = strlen(spec->prefix);\n+\t}\n+\n+\tfor (i = spec->nr - 1;i >= 0; i--) {\n+\t\tstruct narrow_pattern *p = spec->patterns[i];\n+\t\tconst char *new_path = path + prefix_len;\n+\t\tint match;\n+\n+\t\tif (p->has_root)\n+\t\t\tnew_path = path; /* match full path */\n+\t\telse if (spec->has_root) {\n+\t\t\tif (prefixcmp(path, spec->prefix))\n+\t\t\t\tcontinue;\n+\t\t}\n+\t\t/* !spec->has_root case has been handled above */\n+\n+\t\tif (p->has_trailing_slash) {\n+\t\t\t/* the only \"wildcard\" here is backslash escape */\n+\t\t\tif (p->has_wildcards) {\n+\t\t\t\tchar *unescaped_pattern = xstrdup(p->pattern);\n+\t\t\t\tchar *src, *dst;\n+\n+\t\t\t\tsrc = dst = unescaped_pattern;\n+\t\t\t\twhile (*src) {\n+\t\t\t\t\tif (*src == '\\\\')\n+\t\t\t\t\t\tsrc++;\n+\t\t\t\t\tif (src != dst)\n+\t\t\t\t\t\t*dst = *src;\n+\t\t\t\t\tsrc++;\n+\t\t\t\t\tdst++;\n+\t\t\t\t}\n+\t\t\t\t*dst = '\\0';\n+\t\t\t\tmatch = prefixcmp(new_path, unescaped_pattern) == 0;\n+\t\t\t\tfree(unescaped_pattern);\n+\t\t\t}\n+\t\t\telse\n+\t\t\t\tmatch = prefixcmp(new_path, p->pattern) == 0;\n+\t\t}\n+\t\telse if (p->has_slashes) {\n+\t\t\tif (p->has_wildcards)\n+\t\t\t\tmatch = fnmatch(p->pattern, new_path, FNM_PATHNAME) == 0;\n+\t\t\telse\n+\t\t\t\tmatch = strcmp(p->pattern, new_path) == 0;\n+\t\t}\n+\t\telse {\n+\t\t\tconst char *basename = strrchr(path + prefix_len, '/');\n+\t\t\tif (basename)\n+\t\t\t\tbasename++;\n+\t\t\telse\n+\t\t\t\tbasename = path + prefix_len;\n+\t\t\tif (p->has_wildcards)\n+\t\t\t\tmatch = fnmatch(p->pattern, basename, 0) == 0;\n+\t\t\telse\n+\t\t\t\tmatch = strcmp(p->pattern, basename) == 0;\n+\t\t}\n+\t\tif (match)\n+\t\t\treturn p->negative ? 0 : 1;\n+\t}\n+\n+\t/* no pattern is matched */\n+\treturn 0;\n+}\n+\n int threeway_merge(struct cache_entry **stages, struct unpack_trees_options *o)\n {\n \tstruct cache_entry *index;\ndiff --git a/unpack-trees.h b/unpack-trees.h\nindex 0d26f3d..6b1971f 100644\n--- a/unpack-trees.h\n+++ b/unpack-trees.h\n@@ -16,6 +16,22 @@ struct unpack_trees_error_msgs {\n \tconst char *bind_overlap;\n };\n \n+struct narrow_spec {\n+\tint nr;\n+\tint alloc;\n+\tint has_root:1;\n+\tconst char *prefix;\n+\tstruct narrow_pattern {\n+\t\tint len;\n+\t\tint has_root:1;\n+\t\tint has_slashes:1;\n+\t\tint has_wildcards:1;\n+\t\tint has_trailing_slash:1;\n+\t\tint negative:1;\n+\t\tchar pattern[FLEX_ARRAY];\n+\t} **patterns;\n+};\n+\n struct unpack_trees_options {\n \tunsigned int reset:1,\n \t\t     merge:1,\n@@ -48,6 +64,8 @@ struct unpack_trees_options {\n extern int unpack_trees(unsigned n, struct tree_desc *t,\n \t\tstruct unpack_trees_options *options);\n \n+struct narrow_spec *parse_narrow_spec(const char *spec, const char *prefix);\n+int match_narrow_spec(struct narrow_spec *spec, const char *path);\n int threeway_merge(struct cache_entry **stages, struct unpack_trees_options *o);\n int twoway_merge(struct cache_entry **src, struct unpack_trees_options *o);\n int bind_merge(struct cache_entry **src, struct unpack_trees_options *o);\n-- \n1.6.0.96.g2fad1.dirty\n"},{"id":"91180","messageId":"1221904913-25887-12-git-send-email-pclouds@gmail.com","threadId":"15604","inReplyTo":"1221904913-25887-11-git-send-email-pclouds@gmail.com","subject":"[PATCH 11/14] unpack_trees(): add support for sparse checkout","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2008-09-20T10:01:50Z","receivedAt":"2008-09-20T10:01:50Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This patch teaches unpack_trees() to checkout/remove entries\non working directories appropriately when sparse checkout area is\nchanged. There are three kind of changes:\n\n - new_narrow_path: reset workdir to a completely new checkout area\n - add_narrow_path: keep current areas and add more entries\n - remove_narrow_path: remove some entries from current areas\n\nCE_WD_REMOVE is introduced to remove entries from working directories,\nbut still keep them in index\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n cache.h        |    3 ++\n unpack-trees.c |   74 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-\n unpack-trees.h |    4 +++\n 3 files changed, 80 insertions(+), 1 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex 6e875d5..f4025b5 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -167,6 +167,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_WD_REMOVE (0x400000)\n+\n /*\n  * Extended on-disk flags\n  */\ndiff --git a/unpack-trees.c b/unpack-trees.c\nindex ce4c826..10f377c 100644\n--- a/unpack-trees.c\n+++ b/unpack-trees.c\n@@ -96,7 +96,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_WD_REMOVE))\n \t\t\t\ttotal++;\n \t\t}\n \n@@ -108,6 +108,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_WD_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@@ -133,6 +140,66 @@ static int check_updates(struct unpack_trees_options *o)\n \treturn errs != 0;\n }\n \n+static int verify_uptodate(struct cache_entry *ce, struct unpack_trees_options *o);\n+static int apply_narrow_spec(struct unpack_trees_options *o)\n+{\n+\tstruct index_state *index = &o->result;\n+\tint i;\n+\n+\tif (!(o->new_narrow_path | o->add_narrow_path | o->remove_narrow_path))\n+\t\treturn 0;\n+\n+\tfor (i = 0; i < index->cache_nr; i++) {\n+\t\tstruct cache_entry *ce = index->cache[i];\n+\t\tint was_checkout = ce_checkout(ce);\n+\t\tint match = match_narrow_spec(o->narrow_spec, ce->name);\n+\n+\t\tif (ce_stage(ce))\n+\t\t\tcontinue;\n+\n+\t\tif (o->new_narrow_path) {\n+\t\t\tif (match)\n+\t\t\t\tce_mark_checkout(ce);\n+\t\t\telse\n+\t\t\t\tce_mark_no_checkout(ce);\n+\t\t}\n+\n+\t\tif (o->add_narrow_path && match)\n+\t\t\tce_mark_checkout(ce);\n+\n+\t\tif (o->remove_narrow_path && match)\n+\t\t\tce_mark_no_checkout(ce);\n+\n+\t\t/* Update worktree, add/remove entries if needed */\n+\n+\t\t/*\n+\t\t * We only care about files getting into the checkout area\n+\t\t * If merge strategies want to remove some, go ahead\n+\t\t */\n+\t\tif (ce->ce_flags & CE_REMOVE)\n+\t\t\tcontinue;\n+\n+\t\tif (was_checkout && ce_no_checkout(ce)) {\n+\t\t\t/*\n+\t\t\t * If CE_UPDATE is set, verify_uptodate() must be called already\n+\t\t\t * also stat info may have lost after merged_entry() so calling\n+\t\t\t * verify_uptodate() again may fail\n+\t\t\t */\n+\t\t\tif (!(ce->ce_flags & CE_UPDATE) && verify_uptodate(ce, o))\n+\t\t\t\treturn -1;\n+\t\t\tce->ce_flags |= CE_WD_REMOVE;\n+\t\t}\n+\t\tif (!was_checkout && ce_checkout(ce))\n+\t\t\tce->ce_flags |= CE_UPDATE;\n+\n+\t\t/* merge strategies may set CE_UPDATE outside checkout area */\n+\t\tif (ce_no_checkout(ce))\n+\t\t\tce->ce_flags &= ~CE_UPDATE;\n+\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@@ -409,6 +476,9 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options\n \tif (o->trivial_merges_only && o->nontrivial_merge)\n \t\treturn unpack_failed(o, \"Merge requires file-level merging\");\n \n+\tif (apply_narrow_spec(o))\n+\t\treturn unpack_failed(o, NULL);\n+\n \to->src_index = NULL;\n \tret = check_updates(o) ? (-2) : 0;\n \tif (o->dst_index)\n@@ -677,6 +747,8 @@ static int merged_entry(struct cache_entry *merge, struct cache_entry *old,\n \t\t\t\treturn -1;\n \t\t\tinvalidate_ce_path(old, o);\n \t\t}\n+\t\tif (ce_no_checkout(old))\n+\t\t\tupdate |= CE_NO_CHECKOUT;\n \t}\n \telse {\n \t\tif (verify_absent(merge, \"overwritten\", o))\ndiff --git a/unpack-trees.h b/unpack-trees.h\nindex 6b1971f..0d899b6 100644\n--- a/unpack-trees.h\n+++ b/unpack-trees.h\n@@ -43,6 +43,9 @@ struct unpack_trees_options {\n \t\t     aggressive:1,\n \t\t     skip_unmerged:1,\n \t\t     initial_checkout:1,\n+\t\t     new_narrow_path:1,\n+\t\t     add_narrow_path:2,\n+\t\t     remove_narrow_path:2,\n \t\t     gently:1;\n \tconst char *prefix;\n \tint pos;\n@@ -54,6 +57,7 @@ struct unpack_trees_options {\n \tint merge_size;\n \n \tstruct cache_entry *df_conflict_entry;\n+\tstruct narrow_spec *narrow_spec;\n \tvoid *unpack_data;\n \n \tstruct index_state *dst_index;\n-- \n1.6.0.96.g2fad1.dirty\n"},{"id":"91179","messageId":"1221904913-25887-13-git-send-email-pclouds@gmail.com","threadId":"15604","inReplyTo":"1221904913-25887-12-git-send-email-pclouds@gmail.com","subject":"[PATCH 12/14] clone: support sparse checkout with --narrow-path option","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2008-09-20T10:01:51Z","receivedAt":"2008-09-20T10:01:51Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Documentation/git-clone.txt |   10 +++++++++-\n builtin-clone.c             |   13 +++++++++++++\n t/t5703-clone-narrow.sh     |   39 +++++++++++++++++++++++++++++++++++++++\n 3 files changed, 61 insertions(+), 1 deletions(-)\n create mode 100755 t/t5703-clone-narrow.sh\n\ndiff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt\nindex 0e14e73..c283cf4 100644\n--- a/Documentation/git-clone.txt\n+++ b/Documentation/git-clone.txt\n@@ -12,7 +12,8 @@ SYNOPSIS\n 'git clone' [--template=<template_directory>]\n \t  [-l] [-s] [--no-hardlinks] [-q] [-n] [--bare] [--mirror]\n \t  [-o <name>] [-u <upload-pack>] [--reference <repository>]\n-\t  [--depth <depth>] [--] <repository> [<directory>]\n+\t  [--depth <depth>] [--narrow-path=<sparse patterns>] [--]\n+\t  <repository> [<directory>]\n \n DESCRIPTION\n -----------\n@@ -94,6 +95,13 @@ then the cloned repository will become corrupt.\n -n::\n \tNo checkout of HEAD is performed after the clone is complete.\n \n+--narrow-path=<sparse patterns>::\n+\tMake a sparse checkout instead of full one. The checkout area\n+\twill be narrowed to specific areas based on given sparse\n+\tpatterns. This option will not work with either --no-checkout\n+\tor --bare.  Please refer to linkgit:git-checkout[1] for more\n+\tdetail on sparse checkout and sparse patterns.\n+\n --bare::\n \tMake a 'bare' GIT repository.  That is, instead of\n \tcreating `<directory>` and placing the administrative\ndiff --git a/builtin-clone.c b/builtin-clone.c\nindex a4b8790..5ee8362 100644\n--- a/builtin-clone.c\n+++ b/builtin-clone.c\n@@ -36,6 +36,7 @@ static const char * const builtin_clone_usage[] = {\n static int option_quiet, option_no_checkout, option_bare, option_mirror;\n static int option_local, option_no_hardlinks, option_shared;\n static char *option_template, *option_reference, *option_depth;\n+static char *option_narrow_path;\n static char *option_origin = NULL;\n static char *option_upload_pack = \"git-upload-pack\";\n \n@@ -43,6 +44,8 @@ static struct option builtin_clone_options[] = {\n \tOPT__QUIET(&option_quiet),\n \tOPT_BOOLEAN('n', \"no-checkout\", &option_no_checkout,\n \t\t    \"don't create a checkout\"),\n+\tOPT_STRING(0, \"narrow-path\", &option_narrow_path, \"prefixes\",\n+\t\t    \"limit checkout to specified areas (sparse checkout)\"),\n \tOPT_BOOLEAN(0, \"bare\", &option_bare, \"create a bare repository\"),\n \tOPT_BOOLEAN(0, \"naked\", &option_bare, \"create a bare repository\"),\n \tOPT_BOOLEAN(0, \"mirror\", &option_mirror,\n@@ -378,10 +381,15 @@ int cmd_clone(int argc, const char **argv, const char *prefix)\n \t\tif (option_origin)\n \t\t\tdie(\"--bare and --origin %s options are incompatible.\",\n \t\t\t    option_origin);\n+\t\tif (option_narrow_path)\n+\t\t\tdie(\"--bare and --narrow-path options are incompatible.\");\n \t\toption_no_checkout = 1;\n \t\tuse_separate_remote = 0;\n \t}\n \n+\tif (option_no_checkout && option_narrow_path)\n+\t\tdie(\"--no-checkout and --narrow-path options are incompatible.\");\n+\n \tif (!option_origin)\n \t\toption_origin = \"origin\";\n \n@@ -590,6 +598,11 @@ int cmd_clone(int argc, const char **argv, const char *prefix)\n \t\topts.src_index = &the_index;\n \t\topts.dst_index = &the_index;\n \n+\t\tif (option_narrow_path) {\n+\t\t\topts.new_narrow_path = 1;\n+\t\t\topts.narrow_spec = parse_narrow_spec(option_narrow_path, NULL);\n+\t\t}\n+\n \t\ttree = parse_tree_indirect(remote_head->old_sha1);\n \t\tparse_tree(tree);\n \t\tinit_tree_desc(&t, tree->buffer, tree->size);\ndiff --git a/t/t5703-clone-narrow.sh b/t/t5703-clone-narrow.sh\nnew file mode 100755\nindex 0000000..66f9191\n--- /dev/null\n+++ b/t/t5703-clone-narrow.sh\n@@ -0,0 +1,39 @@\n+#!/bin/sh\n+\n+test_description='narrow clone'\n+\n+. ./test-lib.sh\n+\n+test_expect_success setup '\n+\trm -fr .git &&\n+\ttest_create_repo src &&\n+\t(\n+\t\tcd src\n+\t\tmkdir -p work/sub/dir\n+\t\ttouch untracked tracked modified added\n+\t\ttouch work/untracked work/tracked work/modified work/added\n+\t\tgit add tracked work/tracked\n+\t\tgit add modified work/modified\n+\t\tgit commit -m initial\n+\t)\n+\n+'\n+\n+test_expect_success 'narrow clone incompatible with --bare' '\n+\trm -fr dst &&\n+\ttest_must_fail git clone --narrow-path=work --bare src dst\n+'\n+\n+test_expect_success 'narrow clone incompatible with --no-checkout' '\n+\trm -fr dst &&\n+\ttest_must_fail git clone --narrow-path=work -n src dst\n+'\n+\n+test_expect_success 'clone with --narrow-path' '\n+\trm -fr dst &&\n+\tgit clone --narrow-path=work src dst &&\n+\tcd dst &&\n+\ttest -z \"$(git ls-files --sparse | grep -v ^work/)\"\n+'\n+\n+test_done\n-- \n1.6.0.96.g2fad1.dirty\n"},{"id":"91181","messageId":"1221904913-25887-14-git-send-email-pclouds@gmail.com","threadId":"15604","inReplyTo":"1221904913-25887-13-git-send-email-pclouds@gmail.com","subject":"[PATCH 13/14] checkout: add new options to support sparse checkout","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2008-09-20T10:01:52Z","receivedAt":"2008-09-20T10:01:52Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This patch adds main interface to manipulate sparse checkout.\nNew options are added to support entering/updating/leaving sparse\ncheckout:\n\n --full: return to full checkout (default)\n --reset-path: set checkout area according to given spec\n --add-path/--remove-path: adjust current sparse checkout area\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Documentation/git-checkout.txt |   54 +++++++++++++++++++-\n builtin-checkout.c             |   37 ++++++++++++++\n t/t2011-checkout-sparse.sh     |  108 ++++++++++++++++++++++++++++++++++++++++\n 3 files changed, 196 insertions(+), 3 deletions(-)\n create mode 100755 t/t2011-checkout-sparse.sh\n\ndiff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt\nindex d6f94a6..571e2a4 100644\n--- a/Documentation/git-checkout.txt\n+++ b/Documentation/git-checkout.txt\n@@ -8,8 +8,10 @@ git-checkout - Checkout a branch or paths to the working tree\n SYNOPSIS\n --------\n [verse]\n-'git checkout' [-q] [-f] [--track | --no-track] [-b <new_branch> [-l]] [-m] [<branch>]\n-'git checkout' [-f|--ours|--theirs|-m|--conflict=<style>] [<tree-ish>] [--] <paths>...\n+'git checkout' [-q] [-f] [--track | --no-track] [-b <new_branch> [-l]] [-m]\n+\t  [<sparse checkout options>] [<branch>]\n+'git checkout' [-f|--ours|--theirs|-m|--conflict=<style>] [<tree-ish>]\n+\t  [<sparse checkout options>] [--] <paths>...\n \n DESCRIPTION\n -----------\n@@ -34,6 +36,10 @@ used to specify a specific tree-ish (i.e. commit, tag or tree)\n to update the index for the given paths before updating the\n working tree.\n \n+<sparse checkout options> include --full, --reset-path, --add-path\n+and --remove-path. The last three require sparse patterns. Please refer\n+to \"sparse checkout\" section for more information about this mode.\n+\n The index may contain unmerged entries after a failed merge.  By\n default, if you try to check out such an entry from the index, the\n checkout operation will fail and nothing will be checked out.\n@@ -117,6 +123,32 @@ should result in deletion of the path).\n When checking out paths from the index, this option lets you recreate\n the conflicted merge in the specified paths.\n \n+--full::\n+\tQuit sparse checkout mode. Return to full checkout. This option\n+\tcannot be used with either --reset-path, --add-path,\n+\t--remove-path or <paths>.\n+\n+--reset-path=<sparse patterns>::\n+\tRe-apply new sparse patterns on current working directory to\n+\tform new checkout area. All no-checkout bits will be wiped\n+\tout before applying the patterns. This option cannot be used\n+\twith --full, --add-path, --remove-path or <paths>. Multiple\n+\t--reset-path is not allowed.\n+\n+--add-path=<sparse patterns>::\n+\tCheckout more areas specified by sparse patterns to current\n+\tcheckout area. Already checked out entries are not affected.\n+\tThis option cannot be used with --full, --reset-path,\n+\t--remove-path or <paths>. Multiple --add-path is not allowed.\n+\n+--remove-path=<sparse patterns>::\n+\tNarrow checkout area by removing files specified by sparse patterns\n+\tfrom current checkout area. This operation will fail if there\n+\tare unmerged or modified files in the removing areas. No-checkout\n+\tentries are not affected. This option cannot be used with --full,\n+\t--reset-path, --add-path or <paths>. Multiple --remove-path is not\n+\tallowed.\n+\n --conflict=<style>::\n \tThe same as --merge option above, but changes the way the\n \tconflicting hunks are presented, overriding the\n@@ -186,7 +218,10 @@ Because sparse checkout uses a new index format, it will be\n incompatible with git prior to 1.6.0 regarding worktree operations.\n Operations that only need access to the repository itself, such as\n clone, push, or pull/fetch from another (normal) repository... should\n-not be affected by sparse checkout.\n+not be affected by sparse checkout. In order to make your working\n+directory work again with those versions, you can use\n+`git checkout --full` to return to normal mode (and compatible index\n+format).\n \n In sparse checkout mode, checkout status of every files in your\n working directory will be recorded in index. If a file is marked\n@@ -251,6 +286,19 @@ Patterns have the following format:\n  - Because colons are used to separate patterns, you cannot put them\n    in patterns directly. You must quote them using backslash.\n \n+When you apply new sparse patterns to your working directory using either\n+--reset-path, --add-path or --remove-path, it will update \"checkout\" status\n+in index accordingly. Moreover, if a file is marked \"no-checkout\" and\n+is present in working directory, it will be removed. If a file is\n+turned from \"no-checkout\" to \"checkout\", then it will be added again\n+to working directory. Modified and unmerged entries can't bear\n+\"no-checkout\" status, if sparse patterns apply to them, \"git checkout\"\n+will refuse to update working directory.\n+\n+Sparse patterns are not saved by \"git checkout\" anywhere in the repository.\n+You can form your checkout area in one go with --reset-path option,\n+or do it incrementally with --add-path and --remove-path.\n+\n EXAMPLES\n --------\n \ndiff --git a/builtin-checkout.c b/builtin-checkout.c\nindex c7b0aad..d459bc6 100644\n--- a/builtin-checkout.c\n+++ b/builtin-checkout.c\n@@ -33,6 +33,12 @@ struct checkout_opts {\n \tconst char *new_branch;\n \tint new_branch_log;\n \tenum branch_track track;\n+\n+\tconst char *prefix;\n+\tchar *new_path;\n+\tchar *add_path;\n+\tchar *remove_path;\n+\tint all_path;\n };\n \n static int post_checkout_hook(struct commit *old, struct commit *new,\n@@ -412,6 +418,23 @@ static int merge_working_tree(struct checkout_opts *opts,\n \t\ttree = parse_tree_indirect(new->commit->object.sha1);\n \t\tinit_tree_desc(&trees[1], tree->buffer, tree->size);\n \n+\t\tif (opts->all_path) {\n+\t\t\t/* leave narrow_spec NULL */\n+\t\t\ttopts.new_narrow_path = 1;\n+\t\t}\n+\t\telse if (opts->new_path) {\n+\t\t\ttopts.narrow_spec = parse_narrow_spec(opts->new_path, opts->prefix);\n+\t\t\ttopts.new_narrow_path = 1;\n+\t\t}\n+\t\telse if (opts->add_path) {\n+\t\t\ttopts.narrow_spec = parse_narrow_spec(opts->add_path, opts->prefix);\n+\t\t\ttopts.add_narrow_path = 1;\n+\t\t}\n+\t\telse if (opts->remove_path) {\n+\t\t\ttopts.narrow_spec = parse_narrow_spec(opts->remove_path, opts->prefix);\n+\t\t\ttopts.remove_narrow_path = 1;\n+\t\t}\n+\n \t\tret = unpack_trees(2, trees, &topts);\n \t\tif (ret == -1) {\n \t\t\t/*\n@@ -600,6 +623,10 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)\n \t\tOPT_BOOLEAN('m', \"merge\", &opts.merge, \"merge\"),\n \t\tOPT_STRING(0, \"conflict\", &conflict_style, \"style\",\n \t\t\t   \"conflict style (merge or diff3)\"),\n+\t\tOPT_BOOLEAN(0, \"full\", &opts.all_path, \"quit sparse checkout\"),\n+\t\tOPT_STRING(0, \"reset-path\", &opts.new_path, \"prefixes\", \"reset to new sparse checkout\"),\n+\t\tOPT_STRING(0, \"add-path\", &opts.add_path, \"prefixes\", \"widen checkout area\"),\n+\t\tOPT_STRING(0, \"remove-path\", &opts.remove_path, \"prefixes\", \"narrow checkout area\"),\n \t\tOPT_END(),\n \t};\n \tint has_dash_dash;\n@@ -610,6 +637,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)\n \tgit_config(git_checkout_config, NULL);\n \n \topts.track = BRANCH_TRACK_UNSPECIFIED;\n+\topts.prefix = prefix;\n \n \targc = parse_options(argc, argv, options, checkout_usage,\n \t\t\t     PARSE_OPT_KEEP_DASHDASH);\n@@ -639,6 +667,12 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)\n \tif (!opts.new_branch && (opts.track != git_branch_track))\n \t\tdie(\"git checkout: --track and --no-track require -b\");\n \n+\tif (((opts.all_path ? 1 : 0) +\n+\t     (opts.new_path ? 1 : 0) +\n+\t     (opts.add_path ? 1 : 0) +\n+\t     (opts.remove_path ? 1 : 0)) > 1)\n+\t\tdie(\"git checkout: --reset-path, --full, --add-path and --remove-path are incompatible\");\n+\n \tif (opts.force && opts.merge)\n \t\tdie(\"git checkout: -f and -m are incompatible\");\n \n@@ -732,6 +766,9 @@ no_reference:\n \t\tif (1 < !!opts.writeout_stage + !!opts.force + !!opts.merge)\n \t\t\tdie(\"git checkout: --ours/--theirs, --force and --merge are incompatible when\\nchecking out of the index.\");\n \n+\t\tif (opts.all_path || opts.new_path || opts.add_path || opts.remove_path)\n+\t\t\tdie(\"git checkout: updating paths is incompatible with setting sparse checkout\");\n+\n \t\treturn checkout_paths(source_tree, pathspec, &opts);\n \t}\n \ndiff --git a/t/t2011-checkout-sparse.sh b/t/t2011-checkout-sparse.sh\nnew file mode 100755\nindex 0000000..b5ccfe4\n--- /dev/null\n+++ b/t/t2011-checkout-sparse.sh\n@@ -0,0 +1,108 @@\n+#!/bin/sh\n+\n+test_description='sparse checkout'\n+\n+. ./test-lib.sh\n+\n+test_expect_success setup '\n+\tmkdir work1 work2 work3\n+\ttouch one two three\n+\ttouch work1/one work2/two work3/three\n+\tgit add one work1/one\n+\tgit commit -m work1\n+\tgit add two work2/two\n+\tgit commit -m work2\n+\tgit add three work3/three\n+\tgit commit -m work3\n+'\n+\n+test_expect_success '--full on no-narrow checkout' '\n+\tgit checkout --full\n+'\n+\n+test_expect_success '--full and --reset-path incompatible' '\n+\ttest_must_fail git checkout --full --reset-path=work1\n+'\n+\n+test_expect_success 'limit worktree to work1 and work2' '\n+\tgit checkout --reset-path=work1/:work2/ &&\n+\ttest -f work1/one &&\n+\ttest -f work2/two &&\n+\t! test -f work3/three\n+'\n+\n+test_expect_success 'update worktree to work2 and work3' '\n+\tgit checkout --reset-path=work2/:work3/ &&\n+\t! test -f work1/one &&\n+\ttest -f work2/two &&\n+\ttest -f work3/three\n+'\n+\n+test_expect_success 'update narrow prefix with modification' '\n+\techo modified >> work2/two &&\n+\tgit checkout --reset-path=work1/:work2/ &&\n+\ttest -f work1/one &&\n+\ttest -f work2/two &&\n+\t! test -f work3/three &&\n+\tgrep -q modified work2/two\n+'\n+\n+test_expect_success 'update checkout should not lose modification' '\n+\t! git checkout --reset-path=work1/:work3/ &&\n+\ttest -f work1/one &&\n+\ttest -f work2/two &&\n+\t! test -f work3/three &&\n+\tgrep -q modified work2/two\n+'\n+\n+test_expect_success 'widen checkout area' '\n+\tgit checkout --add-path=work3/ &&\n+\ttest -f work1/one &&\n+\ttest -f work2/two &&\n+\ttest -f work3/three\n+'\n+\n+test_expect_success 'narrow checkout area' '\n+\tgit checkout --remove-path=work3/ &&\n+\ttest -f work1/one &&\n+\ttest -f work2/two &&\n+\t! test -f work3/three\n+'\n+\n+test_expect_success 'update outside checkout area' '\n+\techo one >> work1/one &&\n+\tgit add work1/one &&\n+\tgit commit -m update &&\n+\tgit checkout --reset-path=work2/ &&\n+\tgit checkout HEAD^ &&\n+\tgit checkout master\n+'\n+\n+test_expect_success 'conflict outside checkout area' '\n+\tgit checkout --add-path=work1/one -b conflict HEAD~2 &&\n+\techo two >> work1/one &&\n+\tgit add work1/one &&\n+\tgit commit -m conflict-update &&\n+\tgit checkout --reset-path=work2/ master &&\n+\ttest -z \"$(git ls-files --sparse work1/one)\"\n+\tgit merge conflict\n+\ttest $? = 1 &&\n+\ttest -n \"$(git ls-files --sparse work1/one)\" &&\n+\tgit reset --hard HEAD\n+'\n+\n+test_expect_success 'removal outside checkout area' '\n+\tgit rm work1/one &&\n+\tgit commit -m remove &&\n+\tgit checkout --reset-path=work2/ HEAD^\n+'\n+\n+test_expect_success 'exit sparse checkout' '\n+\tgit checkout --full &&\n+\ttest -f work1/one &&\n+\ttest -f work2/two &&\n+\ttest -f work3/three &&\n+\ttest one\n+'\n+\n+test_done\n-- \n1.6.0.96.g2fad1.dirty\n"},{"id":"91182","messageId":"1221904913-25887-15-git-send-email-pclouds@gmail.com","threadId":"15604","inReplyTo":"1221904913-25887-14-git-send-email-pclouds@gmail.com","subject":"[PATCH 14/14] wt-status: Show orphaned entries in \"git status\" output","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2008-09-20T10:01:53Z","receivedAt":"2008-09-20T10:01:53Z","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 wt-status.c |   39 +++++++++++++++++++++++++++++++++++++++\n wt-status.h |    1 +\n 2 files changed, 40 insertions(+), 0 deletions(-)\n\ndiff --git a/wt-status.c b/wt-status.c\nindex 7cf890f..4c237e2 100644\n--- a/wt-status.c\n+++ b/wt-status.c\n@@ -20,6 +20,7 @@ static char wt_status_colors[][COLOR_MAXLEN] = {\n \t\"\\033[31m\", /* WT_STATUS_CHANGED: red */\n \t\"\\033[31m\", /* WT_STATUS_UNTRACKED: red */\n \t\"\\033[31m\", /* WT_STATUS_NOBRANCH: red */\n+\t\"\\033[31m\", /* WT_STATUS_ORPHANED: red */\n };\n \n enum untracked_status_type show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES;\n@@ -83,6 +84,16 @@ static void wt_status_print_dirty_header(struct wt_status *s,\n \tcolor_fprintf_ln(s->fp, c, \"#\");\n }\n \n+static void wt_status_print_orphaned_header(struct wt_status *s)\n+{\n+\tconst char *c = color(WT_STATUS_HEADER);\n+\tcolor_fprintf_ln(s->fp, c, \"# Orphaned files:\");\n+\tcolor_fprintf_ln(s->fp, c, \"#   (these are tracked, but marked no-checkout and should not be present)\");\n+\tcolor_fprintf_ln(s->fp, c, \"#   (use \\\"git update-index --checkout\\\" to remove no-checkout status)\");\n+\tcolor_fprintf_ln(s->fp, c, \"#   (otherwise remove them to avoid confusion because git will ignore them)\");\n+\tcolor_fprintf_ln(s->fp, c, \"#\");\n+}\n+\n static void wt_status_print_untracked_header(struct wt_status *s)\n {\n \tconst char *c = color(WT_STATUS_HEADER);\n@@ -233,6 +244,33 @@ static void wt_status_print_changed(struct wt_status *s)\n \trun_diff_files(&rev, 0);\n }\n \n+static void wt_status_print_orphaned(struct wt_status *s)\n+{\n+\tint i, show_header = 0;\n+\tstruct stat st;\n+\tstruct strbuf buf;\n+\n+\tstrbuf_init(&buf, 0);\n+\tfor (i = 0; i < the_index.cache_nr; i++) {\n+\t\tstruct cache_entry *ce = the_index.cache[i];\n+\n+\t\tif (ce_checkout(ce) || lstat(ce->name, &st))\n+\t\t\tcontinue;\n+\n+\t\tif (!show_header) {\n+\t\t\twt_status_print_orphaned_header(s);\n+\t\t\tshow_header = 1;\n+\t\t}\n+\n+\t\tcolor_fprintf(s->fp, color(WT_STATUS_HEADER), \"#\\t\");\n+\t\tcolor_fprintf_ln(s->fp, color(WT_STATUS_ORPHANED), \"%s\",\n+\t\t\t\t quote_path(ce->name, -1, &buf, s->prefix));\n+\t}\n+\n+\tif (show_header)\n+\t\tcolor_fprintf_ln(s->fp, color(WT_STATUS_HEADER),\"#\");\n+}\n+\n static void wt_status_print_submodule_summary(struct wt_status *s)\n {\n \tstruct child_process sm_summary;\n@@ -373,6 +411,7 @@ void wt_status_print(struct wt_status *s)\n \t}\n \n \twt_status_print_changed(s);\n+\twt_status_print_orphaned(s);\n \tif (wt_status_submodule_summary)\n \t\twt_status_print_submodule_summary(s);\n \tif (show_untracked_files)\ndiff --git a/wt-status.h b/wt-status.h\nindex 78add09..52f1eb5 100644\n--- a/wt-status.h\n+++ b/wt-status.h\n@@ -9,6 +9,7 @@ enum color_wt_status {\n \tWT_STATUS_CHANGED,\n \tWT_STATUS_UNTRACKED,\n \tWT_STATUS_NOBRANCH,\n+\tWT_STATUS_ORPHANED,\n };\n \n enum untracked_status_type {\n-- \n1.6.0.96.g2fad1.dirty\n"},{"id":"91184","messageId":"adf1fd3d0809200348h1170e8cm302e92043da8995d@mail.gmail.com","threadId":"15604","inReplyTo":"1221904913-25887-1-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH v2 00/14] Sparse checkout","fromName":"Santi Béjar","fromEmail":"santi@agolina.net","sentAt":"2008-09-20T10:48:32Z","receivedAt":"2008-09-20T10:48:32Z","isPatch":true,"sender":{"key":"santi@agolina.net","avatar":null},"body":"On Sat, Sep 20, 2008 at 12:01 PM, Nguyễn Thái Ngọc Duy\n<pclouds@gmail.com> wrote:\n>\n> Nguyễn Thái Ngọc Duy (14):\n>  Extend index to save more flags\n>  Introduce CE_NO_CHECKOUT bit\n>  ls-files: add options to support sparse checkout\n>  update-index: refactor mark_valid() in preparation for new options\n>  update-index: add --checkout/--no-checkout to update CE_NO_CHECKOUT bit\n>  ls-files: Add tests for --sparse and friends\n>  Prevent diff machinery from examining worktree outside sparse checkout\n>  checkout_entry(): CE_NO_CHECKOUT on checked out entries.\n>  grep: skip files outside sparse checkout area\n>  ls-files: support \"sparse patterns\", used to form sparse checkout areas\n>  unpack_trees(): add support for sparse checkout\n>  clone: support sparse checkout with --narrow-path option\n>  checkout: add new options to support sparse checkout\n>  wt-status: Show orphaned entries in \"git status\" output\n>\n\nI would like to test it, do you have a public repo to fetch it?\n\nSanti\n"},{"id":"91185","messageId":"fcaeb9bf0809200507j61f42369o4a22a02f58733ae1@mail.gmail.com","threadId":"15604","inReplyTo":"adf1fd3d0809200348h1170e8cm302e92043da8995d@mail.gmail.com","subject":"Re: [PATCH v2 00/14] Sparse checkout","fromName":"Nguyen Thai Ngoc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2008-09-20T12:07:01Z","receivedAt":"2008-09-20T12:07:01Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On 9/20/08, Santi Béjar <santi@agolina.net> wrote:\n> On Sat, Sep 20, 2008 at 12:01 PM, Nguyễn Thái Ngọc Duy\n>  <pclouds@gmail.com> wrote:\n>  >\n>  > Nguyễn Thái Ngọc Duy (14):\n>  >  Extend index to save more flags\n>  >  Introduce CE_NO_CHECKOUT bit\n>  >  ls-files: add options to support sparse checkout\n>  >  update-index: refactor mark_valid() in preparation for new options\n>  >  update-index: add --checkout/--no-checkout to update CE_NO_CHECKOUT bit\n>  >  ls-files: Add tests for --sparse and friends\n>  >  Prevent diff machinery from examining worktree outside sparse checkout\n>  >  checkout_entry(): CE_NO_CHECKOUT on checked out entries.\n>  >  grep: skip files outside sparse checkout area\n>  >  ls-files: support \"sparse patterns\", used to form sparse checkout areas\n>  >  unpack_trees(): add support for sparse checkout\n>  >  clone: support sparse checkout with --narrow-path option\n>  >  checkout: add new options to support sparse checkout\n>  >  wt-status: Show orphaned entries in \"git status\" output\n>  >\n>\n>\n> I would like to test it, do you have a public repo to fetch it?\n\ngit://repo.or.cz/git/pclouds.git branch sparse-checkout.\n-- \nDuy\n"},{"id":"91186","messageId":"m31vzen4v5.fsf@localhost.localdomain","threadId":"15604","inReplyTo":"1221904913-25887-1-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH v2 00/14] Sparse checkout","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2008-09-20T16:45:22Z","receivedAt":"2008-09-20T16:45:22Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Nguyễn Thái Ngọc Duy <pclouds@gmail.com> writes:\n\n> Main changes from the last round are:\n>  - The name is now \"sparse checkout\"\n\nI guess that 'sparse checkout' would be more recognizable than 'narrow\ncheckout'.\n\n>  - \"git clone --path\" => \"git clone --narrow-path\"\n>  - \"git checkout --path\" => \"git checkout --reset-path\"\n\nI am not sure about that change, especially the fact that git-clone\nand git-checkout use differently named options, because those options\naffect clone only as they affect the checkout part of the clone.  One\nwould think that git-clone = git-init + git-remote add + git-fetch +\ngit-checkout, and that git-clone would simply pass sparse checkout\nflags to git-checkout.\n\n>  - New narrow spec (or \"sparse patterns\" from now) resembles\n>    .gitignore patterns\n\nYou mean here that rules for patterns to select which parts of tree\nmark as \"no-checkout\" and/or checkout/leave in checkout are the same\n(or nearly the same) as rules for ignoring files, isn't it?\n\nBTW I think that the same rules are used in gitattributes, aren't\nthey?\n\n>  - \"git ls-files\" now supports more fine-grained listing. It can now\n>    list checkout files, no-checkout files or orphaned (previously\n>    \"overlay\") files. --overlay is gone\n\nGood.  I hope (I haven't read the post yet) that you extended '-t' and\n'-v' output (or added similar option for no-checkout bit specially)\nfor git-ls-files.\n\n>  - \"git status\" shows orphaned entries and remedies\n\nGood.  I guess (I haven't read the post yet) that git-status displays,\nor can be asked to display \"orphaned\"/\"unwanted\" files (files which\nexists in working repository, but are marked with \"no-checkout\" bit),\nand perhaps simply the fact that we commit/are in narrow checkout\n(there is at least one file with \"no-checkout\" bit set in the index).\n\n> For code changes, significant changes are:\n\n>   [10/14] ls-files: support \"sparse patterns\", used to form sparse\n>           checkout areas\n\nHmmm...\n \n> I hope I have addressed all the issues. If I miss anything, please\n> speak up.\n \nBy the way, pleas do not worry if there would be new round of\ncomments.  Sparse checkout is a new feature, and I think it is quite\nimportant to get UI (interface) part, like names of configuration\nvariables and options first, or at least correct them before sparse\ncheckout hits released version.  It is harder IMVHO to change user\ninterface (this applies also to non-local repository data) due to\nconcerns for backwards compatibility; it is I think easier to correct\ncode.\n\n> Nguyá»n ThÃ¡i Ngá»c Duy (14):\n\nErrr... what happened here? For me it doesn't look like correct UTF-8\nencoding, but perhaps that it is just my news client (Gnus)...\n\nP.S. Thanks for numbering this series.\n-- \nJakub Narebski\nPoland\nShadeHawk on #git\n"},{"id":"91188","messageId":"fcaeb9bf0809201033o1e9298a8ob135c68228b77218@mail.gmail.com","threadId":"15604","inReplyTo":"m31vzen4v5.fsf@localhost.localdomain","subject":"Re: [PATCH v2 00/14] Sparse checkout","fromName":"Nguyen Thai Ngoc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2008-09-20T17:33:52Z","receivedAt":"2008-09-20T17:33:52Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On 9/20/08, Jakub Narebski <jnareb@gmail.com> wrote:\n>  >  - \"git clone --path\" => \"git clone --narrow-path\"\n>  >  - \"git checkout --path\" => \"git checkout --reset-path\"\n>\n>\n> I am not sure about that change, especially the fact that git-clone\n>  and git-checkout use differently named options, because those options\n>  affect clone only as they affect the checkout part of the clone.  One\n>  would think that git-clone = git-init + git-remote add + git-fetch +\n>  git-checkout, and that git-clone would simply pass sparse checkout\n>  flags to git-checkout.\n>\n\nJohannes sixt said --path was too generic so I changed the name. Hmm..\nI did not think the same option name for git-checkout and git-clone\nwas important, rather worry about people may misunderstand that it is\n\"narrow clone\" (do not fetch objects outside given paths for all\nhistory). Maybe \"git clone --narrow-checkout\" would be better.\n\"--reset-path\", I think, is a better name though. It would express the\nrelation compared to --add-path and --remove-path.\n\n>  >  - New narrow spec (or \"sparse patterns\" from now) resembles\n>  >    .gitignore patterns\n>\n>\n> You mean here that rules for patterns to select which parts of tree\n>  mark as \"no-checkout\" and/or checkout/leave in checkout are the same\n>  (or nearly the same) as rules for ignoring files, isn't it?\n\nYes, almost the same, exceptions include \"./\" support (this may have\nworked already for .gitignore, I dunno) and backslash escape for\ncolons.\n\n>  BTW I think that the same rules are used in gitattributes, aren't\n>  they?\n\nThey have different implementations. Though the rules may be the same.\n\n>  > Nguyá»…n ThÃ¡i Ngá» c Duy (14):\n>\n>  Errr... what happened here? For me it doesn't look like correct UTF-8\n>  encoding, but perhaps that it is just my news client (Gnus)...\n\nThe cover letter lacks MIME-Version and Content-Type, hmm..\n-- \nDuy\n"},{"id":"91189","messageId":"200809202001.28383.jnareb@gmail.com","threadId":"15604","inReplyTo":"fcaeb9bf0809201033o1e9298a8ob135c68228b77218@mail.gmail.com","subject":"Re: [PATCH v2 00/14] Sparse checkout","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2008-09-20T18:01:27Z","receivedAt":"2008-09-20T18:01:27Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"On Sat, 20 Sep 2008, Nguyen Thai Ngoc Duy wrote:\n> On 9/20/08, Jakub Narebski <jnareb@gmail.com> wrote:\n>>>\n>>>  - \"git clone --path\" => \"git clone --narrow-path\"\n>>>  - \"git checkout --path\" => \"git checkout --reset-path\"\n>>\n>>\n>> I am not sure about that change, especially the fact that git-clone\n>> and git-checkout use differently named options, because those options\n>> affect clone only as they affect the checkout part of the clone.  One\n>> would think that git-clone = git-init + git-remote add + git-fetch +\n>> git-checkout, and that git-clone would simply pass sparse checkout\n>> flags to git-checkout.\n>>\n> \n> Johannes sixt said --path was too generic so I changed the name. Hmm..\n> I did not think the same option name for git-checkout and git-clone\n> was important, rather worry about people may misunderstand that it is\n> \"narrow clone\" (do not fetch objects outside given paths for all\n> history). Maybe \"git clone --narrow-checkout\" would be better.\n\nTrue, I didn't thought that git-clone can have option with explicit\n'checkout' in a name, for example --checkout-paths, or --checkout-only,\nor --narrow-checkout (although for me this one doesn't look as it\naccepts arguments, at least on first glance), or --sparse-checkout\n(the same).\n\n> \"--reset-path\", I think, is a better name though. It would express the\n> relation compared to --add-path and --remove-path.\n\nI don't like very much '--reset-path' option name, because it is not\nabout 'reset' or 'resetting', but about limiting checkout to specified\npaths.  Unfortunately --include / --exclude looks like are for ignoring\nfiles, not marking files with \"no-checkout\" bit etc.\n\nBut I am not native English speaker.\n\nFurther proposals: --only (\"git checkout --only <pattern>\") with\n--checkout-only as counterpart in git-clone; --limit-to, --sparse.\n\n\nGNU tar uses --exclude and --exclude-file (with --no-recurse,\n--no-wildcards, --no-wildcards-match-slash). wget uses --accept\nand --reject for filename patterns, and --include / --exclude for\ndirectories.  Neither looks right for sparse checkout in Git.\n\n>>>  - New narrow spec (or \"sparse patterns\" from now) resembles\n>>>    .gitignore patterns\n>>\n>>\n>> You mean here that rules for patterns to select which parts of tree\n>>  mark as \"no-checkout\" and/or checkout/leave in checkout are the same\n>>  (or nearly the same) as rules for ignoring files, isn't it?\n> \n> Yes, almost the same, exceptions include \"./\" support (this may have\n> worked already for .gitignore, I dunno) and backslash escape for\n> colons.\n\n'./', or rather '/' support works for gitignore: this is the only way\nto have pattern which matches only files in given directory, \nnonrecursively.  For example last line in last example on gitignore(5)\nman page.\n\n>>  BTW I think that the same rules are used in gitattributes, aren't\n>>  they?\n> \n> They have different implementations. Though the rules may be the same.\n\nWere you able to reuse either one?\n\n>>> Nguyá»…n ThÃ¡i Ngá» c Duy (14):\n>>\n>>  Errr... what happened here? For me it doesn't look like correct UTF-8\n>>  encoding, but perhaps that it is just my news client (Gnus)...\n> \n> The cover letter lacks MIME-Version and Content-Type, hmm..\n\nBug in git-format-patch? IIRC --cover-letter was added quite late, and\nis quite a new option; some bugs might have been not ironed out yet.\n\n-- \nJakub Narebski\nPoland\n"},{"id":"91190","messageId":"20080920184018.GC18932@strlen.de","threadId":"15604","inReplyTo":"200809202001.28383.jnareb@gmail.com","subject":"Re: Encoding problems with format-patch [Was: [PATCH v2 00/14] Sparse checkout]","fromName":"Uwe Kleine-König","fromEmail":"ukleinek@strlen.de","sentAt":"2008-09-20T18:40:18Z","receivedAt":"2008-09-20T18:40:18Z","isPatch":true,"sender":{"key":"ukleinek@strlen.de","avatar":"https://gravatar.com/avatar/71e008a89bd4c9d95c03e4823fa14b01e7f658bfc746c8a735286b945417f2d6?d=mp&s=160"},"body":"Hello,\n\nOn Sat, Sep 20, 2008 at 08:01:27PM +0200, Jakub Narebski wrote:\n> On Sat, 20 Sep 2008, Nguyen Thai Ngoc Duy wrote:\n> >>> Nguyá»…n ThÃ¡i Ngá» c Duy (14):\n> >>\n> >>  Errr... what happened here? For me it doesn't look like correct UTF-8\n> >>  encoding, but perhaps that it is just my news client (Gnus)...\n> > \n> > The cover letter lacks MIME-Version and Content-Type, hmm..\n> \n> Bug in git-format-patch? IIRC --cover-letter was added quite late, and\n> is quite a new option; some bugs might have been not ironed out yet.\nI hit this kind of problem already, too.\n\nMy problem was that format-patch only adds MIME-Version and\nContent-Type headers if the commit has non-ascii characters.  If I add a\nS-o-b only after the format-patch step I easily forget to add the needed\nheaders.  IMHO the right fix is to let send-email stop if there is no\nencoding related header in the mail but non-ascii characters.\n\nBest regards\nUwe\n"},{"id":"91192","messageId":"7vvdwq3b0l.fsf@gitster.siamese.dyndns.org","threadId":"15604","inReplyTo":"fcaeb9bf0809201033o1e9298a8ob135c68228b77218@mail.gmail.com","subject":"Re: [PATCH v2 00/14] Sparse checkout","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-09-20T18:52:42Z","receivedAt":"2008-09-20T18:52:42Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Nguyen Thai Ngoc Duy\" <pclouds@gmail.com> writes:\n\n> On 9/20/08, Jakub Narebski <jnareb@gmail.com> wrote:\n>>  >  - \"git clone --path\" => \"git clone --narrow-path\"\n>>  >  - \"git checkout --path\" => \"git checkout --reset-path\"\n>>\n>> I am not sure about that change, especially the fact that git-clone\n>>  and git-checkout use differently named options, because those options\n>>  affect clone only as they affect the checkout part of the clone.  One\n>>  would think that git-clone = git-init + git-remote add + git-fetch +\n>>  git-checkout, and that git-clone would simply pass sparse checkout\n>>  flags to git-checkout.\n>>\n>\n> Johannes sixt said --path was too generic so I changed the name. Hmm..\n> I did not think the same option name for git-checkout and git-clone\n> was important, rather worry about people may misunderstand that it is\n> \"narrow clone\" (do not fetch objects outside given paths for all\n> history). Maybe \"git clone --narrow-checkout\" would be better.\n\nBe it narrow or sparse, I would agree this round is better than too\ngeneric sounding --path.  Whatever that \"limited set of paths that are to\nappear in the working tree\" is called, it is a good idea to name options\nto clarify what effect each option causes on that concept X.  So perhaps:\n\n\t--reset-X\tresets the checkout set\n        --widen-X\twidens the checkout set\n        --narrow-X\tnarrows the checkout set\n\nis a good set of options to give \"checkout\".\n\nYou could argue that using \"--reset-X\" would be more consistent for clone,\nbut I think the \"--reset-\" part is redundant, because clone cannot\npossibly say \"add these\" or \"subtract those\".  I.e. it can only establish\nthe initial set (which is \"--reset-X\").  Which leads me to suggest that it\nwould not be such a good idea to use the same option name for clone and\ncheckout\n\nWith s/X/sparse/, above would give a set of options that does not sound\ntoo bad, I think.  It certainly is better than s/X/narrow/ which would\nhave a strong \"Huh?\" factor in \"--narrow-narrow\" one ;-)\n"},{"id":"91193","messageId":"fcaeb9bf0809201248w2850a243n50596dda3121f2c@mail.gmail.com","threadId":"15604","inReplyTo":"200809202001.28383.jnareb@gmail.com","subject":"Re: [PATCH v2 00/14] Sparse checkout","fromName":"Nguyen Thai Ngoc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2008-09-20T19:48:44Z","receivedAt":"2008-09-20T19:48:44Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On 9/21/08, Jakub Narebski <jnareb@gmail.com> wrote:\n>  > \"--reset-path\", I think, is a better name though. It would express the\n>  > relation compared to --add-path and --remove-path.\n>\n>\n> I don't like very much '--reset-path' option name, because it is not\n>  about 'reset' or 'resetting', but about limiting checkout to specified\n>  paths.  Unfortunately --include / --exclude looks like are for ignoring\n>  files, not marking files with \"no-checkout\" bit etc.\n>\n>  But I am not native English speaker.\n>\n>  Further proposals: --only (\"git checkout --only <pattern>\") with\n>  --checkout-only as counterpart in git-clone; --limit-to, --sparse.\n>\n>\n>  GNU tar uses --exclude and --exclude-file (with --no-recurse,\n>  --no-wildcards, --no-wildcards-match-slash). wget uses --accept\n>  and --reject for filename patterns, and --include / --exclude for\n>  directories.  Neither looks right for sparse checkout in Git.\n\nI think --exclude and --include are quite good. With Junio's\nsuggestion \"foo-X\", how about this?\n\ngit clone --sparse-checkout=<patterns> [1]\ngit checkout --set-sparse=<patterns>\ngit checkout --include-sparse=<patterns>\ngit checkout --exclude-sparse=<patterns> [2]\n\n[1] \"checkout\" is there to avoid being interpreted as \"sparse clone\"\n[2] --narrow-sparse IMO does not tell how the following patterns are\nused (is it the set that will be excluded or the target set?),\n\"exclude\" does better.\n\n>  >>  BTW I think that the same rules are used in gitattributes, aren't\n>  >>  they?\n>  >\n>  > They have different implementations. Though the rules may be the same.\n>\n>\n> Were you able to reuse either one?\n\nNo. .gitignore is tied to read_directory() while .gitattributes has\nattributes attached. So I rolled out another one for index.\n-- \nDuy\n"},{"id":"91199","messageId":"m3skrulbrd.fsf@localhost.localdomain","threadId":"15604","inReplyTo":"1221904913-25887-2-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH 01/14] Extend index to save more flags","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2008-09-20T21:59:20Z","receivedAt":"2008-09-20T21:59:20Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Comments below are just nitpicking. Feel free to diregard them...\n\nNguyễn Thái Ngọc Duy <pclouds@gmail.com> writes:\n\n> The on-disk format of index only saves 16 bit flags, nearly all have\n> been used. The last bit (CE_EXTENDED) is used to for future extension.\n> \n> This patch extends index entry format to save more flags in future.\n> The new entry format will be used when CE_EXTENDED bit is 1.\n> \n> Because older implementation may not understand CE_EXTENDED bit and\n> misread the new format, if there is any extended entry in index, index\n> header version will turn 3, which makes it incompatible for older git.\n> If there is none, header version will return to 2 again.\n> \n> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n\nIt would be nice if at least this part of series got accepted...\n\n> ---\n>  cache.h      |   58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++----\n>  read-cache.c |   51 +++++++++++++++++++++++++++++++++++++++++----------\n>  2 files changed, 95 insertions(+), 14 deletions(-)\n> \n> diff --git a/cache.h b/cache.h\n> index f4b8ddf..77b6eb3 100644\n> --- a/cache.h\n> +++ b/cache.h\n> @@ -109,6 +109,26 @@ struct ondisk_cache_entry {\n>  \tchar name[FLEX_ARRAY]; /* more */\n>  };\n>  \n> +/*\n> + * This struct is used when CE_EXTENDED bit is 1\n> + * The struct must match ondisk_cache_entry exactly from\n> + * ctime till flags\n> + */\n\nErrr... \"must match\"? Wouldn't \"does match\" be better?\nThis type is defined below, not is to be defined...\n\n> +struct ondisk_cache_entry_extended {\n> +\tstruct cache_time ctime;\n> +\tstruct cache_time mtime;\n> +\tunsigned int dev;\n> +\tunsigned int ino;\n> +\tunsigned int mode;\n> +\tunsigned int uid;\n> +\tunsigned int gid;\n> +\tunsigned int size;\n> +\tunsigned char sha1[20];\n> +\tunsigned short flags;\n> +\tunsigned short flags2;\n\nflags and flags2? Why not flags1 and flags2, or flags[2], or flags and\nflags_ext/flags_extended?\n\nJust nitpicking.\n\n> +\tchar name[FLEX_ARRAY]; /* more */\n> +};\n> +\n>  struct cache_entry {\n>  \tunsigned int ce_ctime;\n>  \tunsigned int ce_mtime;\n> @@ -130,7 +150,15 @@ struct cache_entry {\n>  #define CE_VALID     (0x8000)\n>  #define CE_STAGESHIFT 12\n>  \n> -/* In-memory only */\n> +/*\n> + * Range 0xFFFF0000 in ce_flags is divided into\n> + * two parts: in-memory flags and on-disk ones.\n> + * Flags in CE_EXTENDED_FLAGS will get saved on-disk\n\nSemicolon at the end of below text to separate, I think. Or at least\ncomma.\n\n> + * if you want to save a new flag, add it in\n> + * CE_EXTENDED_FLAGS\n\nNice comment.\n\n> + *\n> + * In-memory only flags\n> + */\n>  #define CE_UPDATE    (0x10000)\n>  #define CE_REMOVE    (0x20000)\n>  #define CE_UPTODATE  (0x40000)\n> @@ -140,6 +168,24 @@ struct cache_entry {\n>  #define CE_UNHASHED  (0x200000)\n>  \n>  /*\n> + * Extended on-disk flags\n> + */\n> +/* CE_EXTENDED2 is for future extension */\n> +#define CE_EXTENDED2 0x80000000\n\nPerhaps CE_RESERVED then?\n\n> +\n> +#define CE_EXTENDED_FLAGS (0)\n> +\n> +/*\n> + * Safeguard to avoid saving wrong flags:\n> + *  - CE_EXTENDED2 won't get saved until its semantic is known\n> + *  - Bits in 0x0000FFFF have been saved in ce_flags already\n> + *  - Bits in 0x003F0000 are currently in-memory flags\n> + */\n> +#if CE_EXTENDED_FLAGS & 0x80CFFFFF\n> +#error \"CE_EXTENDED_FLAGS out of range\"\n> +#endif\n\nI don't quite understand the above fragment (especially with the fact\nthat CE_EXTENDED_FLAGS is defined as (0))...\n\n> diff --git a/read-cache.c b/read-cache.c\n> index c5a8659..667c36b 100644\n> --- a/read-cache.c\n> +++ b/read-cache.c\n> @@ -1096,7 +1096,7 @@ static int verify_hdr(struct cache_header *hdr, unsigned long size)\n>  \n>  \tif (hdr->hdr_signature != htonl(CACHE_SIGNATURE))\n>  \t\treturn error(\"bad signature\");\n> -\tif (hdr->hdr_version != htonl(2))\n> +\tif (hdr->hdr_version != htonl(2) && hdr->hdr_version != htonl(3))\n>  \t\treturn error(\"bad index version\");\n\nBy the way: what was index version 1?\n\n[...]\n-- \nJakub Narebski\nPoland\nShadeHawk on #git\n"},{"id":"91200","messageId":"7vzlm21n83.fsf@gitster.siamese.dyndns.org","threadId":"15604","inReplyTo":"fcaeb9bf0809201248w2850a243n50596dda3121f2c@mail.gmail.com","subject":"Re: [PATCH v2 00/14] Sparse checkout","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-09-20T22:11:56Z","receivedAt":"2008-09-20T22:11:56Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Nguyen Thai Ngoc Duy\" <pclouds@gmail.com> writes:\n\n> On 9/21/08, Jakub Narebski <jnareb@gmail.com> wrote:\n> ...\n>>  >>  BTW I think that the same rules are used in gitattributes, aren't\n>>  >>  they?\n>>  >\n>>  > They have different implementations. Though the rules may be the same.\n>>\n>> Were you able to reuse either one?\n>\n> No. .gitignore is tied to read_directory() while .gitattributes has\n> attributes attached. So I rolled out another one for index.\n\nI am sorry, but that sounds like a rather lame excuse.  It certainly is\npossible to introduce an \"ignored\" attribute and have .gitattributes file\nspecify that, instead of having an entry in .gitignore file, if you teach\nread_directory() to pay attention to the attributes mechanism.  If we had\nfrom day one that a more generic gitattributes mechanism, I would imagine\nwe wouldn't even had a separate .gitignore codepath but used the attribute\nmechanism throughout the system.\n\nNow I do not think we are ever going to deprecate gitignore and move\neverybody to \"ignored\" attributes, because such a transition would not buy\nthe end users anything, but it technically is possible and would have been\nthe right thing to do, if we were building the system from scratch.  We\nstill could add it as an optional feature (i.e. if a path has the\nattribute that says \"ignored\" or \"not ignored\", then that determines the\nfate of the path, otherwise we look at gitignore).\n\nI wouldn't be surprised if an alternative implementation of your code to\nassign \"sparseness\" to each path internally used \"to-be-checked-out\"\nattribute, and used that attribute to control how ls-files filters its\noutput.\n\nA better excuse might have been that \"I am not reading these patterns from\nanywhere but command line\", but that got me thinking further.\n\nHow would that --narrow-match that is not stored anywhere on the\nfilesystem but used only for filtering the output be any more useful than\na grep that filters ls-files output in practice?\n\nI would imagine it would be much more useful if .git/info/attributes can\nspecify \"checkout\" attribute that is defined like this:\n\n        `checkout`\n        ^^^^^^^^^^\n\n        This attribute controls if the path can be left not checked-out to the\n        working tree.\n\n        Unset::\n                Unsetting the `checkout` marks the path not to be checked out.\n\n        Unspecified::\n                A path which does not have any `checkout` attribute specified is\n                handled in no special way.\n\n        Any value set to `checkout` is ignored, and git acts as if the\n        attribute is left unspecified.\n\nThen whenever a new path enters the index, you _could_ check with the\nattribute mechanism to set the CE_NOCHECKOUT flag.  Just like an already\ntracked path is not ignored even if it matches .gitignore pattern, a path\nwithout CE_NOCHECKOUT that is in the index is checked out even if it has\ncheckout attribute Unset.\n\nHmm?\n"},{"id":"91202","messageId":"7vvdwq1moh.fsf@gitster.siamese.dyndns.org","threadId":"15604","inReplyTo":"m3skrulbrd.fsf@localhost.localdomain","subject":"Re: [PATCH 01/14] Extend index to save more flags","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-09-20T22:23:42Z","receivedAt":"2008-09-20T22:23:42Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jakub Narebski <jnareb@gmail.com> writes:\n\n> By the way: what was index version 1?\n\nIt was the format used before ccc4feb (Convert the index file\nreading/writing to use network byte order., 2005-04-15)\n"},{"id":"91203","messageId":"7vr67e1mjw.fsf@gitster.siamese.dyndns.org","threadId":"15604","inReplyTo":"7vvdwq1moh.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH 01/14] Extend index to save more flags","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-09-20T22:26:27Z","receivedAt":"2008-09-20T22:26:27Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Jakub Narebski <jnareb@gmail.com> writes:\n>\n>> By the way: what was index version 1?\n>\n> It was the format used before ccc4feb (Convert the index file\n> reading/writing to use network byte order., 2005-04-15)\n\nSorry, I dug that wrong.  The right one is:\n\nca9be05 (Make the sha1 of the index file go at the very end of the file., 2005-04-20)\n"},{"id":"91212","messageId":"fcaeb9bf0809202134p2457e0cdn50ae8183ba07bcde@mail.gmail.com","threadId":"15604","inReplyTo":"m3skrulbrd.fsf@localhost.localdomain","subject":"Re: [PATCH 01/14] Extend index to save more flags","fromName":"Nguyen Thai Ngoc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2008-09-21T04:34:51Z","receivedAt":"2008-09-21T04:34:51Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On 9/21/08, Jakub Narebski <jnareb@gmail.com> wrote:\n>  > +\n>  > +#define CE_EXTENDED_FLAGS (0)\n>  > +\n>  > +/*\n>  > + * Safeguard to avoid saving wrong flags:\n>  > + *  - CE_EXTENDED2 won't get saved until its semantic is known\n>  > + *  - Bits in 0x0000FFFF have been saved in ce_flags already\n>  > + *  - Bits in 0x003F0000 are currently in-memory flags\n>  > + */\n>  > +#if CE_EXTENDED_FLAGS & 0x80CFFFFF\n>  > +#error \"CE_EXTENDED_FLAGS out of range\"\n>  > +#endif\n>\n>\n> I don't quite understand the above fragment (especially with the fact\n>  that CE_EXTENDED_FLAGS is defined as (0))...\n\nBecause this patch does not introduce any new on-disk flag yet so\nCE_EXTENDED_FLAGS remains 0. In the next patch, CE_EXTENDED_FLAGS will\nbe updated to have CE_NO_CHECKOUT.\n-- \nDuy\n"},{"id":"91216","messageId":"fcaeb9bf0809210311x7e9337fbmd978e95aa7998525@mail.gmail.com","threadId":"15604","inReplyTo":"7vzlm21n83.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH v2 00/14] Sparse checkout","fromName":"Nguyen Thai Ngoc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2008-09-21T10:11:52Z","receivedAt":"2008-09-21T10:11:52Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On 9/21/08, Junio C Hamano <gitster@pobox.com> wrote:\n> \"Nguyen Thai Ngoc Duy\" <pclouds@gmail.com> writes:\n>\n>  > On 9/21/08, Jakub Narebski <jnareb@gmail.com> wrote:\n>\n> > ...\n>\n> >>  >>  BTW I think that the same rules are used in gitattributes, aren't\n>  >>  >>  they?\n>  >>  >\n>  >>  > They have different implementations. Though the rules may be the same.\n>  >>\n>  >> Were you able to reuse either one?\n>  >\n>  > No. .gitignore is tied to read_directory() while .gitattributes has\n>  > attributes attached. So I rolled out another one for index.\n>\n>\n> I am sorry, but that sounds like a rather lame excuse.  It certainly is\n>  possible to introduce an \"ignored\" attribute and have .gitattributes file\n>  specify that, instead of having an entry in .gitignore file, if you teach\n>  read_directory() to pay attention to the attributes mechanism.  If we had\n>  from day one that a more generic gitattributes mechanism, I would imagine\n>  we wouldn't even had a separate .gitignore codepath but used the attribute\n>  mechanism throughout the system.\n>\n>  Now I do not think we are ever going to deprecate gitignore and move\n>  everybody to \"ignored\" attributes, because such a transition would not buy\n>  the end users anything, but it technically is possible and would have been\n>  the right thing to do, if we were building the system from scratch.  We\n>  still could add it as an optional feature (i.e. if a path has the\n>  attribute that says \"ignored\" or \"not ignored\", then that determines the\n>  fate of the path, otherwise we look at gitignore).\n>\n>  I wouldn't be surprised if an alternative implementation of your code to\n>  assign \"sparseness\" to each path internally used \"to-be-checked-out\"\n>  attribute, and used that attribute to control how ls-files filters its\n>  output.\n>\n>  A better excuse might have been that \"I am not reading these patterns from\n>  anywhere but command line\", but that got me thinking further.\n\nThat \"from command line\" piece makes a bit of difference. For example\npatterns separated by colons and backslash escape, but that does not\nstop it from reusing attr.c.\n\n>  How would that --narrow-match that is not stored anywhere on the\n>  filesystem but used only for filtering the output be any more useful than\n>  a grep that filters ls-files output in practice?\n\nWell, it works exactly like 'grep' internally.\n\n>  I would imagine it would be much more useful if .git/info/attributes can\n>  specify \"checkout\" attribute that is defined like this:\n>\n>         `checkout`\n>         ^^^^^^^^^^\n>\n>         This attribute controls if the path can be left not checked-out to the\n>         working tree.\n>\n>         Unset::\n>                 Unsetting the `checkout` marks the path not to be checked out.\n>\n>         Unspecified::\n>                 A path which does not have any `checkout` attribute specified is\n>                 handled in no special way.\n>\n>         Any value set to `checkout` is ignored, and git acts as if the\n>         attribute is left unspecified.\n>\n>  Then whenever a new path enters the index, you _could_ check with the\n>  attribute mechanism to set the CE_NOCHECKOUT flag.  Just like an already\n>  tracked path is not ignored even if it matches .gitignore pattern, a path\n>  without CE_NOCHECKOUT that is in the index is checked out even if it has\n>  checkout attribute Unset.\n>\n>  Hmm?\n\nWell I think people would want to save no-checkout rules eventually.\nBut I don't know how they want to use it. Will the saved rules be hard\nrestriction, that no files can be checked out outside defined areas?\nWill it be to save a couple of keystrokes,   that is, instead of\ntyping \"--reset-sparse=blah\" all the time, now just \"--reset-sparse\"\nand default rules will be applied? Your suggestion would be the third,\napplying on new files only.\n\nAnyway I will try to extend attr.c a bit to take input from command\nline, then move \"sparse patterns\" over to use attr.c.\n-- \nDuy\n"},{"id":"91218","messageId":"200809211249.10016.jnareb@gmail.com","threadId":"15604","inReplyTo":"fcaeb9bf0809210311x7e9337fbmd978e95aa7998525@mail.gmail.com","subject":"Re: [PATCH v2 00/14] Sparse checkout","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2008-09-21T10:49:08Z","receivedAt":"2008-09-21T10:49:08Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"On Sun, 21 Sep 2008, Nguyen Thai Ngoc Duy wrote:\n> On 9/21/08, Junio C Hamano <gitster@pobox.com> wrote:\n\n> >  How would that --narrow-match that is not stored anywhere on the\n> >  filesystem but used only for filtering the output be any more useful than\n> >  a grep that filters ls-files output in practice?\n> \n> Well, it works exactly like 'grep' internally.\n> \n> >  I would imagine it would be much more useful if .git/info/attributes can\n> >  specify \"checkout\" attribute that is defined like this:\n> >\n> >         `checkout`\n> >         ^^^^^^^^^^\n[...]\n\n> >  Then whenever a new path enters the index, you _could_ check with the\n> >  attribute mechanism to set the CE_NOCHECKOUT flag.  Just like an already\n> >  tracked path is not ignored even if it matches .gitignore pattern, a path\n> >  without CE_NOCHECKOUT that is in the index is checked out even if it has\n> >  checkout attribute Unset.\n> >\n> >  Hmm?\n> \n> Well I think people would want to save no-checkout rules eventually.\n> But I don't know how they want to use it. Will the saved rules be hard\n> restriction, that no files can be checked out outside defined areas?\n> Will it be to save a couple of keystrokes,   that is, instead of\n> typing \"--reset-sparse=blah\" all the time, now just \"--reset-sparse\"\n> and default rules will be applied? Your suggestion would be the third,\n> applying on new files only.\n> \n> Anyway I will try to extend attr.c a bit to take input from command\n> line, then move \"sparse patterns\" over to use attr.c.\n\nFirst, I think that this was Junio asking for discussion more than\nfor changing the design.\n\nSecond, while unifying the \"check the match\" part of gitignore,\ngitattribute and sparse checkout would be IMVHO a good idea, I'm\nnot sure if trying to use/reuse attr.c literally would be a good\nidea, at least not without larger surgery.  AFAIK, IIUC gitattributes\nhave some limitations, one of which that they are read from working\narea (and there is no API for reading from tree); although this could\nbe enough for `checkout' attribute, which is not that different in\nwork from `smudge' attribute, or `crlf` attribute.\n\n-- \nJakub Narebski\nPoland\n"},{"id":"91222","messageId":"fcaeb9bf0809210432x500cf586k877d07b335bf33de@mail.gmail.com","threadId":"15604","inReplyTo":"200809211249.10016.jnareb@gmail.com","subject":"Re: [PATCH v2 00/14] Sparse checkout","fromName":"Nguyen Thai Ngoc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2008-09-21T11:32:56Z","receivedAt":"2008-09-21T11:32:56Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On 9/21/08, Jakub Narebski <jnareb@gmail.com> wrote:\n> On Sun, 21 Sep 2008, Nguyen Thai Ngoc Duy wrote:\n>  > On 9/21/08, Junio C Hamano <gitster@pobox.com> wrote:\n>\n>\n> > >  How would that --narrow-match that is not stored anywhere on the\n>  > >  filesystem but used only for filtering the output be any more useful than\n>  > >  a grep that filters ls-files output in practice?\n>  >\n>  > Well, it works exactly like 'grep' internally.\n>  >\n>  > >  I would imagine it would be much more useful if .git/info/attributes can\n>  > >  specify \"checkout\" attribute that is defined like this:\n>  > >\n>  > >         `checkout`\n>  > >         ^^^^^^^^^^\n>\n> [...]\n>\n>\n>  > >  Then whenever a new path enters the index, you _could_ check with the\n>  > >  attribute mechanism to set the CE_NOCHECKOUT flag.  Just like an already\n>  > >  tracked path is not ignored even if it matches .gitignore pattern, a path\n>  > >  without CE_NOCHECKOUT that is in the index is checked out even if it has\n>  > >  checkout attribute Unset.\n>  > >\n>  > >  Hmm?\n>  >\n>  > Well I think people would want to save no-checkout rules eventually.\n>  > But I don't know how they want to use it. Will the saved rules be hard\n>  > restriction, that no files can be checked out outside defined areas?\n>  > Will it be to save a couple of keystrokes,   that is, instead of\n>  > typing \"--reset-sparse=blah\" all the time, now just \"--reset-sparse\"\n>  > and default rules will be applied? Your suggestion would be the third,\n>  > applying on new files only.\n>  >\n>  > Anyway I will try to extend attr.c a bit to take input from command\n>  > line, then move \"sparse patterns\" over to use attr.c.\n>\n>\n> First, I think that this was Junio asking for discussion more than\n>  for changing the design.\n\nI just tried to see if it was feasible. Checking the source again, I\nmisunderstood  gitattributes/gitingore's leading '/' notion (in a good\nway). Leading '/' means './' and that would be fine for\n.git{attributes,ignore}. In sparse patterns, leading '/' means\ntoplevel directory because you may want to checkout some more from a\nsubdirectory without moving up to toplevel directory. Now\n.git{ignore,attributes} and sparse patterns are incompatible, gaah...\n\n>  Second, while unifying the \"check the match\" part of gitignore,\n>  gitattribute and sparse checkout would be IMVHO a good idea, I'm\n\nIt is surely good. Optimization like 68492fc (Speedup scanning for\nexcluded files.) could be applied to .gitattributes too. Now I know\nwhy I was confused when reading the matching part of\n.git{attributes,ignore}.\n-- \nDuy\n"},{"id":"91271","messageId":"200809220014.17970.jnareb@gmail.com","threadId":"15604","inReplyTo":"fcaeb9bf0809210432x500cf586k877d07b335bf33de@mail.gmail.com","subject":"Re: [PATCH v2 00/14] Sparse checkout","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2008-09-21T22:14:15Z","receivedAt":"2008-09-21T22:14:15Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"On Sun, 21 Sep 2008, Nguyen Thai Ngoc Duy wrote:\n> On 9/21/08, Jakub Narebski <jnareb@gmail.com> wrote:\n>> On Sun, 21 Sep 2008, Nguyen Thai Ngoc Duy wrote:\n>>> On 9/21/08, Junio C Hamano <gitster@pobox.com> wrote:\n\n> [...] Checking the source again, I\n> misunderstood  gitattributes/gitingore's leading '/' notion (in a good\n> way). Leading '/' means './' and that would be fine for\n> .git{attributes,ignore}. \n\nBy the way it would be nice if gitignore accepted './' as equivalent\nto current '/', as this is something I think (from questions here\nand on #git) that people expect to work (not reading documentation\ncarefully enough).  This is something that for example `ls' would use,\nor something that `find' returns.\n\n> In sparse patterns, leading '/' means toplevel directory because you\n> may want to checkout some more from a subdirectory without moving up\n> to toplevel directory. Now .git{ignore,attributes} and sparse patterns\n> are incompatible, gaah... \n\nWell, this doesn't make sense in a _file_, but makes perfect sense when\ninvoked from _command line_, as option argument.\n\nBut I was thinking more about centralizing pattern matching wrt either\nfull pathname (with prefix stripped, or not), or basename of a file.\nIf match check is centralized, then if you enhance pattern language (for\nselecting which files to mark no-checkout in sparse checkout for example\nby allowing '**' which matches also '/' (if you don't go route of 'tar'\nwith '--wildcards-match-slash' option)), then it would enhance gitignore\npatterns and gitattributes patterns too (well, excluding the fact that\nthey are delimited differently).\n \n>>  Second, while unifying the \"check the match\" part of gitignore,\n>>  gitattribute and sparse checkout would be IMVHO a good idea, [...]\n> \n> It is surely good. Optimization like 68492fc (Speedup scanning for\n> excluded files.) could be applied to .gitattributes too. Now I know\n> why I was confused when reading the matching part of\n> .git{attributes,ignore}.\n\nAnd all speedups (well, perhaps not all) would apply to all classes\nof matching against patterns as well.\n-- \nJakub Narebski\nPoland\n"},{"id":"91273","messageId":"200809220021.11820.jnareb@gmail.com","threadId":"15604","inReplyTo":"fcaeb9bf0809202134p2457e0cdn50ae8183ba07bcde@mail.gmail.com","subject":"Re: [PATCH 01/14] Extend index to save more flags","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2008-09-21T22:21:11Z","receivedAt":"2008-09-21T22:21:11Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"On Sun, 21 Sep 2008, Nguyen Thai Ngoc Duy wrote:\n> On 9/21/08, Jakub Narebski <jnareb@gmail.com> wrote:\n> > > +\n> > > +#define CE_EXTENDED_FLAGS (0)\n> > > +\n> > > +/*\n> > > + * Safeguard to avoid saving wrong flags:\n> > > + *  - CE_EXTENDED2 won't get saved until its semantic is known\n> > > + *  - Bits in 0x0000FFFF have been saved in ce_flags already\n> > > + *  - Bits in 0x003F0000 are currently in-memory flags\n> > > + */\n> > > +#if CE_EXTENDED_FLAGS & 0x80CFFFFF\n> > > +#error \"CE_EXTENDED_FLAGS out of range\"\n> > > +#endif\n> >\n> >\n> > I don't quite understand the above fragment (especially with the fact\n> >  that CE_EXTENDED_FLAGS is defined as (0))...\n> \n> Because this patch does not introduce any new on-disk flag yet so\n> CE_EXTENDED_FLAGS remains 0. In the next patch, CE_EXTENDED_FLAGS will\n> be updated to have CE_NO_CHECKOUT.\n\nWell, now I understand CE_EXTENDED_FLAGS being (0).\n\nWhat I still don't understand the pattern it is protected against.  \nAs I understand it if CE_EXTENDED_FLAGS & 0x0000FFFF it is bad,\nbecause ce_flags saved flags are not extended flags, and \nCE_EXTENDED_FLAGS & 0x003F0000 are in-memory flags.  But why\nCE_EXTENDED_FLAGS & 0x80C00000 is bad, and why (if I understand it)\nCE_EXTENDED_FLAGS & 0x00300000 is not bad.\n\n-- \nJakub Narebski\nPoland\n"},{"id":"91375","messageId":"adf1fd3d0809230406r598f6d1l41cd860568de761f@mail.gmail.com","threadId":"15604","inReplyTo":"fcaeb9bf0809210311x7e9337fbmd978e95aa7998525@mail.gmail.com","subject":"Re: [PATCH v2 00/14] Sparse checkout","fromName":"Santi Béjar","fromEmail":"santi@agolina.net","sentAt":"2008-09-23T11:06:47Z","receivedAt":"2008-09-23T11:06:47Z","isPatch":true,"sender":{"key":"santi@agolina.net","avatar":null},"body":"On Sun, Sep 21, 2008 at 12:11 PM, Nguyen Thai Ngoc Duy\n<pclouds@gmail.com> wrote:\n> On 9/21/08, Junio C Hamano <gitster@pobox.com> wrote:\n>> \"Nguyen Thai Ngoc Duy\" <pclouds@gmail.com> writes:\n>>\n>>  > On 9/21/08, Jakub Narebski <jnareb@gmail.com> wrote:\n>>\n>> > ...\n>>\n>> >>  >>  BTW I think that the same rules are used in gitattributes, aren't\n>>  >>  >>  they?\n>>  >>  >\n>>  >>  > They have different implementations. Though the rules may be the same.\n>>  >>\n>>  >> Were you able to reuse either one?\n>>  >\n>>  > No. .gitignore is tied to read_directory() while .gitattributes has\n>>  > attributes attached. So I rolled out another one for index.\n>>\n>>\n>> I am sorry, but that sounds like a rather lame excuse.  It certainly is\n>>  possible to introduce an \"ignored\" attribute and have .gitattributes file\n>>  specify that, instead of having an entry in .gitignore file, if you teach\n>>  read_directory() to pay attention to the attributes mechanism.  If we had\n>>  from day one that a more generic gitattributes mechanism, I would imagine\n>>  we wouldn't even had a separate .gitignore codepath but used the attribute\n>>  mechanism throughout the system.\n>>\n>>  Now I do not think we are ever going to deprecate gitignore and move\n>>  everybody to \"ignored\" attributes, because such a transition would not buy\n>>  the end users anything, but it technically is possible and would have been\n>>  the right thing to do, if we were building the system from scratch.  We\n>>  still could add it as an optional feature (i.e. if a path has the\n>>  attribute that says \"ignored\" or \"not ignored\", then that determines the\n>>  fate of the path, otherwise we look at gitignore).\n>>\n>>  I wouldn't be surprised if an alternative implementation of your code to\n>>  assign \"sparseness\" to each path internally used \"to-be-checked-out\"\n>>  attribute, and used that attribute to control how ls-files filters its\n>>  output.\n>>\n>>  A better excuse might have been that \"I am not reading these patterns from\n>>  anywhere but command line\", but that got me thinking further.\n>\n> That \"from command line\" piece makes a bit of difference. For example\n> patterns separated by colons and backslash escape, but that does not\n> stop it from reusing attr.c.\n>\n>>  How would that --narrow-match that is not stored anywhere on the\n>>  filesystem but used only for filtering the output be any more useful than\n>>  a grep that filters ls-files output in practice?\n>\n> Well, it works exactly like 'grep' internally.\n>\n>>  I would imagine it would be much more useful if .git/info/attributes can\n>>  specify \"checkout\" attribute that is defined like this:\n>>\n>>         `checkout`\n>>         ^^^^^^^^^^\n>>\n>>         This attribute controls if the path can be left not checked-out to the\n>>         working tree.\n>>\n>>         Unset::\n>>                 Unsetting the `checkout` marks the path not to be checked out.\n>>\n>>         Unspecified::\n>>                 A path which does not have any `checkout` attribute specified is\n>>                 handled in no special way.\n>>\n>>         Any value set to `checkout` is ignored, and git acts as if the\n>>         attribute is left unspecified.\n>>\n>>  Then whenever a new path enters the index, you _could_ check with the\n>>  attribute mechanism to set the CE_NOCHECKOUT flag.  Just like an already\n>>  tracked path is not ignored even if it matches .gitignore pattern, a path\n>>  without CE_NOCHECKOUT that is in the index is checked out even if it has\n>>  checkout attribute Unset.\n>>\n>>  Hmm?\n>\n> Well I think people would want to save no-checkout rules eventually.\n> But I don't know how they want to use it. Will the saved rules be hard\n> restriction, that no files can be checked out outside defined areas?\n> Will it be to save a couple of keystrokes,   that is, instead of\n> typing \"--reset-sparse=blah\" all the time, now just \"--reset-sparse\"\n> and default rules will be applied? Your suggestion would be the third,\n> applying on new files only.\n>\n> Anyway I will try to extend attr.c a bit to take input from command\n> line, then move \"sparse patterns\" over to use attr.c.\n\n\nWhile I agree that the checkout attr looks like an attribute (so\nreusing attr.c is a good idea) and $GIT_DIR/info/gitattributes seems a\ngood place to specify them, I think it will be better in the config\n$GIT_DIR/config. There it is clear that it is a local thing and you\nhave \"git config\" to read and write them. Additionally you could have\ndifferent patterns in the config (sparse.default, sparse.doc,\nsparse.src,...), although maybe it is not very useful.\n\nI think the main UI to sparse checkout should be a default sparse\npattern that is used for \"all\" commands, like merge, reset, and\ncheckout. Now it is too easy to escape from the sparse checkout, when\nyou merge or checkout a branch with new files, when doing a \"git reset\n--hard\" (when you abort a failed merge), or when doing a diff\n(specially when you pull).\n\nSanti\n"},{"id":"91382","messageId":"20080923115655.GA7140@laptop","threadId":"15604","inReplyTo":"adf1fd3d0809230406r598f6d1l41cd860568de761f@mail.gmail.com","subject":"Re: [PATCH v2 00/14] Sparse checkout","fromName":"Nguyen Thai Ngoc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2008-09-23T11:56:56Z","receivedAt":"2008-09-23T11:56:56Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Tue, Sep 23, 2008 at 01:06:47PM +0200, =?ISO-8859-1?Q?Santi_B=E9jar_ wrote:\n> While I agree that the checkout attr looks like an attribute (so\n> reusing attr.c is a good idea) and $GIT_DIR/info/gitattributes seems a\n> good place to specify them, I think it will be better in the config\n> $GIT_DIR/config. There it is clear that it is a local thing and you\n> have \"git config\" to read and write them. Additionally you could have\n> different patterns in the config (sparse.default, sparse.doc,\n> sparse.src,...), although maybe it is not very useful.\n> \n> I think the main UI to sparse checkout should be a default sparse\n> pattern that is used for \"all\" commands, like merge, reset, and\n> checkout. Now it is too easy to escape from the sparse checkout, when\n> you merge or checkout a branch with new files, when doing a \"git reset\n> --hard\" (when you abort a failed merge), or when doing a diff\n> (specially when you pull).\n\nIt should not escape that easy (except newly added files). There is a\nbug in my apply_narrow_spec() that effectively disables sparse\ncheckkout for other unpack_trees() calls except checkout/clone. Try\nthe below patch.\n\ndiff --git a/unpack-trees.c b/unpack-trees.c\nindex 10f377c..5bbe016 100644\n--- a/unpack-trees.c\n+++ b/unpack-trees.c\n@@ -146,8 +146,10 @@ static int apply_narrow_spec(struct unpack_trees_options *o)\n \tstruct index_state *index = &o->result;\n \tint i;\n \n+\t/*\n \tif (!(o->new_narrow_path | o->add_narrow_path | o->remove_narrow_path))\n \t\treturn 0;\n+\t*/\n \n \tfor (i = 0; i < index->cache_nr; i++) {\n \t\tstruct cache_entry *ce = index->cache[i];\n-- \nDuy\n"},{"id":"91383","messageId":"adf1fd3d0809230457u200f4331n849b302eabe4f960@mail.gmail.com","threadId":"15604","inReplyTo":"1221904913-25887-1-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH v2 00/14] Sparse checkout","fromName":"Santi Béjar","fromEmail":"santi@agolina.net","sentAt":"2008-09-23T11:57:12Z","receivedAt":"2008-09-23T11:57:12Z","isPatch":true,"sender":{"key":"santi@agolina.net","avatar":null},"body":"Hi,\n\n  Just some comments.\n\n  When you exclude the .gitignore file all the ignored files are\nreported as \"Untracked files\". I.e, as in:\n\n$git clone $git_url\n$ cd git\n$ make\n$ git checkout --reset-path=Documentation/\n$ git status\n\n  When you have local changes it says that it cannot switch branches\n\n$ git checkout --reset-path=Documentation/\nerror: You have local changes to 'Makefile'; cannot switch branches.\n\n$ git checkout -h\n...\n    --reset-path <prefixes>\n                          reset to new sparse checkout\n    --add-path <prefixes>\n                          widen checkout area\n    --remove-path <prefixes>\n                          narrow checkout area\n\ns/prefixes/sparse patterns/\n\nBest regards,\n\nSanti\n"},{"id":"91703","messageId":"fcaeb9bf0809260900g4011411fkff1d61029c362e75@mail.gmail.com","threadId":"15604","inReplyTo":"adf1fd3d0809230406r598f6d1l41cd860568de761f@mail.gmail.com","subject":"Re: [PATCH v2 00/14] Sparse checkout","fromName":"Nguyen Thai Ngoc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2008-09-26T16:00:02Z","receivedAt":"2008-09-26T16:00:02Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On 9/23/08, Santi Béjar <santi@agolina.net> wrote:\n> While I agree that the checkout attr looks like an attribute (so\n>  reusing attr.c is a good idea) and $GIT_DIR/info/gitattributes seems a\n>  good place to specify them, I think it will be better in the config\n>  $GIT_DIR/config. There it is clear that it is a local thing and you\n>  have \"git config\" to read and write them. Additionally you could have\n>  different patterns in the config (sparse.default, sparse.doc,\n>  sparse.src,...), although maybe it is not very useful.\n>\n>  I think the main UI to sparse checkout should be a default sparse\n>  pattern that is used for \"all\" commands, like merge, reset, and\n>  checkout. Now it is too easy to escape from the sparse checkout, when\n>  you merge or checkout a branch with new files, when doing a \"git reset\n>  --hard\" (when you abort a failed merge), or when doing a diff\n>  (specially when you pull).\n\nI have made a patch to save default sparse patterns, something to play\nwith so we can have better idea how to do it properly.\n\nThere is another option --default-sparse in \"git clone\" and \"git\ncheckout\". The option can be used to save default sparse patterns\n(specified by --sparse-checkout in \"git clone\" or --reset-sparse in\n\"git checkout\"). Something like this:\n\ngit clone --default-sparse --sparse-checkout=Documentation/ git.git\ngit checkout --default-sparse --reset-sparse=t/\n\nDefault sparse patterns will be used for other unpack_trees()-related\ncommands like reset, read-tree, merge, pull... For \"git checkout\" it\nwill only be used when neither --full, --reset-sparse,\n--include-sparse nor --exclude-sparse is present. And it only applies\nto newly-added files.\n\nPatch series is in http://repo.or.cz/w/git/pclouds.git (branch\nsparse-checkout). Note that it also incorporates fixes and some option\nrenames.\n-- \nDuy\n"}]}