Introduce CE_NO_CHECKOUT bit
A message that is not in the archive (sent off-list or not yet received): [email protected]
PATCH 1/9 Introduce CE_NO_CHECKOUT bit
This bit is the basis of narrow checkout. If this bit is on, the entry is outside narrow checkout and therefore should be ignored (similar to CE_VALID)
--- cache.h | 8 ++++++++ read-cache.c | 6 +++--- 2 files changed, 11 insertions(+), 3 deletions(-)
cache.h +8 -0
@@ -126,6 +126,7 @@ struct cache_entry {#define CE_NAMEMASK (0x0fff)#define CE_STAGEMASK (0x3000) +#define CE_NO_CHECKOUT (0x4000)#define CE_VALID (0x8000)#define CE_STAGESHIFT 12
@@ -138,6 +139,9 @@ struct cache_entry {#define CE_HASHED (0x100000)#define CE_UNHASHED (0x200000) +/* "Assume unchanged" mask */ +#define CE_VALID_MASK (CE_VALID | CE_NO_CHECKOUT) +/* * Copy the sha1 and stat state of a cache entry from one to * another. But we never change the name, or the hash state!
@@ -173,6 +177,10 @@ static inline size_t ce_namelen(const struct cache_entry *ce)#define ondisk_ce_size (ce) ondisk_cache_entry_size(ce_namelen(ce))#define ce_stage (ce) ((CE_STAGEMASK & (ce)->ce_flags) >> CE_STAGESHIFT)#define ce_uptodate (ce) ((ce)->ce_flags & CE_UPTODATE) +#define ce_no_checkout (ce) ((ce)->ce_flags & CE_NO_CHECKOUT) +#define ce_checkout (ce) (!ce_no_checkout(ce)) +#define ce_mark_no_checkout (ce) ((ce)->ce_flags |= CE_NO_CHECKOUT) +#define ce_mark_checkout (ce) ((ce)->ce_flags &= ~CE_NO_CHECKOUT)#define ce_mark_uptodate (ce) ((ce)->ce_flags |= CE_UPTODATE)#define ce_permissions (mode) (((mode) & 0100) ? 0755 : 0644)
read-cache.c +3 -3
@@ -253,7 +253,7 @@ int ie_match_stat(const struct index_state *istate,* If it's marked as always valid in the index, it's * valid whatever the checked-out copy says. */ -if (!ignore_valid && (ce->ce_flags &CE_VALID )) +if (!ignore_valid && (ce->ce_flags &CE_VALID_MASK ))return 0 ; changed =ce_match_stat_basic (ce, st);
@@ -943,10 +943,10 @@ static struct cache_entry *refresh_cache_ent(struct index_state *istate,return ce;/* -* CE_VALID means the user promised us that the change to +* CE_VALID_MASK means the user promised us that the change to * the work tree does not matter and told us not to worry. */ -if (!ignore_valid && (ce->ce_flags &CE_VALID )) { +if (!ignore_valid && (ce->ce_flags &CE_VALID_MASK )) {ce_mark_uptodate (ce);return ce; }
Signature · 1 line
1.6.0.rc3.250.g8dd0
PATCH 2/9 update-index: add --checkout/--no-checkout options to update CE_NO_CHECKOUT bit
In reply to a message not in the archive--- builtin-update-index.c | 40 +++++++++++++++++++++++++--------------- 1 files changed, 25 insertions(+), 15 deletions(-)
builtin-update-index.c +25 -15
@@ -24,8 +24,9 @@ static int info_only;static int force_remove;static int verbose;static int mark_valid_only; -#define MARK_VALID 1 -#define UNMARK_VALID 2 +static int mark_no_checkout_only; +#define MARK_FLAG 1 +#define UNMARK_FLAG 2static void report (const char *fmt, ...) {
@@ -40,19 +41,15 @@ static void report(const char *fmt, ...)va_end (vp); } -static int mark_valid (const char *path) +static int mark_ce_flags (const char *path,int flag,int mark) {int namelen =strlen (path);int pos =cache_name_pos (path, namelen);if (0 <= pos) { -switch (mark_valid_only) { -case MARK_VALID : - active_cache[pos]->ce_flags |=CE_VALID ; -break ; -case UNMARK_VALID : - active_cache[pos]->ce_flags &= ~CE_VALID ; -break ; - } +if (mark) + active_cache[pos]->ce_flags |= flag; +else + active_cache[pos]->ce_flags &= ~flag;cache_tree_invalidate_path (active_cache_tree, path); active_cache_changed =1 ;return 0 ;
@@ -276,7 +273,12 @@ static void update_one(const char *path, const char *prefix, int prefix_length) goto free_return; }if (mark_valid_only) { -if (mark_valid (p)) +if (mark_ce_flags (p,CE_VALID , mark_valid_only ==MARK_FLAG )) +die ("Unable to mark file %s" , path); + goto free_return; + } +if (mark_no_checkout_only) { +if (mark_ce_flags (p,CE_NO_CHECKOUT , mark_no_checkout_only ==MARK_FLAG ))die ("Unable to mark file %s" , path); goto free_return; }
@@ -390,7 +392,7 @@ static void read_index_info(int line_termination) }static const char update_index_usage[] = -"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>..." ; +"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>..." ;static unsigned char head_sha1[20 ];static unsigned char merge_head_sha1[20 ];
@@ -647,11 +649,19 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)continue ; }if (!strcmp (path,"--assume-unchanged" )) { - mark_valid_only =MARK_VALID ; + mark_valid_only =MARK_FLAG ;continue ; }if (!strcmp (path,"--no-assume-unchanged" )) { - mark_valid_only =UNMARK_VALID ; + mark_valid_only =UNMARK_FLAG ; +continue ; + } +if (!strcmp (path,"--checkout" )) { + mark_no_checkout_only =UNMARK_FLAG ; +continue ; + } +if (!strcmp (path,"--no-checkout" )) { + mark_no_checkout_only =MARK_FLAG ;continue ; }if (!strcmp (path,"--info-only" )) {
Signature · 1 line
1.6.0.rc3.250.g8dd0
PATCH 3/9 ls-files: add --checkout option to show checked out files
In reply to a message not in the archive--- builtin-ls-files.c | 13 ++++++++++--- 1 files changed, 10 insertions(+), 3 deletions(-)
builtin-ls-files.c +10 -3
@@ -14,6 +14,7 @@static int abbrev;static int show_deleted;static int show_cached; +static int show_checkout;static int show_others;static int show_stage;static int show_unmerged;
@@ -235,7 +236,7 @@ static void show_files(struct dir_struct *dir, const char *prefix)if (show_killed)show_killed_files (dir); } -if (show_cached | show_stage) { +if (show_cached | show_stage | show_checkout) {for (i =0 ; i < active_nr; i++) {struct cache_entry *ce = active_cache[i];int dtype =ce_to_dtype (ce);
@@ -245,6 +246,8 @@ static void show_files(struct dir_struct *dir, const char *prefix)continue ;if (ce->ce_flags &CE_UPDATE )continue ; +if (show_checkout &&ce_no_checkout (ce)) +continue ;show_ce_entry (ce_stage (ce) ? tag_unmerged : tag_cached, ce); } }
@@ -423,7 +426,7 @@ int report_path_error(const char *ps_matched, const char **pathspec, int prefix_ }static const char ls_files_usage[] = -"git ls-files [-z] [-t] [-v] (--[cached|deleted|others|stage|unmerged|killed|modified])* " +"git ls-files [-z] [-t] [-v] (--[cached|checkout|deleted|others|stage|unmerged|killed|modified])* " "[ --ignored ] [--exclude=<pattern>] [--exclude-from=<file>] " "[ --exclude-per-directory=<filename> ] [--exclude-standard] " "[--full-name] [--abbrev] [--] [<file>]*" ;
@@ -465,6 +468,10 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix) show_cached =1 ;continue ; } +if (!strcmp (arg,"--checkout" )) { + show_checkout =1 ; +continue ; + }if (!strcmp (arg,"-d" ) || !strcmp (arg,"--deleted" )) { show_deleted =1 ;continue ;
@@ -593,7 +600,7 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)/* With no flags, we default to showing the cached files */ if (!(show_stage | show_deleted | show_others | show_unmerged | - show_killed | show_modified)) + show_killed | show_modified | show_checkout)) show_cached =1 ;read_cache ();
Signature · 1 line
1.6.0.rc3.250.g8dd0
PATCH 4/9 Prevent diff machinery from examining worktree outside narrow checkout
In reply to a message not in the archive--- diff-lib.c | 5 +++-- diff.c | 4 +++- 2 files changed, 6 insertions(+), 3 deletions(-)
diff-lib.c +3 -2
@@ -159,7 +159,7 @@ int run_diff_files(struct rev_info *revs, unsigned int option)continue ; } -if (ce_uptodate (ce)) +if (ce_uptodate (ce) ||ce_no_checkout (ce))continue ; changed =check_removed (ce, &st);
@@ -346,6 +346,8 @@ static void do_oneway_diff(struct unpack_trees_options *o,struct rev_info *revs = cbdata->revs;int match_missing, cached; +/* if the entry is not checked out, don't examine work tree */ + cached = o->index_only ||ce_no_checkout (idx);/* * Backward compatibility wart - "diff-index -m" does * not mean "do not ignore merges", but "match_missing".
@@ -353,7 +355,6 @@ static void do_oneway_diff(struct unpack_trees_options *o,* But with the revision flag parsing, that's found in * "!revs->ignore_merges". */ - cached = o->index_only; match_missing = !revs->ignore_merges;if (cached && idx &&ce_stage (idx)) {
diff.c +3 -1
@@ -1716,8 +1716,10 @@ static int reuse_worktree_file(const char *name, const unsigned char *sha1, int/* * If ce matches the file in the work tree, we can reuse it. +* For narrow checkout case, ce_uptodate() may be true although +* the file may or may not exist in the work tree. */ -if (ce_uptodate (ce) || +if ((ce_uptodate (ce) &&ce_checkout (ce)) || (!lstat (name, &st) && !ce_match_stat (ce, &st,0 )))return 1 ;
Signature · 1 line
1.6.0.rc3.250.g8dd0
PATCH 5/9 Clear CE_NO_CHECKOUT on checked out entries.
In reply to a message not in the archiveWith this you can just do "git checkout some-files" to widen your checkout. On caveat though: caller must save the index.
--- entry.c | 1 + 1 files changed, 1 insertions(+), 0 deletions(-)
entry.c +1 -0
@@ -230,5 +230,6 @@ int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *t }else if (state->not_new)return 0 ;create_directories (path, state); +ce_mark_checkout (ce);return write_entry (ce, path, state,0 ); }
Signature · 1 line
1.6.0.rc3.250.g8dd0
PATCH 6/9 Add support for narrow checkout in unpack_trees()
In reply to a message not in the archiveThis patch teaches unpack_trees() to checkout/remove entries on working directories appropriately when narrow area is changed. There are three kind of changes:
- new_narrow_path: reset workdir to a new narrow checkout
- add_narrow_path: keep current narrow areas and add more entries
- remove_narrow_path: remove some entries from current narrow areas
CE_WD_REMOVE is introduced to remove entries from working directories, but still keep them in index
--- cache.h | 3 ++ unpack-trees.c | 106 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ unpack-trees.h | 4 ++ 3 files changed, 113 insertions(+), 0 deletions(-)
cache.h +3 -0
@@ -139,6 +139,9 @@ struct cache_entry {#define CE_HASHED (0x100000)#define CE_UNHASHED (0x200000) +/* Only remove in work directory, not index */ +#define CE_WD_REMOVE (0x400000) +/* "Assume unchanged" mask */ #define CE_VALID_MASK (CE_VALID | CE_NO_CHECKOUT)
unpack-trees.c +106 -0
160 lines not on this page · raw message
unpack-trees.h +4 -0
@@ -26,6 +26,9 @@ struct unpack_trees_options { verbose_update:1, aggressive:1, skip_unmerged:1, + new_narrow_path:1, + add_narrow_path:2, + remove_narrow_path:2, gently:1;const char *prefix;int pos;
@@ -37,6 +40,7 @@ struct unpack_trees_options {int merge_size;struct cache_entry *df_conflict_entry; +const char *narrow_spec;void *unpack_data;struct index_state *dst_index;
Signature · 1 line
1.6.0.rc3.250.g8dd0
PATCH 7/9 ls-files: add --narrow-match=spec option to test narrow matching
In reply to a message not in the archive--- builtin-ls-files.c | 10 +++++++++- 1 files changed, 9 insertions(+), 1 deletions(-)
builtin-ls-files.c +9 -1
@@ -29,6 +29,7 @@ static const char **pathspec;static int error_unmatch;static char *ps_matched;static const char *with_tree; +static const char *narrow_spec;static const char *tag_cached ="" ;static const char *tag_unmerged ="" ;
@@ -219,6 +220,7 @@ static void show_ce_entry(const char *tag, struct cache_entry *ce)write_name_quoted (ce->name + offset, stdout, line_terminator); } +int match_narrow_spec (const char *spec_,const char *path);/* unpack-trees.c */ static void show_files (struct dir_struct *dir,const char *prefix) {int i;
@@ -248,6 +250,8 @@ static void show_files(struct dir_struct *dir, const char *prefix)continue ;if (show_checkout &&ce_no_checkout (ce))continue ; +if (narrow_spec && !match_narrow_spec (narrow_spec, ce->name)) +continue ;show_ce_entry (ce_stage (ce) ? tag_unmerged : tag_cached, ce); } }
@@ -429,7 +433,7 @@ static const char ls_files_usage[] ="git ls-files [-z] [-t] [-v] (--[cached|checkout|deleted|others|stage|unmerged|killed|modified])* " "[ --ignored ] [--exclude=<pattern>] [--exclude-from=<file>] " "[ --exclude-per-directory=<filename> ] [--exclude-standard] " -"[--full-name] [--abbrev] [--] [<file>]*" ; +"[--narrow-match=narrowspec] [--full-name] [--abbrev] [--] [<file>]*" ;int cmd_ls_files (int argc,const char **argv,const char *prefix) {
@@ -472,6 +476,10 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix) show_checkout =1 ;continue ; } +if (!prefixcmp (arg,"--narrow-match=" )) { + narrow_spec = arg+15 ; +continue ; + }if (!strcmp (arg,"-d" ) || !strcmp (arg,"--deleted" )) { show_deleted =1 ;continue ;
Signature · 1 line
1.6.0.rc3.250.g8dd0
PATCH 8/9 clone: support narrow checkout with --path option
In reply to a message not in the archive--- builtin-clone.c | 13 +++++++++++++ 1 files changed, 13 insertions(+), 0 deletions(-)
builtin-clone.c +13 -0
@@ -36,6 +36,7 @@ static const char * const builtin_clone_usage[] = {static int option_quiet, option_no_checkout, option_bare, option_mirror;static int option_local, option_no_hardlinks, option_shared;static char *option_template, *option_reference, *option_depth; +static char *option_narrow_path;static char *option_origin =NULL ;static char *option_upload_pack ="git-upload-pack" ;
@@ -43,6 +44,8 @@ static struct option builtin_clone_options[] = {OPT__QUIET (&option_quiet),OPT_BOOLEAN ('n' ,"no-checkout" , &option_no_checkout,"don't create a checkout" ), +OPT_STRING (0 ,"path" , &option_narrow_path,"prefixes" , +"limit checkout to specified paths (narrow checkout)" ),OPT_BOOLEAN (0 ,"bare" , &option_bare,"create a bare repository" ),OPT_BOOLEAN (0 ,"naked" , &option_bare,"create a bare repository" ), OPT_BOOLEAN(0, "mirror", &option_mirror,
@@ -376,10 +379,15 @@ int cmd_clone(int argc, const char **argv, const char *prefix)if (option_origin)die ("--bare and --origin %s options are incompatible." , option_origin); +if (option_narrow_path) +die ("--bare and --path options are incompatible." ); option_no_checkout =1 ; use_separate_remote =0 ; } +if (option_no_checkout && option_narrow_path) +die ("--no-checkout and --path options are incompatible." ); +if (!option_origin) option_origin ="origin" ;
@@ -586,6 +594,11 @@ int cmd_clone(int argc, const char **argv, const char *prefix) opts.src_index = &the_index; opts.dst_index = &the_index; +if (option_narrow_path) { + opts.new_narrow_path =1 ; + opts.narrow_spec = option_narrow_path; + } + tree =parse_tree_indirect (remote_head->old_sha1);parse_tree (tree);init_tree_desc (&t, tree->buffer, tree->size);
Signature · 1 line
1.6.0.rc3.250.g8dd0
PATCH 9/9 checkout: add new options to support narrow checkout
In reply to a message not in the archiveThese options include:
--full: return to full checkout (default)
--path: narrow checkout to some areas according to given spec --add-path/--remove-path: adjust current narrow checkout
--- builtin-checkout.c | 41 +++++++++++++++++++++++++++++++++++++++++ 1 files changed, 41 insertions(+), 0 deletions(-)
builtin-checkout.c +41 -0
@@ -160,6 +160,11 @@ struct checkout_opts {char *new_branch;int new_branch_log;enum branch_track track; + +char *new_path; +char *add_path; +char *remove_path; +int no_narrow_checkout; };static int reset_tree (struct tree *tree,struct checkout_opts *o,int worktree)
@@ -255,6 +260,23 @@ static int merge_working_tree(struct checkout_opts *opts, tree =parse_tree_indirect (new->commit->object.sha1);init_tree_desc (&trees[1 ], tree->buffer, tree->size); +if (opts->no_narrow_checkout) { +/* leave narrow_spec NULL */ + topts.new_narrow_path =1 ; + } +else if (opts->new_path) { + topts.narrow_spec = opts->new_path; + topts.new_narrow_path =1 ; + } +else if (opts->add_path) { + topts.narrow_spec = opts->add_path; + topts.add_narrow_path =1 ; + } +else if (opts->remove_path) { + topts.narrow_spec = opts->remove_path; + topts.remove_narrow_path =1 ; + } + ret =unpack_trees (2 , trees, &topts);if (ret ==-1 ) {/*
@@ -428,6 +450,10 @@ int cmd_checkout(int argc, const char **argv, const char *prefix) BRANCH_TRACK_EXPLICIT),OPT_BOOLEAN ('f' ,NULL , &opts.force,"force" ),OPT_BOOLEAN ('m' ,NULL , &opts.merge,"merge" ), +OPT_BOOLEAN (0 ,"full" , &opts.no_narrow_checkout,"quit sparse checkout" ), +OPT_STRING (0 ,"path" , &opts.new_path,"prefixes" ,"apply new narrow checkout path" ), +OPT_STRING (0 ,"add-path" , &opts.add_path,"prefixes" ,"add more checkout area" ), +OPT_STRING (0 ,"remove-path" , &opts.remove_path,"prefixes" ,"narrow checkout area" ), OPT_END(), };int has_dash_dash;
@@ -460,6 +486,18 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)if (opts.track ==-1 ) opts.track = git_branch_track; +if (((opts.no_narrow_checkout ?1 :0 ) + + (opts.new_path ?1 :0 ) + + (opts.add_path ?1 :0 ) + + (opts.remove_path ?1 :0 )) >1 ) +die ("git checkout: --path, --full, --add-path and --remove-path are incompatible" ); + +if (opts.new_branch && (opts.add_path || opts.remove_path)) +die ("git checkout: --add-path and --remove-path should only be used on current branch" ); + +if (opts.new_branch && opts.no_narrow_checkout) +die ("git checkout: switching branch with --full does not make sense" ); +if (opts.force && opts.merge)die ("git checkout: -f and -m are incompatible" );
@@ -550,6 +588,9 @@ no_reference: } } +if (opts.no_narrow_checkout || opts.new_path || opts.add_path || opts.remove_path) +die ("git checkout: updating paths is incompatible with setting sparse checkout" ); +return checkout_paths (source_tree, pathspec); }
Signature · 1 line
1.6.0.rc3.250.g8dd0