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 <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Nguyễn Thái Ngọc Duy committed
Aug 20, 2009 at 20:46 UTC
44a3691362dc71241a5d68d90b07642c46992e4a
6 files changed
+109
-3
Documentation/git-ls-files.txt
+1
@@ -107,6 +107,7 @@ OPTIONS
107
Identify the file status with the following tags (followed by
108
a space) at the start of each line:
109
H:: cached
110
+ S:: skip-worktree
111
M:: unmerged
112
R:: removed/deleted
113
C:: modified/changed
Documentation/git-update-index.txt
+29
@@ -15,6 +15,7 @@ SYNOPSIS
15
[--cacheinfo <mode> <object> <file>]\*
16
[--chmod=(+|-)x]
17
[--assume-unchanged | --no-assume-unchanged]
18
+ [--skip-worktree | --no-skip-worktree]
19
[--ignore-submodules]
20
[--really-refresh] [--unresolve] [--again | -g]
21
[--info-only] [--index-info]
@@ -99,6 +100,13 @@ in the index e.g. when merging in a commit;
100
thus, in case the assumed-untracked file is changed upstream,
101
you will need to handle the situation manually.
102
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
+
110
-g::
111
--again::
112
Runs 'git-update-index' itself on the paths whose index
@@ -304,6 +312,27 @@ M foo.c
312
<9> now it checks with lstat(2) and finds it has been changed.
313
314
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
+
336
Configuration
337
-------------
338
builtin-ls-files.c
+4
-1
@@ -37,6 +37,7 @@ static const char *tag_removed = "";
37
static const char *tag_other = "";
38
static const char *tag_killed = "";
39
static const char *tag_modified = "";
40
+static const char *tag_skip_worktree = "";
41
42
static void show_dir_entry(const char *tag, struct dir_entry *ent)
43
{
@@ -178,7 +179,8 @@ static void show_files(struct dir_struct *dir, const char *prefix)
179
continue;
180
if (ce->ce_flags & CE_UPDATE)
181
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);
184
}
185
}
186
if (show_deleted | show_modified) {
@@ -490,6 +492,7 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)
492
tag_modified = "C ";
493
tag_other = "? ";
494
tag_killed = "K ";
495
+ tag_skip_worktree = "S ";
496
}
497
if (show_modified || show_others || show_deleted || (dir.flags & DIR_SHOW_IGNORED) || show_killed)
498
require_work_tree = 1;
builtin-update-index.c
+15
-1
@@ -24,6 +24,7 @@ static int info_only;
24
static int force_remove;
25
static int verbose;
26
static int mark_valid_only;
27
+static int mark_skip_worktree_only;
28
#define MARK_FLAG 1
29
#define UNMARK_FLAG 2
30
@@ -276,6 +277,11 @@ static void update_one(const char *path, const char *prefix, int prefix_length)
277
die("Unable to mark file %s", path);
278
goto free_return;
279
}
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
+ }
285
286
if (force_remove) {
287
if (remove_file_from_cache(p))
@@ -384,7 +390,7 @@ static void read_index_info(int line_termination)
390
}
391
392
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>...";
394
395
static unsigned char head_sha1[20];
396
static unsigned char merge_head_sha1[20];
@@ -650,6 +656,14 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
656
mark_valid_only = UNMARK_FLAG;
657
continue;
658
}
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
+ }
667
if (!strcmp(path, "--info-only")) {
668
info_only = 1;
669
continue;
cache.h
+3
-1
@@ -181,10 +181,11 @@ struct cache_entry {
181
* Extended on-disk flags
182
*/
183
#define CE_INTENT_TO_ADD 0x20000000
184
+#define CE_SKIP_WORKTREE 0x40000000
185
/* CE_EXTENDED2 is for future extension */
186
#define CE_EXTENDED2 0x80000000
187
187
-#define CE_EXTENDED_FLAGS (CE_INTENT_TO_ADD)
188
+#define CE_EXTENDED_FLAGS (CE_INTENT_TO_ADD | CE_SKIP_WORKTREE)
189
190
/*
191
* Safeguard to avoid saving wrong flags:
@@ -233,6 +234,7 @@ static inline size_t ce_namelen(const struct cache_entry *ce)
234
ondisk_cache_entry_size(ce_namelen(ce)))
235
#define ce_stage(ce) ((CE_STAGEMASK & (ce)->ce_flags) >> CE_STAGESHIFT)
236
#define ce_uptodate(ce) ((ce)->ce_flags & CE_UPTODATE)
237
+#define ce_skip_worktree(ce) ((ce)->ce_flags & CE_SKIP_WORKTREE)
238
#define ce_mark_uptodate(ce) ((ce)->ce_flags |= CE_UPTODATE)
239
240
#define ce_permissions(mode) (((mode) & 0100) ? 0755 : 0644)
t/t2104-update-index-skip-worktree.sh
new
+57
@@ -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