diff options
-rw-r--r-- | Documentation/git-ls-files.txt | 1 | ||||
-rw-r--r-- | Documentation/git-update-index.txt | 29 | ||||
-rw-r--r-- | builtin-ls-files.c | 5 | ||||
-rw-r--r-- | builtin-update-index.c | 16 | ||||
-rw-r--r-- | cache.h | 4 | ||||
-rwxr-xr-x | t/t2104-update-index-skip-worktree.sh | 57 |
6 files changed, 109 insertions, 3 deletions
diff --git a/Documentation/git-ls-files.txt b/Documentation/git-ls-files.txt index 021066e95d..6f9d880aa4 100644 --- a/Documentation/git-ls-files.txt +++ b/Documentation/git-ls-files.txt @@ -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 diff --git a/Documentation/git-update-index.txt b/Documentation/git-update-index.txt index 25e0bbea86..a10f355b7c 100644 --- a/Documentation/git-update-index.txt +++ b/Documentation/git-update-index.txt @@ -15,6 +15,7 @@ SYNOPSIS [--cacheinfo <mode> <object> <file>]\* [--chmod=(+|-)x] [--assume-unchanged | --no-assume-unchanged] + [--skip-worktree | --no-skip-worktree] [--ignore-submodules] [--really-refresh] [--unresolve] [--again | -g] [--info-only] [--index-info] @@ -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 ------------- diff --git a/builtin-ls-files.c b/builtin-ls-files.c index f473220502..c1afbad453 100644 --- a/builtin-ls-files.c +++ b/builtin-ls-files.c @@ -37,6 +37,7 @@ static const char *tag_removed = ""; static const char *tag_other = ""; static const char *tag_killed = ""; static const char *tag_modified = ""; +static const char *tag_skip_worktree = ""; static void show_dir_entry(const char *tag, struct dir_entry *ent) { @@ -178,7 +179,8 @@ static void show_files(struct dir_struct *dir, const char *prefix) continue; if (ce->ce_flags & CE_UPDATE) continue; - show_ce_entry(ce_stage(ce) ? tag_unmerged : tag_cached, ce); + show_ce_entry(ce_stage(ce) ? tag_unmerged : + (ce_skip_worktree(ce) ? tag_skip_worktree : tag_cached), ce); } } if (show_deleted | show_modified) { @@ -490,6 +492,7 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix) tag_modified = "C "; tag_other = "? "; tag_killed = "K "; + tag_skip_worktree = "S "; } if (show_modified || show_others || show_deleted || (dir.flags & DIR_SHOW_IGNORED) || show_killed) require_work_tree = 1; diff --git a/builtin-update-index.c b/builtin-update-index.c index f1b6c8e88e..5e97d09497 100644 --- a/builtin-update-index.c +++ b/builtin-update-index.c @@ -24,6 +24,7 @@ static int info_only; static int force_remove; static int verbose; static int mark_valid_only; +static int mark_skip_worktree_only; #define MARK_FLAG 1 #define UNMARK_FLAG 2 @@ -276,6 +277,11 @@ static void update_one(const char *path, const char *prefix, int prefix_length) die("Unable to mark file %s", path); goto free_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); + goto free_return; + } if (force_remove) { if (remove_file_from_cache(p)) @@ -384,7 +390,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] [--skip-worktree|--no-skip-worktree] [--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]; @@ -650,6 +656,14 @@ int cmd_update_index(int argc, const char **argv, const char *prefix) mark_valid_only = UNMARK_FLAG; continue; } + if (!strcmp(path, "--no-skip-worktree")) { + mark_skip_worktree_only = UNMARK_FLAG; + continue; + } + if (!strcmp(path, "--skip-worktree")) { + mark_skip_worktree_only = MARK_FLAG; + continue; + } if (!strcmp(path, "--info-only")) { info_only = 1; continue; @@ -181,10 +181,11 @@ struct cache_entry { * Extended on-disk flags */ #define CE_INTENT_TO_ADD 0x20000000 +#define CE_SKIP_WORKTREE 0x40000000 /* CE_EXTENDED2 is for future extension */ #define CE_EXTENDED2 0x80000000 -#define CE_EXTENDED_FLAGS (CE_INTENT_TO_ADD) +#define CE_EXTENDED_FLAGS (CE_INTENT_TO_ADD | CE_SKIP_WORKTREE) /* * Safeguard to avoid saving wrong flags: @@ -233,6 +234,7 @@ static inline size_t ce_namelen(const struct cache_entry *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_skip_worktree(ce) ((ce)->ce_flags & CE_SKIP_WORKTREE) #define ce_mark_uptodate(ce) ((ce)->ce_flags |= CE_UPTODATE) #define ce_permissions(mode) (((mode) & 0100) ? 0755 : 0644) diff --git a/t/t2104-update-index-skip-worktree.sh b/t/t2104-update-index-skip-worktree.sh new file mode 100755 index 0000000000..1d0879be06 --- /dev/null +++ b/t/t2104-update-index-skip-worktree.sh @@ -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 +H 1 +H 2 +H sub/1 +H sub/2 +EOF + +cat >expect.skip <<EOF +S 1 +H 2 +S sub/1 +H sub/2 +EOF + +test_expect_success 'setup' ' + mkdir sub && + touch ./1 ./2 sub/1 sub/2 && + git add 1 2 sub/1 sub/2 && + git ls-files -t | test_cmp expect.full - +' + +test_expect_success 'index is at version 2' ' + test "$(test-index-version < .git/index)" = 2 +' + +test_expect_success 'update-index --skip-worktree' ' + git update-index --skip-worktree 1 sub/1 && + git ls-files -t | test_cmp expect.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' ' + git ls-files -t | test_cmp expect.skip - +' + +test_expect_success 'update-index --no-skip-worktree' ' + git update-index --no-skip-worktree 1 sub/1 && + git ls-files -t | test_cmp expect.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 |