{"thread":{"id":"15521","subject":"[PATCH 00/16] Narrow/Partial/Sparse checkout","startedAt":"2008-09-14T13:07:49Z","lastAt":"2008-09-16T17:00:50Z","messageCount":35,"participants":["Nguyễn Thái Ngọc Duy","Jakub Narebski","Junio C Hamano","Baz","Johannes Sixt","Nguyen Thai Ngoc Duy"],"isPatch":true,"patchVersion":1,"patchTotal":16},"messages":[{"id":"90658","messageId":"1221397685-27715-1-git-send-email-pclouds@gmail.com","threadId":"15521","inReplyTo":null,"subject":"[PATCH 00/16] Narrow/Partial/Sparse checkout","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2008-09-14T13:07:49Z","receivedAt":"2008-09-14T13:07:49Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"I hope this series is now ready to be reviewed. Documentation is in\nplace so no more explanation here (main document is in git-checkout.txt).\nThe series could be splitted into:\n\nNguyá»n ThÃ¡i Ngá»c Duy (6):\n  Extend index to save more flags\n  Introduce CE_NO_CHECKOUT bit\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 --narrow-checkout option to \"will checkout\" entries\n  Add tests for updating no-checkout entries in index\n\n .gitignore                         |    1 +\n Documentation/git-ls-files.txt     |    6 +++\n Documentation/git-update-index.txt |   12 ++++++\n Makefile                           |    2 +-\n builtin-ls-files.c                 |   11 ++++++\n builtin-update-index.c             |   40 +++++++++++++--------\n cache.h                            |   66 +++++++++++++++++++++++++++++++++--\n read-cache.c                       |   57 ++++++++++++++++++++++++-------\n t/t2104-update-index-narrow.sh     |   36 +++++++++++++++++++\n test-index-version.c               |   14 ++++++++\n 10 files changed, 212 insertions(+), 33 deletions(-)\n\nThis adds CE_NO_CHECKOUT bit and plumbing support to manipulate it.\nThis bit is to mark what entry will be checked out.\n\nNguyá»n ThÃ¡i Ngá»c Duy (4):\n  Prevent diff machinery from examining worktree outside narrow checkout\n  checkout_entry(): CE_NO_CHECKOUT on checked out entries.\n  ls-files: apply --deleted on narrow area only\n  grep: skip files that have not been checked out\n\n builtin-grep.c                 |    7 ++++++-\n builtin-ls-files.c             |    2 +-\n diff-lib.c                     |    5 +++--\n diff.c                         |    4 +++-\n entry.c                        |    1 +\n t/t2104-update-index-narrow.sh |    6 ++++++\n 6 files changed, 20 insertions(+), 5 deletions(-)\n\nVarious fixes to make sure it works once in this mode.\n\nNguyá»n ThÃ¡i Ngá»c Duy (5):\n  unpack_trees(): add support for narrow checkout\n  narrow spec: put '+' before a spec will change semantic of '*'\n  ls-files: add --narrow-match=spec option for testing narrow matching\n  clone: support narrow checkout with --path option\n  checkout: add new options to support narrow checkout\n\n Documentation/git-checkout.txt   |   68 ++++++++++++++++++++++++-\n Documentation/git-clone.txt      |    8 +++-\n Documentation/git-ls-files.txt   |    7 ++-\n builtin-checkout.c               |   44 ++++++++++++++++\n builtin-clone.c                  |   13 +++++\n builtin-ls-files.c               |   14 +++++-\n cache.h                          |    3 +\n t/t2011-checkout-narrow.sh       |   80 +++++++++++++++++++++++++++++\n t/t3003-ls-files-narrow-match.sh |   45 ++++++++++++++++\n t/t5703-clone-narrow.sh          |   39 ++++++++++++++\n unpack-trees.c                   |  105 ++++++++++++++++++++++++++++++++++++++\n unpack-trees.h                   |    6 ++\n 12 files changed, 427 insertions(+), 5 deletions(-)\n\nSupport for \"git checkout\" and \"git clone\" to enter/update/leave\nnarrow/sparse/partial checkout.\n\nNguyá»n ThÃ¡i Ngá»c Duy (1):\n  ls-files: add --overlay option\n\n Documentation/git-ls-files.txt |    4 ++++\n builtin-ls-files.c             |   16 +++++++++++++---\n t/t2104-update-index-narrow.sh |    4 ++++\n 3 files changed, 21 insertions(+), 3 deletions(-)\n\nBonus stuff, not strictly needed.\n"},{"id":"90659","messageId":"1221397685-27715-2-git-send-email-pclouds@gmail.com","threadId":"15521","inReplyTo":"1221397685-27715-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 01/16] Extend index to save more flags","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2008-09-14T13:07:50Z","receivedAt":"2008-09-14T13:07:50Z","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 f725783..1e572e4 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":"90660","messageId":"1221397685-27715-3-git-send-email-pclouds@gmail.com","threadId":"15521","inReplyTo":"1221397685-27715-2-git-send-email-pclouds@gmail.com","subject":"[PATCH 02/16] Introduce CE_NO_CHECKOUT bit","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2008-09-14T13:07:51Z","receivedAt":"2008-09-14T13:07:51Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This bit is the basis of narrow checkout. If this bit is on, the entry\nis outside narrow 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 cache.h      |   10 +++++++++-\n read-cache.c |    6 +++---\n 2 files changed, 12 insertions(+), 4 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex 1e572e4..2b2c90f 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":"90661","messageId":"1221397685-27715-4-git-send-email-pclouds@gmail.com","threadId":"15521","inReplyTo":"1221397685-27715-3-git-send-email-pclouds@gmail.com","subject":"[PATCH 03/16] 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-14T13:07:52Z","receivedAt":"2008-09-14T13:07:52Z","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 ce83224..f63a34e 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":"90662","messageId":"1221397685-27715-5-git-send-email-pclouds@gmail.com","threadId":"15521","inReplyTo":"1221397685-27715-4-git-send-email-pclouds@gmail.com","subject":"[PATCH 04/16] 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-14T13:07:53Z","receivedAt":"2008-09-14T13:07: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 Documentation/git-update-index.txt |   12 ++++++++++++\n builtin-update-index.c             |   16 +++++++++++++++-\n 2 files changed, 27 insertions(+), 1 deletions(-)\n\ndiff --git a/Documentation/git-update-index.txt b/Documentation/git-update-index.txt\nindex 1d9d81a..707c33f 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@@ -88,6 +89,17 @@ OPTIONS\n \tsometimes helpful when working with a big project on a\n \tfilesystem that has very slow lstat(2) system call\n \t(e.g. cifs).\n+--checkout::\n+--no-checkout::\n+\tWhen these flags are 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 narrow 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+\tnarrow checkout.\n +\n This option can be also used as a coarse file-level mechanism\n to ignore uncommitted changes in tracked files (akin to what\ndiff --git a/builtin-update-index.c b/builtin-update-index.c\nindex f63a34e..6ed883d 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;\n-- \n1.6.0.96.g2fad1.dirty\n"},{"id":"90663","messageId":"1221397685-27715-6-git-send-email-pclouds@gmail.com","threadId":"15521","inReplyTo":"1221397685-27715-5-git-send-email-pclouds@gmail.com","subject":"[PATCH 05/16] ls-files: add --narrow-checkout option to \"will checkout\" entries","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2008-09-14T13:07:54Z","receivedAt":"2008-09-14T13:07:54Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Even in narrow checkout mode, \"git ls-files --cached\" (and --stage)\nwill show all entries in index. When those options are used together\nwith --narrow-checkout, no-checkout entries will be skipped.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Documentation/git-ls-files.txt |    6 ++++++\n builtin-ls-files.c             |   11 +++++++++++\n 2 files changed, 17 insertions(+), 0 deletions(-)\n\ndiff --git a/Documentation/git-ls-files.txt b/Documentation/git-ls-files.txt\nindex 9f85d60..f74b212 100644\n--- a/Documentation/git-ls-files.txt\n+++ b/Documentation/git-ls-files.txt\n@@ -12,6 +12,7 @@ SYNOPSIS\n 'git ls-files' [-z] [-t] [-v]\n \t\t(--[cached|deleted|others|ignored|stage|unmerged|killed|modified])\\*\n \t\t(-[c|d|o|i|s|u|k|m])\\*\n+\t\t[--narrow-checkout]\n \t\t[-x <pattern>|--exclude=<pattern>]\n \t\t[-X <file>|--exclude-from=<file>]\n \t\t[--exclude-per-directory=<file>]\n@@ -72,6 +73,11 @@ OPTIONS\n \tto file/directory conflicts for checkout-index to\n \tsucceed.\n \n+--narrow-checkout::\n+\tWhen narrow checkout is being used, this option together with other\n+\tindex-based selection options like --cached or --stage, only narrowed\n+\tportion will be printed out.\n+\n -z::\n \t\\0 line termination on output.\n \ndiff --git a/builtin-ls-files.c b/builtin-ls-files.c\nindex 068f424..456d41c 100644\n--- a/builtin-ls-files.c\n+++ b/builtin-ls-files.c\n@@ -20,6 +20,7 @@ static int show_unmerged;\n static int show_modified;\n static int show_killed;\n static int show_valid_bit;\n+static int narrow_checkout;\n static int line_terminator = '\\n';\n \n static int prefix_len;\n@@ -245,6 +246,8 @@ static void show_files(struct dir_struct *dir, const char *prefix)\n \t\t\t\tcontinue;\n \t\t\tif (ce->ce_flags & CE_UPDATE)\n \t\t\t\tcontinue;\n+\t\t\tif (narrow_checkout && ce_no_checkout(ce))\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@@ -424,6 +427,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])* \"\n+\t\"[ --narrow-checkout ] \"\n \t\"[ --ignored ] [--exclude=<pattern>] [--exclude-from=<file>] \"\n \t\"[ --exclude-per-directory=<filename> ] [--exclude-standard] \"\n \t\"[--full-name] [--abbrev] [--] [<file>]*\";\n@@ -465,6 +469,10 @@ 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, \"--narrow-checkout\")) {\n+\t\t\tnarrow_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@@ -596,6 +604,9 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)\n \t      show_killed | show_modified))\n \t\tshow_cached = 1;\n \n+\tif (narrow_checkout && !show_cached && !show_stage)\n+\t\tdie(\"ls-files: --narrow-checkout can only be used with either --cached or --stage\");\n+\n \tread_cache();\n \tif (prefix)\n \t\tprune_cache(prefix);\n-- \n1.6.0.96.g2fad1.dirty\n"},{"id":"90664","messageId":"1221397685-27715-7-git-send-email-pclouds@gmail.com","threadId":"15521","inReplyTo":"1221397685-27715-6-git-send-email-pclouds@gmail.com","subject":"[PATCH 06/16] Add tests for updating no-checkout entries in index","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2008-09-14T13:07:55Z","receivedAt":"2008-09-14T13:07:55Z","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 Makefile                       |    2 +-\n t/t2104-update-index-narrow.sh |   36 ++++++++++++++++++++++++++++++++++++\n test-index-version.c           |   14 ++++++++++++++\n 4 files changed, 52 insertions(+), 1 deletions(-)\n create mode 100755 t/t2104-update-index-narrow.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/Makefile b/Makefile\nindex 716161d..7a22bde 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -1323,7 +1323,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/t/t2104-update-index-narrow.sh b/t/t2104-update-index-narrow.sh\nnew file mode 100755\nindex 0000000..2683929\n--- /dev/null\n+++ b/t/t2104-update-index-narrow.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 narrow checkout update'\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 --narrow-checkout|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 --narrow-checkout)\"'\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":"90665","messageId":"1221397685-27715-8-git-send-email-pclouds@gmail.com","threadId":"15521","inReplyTo":"1221397685-27715-7-git-send-email-pclouds@gmail.com","subject":"[PATCH 07/16] Prevent diff machinery from examining worktree outside narrow checkout","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2008-09-14T13:07:56Z","receivedAt":"2008-09-14T13:07:56Z","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 a2f4850..7a8f520 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -1784,8 +1784,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 narrow 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":"90666","messageId":"1221397685-27715-9-git-send-email-pclouds@gmail.com","threadId":"15521","inReplyTo":"1221397685-27715-8-git-send-email-pclouds@gmail.com","subject":"[PATCH 08/16] checkout_entry(): CE_NO_CHECKOUT on checked out entries.","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2008-09-14T13:07:57Z","receivedAt":"2008-09-14T13:07:57Z","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":"90667","messageId":"1221397685-27715-10-git-send-email-pclouds@gmail.com","threadId":"15521","inReplyTo":"1221397685-27715-9-git-send-email-pclouds@gmail.com","subject":"[PATCH 09/16] ls-files: apply --deleted on narrow area only","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2008-09-14T13:07:58Z","receivedAt":"2008-09-14T13:07:58Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n builtin-ls-files.c             |    2 +-\n t/t2104-update-index-narrow.sh |    6 ++++++\n 2 files changed, 7 insertions(+), 1 deletions(-)\n\ndiff --git a/builtin-ls-files.c b/builtin-ls-files.c\nindex 456d41c..02fa00b 100644\n--- a/builtin-ls-files.c\n+++ b/builtin-ls-files.c\n@@ -260,7 +260,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);\ndiff --git a/t/t2104-update-index-narrow.sh b/t/t2104-update-index-narrow.sh\nindex 2683929..1a3acdd 100755\n--- a/t/t2104-update-index-narrow.sh\n+++ b/t/t2104-update-index-narrow.sh\n@@ -25,6 +25,12 @@ 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 'ls-files --deleted ignores no-checkout entries' '\n+\trm 1 &&\n+\ttest -z \"$(git ls-files --deleted)\" &&\n+\ttouch 1\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 --narrow-checkout)\"'\n-- \n1.6.0.96.g2fad1.dirty\n"},{"id":"90668","messageId":"1221397685-27715-11-git-send-email-pclouds@gmail.com","threadId":"15521","inReplyTo":"1221397685-27715-10-git-send-email-pclouds@gmail.com","subject":"[PATCH 10/16] grep: skip files that have not been checked out","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2008-09-14T13:07:59Z","receivedAt":"2008-09-14T13:07:59Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n builtin-grep.c |    7 ++++++-\n 1 files changed, 6 insertions(+), 1 deletions(-)\n\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":"90669","messageId":"1221397685-27715-12-git-send-email-pclouds@gmail.com","threadId":"15521","inReplyTo":"1221397685-27715-11-git-send-email-pclouds@gmail.com","subject":"[PATCH 11/16] unpack_trees(): add support for narrow checkout","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2008-09-14T13:08:00Z","receivedAt":"2008-09-14T13:08:00Z","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 narrow area is\nchanged. There are three kind of changes:\n\n - new_narrow_path: reset workdir to a new narrow checkout\n - add_narrow_path: keep current narrow areas and add more entries\n - remove_narrow_path: remove some entries from current narrow areas\n\nA simple \"narrow spec\" is introduced to specify what entries is in\nnarrow area. For now it is just a list of prefix separated by colon.\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 |  100 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n unpack-trees.h |    6 +++\n 3 files changed, 109 insertions(+), 0 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex 2b2c90f..1fc0f83 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 e59d144..968cc98 100644\n--- a/unpack-trees.c\n+++ b/unpack-trees.c\n@@ -96,6 +96,15 @@ 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+\n+\t\t\tif (ce->ce_flags & CE_WD_REMOVE) {\n+\t\t\t\ttotal++;\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\n+\t\t\tif (ce_no_checkout(ce))\n+\t\t\t\tcontinue;\n+\n \t\t\tif (ce->ce_flags & (CE_UPDATE | CE_REMOVE))\n \t\t\t\ttotal++;\n \t\t}\n@@ -108,6 +117,16 @@ 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_no_checkout(ce))\n+\t\t\tcontinue;\n+\n \t\tif (ce->ce_flags & CE_REMOVE) {\n \t\t\tdisplay_progress(progress, ++cnt);\n \t\t\tif (o->update)\n@@ -121,6 +140,9 @@ 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_no_checkout(ce))\n+\t\t\tcontinue;\n+\n \t\tif (ce->ce_flags & CE_UPDATE) {\n \t\t\tdisplay_progress(progress, ++cnt);\n \t\t\tce->ce_flags &= ~CE_UPDATE;\n@@ -133,6 +155,47 @@ 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_checkout(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, o->narrow_prefix);\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\tif (was_checkout && ce_no_checkout(ce)) {\n+\t\t\tif (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+\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 +472,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_checkout(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 +743,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))\n@@ -726,6 +794,38 @@ static void show_stage_entry(FILE *o,\n }\n #endif\n \n+int match_narrow_spec(const char *spec_, const char *path, const char *prefix)\n+{\n+\tint match = 0;\n+\tchar *spec, *cur_spec;\n+\tint prefix_len = 0;\n+\n+\tif (!spec_)\n+\t\treturn 1; /* always match if spec_ is NULL */\n+\tif (prefix) {\n+\t\tif (prefixcmp(path, prefix))\n+\t\t\treturn 0;\n+\t\tprefix_len = strlen(prefix);\n+\t}\n+\n+\tspec = cur_spec = xstrdup(spec_);\n+\n+\twhile (!match) {\n+\t\tchar *next_spec = strchr(cur_spec, ':');\n+\t\tif (next_spec)\n+\t\t\t*next_spec = '\\0';\n+\n+\t\tif (!fnmatch(cur_spec, path+prefix_len, 0))\n+\t\t\tmatch = 1;\n+\n+\t\tif (!next_spec)\n+\t\t\tbreak;\n+\t\tcur_spec = next_spec+1;\n+\t}\n+\tfree(spec);\n+\treturn match;\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..942a007 100644\n--- a/unpack-trees.h\n+++ b/unpack-trees.h\n@@ -27,6 +27,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@@ -38,6 +41,8 @@ struct unpack_trees_options {\n \tint merge_size;\n \n \tstruct cache_entry *df_conflict_entry;\n+\tconst char *narrow_spec;\n+\tconst char *narrow_prefix;\n \tvoid *unpack_data;\n \n \tstruct index_state *dst_index;\n@@ -48,6 +53,7 @@ struct unpack_trees_options {\n extern int unpack_trees(unsigned n, struct tree_desc *t,\n \t\tstruct unpack_trees_options *options);\n \n+int match_narrow_spec(const char *spec_, const char *path, const char *prefix);\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":"90670","messageId":"1221397685-27715-13-git-send-email-pclouds@gmail.com","threadId":"15521","inReplyTo":"1221397685-27715-12-git-send-email-pclouds@gmail.com","subject":"[PATCH 12/16] narrow spec: put '+' before a spec will change semantic of '*'","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2008-09-14T13:08:01Z","receivedAt":"2008-09-14T13:08:01Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Previously '*' in narrow spec means 'match everything, even slashes'.\nWith this change, '*' is now 'match everything except slashes' so it is\nmore like shell wildcard one. Putting '+' before a spec will make\n'*' as powerful as before.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n unpack-trees.c |    7 ++++++-\n 1 files changed, 6 insertions(+), 1 deletions(-)\n\ndiff --git a/unpack-trees.c b/unpack-trees.c\nindex 968cc98..3782de6 100644\n--- a/unpack-trees.c\n+++ b/unpack-trees.c\n@@ -812,10 +812,15 @@ int match_narrow_spec(const char *spec_, const char *path, const char *prefix)\n \n \twhile (!match) {\n \t\tchar *next_spec = strchr(cur_spec, ':');\n+\t\tint flag = 0;\n \t\tif (next_spec)\n \t\t\t*next_spec = '\\0';\n \n-\t\tif (!fnmatch(cur_spec, path+prefix_len, 0))\n+\t\tif (*cur_spec == '+')\n+\t\t\tcur_spec++;\n+\t\telse\n+\t\t\tflag = FNM_PATHNAME;\n+\t\tif (!fnmatch(cur_spec, path+prefix_len, flag))\n \t\t\tmatch = 1;\n \n \t\tif (!next_spec)\n-- \n1.6.0.96.g2fad1.dirty\n"},{"id":"90671","messageId":"1221397685-27715-14-git-send-email-pclouds@gmail.com","threadId":"15521","inReplyTo":"1221397685-27715-13-git-send-email-pclouds@gmail.com","subject":"[PATCH 13/16] ls-files: add --narrow-match=spec option for testing narrow matching","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2008-09-14T13:08:02Z","receivedAt":"2008-09-14T13:08:02Z","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-ls-files.txt   |    7 +++++-\n builtin-ls-files.c               |   14 +++++++++++-\n t/t3003-ls-files-narrow-match.sh |   45 ++++++++++++++++++++++++++++++++++++++\n 3 files changed, 64 insertions(+), 2 deletions(-)\n create mode 100755 t/t3003-ls-files-narrow-match.sh\n\ndiff --git a/Documentation/git-ls-files.txt b/Documentation/git-ls-files.txt\nindex f74b212..4f5a37e 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])\\*\n \t\t(-[c|d|o|i|s|u|k|m])\\*\n-\t\t[--narrow-checkout]\n+\t\t[--narrow-checkout] [--narrow-match=<narrow_spec>]\n \t\t[-x <pattern>|--exclude=<pattern>]\n \t\t[-X <file>|--exclude-from=<file>]\n \t\t[--exclude-per-directory=<file>]\n@@ -78,6 +78,11 @@ OPTIONS\n \tindex-based selection options like --cached or --stage, only narrowed\n \tportion will be printed out.\n \n+--narrow-match=<narrow_spec>::\n+\tNarrow spec can be applied on ls-files output so that you can test\n+\tyour spec. Can only be used with --cached. See linkgit:git-checkout[1]\n+\tfor more information about narrow spec.\n+\n -z::\n \t\\0 line termination on output.\n \ndiff --git a/builtin-ls-files.c b/builtin-ls-files.c\nindex 02fa00b..f48a157 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@@ -29,6 +31,7 @@ static const char **pathspec;\n static int error_unmatch;\n static char *ps_matched;\n static const char *with_tree;\n+static const char *narrow_spec;\n \n static const char *tag_cached = \"\";\n static const char *tag_unmerged = \"\";\n@@ -248,6 +251,8 @@ static void show_files(struct dir_struct *dir, const char *prefix)\n \t\t\t\tcontinue;\n \t\t\tif (narrow_checkout && ce_no_checkout(ce))\n \t\t\t\tcontinue;\n+\t\t\tif (narrow_spec && !match_narrow_spec(narrow_spec, ce->name, prefix))\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@@ -427,7 +432,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])* \"\n-\t\"[ --narrow-checkout ] \"\n+\t\"[ --narrow-checkout ] [--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@@ -473,6 +478,10 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)\n \t\t\tnarrow_checkout = 1;\n \t\t\tcontinue;\n \t\t}\n+\t\tif (!prefixcmp(arg, \"--narrow-match=\")) {\n+\t\t\tnarrow_spec = arg+15;\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@@ -607,6 +616,9 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)\n \tif (narrow_checkout && !show_cached && !show_stage)\n \t\tdie(\"ls-files: --narrow-checkout can only be used with either --cached or --stage\");\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 \tread_cache();\n \tif (prefix)\n \t\tprune_cache(prefix);\ndiff --git a/t/t3003-ls-files-narrow-match.sh b/t/t3003-ls-files-narrow-match.sh\nnew file mode 100755\nindex 0000000..b48fdb2\n--- /dev/null\n+++ b/t/t3003-ls-files-narrow-match.sh\n@@ -0,0 +1,45 @@\n+#!/bin/sh\n+\n+test_description='This test is for narrow spec matching'\n+\n+. test-lib.sh\n+\n+test_expect_success 'setup' '\n+\ttouch 1 2 3 &&\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_expect_success 'exact matches' '\n+\ttest \"$(git ls-files --narrow-match=1)\" = 1 &&\n+\ttest -z \"$(git ls-files --narrow-match=sub)\" && # exact match on a directory gives nothing\n+\t(cd sub &&\n+\ttest \"$(git ls-files --full-name --narrow-match=subsub/1)\" = sub/subsub/1 &&\n+\ttest \"$(git ls-files --narrow-match=subsub/1)\" = subsub/1)\n+'\n+\n+test_expect_success 'star matches' '\n+\ttest \"$(git ls-files --narrow-match=\\*1)\" = 1 &&\n+\t(cd sub &&\n+\ttest \"$(git ls-files --full-name --narrow-match=subsub/\\*1)\" = sub/subsub/1 &&\n+\ttest \"$(git ls-files --narrow-match=subsub/\\*1)\" = subsub/1)\n+'\n+\n+cat >starplus-1.expected <<\\EOF\n+1\n+sub/1\n+sub/subsub/1\n+EOF\n+cat >starplus-2.expected <<\\EOF\n+sub/1\n+sub/subsub/1\n+EOF\n+test_expect_success 'starplus matches' '\n+\tgit ls-files --narrow-match=+\\*1 | cmp starplus-1.expected\n+\t(cd sub &&\n+\tgit ls-files --full-name --narrow-match=+\\*1 | cmp ../starplus-2.expected)\n+'\n+\n+test_done\n-- \n1.6.0.96.g2fad1.dirty\n"},{"id":"90672","messageId":"1221397685-27715-15-git-send-email-pclouds@gmail.com","threadId":"15521","inReplyTo":"1221397685-27715-14-git-send-email-pclouds@gmail.com","subject":"[PATCH 14/16] clone: support narrow checkout with --path option","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2008-09-14T13:08:03Z","receivedAt":"2008-09-14T13:08:03Z","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 |    8 +++++++-\n builtin-clone.c             |   13 +++++++++++++\n t/t5703-clone-narrow.sh     |   39 +++++++++++++++++++++++++++++++++++++++\n 3 files changed, 59 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..0a7d11d 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>] [--path=<narrow_spec>] [--]\n+\t  <repository> [<directory>]\n \n DESCRIPTION\n -----------\n@@ -94,6 +95,11 @@ then the cloned repository will become corrupt.\n -n::\n \tNo checkout of HEAD is performed after the clone is complete.\n \n+--path=<narrow_spec>::\n+\tA narrow checkout of HEAD is performed after clone is complete\n+\twith given narrow spec. Please refer to linkgit:git-checkout[1]\n+\tfor more detail on narrow checkout and narrow spec.\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 c843529..37d44ca 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, \"path\", &option_narrow_path, \"prefixes\",\n+\t\t    \"limit checkout to specified paths (narrow 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@@ -385,10 +388,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 --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 --path options are incompatible.\");\n+\n \tif (!option_origin)\n \t\toption_origin = \"origin\";\n \n@@ -597,6 +605,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 = option_narrow_path;\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..3ab9eaf\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 --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 --path=work -n src dst\n+'\n+\n+test_expect_success 'clone with --path' '\n+\trm -fr dst &&\n+\tgit clone --path=work src dst &&\n+\tcd dst &&\n+\ttest -z \"$(git ls-files --checkout | grep -v ^work/)\"\n+'\n+\n+test_done\n-- \n1.6.0.96.g2fad1.dirty\n"},{"id":"90673","messageId":"1221397685-27715-16-git-send-email-pclouds@gmail.com","threadId":"15521","inReplyTo":"1221397685-27715-15-git-send-email-pclouds@gmail.com","subject":"[PATCH 15/16] checkout: add new options to support narrow checkout","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2008-09-14T13:08:04Z","receivedAt":"2008-09-14T13:08:04Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"These options include:\n\n --full: return to full checkout (default)\n --path: narrow checkout to some areas according to given spec\n --add-path/--remove-path: adjust current narrow checkout\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Documentation/git-checkout.txt |   68 +++++++++++++++++++++++++++++++++-\n builtin-checkout.c             |   44 ++++++++++++++++++++++\n t/t2011-checkout-narrow.sh     |   80 ++++++++++++++++++++++++++++++++++++++++\n 3 files changed, 190 insertions(+), 2 deletions(-)\n create mode 100755 t/t2011-checkout-narrow.sh\n\ndiff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt\nindex 82e154d..2ae483b 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  [<narrow options>] [<branch>]\n+'git checkout' [-f|--ours|--theirs|-m|--conflict=<style>] [<tree-ish>]\n+\t  [<narrow 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+<narrow options> include --full, --path, --add-path and --remove-path.\n+The last three require narrow spec. Please refer to \"narrow checkout\"\n+section to have 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@@ -108,6 +114,22 @@ exlicitly give a name with '-b' in such a case.\n \tHowever, with this option, a three-way merge between the current\n \tbranch, your working tree contents, and the new branch\n \tis done, and you will be on the new branch.\n+\n+--full::\n+\tQuit narrow checkout mode. Return to full checkout.\n+\n+--path=<narrow_spec>::\n+\tRe-apply new narrow spec on current working directory to\n+\tform new checkout area.\n+\n+--add-path=<narrow_spec>::\n+\tCheckout more areas specified by narrow spec to current\n+\tcheckout area.\n+\n+--remove-path=<narrow_spec>::\n+\tNarrow checkout area by removing files specified by narrow spec\n+\tfrom current checkout area. This operation will fail if there\n+\tis unmerged or modified files in the removing areas.\n +\n When a merge conflict happens, the index entries for conflicting\n paths are left unmerged, and you need to resolve the conflicts\n@@ -171,6 +193,48 @@ the reflog for HEAD where you were, e.g.\n $ git log -g -2 HEAD\n ------------\n \n+Narrow checkout\n+---------------\n+\n+Normally when you do 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 required. Narrow\n+checkout is a mode that limits checkout area according to your\n+rules.\n+\n+Because narrow checkout uses new index format, it will be\n+incompatible with git prior to 1.6.0. In order to make your\n+working directory work with those versions, you can use `git\n+checkout --full` to return to normal mode (and compatible index\n+format).\n+\n+Narrow works by applying your rules to the index, marking which\n+file you need and which file you need not. Modified/Unmerged\n+files cannot be marked unneeded. Unnecessary files will be\n+removed from working directory.  Note that after this step,\n+removed files can still be added to working directory when they\n+are needed by any git command. For example, when you have a merge\n+conflict, conflicted files will be checked out on working\n+directory and will no longer be marked \"unneeded\".\n+\n+New files after merges will always be \"needed\". You can also\n+apply rules when switching branches to avoid unwanted new files.\n+\n+Files that are marked \"no-checkout\" will be treated like entries\n+with \"assume-unchanged bit\" (see linkgit:git-update-index[1]). In\n+short, Git will never look for those files in working directory\n+no matter whether they exist in working directory.\n+\n+You can apply your rules at once with --path option, or do it\n+incrementally with --add-path and --remove-path.\n+\n+Narrow spec will be used to specify how you want to narrow your\n+checkout. It is a list of pathspecs separated by colons. Each\n+patchspec specifies what files should be checked out on working\n+directory. Pathspec can contain wildcards and is relative to\n+current working directory. Usually asterisk (*) does not match\n+slashes. If a pathspec is prefixed by a plus sign (+), then\n+any asterisk will match anything, even slashes.\n \n EXAMPLES\n --------\ndiff --git a/builtin-checkout.c b/builtin-checkout.c\nindex c7b0aad..b6bc3c5 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 no_narrow_checkout;\n };\n \n static int post_checkout_hook(struct commit *old, struct commit *new,\n@@ -412,6 +418,24 @@ 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\ttopts.narrow_prefix = opts->prefix;\n+\t\tif (opts->no_narrow_checkout) {\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 = opts->new_path;\n+\t\t\ttopts.new_narrow_path = 1;\n+\t\t}\n+\t\telse if (opts->add_path) {\n+\t\t\ttopts.narrow_spec = opts->add_path;\n+\t\t\ttopts.add_narrow_path = 1;\n+\t\t}\n+\t\telse if (opts->remove_path) {\n+\t\t\ttopts.narrow_spec = opts->remove_path;\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 +624,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.no_narrow_checkout, \"quit sparse checkout\"),\n+\t\tOPT_STRING(0, \"path\", &opts.new_path, \"prefixes\", \"apply new narrow checkout path\"),\n+\t\tOPT_STRING(0, \"add-path\", &opts.add_path, \"prefixes\", \"add more 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 +638,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 +668,18 @@ 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.no_narrow_checkout ? 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: --path, --full, --add-path and --remove-path are incompatible\");\n+\n+\tif (opts.new_branch && (opts.add_path || opts.remove_path))\n+\t\tdie(\"git checkout: --add-path and --remove-path should only be used on current branch\");\n+\n+\tif (opts.new_branch && opts.no_narrow_checkout)\n+\t\tdie(\"git checkout: switching branch with --full does not make sense\");\n+\n \tif (opts.force && opts.merge)\n \t\tdie(\"git checkout: -f and -m are incompatible\");\n \n@@ -732,6 +773,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.no_narrow_checkout || 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-narrow.sh b/t/t2011-checkout-narrow.sh\nnew file mode 100755\nindex 0000000..77b99e1\n--- /dev/null\n+++ b/t/t2011-checkout-narrow.sh\n@@ -0,0 +1,80 @@\n+#!/bin/sh\n+\n+test_description='narrow 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 --path incompatible' '\n+\ttest_must_fail git checkout --full --path=work1\n+'\n+\n+test_expect_success 'limit worktree to work1 and work2' '\n+\tgit checkout --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 --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 --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 narrow should not lose modification' '\n+\t! git checkout --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 'exit narrow 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":"90674","messageId":"1221397685-27715-17-git-send-email-pclouds@gmail.com","threadId":"15521","inReplyTo":"1221397685-27715-16-git-send-email-pclouds@gmail.com","subject":"[PATCH 16/16] ls-files: add --overlay option","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2008-09-14T13:08:05Z","receivedAt":"2008-09-14T13:08:05Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Narrow checkout mode introduces an interesting case: some files\nare not to be checked out (marked CE_NO_CHECKOUT in index) but still\nexist in working directory. Those files will be ignored by Git unless\nexplicitly specified. In Clearcase, these files are called \"eclipsed\".\nI would call them \"overlay\" for now. Any better term is welcome.\n\nThe same situation happens for \"assume unchanged\" bit, but I would\nexpect narrow checkout to be more user-friendly and should notify users\nthese cases so users will not be confused. On this first step, users\nmay check by themselves with \"git ls-files --overlay\", further steps\nmay make the information visible from \"git status\".\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Documentation/git-ls-files.txt |    4 ++++\n builtin-ls-files.c             |   16 +++++++++++++---\n t/t2104-update-index-narrow.sh |    4 ++++\n 3 files changed, 21 insertions(+), 3 deletions(-)\n\ndiff --git a/Documentation/git-ls-files.txt b/Documentation/git-ls-files.txt\nindex 4f5a37e..9e749ef 100644\n--- a/Documentation/git-ls-files.txt\n+++ b/Documentation/git-ls-files.txt\n@@ -56,6 +56,9 @@ OPTIONS\n --stage::\n \tShow staged contents' object name, mode bits and stage number in the output.\n \n+--overlay::\n+\tShow files that are marked no-checkout but exist in working directory.\n+\n --directory::\n \tIf a whole directory is classified as \"other\", show just its\n \tname (with a trailing slash) and not its whole contents.\n@@ -122,6 +125,7 @@ OPTIONS\n \tR::\tremoved/deleted\n \tC::\tmodified/changed\n \tK::\tto be killed\n+\t!::\toverlay files\n \t?::\tother\n \n -v::\ndiff --git a/builtin-ls-files.c b/builtin-ls-files.c\nindex f48a157..6e55207 100644\n--- a/builtin-ls-files.c\n+++ b/builtin-ls-files.c\n@@ -20,6 +20,7 @@ static int show_others;\n static int show_stage;\n static int show_unmerged;\n static int show_modified;\n+static int show_overlay;\n static int show_killed;\n static int show_valid_bit;\n static int narrow_checkout;\n@@ -39,6 +40,7 @@ static const char *tag_removed = \"\";\n static const char *tag_other = \"\";\n static const char *tag_killed = \"\";\n static const char *tag_modified = \"\";\n+static const char *tag_overlay = \"\";\n \n \n /*\n@@ -256,7 +258,7 @@ static void show_files(struct dir_struct *dir, const char *prefix)\n \t\t\tshow_ce_entry(ce_stage(ce) ? tag_unmerged : tag_cached, ce);\n \t\t}\n \t}\n-\tif (show_deleted | show_modified) {\n+\tif (show_deleted | show_modified | show_overlay) {\n \t\tfor (i = 0; i < active_nr; i++) {\n \t\t\tstruct cache_entry *ce = active_cache[i];\n \t\t\tstruct stat st;\n@@ -265,6 +267,8 @@ 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_overlay && ce_no_checkout(ce) && !err)\n+\t\t\t\tshow_ce_entry(tag_overlay, ce);\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@@ -431,7 +435,7 @@ 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|overlay])* \"\n \t\"[ --narrow-checkout ] [--narrow-match=<narrow_spec>] \"\n \t\"[ --ignored ] [--exclude=<pattern>] [--exclude-from=<file>] \"\n \t\"[ --exclude-per-directory=<filename> ] [--exclude-standard] \"\n@@ -466,6 +470,7 @@ 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_overlay = \"! \";\n \t\t\tif (arg[1] == 'v')\n \t\t\t\tshow_valid_bit = 1;\n \t\t\tcontinue;\n@@ -491,6 +496,11 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)\n \t\t\trequire_work_tree = 1;\n \t\t\tcontinue;\n \t\t}\n+\t\tif (!strcmp(arg, \"--overlay\")) {\n+\t\t\tshow_overlay = 1;\n+\t\t\trequire_work_tree = 1;\n+\t\t\tcontinue;\n+\t\t}\n \t\tif (!strcmp(arg, \"-o\") || !strcmp(arg, \"--others\")) {\n \t\t\tshow_others = 1;\n \t\t\trequire_work_tree = 1;\n@@ -610,7 +620,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_overlay))\n \t\tshow_cached = 1;\n \n \tif (narrow_checkout && !show_cached && !show_stage)\ndiff --git a/t/t2104-update-index-narrow.sh b/t/t2104-update-index-narrow.sh\nindex 1a3acdd..79da418 100755\n--- a/t/t2104-update-index-narrow.sh\n+++ b/t/t2104-update-index-narrow.sh\n@@ -31,6 +31,10 @@ test_expect_success 'ls-files --deleted ignores no-checkout entries' '\n \ttouch 1\n '\n \n+test_expect_success 'there are overlay entries' '\n+\ttest \"$(git ls-files --overlay|grep 1|wc -l)\" = 2\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 --narrow-checkout)\"'\n-- \n1.6.0.96.g2fad1.dirty\n"},{"id":"90683","messageId":"m38wtuo92v.fsf@localhost.localdomain","threadId":"15521","inReplyTo":"1221397685-27715-5-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH 04/16] update-index: add --checkout/--no-checkout to update CE_NO_CHECKOUT bit","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2008-09-14T18:50:51Z","receivedAt":"2008-09-14T18:50:51Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"I will comment only on documentation...\n\nNguyễn Thái Ngọc Duy <pclouds@gmail.com> writes:\n\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> @@ -88,6 +89,17 @@ OPTIONS\n>  \tsometimes helpful when working with a big project on a\n>  \tfilesystem that has very slow lstat(2) system call\n>  \t(e.g. cifs).\n> +--checkout::\n> +--no-checkout::\n> +\tWhen these flags are 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 narrow 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> +\tnarrow checkout.\n\nLow level (porcelain) access to \"no checkout\" bit/flag, isn't it?\n\nNice. One caveat: you refer to git-checkout(1), which I think is\nupdated to include referenced information only later in the series.\nPerhaps add \"See linkgit:git-checkout[1]...\" part only _after_ the\nreferenced information is in Documentation/git-checkout.txt\n\n>  +\n>  This option can be also used as a coarse file-level mechanism\n>  to ignore uncommitted changes in tracked files (akin to what\n\nOoops. It looks like it is continuation line to _previous_ option,\nprobably --assume-unchanged, which you have interrupted by mistake.\n\n-- \nJakub Narebski\nPoland\nShadeHawk on #git\n"},{"id":"90684","messageId":"m34p4io8vt.fsf@localhost.localdomain","threadId":"15521","inReplyTo":"1221397685-27715-6-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH 05/16] ls-files: add --narrow-checkout option to \"will checkout\" entries","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2008-09-14T18:55:06Z","receivedAt":"2008-09-14T18:55:06Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"I will comment only on the documentation...\n\nNguyễn Thái Ngọc Duy <pclouds@gmail.com> writes:\n\n> Even in narrow checkout mode, \"git ls-files --cached\" (and --stage)\n> will show all entries in index. When those options are used together\n> with --narrow-checkout, no-checkout entries will be skipped.\n> \n> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n> diff --git a/Documentation/git-ls-files.txt b/Documentation/git-ls-files.txt\n> index 9f85d60..f74b212 100644\n> --- a/Documentation/git-ls-files.txt\n> +++ b/Documentation/git-ls-files.txt\n> @@ -72,6 +73,11 @@ OPTIONS\n>  \tto file/directory conflicts for checkout-index to\n>  \tsucceed.\n>  \n> +--narrow-checkout::\n> +\tWhen narrow checkout is being used, this option together with other\n> +\tindex-based selection options like --cached or --stage, only narrowed\n> +\tportion will be printed out.\n> +\n\nI would rather say, that if git-ls-files is requested to show index\ncontent (by using selection options like --cached or --stage), then\nby default it shows all entries, also those marked \"no checkout\".\nWith this option git-ls-files would show only files that would get\nchecked out.\n\nBTW. I think here --narrow-checkout is a good name, even though\nI prefer 'partial checkout' or 'sparse checkout', because here it\nis about narrowing the list of paths from index shown.\n\n-- \nJakub Narebski\nPoland\nShadeHawk on #git\n"},{"id":"90685","messageId":"m3zlmamu9s.fsf@localhost.localdomain","threadId":"15521","inReplyTo":"1221397685-27715-11-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH 10/16] grep: skip files that have not been checked out","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2008-09-14T18:56:03Z","receivedAt":"2008-09-14T18:56:03Z","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> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n> ---\n>  builtin-grep.c |    7 ++++++-\n>  1 files changed, 6 insertions(+), 1 deletions(-)\n\nNo changes to Documentation/git-grep.txt?\n-- \nJakub Narebski\nPoland\nShadeHawk on #git\n"},{"id":"90686","messageId":"m3vdwymu63.fsf@localhost.localdomain","threadId":"15521","inReplyTo":"1221397685-27715-14-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH 13/16] ls-files: add --narrow-match=spec option for testing narrow matching","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2008-09-14T18:58:14Z","receivedAt":"2008-09-14T18:58:14Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"I will comment only on documentation?\n\nNguyễn Thái Ngọc Duy <pclouds@gmail.com> writes:\n\n> +--narrow-match=<narrow_spec>::\n> +\tNarrow spec can be applied on ls-files output so that you can test\n> +\tyour spec. Can only be used with --cached. See linkgit:git-checkout[1]\n> +\tfor more information about narrow spec.\n> +\n\nWhere were those changes to Documentation/git-checkout.txt?\n\nI think it would better read if you said first what for is this option,\ni.e. first that this option is to test <narrow_spec>.\n-- \nJakub Narebski\nPoland\nShadeHawk on #git\n"},{"id":"90687","messageId":"m3r67mmu0v.fsf@localhost.localdomain","threadId":"15521","inReplyTo":"1221397685-27715-15-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH 14/16] clone: support narrow checkout with --path option","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2008-09-14T19:01:22Z","receivedAt":"2008-09-14T19:01:22Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"I will comment only on the documentation...\n\nNguyễn Thái Ngọc Duy <pclouds@gmail.com> writes:\n\n> +--path=<narrow_spec>::\n> +\tA narrow checkout of HEAD is performed after clone is complete\n> +\twith given narrow spec. Please refer to linkgit:git-checkout[1]\n> +\tfor more detail on narrow checkout and narrow spec.\n\nTwo questions. First, can you repeat those specifiers, i.e. use\n\"git clone --path=Documentation/ --path=.gitignore\"?\n\nSecond, how `--path=<narrow_spec>` interacts with `-n' (no checkout).\nDoes it even have any sense? Perhaps those options should be mutually\nincompatibile (and --bare and this option too)?\n\n-- \nJakub Narebski\nPoland\nShadeHawk on #git\n"},{"id":"90694","messageId":"m3ljxumo1w.fsf@localhost.localdomain","threadId":"15521","inReplyTo":"1221397685-27715-17-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH 16/16] ls-files: add --overlay option","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2008-09-14T21:10:22Z","receivedAt":"2008-09-14T21:10:22Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"I will comment only on the Documentation part...\n\nNguyễn Thái Ngọc Duy    <pclouds@gmail.com> writes:\n\n> Narrow checkout mode introduces an interesting case: some files\n> are not to be checked out (marked CE_NO_CHECKOUT in index) but still\n> exist in working directory. Those files will be ignored by Git unless\n> explicitly specified. In ClearCase, these files are called \"eclipsed\".\n> I would call them \"overlay\" for now. Any better term is welcome.\n\n\"un-un-checked-out\"? Just kidding.  \"not needed\", \"unneeded\",...\nah, I know, perhaps \"unwanted\"? Or \"orphaned\" (\"abandoned\")?\n\n[...]\n> --- a/Documentation/git-ls-files.txt\n> +++ b/Documentation/git-ls-files.txt\n[...]\n> +--overlay::\n> +\tShow files that are marked no-checkout but exist in working directory.\n> +\n\nShouldn't this be another letter in status mode? What about files\nwhich should be not checked-out, but are modified? Or for simplicity\nit is just list of files which have \"no checkout\" bit set, but are\npresent in working directory (and are not unmerged?)?\n\n-- \nJakub Narebski\nPoland\nShadeHawk on #git\n"},{"id":"90695","messageId":"m3iqsymnyd.fsf@localhost.localdomain","threadId":"15521","inReplyTo":"1221397685-27715-16-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH 15/16] checkout: add new options to support narrow checkout","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2008-09-14T21:12:28Z","receivedAt":"2008-09-14T21:12:28Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"I will comment only on the documentation...\n\nNguyễn Thái Ngọc Duy <pclouds@gmail.com> writes:\n\n> These options include:\n> \n>  --full: return to full checkout (default)\n>  --path: narrow checkout to some areas according to given spec\n>  --add-path/--remove-path: adjust current narrow checkout\n\nHmmm... I'm not sure if such formatting of commit message, with\nbody being not independent on the subject (first line of commit\nmessage) is a good idea.\n\n> diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt\n[...]\n> +--full::\n> +\tQuit narrow checkout mode. Return to full checkout.\n> +\n> +--path=<narrow_spec>::\n> +\tRe-apply new narrow spec on current working directory to\n> +\tform new checkout area.\n> +\n> +--add-path=<narrow_spec>::\n> +\tCheckout more areas specified by narrow spec to current\n> +\tcheckout area.\n> +\n> +--remove-path=<narrow_spec>::\n> +\tNarrow checkout area by removing files specified by narrow spec\n> +\tfrom current checkout area. This operation will fail if there\n> +\tis unmerged or modified files in the removing areas.\n\nSubversion from version 1.5 supports something called \"Sparse directories\",\nhttp://blogs.open.collab.net/svn/2007/06/sparse-director.html (as pointed\nout by Bjorn Steinbrink (doener_) on #git).  Subversion has the following\noptions for 'svn checkout':\n\n  -N::\n  --non-recursive::\n         Checkout only the main directory of the trunk and not the\n         sub-directories\n   --depth=empty::\n         Updates will not pull in any files or subdirectories not\n         already present.\n   --depth=files::\n         Updates will pull in any files not already present,\n         but not subdirectories.\n   --depth=immediates::  \n         Updates will pull in any files or subdirectories not\n         already present; the subdirectories will have depth=empty.\n   --depth=infinity::\n         Updates will pull in any files or subdirectories not\n         already present; the subdirectories will have depth=infinity.\n         Equivalent to today's default update behavior.\n\nI'm not sure if those ways of limiting are worth implementing, but\nI guess that they are at least worth thinking about.\n\n> +Narrow checkout\n> +---------------\n> +\n> +Normally when you do 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 required. Narrow\n> +checkout is a mode that limits checkout area according to your\n> +rules.\n\nPerhaps s/required/needed/?\n\n> +\n> +Because narrow checkout uses new index format, it will be\n> +incompatible with git prior to 1.6.0. In order to make your\n> +working directory work with those versions, you can use `git\n> +checkout --full` to return to normal mode (and compatible index\n> +format).\n\nVery nice to have those compatibility concerns mentioned upfront.\nIn short: new feature, wouldn't work with git prior to 1.6.0.\n\nI hope that nobody mistakes _working_ with repository with \npartial / sparse / narrow checkout, which requires >= 1.6.0,\nwith being able to clone / fetch such repository, where there\nare no limitations, contrary for example to what was for submodule\nsupport.\n\n> +\n> +Narrow works by applying your rules to the index, marking which\n> +file you need and which file you need not. Modified/Unmerged\n> +files cannot be marked unneeded. Unnecessary files will be\n> +removed from working directory.  Note that after this step,\n> +removed files can still be added to working directory when they\n> +are needed by any git command. For example, when you have a merge\n> +conflict, conflicted files will be checked out on working\n> +directory and will no longer be marked \"unneeded\".\n\nThis paragraph I think need some more love...\n\nSo the \"checkout rules\" are meant to mark which paths are \"wanted\"\nor \"needed\", and we would like to have in the checkout, and which\nfiles are \"unwanted\" or \"not needed\" (\"unneeded\"?) and we want to\nnot have them present in working directory; something akin to accept\nand deny rules, isn't it?\n\nWhat are the rules, does all files except those marked explicitely\nas needed are unneeded, or do you have to first mark all files as\nunneeded?\n\nHow would the following table look like:\n\n  working directory  || needed       | not needed    |\n  ----------------------------------------------------\n  file is absent     || checkout     | no change     |\n  file is present    || no change    | removed       |\n  file is modified   || conflict     | conflict?     |\n\n> +\n> +New files after merges will always be \"needed\". You can also\n> +apply rules when switching branches to avoid unwanted new files.\n\nDoes it mean that if merge brings some new files, then those\nfiles would be \"needed\" (without \"no checkout\" bit)?\n\nWhat does it mean this sentence about switching branches:\nhow does partial/sparse/narrow checkout rules change when\nswitching to other branch (which, like 'html' and 'todo'\nbranches in git repository, can be completely unrelated)?\n\n> +\n> +Files that are marked \"no-checkout\" will be treated like entries\n> +with \"assume-unchanged bit\" (see linkgit:git-update-index[1]). In\n> +short, Git will never look for those files in working directory\n> +no matter whether they exist in working directory.\n\nPerhaps add that they would be marked with \"no checkout\" bit, and\nrefer to --no-checkout flag of git-update-index?  I'm not sure here\nabout that...\n\n> +\n> +You can apply your rules at once with --path option, or do it\n> +incrementally with --add-path and --remove-path.\n\nNice.\n\n> +\n> +Narrow spec will be used to specify how you want to narrow your\n> +checkout. It is a list of pathspecs separated by colons. Each\n> +patchspec specifies what files should be checked out on working\n> +directory. Pathspec can contain wildcards and is relative to\n> +current working directory. Usually asterisk (*) does not match\n> +slashes. If a pathspec is prefixed by a plus sign (+), then\n> +any asterisk will match anything, even slashes.\n\nFirst, does this mean that you can specify paths containing colons\n(':') only using --add-path and --remove-path, or does it mean that\nyou cannot specify paths containg colon ':' (which should be rare)\nat all as checkout limiter / checkout narrowing rule?\n\nSecond, wouldn't it be better to use '**' to match also '/'?\nChanging meaning of '*' using per-path flag seems a bit bad.\n\n-- \nJakub Narebski\nPoland\nShadeHawk on #git\n"},{"id":"90762","messageId":"7vsks1b3tq.fsf@gitster.siamese.dyndns.org","threadId":"15521","inReplyTo":"1221397685-27715-12-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH 11/16] unpack_trees(): add support for narrow checkout","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-09-15T19:34:57Z","receivedAt":"2008-09-15T19:34:57Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:\n\n> diff --git a/cache.h b/cache.h\n> index 2b2c90f..1fc0f83 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>   */\n> diff --git a/unpack-trees.c b/unpack-trees.c\n> index e59d144..968cc98 100644\n> --- a/unpack-trees.c\n> +++ b/unpack-trees.c\n> @@ -96,6 +96,15 @@ 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> +\n> +\t\t\tif (ce->ce_flags & CE_WD_REMOVE) {\n> +\t\t\t\ttotal++;\n> +\t\t\t\tcontinue;\n> +\t\t\t}\n> +\n> +\t\t\tif (ce_no_checkout(ce))\n> +\t\t\t\tcontinue;\n> +\n>  \t\t\tif (ce->ce_flags & (CE_UPDATE | CE_REMOVE))\n>  \t\t\t\ttotal++;\n>  \t\t}\n\nThis check for ce_no_checkout() before the existing check to see if\nCE_UPDATE and/or CE_REMOVE are on puzzles me (you have the same check\nsequence in later loop that does the actualy worktree updates).  If\napply_narrow_checkout() check is working correctly, would we ever give\nCE_UPDATE and/or CE_REMOVE bits to a cache entry with CE_NO_CHECKOUT set?\n\nIOW, I think this extra check is Ok as it is expected to be no-op when\ncombined with the existing check, but it leaves me wondering if it is\nhiding some codepath that incorrectly sets CE_UPDATE/CE_REMOVE to an entry\noutside the narrow checkout area.\n\nI have two more messages but other than these the series is nicely done\nand a pleasure to read.\n"},{"id":"90764","messageId":"7vljxtb3tf.fsf@gitster.siamese.dyndns.org","threadId":"15521","inReplyTo":"1221397685-27715-17-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH 16/16] ls-files: add --overlay option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-09-15T19:35:08Z","receivedAt":"2008-09-15T19:35:08Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:\n\n> The same situation happens for \"assume unchanged\" bit, but I would\n> expect narrow checkout to be more user-friendly and should notify users\n> these cases so users will not be confused. On this first step, users\n> may check by themselves with \"git ls-files --overlay\",...\n\nCould you explain how the earlier --narrow-checkout option introduced in\n[05/16] interacts with this one?\n\nThe user has X inside narrow area and Y outside.  ls-files reports both X\nand Y.  'ls-files --narrow-checkout' reports only X.  Y is tracked but not\nreally, so 'ls-files --narrow-checkout -o' shouldn't say Y is untracked;\nthere is no cue to tell between X and Y.\n\nBut with a half of your patch to 'ls-files -t', you already can show these\npotentially stale (leftover from an ancient checkout un-updated because of\nnarrowness) files.  Could a simpler alternative be to do this processing\nnot inside \"if (show_deleted/modified)\" part of show_files(), but inside\n\"if (show_cached/stage)\" part of it?  Instead of saying tag_cached\nunconditionally, if the entry is marked no_checkout, then you would\nlstat(2) it there and report that the path is \"marked not to be checked\nout but somehow something exists there\".\n\nBy the way, I do not see an easy way to review what paths are marked with\nno-checkout easily from your command set.  It might be worthwhile to add a\nnew option that iterates over the index, finds a set of common prefixes to\nno-checkout entries and reports that set.\n"},{"id":"90763","messageId":"7vej3lb3t4.fsf@gitster.siamese.dyndns.org","threadId":"15521","inReplyTo":"1221397685-27715-10-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH 09/16] ls-files: apply --deleted on narrow area only","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-09-15T19:35:19Z","receivedAt":"2008-09-15T19:35:19Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"I think this should be part of [05/16], not a separate patch.\n"},{"id":"90768","messageId":"7v3ak1b1q7.fsf@gitster.siamese.dyndns.org","threadId":"15521","inReplyTo":"m34p4io8vt.fsf@localhost.localdomain","subject":"Re: [PATCH 05/16] ls-files: add --narrow-checkout option to \"will checkout\" entries","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-09-15T20:20:16Z","receivedAt":"2008-09-15T20:20:16Z","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>> @@ -72,6 +73,11 @@ OPTIONS\n>>  \tto file/directory conflicts for checkout-index to\n>>  \tsucceed.\n>>  \n>> +--narrow-checkout::\n>> +\tWhen narrow checkout is being used, this option together with other\n>> +\tindex-based selection options like --cached or --stage, only narrowed\n>> +\tportion will be printed out.\n>> +\n>\n> I would rather say, that if git-ls-files is requested to show index\n> content (by using selection options like --cached or --stage), then\n> by default it shows all entries, also those marked \"no checkout\".\n> With this option git-ls-files would show only files that would get\n> checked out.\n\nls-files is a very low-level interrogator, and I have this queasy feeling\nin the stomach if it suddenly stopped showing half of the index without\nexplicitly asked to with an option like this.  If somebody iterates over\nls-files output (with or without pathspecs), most often it would be to do\nsomething interesting on the work tree files that correspond to these\npaths, and for that use case it would make sense to have a mode that shows\nonly the paths marked for checkout.  But unless you can prove that \"most\noften\" above is \"100%\", you risk breaking somebody's script.  Maybe you\nare doing something similar [*1*] to the index-filter feature of\nfilter-branch, starting from the current index that has no-checkout marks\nin its entries, and it wants to know all the paths in the index.  Who\nknows?\n\n\n[Footnote]\n\n*1* filter-branch happens to start with an empty index and does not know\nabout the new 'narrow checkout' feature, so it is Ok, but it is plausible\nas an optimization for it to prime the initial index from the current\n\"real\" index, which may have the no-checkout marks.\n"},{"id":"90770","messageId":"7vy71t9muf.fsf@gitster.siamese.dyndns.org","threadId":"15521","inReplyTo":"m3r67mmu0v.fsf@localhost.localdomain","subject":"Re: [PATCH 14/16] clone: support narrow checkout with --path option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-09-15T20:27:04Z","receivedAt":"2008-09-15T20:27:04Z","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> Second, how `--path=<narrow_spec>` interacts with `-n' (no checkout).\n> Does it even have any sense? Perhaps those options should be mutually\n> incompatibile (and --bare and this option too)?\n\nTechnically you could mark the index entries with no-checkout bits even\nwith -n, so that later checkout or branch switching would honor that, but\nthe branch switching would make paths that do not exist in the remote HEAD\nbranch but do exist in the switched-to branch appear, which would be\nconfusing.  So instead of supporting:\n\n\t$ git clone -n --path=Documentation/ $there work\n        $ cd work\n        $ git checkout next\n\nwe can support:\n\n\t$ git clone -n $there work\n        $ cd work\n        $ git checkout --path=Documentation/ next\n\nwhich is much easier to explain and understand.\n"},{"id":"90822","messageId":"2faad3050809160253r7076027fgd74a1ce0e55a5dc4@mail.gmail.com","threadId":"15521","inReplyTo":"1221397685-27715-16-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH 15/16] checkout: add new options to support narrow checkout","fromName":"Baz","fromEmail":"brian.ewins@gmail.com","sentAt":"2008-09-16T09:53:28Z","receivedAt":"2008-09-16T09:53:28Z","isPatch":true,"sender":{"key":"brian.ewins@gmail.com","avatar":"https://gravatar.com/avatar/9ac03d89105e50a7151e695a1b4b1228151064ec3ac380a73b74ab397796baf7?d=mp&s=160"},"body":"Just a few minor grammar nits and typos in the docs, and one leftover\nmention of 'sparse' that should be 'narrow'.\n\nOn Sun, Sep 14, 2008 at 2:08 PM, Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:\n> These options include:\n>\n>  --full: return to full checkout (default)\n>  --path: narrow checkout to some areas according to given spec\n>  --add-path/--remove-path: adjust current narrow checkout\n>\n> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n> ---\n>  Documentation/git-checkout.txt |   68 +++++++++++++++++++++++++++++++++-\n>  builtin-checkout.c             |   44 ++++++++++++++++++++++\n>  t/t2011-checkout-narrow.sh     |   80 ++++++++++++++++++++++++++++++++++++++++\n>  3 files changed, 190 insertions(+), 2 deletions(-)\n>  create mode 100755 t/t2011-checkout-narrow.sh\n>\n> diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt\n> index 82e154d..2ae483b 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> +         [<narrow options>] [<branch>]\n> +'git checkout' [-f|--ours|--theirs|-m|--conflict=<style>] [<tree-ish>]\n> +         [<narrow 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> +<narrow options> include --full, --path, --add-path and --remove-path.\n> +The last three require narrow spec. Please refer to \"narrow checkout\"\n> +section to have more information about this mode.\n\ns/to have/for/\n\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> @@ -108,6 +114,22 @@ exlicitly give a name with '-b' in such a case.\n>        However, with this option, a three-way merge between the current\n>        branch, your working tree contents, and the new branch\n>        is done, and you will be on the new branch.\n> +\n> +--full::\n> +       Quit narrow checkout mode. Return to full checkout.\n> +\n> +--path=<narrow_spec>::\n> +       Re-apply new narrow spec on current working directory to\n> +       form new checkout area.\n> +\n> +--add-path=<narrow_spec>::\n> +       Checkout more areas specified by narrow spec to current\n> +       checkout area.\n> +\n> +--remove-path=<narrow_spec>::\n> +       Narrow checkout area by removing files specified by narrow spec\n> +       from current checkout area. This operation will fail if there\n> +       is unmerged or modified files in the removing areas.\n\ns/is/are/\n\n>  +\n>  When a merge conflict happens, the index entries for conflicting\n>  paths are left unmerged, and you need to resolve the conflicts\n> @@ -171,6 +193,48 @@ the reflog for HEAD where you were, e.g.\n>  $ git log -g -2 HEAD\n>  ------------\n>\n> +Narrow checkout\n> +---------------\n> +\n> +Normally when you do checkout a branch, your working directory\n\ns/do//\n\n> +will be fully populated. In some situations, you just need to\n> +work on certain files, no full checkout is required. Narrow\n> +checkout is a mode that limits checkout area according to your\n\ns/limits checkout area/limits the checkout area/\n\n> +rules.\n> +\n> +Because narrow checkout uses new index format, it will be\n\ns/uses new index format/uses a new index format/\n\n> +incompatible with git prior to 1.6.0. In order to make your\n> +working directory work with those versions, you can use `git\n> +checkout --full` to return to normal mode (and compatible index\n> +format).\n> +\n> +Narrow works by applying your rules to the index, marking which\n> +file you need and which file you need not. Modified/Unmerged\n\ns/file you need and file you need not/files you need and which you do not/\n\n> +files cannot be marked unneeded. Unnecessary files will be\n\nThis reads a bit awkwardly. 'marked as unneeded' maybe, or 'marked\n\"unneeded\"' as you've done elsewhere.\n\n> +removed from working directory.  Note that after this step,\n> +removed files can still be added to working directory when they\n> +are needed by any git command. For example, when you have a merge\n> +conflict, conflicted files will be checked out on working\n> +directory and will no longer be marked \"unneeded\".\n> +\n> +New files after merges will always be \"needed\". You can also\n> +apply rules when switching branches to avoid unwanted new files.\n> +\n> +Files that are marked \"no-checkout\" will be treated like entries\n> +with \"assume-unchanged bit\" (see linkgit:git-update-index[1]). In\n> +short, Git will never look for those files in working directory\n> +no matter whether they exist in working directory.\n> +\n> +You can apply your rules at once with --path option, or do it\n> +incrementally with --add-path and --remove-path.\n> +\n> +Narrow spec will be used to specify how you want to narrow your\n\n\"The narrow spec specifies how you want to narrow your...\"\n\n> +checkout. It is a list of pathspecs separated by colons. Each\n> +patchspec specifies what files should be checked out on working\n\npathspec here, not patchspec.\n\n> +directory. Pathspec can contain wildcards and is relative to\n> +current working directory. Usually asterisk (*) does not match\n> +slashes. If a pathspec is prefixed by a plus sign (+), then\n> +any asterisk will match anything, even slashes.\n>\n>  EXAMPLES\n>  --------\n> diff --git a/builtin-checkout.c b/builtin-checkout.c\n> index c7b0aad..b6bc3c5 100644\n> --- a/builtin-checkout.c\n> +++ b/builtin-checkout.c\n> @@ -33,6 +33,12 @@ struct checkout_opts {\n>        const char *new_branch;\n>        int new_branch_log;\n>        enum branch_track track;\n> +\n> +       const char *prefix;\n> +       char *new_path;\n> +       char *add_path;\n> +       char *remove_path;\n> +       int no_narrow_checkout;\n>  };\n>\n>  static int post_checkout_hook(struct commit *old, struct commit *new,\n> @@ -412,6 +418,24 @@ static int merge_working_tree(struct checkout_opts *opts,\n>                tree = parse_tree_indirect(new->commit->object.sha1);\n>                init_tree_desc(&trees[1], tree->buffer, tree->size);\n>\n> +               topts.narrow_prefix = opts->prefix;\n> +               if (opts->no_narrow_checkout) {\n> +                       /* leave narrow_spec NULL */\n> +                       topts.new_narrow_path = 1;\n> +               }\n> +               else if (opts->new_path) {\n> +                       topts.narrow_spec = opts->new_path;\n> +                       topts.new_narrow_path = 1;\n> +               }\n> +               else if (opts->add_path) {\n> +                       topts.narrow_spec = opts->add_path;\n> +                       topts.add_narrow_path = 1;\n> +               }\n> +               else if (opts->remove_path) {\n> +                       topts.narrow_spec = opts->remove_path;\n> +                       topts.remove_narrow_path = 1;\n> +               }\n> +\n>                ret = unpack_trees(2, trees, &topts);\n>                if (ret == -1) {\n>                        /*\n> @@ -600,6 +624,10 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)\n>                OPT_BOOLEAN('m', \"merge\", &opts.merge, \"merge\"),\n>                OPT_STRING(0, \"conflict\", &conflict_style, \"style\",\n>                           \"conflict style (merge or diff3)\"),\n> +               OPT_BOOLEAN(0, \"full\", &opts.no_narrow_checkout, \"quit sparse checkout\"),\n\ns/quit sparse checkout/quit narrow checkout mode/\n\nAs per your documentation above. I noticed this because I was\nsearching for 'sparse checkout' and was surprised when only one mail\nin a patch series matched :)\n\nHope this helps,\nBaz\n\n> +               OPT_STRING(0, \"path\", &opts.new_path, \"prefixes\", \"apply new narrow checkout path\"),\n> +               OPT_STRING(0, \"add-path\", &opts.add_path, \"prefixes\", \"add more checkout area\"),\n> +               OPT_STRING(0, \"remove-path\", &opts.remove_path, \"prefixes\", \"narrow checkout area\"),\n>                OPT_END(),\n>        };\n>        int has_dash_dash;\n> @@ -610,6 +638,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)\n>        git_config(git_checkout_config, NULL);\n>\n>        opts.track = BRANCH_TRACK_UNSPECIFIED;\n> +       opts.prefix = prefix;\n>\n>        argc = parse_options(argc, argv, options, checkout_usage,\n>                             PARSE_OPT_KEEP_DASHDASH);\n> @@ -639,6 +668,18 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)\n>        if (!opts.new_branch && (opts.track != git_branch_track))\n>                die(\"git checkout: --track and --no-track require -b\");\n>\n> +       if (((opts.no_narrow_checkout ? 1 : 0) +\n> +            (opts.new_path ? 1 : 0) +\n> +            (opts.add_path ? 1 : 0) +\n> +            (opts.remove_path ? 1 : 0)) > 1)\n> +               die(\"git checkout: --path, --full, --add-path and --remove-path are incompatible\");\n> +\n> +       if (opts.new_branch && (opts.add_path || opts.remove_path))\n> +               die(\"git checkout: --add-path and --remove-path should only be used on current branch\");\n> +\n> +       if (opts.new_branch && opts.no_narrow_checkout)\n> +               die(\"git checkout: switching branch with --full does not make sense\");\n> +\n>        if (opts.force && opts.merge)\n>                die(\"git checkout: -f and -m are incompatible\");\n>\n> @@ -732,6 +773,9 @@ no_reference:\n>                if (1 < !!opts.writeout_stage + !!opts.force + !!opts.merge)\n>                        die(\"git checkout: --ours/--theirs, --force and --merge are incompatible when\\nchecking out of the index.\");\n>\n> +               if (opts.no_narrow_checkout || opts.new_path || opts.add_path || opts.remove_path)\n> +                       die(\"git checkout: updating paths is incompatible with setting sparse checkout\");\n> +\n>                return checkout_paths(source_tree, pathspec, &opts);\n>        }\n>\n> diff --git a/t/t2011-checkout-narrow.sh b/t/t2011-checkout-narrow.sh\n> new file mode 100755\n> index 0000000..77b99e1\n> --- /dev/null\n> +++ b/t/t2011-checkout-narrow.sh\n> @@ -0,0 +1,80 @@\n> +#!/bin/sh\n> +\n> +test_description='narrow checkout'\n> +\n> +. ./test-lib.sh\n> +\n> +test_expect_success setup '\n> +       mkdir work1 work2 work3\n> +       touch one two three\n> +       touch work1/one work2/two work3/three\n> +       git add one work1/one\n> +       git commit -m work1\n> +       git add two work2/two\n> +       git commit -m work2\n> +       git add three work3/three\n> +       git commit -m work3\n> +'\n> +\n> +test_expect_success '--full on no-narrow checkout' '\n> +       git checkout --full\n> +'\n> +\n> +test_expect_success '--full and --path incompatible' '\n> +       test_must_fail git checkout --full --path=work1\n> +'\n> +\n> +test_expect_success 'limit worktree to work1 and work2' '\n> +       git checkout --path=\"work1/*:work2/*\" &&\n> +       test -f work1/one &&\n> +       test -f work2/two &&\n> +       ! test -f work3/three\n> +'\n> +\n> +test_expect_success 'update worktree to work2 and work3' '\n> +       git checkout --path=\"work2/*:work3/*\" &&\n> +       ! test -f work1/one &&\n> +       test -f work2/two &&\n> +       test -f work3/three\n> +'\n> +\n> +test_expect_success 'update narrow prefix with modification' '\n> +       echo modified >> work2/two &&\n> +       git checkout --path=\"work1/*:work2/*\" &&\n> +       test -f work1/one &&\n> +       test -f work2/two &&\n> +       ! test -f work3/three &&\n> +       grep -q modified work2/two\n> +'\n> +\n> +test_expect_success 'update narrow should not lose modification' '\n> +       ! git checkout --path=\"work1/*:work3/*\" &&\n> +       test -f work1/one &&\n> +       test -f work2/two &&\n> +       ! test -f work3/three &&\n> +       grep -q modified work2/two\n> +'\n> +\n> +test_expect_success 'widen checkout area' '\n> +       git checkout --add-path=\"work3/*\" &&\n> +       test -f work1/one &&\n> +       test -f work2/two &&\n> +       test -f work3/three\n> +'\n> +\n> +test_expect_success 'narrow checkout area' '\n> +       git checkout --remove-path=\"work3/*\" &&\n> +       test -f work1/one &&\n> +       test -f work2/two &&\n> +       ! test -f work3/three\n> +'\n> +\n> +test_expect_success 'exit narrow checkout' '\n> +       git checkout --full &&\n> +       test -f work1/one &&\n> +       test -f work2/two &&\n> +       test -f work3/three &&\n> +       test one\n> +'\n> +\n> +test_done\n> --\n> 1.6.0.96.g2fad1.dirty\n>\n> --\n> To unsubscribe from this list: send the line \"unsubscribe git\" in\n> the body of a message to majordomo@vger.kernel.org\n> More majordomo info at  http://vger.kernel.org/majordomo-info.html\n>\n"},{"id":"90823","messageId":"48CF879F.6020006@viscovery.net","threadId":"15521","inReplyTo":"1221397685-27715-16-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH 15/16] checkout: add new options to support narrow checkout","fromName":"Johannes Sixt","fromEmail":"j.sixt@viscovery.net","sentAt":"2008-09-16T10:17:03Z","receivedAt":"2008-09-16T10:17:03Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Nguyễn Thái Ngọc Duy schrieb:\n> +--full::\n> +\tQuit narrow checkout mode. Return to full checkout.\n> +\n> +--path=<narrow_spec>::\n> +\tRe-apply new narrow spec on current working directory to\n> +\tform new checkout area.\n> +\n> +--add-path=<narrow_spec>::\n> +\tCheckout more areas specified by narrow spec to current\n> +\tcheckout area.\n> +\n> +--remove-path=<narrow_spec>::\n> +\tNarrow checkout area by removing files specified by narrow spec\n> +\tfrom current checkout area. This operation will fail if there\n> +\tis unmerged or modified files in the removing areas.\n\nThe option --path is named a bit too generic for my taste. How about\n--narrow=...? And how would you like --more= instead of --add-path= and\n--less= instead of --remove-path=? I do think that --full is OK.\n\n-- Hannes\n"},{"id":"90824","messageId":"fcaeb9bf0809160445i29e109d7q2e29964ad3e542fa@mail.gmail.com","threadId":"15521","inReplyTo":"7vsks1b3tq.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH 11/16] unpack_trees(): add support for narrow checkout","fromName":"Nguyen Thai Ngoc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2008-09-16T11:45:55Z","receivedAt":"2008-09-16T11:45:55Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On 9/16/08, Junio C Hamano <gitster@pobox.com> wrote:\n> Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:\n>\n>  > diff --git a/cache.h b/cache.h\n>  > index 2b2c90f..1fc0f83 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>  >   */\n>  > diff --git a/unpack-trees.c b/unpack-trees.c\n>  > index e59d144..968cc98 100644\n>  > --- a/unpack-trees.c\n>  > +++ b/unpack-trees.c\n>  > @@ -96,6 +96,15 @@ static int check_updates(struct unpack_trees_options *o)\n>  >       if (o->update && o->verbose_update) {\n>  >               for (total = cnt = 0; cnt < index->cache_nr; cnt++) {\n>  >                       struct cache_entry *ce = index->cache[cnt];\n>  > +\n>  > +                     if (ce->ce_flags & CE_WD_REMOVE) {\n>  > +                             total++;\n>  > +                             continue;\n>  > +                     }\n>  > +\n>  > +                     if (ce_no_checkout(ce))\n>  > +                             continue;\n>  > +\n>  >                       if (ce->ce_flags & (CE_UPDATE | CE_REMOVE))\n>  >                               total++;\n>  >               }\n>\n>\n> This check for ce_no_checkout() before the existing check to see if\n>  CE_UPDATE and/or CE_REMOVE are on puzzles me (you have the same check\n>  sequence in later loop that does the actualy worktree updates).  If\n>  apply_narrow_checkout() check is working correctly, would we ever give\n>  CE_UPDATE and/or CE_REMOVE bits to a cache entry with CE_NO_CHECKOUT set?\n>\n>  IOW, I think this extra check is Ok as it is expected to be no-op when\n>  combined with the existing check, but it leaves me wondering if it is\n>  hiding some codepath that incorrectly sets CE_UPDATE/CE_REMOVE to an entry\n>  outside the narrow checkout area.\n\nGaaah.. I was confused with older series where verify_uptodate() was\npatched to ignore missing files. You are right, the check is not\nnecessary, will need more test for this. With the current patch, it\nwill fail to merge as soon as some files need to be updated outside\nnarrow area.\n-- \nDuy\n"},{"id":"90825","messageId":"fcaeb9bf0809160500y4b67c621g45b0c6ddf3745a84@mail.gmail.com","threadId":"15521","inReplyTo":"7vljxtb3tf.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH 16/16] ls-files: add --overlay option","fromName":"Nguyen Thai Ngoc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2008-09-16T12:00:03Z","receivedAt":"2008-09-16T12:00:03Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On 9/16/08, Junio C Hamano <gitster@pobox.com> wrote:\n> Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:\n>\n>  > The same situation happens for \"assume unchanged\" bit, but I would\n>  > expect narrow checkout to be more user-friendly and should notify users\n>  > these cases so users will not be confused. On this first step, users\n>\n> > may check by themselves with \"git ls-files --overlay\",...\n>\n>  Could you explain how the earlier --narrow-checkout option introduced in\n>  [05/16] interacts with this one?\n>\n>  The user has X inside narrow area and Y outside.  ls-files reports both X\n>  and Y.  'ls-files --narrow-checkout' reports only X.  Y is tracked but not\n>  really, so 'ls-files --narrow-checkout -o' shouldn't say Y is untracked;\n>  there is no cue to tell between X and Y.\n\nRight, \"ls-files -o\" should not list Y as untracked.\n\n>  But with a half of your patch to 'ls-files -t', you already can show these\n>  potentially stale (leftover from an ancient checkout un-updated because of\n>  narrowness) files.  Could a simpler alternative be to do this processing\n>  not inside \"if (show_deleted/modified)\" part of show_files(), but inside\n>  \"if (show_cached/stage)\" part of it?  Instead of saying tag_cached\n>  unconditionally, if the entry is marked no_checkout, then you would\n>  lstat(2) it there and report that the path is \"marked not to be checked\n>  out but somehow something exists there\".\n\nYes, makes sense.\n\n>  By the way, I do not see an easy way to review what paths are marked with\n>  no-checkout easily from your command set.  It might be worthwhile to add a\n>  new option that iterates over the index, finds a set of common prefixes to\n>  no-checkout entries and reports that set.\n\nWhat is it for? I can only think of it (actually the opposite, find a\nset of common prefixes to checkout entries) as a way to reconstruct\nnarrow spec (simple rules only).\n-- \nDuy\n"},{"id":"90830","messageId":"fcaeb9bf0809160613w3aed3db4g8ce2cb8cfc92818a@mail.gmail.com","threadId":"15521","inReplyTo":"48CF879F.6020006@viscovery.net","subject":"Re: [PATCH 15/16] checkout: add new options to support narrow checkout","fromName":"Nguyen Thai Ngoc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2008-09-16T13:13:33Z","receivedAt":"2008-09-16T13:13:33Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On 9/16/08, Johannes Sixt <j.sixt@viscovery.net> wrote:\n> Nguyễn Thái Ngọc Duy schrieb:\n>\n> > +--full::\n>  > +     Quit narrow checkout mode. Return to full checkout.\n>  > +\n>  > +--path=<narrow_spec>::\n>  > +     Re-apply new narrow spec on current working directory to\n>  > +     form new checkout area.\n>  > +\n>  > +--add-path=<narrow_spec>::\n>  > +     Checkout more areas specified by narrow spec to current\n>  > +     checkout area.\n>  > +\n>  > +--remove-path=<narrow_spec>::\n>  > +     Narrow checkout area by removing files specified by narrow spec\n>  > +     from current checkout area. This operation will fail if there\n>  > +     is unmerged or modified files in the removing areas.\n>\n>\n> The option --path is named a bit too generic for my taste. How about\n>  --narrow=...?\n\n--narrow or --narrow-template (or --checkout-template?) seems good.\n\n> And how would you like --more= instead of --add-path= and\n>  --less= instead of --remove-path=?\n\nNow these --more/--less are too generic to me ;)\n\n> I do think that --full is OK.\n>\n>  -- Hannes\n>\n>\n\n\n-- \nDuy\n"},{"id":"90847","messageId":"7v7i9c6n5p.fsf@gitster.siamese.dyndns.org","threadId":"15521","inReplyTo":"fcaeb9bf0809160500y4b67c621g45b0c6ddf3745a84@mail.gmail.com","subject":"Re: [PATCH 16/16] ls-files: add --overlay option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-09-16T17:00:50Z","receivedAt":"2008-09-16T17:00:50Z","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>>  By the way, I do not see an easy way to review what paths are marked with\n>>  no-checkout easily from your command set.  It might be worthwhile to add a\n>>  new option that iterates over the index, finds a set of common prefixes to\n>>  no-checkout entries and reports that set.\n>\n> What is it for? I can only think of it (actually the opposite, find a\n> set of common prefixes to checkout entries) as a way to reconstruct\n> narrow spec (simple rules only).\n\nThat's the list you can use as input to \"find $them -type f\" to see what\nstale files from previous unnarrowed checkout are on the filesystem.\n\nI agree that the opposite is also interesting and could be useful.  Only\nthe individual index entries remember the area the user told us to check\nout, and I expect that \"what's my narrow area right now?\" would be a\ncommon question users may want to ask.  A full answer can be obtained with\nls-files --narrow, but if we can summarize it into a more concise form, it\nwould be a useful thing to do.\n"}]}