1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
|
#!/bin/sh
test_description='applying patch with mode bits'
. ./test-lib.sh
test_expect_success setup '
echo original >file &&
git add file &&
test_tick &&
git commit -m initial &&
git tag initial &&
echo modified >file &&
git diff --stat -p >patch-0.txt &&
chmod +x file &&
git diff --stat -p >patch-1.txt &&
sed "s/^\(new mode \).*/\1/" <patch-1.txt >patch-empty-mode.txt &&
sed "s/^\(new mode \).*/\1garbage/" <patch-1.txt >patch-bogus-mode.txt
'
test_expect_success FILEMODE 'same mode (no index)' '
git reset --hard &&
chmod +x file &&
git apply patch-0.txt &&
test -x file
'
test_expect_success FILEMODE 'same mode (with index)' '
git reset --hard &&
chmod +x file &&
git add file &&
git apply --index patch-0.txt &&
test -x file &&
git diff --exit-code
'
test_expect_success FILEMODE 'same mode (index only)' '
git reset --hard &&
chmod +x file &&
git add file &&
git apply --cached patch-0.txt &&
git ls-files -s file >ls-files-output &&
test_grep "^100755" ls-files-output
'
test_expect_success FILEMODE 'mode update (no index)' '
git reset --hard &&
git apply patch-1.txt &&
test -x file
'
test_expect_success FILEMODE 'mode update (with index)' '
git reset --hard &&
git apply --index patch-1.txt &&
test -x file &&
git diff --exit-code
'
test_expect_success FILEMODE 'mode update (index only)' '
git reset --hard &&
git apply --cached patch-1.txt &&
git ls-files -s file >ls-files-output &&
test_grep "^100755" ls-files-output
'
test_expect_success FILEMODE 'empty mode is rejected' '
git reset --hard &&
test_must_fail git apply patch-empty-mode.txt 2>err &&
test_grep "invalid mode" err
'
test_expect_success FILEMODE 'bogus mode is rejected' '
git reset --hard &&
test_must_fail git apply patch-bogus-mode.txt 2>err &&
test_grep "invalid mode" err
'
test_expect_success POSIXPERM 'do not use core.sharedRepository for working tree files' '
git reset --hard &&
test_config core.sharedRepository 0666 &&
(
# Remove a default ACL if possible.
(setfacl -k . 2>/dev/null || true) &&
umask 0077 &&
# Test both files (f1) and leading dirs (d)
mkdir d &&
touch f1 d/f2 &&
git add f1 d/f2 &&
git diff --staged >patch-f1-and-f2.txt &&
rm -rf d f1 &&
git apply patch-f1-and-f2.txt &&
echo "-rw-------" >f1_mode.expected &&
echo "drwx------" >d_mode.expected &&
test_modebits f1 >f1_mode.actual &&
test_modebits d >d_mode.actual &&
test_cmp f1_mode.expected f1_mode.actual &&
test_cmp d_mode.expected d_mode.actual
)
'
test_file_mode_common () {
if test "$1" = "000000"
then
test_must_be_empty "$2"
else
test_grep "^$1 " "$2"
fi
}
test_file_mode_staged () {
git ls-files --stage -- "$2" >ls-files-output &&
test_file_mode_common "$1" ls-files-output
}
test_file_mode_HEAD () {
git ls-tree HEAD -- "$2" >ls-tree-output &&
test_file_mode_common "$1" ls-tree-output
}
test_expect_success 'git apply respects core.fileMode' '
test_config core.fileMode false &&
echo true >script.sh &&
git add --chmod=+x script.sh &&
test_file_mode_staged 100755 script.sh &&
test_tick && git commit -m "Add script" &&
test_file_mode_HEAD 100755 script.sh &&
echo true >>script.sh &&
test_tick && git commit -m "Modify script" script.sh &&
git format-patch -1 --stdout >patch &&
test_grep "^index.*100755$" patch &&
git switch -c branch HEAD^ &&
git apply --index patch 2>err &&
test_grep ! "has type 100644, expected 100755" err &&
git reset --hard &&
git apply patch 2>err &&
test_grep ! "has type 100644, expected 100755" err &&
git apply --cached patch 2>err &&
test_grep ! "has type 100644, expected 100755" err &&
git reset --hard
'
test_expect_success 'setup: git apply [--reverse] warns about incorrect file modes' '
test_config core.fileMode false &&
>mode_test &&
git add --chmod=-x mode_test &&
test_file_mode_staged 100644 mode_test &&
test_tick && git commit -m "add mode_test" &&
test_file_mode_HEAD 100644 mode_test &&
git tag mode_test_forward_initial &&
echo content >>mode_test &&
test_tick && git commit -m "append to mode_test" mode_test &&
test_file_mode_HEAD 100644 mode_test &&
git tag mode_test_reverse_initial &&
git format-patch -1 --stdout >patch &&
test_grep "^index .* 100644$" patch
'
test_expect_success 'git apply warns about incorrect file modes' '
test_config core.fileMode false &&
git reset --hard mode_test_forward_initial &&
git add --chmod=+x mode_test &&
test_file_mode_staged 100755 mode_test &&
test_tick && git commit -m "make mode_test executable" &&
test_file_mode_HEAD 100755 mode_test &&
git apply --index patch 2>err &&
test_grep "has type 100755, expected 100644" err &&
test_file_mode_staged 100755 mode_test &&
test_tick && git commit -m "redo: append to mode_test" &&
test_file_mode_HEAD 100755 mode_test
'
test_expect_success 'git apply --reverse warns about incorrect file modes' '
test_config core.fileMode false &&
git reset --hard mode_test_reverse_initial &&
git add --chmod=+x mode_test &&
test_file_mode_staged 100755 mode_test &&
test_tick && git commit -m "make mode_test executable" &&
test_file_mode_HEAD 100755 mode_test &&
git apply --index --reverse patch 2>err &&
test_grep "has type 100755, expected 100644" err &&
test_file_mode_staged 100755 mode_test &&
test_tick && git commit -m "undo: append to mode_test" &&
test_file_mode_HEAD 100755 mode_test
'
test_expect_success 'setup: git apply [--reverse] restores file modes (change_x_to_notx)' '
test_config core.fileMode false &&
touch change_x_to_notx &&
git add --chmod=+x change_x_to_notx &&
test_file_mode_staged 100755 change_x_to_notx &&
test_tick && git commit -m "add change_x_to_notx as executable" &&
test_file_mode_HEAD 100755 change_x_to_notx &&
git add --chmod=-x change_x_to_notx &&
test_file_mode_staged 100644 change_x_to_notx &&
test_tick && git commit -m "make change_x_to_notx not executable" &&
test_file_mode_HEAD 100644 change_x_to_notx &&
git rm change_x_to_notx &&
test_file_mode_staged 000000 change_x_to_notx &&
test_tick && git commit -m "remove change_x_to_notx" &&
test_file_mode_HEAD 000000 change_x_to_notx &&
git format-patch -o patches -3 &&
mv patches/0001-* change_x_to_notx-0001-create-0755.patch &&
mv patches/0002-* change_x_to_notx-0002-chmod-0644.patch &&
mv patches/0003-* change_x_to_notx-0003-delete.patch &&
test_grep "^new file mode 100755$" change_x_to_notx-0001-create-0755.patch &&
test_grep "^old mode 100755$" change_x_to_notx-0002-chmod-0644.patch &&
test_grep "^new mode 100644$" change_x_to_notx-0002-chmod-0644.patch &&
test_grep "^deleted file mode 100644$" change_x_to_notx-0003-delete.patch &&
git tag change_x_to_notx_initial
'
test_expect_success 'git apply restores file modes (change_x_to_notx)' '
test_config core.fileMode false &&
git reset --hard change_x_to_notx_initial &&
git apply --index change_x_to_notx-0001-create-0755.patch &&
test_file_mode_staged 100755 change_x_to_notx &&
test_tick && git commit -m "redo: add change_x_to_notx as executable" &&
test_file_mode_HEAD 100755 change_x_to_notx &&
git apply --index change_x_to_notx-0002-chmod-0644.patch 2>err &&
test_grep ! "has type 100.*, expected 100.*" err &&
test_file_mode_staged 100644 change_x_to_notx &&
test_tick && git commit -m "redo: make change_x_to_notx not executable" &&
test_file_mode_HEAD 100644 change_x_to_notx &&
git apply --index change_x_to_notx-0003-delete.patch 2>err &&
test_grep ! "has type 100.*, expected 100.*" err &&
test_file_mode_staged 000000 change_x_to_notx &&
test_tick && git commit -m "redo: remove change_notx_to_x" &&
test_file_mode_HEAD 000000 change_x_to_notx
'
test_expect_success 'git apply --reverse restores file modes (change_x_to_notx)' '
test_config core.fileMode false &&
git reset --hard change_x_to_notx_initial &&
git apply --index --reverse change_x_to_notx-0003-delete.patch &&
test_file_mode_staged 100644 change_x_to_notx &&
test_tick && git commit -m "undo: remove change_x_to_notx" &&
test_file_mode_HEAD 100644 change_x_to_notx &&
git apply --index --reverse change_x_to_notx-0002-chmod-0644.patch 2>err &&
test_grep ! "has type 100.*, expected 100.*" err &&
test_file_mode_staged 100755 change_x_to_notx &&
test_tick && git commit -m "undo: make change_x_to_notx not executable" &&
test_file_mode_HEAD 100755 change_x_to_notx &&
git apply --index --reverse change_x_to_notx-0001-create-0755.patch 2>err &&
test_grep ! "has type 100.*, expected 100.*" err &&
test_file_mode_staged 000000 change_x_to_notx &&
test_tick && git commit -m "undo: add change_x_to_notx as executable" &&
test_file_mode_HEAD 000000 change_x_to_notx
'
test_expect_success 'setup: git apply [--reverse] restores file modes (change_notx_to_x)' '
test_config core.fileMode false &&
touch change_notx_to_x &&
git add --chmod=-x change_notx_to_x &&
test_file_mode_staged 100644 change_notx_to_x &&
test_tick && git commit -m "add change_notx_to_x as not executable" &&
test_file_mode_HEAD 100644 change_notx_to_x &&
git add --chmod=+x change_notx_to_x &&
test_file_mode_staged 100755 change_notx_to_x &&
test_tick && git commit -m "make change_notx_to_x executable" &&
test_file_mode_HEAD 100755 change_notx_to_x &&
git rm change_notx_to_x &&
test_file_mode_staged 000000 change_notx_to_x &&
test_tick && git commit -m "remove change_notx_to_x" &&
test_file_mode_HEAD 000000 change_notx_to_x &&
git format-patch -o patches -3 &&
mv patches/0001-* change_notx_to_x-0001-create-0644.patch &&
mv patches/0002-* change_notx_to_x-0002-chmod-0755.patch &&
mv patches/0003-* change_notx_to_x-0003-delete.patch &&
test_grep "^new file mode 100644$" change_notx_to_x-0001-create-0644.patch &&
test_grep "^old mode 100644$" change_notx_to_x-0002-chmod-0755.patch &&
test_grep "^new mode 100755$" change_notx_to_x-0002-chmod-0755.patch &&
test_grep "^deleted file mode 100755$" change_notx_to_x-0003-delete.patch &&
git tag change_notx_to_x_initial
'
test_expect_success 'git apply restores file modes (change_notx_to_x)' '
test_config core.fileMode false &&
git reset --hard change_notx_to_x_initial &&
git apply --index change_notx_to_x-0001-create-0644.patch &&
test_file_mode_staged 100644 change_notx_to_x &&
test_tick && git commit -m "redo: add change_notx_to_x as not executable" &&
test_file_mode_HEAD 100644 change_notx_to_x &&
git apply --index change_notx_to_x-0002-chmod-0755.patch 2>err &&
test_grep ! "has type 100.*, expected 100.*" err &&
test_file_mode_staged 100755 change_notx_to_x &&
test_tick && git commit -m "redo: make change_notx_to_x executable" &&
test_file_mode_HEAD 100755 change_notx_to_x &&
git apply --index change_notx_to_x-0003-delete.patch &&
test_grep ! "has type 100.*, expected 100.*" err &&
test_file_mode_staged 000000 change_notx_to_x &&
test_tick && git commit -m "undo: remove change_notx_to_x" &&
test_file_mode_HEAD 000000 change_notx_to_x
'
test_expect_success 'git apply --reverse restores file modes (change_notx_to_x)' '
test_config core.fileMode false &&
git reset --hard change_notx_to_x_initial &&
git apply --index --reverse change_notx_to_x-0003-delete.patch &&
test_file_mode_staged 100755 change_notx_to_x &&
test_tick && git commit -m "undo: remove change_notx_to_x" &&
test_file_mode_HEAD 100755 change_notx_to_x &&
git apply --index --reverse change_notx_to_x-0002-chmod-0755.patch 2>err &&
test_grep ! "has type 100.*, expected 100.*" err &&
test_file_mode_staged 100644 change_notx_to_x &&
test_tick && git commit -m "undo: make change_notx_to_x executable" &&
test_file_mode_HEAD 100644 change_notx_to_x &&
git apply --index --reverse change_notx_to_x-0001-create-0644.patch 2>err &&
test_grep ! "has type 100.*, expected 100.*" err &&
test_file_mode_staged 000000 change_notx_to_x &&
test_tick && git commit -m "undo: add change_notx_to_x as not executable" &&
test_file_mode_HEAD 000000 change_notx_to_x
'
test_expect_success POSIXPERM 'patch mode for new file is canonicalized' '
cat >patch <<-\EOF &&
diff --git a/non-canon b/non-canon
new file mode 100660
--- /dev/null
+++ b/non-canon
+content
EOF
test_when_finished "git reset --hard" &&
(
umask 0 &&
git apply --index patch 2>err
) &&
test_must_be_empty err &&
git ls-files -s -- non-canon >staged &&
test_grep "^100644" staged &&
ls -l non-canon >worktree &&
test_grep "^-rw-rw-rw" worktree
'
test_expect_success POSIXPERM 'patch mode for deleted file is canonicalized' '
test_when_finished "git reset --hard" &&
echo content >non-canon &&
chmod 666 non-canon &&
git add non-canon &&
cat >patch <<-\EOF &&
diff --git a/non-canon b/non-canon
deleted file mode 100660
--- a/non-canon
+++ /dev/null
@@ -1 +0,0 @@
-content
EOF
git apply --index patch 2>err &&
test_must_be_empty err &&
git ls-files -- non-canon >staged &&
test_must_be_empty staged &&
test_path_is_missing non-canon
'
test_expect_success POSIXPERM 'patch mode for mode change is canonicalized' '
test_when_finished "git reset --hard" &&
echo content >non-canon &&
git add non-canon &&
cat >patch <<-\EOF &&
diff --git a/non-canon b/non-canon
old mode 100660
new mode 100770
EOF
(
umask 0 &&
git apply --index patch 2>err
) &&
test_must_be_empty err &&
git ls-files -s -- non-canon >staged &&
test_grep "^100755" staged &&
ls -l non-canon >worktree &&
test_grep "^-rwxrwxrwx" worktree
'
test_done
|