@matheusbsbs / matheus-bagliano / commits / 44a3691362
Fork 0

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