Teach Git to respect skip-worktree bit (reading part)
grep: turn on --cached for files that is marked skip-worktree ls-files: do not check for deleted file that is marked skip-worktree update-index: ignore update request if it's skip-worktree, while still allows removing diff*: skip worktree version 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
b4d1690df11ae6ce382b93778616b1a20f1774ff
8 files changed
+199
-26
builtin-commit.c
+5
@@ -180,6 +180,11 @@ static void add_remove_files(struct string_list *list)
180
for (i = 0; i < list->nr; i++) {
181
struct stat st;
182
struct string_list_item *p = &(list->items[i]);
183
+ int pos = index_name_pos(&the_index, p->string, strlen(p->string));
184
+ struct cache_entry *ce = pos < 0 ? NULL : active_cache[pos];
185
+
186
+ if (ce && ce_skip_worktree(ce))
187
+ continue;
188
189
if (!lstat(p->string, &st)) {
190
if (add_to_cache(p->string, &st, 0))
builtin-grep.c
+1
-1
@@ -517,7 +517,7 @@ static int grep_cache(struct grep_opt *opt, const char **paths, int cached,
517
* are identical, even if worktree file has been modified, so use
518
* cache version instead
519
*/
520
- if (cached || (ce->ce_flags & CE_VALID)) {
520
+ if (cached || (ce->ce_flags & CE_VALID) || ce_skip_worktree(ce)) {
521
if (ce_stage(ce))
522
continue;
523
hit |= grep_sha1(opt, ce->sha1, ce->name, 0);
builtin-ls-files.c
+2
@@ -194,6 +194,8 @@ static void show_files(struct dir_struct *dir, const char *prefix)
194
continue;
195
if (ce->ce_flags & CE_UPDATE)
196
continue;
197
+ if (ce_skip_worktree(ce))
198
+ continue;
199
err = lstat(ce->name, &st);
200
if (show_deleted && err)
201
show_ce_entry(tag_removed, ce);
builtin-update-index.c
+22
-16
@@ -172,29 +172,29 @@ static int process_directory(const char *path, int len, struct stat *st)
172
return error("%s: is a directory - add files inside instead", path);
173
}
174
175
-/*
176
- * Process a regular file
177
- */
178
-static int process_file(const char *path, int len, struct stat *st)
179
-{
180
- int pos = cache_name_pos(path, len);
181
- struct cache_entry *ce = pos < 0 ? NULL : active_cache[pos];
182
-
183
- if (ce && S_ISGITLINK(ce->ce_mode))
184
- return error("%s is already a gitlink, not replacing", path);
185
-
186
- return add_one_path(ce, path, len, st);
187
-}
188
-
175
static int process_path(const char *path)
176
{
191
- int len;
177
+ int pos, len;
178
struct stat st;
179
+ struct cache_entry *ce;
180
181
len = strlen(path);
182
if (has_symlink_leading_path(path, len))
183
return error("'%s' is beyond a symbolic link", path);
184
185
+ pos = cache_name_pos(path, len);
186
+ ce = pos < 0 ? NULL : active_cache[pos];
187
+ if (ce && ce_skip_worktree(ce)) {
188
+ /*
189
+ * working directory version is assumed "good"
190
+ * so updating it does not make sense.
191
+ * On the other hand, removing it from index should work
192
+ */
193
+ if (allow_remove && remove_file_from_cache(path))
194
+ return error("%s: cannot remove from the index", path);
195
+ return 0;
196
+ }
197
+
198
/*
199
* First things first: get the stat information, to decide
200
* what to do about the pathname!
@@ -205,7 +205,13 @@ static int process_path(const char *path)
205
if (S_ISDIR(st.st_mode))
206
return process_directory(path, len, &st);
207
208
- return process_file(path, len, &st);
208
+ /*
209
+ * Process a regular file
210
+ */
211
+ if (ce && S_ISGITLINK(ce->ce_mode))
212
+ return error("%s is already a gitlink, not replacing", path);
213
+
214
+ return add_one_path(ce, path, len, &st);
215
}
216
217
static int add_cacheinfo(unsigned int mode, const unsigned char *sha1,
diff-lib.c
+3
-2
@@ -159,7 +159,7 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
159
continue;
160
}
161
162
- if (ce_uptodate(ce))
162
+ if (ce_uptodate(ce) || ce_skip_worktree(ce))
163
continue;
164
165
/* 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,
339
int match_missing, cached;
340
341
/* if the entry is not checked out, don't examine work tree */
342
- cached = o->index_only || (idx && (idx->ce_flags & CE_VALID));
342
+ cached = o->index_only ||
343
+ (idx && ((idx->ce_flags & CE_VALID) || ce_skip_worktree(idx)));
344
/*
345
* Backward compatibility wart - "diff-index -m" does
346
* not mean "do not ignore merges", but "match_missing".
diff.c
+1
-1
@@ -1805,7 +1805,7 @@ static int reuse_worktree_file(const char *name, const unsigned char *sha1, int
1805
* If ce is marked as "assume unchanged", there is no
1806
* guarantee that work tree matches what we are looking for.
1807
*/
1808
- if (ce->ce_flags & CE_VALID)
1808
+ if ((ce->ce_flags & CE_VALID) || ce_skip_worktree(ce))
1809
return 0;
1810
1811
/*
read-cache.c
+2
-6
@@ -265,7 +265,7 @@ int ie_match_stat(const struct index_state *istate,
265
* If it's marked as always valid in the index, it's
266
* valid whatever the checked-out copy says.
267
*/
268
- if (!ignore_valid && (ce->ce_flags & CE_VALID))
268
+ if (!ignore_valid && ((ce->ce_flags & CE_VALID) || ce_skip_worktree(ce)))
269
return 0;
270
271
/*
@@ -1004,11 +1004,7 @@ static struct cache_entry *refresh_cache_ent(struct index_state *istate,
1004
if (ce_uptodate(ce))
1005
return ce;
1006
1007
- /*
1008
- * CE_VALID means the user promised us that the change to
1009
- * the work tree does not matter and told us not to worry.
1010
- */
1011
- if (!ignore_valid && (ce->ce_flags & CE_VALID)) {
1007
+ if (!ignore_valid && ((ce->ce_flags & CE_VALID) || ce_skip_worktree(ce))) {
1008
ce_mark_uptodate(ce);
1009
return ce;
1010
}
t/t7011-skip-worktree-reading.sh
new
+163
@@ -0,0 +1,163 @@
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 init.t
14
+H sub/1
15
+H sub/2
16
+EOF
17
+
18
+cat >expect.skip <<EOF
19
+S 1
20
+H 2
21
+H init.t
22
+S sub/1
23
+H sub/2
24
+EOF
25
+
26
+NULL_SHA1=e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
27
+ZERO_SHA0=0000000000000000000000000000000000000000
28
+setup_absent() {
29
+ test -f 1 && rm 1
30
+ git update-index --remove 1 &&
31
+ git update-index --add --cacheinfo 100644 $NULL_SHA1 1 &&
32
+ git update-index --skip-worktree 1
33
+}
34
+
35
+test_absent() {
36
+ echo "100644 $NULL_SHA1 0 1" > expected &&
37
+ git ls-files --stage 1 > result &&
38
+ test_cmp expected result &&
39
+ test ! -f 1
40
+}
41
+
42
+setup_dirty() {
43
+ git update-index --force-remove 1 &&
44
+ echo dirty > 1 &&
45
+ git update-index --add --cacheinfo 100644 $NULL_SHA1 1 &&
46
+ git update-index --skip-worktree 1
47
+}
48
+
49
+test_dirty() {
50
+ echo "100644 $NULL_SHA1 0 1" > expected &&
51
+ git ls-files --stage 1 > result &&
52
+ test_cmp expected result &&
53
+ echo dirty > expected
54
+ test_cmp expected 1
55
+}
56
+
57
+test_expect_success 'setup' '
58
+ test_commit init &&
59
+ mkdir sub &&
60
+ touch ./1 ./2 sub/1 sub/2 &&
61
+ git add 1 2 sub/1 sub/2 &&
62
+ git update-index --skip-worktree 1 sub/1 &&
63
+ git ls-files -t > result &&
64
+ test_cmp expect.skip result
65
+'
66
+
67
+test_expect_success 'update-index' '
68
+ setup_absent &&
69
+ git update-index 1 &&
70
+ test_absent
71
+'
72
+
73
+test_expect_success 'update-index' '
74
+ setup_dirty &&
75
+ git update-index 1 &&
76
+ test_dirty
77
+'
78
+
79
+test_expect_success 'update-index --remove' '
80
+ setup_absent &&
81
+ git update-index --remove 1 &&
82
+ test -z "$(git ls-files 1)" &&
83
+ test ! -f 1
84
+'
85
+
86
+test_expect_success 'update-index --remove' '
87
+ setup_dirty &&
88
+ git update-index --remove 1 &&
89
+ test -z "$(git ls-files 1)" &&
90
+ echo dirty > expected &&
91
+ test_cmp expected 1
92
+'
93
+
94
+test_expect_success 'ls-files --delete' '
95
+ setup_absent &&
96
+ test -z "$(git ls-files -d)"
97
+'
98
+
99
+test_expect_success 'ls-files --delete' '
100
+ setup_dirty &&
101
+ test -z "$(git ls-files -d)"
102
+'
103
+
104
+test_expect_success 'ls-files --modified' '
105
+ setup_absent &&
106
+ test -z "$(git ls-files -m)"
107
+'
108
+
109
+test_expect_success 'ls-files --modified' '
110
+ setup_dirty &&
111
+ test -z "$(git ls-files -m)"
112
+'
113
+
114
+test_expect_success 'grep with skip-worktree file' '
115
+ git update-index --no-skip-worktree 1 &&
116
+ echo test > 1 &&
117
+ git update-index 1 &&
118
+ git update-index --skip-worktree 1 &&
119
+ rm 1 &&
120
+ test "$(git grep --no-ext-grep test)" = "1:test"
121
+'
122
+
123
+echo ":000000 100644 $ZERO_SHA0 $NULL_SHA1 A 1" > expected
124
+test_expect_success 'diff-index does not examine skip-worktree absent entries' '
125
+ setup_absent &&
126
+ git diff-index HEAD -- 1 > result &&
127
+ test_cmp expected result
128
+'
129
+
130
+test_expect_success 'diff-index does not examine skip-worktree dirty entries' '
131
+ setup_dirty &&
132
+ git diff-index HEAD -- 1 > result &&
133
+ test_cmp expected result
134
+'
135
+
136
+test_expect_success 'diff-files does not examine skip-worktree absent entries' '
137
+ setup_absent &&
138
+ test -z "$(git diff-files -- one)"
139
+'
140
+
141
+test_expect_success 'diff-files does not examine skip-worktree dirty entries' '
142
+ setup_dirty &&
143
+ test -z "$(git diff-files -- one)"
144
+'
145
+
146
+test_expect_success 'git-rm succeeds on skip-worktree absent entries' '
147
+ setup_absent &&
148
+ git rm 1
149
+'
150
+
151
+test_expect_failure 'commit on skip-worktree absent entries' '
152
+ git reset &&
153
+ setup_absent &&
154
+ test_must_fail git commit -m null 1
155
+'
156
+
157
+test_expect_failure 'commit on skip-worktree dirty entries' '
158
+ git reset &&
159
+ setup_dirty &&
160
+ test_must_fail git commit -m null 1
161
+'
162
+
163
+test_done