@@ -172,29 +172,29 @@ static int process_directory(const char *path, int len, struct stat *st)returnerror("%s: is a directory - add files inside instead",path);}-/*-*Processaregularfile-*/-staticintprocess_file(constchar*path,intlen,structstat*st)-{-intpos=cache_name_pos(path,len);-structcache_entry*ce=pos<0?NULL:active_cache[pos];--if(ce&&S_ISGITLINK(ce->ce_mode))-returnerror("%s is already a gitlink, not replacing",path);--returnadd_one_path(ce,path,len,st);-}-staticintprocess_path(constchar*path){-intlen;+intpos,len;structstatst;+structcache_entry*ce;len=strlen(path);if(has_symlink_leading_path(path,len))returnerror("'%s' is beyond a symbolic link",path);+pos=cache_name_pos(path,len);+ce=pos<0?NULL:active_cache[pos];+if(ce&&ce_skip_worktree(ce)){+/*+*workingdirectoryversionisassumed"good"+*soupdatingitdoesnotmakesense.+*Ontheotherhand,removingitfromindexshouldwork+*/+if(allow_remove&&remove_file_from_cache(path))+returnerror("%s: cannot remove from the index",path);+return0;+}+/**Firstthingsfirst:getthestatinformation,todecide*whattodoaboutthepathname!
@@ -205,7 +205,13 @@ static int process_path(const char *path)if(S_ISDIR(st.st_mode))returnprocess_directory(path,len,&st);-returnprocess_file(path,len,&st);+/*+*Processaregularfile+*/+if(ce&&S_ISGITLINK(ce->ce_mode))+returnerror("%s is already a gitlink, not replacing",path);++returnadd_one_path(ce,path,len,&st);}staticintadd_cacheinfo(unsignedintmode,constunsignedchar*sha1,
There is nothing much to do when the index is committed as-is. But
when partial commit is used, the index will be reset to HEAD. This
leads to loss of skip-worktree bits in the original index. Those bits
are kept (for committed paths only) so git-commit will know which
paths to ignore later on.
Signed-off-by: Nguyễn Thái Ngọc Duy <redacted>
---
builtin-commit.c | 11 +++++++++--
t/t7011-skip-worktree-reading.sh | 12 ++++++++++++
2 files changed, 21 insertions(+), 2 deletions(-)
@@ -152,7 +152,7 @@ static int commit_index_files(void)staticintlist_paths(structstring_list*list,constchar*with_tree,constchar*prefix,constchar**pattern){-inti;+staticinti;char*m;for(i=0;pattern[i];i++)
@@ -164,11 +164,15 @@ static int list_paths(struct string_list *list, const char *with_tree,for(i=0;i<active_nr;i++){structcache_entry*ce=active_cache[i];+structstring_list_item*item;+if(ce->ce_flags&CE_UPDATE)continue;if(!match_pathspec(pattern,ce->name,ce_namelen(ce),0,m))continue;-string_list_insert(ce->name,list);+item=string_list_insert(ce->name,list);+if(ce_skip_worktree(ce))+item->util=&i;/* better a valid pointer than a fake one */}returnreport_path_error(m,pattern,prefix?strlen(prefix):0);
This patch introduces core.sparseCheckout, which will control whether
sparse checkout support is enabled in unpack_trees()
It also loads sparse-checkout file that will be used in the next patch.
I split it out so the next patch will be shorter, easier to read.
Signed-off-by: Nguyễn Thái Ngọc Duy <redacted>
Signed-off-by: Junio C Hamano <redacted>
---
Documentation/config.txt | 4 ++++
Documentation/git-read-tree.txt | 4 +++-
cache.h | 1 +
config.c | 5 +++++
environment.c | 1 +
unpack-trees.c | 36 ++++++++++++++++++++++++++++++------
unpack-trees.h | 4 ++++
7 files changed, 48 insertions(+), 7 deletions(-)
@@ -439,6 +439,10 @@ On some file system/operating system combinations, this is unreliable. Set this config setting to 'rename' there; However, This will remove the check that makes sure that existing object files will not get overwritten.+core.sparseCheckout::+ Enable "sparse checkout" feature. See section "Sparse checkout" in+ linkgit:git-read-tree[1] for more information.+ add.ignore-errors:: Tells 'git-add' to continue adding files when some files cannot be added due to indexing errors. Equivalent to the '--ignore-errors'
@@ -401,7 +401,9 @@ follows: ---------------- Then you can disable sparse checkout. Sparse checkout support in "git-read-tree" and similar commands is disabled by default.+read-tree" and similar commands is disabled by default. You need to+turn `core.sparseCheckout` on in order to have sparse checkout+support. SEE ALSO
@@ -503,6 +503,11 @@ static int git_default_core_config(const char *var, const char *value)return0;}+if(!strcmp(var,"core.sparsecheckout")){+core_apply_sparse_checkout=git_config_bool(var,value);+return0;+}+/* Add other config variables here and to Documentation/config.txt. */return0;}
@@ -48,6 +48,7 @@ enum push_default_type push_default = PUSH_DEFAULT_MATCHING;#endifenumobject_creation_modeobject_creation_mode=OBJECT_CREATION_MODE;intgrafts_replace_parents=1;+intcore_apply_sparse_checkout;/* Parallel index stat data preload? */intcore_preload_index=0;
CE_REMOVE now removes both worktree and index versions. Sparse
checkout must be able to remove worktree version while keep the
index intact when checkout area is narrowed.
Signed-off-by: Nguyễn Thái Ngọc Duy <redacted>
Signed-off-by: Junio C Hamano <redacted>
---
cache.h | 3 +++
unpack-trees.c | 9 ++++++++-
2 files changed, 11 insertions(+), 1 deletions(-)
@@ -177,6 +177,9 @@ struct cache_entry {#define CE_HASHED (0x100000)#define CE_UNHASHED (0x200000)+/* Only remove in work directory, not index */+#define CE_WT_REMOVE (0x400000)+/**Extendedon-diskflags*/
With skip-worktree bit, you can manually set it to unwanted files,
then remove them: you would have the so-called sparse checkout. The
disadvantages are:
- Porcelain tools are not aware of this. Everytime you do an
operation that may update working directory, skip-worktree may be
cleared out. You have to set them again.
- You still have to remove skip-worktree'd files manually, which is
boring and ineffective.
These will be addressed in the following patches. This patch gives an
idea what is "sparse checkout" in Documentation/git-read-tree.txt.
This file is chosen instead of git-checkout.txt because it is quite
technical and user-unfriendly. I'd expect git-checkout.txt to have
something when Porcelain support is done.
Signed-off-by: Nguyễn Thái Ngọc Duy <redacted>
Signed-off-by: Junio C Hamano <redacted>
---
Documentation/git-read-tree.txt | 44 +++++++++++++++++++++++++++++++++++++++
1 files changed, 44 insertions(+), 0 deletions(-)
@@ -360,6 +360,50 @@ middle of doing, and when your working tree is ready (i.e. you have finished your work-in-progress), attempt the merge again.+Sparse checkout+---------------++"Sparse checkout" allows to sparsely populate working directory.+It uses skip-worktree bit (see linkgit:git-update-index[1]) to tell+Git whether a file on working directory is worth looking at.++"git read-tree" and other merge-based commands ("git merge", "git+checkout"...) can help maintaining skip-worktree bitmap and working+directory update. `$GIT_DIR/info/sparse-checkout` is used to+define the skip-worktree reference bitmap. When "git read-tree" needs+to update working directory, it will reset skip-worktree bit in index+based on this file, which uses the same syntax as .gitignore files.+If an entry matches a pattern in this file, skip-worktree will be+set on that entry. Otherwise, skip-worktree will be unset.++Then it compares the new skip-worktree value with the previous one. If+skip-worktree turns from unset to set, it will add the corresponding+file back. If it turns from set to unset, that file will be removed.++While `$GIT_DIR/info/sparse-checkout` is usually used to specify what+files are in. You can also specify what files are _not_ in, using+negate patterns. For example, to remove file "unwanted":++----------------+*+!unwanted+----------------++Another tricky thing is fully repopulating working directory when you+no longer want sparse checkout. You cannot just disable "sparse+checkout" because skip-worktree are still in the index and you working+directory is still sparsely populated. You should re-populate working+directory with the `$GIT_DIR/info/sparse-checkout` file content as+follows:++----------------+*+----------------++Then you can disable sparse checkout. Sparse checkout support in "git+read-tree" and similar commands is disabled by default.++ SEE ALSO -------- linkgit:git-write-tree[1]; linkgit:git-ls-files[1];
These functions are used to handle .gitignore. They are now exported
so that sparse checkout can reuse.
Signed-off-by: Nguyễn Thái Ngọc Duy <redacted>
Signed-off-by: Junio C Hamano <redacted>
---
dir.c | 32 ++++++++++++++++----------------
dir.h | 4 ++++
2 files changed, 20 insertions(+), 16 deletions(-)
@@ -274,8 +274,8 @@ static int add_excludes_from_file_1(const char *fname,voidadd_excludes_from_file(structdir_struct*dir,constchar*fname){-if(add_excludes_from_file_1(fname,"",0,NULL,-&dir->exclude_list[EXC_FILE],0)<0)+if(add_excludes_from_file_to_list(fname,"",0,NULL,+&dir->exclude_list[EXC_FILE],0)<0)die("cannot use %s as an exclude file",fname);}
@@ -336,9 +336,9 @@ static void prep_exclude(struct dir_struct *dir, const char *base, int baselen)/* Scan the list and let the last match determine the fate.*Return1forexclude,0forincludeand-1forundecided.*/-staticintexcluded_1(constchar*pathname,-intpathlen,constchar*basename,int*dtype,-structexclude_list*el)+intexcluded_from_list(constchar*pathname,+intpathlen,constchar*basename,int*dtype,+structexclude_list*el){inti;
@@ -412,8 +412,8 @@ int excluded(struct dir_struct *dir, const char *pathname, int *dtype_p)prep_exclude(dir,pathname,basename-pathname);for(st=EXC_CMDL;st<=EXC_FILE;st++){-switch(excluded_1(pathname,pathlen,basename,-dtype_p,&dir->exclude_list[st])){+switch(excluded_from_list(pathname,pathlen,basename,+dtype_p,&dir->exclude_list[st])){case0:return0;case1:
This part is mainly to remove CE_VALID shortcuts (and as a
consequence, ce_uptodate() shortcuts as it may be turned on by
CE_VALID) in writing code path if skip-worktree is used. Various tests
are added to avoid future breakages.
Signed-off-by: Nguyễn Thái Ngọc Duy <redacted>
Signed-off-by: Junio C Hamano <redacted>
---
t/t7012-skip-worktree-writing.sh | 139 ++++++++++++++++++++++++++++++++++++++
unpack-trees.c | 4 +-
2 files changed, 141 insertions(+), 2 deletions(-)
create mode 100755 t/t7012-skip-worktree-writing.sh
In this code path, we would remove "old" and replace it with "merge".
"old" may have skip-worktree bit, so re-add it to "merge".
Signed-off-by: Nguyễn Thái Ngọc Duy <redacted>
Signed-off-by: Junio C Hamano <redacted>
---
unpack-trees.c | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)
Index does not really have "directories", attempts to match "foo/"
against index will fail unless someone tries to reconstruct directories
from a list of file.
Observing that dtype in this function can never be NULL (otherwise
it would segfault), dtype NULL will be used to say "hey.. you are
matching against index" and behave properly.
Signed-off-by: Nguyễn Thái Ngọc Duy <redacted>
Signed-off-by: Junio C Hamano <redacted>
---
dir.c | 6 ++++++
1 files changed, 6 insertions(+), 0 deletions(-)
In the next patch, the buffer that is being used within
add_excludes_from_file_1() comes from another function and does not
have extra space to put \n at the end.
Signed-off-by: Nguyễn Thái Ngọc Duy <redacted>
Signed-off-by: Junio C Hamano <redacted>
---
dir.c | 5 ++---
1 files changed, 2 insertions(+), 3 deletions(-)
This adds index as a prerequisite for directory listing (with
exclude). At the moment directory listing is used by "git clean",
"git add", "git ls-files" and "git status"/"git commit" and
unpack_trees()-related commands. These commands have been
checked/modified to populate index before doing directory listing.
add_excludes_from_file() does not enable this feature, because it
is used to read .git/info/exclude and some explicit files specified
by "git ls-files".
Signed-off-by: Nguyễn Thái Ngọc Duy <redacted>
Signed-off-by: Junio C Hamano <redacted>
---
Documentation/technical/api-directory-listing.txt | 3 +
builtin-clean.c | 4 +-
builtin-ls-files.c | 4 +-
dir.c | 65 ++++++++++++++------
t/t3001-ls-files-others-exclude.sh | 22 +++++++
t/t7300-clean.sh | 19 ++++++
6 files changed, 95 insertions(+), 22 deletions(-)
@@ -58,6 +58,9 @@ The result of the enumeration is left in these fields:: Calling sequence ----------------+Note: index may be looked at for .gitignore files that are CE_SKIP_WORKTREE+marked. If you to exclude files, make sure you have loaded index first.+ * Prepare `struct dir_struct dir` and clear it with `memset(&dir, 0, sizeof(dir))`.
@@ -513,7 +516,6 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)pathspec=get_pathspec(prefix,argv);/* be nice with submodule paths ending in a slash */-read_cache();if(pathspec)strip_trailing_slash_from_submodules();
@@ -212,20 +236,26 @@ static int add_excludes_from_file_1(const char *fname,char*buf,*entry;fd=open(fname,O_RDONLY);-if(fd<0||fstat(fd,&st)<0)-gotoerr;-size=xsize_t(st.st_size);-if(size==0){-close(fd);-return0;+if(fd<0||fstat(fd,&st)<0){+if(0<=fd)+close(fd);+if(!check_index||+(buf=read_skip_worktree_file_from_index(fname,&size))==NULL)+return-1;}-buf=xmalloc(size+1);-if(read_in_full(fd,buf,size)!=size)-{-free(buf);-gotoerr;+else{+size=xsize_t(st.st_size);+if(size==0){+close(fd);+return0;+}+buf=xmalloc(size);+if(read_in_full(fd,buf,size)!=size){+close(fd);+return-1;+}+close(fd);}-close(fd);if(buf_p)*buf_p=buf;
@@ -240,17 +270,12 @@ static int add_excludes_from_file_1(const char *fname,}}return0;--err:-if(0<=fd)-close(fd);-return-1;}voidadd_excludes_from_file(structdir_struct*dir,constchar*fname){if(add_excludes_from_file_1(fname,"",0,NULL,-&dir->exclude_list[EXC_FILE])<0)+&dir->exclude_list[EXC_FILE],0)<0)die("cannot use %s as an exclude file",fname);}
@@ -107,6 +107,7 @@ OPTIONS Identify the file status with the following tags (followed by a space) at the start of each line: H:: cached+ S:: skip-worktree M:: unmerged R:: removed/deleted C:: modified/changed
@@ -99,6 +100,13 @@ in the index e.g. when merging in a commit; thus, in case the assumed-untracked file is changed upstream, you will need to handle the situation manually.+--skip-worktree::+--no-skip-worktree::+ When one of these flags is specified, the object name recorded+ for the paths are not updated. Instead, these options+ set and unset the "skip-worktree" bit for the paths. See+ section "Skip-worktree bit" below for more information.+ -g:: --again:: Runs 'git-update-index' itself on the paths whose index
@@ -304,6 +312,27 @@ M foo.c <9> now it checks with lstat(2) and finds it has been changed.+Skip-worktree bit+-----------------++Skip-worktree bit can be defined in one (long) sentence: When reading+an entry, if it is marked as skip-worktree, then Git pretends its+working directory version is up to date and read the index version+instead.++To elaborate, "reading" means checking for file existence, reading+file attributes or file content. The working directory version may be+present or absent. If present, its content may match against the index+version or not. Writing is not affected by this bit, content safety+is still first priority. Note that Git _can_ update working directory+file, that is marked skip-worktree, if it is safe to do so (i.e.+working directory version matches index version)++Although this bit looks similar to assume-unchanged bit, its goal is+different from assume-unchanged bit's. Skip-worktree also takes+precedence over assume-unchanged bit when both are set.++ Configuration -------------
@@ -276,6 +277,11 @@ static void update_one(const char *path, const char *prefix, int prefix_length)die("Unable to mark file %s",path);gotofree_return;}+if(mark_skip_worktree_only){+if(mark_ce_flags(p,CE_SKIP_WORKTREE,mark_skip_worktree_only==MARK_FLAG))+die("Unable to mark file %s",path);+gotofree_return;+}if(force_remove){if(remove_file_from_cache(p))
@@ -0,0 +1,57 @@+#!/bin/sh+#+# Copyright (c) 2008 Nguyễn Thái Ngọc Duy+#++test_description='skip-worktree bit test'++../test-lib.sh++cat>expect.full<<EOF+H1+H2+Hsub/1+Hsub/2+EOF++cat>expect.skip<<EOF+S1+H2+Ssub/1+Hsub/2+EOF++test_expect_success'setup''+mkdirsub&&+touch./1./2sub/1sub/2&&+gitadd12sub/1sub/2&&+gitls-files-t|test_cmpexpect.full-+'++test_expect_success'index is at version 2''+test"$(test-index-version<.git/index)"=2+'++test_expect_success'update-index --skip-worktree''+gitupdate-index--skip-worktree1sub/1&&+gitls-files-t|test_cmpexpect.skip-+'++test_expect_success'index is at version 3 after having some skip-worktree entries''+test"$(test-index-version<.git/index)"=3+'++test_expect_success'ls-files -t''+gitls-files-t|test_cmpexpect.skip-+'++test_expect_success'update-index --no-skip-worktree''+gitupdate-index--no-skip-worktree1sub/1&&+gitls-files-t|test_cmpexpect.full-+'++test_expect_success'index version is back to 2 when there is no skip-worktree entry''+test"$(test-index-version<.git/index)"=2+'++test_done
The way sparse checkout works, users may empty their worktree
completely, because of non-matching sparse-checkout spec, or empty
spec. I believe this is not desired. This patch makes Git refuse to
produce such worktree.
Signed-off-by: Nguyễn Thái Ngọc Duy <redacted>
Signed-off-by: Junio C Hamano <redacted>
---
t/t1011-read-tree-sparse-checkout.sh | 10 +++-------
unpack-trees.c | 7 +++++++
2 files changed, 10 insertions(+), 7 deletions(-)
@@ -512,8 +513,14 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options*/if(ce_skip_worktree(ce))ce->ce_flags&=~(CE_UPDATE|CE_REMOVE);+else+empty_worktree=0;}+if(o->result.cache_nr&&empty_worktree){+ret=unpack_failed(o,"Sparse checkout leaves no entry on working directory");+gotodone;+}}o->src_index=NULL;
@@ -110,6 +110,10 @@ OPTIONS directories the index file and index output file are located in.+--no-sparse-checkout::+ Disable sparse checkout support even if `core.sparseCheckout`+ is true.+ <tree-ish#>:: The id of the tree object(s) to be read/merged.
@@ -98,6 +98,8 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)PARSE_OPT_NONEG,exclude_per_directory_cb},OPT_SET_INT('i',NULL,&opts.index_only,"don't check the working tree after merging",1),+OPT_SET_INT(0,"no-sparse-checkout",&opts.skip_sparse_checkout,+"skip applying sparse checkout filter",1),OPT_END()};
verify_absent() and verify_uptodate() are used to ensure worktree
is safe to be updated, then CE_REMOVE or CE_UPDATE will be set.
Finally check_updates() bases on CE_REMOVE, CE_UPDATE and the
recently added CE_WT_REMOVE to update working directory accordingly.
The entries that are checked may eventually be left out of checkout
area (done later in apply_sparse_checkout()). We don't want to update
outside checkout area. This patch teaches Git to assume "good",
skip these checks when it's sure those entries will be outside checkout
area, and clear CE_REMOVE|CE_UPDATE that could be set due to this
assumption.
Signed-off-by: Nguyễn Thái Ngọc Duy <redacted>
Signed-off-by: Junio C Hamano <redacted>
---
unpack-trees.c | 12 ++++++++++++
1 files changed, 12 insertions(+), 0 deletions(-)
@@ -0,0 +1,154 @@+#!/bin/sh++test_description='sparse checkout tests'++../test-lib.sh++cat>expected<<EOF+10064477f0ba1734ed79d12881f81b36ee134de6a3327b0init.t+100644e69de29bb2d1d6434b8b29ae775ad8c2e48c53910sub/added+EOF+test_expect_success'setup''+test_commitinit&&+echomodified>>init.t&&+mkdirsub&&+touchsub/added&&+gitaddinit.tsub/added&&+gitcommit-m"modified and added"&&+gittagtop&&+gitrmsub/added&&+gitcommit-mremoved&&+gittagremoved&&+gitcheckouttop&&+gitls-files--stage>result&&+test_cmpexpectedresult+'++cat>expected.swt<<EOF+Hinit.t+Hsub/added+EOF+test_expect_success'read-tree without .git/info/sparse-checkout''+gitread-tree-m-uHEAD&&+gitls-files--stage>result&&+test_cmpexpectedresult&&+gitls-files-t>result&&+test_cmpexpected.swtresult+'++test_expect_success'read-tree with .git/info/sparse-checkout but disabled''+echo>.git/info/sparse-checkout+gitread-tree-m-uHEAD&&+gitls-files-t>result&&+test_cmpexpected.swtresult&&+test-finit.t&&+test-fsub/added+'++test_expect_success'read-tree --no-sparse-checkout with empty .git/info/sparse-checkout and enabled''+gitconfigcore.sparsecheckouttrue&&+echo>.git/info/sparse-checkout&&+gitread-tree--no-sparse-checkout-m-uHEAD&&+gitls-files-t>result&&+test_cmpexpected.swtresult&&+test-finit.t&&+test-fsub/added+'++cat>expected.swt<<EOF+Sinit.t+Ssub/added+EOF+test_expect_success'read-tree with empty .git/info/sparse-checkout''+gitconfigcore.sparsecheckouttrue&&+echo>.git/info/sparse-checkout&&+gitread-tree-m-uHEAD&&+gitls-files--stage>result&&+test_cmpexpectedresult&&+gitls-files-t>result&&+test_cmpexpected.swtresult&&+test!-finit.t&&+test!-fsub/added+'++cat>expected.swt<<EOF+Sinit.t+Hsub/added+EOF+test_expect_success'match directories with trailing slash''+echosub/>.git/info/sparse-checkout&&+gitread-tree-m-uHEAD&&+gitls-files-t>result&&+test_cmpexpected.swtresult&&+test!-finit.t&&+test-fsub/added+'++cat>expected.swt<<EOF+Hinit.t+Hsub/added+EOF+test_expect_failure'match directories without trailing slash''+echoinit.t>.git/info/sparse-checkout&&+echosub>>.git/info/sparse-checkout&&+gitread-tree-m-uHEAD&&+gitls-files-t>result&&+test_cmpexpected.swtresult&&+test!-finit.t&&+test-fsub/added+'++cat>expected.swt<<EOF+Hinit.t+Ssub/added+EOF+test_expect_success'checkout area changes''+echoinit.t>.git/info/sparse-checkout&&+gitread-tree-m-uHEAD&&+gitls-files-t>result&&+test_cmpexpected.swtresult&&+test-finit.t&&+test!-fsub/added+'++test_expect_success'read-tree updates worktree, absent case''+echosub/added>.git/info/sparse-checkout&&+gitcheckout-ftop&&+gitread-tree-m-uHEAD^&&+test!-finit.t+'++test_expect_success'read-tree updates worktree, dirty case''+echosub/added>.git/info/sparse-checkout&&+gitcheckout-ftop&&+echodirty>init.t&&+gitread-tree-m-uHEAD^&&+grep-qdirtyinit.t&&+rminit.t+'++test_expect_success'read-tree removes worktree, dirty case''+echoinit.t>.git/info/sparse-checkout&&+gitcheckout-ftop&&+echodirty>added&&+gitread-tree-m-uHEAD^&&+grep-qdirtyadded+'++test_expect_success'read-tree adds to worktree, absent case''+echoinit.t>.git/info/sparse-checkout&&+gitcheckout-fremoved&&+gitread-tree-u-mHEAD^&&+test!-fsub/added+'++test_expect_success'read-tree adds to worktree, dirty case''+echoinit.t>.git/info/sparse-checkout&&+gitcheckout-fremoved&&+mkdirsub&&+echodirty>sub/added&&+gitread-tree-u-mHEAD^&&+grep-qdirtysub/added+'++test_done
@@ -462,6 +462,8 @@ extern int index_name_is_other(const struct index_state *, const char *, int);#define CE_MATCH_IGNORE_VALID 01/* do not check the contents but report dirty on racily-clean entries */#define CE_MATCH_RACY_IS_DIRTY 02+/* do stat comparison even if CE_SKIP_WORKTREE is true */+#define CE_MATCH_IGNORE_SKIP_WORKTREE 04externintie_match_stat(conststructindex_state*,structcache_entry*,structstat*,unsignedint);externintie_modified(conststructindex_state*,structcache_entry*,structstat*,unsignedint);
@@ -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_skip_worktree(ce))continue;/* If CE_VALID is set, don't look at workdir for file removal */
@@ -339,7 +339,8 @@ static void do_oneway_diff(struct unpack_trees_options *o,intmatch_missing,cached;/* if the entry is not checked out, don't examine work tree */-cached=o->index_only||(idx&&(idx->ce_flags&CE_VALID));+cached=o->index_only||+(idx&&((idx->ce_flags&CE_VALID)||ce_skip_worktree(idx)));/**Backwardcompatibilitywart-"diff-index -m"does*notmean"do not ignore merges",but"match_missing".
@@ -111,4 +111,27 @@ test_expect_success 'ls-files --modified' 'test-z"$(gitls-files-m)"'+echo":000000 100644 $ZERO_SHA1$NULL_SHA1 A 1">expected+test_expect_success'diff-index does not examine skip-worktree absent entries''+setup_absent&&+gitdiff-indexHEAD--1>result&&+test_cmpexpectedresult+'++test_expect_success'diff-index does not examine skip-worktree dirty entries''+setup_dirty&&+gitdiff-indexHEAD--1>result&&+test_cmpexpectedresult+'++test_expect_success'diff-files does not examine skip-worktree absent entries''+setup_absent&&+test-z"$(gitdiff-files--one)"+'++test_expect_success'diff-files does not examine skip-worktree dirty entries''+setup_dirty&&+test-z"$(gitdiff-files--one)"+'+ test_done
Commit 06aaaa0bf70fe37d198893f4e25fa73b6516f8a9 may step index format
version up and down, depends on whether extended flags present in the
index. This adds a test to check for index format version.
Signed-off-by: Nguyễn Thái Ngọc Duy <redacted>
Signed-off-by: Junio C Hamano <redacted>
---
.gitignore | 1 +
Makefile | 1 +
test-index-version.c | 14 ++++++++++++++
3 files changed, 16 insertions(+), 0 deletions(-)
create mode 100644 test-index-version.c
From: Johannes Sixt <hidden> Date: 2016-06-15 22:47:54
Nguyễn Thái Ngọc Duy schrieb:
Compared to the current series in pu, ...
Obviously, you didn't notice that the series is already in next, which
means that you should have made incremental patches on top of bbbe508d77.
-- Hannes
+Skip-worktree bit
+-----------------
+
+Skip-worktree bit can be defined in one (long) sentence: When reading
+an entry, if it is marked as skip-worktree, then Git pretends its
+working directory version is up to date and read the index version
+instead.
+
+To elaborate, "reading" means checking for file existence, reading
+file attributes or file content. The working directory version may be
+present or absent. If present, its content may match against the index
+version or not. Writing is not affected by this bit, content safety
+is still first priority. Note that Git _can_ update working directory
+file, that is marked skip-worktree, if it is safe to do so (i.e.
+working directory version matches index version)
+
+Although this bit looks similar to assume-unchanged bit, its goal is
+different from assume-unchanged bit's. Skip-worktree also takes
+precedence over assume-unchanged bit when both are set.
I confess I can't tell how the skip-worktree bit does differ from
assume-unchanged. Is its 'goal' different only in that you have a
different motivation for introducing it, or does it actually have a
different effect -- and what is that different effect?
Looking forward to seeing sparse checkouts soon!
Cheers,
Greg
I confess I can't tell how the skip-worktree bit does differ from
assume-unchanged. Is its 'goal' different only in that you have a
different motivation for introducing it, or does it actually have a
different effect -- and what is that different effect?
On the fun side, you could use both bits in the same worktree, to
narrow your worktree and have some assume-unchanged files.
Another difference is that with assume-unchanged bit, you make a
promise to Git that those assume-unchanged files are "good", Git does
not have to care for them. If somehow you violate the promise, Git can
harm your files on worktree.
--
Duy
From: Johannes Sixt <hidden> Date: 2016-06-15 22:47:54
Nguyen Thai Ngoc Duy schrieb:
2009/12/15 Greg Price [off-list ref]:
quoted
I confess I can't tell how the skip-worktree bit does differ from
assume-unchanged. Is its 'goal' different only in that you have a
different motivation for introducing it, or does it actually have a
different effect -- and what is that different effect?
On the fun side, you could use both bits in the same worktree, to
narrow your worktree and have some assume-unchanged files.
Another difference is that with assume-unchanged bit, you make a
promise to Git that those assume-unchanged files are "good", Git does
not have to care for them. If somehow you violate the promise, Git can
harm your files on worktree.
So, the difference is that skip-worktree will not overwrite a file that is
different from the version in the index, but assume-unchanged can? Right?
-- Hannes
On Tue, Dec 15, 2009 at 2:20 PM, Johannes Sixt [off-list ref] wrote:
Nguyen Thai Ngoc Duy schrieb:
quoted
2009/12/15 Greg Price [off-list ref]:
quoted
I confess I can't tell how the skip-worktree bit does differ from
assume-unchanged. Is its 'goal' different only in that you have a
different motivation for introducing it, or does it actually have a
different effect -- and what is that different effect?
On the fun side, you could use both bits in the same worktree, to
narrow your worktree and have some assume-unchanged files.
Another difference is that with assume-unchanged bit, you make a
promise to Git that those assume-unchanged files are "good", Git does
not have to care for them. If somehow you violate the promise, Git can
harm your files on worktree.
So, the difference is that skip-worktree will not overwrite a file that is
different from the version in the index, but assume-unchanged can? Right?