Skip to content

Commit 44a3691

Browse files
pcloudsgitster
authored andcommitted
Introduce "skip-worktree" bit in index, teach Git to get/set this bit
Detail about this bit is in Documentation/git-update-index.txt. Signed-off-by: Nguyễn Thái Ngọc Duy <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent dbd57f9 commit 44a3691

File tree

6 files changed

+109
-3
lines changed

6 files changed

+109
-3
lines changed

Documentation/git-ls-files.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ OPTIONS
107107
Identify the file status with the following tags (followed by
108108
a space) at the start of each line:
109109
H:: cached
110+
S:: skip-worktree
110111
M:: unmerged
111112
R:: removed/deleted
112113
C:: modified/changed

Documentation/git-update-index.txt

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ SYNOPSIS
1515
[--cacheinfo <mode> <object> <file>]\*
1616
[--chmod=(+|-)x]
1717
[--assume-unchanged | --no-assume-unchanged]
18+
[--skip-worktree | --no-skip-worktree]
1819
[--ignore-submodules]
1920
[--really-refresh] [--unresolve] [--again | -g]
2021
[--info-only] [--index-info]
@@ -99,6 +100,13 @@ in the index e.g. when merging in a commit;
99100
thus, in case the assumed-untracked file is changed upstream,
100101
you will need to handle the situation manually.
101102

103+
--skip-worktree::
104+
--no-skip-worktree::
105+
When one of these flags is specified, the object name recorded
106+
for the paths are not updated. Instead, these options
107+
set and unset the "skip-worktree" bit for the paths. See
108+
section "Skip-worktree bit" below for more information.
109+
102110
-g::
103111
--again::
104112
Runs 'git-update-index' itself on the paths whose index
@@ -304,6 +312,27 @@ M foo.c
304312
<9> now it checks with lstat(2) and finds it has been changed.
305313

306314

315+
Skip-worktree bit
316+
-----------------
317+
318+
Skip-worktree bit can be defined in one (long) sentence: When reading
319+
an entry, if it is marked as skip-worktree, then Git pretends its
320+
working directory version is up to date and read the index version
321+
instead.
322+
323+
To elaborate, "reading" means checking for file existence, reading
324+
file attributes or file content. The working directory version may be
325+
present or absent. If present, its content may match against the index
326+
version or not. Writing is not affected by this bit, content safety
327+
is still first priority. Note that Git _can_ update working directory
328+
file, that is marked skip-worktree, if it is safe to do so (i.e.
329+
working directory version matches index version)
330+
331+
Although this bit looks similar to assume-unchanged bit, its goal is
332+
different from assume-unchanged bit's. Skip-worktree also takes
333+
precedence over assume-unchanged bit when both are set.
334+
335+
307336
Configuration
308337
-------------
309338

builtin-ls-files.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ static const char *tag_removed = "";
3737
static const char *tag_other = "";
3838
static const char *tag_killed = "";
3939
static const char *tag_modified = "";
40+
static const char *tag_skip_worktree = "";
4041

4142
static void show_dir_entry(const char *tag, struct dir_entry *ent)
4243
{
@@ -178,7 +179,8 @@ static void show_files(struct dir_struct *dir, const char *prefix)
178179
continue;
179180
if (ce->ce_flags & CE_UPDATE)
180181
continue;
181-
show_ce_entry(ce_stage(ce) ? tag_unmerged : tag_cached, ce);
182+
show_ce_entry(ce_stage(ce) ? tag_unmerged :
183+
(ce_skip_worktree(ce) ? tag_skip_worktree : tag_cached), ce);
182184
}
183185
}
184186
if (show_deleted | show_modified) {
@@ -490,6 +492,7 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)
490492
tag_modified = "C ";
491493
tag_other = "? ";
492494
tag_killed = "K ";
495+
tag_skip_worktree = "S ";
493496
}
494497
if (show_modified || show_others || show_deleted || (dir.flags & DIR_SHOW_IGNORED) || show_killed)
495498
require_work_tree = 1;

builtin-update-index.c

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ static int info_only;
2424
static int force_remove;
2525
static int verbose;
2626
static int mark_valid_only;
27+
static int mark_skip_worktree_only;
2728
#define MARK_FLAG 1
2829
#define UNMARK_FLAG 2
2930

@@ -276,6 +277,11 @@ static void update_one(const char *path, const char *prefix, int prefix_length)
276277
die("Unable to mark file %s", path);
277278
goto free_return;
278279
}
280+
if (mark_skip_worktree_only) {
281+
if (mark_ce_flags(p, CE_SKIP_WORKTREE, mark_skip_worktree_only == MARK_FLAG))
282+
die("Unable to mark file %s", path);
283+
goto free_return;
284+
}
279285

280286
if (force_remove) {
281287
if (remove_file_from_cache(p))
@@ -384,7 +390,7 @@ static void read_index_info(int line_termination)
384390
}
385391

386392
static const char update_index_usage[] =
387-
"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>...";
393+
"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>...";
388394

389395
static unsigned char head_sha1[20];
390396
static unsigned char merge_head_sha1[20];
@@ -650,6 +656,14 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
650656
mark_valid_only = UNMARK_FLAG;
651657
continue;
652658
}
659+
if (!strcmp(path, "--no-skip-worktree")) {
660+
mark_skip_worktree_only = UNMARK_FLAG;
661+
continue;
662+
}
663+
if (!strcmp(path, "--skip-worktree")) {
664+
mark_skip_worktree_only = MARK_FLAG;
665+
continue;
666+
}
653667
if (!strcmp(path, "--info-only")) {
654668
info_only = 1;
655669
continue;

cache.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,10 +181,11 @@ struct cache_entry {
181181
* Extended on-disk flags
182182
*/
183183
#define CE_INTENT_TO_ADD 0x20000000
184+
#define CE_SKIP_WORKTREE 0x40000000
184185
/* CE_EXTENDED2 is for future extension */
185186
#define CE_EXTENDED2 0x80000000
186187

187-
#define CE_EXTENDED_FLAGS (CE_INTENT_TO_ADD)
188+
#define CE_EXTENDED_FLAGS (CE_INTENT_TO_ADD | CE_SKIP_WORKTREE)
188189

189190
/*
190191
* Safeguard to avoid saving wrong flags:
@@ -233,6 +234,7 @@ static inline size_t ce_namelen(const struct cache_entry *ce)
233234
ondisk_cache_entry_size(ce_namelen(ce)))
234235
#define ce_stage(ce) ((CE_STAGEMASK & (ce)->ce_flags) >> CE_STAGESHIFT)
235236
#define ce_uptodate(ce) ((ce)->ce_flags & CE_UPTODATE)
237+
#define ce_skip_worktree(ce) ((ce)->ce_flags & CE_SKIP_WORKTREE)
236238
#define ce_mark_uptodate(ce) ((ce)->ce_flags |= CE_UPTODATE)
237239

238240
#define ce_permissions(mode) (((mode) & 0100) ? 0755 : 0644)

t/t2104-update-index-skip-worktree.sh

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
#!/bin/sh
2+
#
3+
# Copyright (c) 2008 Nguyễn Thái Ngọc Duy
4+
#
5+
6+
test_description='skip-worktree bit test'
7+
8+
. ./test-lib.sh
9+
10+
cat >expect.full <<EOF
11+
H 1
12+
H 2
13+
H sub/1
14+
H sub/2
15+
EOF
16+
17+
cat >expect.skip <<EOF
18+
S 1
19+
H 2
20+
S sub/1
21+
H sub/2
22+
EOF
23+
24+
test_expect_success 'setup' '
25+
mkdir sub &&
26+
touch ./1 ./2 sub/1 sub/2 &&
27+
git add 1 2 sub/1 sub/2 &&
28+
git ls-files -t | test_cmp expect.full -
29+
'
30+
31+
test_expect_success 'index is at version 2' '
32+
test "$(test-index-version < .git/index)" = 2
33+
'
34+
35+
test_expect_success 'update-index --skip-worktree' '
36+
git update-index --skip-worktree 1 sub/1 &&
37+
git ls-files -t | test_cmp expect.skip -
38+
'
39+
40+
test_expect_success 'index is at version 3 after having some skip-worktree entries' '
41+
test "$(test-index-version < .git/index)" = 3
42+
'
43+
44+
test_expect_success 'ls-files -t' '
45+
git ls-files -t | test_cmp expect.skip -
46+
'
47+
48+
test_expect_success 'update-index --no-skip-worktree' '
49+
git update-index --no-skip-worktree 1 sub/1 &&
50+
git ls-files -t | test_cmp expect.full -
51+
'
52+
53+
test_expect_success 'index version is back to 2 when there is no skip-worktree entry' '
54+
test "$(test-index-version < .git/index)" = 2
55+
'
56+
57+
test_done

0 commit comments

Comments
 (0)